feat(desktop): every sidebar card can be dismissed, and no em dashes in desktop UI

Merged
KI
1h ago
+2798-2668

Links

Summary

  1. Every sidebar card can be dismissed. The "Pro ended" / "Payment failed" card had no close button. It now dismisses per state and invoice. SidebarCardEntry.onDismiss is required, so a new card can't ship without one.
  2. One dismiss button and a quieter warning style. Plain sidebar cards use the release-notes card's hover − button. The payment card drops its gold outline: a warning-toned badge is now its only urgency signal.
  3. No em dashes in desktop UI copy. 87 strings in 68 files, with translations carried over to the re-keyed messages in all 18 locales.

How to review: three commits. Read 4a07b7a (cards, ~7 files) first, then skim c463aab (string edits). d0c1044 is the catalogs only.


Part 1: Dismissible sidebar cards

Why

The sidebar card slot showed a "Pro ended: $20.00 unpaid" card with no way to close it. Every other card (setup scripts, getting started, release notes, hiring) was already dismissible.

How

  • usePaymentFailedCard saves dismissals in a new payment-failed-card-dismissals store (built on createDismissalsStore, registered in the persisted-key registry). The key is <past_due|lapsed>:<invoiceId>, so a new failed charge, or a move from "Payment failed" to "Pro ended", shows the card again. Sends payment_failed_banner_dismissed.
  • SidebarCardEntry.onDismiss is required. The payment card was the only entry without it.
  • SidebarCard (packages/ui): the always-visible × on plain cards is now the hover-revealed − the image (release-notes) card uses. New optional tone="warning" colors only the badge, using the same tint as the billing page's PaymentFailedBanner.

Design decisions

  • Badge tone instead of a colored border: the outline was loud without saying anything. One small cue keeps the card calm but distinct from promo cards.
  • Dismiss per invoice, not forever: the card was non-dismissible because orgs had lost Pro without ever seeing a warning. Scoping the dismissal to one state of one invoice means a new billing problem always resurfaces.

Part 2: Em dashes out of desktop UI strings

One rule per pattern so the same kind of text reads the same way everywhere:

PatternBecomesExample
Status + detailcolonPro ended: $20.00 unpaid, Ports: 3 live
Two clausesperiodCopy your key now. You won't be able to see it again.
Name pairmiddle dotnotification titles, window title, PR #12 · title
Short asidecommaon mac-mini, won't run here

Unchanged on purpose: the lone — empty-cell placeholder in tables, log messages, code comments, and headings in prompts sent to agents. Web, mobile, marketing, CLI output and server error messages are not swept here.

Catalogs: editing English re-keys a message, so 68 messages needed new entries per locale. Each old translation was reused, with its dash converted the same way the English was (full-width punctuation for ja/zh, a spaced colon for fr). Translations that never used a dash were copied as they were. The catalog integrity test caught 5 placeholders the first pass had capitalized ({failedLabels}); those are fixed.


Manual QA Checklist

Dev desktop app over CDP. The org's billing is healthy, so a lapsed plan and a $20 invoice were seeded into the React Query cache. The hover and click used real mouse input.

  • Lapsed card renders "Pro ended: $20.00 unpaid" with a warning-toned badge and a plain border
  • Hovering the card reveals − (opacity 0 to 1)
  • Clicking − removes the card and stores lapsed:in_fake_1
  • Reload with the same invoice: card stays hidden
  • A different invoice id: card comes back
  • The − button on the setup-script, getting-started and hiring cards (same component, not checked on screen)
  • Translated strings in a non-English locale (checked through the catalogs and tests only)

Testing

  • bun run check:i18n: passes
  • bun test in packages/i18n: 169 pass (catalog integrity included)
  • bun test src in apps/desktop: 9464 pass, 39 fail. The failures are environmental (tests that create real git repos, read the shell environment, or run the native-messaging host) and don't involve UI strings. Not compared against main.
  • tsc --noEmit in apps/desktop: no errors in touched files (the worktree has the usual route-tree and path-casing noise)
  • Biome: clean

Known Limitations

  • "Restart Pro" goes to Settings → Billing, where a lapsed org sees a generic "Upgrade to Pro" card with no mention of the lapse or the unpaid invoice. CTA and billing-page copy are left for a follow-up.
  • The payment card's English strings were never wrapped in Lingui; still the case.
  • The new dismissals store grows by one entry per dismissed invoice. Each entry is tiny, but nothing prunes old ones.

Summary by cubic

Every sidebar card can now be dismissed, and em dashes are replaced in desktop UI copy. The "Pro ended" / "Payment failed" card previously had no way to dismiss it; it now dismisses per billing state and invoice, so a new failed charge or the move to "Pro ended" shows it again. SidebarCardEntry.onDismiss is now required.

Dismissible sidebar cards

  • Plain cards use the release-notes card's hover-revealed − button; the payment card's gold outline is replaced with a warning-toned badge.
  • Dismissal keeps only the last <past_due|lapsed>:<invoiceId> entry; with no invoice id the dismissal lasts just for the session, so a later, different failure still shows the card.
  • The hook subscribes to the stored dismissed state so dismissing removes the card immediately. Dismissing sends payment_failed_banner_dismissed.

No em dashes in desktop UI copy

  • 87 strings in 68 files switch to a consistent pattern: colon for status + detail, period for two clauses, middle dot for name pairs, comma for short asides.
  • Trailing punctuation is trimmed from error text before appending ". Click to retry" or ". Try the Paradev tray menu…".
  • Re-keyed messages have existing translations carried over in all 18 locales, with doubled punctuation collapsed in zh-CN/zh-TW; empty-cell — placeholders, log messages, comments, and agent prompt headings are unchanged.

Summary by CodeRabbit

  • UI Updates
    • Updated punctuation and separators across desktop messages, labels, tooltips, and notifications.
    • Updated translations to match revised interface text, including status and guidance messages.
  • Billing
    • Payment warning cards use warning styling and can be dismissed. Dismissal is remembered for the matching invoice when available; otherwise, it applies for the current session.