151 lines
6.3 KiB
TypeScript
151 lines
6.3 KiB
TypeScript
import React from "react"
|
|
import { AlertTriangle, Trash2 } from "lucide-react"
|
|
|
|
import {
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogCancel,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
AlertDialogTrigger,
|
|
} from "@/components/ui/alert-dialog"
|
|
import { AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Separator } from "@/components/ui/separator"
|
|
import type { JobStatus } from "@shared/types"
|
|
import { ALL_JOB_STATUSES, STATUS_DESCRIPTIONS } from "@client/pages/settings/constants"
|
|
|
|
type DangerZoneSectionProps = {
|
|
statusesToClear: JobStatus[]
|
|
toggleStatusToClear: (status: JobStatus) => void
|
|
handleClearByStatuses: () => void
|
|
handleClearDatabase: () => void
|
|
isLoading: boolean
|
|
isSaving: boolean
|
|
}
|
|
|
|
export const DangerZoneSection: React.FC<DangerZoneSectionProps> = ({
|
|
statusesToClear,
|
|
toggleStatusToClear,
|
|
handleClearByStatuses,
|
|
handleClearDatabase,
|
|
isLoading,
|
|
isSaving,
|
|
}) => {
|
|
return (
|
|
<AccordionItem value="danger-zone" className="border rounded-lg px-4 border-destructive/30 mt-4">
|
|
<AccordionTrigger className="hover:no-underline py-4">
|
|
<div className="flex items-center gap-2 text-destructive">
|
|
<AlertTriangle className="h-4 w-4" />
|
|
<span className="text-base font-semibold tracking-wider">Danger Zone</span>
|
|
</div>
|
|
</AccordionTrigger>
|
|
<AccordionContent className="pb-4">
|
|
<div className="space-y-4 pt-2">
|
|
<div className="p-3 rounded-md space-y-4">
|
|
<div className="space-y-0.5">
|
|
<div className="text-sm font-semibold text-destructive">Clear Jobs by Status</div>
|
|
<div className="text-xs text-muted-foreground">
|
|
Select which job statuses you want to clear.
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 sm:grid-cols-3 gap-2">
|
|
{ALL_JOB_STATUSES.map((status) => {
|
|
const isSelected = statusesToClear.includes(status)
|
|
return (
|
|
<button
|
|
key={status}
|
|
type="button"
|
|
onClick={() => toggleStatusToClear(status)}
|
|
disabled={isLoading || isSaving}
|
|
className={`flex items-start gap-3 rounded-lg border p-3 text-left transition-colors hover:bg-destructive/20 disabled:cursor-not-allowed disabled:opacity-50 ${
|
|
isSelected ? 'border-destructive bg-destructive/10' : 'border-border'
|
|
}`}
|
|
>
|
|
<div className={`mt-0.5 h-4 w-4 rounded-full border-2 flex items-center justify-center ${
|
|
isSelected ? 'border-destructive' : 'border-muted-foreground'
|
|
}`}>
|
|
{isSelected && <div className="h-2 w-2 rounded-full bg-destructive" />}
|
|
</div>
|
|
<div className="grid gap-0.5">
|
|
<span className="text-sm font-medium capitalize">{status}</span>
|
|
<span className="text-xs text-muted-foreground">
|
|
{STATUS_DESCRIPTIONS[status]}
|
|
</span>
|
|
</div>
|
|
</button>
|
|
)
|
|
})}
|
|
</div>
|
|
|
|
<AlertDialog>
|
|
<AlertDialogTrigger asChild>
|
|
<Button
|
|
variant="destructive"
|
|
size="sm"
|
|
disabled={isLoading || isSaving || statusesToClear.length === 0}
|
|
>
|
|
<Trash2 className="mr-2 h-4 w-4" />
|
|
Clear Selected ({statusesToClear.length})
|
|
</Button>
|
|
</AlertDialogTrigger>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>Clear jobs by status?</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
This will delete all jobs with the following statuses: {statusesToClear.join(', ')}.
|
|
This action cannot be undone.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
<AlertDialogAction onClick={handleClearByStatuses} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
|
|
Clear {statusesToClear.length} status{statusesToClear.length !== 1 ? 'es' : ''}
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between p-3 rounded-md">
|
|
<div className="space-y-0.5">
|
|
<div className="text-sm font-semibold text-destructive">Clear Entire Database</div>
|
|
<div className="text-xs text-muted-foreground">
|
|
Delete all jobs and pipeline runs from the database.
|
|
</div>
|
|
</div>
|
|
<AlertDialog>
|
|
<AlertDialogTrigger asChild>
|
|
<Button variant="destructive" size="sm" disabled={isLoading || isSaving}>
|
|
<Trash2 className="mr-2 h-4 w-4" />
|
|
Clear Database
|
|
</Button>
|
|
</AlertDialogTrigger>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>Clear all jobs?</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
This deletes all jobs and pipeline runs from the database. This action cannot be undone.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
<AlertDialogAction onClick={handleClearDatabase} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
|
|
Clear database
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
</div>
|
|
</div>
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
)
|
|
}
|