summaryrefslogtreecommitdiffhomepage
path: root/packages/core/src
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-02 14:43:16 +0900
committerAdam Malczewski <[email protected]>2026-06-02 14:43:16 +0900
commit3ebcd49c404ed287a97af159ac8adfa63d572849 (patch)
treef8245ed28530a8e96046221eb1d7eca47d508dc8 /packages/core/src
parent7c527b4d8a72159954405e720d5bf776802dc0ff (diff)
downloaddispatch-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.ts14
-rw-r--r--packages/core/src/index.ts1
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";