Openstatus www.openstatus.dev

feat: add icon to monitor description (#1082)

authored by

Maximilian Kaske and committed by
GitHub
fc7ef55b 64c14125

+59 -7
+7
apps/web/src/app/app/[workspaceSlug]/(dashboard)/monitors/[id]/layout.tsx
··· 5 5 import { Header } from "@/components/dashboard/header"; 6 6 import AppPageWithSidebarLayout from "@/components/layout/app-page-with-sidebar-layout"; 7 7 import { JobTypeIconWithTooltip } from "@/components/monitor/job-type-icon-with-tooltip"; 8 + import { NotificationIconWithTooltip } from "@/components/monitor/notification-icon-with-tooltip"; 8 9 import { StatusDotWithTooltip } from "@/components/monitor/status-dot-with-tooltip"; 9 10 import { TagBadgeWithTooltip } from "@/components/monitor/tag-badge-with-tooltip"; 10 11 import { api } from "@/trpc/server"; ··· 72 73 <Badge variant="secondary">public</Badge> 73 74 </> 74 75 ) : null} 76 + <span className="text-muted-foreground/50 text-xs">•</span> 77 + <NotificationIconWithTooltip 78 + notifications={monitor.monitorsToNotifications.map( 79 + ({ notification }) => notification, 80 + )} 81 + /> 75 82 </div> 76 83 } 77 84 />
+6 -5
apps/web/src/components/data-table/monitor/columns.tsx
··· 80 80 { 81 81 accessorKey: "active", 82 82 accessorFn: (row) => row.monitor.active, 83 - header: () => ( 84 - <div className="w-4"> 85 - <Radio className="h-4 w-4" /> 86 - </div> 87 - ), 83 + header: () => <Radio className="h-4 w-4" />, 88 84 cell: ({ row }) => { 89 85 const { active, status } = row.original.monitor; 90 86 const maintenance = isActiveMaintenance(row.original.maintenances); ··· 101 97 filterFn: (row, _id, value) => { 102 98 if (!Array.isArray(value)) return true; 103 99 return value.includes(row.original.monitor.active); 100 + }, 101 + meta: { 102 + headerClassName: "w-4", 104 103 }, 105 104 }, 106 105 { ··· 130 129 header: "Tags", 131 130 cell: ({ row }) => { 132 131 const { tags } = row.original; 132 + if (!tags?.length) 133 + return <span className="text-muted-foreground">-</span>; 133 134 return <TagBadgeWithTooltip tags={tags} />; 134 135 }, 135 136 filterFn: (row, _id, value) => {
+8 -2
apps/web/src/components/data-table/monitor/data-table.tsx
··· 118 118 {headerGroup.headers.map((header) => { 119 119 return ( 120 120 // FIXME: className="[&:has(svg)]:w-4" takes the svg of the button > checkbox into account 121 - <TableHead key={header.id}> 121 + <TableHead 122 + key={header.id} 123 + className={header.column.columnDef.meta?.headerClassName} 124 + > 122 125 {header.isPlaceholder 123 126 ? null 124 127 : flexRender( ··· 139 142 data-state={row.getIsSelected() && "selected"} 140 143 > 141 144 {row.getVisibleCells().map((cell) => ( 142 - <TableCell key={cell.id}> 145 + <TableCell 146 + key={cell.id} 147 + className={cell.column.columnDef.meta?.cellClassName} 148 + > 143 149 {flexRender( 144 150 cell.column.columnDef.cell, 145 151 cell.getContext(),
+32
apps/web/src/components/monitor/notification-icon-with-tooltip.tsx
··· 1 + import type { Notification } from "@openstatus/db/src/schema"; 2 + import { 3 + Tooltip, 4 + TooltipContent, 5 + TooltipProvider, 6 + TooltipTrigger, 7 + } from "@openstatus/ui/src/components/tooltip"; 8 + 9 + import { Bell, BellOff } from "lucide-react"; 10 + 11 + export function NotificationIconWithTooltip({ 12 + notifications, 13 + }: { 14 + notifications?: Notification[]; 15 + }) { 16 + return ( 17 + <TooltipProvider> 18 + <Tooltip delayDuration={200}> 19 + <TooltipTrigger className="text-muted-foreground"> 20 + {notifications?.length ? ( 21 + <Bell className="h-4 w-4" /> 22 + ) : ( 23 + <BellOff className="h-4 w-4" /> 24 + )} 25 + </TooltipTrigger> 26 + <TooltipContent side="top" className="flex gap-2"> 27 + {`${notifications?.length || "No"} notification channels`} 28 + </TooltipContent> 29 + </Tooltip> 30 + </TooltipProvider> 31 + ); 32 + }
+6
packages/api/src/router/monitor.ts
··· 190 190 with: { maintenance: true }, 191 191 where: eq(maintenancesToMonitors.monitorId, opts.input.id), 192 192 }, 193 + monitorsToNotifications: { with: { notification: true } }, 193 194 }, 194 195 }); 195 196 ··· 201 202 }) 202 203 .array(), 203 204 maintenance: z.boolean().default(false).optional(), 205 + monitorsToNotifications: z 206 + .object({ 207 + notification: selectNotificationSchema, 208 + }) 209 + .array(), 204 210 }) 205 211 .safeParse({ 206 212 ..._monitor,