feat: Add canvas gallery with soft delete, snapshots and components
Replace the empty dynamic canvas placeholder with a gallery showing saved canvases, snapshots and Vue components. Users can create new canvases, restore snapshots, load components, and manage canvas toolbar/archive settings from the gallery. - Backend: soft delete (archive) instead of hard delete, status column - Frontend: CanvasGallery component with grid, search, settings popover - Show canvas name in global header when viewing a project canvas - Remove ProjectsPage (replaced by gallery), clean all references - MCP tools: project category available on canvas page, update handlers
This commit is contained in:
@@ -14,6 +14,7 @@ import { initToolRegistry, activatePageTools, initToolsOnRefresh } from './servi
|
||||
import { setTerminalControls } from './services/tools/handlers/terminalHandlers'
|
||||
import { setResponseControls } from './services/tools/handlers/responseHandlers'
|
||||
import { useCanvasStore } from './stores/canvas'
|
||||
import { useProjectCanvasStore } from './stores/projectCanvas'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@@ -63,6 +64,7 @@ const terminalRef = ref<InstanceType<typeof FloatingTerminal> | null>(null)
|
||||
const responseRef = ref<InstanceType<typeof FloatingResponse> | null>(null)
|
||||
const voiceRef = ref<InstanceType<typeof FloatingVoice> | null>(null)
|
||||
const canvasStore = useCanvasStore()
|
||||
const projectCanvasStore = useProjectCanvasStore()
|
||||
|
||||
// Voice FAB push-to-talk state
|
||||
const voicePTTActive = ref(false)
|
||||
@@ -238,7 +240,7 @@ function triggerToolFlash() {
|
||||
}, 500)
|
||||
}
|
||||
|
||||
type PageName = 'home' | 'canvas' | 'components' | 'themes' | 'projects' | 'project-canvas' | 'database' | 'source' | 'terminal' | 'tools'
|
||||
type PageName = 'home' | 'canvas' | 'components' | 'themes' | 'project-canvas' | 'database' | 'source' | 'terminal' | 'tools'
|
||||
|
||||
onMounted(async () => {
|
||||
// Connect to WebSocket for Claude status updates
|
||||
@@ -350,6 +352,11 @@ watch(() => route.name, (newPage) => {
|
||||
<header class="app-header">
|
||||
<div class="header-left">
|
||||
<h1 class="logo">Agent UI</h1>
|
||||
<template v-if="projectCanvasStore.activeCanvas && route.name === 'project-canvas'">
|
||||
<span class="header-sep">/</span>
|
||||
<span class="header-canvas-name">{{ projectCanvasStore.activeCanvas.name }}</span>
|
||||
<span v-if="projectCanvasStore.activeCanvas.is_system" class="header-canvas-badge">Sistema</span>
|
||||
</template>
|
||||
<button class="debug-btn" :class="{ active: showDebugConsole }" @click="showDebugConsole = !showDebugConsole" title="Debug Console">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
|
||||
@@ -561,6 +568,27 @@ watch(() => route.name, (newPage) => {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-sep {
|
||||
color: var(--text-muted);
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.header-canvas-name {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.header-canvas-badge {
|
||||
padding: 0.125rem 0.5rem;
|
||||
background: rgba(99, 102, 241, 0.15);
|
||||
color: #6366f1;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 500;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user