Project Workspace view, abort button, session invalidation, workspace fixes

Workspace (/workspace/:projectId):
- Three-panel layout (tasks / chat / notes) with CSS grid collapse toggles
- WorkspaceTaskPanel: tasks grouped by milestone, collapsible groups, task
  detail slide-over with status cycling, TaskLogSection work log, and
  inline-confirm delete
- WorkspaceNoteEditor: list view (sorted by updated_at, inline tag pills,
  inline-confirm delete) with editor view (TipTap, TagInput, Suggest tags,
  60s autosave)
- Persistent workspace conversation stored in localStorage per project;
  reused on return visits
- Thinking enabled (think: true) with Reasoning block in streaming bubble
- workspace_project_id backend pipeline: chat.py → generation_task.py →
  llm.py; system prompt uses project title so agent passes project="Title"
  to tools (fixes create_note failing with numeric project string)
- SSE tool-call watcher bridges agent actions to panel updates
- Height fix: workspace-root uses height 100%; app-content switches to
  overflow hidden via :has() selector
- Entry point: "Open Workspace" button on ProjectView

Abort button:
- Stop button in ChatView header and WorkspaceView input bar
- Calls existing cancelGeneration() / POST .../generation/cancel

Session invalidation:
- POST /api/auth/invalidate-sessions bumps session_version, keeps current
  session alive; useful after SSO/OAuth password rotation
- Button in Settings → Active Sessions section

Other:
- Dashboard recent notes limit increased from 8 to 16
- Workspace chat abort replaces Send button while streaming

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-07 11:34:06 -05:00
parent a8bb687349
commit 74ebb8a87f
15 changed files with 1927 additions and 9 deletions
+1 -1
View File
@@ -122,7 +122,7 @@ onMounted(async () => {
const [notesRes, overdueRes, dueSoonRes, highPriRes, inProgressRes, otherRes] =
await Promise.allSettled([
apiGet<NoteListResponse>("/api/notes?sort=updated_at&order=desc&limit=8"),
apiGet<NoteListResponse>("/api/notes?sort=updated_at&order=desc&limit=16"),
apiGet<TaskListResponse>(`/api/tasks?due_before=${today}&sort=due_date&order=asc&limit=20`),
apiGet<TaskListResponse>(`/api/tasks?due_after=${today}&due_before=${nextWeek}&sort=due_date&order=asc&limit=20`),
apiGet<TaskListResponse>(`/api/tasks?priority=high&sort=updated_at&order=desc&limit=10`),