mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: improve workspace upgrade flow when template parameters change (#18917)
This commit is contained in:
+35
-11
@@ -24,6 +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 type {
|
||||
DynamicParametersRequest,
|
||||
PostWorkspaceUsageRequest,
|
||||
@@ -390,6 +391,15 @@ 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;
|
||||
@@ -1239,7 +1249,6 @@ class ApiMethods {
|
||||
`/api/v2/workspaces/${workspaceId}/builds`,
|
||||
data,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
@@ -2268,19 +2277,34 @@ class ApiMethods {
|
||||
|
||||
const activeVersionId = template.active_version_id;
|
||||
|
||||
let templateParameters: TypesGen.TemplateVersionParameter[] = [];
|
||||
|
||||
if (isDynamicParametersEnabled) {
|
||||
templateParameters = await this.getDynamicParameters(
|
||||
activeVersionId,
|
||||
workspace.owner_id,
|
||||
oldBuildParameters,
|
||||
);
|
||||
} else {
|
||||
templateParameters =
|
||||
await this.getTemplateVersionRichParameters(activeVersionId);
|
||||
try {
|
||||
return await this.postWorkspaceBuild(workspace.id, {
|
||||
transition: "start",
|
||||
template_version_id: activeVersionId,
|
||||
rich_parameter_values: newBuildParameters,
|
||||
});
|
||||
} catch (error) {
|
||||
// If the build failed because of a parameter validation error, then we
|
||||
// throw a special sentinel error that can be caught by the caller.
|
||||
if (
|
||||
isApiError(error) &&
|
||||
error.response.status === 400 &&
|
||||
error.response.data.validations &&
|
||||
error.response.data.validations.length > 0
|
||||
) {
|
||||
throw new ParameterValidationError(
|
||||
activeVersionId,
|
||||
error.response.data.validations,
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
const templateParameters =
|
||||
await this.getTemplateVersionRichParameters(activeVersionId);
|
||||
|
||||
const missingParameters = getMissingParameters(
|
||||
oldBuildParameters,
|
||||
newBuildParameters,
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
import type { TemplateVersionParameter } from "api/typesGenerated";
|
||||
import type { FieldError } from "api/errors";
|
||||
import { Button } from "components/Button/Button";
|
||||
import {
|
||||
Dialog,
|
||||
@@ -14,7 +14,7 @@ import { useNavigate } from "react-router-dom";
|
||||
type UpdateBuildParametersDialogExperimentalProps = {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
missedParameters: TemplateVersionParameter[];
|
||||
validations: FieldError[];
|
||||
workspaceOwnerName: string;
|
||||
workspaceName: string;
|
||||
templateVersionId: string | undefined;
|
||||
@@ -23,7 +23,7 @@ type UpdateBuildParametersDialogExperimentalProps = {
|
||||
export const UpdateBuildParametersDialogExperimental: FC<
|
||||
UpdateBuildParametersDialogExperimentalProps
|
||||
> = ({
|
||||
missedParameters,
|
||||
validations,
|
||||
open,
|
||||
onClose,
|
||||
workspaceOwnerName,
|
||||
@@ -47,8 +47,8 @@ export const UpdateBuildParametersDialogExperimental: FC<
|
||||
<DialogDescription>
|
||||
This template has{" "}
|
||||
<strong className="text-content-primary">
|
||||
{missedParameters.length} new parameter
|
||||
{missedParameters.length === 1 ? "" : "s"}
|
||||
{validations.length} parameter
|
||||
{validations.length === 1 ? "" : "s"}
|
||||
</strong>{" "}
|
||||
that must be configured to complete the update.
|
||||
</DialogDescription>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MissingBuildParameters } from "api/api";
|
||||
import { MissingBuildParameters, ParameterValidationError } from "api/api";
|
||||
import { isApiError } from "api/errors";
|
||||
import { type ApiError, getErrorMessage } from "api/errors";
|
||||
import {
|
||||
@@ -192,19 +192,19 @@ export const WorkspaceMoreActions: FC<WorkspaceMoreActionsProps> = ({
|
||||
/>
|
||||
) : (
|
||||
<UpdateBuildParametersDialogExperimental
|
||||
missedParameters={
|
||||
changeVersionMutation.error instanceof MissingBuildParameters
|
||||
? changeVersionMutation.error.parameters
|
||||
validations={
|
||||
changeVersionMutation.error instanceof ParameterValidationError
|
||||
? changeVersionMutation.error.validations
|
||||
: []
|
||||
}
|
||||
open={changeVersionMutation.error instanceof MissingBuildParameters}
|
||||
open={changeVersionMutation.error instanceof ParameterValidationError}
|
||||
onClose={() => {
|
||||
changeVersionMutation.reset();
|
||||
}}
|
||||
workspaceOwnerName={workspace.owner_name}
|
||||
workspaceName={workspace.name}
|
||||
templateVersionId={
|
||||
changeVersionMutation.error instanceof MissingBuildParameters
|
||||
changeVersionMutation.error instanceof ParameterValidationError
|
||||
? changeVersionMutation.error?.versionId
|
||||
: undefined
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MissingBuildParameters } from "api/api";
|
||||
import { MissingBuildParameters, ParameterValidationError } from "api/api";
|
||||
import { updateWorkspace } from "api/queries/workspaces";
|
||||
import type {
|
||||
TemplateVersion,
|
||||
@@ -78,7 +78,10 @@ export const useWorkspaceUpdate = ({
|
||||
updateWorkspaceMutation.reset();
|
||||
},
|
||||
onUpdate: (buildParameters: WorkspaceBuildParameter[]) => {
|
||||
if (updateWorkspaceMutation.error instanceof MissingBuildParameters) {
|
||||
if (
|
||||
updateWorkspaceMutation.error instanceof MissingBuildParameters ||
|
||||
updateWorkspaceMutation.error instanceof ParameterValidationError
|
||||
) {
|
||||
confirmUpdate(buildParameters);
|
||||
}
|
||||
},
|
||||
@@ -154,8 +157,10 @@ const MissingBuildParametersDialog: FC<MissingBuildParametersDialogProps> = ({
|
||||
const missedParameters =
|
||||
error instanceof MissingBuildParameters ? error.parameters : [];
|
||||
const versionId =
|
||||
error instanceof MissingBuildParameters ? error.versionId : undefined;
|
||||
const isOpen = error instanceof MissingBuildParameters;
|
||||
error instanceof ParameterValidationError ? error.versionId : undefined;
|
||||
const isOpen =
|
||||
error instanceof MissingBuildParameters ||
|
||||
error instanceof ParameterValidationError;
|
||||
|
||||
return workspace.template_use_classic_parameter_flow ? (
|
||||
<UpdateBuildParametersDialog
|
||||
@@ -165,7 +170,9 @@ const MissingBuildParametersDialog: FC<MissingBuildParametersDialogProps> = ({
|
||||
/>
|
||||
) : (
|
||||
<UpdateBuildParametersDialogExperimental
|
||||
missedParameters={missedParameters}
|
||||
validations={
|
||||
error instanceof ParameterValidationError ? error.validations : []
|
||||
}
|
||||
open={isOpen}
|
||||
onClose={dialogProps.onClose}
|
||||
workspaceOwnerName={workspace.owner_name}
|
||||
|
||||
Reference in New Issue
Block a user