Skip to content

feat(workspaces): IPC API and extension-side data layer for the panel - #1099

Merged
EhabY merged 1 commit into
mainfrom
ehab/devex-622-workspaces-ipc-api-extension-side-provider-with-data-layer
Sep 10, 2026
Merged

feat(workspaces): IPC API and extension-side data layer for the panel#1099
EhabY merged 1 commit into
mainfrom
ehab/devex-622-workspaces-ipc-api-extension-side-provider-with-data-layer

Conversation

@EhabY

@EhabY EhabY commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Closes DEVEX-622.

Extension side of the new Workspaces view, behind coder.experimental.workspacesPanel. No UI yet: the panel prints the pushed state so the data flow can be verified.

Contract

packages/shared/src/workspaces/ holds the types and messages both sides import.

Direction Messages
extension to webview stateChanged (the whole WorkspacesState)
webview to extension ready, openWorkspace, viewInDashboard, refresh, setFilter, watchAgents

The extension pushes the whole state whenever any of it changes and skips the push when nothing did, so the webview never merges deltas and quiet polls stay off the wire. Payloads carry decisions, not facts to derive:

  • capabilities lists the filters the user may select
  • status is loading (only for a list the user waits on: the first for a filter, or a refresh), ready, or failed with the error
  • each agent's metadata is pending, reported, or failed

ready resets the watched agents, since a fresh webview shows nothing expanded.

Data layer

  • WorkspaceStore owns the state: the active filter and its list, the filters the session may select (minus those the deployment rejected with HTTP 400, until a visible refresh re-validates them), and the agents the webview is showing. Callers raise loading and the list lowers it. A hidden store keeps its list and sockets, and lists again on reveal. A rejected query falls back to the default filter within the same run.
  • Poller runs the store's list(token) task one run at a time, with a cancellation token per run so a superseded fetch drops its result. The task answers with the filter's poll interval, retry (backing off to a cap), or idle.
  • AgentMetadataTracker owns the watched set and its sockets. A released socket lingers 15 s, so collapsing and re-expanding a row reuses it. clear closes everything on a session change.
  • filters.ts owns each filter's query, role requirement, poll interval, and presentation, shared with the tree views, which now take a WorkspaceFilter instead of the WorkspaceQuery enum.
  • dispatch.ts gains dispatchWebviewMessage, used by the Tasks, Workspaces, and result panels. Commands gains openWorkspaceFromSidebar and openWorkspaceInDashboard, shared with the tree's sidebar commands. isOwner moved to api-helper.ts.

WorkspacesPanelProvider takes (extensionUri, store, commands, logger), follows the view's visibility through one syncVisibility, and pushes every store change to the retained view.

Notes for review

  • Pushing the whole state means a metadata tick resends the workspace list. That is small for mine; if it ever matters, give metadata its own notification rather than diffing fields.
  • Sockets follow watchAgents, not visibility, so they stay open while the panel is hidden, as the tree's do. The UI must send the rows it shows and an empty set when it unmounts.
  • A rejected shared query drops the filter from the picker instead of showing the tree's "requires Coder 2.27.0" notice. That copy belongs to the UI ticket.
  • No theme-change replay: packages/ui re-reads theme tokens in the webview.
  • The tree keeps its own polling and metadata bookkeeping for now. Poller and the tracker can replace it later.
  • Known follow-up: a socket that closes cleanly (code 1000) is not reopened until the next list, as in the tree today.
  • Tests: each file has its own setup(). createMockWebviewView in testHelpers.ts is shared with the Tasks panel test.
Review log

The first review pass fixed a visible view flapping hidden on re-resolve, requestedAgents surviving a webview rebuild, the first retry waiting two intervals, and a hidden refresh re-offering filters it could not validate.

A simplification pass then merged stateReplaced and stateUpdated into stateChanged, replaced the loading and error fields with status unions, dropped the poller's again, generation, running, and pause, folded TREE_PRESENTATION and the WorkspaceQuery enum into WORKSPACE_FILTERS, moved the panel onto Commands, removed the reveal and theme replays, and cut the tests from 1482 to 1075 lines with a setup() per file. A final architecture review found no races or ordering hazards.

@linear-code

linear-code Bot commented Aug 26, 2026

Copy link
Copy Markdown

DEVEX-622

@EhabY
EhabY force-pushed the ehab/devex-622-workspaces-ipc-api-extension-side-provider-with-data-layer branch 12 times, most recently from a17482e to 5ae7bef Compare August 26, 2026 20:36
@EhabY
EhabY marked this pull request as ready for review August 27, 2026 18:01
@EhabY
EhabY force-pushed the ehab/devex-622-workspaces-ipc-api-extension-side-provider-with-data-layer branch 10 times, most recently from 869bb9d to ba2ea39 Compare September 9, 2026 14:11
Adds the typed IPC contract for the experimental Workspaces panel and the
extension-side store that owns its data, porting the tree views' behaviors
to push through IPC. No UI yet: the webview prints the pushed state so the
data flow can be verified.

`packages/shared/src/workspaces` defines the contract. One notification,
`stateChanged`, carries the whole `WorkspacesState` whenever any of it
changes; `ready`, `openWorkspace`, `viewInDashboard`, `refresh`,
`setFilter` and `watchAgents` come back. The state is flat: capabilities,
filter, workspaces, a `status` union (loading, ready, or failed with the
error) and per-agent metadata as a union (pending, reported, or failed).
Payloads carry decisions rather than facts to derive, so the webview holds
no data and applies no policy: it asks for the state with `ready` and
renders what arrives. `ready` also resets the watched agents, since a
webview that just loaded shows nothing expanded.

`WorkspaceStore` owns the panel's state: the active filter and its list,
the filters the session may select (minus those the deployment rejected
with HTTP 400, until a visible refresh re-validates them), and the agents
the webview is showing. It pushes the whole state on every change and
skips the push when nothing changed, so quiet polls stay off the wire. A
hidden store keeps its list and its sockets; a revealed one lists again
without a loading flicker. Callers raise `loading` (a filter switch, a
refresh, a session change) and the list lowers it, so a poll never touches
it.

Split by concern:

- `src/util/poller.ts`: runs one task at a time with a cancellation
  token per run, so a superseded fetch drops its result. The task answers
  with a delay in ms, `retry` (backing off to a cap) or `idle`.
- `src/workspace/agentMetadataTracker.ts`: the watched set and its
  sockets, which linger briefly after release so toggling a row reuses them.
- `src/workspace/filters.ts`: each filter's query, role requirement, poll
  interval and presentation, shared with the tree views, which now take a
  `WorkspaceFilter` instead of the `WorkspaceQuery` enum. `isQueryRejected`
  names the HTTP 400 both clients handle.
- `src/webviews/dispatch.ts`: `dispatchWebviewMessage`, the request and
  command routing the Tasks, Workspaces and result panels use, with one
  `DispatchOptions` shape.

`WorkspacesPanelProvider` takes the store and `Commands`, follows the
view's visibility through one `syncVisibility`, and leaves theme changes to
the webview. `Commands` gains `openWorkspaceFromSidebar` and
`openWorkspaceInDashboard`, which the tree's sidebar commands share.
`isOwner(user)` moved to `api-helper.ts` for `deploymentManager` and the
filters. The mock `WebviewView` lives in `testHelpers.createMockWebviewView`,
shared with the Tasks panel test.
@EhabY
EhabY force-pushed the ehab/devex-622-workspaces-ipc-api-extension-side-provider-with-data-layer branch from ba2ea39 to 2182874 Compare September 9, 2026 14:21
Comment thread src/webviews/workspaces/workspaceStore.ts
@EhabY
EhabY requested a review from jeremyruppel September 10, 2026 10:54
@EhabY
EhabY merged commit a91ae70 into main Sep 10, 2026
12 of 13 checks passed
@EhabY
EhabY deleted the ehab/devex-622-workspaces-ipc-api-extension-side-provider-with-data-layer branch September 10, 2026 12:56
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.

2 participants