mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: handle update build for dynamic params (#18226)
resolves coder/preview#110 --------- Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
blink-so[bot]
parent
c339066be3
commit
508fba83dd
@@ -0,0 +1,42 @@
|
||||
import { useQuery } from "react-query";
|
||||
|
||||
export const optOutKey = (id: string): string => `parameters.${id}.optOut`;
|
||||
|
||||
interface UseDynamicParametersOptOutOptions {
|
||||
templateId: string | undefined;
|
||||
templateUsesClassicParameters: boolean | undefined;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export const useDynamicParametersOptOut = ({
|
||||
templateId,
|
||||
templateUsesClassicParameters,
|
||||
enabled,
|
||||
}: UseDynamicParametersOptOutOptions) => {
|
||||
return useQuery({
|
||||
enabled: !!templateId && enabled,
|
||||
queryKey: ["dynamicParametersOptOut", templateId],
|
||||
queryFn: () => {
|
||||
if (!templateId) {
|
||||
// This should not happen if enabled is working correctly,
|
||||
// but as a type guard and sanity check.
|
||||
throw new Error("templateId is required");
|
||||
}
|
||||
const localStorageKey = optOutKey(templateId);
|
||||
const storedOptOutString = localStorage.getItem(localStorageKey);
|
||||
|
||||
let optedOut: boolean;
|
||||
|
||||
if (storedOptOutString !== null) {
|
||||
optedOut = storedOptOutString === "true";
|
||||
} else {
|
||||
optedOut = Boolean(templateUsesClassicParameters);
|
||||
}
|
||||
|
||||
return {
|
||||
templateId,
|
||||
optedOut,
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
import type { TemplateVersionParameter } from "api/typesGenerated";
|
||||
import { Button } from "components/Button/Button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "components/Dialog/Dialog";
|
||||
import type { FC } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
type UpdateBuildParametersDialogExperimentalProps = {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
missedParameters: TemplateVersionParameter[];
|
||||
workspaceOwnerName: string;
|
||||
workspaceName: string;
|
||||
templateVersionId: string | undefined;
|
||||
};
|
||||
|
||||
export const UpdateBuildParametersDialogExperimental: FC<
|
||||
UpdateBuildParametersDialogExperimentalProps
|
||||
> = ({
|
||||
missedParameters,
|
||||
open,
|
||||
onClose,
|
||||
workspaceOwnerName,
|
||||
workspaceName,
|
||||
templateVersionId,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleGoToParameters = () => {
|
||||
onClose();
|
||||
navigate(
|
||||
`/@${workspaceOwnerName}/${workspaceName}/settings/parameters?templateVersionId=${templateVersionId}`,
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Update workspace parameters</DialogTitle>
|
||||
<DialogDescription>
|
||||
This template has{" "}
|
||||
<strong className="text-content-primary">
|
||||
{missedParameters.length} new parameter
|
||||
{missedParameters.length === 1 ? "" : "s"}
|
||||
</strong>{" "}
|
||||
that must be configured to complete the update.
|
||||
</DialogDescription>
|
||||
<DialogDescription>
|
||||
Would you like to go to the workspace parameters page to review and
|
||||
update these parameters before continuing?
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<Button onClick={onClose} variant="outline">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleGoToParameters}>
|
||||
Go to workspace parameters
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -21,12 +21,15 @@ import {
|
||||
SettingsIcon,
|
||||
TrashIcon,
|
||||
} from "lucide-react";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
import { useDynamicParametersOptOut } from "modules/workspaces/DynamicParameter/useDynamicParametersOptOut";
|
||||
import { type FC, useEffect, useState } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { ChangeWorkspaceVersionDialog } from "./ChangeWorkspaceVersionDialog";
|
||||
import { DownloadLogsDialog } from "./DownloadLogsDialog";
|
||||
import { UpdateBuildParametersDialog } from "./UpdateBuildParametersDialog";
|
||||
import { UpdateBuildParametersDialogExperimental } from "./UpdateBuildParametersDialogExperimental";
|
||||
import { WorkspaceDeleteDialog } from "./WorkspaceDeleteDialog";
|
||||
import { useWorkspaceDuplication } from "./useWorkspaceDuplication";
|
||||
|
||||
@@ -40,6 +43,15 @@ export const WorkspaceMoreActions: FC<WorkspaceMoreActionsProps> = ({
|
||||
disabled,
|
||||
}) => {
|
||||
const queryClient = useQueryClient();
|
||||
const { experiments } = useDashboard();
|
||||
const isDynamicParametersEnabled = experiments.includes("dynamic-parameters");
|
||||
|
||||
const optOutQuery = useDynamicParametersOptOut({
|
||||
templateId: workspace.template_id,
|
||||
templateUsesClassicParameters:
|
||||
workspace.template_use_classic_parameter_flow,
|
||||
enabled: isDynamicParametersEnabled,
|
||||
});
|
||||
|
||||
// Permissions
|
||||
const { data: permissions } = useQuery(workspacePermissions(workspace));
|
||||
@@ -50,7 +62,7 @@ export const WorkspaceMoreActions: FC<WorkspaceMoreActionsProps> = ({
|
||||
// Change version
|
||||
const [changeVersionDialogOpen, setChangeVersionDialogOpen] = useState(false);
|
||||
const changeVersionMutation = useMutation(
|
||||
changeVersion(workspace, queryClient),
|
||||
changeVersion(workspace, queryClient, optOutQuery.data?.optedOut === false),
|
||||
);
|
||||
|
||||
// Delete
|
||||
@@ -142,25 +154,46 @@ export const WorkspaceMoreActions: FC<WorkspaceMoreActionsProps> = ({
|
||||
onClose={() => setIsDownloadDialogOpen(false)}
|
||||
/>
|
||||
|
||||
<UpdateBuildParametersDialog
|
||||
missedParameters={
|
||||
changeVersionMutation.error instanceof MissingBuildParameters
|
||||
? changeVersionMutation.error.parameters
|
||||
: []
|
||||
}
|
||||
open={changeVersionMutation.error instanceof MissingBuildParameters}
|
||||
onClose={() => {
|
||||
changeVersionMutation.reset();
|
||||
}}
|
||||
onUpdate={(buildParameters) => {
|
||||
if (changeVersionMutation.error instanceof MissingBuildParameters) {
|
||||
changeVersionMutation.mutate({
|
||||
versionId: changeVersionMutation.error.versionId,
|
||||
buildParameters,
|
||||
});
|
||||
{!isDynamicParametersEnabled || optOutQuery.data?.optedOut ? (
|
||||
<UpdateBuildParametersDialog
|
||||
missedParameters={
|
||||
changeVersionMutation.error instanceof MissingBuildParameters
|
||||
? changeVersionMutation.error.parameters
|
||||
: []
|
||||
}
|
||||
}}
|
||||
/>
|
||||
open={changeVersionMutation.error instanceof MissingBuildParameters}
|
||||
onClose={() => {
|
||||
changeVersionMutation.reset();
|
||||
}}
|
||||
onUpdate={(buildParameters) => {
|
||||
if (changeVersionMutation.error instanceof MissingBuildParameters) {
|
||||
changeVersionMutation.mutate({
|
||||
versionId: changeVersionMutation.error.versionId,
|
||||
buildParameters,
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<UpdateBuildParametersDialogExperimental
|
||||
missedParameters={
|
||||
changeVersionMutation.error instanceof MissingBuildParameters
|
||||
? changeVersionMutation.error.parameters
|
||||
: []
|
||||
}
|
||||
open={changeVersionMutation.error instanceof MissingBuildParameters}
|
||||
onClose={() => {
|
||||
changeVersionMutation.reset();
|
||||
}}
|
||||
workspaceOwnerName={workspace.owner_name}
|
||||
workspaceName={workspace.name}
|
||||
templateVersionId={
|
||||
changeVersionMutation.error instanceof MissingBuildParameters
|
||||
? changeVersionMutation.error?.versionId
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ChangeWorkspaceVersionDialog
|
||||
workspace={workspace}
|
||||
|
||||
@@ -6,9 +6,14 @@ import type {
|
||||
WorkspaceBuild,
|
||||
WorkspaceBuildParameter,
|
||||
} from "api/typesGenerated";
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { MemoizedInlineMarkdown } from "components/Markdown/Markdown";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
import { useDynamicParametersOptOut } from "modules/workspaces/DynamicParameter/useDynamicParametersOptOut";
|
||||
import { UpdateBuildParametersDialog } from "modules/workspaces/WorkspaceMoreActions/UpdateBuildParametersDialog";
|
||||
import { UpdateBuildParametersDialogExperimental } from "modules/workspaces/WorkspaceMoreActions/UpdateBuildParametersDialogExperimental";
|
||||
import { type FC, useState } from "react";
|
||||
import { useMutation, useQueryClient } from "react-query";
|
||||
|
||||
@@ -51,8 +56,21 @@ export const useWorkspaceUpdate = ({
|
||||
setIsConfirmingUpdate(true);
|
||||
};
|
||||
|
||||
const { experiments } = useDashboard();
|
||||
const isDynamicParametersEnabled = experiments.includes("dynamic-parameters");
|
||||
|
||||
const optOutQuery = useDynamicParametersOptOut({
|
||||
templateId: workspace.template_id,
|
||||
templateUsesClassicParameters:
|
||||
workspace.template_use_classic_parameter_flow,
|
||||
enabled: isDynamicParametersEnabled,
|
||||
});
|
||||
|
||||
const confirmUpdate = (buildParameters: WorkspaceBuildParameter[] = []) => {
|
||||
updateWorkspaceMutation.mutate(buildParameters);
|
||||
updateWorkspaceMutation.mutate({
|
||||
buildParameters,
|
||||
isDynamicParametersEnabled: optOutQuery.data?.optedOut === false,
|
||||
});
|
||||
setIsConfirmingUpdate(false);
|
||||
};
|
||||
|
||||
@@ -67,6 +85,7 @@ export const useWorkspaceUpdate = ({
|
||||
latestVersion,
|
||||
},
|
||||
missingBuildParameters: {
|
||||
workspace,
|
||||
error: updateWorkspaceMutation.error,
|
||||
onClose: () => {
|
||||
updateWorkspaceMutation.reset();
|
||||
@@ -134,22 +153,57 @@ const UpdateConfirmationDialog: FC<UpdateConfirmationDialogProps> = ({
|
||||
};
|
||||
|
||||
type MissingBuildParametersDialogProps = {
|
||||
workspace: Workspace;
|
||||
error: unknown;
|
||||
onClose: () => void;
|
||||
onUpdate: (buildParameters: WorkspaceBuildParameter[]) => void;
|
||||
};
|
||||
|
||||
const MissingBuildParametersDialog: FC<MissingBuildParametersDialogProps> = ({
|
||||
workspace,
|
||||
error,
|
||||
...dialogProps
|
||||
}) => {
|
||||
return (
|
||||
const { experiments } = useDashboard();
|
||||
const isDynamicParametersEnabled = experiments.includes("dynamic-parameters");
|
||||
const optOutQuery = useDynamicParametersOptOut({
|
||||
templateId: workspace.template_id,
|
||||
templateUsesClassicParameters:
|
||||
workspace.template_use_classic_parameter_flow,
|
||||
enabled: isDynamicParametersEnabled,
|
||||
});
|
||||
|
||||
const missedParameters =
|
||||
error instanceof MissingBuildParameters ? error.parameters : [];
|
||||
const versionId =
|
||||
error instanceof MissingBuildParameters ? error.versionId : undefined;
|
||||
const isOpen = error instanceof MissingBuildParameters;
|
||||
|
||||
if (optOutQuery.isError) {
|
||||
return <ErrorAlert error={optOutQuery.error} />;
|
||||
}
|
||||
if (isDynamicParametersEnabled && !optOutQuery.data) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
// If dynamic parameters experiment is not enabled, or if opted out, use classic dialog
|
||||
const shouldUseClassicDialog =
|
||||
!isDynamicParametersEnabled || optOutQuery.data?.optedOut;
|
||||
|
||||
return shouldUseClassicDialog ? (
|
||||
<UpdateBuildParametersDialog
|
||||
missedParameters={
|
||||
error instanceof MissingBuildParameters ? error.parameters : []
|
||||
}
|
||||
open={error instanceof MissingBuildParameters}
|
||||
missedParameters={missedParameters}
|
||||
open={isOpen}
|
||||
{...dialogProps}
|
||||
/>
|
||||
) : (
|
||||
<UpdateBuildParametersDialogExperimental
|
||||
missedParameters={missedParameters}
|
||||
open={isOpen}
|
||||
onClose={dialogProps.onClose}
|
||||
workspaceOwnerName={workspace.owner_name}
|
||||
workspaceName={workspace.name}
|
||||
templateVersionId={versionId}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user