Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
5.1 kB ยท 188 lines
TSX
at incident-api
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189"use client";
import { useStatusBlocksLabels } from "@openstatus/ui/components/blocks/status-i18n";import { Button } from "@openstatus/ui/components/ui/button";import { Input } from "@openstatus/ui/components/ui/input";import { Popover, PopoverContent, PopoverTrigger,} from "@openstatus/ui/components/ui/popover";import { Separator } from "@openstatus/ui/components/ui/separator";import { useCopyToClipboard } from "@openstatus/ui/hooks/use-copy-to-clipboard";import { cn } from "@openstatus/ui/lib/utils";import { Check, Copy } from "lucide-react";
/** * StatusUpdates โ popover root for "Get updates" controls. * * Flat exports. Compose `StatusUpdatesTrigger` + `StatusUpdatesContent` and * pick whichever channel children apply (`StatusUpdatesRss`, * `StatusUpdatesJson`, `StatusUpdatesSlack`, `StatusUpdatesSsh`, or your own * email form). The block does not enforce a tab structure โ callers wrap * children with `Tabs` themselves if needed. */export function StatusUpdates({ children, ...props}: React.ComponentProps<typeof Popover>) { return <Popover {...props}>{children}</Popover>;}
export function StatusUpdatesTrigger({ children, className, ...props}: React.ComponentProps<typeof Button>) { const labels = useStatusBlocksLabels(); return ( <PopoverTrigger asChild> <Button data-slot="status-updates-trigger" size="sm" variant="outline" className={cn(className)} {...props} > {children ?? labels.subscribe} </Button> </PopoverTrigger> );}
export function StatusUpdatesContent({ className, ...props}: React.ComponentProps<typeof PopoverContent>) { return ( <PopoverContent data-slot="status-updates-content" align="end" className={cn("w-80 overflow-hidden p-0", className)} {...props} /> );}
/** * StatusUpdatesSection โ single channel description + content slot. * Use to compose custom channels; the built-in `StatusUpdatesRss`/`Json`/ * `Slack`/`Ssh` children render this internally. */export function StatusUpdatesSection({ description, children, className, ...props}: React.ComponentProps<"div"> & { description?: React.ReactNode;}) { return ( <div data-slot="status-updates-section" className={cn("flex flex-col gap-2 px-2 py-2", className)} {...props} > {description ? <div className="text-sm">{description}</div> : null} {children} </div> );}
export function StatusUpdatesCopyInput({ value, className, onClick, ...props}: Omit<React.ComponentProps<typeof Input>, "value"> & { value: string }) { const labels = useStatusBlocksLabels(); const { copy, isCopied } = useCopyToClipboard(); return ( <div data-slot="status-updates-copy-input" className={cn("relative w-full", className)} > <Input data-slot="status-updates-copy-input-field" value={value} readOnly onClick={(e) => { copy(value, { successMessage: labels.linkCopiedToClipboard, withToast: true, }); onClick?.(e); }} {...props} /> <Button data-slot="status-updates-copy-input-button" type="button" variant="outline" size="icon" onClick={() => copy(value, { successMessage: labels.linkCopiedToClipboard, withToast: true, }) } className="absolute top-1/2 right-2 size-6 -translate-y-1/2 backdrop-blur-xs" > {isCopied ? <Check /> : <Copy />} <span className="sr-only">{labels.ariaCopyLink}</span> </Button> </div> );}
export function StatusUpdatesRss({ rssUrl, atomUrl,}: { rssUrl: string; atomUrl?: string;}) { const labels = useStatusBlocksLabels(); return ( <> <StatusUpdatesSection description={labels.subscribeRssDescription}> <StatusUpdatesCopyInput value={rssUrl} /> </StatusUpdatesSection> {atomUrl ? ( <> <Separator /> <StatusUpdatesSection description={labels.subscribeAtomDescription}> <StatusUpdatesCopyInput value={atomUrl} /> </StatusUpdatesSection> </> ) : null} </> );}
export function StatusUpdatesJson({ url }: { url: string }) { const labels = useStatusBlocksLabels(); return ( <StatusUpdatesSection description={labels.subscribeJsonDescription}> <StatusUpdatesCopyInput value={url} /> </StatusUpdatesSection> );}
export function StatusUpdatesSlack({ rssUrl }: { rssUrl: string }) { const labels = useStatusBlocksLabels(); return ( <StatusUpdatesSection description={labels.subscribeSlackDescription}> <StatusUpdatesCopyInput value={`/feed subscribe ${rssUrl}`} /> </StatusUpdatesSection> );}
export function StatusUpdatesSsh({ command }: { command: string }) { const labels = useStatusBlocksLabels(); return ( <StatusUpdatesSection description={labels.subscribeSshDescription}> <StatusUpdatesCopyInput value={command} /> </StatusUpdatesSection> );}