🤖 refactor: style goal row actions as real buttons#3342
Conversation
The Archive action on completed goals (and its sibling row actions — Edit / Promote / Remove on upcoming, Revive on archived) rendered as bare text+icon links with no border, padding, or background. They looked like inline text instead of clickable controls, breaking visual consistency with the bordered Cancel / Queue-goal buttons in the same file and forcing the user to discover the affordance via hover. Factor a local RowActionButton helper that renders a bordered chip-style button with neutral / positive / destructive tones, and convert all 5 sites in GoalBoardSections.tsx. Aria-labels and click handlers are preserved. The de-emphasized 'Archive this goal' / 'Clear goal' underlined text link in GoalTab.tsx is intentionally left alone — an inline comment already documents that it's styled that way so it doesn't compete with the primary Pause / Resume / Mark complete actions above.
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
GoalBoardSections owns the Archive / Revive / Edit / Promote / Remove per-row buttons, but it has no story file of its own — and GoalTab.test.tsx mocks GoalBoardSections away — so the recent restyle to bordered chip-style RowActionButtons had zero automated visual coverage. Add a colocated GoalBoardSections.stories.tsx that: - mounts the component under a lightweight APIProvider + TooltipProvider so the section subcomponents' useAPI() calls don't throw - hand-rolls a GoalBoardSnapshot with upcoming, completed, and archived entries so every RowActionButton variant renders - pins one smoke story (FullBoard) to CHROMATIC_SMOKE_MODES so a future regression on either theme is caught by Chromatic - splits the remaining sections into focused stories (UpcomingOnly / CompletedOnly / ArchivedOnly / EmptyBoard) so individual surfaces are reviewable in isolation
|
@codex review Added storybook coverage for the goal row-action buttons ( |
|
Codex Review: Didn't find any major issues. Delightful! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Replace the standalone GoalBoardSections story with a full-tab `CompleteWithBoard` story so the row Archive button (and its RowActionButton siblings — Revive / Promote / Remove / Edit) render in context alongside the goal header, budget tile, and de-emphasized 'Archive this goal' link. GoalTab only mounts GoalBoardSections when `workspaceId` is set, and the board reaches the renderer through `useGoalBoard → api.workspace .getGoalBoard`. To populate that path in storybook: - Add a `goalBoardSnapshots: Map<workspaceId, GoalBoardSnapshot>` option to `createMockORPCClient`; `getGoalBoard` returns the seeded snapshot for the calling workspace or falls back to empty entries. - Wrap the new story in an `APIProvider` decorator backed by the mock client, with one upcoming / one completed / one archived entry. - Tag the story with `CHROMATIC_SMOKE_MODES` so the restyle gains dual-theme baseline coverage in Chromatic. `GoalTab.test.tsx` still mocks GoalBoardSections away, so this is the only automated visual surface for the row-action buttons.
|
@codex review Replaced the standalone |
|
Codex Review: Didn't find any major issues. Breezy! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Previously the 'Archive this goal' / 'Clear goal' affordance on the active-goal card was rendered as an underlined muted text link with an inline comment justifying the de-emphasis. With the rest of the goal tab's Archive controls now sharing a chip-style RowActionButton, the text-link variant was the last remaining link-vs-button anti-pattern on the surface and stood out in the new Chromatic baseline. Export RowActionButton from GoalBoardSections.tsx and reuse it here. The action stays visually de-emphasized relative to Pause / Resume / Mark complete by virtue of the smaller chip size and its position below the primary action row. Inbox icon for 'Archive this goal' matches the row Archive button in CompletedSection (which calls the same archiveGoal endpoint); Trash2 for 'Clear goal' mirrors Remove in UpcomingRow. The GoalTab test that previously asserted on the legacy 'underline' className is updated to assert the meaningful behavioral guard (no primary 'bg-accent' background) instead of the now-stale implementation detail.
|
@codex review Followed up: the "Archive this goal" affordance on the active-goal card now uses the same |
|
Codex Review: Didn't find any major issues. Breezy! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Previously a completed goal showed the green-tinted Reopen as the only 'main' action and Archive as a small chip below — but the user-intent hierarchy is the opposite: when a goal is finished, filing it away is the obvious next step, and Reopen is the rare recovery affordance for goals the agent declared done too eagerly. Restructure the action row so that when `lifecycle === "complete"`: - Reopen sits on the left with the neutral border style used by Pause / Mark complete; it stays available but no longer looks like the primary action. - Archive sits to the right of Reopen with the accent fill used by Save / Set goal; both buttons share the `px-3 py-1.5 text-sm` sizing of the rest of the action row so they read as peers. The `canResume` branch is narrowed to non-complete lifecycles to avoid double-rendering Reopen, and the underlined-link/chip 'Archive this goal' below the action row is dropped for completed goals (Clear stays as a chip for lifecycle-active goals — destructive for an in-flight goal, deserves de-emphasis). The GoalTab test that previously asserted on the legacy 'underline' className was already updated last commit; tighten it further to assert the new primary/secondary hierarchy (`bg-accent` on Archive, neutral on Reopen) and the absence of 'Clear goal' wording for completed goals.
|
@codex review Followed up: on completed goals, Archive now sits to the right of Reopen as the accent-colored primary action (filing is the obvious next step), while Reopen is demoted to the neutral border style as the secondary recovery path. Both buttons share the row's |
|
Codex Review: Didn't find any major issues. 🚀 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Summary
Make the Goal tab's Archive controls visually consistent with the rest of the tab, and reshape the completed-goal action row so Archive is the primary action and Reopen the secondary — matching user intent (a finished goal usually wants to be filed, only rarely reopened).
Background
Three layers of inconsistency lived on the Goal tab:
Per-row controls in
GoalBoardSections.tsx— Edit / Promote / Remove / Archive / Revive all rendered as bare<button>s with onlytext-muted+ a small icon. They read as inline text labels rather than clickable controls and were inconsistent with the bordered Cancel / Save / Queue-goal buttons in the same file.Active-goal "Archive this goal" link in
GoalTab.tsx— rendered as an underlined muted text link with an inline comment justifying the de-emphasis. After the row controls became buttons, this stood out as the last remaining text-link on the surface.Completed-goal action hierarchy was inverted — Reopen rendered with the green "primary" tint and Archive lived as a small chip on a separate line below. But filing a finished goal is the obvious next step; reopening is the rare recovery path when the agent declared done too eagerly.
The existing
GoalTab.test.tsxmocksGoalBoardSectionsaway entirely, and no existing GoalTab story setworkspaceId, so the row Archive button had no automated visual coverage either.Implementation
Row buttons (
GoalBoardSections.tsx)Added a small
RowActionButtonhelper (exported soGoalTab.tsxcan reuse it for the active-goal Clear). Renders a bordered chip-style<button>with atoneprop (neutral/positive/destructive) that tints hover color + background:neutral— Edit / Archive (row) / Revive / Clear goal (active lifecycle)positive— Promote (upcoming → active)destructive— Remove (drops the goal from the board)Converted all 5 row sites. Aria-labels, click handlers, and goal-context interpolation are preserved verbatim.
Completed-goal action row (
GoalTab.tsx)Restructured
{canEdit && <div>…</div>}so that whenlifecycle === "complete":border-border-light bg-surface-secondary text-foreground). Still available — just no longer looks like the primary action.bg-accent text-accent-foreground hover:bg-accent-dark) used by Save / Set goal. Samepx-3 py-1.5 text-smsizing as the rest of the row so the two buttons read as peers, not as a chip-style afterthought.The
canResumebranch is narrowed to non-complete lifecycles to avoid double-rendering Reopen, and the chip-style "Archive this goal" below the action row is dropped for completed goals. Clear stays as a chip for lifecycle-active goals (destructive on an in-flight goal — deserves de-emphasis).Story coverage
Added a
CompleteWithBoardstory toGoalTab.stories.tsxthat renders the full tab with upcoming + completed + archived board entries so the new Reopen + Archive pair, the budget tile, the goal header, and every row-action button variant are all visible in one snapshot.GoalTabonly mountsGoalBoardSectionswhenworkspaceIdis set, and the board reaches the renderer throughuseGoalBoard → api.workspace.getGoalBoard. To populate that path:goalBoardSnapshots: Map<workspaceId, GoalBoardSnapshot>option tocreateMockORPCClient.getGoalBoardreturns the seeded snapshot for the calling workspace, or falls back to empty entries.APIProviderdecorator backed by the mock client.CHROMATIC_SMOKE_MODESfor dual-theme baseline coverage.Tests
Tightened the existing
clear controlGoalTab test to assert the new primary/secondary hierarchy (bg-accenton Archive, neutral on Reopen) and the absence of "Clear goal" wording for completed goals, instead of the oldunderlineclassName.Validation
make typecheck,make lint,make fmt-check,make static-check,make storybook-build— all green.bun test src/browser/features/RightSidebar/— passes.bun test ./tests/ui/storybook/coverage.test.ts— passes.Risks
Low. Visual restyle + reordering of buttons inside a single component plus a new Storybook story and an additive option on the mock orpc client. No backend, IPC, or business-logic changes. Both completed-goal actions still route through the same backend endpoints they did before (
workspace.setGoal({ status: "active" })for Reopen,workspace.archiveGoalfor Archive). Aria-labels are preserved for screen-reader behavior.Generated with
mux• Model:anthropic:claude-opus-4-7• Thinking:max• Cost:$3.20