feat: Add Alert Creation Page and Update Related Components

- Implemented a new page for creating alerts with a form that includes fields for title, description, severity, state, monitor, on-call policy, labels, root cause, and remediation notes.
- Updated the AlertsTable component to conditionally render a "Create Alert" button based on the disableCreate prop.
- Modified the AlertsLayout to optionally hide the side menu when navigating to the create alert page.
- Enhanced routing to include a new route for the alert creation page and adjusted the side menu visibility accordingly.
- Updated PageMap and RouteMap to include the new alert creation route.
- Added migration to update database schema related to incident and alert policies.
This commit is contained in:
Nawaz Dhandala
2026-02-11 19:17:25 +00:00
parent 9a5bcb9f31
commit 3545a221bc
11 changed files with 727 additions and 106 deletions

View File

@@ -419,8 +419,7 @@ export default class Alert extends BaseModel {
@TableColumn({
type: TableColumnType.ObjectID,
title: "Monitor ID",
description:
"ID of the monitor this alert belongs to",
description: "ID of the monitor this alert belongs to",
})
@Column({
type: ColumnType.ObjectID,

View File

@@ -524,7 +524,8 @@ export default class IncidentTemplate extends BaseModel {
type: TableColumnType.EntityArray,
modelType: OnCallDutyPolicy,
title: "On-Call Duty Policies",
description: "List of on-call duty policies affected by this incident template.",
description:
"List of on-call duty policies affected by this incident template.",
})
@ManyToMany(
() => {

View File

@@ -1,73 +1,156 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1770833704656 implements MigrationInterface {
public name = 'MigrationName1770833704656'
public name = "MigrationName1770833704656";
public async up(queryRunner: QueryRunner): Promise<void> {
// AlertOnCallDutyPolicy: fix column names
// Original columns: onCallDutyPolicyId (FK → Alert._id), monitorId (FK → OnCallDutyPolicy._id)
// Target columns: alertId (FK → Alert._id), onCallDutyPolicyId (FK → OnCallDutyPolicy._id)
// Must rename onCallDutyPolicyId first to free the name, then rename monitorId.
public async up(queryRunner: QueryRunner): Promise<void> {
/*
* AlertOnCallDutyPolicy: fix column names
* Original columns: onCallDutyPolicyId (FK → Alert._id), monitorId (FK → OnCallDutyPolicy._id)
* Target columns: alertId (FK → Alert._id), onCallDutyPolicyId (FK → OnCallDutyPolicy._id)
* Must rename onCallDutyPolicyId first to free the name, then rename monitorId.
*/
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_0eca13d28cf4d2349406ddebc5c"`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_1ef6702995a8406630f75f06e28"`);
await queryRunner.query(`DROP INDEX "public"."IDX_0eca13d28cf4d2349406ddebc5"`);
await queryRunner.query(`DROP INDEX "public"."IDX_1ef6702995a8406630f75f06e2"`);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_0eca13d28cf4d2349406ddebc5c"`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_1ef6702995a8406630f75f06e28"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_0eca13d28cf4d2349406ddebc5"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_1ef6702995a8406630f75f06e2"`,
);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" RENAME COLUMN "onCallDutyPolicyId" TO "alertId"`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" RENAME COLUMN "monitorId" TO "onCallDutyPolicyId"`);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" RENAME COLUMN "onCallDutyPolicyId" TO "alertId"`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" RENAME COLUMN "monitorId" TO "onCallDutyPolicyId"`,
);
await queryRunner.query(`CREATE INDEX "IDX_AlertOnCallDutyPolicy_alertId" ON "AlertOnCallDutyPolicy" ("alertId")`);
await queryRunner.query(`CREATE INDEX "IDX_AlertOnCallDutyPolicy_onCallDutyPolicyId" ON "AlertOnCallDutyPolicy" ("onCallDutyPolicyId")`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_AlertOnCallDutyPolicy_alertId" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_AlertOnCallDutyPolicy_onCallDutyPolicyId" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(
`CREATE INDEX "IDX_AlertOnCallDutyPolicy_alertId" ON "AlertOnCallDutyPolicy" ("alertId")`,
);
await queryRunner.query(
`CREATE INDEX "IDX_AlertOnCallDutyPolicy_onCallDutyPolicyId" ON "AlertOnCallDutyPolicy" ("onCallDutyPolicyId")`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_AlertOnCallDutyPolicy_alertId" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_AlertOnCallDutyPolicy_onCallDutyPolicyId" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
// IncidentOnCallDutyPolicy: fix column names
// Original columns: onCallDutyPolicyId (FK → Incident._id), monitorId (FK → OnCallDutyPolicy._id)
// Target columns: incidentId (FK → Incident._id), onCallDutyPolicyId (FK → OnCallDutyPolicy._id)
/*
* IncidentOnCallDutyPolicy: fix column names
* Original columns: onCallDutyPolicyId (FK → Incident._id), monitorId (FK → OnCallDutyPolicy._id)
* Target columns: incidentId (FK → Incident._id), onCallDutyPolicyId (FK → OnCallDutyPolicy._id)
*/
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_2d127b6da0e4fab9f905b4d332d"`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_f89b23e3cafd1c6a0bfd42c297d"`);
await queryRunner.query(`DROP INDEX "public"."IDX_2d127b6da0e4fab9f905b4d332"`);
await queryRunner.query(`DROP INDEX "public"."IDX_f89b23e3cafd1c6a0bfd42c297"`);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_2d127b6da0e4fab9f905b4d332d"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_f89b23e3cafd1c6a0bfd42c297d"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_2d127b6da0e4fab9f905b4d332"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_f89b23e3cafd1c6a0bfd42c297"`,
);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" RENAME COLUMN "onCallDutyPolicyId" TO "incidentId"`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" RENAME COLUMN "monitorId" TO "onCallDutyPolicyId"`);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" RENAME COLUMN "onCallDutyPolicyId" TO "incidentId"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" RENAME COLUMN "monitorId" TO "onCallDutyPolicyId"`,
);
await queryRunner.query(`CREATE INDEX "IDX_IncidentOnCallDutyPolicy_incidentId" ON "IncidentOnCallDutyPolicy" ("incidentId")`);
await queryRunner.query(`CREATE INDEX "IDX_IncidentOnCallDutyPolicy_onCallDutyPolicyId" ON "IncidentOnCallDutyPolicy" ("onCallDutyPolicyId")`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_IncidentOnCallDutyPolicy_incidentId" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_IncidentOnCallDutyPolicy_onCallDutyPolicyId" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
}
await queryRunner.query(
`CREATE INDEX "IDX_IncidentOnCallDutyPolicy_incidentId" ON "IncidentOnCallDutyPolicy" ("incidentId")`,
);
await queryRunner.query(
`CREATE INDEX "IDX_IncidentOnCallDutyPolicy_onCallDutyPolicyId" ON "IncidentOnCallDutyPolicy" ("onCallDutyPolicyId")`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_IncidentOnCallDutyPolicy_incidentId" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_IncidentOnCallDutyPolicy_onCallDutyPolicyId" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
// Revert IncidentOnCallDutyPolicy
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_IncidentOnCallDutyPolicy_onCallDutyPolicyId"`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_IncidentOnCallDutyPolicy_incidentId"`);
await queryRunner.query(`DROP INDEX "public"."IDX_IncidentOnCallDutyPolicy_onCallDutyPolicyId"`);
await queryRunner.query(`DROP INDEX "public"."IDX_IncidentOnCallDutyPolicy_incidentId"`);
public async down(queryRunner: QueryRunner): Promise<void> {
// Revert IncidentOnCallDutyPolicy
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_IncidentOnCallDutyPolicy_onCallDutyPolicyId"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_IncidentOnCallDutyPolicy_incidentId"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_IncidentOnCallDutyPolicy_onCallDutyPolicyId"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_IncidentOnCallDutyPolicy_incidentId"`,
);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" RENAME COLUMN "onCallDutyPolicyId" TO "monitorId"`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" RENAME COLUMN "incidentId" TO "onCallDutyPolicyId"`);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" RENAME COLUMN "onCallDutyPolicyId" TO "monitorId"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" RENAME COLUMN "incidentId" TO "onCallDutyPolicyId"`,
);
await queryRunner.query(`CREATE INDEX "IDX_2d127b6da0e4fab9f905b4d332" ON "IncidentOnCallDutyPolicy" ("onCallDutyPolicyId")`);
await queryRunner.query(`CREATE INDEX "IDX_f89b23e3cafd1c6a0bfd42c297" ON "IncidentOnCallDutyPolicy" ("monitorId")`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_2d127b6da0e4fab9f905b4d332d" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_f89b23e3cafd1c6a0bfd42c297d" FOREIGN KEY ("monitorId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(
`CREATE INDEX "IDX_2d127b6da0e4fab9f905b4d332" ON "IncidentOnCallDutyPolicy" ("onCallDutyPolicyId")`,
);
await queryRunner.query(
`CREATE INDEX "IDX_f89b23e3cafd1c6a0bfd42c297" ON "IncidentOnCallDutyPolicy" ("monitorId")`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_2d127b6da0e4fab9f905b4d332d" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_f89b23e3cafd1c6a0bfd42c297d" FOREIGN KEY ("monitorId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
// Revert AlertOnCallDutyPolicy
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_AlertOnCallDutyPolicy_onCallDutyPolicyId"`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_AlertOnCallDutyPolicy_alertId"`);
await queryRunner.query(`DROP INDEX "public"."IDX_AlertOnCallDutyPolicy_onCallDutyPolicyId"`);
await queryRunner.query(`DROP INDEX "public"."IDX_AlertOnCallDutyPolicy_alertId"`);
// Revert AlertOnCallDutyPolicy
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_AlertOnCallDutyPolicy_onCallDutyPolicyId"`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_AlertOnCallDutyPolicy_alertId"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_AlertOnCallDutyPolicy_onCallDutyPolicyId"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_AlertOnCallDutyPolicy_alertId"`,
);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" RENAME COLUMN "onCallDutyPolicyId" TO "monitorId"`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" RENAME COLUMN "alertId" TO "onCallDutyPolicyId"`);
await queryRunner.query(`CREATE INDEX "IDX_0eca13d28cf4d2349406ddebc5" ON "AlertOnCallDutyPolicy" ("onCallDutyPolicyId")`);
await queryRunner.query(`CREATE INDEX "IDX_1ef6702995a8406630f75f06e2" ON "AlertOnCallDutyPolicy" ("monitorId")`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_0eca13d28cf4d2349406ddebc5c" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_1ef6702995a8406630f75f06e28" FOREIGN KEY ("monitorId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
}
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" RENAME COLUMN "onCallDutyPolicyId" TO "monitorId"`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" RENAME COLUMN "alertId" TO "onCallDutyPolicyId"`,
);
await queryRunner.query(
`CREATE INDEX "IDX_0eca13d28cf4d2349406ddebc5" ON "AlertOnCallDutyPolicy" ("onCallDutyPolicyId")`,
);
await queryRunner.query(
`CREATE INDEX "IDX_1ef6702995a8406630f75f06e2" ON "AlertOnCallDutyPolicy" ("monitorId")`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_0eca13d28cf4d2349406ddebc5c" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_1ef6702995a8406630f75f06e28" FOREIGN KEY ("monitorId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
}

View File

@@ -1,48 +1,119 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1770834237090 implements MigrationInterface {
name = 'MigrationName1770834237090'
name = "MigrationName1770834237090";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_IncidentOnCallDutyPolicy_incidentId"`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_IncidentOnCallDutyPolicy_onCallDutyPolicyId"`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_AlertOnCallDutyPolicy_alertId"`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_AlertOnCallDutyPolicy_onCallDutyPolicyId"`);
await queryRunner.query(`DROP INDEX "public"."IDX_IncidentOnCallDutyPolicy_onCallDutyPolicyId"`);
await queryRunner.query(`DROP INDEX "public"."IDX_IncidentOnCallDutyPolicy_incidentId"`);
await queryRunner.query(`DROP INDEX "public"."IDX_AlertOnCallDutyPolicy_alertId"`);
await queryRunner.query(`DROP INDEX "public"."IDX_AlertOnCallDutyPolicy_onCallDutyPolicyId"`);
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`);
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`);
await queryRunner.query(`CREATE INDEX "IDX_47b1a29b40fc779495dd7ba407" ON "IncidentOnCallDutyPolicy" ("incidentId") `);
await queryRunner.query(`CREATE INDEX "IDX_2d127b6da0e4fab9f905b4d332" ON "IncidentOnCallDutyPolicy" ("onCallDutyPolicyId") `);
await queryRunner.query(`CREATE INDEX "IDX_359174b1e315a1600ddee16812" ON "AlertOnCallDutyPolicy" ("alertId") `);
await queryRunner.query(`CREATE INDEX "IDX_0eca13d28cf4d2349406ddebc5" ON "AlertOnCallDutyPolicy" ("onCallDutyPolicyId") `);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_47b1a29b40fc779495dd7ba4076" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_2d127b6da0e4fab9f905b4d332d" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_359174b1e315a1600ddee168129" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_0eca13d28cf4d2349406ddebc5c" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_0eca13d28cf4d2349406ddebc5c"`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_359174b1e315a1600ddee168129"`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_2d127b6da0e4fab9f905b4d332d"`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_47b1a29b40fc779495dd7ba4076"`);
await queryRunner.query(`DROP INDEX "public"."IDX_0eca13d28cf4d2349406ddebc5"`);
await queryRunner.query(`DROP INDEX "public"."IDX_359174b1e315a1600ddee16812"`);
await queryRunner.query(`DROP INDEX "public"."IDX_2d127b6da0e4fab9f905b4d332"`);
await queryRunner.query(`DROP INDEX "public"."IDX_47b1a29b40fc779495dd7ba407"`);
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`);
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`);
await queryRunner.query(`CREATE INDEX "IDX_AlertOnCallDutyPolicy_onCallDutyPolicyId" ON "AlertOnCallDutyPolicy" ("onCallDutyPolicyId") `);
await queryRunner.query(`CREATE INDEX "IDX_AlertOnCallDutyPolicy_alertId" ON "AlertOnCallDutyPolicy" ("alertId") `);
await queryRunner.query(`CREATE INDEX "IDX_IncidentOnCallDutyPolicy_incidentId" ON "IncidentOnCallDutyPolicy" ("incidentId") `);
await queryRunner.query(`CREATE INDEX "IDX_IncidentOnCallDutyPolicy_onCallDutyPolicyId" ON "IncidentOnCallDutyPolicy" ("onCallDutyPolicyId") `);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_AlertOnCallDutyPolicy_onCallDutyPolicyId" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_AlertOnCallDutyPolicy_alertId" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_IncidentOnCallDutyPolicy_onCallDutyPolicyId" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_IncidentOnCallDutyPolicy_incidentId" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
}
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_IncidentOnCallDutyPolicy_incidentId"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_IncidentOnCallDutyPolicy_onCallDutyPolicyId"`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_AlertOnCallDutyPolicy_alertId"`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_AlertOnCallDutyPolicy_onCallDutyPolicyId"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_IncidentOnCallDutyPolicy_onCallDutyPolicyId"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_IncidentOnCallDutyPolicy_incidentId"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_AlertOnCallDutyPolicy_alertId"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_AlertOnCallDutyPolicy_onCallDutyPolicyId"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
await queryRunner.query(
`CREATE INDEX "IDX_47b1a29b40fc779495dd7ba407" ON "IncidentOnCallDutyPolicy" ("incidentId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_2d127b6da0e4fab9f905b4d332" ON "IncidentOnCallDutyPolicy" ("onCallDutyPolicyId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_359174b1e315a1600ddee16812" ON "AlertOnCallDutyPolicy" ("alertId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_0eca13d28cf4d2349406ddebc5" ON "AlertOnCallDutyPolicy" ("onCallDutyPolicyId") `,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_47b1a29b40fc779495dd7ba4076" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_2d127b6da0e4fab9f905b4d332d" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_359174b1e315a1600ddee168129" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_0eca13d28cf4d2349406ddebc5c" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_0eca13d28cf4d2349406ddebc5c"`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" DROP CONSTRAINT "FK_359174b1e315a1600ddee168129"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_2d127b6da0e4fab9f905b4d332d"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" DROP CONSTRAINT "FK_47b1a29b40fc779495dd7ba4076"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_0eca13d28cf4d2349406ddebc5"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_359174b1e315a1600ddee16812"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_2d127b6da0e4fab9f905b4d332"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_47b1a29b40fc779495dd7ba407"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`CREATE INDEX "IDX_AlertOnCallDutyPolicy_onCallDutyPolicyId" ON "AlertOnCallDutyPolicy" ("onCallDutyPolicyId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_AlertOnCallDutyPolicy_alertId" ON "AlertOnCallDutyPolicy" ("alertId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_IncidentOnCallDutyPolicy_incidentId" ON "IncidentOnCallDutyPolicy" ("incidentId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_IncidentOnCallDutyPolicy_onCallDutyPolicyId" ON "IncidentOnCallDutyPolicy" ("onCallDutyPolicyId") `,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_AlertOnCallDutyPolicy_onCallDutyPolicyId" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "AlertOnCallDutyPolicy" ADD CONSTRAINT "FK_AlertOnCallDutyPolicy_alertId" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_IncidentOnCallDutyPolicy_onCallDutyPolicyId" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentOnCallDutyPolicy" ADD CONSTRAINT "FK_IncidentOnCallDutyPolicy_incidentId" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
}

View File

@@ -519,5 +519,5 @@ export default [
MigrationName1770728946893,
MigrationName1770732721195,
MigrationName1770833704656,
MigrationName1770834237090
MigrationName1770834237090,
];

View File

@@ -26,6 +26,9 @@ import React, {
} from "react";
import RouteMap, { RouteUtil } from "../../Utils/RouteMap";
import PageMap from "../../Utils/PageMap";
import { CardButtonSchema } from "Common/UI/Components/Card/Card";
import Route from "Common/Types/API/Route";
import Navigation from "Common/UI/Utils/Navigation";
import MonitorElement from "../Monitor/Monitor";
import {
BulkActionButtonSchema,
@@ -51,6 +54,7 @@ export interface ComponentProps {
description?: string | undefined;
createInitialValues?: FormValues<Alert> | undefined;
saveFilterProps?: SaveFilterProps | undefined;
disableCreate?: boolean | undefined;
}
const AlertsTable: FunctionComponent<ComponentProps> = (
@@ -211,6 +215,25 @@ const AlertsTable: FunctionComponent<ComponentProps> = (
};
};
let cardbuttons: Array<CardButtonSchema> = [];
if (!props.disableCreate) {
cardbuttons = [
{
title: "Create Alert",
onClick: () => {
Navigation.navigate(
RouteUtil.populateRouteParams(
RouteMap[PageMap.ALERT_CREATE] as Route,
),
);
},
buttonStyle: ButtonStyleType.NORMAL,
icon: IconProp.Add,
},
];
}
return (
<>
<ModelTable<Alert>
@@ -240,6 +263,7 @@ const AlertsTable: FunctionComponent<ComponentProps> = (
}
cardProps={{
title: props.title || "Alerts",
buttons: cardbuttons,
description:
props.description || "Here is a list of alerts for this project.",
}}

View File

@@ -0,0 +1,404 @@
import PageMap from "../../Utils/PageMap";
import RouteMap, { RouteUtil } from "../../Utils/RouteMap";
import PageComponentProps from "../PageComponentProps";
import Route from "Common/Types/API/Route";
import Alert from "Common/Models/DatabaseModels/Alert";
import MarkdownUtil from "Common/UI/Utils/Markdown";
import React, {
Fragment,
FunctionComponent,
ReactElement,
useEffect,
useState,
} from "react";
import ModelForm, { FormType } from "Common/UI/Components/Forms/ModelForm";
import Navigation from "Common/UI/Utils/Navigation";
import FormFieldSchemaType from "Common/UI/Components/Forms/Types/FormFieldSchemaType";
import Card from "Common/UI/Components/Card/Card";
import Monitor from "Common/Models/DatabaseModels/Monitor";
import OnCallDutyPolicy from "Common/Models/DatabaseModels/OnCallDutyPolicy";
import ProjectUtil from "Common/UI/Utils/Project";
import Label from "Common/Models/DatabaseModels/Label";
import AlertSeverity from "Common/Models/DatabaseModels/AlertSeverity";
import { JSONObject } from "Common/Types/JSON";
import ObjectID from "Common/Types/ObjectID";
import ModelAPI, { ListResult } from "Common/UI/Utils/ModelAPI/ModelAPI";
import { LIMIT_PER_PROJECT } from "Common/Types/Database/LimitMax";
import AlertState from "Common/Models/DatabaseModels/AlertState";
import SortOrder from "Common/Types/BaseDatabase/SortOrder";
import Color from "Common/Types/Color";
import { DropdownOption } from "Common/UI/Components/Dropdown/Dropdown";
import FormValues from "Common/UI/Components/Forms/Types/FormValues";
import FetchLabels from "../../Components/Label/FetchLabels";
import FetchOnCallDutyPolicies from "../../Components/OnCallPolicy/FetchOnCallPolicies";
import FetchMonitors from "../../Components/Monitor/FetchMonitors";
const AlertCreate: FunctionComponent<PageComponentProps> = (): ReactElement => {
const [initialValuesForAlert, setInitialValuesForAlert] =
useState<JSONObject>({});
useEffect(() => {
fetchFirstAlertState();
}, []);
const fetchFirstAlertState: () => Promise<void> = async (): Promise<void> => {
const projectId: ObjectID | null = ProjectUtil.getCurrentProjectId();
if (!projectId) {
return;
}
try {
const alertStates: ListResult<AlertState> =
await ModelAPI.getList<AlertState>({
modelType: AlertState,
query: {
projectId: projectId,
},
limit: 1,
skip: 0,
select: {
_id: true,
},
sort: {
order: SortOrder.Ascending,
},
});
if (alertStates.data.length > 0) {
const firstStateId: string | undefined =
alertStates.data[0]!._id?.toString();
if (firstStateId) {
setInitialValuesForAlert((prev: JSONObject) => {
return {
...prev,
currentAlertState: firstStateId,
};
});
}
}
} catch {
// Silently fail to avoid breaking the form
}
};
return (
<Fragment>
<Card
title="Create New Alert"
description={
"Create a new alert to notify your team about an issue that needs attention."
}
className="mb-10"
>
<div>
<ModelForm<Alert>
modelType={Alert}
initialValues={initialValuesForAlert}
name="Create New Alert"
id="create-alert-form"
fields={[
{
field: {
title: true,
},
title: "Title",
fieldType: FormFieldSchemaType.Text,
stepId: "alert-details",
required: true,
placeholder: "Alert Title",
validation: {
minLength: 2,
},
},
{
field: {
description: true,
},
title: "Description",
stepId: "alert-details",
fieldType: FormFieldSchemaType.Markdown,
required: false,
description: MarkdownUtil.getMarkdownCheatsheet(
"Describe the alert details here",
),
},
{
field: {
alertSeverity: true,
},
title: "Alert Severity",
stepId: "alert-details",
description: "What is the severity of this alert?",
fieldType: FormFieldSchemaType.Dropdown,
dropdownModal: {
type: AlertSeverity,
labelField: "name",
valueField: "_id",
},
required: true,
placeholder: "Alert Severity",
},
{
field: {
currentAlertState: true,
},
title: "Alert State",
stepId: "alert-details",
description:
"Select the initial state for this alert to be in.",
fieldType: FormFieldSchemaType.Dropdown,
dropdownModal: {
type: AlertState,
labelField: "name",
valueField: "_id",
},
required: false,
placeholder: "Select Initial State",
fetchDropdownOptions: async () => {
const projectId: ObjectID | null =
ProjectUtil.getCurrentProjectId();
if (!projectId) {
return [];
}
try {
const alertStates: ListResult<AlertState> =
await ModelAPI.getList<AlertState>({
modelType: AlertState,
query: {
projectId: projectId,
},
limit: LIMIT_PER_PROJECT,
skip: 0,
select: {
_id: true,
name: true,
color: true,
},
sort: {
order: SortOrder.Ascending,
},
});
return alertStates.data.map(
(state: AlertState): DropdownOption => {
const option: DropdownOption = {
label: state.name || "",
value: state._id?.toString() || "",
color: state.color as Color,
};
return option;
},
);
} catch {
return [];
}
},
getSummaryElement: (item: FormValues<Alert>) => {
if (!item.currentAlertState) {
return <p>Will use first available state by priority</p>;
}
return <p>Initial state will be set to selected state</p>;
},
},
{
field: {
monitor: true,
},
title: "Monitor",
stepId: "on-call",
description: "Select the monitor affected by this alert.",
fieldType: FormFieldSchemaType.Dropdown,
dropdownModal: {
type: Monitor,
labelField: "name",
valueField: "_id",
},
required: false,
placeholder: "Select Monitor",
getSummaryElement: (item: FormValues<Alert>) => {
if (!item.monitor) {
return <p>No monitor selected.</p>;
}
return (
<div>
<FetchMonitors
monitorIds={[new ObjectID(item.monitor.toString())]}
/>
</div>
);
},
},
{
field: {
onCallDutyPolicies: true,
},
title: "On-Call Policy",
stepId: "on-call",
description:
"Select on-call duty policy to execute when this alert is created.",
fieldType: FormFieldSchemaType.MultiSelectDropdown,
dropdownModal: {
type: OnCallDutyPolicy,
labelField: "name",
valueField: "_id",
},
required: false,
placeholder: "Select on-call policies",
getSummaryElement: (item: FormValues<Alert>) => {
if (
!item.onCallDutyPolicies ||
!Array.isArray(item.onCallDutyPolicies)
) {
return (
<p>
No on-call policies will be executed when this alert is
created.
</p>
);
}
const onCallDutyPolicyIds: Array<ObjectID> = [];
for (const onCallDutyPolicy of item.onCallDutyPolicies) {
if (typeof onCallDutyPolicy === "string") {
onCallDutyPolicyIds.push(new ObjectID(onCallDutyPolicy));
continue;
}
if (onCallDutyPolicy instanceof ObjectID) {
onCallDutyPolicyIds.push(onCallDutyPolicy);
continue;
}
if (onCallDutyPolicy instanceof OnCallDutyPolicy) {
onCallDutyPolicyIds.push(
new ObjectID(onCallDutyPolicy._id?.toString() || ""),
);
continue;
}
}
return (
<div>
<FetchOnCallDutyPolicies
onCallDutyPolicyIds={onCallDutyPolicyIds}
/>
</div>
);
},
},
{
field: {
labels: true,
},
title: "Labels",
stepId: "more",
description:
"Team members with access to these labels will only be able to access this resource. This is optional and an advanced feature.",
fieldType: FormFieldSchemaType.MultiSelectDropdown,
dropdownModal: {
type: Label,
labelField: "name",
valueField: "_id",
},
required: false,
placeholder: "Labels",
getSummaryElement: (item: FormValues<Alert>) => {
if (!item.labels || !Array.isArray(item.labels)) {
return <p>No labels assigned.</p>;
}
const labelIds: Array<ObjectID> = [];
for (const label of item.labels) {
if (typeof label === "string") {
labelIds.push(new ObjectID(label));
continue;
}
if (label instanceof ObjectID) {
labelIds.push(label);
continue;
}
if (label instanceof Label) {
labelIds.push(new ObjectID(label._id?.toString() || ""));
continue;
}
}
return (
<div>
<FetchLabels labelIds={labelIds} />
</div>
);
},
},
{
field: {
rootCause: true,
},
title: "Root Cause",
stepId: "more",
fieldType: FormFieldSchemaType.Markdown,
required: false,
description: MarkdownUtil.getMarkdownCheatsheet(
"Describe the root cause here",
),
},
{
field: {
remediationNotes: true,
},
title: "Remediation Notes",
stepId: "more",
fieldType: FormFieldSchemaType.Markdown,
required: false,
description: MarkdownUtil.getMarkdownCheatsheet(
"Describe the remediation steps here",
),
},
]}
steps={[
{
title: "Alert Details",
id: "alert-details",
},
{
title: "On-Call",
id: "on-call",
},
{
title: "More",
id: "more",
},
]}
onSuccess={async (createdItem: Alert) => {
Navigation.navigate(
RouteUtil.populateRouteParams(
RouteUtil.populateRouteParams(
RouteMap[PageMap.ALERT_VIEW] as Route,
{
modelId: createdItem._id,
},
),
),
);
}}
submitButtonText={"Create Alert"}
formType={FormType.Create}
summary={{
enabled: true,
}}
/>
</div>
</Card>
</Fragment>
);
};
export default AlertCreate;

View File

@@ -1,20 +1,24 @@
import { getAlertsBreadcrumbs } from "../../Utils/Breadcrumbs/AlertBreadcrumbs";
import { RouteUtil } from "../../Utils/RouteMap";
import PageComponentProps from "../PageComponentProps";
import LayoutPageComponentProps from "../LayoutPageComponentProps";
import SideMenu from "./SideMenu";
import Page from "Common/UI/Components/Page/Page";
import Navigation from "Common/UI/Utils/Navigation";
import React, { FunctionComponent, ReactElement } from "react";
import { Outlet } from "react-router-dom";
const AlertsLayout: FunctionComponent<PageComponentProps> = (
props: PageComponentProps,
const AlertsLayout: FunctionComponent<LayoutPageComponentProps> = (
props: LayoutPageComponentProps,
): ReactElement => {
const path: string = Navigation.getRoutePath(RouteUtil.getRoutes());
return (
<Page
title={"Alerts"}
sideMenu={<SideMenu project={props.currentProject || undefined} />}
sideMenu={
props.hideSideMenu ? undefined : (
<SideMenu project={props.currentProject || undefined} />
)
}
breadcrumbLinks={getAlertsBreadcrumbs(path)}
>
<Outlet />

View File

@@ -1,3 +1,4 @@
import Navigation from "Common/UI/Utils/Navigation";
import Loader from "../Components/Loader/Loader";
import Layout from "../Pages/Alerts/Layout";
import AlertViewLayout from "../Pages/Alerts/View/Layout";
@@ -19,6 +20,11 @@ const Alerts: LazyExoticComponent<FunctionComponent<ComponentProps>> = lazy(
return import("../Pages/Alerts/Alerts");
},
);
const AlertCreate: LazyExoticComponent<FunctionComponent<ComponentProps>> =
lazy(() => {
return import("../Pages/Alerts/Create");
});
const AlertView: LazyExoticComponent<FunctionComponent<ComponentProps>> = lazy(
() => {
return import("../Pages/Alerts/View/Index");
@@ -230,9 +236,18 @@ const AlertEpisodeDocs: LazyExoticComponent<FunctionComponent<ComponentProps>> =
const AlertsRoutes: FunctionComponent<ComponentProps> = (
props: ComponentProps,
) => {
let hideSideMenu: boolean = false;
if (Navigation.isOnThisPage(RouteMap[PageMap.ALERT_CREATE] as Route)) {
hideSideMenu = true;
}
return (
<Routes>
<PageRoute path="/" element={<Layout {...props} />}>
<PageRoute
path="/"
element={<Layout {...props} hideSideMenu={hideSideMenu} />}
>
<PageRoute
path={AlertsRoutePath[PageMap.ALERTS] || ""}
element={
@@ -293,6 +308,18 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
}
/>
<PageRoute
path={AlertsRoutePath[PageMap.ALERT_CREATE] || ""}
element={
<Suspense fallback={Loader}>
<AlertCreate
{...props}
pageRoute={RouteMap[PageMap.ALERT_CREATE] as Route}
/>
</Suspense>
}
/>
{/* Settings Routes */}
<PageRoute
path={AlertsRoutePath[PageMap.ALERTS_SETTINGS_STATE] || ""}

View File

@@ -93,6 +93,7 @@ enum PageMap {
UNRESOLVED_ALERTS = "UNRESOLVED_ALERTS",
ALERTS_WORKSPACE_CONNECTION_SLACK = "ALERTS_WORKSPACE_CONNECTION_SLACK",
ALERTS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS = "ALERTS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS",
ALERT_CREATE = "ALERT_CREATE",
ALERT_VIEW = "ALERT_VIEW",
ALERT_VIEW_DELETE = "ALERT_VIEW_DELETE",
ALERT_VIEW_STATE_TIMELINE = "ALERT_VIEW_STATE_TIMELINE",

View File

@@ -218,6 +218,7 @@ export const IncidentsRoutePath: Dictionary<string> = {
};
export const AlertsRoutePath: Dictionary<string> = {
[PageMap.ALERT_CREATE]: "create",
[PageMap.UNRESOLVED_ALERTS]: "unresolved",
[PageMap.ALERTS_WORKSPACE_CONNECTION_SLACK]: "workspace-connection-slack",
[PageMap.ALERTS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS]:
@@ -610,6 +611,12 @@ const RouteMap: Dictionary<Route> = {
}`,
),
[PageMap.ALERT_CREATE]: new Route(
`/dashboard/${RouteParams.ProjectID}/alerts/${
AlertsRoutePath[PageMap.ALERT_CREATE]
}`,
),
[PageMap.ALERT_VIEW]: new Route(
`/dashboard/${RouteParams.ProjectID}/alerts/${
AlertsRoutePath[PageMap.ALERT_VIEW]