fix(desktop): GitHub mention chips: state colors, open link, no fetch on load (SUPER-2978, SUPER-2977, SUPER-2979)

SU
12d ago
+247-173

Fixes SUPER-2978, SUPER-2977, SUPER-2979

Three fixes for links and mentions in the Chat v3 transcript, one commit each. Together: a chip is plain and loads nothing until someone hovers it, then shows GitHub's real state, and its card has a link to open it.

1. Chip colors match GitHub's state (SUPER-2978)

Problem: a pull request chip was always violet, GitHub's color for merged, so an open PR looked merged. Issue chips were always green, so a closed issue looked open.

Change:

  • GithubWorkItemChip gets its color from the item's state, not its kind. It stays neutral until the state is known, then:
    • open → green
    • merged PR / completed issue → violet
    • closed PR → red
    • draft PR / not-planned or duplicate issue → grey
  • The chip reads the hover card's github.getWorkItem query from the cache (enabled: false), so it never starts a request.
  • The hover card uses the same githubWorkItemTone mapping. A closed issue now shows as completed (violet, check icon) or not planned (grey, slash icon), the way GitHub does.

Supersedes #9020 (SUPER-2980). #9020, merged to main after this PR was opened, made the PR chip always sky blue so it implied no state. This PR replaces that with the state-based colour above, and the merge conflict was resolved in favour of this version. Both avoid showing an open PR as merged.

2. Open the pull request from its hover card (SUPER-2977)

Problem: the card had nothing to click. Its footer only said "Click the chip to open…".

Change:

  • The card's title links to the PR or issue.
  • An Open on GitHub link sits at the bottom of every card, including while details load and when they are unavailable.
  • Both go through the chat pane's openLink, with target="_blank" as the fallback.
  • I removed the openHint prop and its two strings. "Open on GitHub" was already translated in every locale, so the catalog diff only removes lines.

3. No preview fetches when a transcript loads (SUPER-2979)

Problem: LinkPreviewChip, which renders the first plain link in each user message, called linkPreview.get on render, so opening a long chat fetched one preview per message.

Change: the chip shows the bare host until hovered, then reads the title and icon from the hover card's linkPreview.get({ url, image: true }) query (enabled: false).

Other places I checked: GitHub chips and links, website and Slack hover cards, chat-link previews, and composer chips already waited for a hover. Not changed: PageLinkCard still loads page.preview on render. It is the full card for a published Paradev page, not a mention, so I left it out of scope.

4. Review fixes

  • Closed draft PRs now read as closed (red), as on GitHub. Before, they showed as a grey draft.
  • Light theme: chip and card colors use the app's existing light/dark PR colors (pull-request-colors.ts, PR_STATE_INK_CLASS_NAME). The chip tints its background from currentColor, like PullRequestStatePill.
  • Code layout: the state-to-color mapping moved to utils/githubWorkItemTone/, with a pure test covering PR states, closed drafts and issue close reasons.
  • Pasted URL: the card links to the URL that was pasted (keeping /files or #issuecomment-…) and closes after you open the link.
  • Tests: they flush effects before asserting "no request on load". I checked that these tests fail if either chip is switched to fetch on render.

5. Mode picker icon alignment

In the composer's approval-mode menu (Ask for approval / Approve for me / Full access), the icons sat about 2px above their titles. The icon and check boxes were 16px tall at the top of a 20px title line; they now match the title's line height (h-5 + leading-5).

Validation

  • GithubWorkItemChip.test.tsx: the chip is neutral and makes no request before hover; it turns violet for a merged PR and green (not violet) for an open one; a failed lookup leaves it neutral; the card's title and its "Open on GitHub" link both call openLink with the PR URL.
  • UserMessageText.test.tsx: a link chip shows the host and makes no request on render; on focus it makes one request and shows the title and icon.
  • All 458 tests under ChatSession/ pass (after merging main). apps/desktop typecheck passes. Biome is clean on the changed files. bun run check:i18n reports no missing messages.
  • I have not checked this in the running app.