diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 7e50291a9b995..ae26b8b0cbb80 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1287,6 +1287,15 @@ export const updateWorkspace = async ( }); }; +export const getWorkspaceResolveAutostart = async ( + workspaceId: string, +): Promise => { + const response = await axios.get( + `/api/v2/workspaces/${workspaceId}/resolve-autostart`, + ); + return response.data; +}; + const getMissingParameters = ( oldBuildParameters: TypesGen.WorkspaceBuildParameter[], newBuildParameters: TypesGen.WorkspaceBuildParameter[], diff --git a/site/src/api/queries/workspaceQuota.ts b/site/src/api/queries/workspaceQuota.ts index 72aaf5c716af3..b8d627783838b 100644 --- a/site/src/api/queries/workspaceQuota.ts +++ b/site/src/api/queries/workspaceQuota.ts @@ -11,3 +11,15 @@ export const workspaceQuota = (username: string) => { queryFn: () => API.getWorkspaceQuota(username), }; }; + +const getWorkspaceResolveAutostartQueryKey = (workspaceId: string) => [ + workspaceId, + "workspaceResolveAutostart", +]; + +export const workspaceResolveAutostart = (workspaceId: string) => { + return { + queryKey: getWorkspaceResolveAutostartQueryKey(workspaceId), + queryFn: () => API.getWorkspaceResolveAutostart(workspaceId), + }; +}; diff --git a/site/src/pages/WorkspacePage/Workspace.stories.tsx b/site/src/pages/WorkspacePage/Workspace.stories.tsx index d77bff78c5875..a455812f125eb 100644 --- a/site/src/pages/WorkspacePage/Workspace.stories.tsx +++ b/site/src/pages/WorkspacePage/Workspace.stories.tsx @@ -212,6 +212,14 @@ export const Outdated: Story = { }, }; +export const CantAutostart: Story = { + args: { + ...Running.args, + canAutostart: false, + workspace: Mocks.MockOutdatedRunningWorkspaceRequireActiveVersion, + }, +}; + export const GetBuildsError: Story = { args: { ...Running.args, diff --git a/site/src/pages/WorkspacePage/Workspace.tsx b/site/src/pages/WorkspacePage/Workspace.tsx index 761592d32f25b..b8d49bf17ded1 100644 --- a/site/src/pages/WorkspacePage/Workspace.tsx +++ b/site/src/pages/WorkspacePage/Workspace.tsx @@ -73,6 +73,7 @@ export interface WorkspaceProps { onLoadMoreBuilds: () => void; isLoadingMoreBuilds: boolean; hasMoreBuilds: boolean; + canAutostart: boolean; } /** @@ -111,6 +112,7 @@ export const Workspace: FC> = ({ onLoadMoreBuilds, isLoadingMoreBuilds, hasMoreBuilds, + canAutostart, }) => { const navigate = useNavigate(); const serverVersion = buildInfo?.version || ""; @@ -168,6 +170,14 @@ export const Workspace: FC> = ({ clearTimeout(showTimer); }; }, [workspace, now, showAlertPendingInQueue]); + + const updateRequired = + (workspace.template_require_active_version || + workspace.automatic_updates === "always") && + workspace.outdated; + const autoStartFailing = workspace.autostart_schedule && !canAutostart; + const requiresManualUpdate = updateRequired && autoStartFailing; + return ( <> @@ -220,12 +230,25 @@ export const Workspace: FC> = ({ - {workspace.outdated && ( - - An update is available for your workspace - {updateMessage && {updateMessage}} - - )} + {workspace.outdated && + (requiresManualUpdate ? ( + + + Autostart has been disabled for your workspace. + + + Autostart is unable to automatically update your workspace. + Manually update your workspace to reenable Autostart. + + + ) : ( + + + An update is available for your workspace + + {updateMessage && {updateMessage}} + + ))} {buildError} {cancellationError} {workspace.latest_build.status === "running" && diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts b/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts index 4d49df9d0b0a1..4209f15f48f1e 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts +++ b/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts @@ -45,7 +45,7 @@ export const actionsByWorkspaceStatus = ( } if ( workspace.outdated && - workspaceUpdatePolicy(workspace, canChangeVersions) + workspaceUpdatePolicy(workspace, canChangeVersions) === "always" ) { if (status === "running") { return { diff --git a/site/src/pages/WorkspacePage/WorkspacePage.tsx b/site/src/pages/WorkspacePage/WorkspacePage.tsx index 2c8dc3d8b9d7d..01bd83075f793 100644 --- a/site/src/pages/WorkspacePage/WorkspacePage.tsx +++ b/site/src/pages/WorkspacePage/WorkspacePage.tsx @@ -9,7 +9,10 @@ import { ErrorAlert } from "components/Alert/ErrorAlert"; import { useOrganizationId } from "hooks"; import { isAxiosError } from "axios"; import { Margins } from "components/Margins/Margins"; -import { workspaceQuota } from "api/queries/workspaceQuota"; +import { + workspaceQuota, + workspaceResolveAutostart, +} from "api/queries/workspaceQuota"; import { useInfiniteQuery, useQuery } from "react-query"; import { infiniteWorkspaceBuilds } from "api/queries/workspaceBuilds"; @@ -41,6 +44,12 @@ export const WorkspacePage: FC = () => { enabled: Boolean(workspace), }); + const canAutostartResponse = useQuery( + workspaceResolveAutostart(workspace?.id ?? ""), + ); + + const canAutostart = !canAutostartResponse.data?.parameter_mismatch ?? false; + if (pageError) { return ( @@ -70,6 +79,7 @@ export const WorkspacePage: FC = () => { await buildsQuery.fetchNextPage(); }} hasMoreBuilds={Boolean(buildsQuery.hasNextPage)} + canAutostart={canAutostart} /> ); diff --git a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx index 34cbb665c85a8..766d7a356e5f3 100644 --- a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx @@ -46,6 +46,7 @@ interface WorkspaceReadyPageProps { onLoadMoreBuilds: () => void; isLoadingMoreBuilds: boolean; hasMoreBuilds: boolean; + canAutostart: boolean; } export const WorkspaceReadyPage = ({ @@ -57,6 +58,7 @@ export const WorkspaceReadyPage = ({ onLoadMoreBuilds, isLoadingMoreBuilds, hasMoreBuilds, + canAutostart, }: WorkspaceReadyPageProps): JSX.Element => { const { buildInfo } = useDashboard(); const featureVisibility = useFeatureVisibility(); @@ -213,6 +215,7 @@ export const WorkspaceReadyPage = ({ ) } + canAutostart={canAutostart} />