feat: implement RAG dashboard with MUI and react-router
Add new RAG dashboard feature including: - Main application layout with header and sidebar - Multiple pages (Home, KnowledgeBase, PipelineConfig, Dashboard, MCP) - Theme configuration and styling - Routing setup with protected routes - Login page and authentication flow - Various UI components and mock data for dashboard views
This commit is contained in:
218
src/pages/Home.tsx
Normal file
218
src/pages/Home.tsx
Normal file
@@ -0,0 +1,218 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
Grid,
|
||||
LinearProgress,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Typography,
|
||||
styled
|
||||
} from '@mui/material';
|
||||
|
||||
const StyledCard = styled(Card)({
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
||||
borderRadius: '8px',
|
||||
});
|
||||
|
||||
const CardTitle = styled(Typography)({
|
||||
fontSize: '1rem',
|
||||
fontWeight: 'bold',
|
||||
marginBottom: '16px',
|
||||
});
|
||||
|
||||
const MetricsContainer = styled(Box)({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: '16px',
|
||||
});
|
||||
|
||||
const Metric = styled(Box)({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
});
|
||||
|
||||
const MetricValue = styled(Typography)({
|
||||
fontSize: '1.5rem',
|
||||
fontWeight: 'bold',
|
||||
});
|
||||
|
||||
const MetricLabel = styled(Typography)({
|
||||
fontSize: '0.75rem',
|
||||
color: '#666',
|
||||
});
|
||||
|
||||
const ProgressContainer = styled(Box)({
|
||||
marginBottom: '16px',
|
||||
});
|
||||
|
||||
const ProgressLabel = styled(Box)({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
fontSize: '0.65rem',
|
||||
marginBottom: '4px',
|
||||
});
|
||||
|
||||
const StyledLinearProgress = styled(LinearProgress)({
|
||||
height: '8px',
|
||||
borderRadius: '4px',
|
||||
});
|
||||
|
||||
const StatusPill = styled(Box)<{ status?: string }>(({ status }) => ({
|
||||
display: 'inline-block',
|
||||
padding: '4px 8px',
|
||||
borderRadius: '12px',
|
||||
fontSize: '0.65rem',
|
||||
fontWeight: 'bold',
|
||||
backgroundColor: status === 'OK' ? '#e6f7ed' : '#ffebee',
|
||||
color: status === 'OK' ? '#00a389' : '#d32f2f',
|
||||
}));
|
||||
|
||||
const InlineNote = styled('span')({
|
||||
fontSize: '0.75rem',
|
||||
color: '#666',
|
||||
fontWeight: 'normal',
|
||||
marginLeft: '4px',
|
||||
});
|
||||
|
||||
// 模拟数据
|
||||
const recentQueries = [
|
||||
{ query: 'How to reset device firmware?', latency: 732, source: 'manual.pdf', time: '09:21', status: 'OK' },
|
||||
{ query: 'List authentication failure codes', latency: 801, source: 'auth_guide.html', time: '09:18', status: 'OK' },
|
||||
{ query: 'Can we purge stale vectors?', latency: 915, source: 'system_kb', time: '09:10', status: 'OK' },
|
||||
{ query: 'Explain retrieval scoring logic', latency: 845, source: 'design_notes', time: '08:57', status: 'OK' },
|
||||
{ query: 'Pipeline concurrency limits?', latency: 1042, source: 'ops_doc', time: '08:43', status: 'OK' },
|
||||
];
|
||||
|
||||
const Home = () => {
|
||||
return (
|
||||
<Box>
|
||||
<Grid container spacing={3}>
|
||||
{/* Knowledge Base Status Card */}
|
||||
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||
<StyledCard>
|
||||
<CardContent>
|
||||
<CardTitle>Knowledge Base Status</CardTitle>
|
||||
<MetricsContainer>
|
||||
<Metric>
|
||||
<MetricLabel>Documents</MetricLabel>
|
||||
<MetricValue>4,218</MetricValue>
|
||||
</Metric>
|
||||
<Metric>
|
||||
<MetricLabel>Sources</MetricLabel>
|
||||
<MetricValue>17</MetricValue>
|
||||
</Metric>
|
||||
<Metric>
|
||||
<MetricLabel>Vectors</MetricLabel>
|
||||
<MetricValue>1.2M</MetricValue>
|
||||
</Metric>
|
||||
</MetricsContainer>
|
||||
|
||||
<ProgressContainer>
|
||||
<ProgressLabel>
|
||||
<span>Sync Progress</span>
|
||||
<span>62%</span>
|
||||
</ProgressLabel>
|
||||
<StyledLinearProgress variant="determinate" value={62} />
|
||||
</ProgressContainer>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
fullWidth
|
||||
sx={{
|
||||
backgroundColor: '#1a1a2e',
|
||||
'&:hover': { backgroundColor: '#2a2a3e' }
|
||||
}}
|
||||
>
|
||||
Create New Knowledge Base
|
||||
</Button>
|
||||
</CardContent>
|
||||
</StyledCard>
|
||||
</Grid>
|
||||
|
||||
{/* Recent Activity Card */}
|
||||
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||
<StyledCard>
|
||||
<CardContent>
|
||||
<CardTitle>
|
||||
Recent Activity <InlineNote>(latest 24h)</InlineNote>
|
||||
</CardTitle>
|
||||
<Box sx={{ fontSize: '0.7rem', lineHeight: 1.8 }}>
|
||||
<Box>152 user queries processed</Box>
|
||||
<Box>87 new documents ingested</Box>
|
||||
<Box>4 pipeline adjustments</Box>
|
||||
</Box>
|
||||
<Box sx={{ marginTop: 'auto', fontSize: '0.65rem', opacity: 0.75, mt: 2 }}>
|
||||
Latency stable at p95 820ms
|
||||
</Box>
|
||||
</CardContent>
|
||||
</StyledCard>
|
||||
</Grid>
|
||||
|
||||
{/* Model Overview Card */}
|
||||
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||
<StyledCard>
|
||||
<CardContent>
|
||||
<CardTitle>Model Overview</CardTitle>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '0.4rem', fontSize: '0.7rem' }}>
|
||||
<Box>Embedding Model: <strong>text-embedding-3-large</strong></Box>
|
||||
<Box>Generator: <strong>gpt-4o-mini</strong></Box>
|
||||
<Box>Reranker: <strong>cross-encoder-v2</strong></Box>
|
||||
<Box>Chunking: 512 tokens</Box>
|
||||
<Box>Retriever Top-K: 8</Box>
|
||||
</Box>
|
||||
<StatusPill status="OK" sx={{ mt: 1 }}>Healthy</StatusPill>
|
||||
</CardContent>
|
||||
</StyledCard>
|
||||
</Grid>
|
||||
|
||||
{/* Recent RAG Queries Table */}
|
||||
<Grid size={12}>
|
||||
<StyledCard>
|
||||
<CardContent>
|
||||
<CardTitle>
|
||||
Recent RAG Queries <InlineNote>(latest 5)</InlineNote>
|
||||
</CardTitle>
|
||||
<TableContainer>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Query</TableCell>
|
||||
<TableCell>Latency (ms)</TableCell>
|
||||
<TableCell>Source</TableCell>
|
||||
<TableCell>Time</TableCell>
|
||||
<TableCell>Status</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{recentQueries.map((row, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell>{row.query}</TableCell>
|
||||
<TableCell>{row.latency}</TableCell>
|
||||
<TableCell>{row.source}</TableCell>
|
||||
<TableCell>{row.time}</TableCell>
|
||||
<TableCell>
|
||||
<StatusPill status={row.status}>{row.status}</StatusPill>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</CardContent>
|
||||
</StyledCard>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
Reference in New Issue
Block a user