diff --git a/site/src/pages/TemplateBuilder/BaseInfraSelectStep.tsx b/site/src/pages/TemplateBuilder/BaseInfraSelectStep.tsx
index 9b4b0ee077..f52e856e08 100644
--- a/site/src/pages/TemplateBuilder/BaseInfraSelectStep.tsx
+++ b/site/src/pages/TemplateBuilder/BaseInfraSelectStep.tsx
@@ -20,6 +20,7 @@ function toSelectedBaseMeta(base: TemplateBuilderBase): SelectedBaseMeta {
os: base.os,
hasParameters:
base.variables.length > 0 && base.variables.some((v) => !v.sensitive),
+ hasPrerequisites: Boolean(base.prerequisites?.length),
};
}
diff --git a/site/src/pages/TemplateBuilder/BaseTemplateParametersStep.tsx b/site/src/pages/TemplateBuilder/BaseTemplateParametersStep.tsx
index e3d6f509b5..c3d128b467 100644
--- a/site/src/pages/TemplateBuilder/BaseTemplateParametersStep.tsx
+++ b/site/src/pages/TemplateBuilder/BaseTemplateParametersStep.tsx
@@ -5,6 +5,7 @@ import type {
TemplateBuilderBasesResponse,
TemplateBuilderModuleVariable,
} from "#/api/typesGenerated";
+import { MemoizedMarkdown } from "#/components/Markdown/Markdown";
import type { ConfigurationFieldDefinition } from "./ConfigurationField";
import { TemplateConfiguration } from "./TemplateConfiguration";
@@ -89,6 +90,7 @@ export const BaseTemplateParametersStep: FC<
const { data } = useQuery(templateBuilderBases());
const base = data?.bases.find((b) => b.id === baseId);
const variables = base?.variables.filter((v) => !v.sensitive) ?? [];
+ const prerequisites = base?.prerequisites ?? "";
const handleChange = (name: string, value: string) => {
onChangeValues({ ...values, [name]: value });
@@ -105,6 +107,12 @@ export const BaseTemplateParametersStep: FC<
iconUrl={base?.icon}
detailsUrl={detailsUrl(baseId)}
fields={fields}
- />
+ >
+ {prerequisites && (
+
+ {prerequisites}
+
+ )}
+
);
};
diff --git a/site/src/pages/TemplateBuilder/TemplateConfiguration.tsx b/site/src/pages/TemplateBuilder/TemplateConfiguration.tsx
index 33bcab4387..4438230f2d 100644
--- a/site/src/pages/TemplateBuilder/TemplateConfiguration.tsx
+++ b/site/src/pages/TemplateBuilder/TemplateConfiguration.tsx
@@ -1,16 +1,17 @@
+import type { PropsWithChildren } from "react";
import { Link } from "#/components/Link/Link";
import {
ConfigurationField,
type ConfigurationFieldDefinition,
} from "./ConfigurationField";
-type TemplateConfigurationProps = {
+type TemplateConfigurationProps = PropsWithChildren<{
name: string;
description: string;
iconUrl?: string;
detailsUrl?: string;
fields?: ConfigurationFieldDefinition[];
-};
+}>;
export const TemplateConfiguration: React.FC = ({
name,
@@ -18,6 +19,7 @@ export const TemplateConfiguration: React.FC = ({
iconUrl,
detailsUrl,
fields,
+ children,
}) => {
return (
@@ -59,6 +61,7 @@ export const TemplateConfiguration: React.FC = ({
))}
)}
+ {children}
);
};
diff --git a/site/src/pages/TemplateBuilder/steps.test.ts b/site/src/pages/TemplateBuilder/steps.test.ts
index b77c09506a..f17645c1e2 100644
--- a/site/src/pages/TemplateBuilder/steps.test.ts
+++ b/site/src/pages/TemplateBuilder/steps.test.ts
@@ -35,6 +35,7 @@ describe("shouldSkip", () => {
id: "docker",
name: "Docker",
hasParameters: false,
+ hasPrerequisites: false,
},
});
expect(stepById("base-parameters").shouldSkip(noParams)).toBe(true);
@@ -46,6 +47,7 @@ describe("shouldSkip", () => {
id: "aws-linux",
name: "AWS Linux",
hasParameters: true,
+ hasPrerequisites: false,
},
});
expect(stepById("base-parameters").shouldSkip(withParams)).toBe(false);
@@ -137,6 +139,7 @@ describe("findNextVisibleIndex", () => {
id: "docker",
name: "Docker",
hasParameters: false,
+ hasPrerequisites: false,
},
});
// From base-infra (index 0), next visible should be module-select (index 2).
@@ -160,6 +163,7 @@ describe("findNextVisibleIndex", () => {
id: "aws-linux",
name: "AWS Linux",
hasParameters: true,
+ hasPrerequisites: false,
},
selectedModules: [
{
@@ -186,6 +190,7 @@ describe("findPrevVisibleIndex", () => {
id: "docker",
name: "Docker",
hasParameters: false,
+ hasPrerequisites: false,
},
});
// From module-select (index 2), prev visible should be base-infra (index 0).
@@ -220,6 +225,7 @@ describe("nearestVisible", () => {
id: "docker",
name: "Docker",
hasParameters: false,
+ hasPrerequisites: false,
},
};
// Index 1 (base-parameters) is skipped, nearest backward is 0 (base-infra).
diff --git a/site/src/pages/TemplateBuilder/steps.ts b/site/src/pages/TemplateBuilder/steps.ts
index bed062caf5..85d26a211d 100644
--- a/site/src/pages/TemplateBuilder/steps.ts
+++ b/site/src/pages/TemplateBuilder/steps.ts
@@ -40,7 +40,9 @@ export const WIZARD_STEPS: readonly WizardStep[] = [
{
id: "base-parameters",
group: 1,
- shouldSkip: (state) => !state.selectedBase?.hasParameters,
+ shouldSkip: (state) =>
+ !state.selectedBase?.hasParameters &&
+ !state.selectedBase?.hasPrerequisites,
},
{
id: "module-select",
diff --git a/site/src/pages/TemplateBuilder/wizardState.test.ts b/site/src/pages/TemplateBuilder/wizardState.test.ts
index 5d4b7edb1c..dbcfcabaff 100644
--- a/site/src/pages/TemplateBuilder/wizardState.test.ts
+++ b/site/src/pages/TemplateBuilder/wizardState.test.ts
@@ -26,6 +26,7 @@ describe("wizardReducer", () => {
id: "docker",
name: "Docker",
hasParameters: false,
+ hasPrerequisites: false,
},
},
]);
@@ -37,7 +38,12 @@ describe("wizardReducer", () => {
const state = reduce([
{
type: "SET_BASE",
- base: { id: "docker", name: "Docker", hasParameters: true },
+ base: {
+ id: "docker",
+ name: "Docker",
+ hasParameters: true,
+ hasPrerequisites: false,
+ },
},
{
type: "SET_BASE_VARIABLES",
@@ -45,7 +51,12 @@ describe("wizardReducer", () => {
},
{
type: "SET_BASE",
- base: { id: "aws-linux", name: "AWS Linux", hasParameters: true },
+ base: {
+ id: "aws-linux",
+ name: "AWS Linux",
+ hasParameters: true,
+ hasPrerequisites: false,
+ },
},
]);
expect(state.baseTemplateId).toBe("aws-linux");
@@ -56,7 +67,12 @@ describe("wizardReducer", () => {
const state = reduce([
{
type: "SET_BASE",
- base: { id: "docker", name: "Docker", hasParameters: true },
+ base: {
+ id: "docker",
+ name: "Docker",
+ hasParameters: true,
+ hasPrerequisites: false,
+ },
},
{
type: "SET_BASE_VARIABLES",
@@ -64,7 +80,12 @@ describe("wizardReducer", () => {
},
{
type: "SET_BASE",
- base: { id: "docker", name: "Docker", hasParameters: true },
+ base: {
+ id: "docker",
+ name: "Docker",
+ hasParameters: true,
+ hasPrerequisites: false,
+ },
},
]);
expect(state.baseVariableValues).toEqual({ image: "ubuntu" });
@@ -254,7 +275,12 @@ describe("wizardReducer", () => {
const state = reduce([
{
type: "SET_BASE",
- base: { id: "docker", name: "Docker", hasParameters: true },
+ base: {
+ id: "docker",
+ name: "Docker",
+ hasParameters: true,
+ hasPrerequisites: false,
+ },
},
{
type: "SET_CUSTOMIZATION",
diff --git a/site/src/pages/TemplateBuilder/wizardState.ts b/site/src/pages/TemplateBuilder/wizardState.ts
index 53ee055091..a2bf362b31 100644
--- a/site/src/pages/TemplateBuilder/wizardState.ts
+++ b/site/src/pages/TemplateBuilder/wizardState.ts
@@ -15,6 +15,7 @@ export type SelectedBaseMeta = {
iconUrl?: string;
os?: string;
hasParameters: boolean;
+ hasPrerequisites: boolean;
};
/**