feat: checklist multi-type assignments, tab layouts for Fahrzeuge/Ausruestung, admin cleanup

- Migration 074: convert checklist vorlage single FK fields to junction tables
  (vorlage_fahrzeug_typen, vorlage_fahrzeuge, vorlage_ausruestung_typen, vorlage_ausruestungen)
- Backend checklist service: multi-type create/update/query with array fields
- Backend cleanup service: add checklist-history and reset-checklist-history targets
- Frontend types/service: singular FK fields replaced with arrays (fahrzeug_typ_ids, etc.)
- Frontend Checklisten.tsx: multi-select Autocomplete pickers for all assignment types
- Fahrzeuge.tsx/Ausruestung.tsx: add tab layout (Uebersicht + Einstellungen), inline type CRUD
- FahrzeugEinstellungen/AusruestungEinstellungen: replaced with redirects to tab URLs
- Sidebar: add Uebersicht sub-items, update Einstellungen paths to tab URLs
- DataManagementTab: add checklist-history cleanup and reset sections

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Matthias Hochmeister
2026-03-28 18:57:46 +01:00
parent 893fbe43a0
commit 4349de9bc9
14 changed files with 1078 additions and 1188 deletions

View File

@@ -24,6 +24,7 @@ const SECTIONS: CleanupSection[] = [
{ key: 'orders', label: 'Bestellungen', description: 'Abgeschlossene Bestellungen entfernen.', defaultDays: 365 },
{ key: 'vehicle-history', label: 'Fahrzeug-Wartungslog', description: 'Alte Fahrzeug-Wartungseintraege entfernen.', defaultDays: 730 },
{ key: 'equipment-history', label: 'Ausruestungs-Wartungslog', description: 'Alte Ausruestungs-Wartungseintraege entfernen.', defaultDays: 730 },
{ key: 'checklist-history', label: 'Checklisten-Historie', description: 'Alte Checklisten-Ausfuehrungen entfernen.', defaultDays: 365 },
];
interface ResetSection {
@@ -36,6 +37,7 @@ const RESET_SECTIONS: ResetSection[] = [
{ key: 'reset-bestellungen', label: 'Bestellungen zuruecksetzen', description: 'Alle Bestellungen, Positionen, Dateien, Erinnerungen und Historie loeschen und Nummern zuruecksetzen.' },
{ key: 'reset-ausruestung-anfragen', label: 'Interne Bestellungen zuruecksetzen', description: 'Alle internen Bestellungen und zugehoerige Positionen loeschen und Nummern zuruecksetzen.' },
{ key: 'reset-issues', label: 'Issues zuruecksetzen', description: 'Alle Issues und Kommentare loeschen und Nummern zuruecksetzen.' },
{ key: 'reset-checklist-history', label: 'Checklisten-Historie zuruecksetzen', description: 'Alle Checklisten-Ausfuehrungen und Faelligkeiten loeschen und Nummern zuruecksetzen.' },
];
interface SectionState {

View File

@@ -193,12 +193,17 @@ function Sidebar({ mobileOpen, onMobileClose }: SidebarProps) {
const vehicleSubItems: SubItem[] = useMemo(
() => {
const items: SubItem[] = (vehicleList ?? []).map((v) => ({
text: v.bezeichnung ?? v.kurzname,
path: `/fahrzeuge/${v.id}`,
}));
const items: SubItem[] = [
{ text: 'Übersicht', path: '/fahrzeuge?tab=0' },
];
(vehicleList ?? []).forEach((v) => {
items.push({
text: v.bezeichnung ?? v.kurzname,
path: `/fahrzeuge/${v.id}`,
});
});
if (hasPermission('fahrzeuge:edit')) {
items.push({ text: 'Einstellungen', path: '/fahrzeuge/einstellungen' });
items.push({ text: 'Einstellungen', path: '/fahrzeuge?tab=1' });
}
return items;
},
@@ -246,9 +251,11 @@ function Sidebar({ mobileOpen, onMobileClose }: SidebarProps) {
.map((item) => {
if (item.path === '/fahrzeuge') return fahrzeugeItem;
if (item.path === '/ausruestung') {
const ausruestungSubs: SubItem[] = [];
const ausruestungSubs: SubItem[] = [
{ text: 'Übersicht', path: '/ausruestung?tab=0' },
];
if (hasPermission('ausruestung:manage_types')) {
ausruestungSubs.push({ text: 'Einstellungen', path: '/ausruestung/einstellungen' });
ausruestungSubs.push({ text: 'Einstellungen', path: '/ausruestung?tab=1' });
}
return ausruestungSubs.length > 0 ? { ...item, subItems: ausruestungSubs } : item;
}