fix(robustheit+ux): atomares Speichern, Offline-Härtung, Einsatz-Beenden, Audit raus
Robustheit / Datensicherheit: - Features-PUT in prisma.$transaction (delete+create atomar) — verhindert Totalverlust bei Abbruch zwischen Löschen und Neuanlegen - localStorage-Features pro Projekt (lageplan-features-<id>) statt globalem Key — verhindert Datenübertrag zwischen Projekten - Sync-Queue verwirft dauerhafte 4xx-Fehler statt Endlos-Retry - beforeunload persistiert auch leere Feature-Listen (Löschungen gehen nicht verloren) UX: - Leitungsrechner-Dropdown: Popover z-[2000] (lag hinter dem Panel), Label gekürzt - Neuer "Einsatz beenden"-Button (speichert, löst Lock, schliesst Einsatz) - Audit-Trail-Einstiege entfernt (Toolbar-Button + Menü-Eintrag) Version 1.4.10 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,7 @@ import {
|
||||
HelpCircle,
|
||||
Lock,
|
||||
Unlock,
|
||||
CheckCircle2,
|
||||
} from 'lucide-react'
|
||||
import { HoseSettingsDialog } from '@/components/dialogs/hose-settings-dialog'
|
||||
import type { Project, DrawFeature, ProjectMode } from '@/types'
|
||||
@@ -51,6 +52,7 @@ import { Logo } from '@/components/ui/logo'
|
||||
interface TopbarProps {
|
||||
project: Project | null
|
||||
onNewProject: (mode?: ProjectMode) => void
|
||||
onEndProject?: () => void
|
||||
onSaveProject: () => void
|
||||
onLoadProject: (project: Project, features: DrawFeature[]) => void
|
||||
onDeleteProject?: (projectId: string) => void
|
||||
@@ -76,6 +78,7 @@ interface TopbarProps {
|
||||
export function Topbar({
|
||||
project,
|
||||
onNewProject,
|
||||
onEndProject,
|
||||
onSaveProject,
|
||||
onLoadProject,
|
||||
onDeleteProject,
|
||||
@@ -285,19 +288,17 @@ export function Topbar({
|
||||
{isFullscreen ? <Minimize className="w-4 h-4" /> : <Maximize className="w-4 h-4" />}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant={isAuditOpen ? 'default' : 'outline'}
|
||||
className="hidden md:flex h-9 px-2 relative"
|
||||
onClick={onToggleAudit}
|
||||
title="Audit Trail"
|
||||
>
|
||||
<ClipboardList className="w-4 h-4" />
|
||||
{auditLog.length > 0 && (
|
||||
<span className="absolute -top-1 -right-1 w-4 h-4 bg-primary text-primary-foreground text-[10px] rounded-full flex items-center justify-center font-bold">
|
||||
{auditLog.length > 99 ? '99' : auditLog.length}
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
{project && onEndProject && (
|
||||
<Button
|
||||
variant="outline"
|
||||
className="hidden md:flex h-9 px-2 md:px-3 border-red-300 text-red-600 hover:bg-red-50 hover:text-red-700 dark:border-red-800 dark:text-red-400 dark:hover:bg-red-950/40"
|
||||
onClick={onEndProject}
|
||||
title="Einsatz speichern und schliessen"
|
||||
>
|
||||
<CheckCircle2 className="w-4 h-4 lg:mr-1" />
|
||||
<span className="hidden lg:inline">Einsatz beenden</span>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Desktop: User menu dropdown */}
|
||||
{userName && onLogout && (
|
||||
@@ -366,10 +367,6 @@ export function Topbar({
|
||||
<Settings className="w-4 h-4 mr-2" />
|
||||
Einstellungen
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={onToggleAudit}>
|
||||
<ClipboardList className="w-4 h-4 mr-2" />
|
||||
Audit Trail {auditLog.length > 0 && `(${auditLog.length})`}
|
||||
</DropdownMenuItem>
|
||||
{onLogout && (
|
||||
<DropdownMenuItem onClick={onLogout} className="text-destructive">
|
||||
<LogOut className="w-4 h-4 mr-2" />
|
||||
|
||||
Reference in New Issue
Block a user