livrare lot 2

This commit is contained in:
EVOTECH IT SRL 2026-07-10 03:39:53 -07:00
commit 8ecc78e729
763 changed files with 164593 additions and 0 deletions

View file

@ -0,0 +1,152 @@
import React, { useState } from 'react';
import { Card, CardContent, Typography, Box, Switch, TextField, Slider, Button, FormControlLabel, Alert } from '@mui/material';
import { Save as SaveIcon } from '@mui/icons-material';
import type { ModerationConfig } from './api';
import { updateModerationConfig } from './api';
interface Props {
config: ModerationConfig;
onSaved: (next: ModerationConfig) => void;
onError: (msg: string) => void;
}
export const TriageCard: React.FC<Props> = ({ config, onSaved, onError }) => {
const [draft, setDraft] = useState<ModerationConfig>(config);
const [saving, setSaving] = useState(false);
React.useEffect(() => { setDraft(config); }, [config]);
const dirty = JSON.stringify(draft) !== JSON.stringify(config);
const handleSave = async () => {
setSaving(true);
try {
const res = await updateModerationConfig({
triage_enabled: draft.triage_enabled,
confidence_low: Number(draft.confidence_low),
risk_grey_min: Number(draft.risk_grey_min),
risk_grey_max: Number(draft.risk_grey_max),
queue_relax_at: draft.queue_relax_at,
queue_strict_at: draft.queue_strict_at,
auto_tune_enabled: draft.auto_tune_enabled,
});
if (res.success && res.data) {
onSaved(res.data);
} else {
onError(res.error ?? 'Update failed');
}
} catch (e) {
onError((e as Error).message);
} finally {
setSaving(false);
}
};
return (
<Card variant="outlined">
<CardContent>
<Box display="flex" justifyContent="space-between" alignItems="flex-start" mb={1}>
<Box>
<Typography variant="h6" fontWeight={700}>Triage</Typography>
<Typography variant="caption" color="text.secondary">
Decide which sessions enter the moderation queue. Edits sync to Redis on save.
</Typography>
</Box>
<FormControlLabel
control={
<Switch
checked={draft.triage_enabled}
onChange={(e) => setDraft({ ...draft, triage_enabled: e.target.checked })}
/>
}
label={draft.triage_enabled ? 'Enabled' : 'Disabled'}
labelPlacement="start"
/>
</Box>
{!draft.triage_enabled && (
<Alert severity="info" sx={{ mb: 2 }}>
Triage is OFF. No sessions will enter the moderation queue.
</Alert>
)}
<Box display="grid" gridTemplateColumns="1fr 1fr" gap={3} mt={2}>
<Box>
<Typography variant="body2" gutterBottom>Confidence threshold (low)</Typography>
<Slider
value={Number(draft.confidence_low)}
min={0}
max={100}
step={1}
valueLabelDisplay="auto"
onChange={(_, v) => setDraft({ ...draft, confidence_low: Number(v) })}
/>
<Typography variant="caption" color="text.secondary">
Sessions with confidence &lt; {draft.confidence_low} go to queue
</Typography>
</Box>
<Box>
<Typography variant="body2" gutterBottom>Risk grey zone</Typography>
<Box display="flex" gap={1} alignItems="center">
<TextField
size="small" type="number" label="min"
value={draft.risk_grey_min}
onChange={(e) => setDraft({ ...draft, risk_grey_min: e.target.value })}
/>
<Typography></Typography>
<TextField
size="small" type="number" label="max"
value={draft.risk_grey_max}
onChange={(e) => setDraft({ ...draft, risk_grey_max: e.target.value })}
/>
</Box>
<Typography variant="caption" color="text.secondary">
Sensitive topics with risk in this band go to queue
</Typography>
</Box>
<Box>
<TextField
size="small" type="number" fullWidth label="Auto-relax at pending"
helperText="If queue ≥ this many pending, drop topic filter"
value={draft.queue_relax_at}
onChange={(e) => setDraft({ ...draft, queue_relax_at: parseInt(e.target.value, 10) || 0 })}
/>
</Box>
<Box>
<TextField
size="small" type="number" fullWidth label="Auto-strict at pending"
helperText="If queue ≤ this many pending, broaden triage"
value={draft.queue_strict_at}
onChange={(e) => setDraft({ ...draft, queue_strict_at: parseInt(e.target.value, 10) || 0 })}
/>
</Box>
<Box>
<FormControlLabel
control={
<Switch
checked={draft.auto_tune_enabled}
onChange={(e) => setDraft({ ...draft, auto_tune_enabled: e.target.checked })}
/>
}
label="Auto-tune thresholds (cron)"
/>
</Box>
</Box>
<Box mt={2} display="flex" justifyContent="flex-end" gap={1}>
<Button
variant="contained"
startIcon={<SaveIcon />}
onClick={handleSave}
disabled={!dirty || saving}
>
{saving ? 'Saving…' : 'Save Triage'}
</Button>
</Box>
</CardContent>
</Card>
);
};