Compare commits

...

2 Commits

Author SHA1 Message Date
s8613 3d6458ffb0 Removed example for edit mode. 2025-07-01 11:06:20 +02:00
s8613 7eeca5c3ba Fixed extra frame font and small styling issues. 2025-07-01 10:52:56 +02:00
2 changed files with 100 additions and 53 deletions

View File

@ -7,6 +7,7 @@ import type { Kennzahl } from "../types/kpi";
import { typeDisplayMapping } from "../types/kpi"; import { typeDisplayMapping } from "../types/kpi";
import Snackbar from "@mui/material/Snackbar"; import Snackbar from "@mui/material/Snackbar";
import MuiAlert from "@mui/material/Alert"; import MuiAlert from "@mui/material/Alert";
import { API_HOST } from "../util/api";
interface KPIFormProps { interface KPIFormProps {
@ -29,6 +30,7 @@ const emptyKPI: Partial<Kennzahl> = {
export function KPIForm({ mode, initialData, onSave, onCancel, loading = false, resetTrigger }: KPIFormProps) { export function KPIForm({ mode, initialData, onSave, onCancel, loading = false, resetTrigger }: KPIFormProps) {
const [formData, setFormData] = useState<Partial<Kennzahl>>(emptyKPI); const [formData, setFormData] = useState<Partial<Kennzahl>>(emptyKPI);
const [originalExamples, setOriginalExamples] = useState<Array<{ sentence: string; value: string }>>([]);
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
const [snackbarOpen, setSnackbarOpen] = useState(false); const [snackbarOpen, setSnackbarOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState(""); const [snackbarMessage, setSnackbarMessage] = useState("");
@ -37,14 +39,20 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
useEffect(() => { useEffect(() => {
if (mode === 'edit' && initialData) { if (mode === 'edit' && initialData) {
setFormData(initialData); setOriginalExamples(initialData.examples || []);
setFormData({
...initialData,
examples: [{ sentence: '', value: '' }]
});
} else if (mode === 'add') { } else if (mode === 'add') {
setOriginalExamples([]);
setFormData(emptyKPI); setFormData(emptyKPI);
} }
}, [mode, initialData]); }, [mode, initialData]);
useEffect(() => { useEffect(() => {
if (mode === 'add') { if (mode === 'add') {
setOriginalExamples([]);
setFormData(emptyKPI); setFormData(emptyKPI);
} }
}, [resetTrigger]); }, [resetTrigger]);
@ -64,24 +72,30 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
setSnackbarMessage("Mindestens ein Beispielsatz ist erforderlich"); setSnackbarMessage("Mindestens ein Beispielsatz ist erforderlich");
setSnackbarSeverity("error"); setSnackbarSeverity("error");
setSnackbarOpen(true); setSnackbarOpen(true);
return; return;
} }
for (const ex of formData.examples) { const newExamples = formData.examples.filter(ex => ex.sentence?.trim() && ex.value?.trim());
if (newExamples.length === 0) {
setSnackbarMessage('Mindestens ein vollständiger Beispielsatz ist erforderlich.');
setSnackbarSeverity("error");
setSnackbarOpen(true);
return;
}
for (const ex of newExamples) {
if (!ex.sentence?.trim() || !ex.value?.trim()) { if (!ex.sentence?.trim() || !ex.value?.trim()) {
setSnackbarMessage('Alle Beispielsätze müssen vollständig sein.'); setSnackbarMessage('Alle Beispielsätze müssen vollständig sein.');
setSnackbarSeverity("error"); setSnackbarSeverity("error");
setSnackbarOpen(true); setSnackbarOpen(true);
return; return;
} }
} }
setIsSaving(true); setIsSaving(true);
try { try {
const spacyEntries = generateSpacyEntries(formData); const spacyEntries = generateSpacyEntries({ ...formData, examples: newExamples });
// Für jeden einzelnen Beispielsatz: // Für jeden einzelnen Beispielsatz:
for (const entry of spacyEntries) { for (const entry of spacyEntries) {
@ -92,7 +106,7 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
localStorage.setItem("spacyData", JSON.stringify(updated)); localStorage.setItem("spacyData", JSON.stringify(updated));
// POST Request an das Flask-Backend // POST Request an das Flask-Backend
const response = await fetch("http://localhost:5050/api/spacy/append-training-entry", { const response = await fetch(`${API_HOST}/api/spacy/append-training-entry/`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json"
@ -109,6 +123,10 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
console.log("SpaCy-Eintrag gespeichert:", data); console.log("SpaCy-Eintrag gespeichert:", data);
} }
const allExamples = mode === 'edit'
? [...originalExamples, ...newExamples]
: newExamples;
// Dann in die DB speichern // Dann in die DB speichern
await onSave({ await onSave({
name: formData.name!, name: formData.name!,
@ -116,11 +134,18 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
type: formData.type || 'string', type: formData.type || 'string',
position: formData.position ?? 0, position: formData.position ?? 0,
active: formData.active ?? true, active: formData.active ?? true,
examples: formData.examples ?? [], examples: allExamples,
is_trained: false, is_trained: false,
}); });
// Formular zurücksetzen: // Formular zurücksetzen:
setFormData(emptyKPI); if (mode === 'add') {
setFormData(emptyKPI);
} else {
setFormData(prev => ({
...prev,
examples: [{ sentence: '', value: '' }]
}));
}
setSnackbarMessage("Beispielsätze gespeichert. Jetzt auf -Neu trainieren- klicken oder weitere Kennzahlen hinzufügen."); setSnackbarMessage("Beispielsätze gespeichert. Jetzt auf -Neu trainieren- klicken oder weitere Kennzahlen hinzufügen.");
@ -240,45 +265,69 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
</FormControl> </FormControl>
</Box> </Box>
<Divider sx={{ my: 3 }} />
{mode === 'add' && ( <Box mb={4}>
<> <FormControlLabel
<Divider sx={{ my: 3 }} /> control={
<Box mb={4}> <Checkbox
<FormControlLabel checked={formData.active !== false}
control={ onChange={(e) => updateField('active', e.target.checked)}
<Checkbox sx={{
checked={formData.active !== false} color: '#666666',
onChange={(e) => updateField('active', e.target.checked)} '&.Mui-checked': {
sx={{ color: '#383838' }} color: '#333333',
/> },
} '&:hover': {
label="Aktiv" backgroundColor: 'rgba(102, 102, 102, 0.04)',
}
}}
/> />
<Typography variant="body2" color="text.secondary" ml={4}> }
Die Kennzahl ist aktiv und wird angezeigt label="Aktiv"
</Typography> />
</Box> <Typography variant="body2" color="text.secondary" ml={4}>
<Box mt={3}> Die Kennzahl ist aktiv und wird angezeigt
<FormControlLabel </Typography>
control={ </Box>
<Checkbox <Box mt={3}>
checked={formData.mandatory || false} <FormControlLabel
onChange={(e) => updateField('mandatory', e.target.checked)} control={
sx={{ color: '#383838' }} <Checkbox
/> checked={formData.mandatory || false}
} onChange={(e) => updateField('mandatory', e.target.checked)}
label="Erforderlich" sx={{
color: '#666666',
'&.Mui-checked': {
color: '#333333',
},
'&:hover': {
backgroundColor: 'rgba(102, 102, 102, 0.04)',
}
}}
/> />
<Typography variant="body2" color="text.secondary" ml={4}> }
Die Kennzahl erlaubt keine leeren Werte label="Erforderlich"
</Typography> />
</Box> <Typography variant="body2" color="text.secondary" ml={4}>
</> Die Kennzahl erlaubt keine leeren Werte
)} </Typography>
</Box>
<Divider sx={{ my: 3 }} /> <Divider sx={{ my: 3 }} />
{/* Hinweistext wie viele Beispielsätzen vorhanden sind*/}
{mode === 'edit' && originalExamples.length > 0 && (
<Box mb={2} p={2} sx={{ backgroundColor: '#e3f2fd', border: '1px solid #90caf9', borderRadius: 2 }}>
<Typography variant="body1" sx={{ fontWeight: 'bold', mb: 1 }}>
Vorhandene Beispielsätze: {originalExamples.length}
</Typography>
<Typography variant="body2">
Diese Kennzahl hat bereits {originalExamples.length} Beispielsätze. Neue Beispielsätze werden zu den vorhandenen hinzugefügt.
</Typography>
</Box>
)}
{/* Hinweistext vor Beispielsätzen */} {/* Hinweistext vor Beispielsätzen */}
<Box mb={2} p={2} sx={{ backgroundColor: '#fff8e1', border: '1px solid #ffe082', borderRadius: 2 }}> <Box mb={2} p={2} sx={{ backgroundColor: '#fff8e1', border: '1px solid #ffe082', borderRadius: 2 }}>
<Typography variant="body1" sx={{ fontWeight: 'bold', mb: 1 }}> <Typography variant="body1" sx={{ fontWeight: 'bold', mb: 1 }}>

View File

@ -188,6 +188,10 @@ export default function PDFViewer({
); );
}, []); }, []);
const contentWidth = baseWidth ? baseWidth * 0.98 * zoomLevel : 0;
const containerWidth = baseWidth ? baseWidth : 0;
const willOverflow = contentWidth > containerWidth;
return ( return (
<Box <Box
display="flex" display="flex"
@ -197,11 +201,6 @@ export default function PDFViewer({
width="100%" width="100%"
maxWidth="850px" maxWidth="850px"
margin="0 auto" margin="0 auto"
sx={{
backgroundColor: "#f5f5f5",
borderRadius: 2,
boxShadow: 2,
}}
> >
<Box <Box
ref={containerRef} ref={containerRef}
@ -213,11 +212,10 @@ export default function PDFViewer({
borderRadius: 0, borderRadius: 0,
boxShadow: "none", boxShadow: "none",
overflow: "auto", overflow: "auto",
display: "flex", display: willOverflow ? "block" : "flex",
justifyContent: "center", justifyContent: willOverflow ? "flex-start" : "center",
alignItems: "center", alignItems: willOverflow ? "flex-start" : "center",
marginTop: 2, padding: willOverflow ? `${Math.max(0, (500 - (contentWidth * (500 / containerWidth))) / 2)}px ${Math.max(0, (containerWidth - contentWidth) / 2)}px` : 0,
marginBottom: 2,
}} }}
> >
<Document <Document