Files
pansy/web/src/editor/UndoButton.tsx
T
steve 2a8fe24766
Build image / build-and-push (push) Successful in 9s
History panel + undo in the editor (#49) (#63)
Co-authored-by: Steve Dudenhoeffer <[email protected]>
2026-07-21 05:23:25 +00:00

52 lines
1.5 KiB
TypeScript

import { Button } from '@/components/ui/Button'
import { cn } from '@/lib/cn'
import type { ChangeSet, UndoOutcome, useUndo } from '@/lib/history'
/**
* Undo, plus what happened. Paired with useUndo so the history list and the
* agent turn's inline undo (#57) behave identically — including the part that
* actually matters, which is reporting a partial result honestly rather than as
* a success or a failure.
*/
export function UndoButton({
changeSet,
undo,
className,
label = 'Undo',
}: {
changeSet: ChangeSet
undo: ReturnType<typeof useUndo>
className?: string
label?: string
}) {
const outcome = undo.outcomeFor(changeSet.id)
return (
<div className={cn('flex flex-col items-end gap-1', className)}>
<Button
variant="ghost"
className="px-2 py-1 text-xs"
disabled={outcome?.tone === 'pending'}
onClick={() => undo.undo(changeSet)}
>
{outcome?.tone === 'pending' ? 'Undoing…' : label}
</Button>
{outcome && outcome.tone !== 'pending' && <OutcomeNote outcome={outcome} />}
</div>
)
}
const TONE_CLASS: Record<Exclude<UndoOutcome['tone'], 'pending'>, string> = {
ok: 'text-muted',
partial: 'text-amber-700 dark:text-amber-400',
error: 'text-red-700 dark:text-red-400',
}
function OutcomeNote({ outcome }: { outcome: UndoOutcome }) {
if (outcome.tone === 'pending') return null
return (
<p role="status" className={cn('text-right text-xs', TONE_CLASS[outcome.tone])}>
{outcome.message}
</p>
)
}