Skip to content

feat(ui): implement filter density tiers, mobile route deduplication, favourites timestamps, and answer notice (#309, #281, #339, #165) - #2074

Merged
BigSimmo merged 23 commits into
mainfrom
gemini/ui-filter-density-mobile-polish
Aug 18, 2026
Merged

feat(ui): implement filter density tiers, mobile route deduplication, favourites timestamps, and answer notice (#309, #281, #339, #165)#2074
BigSimmo merged 23 commits into
mainfrom
gemini/ui-filter-density-mobile-polish

Conversation

@BigSimmo

@BigSimmoBigSimmo commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • Filter density tiers (chore(deps): bump @next/env from 16.2.9 to 16.2.10 #309):ResultFilterFacetChips (src/components/clinical-dashboard/result-filter-control.tsx) now renders three density tiers instead of two: ≤5 options stay as wrapping chips, 6–20 options render as a dense full-width vertical list with a right-aligned count column and group headings, and >3 groups or >20 options additionally add find-a-filter plus collapse-by-default chrome. docs/filter-contract.md §5 is updated to document the new thresholds. Adds src/components/search/ResultFilterSheet.tsx as a thin client re-export of the shared facet-chip primitives.
  • Mobile route dedup (fix(db): reconcile live database drift and harden security without RAG regression #281):DocumentViewer.tsx gives the in-flow DocumentClinicalSummary card a canonical id="source-summary-card" and scroll-margin offset; document-rail-panels.tsx hides the rail's duplicate high-yield summary panel on phones (max-sm:hidden) so the phone document route no longer renders two clinical-summary surfaces. use-section-spy.ts gets a source-summary anchor alias so in-page navigation still resolves to the visible copy.
  • Favourites timestamps (Ingestion concurrency + scale review (phases 1-2); fixes held for db-reliability #339): New src/components/favourites/favourites-storage.ts centralizes "last opened" timestamps and pinned-item ids in localStorage, with a single shared storage-event listener (avoiding an O(N²) fan-out across subscribers) and safe fallbacks for SSR/quota errors. favourites-command-library-page.tsx consumes it via useSyncExternalStore. Covered by tests/favourites.test.ts.
  • Answer notice (**<sub><sub>![P2 Badge](https://img.shields.io/badge/P2-yellow?style=flat)</sub></sub> Preserve client-error status for malformed upload bodies** #165):answer-status.tsx's shared empty state now renders a ModeHomeVerificationFooter ("Clinical decision support — verify against cited sources before clinical use") on the answer mode home, replacing a comment that explained why no notice was there.
  • Adds tests/filter-contract.dom.test.tsx and tests/filter-contract.test.ts for the new density-tier behaviour.

Follow-up commits after the initial push (c132a10, 3a6c202, a98c42e) repaired CI blockers, fixed a duplicate DOM id under density tiers, and fixed the favourites O(N²) callback / hydration-mismatch issue. This handoff additionally fixed three problems the mobile-dedup change (#281) left behind, each caught by a subsequent CI run:

  • Prettier formatting (2b1ba0c): favourites-command-library-page.tsx failed the Static PR checksformat:changed job.
  • Print visibility (09761d8): max-sm:hidden on the rail's high-yield summary panel also suppressed it during print emulation at phone viewport widths (the print stylesheet only restores overflow/box-shadow, never display). Added print:block, the same pattern already used in verification-notice.tsx and medication-considerations.tsx.
  • Stale test assertion (fb6bf13): after the print fix let the test proceed further, document viewer content disclosures are naturally closed and mutually exclusive by default still failed one line later — it asserted the rail's <details id="source-summary"> opens after clicking the "High-yield summary" nav row at a 390px viewport. That's superseded behaviour: jumpToDocumentSection already resolves the displayed copy of a section (via the source-summarysource-summary-card alias this same PR added to use-section-spy.ts), so on phones it correctly scrolls to the visible in-flow card instead of toggling the now-hidden rail accordion. Updated the assertion to check the card scrolls into view, matching the pattern already used for the "Indexed source text" row directly above it.

Verification

  • Reproduced all three CI failures from CI logs before fixing, and each subsequent CI run progressed further into the same test until it passed the newly-fixed step — i.e. these were verified as the actual blocking failures, not guessed at:
    1. Prettier format:changed on favourites-command-library-page.tsx.
    2. Production UI Playwright failure at tests/ui-smoke.spec.ts:4868 (print visibility).
    3. Production UI Playwright failure at tests/ui-smoke.spec.ts:4889 (stale accordion-open assertion), surfaced only after fixBump actions/setup-node from 4 to 6 #2 let the test run further.
  • Ran the CI-adjacent static checks locally against this branch: docs:check-index, docs:check-inventory, docs:check-scripts, docs:check-links, check:type-scale, check:icon-scale, and npx prettier --check on every changed file all pass. sitemap:check could not be run in this environment (missing tsx devDependency locally, no npm ci performed) — this PR does not add or move any routes, so drift risk is low, but CI's own Site map drift job will still catch it if wrong.
  • git merge-tree --write-tree origin/main <head> produces a clean tree with no conflict markers throughout this handoff — no real content conflict at any point; GitHub's "blocked" mergeable state reflected pending/failing required checks, not a merge conflict. The branch was also auto-synced with main by existing repo automation partway through (merge commit 09bb336), which is expected and unrelated to the above.
  • Full verify:pr-local/verify:cheap were not re-run locally in this pass (no local toolchain install in this environment); rely on the CI run against the pushed fix commits for that evidence.

Risk and rollout

  • Risk: Low — UI/behavioural change scoped to filter rendering, phone document-summary de-duplication, favourites timestamp storage, and one static notice string. No API, schema, ingestion, or answer-generation code is touched.
  • Rollback: Revert the merge commit; favourites-storage.ts only touches a namespaced localStorage key, so no server-side state to unwind.
  • Provider or production effects: None.

Clinical Governance Preflight

Not applicable in the strict sense — no ingestion, answer-generation, retrieval/ranking, or document-access code changed. The one clinical-facing string added (ModeHomeVerificationFooter on the answer mode home) reinforces, rather than weakens, the existing "verify against cited sources" posture. pr-policy did not classify this diff as clinical-risk.

Notes

  • 2b1ba0c and 09761d8 are non-behavioural (formatting; a one-class print-only CSS addition). fb6bf13 only updates a test assertion to match behaviour this PR's own use-section-spy.ts alias mechanism already implements — it does not change any production code.

@supabase

supabaseBot commented Aug 17, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in:38 minutes

Limit details: You’ve used all 1 included review currently available under your plan. You completed 100 included PR reviews in the past 7 days; at that activity level, included reviews refill at 1 review per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c22a728a-54e2-4826-9b81-a6819c24bfc3

📥 Commits

Reviewing files that changed from the base of the PR and between 844c001 and 3c3609e.

📒 Files selected for processing (13)
  • docs/filter-contract.md
  • src/components/DocumentViewer.tsx
  • src/components/clinical-dashboard/answer-status.tsx
  • src/components/clinical-dashboard/favourites-command-library-page.tsx
  • src/components/clinical-dashboard/result-filter-control.tsx
  • src/components/document-viewer/document-rail-panels.tsx
  • src/components/document-viewer/use-section-spy.ts
  • src/components/favourites/favourites-storage.ts
  • src/components/search/ResultFilterSheet.tsx
  • tests/favourites.test.ts
  • tests/filter-contract.dom.test.tsx
  • tests/filter-contract.test.ts
  • tests/ui-smoke.spec.ts

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@BigSimmo
BigSimmo enabled auto-merge (squash) August 17, 2026 18:17
@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

CI triage

CI failed on this PR. Automated classification of the 2 failed job(s):

  • Production UI (1)needs investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

Compared with main CI run #11820 (cancelled).

Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger.

@BigSimmo
BigSimmo requested a lite review from CopilotAugust 18, 2026 02:02

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the search UI/filtering and favourites experience by introducing density tiers for filter facets, a shared filter-sheet export surface, and client-side favourites “last opened” / pinned state, plus a small document viewer anchor adjustment and an answer-mode verification notice.

Changes:

  • Add density-tier rendering for filter facet options (chips vs dense full-width rows) and document the contract.
  • Introduce favourites localStorage-backed last-opened timestamps + pinned IDs, and integrate them into the favourites command library UI.
  • Add contract tests covering filter exports, density tier behavior, and favourites storage behavior.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
tests/filter-contract.test.tsAdds a structural/contract test asserting filter exports, density-tier detection, and documentation text.
tests/filter-contract.dom.test.tsxAdds DOM-level tests for facet density tier rendering, disclosure chrome, and lens radio behavior.
tests/favourites.test.tsAdds unit tests for favourites localStorage persistence, formatting, and scoring.
src/components/search/ResultFilterSheet.tsxAdds a search/-scoped re-export surface for the filter sheet and related helpers/types.
src/components/favourites/favourites-storage.tsIntroduces the favourites localStorage store (timestamps + pinned IDs) and subscription mechanism.
src/components/clinical-dashboard/favourites-command-library-page.tsxIntegrates favourites store state into command items and records “opened” timestamps on interactions.
src/components/clinical-dashboard/result-filter-control.tsxImplements density tier detection and dense list rendering for 6–20 facet options.
docs/filter-contract.mdUpdates the documented filter density tiers and thresholds.
src/components/DocumentViewer.tsxAdds a dedicated source-summary-card anchor id and scroll margin for the in-flow summary.
src/components/document-viewer/use-section-spy.tsAdds an anchor alias so the section spy can resolve the correct rendered copy per breakpoint.
src/components/document-viewer/document-rail-panels.tsxHides the rail summary panel on small screens to avoid duplicate rendered sections.
src/components/clinical-dashboard/answer-status.tsxAdds an answer-mode verification footer (“Verify against cited sources before clinical use”).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadsrc/components/favourites/favourites-storage.ts Outdated
Comment threadsrc/components/clinical-dashboard/favourites-command-library-page.tsx Outdated
@BigSimmo

Copy link
Copy Markdown
OwnerAuthor

@copilot Fix the code for all comments in this review thread.

When a review comment includes a suggested change, apply the suggestion exactly.

Do not make changes beyond what is described in the linked review thread.

…n useSyncExternalStore
Co-authored-by: BigSimmo <87357024+BigSimmo@users.noreply.github.com>
auto-merge was automatically disabled August 18, 2026 02:17

Head branch was pushed to by a user without write access

CopilotAI commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

@copilot Fix the code for all comments in this review thread.

When a review comment includes a suggested change, apply t...

Both issues addressed in commit fix(favourites): fix O(N²) storage callbacks and hydration mismatch in useSyncExternalStore:

  1. O(N²) storage callbacks (favourites-storage.ts): Replaced the per-subscriber storage event handler (which called notifyListeners() and fired all N listeners per event) with a single shared module-level handler via ensureSharedStorageListener(). One storage event now calls notifyListeners() exactly once. The subscribe function just adds/removes from the listener set.

  2. useSyncExternalStore hydration mismatch (favourites-command-library-page.tsx): Replaced loadFavouriteLastOpened/loadFavouritePinnedIds as getServerSnapshot with stable empty values (() => ({}) and () => new Set<string>()). SSR now produces deterministic markup; the client fills in localStorage state after hydration.

@BigSimmo
BigSimmo enabled auto-merge (squash) August 18, 2026 02:19
@BigSimmo
BigSimmo disabled auto-merge August 18, 2026 02:26
@BigSimmoClaude

Copy link
Copy Markdown
OwnerAuthor

Overlap advisory (part of a cross-PR conflict sweep — no code changes made here beyond syncing this branch with main).

This branch overlaps with #2040: #2040 folds a new service-group facet into /services that renders through ResultFilterFacetChips in result-filter-control.tsx, which this PR rewrites. This is a behavioral collision, not a textual one, so it won't show up as a merge conflict — whichever of #2040/#2074 merges second should manually re-check the facet chips UI on /services afterward.

This branch was just rebased onto the latest main (which now includes the already-merged #2072 and #2076) as part of this sweep, so it's current as of this comment.


Generated by Claude Code

CI's format:changed check was failing on this file's useSyncExternalStore
formatting.
@BigSimmoBigSimmo changed the title feat(ui): implement filter density tiers, mobile route deduplication,…feat(ui): implement filter density tiers, mobile route deduplication, favourites timestamps, and answer notice (#309, #281, #339, #165)Aug 18, 2026
BigSimmoand others added 5 commits August 18, 2026 11:05
`max-sm:hidden` (added to dedupe the summary panel on phone viewports)
also suppressed it during print emulation at narrow viewport widths,
since the print stylesheet only restores overflow/box-shadow and never
overrides display:none. Add `print:block`, the pattern already used
elsewhere in this codebase (verification-notice.tsx,
medication-considerations.tsx) to keep a responsively-hidden element
printable.
Fixes the "document viewer content disclosures are naturally closed
and mutually exclusive by default" Production UI failure, which set a
390px viewport and asserted the high-yield-summary content becomes
visible under print media.
The exclusive-accordion assertions after clicking the "High-yield
summary" section-nav row assumed the rail's <details id="source-summary">
still opens on a 390px viewport. Since the mobile route-dedup change
hides that rail copy (max-sm:hidden) in favour of the always-visible
in-flow DocumentClinicalSummary card, jumpToDocumentSection's existing
"displayed copy" resolution (use-section-spy.ts's source-summary ->
source-summary-card alias) now scrolls to the card instead of toggling
the hidden accordion — so `summary.open` never becomes true at this
viewport. Assert the visible copy scrolls into view instead, matching
the pattern already used for the "Indexed source text" row above it.
@BigSimmo
BigSimmo enabled auto-merge (squash) August 18, 2026 04:57
@BigSimmo
BigSimmo disabled auto-merge August 18, 2026 05:05
@BigSimmo
BigSimmo enabled auto-merge (squash) August 18, 2026 05:05
@BigSimmo
BigSimmo merged commit 6b72b3a into mainAug 18, 2026
27 checks passed
@BigSimmo
BigSimmo deleted the gemini/ui-filter-density-mobile-polish branch August 18, 2026 05:12
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@BigSimmo@claude