Thanks to visit codestin.com
Credit goes to github.com

Skip to content
9 changes: 3 additions & 6 deletions site/src/pages/TemplateBuilder/BaseTemplateParametersStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ import {
TemplateBuilderSubtitle,
TemplateBuilderTitle,
} from "#/pages/TemplateBuilder/TemplateBuilderHeader";
import {
type ConfigurationFieldDefinition,
ConfigurationFieldLabel,
} from "./ConfigurationField";
import type { ConfigurationFieldDefinition } from "./ConfigurationField";
import { defaultPlaceholder } from "./defaultPlaceholder";
import { TemplateConfiguration } from "./TemplateConfiguration";

Expand All @@ -40,7 +37,7 @@ function variableToField(
error: boolean,
): ConfigurationFieldDefinition {
const id = `base-var-${variable.name}`;
const label = <ConfigurationFieldLabel variable={variable} />;
const label = variable.name;

if (variable.type === "bool") {
return {
Expand All @@ -63,7 +60,7 @@ function variableToField(
required: variable.required,
placeholder:
defaultPlaceholder(variable.default) ??
(variable.required ? "Required" : "Optional"),
(variable.required ? "Required" : ""),
field: {
name: variable.name,
id,
Expand Down
34 changes: 4 additions & 30 deletions site/src/pages/TemplateBuilder/ConfigurationField.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { FC, PropsWithChildren, ReactNode } from "react";
import type { TemplateBuilderModuleVariable } from "#/api/typesGenerated";
import { FormField } from "#/components/FormField/FormField";
import { Label } from "#/components/Label/Label";
import { RadioGroup, RadioGroupItem } from "#/components/RadioGroup/RadioGroup";
Expand Down Expand Up @@ -104,6 +103,7 @@ const TextField: FC<TextFieldDefinition> = ({
description={description}
required={required}
placeholder={placeholder}
className="placeholder:text-content-disabled"
/>
);

Expand All @@ -123,15 +123,13 @@ const SelectField: FC<SelectFieldDefinition> = ({
<div className="col-end-1! flex flex-col gap-2">
<Label htmlFor={id}>
{label}
{required ? (
{required && (
<>
{" "}
<span className="text-sm font-bold text-content-destructive">
*
</span>
</>
) : (
<OptionalIndicator />
)}
</Label>
{description && (
Expand Down Expand Up @@ -173,15 +171,13 @@ const RadioField: FC<RadioFieldDefinition> = ({
<div className="flex flex-col gap-2">
<Label id={labelId}>
{label}
{required ? (
{required && (
<>
{" "}
<span className="text-sm font-bold text-content-destructive">
*
</span>
</>
) : (
<OptionalIndicator />
)}
</Label>
{description && (
Expand Down Expand Up @@ -298,15 +294,13 @@ const SwitchGroupField: FC<SwitchGroupFieldDefinition> = ({
<div className="flex flex-col gap-2">
<Label id={labelId}>
{label}
{required ? (
{required && (
<>
{" "}
<span className="text-sm font-bold text-content-destructive">
*
</span>
</>
) : (
<OptionalIndicator />
)}
</Label>
{description && (
Expand Down Expand Up @@ -342,23 +336,3 @@ export const ConfigurationFieldContainer: FC<PropsWithChildren> = ({
</div>
);
};

const OptionalIndicator: FC = () => {
return (
<>
{" "}
<span className="text-content-secondary">(optional)</span>
</>
);
};

export const ConfigurationFieldLabel: FC<{
variable: TemplateBuilderModuleVariable;
}> = ({ variable }) => {
return (
<>
{variable.name}
{!variable.required && <OptionalIndicator />}
</>
);
};
11 changes: 5 additions & 6 deletions site/src/pages/TemplateBuilder/ModuleSettingsStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ import {
TemplateBuilderSubtitle,
TemplateBuilderTitle,
} from "#/pages/TemplateBuilder/TemplateBuilderHeader";
import {
type ConfigurationFieldDefinition,
ConfigurationFieldLabel,
} from "./ConfigurationField";
import type { ConfigurationFieldDefinition } from "./ConfigurationField";
import { defaultPlaceholder } from "./defaultPlaceholder";
import { ModuleConfiguration } from "./ModuleConfiguration";
import { getModuleFieldPlaceholder } from "./moduleFieldPlaceholders";

interface ModuleSettingsStepProps {
baseId: string;
Expand All @@ -38,7 +36,7 @@ function variableToField(
error: boolean,
): ConfigurationFieldDefinition {
const id = `mod-${moduleId}-${variable.name}`;
const label = <ConfigurationFieldLabel variable={variable} />;
const label = variable.name;

if (variable.type === "bool") {
return {
Expand All @@ -60,8 +58,9 @@ function variableToField(
description: variable.description || undefined,
required: variable.required,
placeholder:
getModuleFieldPlaceholder(moduleId, variable.name) ??
defaultPlaceholder(variable.default) ??
(variable.required ? "Required" : "Optional"),
(variable.required ? "Required" : ""),
field: {
name: variable.name,
id,
Expand Down
33 changes: 33 additions & 0 deletions site/src/pages/TemplateBuilder/moduleFieldPlaceholders.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, expect, it } from "vitest";
import { getModuleFieldPlaceholder } from "./moduleFieldPlaceholders";

describe("getModuleFieldPlaceholder", () => {
it("returns the override for known module/variable pairs", () => {
expect(getModuleFieldPlaceholder("codex", "model_reasoning_effort")).toBe(
"none, minimal, low, medium, high, or xhigh",
);
expect(getModuleFieldPlaceholder("claude-code", "anthropic_api_key")).toBe(
"sk-ant-...",
);
expect(getModuleFieldPlaceholder("claude-code", "model")).toBe(
"e.g. claude-sonnet-5",
);
expect(getModuleFieldPlaceholder("git-clone", "base_dir")).toBe("$HOME");
expect(getModuleFieldPlaceholder("git-clone", "branch_name")).toBe(
"Default branch",
);
expect(getModuleFieldPlaceholder("dotfiles", "description")).toBe(
"e.g https://dotfiles.github.io or an SSH URL git@host:user/repo",
);
});

it("returns undefined for a module without overrides", () => {
expect(getModuleFieldPlaceholder("code-server", "port")).toBeUndefined();
});

it("returns undefined for an unmatched variable on a known module", () => {
expect(
getModuleFieldPlaceholder("codex", "does_not_exist"),
).toBeUndefined();
});
});
42 changes: 42 additions & 0 deletions site/src/pages/TemplateBuilder/moduleFieldPlaceholders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Per-module placeholder text overrides for the template builder's
* module configuration fields.
*
* The API delivers each module's variable defaults verbatim from its
* `module.json`. Some of those defaults are prose that is more useful as
* documentation than as placeholder text (for example the dotfiles
* `description` default is a two-sentence explanation). This table lets
* us substitute short, actionable placeholder hints for a specific set
* of variables without changing the underlying module manifest.
*
* Lookup order used by the module configuration step:
* 1. Override in this table (if present).
* 2. Variable's `default` value.
* 3. `Required` when the variable is required, otherwise empty.
*/
const MODULE_FIELD_PLACEHOLDERS: Readonly<
Record<string, Readonly<Record<string, string>>>
> = {
codex: {
model_reasoning_effort: "none, minimal, low, medium, high, or xhigh",
},
"claude-code": {
anthropic_api_key: "sk-ant-...",
model: "e.g. claude-sonnet-5",
},
"git-clone": {
base_dir: "$HOME",
branch_name: "Default branch",
},
dotfiles: {
description:
"e.g https://dotfiles.github.io or an SSH URL git@host:user/repo",
},
};

export function getModuleFieldPlaceholder(
moduleId: string,
variableName: string,
): string | undefined {
return MODULE_FIELD_PLACEHOLDERS[moduleId]?.[variableName];
}
Loading