diff options
| author | Adam Malczewski <[email protected]> | 2026-06-02 14:43:16 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-02 14:43:16 +0900 |
| commit | 3ebcd49c404ed287a97af159ac8adfa63d572849 (patch) | |
| tree | f8245ed28530a8e96046221eb1d7eca47d508dc8 /packages/core/src | |
| parent | 7c527b4d8a72159954405e720d5bf776802dc0ff (diff) | |
| download | dispatch-3ebcd49c404ed287a97af159ac8adfa63d572849.tar.gz dispatch-3ebcd49c404ed287a97af159ac8adfa63d572849.zip | |
feat(tabs): drag-reorder + double-click rename + per-tab chat draft
- TabBar: HTML5 drag-and-drop to reorder user tabs (subagent tabs untouched);
double-click a tab title to rename (Enter/blur confirm, Escape cancel).
- Store: add reorderTabs/renameTab/setDraft; per-tab in-memory `draft` and
`manualTitle` fields. Manual rename suppresses first-message auto-title.
- ChatInput: bind to the active tab's draft so switching tabs saves/restores
unsent text instead of clobbering it.
- Backend: updateTabPositions() + PATCH /tabs/reorder persist tab order to the
existing `position` column; tabs without a stored position fall to the end
then get explicit positions on first reorder.
- Tests: store reorder/rename/auto-title-guard/draft coverage; core
updateTabPositions coverage (FakeDatabase extended with transaction support).
Diffstat (limited to 'packages/core/src')
| -rw-r--r-- | packages/core/src/db/tabs.ts | 14 | ||||
| -rw-r--r-- | packages/core/src/index.ts | 1 |
2 files changed, 15 insertions, 0 deletions
diff --git a/packages/core/src/db/tabs.ts b/packages/core/src/db/tabs.ts index 8b290d2..f719a01 100644 --- a/packages/core/src/db/tabs.ts +++ b/packages/core/src/db/tabs.ts @@ -115,6 +115,20 @@ export function updateTabStatus(id: string, status: string): void { }); } +export function updateTabPositions(idsInOrder: string[]): void { + const db = getDatabase(); + const now = Date.now(); + const update = db.query("UPDATE tabs SET position = $position, updated_at = $now WHERE id = $id"); + // One transaction so a reorder is atomic: either every tab lands at its new + // slot or none does, never a half-applied ordering. + const applyAll = db.transaction(() => { + idsInOrder.forEach((id, index) => { + update.run({ $id: id, $position: index, $now: now }); + }); + }); + applyAll(); +} + export function archiveTab(id: string): void { const db = getDatabase(); db.query("UPDATE tabs SET is_open = 0, updated_at = $now WHERE id = $id").run({ diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 7818024..f67ad53 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -56,6 +56,7 @@ export { shortestUniquePrefix, type TabRow, updateTabModel, + updateTabPositions, updateTabStatus, updateTabTitle, } from "./db/tabs.js"; |
