95 lines
3.2 KiB
TypeScript
95 lines
3.2 KiB
TypeScript
'use client'
|
||
|
||
import { useState } from 'react'
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from '@/components/ui/dialog'
|
||
import { Button } from '@/components/ui/button'
|
||
import { useScheduleHistory, useRollbackSchedule } from '@/hooks/use-channels'
|
||
|
||
interface Props {
|
||
channelId: string
|
||
open: boolean
|
||
onOpenChange: (open: boolean) => void
|
||
}
|
||
|
||
const fmtDateRange = (from: string, until: string) =>
|
||
`${new Date(from).toLocaleDateString()} – ${new Date(until).toLocaleDateString()}`
|
||
|
||
export function ScheduleHistoryDialog({ channelId, open, onOpenChange }: Props) {
|
||
const { data: entries } = useScheduleHistory(channelId)
|
||
const rollback = useRollbackSchedule()
|
||
const [confirmId, setConfirmId] = useState<string | null>(null)
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
<DialogContent>
|
||
<DialogHeader>
|
||
<DialogTitle>Schedule history</DialogTitle>
|
||
</DialogHeader>
|
||
<div className="flex flex-col gap-2 mt-2 max-h-[60vh] overflow-y-auto">
|
||
{(entries ?? []).map((entry, i) => (
|
||
<div
|
||
key={entry.id}
|
||
className="flex items-center gap-3 p-3 rounded border border-border"
|
||
>
|
||
<div className="flex-1 min-w-0">
|
||
<div className="text-sm font-medium">
|
||
Gen #{entry.generation}
|
||
{i === 0 && (
|
||
<span className="ml-2 text-xs text-green-400 bg-green-950 px-1.5 py-0.5 rounded">
|
||
active
|
||
</span>
|
||
)}
|
||
</div>
|
||
<div className="text-xs text-muted-foreground mt-0.5">
|
||
{fmtDateRange(entry.valid_from, entry.valid_until)}
|
||
</div>
|
||
</div>
|
||
|
||
{i > 0 && (
|
||
confirmId === entry.id ? (
|
||
<div className="flex items-center gap-1 text-xs">
|
||
<span className="text-amber-400 whitespace-nowrap">Roll back to gen #{entry.generation}?</span>
|
||
<Button
|
||
size="sm"
|
||
variant="destructive"
|
||
disabled={rollback.isPending}
|
||
onClick={() => {
|
||
rollback.mutate({ channelId, genId: entry.id })
|
||
setConfirmId(null)
|
||
onOpenChange(false)
|
||
}}
|
||
>
|
||
Confirm
|
||
</Button>
|
||
<Button size="sm" variant="ghost" onClick={() => setConfirmId(null)}>
|
||
Cancel
|
||
</Button>
|
||
</div>
|
||
) : (
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
onClick={() => setConfirmId(entry.id)}
|
||
>
|
||
Rollback to here
|
||
</Button>
|
||
)
|
||
)}
|
||
</div>
|
||
))}
|
||
{(entries ?? []).length === 0 && (
|
||
<p className="text-sm text-muted-foreground text-center py-8">
|
||
No schedule history yet. Generate a schedule to get started.
|
||
</p>
|
||
)}
|
||
</div>
|
||
</DialogContent>
|
||
</Dialog>
|
||
)
|
||
}
|