0b9150f16f
Build + Deploy / build-admin-compliance (push) Successful in 2m16s
Build + Deploy / build-backend-compliance (push) Successful in 3m27s
Build + Deploy / build-ai-sdk (push) Successful in 58s
Build + Deploy / build-developer-portal (push) Successful in 1m13s
Build + Deploy / build-tts (push) Successful in 1m43s
Build + Deploy / build-document-crawler (push) Successful in 45s
Build + Deploy / build-dsms-gateway (push) Successful in 30s
Build + Deploy / build-dsms-node (push) Successful in 19s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / loc-budget (push) Failing after 17s
CI / secret-scan (push) Has been skipped
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m35s
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-go (push) Successful in 43s
CI / test-python-backend (push) Successful in 37s
CI / test-python-document-crawler (push) Successful in 26s
CI / test-python-dsms-gateway (push) Successful in 21s
CI / validate-canonical-controls (push) Successful in 14s
Build + Deploy / trigger-orca (push) Successful in 3m33s
Phase 4-5: Professional Pruefprotokoll report builder with styled HTML output (Kopfdaten, Kategorie-Scores, L1/L2 Check-Hierarchie, Findings, Freigabe-Block). Frontend at /sdk/vendor-assessment with 3-step flow: DocumentUploader → AssessmentProgress → PruefprotokollView. Sidebar: "Use-Case Audits" → "Vertragspruefung" renamed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
94 lines
3.2 KiB
TypeScript
94 lines
3.2 KiB
TypeScript
'use client'
|
|
|
|
import React, { useEffect, useRef, useState } from 'react'
|
|
|
|
interface Props {
|
|
assessmentId: string
|
|
backendUrl: string
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
onComplete: (result: any) => void
|
|
onError: (msg: string) => void
|
|
}
|
|
|
|
export function AssessmentProgress({ assessmentId, backendUrl, onComplete, onError }: Props) {
|
|
const [progress, setProgress] = useState('Initialisierung...')
|
|
const [dots, setDots] = useState(0)
|
|
const pollRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
|
|
|
useEffect(() => {
|
|
const dotTimer = setInterval(() => setDots(d => (d + 1) % 4), 500)
|
|
|
|
pollRef.current = setInterval(async () => {
|
|
try {
|
|
const res = await fetch(
|
|
`${backendUrl}/api/vendor-compliance/assessments/${assessmentId}`,
|
|
)
|
|
if (!res.ok) return
|
|
|
|
const data = await res.json()
|
|
|
|
if (data.status === 'completed' && data.result) {
|
|
if (pollRef.current) clearInterval(pollRef.current)
|
|
clearInterval(dotTimer)
|
|
onComplete(data.result)
|
|
return
|
|
}
|
|
|
|
if (data.status === 'failed') {
|
|
if (pollRef.current) clearInterval(pollRef.current)
|
|
clearInterval(dotTimer)
|
|
onError(data.error || 'Pruefung fehlgeschlagen')
|
|
return
|
|
}
|
|
|
|
if (data.progress) {
|
|
setProgress(data.progress)
|
|
}
|
|
} catch {
|
|
// retry silently
|
|
}
|
|
}, 2000)
|
|
|
|
return () => {
|
|
if (pollRef.current) clearInterval(pollRef.current)
|
|
clearInterval(dotTimer)
|
|
}
|
|
}, [assessmentId, backendUrl, onComplete, onError])
|
|
|
|
return (
|
|
<div className="bg-white rounded-xl border border-gray-200 p-12 text-center">
|
|
<div className="w-16 h-16 mx-auto mb-6 relative">
|
|
<div className="absolute inset-0 border-4 border-blue-200 rounded-full" />
|
|
<div className="absolute inset-0 border-4 border-blue-600 rounded-full border-t-transparent animate-spin" />
|
|
</div>
|
|
|
|
<h2 className="text-xl font-semibold text-gray-800 mb-2">
|
|
Vertragspruefung laeuft
|
|
</h2>
|
|
|
|
<p className="text-gray-600 text-sm mb-6">
|
|
{progress}{'.'.repeat(dots)}
|
|
</p>
|
|
|
|
<div className="max-w-md mx-auto">
|
|
<div className="flex items-center gap-3 text-left text-xs text-gray-500 mb-2">
|
|
<span className="w-5 h-5 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-bold">1</span>
|
|
Text extrahieren
|
|
</div>
|
|
<div className="flex items-center gap-3 text-left text-xs text-gray-500 mb-2">
|
|
<span className="w-5 h-5 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-bold">2</span>
|
|
Checklisten pruefen (L1/L2)
|
|
</div>
|
|
<div className="flex items-center gap-3 text-left text-xs text-gray-500 mb-2">
|
|
<span className="w-5 h-5 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-bold">3</span>
|
|
Cross-Check zwischen Dokumenten
|
|
</div>
|
|
<div className="flex items-center gap-3 text-left text-xs text-gray-500">
|
|
<span className="w-5 h-5 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-bold">4</span>
|
|
Pruefprotokoll generieren
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|