"use client"; import { Check, Copy, type IconType, More, Delete } from "@openstatus/icons"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@openstatus/ui/components/ui/alert-dialog"; import { Button } from "@openstatus/ui/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@openstatus/ui/components/ui/dropdown-menu"; import { Input } from "@openstatus/ui/components/ui/input"; import { useCopyToClipboard } from "@openstatus/ui/hooks/use-copy-to-clipboard"; import type { DropdownMenuContentProps } from "@radix-ui/react-dropdown-menu"; import { isTRPCClientError } from "@trpc/client"; import type * as React from "react"; import { useState, useTransition } from "react"; import { toast } from "sonner"; interface QuickActionsProps extends React.ComponentProps { align?: DropdownMenuContentProps["align"]; side?: DropdownMenuContentProps["side"]; actions?: { id: string; label: string; icon: IconType; variant: "default" | "destructive"; onClick?: () => Promise | void; }[]; deleteAction?: { /** * The value that must be typed to confirm deletion. Also used in the dialog title. * If omitted, no type-to-confirm step is shown. */ confirmationValue?: string; submitAction?: () => Promise; }; } export function QuickActions({ align = "end", side, className, actions, deleteAction, children, ...props }: QuickActionsProps) { const [value, setValue] = useState(""); const [isPending, startTransition] = useTransition(); const [open, setOpen] = useState(false); const { copy, isCopied } = useCopyToClipboard(); const handleDelete = async () => { startTransition(async () => { if (!deleteAction?.submitAction) return; const promise = deleteAction.submitAction(); toast.promise(promise, { loading: "Deleting...", success: "Deleted", error: (error) => { if (isTRPCClientError(error)) { return error.message; } return "Failed to delete"; }, }); try { await promise; } catch (error) { console.error("Failed to delete:", error); } finally { setOpen(false); } }); }; return ( {children ?? ( )} Quick Actions {actions ?.filter((item) => item.id !== "delete") .map((item) => ( { e.stopPropagation(); item.onClick?.(); }} > {item.label} ))} {deleteAction && ( <> {/* NOTE: add a separator only if actions exist */} {actions?.length ? : null} Delete )} { // NOTE: bug where the body is not clickable after closing the alert dialog event.preventDefault(); document.body.style.pointerEvents = ""; }} > {deleteAction?.confirmationValue ? `Are you sure about deleting \`${deleteAction.confirmationValue}\`?` : "Are you sure?"} This action cannot be undone. This will permanently remove the entry from the database. {deleteAction?.confirmationValue ? (

Type{" "} {" "} to confirm

setValue(e.target.value)} />
) : null} e.stopPropagation()}> Cancel { e.preventDefault(); handleDelete(); }} > {isPending ? "Deleting..." : "Delete"}
); }