import { useState, useEffect, useCallback } from 'react' import type { PipelineStatus, PipelineRun, SystemStats, DockerStats, WoodpeckerStatus, TabType, ContainerFilter, ContainerInfo, } from './types' export interface CiCdData { // Tab activeTab: TabType setActiveTab: (tab: TabType) => void // Pipeline pipelineStatus: PipelineStatus | null pipelineHistory: PipelineRun[] triggeringPipeline: boolean triggerPipeline: () => Promise // Container systemStats: SystemStats | null dockerStats: DockerStats | null containerFilter: ContainerFilter setContainerFilter: (f: ContainerFilter) => void filteredContainers: ContainerInfo[] actionLoading: string | null containerAction: (containerId: string, action: 'start' | 'stop' | 'restart') => Promise loadContainerData: () => Promise // Woodpecker woodpeckerStatus: WoodpeckerStatus | null triggeringWoodpecker: boolean triggerWoodpeckerPipeline: () => Promise // General loading: boolean error: string | null message: string | null } export function useCiCdData(): CiCdData { const [activeTab, setActiveTab] = useState('overview') // Pipeline State const [pipelineStatus, setPipelineStatus] = useState(null) const [pipelineHistory, setPipelineHistory] = useState([]) const [triggeringPipeline, setTriggeringPipeline] = useState(false) // Container State const [systemStats, setSystemStats] = useState(null) const [dockerStats, setDockerStats] = useState(null) const [containerFilter, setContainerFilter] = useState('all') const [actionLoading, setActionLoading] = useState(null) // Woodpecker State const [woodpeckerStatus, setWoodpeckerStatus] = useState(null) const [triggeringWoodpecker, setTriggeringWoodpecker] = useState(false) // General State const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [message, setMessage] = useState(null) const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL || '' // ============================================================================ // Data Loading // ============================================================================ const loadPipelineData = useCallback(async () => { try { const [statusRes, historyRes] = await Promise.all([ fetch(`${BACKEND_URL}/api/v1/security/sbom/pipeline/status`), fetch(`${BACKEND_URL}/api/v1/security/sbom/pipeline/history`), ]) if (statusRes.ok) { setPipelineStatus(await statusRes.json()) } if (historyRes.ok) { setPipelineHistory(await historyRes.json()) } } catch (err) { console.error('Failed to load pipeline data:', err) } }, [BACKEND_URL]) const loadContainerData = useCallback(async () => { try { const response = await fetch('/api/admin/infrastructure/mac-mini') if (response.ok) { const data = await response.json() setSystemStats(data.system) setDockerStats(data.docker) } } catch (err) { console.error('Failed to load container data:', err) } }, []) const loadWoodpeckerData = useCallback(async () => { try { const response = await fetch('/api/admin/infrastructure/woodpecker?limit=10') if (response.ok) { const data = await response.json() setWoodpeckerStatus(data) } } catch (err) { console.error('Failed to load Woodpecker data:', err) setWoodpeckerStatus({ status: 'offline', pipelines: [], lastUpdate: new Date().toISOString(), error: 'Verbindung fehlgeschlagen' }) } }, []) const loadAllData = useCallback(async () => { setLoading(true) setError(null) await Promise.all([loadPipelineData(), loadContainerData(), loadWoodpeckerData()]) setLoading(false) }, [loadPipelineData, loadContainerData, loadWoodpeckerData]) useEffect(() => { loadAllData() }, [loadAllData]) // Auto-refresh every 30 seconds useEffect(() => { const interval = setInterval(loadAllData, 30000) return () => clearInterval(interval) }, [loadAllData]) // ============================================================================ // Actions // ============================================================================ const triggerPipeline = async () => { setTriggeringPipeline(true) try { const response = await fetch(`${BACKEND_URL}/api/v1/security/sbom/pipeline/trigger`, { method: 'POST', }) if (response.ok) { setMessage('Pipeline gestartet!') setTimeout(loadPipelineData, 2000) setTimeout(loadPipelineData, 5000) } } catch (err) { setError('Pipeline-Trigger fehlgeschlagen') } finally { setTriggeringPipeline(false) } } const triggerWoodpeckerPipeline = async () => { setTriggeringWoodpecker(true) setMessage(null) try { const response = await fetch('/api/admin/infrastructure/woodpecker', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ branch: 'main' }) }) if (response.ok) { const result = await response.json() setMessage(`Woodpecker Pipeline #${result.pipeline?.number || '?'} gestartet!`) setTimeout(loadWoodpeckerData, 2000) setTimeout(loadWoodpeckerData, 5000) } else { setError('Pipeline-Start fehlgeschlagen') } } catch (err) { setError('Pipeline konnte nicht gestartet werden') } finally { setTriggeringWoodpecker(false) } } const containerAction = async (containerId: string, action: 'start' | 'stop' | 'restart') => { setActionLoading(`${containerId}-${action}`) setMessage(null) try { const response = await fetch('/api/admin/infrastructure/mac-mini', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ container_id: containerId, action }), }) if (!response.ok) { throw new Error('Aktion fehlgeschlagen') } setMessage(`Container ${action} erfolgreich`) setTimeout(loadContainerData, 1000) setTimeout(loadContainerData, 3000) } catch (err) { setError(err instanceof Error ? err.message : 'Fehler') } finally { setActionLoading(null) } } // ============================================================================ // Derived // ============================================================================ const filteredContainers = dockerStats?.containers.filter(c => { if (containerFilter === 'all') return true if (containerFilter === 'running') return c.state === 'running' if (containerFilter === 'stopped') return c.state !== 'running' return true }) || [] return { activeTab, setActiveTab, pipelineStatus, pipelineHistory, triggeringPipeline, triggerPipeline, systemStats, dockerStats, containerFilter, setContainerFilter, filteredContainers, actionLoading, containerAction, loadContainerData, woodpeckerStatus, triggeringWoodpecker, triggerWoodpeckerPipeline, loading, error, message, } }