Skip to content

feat: worktrees dashboard widget with remove action#314

Open
Bottelet wants to merge 3 commits into
geodro:mainfrom
Bottelet:feat/worktrees-dashboard-widget
Open

feat: worktrees dashboard widget with remove action#314
Bottelet wants to merge 3 commits into
geodro:mainfrom
Bottelet:feat/worktrees-dashboard-widget

Conversation

@Bottelet
Copy link
Copy Markdown
Contributor

@Bottelet Bottelet commented May 8, 2026

Summary

Adds a Worktrees panel to the dashboard showing all active worktrees across sites with status indicators, open-in-browser, and remove actions.

Changes

Frontend:

  • New WorktreesWidget.svelte on the dashboard grid alongside Sites, Services, and Workers
  • Each worktree shows: status dot, branch name, parent site, DB isolation badge
  • Open in browser (globe icon) and remove (X icon) per worktree
  • Pending state with amber pulse during actions
  • Empty state with lerd worktree add hint

Backend:

  • worktree-remove API action: runs git worktree remove --force non-interactively, watcher handles cleanup
  • Store helpers: removeWorktree(), stopWorktreeVite()
image

Adds a Worktrees panel to the dashboard showing all active worktrees
across sites with status dots, branch names, open-in-browser, and
remove actions.

- New WorktreesWidget.svelte on the dashboard grid
- Backend worktree-remove API action via git worktree remove --force
- Store helpers for removeWorktree and stopWorktreeVite
- Pending state tracking with amber pulse during actions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Owner

@geodro geodro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition, the widget reads well next to the existing dashboard tiles, the empty state and pending dots match the rest of the grid, and the backend remove action through the watcher cleanup chain is the right shape. Build and CI both green locally on the branch.

A few things before this lands though. The biggest is the open in browser path, onOpen hardcodes https for the worktree URL, so on any unsecured site the globe icon opens a page that just fails to connect. There is already an openSiteInBrowser helper in stores/sites.ts that does the right thing for the parent site, but it has the inverse bug for worktrees, it forces http when a branch argument is set even though worktrees inherit TLS via the wildcard cert. Cleanest fix is to drop the branch equality clause in that helper and call it from the widget, that way both the parent and worktree paths get the correct scheme from a single place.

The remove action also needs to call the worktree-vite-stop endpoint before git remove, otherwise we hit the same orphan unit issue from PR 310 every time someone removes a worktree from the dashboard. The endpoint is already wired up in the store, just not invoked from the remove flow.

Related, onStop and stopWorktreeVite are imported and defined but no UI element ever calls onStop, so it currently reads as dead code. Either wire a stop button into the row, or remove the unused half. Given the orphan cleanup above wants the endpoint anyway, a small stop control next to the existing globe and remove icons probably makes sense.

A couple of UI calls too. The DB isolation indicator currently shows the letters DB in amber, indicators on the dashboard generally read better as icons rather than initials, a small database glyph would fit the rest of the grid more naturally. And the Worktrees card itself takes a full slot even when empty, which throws the dashboard layout off for anyone not using worktrees, can we either hide it when there are zero worktrees or fold it into the Workers card so we keep the existing six card layout regardless of whether worktrees are in use.

Smaller items, the failure path for both remove and stop only logs to console, the pending dot flips back to green silently so the user has no idea the action failed. A toast or a persistent error state on the row would help. The native browser confirm for remove also sticks out next to the rest of the dashboard's modal patterns. And neither WorktreesWidget.svelte nor the new dashboard feature shows up in tests or docs, the codebase already has the DashboardCard.test.svelte convention, would be good to extend it here.

- Use parent site's TLS status for open-in-browser scheme instead of
  hardcoding https
- Stop vite worker before removing worktree to prevent orphan units
- Wire up the stop button (was dead code) between globe and remove
- Hide the widget entirely when there are zero worktrees
- Show error state inline on the row (red dot + message) instead of
  silent console.log

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Bottelet
Copy link
Copy Markdown
Contributor Author

Bottelet commented May 8, 2026

all addressed:

scheme — onOpen now reads the parent site's tls field instead of hardcoding https. http sites get http URLs, secured sites get https.

orphan cleanup on remove — onDelete calls stopWorktreeVite before removeWorktree so the vite unit is stopped before git removes the checkout.

dead code — wired the stop button back in between globe and remove. onStop is no longer unused.

hidden when empty — the entire DashboardCard is wrapped in {#if total > 0}, so the widget doesn't render at all when there are no worktrees. keeps the dashboard layout clean for non-worktree users.

error handling — errors are now shown inline on the row with a red status dot and the error message below the branch name, instead of silently logging to console.

left the native confirm and DB indicator as-is for now — happy to swap those to a modal and icon in a follow-up if you want.

@geodro
Copy link
Copy Markdown
Owner

geodro commented May 8, 2026

Hey Casper, thanks for working on this. The instinct to give worktrees a single inventory view on the dashboard is sound, and the widget itself is well built (the busy and error states are nice). A few reasons we want to send this back rather than merge as is.

The dashboard today is a glanceable surface, sites and services and workers and system health, and our model is look here, click to drill in. The new card moves it from inventory to control, and once we accept destructive actions on the dashboard the next contribution will naturally extend that, so we want to hold the line. The git worktree remove force is the most obvious example, but stop vite is also a per worker action that already has a richer home in SiteDetail after #319 landed.

On layout, adding a seventh card pushes the rest below the fold on a typical laptop. The hidden when empty fallback helps but means the layout shifts as worktrees come and go, which is the wrong contract for a dashboard.

After #319 the vite stop endpoint is duplicative with the existing worker name start stop action which already accepts branch as a query parameter, and SiteDetail now renders per worktree worker toggles directly in the worktree picker. So the per branch controls actually live there now, with full context (php version, isolated db, lan share, workers).

The piece that is genuinely missing today is branch names on the dashboard, since the chip on each site row only shows a count. If you want to keep working on this, I would suggest making the chip expandable on click so the branch list shows inline under the site, with a chevron to collapse, and let those rows navigate into SiteDetail with the branch picker preset. That keeps the dashboard at six cards, keeps the data honest (read only), and lets users drill into any worktree with one click.

For the actions themselves, the cleanest place is inside SiteDetail next to the existing worktree controls. Open in browser is small and easy to add there, and remove worktree should call into a shared cli helper rather than shelling out to git directly so the cleanup path is the same as lerd worktree remove will eventually use.

Happy to look at a follow up that goes that direction.

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