diff --git a/site/src/components/Resources/AgentRow.tsx b/site/src/components/Resources/AgentRow.tsx index fd9dd4c146baa..00d84793fb2d4 100644 --- a/site/src/components/Resources/AgentRow.tsx +++ b/site/src/components/Resources/AgentRow.tsx @@ -44,6 +44,7 @@ export interface AgentRowProps { applicationsHost: string | undefined showApps: boolean hideSSHButton?: boolean + sshPrefix?: string hideVSCodeDesktopButton?: boolean serverVersion: string onUpdateAgent: () => void @@ -61,6 +62,7 @@ export const AgentRow: FC = ({ serverVersion, onUpdateAgent, storybookStartupLogs, + sshPrefix, }) => { const styles = useStyles() const { t } = useTranslation("agent") @@ -308,6 +310,7 @@ export const AgentRow: FC = ({ )} {!hideVSCodeDesktopButton && ( diff --git a/site/src/components/SSHButton/SSHButton.stories.tsx b/site/src/components/SSHButton/SSHButton.stories.tsx index e841b95355e3c..626292069b7d6 100644 --- a/site/src/components/SSHButton/SSHButton.stories.tsx +++ b/site/src/components/SSHButton/SSHButton.stories.tsx @@ -13,6 +13,7 @@ export const Closed = Template.bind({}) Closed.args = { workspaceName: MockWorkspace.name, agentName: MockWorkspaceAgent.name, + sshPrefix: "coder.", } export const Opened = Template.bind({}) @@ -20,4 +21,5 @@ Opened.args = { workspaceName: MockWorkspace.name, agentName: MockWorkspaceAgent.name, defaultIsOpen: true, + sshPrefix: "coder.", } diff --git a/site/src/components/SSHButton/SSHButton.tsx b/site/src/components/SSHButton/SSHButton.tsx index a26774b031121..fbf772eb2c878 100644 --- a/site/src/components/SSHButton/SSHButton.tsx +++ b/site/src/components/SSHButton/SSHButton.tsx @@ -15,12 +15,14 @@ export interface SSHButtonProps { workspaceName: string agentName: string defaultIsOpen?: boolean + sshPrefix?: string } export const SSHButton: React.FC> = ({ workspaceName, agentName, defaultIsOpen = false, + sshPrefix, }) => { const anchorRef = useRef(null) const [isOpen, setIsOpen] = useState(defaultIsOpen) @@ -79,7 +81,9 @@ export const SSHButton: React.FC> = ({ Connect to the agent: - + diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index d2161fd17cb6a..126b4146a4b06 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -53,6 +53,7 @@ export interface WorkspaceProps { workspaceErrors: Partial> buildInfo?: TypesGen.BuildInfoResponse applicationsHost?: string + sshPrefix?: string template?: TypesGen.Template quota_budget?: number } @@ -78,6 +79,7 @@ export const Workspace: FC> = ({ hideVSCodeDesktopButton, buildInfo, applicationsHost, + sshPrefix, template, quota_budget, }) => { @@ -193,6 +195,7 @@ export const Workspace: FC> = ({ agent={agent} workspace={workspace} applicationsHost={applicationsHost} + sshPrefix={sshPrefix} showApps={canUpdateWorkspace} hideSSHButton={hideSSHButton} hideVSCodeDesktopButton={hideVSCodeDesktopButton} diff --git a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx index 88a614df0b234..3858821ef7b3d 100644 --- a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx @@ -51,6 +51,7 @@ export const WorkspaceReadyPage = ({ buildError, cancellationError, applicationsHost, + sshPrefix, permissions, missedParameters, } = workspaceState.context @@ -124,6 +125,7 @@ export const WorkspaceReadyPage = ({ }} buildInfo={buildInfo} applicationsHost={applicationsHost} + sshPrefix={sshPrefix} template={template} quota_budget={quotaState.context.quota?.budget} /> diff --git a/site/src/xServices/workspace/workspaceXService.ts b/site/src/xServices/workspace/workspaceXService.ts index 1fc1c543fd78e..c83e57b19a361 100644 --- a/site/src/xServices/workspace/workspaceXService.ts +++ b/site/src/xServices/workspace/workspaceXService.ts @@ -72,6 +72,8 @@ export interface WorkspaceContext { checkPermissionsError?: Error | unknown // applications applicationsHost?: string + // SSH Config + sshPrefix?: string } export type WorkspaceEvent = @@ -162,6 +164,9 @@ export const workspaceMachine = createMachine( getApplicationsHost: { data: TypesGen.AppHostResponse } + getSSHPrefix: { + data: TypesGen.SSHConfigResponse + } }, }, initial: "idle", @@ -456,6 +461,30 @@ export const workspaceMachine = createMachine( }, }, }, + sshConfig: { + initial: "gettingSshConfig", + states: { + gettingSshConfig: { + invoke: { + src: "getSSHPrefix", + onDone: { + target: "success", + actions: ["assignSSHPrefix"], + }, + onError: { + target: "error", + actions: ["displaySSHPrefixError"], + }, + }, + }, + error: { + type: "final", + }, + success: { + type: "final", + }, + }, + }, schedule: { invoke: { id: "scheduleBannerMachine", @@ -579,6 +608,17 @@ export const workspaceMachine = createMachine( ) displayError(message) }, + // SSH + assignSSHPrefix: assign({ + sshPrefix: (_, { data }) => data.hostname_prefix, + }), + displaySSHPrefixError: (_, { data }) => { + const message = getErrorMessage( + data, + "Error getting the deployment ssh configuration.", + ) + displayError(message) + }, // Optimistically update. So when the user clicks on stop, we can show // the "pending" state right away without having to wait 0.5s ~ 2s to // display the visual feedback to the user. @@ -736,6 +776,9 @@ export const workspaceMachine = createMachine( getApplicationsHost: async () => { return API.getApplicationsHost() }, + getSSHPrefix: async () => { + return API.getDeploymentSSHConfig() + }, }, }, )