mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
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:
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
() => {
|
||||
|
||||
@@ -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`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,5 +519,5 @@ export default [
|
||||
MigrationName1770728946893,
|
||||
MigrationName1770732721195,
|
||||
MigrationName1770833704656,
|
||||
MigrationName1770834237090
|
||||
MigrationName1770834237090,
|
||||
];
|
||||
|
||||
@@ -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.",
|
||||
}}
|
||||
|
||||
404
Dashboard/src/Pages/Alerts/Create.tsx
Normal file
404
Dashboard/src/Pages/Alerts/Create.tsx
Normal 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;
|
||||
@@ -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 />
|
||||
|
||||
@@ -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] || ""}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user