feat: disable start/restart if active version required (#10809)

This commit is contained in:
Jon Ayers
2023-11-21 18:06:30 -06:00
committed by GitHub
parent 214123d476
commit 782fe84c7c
5 changed files with 96 additions and 33 deletions
@@ -11,10 +11,13 @@ import { Workspace, WorkspaceBuildParameter } from "api/typesGenerated";
import { BuildParametersPopover } from "./BuildParametersPopover";
import PowerSettingsNewIcon from "@mui/icons-material/PowerSettingsNew";
import LoadingButton from "@mui/lab/LoadingButton";
import Tooltip from "@mui/material/Tooltip";
interface WorkspaceAction {
loading?: boolean;
handleAction: () => void;
disabled?: boolean;
tooltipText?: string;
}
export const UpdateButton: FC<WorkspaceAction> = ({
@@ -55,8 +58,8 @@ export const StartButton: FC<
workspace: Workspace;
handleAction: (buildParameters?: WorkspaceBuildParameter[]) => void;
}
> = ({ handleAction, workspace, loading }) => {
return (
> = ({ handleAction, workspace, loading, disabled, tooltipText }) => {
const buttonContent = (
<ButtonGroup
variant="outlined"
sx={{
@@ -65,12 +68,14 @@ export const StartButton: FC<
borderLeft: "1px solid #FFF",
},
}}
disabled={disabled}
>
<LoadingButton
loading={loading}
loadingPosition="start"
startIcon={<PlayCircleOutlineIcon />}
onClick={() => handleAction()}
disabled={disabled}
>
{loading ? <>Starting&hellip;</> : "Start"}
</LoadingButton>
@@ -81,6 +86,12 @@ export const StartButton: FC<
/>
</ButtonGroup>
);
return tooltipText ? (
<Tooltip title={tooltipText}>{buttonContent}</Tooltip>
) : (
buttonContent
);
};
export const StopButton: FC<WorkspaceAction> = ({ handleAction, loading }) => {
@@ -102,8 +113,8 @@ export const RestartButton: FC<
workspace: Workspace;
handleAction: (buildParameters?: WorkspaceBuildParameter[]) => void;
}
> = ({ handleAction, loading, workspace }) => {
return (
> = ({ handleAction, loading, workspace, disabled, tooltipText }) => {
const buttonContent = (
<ButtonGroup
variant="outlined"
sx={{
@@ -112,6 +123,7 @@ export const RestartButton: FC<
borderLeft: "1px solid #FFF",
},
}}
disabled={disabled}
>
<LoadingButton
loading={loading}
@@ -119,6 +131,7 @@ export const RestartButton: FC<
startIcon={<ReplayIcon />}
onClick={() => handleAction()}
data-testid="workspace-restart-button"
disabled={disabled}
>
{loading ? <>Restarting&hellip;</> : <>Restart&hellip;</>}
</LoadingButton>
@@ -129,6 +142,12 @@ export const RestartButton: FC<
/>
</ButtonGroup>
);
return tooltipText ? (
<Tooltip title={tooltipText}>{buttonContent}</Tooltip>
) : (
buttonContent
);
};
export const CancelButton: FC<WorkspaceAction> = ({ handleAction }) => {
@@ -93,3 +93,17 @@ export const RequireActiveVersionStopped: Story = {
canChangeVersions: false,
},
};
export const AlwaysUpdateStarted: Story = {
args: {
workspace: Mocks.MockOutdatedRunningWorkspaceAlwaysUpdate,
canChangeVersions: true,
},
};
export const AlwaysUpdateStopped: Story = {
args: {
workspace: Mocks.MockOutdatedStoppedWorkspaceAlwaysUpdate,
canChangeVersions: true,
},
};
@@ -30,6 +30,7 @@ import {
MoreMenuTrigger,
ThreeDotsButton,
} from "components/MoreMenu/MoreMenu";
import { workspaceUpdatePolicy } from "utils/workspace";
export interface WorkspaceActionsProps {
workspace: Workspace;
@@ -67,15 +68,28 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
canCancel,
canAcceptJobs,
actions: actionsByStatus,
} = actionsByWorkspaceStatus(
workspace,
workspace.latest_build.status,
canChangeVersions,
);
} = actionsByWorkspaceStatus(workspace, workspace.latest_build.status);
const canBeUpdated = workspace.outdated && canAcceptJobs;
const { duplicateWorkspace, isDuplicationReady } =
useWorkspaceDuplication(workspace);
const disabled =
workspaceUpdatePolicy(workspace, canChangeVersions) === "always" &&
workspace.outdated;
const tooltipText = ((): string => {
if (!disabled) {
return "";
}
if (workspace.template_require_active_version) {
return "This template requires automatic updates";
}
if (workspace.automatic_updates === "always") {
return "You have enabled automatic updates for this workspace";
}
return "";
})();
// A mapping of button type to the corresponding React component
const buttonMapping: ButtonMapping = {
[ButtonTypesEnum.update]: <UpdateButton handleAction={handleUpdate} />,
@@ -83,23 +97,41 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
<UpdateButton loading handleAction={handleUpdate} />
),
[ButtonTypesEnum.start]: (
<StartButton workspace={workspace} handleAction={handleStart} />
<StartButton
workspace={workspace}
handleAction={handleStart}
disabled={disabled}
tooltipText={tooltipText}
/>
),
[ButtonTypesEnum.starting]: (
<StartButton loading workspace={workspace} handleAction={handleStart} />
<StartButton
loading
workspace={workspace}
handleAction={handleStart}
disabled={disabled}
tooltipText={tooltipText}
/>
),
[ButtonTypesEnum.stop]: <StopButton handleAction={handleStop} />,
[ButtonTypesEnum.stopping]: (
<StopButton loading handleAction={handleStop} />
),
[ButtonTypesEnum.restart]: (
<RestartButton workspace={workspace} handleAction={handleRestart} />
<RestartButton
workspace={workspace}
handleAction={handleRestart}
disabled={disabled}
tooltipText={tooltipText}
/>
),
[ButtonTypesEnum.restarting]: (
<RestartButton
loading
workspace={workspace}
handleAction={handleRestart}
disabled={disabled}
tooltipText={tooltipText}
/>
),
[ButtonTypesEnum.deleting]: <ActionLoadingButton label="Deleting" />,
@@ -1,6 +1,5 @@
import { Workspace, WorkspaceStatus } from "api/typesGenerated";
import { ReactNode } from "react";
import { workspaceUpdatePolicy } from "utils/workspace";
// the button types we have
export enum ButtonTypesEnum {
@@ -34,7 +33,6 @@ interface WorkspaceAbilities {
export const actionsByWorkspaceStatus = (
workspace: Workspace,
status: WorkspaceStatus,
canChangeVersions: boolean,
): WorkspaceAbilities => {
if (workspace.dormant_at) {
return {
@@ -43,25 +41,6 @@ export const actionsByWorkspaceStatus = (
canAcceptJobs: false,
};
}
if (
workspace.outdated &&
workspaceUpdatePolicy(workspace, canChangeVersions) === "always"
) {
if (status === "running") {
return {
actions: [ButtonTypesEnum.stop],
canCancel: false,
canAcceptJobs: true,
};
}
if (status === "stopped") {
return {
actions: [],
canCancel: false,
canAcceptJobs: true,
};
}
}
return statusToActions[status];
};
+19
View File
@@ -1057,6 +1057,17 @@ export const MockOutdatedRunningWorkspaceRequireActiveVersion: TypesGen.Workspac
},
};
export const MockOutdatedRunningWorkspaceAlwaysUpdate: TypesGen.Workspace = {
...MockWorkspace,
id: "test-outdated-workspace-always-update",
outdated: true,
automatic_updates: "always",
latest_build: {
...MockWorkspaceBuild,
status: "running",
},
};
export const MockOutdatedStoppedWorkspaceRequireActiveVersion: TypesGen.Workspace =
{
...MockOutdatedRunningWorkspaceRequireActiveVersion,
@@ -1066,6 +1077,14 @@ export const MockOutdatedStoppedWorkspaceRequireActiveVersion: TypesGen.Workspac
},
};
export const MockOutdatedStoppedWorkspaceAlwaysUpdate: TypesGen.Workspace = {
...MockOutdatedRunningWorkspaceAlwaysUpdate,
latest_build: {
...MockWorkspaceBuild,
status: "stopped",
},
};
export const MockPendingWorkspace: TypesGen.Workspace = {
...MockWorkspace,
id: "test-pending-workspace",