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:
@@ -21,6 +21,7 @@ const currentPassword = ref("");
|
||||
const newPassword = ref("");
|
||||
const confirmNewPassword = ref("");
|
||||
const changingPassword = ref(false);
|
||||
const invalidatingSessions = ref(false);
|
||||
const saving = ref(false);
|
||||
const saved = ref(false);
|
||||
const exporting = ref(false);
|
||||
@@ -155,6 +156,18 @@ async function changeEmail() {
|
||||
}
|
||||
}
|
||||
|
||||
async function invalidateSessions() {
|
||||
invalidatingSessions.value = true;
|
||||
try {
|
||||
await apiPost("/api/auth/invalidate-sessions", {});
|
||||
toastStore.show("All other sessions have been invalidated");
|
||||
} catch {
|
||||
toastStore.show("Failed to invalidate sessions", "error");
|
||||
} finally {
|
||||
invalidatingSessions.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function changePassword() {
|
||||
if (newPassword.value !== confirmNewPassword.value) {
|
||||
toastStore.show("New passwords do not match", "error");
|
||||
@@ -457,6 +470,20 @@ function hostname(url: string): string {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Invalidate Sessions ── half width ── -->
|
||||
<section class="settings-section">
|
||||
<h2>Active Sessions</h2>
|
||||
<p class="section-desc">
|
||||
Sign out all other devices and sessions. Use this after an SSO password change
|
||||
to ensure stale sessions are revoked.
|
||||
</p>
|
||||
<div class="actions">
|
||||
<button class="btn-danger-outline" @click="invalidateSessions" :disabled="invalidatingSessions">
|
||||
{{ invalidatingSessions ? "Invalidating..." : "Invalidate All Other Sessions" }}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Change Password ── half width ── -->
|
||||
<section class="settings-section">
|
||||
<h2>Change Password</h2>
|
||||
@@ -882,6 +909,23 @@ function hostname(url: string): string {
|
||||
.btn-save:disabled { opacity: 0.6; cursor: default; }
|
||||
.btn-save:hover:not(:disabled) { opacity: 0.9; }
|
||||
|
||||
.btn-danger-outline {
|
||||
padding: 0.4rem 0.9rem;
|
||||
background: none;
|
||||
color: var(--color-danger, #e74c3c);
|
||||
border: 1px solid var(--color-danger, #e74c3c);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
font-family: inherit;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.btn-danger-outline:hover:not(:disabled) {
|
||||
background: var(--color-danger, #e74c3c);
|
||||
color: #fff;
|
||||
}
|
||||
.btn-danger-outline:disabled { opacity: 0.5; cursor: default; }
|
||||
|
||||
.btn-secondary {
|
||||
padding: 0.4rem 0.9rem;
|
||||
background: var(--color-bg-secondary);
|
||||
|
||||
Reference in New Issue
Block a user