From 72976b4749702749f20da5df451995e03c12a994 Mon Sep 17 00:00:00 2001 From: Kacper Sawicki Date: Wed, 25 Mar 2026 10:36:17 +0100 Subject: [PATCH] feat(site): warn about active prebuilds when duplicating template (#22945) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description When duplicating a template that has prebuilds configured, a warning alert is now shown above the create template form. The warning displays the total number of prebuilds that will be automatically created. ![Warning example](https://img.shields.io/badge/⚠️-This_template_has_prebuilds_configured-orange) ### Changes **Single file modified:** `site/src/pages/CreateTemplatePage/DuplicateTemplateView.tsx` - Fetches presets for the template's active version using the existing `templateVersionPresets` React Query helper - Computes total prebuild count by summing `DesiredPrebuildInstances` across all presets - Renders a warning `` above the form when prebuilds are configured ### Design decisions | Decision | Rationale | |---|---| | Warning in `DuplicateTemplateView`, not `CreateTemplateForm` | Only the duplicate flow needs this. Keeps data fetching local. No new props. | | Feature-flag gated (`workspace_prebuilds`) | Matches existing pattern in `TemplateLayout.tsx`. | | Non-blocking query | Presets fetch failure shouldn't prevent duplication. Warning is informational. | | Count with pluralization | Users know exactly how many prebuilds will spin up. | image Closes #18987 --- .../DuplicateTemplateView.tsx | 70 ++++++++++++------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/site/src/pages/CreateTemplatePage/DuplicateTemplateView.tsx b/site/src/pages/CreateTemplatePage/DuplicateTemplateView.tsx index 00d9c99e22..cdd584f7df 100644 --- a/site/src/pages/CreateTemplatePage/DuplicateTemplateView.tsx +++ b/site/src/pages/CreateTemplatePage/DuplicateTemplateView.tsx @@ -3,13 +3,16 @@ import { template, templateVersion, templateVersionLogs, + templateVersionPresets, templateVersionVariables, } from "api/queries/templates"; import type { Template, TemplateVersion } from "api/typesGenerated"; import { useDashboard } from "modules/dashboard/useDashboard"; +import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import type { FC } from "react"; import { useQuery } from "react-query"; import { useNavigate, useSearchParams } from "react-router"; +import { Alert } from "#/components/Alert/Alert"; import { ErrorAlert } from "#/components/Alert/ErrorAlert"; import { Loader } from "#/components/Loader/Loader"; import { CreateTemplateForm } from "./CreateTemplateForm"; @@ -38,6 +41,16 @@ export const DuplicateTemplateView: FC = ({ ...templateVersionVariables(activeVersionId), enabled: templateQuery.isSuccess, }); + const { workspace_prebuilds: prebuildsEnabled } = useFeatureVisibility(); + const presetsQuery = useQuery({ + ...templateVersionPresets(activeVersionId), + enabled: templateQuery.isSuccess && prebuildsEnabled, + }); + const totalPrebuilds = + presetsQuery.data?.reduce( + (sum, preset) => sum + (preset.DesiredPrebuildInstances ?? 0), + 0, + ) ?? 0; const isLoading = templateQuery.isLoading || templateVersionQuery.isLoading || @@ -64,29 +77,38 @@ export const DuplicateTemplateView: FC = ({ } return ( - navigate(-1)} - jobError={isJobError ? error.job.error : undefined} - logs={templateVersionLogsQuery.data} - onSubmit={async (formData) => { - await onCreateTemplate({ - organization: (templateQuery.data as Template).organization_name, - version: firstVersionFromFile( - (templateVersionQuery.data as TemplateVersion).job.file_id, - formData.user_variable_values, - formData.provisioner_type, - formData.tags, - ), - template: newTemplate(formData), - }); - }} - /> + <> + {totalPrebuilds > 0 && ( + + This template has prebuilds configured. Duplicating this template will + automatically cause {totalPrebuilds}{" "} + {totalPrebuilds === 1 ? "prebuild" : "prebuilds"} to be created. + + )} + navigate(-1)} + jobError={isJobError ? error.job.error : undefined} + logs={templateVersionLogsQuery.data} + onSubmit={async (formData) => { + await onCreateTemplate({ + organization: (templateQuery.data as Template).organization_name, + version: firstVersionFromFile( + (templateVersionQuery.data as TemplateVersion).job.file_id, + formData.user_variable_values, + formData.provisioner_type, + formData.tags, + ), + template: newTemplate(formData), + }); + }} + /> + ); };