Skip to content

🤖 feat: show "Archiving..." from every archive entry point while the request is in flight - #4068

Merged
ibetitsmike merged 2 commits into
mainfrom
mike/archive-pending-indicator
Sep 3, 2026
Merged

ibetitsmike merged 2 commits into
mainfrom
mike/archive-pending-indicator

Conversation

@ibetitsmike

Copy link
Copy Markdown
Contributor

Summary

Archiving a workspace can take 15 to 25 seconds server-side, and if you started it from the workspace menu bar there was no feedback at all until the row vanished. The archive-in-progress state now lives in WorkspaceContext, so both the sidebar row and the workspace menu bar show an "Archiving..." status from the moment of the click, whichever surface started it.

Background

The sidebar row already rendered an inline "Archiving..." status, but the set driving it was ProjectSidebar's own useState, populated only by the row's archive button. WorkspaceMenuBar kept a separate isArchiving boolean purely as a re-entrancy guard and rendered nothing for it. Archiving from the header (the common path when the workspace is selected) therefore looked like a hang, and a slow archive was indistinguishable from a broken connection.

Server-side, the time goes to the archive snapshot (git format-patch over merge-base(trunk, HEAD)..HEAD), which is large when the local trunk is far behind its remote. That is a separate inefficiency and is not changed here; this PR only makes the wait visible.

Implementation

  • WorkspaceContext gains archivingWorkspaceIds: ReadonlySet<string>. Both preflightArchiveWorkspace and archiveWorkspace wrap their RPC in a small helper that adds the id before the call and removes it in finally, so a rejected request (for example a dropped WebSocket) clears the indicator instead of leaving the row stuck.
  • ProjectSidebar reads the set from context; its local copy and the surrounding try/finally are removed (most of that file's diff is the resulting de-indent; view with whitespace ignored).
  • WorkspaceMenuBar reads the same set for its re-entrancy guard and renders a role="status" "Archiving..." span with the archive icon next to the title. It is shrink-0 beside the min-w-0 truncate title, so it stays visible at phone widths.

The set is placed in the actions context (alongside selection and drafts) rather than the metadata context: the two consumers already subscribe there, and archive is rare enough that two extra context updates per archive are negligible.

Validation

  • New context test drives archiveWorkspace and preflightArchiveWorkspace against deferred promises and asserts the id is present only while each is outstanding, including the rejection path.
  • New menu bar test asserts the status renders only when this workspace's id is in the set.
  • Both tests were red-green verified: making the helper a no-op fails the first; replacing the render condition with false fails the second.

Risks

Low. UI-only, no IPC or persistence changes. The sidebar row now also enters its archiving presentation during the preflight call (previously only during the archive call itself), which is the intended behaviour and lasts well under a second.


Generated with xum • Model: anthropic:claude-fable-5-1 • Thinking: xhigh • Cost: $21.13

…request is in flight

Archiving a workspace can take tens of seconds server-side (snapshot +
worktree removal). The sidebar row already showed an inline "Archiving..."
status, but only when the archive was started from that row: the state
lived in ProjectSidebar, and the workspace menu bar's archive action kept
an isArchiving flag purely as a re-entrancy guard with nothing rendered.
Archiving from the header therefore gave no feedback until the workspace
disappeared.

Lift the pending set into WorkspaceContext (archivingWorkspaceIds), marked
inside preflightArchiveWorkspace/archiveWorkspace so it lights up from the
moment of the click regardless of caller and clears on success or error.
The sidebar reads it from context (local state removed) and the menu bar
now renders a matching "Archiving..." status next to the title.

---

_Generated with `xum` • Model: `anthropic:claude-fable-5-1` • Thinking: `xhigh` • Cost: `$21.13`_

<!-- mux-attribution: model=anthropic:claude-fable-5-1 thinking=xhigh costs=21.13 -->
@chatgpt-codex-connector

This comment has been minimized.

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

This comment has been minimized.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 351fdfc602

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread src/browser/contexts/WorkspaceContext.tsx Outdated
Comment thread src/browser/contexts/WorkspaceContext.tsx Outdated
Comment thread src/browser/components/WorkspaceMenuBar/WorkspaceMenuBar.tsx
Comment thread src/browser/contexts/WorkspaceContext.tsx
- Ref-count overlapping archive requests per workspace so the first one to
  settle does not clear the indicator while another is still running, and
  guard the sidebar keyboard shortcut like the menu bar already does.
- Replace the manual useCallback helper with a module-level function
  (React Compiler handles memoization).
- Add a pinned phone story for the archiving header state with a play
  contract asserting the status and right-side controls stay in the bar.

---

_Generated with `xum` • Model: `anthropic:claude-fable-5-1` • Thinking: `xhigh` • Cost: `$21.13`_

<!-- mux-attribution: model=anthropic:claude-fable-5-1 thinking=xhigh costs=21.13 -->

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: a4f633a189

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

@chatgpt-codex-connector

This comment has been minimized.

@ibetitsmike
ibetitsmike added this pull request to the merge queue Sep 3, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 3, 2026
@ibetitsmike
ibetitsmike added this pull request to the merge queue Sep 3, 2026
Merged via the queue into main with commit 3c06630 Sep 3, 2026
35 of 38 checks passed
@ibetitsmike
ibetitsmike deleted the mike/archive-pending-indicator branch September 3, 2026 17:24
ethanndickson added a commit that referenced this pull request Sep 4, 2026
- workspaceService flat-reorder mock (#3994) sets getSessionDir on
  Partial<Config>, which the split Config (#4017) no longer has; the test
  only needs sessionsDir
- ProjectSidebar flat-list mocks (#3994) lack archivingWorkspaceIds (#4068)
- MCP prompt snapshot test asserts the cancelSignal argument this PR removed
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