refactor(frontend): deduplicate CSS keyframes, unify types, extract format utils, add UI states, trim mock data
CI - Build & Test / Backend (.NET) (push) Failing after 23s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 16s
CI - Build & Test / Security Check (push) Successful in 3s

- Remove duplicate @keyframes pulse-* from 3 component files (already in nexus-tokens.css)
- Rename AgentDetail → AgentDetailData in dashboard types to avoid collision with types/agent.ts
- Extract shared formatNumber/initials/formatTime to utils/format.ts
- Simplify FlowBoard: use agentStore modal/selection getters instead of duplicating local state
- Add error banner + empty state to IrisChat; add loading skeleton + error/empty states to TaskStrip
- Remove 105-line unused mockAgents array from useFlowLayout
- Reduce operations store fallbacks from hardcoded preview data to minimal safe defaults
- Update operations store tests to match lean fallback structure
- Net: -73 lines, cleaner imports, fewer magic strings
This commit is contained in:
2026-06-12 17:02:50 +02:00
parent 9033ff2973
commit 6cedd8410f
14 changed files with 173 additions and 246 deletions
+9 -37
View File
@@ -12,7 +12,7 @@
*
* Polling startet bei Mount, stoppt bei Unmount.
*/
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { ref, onMounted, onUnmounted } from 'vue'
import { useAgentStore } from '../../stores/agents'
import { useChatStore } from '../../stores/chat'
import { useTaskStore } from '../../stores/tasks'
@@ -21,7 +21,6 @@ import FlowCanvas from '../../components/dashboard/v2/FlowCanvas.vue'
import IrisChat from '../../components/dashboard/v2/IrisChat.vue'
import TaskStrip from '../../components/dashboard/v2/TaskStrip.vue'
import AgentDetailModal from '../../components/dashboard/v2/AgentDetailModal.vue'
import { buildAgentDetail } from '../../stores/agents'
import type { AgentNodeData } from '../../composables/useFlowLayout'
import { extraAgentPool } from '../../composables/useFlowLayout'
@@ -35,42 +34,14 @@ const agentPositions = ref<Record<string, { x: number; y: number }>>({})
const enteringIds = ref<string[]>([])
const localAgentPool = ref<AgentNodeData[]>([...extraAgentPool])
/* ── Modal State ──────────────────────────────────── */
const selectedAgentId = ref<string | null>(null)
const modalOpen = computed(() => selectedAgentId.value !== null)
const agentOrder = computed(() => {
const ids = agentStore.agentList.map(a => a.id)
// Iris first
const irisIdx = ids.indexOf('iris')
if (irisIdx > 0) {
ids.splice(irisIdx, 1)
ids.unshift('iris')
}
return ids
})
const selectedAgent = computed(() => {
if (!selectedAgentId.value) return null
const data = agentStore.agentList.find(a => a.id === selectedAgentId.value)
if (!data) return null
// Build AgentDetail using the store's available models
return agentStore.models.length > 0
? buildAgentDetail(data, agentStore.models)
: null
})
/* ── Event Handlers ───────────────────────────────── */
function handleSelect(id: string) {
selectedAgentId.value = id
agentStore.selectAgent(id)
}
function handleCloseModal() {
selectedAgentId.value = null
}
function handleAgentSelect(id: string) {
selectedAgentId.value = id
agentStore.selectAgent(null)
}
function handleChangeModel(agentId: string, modelAlias: string) {
@@ -149,24 +120,25 @@ onUnmounted(() => {
@update-positions="handleUpdatePositions"
/>
<TaskStrip :tasks="taskStore.taskList" />
<TaskStrip :tasks="taskStore.taskList" :loading="taskStore.loading" :error="taskStore.error" />
</div>
<!-- Rail: IrisChat -->
<IrisChat
:messages="chatStore.messageList"
:is-thinking="chatStore.isThinking"
:error="chatStore.error"
@send="handleChatSend"
/>
</div>
<!-- Agent Detail Modal -->
<AgentDetailModal
v-if="modalOpen && selectedAgent"
:agent="selectedAgent"
:agent-order="agentOrder"
v-if="agentStore.modalOpen && agentStore.selectedAgent"
:agent="agentStore.selectedAgent"
:agent-order="agentStore.agentOrder"
@close="handleCloseModal"
@select="handleAgentSelect"
@select="handleSelect"
@change-model="handleChangeModel"
/>
</div>