- pages_v3: include Durations tab in the search index so
setting-durations-* fields are actually indexed
- test_web_settings_ui: assert setting-durations-clock is present in
the search-index endpoint response
- settings-search.js: on index fetch failure, reset buildPromise
instead of caching an empty (truthy) index so search can retry
- settings-search.js: filterScope returns null (not document) when no
tab container matches, and the caller guards, so the per-tab filter
can't hide fields across unrelated tabs
- settings-search.js: refresh the stale header comment to describe the
server-side JSON index flow
- app.css: cap #settings-search-results height with overflow-y so the
dropdown scrolls instead of overflowing small screens
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gZxznuxw8L92FUMBN3Nqz
Move index building off the client so there is no client-side HTML fetching
or DOM parsing (resolves Codacy's variable-fetch and DOMParser flags on the
read-only, same-origin index build).
- Add GET /v3/settings/search-index (pages_v3.py): renders the settings
partials server-side and extracts each field's anchor id, key, label,
tooltip, and section with a small stdlib HTMLParser, then caches the result
keyed on the installed-plugin set. Parsing the rendered HTML keeps anchor
ids identical to the live DOM, so the index cannot drift.
- settings-search.js: buildIndex() now does a single fetch of the literal
endpoint + .json(); removed the per-partial fetch loop, DOMParser, scanDoc,
CORE_TABS, and the plugin-id allowlist. Search, keyboard nav, navigation,
and the per-tab filter are unchanged.
Net: fewer requests and no client-side HTML parsing. Verified with a new
endpoint test in test_web_settings_ui.py (12 pass) and the headless-Chromium
test (tooltip, filter, search navigate + flash all green).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gZxznuxw8L92FUMBN3Nqz
Help users quickly find settings and understand how each one works.
Tooltips: a new delegated controller (static/v3/js/tooltips.js) drives an
accessible (i) info tooltip that appears on hover, keyboard focus, and tap.
A shared `help_tip` Jinja macro (partials/_macros.html) emits the trigger;
the plugin config macro and the core settings partials now surface help
text through it. Per the design, the always-visible field help paragraphs
are folded into the tooltip to declutter the forms, and the hardware/display
settings carry authored detail (default, range, recommendation).
Search: a global header search box finds settings across every settings tab
— even ones not yet opened — via a lazy client-side index built by scanning
the same field markup (static/v3/js/settings-search.js). Selecting a result
switches tabs, waits for the field to load, then scrolls to and flashes it.
A per-tab filter box hides non-matching fields on the current tab.
Plugin settings get tooltips for free by reusing each field's schema
`description`; every settings field also gets a stable `setting-<tab>-<key>`
anchor id for search navigation.
Styling uses the existing --color-* theme vars so light/dark mode both work,
and honors prefers-reduced-motion. Adds Flask render smoke tests that assert
each settings partial ships tooltips, anchors, and a filter box.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gZxznuxw8L92FUMBN3Nqz