feat(site): warn about active prebuilds when duplicating template (#22945)

## 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 `<Alert>` 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. |

<img width="1136" height="375" alt="image"
src="https://github.com/user-attachments/assets/1ca42608-a204-48f5-b27d-6d476ab32fa7"
/>


Closes #18987
This commit is contained in:
Kacper Sawicki
2026-03-25 10:36:17 +01:00
committed by GitHub
parent 4bfa0b197b
commit 72976b4749
@@ -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<CreateTemplatePageViewProps> = ({
...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<CreateTemplatePageViewProps> = ({
}
return (
<CreateTemplateForm
{...formPermissions}
variablesSectionRef={variablesSectionRef}
onOpenBuildLogsDrawer={onOpenBuildLogsDrawer}
copiedTemplate={templateQuery.data as Template}
error={error}
isSubmitting={isCreating}
variables={templateVersionVariablesQuery.data}
onCancel={() => 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 && (
<Alert severity="warning" css={{ marginBottom: 16 }}>
This template has prebuilds configured. Duplicating this template will
automatically cause {totalPrebuilds}{" "}
{totalPrebuilds === 1 ? "prebuild" : "prebuilds"} to be created.
</Alert>
)}
<CreateTemplateForm
{...formPermissions}
variablesSectionRef={variablesSectionRef}
onOpenBuildLogsDrawer={onOpenBuildLogsDrawer}
copiedTemplate={templateQuery.data as Template}
error={error}
isSubmitting={isCreating}
variables={templateVersionVariablesQuery.data}
onCancel={() => 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),
});
}}
/>
</>
);
};