Files
MikrotikManager/components/backups/backup-create-sheet.tsx
T

211 lines
8.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client"
import type { Server } from "@/lib/data"
import { FormField } from "@/components/form-kit"
import { StatusBadge } from "@/components/status-badge"
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { Input } from "@/components/ui/input"
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription,
SheetFooter,
SheetClose,
} from "@/components/ui/sheet"
import {
Stepper,
StepperContent,
StepperIndicator,
StepperItem,
StepperNav,
StepperPanel,
StepperSeparator,
StepperTitle,
StepperTrigger,
} from "@/components/reui/stepper"
import { cn } from "@/lib/utils"
export function BackupCreateSheet({
open,
onOpenChange,
step,
onStepChange,
servers,
selected,
onToggle,
onSelectAll,
onClear,
notes,
onNotesChange,
destinationLabel,
busy,
onSubmit,
locked = false,
terminal = false,
canObserve = true,
jobId,
jobStatus,
result,
onReset,
}: {
open: boolean
onOpenChange: (open: boolean) => void
step: number
onStepChange: (step: number) => void
servers: Server[]
selected: Set<string>
onToggle: (id: string) => void
onSelectAll: () => void
onClear: () => void
notes: string
onNotesChange: (value: string) => void
destinationLabel: string
busy: boolean
locked?: boolean
terminal?: boolean
canObserve?: boolean
jobId?: string
jobStatus?: string
result?: string
onReset: () => void
onSubmit: () => void
}) {
return (
<Sheet open={open} onOpenChange={(v) => { onOpenChange(v); if (!v) onStepChange(1) }}>
<SheetContent side="right" className="data-[side=right]:w-full data-[side=right]:sm:max-w-md min-w-0 flex flex-col gap-0 p-0">
<SheetHeader className="px-6 pt-6 pb-4 border-b shrink-0">
<SheetTitle>{locked ? "Задача резервного копирования" : "Новый бэкап"}</SheetTitle>
<SheetDescription>Снять конфигурацию вручную с выбранных серверов</SheetDescription>
</SheetHeader>
{locked && <div role="status" className="px-6 py-3 text-sm break-all"><p>ID: {jobId}</p><p>{jobStatus}</p>{result && <p>{result}</p>}<p className="text-xs text-muted-foreground">Закрытие формы не отменяет задачу. Повторная проверка не создаёт новые копии.</p></div>}
<fieldset disabled={busy || locked} className="flex-1 min-h-0 flex flex-col">
<Stepper value={step} onValueChange={onStepChange} className="flex-1 flex flex-col min-h-0 px-6 py-5">
<StepperNav className="mb-5">
<StepperItem step={1}>
<StepperTrigger>
<StepperIndicator>1</StepperIndicator>
<StepperTitle className="sr-only">Серверы</StepperTitle>
</StepperTrigger>
<StepperSeparator />
</StepperItem>
<StepperItem step={2}>
<StepperTrigger>
<StepperIndicator>2</StepperIndicator>
<StepperTitle className="sr-only">Заметка</StepperTitle>
</StepperTrigger>
<StepperSeparator />
</StepperItem>
<StepperItem step={3}>
<StepperTrigger>
<StepperIndicator>3</StepperIndicator>
<StepperTitle className="sr-only">Подтверждение</StepperTitle>
</StepperTrigger>
</StepperItem>
</StepperNav>
<StepperPanel className="flex-1 overflow-y-auto">
<StepperContent value={1} className="flex flex-col gap-3">
<div className="flex items-center justify-between mb-1">
<p className="text-sm font-medium">Выберите серверы</p>
<div className="flex items-center gap-2">
<button type="button" onClick={onSelectAll} className="text-xs text-primary hover:underline">
Все
</button>
<span className="text-border">·</span>
<button
type="button"
onClick={onClear}
className="text-xs text-muted-foreground hover:text-foreground hover:underline"
>
Сбросить
</button>
</div>
</div>
{servers.map((s) => {
const checked = selected.has(s.id)
return (
<label
key={s.id}
className={cn(
"flex cursor-pointer items-center gap-3 rounded-lg border p-3 text-left transition-colors",
checked ? "border-primary/40 bg-primary/5" : "border-border hover:bg-muted/40",
)}
>
<Checkbox
checked={checked}
onCheckedChange={() => onToggle(s.id)}
aria-label={`Выбрать ${s.name}`}
/>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium">{s.name}</p>
<div className="flex items-center gap-1.5 mt-0.5">
<span className="text-xs font-mono text-muted-foreground">{s.host}</span>
<StatusBadge status={s.status} />
</div>
</div>
{s.status === "offline" && (
<span className="text-xs text-muted-foreground">недоступен</span>
)}
</label>
)
})}
</StepperContent>
<StepperContent value={2} className="flex flex-col gap-4">
<FormField label="Заметка">
<Input
placeholder="Например: перед обновлением BGP"
aria-label="Заметка резервной копии"
maxLength={500}
value={notes}
onChange={(e) => onNotesChange(e.target.value)}
/>
</FormField>
</StepperContent>
<StepperContent value={3} className="flex flex-col gap-3 text-sm">
<p className="text-muted-foreground">
Будет создан бэкап для <strong className="text-foreground">{selected.size}</strong> серверов.
</p>
<p className="text-muted-foreground">
Куда сохранится: <strong className="text-foreground">{destinationLabel}</strong>
</p>
{notes ? <p className="text-muted-foreground">Заметка: {notes}</p> : null}
</StepperContent>
</StepperPanel>
</Stepper>
</fieldset>
<SheetFooter className="px-6 py-4 border-t shrink-0 flex-row flex-wrap gap-2">
<SheetClose render={<Button variant="outline" className="flex-1" />}>Закрыть</SheetClose>
{!locked && step > 1 && (
<Button type="button" variant="outline" className="flex-1" onClick={() => onStepChange(step - 1)}>
Назад
</Button>
)}
{locked ? <><Button type="button" disabled={!canObserve || busy || terminal} onClick={onSubmit}>Проверить задачу</Button>{terminal && <Button type="button" onClick={onReset}>Новая задача</Button>}</> : step < 3 ? (
<Button
type="button"
className="flex-1"
disabled={step === 1 && selected.size === 0}
onClick={() => onStepChange(step + 1)}
>
Далее
</Button>
) : (
<Button
type="button"
className="flex-1"
disabled={selected.size === 0 || busy}
onClick={onSubmit}
>
Снять бэкап ({selected.size})
</Button>
)}
</SheetFooter>
</SheetContent>
</Sheet>
)
}