Commit Graph
4 Commits
Author SHA1 Message Date
Mohamed BoudraandGitHub 19a7d26349 feat(app): make the side panel user-directed (#3605)
* feat(app): let the file panel close its tree rail

The file panel's tree rail was permanent on desktop — the changes panel
had a folder-tree toggle in its toolbar, the file toolbar had nothing, so
the rail was there whether you wanted it or not.

The changes panel's private DesktopTreeToggle becomes a shared
TreeRailToggle so both toolbars render the same affordance; that also
drops the treeToggleStyle prop threaded through ChangesToolbarProps,
which recomputed exactly what the component already built internally.
The i18n keys move out of workspace.git.diff into workspace.tree, since a
shared component reaching into the git namespace would rot.

The two rails keep independent flags — the file rail in panel-store, the
changes rail in useChangesPreferences — so closing one leaves the other
alone. FileTreeToggle wires itself to the store rather than taking a
callback: the bar renders several components below FilePanel, where the
rail actually lives.

Both rails also get narrower (320 -> 260 default, 200 -> 180 minimum).
The persist version bump resets treeRailWidth on purpose: nearly every
existing install carries the old 320 default, so without the reset the
narrower rail would only ever reach new users. Anyone who dragged their
rail to a deliberate custom width loses it once.

Note that MIN_CONTENT_WIDTH still clamps the rail to
`containerWidth - 240`, so in a narrow pane the new default never
applies — that floor, not the default, is what sets the width there.

* feat(app): make the side panel an empty workspace surface

The fixed, hideable side panel keeps supporting context beside an agent without seeding content. Pane-local choices stay local, while implicit supporting opens follow a persisted routing preference.

* test(app): exercise side panel policy through its capability boundary

The browser rail journey already covers the real tree-toggle behavior. Side-panel policy tests now pass their platform capability through the public boundary instead of replacing a production module.

* test(app): expect an empty side panel after upgrade

* test(app): expect an empty first split pane

* test(app): account for the empty side panel in split retention

* feat(app): make workspace panel tabs independent

Give explicit New actions fresh tab instances, keep panel state opaque to tab management, preserve File navigation context, and stabilize uncached File transitions.

* fix(app): preserve file conflicts during preview refresh

Keep the current preview mounted for same-target reads and conversions so the editor retains its conflict observation state. Clear retained previews only when the file target changes.
2026-08-20 21:49:23 +02:00
Mohamed Boudra c859b59c99 fix(app): dismiss the composer track panel when a row is chosen
Track pills became menu surfaces when the trackers moved out of stacked
cards, but ComposerTrackRow kept the raw Pressable it had as an inline
card row. Nothing in that path reaches selectItem, so the popover or
sheet stayed parked over the transcript after opening a subagent, and on
iOS the action fired while UIKit was still tearing the sheet down. Rows
now hand the press to the engine and take closeOnSelect, as MenuItem
does; bulk archive opts out because its progress lands in the panel.

The running mark is the shared StatusRing rather than a still dot the
pill drew for itself, and the remaining dots read their colour from the
one bucket-to-colour map. The slot is sized for the ring in every state
so the label does not step sideways when the last child finishes.

Mounting the real menu engine in a test needed harness work: stubs for
two packages that ship untranspiled Flow, reanimated left out of Vite's
prebundle so its .web files win, and the gaps filled in the unistyles
test theme.
2026-08-17 23:43:01 +02:00
Mohamed BoudraandGitHub 6d7606160e Let plugins add contextual workspace tools (#3465)
* feat(plugins): add workspace panels and command center contributions

Give local plugins contextual UI entry points without making the daemon interpret client placement or callbacks. Panels receive stable IDs and read cached client state through required selectors with shallow equality, avoiding unrelated guest rerenders and context-discovery RPCs.

* fix(plugins): align shared client state ownership

Workspace panels and Command Center callbacks consume the same frozen client snapshots, so their adapter belongs to the plugin boundary rather than either contribution surface. Refresh the Nix dependency hash for the selector-store dependency added by this feature.
2026-08-17 19:26:40 +02:00
a8ebd390fa feat(forge): pluggable forge abstraction + GitLab and Gitea/Forgejo/Codeberg (#1913)
* refactor(forge): forge-neutral foundation (GitHub-only)

Decouple git-hosting from GitHub behind a neutral abstraction (issue #1616), GitHub-only for now; existing GitHub behaviour is unchanged.

- Forge manifest, neutral ForgeService contract, forge registry + resolver, and a client forge-module registry.
- GitHub code renamed to the neutral shape; PR/Issue attachment wording preserved.
- forge.search.response enums parse tolerantly (unknown kind/auth state degrade instead of breaking the client).
- createPullRequest reports typed CLI/auth errors instead of a generic message.
- forge-resolver host/remote caches are LRU-bounded.
- Forge host trust is explicit: only a known cloud host or a CLI-authenticated host is ever talked to; an unauthenticated GitHub Enterprise host fails resolution instead of routing to github.com.
- Docs: forge-providers guide, glossary and i18n forge-copy conventions, architecture and rpc-namespacing terminology.
- Vitest React Native mocks (unistyles, svg, linking, lucide) consolidated into shared aliased test-stubs.

* feat(forge): GitLab adapter, forge-aware UI, pipelines and approvals

GitLab adapter over the glab CLI on the neutral contracts: MR status, forge-aware UI, pipeline tree, and N-of-M approvals.

- threadIsResolved is part of the neutral timeline item.
- Pipeline load failures show an error instead of an empty section.
- Manual pipeline jobs render as pending.
- Fork/detached MR head pipelines are fetched by MR iid (glab ci get --merge-request).

* feat(forge): Gitea family adapter (Gitea, Forgejo, Codeberg)

One adapter over the tea CLI serving Gitea, Forgejo, and Codeberg on the neutral contracts.

- CI status aggregates commit statuses and Actions runs together.
- Gitea's terminal "warning" state maps to failure on server and client.
- Gitea Actions check details are reachable from the PR pane by workflowRunId.

* refactor(forge): localize compatibility handling

* test(forge): expect normalized GitLab facts

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-17 15:03:26 +08:00