feat(network): add undo/redo buttons to DiagramHeader

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-04-13 20:04:58 +00:00
parent b9c9bb548d
commit a392d24101
2 changed files with 47 additions and 24 deletions

View File

@@ -1,6 +1,6 @@
import { useState, useCallback, useRef, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { ChevronLeft, Save, Download, FileJson, Image, FileText } from 'lucide-react'
import { ChevronLeft, Save, Download, FileJson, Image, FileText, Undo2, Redo2 } from 'lucide-react'
interface DiagramHeaderProps {
name: string
@@ -14,6 +14,10 @@ interface DiagramHeaderProps {
onExportPng: () => void
onExportPdf: () => void
onExportJson: () => void
onUndo: () => void
onRedo: () => void
canUndo: boolean
canRedo: boolean
}
export function DiagramHeader({
@@ -28,6 +32,10 @@ export function DiagramHeader({
onExportPng,
onExportPdf,
onExportJson,
onUndo,
onRedo,
canUndo,
canRedo,
}: DiagramHeaderProps) {
const navigate = useNavigate()
const [editing, setEditing] = useState(false)
@@ -88,6 +96,27 @@ export function DiagramHeader({
<div className="mx-2 h-5 w-px bg-border-default" />
<div className="flex items-center gap-1">
<button
onClick={onUndo}
disabled={!canUndo}
title="Undo (Ctrl+Z)"
className="p-1.5 rounded text-muted-foreground hover:text-primary hover:bg-elevated disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
>
<Undo2 size={16} />
</button>
<button
onClick={onRedo}
disabled={!canRedo}
title="Redo (Ctrl+Y)"
className="p-1.5 rounded text-muted-foreground hover:text-primary hover:bg-elevated disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
>
<Redo2 size={16} />
</button>
</div>
<div className="mx-2 h-5 w-px bg-border-default" />
{editing ? (
<input
ref={inputRef}

View File

@@ -628,29 +628,23 @@ function DiagramEditorInner() {
return (
<div className="flex h-full flex-col">
{(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const DiagramHeaderAny = DiagramHeader as any
return (
<DiagramHeaderAny
name={name}
clientName={clientName}
isDirty={isDirty}
isSaving={isSaving}
lastSavedAt={lastSavedAt}
diagramId={diagramId}
onNameChange={(n: string) => { setName(n); setIsDirty(true) }}
onSave={handleSave}
onExportPng={handleExportPng}
onExportPdf={handleExportPdf}
onExportJson={handleExportJson}
onUndo={undo}
onRedo={redo}
canUndo={canUndo}
canRedo={canRedo}
/>
)
})()}
<DiagramHeader
name={name}
clientName={clientName}
isDirty={isDirty}
isSaving={isSaving}
lastSavedAt={lastSavedAt}
diagramId={diagramId}
onNameChange={(n: string) => { setName(n); setIsDirty(true) }}
onSave={handleSave}
onExportPng={handleExportPng}
onExportPdf={handleExportPdf}
onExportJson={handleExportJson}
onUndo={undo}
onRedo={redo}
canUndo={canUndo}
canRedo={canRedo}
/>
<div className="flex flex-1 min-h-0">
<DeviceToolbar deviceTypes={deviceTypes} onDeviceTypesChange={loadDeviceTypes} />
<div className="flex flex-1 flex-col min-h-0">