fix(v2): reviewer bugfixes — scroll, block-status, NaN guard, dead code cleanup
CI - Build & Test / Backend (.NET) (push) Failing after 22s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 15s
CI - Build & Test / Security Check (push) Successful in 3s

This commit is contained in:
2026-06-12 00:51:42 +02:00
parent 166c9f9051
commit 6023b5ea24
7 changed files with 941 additions and 22 deletions
+116 -3
View File
@@ -15,6 +15,8 @@ import IrisChat from '../../components/dashboard/v2/IrisChat.vue'
import type { ChatMessage } from '../../components/dashboard/v2/types'
import TaskStrip from '../../components/dashboard/v2/TaskStrip.vue'
import type { TaskItem } from '../../components/dashboard/v2/types'
import AgentDetailModal from '../../components/dashboard/v2/AgentDetailModal.vue'
import type { AgentDetail, ThinkingItem } from '../../components/dashboard/v2/types'
import { mockAgents, extraAgentPool } from '../../composables/useFlowLayout'
import type { AgentNodeData } from '../../composables/useFlowLayout'
@@ -25,8 +27,108 @@ const enteringIds = ref<string[]>([])
const agentPool = ref<AgentNodeData[]>(extraAgentPool)
/* ── Agent Detail Modal State ──────────────────────── */
const selectedAgentId = ref<string | null>(null)
const modalOpen = computed(() => selectedAgentId.value !== null)
const agentOrder = computed(() => agents.value.map(a => a.id))
const availableModels = [
{ id: 'deepseek-v4-flash', alias: 'Deepseek V4 Flash' },
{ id: 'deepseek-v4-pro', alias: 'Deepseek V4 Pro' },
{ id: 'gpt-4o', alias: 'GPT-4o' },
{ id: 'claude-35-sonnet', alias: 'Claude 3.5 Sonnet' },
]
/**
* Erzeugt simulierte Thinking-Items aus einem AgentNodeData.think-String.
*/
function buildThinkingItems(data: AgentNodeData): ThinkingItem[] {
if (!data.think) return []
const now = new Date()
const ts = (ago: number) => {
const d = new Date(now.getTime() - ago * 1000)
return d.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' })
}
// Aus dem think-String mehrere simulierte Items erzeugen
const items: ThinkingItem[] = []
const sentences = data.think.split(/[.…!?]+/).filter(s => s.trim().length > 5)
if (sentences.length >= 2) {
items.push({ type: 'thought', text: sentences[0].trim() + '.', ts: ts(30) })
items.push({ type: 'action', text: sentences[1].trim() + '…', ts: ts(18) })
if (sentences.length >= 3) {
items.push({ type: 'result', text: sentences[sentences.length - 1].trim() + '.', ts: ts(3) })
} else {
items.push({ type: 'result', text: 'Verarbeitung abgeschlossen.', ts: ts(3) })
}
} else if (sentences.length === 1) {
items.push({ type: 'thought', text: sentences[0].trim(), ts: ts(15) })
items.push({ type: 'action', text: 'Analysiere Daten und erstelle nächsten Schritt…', ts: ts(6) })
} else {
items.push({ type: 'thought', text: data.think, ts: ts(10) })
}
return items
}
/**
* Konvertiert AgentNodeData → AgentDetail für das Modal.
*/
function buildAgentDetail(data: AgentNodeData): AgentDetail {
// Aus tokens/cost die numerischen Werte extrahieren
const tokenNum = parseFloat(data.tokens?.replace(/[^0-9.]/g, '') || '0')
const tokenMultiplier = data.tokens?.includes('M') ? 1_000_000 : data.tokens?.includes('k') ? 1_000 : 1
const tokensToday = Math.round(tokenNum * tokenMultiplier)
const costNum = parseFloat(data.cost || '0')
const progress = data.progress || 0
return {
id: data.id,
name: data.name,
role: data.role,
model: data.model,
status: data.status === 'block' ? 'idle' : data.status,
tokensToday,
costToday: costNum,
workload: progress,
uptime: data.elapsed || '—',
lastActive: data.elapsed !== '—' ? 'Vor ' + data.elapsed : 'Nicht aktiv',
activeTaskCount: data.task ? 1 : 0,
thinking: buildThinkingItems(data),
availableModels,
}
}
const selectedAgent = computed<AgentDetail | null>(() => {
if (!selectedAgentId.value) return null
const data = agents.value.find(a => a.id === selectedAgentId.value)
if (!data) return null
return buildAgentDetail(data)
})
function handleSelect(id: string) {
console.log('[FlowBoard] selected agent:', id)
selectedAgentId.value = id
}
function handleCloseModal() {
selectedAgentId.value = null
}
function handleAgentSelect(id: string) {
// Zum nächsten/vorherigen Agenten springen (Pfeiltasten)
selectedAgentId.value = id
}
function handleChangeModel(agentId: string, modelId: string) {
const agent = agents.value.find(a => a.id === agentId)
if (agent) {
agent.model = modelId
}
}
function handleAdd() {
@@ -62,8 +164,9 @@ const todayCost = computed(() => {
})
const todayTokens = computed(() => {
const total = agents.value.reduce((s, a) => {
const v = a.tokens?.replace(/[^0-9.]/g, '')
return v ? s + parseFloat(v) : s
const raw = a.tokens?.replace(/[^0-9.]/g, '') || '0'
const v = parseFloat(raw)
return Number.isFinite(v) ? s + v : s
}, 0)
return total >= 1000 ? Math.round(total / 1000) + 'k' : Math.round(total) + ''
})
@@ -213,6 +316,16 @@ const tasks = ref<TaskItem[]>([
@send="handleChatSend"
/>
</div>
<!-- Agent Detail Modal -->
<AgentDetailModal
v-if="modalOpen && selectedAgent"
:agent="selectedAgent"
:agent-order="agentOrder"
@close="handleCloseModal"
@select="handleAgentSelect"
@change-model="handleChangeModel"
/>
</div>
</template>