46acca9e62
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
82 lines
2.7 KiB
TypeScript
82 lines
2.7 KiB
TypeScript
import { Box, Button, Card, CardContent, Chip, LinearProgress, Typography } from '@mui/material'
|
|
import type { DataQualitySummary } from '../../domain/dashboard'
|
|
|
|
interface DataQualityWidgetProps {
|
|
summary: DataQualitySummary
|
|
onNavigate: () => void
|
|
}
|
|
|
|
function qualityColor(score: number): 'success' | 'warning' | 'error' {
|
|
if (score >= 80) return 'success'
|
|
if (score >= 60) return 'warning'
|
|
return 'error'
|
|
}
|
|
|
|
export function DataQualityWidget({ summary, onNavigate }: DataQualityWidgetProps) {
|
|
const color = qualityColor(summary.avgScore)
|
|
|
|
return (
|
|
<Card>
|
|
<CardContent sx={{ p: 2.5 }}>
|
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
|
<Typography variant="h6" sx={{ fontWeight: 600 }}>
|
|
Datenqualität
|
|
</Typography>
|
|
<Button size="small" onClick={onNavigate}>
|
|
Details
|
|
</Button>
|
|
</Box>
|
|
|
|
<Box sx={{ mb: 2 }}>
|
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 0.5 }}>
|
|
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
|
|
Ø Score
|
|
</Typography>
|
|
<Typography variant="body2" sx={{ fontWeight: 600 }}>
|
|
{summary.avgScore}%
|
|
</Typography>
|
|
</Box>
|
|
<LinearProgress
|
|
variant="determinate"
|
|
value={summary.avgScore}
|
|
color={color}
|
|
sx={{ borderRadius: 1, height: 8 }}
|
|
/>
|
|
</Box>
|
|
|
|
<Box sx={{ display: 'flex', gap: 2, mb: 2 }}>
|
|
<Box>
|
|
<Typography variant="h5" sx={{ fontWeight: 700, color: summary.critical > 0 ? 'error.main' : 'text.primary' }}>
|
|
{summary.critical}
|
|
</Typography>
|
|
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
|
Kritische Objekte
|
|
</Typography>
|
|
</Box>
|
|
<Box>
|
|
<Typography variant="h5" sx={{ fontWeight: 700 }}>
|
|
{summary.propertiesWithMissingCritical}
|
|
</Typography>
|
|
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
|
Fehlende Pflichtfelder
|
|
</Typography>
|
|
</Box>
|
|
</Box>
|
|
|
|
{summary.topMissingFields.length > 0 && (
|
|
<Box>
|
|
<Typography variant="caption" sx={{ color: 'text.secondary', display: 'block', mb: 0.5 }}>
|
|
Häufig fehlende Felder:
|
|
</Typography>
|
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
|
|
{summary.topMissingFields.map(field => (
|
|
<Chip key={field} label={field} size="small" color="warning" variant="outlined" />
|
|
))}
|
|
</Box>
|
|
</Box>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
)
|
|
}
|