sandbox-web-ide/frontend/context/TerminalContext.tsx

138 lines
3.7 KiB
TypeScript
Raw Permalink Normal View History

2024-10-21 13:57:45 -06:00
"use client"
2024-07-23 17:30:35 -04:00
2024-10-21 13:57:45 -06:00
import { useSocket } from "@/context/SocketContext"
import {
closeTerminal as closeTerminalHelper,
createTerminal as createTerminalHelper,
} from "@/lib/terminal"
import { Terminal } from "@xterm/xterm"
import React, { createContext, useContext, useState } from "react"
2024-07-23 17:30:35 -04:00
interface TerminalContextType {
2024-10-21 13:57:45 -06:00
terminals: { id: string; terminal: Terminal | null }[]
setTerminals: React.Dispatch<
React.SetStateAction<{ id: string; terminal: Terminal | null }[]>
>
activeTerminalId: string
setActiveTerminalId: React.Dispatch<React.SetStateAction<string>>
creatingTerminal: boolean
setCreatingTerminal: React.Dispatch<React.SetStateAction<boolean>>
createNewTerminal: (command?: string) => Promise<void>
closeTerminal: (id: string) => void
deploy: (callback: () => void) => void
getAppExists:
| ((appName: string) => Promise<{ success: boolean; exists?: boolean }>)
| null
2024-07-23 17:30:35 -04:00
}
2024-10-21 13:57:45 -06:00
const TerminalContext = createContext<TerminalContextType | undefined>(
undefined
)
2024-07-23 17:30:35 -04:00
2024-10-21 13:57:45 -06:00
export const TerminalProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const { socket } = useSocket()
const [terminals, setTerminals] = useState<
{ id: string; terminal: Terminal | null }[]
>([])
const [activeTerminalId, setActiveTerminalId] = useState<string>("")
const [creatingTerminal, setCreatingTerminal] = useState<boolean>(false)
const [isSocketReady, setIsSocketReady] = useState<boolean>(false)
// Listen for the "ready" signal from the socket
React.useEffect(() => {
if (socket) {
socket.on("ready", () => {
setIsSocketReady(true)
})
}
return () => {
if (socket) socket.off("ready")
}
}, [socket])
2024-07-23 17:30:35 -04:00
const createNewTerminal = async (command?: string): Promise<void> => {
2024-10-21 13:57:45 -06:00
if (!socket) return
setCreatingTerminal(true)
2024-07-23 17:30:35 -04:00
try {
createTerminalHelper({
setTerminals,
setActiveTerminalId,
setCreatingTerminal,
command,
2024-07-23 17:30:35 -04:00
socket,
2024-10-21 13:57:45 -06:00
})
2024-07-23 17:30:35 -04:00
} catch (error) {
2024-10-21 13:57:45 -06:00
console.error("Error creating terminal:", error)
2024-07-23 17:30:35 -04:00
} finally {
2024-10-21 13:57:45 -06:00
setCreatingTerminal(false)
2024-07-23 17:30:35 -04:00
}
2024-10-21 13:57:45 -06:00
}
2024-07-23 17:30:35 -04:00
const closeTerminal = (id: string) => {
2024-10-21 13:57:45 -06:00
if (!socket) return
const terminalToClose = terminals.find((term) => term.id === id)
2024-07-23 17:30:35 -04:00
if (terminalToClose) {
closeTerminalHelper({
term: terminalToClose,
terminals,
setTerminals,
setActiveTerminalId,
2024-11-17 12:35:56 -05:00
setClosingTerminal: () => {},
2024-07-23 17:30:35 -04:00
socket,
activeTerminalId,
2024-10-21 13:57:45 -06:00
})
2024-07-23 17:30:35 -04:00
}
2024-10-21 13:57:45 -06:00
}
2024-07-23 17:30:35 -04:00
const deploy = (callback: () => void) => {
2024-10-21 13:57:45 -06:00
if (!socket) console.error("Couldn't deploy: No socket")
console.log("Deploying...")
socket?.emit("deploy", {}, () => {
2024-10-21 13:57:45 -06:00
callback()
})
}
const getAppExists = async (
appName: string
): Promise<{ success: boolean; exists?: boolean }> => {
console.log("Is there a socket: " + !!socket)
if (!socket) {
console.error("Couldn't check if app exists: No socket")
return { success: false }
}
const response: { success: boolean; exists?: boolean } = await new Promise(
(resolve) => socket.emit("getAppExists", { appName }, resolve)
)
return response
}
2024-07-23 17:30:35 -04:00
const value = {
terminals,
setTerminals,
activeTerminalId,
setActiveTerminalId,
creatingTerminal,
setCreatingTerminal,
createNewTerminal,
closeTerminal,
2024-10-21 13:57:45 -06:00
deploy,
getAppExists: isSocketReady ? getAppExists : null,
2024-10-21 13:57:45 -06:00
}
2024-07-23 17:30:35 -04:00
return (
<TerminalContext.Provider value={value}>
{children}
</TerminalContext.Provider>
2024-10-21 13:57:45 -06:00
)
}
2024-07-23 17:30:35 -04:00
export const useTerminal = (): TerminalContextType => {
2024-10-21 13:57:45 -06:00
const context = useContext(TerminalContext)
2024-07-23 17:30:35 -04:00
if (!context) {
2024-10-21 13:57:45 -06:00
throw new Error("useTerminal must be used within a TerminalProvider")
2024-07-23 17:30:35 -04:00
}
2024-10-21 13:57:45 -06:00
return context
}