fix: Scan progress display — separate progress state, guard ScanResult render
- scanProgress state tracks live progress (not mixed into scanData) - ScanResult only renders when scanData.services exists (prevents crash) - Purple progress bar with spinner shows current step during scan - Fixes: TypeError 's.services.filter' when progress data set as scanData Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@ export default function AgentPage() {
|
|||||||
const [scanLoading, setScanLoading] = useState(false)
|
const [scanLoading, setScanLoading] = useState(false)
|
||||||
const [scanError, setScanError] = useState<string | null>(null)
|
const [scanError, setScanError] = useState<string | null>(null)
|
||||||
const [scanData, setScanData] = useState<any>(null)
|
const [scanData, setScanData] = useState<any>(null)
|
||||||
|
const [scanProgress, setScanProgress] = useState<string>('')
|
||||||
const { analyze, answerFollowUp, loading, error, result, history } = useAgentAnalysis()
|
const { analyze, answerFollowUp, loading, error, result, history } = useAgentAnalysis()
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
@@ -39,6 +40,7 @@ export default function AgentPage() {
|
|||||||
setScanLoading(true)
|
setScanLoading(true)
|
||||||
setScanError(null)
|
setScanError(null)
|
||||||
setScanData(null)
|
setScanData(null)
|
||||||
|
setScanProgress('Scan wird gestartet...')
|
||||||
try {
|
try {
|
||||||
// Step 1: Start async scan
|
// Step 1: Start async scan
|
||||||
const startRes = await fetch('/api/sdk/v1/agent/scan', {
|
const startRes = await fetch('/api/sdk/v1/agent/scan', {
|
||||||
@@ -57,27 +59,26 @@ export default function AgentPage() {
|
|||||||
await new Promise(r => setTimeout(r, 5000))
|
await new Promise(r => setTimeout(r, 5000))
|
||||||
const pollRes = await fetch(`/api/sdk/v1/agent/scan?scan_id=${scan_id}`)
|
const pollRes = await fetch(`/api/sdk/v1/agent/scan?scan_id=${scan_id}`)
|
||||||
if (!pollRes.ok) { attempts++; continue }
|
if (!pollRes.ok) { attempts++; continue }
|
||||||
const status = await pollRes.json()
|
const pollData = await pollRes.json()
|
||||||
|
|
||||||
// Update progress message
|
if (pollData.progress) {
|
||||||
if (status.progress) {
|
setScanProgress(pollData.progress)
|
||||||
setScanError(null)
|
|
||||||
// Show progress as temporary "error" (will be cleared when done)
|
|
||||||
setScanData({ _progress: status.progress } as any)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.status === 'completed' && status.result) {
|
if (pollData.status === 'completed' && pollData.result) {
|
||||||
setScanData(status.result)
|
setScanData(pollData.result)
|
||||||
|
setScanProgress('')
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (status.status === 'failed') {
|
if (pollData.status === 'failed') {
|
||||||
throw new Error(status.error || 'Scan fehlgeschlagen')
|
throw new Error(pollData.error || 'Scan fehlgeschlagen')
|
||||||
}
|
}
|
||||||
attempts++
|
attempts++
|
||||||
}
|
}
|
||||||
if (attempts >= maxAttempts) throw new Error('Scan-Timeout (10 Minuten)')
|
if (attempts >= maxAttempts) throw new Error('Scan-Timeout (10 Minuten)')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setScanError(e instanceof Error ? e.message : 'Unbekannter Fehler')
|
setScanError(e instanceof Error ? e.message : 'Unbekannter Fehler')
|
||||||
|
setScanProgress('')
|
||||||
} finally {
|
} finally {
|
||||||
setScanLoading(false)
|
setScanLoading(false)
|
||||||
}
|
}
|
||||||
@@ -141,6 +142,17 @@ export default function AgentPage() {
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{/* Scan Progress */}
|
||||||
|
{scanProgress && tab === 'scan' && (
|
||||||
|
<div className="bg-purple-50 border border-purple-200 rounded-lg p-4 text-sm text-purple-700 flex items-center gap-3">
|
||||||
|
<svg className="animate-spin w-5 h-5 text-purple-500 shrink-0" fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
|
||||||
|
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
|
||||||
|
</svg>
|
||||||
|
{scanProgress}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Error */}
|
{/* Error */}
|
||||||
{currentError && (
|
{currentError && (
|
||||||
<div className="bg-red-50 border border-red-200 rounded-lg p-4 text-sm text-red-700">{currentError}</div>
|
<div className="bg-red-50 border border-red-200 rounded-lg p-4 text-sm text-red-700">{currentError}</div>
|
||||||
@@ -158,8 +170,8 @@ export default function AgentPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Scan Result */}
|
{/* Scan Result — only render when we have a complete response with services */}
|
||||||
{tab === 'scan' && scanData && (
|
{tab === 'scan' && scanData && scanData.services && (
|
||||||
<div className="bg-white border border-gray-200 rounded-xl p-6 shadow-sm">
|
<div className="bg-white border border-gray-200 rounded-xl p-6 shadow-sm">
|
||||||
<ScanResult data={scanData} />
|
<ScanResult data={scanData} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user