From 2b8223bdd53a693b9e0e01199fcd1af8666e38b2 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 12 Sep 2022 11:46:13 -0500 Subject: [PATCH] fix: Use command property when launching an application (#3998) Fixes #3777. --- site/src/components/AppLink/AppLink.tsx | 9 ++++++++- site/src/components/Resources/Resources.tsx | 1 + site/src/pages/TerminalPage/TerminalPage.tsx | 10 +++++----- site/src/xServices/terminal/terminalXService.ts | 9 ++++++--- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/site/src/components/AppLink/AppLink.tsx b/site/src/components/AppLink/AppLink.tsx index 5429e31668..fb302f894b 100644 --- a/site/src/components/AppLink/AppLink.tsx +++ b/site/src/components/AppLink/AppLink.tsx @@ -16,6 +16,7 @@ export interface AppLinkProps { agentName: TypesGen.WorkspaceAgent["name"] appName: TypesGen.WorkspaceApp["name"] appIcon?: TypesGen.WorkspaceApp["icon"] + appCommand?: TypesGen.WorkspaceApp["command"] } export const AppLink: FC> = ({ @@ -24,9 +25,15 @@ export const AppLink: FC> = ({ agentName, appName, appIcon, + appCommand, }) => { const styles = useStyles() - const href = `/@${userName}/${workspaceName}.${agentName}/apps/${encodeURIComponent(appName)}` + let href = `/@${userName}/${workspaceName}.${agentName}/apps/${encodeURIComponent(appName)}` + if (appCommand) { + href = `/@${userName}/${workspaceName}.${agentName}/terminal?command=${encodeURIComponent( + appCommand, + )}` + } return ( > = ({ key={app.name} appIcon={app.icon} appName={app.name} + appCommand={app.command} userName={workspace.owner_name} workspaceName={workspace.name} agentName={agent.name} diff --git a/site/src/pages/TerminalPage/TerminalPage.tsx b/site/src/pages/TerminalPage/TerminalPage.tsx index 4a6fb6cc01..abd9a15367 100644 --- a/site/src/pages/TerminalPage/TerminalPage.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.tsx @@ -2,7 +2,7 @@ import { makeStyles } from "@material-ui/core/styles" import { useMachine } from "@xstate/react" import { FC, useEffect, useRef, useState } from "react" import { Helmet } from "react-helmet-async" -import { useLocation, useNavigate, useParams } from "react-router-dom" +import { useLocation, useNavigate, useParams, useSearchParams } from "react-router-dom" import { colors } from "theme/colors" import { v4 as uuidv4 } from "uuid" import * as XTerm from "xterm" @@ -31,13 +31,12 @@ const TerminalPage: FC< const xtermRef = useRef(null) const [terminal, setTerminal] = useState(null) const [fitAddon, setFitAddon] = useState(null) + const [searchParams] = useSearchParams() // The reconnection token is a unique token that identifies // a terminal session. It's generated by the client to reduce // a round-trip, and must be a UUIDv4. - const [reconnectionToken] = useState(() => { - const search = new URLSearchParams(location.search) - return search.get("reconnect") ?? uuidv4() - }) + const reconnectionToken = searchParams.get("reconnect") ?? uuidv4() + const command = searchParams.get("command") || undefined // The workspace name is in the format: // [.] const workspaceNameParts = workspace?.split(".") @@ -47,6 +46,7 @@ const TerminalPage: FC< reconnection: reconnectionToken, workspaceName: workspaceNameParts?.[0], username: username, + command: command, }, actions: { readMessage: (_, event) => { diff --git a/site/src/xServices/terminal/terminalXService.ts b/site/src/xServices/terminal/terminalXService.ts index 3bc57cc0ba..8e0fee2be3 100644 --- a/site/src/xServices/terminal/terminalXService.ts +++ b/site/src/xServices/terminal/terminalXService.ts @@ -18,6 +18,7 @@ export interface TerminalContext { username?: string workspaceName?: string reconnection?: string + command?: string } export type TerminalEvent = @@ -170,9 +171,11 @@ export const terminalMachine = return reject("workspace agent is not set") } const proto = location.protocol === "https:" ? "wss:" : "ws:" - const socket = new WebSocket( - `${proto}//${location.host}/api/v2/workspaceagents/${context.workspaceAgent.id}/pty?reconnect=${context.reconnection}`, - ) + const commandQuery = context.command + ? `&command=${encodeURIComponent(context.command)}` + : "" + const url = `${proto}//${location.host}/api/v2/workspaceagents/${context.workspaceAgent.id}/pty?reconnect=${context.reconnection}${commandQuery}` + const socket = new WebSocket(url) socket.binaryType = "arraybuffer" socket.addEventListener("open", () => { resolve(socket)