feat: F019 AI monitoring layer — output transparency & governance workspace
Full 2-panel workspace at /ops/ai-monitoring: metrics strip (total, failed, pending, approval rate, top prompt version, active model), filterable output table by type/status/error, and detail panel with output preview, prompt versioning, error details, and role-aware review actions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import { Box, Button, Tooltip } from '@mui/material'
|
||||
import { CheckCircle, XCircle, Send, Copy } from 'lucide-react'
|
||||
import type { AIOutput } from '../../domain/aiOutput'
|
||||
import type { ReviewStatus } from '../../domain/enums'
|
||||
|
||||
interface Props {
|
||||
output: AIOutput
|
||||
onUpdateStatus: (status: ReviewStatus) => void
|
||||
onCopyJson: () => void
|
||||
isSubmitting?: boolean
|
||||
}
|
||||
|
||||
export function AIReviewActionToolbar({ output, onUpdateStatus, onCopyJson, isSubmitting }: Props) {
|
||||
const { reviewStatus } = output
|
||||
|
||||
const canSendToReview = reviewStatus === 'UNREVIEWED' || reviewStatus === 'FLAGGED'
|
||||
const canApprove = reviewStatus === 'IN_REVIEW' || reviewStatus === 'UNREVIEWED'
|
||||
const canReject = reviewStatus !== 'REJECTED'
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', gap: 0.75, flexWrap: 'wrap' }}>
|
||||
{canSendToReview && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
disabled={isSubmitting}
|
||||
startIcon={<Send size={13} />}
|
||||
onClick={() => onUpdateStatus('IN_REVIEW')}
|
||||
sx={{ textTransform: 'none', fontSize: '0.75rem', color: '#d97706', borderColor: '#d97706', '&:hover': { bgcolor: '#fffbeb', borderColor: '#b45309' } }}
|
||||
>
|
||||
Zur Prüfung
|
||||
</Button>
|
||||
)}
|
||||
{canApprove && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="contained"
|
||||
disabled={isSubmitting}
|
||||
startIcon={<CheckCircle size={13} />}
|
||||
onClick={() => onUpdateStatus('APPROVED')}
|
||||
sx={{ textTransform: 'none', fontSize: '0.75rem', bgcolor: '#1a7a4a', '&:hover': { bgcolor: '#155f3a' } }}
|
||||
>
|
||||
Genehmigen
|
||||
</Button>
|
||||
)}
|
||||
{canReject && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
disabled={isSubmitting}
|
||||
startIcon={<XCircle size={13} />}
|
||||
onClick={() => onUpdateStatus('REJECTED')}
|
||||
sx={{ textTransform: 'none', fontSize: '0.75rem', color: '#c0392b', borderColor: '#c0392b', '&:hover': { bgcolor: '#fef2f2', borderColor: '#a93226' } }}
|
||||
>
|
||||
Ablehnen
|
||||
</Button>
|
||||
)}
|
||||
<Tooltip title="Output-JSON kopieren">
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
onClick={onCopyJson}
|
||||
startIcon={<Copy size={13} />}
|
||||
sx={{ textTransform: 'none', fontSize: '0.75rem', color: '#64748b', borderColor: '#e2e8f0', '&:hover': { bgcolor: '#f8fafc' } }}
|
||||
>
|
||||
JSON
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user