From cf51f13af4d62ed981dead03643fd1833f2ceae1 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 1 Mar 2024 14:37:17 +0000 Subject: [PATCH 1/9] Chosmetic changes --- .../WorkspaceActions/Buttons.tsx | 28 ++++++++++--------- .../WorkspaceActions/WorkspaceActions.tsx | 7 +++-- .../pages/WorkspacePage/WorkspaceTopbar.tsx | 2 +- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx index d8cc82be6a7f0..81e36cfd121d9 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx @@ -7,8 +7,8 @@ import ReplayIcon from "@mui/icons-material/Replay"; import BlockIcon from "@mui/icons-material/Block"; import OutlinedBlockIcon from "@mui/icons-material/BlockOutlined"; import PowerSettingsNewIcon from "@mui/icons-material/PowerSettingsNew"; -import RetryIcon from "@mui/icons-material/BuildOutlined"; -import RetryDebugIcon from "@mui/icons-material/BugReportOutlined"; +import RetryIcon from "@mui/icons-material/CachedOutlined"; +import DebugIcon from "@mui/icons-material/BugReportOutlined"; import Star from "@mui/icons-material/Star"; import StarBorder from "@mui/icons-material/StarBorder"; import { type FC } from "react"; @@ -175,20 +175,22 @@ export const DisabledButton: FC = ({ label }) => { ); }; -type RetryButtonProps = Omit & { - debug?: boolean; +type RetryButtonProps = Omit; + +export const RetryButton: FC = ({ handleAction }) => { + return ( + } onClick={() => handleAction()}> + Retry + + ); }; -export const RetryButton: FC = ({ - handleAction, - debug = false, -}) => { +type DebugButtonProps = Omit; + +export const DebugButton: FC = ({ handleAction }) => { return ( - : } - onClick={() => handleAction()} - > - Retry{debug && " (Debug)"} + } onClick={() => handleAction()}> + Debug ); }; diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx index fb6536b2a08f1..f6283f5bcc6fa 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx @@ -13,6 +13,7 @@ import { ActivateButton, RetryButton, FavoriteButton, + DebugButton, } from "./Buttons"; import Divider from "@mui/material/Divider"; @@ -41,7 +42,7 @@ export interface WorkspaceActionsProps { handleSettings: () => void; handleChangeVersion: () => void; handleRetry: () => void; - handleRetryDebug: () => void; + handleDebug: () => void; handleDormantActivate: () => void; isUpdating: boolean; isRestarting: boolean; @@ -62,7 +63,7 @@ export const WorkspaceActions: FC = ({ handleCancel, handleSettings, handleRetry, - handleRetryDebug, + handleDebug, handleChangeVersion, handleDormantActivate, isUpdating, @@ -133,7 +134,7 @@ export const WorkspaceActions: FC = ({ activate: , activating: , retry: , - retryDebug: , + retryDebug: , toggleFavorite: ( = ({ handleCancel={handleCancel} handleSettings={handleSettings} handleRetry={handleBuildRetry} - handleRetryDebug={handleBuildRetryDebug} + handleDebug={handleBuildRetryDebug} handleChangeVersion={handleChangeVersion} handleDormantActivate={handleDormantActivate} handleToggleFavorite={handleToggleFavorite} From 1bbe8d0020e6b0becd98596ddf15cd5ee930b74e Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 1 Mar 2024 16:21:11 +0000 Subject: [PATCH 2/9] Support build parameters on retry and debug actions --- site/src/pages/WorkspacePage/Workspace.tsx | 28 ++------ .../WorkspaceActions/Buttons.tsx | 64 +++++++++++++++++-- .../WorkspaceActions/WorkspaceActions.tsx | 20 ++++-- .../WorkspaceActions/constants.ts | 8 +-- .../WorkspacePage/WorkspaceReadyPage.tsx | 26 ++++++-- .../pages/WorkspacePage/WorkspaceTopbar.tsx | 12 ++-- 6 files changed, 113 insertions(+), 45 deletions(-) diff --git a/site/src/pages/WorkspacePage/Workspace.tsx b/site/src/pages/WorkspacePage/Workspace.tsx index 236933d017961..32156c0b048c5 100644 --- a/site/src/pages/WorkspacePage/Workspace.tsx +++ b/site/src/pages/WorkspacePage/Workspace.tsx @@ -1,5 +1,4 @@ import { type Interpolation, type Theme } from "@emotion/react"; -import Button from "@mui/material/Button"; import AlertTitle from "@mui/material/AlertTitle"; import { type FC } from "react"; import { useNavigate } from "react-router-dom"; @@ -44,8 +43,8 @@ export interface WorkspaceProps { sshPrefix?: string; template: TypesGen.Template; canRetryDebugMode: boolean; - handleBuildRetry: () => void; - handleBuildRetryDebug: () => void; + handleRetry: (buildParameters?: TypesGen.WorkspaceBuildParameter[]) => void; + handleDebug: (buildParameters?: TypesGen.WorkspaceBuildParameter[]) => void; buildLogs?: React.ReactNode; latestVersion?: TypesGen.TemplateVersion; permissions: WorkspacePermissions; @@ -76,8 +75,8 @@ export const Workspace: FC = ({ sshPrefix, template, canRetryDebugMode, - handleBuildRetry, - handleBuildRetryDebug, + handleRetry, + handleDebug, buildLogs, latestVersion, permissions, @@ -129,8 +128,8 @@ export const Workspace: FC = ({ handleUpdate={handleUpdate} handleCancel={handleCancel} handleSettings={handleSettings} - handleBuildRetry={handleBuildRetry} - handleBuildRetryDebug={handleBuildRetryDebug} + handleRetry={handleRetry} + handleDebug={handleDebug} handleChangeVersion={handleChangeVersion} handleDormantActivate={handleDormantActivate} handleToggleFavorite={handleToggleFavorite} @@ -208,20 +207,7 @@ export const Workspace: FC = ({ )} {workspace.latest_build.job.error && ( - - Retry{canRetryDebugMode && " in debug mode"} - - } - > + Workspace build failed {workspace.latest_build.job.error} diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx index 81e36cfd121d9..3a85b6d931ec9 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx @@ -175,24 +175,76 @@ export const DisabledButton: FC = ({ label }) => { ); }; -type RetryButtonProps = Omit; +type RetryButtonProps = Omit & { + enableBuildParameters: boolean; + workspace: Workspace; +}; -export const RetryButton: FC = ({ handleAction }) => { - return ( +export const RetryButton: FC = ({ + handleAction, + workspace, + enableBuildParameters, +}) => { + const mainAction = ( } onClick={() => handleAction()}> Retry ); -}; -type DebugButtonProps = Omit; + if (!enableBuildParameters) { + return mainAction; + } -export const DebugButton: FC = ({ handleAction }) => { return ( + button:hover + button": { + borderLeft: "1px solid #FFF", + }, + }} + > + {mainAction} + + + ); +}; + +type DebugButtonProps = Omit & { + workspace: Workspace; + enableBuildParameters: boolean; +}; + +export const DebugButton: FC = ({ + handleAction, + workspace, + enableBuildParameters, +}) => { + const mainAction = ( } onClick={() => handleAction()}> Debug ); + + if (!enableBuildParameters) { + return mainAction; + } + + return ( + button:hover + button": { + borderLeft: "1px solid #FFF", + }, + }} + > + {mainAction} + + + ); }; interface FavoriteButtonProps { diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx index f6283f5bcc6fa..b7830fcad5419 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx @@ -41,8 +41,8 @@ export interface WorkspaceActionsProps { handleCancel: () => void; handleSettings: () => void; handleChangeVersion: () => void; - handleRetry: () => void; - handleDebug: () => void; + handleRetry: (buildParameters?: WorkspaceBuildParameter[]) => void; + handleDebug: (buildParameters?: WorkspaceBuildParameter[]) => void; handleDormantActivate: () => void; isUpdating: boolean; isRestarting: boolean; @@ -133,8 +133,20 @@ export const WorkspaceActions: FC = ({ pending: , activate: , activating: , - retry: , - retryDebug: , + retry: ( + + ), + debug: ( + + ), toggleFavorite: ( { if (workspace.dormant_at) { return { @@ -50,10 +50,10 @@ export const abilitiesByWorkspaceStatus = ( } const status = workspace.latest_build.status; - if (status === "failed" && canRetryDebug) { + if (status === "failed" && canDebug) { return { ...statusToAbility.failed, - actions: ["retry", "retryDebug"], + actions: ["retry", "debug"], }; } diff --git a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx index e8621990333bf..66e55f7c6dbfd 100644 --- a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx @@ -153,12 +153,18 @@ export const WorkspaceReadyPage: FC = ({ // Cancel build const cancelBuildMutation = useMutation(cancelBuild(workspace, queryClient)); - const handleBuildRetry = (debug = false) => { + const runLastBuild = ( + buildParameters: TypesGen.WorkspaceBuildParameter[] | undefined, + debug: boolean, + ) => { const logLevel = debug ? "debug" : undefined; switch (workspace.latest_build.transition) { case "start": - startWorkspaceMutation.mutate({ logLevel }); + startWorkspaceMutation.mutate({ + logLevel, + buildParameters, + }); break; case "stop": stopWorkspaceMutation.mutate({ logLevel }); @@ -169,6 +175,18 @@ export const WorkspaceReadyPage: FC = ({ } }; + const handleRetry = ( + buildParameters?: TypesGen.WorkspaceBuildParameter[], + ) => { + runLastBuild(buildParameters, false); + }; + + const handleDebug = ( + buildParameters?: TypesGen.WorkspaceBuildParameter[], + ) => { + runLastBuild(buildParameters, true); + }; + return ( <> @@ -207,8 +225,8 @@ export const WorkspaceReadyPage: FC = ({ }} handleCancel={cancelBuildMutation.mutate} handleSettings={() => navigate("settings")} - handleBuildRetry={() => handleBuildRetry(false)} - handleBuildRetryDebug={() => handleBuildRetry(true)} + handleRetry={handleRetry} + handleDebug={handleDebug} canRetryDebugMode={ deploymentValues?.config.enable_terraform_debug_mode ?? false } diff --git a/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx b/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx index 3723fe3c9ddc8..3559743727242 100644 --- a/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx @@ -53,8 +53,8 @@ export interface WorkspaceProps { canUpdateWorkspace: boolean; canChangeVersions: boolean; canRetryDebugMode: boolean; - handleBuildRetry: () => void; - handleBuildRetryDebug: () => void; + handleRetry: (buildParameters?: TypesGen.WorkspaceBuildParameter[]) => void; + handleDebug: (buildParameters?: TypesGen.WorkspaceBuildParameter[]) => void; isOwner: boolean; template: TypesGen.Template; permissions: WorkspacePermissions; @@ -79,8 +79,8 @@ export const WorkspaceTopbar: FC = ({ canUpdateWorkspace, canChangeVersions, canRetryDebugMode, - handleBuildRetry, - handleBuildRetryDebug, + handleRetry, + handleDebug, isOwner, template, latestVersion, @@ -266,8 +266,8 @@ export const WorkspaceTopbar: FC = ({ handleUpdate={handleUpdate} handleCancel={handleCancel} handleSettings={handleSettings} - handleRetry={handleBuildRetry} - handleDebug={handleBuildRetryDebug} + handleRetry={handleRetry} + handleDebug={handleDebug} handleChangeVersion={handleChangeVersion} handleDormantActivate={handleDormantActivate} handleToggleFavorite={handleToggleFavorite} From ae3f3f04290c9cd695fce04a795aa0bb6705c928 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 1 Mar 2024 16:49:05 +0000 Subject: [PATCH 3/9] Extract retry button --- site/src/pages/WorkspacePage/Workspace.tsx | 6 +-- .../WorkspaceActions/Buttons.tsx | 39 +------------- .../WorkspaceActions/RetryButton.stories.tsx | 54 +++++++++++++++++++ .../WorkspaceActions/RetryButton.tsx | 43 +++++++++++++++ .../WorkspaceActions/WorkspaceActions.tsx | 8 +-- .../WorkspacePage/WorkspaceReadyPage.tsx | 2 +- .../pages/WorkspacePage/WorkspaceTopbar.tsx | 6 +-- 7 files changed, 109 insertions(+), 49 deletions(-) create mode 100644 site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.stories.tsx create mode 100644 site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.tsx diff --git a/site/src/pages/WorkspacePage/Workspace.tsx b/site/src/pages/WorkspacePage/Workspace.tsx index 32156c0b048c5..011b7329fd4eb 100644 --- a/site/src/pages/WorkspacePage/Workspace.tsx +++ b/site/src/pages/WorkspacePage/Workspace.tsx @@ -42,7 +42,7 @@ export interface WorkspaceProps { buildInfo?: TypesGen.BuildInfoResponse; sshPrefix?: string; template: TypesGen.Template; - canRetryDebugMode: boolean; + canDebugMode: boolean; handleRetry: (buildParameters?: TypesGen.WorkspaceBuildParameter[]) => void; handleDebug: (buildParameters?: TypesGen.WorkspaceBuildParameter[]) => void; buildLogs?: React.ReactNode; @@ -74,7 +74,7 @@ export const Workspace: FC = ({ buildInfo, sshPrefix, template, - canRetryDebugMode, + canDebugMode, handleRetry, handleDebug, buildLogs, @@ -133,7 +133,7 @@ export const Workspace: FC = ({ handleChangeVersion={handleChangeVersion} handleDormantActivate={handleDormantActivate} handleToggleFavorite={handleToggleFavorite} - canRetryDebugMode={canRetryDebugMode} + canDebugMode={canDebugMode} canChangeVersions={canChangeVersions} isUpdating={isUpdating} isRestarting={isRestarting} diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx index 3a85b6d931ec9..18b7c47948c93 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx @@ -7,7 +7,6 @@ import ReplayIcon from "@mui/icons-material/Replay"; import BlockIcon from "@mui/icons-material/Block"; import OutlinedBlockIcon from "@mui/icons-material/BlockOutlined"; import PowerSettingsNewIcon from "@mui/icons-material/PowerSettingsNew"; -import RetryIcon from "@mui/icons-material/CachedOutlined"; import DebugIcon from "@mui/icons-material/BugReportOutlined"; import Star from "@mui/icons-material/Star"; import StarBorder from "@mui/icons-material/StarBorder"; @@ -16,7 +15,7 @@ import type { Workspace, WorkspaceBuildParameter } from "api/typesGenerated"; import { BuildParametersPopover } from "./BuildParametersPopover"; import { TopbarButton } from "components/FullPageLayout/Topbar"; -interface ActionButtonProps { +export interface ActionButtonProps { loading?: boolean; handleAction: (buildParameters?: WorkspaceBuildParameter[]) => void; disabled?: boolean; @@ -175,42 +174,6 @@ export const DisabledButton: FC = ({ label }) => { ); }; -type RetryButtonProps = Omit & { - enableBuildParameters: boolean; - workspace: Workspace; -}; - -export const RetryButton: FC = ({ - handleAction, - workspace, - enableBuildParameters, -}) => { - const mainAction = ( - } onClick={() => handleAction()}> - Retry - - ); - - if (!enableBuildParameters) { - return mainAction; - } - - return ( - button:hover + button": { - borderLeft: "1px solid #FFF", - }, - }} - > - {mainAction} - - - ); -}; - type DebugButtonProps = Omit & { workspace: Workspace; enableBuildParameters: boolean; diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.stories.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.stories.tsx new file mode 100644 index 0000000000000..296ebdb62c221 --- /dev/null +++ b/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.stories.tsx @@ -0,0 +1,54 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { RetryButton } from "./RetryButton"; +import { MockWorkspace } from "testHelpers/entities"; +import { userEvent, waitFor, within } from "@storybook/test"; + +const meta: Meta = { + title: "pages/WorkspacePage/RetryButton", + component: RetryButton, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const WithBuildParameters: Story = { + args: { + enableBuildParameters: true, + workspace: MockWorkspace, + }, + parameters: { + queries: [ + { + key: ["workspace", MockWorkspace.id, "parameters"], + data: { templateVersionRichParameters: [], buildParameters: [] }, + }, + ], + }, +}; + +export const WithOpenBuildParameters: Story = { + args: { + enableBuildParameters: true, + workspace: MockWorkspace, + }, + parameters: { + queries: [ + { + key: ["workspace", MockWorkspace.id, "parameters"], + data: { templateVersionRichParameters: [], buildParameters: [] }, + }, + ], + }, + play: async ({ canvasElement, step }) => { + const screen = within(canvasElement); + + await step("open popover", async () => { + await userEvent.click(screen.getByTestId("build-parameters-button")); + await waitFor(() => + expect(screen.getByText("Build Options")).toBeInTheDocument(), + ); + }); + }, +}; diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.tsx new file mode 100644 index 0000000000000..ab2106eb2aa2d --- /dev/null +++ b/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.tsx @@ -0,0 +1,43 @@ +import ButtonGroup from "@mui/material/ButtonGroup"; +import RetryIcon from "@mui/icons-material/CachedOutlined"; +import { type FC } from "react"; +import type { Workspace } from "api/typesGenerated"; +import { BuildParametersPopover } from "./BuildParametersPopover"; +import { TopbarButton } from "components/FullPageLayout/Topbar"; +import { ActionButtonProps } from "./Buttons"; + +type RetryButtonProps = Omit & { + enableBuildParameters: boolean; + workspace: Workspace; +}; + +export const RetryButton: FC = ({ + handleAction, + workspace, + enableBuildParameters, +}) => { + const mainAction = ( + } onClick={() => handleAction()}> + Retry + + ); + + if (!enableBuildParameters) { + return mainAction; + } + + return ( + button:hover + button": { + borderLeft: "1px solid #FFF", + }, + }} + > + {mainAction} + + + ); +}; diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx index b7830fcad5419..b29c8db06bfea 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx @@ -11,7 +11,6 @@ import { RestartButton, UpdateButton, ActivateButton, - RetryButton, FavoriteButton, DebugButton, } from "./Buttons"; @@ -29,6 +28,7 @@ import { } from "components/MoreMenu/MoreMenu"; import { TopbarIconButton } from "components/FullPageLayout/Topbar"; import MoreVertOutlined from "@mui/icons-material/MoreVertOutlined"; +import { RetryButton } from "./RetryButton"; export interface WorkspaceActionsProps { workspace: Workspace; @@ -48,7 +48,7 @@ export interface WorkspaceActionsProps { isRestarting: boolean; children?: ReactNode; canChangeVersions: boolean; - canRetryDebug: boolean; + canDebug: boolean; isOwner: boolean; } @@ -69,7 +69,7 @@ export const WorkspaceActions: FC = ({ isUpdating, isRestarting, canChangeVersions, - canRetryDebug, + canDebug, isOwner, }) => { const { duplicateWorkspace, isDuplicationReady } = @@ -77,7 +77,7 @@ export const WorkspaceActions: FC = ({ const { actions, canCancel, canAcceptJobs } = abilitiesByWorkspaceStatus( workspace, - canRetryDebug, + canDebug, ); const showCancel = canCancel && diff --git a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx index 66e55f7c6dbfd..37eee8b99190a 100644 --- a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx @@ -227,7 +227,7 @@ export const WorkspaceReadyPage: FC = ({ handleSettings={() => navigate("settings")} handleRetry={handleRetry} handleDebug={handleDebug} - canRetryDebugMode={ + canDebugMode={ deploymentValues?.config.enable_terraform_debug_mode ?? false } handleChangeVersion={() => { diff --git a/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx b/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx index 3559743727242..2298b5d73a8ae 100644 --- a/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx @@ -52,7 +52,7 @@ export interface WorkspaceProps { workspace: TypesGen.Workspace; canUpdateWorkspace: boolean; canChangeVersions: boolean; - canRetryDebugMode: boolean; + canDebugMode: boolean; handleRetry: (buildParameters?: TypesGen.WorkspaceBuildParameter[]) => void; handleDebug: (buildParameters?: TypesGen.WorkspaceBuildParameter[]) => void; isOwner: boolean; @@ -78,7 +78,7 @@ export const WorkspaceTopbar: FC = ({ isRestarting, canUpdateWorkspace, canChangeVersions, - canRetryDebugMode, + canDebugMode, handleRetry, handleDebug, isOwner, @@ -271,7 +271,7 @@ export const WorkspaceTopbar: FC = ({ handleChangeVersion={handleChangeVersion} handleDormantActivate={handleDormantActivate} handleToggleFavorite={handleToggleFavorite} - canRetryDebug={canRetryDebugMode} + canDebug={canDebugMode} canChangeVersions={canChangeVersions} isUpdating={isUpdating} isRestarting={isRestarting} From c3a8dd93f5fc5236ca0b19b84f8b62dc476c9105 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 1 Mar 2024 16:51:39 +0000 Subject: [PATCH 4/9] Extract debug button --- .../WorkspaceActions/Buttons.tsx | 37 ------------- .../WorkspaceActions/DebugButton.stories.tsx | 54 +++++++++++++++++++ .../WorkspaceActions/DebugButton.tsx | 43 +++++++++++++++ .../WorkspaceActions/WorkspaceActions.tsx | 2 +- 4 files changed, 98 insertions(+), 38 deletions(-) create mode 100644 site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.stories.tsx create mode 100644 site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.tsx diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx index 18b7c47948c93..b865aac7886cf 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx @@ -7,7 +7,6 @@ import ReplayIcon from "@mui/icons-material/Replay"; import BlockIcon from "@mui/icons-material/Block"; import OutlinedBlockIcon from "@mui/icons-material/BlockOutlined"; import PowerSettingsNewIcon from "@mui/icons-material/PowerSettingsNew"; -import DebugIcon from "@mui/icons-material/BugReportOutlined"; import Star from "@mui/icons-material/Star"; import StarBorder from "@mui/icons-material/StarBorder"; import { type FC } from "react"; @@ -174,42 +173,6 @@ export const DisabledButton: FC = ({ label }) => { ); }; -type DebugButtonProps = Omit & { - workspace: Workspace; - enableBuildParameters: boolean; -}; - -export const DebugButton: FC = ({ - handleAction, - workspace, - enableBuildParameters, -}) => { - const mainAction = ( - } onClick={() => handleAction()}> - Debug - - ); - - if (!enableBuildParameters) { - return mainAction; - } - - return ( - button:hover + button": { - borderLeft: "1px solid #FFF", - }, - }} - > - {mainAction} - - - ); -}; - interface FavoriteButtonProps { onToggle: (workspaceID: string) => void; workspaceID: string; diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.stories.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.stories.tsx new file mode 100644 index 0000000000000..452b352d9115d --- /dev/null +++ b/site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.stories.tsx @@ -0,0 +1,54 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { DebugButton } from "./DebugButton"; +import { MockWorkspace } from "testHelpers/entities"; +import { userEvent, waitFor, within } from "@storybook/test"; + +const meta: Meta = { + title: "pages/WorkspacePage/DebugButton", + component: DebugButton, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const WithBuildParameters: Story = { + args: { + enableBuildParameters: true, + workspace: MockWorkspace, + }, + parameters: { + queries: [ + { + key: ["workspace", MockWorkspace.id, "parameters"], + data: { templateVersionRichParameters: [], buildParameters: [] }, + }, + ], + }, +}; + +export const WithOpenBuildParameters: Story = { + args: { + enableBuildParameters: true, + workspace: MockWorkspace, + }, + parameters: { + queries: [ + { + key: ["workspace", MockWorkspace.id, "parameters"], + data: { templateVersionRichParameters: [], buildParameters: [] }, + }, + ], + }, + play: async ({ canvasElement, step }) => { + const screen = within(canvasElement); + + await step("open popover", async () => { + await userEvent.click(screen.getByTestId("build-parameters-button")); + await waitFor(() => + expect(screen.getByText("Build Options")).toBeInTheDocument(), + ); + }); + }, +}; diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.tsx new file mode 100644 index 0000000000000..8f3fd7543aa5f --- /dev/null +++ b/site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.tsx @@ -0,0 +1,43 @@ +import ButtonGroup from "@mui/material/ButtonGroup"; +import DebugIcon from "@mui/icons-material/BugReportOutlined"; +import { type FC } from "react"; +import type { Workspace } from "api/typesGenerated"; +import { BuildParametersPopover } from "./BuildParametersPopover"; +import { TopbarButton } from "components/FullPageLayout/Topbar"; +import { ActionButtonProps } from "./Buttons"; + +type DebugButtonProps = Omit & { + workspace: Workspace; + enableBuildParameters: boolean; +}; + +export const DebugButton: FC = ({ + handleAction, + workspace, + enableBuildParameters, +}) => { + const mainAction = ( + } onClick={() => handleAction()}> + Debug + + ); + + if (!enableBuildParameters) { + return mainAction; + } + + return ( + button:hover + button": { + borderLeft: "1px solid #FFF", + }, + }} + > + {mainAction} + + + ); +}; diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx index b29c8db06bfea..7d573d9600170 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx @@ -12,7 +12,6 @@ import { UpdateButton, ActivateButton, FavoriteButton, - DebugButton, } from "./Buttons"; import Divider from "@mui/material/Divider"; @@ -29,6 +28,7 @@ import { import { TopbarIconButton } from "components/FullPageLayout/Topbar"; import MoreVertOutlined from "@mui/icons-material/MoreVertOutlined"; import { RetryButton } from "./RetryButton"; +import { DebugButton } from "./DebugButton"; export interface WorkspaceActionsProps { workspace: Workspace; From 5858c8dc0dcafdfaa6ce640776ee6b78530251a1 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 1 Mar 2024 16:52:54 +0000 Subject: [PATCH 5/9] Add story for checking debug --- .../WorkspaceActions/WorkspaceActions.stories.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx index f56c0456a46e9..d14e26a58570b 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx @@ -73,6 +73,13 @@ export const Failed: Story = { }, }; +export const FailedWithDebug: Story = { + args: { + workspace: Mocks.MockFailedWorkspace, + canDebug: true, + }, +}; + export const Updating: Story = { args: { isUpdating: true, From 642e47598293422dc358ae88a8207b3c49545020 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 1 Mar 2024 17:25:27 +0000 Subject: [PATCH 6/9] Fix workspace tests warnings --- site/src/components/FullPageLayout/Sidebar.tsx | 9 ++++++--- site/src/testHelpers/handlers.ts | 10 ++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/site/src/components/FullPageLayout/Sidebar.tsx b/site/src/components/FullPageLayout/Sidebar.tsx index a1e9817250775..93f782cd20770 100644 --- a/site/src/components/FullPageLayout/Sidebar.tsx +++ b/site/src/components/FullPageLayout/Sidebar.tsx @@ -74,14 +74,17 @@ interface SidebarIconButton extends ComponentProps { isActive: boolean; } -export const SidebarIconButton: FC = (props) => { +export const SidebarIconButton: FC = ({ + isActive, + ...buttonProps +}) => { return ( ); }; diff --git a/site/src/testHelpers/handlers.ts b/site/src/testHelpers/handlers.ts index 604695977d7b0..77ab2ec61fd84 100644 --- a/site/src/testHelpers/handlers.ts +++ b/site/src/testHelpers/handlers.ts @@ -245,6 +245,12 @@ export const handlers = [ rest.put("/api/v2/workspaces/:workspaceId/extend", async (req, res, ctx) => { return res(ctx.status(200)); }), + rest.get( + "/api/v2/workspaces/:workspaceId/resolve-autostart", + async (req, res, ctx) => { + return res(ctx.status(200), ctx.json({ parameter_mismatch: false })); + }, + ), // workspace builds rest.post("/api/v2/workspaces/:workspaceId/builds", async (req, res, ctx) => { @@ -438,4 +444,8 @@ export const handlers = [ rest.get("/api/v2/workspaceagents/:agent/listening-ports", (_, res, ctx) => { return res(ctx.status(200), ctx.json(M.MockListeningPortsResponse)); }), + + rest.get("/api/v2/integrations/jfrog/xray-scan", (_, res, ctx) => { + return res(ctx.status(404)); + }), ]; From a9e122f34c506fff276ac451b58e6f65def68f3e Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 1 Mar 2024 17:46:41 +0000 Subject: [PATCH 7/9] Add tests for retry with build parameters --- .../BuildParametersPopover.tsx | 4 ++ .../WorkspaceActions/Buttons.tsx | 2 + .../WorkspaceActions/DebugButton.tsx | 6 ++- .../WorkspaceActions/RetryButton.tsx | 6 ++- .../WorkspacePage/WorkspacePage.test.tsx | 52 ++++++++++++++++++- 5 files changed, 67 insertions(+), 3 deletions(-) diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/BuildParametersPopover.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/BuildParametersPopover.tsx index 905898023cb22..1cad2f77aebbb 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/BuildParametersPopover.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/BuildParametersPopover.tsx @@ -32,16 +32,19 @@ import { usePopover, } from "components/Popover/Popover"; import { TopbarButton } from "components/FullPageLayout/Topbar"; +import visuallyHidden from "@mui/utils/visuallyHidden"; interface BuildParametersPopoverProps { workspace: Workspace; disabled?: boolean; onSubmit: (buildParameters: WorkspaceBuildParameter[]) => void; + label: string; } export const BuildParametersPopover: FC = ({ workspace, disabled, + label, onSubmit, }) => { const { data: parameters } = useQuery({ @@ -62,6 +65,7 @@ export const BuildParametersPopover: FC = ({ css={{ paddingLeft: 0, paddingRight: 0, minWidth: "28px !important" }} > + {label} = ({ {loading ? <>Starting… : "Start"} = ({ {loading ? <>Restarting… : <>Restart…} = ({ }} > {mainAction} - + ); }; diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.tsx index ab2106eb2aa2d..768b50501883f 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.tsx @@ -37,7 +37,11 @@ export const RetryButton: FC = ({ }} > {mainAction} - + ); }; diff --git a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx index d2482b8494cb4..f696e8737e40e 100644 --- a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx +++ b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx @@ -1,4 +1,4 @@ -import { type Workspace } from "api/typesGenerated"; +import { TemplateVersionParameter, type Workspace } from "api/typesGenerated"; import { screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import EventSourceMock from "eventsourcemock"; @@ -21,6 +21,7 @@ import * as api from "api/api"; import { renderWithAuth } from "testHelpers/renderHelpers"; import { server } from "testHelpers/server"; import { WorkspacePage } from "./WorkspacePage"; +import { satisfies } from "semver"; // Renders the workspace page and waits for it be loaded const renderWorkspacePage = async (workspace: Workspace) => { @@ -438,4 +439,53 @@ describe("WorkspacePage", () => { }); }); }); + + it.only("retry with build parameters", async () => { + const user = userEvent.setup(); + const workspace = { + ...MockFailedWorkspace, + latest_build: { + ...MockFailedWorkspace.latest_build, + transition: "start", + }, + } satisfies Workspace; + const parameter = { + ...MockTemplateVersionParameter1, + display_name: "Parameter 1", + ephemeral: true, + } satisfies TemplateVersionParameter; + + server.use( + rest.get( + "/api/v2/templateversions/:versionId/rich-parameters", + (req, res, ctx) => { + return res(ctx.status(200), ctx.json([parameter])); + }, + ), + ); + const startWorkspaceSpy = jest.spyOn(api, "startWorkspace"); + + await renderWorkspacePage(workspace); + const retryWithBuildParametersButton = await screen.findByRole("button", { + name: "Retry with build parameters", + }); + await user.click(retryWithBuildParametersButton); + await screen.findByText("Build Options"); + const parameterField = screen.getByLabelText(parameter.display_name, { + exact: false, + }); + await user.clear(parameterField); + await user.type(parameterField, "some-value"); + const submitButton = screen.getByText("Build workspace"); + await user.click(submitButton); + + await waitFor(() => { + expect(startWorkspaceSpy).toBeCalledWith( + workspace.id, + workspace.latest_build.template_version_id, + undefined, + [{ name: parameter.name, value: "some-value" }], + ); + }); + }); }); From 7d245c5c16515584a4e9a136900d83047b76d2ea Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 1 Mar 2024 17:51:17 +0000 Subject: [PATCH 8/9] Add test for debug --- .../WorkspacePage/WorkspacePage.test.tsx | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx index f696e8737e40e..1b262907bf39e 100644 --- a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx +++ b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx @@ -21,7 +21,6 @@ import * as api from "api/api"; import { renderWithAuth } from "testHelpers/renderHelpers"; import { server } from "testHelpers/server"; import { WorkspacePage } from "./WorkspacePage"; -import { satisfies } from "semver"; // Renders the workspace page and waits for it be loaded const renderWorkspacePage = async (workspace: Workspace) => { @@ -358,7 +357,7 @@ describe("WorkspacePage", () => { // each function gets called with describe("Retrying failed workspaces", () => { const retryButtonRe = /^Retry$/i; - const retryDebugButtonRe = /^Retry \(Debug\)$/i; + const retryDebugButtonRe = /^Debug$/i; describe("Retries a failed 'Start' transition", () => { const mockStart = jest.spyOn(api, "startWorkspace"); @@ -440,7 +439,7 @@ describe("WorkspacePage", () => { }); }); - it.only("retry with build parameters", async () => { + it("retry with build parameters", async () => { const user = userEvent.setup(); const workspace = { ...MockFailedWorkspace, @@ -488,4 +487,53 @@ describe("WorkspacePage", () => { ); }); }); + + it("debug with build parameters", async () => { + const user = userEvent.setup(); + const workspace = { + ...MockFailedWorkspace, + latest_build: { + ...MockFailedWorkspace.latest_build, + transition: "start", + }, + } satisfies Workspace; + const parameter = { + ...MockTemplateVersionParameter1, + display_name: "Parameter 1", + ephemeral: true, + } satisfies TemplateVersionParameter; + + server.use( + rest.get( + "/api/v2/templateversions/:versionId/rich-parameters", + (req, res, ctx) => { + return res(ctx.status(200), ctx.json([parameter])); + }, + ), + ); + const startWorkspaceSpy = jest.spyOn(api, "startWorkspace"); + + await renderWorkspacePage(workspace); + const retryWithBuildParametersButton = await screen.findByRole("button", { + name: "Debug with build parameters", + }); + await user.click(retryWithBuildParametersButton); + await screen.findByText("Build Options"); + const parameterField = screen.getByLabelText(parameter.display_name, { + exact: false, + }); + await user.clear(parameterField); + await user.type(parameterField, "some-value"); + const submitButton = screen.getByText("Build workspace"); + await user.click(submitButton); + + await waitFor(() => { + expect(startWorkspaceSpy).toBeCalledWith( + workspace.id, + workspace.latest_build.template_version_id, + "debug", + [{ name: parameter.name, value: "some-value" }], + ); + }); + }); }); From 79673eb62cf73d858325d78a825f38ef159827fc Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Mon, 4 Mar 2024 13:20:34 +0000 Subject: [PATCH 9/9] Fix test errors --- .../WorkspacePage/WorkspaceActions/DebugButton.stories.tsx | 2 +- .../WorkspacePage/WorkspaceActions/RetryButton.stories.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.stories.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.stories.tsx index 452b352d9115d..870f1bb97bca7 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.stories.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from "@storybook/react"; import { DebugButton } from "./DebugButton"; import { MockWorkspace } from "testHelpers/entities"; -import { userEvent, waitFor, within } from "@storybook/test"; +import { userEvent, waitFor, within, expect } from "@storybook/test"; const meta: Meta = { title: "pages/WorkspacePage/DebugButton", diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.stories.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.stories.tsx index 296ebdb62c221..25fc7567f104e 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.stories.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from "@storybook/react"; import { RetryButton } from "./RetryButton"; import { MockWorkspace } from "testHelpers/entities"; -import { userEvent, waitFor, within } from "@storybook/test"; +import { userEvent, waitFor, within, expect } from "@storybook/test"; const meta: Meta = { title: "pages/WorkspacePage/RetryButton",