Openstatus www.openstatus.dev

refactor: description string to react node (#704)

authored by

Maximilian Kaske and committed by
GitHub
9bd546e5 c961ee3c

+68 -10
+24 -1
apps/web/src/app/app/[workspaceSlug]/(dashboard)/monitors/[id]/layout.tsx
··· 1 1 import { notFound } from "next/navigation"; 2 2 3 + import { Badge } from "@openstatus/ui"; 4 + 3 5 import { Header } from "@/components/dashboard/header"; 4 6 import AppPageWithSidebarLayout from "@/components/layout/app-page-with-sidebar-layout"; 7 + import { StatusDotWithTooltip } from "@/components/monitor/status-dot-with-tooltip"; 5 8 import { api } from "@/trpc/server"; 6 9 7 10 export default async function Layout({ ··· 23 26 24 27 return ( 25 28 <AppPageWithSidebarLayout id="monitors"> 26 - <Header title={monitor.name} description={monitor.url} /> 29 + <Header 30 + title={monitor.name} 31 + description={ 32 + <div className="text-muted-foreground flex items-center gap-2"> 33 + <span>{monitor.url}</span> 34 + <span className="text-muted-foreground/50 text-xs">•</span> 35 + <StatusDotWithTooltip 36 + active={monitor.active} 37 + status={monitor.status} 38 + /> 39 + <span className="text-muted-foreground/50 text-xs">•</span> 40 + <Badge className="inline-flex" variant="secondary"> 41 + {monitor.method} 42 + </Badge> 43 + <span className="text-muted-foreground/50 text-xs">•</span> 44 + <span className="text-sm"> 45 + every <code>{monitor.periodicity}</code> 46 + </span> 47 + </div> 48 + } 49 + /> 27 50 {children} 28 51 </AppPageWithSidebarLayout> 29 52 );
+5 -3
apps/web/src/components/dashboard/header.tsx
··· 4 4 5 5 interface HeaderProps extends React.HTMLAttributes<HTMLDivElement> { 6 6 title?: string; 7 - description?: string | null; 7 + description?: React.ReactNode; 8 8 actions?: React.ReactNode | React.ReactNode[]; 9 9 } 10 10 ··· 21 21 > 22 22 <div className="flex min-w-0 flex-col gap-1"> 23 23 <h1 className="font-cal text-3xl">{title}</h1> 24 - {description ? ( 24 + {typeof description === "string" ? ( 25 25 <p className="text-muted-foreground">{description}</p> 26 - ) : null} 26 + ) : ( 27 + description 28 + )} 27 29 </div> 28 30 {actions ? ( 29 31 <div className="flex flex-1 items-center justify-end gap-2">
+2 -2
apps/web/src/components/data-table/monitor/columns.tsx
··· 17 17 TooltipTrigger, 18 18 } from "@openstatus/ui"; 19 19 20 - import { StatusDot } from "@/components/monitor/status-dot"; 20 + import { StatusDotWithTooltip } from "@/components/monitor/status-dot-with-tooltip"; 21 21 import { Bar } from "@/components/tracker/tracker"; 22 22 import { DataTableRowActions } from "./data-table-row-actions"; 23 23 ··· 37 37 href={`./monitors/${row.original.monitor.id}/overview`} 38 38 className="group flex max-w-[150px] items-center gap-2 md:max-w-[250px]" 39 39 > 40 - <StatusDot active={active} status={status} /> 40 + <StatusDotWithTooltip active={active} status={status} /> 41 41 <span className="truncate group-hover:underline">{name}</span> 42 42 </Link> 43 43 );
+34
apps/web/src/components/monitor/status-dot-with-tooltip.tsx
··· 1 + import type { Monitor } from "@openstatus/db/src/schema"; 2 + import { 3 + Tooltip, 4 + TooltipContent, 5 + TooltipProvider, 6 + TooltipTrigger, 7 + } from "@openstatus/ui"; 8 + 9 + import { StatusDot } from "./status-dot"; 10 + 11 + export interface StatusDotWithTooltipProps 12 + extends Pick<Monitor, "active" | "status"> {} 13 + 14 + export function StatusDotWithTooltip({ 15 + status, 16 + active, 17 + }: StatusDotWithTooltipProps) { 18 + return ( 19 + <TooltipProvider delayDuration={50}> 20 + <Tooltip> 21 + <TooltipTrigger> 22 + <StatusDot {...{ status, active }} /> 23 + </TooltipTrigger> 24 + <TooltipContent> 25 + {active 26 + ? status === "active" 27 + ? "Monitor is active" 28 + : "Monitor has failed" 29 + : "Monitor is inactive"} 30 + </TooltipContent> 31 + </Tooltip> 32 + </TooltipProvider> 33 + ); 34 + }
+3 -4
apps/web/src/components/monitor/status-dot.tsx
··· 1 1 import type { Monitor } from "@openstatus/db/src/schema"; 2 2 3 - export function StatusDot({ 4 - active, 5 - status, 6 - }: Pick<Monitor, "active" | "status">) { 3 + export interface StatusDotProps extends Pick<Monitor, "active" | "status"> {} 4 + 5 + export function StatusDot({ active, status }: StatusDotProps) { 7 6 if (!active) { 8 7 return ( 9 8 <span className="relative flex h-2 w-2">