'use client' import { useState, useCallback } from 'react' import Link from 'next/link' import { useFlowRun } from '@/hooks/useFlowRun' import StreamingTerminal from '@/components/StreamingTerminal' import ConfirmDialog from '@/components/ConfirmDialog' // One panel runs either flow; we switch step-list + description based on the // currently active or last-triggered action. Wording mirrors the existing // /settings/backups → server-backup-section so the two entry points stay // consistent. The actual work in both flows runs out-of-band via systemd // (server-backup.service) — the ops-agent flow just kicks it off and tails // the resulting log / status file. type Kind = 'backup' | 'restore' type FlowSpec = { flowKey: string buttonLabel: string shortDescription: string steps: string[] confirmTitle: string confirmBody: string } const FLOWS: Record = { backup: { flowKey: 'server_backup_full', buttonLabel: 'Backup now', shortDescription: 'Volledige server-backup: pg_dumpall van alle databases + restic snapshot naar NAS én Backblaze B2 (Object Lock). Draait dagelijks via timer; deze knop triggert handmatig.', steps: [ 'trigger_server_backup (systemctl start server-backup.service)', 'tail_backup_log_today (live log mee-stream)', 'read_backup_status (lees status.json met repo-totalen + duur)', ], confirmTitle: 'Trigger server backup', confirmBody: 'flow: server_backup_full\n\nSteps:\n 1. trigger_server_backup (systemctl start server-backup.service)\n 2. tail_backup_log_today\n 3. read_backup_status\n\nThe actual work happens in systemd; this flow kicks it off and tails the log.', }, restore: { flowKey: 'server_backup_restore_test', buttonLabel: 'Run restore test', shortDescription: 'Non-destructieve restore-test: haalt de laatste snapshot uit de NAS-repo terug naar /tmp/restore-test en verifieert dat kritieke files er zijn. Raakt niets in de live stack.', steps: [ 'trigger_restore_test (restore latest NAS snapshot to /tmp/restore-test/)', 'read_backup_status (lees assertions + per-file outcome)', ], confirmTitle: 'Run restore test (NAS)', confirmBody: 'flow: server_backup_restore_test\n\nSteps:\n 1. trigger_restore_test (restore latest NAS snapshot to /tmp/restore-test/)\n 2. read_backup_status\n\nNon-destructive — restores into /tmp only and asserts critical files exist.', }, } export default function FlowPanel() { // `displayKind` drives the steps/description card; updated optimistically // when the user presses a button so the displayed flow matches the pending // confirm. `activeKind` only flips once the flow actually starts. const [displayKind, setDisplayKind] = useState('backup') const [pendingKind, setPendingKind] = useState(null) const [activeKind, setActiveKind] = useState(null) const [completedFlowRunId, setCompletedFlowRunId] = useState(null) const handleComplete = useCallback((flowRunId: string) => { setCompletedFlowRunId(flowRunId) }, []) const flowRun = useFlowRun(handleComplete) const handleClickKind = useCallback((kind: Kind) => { setDisplayKind(kind) setPendingKind(kind) }, []) const handleConfirm = useCallback(() => { if (pendingKind === null) return const kind = pendingKind setPendingKind(null) setCompletedFlowRunId(null) setActiveKind(kind) flowRun.startFlow(FLOWS[kind].flowKey, false) }, [pendingKind, flowRun]) const handleReset = useCallback(() => { flowRun.reset() setCompletedFlowRunId(null) setActiveKind(null) }, [flowRun]) const spec = FLOWS[displayKind] return (

{spec.shortDescription}

flow: {spec.flowKey}

    {spec.steps.map((step, i) => (
  1. {i + 1}. {step}
  2. ))}
{flowRun.status !== 'idle' && flowRun.status !== 'running' && ( )}
{flowRun.status !== 'idle' && (
Output{activeKind ? ` — ${FLOWS[activeKind].buttonLabel}` : ''} {completedFlowRunId && ( View in audit log → )}
)} setPendingKind(null)} />
) }