Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions clients/tui/__tests__/schemaToForm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,15 @@ describe("schemaToForm", () => {
});
});

it("builds a select field from an array-of-enum", () => {
it("builds a select field from an array-of-enum on items.enum alone", () => {
const form = schemaToForm(
{
properties: {
// The array branch is nested under the outer `enum` guard, so a
// top-level `enum` must also be present for it to be reached; the
// options are taken from `items.enum`.
// Standard array-of-enums shape: options come from `items.enum` with
// NO top-level `enum`. The array branch keys on `items.enum` alone
// (matching the web guard), so this renders as a select.
tags: {
type: "array",
enum: ["a", "b"],
items: { enum: ["a", "b"] },
},
},
Expand All @@ -82,6 +81,28 @@ describe("schemaToForm", () => {
});
});

it("still builds a select for an array-of-enum that also carries a top-level enum", () => {
const form = schemaToForm(
{
properties: {
tags: {
type: "array",
enum: ["a", "b"],
items: { enum: ["a", "b"] },
},
},
},
"arrayEnumRedundant",
);
expect(form.sections[0]!.fields[0]).toMatchObject({
type: "select",
options: [
{ label: "a", value: "a" },
{ label: "b", value: "b" },
],
});
});

it("uses enumNames as single-select labels while keeping raw values", () => {
const form = schemaToForm(
{
Expand Down Expand Up @@ -133,7 +154,6 @@ describe("schemaToForm", () => {
properties: {
pets: {
type: "array",
enum: ["pet-1", "pet-2"],
items: { enum: ["pet-1", "pet-2"], enumNames: ["Cats", "Dogs"] },
},
},
Expand All @@ -155,7 +175,6 @@ describe("schemaToForm", () => {
properties: {
pets: {
type: "array",
enum: ["pet-1", "pet-2"],
items: { enum: ["pet-1", "pet-2"], enumNames: ["Cats"] },
},
},
Expand Down
39 changes: 18 additions & 21 deletions clients/tui/src/utils/schemaToForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,27 +69,24 @@ export function schemaToForm(

let field: FormField;

// Handle enum -> select
if (property.enum) {
if (property.type === "array" && property.items?.enum) {
// For array of enums, we'll use select but handle it differently
// Note: ink-form doesn't have multiselect, so we'll use select
field = {
type: "select",
...baseField,
options: toSelectOptions(
property.items.enum,
property.items.enumNames,
),
} as FormField;
} else {
// Single select
field = {
type: "select",
...baseField,
options: toSelectOptions(property.enum, property.enumNames),
} as FormField;
}
// Handle enum -> select. Detect the array-of-enums case on `items.enum`
// alone (matching the web SchemaForm guard) — a standard array-of-enums
// schema carries no top-level `enum`, so gating on it would drop the field
// to a plain string input.
if (property.type === "array" && property.items?.enum) {
// ink-form has no multiselect, so we render a single select.
field = {
type: "select",
...baseField,
options: toSelectOptions(property.items.enum, property.items.enumNames),
} as FormField;
} else if (property.enum) {
// Single select
field = {
type: "select",
...baseField,
options: toSelectOptions(property.enum, property.enumNames),
} as FormField;
} else {
// Map JSON Schema types to ink-form types
switch (property.type) {
Expand Down
28 changes: 28 additions & 0 deletions pr-screenshots/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
# TUI array-of-enum renders as a select on `items.enum` alone (#1751) — proof screenshots

Follow-up to #1691. The TUI `schemaToForm` array-of-enum branch was nested under
`if (property.enum)`, so a standard array-of-enums schema —
`{ type: "array", items: { enum, enumNames } }` with **no** top-level `enum` —
fell through to a plain text input. The fix keys the array case on `items.enum`
alone (matching the web `SchemaForm`). Captured non-interactively (a standalone
render of the real `ink-form` built by the real `schemaToForm`).

The demo schema has a `Sizes` array-of-enum field (`enum: [s,m,l]` +
`enumNames: [Small, Medium, Large]`, `default: "m"`, **no** top-level `enum`)
and a `Priority` single-enum control (has a top-level `enum`).

![Before #1751 — the array-of-enum field is a plain text input showing the raw default "m"](tui-1751-before-string.png)

**Before the fix** (reproducing the old nesting): `Sizes` is a plain **text
field** showing the raw default **`m`** — `enumNames` never applies because it
isn't a select at all.

![With the #1751 fix — the array-of-enum field is a select resolving "m" to its title "Medium"](tui-1751-after-select.png)

**With the fix:** `Sizes` is now a **select**; the default `m` resolves to its
title **`Medium`**. The `Priority` control (which has a top-level `enum`) shows
`High` in both — unchanged, confirming the reorder only affects the intended
`items.enum`-only case.

---

# TUI enum forms honor `enumNames` (#1691) — proof screenshots

The TUI tool-test form (`schemaToForm` → `ink-form`) rendered against a legacy
Expand Down
Binary file added pr-screenshots/tui-1751-after-select.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pr-screenshots/tui-1751-before-string.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading