Skip to content

feat(priority): pin metrics to a Pinned section at the top of Priority - #1553

Merged
robinebers merged 3 commits into
mainfrom
feat/pin-metrics-priority
Nov 3, 2026
Merged

robinebers merged 3 commits into
mainfrom
feat/pin-metrics-priority

Conversation

@robinebers

@robinebers robinebers commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

TL;DR

Every metric row on an account's page gets a pin beside its show/hide switch. Pinned metrics, from every account, get their own Pinned section at the top of the Priority tab.

What was happening

What this changes

  • Pin button. Each metric row on the account page has an SF Symbol pin / pin.fill button just left of the switch, styled like the row's drag handle. No tooltip. It is disabled while the metric is hidden.
  • Saved per account and metric. Pins live in the layout under priorityPinIDs, next to the hidden metrics from feat(accounts): hide and reorder an account's metrics from its page #1540, so they survive a restart and take part in ⌘Z undo. Hiding a metric unpins it, and showing it again does not bring the pin back. Pins of a removed account are dropped the same way its hidden metrics are.
  • Pinned section. Priority opens with Pinned when anything is pinned, listing every pinned metric in dashboard order: the saved account order, then each account's metric order. Rows reuse the Running Out row (ring, title, account name, amount, reset), coloured by the metric's own level. A pinned metric is not listed again under Running Out or Used Up. With no pins the section doesn't exist.
  • Pinned colours and copying. A pinned metric's ring uses Priority's own colour rule, so a pinned $0 balance stays red. Copy Priority Screenshot also shows when the tab lists only pins.
  • All Clear row. The board now decides whether the small "All Clear" row shows (showsClearRow, which replaces hasCompleteUsage, its only reader). It counts pinned limits, so a pinned limit that is running out keeps All Clear away, the same as it would unpinned.
  • README, docs/dashboard.md, docs/accounts.md, and CHANGELOG describe pinning.

Heads-up

  • Used-up pins show as limit rows. Robin asked for pins to look like the existing Priority rows. A pinned limit that's used up, or a pinned balance at $0, shows in Pinned as an empty ring with 0% left or $0 left and its reset, instead of in the faded Used Up list. If Robin wants an extra red marker for that empty state, it's a small follow-up. This is the closest match to "any pinned [metric] will get its own section".
  • Pins with no data. Priority, like All Usage, skips a metric with no reading, so a pinned metric with no data doesn't appear until it has one. If an account has pins but no readings yet, Priority shows Waiting for Usage under the empty Pinned area as before.
  • The menu bar is unchanged. It still shows the limits closest to running out. Pins affect only the Priority tab, which includes the Copy Priority Screenshot picture.
  • Old star data stays ignored. The pre-feat(dashboard): rebuild the panel around Priority and All Usage #1535 menu-bar stars were saved as pinnedMetricIDs. That's why the new field has a different name: an upgrade does not turn old stars into pins (covered by a test).

Tests

New MetricPinTests covers saving per account and metric across a restart (old stars ignored), hide-unpins and hidden-can't-pin, Pinned order (account order, then metric order, never by name) with no duplicates under Running Out or Used Up, and removing an account removing its pins.

On the Mac mini (macOS 15.7.7, nice -n 10 script/test_quiet.sh --filter, one suite at a time):

  • Red: with the pinned severity taken from the raw reading and the copy button gated on .listed only, PriorityBoardTests fails twice (the empty balance colour and the pins-only copy). With showsClearRow ignoring pinned limits, the All Clear assertion fails (1 failure). With the tests only, MetricPinTests fails to compile on main. With the API present but the behaviour reverted (hiding doesn't unpin, a hidden metric can be pinned, pinned metrics stay in Running Out/Used Up, a removed account's pins are kept), it ran 4 tests with 6 failures across the hide, no-duplicate, and removal tests.
  • Green: MetricPinTests (4), PriorityBoardTests (23), PriorityDashboardTests (3), AccountMetricSettingsTests (2), LayoutPersistenceTests (3), LayoutStoreTests (10), LayoutMigrationTests (8), MenuBarContentTests (13), SignInAgainVisibilityTests (2), ShareCardRendererTests (1). All passed with 0 failures.

Screenshots

These are offscreen renders from the mini with two accounts: Claude "Personal" (Sonnet hidden) and ChatGPT "Work". After the change, Personal Session and Weekly and Work Weekly are pinned. Weekly at 24% left moves out of Running Out and into Pinned.

Before After
Account page, light
Account page, dark
Priority, light
Priority, dark

Open in Capy


Note

Low Risk
User-facing layout and Priority UI only; pin state is local persistence with no auth or fetch-path changes.

Overview
Adds metric pinning so limits you care about stay visible on the Priority tab even when they are healthy.

On each account's metrics page, a pin control beside the show/hide switch toggles persistence in layout state (priorityPinIDs, undo-aware, distinct from legacy menu-bar pinnedMetricIDs). Hiding a metric unpins it; only shown metrics can be pinned.

Priority now opens with a Pinned section (dashboard account order, then metric order) using the same row styling as Running Out, with severity from the metric's level—including used-up pins as red limit rows instead of the Used Up list. Pinned IDs are excluded from Running Out and Used Up. All Clear visibility uses new showsClearRow so pinned running-low limits still suppress it; Copy Priority Screenshot appears whenever the tab has pinned rows or a listed summary (hasRows).

Docs and changelog describe hide/pin/order behavior; MetricPinTests and PriorityBoardTests cover persistence, hide interactions, ordering, and account removal.

Reviewed by Cursor Bugbot for commit 11a5342. Bugbot is set up for automated code reviews on this repo. Configure here.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Important

Two edge cases need attention: healthy pinned metrics cannot be copied as a Priority screenshot, and pinning an exhausted balance removes its Used Up status without preserving that status in Pinned.

Reviewed changes: Reviewed the complete pinning feature, including layout persistence, dashboard classification, rendering, screenshot integration, tests, and documentation.

  • Pin controls and storage: Account metric rows gain persisted, undoable pins; hiding a metric removes its pin, and registry reload filters removed accounts.
  • Priority presentation: Pins appear in dashboard order above existing sections and are excluded from Running Out and Used Up; menu-bar selection remains unchanged.
  • Coverage and documentation: Four regression tests cover core pin behavior, and the README and behavior docs explain the feature. Changed Swift files passed syntax parsing on Linux; macOS build, tests, and UI validation could not be run here.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6-astra | 𝕏

…mits

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Important

No new issues found in this delta. The existing screenshot-availability and exhausted-balance presentation threads remain unresolved, so this is not an approval.

Reviewed changes: Reviewed 91a16cd..5a1ab0d, focusing on the revised All Clear rule and its callers.

  • Moved the All Clear decision into the board. Replaced hasCompleteUsage and the view's pin-severity check with showsClearRow, which considers running-low limits whether pinned or not.
  • Extended regression coverage. Added an assertion that pinning the remaining running-low metric does not expose All Clear, and updated the unavailable-account assertion.
  • Simplified dashboard documentation. Removed the visual comparison between Pinned and Running Out rows.
  • Validated Swift syntax. All four changed Swift files passed syntax parsing; macOS build, tests, and UI validation could not run on Linux.

Pullfrog  | Fix it ➔ | View workflow run | Using gpt-6-astra | 𝕏

…copied

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Important

Pins-only screenshot copying is fixed, but the empty-balance color fix still needs a visible zero-fraction indicator.

Reviewed changes: Reviewed 5a1ab0d..11a5342, focusing on screenshot availability and the updated severity-to-rendering path.

  • Enabled pins-only copying. Added hasRows and used it for the footer's screenshot button without changing summary classification.
  • Propagated Priority severity. Derived pinned severity from PriorityItem.Reason and passed explicit severity into the shared limit row.
  • Added regression coverage. Covered empty-balance classification and healthy-pin copying; the color assertion checks model state rather than rendered output.
  • Validated Swift syntax. All four changed Swift files passed syntax parsing. macOS build, tests, and rendering validation were unavailable on this Linux runner.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6-astra | 𝕏

@robinebers
robinebers merged commit 313213a into main Nov 3, 2026
7 of 8 checks passed
@robinebers
robinebers deleted the feat/pin-metrics-priority branch November 3, 2026 06:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant