diff --git a/ui/src/ui/views/config-form.render.ts b/ui/src/ui/views/config-form.render.ts index 52e60e3918d..9311839bca3 100644 --- a/ui/src/ui/views/config-form.render.ts +++ b/ui/src/ui/views/config-form.render.ts @@ -438,20 +438,25 @@ export function renderConfigForm(props: ConfigFormProps) { sectionKey: string; label: string; description: string; + showHeader: boolean; node: JsonSchema; nodeValue: unknown; path: Array; }) => html`
-
- ${getSectionIcon(params.sectionKey)} -
-

${params.label}

- ${params.description - ? html`

${params.description}

` - : nothing} -
-
+ ${params.showHeader + ? html` +
+ ${getSectionIcon(params.sectionKey)} +
+

${params.label}

+ ${params.description + ? html`

${params.description}

` + : nothing} +
+
+ ` + : nothing}
${renderNode({ schema: params.node, @@ -490,6 +495,7 @@ export function renderConfigForm(props: ConfigFormProps) { sectionKey, label, description, + showHeader: false, node, nodeValue: scopedValue, path: [sectionKey, subsectionKey], @@ -506,6 +512,7 @@ export function renderConfigForm(props: ConfigFormProps) { sectionKey: key, label: meta.label, description: meta.description, + showHeader: activeSection == null, node, nodeValue: value[key], path: [key], diff --git a/ui/src/ui/views/config.browser.test.ts b/ui/src/ui/views/config.browser.test.ts index ae7de0a5c93..6c46caaa120 100644 --- a/ui/src/ui/views/config.browser.test.ts +++ b/ui/src/ui/views/config.browser.test.ts @@ -349,7 +349,80 @@ describe("config view", () => { (input as HTMLInputElement).value = "gateway"; input.dispatchEvent(new Event("input", { bubbles: true })); expect(onSearchChange).toHaveBeenCalledWith("gateway"); + }); + it("shows section hero and hides nested card header in single-section form view", () => { + const { container } = renderConfigView({ + activeSection: "auth", + schema: { + type: "object", + properties: { + auth: { + type: "object", + properties: { + authPermanentBackoffMinutes: { + type: "number", + }, + }, + }, + }, + }, + formValue: { + auth: { + authPermanentBackoffMinutes: 10, + }, + }, + originalValue: { + auth: { + authPermanentBackoffMinutes: 10, + }, + }, + }); + + const heroTitle = container.querySelector(".config-section-hero__title"); + expect(heroTitle?.textContent?.trim()).toBe("Authentication"); + expect(container.querySelector(".config-section-card__header")).toBeNull(); + }); + + it("keeps card headers in multi-section root view", () => { + const { container } = renderConfigView({ + schema: { + type: "object", + properties: { + auth: { + type: "object", + properties: {}, + }, + gateway: { + type: "object", + properties: {}, + }, + }, + }, + formValue: { + auth: {}, + gateway: {}, + }, + originalValue: { + auth: {}, + gateway: {}, + }, + }); + + expect(container.querySelectorAll(".config-section-card__header").length).toBeGreaterThan(0); + }); + + it("clears the active search query", () => { + const container = document.createElement("div"); + const onSearchChange = vi.fn(); + render( + renderConfig({ + ...baseProps(), + searchQuery: "gateway", + onSearchChange, + }), + container, + ); const clearButton = container.querySelector(".config-search__clear"); expect(clearButton).toBeTruthy(); clearButton?.click();