tab-close + chat archive/delete + landing-card buttons + 1000px content cap

Feature 1 — Tab close menu (pure local pane state, no API):
- ChatTabBar context menu: Rename / sep / Close / Close others / Close to right / Close all
- Workspace bulk-tab primitives: closeOtherTabs, closeTabsToRight, closeAllTabs (manipulate panes[].chatIds, no fetch)
- Drop in-bar Delete; landing card's name-typed Delete is the canonical destructive path

Feature 2 — Chat archive + delete:
- chats.status vocabulary aligned with projects ('open' | 'archived'); DROP old inline CHECK, UPDATE 'closed' → 'archived', ADD new named chats_status_chk
- POST /api/chats/:id/archive (204) + POST /api/chats/:id/unarchive (200) + GET /api/sessions/:id/chats?status=archived; DELETE publishes chat_deleted; PATCH simplified to name-only
- 3 new WS frames: chat_archived, chat_unarchived, chat_deleted (renamed from chat_closed)
- Same dedup discipline: server-only publish, no local sessionEvents.emit in client
- SessionLandingPage: right-click ContextMenu (Open / Rename / Archive / sep / Delete-destructive), inline rename, archive confirm dialog, delete dialog with name-typed Input gated until typed text === chat.name, Archived chats collapsible section with Restore
- Card-level Archive + Delete icon buttons reusing the same dialog state setters; stopPropagation on both so card click still opens the chat; archived cards keep only Restore

UX — chat content width cap:
- ChatPane content (MessageList, queue chips, stop button, ChatInput) wrapped in inner max-w-[1000px] mx-auto w-full so messages center; outer border-t / scroll containers stay full-width so pane chrome and backgrounds remain edge-to-edge
- No new deps, no media queries (narrow viewports collapse to width naturally)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 03:21:26 +00:00
parent 48a972e139
commit e09c67d65c
13 changed files with 475 additions and 139 deletions

View File

@@ -77,7 +77,7 @@ CREATE TABLE IF NOT EXISTS chats (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
name TEXT,
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'closed')),
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'archived')),
created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp()
);
@@ -144,3 +144,17 @@ BEGIN
CHECK (status IN ('open', 'archived'));
END IF;
END $$;
-- v1.3-tab-close-chat-archive: align chats.status vocabulary with projects ('archived' not 'closed')
-- KEEP IN SYNC: apps/server/src/types/api.ts CHAT_STATUSES
-- Order matters: (1) drop the OLD inline CHECK that only allowed ('open','closed');
-- (2) migrate existing rows; (3) add new named CHECK allowing ('open','archived').
ALTER TABLE chats DROP CONSTRAINT IF EXISTS chats_status_check;
UPDATE chats SET status = 'archived' WHERE status = 'closed';
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'chats_status_chk') THEN
ALTER TABLE chats ADD CONSTRAINT chats_status_chk
CHECK (status IN ('open', 'archived'));
END IF;
END $$;