diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 2b21ddf1e8a08..dc6e8894a68cc 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -24,7 +24,7 @@ import type dayjs from "dayjs"; import userAgentParser from "ua-parser-js"; import { OneWayWebSocket } from "../utils/OneWayWebSocket"; import { delay } from "../utils/delay"; -import { type FieldError, isApiError } from "./errors"; +import { ParameterValidationError, isApiError } from "./errors"; import type { DynamicParametersRequest, PostWorkspaceUsageRequest, @@ -398,15 +398,6 @@ export class MissingBuildParameters extends Error { } } -export class ParameterValidationError extends Error { - constructor( - public readonly versionId: string, - public readonly validations: FieldError[], - ) { - super("Parameters are not valid for new template version"); - } -} - export type GetProvisionerJobsParams = { status?: string; limit?: number; @@ -2240,63 +2231,11 @@ class ApiMethods { const currentBuildParameters = await this.getWorkspaceBuildParameters( workspace.latest_build.id, ); - - let templateParameters: TypesGen.TemplateVersionParameter[] = []; - if (isDynamicParametersEnabled) { - templateParameters = await this.getDynamicParameters( - templateVersionId, - workspace.owner_id, - currentBuildParameters, - ); - } else { - templateParameters = - await this.getTemplateVersionRichParameters(templateVersionId); - } - - const missingParameters = getMissingParameters( - currentBuildParameters, - newBuildParameters, - templateParameters, - ); - - if (missingParameters.length > 0) { - throw new MissingBuildParameters(missingParameters, templateVersionId); - } - - return this.postWorkspaceBuild(workspace.id, { - transition: "start", - template_version_id: templateVersionId, - rich_parameter_values: newBuildParameters, - }); - }; - - /** Steps to update the workspace - * - Get the latest template to access the latest active version - * - Get the current build parameters - * - Get the template parameters - * - Update the build parameters and check if there are missed parameters for - * the newest version - * - If there are missing parameters raise an error - * - Stop the workspace with the current template version if it is already running - * - Create a build with the latest version and updated build parameters - */ - updateWorkspace = async ( - workspace: TypesGen.Workspace, - newBuildParameters: TypesGen.WorkspaceBuildParameter[] = [], - isDynamicParametersEnabled = false, - ): Promise => { - const [template, oldBuildParameters] = await Promise.all([ - this.getTemplate(workspace.template_id), - this.getWorkspaceBuildParameters(workspace.latest_build.id), - ]); - - const activeVersionId = template.active_version_id; - if (isDynamicParametersEnabled) { try { return await this.postWorkspaceBuild(workspace.id, { transition: "start", - template_version_id: activeVersionId, + template_version_id: templateVersionId, rich_parameter_values: newBuildParameters, }); } catch (error) { @@ -2308,8 +2247,9 @@ class ApiMethods { error.response.data.validations && error.response.data.validations.length > 0 ) { + console.log(error.response.data.validations); throw new ParameterValidationError( - activeVersionId, + templateVersionId, error.response.data.validations, ); } @@ -2318,38 +2258,63 @@ class ApiMethods { } const templateParameters = - await this.getTemplateVersionRichParameters(activeVersionId); + await this.getTemplateVersionRichParameters(templateVersionId); const missingParameters = getMissingParameters( - oldBuildParameters, + currentBuildParameters, newBuildParameters, templateParameters, ); if (missingParameters.length > 0) { - throw new MissingBuildParameters(missingParameters, activeVersionId); + throw new MissingBuildParameters(missingParameters, templateVersionId); } // Stop the workspace if it is already running. if (workspace.latest_build.status === "running") { const stopBuild = await this.stopWorkspace(workspace.id); const awaitedStopBuild = await this.waitForBuild(stopBuild); - // If the stop is canceled halfway through, we bail. - // This is the same behaviour as restartWorkspace. + // If the stop is canceled halfway through, we bail. This is the same + // behaviour as restartWorkspace. if (awaitedStopBuild?.status === "canceled") { - return Promise.reject( - new Error("Workspace stop was canceled, not proceeding with update."), + throw new Error( + "Workspace stop was canceled, not proceeding with update.", ); } } return this.postWorkspaceBuild(workspace.id, { transition: "start", - template_version_id: activeVersionId, + template_version_id: templateVersionId, rich_parameter_values: newBuildParameters, }); }; + /** Steps to update the workspace + * - Get the latest template to access the latest active version + * - Get the current build parameters + * - Get the template parameters + * - Update the build parameters and check if there are missed parameters for + * the newest version + * - If there are missing parameters raise an error + * - Stop the workspace with the current template version if it is already running + * - Create a build with the latest version and updated build parameters + */ + updateWorkspace = async ( + workspace: TypesGen.Workspace, + newBuildParameters: TypesGen.WorkspaceBuildParameter[] = [], + isDynamicParametersEnabled = false, + ): Promise => { + const template = await this.getTemplate(workspace.template_id); + + return this.changeWorkspaceVersion( + workspace, + template.active_version_id, + newBuildParameters, + isDynamicParametersEnabled, + ); + }; + getWorkspaceResolveAutostart = async ( workspaceId: string, ): Promise => { diff --git a/site/src/api/errors.ts b/site/src/api/errors.ts index 9705a08ff057c..a3f458c405242 100644 --- a/site/src/api/errors.ts +++ b/site/src/api/errors.ts @@ -149,3 +149,12 @@ export class DetailedError extends Error { super(message); } } + +export class ParameterValidationError extends Error { + constructor( + public readonly versionId: string, + public readonly validations: FieldError[], + ) { + super("Parameters are not valid for new template version"); + } +} diff --git a/site/src/modules/workspaces/WorkspaceMoreActions/WorkspaceMoreActions.tsx b/site/src/modules/workspaces/WorkspaceMoreActions/WorkspaceMoreActions.tsx index 8e7b9e33b93d2..e7653b53111b3 100644 --- a/site/src/modules/workspaces/WorkspaceMoreActions/WorkspaceMoreActions.tsx +++ b/site/src/modules/workspaces/WorkspaceMoreActions/WorkspaceMoreActions.tsx @@ -1,5 +1,5 @@ -import { MissingBuildParameters, ParameterValidationError } from "api/api"; -import { isApiError } from "api/errors"; +import { MissingBuildParameters } from "api/api"; +import { ParameterValidationError, isApiError } from "api/errors"; import { type ApiError, getErrorMessage } from "api/errors"; import { changeVersion, diff --git a/site/src/modules/workspaces/WorkspaceUpdateDialogs.tsx b/site/src/modules/workspaces/WorkspaceUpdateDialogs.tsx index 2fad94de2da73..74e7a4dcf3b55 100644 --- a/site/src/modules/workspaces/WorkspaceUpdateDialogs.tsx +++ b/site/src/modules/workspaces/WorkspaceUpdateDialogs.tsx @@ -1,4 +1,5 @@ -import { MissingBuildParameters, ParameterValidationError } from "api/api"; +import { MissingBuildParameters } from "api/api"; +import { ParameterValidationError } from "api/errors"; import { updateWorkspace } from "api/queries/workspaces"; import type { TemplateVersion, diff --git a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx index 288e80127af4a..cc882a5d5f6f1 100644 --- a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx +++ b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx @@ -1,6 +1,7 @@ import { screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import * as apiModule from "api/api"; +import { ParameterValidationError } from "api/errors"; import type { TemplateVersionParameter, Workspace } from "api/typesGenerated"; import MockServerSocket from "jest-websocket-mock"; import { @@ -282,11 +283,9 @@ describe("WorkspacePage", () => { }); it("requests an update when the user presses Update", async () => { - // Mocks jest .spyOn(API, "getWorkspaceByOwnerAndName") .mockResolvedValueOnce(MockOutdatedWorkspace); - const updateWorkspaceMock = jest .spyOn(API, "updateWorkspace") .mockResolvedValueOnce(MockWorkspaceBuild); @@ -306,71 +305,37 @@ describe("WorkspacePage", () => { }); }); - it("updates the parameters when they are missing during update", async () => { - // Mocks + it("requires invalid parameters to be updated", async () => { jest .spyOn(API, "getWorkspaceByOwnerAndName") .mockResolvedValueOnce(MockOutdatedWorkspace); - const updateWorkspaceSpy = jest + const updateWorkspaceMock = jest .spyOn(API, "updateWorkspace") .mockRejectedValueOnce( - new MissingBuildParameters( - [MockTemplateVersionParameter1, MockTemplateVersionParameter2], + new ParameterValidationError( MockOutdatedWorkspace.template_active_version_id, + [ + { + field: MockTemplateVersionParameter1.name, + detail: + "Required parameter not provided; parameter value is null", + }, + ], ), ); - // Render await renderWorkspacePage(MockWorkspace); - // Actions + // Start workspace update const user = userEvent.setup(); await user.click(screen.getByTestId("workspace-update-button")); const confirmButton = await screen.findByTestId("confirm-button"); await user.click(confirmButton); - // The update was called - await waitFor(() => { - expect(API.updateWorkspace).toBeCalled(); - updateWorkspaceSpy.mockClear(); - }); - - // After trying to update, a new dialog asking for missed parameters should - // be displayed and filled - const dialog = await waitFor(() => screen.findByTestId("dialog")); - const firstParameterInput = within(dialog).getByLabelText( - MockTemplateVersionParameter1.name, - { exact: false }, - ); - await user.clear(firstParameterInput); - await user.type(firstParameterInput, "some-value"); - const secondParameterInput = within(dialog).getByLabelText( - MockTemplateVersionParameter2.name, - { exact: false }, - ); - await user.clear(secondParameterInput); - await user.type(secondParameterInput, "2"); - await user.click( - within(dialog).getByRole("button", { name: /update parameters/i }), - ); - - // Check if the update was called using the values from the form - await waitFor(() => { - expect(API.updateWorkspace).toHaveBeenCalledWith( - MockOutdatedWorkspace, - [ - { - name: MockTemplateVersionParameter1.name, - value: "some-value", - }, - { - name: MockTemplateVersionParameter2.name, - value: "2", - }, - ], - false, - ); - }); + // Dialog should warn the parameters need to be updated + const dialog = await screen.findByTestId("dialog"); + await within(dialog).findByText("Update workspace parameters"); + await screen.findByText(/go to the workspace parameters page to review/); }); it("restart the workspace with one time parameters when having the confirmation dialog", async () => { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy