Openstatus www.openstatus.dev
at main 132 lines 3.9 kB view raw
1"use client"; 2 3import { TableCellBadge } from "@/components/data-table/table-cell-badge"; 4import { TableCellDate } from "@/components/data-table/table-cell-date"; 5import { TableCellNumber } from "@/components/data-table/table-cell-number"; 6import { Button } from "@/components/ui/button"; 7import { DataTableColumnHeader } from "@/components/ui/data-table/data-table-column-header"; 8import { colors } from "@/data/status-report-updates.client"; 9import { cn } from "@/lib/utils"; 10import type { RouterOutputs } from "@openstatus/api"; 11import type { ColumnDef } from "@tanstack/react-table"; 12import { ChevronDown, ChevronUp } from "lucide-react"; 13import Link from "next/link"; 14import { DataTableRowActions } from "./data-table-row-actions"; 15 16type StatusReport = RouterOutputs["statusReport"]["list"][number]; 17 18export const columns: ColumnDef<StatusReport>[] = [ 19 { 20 id: "expander", 21 header: () => null, 22 cell: ({ row }) => { 23 return row.getCanExpand() ? ( 24 <Button 25 {...{ 26 className: "size-7 shadow-none text-muted-foreground", 27 onClick: (e) => { 28 e.stopPropagation(); 29 row.toggleExpanded(); 30 }, 31 "aria-expanded": row.getIsExpanded(), 32 "aria-label": row.getIsExpanded() 33 ? `Collapse details for ${row.original.title}` 34 : `Expand details for ${row.original.title}`, 35 size: "icon", 36 variant: "ghost", 37 }} 38 > 39 {row.getIsExpanded() ? ( 40 <ChevronUp className="opacity-60" size={16} aria-hidden="true" /> 41 ) : ( 42 <ChevronDown className="opacity-60" size={16} aria-hidden="true" /> 43 )} 44 </Button> 45 ) : undefined; 46 }, 47 meta: { 48 headerClassName: "w-7", 49 }, 50 }, 51 { 52 accessorKey: "title", 53 header: "Title", 54 enableSorting: false, 55 enableHiding: false, 56 meta: { 57 cellClassName: "max-w-[200px] truncate", 58 }, 59 }, 60 { 61 accessorKey: "status", 62 header: "Current Status", 63 cell: ({ row }) => { 64 const value = String(row.getValue("status")); 65 return ( 66 <div 67 className={cn( 68 "font-mono capitalize", 69 colors[value as keyof typeof colors], 70 )} 71 > 72 {value} 73 </div> 74 ); 75 }, 76 enableSorting: false, 77 enableHiding: false, 78 }, 79 { 80 id: "updates", 81 accessorFn: (row) => row.updates.length, 82 header: "Total Updates", 83 cell: ({ row }) => { 84 const value = row.getValue("updates"); 85 return <TableCellNumber value={value} />; 86 }, 87 }, 88 { 89 id: "pageComponents", 90 accessorFn: (row) => row?.pageComponents, 91 header: "Affected", 92 cell: ({ row }) => { 93 const value = row.getValue("pageComponents"); 94 if (Array.isArray(value) && value.length > 0 && "name" in value[0]) { 95 return ( 96 <div className="flex flex-wrap gap-1"> 97 {value.map((m) => 98 m.monitorId ? ( 99 <Link href={`/monitors/${m.monitorId}/overview`} key={m.id}> 100 <TableCellBadge value={m.name} /> 101 </Link> 102 ) : ( 103 <TableCellBadge value={m.name} key={m.id} /> 104 ), 105 )} 106 </div> 107 ); 108 } 109 return <div className="text-muted-foreground">-</div>; 110 }, 111 }, 112 { 113 id: "startedAt", 114 accessorFn: (row) => 115 row.updates.sort((a, b) => a.date.getTime() - b.date.getTime())[0]?.date, 116 header: ({ column }) => ( 117 <DataTableColumnHeader column={column} title="Started At" /> 118 ), 119 cell: ({ row }) => <TableCellDate value={row.getValue("startedAt")} />, 120 enableHiding: false, 121 meta: { 122 cellClassName: "w-[170px]", 123 }, 124 }, 125 { 126 id: "actions", 127 cell: ({ row }) => <DataTableRowActions row={row} />, 128 meta: { 129 cellClassName: "w-8", 130 }, 131 }, 132];