import { useCallback, useEffect, useRef, useState } from 'react'; import { AssessorApiClient } from '../../api/assessor-api-client'; import { Dialog } from '../../components/Dialog/Dialog'; import { OperationProgressDialog } from '../../components/OperationProgress/OperationProgress'; import { TriangleIcon } from '../../components/TriangleIcon'; import type { MicrosoftSecurityBaselineRecord } from '../../domain/microsoft-security-baseline'; const assessorApi = new AssessorApiClient(); function formatBytes(value: number): string { return value < 1024 * 1024 ? `${(value / 1024).toLocaleString('de-DE', { maximumFractionDigits: 1 })} KB` : `${(value / 1024 / 1024).toLocaleString('de-DE', { maximumFractionDigits: 1 })} MB`; } function formatTimestamp(value: string): string { const date = new Date(value); return Number.isNaN(date.getTime()) ? '—' : new Intl.DateTimeFormat('en-US', { dateStyle: 'short', timeStyle: 'medium' }).format(date); } export function MicrosoftBaselineLibrary() { const inputRef = useRef(null); const [records, setRecords] = useState([]); const [busy, setBusy] = useState(false); const [progress, setProgress] = useState(); const [deleteTarget, setDeleteTarget] = useState(null); const [feedback, setFeedback] = useState(null); const [error, setError] = useState(null); const load = useCallback(async () => { try { setRecords((await assessorApi.listMicrosoftSecurityBaselines()).records); } catch (reason) { setError(reason instanceof Error ? reason.message : 'Baseline-Katalog konnte nicht geladen werden.'); } }, []); useEffect(() => { void load(); }, [load]); const upload = async (files: FileList) => { setBusy(true); setError(null); setFeedback(null); try { const selected = Array.from(files); for (const [index, file] of selected.entries()) { setProgress(`Importing baseline ${index + 1} of ${selected.length}`); await assessorApi.submitMicrosoftSecurityBaseline(file); } await load(); setFeedback(`${files.length} Baseline-Paket${files.length === 1 ? '' : 'e'} im Katalog gespeichert.`); } catch (reason) { setError(reason instanceof Error ? reason.message : 'Baseline-Upload fehlgeschlagen.'); } finally { setBusy(false); setProgress(undefined); } }; const deleteBaseline = async () => { if (!deleteTarget) return; setBusy(true); setError(null); setFeedback(null); try { const deleted = await assessorApi.deleteMicrosoftSecurityBaseline(deleteTarget.id); setDeleteTarget(null); await load(); setFeedback(`${deleted.record.fileName} was deleted from the baseline catalog.`); } catch (reason) { setError(reason instanceof Error ? reason.message : 'Baseline deletion failed.'); } finally { setBusy(false); } }; return <>
{records.length.toLocaleString('en-US')}Imported Security Baselines { if (event.target.files?.length) void upload(event.target.files); event.target.value = ''; }}/> {feedback &&
{feedback}
} {error &&
{error}
} {records.length > 0 &&
FileSizeImportedStatusActions
{records.map(record => { return
{record.fileName} {formatBytes(record.sizeBytes)} {formatTimestamp(record.importedAt)} {record.status === 'eligible' ? 'Eligible' : 'Metadata required'}
; })}
}
{deleteTarget && !busy && setDeleteTarget(null)}>
{deleteTarget.fileName}

Baseline and derived evaluations will be deleted.

} ; }