feat(site/src/pages/TemplateBuilder): add provisioner warning to Template Builder form (#26935)

## Summary

Show a warning in the Template Builder customizations step when the
selected organization has no provisioner daemons connected. This matches
the existing behavior in the current `CreateTemplateForm`.

## Changes

- Added a `provisionerDaemons` query in `TemplateCustomizationsStep`,
gated on the selected org
- Renders an `Alert` warning with a link to provisioner docs when no
daemons are found
- Warning is informational only and does not block form submission

<details>
<summary>Implementation plan</summary>

The current `CreateTemplateForm` (used for upload/starter/duplicate
flows) shows a warning when the selected organization has no provisioner
daemons connected. The new Template Builder wizard
(`/templates/new/builder`) had an org picker in
`TemplateCustomizationsStep` but did not perform this check.

### What was done

1. Imported `provisionerDaemons` query helper, `Alert`, `Link`, and
`docs` utility into `TemplateCustomizationsStep.tsx`
2. Added a `useQuery` call for provisioner daemons, enabled only when an
org is selected
3. Computed `showProvisionerWarning` (true when the provisioners list is
empty)
4. Added a local `ProvisionerWarning` component rendering the same
warning text and docs link as `CreateTemplateForm`
5. Rendered the warning below the `OrganizationAutocomplete` picker

### Design decisions

- Warning is informational only (does not block submission), matching
the existing form behavior and the TODO rationale: a user may connect a
provisioner without refreshing
- Used the project's `Link` component (`#/components/Link/Link`) instead
of MUI Link
- Kept `ProvisionerWarning` as a local component rather than extracting
to shared, since the component is small (~8 lines)

</details>

> 🤖 Generated by Coder Agents on behalf of @jeremyruppel

<img width="2574" height="1274" alt="Screenshot 2026-07-01 at 3 56
58 PM"
src="https://github.com/user-attachments/assets/45f0d81b-1f9a-4a93-a2d3-5f037e82d1d0"
/>
This commit is contained in:
Jeremy Ruppel
2026-07-01 16:27:24 -04:00
committed by GitHub
parent ff7e0bc193
commit 1101a0f974
@@ -1,16 +1,22 @@
import { type FC, useEffect, useState } from "react";
import { useQuery } from "react-query";
import { permittedOrganizations } from "#/api/queries/organizations";
import {
permittedOrganizations,
provisionerDaemons,
} from "#/api/queries/organizations";
import type { Organization } from "#/api/typesGenerated";
import { Alert } from "#/components/Alert/Alert";
import { IconField } from "#/components/IconField/IconField";
import { Input } from "#/components/Input/Input";
import { Label } from "#/components/Label/Label";
import { Link } from "#/components/Link/Link";
import { OrganizationAutocomplete } from "#/components/OrganizationAutocomplete/OrganizationAutocomplete";
import { Textarea } from "#/components/Textarea/Textarea";
import {
TemplateBuilderSubtitle,
TemplateBuilderTitle,
} from "#/pages/TemplateBuilder/TemplateBuilderHeader";
import { docs } from "#/utils/docs";
import type {
SelectedBaseMeta,
TemplateBuilderWizardState,
@@ -37,6 +43,12 @@ export const TemplateCustomizationsStep: FC<
const [selectedOrg, setSelectedOrg] = useState<Organization | null>(null);
const { data: provisioners } = useQuery({
...provisionerDaemons(selectedOrg?.id ?? ""),
enabled: Boolean(selectedOrg),
});
const showProvisionerWarning = provisioners ? provisioners.length < 1 : false;
// Auto-select when exactly one org is available.
useEffect(() => {
if (orgOptions.length === 1 && !selectedOrg) {
@@ -57,6 +69,8 @@ export const TemplateCustomizationsStep: FC<
Add additional configurations.
</TemplateBuilderSubtitle>
{showProvisionerWarning && <ProvisionerWarning />}
<div className="flex gap-8">
{/* Base template card */}
{state.selectedBase && <BaseTemplateCard base={state.selectedBase} />}
@@ -142,6 +156,18 @@ export const TemplateCustomizationsStep: FC<
);
};
const ProvisionerWarning: FC = () => {
return (
<Alert severity="warning" prominent className="my-4">
This organization does not have any provisioners. Before you create a
template, you&apos;ll need to configure a provisioner.{" "}
<Link href={docs("/admin/provisioners#organization-scoped-provisioners")}>
See our documentation
</Link>
</Alert>
);
};
const BaseTemplateCard: FC<{ base: SelectedBaseMeta }> = ({ base }) => {
return (
<div className="w-56 shrink-0 rounded-lg bg-surface-secondary p-4 self-start">