diff options
| author | Adam Malczewski <[email protected]> | 2026-10-16 15:25:40 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-10-16 15:25:40 +0900 |
| commit | a4aa86e66dad93f40bce640545d8903f7e6bcb64 (patch) | |
| tree | f02f83ffffc5a03ed34e5bd460f806b456b02bbe /src/features/tabs/tab-groups.ts | |
| parent | f6d96289470ac888670050ff64c54bbe69b973cb (diff) | |
| download | dispatch-web-a4aa86e66dad93f40bce640545d8903f7e6bcb64.tar.gz dispatch-web-a4aa86e66dad93f40bce640545d8903f7e6bcb64.zip | |
feat(tabs): confirm dialog that cascades a tab close to its subagents
Closing a tab whose visible subagent group is non-empty now asks ONE
daisyUI modal (CloseSubagentsConfirm): 'Yes, close all N' closes the tab
plus every transitive descendant tab (sub-sub-agents included, no further
prompts), 'No, keep them open' closes only the tab, and Cancel/Escape/
backdrop closes nothing. Plain tabs close directly as before.
- cascadeCloseIds (pure, tab-groups.ts): the tab + its transitive visible
group descendants in tab order — one decision covers the whole subtree
- TabList intercepts tab-close and opens the dialog only when the
subtree has >1 tab; ids are snapshotted at open time
- each closed conversation goes through the existing onClose port, so
every close still POSTs /conversations/:id/close (backend doesn't
cascade; it is idempotent)
Diffstat (limited to 'src/features/tabs/tab-groups.ts')
| -rw-r--r-- | src/features/tabs/tab-groups.ts | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/src/features/tabs/tab-groups.ts b/src/features/tabs/tab-groups.ts index 12870ee..a1aa464 100644 --- a/src/features/tabs/tab-groups.ts +++ b/src/features/tabs/tab-groups.ts @@ -104,6 +104,22 @@ export function groupDescendants(tabs: readonly Tab[], conversationId: string): } /** + * The tabs removed by a CASCADING close of `conversationId` (the user chose + * "also close its subagents"): the tab itself first, then its transitive + * visible-group descendants in tab order. ONE decision covers the whole + * subtree — closing never re-prompts per level. A single-element result (the + * tab alone) means the tab has no subagents and closes without a prompt. + */ +export function cascadeCloseIds(tabs: readonly Tab[], conversationId: string): string[] { + const descendants = groupDescendants(tabs, conversationId); + const ids = [conversationId]; + for (const tab of tabs) { + if (descendants.has(tab.conversationId)) ids.push(tab.conversationId); + } + return ids; +} + +/** * The tabs `conversationId` may be moved under (the "Add to group" menu): * every other tab EXCEPT itself, its descendants (that would form a cycle), * and its current visible group parent (already there). Tab order preserved. |
