Openstatus www.openstatus.dev

fix: toaster close and inicdent nav status dot (#1024)

* fix: toaster close and inicdent nav status dot

* ci: apply automated fixes

* fix: missing trpc procedure

* ci: apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

authored by

Maximilian Kaske
autofix-ci[bot]
and committed by
GitHub
2bd5df97 16f24593

+45 -3
+1 -1
apps/web/src/app/layout.tsx
··· 48 48 > 49 49 <ThemeProvider attribute="class" defaultTheme="light" enableSystem> 50 50 <Background>{children}</Background> 51 - <Toaster richColors /> 51 + <Toaster richColors closeButton /> 52 52 <TailwindIndicator /> 53 53 </ThemeProvider> 54 54 </body>
+30 -1
apps/web/src/components/layout/header/app-tabs.tsx
··· 1 + "use client"; 2 + 1 3 import { useParams, useSelectedLayoutSegment } from "next/navigation"; 2 4 3 5 import { TabsContainer, TabsLink } from "@/components/dashboard/tabs-link"; 6 + import { StatusDot } from "@/components/monitor/status-dot"; 4 7 import { pagesConfig } from "@/config/pages"; 8 + import { api } from "@/trpc/client"; 9 + import { useEffect, useState } from "react"; 5 10 6 11 export function AppTabs() { 7 12 const params = useParams(); ··· 16 21 const active = segment === selectedSegment; 17 22 return ( 18 23 <TabsLink 19 - key={title} 24 + key={segment} 20 25 active={active} 21 26 href={`/app/${params?.workspaceSlug}${href}`} 22 27 prefetch={false} 28 + className="relative" 23 29 > 24 30 {title} 31 + {segment === "incidents" ? <IncidentsDot /> : null} 25 32 </TabsLink> 26 33 ); 27 34 })} ··· 29 36 </div> 30 37 ); 31 38 } 39 + 40 + // FIXME: use react-query - once the user resolves the incident, the dot should disappear without refresh 41 + function IncidentsDot() { 42 + const [open, setOpen] = useState(false); 43 + 44 + useEffect(() => { 45 + async function checkOpenIncidents() { 46 + const incidents = await api.incident.getOpenIncidents.query(); 47 + if (incidents.length) setOpen(true); 48 + } 49 + 50 + checkOpenIncidents(); 51 + }, []); 52 + 53 + if (!open) return null; 54 + 55 + return ( 56 + <div className="absolute right-1 top-1"> 57 + <StatusDot status="error" active /> 58 + </div> 59 + ); 60 + }
+14 -1
packages/api/src/router/incident.ts
··· 1 1 import { z } from "zod"; 2 2 3 - import { and, eq, schema } from "@openstatus/db"; 3 + import { and, eq, isNull, schema } from "@openstatus/db"; 4 4 import { selectIncidentSchema } from "@openstatus/db/src/schema"; 5 5 6 6 import { createTRPCRouter, protectedProcedure } from "../trpc"; ··· 50 50 monitorName: result?.monitor?.name, 51 51 }); 52 52 }), 53 + 54 + getOpenIncidents: protectedProcedure.query(async (opts) => { 55 + return await opts.ctx.db 56 + .select() 57 + .from(schema.incidentTable) 58 + .where( 59 + and( 60 + eq(schema.incidentTable.workspaceId, opts.ctx.workspace.id), 61 + isNull(schema.incidentTable.resolvedAt), 62 + ), 63 + ) 64 + .all(); 65 + }), 53 66 54 67 acknowledgeIncident: protectedProcedure 55 68 .input(z.object({ id: z.number() }))