From 5582ec523b2cbcdfee13017bf77714f74f88198e Mon Sep 17 00:00:00 2001 From: Devvyn <22340871+opticon454@users.noreply.github.com> Date: Sun, 1 Nov 2026 10:15:17 +0800 Subject: [PATCH] fix(custom-model): fix picker spacing and the no-matches line --- src/web/public/styles.css | 18 ++++++++++++++-- test/custom-model-run-menu-ui.test.ts | 30 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/web/public/styles.css b/src/web/public/styles.css index c1647f28..01f13b2a 100644 --- a/src/web/public/styles.css +++ b/src/web/public/styles.css @@ -7809,9 +7809,14 @@ html[data-skin="og"] .welcome-primary:hover { /* The picker's search box reuses .session-sidebar-filter-input's theme-token styling (same reasoning as the .set-scope pill above) — only its own spacing - and the no-matches line are added here. */ + and the no-matches line are added here. 0.35rem is the standard gap the + modal's neighbouring form fields already use (`.form-hint`'s own margin-top): + the global `* { margin: 0 }` reset left the box sitting flush under the CLI + hint line above it, and the old 0.5rem read as too big a gap above the list + (compounded by the always-visible no-matches line the rule below fixes). */ #customModelPickModal .custom-model-pick-search { - margin-bottom: 0.5rem; + margin-top: 0.35rem; + margin-bottom: 0.35rem; } #customModelPickModal .custom-model-pick-no-matches { @@ -7819,6 +7824,15 @@ html[data-skin="og"] .welcome-primary:hover { padding: 1rem 0; } +/* Same class of bug as the row rule below: the no-matches line carries + `.form-hint`, whose `display: block` outranks the UA `[hidden]` rule, so + `filterCustomModelPick()` toggling `hidden` changed nothing on screen and + "No models match" showed while every model was listed with an empty search + box. The `[hidden]` re-assertion makes the attribute hide the line again. */ +#customModelPickModal .custom-model-pick-no-matches[hidden] { + display: none !important; +} + /* A filtered-out row's `hidden` must actually hide it: `.run-mode-option` sets `display: flex` (and mobile.css restates the class in a media query), which outranks the UA `[hidden] { display: none }` rule, so the filter would diff --git a/test/custom-model-run-menu-ui.test.ts b/test/custom-model-run-menu-ui.test.ts index 5fbd2c89..a31155da 100644 --- a/test/custom-model-run-menu-ui.test.ts +++ b/test/custom-model-run-menu-ui.test.ts @@ -654,6 +654,36 @@ describe('Custom Model Endpoint Profiles: the "which model" picker', () => { expect(rule, 'picker rows need a [hidden] rule scoped to #customModelPickModal').toBeTruthy(); expect(rule![0]).toMatch(/display:\s*none\s*!important/); }); + + it('pins "No models match" hidden with an empty query and shown only when a query hides every row, in CSS too', async () => { + // The visible symptom: the line carries `.form-hint`, whose `display: block` + // outranks the UA `[hidden]` rule, so `hidden` alone showed "No models match" + // while every model was listed with an empty search box. The attribute half + // was always right (session-ui.js's `filterCustomModelPick`); the CSS half + // needed the same `[hidden] { display: none !important }` re-assertion the + // rows above carry. This test pins both states AND the CSS that makes them + // actually render. + const rule = STYLES_CSS.match(/#customModelPickModal \.custom-model-pick-no-matches\[hidden\]\s*\{[^}]*\}/); + expect(rule, 'the no-matches line needs a [hidden] rule scoped to #customModelPickModal').toBeTruthy(); + expect(rule![0]).toMatch(/display:\s*none\s*!important/); + + const { win, app } = bootApp({ + hosts: [{ id: 'llama-box', label: 'llama.cpp', baseUrl: 'http://x', models: ['qwen3', 'llama3'] }], + }); + win.app = app; + await app.selectCustomModelEntry('claude', 'llama-box'); + const noMatches = win.document.getElementById('customModelPickNoMatches')!; + + // Empty query, models listed: the attribute must be set, and the CSS rule + // above is what makes that attribute actually hide the line. + expect(noMatches.hasAttribute('hidden')).toBe(true); + + // A non-empty query that hides every row: shown again. + const search = win.document.getElementById('customModelPickSearch') as HTMLInputElement; + search.value = 'ghost'; + search.dispatchEvent(new win.Event('input')); + expect(noMatches.hasAttribute('hidden')).toBe(false); + }); }); describe('Custom Model Endpoint Profiles: _getCustomModelCurrentlyLoaded is client-side bounded', () => {