Openstatus www.openstatus.dev

๐Ÿ“Ÿ pagerduty fix (#1161)

* ๐Ÿ“Ÿ pagerduty fix

* ๐Ÿ“Ÿ

* typo

* ๐Ÿ“Ÿ pagerduty

* ๐Ÿ“Ÿ pagerduty

* ci: apply automated fixes

---------

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

authored by

Thibault Le Ouay
autofix-ci[bot]
and committed by
GitHub
1f122887 ed32f3e3

+128 -29
+12
apps/web/src/app/api/callback/pagerduty/route.ts
··· 1 + import { redirect } from "next/navigation"; 2 + 3 + export async function GET(request: Request) { 4 + const { searchParams } = new URL(request.url); 5 + const workspace = searchParams.get("workspace"); 6 + const url = `${ 7 + process.env.NODE_ENV === "development" // FIXME: This sucks 8 + ? "http://localhost:3000" 9 + : "https://www.openstatus.dev" 10 + }/app/${workspace}/notifications/new/pagerduty?${searchParams}`; 11 + redirect(url); 12 + }
+3 -2
apps/web/src/app/app/[workspaceSlug]/(dashboard)/notifications/(overview)/_components/channel-table.tsx
··· 1 + import { env } from "@/env"; 1 2 import type { Workspace } from "@openstatus/db/src/schema"; 2 3 import { getLimit } from "@openstatus/db/src/schema/plan/utils"; 3 4 ··· 34 35 <Channel 35 36 title="PagerDuty" 36 37 description="Send notifications to PagerDuty." 37 - href={`https://app.pagerduty.com/install/integration?app_id=PN76M56&redirect_url=${ 38 + href={`https://app.pagerduty.com/install/integration?app_id=${env.PAGERDUTY_APP_ID}&redirect_url=${ 38 39 process.env.NODE_ENV === "development" // FIXME: This sucks 39 40 ? "http://localhost:3000" 40 41 : "https://www.openstatus.dev" 41 - }/app/${workspace.slug}/notifications/new/pagerduty&version=2`} 42 + }/api/callback/pagerduty?workspace=${workspace.slug}&version=2`} 42 43 disabled={disabled || !workspace.limits.pagerduty} 43 44 /> 44 45 <Separator />
+10 -2
apps/web/src/components/forms/notification/provider/actions.ts
··· 1 1 "use server"; 2 2 3 - import { sendTest } from "@openstatus/notification-opsgenie"; 3 + import { sendTest as sendOpsGenieAlert } from "@openstatus/notification-opsgenie"; 4 4 5 + import { sendTest as sendPagerDutyAlert } from "@openstatus/notification-pagerduty"; 5 6 export async function sendOpsGenieTestAlert( 6 7 apiKey: string, 7 8 region: "us" | "eu", 8 9 ) { 9 - const isSuccessfull = await sendTest({ apiKey, region }); 10 + const isSuccessfull = await sendOpsGenieAlert({ apiKey, region }); 11 + return isSuccessfull; 12 + } 13 + 14 + export async function sendPagerDutyTestAlert(integrationKey: string) { 15 + const isSuccessfull = await sendPagerDutyAlert({ 16 + integrationKey: integrationKey, 17 + }); 10 18 return isSuccessfull; 11 19 }
+51 -4
apps/web/src/components/forms/notification/provider/section-pagerduty.tsx
··· 2 2 3 3 import type { UseFormReturn } from "react-hook-form"; 4 4 5 - import type { 6 - InsertNotificationWithData, 7 - WorkspacePlan, 5 + import { LoadingAnimation } from "@/components/loading-animation"; 6 + import { toastAction } from "@/lib/toast"; 7 + import { 8 + type InsertNotificationWithData, 9 + InsertNotificationWithDataSchema, 10 + NotificationDataSchema, 11 + type WorkspacePlan, 12 + selectNotificationSchema, 8 13 } from "@openstatus/db/src/schema"; 14 + import { PagerDutySchema } from "@openstatus/notification-pagerduty"; 15 + import { Button } from "@openstatus/ui"; 16 + import { useSearchParams } from "next/navigation"; 17 + import { useTransition } from "react"; 18 + import { sendPagerDutyTestAlert } from "./actions"; 9 19 10 20 interface Props { 11 21 form: UseFormReturn<InsertNotificationWithData>; ··· 13 23 } 14 24 15 25 export function SectionPagerDuty({ form }: Props) { 16 - return null; 26 + const [isTestPending, startTestTransition] = useTransition(); 27 + const searchParams = useSearchParams(); 28 + 29 + const config = searchParams.get("config"); 30 + 31 + const result = PagerDutySchema.safeParse(JSON.parse(config || "")); 32 + // We should fix that but that's not working for editing pagerduty notifications 33 + if (result.success === false) { 34 + return null; 35 + } 36 + 37 + const data = result.data; 38 + 39 + async function sendTestAlert() { 40 + startTestTransition(async () => { 41 + const isSuccessfull = await sendPagerDutyTestAlert( 42 + data.integration_keys[0].integration_key, 43 + ); 44 + if (isSuccessfull) { 45 + toastAction("test-success"); 46 + } else { 47 + toastAction("test-error"); 48 + } 49 + }); 50 + } 51 + 52 + return ( 53 + <div className="col-span-full text-right"> 54 + <Button 55 + type="button" 56 + variant="secondary" 57 + className="w-full sm:w-auto" 58 + onClick={sendTestAlert} 59 + > 60 + {!isTestPending ? "Test Alert" : <LoadingAnimation variant="inverse" />} 61 + </Button> 62 + </div> 63 + ); 17 64 }
-1
apps/web/src/middleware.ts
··· 155 155 // "/node_modules/function-bind/**", 156 156 // "**/node_modules/.pnpm/**/function-bind/**", 157 157 // "../../packages/analytics/src/index.ts", 158 - "**/node_modules/.pnpm/@jitsu*/**", 159 158 ], 160 159 };
+51 -19
packages/notifications/pagerduty/src/index.ts
··· 24 24 const notificationData = PagerDutySchema.parse(JSON.parse(notification.data)); 25 25 const { name } = monitor; 26 26 27 - const event = triggerEventPayloadSchema.parse({ 28 - rounting_key: notificationData.integration_keys[0].integration_key, 29 - dedup_key: `${monitor.id}}-${incidentId}`, 30 - event_action: "trigger", 31 - payload: { 32 - summary: `${name} is down`, 33 - source: "Open Status", 34 - severity: "error", 35 - timestamp: new Date(cronTimestamp).toISOString(), 36 - custom_details: { 37 - statusCode, 38 - message, 39 - }, 40 - }, 41 - }); 42 - 43 27 try { 44 28 for await (const integrationKey of notificationData.integration_keys) { 45 29 // biome-ignore lint/correctness/noUnusedVariables: <explanation> 46 30 const { integration_key, type } = integrationKey; 47 - 31 + const event = triggerEventPayloadSchema.parse({ 32 + routing_key: integration_key, 33 + dedup_key: `${monitor.id}}-${incidentId}`, 34 + event_action: "trigger", 35 + payload: { 36 + summary: `${name} is down`, 37 + source: "Open Status", 38 + severity: "error", 39 + timestamp: new Date(cronTimestamp).toISOString(), 40 + custom_details: { 41 + statusCode, 42 + message, 43 + }, 44 + }, 45 + }); 48 46 await fetch("https://events.pagerduty.com/v2/enqueue", { 49 47 method: "POST", 50 48 body: JSON.stringify(event), ··· 73 71 const { name } = monitor; 74 72 75 73 const event = triggerEventPayloadSchema.parse({ 76 - rounting_key: notificationData.integration_keys[0].integration_key, 74 + routing_key: notificationData.integration_keys[0].integration_key, 77 75 dedup_key: `${monitor.id}}`, 78 76 event_action: "trigger", 79 77 payload: { ··· 125 123 try { 126 124 for await (const integrationKey of notificationData.integration_keys) { 127 125 const event = resolveEventPayloadSchema.parse({ 128 - rounting_key: integrationKey.integration_key, 126 + routing_key: integrationKey.integration_key, 129 127 dedup_key: `${monitor.id}}-${incidentId}`, 130 128 event_action: "resolve", 131 129 }); ··· 140 138 } 141 139 }; 142 140 141 + export const sendTest = async ({ 142 + integrationKey, 143 + }: { 144 + integrationKey: string; 145 + }) => { 146 + console.log("Sending test alert to PagerDuty"); 147 + try { 148 + // biome-ignore lint/correctness/noUnusedVariables: <explanation> 149 + const event = triggerEventPayloadSchema.parse({ 150 + routing_key: integrationKey, 151 + dedup_key: "openstatus-test", 152 + event_action: "trigger", 153 + payload: { 154 + summary: "This is a test from OpenStatus", 155 + source: "Open Status", 156 + severity: "error", 157 + timestamp: new Date().toISOString(), 158 + custom_details: { 159 + statusCode: 418, 160 + message: 'I"m a teapot', 161 + }, 162 + }, 163 + }); 164 + 165 + const res = await fetch("https://events.pagerduty.com/v2/enqueue", { 166 + method: "POST", 167 + body: JSON.stringify(event), 168 + }); 169 + } catch (err) { 170 + console.log(err); 171 + return false; 172 + } 173 + return true; 174 + }; 143 175 export { PagerDutySchema };
+1 -1
packages/notifications/pagerduty/src/schema/config.ts
··· 37 37 }); 38 38 39 39 const baseEventPayloadSchema = z.object({ 40 - rounting_key: z.string(), 40 + routing_key: z.string(), 41 41 dedup_key: z.string(), 42 42 }); 43 43