Skip to content

feat(mobile): long-press a workspace to see its linked PR, issues and notes - #29225

Merged
Jinwoo-H merged 150 commits into
mainfrom
feat/phone-workspace-details
Oct 16, 2026
Merged

Jinwoo-H merged 150 commits into
mainfrom
feat/phone-workspace-details

Conversation

@Jinwoo-H

@Jinwoo-H Jinwoo-H commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 7 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​640 $\color{#cf222e}{\Huge{\mathbf{−}}}$​13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​627
Prod 15 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​578 $\color{#cf222e}{\Huge{\mathbf{−}}}$​77 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​501

This PR also carries #29127 (phone Compact rows fold to one line), which is closed in favour of merging both here. See "Also included: Compact rows (from #29127)" below.

ELI5

On the desktop, hovering a workspace in the sidebar shows what it is linked to: its pull request, issues, notes, and who created it. On the phone those only appeared as tiny grey icons on the row that you could not tap. Now, long-pressing a workspace on the phone shows those details at the top of the sheet that already opens there, and you can tap a PR or issue to open it.

What Changed

Before: long-pressing a workspace opened a sheet with a small grey title, the raw branch (refs/heads/...), and Sleep / Pin / Delete. Pin used a pencil icon.

After:

  • The sheet heads with the workspace name in normal text, its short branch name underneath, and, if it was made by an automation or the Orca CLI, one quiet grey line saying so ("Created by automation “Nightly dependency bump”" / "Created from Orca CLI").
  • Below that, one group lists the linked PR or MR and every linked issue (GitHub, GitLab, Linear, Jira) with the icons the phone and desktop already use. The PR shows the same state and color as the row's badge, plus its title and checks. Tapping an item opens it in the browser. The workspace's notes follow as plain text. With nothing linked and no notes, the group is not shown.
  • The actions follow unchanged, except Pin / Unpin now use the pin icons.

Mechanism: the sheet reads only the workspace row the phone already has. It makes no requests of its own.

  • Linked items are read the way the desktop hover card reads them (the shared getWorkspaceAttachments), and the reference label ("PR Add application screenshot to README #12", "MR !3", "ENG-7") is now one shared helper the desktop card uses too, so the two cannot drift.
  • The desktop now stamps two optional fields on each listed workspace: automationName next to the existing automationCreated, and title, url and checksStatus on the existing linkedPR, taken from the GitHub cache it already uses to fill that field. Older phones ignore them; with an older desktop the sheet shows the PR by number and state and says "Created by automation" without the name.
  • One visible side effect: a change in a PR's title or checks now counts as a list change, so the phone receives a fresh list instead of an "unchanged" reply.

Why

The phone is meant to mirror the paired desktop, and the hover card is how the desktop shows these details. Long-press already opens a sheet named for the workspace, so the details need no new gesture or screen. Reading from the row keeps the sheet stateless and always in step with the row's own badge, and the few fields it needed are small, optional, and come from data the desktop already has in hand. Ports were left out at Jinwoo's call. Folder workspaces keep no long-press, as before.

Also included: Compact rows (from #29127)

Before: picking "Compact" in the phone's workspace options barely changed anything; each row kept its second line with the project, the branch or folder path, and the "Child" badge.

After: Compact on the phone matches Compact on the desktop. Each workspace is one line: status, a small framed project icon (left out when grouped by project, and for folder workspaces), the name, the PR badge and other indicators, and the terminal count. Remote (SSH or Orca server) workspaces keep a small server icon. With the new card style on, the project shows as the title icon instead of on the second line, as on the desktop. Detailed is unchanged.

Mechanism: getWorktreeCardDetails in src/shared/worktree/card-properties.ts now answers repoInTitle and metaRow. The desktop card and the phone list both read those answers, so the two layouts cannot drift. No wire or host changes.

Detailed (group by None) Compact (group by None) Compact (group by Project)

Tests: src/shared/worktree/card-properties.test.ts and mobile/src/components/WorktreeListRow.test.ts; desktop sidebar tests pass unchanged. Full write-up and review notes: #29127.

Linked Issue

N/A (internal). Supersedes #29127.

Visual Proof

Android emulator, page and test desktop both built from this branch.

Before A. Automation + Linear B. CLI + PR + Jira + issue + notes
before A B
C. Long names D. Nothing linked
C D

Testing

  • Host: tests for the new row fields (automation name, blank name omitted, PR title/link/checks and nothing else from the cache) and for the shared reference label.

  • Phone: model tests (ordering, older hosts without linkedItems, dedupe matching the desktop, matching the branch PR by number, unsafe links never opened, a same-numbered PR from another repo kept apart from the branch PR) and sheet tests (heading, PR with and without the new fields, tracker keys, notes, origin wording). Overlay tests cover the details sitting above the actions and the Pin / Unpin icons.

  • Mobile: tsc, tests-typecheck ratchet, oxfmt, oxlint, mobile vitest (--maxWorkers=2). Root: tc:node, tc:web, renderer sidebar tests, check:code-quality:changed.

  • rpc:diff shows only view-settings changes that come from the base branch; no recorded flow touches this sheet.

  • Manually on the Android emulator against a test desktop: the four cases above.

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

Review

Three Opus review rounds. The last one followed a "no strange wiring or state" pass that removed the sheet's own fetching in favour of the optional row fields above.

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • SSH and paired servers: nothing new is requested; the fields arrive with the rows each host already lists.
  • Backwards compatibility: the new fields are optional and additive in both directions.
  • Not verified on iOS, or with a GitLab MR title (GitLab titles come from the stored link, when the link has one).

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)

…sleeping filters

A phone created through a desktop now records whom it acted for, so the
desktop's Hide other-client workspaces filter keeps the user's own phone
workspaces (locally and on servers) and hides only other people's.
The desktop relay marks each server row its sidebar would hide, and the
rows its own browser or chat tabs keep awake; the phone applies both.
The project sections the desktop sidebar draws under Group by Project are
built from the project/setup projection, the per-host catalog fold, the
endpoint host stamp, and the section labelling and ordering rules. Move the
pure parts of each into src/shared (no behaviour change) so the paired phone
can call the same code instead of guessing the grouping.
The phone grouped Project sections by repo display name, so it merged
checkouts the desktop keeps apart (several local stablyai/orca checkouts,
or a server's copy) and split what the desktop merges. The phone now reads
each host's repo.list, project.list and projectHostSetup.list (the desktop's
own and each server's through the relay), folds them with the renderer's
shared catalog fold and projection merge, and builds sections with the
desktop's shared grouping, labelling and ordering code. Keys, labels and
Recent order equal the sidebar's; a host that predates the project lists
gets the repo-derived projection, as the desktop does.

Header colour and icon come from the section's anchor repo and rows from
their own repo by id, as on the desktop. The repo filter lists every
catalog repo by id per host instead of merging same-named repos. Group-by
labels read Project and None. project.list and projectHostSetup.list are
routed for paired phones (read-only, workspace permission).
…tab activity into the host flag

A phone now records its owner as the creator (this host for a directly
paired phone, the relaying desktop for a delegated one), so the shared rule
is unchanged and onBehalfOf is gone. The relay ORs the desktop's saved
browser/chat tabs into hasHostSidebarActivity, so the phone's status dot
follows too, and local worktree.ps counts the same signals. The old-server
fallback is removed.
…the desktop's repo order

Review fixes. The sidebar's buildOrderedGroups now calls the shared
buildProjectSections for Group by Project (notice and pending repos are
optional inputs), so desktop and phone run one function. The phone ranks
manual header order by its folded catalog order, which is each host's
repo.list order with the desktop's own repos first, as the renderer loads
them; only the desktop's cross-host manualRepoOrder (pairing-local) is
unknown to it. The projection selector is now a memo over the shared
resolver. A transient project-list failure keeps that host's last catalog;
only forbidden or method_not_found falls back to the repo-derived
projection. Catalog rows are checked on every member grouping reads, and
the parity test answers the renderer's real catalog fetch, includes a
server's own project rows, and fixes Manual and Recent orders that differ.
… of the phone fetching it

The phone fetched repo.list, project.list and projectHostSetup.list from
the desktop and every relay-ready server each minute and folded them
itself, so rows from offline or older servers fell back to repo sections
and keys moved on cold start.

The desktop renderer now publishes the inputs its own Project headers use
(state.repos in sidebar order, the projection selector's projects and
setups, projectOrderBy) on the runtime window graph it already sends to
main, only when they change. Main keeps the last one and answers it on a
new paired-desktop read, mobileRelay.projectSections. The phone reads it
with its repo metadata and groups with the shared builder; a desktop that
predates the read (forbidden or method_not_found) leaves the phone grouping
rows by repo from the desktop's repo.list, and a transient failure keeps
the last catalog. The payload carries only grouping and label fields, no
hooks, credentials or uploaded icons. The phone's own catalog fetching and
its project.list/projectHostSetup.list routes are removed.
… recorded repo-metadata flow

The extra read inside the repo-metadata refresh stalled its recorded RPC
sequence. It now runs beside it with its own throttle. The repo-metadata
goldens are re-recorded for the intended state change: the name-keyed
colour, icon and id maps became desktopRepos.
# Conflicts:
#	config/scripts/ci-shard-timings.json
…ator

The sidebar, the jump palette and the options badge each applied the
Workspace options filters with their own copy of the rules. They now
call one pure evaluator in src/shared/workspace-view, which reads each
row through a small fact reader so the phone can call it next with the
facts its host serves. The sort comparator moves there too, with each
surface supplying its own Agent activity rank.

No behaviour change: a parity test runs the old sidebar chain and the
new evaluator over every toggle combination, and the old comparator
against the new one for each sort mode.
…ng-shared

# Conflicts:
#	config/scripts/ci-shard-timings.json
#	mobile/src/host-screen/host-workspace-list.tsx
#	src/renderer/src/i18n/en-runtime-required.json
…luator

One predicate builder instead of a per-row scope argument; one
exemption-narrowing function taking the hide flag; consumers import the
shared predicates directly; Agent activity ties fall to the label in the
shared comparator. The activation filter lift reuses the shared
predicates. The parity test now covers other-client rows, live agent
attention classes and the sort-label map.
…to another host

The refresh window is now kept per client, so a host screen reused for another desktop doesn't wait out the previous host's 60s window before showing its Project headers.
…ompact-row' into feat/phone-workspace-details
The sheet no longer fetches. The host stamps two optional row fields:
automationName beside automationCreated, and the branch PR's title, url
and checks on linkedPR (from the GitHub cache it already reads). Older
hosts omit them and the sheet shows what they send. Links match by
provider, type and number; the reference label is one shared helper the
desktop card uses too. Folder rows keep no long-press. One sheet file
plus the pure model.
…s Workspace options; tighter card glyph wiring

- The phone's Card layout and card style now live in its view state; one parallel settings.get
  reads them with pinned placement beside ui.get.
- The Card layout preset flag is a write option, no longer a view field or a change-event field.
- getWorktreeCardDetails reads the raw desktop settings and resolves the layout once; the desktop
  card computes it once in its foundation.
- The row computes its glyph presence in one place; Ports is hidden through one set.
- Drops the vanished-page effect, the native-only a11y props and the web-only switch branch.
…h tests; pinned placement changes announce themselves
…orca-lanes/wso into feat/workspace-options-7-phone-compact-row

# Conflicts:
#	mobile/src/components/WorktreeListRow.test.ts
#	mobile/src/host-screen/host-workspace-list.tsx
#	src/renderer/src/components/sidebar/worktree-card-presentation.tsx
…ompact-row' into feat/phone-workspace-details
…isplay names folder paths when the desktop has folder workspaces
…ompact-row' into feat/phone-workspace-details
…s-6-phone-sheet

# Conflicts:
#	mobile/src/host-screen/host-workspace-list.tsx
#	src/renderer/src/components/sidebar/worktree-card-presentation.tsx
…ce-options-7-phone-compact-row

# Conflicts:
#	mobile/src/components/WorktreeListRow.tsx
#	src/renderer/src/components/sidebar/worktree-card-presentation.tsx
…ompact-row' into feat/phone-workspace-details
…ompact-row' into feat/phone-workspace-details
@Jinwoo-H
Jinwoo-H changed the base branch from feat/workspace-options-7-phone-compact-row to main October 16, 2026 02:38
@coderabbitai

coderabbitai Bot commented Oct 16, 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: 71853715-2ff9-447c-b1be-d5261eef67ec
📥 Commits

Reviewing files that changed from the base of the PR and between 2dda7e3 and f918008.

📒 Files selected for processing: 2
  • mobile/src/components/WorktreeListRow.tsx
  • src/shared/runtime-worktree-contracts.ts

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

The changes add shared worktree card layout flags and apply them in desktop and mobile presentations. Runtime summaries now carry optional pull-request details and automation names. New workspace detail helpers format linked items and derive origin and notes. A mobile details sheet displays those details inside the action sheet, with linked URLs opened externally.

Priority: ⬇️ Low

Merge Risk: 🔵 Low · up to f9180

Compact mode may hide folder details, and some linked reviews may show the wrong destination or status. These are bounded issues to resolve or explicitly accept before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 28.95% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 38 functions across 22 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly identifies the primary change: adding linked PR, issue, and note details to the mobile workspace long-press sheet.
Description check Passed The description is complete and explains the user impact, implementation, rationale, linked issue status, visual proof, testing, compatibility considerations, and scope of the compact-row changes. The…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8c2e89d1-030c-49c4-b275-b2c8562d84c9
📥 Commits

Reviewing files that changed from the base of the PR and between 82029e6 and 1dc5794.

📒 Files selected for processing: 22
  • mobile/src/components/ActionSheetModal.tsx
  • mobile/src/components/HostKindIcon.tsx
  • mobile/src/components/WorktreeListRow.test.ts
  • mobile/src/components/WorktreeListRow.tsx
  • mobile/src/host-screen/host-screen-overlays.test.tsx
  • mobile/src/host-screen/host-screen-overlays.tsx
  • mobile/src/host-screen/workspace-details-sheet.test.tsx
  • mobile/src/host-screen/workspace-details-sheet.tsx
  • mobile/src/worktree/workspace-details-model.test.ts
  • mobile/src/worktree/workspace-details-model.ts
  • mobile/src/worktree/workspace-list-types.ts
  • src/main/runtime/runtime-worktree-ps-summaries.test.ts
  • src/main/runtime/runtime-worktree-ps-summaries.ts
  • src/renderer/src/components/sidebar/worktree-attachment-editing.ts
  • src/renderer/src/components/sidebar/worktree-card-presentation.tsx
  • src/shared/execution-host.ts
  • src/shared/runtime-worktree-contracts.ts
  • src/shared/workspace-attachments.test.ts
  • src/shared/workspace-attachments.ts
  • src/shared/worktree/card-properties.test.ts
  • src/shared/worktree/card-properties.ts
  • src/shared/worktree/workspace-kinds.ts

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

@Jinwoo-H
Jinwoo-H merged commit 13084ba into main Oct 16, 2026
33 checks passed
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.

1 participant