From 7de824dd167b670acf74d9d3a7e2e61b8acdbe7e Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Tue, 10 Jan 2023 15:23:39 +0000 Subject: [PATCH 1/3] feat: add experimental button to open vscode locally This uses the new Coder extension to open up any workspace with a single click. --- .../components/Icons/VSCodeIcon.stories.tsx | 12 ++ site/src/components/Icons/VSCodeIcon.tsx | 134 ++++++++++++++++++ .../components/Resources/AgentRow.stories.tsx | 9 ++ site/src/components/Resources/AgentRow.tsx | 10 ++ .../VSCodeDesktopButton.stories.tsx | 25 ++++ .../VSCodeDesktopButton.tsx | 52 +++++++ site/src/components/Workspace/Workspace.tsx | 3 + .../WorkspacePage/WorkspaceReadyPage.tsx | 7 + 8 files changed, 252 insertions(+) create mode 100644 site/src/components/Icons/VSCodeIcon.stories.tsx create mode 100644 site/src/components/Icons/VSCodeIcon.tsx create mode 100644 site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx create mode 100644 site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.tsx diff --git a/site/src/components/Icons/VSCodeIcon.stories.tsx b/site/src/components/Icons/VSCodeIcon.stories.tsx new file mode 100644 index 0000000000000..3656005303789 --- /dev/null +++ b/site/src/components/Icons/VSCodeIcon.stories.tsx @@ -0,0 +1,12 @@ +import { Story } from "@storybook/react" +import { VSCodeIcon } from "./VSCodeIcon" + +export default { + title: "icons/VSCodeIcon", + component: VSCodeIcon, +} + +const Template: Story = (args) => + +export const Example = Template.bind({}) +Example.args = {} diff --git a/site/src/components/Icons/VSCodeIcon.tsx b/site/src/components/Icons/VSCodeIcon.tsx new file mode 100644 index 0000000000000..7231dab0e2c22 --- /dev/null +++ b/site/src/components/Icons/VSCodeIcon.tsx @@ -0,0 +1,134 @@ +import SvgIcon, { SvgIconProps } from "@material-ui/core/SvgIcon" + +export const VSCodeIcon: typeof SvgIcon = (props: SvgIconProps) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +) diff --git a/site/src/components/Resources/AgentRow.stories.tsx b/site/src/components/Resources/AgentRow.stories.tsx index a289c3d1bf19f..7a74352db92fc 100644 --- a/site/src/components/Resources/AgentRow.stories.tsx +++ b/site/src/components/Resources/AgentRow.stories.tsx @@ -32,6 +32,15 @@ HideSSHButton.args = { hideSSHButton: true, } +export const HideVSCodeDesktopButton = Template.bind({}) +HideVSCodeDesktopButton.args = { + agent: MockWorkspaceAgent, + workspace: MockWorkspace, + applicationsHost: "", + showApps: true, + hideVSCodeDesktopButton: true, +} + export const NotShowingApps = Template.bind({}) NotShowingApps.args = { agent: MockWorkspaceAgent, diff --git a/site/src/components/Resources/AgentRow.tsx b/site/src/components/Resources/AgentRow.tsx index 553761233b39c..c6174f7f56807 100644 --- a/site/src/components/Resources/AgentRow.tsx +++ b/site/src/components/Resources/AgentRow.tsx @@ -13,6 +13,7 @@ import { Maybe } from "components/Conditionals/Maybe" import { AgentStatus } from "./AgentStatus" import { AppLinkSkeleton } from "components/AppLink/AppLinkSkeleton" import { useTranslation } from "react-i18next" +import { VSCodeDesktopButton } from "components/VSCodeDesktopButton/VSCodeDesktopButton" export interface AgentRowProps { agent: WorkspaceAgent @@ -20,6 +21,7 @@ export interface AgentRowProps { applicationsHost: string | undefined showApps: boolean hideSSHButton?: boolean + hideVSCodeDesktopButton?: boolean serverVersion: string } @@ -29,6 +31,7 @@ export const AgentRow: FC = ({ applicationsHost, showApps, hideSSHButton, + hideVSCodeDesktopButton, serverVersion, }) => { const styles = useStyles() @@ -105,6 +108,13 @@ export const AgentRow: FC = ({ agentName={agent.name} /> )} + {!hideVSCodeDesktopButton && ( + + )} {applicationsHost !== undefined && applicationsHost !== "" && ( = (args) => ( + +) + +export const Default = Template.bind({}) +Default.args = { + userName: MockWorkspace.owner_name, + workspaceName: MockWorkspace.name, + agentName: MockWorkspaceAgent.name, +} diff --git a/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.tsx b/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.tsx new file mode 100644 index 0000000000000..aa81ef4ea0184 --- /dev/null +++ b/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.tsx @@ -0,0 +1,52 @@ +import Button from "@material-ui/core/Button" +import { getApiKey } from "api/api" +import { VSCodeIcon } from "components/Icons/VSCodeIcon" +import React from "react" + +export interface VSCodeDesktopButtonProps { + userName: string + workspaceName: string + agentName?: string +} + +export const VSCodeDesktopButton: React.FC< + React.PropsWithChildren +> = ({ userName, workspaceName, agentName }) => { + const [loading, setLoading] = React.useState(false) + + return ( + + ) +} diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index d9f3728976ab4..c1405e4bd079a 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -50,6 +50,7 @@ export interface WorkspaceProps { builds?: TypesGen.WorkspaceBuild[] canUpdateWorkspace: boolean hideSSHButton?: boolean + hideVSCodeDesktopButton?: boolean workspaceErrors: Partial> buildInfo?: TypesGen.BuildInfoResponse applicationsHost?: string @@ -75,6 +76,7 @@ export const Workspace: FC> = ({ canUpdateWorkspace, workspaceErrors, hideSSHButton, + hideVSCodeDesktopButton, buildInfo, applicationsHost, template, @@ -215,6 +217,7 @@ export const Workspace: FC> = ({ applicationsHost={applicationsHost} showApps={canUpdateWorkspace} hideSSHButton={hideSSHButton} + hideVSCodeDesktopButton={hideVSCodeDesktopButton} serverVersion={serverVersion} /> )} diff --git a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx index 968b74cd14ebc..7f801b17e8df8 100644 --- a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx @@ -42,6 +42,10 @@ export const WorkspaceReadyPage = ({ workspaceState.children["scheduleBannerMachine"], ) const xServices = useContext(XServiceContext) + const experimental = useSelector( + xServices.entitlementsXService, + (state) => state.context.entitlements.experimental, + ) const featureVisibility = useSelector( xServices.entitlementsXService, selectFeatureVisibility, @@ -120,6 +124,9 @@ export const WorkspaceReadyPage = ({ builds={builds} canUpdateWorkspace={canUpdateWorkspace} hideSSHButton={featureVisibility[FeatureNames.BrowserOnly]} + hideVSCodeDesktopButton={ + !experimental || featureVisibility[FeatureNames.BrowserOnly] + } workspaceErrors={{ [WorkspaceErrors.GET_RESOURCES_ERROR]: refreshWorkspaceWarning, [WorkspaceErrors.GET_BUILDS_ERROR]: getBuildsError, From c59ffbc3d5d13d91b8c757db9e6981fab29111d3 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Tue, 10 Jan 2023 09:48:47 -0600 Subject: [PATCH 2/3] Update site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx Co-authored-by: Kira Pilot --- .../VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx b/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx index 0d244e3531bd1..706d43daa387e 100644 --- a/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx +++ b/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx @@ -2,7 +2,7 @@ import { Story } from "@storybook/react" import { MockWorkspace, MockWorkspaceAgent, -} from "../../testHelpers/renderHelpers" +} from "testHelpers/renderHelpers" import { VSCodeDesktopButton, VSCodeDesktopButtonProps, From 2245dc6dfdf7941d8a793eb5817ef13c702c39db Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Tue, 10 Jan 2023 15:54:42 +0000 Subject: [PATCH 3/3] Fix React imports --- .../VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx | 5 +---- .../VSCodeDesktopButton/VSCodeDesktopButton.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx b/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx index 706d43daa387e..f87c59637e1f3 100644 --- a/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx +++ b/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.stories.tsx @@ -1,8 +1,5 @@ import { Story } from "@storybook/react" -import { - MockWorkspace, - MockWorkspaceAgent, -} from "testHelpers/renderHelpers" +import { MockWorkspace, MockWorkspaceAgent } from "testHelpers/renderHelpers" import { VSCodeDesktopButton, VSCodeDesktopButtonProps, diff --git a/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.tsx b/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.tsx index aa81ef4ea0184..b7d9e9f70b618 100644 --- a/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.tsx +++ b/site/src/components/VSCodeDesktopButton/VSCodeDesktopButton.tsx @@ -1,7 +1,7 @@ import Button from "@material-ui/core/Button" import { getApiKey } from "api/api" import { VSCodeIcon } from "components/Icons/VSCodeIcon" -import React from "react" +import { FC, PropsWithChildren, useState } from "react" export interface VSCodeDesktopButtonProps { userName: string @@ -9,10 +9,10 @@ export interface VSCodeDesktopButtonProps { agentName?: string } -export const VSCodeDesktopButton: React.FC< - React.PropsWithChildren +export const VSCodeDesktopButton: FC< + PropsWithChildren > = ({ userName, workspaceName, agentName }) => { - const [loading, setLoading] = React.useState(false) + const [loading, setLoading] = useState(false) return (