Website (14 monoliths split): - compliance/page.tsx (1,519 → 9), docs/audit (1,262 → 20) - quality (1,231 → 16), alerts (1,203 → 10), docs (1,202 → 11) - i18n.ts (1,173 → 8 language files) - unity-bridge (1,094 → 12), backlog (1,087 → 6) - training (1,066 → 8), rag (1,063 → 8) - Deleted index_original.ts (4,899 LOC dead backup) Studio-v2 (5 monoliths split): - meet/page.tsx (1,481 → 9), messages (1,166 → 9) - AlertsB2BContext.tsx (1,165 → 5 modules) - alerts-b2b/page.tsx (1,019 → 6), korrektur/archiv (1,001 → 6) All existing imports preserved. Zero new TypeScript errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
259 lines
6.6 KiB
TypeScript
259 lines
6.6 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect, useCallback } from 'react'
|
|
import type {
|
|
BridgeStatus,
|
|
LogEntry,
|
|
DiagnosticEntry,
|
|
UnitDefinition,
|
|
AnalyticsOverview,
|
|
GeneratedContent,
|
|
LogsResponse,
|
|
DiagnoseResponse,
|
|
TabId,
|
|
} from './types'
|
|
|
|
export function useUnityBridge() {
|
|
// Tab state
|
|
const [activeTab, setActiveTab] = useState<TabId>('editor')
|
|
|
|
// Editor tab state
|
|
const [status, setStatus] = useState<BridgeStatus | null>(null)
|
|
const [logs, setLogs] = useState<LogEntry[]>([])
|
|
const [diagnostics, setDiagnostics] = useState<DiagnosticEntry[]>([])
|
|
const [isLoading, setIsLoading] = useState(true)
|
|
const [isLoadingLogs, setIsLoadingLogs] = useState(false)
|
|
const [isLoadingDiagnose, setIsLoadingDiagnose] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
// Units tab state
|
|
const [units, setUnits] = useState<UnitDefinition[]>([])
|
|
const [selectedUnit, setSelectedUnit] = useState<UnitDefinition | null>(null)
|
|
const [isLoadingUnits, setIsLoadingUnits] = useState(false)
|
|
const [unitsError, setUnitsError] = useState<string | null>(null)
|
|
|
|
// Analytics tab state
|
|
const [analyticsOverview, setAnalyticsOverview] = useState<AnalyticsOverview | null>(null)
|
|
const [isLoadingAnalytics, setIsLoadingAnalytics] = useState(false)
|
|
|
|
// Content tab state
|
|
const [generatedContent, setGeneratedContent] = useState<GeneratedContent | null>(null)
|
|
const [isGenerating, setIsGenerating] = useState(false)
|
|
|
|
// Fetch status
|
|
const fetchStatus = useCallback(async () => {
|
|
try {
|
|
const res = await fetch('/api/admin/unity-bridge?action=status')
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
if (!data.offline) {
|
|
setStatus(data)
|
|
setError(null)
|
|
} else {
|
|
setError(data.error)
|
|
setStatus(null)
|
|
}
|
|
} else {
|
|
setError('Bridge nicht erreichbar')
|
|
setStatus(null)
|
|
}
|
|
} catch {
|
|
setError('Bridge offline - Server in Unity starten')
|
|
setStatus(null)
|
|
}
|
|
setIsLoading(false)
|
|
}, [])
|
|
|
|
// Fetch logs
|
|
const fetchLogs = useCallback(async () => {
|
|
setIsLoadingLogs(true)
|
|
try {
|
|
const res = await fetch('/api/admin/unity-bridge?action=logs&limit=50')
|
|
if (res.ok) {
|
|
const data: LogsResponse = await res.json()
|
|
if (data.logs) {
|
|
setLogs(data.logs)
|
|
}
|
|
}
|
|
} catch {
|
|
// Ignore errors for logs
|
|
}
|
|
setIsLoadingLogs(false)
|
|
}, [])
|
|
|
|
// Clear logs
|
|
const clearLogs = async () => {
|
|
try {
|
|
await fetch('/api/admin/unity-bridge?action=clear-logs', { method: 'POST' })
|
|
setLogs([])
|
|
} catch {
|
|
// Ignore errors
|
|
}
|
|
}
|
|
|
|
// Run diagnostics
|
|
const runDiagnose = async () => {
|
|
setIsLoadingDiagnose(true)
|
|
try {
|
|
const res = await fetch('/api/admin/unity-bridge?action=diagnose', { method: 'POST' })
|
|
if (res.ok) {
|
|
const data: DiagnoseResponse = await res.json()
|
|
if (data.diagnostics) {
|
|
setDiagnostics(data.diagnostics)
|
|
}
|
|
}
|
|
} catch {
|
|
// Ignore errors
|
|
}
|
|
setIsLoadingDiagnose(false)
|
|
}
|
|
|
|
// Send command
|
|
const sendCommand = async (command: string) => {
|
|
try {
|
|
await fetch(`/api/admin/unity-bridge?action=${command}`)
|
|
setTimeout(fetchStatus, 500)
|
|
} catch {
|
|
// Ignore errors
|
|
}
|
|
}
|
|
|
|
// Units Tab Functions
|
|
const fetchUnits = useCallback(async () => {
|
|
setIsLoadingUnits(true)
|
|
setUnitsError(null)
|
|
try {
|
|
const res = await fetch('/api/admin/unity-bridge?action=units-list')
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
if (Array.isArray(data)) {
|
|
setUnits(data)
|
|
} else if (data.offline) {
|
|
setUnitsError(data.error)
|
|
}
|
|
} else {
|
|
setUnitsError('Fehler beim Laden der Units')
|
|
}
|
|
} catch {
|
|
setUnitsError('Backend nicht erreichbar')
|
|
}
|
|
setIsLoadingUnits(false)
|
|
}, [])
|
|
|
|
const fetchUnitDetails = async (unitId: string) => {
|
|
try {
|
|
const res = await fetch(`/api/admin/unity-bridge?action=units-get&unit_id=${unitId}`)
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
setSelectedUnit(data.definition || data)
|
|
}
|
|
} catch {
|
|
// Ignore errors
|
|
}
|
|
}
|
|
|
|
// Analytics Tab Functions
|
|
const fetchAnalytics = useCallback(async () => {
|
|
setIsLoadingAnalytics(true)
|
|
try {
|
|
const res = await fetch('/api/admin/unity-bridge?action=analytics-overview')
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
if (!data.offline) {
|
|
setAnalyticsOverview(data)
|
|
}
|
|
}
|
|
} catch {
|
|
// Ignore errors
|
|
}
|
|
setIsLoadingAnalytics(false)
|
|
}, [])
|
|
|
|
// Content Tab Functions
|
|
const generateH5P = async (unitId: string) => {
|
|
setIsGenerating(true)
|
|
try {
|
|
const res = await fetch(`/api/admin/unity-bridge?action=content-h5p&unit_id=${unitId}`)
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
setGeneratedContent(data)
|
|
}
|
|
} catch {
|
|
// Ignore errors
|
|
}
|
|
setIsGenerating(false)
|
|
}
|
|
|
|
const generateWorksheet = async (unitId: string) => {
|
|
setIsGenerating(true)
|
|
try {
|
|
const res = await fetch(`/api/admin/unity-bridge?action=content-worksheet&unit_id=${unitId}`)
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
setGeneratedContent(data)
|
|
}
|
|
} catch {
|
|
// Ignore errors
|
|
}
|
|
setIsGenerating(false)
|
|
}
|
|
|
|
const downloadPdf = (unitId: string) => {
|
|
window.open(`/api/admin/unity-bridge?action=content-pdf&unit_id=${unitId}`, '_blank')
|
|
}
|
|
|
|
// Poll status every 5 seconds (Editor tab)
|
|
useEffect(() => {
|
|
fetchStatus()
|
|
fetchLogs()
|
|
const statusInterval = setInterval(fetchStatus, 5000)
|
|
const logsInterval = setInterval(fetchLogs, 10000)
|
|
return () => {
|
|
clearInterval(statusInterval)
|
|
clearInterval(logsInterval)
|
|
}
|
|
}, [fetchStatus, fetchLogs])
|
|
|
|
// Fetch data when tab changes
|
|
useEffect(() => {
|
|
if (activeTab === 'units' && units.length === 0) {
|
|
fetchUnits()
|
|
}
|
|
if (activeTab === 'analytics' && !analyticsOverview) {
|
|
fetchAnalytics()
|
|
}
|
|
}, [activeTab, units.length, analyticsOverview, fetchUnits, fetchAnalytics])
|
|
|
|
return {
|
|
activeTab,
|
|
setActiveTab,
|
|
status,
|
|
logs,
|
|
diagnostics,
|
|
isLoading,
|
|
isLoadingLogs,
|
|
isLoadingDiagnose,
|
|
error,
|
|
units,
|
|
selectedUnit,
|
|
setSelectedUnit,
|
|
isLoadingUnits,
|
|
unitsError,
|
|
analyticsOverview,
|
|
isLoadingAnalytics,
|
|
generatedContent,
|
|
setGeneratedContent,
|
|
isGenerating,
|
|
fetchLogs,
|
|
clearLogs,
|
|
runDiagnose,
|
|
sendCommand,
|
|
fetchUnits,
|
|
fetchUnitDetails,
|
|
fetchAnalytics,
|
|
generateH5P,
|
|
generateWorksheet,
|
|
downloadPdf,
|
|
}
|
|
}
|