Skip to content

feat(sidebar): add a Hide filter badge toggle for workspace options - #25245

Open
ggbdpq wants to merge 2 commits into
stablyai:mainfrom
ggbdpq:feat/hide-filter-count-badge
Open

ggbdpq wants to merge 2 commits into
stablyai:mainfrom
ggbdpq:feat/hide-filter-count-badge

Conversation

@ggbdpq

@ggbdpq ggbdpq commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

ELI5

The sidebar's Workspace options button shows a little number badge while any workspace filter is active. If you keep filters on purpose (many people do), that badge never goes away and turns into permanent visual noise. This PR adds a "Hide filter badge" switch in the same menu, so you can keep your filters and lose the badge.

What Changed

  • New persisted preference hideWorkspaceFilterBadge (default false — current behavior is unchanged), wired through the same six persistence seams as the neighboring workspace-filter preferences: shared PersistedUIState type, UI slice contract, preference actions, hydration, the persisted-UI write baseline (type + field set), and the persisted-UI writer mirror.
  • A "Hide filter badge" FilterToggleRow at the end of the Filters section of the Workspace options menu.
  • The badge render condition becomes hasAnyFilter && !hideWorkspaceFilterBadge. The button's accessible name and tooltip still report the active-filter count while the badge is hidden — screen-reader users keep the state; only the visual noise goes.

Why

The issue offers two directions: a setting to hide the badge, or a subtler dot. We implemented the toggle because it fully removes the noise for people who intentionally run filters long-term, and placing it inside the Workspace options menu — right where filters are turned on — makes it discoverable exactly where the annoyance comes from, without touching the Settings window. The dot variant can still be layered on later if the maintainers prefer it. No changes to the filter-count logic itself: the toggle is a display preference, not a filter, so it never counts toward the badge number.

Linked Issue

Fixes #25127

Visual Proof

N/A for attached media in this environment (headless run). Behavior is pinned by the new component tests: the badge renders with the default preference, disappears while "Hide filter badge" is on, and the accessible name keeps the active-filter count in both states.

Testing

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

New SidebarWorkspaceOptionsMenu.test.tsx (3 tests, red before the fix — the hide case failed with expected '2' to be null — green after). Also updated persisted-ui-write-baseline.test.ts fixture (typecheck-enforced).

Commands actually run locally (macOS): pnpm tc (exit 0), target + baseline + hydration suites via pnpm test (13 passed in the re-run), adjacent store/sidebar suites (123 passed across 7 files), npx oxlint on all touched files (0 warnings, 0 errors), verify:localization-catalogs / verify:localization-coverage (exit 0). Full pnpm test / pnpm build not run locally — CI covers them.

One incidental change: en-runtime-required.json had sendOutcomeLost out of alphabetical order (upstream commit landed without running the sync script); sync:localization-runtime-catalog moved it back — content identical, and the catalog checks fail without it.

AI Disclosure

Coding by GLM-5.3-Flash (ZCode agent), orchestrated and verified by a main agent with the same model; a human reviewed and committed the result.

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

Pure renderer UI change: no platform branches, no SSH/remote surface, no wire/compat impact, no new dependencies. Cross-client persistence is additive — the new field is optional in PersistedUIState, and older clients ignore unknown keys per the shared-state convention.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

@ggbdpq
ggbdpq requested a review from brennanb2025 as a code owner October 4, 2026 13:53

@pullfrog pullfrog Bot 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.

Caution

hideWorkspaceFilterBadge is added to PersistedUIState but not to the strict ui.set schema (UiUpdateFields), so pnpm tc fails and paired web/mobile/relay clients will reject the writer's payload. See the inline comment for the one-line fix.

Reviewed changes

  • New persisted preference hideWorkspaceFilterBadge (default false) — optional field on PersistedUIState, wired through the UI slice contract, preference actions, hydration (=== true), the persisted-UI write baseline (type + field set), and the writer mirror.
  • Badge suppression in SidebarWorkspaceOptionsMenu.tsx — render condition becomes hasAnyFilter && !hideWorkspaceFilterBadge; the accessible name and tooltip keep reporting the active-filter count.
  • New FilterToggleRow in SidebarWorkspaceFilterSection.tsx — "Hide filter badge" with an EyeOff icon, appended to the Filters section.
  • Tests + i18n — new SidebarWorkspaceOptionsMenu.test.tsx (3 tests, verified passing under config/vitest.config.ts); hideFilterBadge added to en.json; incidental alphabetical re-sort of sendOutcomeLost in en-runtime-required.json (content identical).

The persistence seams that are present are correctly wired; I verified the localization gates (verify:localization-catalogs, runtime catalog) pass and that the new test genuinely fails with the bug present. The one blocker is the missing companion schema entry below.

ℹ️ Nitpicks

  • getDefaultUIState() and getStartupErrorFallbackUI() omit the new field. Harmless today (hydration reads === true, default false), but the neighboring hideDetachedHeadWorkspaces is listed there, so adding it keeps new profiles and the startup-error fallback consistent.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/shared/persisted-ui-state-types.ts
@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 944514fd-5203-4691-a44c-ac38ec2dbd43
📥 Commits

Reviewing files that changed from the base of the PR and between ae6a886ba813cfeb4e9658fd77c5f1a57e582565 and 0dd7e64.

📒 Files selected for processing (3)
  • src/renderer/src/components/sidebar/SidebarWorkspaceOptionsMenu.tsx
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/store/slices/ui/ui-slice-preference-actions.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/src/i18n/locales/en.json

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

Adds the hideWorkspaceFilterBadge preference to UI state and persisted UI data. A sidebar toggle controls the preference. When enabled, the active-filter count badge is hidden from the Workspace options button, while the count remains in its accessible name. Tests cover badge visibility and accessible naming.

Priority: ⬇️ Low

Severity of issue fixed: Low

Merge Risk: ⚪ Minimal · up to 0dd7e

The preference hides only the visual badge while retaining the accessible filter count and is described as persisting across reloads. No concrete merge-blocking risk is evident; the change appears ready for normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 0dd7e

The setting changes badge visibility without changing workspace filtering or removing the accessible filter count. No introduced security issue was established. Compatibility with older connected hosts remains unconfirmed and could prevent a bundled preference update from saving.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The field is not classified as pairing-local, so the existing web UI-update path can carry it to the active host’s persisted UI state. The demonstrated new effect is shared badge presentation, not additional repository, credential, or execution authority.

Trust Boundaries and Controls

  • observed — The new preference uses existing UI IPC and RPC update routes. At the reviewed head, the RPC schema constrains the field to a boolean and retains strict unknown-key handling; the changed menu code adds no new privileged invocation.

Resilience and Maintainability Implications

  • observed — Existing writer failure handling settles in-flight markers without acknowledging rejected changes. Terminal rejection does not trigger an unconditional retry loop; applicable later edits can schedule another field diff. This contains transport failure but does not establish older-host compatibility.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 11 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a Hide filter badge toggle for workspace options.
Description check ✅ Passed The description covers the user impact, implementation, rationale, linked issue, testing, and checklist. The required visual proof is not attached; the stated N/A reason does not apply because this ch…
Linked Issues check ✅ Passed Issue #25127 requests a way to hide the active-filter badge without disabling filters. The PR adds the persisted hideWorkspaceFilterBadge preference, a Workspace options toggle, and a render conditi…
Out of Scope Changes check ✅ Passed The UI, persistence, RPC schema, localization label, baseline update, and tests all support issue #25127. The reviewed change summary identifies no unrelated changes.
Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 11 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
🧰 Additional context used
📚 Code guidelines (1)
AGENTS.md — auto-discovered

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@ggbdpq

ggbdpq commented Oct 4, 2026

Copy link
Copy Markdown
Contributor Author

Verified against the code — this was correct, thank you. Fixed in ae6a886ba8: hideWorkspaceFilterBadge: z.boolean().optional() now sits in ClientUiWorkspaceFilterFields, next to its neighbors. Reproduced red before the fix (tsc -b config/tsconfig.node.json --force → TS2322 ... { missingFromSchema: "hideWorkspaceFilterBadge" } at the parity assertion), green after, and swept the remaining consumers of the field for a second list to register in — none found.

One incidental finding worth flagging for reviewers: local pnpm tc stayed green the whole time — the incremental tsbuildinfo did not propagate the src/shared/persisted-ui-state-types.ts change to a re-check of ui-state-schema-parity-checks.ts, so only tsc -b --force surfaces the error. Not touching the build config in this PR, just noting it since the parity guard is the thing that makes this failure mode visible at all.

One semantic question for the maintainers: as written, the preference rides ui.set to paired devices (it is not in pairing-local-ui-fields.ts), so hiding the badge is a per-profile choice that syncs across desktop/web/mobile — same as the neighboring filter toggles. If the intent is instead that each device remembers its own badge visibility, the field should move into the pairing-local list. Happy to adjust either way.

@pullfrog pullfrog Bot 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.

✅ No new issues found.

The prior blocker is resolved: hideWorkspaceFilterBadge now spreads into the strict ui.set schema, pnpm tc:node passes, and the new component test stays green.

Reviewed changes (since the prior pullfrog review at 5493e59)

  • Registered hideWorkspaceFilterBadge in the ui.set wire schema — added hideWorkspaceFilterBadge: z.boolean().optional() to ClientUiWorkspaceFilterFields, which spreads into the strict UiUpdateFields (client-ui-params.ts:163), satisfying the parity assertion and letting paired clients persist the preference.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

ggbdpq added 2 commits October 6, 2026 06:36
The workspace options button shows a numeric badge with the active
filter count. When filters are left on intentionally, the badge never
goes away and becomes constant visual noise. Add a persisted "Hide
filter badge" row at the end of the Filters section: on = suppress the
badge only; the active-filter count stays in the button's accessible
name, so screen-reader users keep the state.

Fixes stablyai#25127

Generated-by: GLM-5.3-Flash (ZCode)
The field was added to PersistedUIState without a matching entry in
ClientUiWorkspaceFilterFields, so the parity assertion in
ui-state-schema-parity-checks fails with missingFromSchema, and paired
clients' strict UiUpdate would reject the whole batched ui.set payload.
Caught by pullfrog in review.

Note: local `pnpm tc` stays green through the incremental tsbuildinfo
cache; the red only shows under `tsc -b --force`.

Generated-by: GLM-5.3-Flash (ZCode)
@ggbdpq
ggbdpq force-pushed the feat/hide-filter-count-badge branch from ae6a886 to 0dd7e64 Compare October 5, 2026 22:40
@ggbdpq

ggbdpq commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (990b0ed): main extracted the inline badge into a shared <OptionsFilterCountBadge> component (#25376), so the hide toggle now gates that component instead of the inline span — same behavior, new structure (20 passed across the sidebar + persistence suites). One incidental drop: our earlier sendOutcomeLost alphabetical-order fix in en-runtime-required.json landed upstream with the same content, so that hunk is gone from the diff. Same CI heads-up as on #24689: pnpm tc has one pre-existing failure on clean upstream/main (structured-agent-session-stop-note-opened-turn.test.ts TS2353), unrelated here.

This branch has not been deployed

No deployments
Sign up for free to 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.

[Feature]: Option to hide the active-filter count badge on the Workspace options button

1 participant