diff --git a/apps/dashboard/src/app/(dashboard)/monitors/[id]/logs/table-schema.tsx b/apps/dashboard/src/app/(dashboard)/monitors/[id]/logs/table-schema.tsx index 197b26007..cf66e3283 100644 --- a/apps/dashboard/src/app/(dashboard)/monitors/[id]/logs/table-schema.tsx +++ b/apps/dashboard/src/app/(dashboard)/monitors/[id]/logs/table-schema.tsx @@ -21,6 +21,7 @@ import { import { addDays, addHours, endOfDay, startOfDay } from "date-fns"; import { HoverCardTiming } from "@/components/common/hover-card-timing"; +import { TableCellEmpty } from "@/components/data-table/table-cell-empty"; import { TableCellNumber } from "@/components/data-table/table-cell-number"; import { TableCellRegion } from "@/components/data-table/table-cell-region"; import { cn } from "@/lib/utils"; @@ -39,10 +40,6 @@ const STATUS_SWATCH: Record = { error: "bg-destructive", }; -function Dash() { - return
-
; -} - /** The same square the table cell draws, so the filter row reads as its legend. */ function StatusSwatch({ value }: { value: string }) { const swatch = STATUS_SWATCH[value]; @@ -151,7 +148,7 @@ export function createLogsTableSchema(options: { .display("custom", { cell: (value) => { const swatch = STATUS_SWATCH[String(value)]; - if (!swatch) return ; + if (!swatch) return Unknown; return (
@@ -208,7 +205,7 @@ export function createLogsTableSchema(options: { .display("custom", { cell: (_value, row) => { const log = row as ResponseLog; - if (!log.timing) return ; + if (!log.timing) return No timing; return ; }, }), @@ -226,7 +223,8 @@ export function createLogsTableSchema(options: { }) .display("custom", { cell: (value) => { - if (value !== "cron" && value !== "api") return ; + if (value !== "cron" && value !== "api") + return Unknown; const Icon = value === "cron" ? Clock : ApiTrigger; const label = value === "cron" ? "Scheduled" : "API"; return ( diff --git a/apps/dashboard/src/app/(dashboard)/settings/integrations/connected-apps-card.tsx b/apps/dashboard/src/app/(dashboard)/settings/integrations/connected-apps-card.tsx index 558dbfda1..155102328 100644 --- a/apps/dashboard/src/app/(dashboard)/settings/integrations/connected-apps-card.tsx +++ b/apps/dashboard/src/app/(dashboard)/settings/integrations/connected-apps-card.tsx @@ -18,6 +18,7 @@ import { EmptyStateDescription, EmptyStateTitle, } from "@/components/content/empty-state"; +import { TableCellEmpty } from "@/components/data-table/table-cell-empty"; import { QuickActions } from "@/components/dropdowns/quick-actions"; import { FormCard, @@ -115,12 +116,18 @@ export function ConnectedAppsCard() { {userLabel(grant.user)} - {grant.createdAt ? formatDate(grant.createdAt) : "-"} + {grant.createdAt ? ( + formatDate(grant.createdAt) + ) : ( + Unknown + )} - {grant.lastUsedAt - ? formatDate(grant.lastUsedAt) - : "Never"} + {grant.lastUsedAt ? ( + formatDate(grant.lastUsedAt) + ) : ( + Never + )}
diff --git a/apps/dashboard/src/app/(dashboard)/status-pages/[id]/sidebar.tsx b/apps/dashboard/src/app/(dashboard)/status-pages/[id]/sidebar.tsx index 27a0af52e..e4315f687 100644 --- a/apps/dashboard/src/app/(dashboard)/status-pages/[id]/sidebar.tsx +++ b/apps/dashboard/src/app/(dashboard)/status-pages/[id]/sidebar.tsx @@ -12,6 +12,7 @@ import { useQuery } from "@tanstack/react-query"; import { useParams } from "next/navigation"; import { Link } from "@/components/common/link"; +import { TableCellEmpty } from "@/components/data-table/table-cell-empty"; import { TableCellLink } from "@/components/data-table/table-cell-link"; import { configurationLabels } from "@/components/forms/status-page/form-configuration"; import { SidebarRight } from "@/components/nav/sidebar-right"; @@ -49,7 +50,12 @@ export function Sidebar() { label: "Access Type", value: statusPage.accessType, }, - { label: "Domain", value: statusPage.customDomain || "-" }, + { + label: "Domain", + value: statusPage.customDomain || ( + No domain + ), + }, { label: "Favicon", value: statusPage.icon ? ( @@ -57,7 +63,7 @@ export function Sidebar() { favicon
) : ( - "-" + No favicon ), }, { @@ -90,19 +96,25 @@ export function Sidebar() { items: [ { label: "Theme", - value: statusPage.configuration?.theme ?? "-", + value: statusPage.configuration?.theme ?? ( + Default + ), }, { label: "Status source", - value: statusPage.configuration?.type - ? configurationLabels.type[statusPage.configuration.type] - : "-", + value: statusPage.configuration?.type ? ( + configurationLabels.type[statusPage.configuration.type] + ) : ( + Default + ), }, { label: "Card shows", - value: statusPage.configuration?.value - ? configurationLabels.value[statusPage.configuration.value] - : "-", + value: statusPage.configuration?.value ? ( + configurationLabels.value[statusPage.configuration.value] + ) : ( + Default + ), }, { label: "Show Uptime", diff --git a/apps/dashboard/src/components/chart/chart-bar-uptime-light.tsx b/apps/dashboard/src/components/chart/chart-bar-uptime-light.tsx index eeba847d7..86a96c9e9 100644 --- a/apps/dashboard/src/components/chart/chart-bar-uptime-light.tsx +++ b/apps/dashboard/src/components/chart/chart-bar-uptime-light.tsx @@ -11,6 +11,7 @@ import { Skeleton } from "@openstatus/ui/components/ui/skeleton"; import { useQuery } from "@tanstack/react-query"; import { Bar, BarChart, XAxis } from "recharts"; +import { TableCellEmpty } from "@/components/data-table/table-cell-empty"; import { mapUptime } from "@/data/metrics.client"; import { useTRPC } from "@/lib/trpc/client"; // import { startOfDay, subDays } from "date-fns"; @@ -59,7 +60,7 @@ export function ChartBarUptimeLight({ const refinedUptime = uptime ? mapUptime(uptime) : []; if (refinedUptime.length === 0) { - return -; + return No data; } return ( diff --git a/apps/dashboard/src/components/chat/tool-renderers/details.test.tsx b/apps/dashboard/src/components/chat/tool-renderers/details.test.tsx index 3306be180..de58fc7bc 100644 --- a/apps/dashboard/src/components/chat/tool-renderers/details.test.tsx +++ b/apps/dashboard/src/components/chat/tool-renderers/details.test.tsx @@ -112,7 +112,7 @@ describe("getMonitorSummaryDetails", () => { ["p50", "p75", "p90", "p95", "p99"], ]); expect(value(data, "Window")).toBe("7d"); - expect(value(data, "Last check")).toBe("-"); + expect(value(data, "Last check")).toBe("None"); expect(value(data, "Failed")).toBe("5"); expect(value(data, "p99")).toBe("400ms"); }); diff --git a/apps/dashboard/src/components/chat/tool-renderers/incidents.test.tsx b/apps/dashboard/src/components/chat/tool-renderers/incidents.test.tsx index cd2ee601c..42bcb56fc 100644 --- a/apps/dashboard/src/components/chat/tool-renderers/incidents.test.tsx +++ b/apps/dashboard/src/components/chat/tool-renderers/incidents.test.tsx @@ -133,7 +133,7 @@ describe("listIncidentsTable", () => { ]); const [closed, open] = table.rows; expect(text(closed.cells.status)).toBe("resolved · closed"); - expect(text(closed.cells.commander)).toBe("-"); + expect(text(closed.cells.commander)).toBe("Unassigned"); expect(text(open.cells.status)).toBe("open"); expect(text(open.cells.commander)).toBe("Ada"); expect(text(open.cells.id)).toBe("2"); @@ -173,7 +173,7 @@ describe("getIncidentDetails", () => { ]); const value = (label: string) => text(overview.rows.find((r) => r.label === label)?.value); - expect(value("Commander")).toBe("-"); + expect(value("Commander")).toBe("Unassigned"); expect(value("Status report")).toBe("Payments degraded"); }); diff --git a/apps/dashboard/src/components/chat/tool-renderers/incidents.tsx b/apps/dashboard/src/components/chat/tool-renderers/incidents.tsx index 46a332c19..4d577bfaf 100644 --- a/apps/dashboard/src/components/chat/tool-renderers/incidents.tsx +++ b/apps/dashboard/src/components/chat/tool-renderers/incidents.tsx @@ -32,7 +32,9 @@ export function listIncidentsTable( status: ( ), - commander: , + commander: ( + + ), id: , }, })), @@ -55,7 +57,12 @@ export function getIncidentDetails( { label: "Status", value: }, { label: "Commander", - value: , + value: ( + + ), }, { label: "Summary", diff --git a/apps/dashboard/src/components/chat/tool-renderers/list-maintenances.tsx b/apps/dashboard/src/components/chat/tool-renderers/list-maintenances.tsx index 7d8e6598f..2b6145010 100644 --- a/apps/dashboard/src/components/chat/tool-renderers/list-maintenances.tsx +++ b/apps/dashboard/src/components/chat/tool-renderers/list-maintenances.tsx @@ -36,7 +36,7 @@ export function listMaintenancesTable( m.pageId !== null ? ( ) : ( - + ), id: , }, diff --git a/apps/dashboard/src/components/chat/tool-renderers/list-page-components.tsx b/apps/dashboard/src/components/chat/tool-renderers/list-page-components.tsx index 09dba5e84..155879408 100644 --- a/apps/dashboard/src/components/chat/tool-renderers/list-page-components.tsx +++ b/apps/dashboard/src/components/chat/tool-renderers/list-page-components.tsx @@ -41,7 +41,7 @@ export function listPageComponentsTable( c.monitorId !== null ? ( ) : ( - + ), id: , }, diff --git a/apps/dashboard/src/components/chat/tool-renderers/list-private-locations.tsx b/apps/dashboard/src/components/chat/tool-renderers/list-private-locations.tsx index 3471bbf6c..4be9d5608 100644 --- a/apps/dashboard/src/components/chat/tool-renderers/list-private-locations.tsx +++ b/apps/dashboard/src/components/chat/tool-renderers/list-private-locations.tsx @@ -1,6 +1,7 @@ import type { AgentToolOutput } from "@openstatus/services/agent-tools"; import { TableCellDate } from "@/components/data-table/table-cell-date"; +import { TableCellEmpty } from "@/components/data-table/table-cell-empty"; import { TableCellLink } from "@/components/data-table/table-cell-link"; import { TableCellMetadata } from "@/components/data-table/table-cell-metadata"; import { TableCellNumber } from "@/components/data-table/table-cell-number"; @@ -46,7 +47,7 @@ export function listPrivateLocationsTable( lastSeenAt: location.lastSeenAt ? ( ) : ( - + Never ), id: , }, diff --git a/apps/dashboard/src/components/chat/tool-renderers/list-response-logs.tsx b/apps/dashboard/src/components/chat/tool-renderers/list-response-logs.tsx index 719a4cf20..1771a6d3d 100644 --- a/apps/dashboard/src/components/chat/tool-renderers/list-response-logs.tsx +++ b/apps/dashboard/src/components/chat/tool-renderers/list-response-logs.tsx @@ -3,6 +3,7 @@ import { cn } from "@openstatus/ui/lib/utils"; import { HoverCardTiming } from "@/components/common/hover-card-timing"; import { TableCellDate } from "@/components/data-table/table-cell-date"; +import { TableCellEmpty } from "@/components/data-table/table-cell-empty"; import { TableCellNumber } from "@/components/data-table/table-cell-number"; import { TableCellRegion } from "@/components/data-table/table-cell-region"; import { TableCellText } from "@/components/data-table/table-cell-text"; @@ -47,7 +48,7 @@ export function listResponseLogsTable( )} /> ) : ( -
-
+ Unknown ), timestamp: ( ) : ( - + No status ), latency: , timing: log.timing ? ( ) : ( -
-
+ No timing ), id: ( ), diff --git a/apps/dashboard/src/components/chat/tool-renderers/list-status-reports.tsx b/apps/dashboard/src/components/chat/tool-renderers/list-status-reports.tsx index 7934a59e9..3b449dde2 100644 --- a/apps/dashboard/src/components/chat/tool-renderers/list-status-reports.tsx +++ b/apps/dashboard/src/components/chat/tool-renderers/list-status-reports.tsx @@ -48,7 +48,7 @@ export function listStatusReportsTable( r.pageId !== null ? ( ) : ( - + ), id: , }, diff --git a/apps/dashboard/src/components/chat/tool-renderers/list-tables.test.tsx b/apps/dashboard/src/components/chat/tool-renderers/list-tables.test.tsx index 08a247974..2fb81e690 100644 --- a/apps/dashboard/src/components/chat/tool-renderers/list-tables.test.tsx +++ b/apps/dashboard/src/components/chat/tool-renderers/list-tables.test.tsx @@ -97,7 +97,7 @@ describe("listPageComponentsTable", () => { it("shows the monitor id, or a placeholder for static components", () => { expect(text(table.rows[0].cells.monitor)).toContain("4"); - expect(text(table.rows[1].cells.monitor).trim()).toBe("-"); + expect(text(table.rows[1].cells.monitor).trim()).toBe("No monitor"); }); }); @@ -122,8 +122,8 @@ describe("listPrivateLocationsTable", () => { ); }); - it("shows 'never' for a location that never reported", () => { - expect(text(table.rows[0].cells.lastSeenAt)).toBe("never"); + it("shows 'Never' for a location that never reported", () => { + expect(text(table.rows[0].cells.lastSeenAt)).toBe("Never"); expect(text(table.rows[0].cells.monitors)).toBe("none"); }); diff --git a/apps/dashboard/src/components/chat/tool-renderers/tables.test.tsx b/apps/dashboard/src/components/chat/tool-renderers/tables.test.tsx index d5b601a22..7ebe952aa 100644 --- a/apps/dashboard/src/components/chat/tool-renderers/tables.test.tsx +++ b/apps/dashboard/src/components/chat/tool-renderers/tables.test.tsx @@ -135,7 +135,7 @@ describe("listMaintenancesTable", () => { ); expect(text(table.rows[0].cells.duration)).toBe("2hours"); expect(text(table.rows[1].cells.duration)).toBe("30minutes"); - expect(text(table.rows[0].cells.page)).toBe("-"); + expect(text(table.rows[0].cells.page)).toBe("No page"); expect(text(table.rows[1].cells.page)).toBe("9"); }); @@ -178,10 +178,10 @@ describe("listResponseLogsTable", () => { }), ).rows; expect(row.id).toBe("row-0"); - expect(text(row.cells.indicator)).toBe("-"); - expect(text(row.cells.status)).toBe("—"); - expect(text(row.cells.timing)).toBe("-"); - expect(text(row.cells.id)).toBe("—"); + expect(text(row.cells.indicator)).toBe("Unknown"); + expect(text(row.cells.status)).toBe("No status"); + expect(text(row.cells.timing)).toBe("No timing"); + expect(text(row.cells.id)).toBe("No ID"); }); }); diff --git a/apps/dashboard/src/components/data-table/audit-logs-workspace/columns.tsx b/apps/dashboard/src/components/data-table/audit-logs-workspace/columns.tsx index be154876a..bb3abb17f 100644 --- a/apps/dashboard/src/components/data-table/audit-logs-workspace/columns.tsx +++ b/apps/dashboard/src/components/data-table/audit-logs-workspace/columns.tsx @@ -19,6 +19,7 @@ import type { ComponentType } from "react"; import { cn } from "@/lib/utils"; import { TableCellDate } from "../table-cell-date"; +import { TableCellEmpty } from "../table-cell-empty"; type AuditLog = RouterOutputs["auditLog"]["list"]["items"][number]; @@ -116,7 +117,7 @@ export const columns: ColumnDef[] = [
); } - return -; + return Unknown; } const via = viaSource[type]; const imgSrc = diff --git a/apps/dashboard/src/components/data-table/incidents/columns.tsx b/apps/dashboard/src/components/data-table/incidents/columns.tsx index fc0f55aab..082d03b33 100644 --- a/apps/dashboard/src/components/data-table/incidents/columns.tsx +++ b/apps/dashboard/src/components/data-table/incidents/columns.tsx @@ -46,7 +46,9 @@ const baseColumns: ColumnDef[] = [ header: ({ column }) => ( ), - cell: ({ row }) => , + cell: ({ row }) => ( + + ), enableHiding: false, }, { @@ -54,7 +56,9 @@ const baseColumns: ColumnDef[] = [ header: ({ column }) => ( ), - cell: ({ row }) => , + cell: ({ row }) => ( + + ), enableHiding: false, }, { diff --git a/apps/dashboard/src/components/data-table/maintenances/columns.tsx b/apps/dashboard/src/components/data-table/maintenances/columns.tsx index 4b9a98e68..3a5b6d064 100644 --- a/apps/dashboard/src/components/data-table/maintenances/columns.tsx +++ b/apps/dashboard/src/components/data-table/maintenances/columns.tsx @@ -11,6 +11,7 @@ import { TableCellLink } from "@/components/data-table/table-cell-link"; import { TableCellNumber } from "@/components/data-table/table-cell-number"; import { DataTableColumnHeader } from "@/components/ui/data-table/data-table-column-header"; +import { TableCellEmpty } from "../table-cell-empty"; import { DataTableRowActions } from "./data-table-row-actions"; type Maintenance = RouterOutputs["maintenance"]["list"][number]; @@ -42,7 +43,7 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => { const value = row.original.pageComponents; if (value.length === 0) { - return
-
; + return No components; } return (
diff --git a/apps/dashboard/src/components/data-table/managed-incidents/columns.tsx b/apps/dashboard/src/components/data-table/managed-incidents/columns.tsx index 95e4a6d23..ea6aca48d 100644 --- a/apps/dashboard/src/components/data-table/managed-incidents/columns.tsx +++ b/apps/dashboard/src/components/data-table/managed-incidents/columns.tsx @@ -62,7 +62,7 @@ export const columns: ColumnDef[] = [ : row.original.status === "canceled" ? row.original.closedAt : new Date(); - if (!end) return ; + if (!end) return ; const [amount, unit] = formatDistanceStrict( row.original.startedAt, end, diff --git a/apps/dashboard/src/components/data-table/monitors/columns.tsx b/apps/dashboard/src/components/data-table/monitors/columns.tsx index 14c76aca5..e79f61d35 100644 --- a/apps/dashboard/src/components/data-table/monitors/columns.tsx +++ b/apps/dashboard/src/components/data-table/monitors/columns.tsx @@ -11,9 +11,9 @@ import { formatDistanceToNowShort } from "@/lib/formatter"; import { TableCellSkeleton } from "../dable-cell-skeleton"; import { TableCellDate } from "../table-cell-date"; +import { TableCellEmpty } from "../table-cell-empty"; import { TableCellIndicator } from "../table-cell-indicator"; import { TableCellNumber } from "../table-cell-number"; -import { TableCellUnavailable } from "../table-cell-unavailable"; import { DataTableRowActions } from "./data-table-row-actions"; type Monitor = RouterOutputs["monitor"]["list"][number] & { @@ -134,7 +134,7 @@ export const columns: ColumnDef[] = [ const value = row.getValue("tags"); if (!Array.isArray(value)) return null; if (value.length === 0) { - return
-
; + return No tags; } return (
@@ -168,11 +168,17 @@ export const columns: ColumnDef[] = [ }, { id: "lastIncident", - header: "Last Incident", + header: "Last Downtime", accessorFn: (row) => row.incidents?.[0]?.createdAt, cell: ({ row }) => { const value = row.getValue("lastIncident"); - return ; + return ( + + ); }, enableHiding: false, enableGlobalFilter: false, @@ -209,6 +215,7 @@ export const columns: ColumnDef[] = [ ? formatDistanceToNowShort(new Date(value)) : value } + empty="Never" /> ); }, @@ -227,7 +234,7 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => { const value = row.getValue("p50"); if (value === undefined) return ; - if (!value) return ; + if (!value) return No data; return ; }, enableHiding: false, @@ -244,7 +251,7 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => { const value = row.getValue("p90"); if (value === undefined) return ; - if (!value) return ; + if (!value) return No data; return ; }, enableHiding: false, @@ -262,7 +269,7 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => { const value = row.getValue("p95"); if (value === undefined) return ; - if (!value) return ; + if (!value) return No data; return ; }, enableHiding: false, diff --git a/apps/dashboard/src/components/data-table/notifications/columns.tsx b/apps/dashboard/src/components/data-table/notifications/columns.tsx index acb007084..80631aed2 100644 --- a/apps/dashboard/src/components/data-table/notifications/columns.tsx +++ b/apps/dashboard/src/components/data-table/notifications/columns.tsx @@ -9,6 +9,7 @@ import { DataTableColumnHeader } from "@/components/ui/data-table/data-table-col import { type NotifierProvider, config } from "@/data/notifications.client"; import { TableCellBadge } from "../table-cell-badge"; +import { TableCellEmpty } from "../table-cell-empty"; import { DataTableRowActions } from "./data-table-row-actions"; type Notifier = RouterOutputs["notification"]["list"][number]; @@ -55,7 +56,7 @@ export const columns: ColumnDef[] = [
); } - return -; + return No monitors; }, meta: { cellClassName: "tabular-nums font-mono", diff --git a/apps/dashboard/src/components/data-table/overview-events/columns.tsx b/apps/dashboard/src/components/data-table/overview-events/columns.tsx index 21d206a86..a18a94d20 100644 --- a/apps/dashboard/src/components/data-table/overview-events/columns.tsx +++ b/apps/dashboard/src/components/data-table/overview-events/columns.tsx @@ -147,7 +147,9 @@ const baseColumns: ColumnDef[] = [ id: "endsAt", accessorFn: (row) => getResolvedAt(row), header: "End", - cell: ({ row }) => , + cell: ({ row }) => ( + + ), enableSorting: false, meta: { cellClassName: "w-[170px]", diff --git a/apps/dashboard/src/components/data-table/page-components/columns.tsx b/apps/dashboard/src/components/data-table/page-components/columns.tsx index 686d34db6..b7b7b49f0 100644 --- a/apps/dashboard/src/components/data-table/page-components/columns.tsx +++ b/apps/dashboard/src/components/data-table/page-components/columns.tsx @@ -5,6 +5,7 @@ import type { ColumnDef } from "@tanstack/react-table"; import { DataTableColumnHeader } from "@/components/ui/data-table/data-table-column-header"; +import { TableCellEmpty } from "../table-cell-empty"; import { DataTableRowActions } from "./data-table-row-actions"; type PageComponent = RouterOutputs["pageComponent"]["list"][number]; @@ -22,9 +23,10 @@ export const columns: ColumnDef[] = [ enableSorting: false, cell: ({ row }) => { const value = row.getValue("description"); + if (!value) return No description; return ( - {value ? String(value) : "-"} + {String(value)} ); }, @@ -46,7 +48,8 @@ export const columns: ColumnDef[] = [ ), cell: ({ row }) => { const value = row.getValue("order"); - return {value != null ? String(value) : "-"}; + if (value == null) return Unset; + return {String(value)}; }, }, { diff --git a/apps/dashboard/src/components/data-table/private-locations/columns.tsx b/apps/dashboard/src/components/data-table/private-locations/columns.tsx index c4c2a6cda..e03daaff3 100644 --- a/apps/dashboard/src/components/data-table/private-locations/columns.tsx +++ b/apps/dashboard/src/components/data-table/private-locations/columns.tsx @@ -9,6 +9,7 @@ import { cn } from "@/lib/utils"; import { TableCellBadge } from "../table-cell-badge"; import { TableCellDate } from "../table-cell-date"; +import { TableCellEmpty } from "../table-cell-empty"; import { TableCellMetadata } from "../table-cell-metadata"; import { TableCellText } from "../table-cell-text"; import { DataTableRowActions } from "./data-table-row-actions"; @@ -61,7 +62,7 @@ export const columns: ColumnDef[] = [ enableHiding: false, cell: ({ row }) => { const value = row.getValue("lastSeenAt"); - return ; + return ; }, }, { @@ -83,7 +84,7 @@ export const columns: ColumnDef[] = [
); } - return -; + return No monitors; }, meta: { cellClassName: "tabular-nums font-mono", diff --git a/apps/dashboard/src/components/data-table/response-logs/columns.tsx b/apps/dashboard/src/components/data-table/response-logs/columns.tsx index b8f575ff6..d178e63be 100644 --- a/apps/dashboard/src/components/data-table/response-logs/columns.tsx +++ b/apps/dashboard/src/components/data-table/response-logs/columns.tsx @@ -18,6 +18,8 @@ import { TableCellNumber } from "@/components/data-table/table-cell-number"; import { TableCellRegion } from "@/components/data-table/table-cell-region"; import { getStatusCodeVariant, textColors } from "@/data/status-codes"; +import { TableCellEmpty } from "../table-cell-empty"; + type ResponseLog = RouterOutputs["tinybird"]["get"]["data"][number]; // export const columns: ColumnDef[] = @@ -41,7 +43,7 @@ export function getColumns( if (value === "success") { return
; } - return
-
; + return Unknown; }, }, { @@ -75,7 +77,7 @@ export function getColumns( ); } - return
-
; + return No status; }, }, { @@ -111,7 +113,7 @@ export function getColumns( if (log.type === "http" && log.timing) { return ; } - return
-
; + return No timing; }, enableSorting: false, enableHiding: false, @@ -137,7 +139,7 @@ export function getColumns( ); } - return
-
; + return Unknown; }, enableSorting: false, enableHiding: false, diff --git a/apps/dashboard/src/components/data-table/settings/api-key/data-table.tsx b/apps/dashboard/src/components/data-table/settings/api-key/data-table.tsx index 73c8072cb..6dbbe597d 100644 --- a/apps/dashboard/src/components/data-table/settings/api-key/data-table.tsx +++ b/apps/dashboard/src/components/data-table/settings/api-key/data-table.tsx @@ -14,6 +14,8 @@ import { QuickActions } from "@/components/dropdowns/quick-actions"; import { formatDate } from "@/lib/formatter"; import { useTRPC } from "@/lib/trpc/client"; +import { TableCellEmpty } from "../../table-cell-empty"; + type ApiKey = RouterOutputs["apiKey"]["list"][number]; /** @@ -72,7 +74,11 @@ export function DataTable({ {apiKey.name} - {apiKey.description ?? "-"} + {apiKey.description ? ( + apiKey.description + ) : ( + No description + )} {apiKey.prefix}... @@ -81,7 +87,11 @@ export function DataTable({ {scopeLabel(apiKey.scopes)} - {apiKey.expiresAt ? formatDate(apiKey.expiresAt) : "-"} + {apiKey.expiresAt ? ( + formatDate(apiKey.expiresAt) + ) : ( + Never + )}
diff --git a/apps/dashboard/src/components/data-table/settings/invitations/data-table.tsx b/apps/dashboard/src/components/data-table/settings/invitations/data-table.tsx index 9edcdf3ad..769b40e7e 100644 --- a/apps/dashboard/src/components/data-table/settings/invitations/data-table.tsx +++ b/apps/dashboard/src/components/data-table/settings/invitations/data-table.tsx @@ -17,6 +17,8 @@ import { QuickActions } from "@/components/dropdowns/quick-actions"; import { formatDate } from "@/lib/formatter"; import { useTRPC } from "@/lib/trpc/client"; +import { TableCellEmpty } from "../../table-cell-empty"; + export function DataTable() { const trpc = useTRPC(); const { data: invitations, refetch } = useQuery( @@ -61,11 +63,19 @@ export function DataTable() { {item.email} {item.role} - {item.createdAt ? formatDate(item.createdAt) : "-"} + {item.createdAt ? ( + formatDate(item.createdAt) + ) : ( + Unknown + )} {formatDate(item.expiresAt)} - {item.acceptedAt ? formatDate(item.acceptedAt) : "-"} + {item.acceptedAt ? ( + formatDate(item.acceptedAt) + ) : ( + Pending + )}
diff --git a/apps/dashboard/src/components/data-table/settings/members/data-table.tsx b/apps/dashboard/src/components/data-table/settings/members/data-table.tsx index d494af4c0..6022ba913 100644 --- a/apps/dashboard/src/components/data-table/settings/members/data-table.tsx +++ b/apps/dashboard/src/components/data-table/settings/members/data-table.tsx @@ -13,6 +13,8 @@ import { QuickActions } from "@/components/dropdowns/quick-actions"; import { formatDate } from "@/lib/formatter"; import { useTRPC } from "@/lib/trpc/client"; +import { TableCellEmpty } from "../../table-cell-empty"; + export function DataTable() { const trpc = useTRPC(); const { data: members, refetch } = useQuery(trpc.member.list.queryOptions()); @@ -51,9 +53,7 @@ export function DataTable() {
- {item.user.name ?? ( - - - )} + {item.user.name ?? No name} {isMe ? You : null}
diff --git a/apps/dashboard/src/components/data-table/status-pages/columns.tsx b/apps/dashboard/src/components/data-table/status-pages/columns.tsx index 053f7214a..d1d2425f2 100644 --- a/apps/dashboard/src/components/data-table/status-pages/columns.tsx +++ b/apps/dashboard/src/components/data-table/status-pages/columns.tsx @@ -6,6 +6,7 @@ import type { ColumnDef } from "@tanstack/react-table"; import { Link } from "@/components/common/link"; import { TableCellLink } from "@/components/data-table/table-cell-link"; +import { TableCellEmpty } from "../table-cell-empty"; import { DataTableRowActions } from "./data-table-row-actions"; type StatusPage = RouterOutputs["page"]["list"][number]; @@ -34,7 +35,7 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => { const value = row.getValue("icon"); if (!value || typeof value !== "string") - return -; + return No favicon; return ( [] = [ cell: ({ row }) => { const value = row.getValue("domain"); if (typeof value !== "string") - return -; + return No domain; return ( {value} diff --git a/apps/dashboard/src/components/data-table/status-reports/columns.tsx b/apps/dashboard/src/components/data-table/status-reports/columns.tsx index e1dcc8632..115f0f297 100644 --- a/apps/dashboard/src/components/data-table/status-reports/columns.tsx +++ b/apps/dashboard/src/components/data-table/status-reports/columns.tsx @@ -19,6 +19,7 @@ import { import { DataTableColumnHeader } from "@/components/ui/data-table/data-table-column-header"; import { reportStartedAt } from "@/data/status-reports.client"; +import { TableCellEmpty } from "../table-cell-empty"; import { DataTableRowActions } from "./data-table-row-actions"; type StatusReport = RouterOutputs["statusReport"]["list"][number]; @@ -63,7 +64,7 @@ export const columns: ColumnDef[] = [ "impact", ); if (impact === undefined) - return
-
; + return No impact; return ; }, }, @@ -101,7 +102,7 @@ export const columns: ColumnDef[] = [
); } - return
-
; + return No components; }, }, { diff --git a/apps/dashboard/src/components/data-table/subscribers/columns.tsx b/apps/dashboard/src/components/data-table/subscribers/columns.tsx index eccab5285..e99309883 100644 --- a/apps/dashboard/src/components/data-table/subscribers/columns.tsx +++ b/apps/dashboard/src/components/data-table/subscribers/columns.tsx @@ -12,6 +12,7 @@ import type { ColumnDef } from "@tanstack/react-table"; import { formatDate } from "@/lib/formatter"; +import { TableCellEmpty } from "../table-cell-empty"; import { DataTableRowActions } from "./data-table-row-actions"; type Subscriber = RouterOutputs["pageSubscriber"]["list"][number]; @@ -138,7 +139,7 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => { const value = row.getValue("createdAt"); if (value instanceof Date) return formatDate(value); - if (!value) return "-"; + if (!value) return Unknown; return value; }, meta: { diff --git a/apps/dashboard/src/components/data-table/table-cell-date.tsx b/apps/dashboard/src/components/data-table/table-cell-date.tsx index c9b7bece8..348a643ba 100644 --- a/apps/dashboard/src/components/data-table/table-cell-date.tsx +++ b/apps/dashboard/src/components/data-table/table-cell-date.tsx @@ -6,12 +6,19 @@ import { HoverCardTimestamp } from "@/components/common/hover-card-timestamp"; import { useHydrated } from "@/hooks/use-hydrated"; import { cn } from "@/lib/utils"; +import { TableCellEmpty } from "./table-cell-empty"; + export function TableCellDate({ value, + empty, className, formatStr = "LLL dd, y HH:mm:ss", ...props -}: React.ComponentProps<"div"> & { value: unknown; formatStr?: string }) { +}: React.ComponentProps<"div"> & { + value: unknown; + formatStr?: string; + empty?: string; +}) { // local-time text differs between server and browser const hydrated = useHydrated(); if (value instanceof Date) { @@ -31,8 +38,8 @@ export function TableCellDate({ ); } return ( -
- - -
+ + {empty} + ); } diff --git a/apps/dashboard/src/components/data-table/table-cell-empty.tsx b/apps/dashboard/src/components/data-table/table-cell-empty.tsx new file mode 100644 index 000000000..63a9148b8 --- /dev/null +++ b/apps/dashboard/src/components/data-table/table-cell-empty.tsx @@ -0,0 +1,13 @@ +import { cn } from "@/lib/utils"; + +export function TableCellEmpty({ + children = "None", + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ {children} +
+ ); +} diff --git a/apps/dashboard/src/components/data-table/table-cell-link.tsx b/apps/dashboard/src/components/data-table/table-cell-link.tsx index 47a49002a..c3223d4ac 100644 --- a/apps/dashboard/src/components/data-table/table-cell-link.tsx +++ b/apps/dashboard/src/components/data-table/table-cell-link.tsx @@ -3,12 +3,16 @@ import { ArrowUpRight, ChevronRight } from "@openstatus/icons"; import { Link } from "@/components/common/link"; import { cn } from "@/lib/utils"; +import { TableCellEmpty } from "./table-cell-empty"; + export function TableCellLink({ value, + empty, className, ...props }: React.ComponentProps & { value: unknown; + empty?: string; }) { if (typeof value === "string") { const isExternal = props.href?.toString().startsWith("http"); @@ -30,5 +34,5 @@ export function TableCellLink({ ); } - return
-
; + return {empty}; } diff --git a/apps/dashboard/src/components/data-table/table-cell-number.tsx b/apps/dashboard/src/components/data-table/table-cell-number.tsx index 2dcffc267..ccd99e910 100644 --- a/apps/dashboard/src/components/data-table/table-cell-number.tsx +++ b/apps/dashboard/src/components/data-table/table-cell-number.tsx @@ -1,14 +1,25 @@ import { cn } from "@/lib/utils"; +import { TableCellEmpty } from "./table-cell-empty"; + export function TableCellNumber({ value, className, unit, + empty = "No data", ...props -}: React.ComponentProps<"div"> & { value: unknown; unit?: string }) { +}: React.ComponentProps<"div"> & { + value: unknown; + unit?: string; + empty?: string; +}) { const _value = Number(value); if (Number.isNaN(_value)) { - return
N/A
; + return ( + + {empty} + + ); } return ( diff --git a/apps/dashboard/src/components/data-table/table-cell-text.tsx b/apps/dashboard/src/components/data-table/table-cell-text.tsx index 8d77923af..1867e567b 100644 --- a/apps/dashboard/src/components/data-table/table-cell-text.tsx +++ b/apps/dashboard/src/components/data-table/table-cell-text.tsx @@ -1,10 +1,13 @@ import { cn } from "@/lib/utils"; +import { TableCellEmpty } from "./table-cell-empty"; + export function TableCellText({ value, + empty, className, ...props -}: React.ComponentProps<"div"> & { value: unknown }) { +}: React.ComponentProps<"div"> & { value: unknown; empty?: string }) { if (typeof value === "string" && value.length > 0) { return (
@@ -20,8 +23,8 @@ export function TableCellText({ ); } return ( -
- - -
+ + {empty} + ); } diff --git a/apps/dashboard/src/components/data-table/table-cell-unavailable.tsx b/apps/dashboard/src/components/data-table/table-cell-unavailable.tsx deleted file mode 100644 index 7c3cd7c87..000000000 --- a/apps/dashboard/src/components/data-table/table-cell-unavailable.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { cn } from "@/lib/utils"; - -export function TableCellUnavailable({ - className, - ...props -}: React.ComponentProps<"div">) { - return ( -
- N/A -
- ); -} diff --git a/apps/dashboard/src/components/status-pages/notifications.tsx b/apps/dashboard/src/components/status-pages/notifications.tsx index ab03d2505..2bbe3503e 100644 --- a/apps/dashboard/src/components/status-pages/notifications.tsx +++ b/apps/dashboard/src/components/status-pages/notifications.tsx @@ -1,5 +1,6 @@ "use client"; +import { Skeleton } from "@openstatus/ui/components/ui/skeleton"; import { useQuery } from "@tanstack/react-query"; import { Link } from "@/components/common/link"; @@ -9,24 +10,32 @@ import { PropertyList, PropertyValue, } from "@/components/content/property-list"; +import { TableCellEmpty } from "@/components/data-table/table-cell-empty"; import { useTRPC } from "@/lib/trpc/client"; /** Who gets told when something is published on the page. */ export function Notifications({ pageId }: { pageId: number }) { const trpc = useTRPC(); - const { data: subscribers } = useQuery( - trpc.pageSubscriber.list.queryOptions({ pageId }), - ); - const active = subscribers?.filter( - (s) => s.acceptedAt !== null && s.unsubscribedAt === null, - ); + const { + data: subscribers, + isPending, + isError, + } = useQuery(trpc.pageSubscriber.list.queryOptions({ pageId })); + const active = + subscribers?.filter( + (s) => s.acceptedAt !== null && s.unsubscribedAt === null, + ) ?? []; return ( Subscribers - {active ? ( + {isPending ? ( + + ) : isError ? ( + Unavailable + ) : active.length > 0 ? ( ) : ( - – + No subscribers )}