diff --git a/frontend/src/components/dashboard/MissionCard.vue b/frontend/src/components/dashboard/MissionCard.vue index f74b45b..824267b 100644 --- a/frontend/src/components/dashboard/MissionCard.vue +++ b/frontend/src/components/dashboard/MissionCard.vue @@ -1,79 +1,77 @@ diff --git a/frontend/src/components/dashboard/OperationsFeed.vue b/frontend/src/components/dashboard/OperationsFeed.vue index ba1c878..5a23da0 100644 --- a/frontend/src/components/dashboard/OperationsFeed.vue +++ b/frontend/src/components/dashboard/OperationsFeed.vue @@ -1,10 +1,52 @@ @@ -121,9 +217,8 @@ defineProps<{ } .feed-action { color: #7e8799; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + white-space: normal; + word-break: break-word; } .feed-empty { @@ -133,6 +228,26 @@ defineProps<{ color: #6b7385; } +.feed-more-btn { + display: block; + width: 100%; + padding: 8px; + margin-top: 4px; + background: rgba(139, 124, 246, 0.08); + border: 1px solid rgba(139, 124, 246, 0.12); + border-radius: 8px; + color: #a78bfa; + font-size: 9.5px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s; + text-align: center; +} +.feed-more-btn:hover { + background: rgba(139, 124, 246, 0.14); + border-color: rgba(139, 124, 246, 0.2); +} + /* TransitionGroup */ .feed-enter-active { transition: all 0.3s ease; @@ -152,4 +267,104 @@ defineProps<{ .feed-move { transition: transform 0.3s ease; } + +/* ── Modal Overlay ── */ +:global(.modal-overlay) { + position: fixed; + inset: 0; + z-index: 1000; + display: grid; + place-items: center; + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(4px); + padding: 20px; +} +:global(.modal-content) { + background: #161b22; + border: 1px solid rgba(139, 124, 246, 0.15); + border-radius: 16px; + padding: 24px; + width: 100%; + max-width: 520px; + max-height: 80vh; + display: flex; + flex-direction: column; + gap: 16px; + box-shadow: 0 8px 40px rgba(0, 0, 0, 0.5); +} +:global(.modal-header) { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} +:global(.modal-title) { + margin: 0; + font-size: 15px; + font-weight: 600; + color: #e8eaf0; +} +:global(.modal-close-btn) { + display: grid; + place-items: center; + width: 28px; + height: 28px; + border: none; + background: rgba(255, 255, 255, 0.05); + border-radius: 6px; + color: #7e8799; + cursor: pointer; + transition: all 0.15s; +} +:global(.modal-close-btn:hover) { + background: rgba(255, 255, 255, 0.1); + color: #e8eaf0; +} +:global(.modal-nav) { + display: flex; + align-items: center; + justify-content: center; + gap: 12px; +} +:global(.nav-btn) { + display: grid; + place-items: center; + width: 30px; + height: 30px; + border: 1px solid rgba(139, 124, 246, 0.15); + background: rgba(139, 124, 246, 0.08); + border-radius: 8px; + color: #a78bfa; + cursor: pointer; + transition: all 0.15s; +} +:global(.nav-btn:hover:not(:disabled)) { + background: rgba(139, 124, 246, 0.16); + border-color: rgba(139, 124, 246, 0.3); +} +:global(.nav-btn:disabled) { + opacity: 0.3; + cursor: not-allowed; +} +:global(.nav-label) { + font-size: 12px; + font-weight: 600; + color: #d1d5db; + min-width: 100px; + text-align: center; +} +:global(.modal-entries) { + display: flex; + flex-direction: column; + gap: 4px; + overflow-y: auto; + max-height: 50vh; + padding-right: 4px; +} +:global(.modal-empty) { + text-align: center; + padding: 24px 0; + font-size: 11px; + color: #6b7385; +} diff --git a/frontend/src/components/dashboard/TeamNetwork.vue b/frontend/src/components/dashboard/TeamNetwork.vue index 1cb4e3e..c4457dd 100644 --- a/frontend/src/components/dashboard/TeamNetwork.vue +++ b/frontend/src/components/dashboard/TeamNetwork.vue @@ -356,19 +356,20 @@ onUnmounted(() => { {{ hero.role }}

{{ hero.description }}

- - - {{ hero.task }} - +
+ + + {{ hero.task }} + + {{ hero.runtime }} +
{{ tag }}
- @@ -402,19 +403,20 @@ onUnmounted(() => { {{ agent.role }}

{{ agent.description }}

- - - {{ agent.task }} - +
+ + + {{ agent.task }} + + {{ agent.runtime }} +
{{ tag }}
- @@ -535,6 +537,38 @@ onUnmounted(() => { line-height: 1.5; margin: 0 0 8px; } + +/* ── Task + Runtime Row ── */ +.task-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: 8px; +} +.node-task { + display: inline-flex; + align-items: center; + font-size: 10px; + color: #9ea5b3; + line-height: 1.4; + flex: 1; + min-width: 0; +} +.node-task-dot { + display: inline-block; + margin-right: 4px; + font-size: 8px; + vertical-align: middle; +} +.node-runtime { + font-size: 9px; + color: #6b7385; + font-variant-numeric: tabular-nums; + flex-shrink: 0; +} + +/* ── Tags ── */ .card-tags { display: flex; flex-wrap: wrap; @@ -548,49 +582,25 @@ onUnmounted(() => { border-radius: 5px; letter-spacing: 0.02em; } -.card-footer-action { - display: flex; - align-items: center; - justify-content: flex-end; - gap: 6px; - margin-top: 12px; - padding-top: 10px; - border-top: 1px solid var(--line, #1f2330); - font-size: 9px; - font-weight: 600; + +/* ── Hover Arrow (bottom-right) ── */ +.card-arrow { + position: absolute; + right: 12px; + bottom: 12px; color: #6b7385; - text-transform: uppercase; - letter-spacing: 0.06em; + opacity: 0; + transform: translateX(-6px); + transition: opacity 0.2s ease, transform 0.2s ease; } -.card-footer-action .arrow { - font-size: 13px; +.agent-card:hover .card-arrow { + opacity: 1; + transform: translateX(0); +} +.arrow-icon { + font-size: 14px; line-height: 1; -} -.agent-card:hover .card-footer-action { - color: var(--card-color, #8b7cf6); -} - -/* ── Node Task ── */ -.node-task { display: block; - font-size: 10px; - color: #9ea5b3; - margin-bottom: 8px; - line-height: 1.4; -} -.node-task-dot { - display: inline-block; - margin-right: 4px; - font-size: 8px; - vertical-align: middle; -} - -/* ── Node Runtime ── */ -.node-runtime { - font-size: 9px; - color: #6b7385; - font-variant-numeric: tabular-nums; - margin-left: auto; } @media (max-width: 720px) { diff --git a/frontend/src/composables/useDashboardData.ts b/frontend/src/composables/useDashboardData.ts index dc07307..3641289 100644 --- a/frontend/src/composables/useDashboardData.ts +++ b/frontend/src/composables/useDashboardData.ts @@ -17,21 +17,19 @@ export interface AgentNodeData { thinkingStream?: Array<{ time: string; text: string }> } -export interface MissionData { +export interface OpenTask { id: string - name: string - progress: number - currentTask: string - lastActivity: string - remainingTasks: number - status: 'healthy' | 'attention' | 'blocked' | 'paused' + title: string + detail: string + source: 'bao' | 'iris' + createdAt: string } export interface FeedEntry { time: string agent: string action: string - timestamp: number + timestamp: string } export interface ChatMessage { @@ -226,56 +224,24 @@ export function useDashboardData() { }, ]) - // Missions - const missions = ref([ - { - id: 'dungeon-system', - name: 'Dungeon System', - progress: 62, - currentTask: 'Implement room generation', - lastActivity: '3 min ago', - remainingTasks: 8, - status: 'healthy', - }, - { - id: 'dashboard-redesign', - name: 'Dashboard Redesign', - progress: 45, - currentTask: 'AI Team Network layout', - lastActivity: 'Just now', - remainingTasks: 6, - status: 'healthy', - }, - { - id: 'infra-optimization', - name: 'Infra Optimization', - progress: 30, - currentTask: 'Optimize build caching', - lastActivity: '12 min ago', - remainingTasks: 4, - status: 'attention', - }, - { - id: 'auth-system', - name: 'Auth System', - progress: 88, - currentTask: 'Finalize refresh token flow', - lastActivity: '45 min ago', - remainingTasks: 2, - status: 'healthy', - }, + // Open Tasks + const openTasks = ref([ + { id: 't1', title: 'Agent Thinking Panel visualisieren', detail: 'Live-Animation der Denkprozesse im AgentModal', source: 'iris', createdAt: '22:30' }, + { id: 't2', title: 'CI/CD Pipeline Monitoring Dashboard', detail: 'Echtzeit-Status der Gitea Actions im Dashboard', source: 'iris', createdAt: '21:15' }, + { id: 't3', title: 'Dungeon System Dokumentation', detail: 'API-Doku für Room-Generation-Endpunkte schreiben', source: 'bao', createdAt: '20:00' }, ]) // Feed + const ts = (offset: number) => new Date(now + offset).toISOString() const feedEntries = ref([ - { time: '20:42', agent: 'Developer', action: 'Created DungeonController endpoints', timestamp: now - 60000 }, - { time: '20:38', agent: 'DevOps', action: 'Optimized Docker COPY order', timestamp: now - 300000 }, - { time: '20:35', agent: 'Iris', action: 'Delegated room generation to Developer', timestamp: now - 540000 }, - { time: '20:28', agent: 'Researcher', action: 'Documented WebSocket vs SSE analysis', timestamp: now - 780000 }, - { time: '20:22', agent: 'Reviewer', action: 'Approved RoomValidator PR', timestamp: now - 900000 }, - { time: '20:15', agent: 'DevOps', action: 'Added .dockerignore for node_modules', timestamp: now - 1200000 }, - { time: '20:08', agent: 'Iris', action: 'Broke down Dungeon System tasks', timestamp: now - 1500000 }, - { time: '19:55', agent: 'Developer', action: 'Defined dungeon schema models', timestamp: now - 1800000 }, + { time: '22:50', agent: 'Developer', action: 'Created DungeonController endpoints', timestamp: ts(-120000) }, + { time: '22:46', agent: 'DevOps', action: 'Optimized Docker COPY order for layer caching', timestamp: ts(-360000) }, + { time: '22:42', agent: 'Iris', action: 'Delegated room generation to Developer with spec', timestamp: ts(-600000) }, + { time: '22:35', agent: 'Researcher', action: 'Documented WebSocket vs SSE analysis results', timestamp: ts(-960000) }, + { time: '22:28', agent: 'Reviewer', action: 'Approved RoomValidator PR with minor fixes', timestamp: ts(-1200000) }, + { time: '22:18', agent: 'DevOps', action: 'Added .dockerignore for node_modules and build artifacts', timestamp: ts(-1500000) }, + { time: '22:08', agent: 'Iris', action: 'Broke down Dungeon System tasks into sub-tasks', timestamp: ts(-1800000) }, + { time: '21:55', agent: 'Developer', action: 'Defined dungeon schema models with validation', timestamp: ts(-2400000) }, ]) // Chat @@ -324,7 +290,7 @@ export function useDashboardData() { return { agents, - missions, + openTasks, feedEntries, chatMessages, irisBusy, diff --git a/frontend/src/views/DashboardView.vue b/frontend/src/views/DashboardView.vue index 5feee27..e7446d8 100644 --- a/frontend/src/views/DashboardView.vue +++ b/frontend/src/views/DashboardView.vue @@ -1,6 +1,6 @@