Repository navigation
feat(trellis): trash projects in place with Undo - #16
Conversation
Moving a Trellis project to the trash no longer asks first or leaves the page: the toast, the project's settings and its sidebar row offer Undo, which restores the item and its conversations; the row stays listed as trashed until the page reloads. The trash result names the Trellis item to restore, and the catalog keeps an empty trashed project (hidden) so a restore reuses it; only purged or graduated ones are deleted. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…listed until its restore shows Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…do covers every trashed member An entry waits for a status showing its root retired before a live status can drop it, so a status from before the trash or a timed-out refresh never discards a fresh Undo; Undo keeps the row until a status shows the restore. Every member environment's status is applied, and project settings undo all trashed members. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 11887b70e2
ℹ️ 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".
| statuses.size === 0 | ||
| ? [] | ||
| : projects.filter((project) => { | ||
| if (`${project.environmentId}:${project.id}` in trashedHere) return false; |
There was a problem hiding this comment.
Keep trashed projects out of new-thread targets
Returning false here keeps the locally trashed project in the shared useSidebarProjects() result, but that hook also feeds useHandleNewThread, the command palette, and the global new-thread default—not just sidebar rendering. If the trashed project is first in project order, the new-thread shortcut silently creates a draft against its removed workspace; users can also explicitly select it and hit the same failure. Preserve it for the Undo row without exposing it as a valid thread target.
AGENTS.md reference: AGENTS.md:L67-L70
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Valid: useSidebarProjects also feeds new-thread targets and the palette. Keeping a just-trashed project is now opt-in (keepTrashedHere), used only by the two sidebars; new-thread defaults, the palette and the home route no longer see it. Fixed in a52f45b.
| if (result._tag === "Failure") { | ||
| if (!isAtomCommandInterrupted(result)) { |
There was a problem hiding this comment.
Reset the restoring phase after an interrupted Undo
When the restore command is interrupted—for example, because a remote WebSocket disconnects before the server executes it—this branch leaves the entry in restoring. After reconnection, a status that still contains the retired root cannot change that phase, so every Undo control remains disabled as “Restoring…” until a page reload. Reset the phase to trashed on interruption; if the server did complete the restore, the next live status will still remove the entry.
AGENTS.md reference: AGENTS.md:L74-L74
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Valid: an interrupted restore now puts the entry back to trashed (Undo enabled again); if the server did restore it, the next status showing it live still drops the entry. Fixed in a52f45b.
| if (retired.has(trimTrailingSlashes(project.workspaceRoot))) { | ||
| if (project.phase === "trashing") store.setPhase(key, "trashed"); | ||
| } else if (project.phase !== "trashing") { |
There was a problem hiding this comment.
Reconcile a fast external restore from the trashing phase
A live status never removes an entry while it is still trashing. If another client or the CLI restores the item before this client observes any status containing its retired root—such as after the post-trash status refresh times out—all subsequent statuses show the root live, but the entry remains permanently labeled “In trash” until reload. The reconciliation needs a way to distinguish a pre-trash stale status from a later authoritative live status so multi-device restores can settle.
AGENTS.md reference: AGENTS.md:L74-L74
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Valid: entries now remember the status cached when they were added (from before the trash) and ignore only that one; any later status settles them, so a restore elsewhere drops the entry even if no status ever showed it trashed. Test added in trellisTrashed.test.ts. Fixed in a52f45b.
…sh state against the pre-trash status Only the sidebars keep a just-trashed project listed. An entry ignores the status cached when it was added and is settled by any later one, so a restore elsewhere drops it even before a status showed it trashed; an interrupted Undo gives the Undo back. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a52f45b7b2
ℹ️ 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".
|
|
||
| export default function LegacySidebar() { | ||
| const projects = useSidebarProjects(); | ||
| const projects = useSidebarProjects({ keepTrashedHere: true }); |
There was a problem hiding this comment.
Disable new-thread actions on retained trash rows
When a project is retained here for Undo, the sidebar still treats it as an ordinary actionable project: SidebarProjectItem's pencil button calls handleNewThread directly with the trashed member, opening a draft whose workspace has been removed, while the default Sidebar also uses its retained projects array for newThreadDisabled, so its sole-project button remains enabled but silently has no valid target. Fresh evidence beyond the earlier target-filtering finding is that both sidebar callers explicitly opt into the retained list even though useHandleNewThread() now uses the filtered list; keep these rows display-only and suppress their creation affordances.
AGENTS.md reference: AGENTS.md:L67-L70
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Valid: the legacy project header no longer renders its new-thread button while the project is in this client's trash list (Undo only), and the new sidebar's new-thread button is disabled when every listed project is just-trashed; its picker and direct create already use the filtered target list. Fixed in a3c7e1c.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a3c7e1c78b
ℹ️ 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".
| ...(restore === undefined | ||
| ? {} | ||
| : { |
There was a problem hiding this comment.
Preserve confirmation when the server cannot provide Undo
When app.t3.codes or a newer desktop client connects to a server predating the new restore field, the optional contract accepts the old { trashed, name } response, but both removal entry points have already skipped confirmation and this branch silently omits Undo. The user therefore gets the new destructive, no-confirm flow without its promised immediate reversal; gate the no-confirm behavior on server support or retain a confirmation for version-skewed remote environments.
AGENTS.md reference: AGENTS.md:L19-L21
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Not changing this one. The fork's Trellis T3 runs as one dev_v2 install whose server and web come from the same build (t3code-install pins a version per instance), so a client without Undo support against this server does not occur in our deployment; app.t3.codes and the store desktop app do not speak dev_v2's orchestration protocol 2 at all. Even with an older server the trash stays reversible: the toast points to Settings → Trellis, where Restore brings the item and its conversations back.
| const trashedHere = useTrellisTrashedStore((state) => | ||
| project.memberProjects.some( | ||
| (member) => trellisTrashedKey(member.environmentId, member.id) in state.projects, | ||
| ), |
There was a problem hiding this comment.
Keep new-thread actions for live members of a grouped project
When a logical project groups checkouts from multiple environments and only one member was just trashed, this some(...) marks the entire group as trashed, so the legacy sidebar removes its new-thread button even though another member remains live and the existing environment chooser could target it. Treat the group as unavailable only when every member is trashed, and exclude trashed members from the chooser.
AGENTS.md reference: AGENTS.md:L74-L74
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Valid: the legacy row now hides its new-thread button only when every member was just trashed. Fixed in b2c40a5.
| // A trashed project stays on this page, with its Undo. | ||
| if (isWholeGroup && !hasOtherMembers && deleted.length > 0) { | ||
| void navigate({ to: "/", replace: true }); |
There was a problem hiding this comment.
Stay on settings when any grouped member was trashed
For a whole logical group containing both a Trellis-managed member and an ordinary member, trashed and deleted are both nonempty; after successfully trashing the first and deleting the second, this condition navigates home merely because deleted.length > 0. That regresses the promised in-place flow and removes the settings-page Undo even though the retained trashed member still owns the route; navigate only when no member was successfully trashed.
AGENTS.md reference: AGENTS.md:L74-L74
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Valid: settings now navigate home only when nothing was trashed (counting successful trashes, not attempts), so a mixed group keeps its page and Undo. Fixed in b2c40a5.
…tay on settings when anything was trashed Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Trellis v1 Stage C, Lane T3 step 5 (trashing projects in place with undo; v1 design M7).
Problem
Trashing a Trellis project meant: project settings → Move to trash → confirm → dropped back on the main screen, and restoring it meant a trip to Settings → Trellis (Andrei's "smoother project trash flow" note).
Change
trashProjectreturns the Trellis item to restore (restore: {kind, id}; an idea restores as an idea, a fork as a workspace).state/trellisTrashed.tsholds this client's trashed projects in phases (trashing→trashed→restoring), settled against each environment's Trellis status.docs/user/trellis.md"Deleting and restoring" is updated.Checks
TrellisCatalog.test.ts: the trash result's restore target (idea, fork); a trashed empty project kept and reused, deleted once purged; no no-op retire actions for trashed empty projects or forks.trellisTrashed.test.ts: phases against stale, fresh and restored statuses, other environments, and statuses that are not ready./trellis/dev-t3with playwright-cli. Trashedbug4-reprofrom its settings: the page stayed, showing "In the Trellis trash · Undo" plus the toast with Undo. The project picker showed "In trash · Undo"; Undo there restored it, the row came back normal, and the selection was kept. A page reload without Undo drops the trashed row, as intended. Screenshots are kept locally:/tmp/stagec-trash-dev/*.png.knip:check(after removing an unused export),vp check,vpr typecheckandrelease-smokepass.t3tests fail only on the knownCodexInstallationandAcpSessionRuntime.processTreefailures. Package tests fail only on the known desktop libsecret and snapshot file-mode failures; client-runtime, relay and mobile pass when run separately.build:desktopfails on the known libsecret helper.🤖 Generated with Claude Code