Refactor and clean up code across multiple files

- Added missing commas in migration index.
- Improved type annotations for dynamic imports in IncidentService and IncidentSlaRuleService.
- Simplified logger debug messages in IncidentSlaService and IncidentSlaRuleService.
- Cleaned up JSX formatting in IconPicker, NotificationBellDropdown, RoleLabel, and Header components.
- Enhanced readability by restructuring long lines and removing unnecessary line breaks in various components.
- Updated error handling in fetch functions within DashboardHeader to use concise catch blocks.
- Refactored UserSettings and Incident routes for better readability.
- Improved code consistency and formatting in CheckSlaBreaches job.
This commit is contained in:
Nawaz Dhandala
2026-01-30 13:50:50 +00:00
parent 61ed224ad0
commit 31d3ce949d
21 changed files with 710 additions and 475 deletions

View File

@@ -520,7 +520,8 @@ export default class IncidentSla extends BaseModel {
type: TableColumnType.Date,
required: false,
title: "Breach Notification Sent At",
description: "The time when breach notification was sent to incident owners",
description:
"The time when breach notification was sent to incident owners",
})
@Column({
type: ColumnType.Date,

View File

@@ -44,10 +44,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
Permission.ReadTeamMemberCustomField,
Permission.ReadAllProjectResources,
],
delete: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
],
delete: [Permission.ProjectOwner, Permission.ProjectAdmin],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,

View File

@@ -44,8 +44,6 @@ export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
const projectId: ObjectID = new ObjectID(req.params["id"] as string);
const body: JSONObject = (req.body as JSONObject) || {};
const data: JSONObject = (body["data"] as JSONObject) || {};
const paymentProviderPlanId: string | undefined = data[
@@ -56,7 +54,6 @@ export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
throw new BadDataException("Plan ID is required to change plan");
}
// Check for payment methods early before making any Stripe API calls
const project: Project | null = await ProjectService.findOneById({
id: projectId,
@@ -82,7 +79,9 @@ export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
);
if (!hasPaymentMethods) {
throw new BadDataException(Errors.BillingService.NO_PAYMENTS_METHODS);
throw new BadDataException(
Errors.BillingService.NO_PAYMENTS_METHODS,
);
}
const permissions: Array<UserPermission> =
@@ -107,7 +106,6 @@ export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
);
}
await ProjectService.changePlan({
projectId: projectId,
paymentProviderPlanId: paymentProviderPlanId,

View File

@@ -1,40 +1,91 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1769772215532 implements MigrationInterface {
public name = 'MigrationName1769772215532'
public name = "MigrationName1769772215532";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "ProjectUserProfile" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "userId" uuid NOT NULL, "customFields" jsonb, "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_2fd2054e182a7603f7032745eb9" PRIMARY KEY ("_id"))`);
await queryRunner.query(`CREATE INDEX "IDX_3ba2d6a8eaeb966afa8820dbf0" ON "ProjectUserProfile" ("projectId") `);
await queryRunner.query(`CREATE INDEX "IDX_39df4735afea8ab70c00674575" ON "ProjectUserProfile" ("userId") `);
await queryRunner.query(`CREATE TABLE "TeamMemberCustomField" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "name" character varying(100) NOT NULL, "description" character varying(500), "customFieldType" character varying(100), "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_c0a4e92fd1fb77fe4cbb2f85ad4" PRIMARY KEY ("_id"))`);
await queryRunner.query(`CREATE INDEX "IDX_e11389841b4ca122ec4a36c472" ON "TeamMemberCustomField" ("projectId") `);
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(`ALTER TABLE "ProjectUserProfile" ADD CONSTRAINT "FK_3ba2d6a8eaeb966afa8820dbf0a" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "ProjectUserProfile" ADD CONSTRAINT "FK_39df4735afea8ab70c006745752" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "ProjectUserProfile" ADD CONSTRAINT "FK_b9db61caf3923a882e09943f367" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "ProjectUserProfile" ADD CONSTRAINT "FK_5fe8245962849bde50687e2c707" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "TeamMemberCustomField" ADD CONSTRAINT "FK_e11389841b4ca122ec4a36c4720" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "TeamMemberCustomField" ADD CONSTRAINT "FK_5ea46786eae26e125d07bbfddfa" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "TeamMemberCustomField" ADD CONSTRAINT "FK_35409d7ec1b559d4de58913e522" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "TeamMemberCustomField" DROP CONSTRAINT "FK_35409d7ec1b559d4de58913e522"`);
await queryRunner.query(`ALTER TABLE "TeamMemberCustomField" DROP CONSTRAINT "FK_5ea46786eae26e125d07bbfddfa"`);
await queryRunner.query(`ALTER TABLE "TeamMemberCustomField" DROP CONSTRAINT "FK_e11389841b4ca122ec4a36c4720"`);
await queryRunner.query(`ALTER TABLE "ProjectUserProfile" DROP CONSTRAINT "FK_5fe8245962849bde50687e2c707"`);
await queryRunner.query(`ALTER TABLE "ProjectUserProfile" DROP CONSTRAINT "FK_b9db61caf3923a882e09943f367"`);
await queryRunner.query(`ALTER TABLE "ProjectUserProfile" DROP CONSTRAINT "FK_39df4735afea8ab70c006745752"`);
await queryRunner.query(`ALTER TABLE "ProjectUserProfile" DROP CONSTRAINT "FK_3ba2d6a8eaeb966afa8820dbf0a"`);
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(`DROP INDEX "public"."IDX_e11389841b4ca122ec4a36c472"`);
await queryRunner.query(`DROP TABLE "TeamMemberCustomField"`);
await queryRunner.query(`DROP INDEX "public"."IDX_39df4735afea8ab70c00674575"`);
await queryRunner.query(`DROP INDEX "public"."IDX_3ba2d6a8eaeb966afa8820dbf0"`);
await queryRunner.query(`DROP TABLE "ProjectUserProfile"`);
}
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "ProjectUserProfile" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "userId" uuid NOT NULL, "customFields" jsonb, "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_2fd2054e182a7603f7032745eb9" PRIMARY KEY ("_id"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_3ba2d6a8eaeb966afa8820dbf0" ON "ProjectUserProfile" ("projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_39df4735afea8ab70c00674575" ON "ProjectUserProfile" ("userId") `,
);
await queryRunner.query(
`CREATE TABLE "TeamMemberCustomField" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "name" character varying(100) NOT NULL, "description" character varying(500), "customFieldType" character varying(100), "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_c0a4e92fd1fb77fe4cbb2f85ad4" PRIMARY KEY ("_id"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_e11389841b4ca122ec4a36c472" ON "TeamMemberCustomField" ("projectId") `,
);
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(
`ALTER TABLE "ProjectUserProfile" ADD CONSTRAINT "FK_3ba2d6a8eaeb966afa8820dbf0a" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "ProjectUserProfile" ADD CONSTRAINT "FK_39df4735afea8ab70c006745752" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "ProjectUserProfile" ADD CONSTRAINT "FK_b9db61caf3923a882e09943f367" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "ProjectUserProfile" ADD CONSTRAINT "FK_5fe8245962849bde50687e2c707" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "TeamMemberCustomField" ADD CONSTRAINT "FK_e11389841b4ca122ec4a36c4720" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "TeamMemberCustomField" ADD CONSTRAINT "FK_5ea46786eae26e125d07bbfddfa" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "TeamMemberCustomField" ADD CONSTRAINT "FK_35409d7ec1b559d4de58913e522" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "TeamMemberCustomField" DROP CONSTRAINT "FK_35409d7ec1b559d4de58913e522"`,
);
await queryRunner.query(
`ALTER TABLE "TeamMemberCustomField" DROP CONSTRAINT "FK_5ea46786eae26e125d07bbfddfa"`,
);
await queryRunner.query(
`ALTER TABLE "TeamMemberCustomField" DROP CONSTRAINT "FK_e11389841b4ca122ec4a36c4720"`,
);
await queryRunner.query(
`ALTER TABLE "ProjectUserProfile" DROP CONSTRAINT "FK_5fe8245962849bde50687e2c707"`,
);
await queryRunner.query(
`ALTER TABLE "ProjectUserProfile" DROP CONSTRAINT "FK_b9db61caf3923a882e09943f367"`,
);
await queryRunner.query(
`ALTER TABLE "ProjectUserProfile" DROP CONSTRAINT "FK_39df4735afea8ab70c006745752"`,
);
await queryRunner.query(
`ALTER TABLE "ProjectUserProfile" DROP CONSTRAINT "FK_3ba2d6a8eaeb966afa8820dbf0a"`,
);
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(
`DROP INDEX "public"."IDX_e11389841b4ca122ec4a36c472"`,
);
await queryRunner.query(`DROP TABLE "TeamMemberCustomField"`);
await queryRunner.query(
`DROP INDEX "public"."IDX_39df4735afea8ab70c00674575"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_3ba2d6a8eaeb966afa8820dbf0"`,
);
await queryRunner.query(`DROP TABLE "ProjectUserProfile"`);
}
}

View File

@@ -1,18 +1,29 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1769774527481 implements MigrationInterface {
public name = 'MigrationName1769774527481'
public name = "MigrationName1769774527481";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "IncidentRole" ADD "roleIcon" character varying(100)`);
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":[]}}'`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
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(`ALTER TABLE "IncidentRole" DROP COLUMN "roleIcon"`);
}
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "IncidentRole" ADD "roleIcon" character varying(100)`,
);
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":[]}}'`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
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(
`ALTER TABLE "IncidentRole" DROP COLUMN "roleIcon"`,
);
}
}

View File

@@ -1,94 +1,245 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1769780297584 implements MigrationInterface {
public name = 'MigrationName1769780297584'
public name = "MigrationName1769780297584";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "IncidentSlaRule" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "name" character varying(100) NOT NULL, "description" character varying(500), "order" integer NOT NULL DEFAULT '1', "isEnabled" boolean NOT NULL DEFAULT true, "responseTimeInMinutes" integer, "resolutionTimeInMinutes" integer, "atRiskThresholdInPercentage" integer NOT NULL DEFAULT '80', "internalNoteReminderIntervalInMinutes" integer, "publicNoteReminderIntervalInMinutes" integer, "internalNoteReminderTemplate" text, "publicNoteReminderTemplate" text, "incidentTitlePattern" character varying(500), "incidentDescriptionPattern" character varying(500), "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_7df8338a70c16abb7151cc9773a" PRIMARY KEY ("_id"))`);
await queryRunner.query(`CREATE INDEX "IDX_cd2943c22620ee3a9910e45663" ON "IncidentSlaRule" ("projectId") `);
await queryRunner.query(`CREATE INDEX "IDX_98e3b3d2a1e67d5d87f6254aad" ON "IncidentSlaRule" ("name") `);
await queryRunner.query(`CREATE INDEX "IDX_7d2380a578cc24568b6e0e9f6a" ON "IncidentSlaRule" ("order") `);
await queryRunner.query(`CREATE INDEX "IDX_ec7114aadb854b2e6f09fa3d16" ON "IncidentSlaRule" ("isEnabled") `);
await queryRunner.query(`CREATE TABLE "IncidentSla" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "incidentId" uuid NOT NULL, "incidentSlaRuleId" uuid NOT NULL, "responseDeadline" TIMESTAMP WITH TIME ZONE, "resolutionDeadline" TIMESTAMP WITH TIME ZONE, "status" character varying NOT NULL DEFAULT 'On Track', "respondedAt" TIMESTAMP WITH TIME ZONE, "resolvedAt" TIMESTAMP WITH TIME ZONE, "lastInternalNoteReminderSentAt" TIMESTAMP WITH TIME ZONE, "lastPublicNoteReminderSentAt" TIMESTAMP WITH TIME ZONE, "breachNotificationSentAt" TIMESTAMP WITH TIME ZONE, "slaStartedAt" TIMESTAMP WITH TIME ZONE NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_1e0e4d23867592377d865cd7fb6" PRIMARY KEY ("_id"))`);
await queryRunner.query(`CREATE INDEX "IDX_b20ae37629c143339b0f105d3f" ON "IncidentSla" ("projectId") `);
await queryRunner.query(`CREATE INDEX "IDX_2716e3d68b8fed7a062cb41e04" ON "IncidentSla" ("incidentId") `);
await queryRunner.query(`CREATE INDEX "IDX_cae25577f21f1c0c52c6d038ab" ON "IncidentSla" ("incidentSlaRuleId") `);
await queryRunner.query(`CREATE INDEX "IDX_872fce6c27af1f0aa04cf5b0bc" ON "IncidentSla" ("status") `);
await queryRunner.query(`CREATE INDEX "IDX_1e9dfd0511bc457251e0d27992" ON "IncidentSla" ("slaStartedAt") `);
await queryRunner.query(`CREATE TABLE "IncidentSlaRuleMonitor" ("incidentSlaRuleId" uuid NOT NULL, "monitorId" uuid NOT NULL, CONSTRAINT "PK_5ca43621c3484d364bba1db0fdb" PRIMARY KEY ("incidentSlaRuleId", "monitorId"))`);
await queryRunner.query(`CREATE INDEX "IDX_330c3f5655149584f1918bf125" ON "IncidentSlaRuleMonitor" ("incidentSlaRuleId") `);
await queryRunner.query(`CREATE INDEX "IDX_3deaa8530c9d6065da31f65116" ON "IncidentSlaRuleMonitor" ("monitorId") `);
await queryRunner.query(`CREATE TABLE "IncidentSlaRuleIncidentSeverity" ("incidentSlaRuleId" uuid NOT NULL, "incidentSeverityId" uuid NOT NULL, CONSTRAINT "PK_2a68293adc48c01c8ef849ffefd" PRIMARY KEY ("incidentSlaRuleId", "incidentSeverityId"))`);
await queryRunner.query(`CREATE INDEX "IDX_9d7443c084cbde74e8ab77d6df" ON "IncidentSlaRuleIncidentSeverity" ("incidentSlaRuleId") `);
await queryRunner.query(`CREATE INDEX "IDX_1dbba01db81040f8139bf5c4aa" ON "IncidentSlaRuleIncidentSeverity" ("incidentSeverityId") `);
await queryRunner.query(`CREATE TABLE "IncidentSlaRuleIncidentLabel" ("incidentSlaRuleId" uuid NOT NULL, "labelId" uuid NOT NULL, CONSTRAINT "PK_c3a28da9a45df8251bb25d5e8d6" PRIMARY KEY ("incidentSlaRuleId", "labelId"))`);
await queryRunner.query(`CREATE INDEX "IDX_a63cac299eedb0d44c1e937fc2" ON "IncidentSlaRuleIncidentLabel" ("incidentSlaRuleId") `);
await queryRunner.query(`CREATE INDEX "IDX_df0e2d83d9dcbc528b830645de" ON "IncidentSlaRuleIncidentLabel" ("labelId") `);
await queryRunner.query(`CREATE TABLE "IncidentSlaRuleMonitorLabel" ("incidentSlaRuleId" uuid NOT NULL, "labelId" uuid NOT NULL, CONSTRAINT "PK_e20fa59ad1d35c2f3a9c45f0832" PRIMARY KEY ("incidentSlaRuleId", "labelId"))`);
await queryRunner.query(`CREATE INDEX "IDX_c94cf6138ec340ae7c1976dbea" ON "IncidentSlaRuleMonitorLabel" ("incidentSlaRuleId") `);
await queryRunner.query(`CREATE INDEX "IDX_93e6f28f50bf56aadcc907f440" ON "IncidentSlaRuleMonitorLabel" ("labelId") `);
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(`ALTER TABLE "IncidentSlaRule" ADD CONSTRAINT "FK_cd2943c22620ee3a9910e456637" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRule" ADD CONSTRAINT "FK_26e788cca21b14940116395350f" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRule" ADD CONSTRAINT "FK_eb48fce1657c9a1e9245611857f" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "IncidentSla" ADD CONSTRAINT "FK_b20ae37629c143339b0f105d3f8" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "IncidentSla" ADD CONSTRAINT "FK_2716e3d68b8fed7a062cb41e04f" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "IncidentSla" ADD CONSTRAINT "FK_cae25577f21f1c0c52c6d038ab4" FOREIGN KEY ("incidentSlaRuleId") REFERENCES "IncidentSlaRule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "IncidentSla" ADD CONSTRAINT "FK_9771f22534ed092c59f55198c5a" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "IncidentSla" ADD CONSTRAINT "FK_c1cadef60fde93931b5131fbbba" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleMonitor" ADD CONSTRAINT "FK_330c3f5655149584f1918bf1258" FOREIGN KEY ("incidentSlaRuleId") REFERENCES "IncidentSlaRule"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleMonitor" ADD CONSTRAINT "FK_3deaa8530c9d6065da31f65116c" FOREIGN KEY ("monitorId") REFERENCES "Monitor"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleIncidentSeverity" ADD CONSTRAINT "FK_9d7443c084cbde74e8ab77d6dfc" FOREIGN KEY ("incidentSlaRuleId") REFERENCES "IncidentSlaRule"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleIncidentSeverity" ADD CONSTRAINT "FK_1dbba01db81040f8139bf5c4aae" FOREIGN KEY ("incidentSeverityId") REFERENCES "IncidentSeverity"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleIncidentLabel" ADD CONSTRAINT "FK_a63cac299eedb0d44c1e937fc24" FOREIGN KEY ("incidentSlaRuleId") REFERENCES "IncidentSlaRule"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleIncidentLabel" ADD CONSTRAINT "FK_df0e2d83d9dcbc528b830645ded" FOREIGN KEY ("labelId") REFERENCES "Label"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleMonitorLabel" ADD CONSTRAINT "FK_c94cf6138ec340ae7c1976dbea2" FOREIGN KEY ("incidentSlaRuleId") REFERENCES "IncidentSlaRule"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleMonitorLabel" ADD CONSTRAINT "FK_93e6f28f50bf56aadcc907f4403" FOREIGN KEY ("labelId") REFERENCES "Label"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleMonitorLabel" DROP CONSTRAINT "FK_93e6f28f50bf56aadcc907f4403"`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleMonitorLabel" DROP CONSTRAINT "FK_c94cf6138ec340ae7c1976dbea2"`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleIncidentLabel" DROP CONSTRAINT "FK_df0e2d83d9dcbc528b830645ded"`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleIncidentLabel" DROP CONSTRAINT "FK_a63cac299eedb0d44c1e937fc24"`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleIncidentSeverity" DROP CONSTRAINT "FK_1dbba01db81040f8139bf5c4aae"`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleIncidentSeverity" DROP CONSTRAINT "FK_9d7443c084cbde74e8ab77d6dfc"`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleMonitor" DROP CONSTRAINT "FK_3deaa8530c9d6065da31f65116c"`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRuleMonitor" DROP CONSTRAINT "FK_330c3f5655149584f1918bf1258"`);
await queryRunner.query(`ALTER TABLE "IncidentSla" DROP CONSTRAINT "FK_c1cadef60fde93931b5131fbbba"`);
await queryRunner.query(`ALTER TABLE "IncidentSla" DROP CONSTRAINT "FK_9771f22534ed092c59f55198c5a"`);
await queryRunner.query(`ALTER TABLE "IncidentSla" DROP CONSTRAINT "FK_cae25577f21f1c0c52c6d038ab4"`);
await queryRunner.query(`ALTER TABLE "IncidentSla" DROP CONSTRAINT "FK_2716e3d68b8fed7a062cb41e04f"`);
await queryRunner.query(`ALTER TABLE "IncidentSla" DROP CONSTRAINT "FK_b20ae37629c143339b0f105d3f8"`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRule" DROP CONSTRAINT "FK_eb48fce1657c9a1e9245611857f"`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRule" DROP CONSTRAINT "FK_26e788cca21b14940116395350f"`);
await queryRunner.query(`ALTER TABLE "IncidentSlaRule" DROP CONSTRAINT "FK_cd2943c22620ee3a9910e456637"`);
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(`DROP INDEX "public"."IDX_93e6f28f50bf56aadcc907f440"`);
await queryRunner.query(`DROP INDEX "public"."IDX_c94cf6138ec340ae7c1976dbea"`);
await queryRunner.query(`DROP TABLE "IncidentSlaRuleMonitorLabel"`);
await queryRunner.query(`DROP INDEX "public"."IDX_df0e2d83d9dcbc528b830645de"`);
await queryRunner.query(`DROP INDEX "public"."IDX_a63cac299eedb0d44c1e937fc2"`);
await queryRunner.query(`DROP TABLE "IncidentSlaRuleIncidentLabel"`);
await queryRunner.query(`DROP INDEX "public"."IDX_1dbba01db81040f8139bf5c4aa"`);
await queryRunner.query(`DROP INDEX "public"."IDX_9d7443c084cbde74e8ab77d6df"`);
await queryRunner.query(`DROP TABLE "IncidentSlaRuleIncidentSeverity"`);
await queryRunner.query(`DROP INDEX "public"."IDX_3deaa8530c9d6065da31f65116"`);
await queryRunner.query(`DROP INDEX "public"."IDX_330c3f5655149584f1918bf125"`);
await queryRunner.query(`DROP TABLE "IncidentSlaRuleMonitor"`);
await queryRunner.query(`DROP INDEX "public"."IDX_1e9dfd0511bc457251e0d27992"`);
await queryRunner.query(`DROP INDEX "public"."IDX_872fce6c27af1f0aa04cf5b0bc"`);
await queryRunner.query(`DROP INDEX "public"."IDX_cae25577f21f1c0c52c6d038ab"`);
await queryRunner.query(`DROP INDEX "public"."IDX_2716e3d68b8fed7a062cb41e04"`);
await queryRunner.query(`DROP INDEX "public"."IDX_b20ae37629c143339b0f105d3f"`);
await queryRunner.query(`DROP TABLE "IncidentSla"`);
await queryRunner.query(`DROP INDEX "public"."IDX_ec7114aadb854b2e6f09fa3d16"`);
await queryRunner.query(`DROP INDEX "public"."IDX_7d2380a578cc24568b6e0e9f6a"`);
await queryRunner.query(`DROP INDEX "public"."IDX_98e3b3d2a1e67d5d87f6254aad"`);
await queryRunner.query(`DROP INDEX "public"."IDX_cd2943c22620ee3a9910e45663"`);
await queryRunner.query(`DROP TABLE "IncidentSlaRule"`);
}
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "IncidentSlaRule" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "name" character varying(100) NOT NULL, "description" character varying(500), "order" integer NOT NULL DEFAULT '1', "isEnabled" boolean NOT NULL DEFAULT true, "responseTimeInMinutes" integer, "resolutionTimeInMinutes" integer, "atRiskThresholdInPercentage" integer NOT NULL DEFAULT '80', "internalNoteReminderIntervalInMinutes" integer, "publicNoteReminderIntervalInMinutes" integer, "internalNoteReminderTemplate" text, "publicNoteReminderTemplate" text, "incidentTitlePattern" character varying(500), "incidentDescriptionPattern" character varying(500), "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_7df8338a70c16abb7151cc9773a" PRIMARY KEY ("_id"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_cd2943c22620ee3a9910e45663" ON "IncidentSlaRule" ("projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_98e3b3d2a1e67d5d87f6254aad" ON "IncidentSlaRule" ("name") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_7d2380a578cc24568b6e0e9f6a" ON "IncidentSlaRule" ("order") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_ec7114aadb854b2e6f09fa3d16" ON "IncidentSlaRule" ("isEnabled") `,
);
await queryRunner.query(
`CREATE TABLE "IncidentSla" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "incidentId" uuid NOT NULL, "incidentSlaRuleId" uuid NOT NULL, "responseDeadline" TIMESTAMP WITH TIME ZONE, "resolutionDeadline" TIMESTAMP WITH TIME ZONE, "status" character varying NOT NULL DEFAULT 'On Track', "respondedAt" TIMESTAMP WITH TIME ZONE, "resolvedAt" TIMESTAMP WITH TIME ZONE, "lastInternalNoteReminderSentAt" TIMESTAMP WITH TIME ZONE, "lastPublicNoteReminderSentAt" TIMESTAMP WITH TIME ZONE, "breachNotificationSentAt" TIMESTAMP WITH TIME ZONE, "slaStartedAt" TIMESTAMP WITH TIME ZONE NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_1e0e4d23867592377d865cd7fb6" PRIMARY KEY ("_id"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_b20ae37629c143339b0f105d3f" ON "IncidentSla" ("projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_2716e3d68b8fed7a062cb41e04" ON "IncidentSla" ("incidentId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_cae25577f21f1c0c52c6d038ab" ON "IncidentSla" ("incidentSlaRuleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_872fce6c27af1f0aa04cf5b0bc" ON "IncidentSla" ("status") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_1e9dfd0511bc457251e0d27992" ON "IncidentSla" ("slaStartedAt") `,
);
await queryRunner.query(
`CREATE TABLE "IncidentSlaRuleMonitor" ("incidentSlaRuleId" uuid NOT NULL, "monitorId" uuid NOT NULL, CONSTRAINT "PK_5ca43621c3484d364bba1db0fdb" PRIMARY KEY ("incidentSlaRuleId", "monitorId"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_330c3f5655149584f1918bf125" ON "IncidentSlaRuleMonitor" ("incidentSlaRuleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_3deaa8530c9d6065da31f65116" ON "IncidentSlaRuleMonitor" ("monitorId") `,
);
await queryRunner.query(
`CREATE TABLE "IncidentSlaRuleIncidentSeverity" ("incidentSlaRuleId" uuid NOT NULL, "incidentSeverityId" uuid NOT NULL, CONSTRAINT "PK_2a68293adc48c01c8ef849ffefd" PRIMARY KEY ("incidentSlaRuleId", "incidentSeverityId"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_9d7443c084cbde74e8ab77d6df" ON "IncidentSlaRuleIncidentSeverity" ("incidentSlaRuleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_1dbba01db81040f8139bf5c4aa" ON "IncidentSlaRuleIncidentSeverity" ("incidentSeverityId") `,
);
await queryRunner.query(
`CREATE TABLE "IncidentSlaRuleIncidentLabel" ("incidentSlaRuleId" uuid NOT NULL, "labelId" uuid NOT NULL, CONSTRAINT "PK_c3a28da9a45df8251bb25d5e8d6" PRIMARY KEY ("incidentSlaRuleId", "labelId"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_a63cac299eedb0d44c1e937fc2" ON "IncidentSlaRuleIncidentLabel" ("incidentSlaRuleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_df0e2d83d9dcbc528b830645de" ON "IncidentSlaRuleIncidentLabel" ("labelId") `,
);
await queryRunner.query(
`CREATE TABLE "IncidentSlaRuleMonitorLabel" ("incidentSlaRuleId" uuid NOT NULL, "labelId" uuid NOT NULL, CONSTRAINT "PK_e20fa59ad1d35c2f3a9c45f0832" PRIMARY KEY ("incidentSlaRuleId", "labelId"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_c94cf6138ec340ae7c1976dbea" ON "IncidentSlaRuleMonitorLabel" ("incidentSlaRuleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_93e6f28f50bf56aadcc907f440" ON "IncidentSlaRuleMonitorLabel" ("labelId") `,
);
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(
`ALTER TABLE "IncidentSlaRule" ADD CONSTRAINT "FK_cd2943c22620ee3a9910e456637" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRule" ADD CONSTRAINT "FK_26e788cca21b14940116395350f" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRule" ADD CONSTRAINT "FK_eb48fce1657c9a1e9245611857f" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSla" ADD CONSTRAINT "FK_b20ae37629c143339b0f105d3f8" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSla" ADD CONSTRAINT "FK_2716e3d68b8fed7a062cb41e04f" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSla" ADD CONSTRAINT "FK_cae25577f21f1c0c52c6d038ab4" FOREIGN KEY ("incidentSlaRuleId") REFERENCES "IncidentSlaRule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSla" ADD CONSTRAINT "FK_9771f22534ed092c59f55198c5a" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSla" ADD CONSTRAINT "FK_c1cadef60fde93931b5131fbbba" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleMonitor" ADD CONSTRAINT "FK_330c3f5655149584f1918bf1258" FOREIGN KEY ("incidentSlaRuleId") REFERENCES "IncidentSlaRule"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleMonitor" ADD CONSTRAINT "FK_3deaa8530c9d6065da31f65116c" FOREIGN KEY ("monitorId") REFERENCES "Monitor"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleIncidentSeverity" ADD CONSTRAINT "FK_9d7443c084cbde74e8ab77d6dfc" FOREIGN KEY ("incidentSlaRuleId") REFERENCES "IncidentSlaRule"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleIncidentSeverity" ADD CONSTRAINT "FK_1dbba01db81040f8139bf5c4aae" FOREIGN KEY ("incidentSeverityId") REFERENCES "IncidentSeverity"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleIncidentLabel" ADD CONSTRAINT "FK_a63cac299eedb0d44c1e937fc24" FOREIGN KEY ("incidentSlaRuleId") REFERENCES "IncidentSlaRule"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleIncidentLabel" ADD CONSTRAINT "FK_df0e2d83d9dcbc528b830645ded" FOREIGN KEY ("labelId") REFERENCES "Label"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleMonitorLabel" ADD CONSTRAINT "FK_c94cf6138ec340ae7c1976dbea2" FOREIGN KEY ("incidentSlaRuleId") REFERENCES "IncidentSlaRule"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleMonitorLabel" ADD CONSTRAINT "FK_93e6f28f50bf56aadcc907f4403" FOREIGN KEY ("labelId") REFERENCES "Label"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleMonitorLabel" DROP CONSTRAINT "FK_93e6f28f50bf56aadcc907f4403"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleMonitorLabel" DROP CONSTRAINT "FK_c94cf6138ec340ae7c1976dbea2"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleIncidentLabel" DROP CONSTRAINT "FK_df0e2d83d9dcbc528b830645ded"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleIncidentLabel" DROP CONSTRAINT "FK_a63cac299eedb0d44c1e937fc24"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleIncidentSeverity" DROP CONSTRAINT "FK_1dbba01db81040f8139bf5c4aae"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleIncidentSeverity" DROP CONSTRAINT "FK_9d7443c084cbde74e8ab77d6dfc"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleMonitor" DROP CONSTRAINT "FK_3deaa8530c9d6065da31f65116c"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRuleMonitor" DROP CONSTRAINT "FK_330c3f5655149584f1918bf1258"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSla" DROP CONSTRAINT "FK_c1cadef60fde93931b5131fbbba"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSla" DROP CONSTRAINT "FK_9771f22534ed092c59f55198c5a"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSla" DROP CONSTRAINT "FK_cae25577f21f1c0c52c6d038ab4"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSla" DROP CONSTRAINT "FK_2716e3d68b8fed7a062cb41e04f"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSla" DROP CONSTRAINT "FK_b20ae37629c143339b0f105d3f8"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRule" DROP CONSTRAINT "FK_eb48fce1657c9a1e9245611857f"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRule" DROP CONSTRAINT "FK_26e788cca21b14940116395350f"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentSlaRule" DROP CONSTRAINT "FK_cd2943c22620ee3a9910e456637"`,
);
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(
`DROP INDEX "public"."IDX_93e6f28f50bf56aadcc907f440"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_c94cf6138ec340ae7c1976dbea"`,
);
await queryRunner.query(`DROP TABLE "IncidentSlaRuleMonitorLabel"`);
await queryRunner.query(
`DROP INDEX "public"."IDX_df0e2d83d9dcbc528b830645de"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_a63cac299eedb0d44c1e937fc2"`,
);
await queryRunner.query(`DROP TABLE "IncidentSlaRuleIncidentLabel"`);
await queryRunner.query(
`DROP INDEX "public"."IDX_1dbba01db81040f8139bf5c4aa"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_9d7443c084cbde74e8ab77d6df"`,
);
await queryRunner.query(`DROP TABLE "IncidentSlaRuleIncidentSeverity"`);
await queryRunner.query(
`DROP INDEX "public"."IDX_3deaa8530c9d6065da31f65116"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_330c3f5655149584f1918bf125"`,
);
await queryRunner.query(`DROP TABLE "IncidentSlaRuleMonitor"`);
await queryRunner.query(
`DROP INDEX "public"."IDX_1e9dfd0511bc457251e0d27992"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_872fce6c27af1f0aa04cf5b0bc"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_cae25577f21f1c0c52c6d038ab"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_2716e3d68b8fed7a062cb41e04"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b20ae37629c143339b0f105d3f"`,
);
await queryRunner.query(`DROP TABLE "IncidentSla"`);
await queryRunner.query(
`DROP INDEX "public"."IDX_ec7114aadb854b2e6f09fa3d16"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_7d2380a578cc24568b6e0e9f6a"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_98e3b3d2a1e67d5d87f6254aad"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_cd2943c22620ee3a9910e45663"`,
);
await queryRunner.query(`DROP TABLE "IncidentSlaRule"`);
}
}

View File

@@ -497,5 +497,5 @@ export default [
MigrationName1769723982900,
MigrationName1769772215532,
MigrationName1769774527481,
MigrationName1769780297584
MigrationName1769780297584,
];

View File

@@ -855,8 +855,13 @@ export class Service extends DatabaseService<Model> {
.then(async () => {
// Create SLA record for incident if a matching rule exists
try {
if (createdItem.projectId && createdItem.id && createdItem.declaredAt) {
const IncidentSlaService = (await import("./IncidentSlaService")).default;
if (
createdItem.projectId &&
createdItem.id &&
createdItem.declaredAt
) {
const IncidentSlaService: typeof import("./IncidentSlaService").default =
(await import("./IncidentSlaService")).default;
await IncidentSlaService.createSlaForIncident({
incidentId: createdItem.id,
projectId: createdItem.projectId,
@@ -1532,7 +1537,8 @@ ${incidentSeverity.name}
// Recalculate SLA deadlines when severity changes
try {
const IncidentSlaService = (await import("./IncidentSlaService")).default;
const IncidentSlaService: typeof import("./IncidentSlaService").default =
(await import("./IncidentSlaService")).default;
await IncidentSlaService.recalculateDeadlines({
incidentId: incidentId,
});

View File

@@ -65,7 +65,9 @@ export class Service extends DatabaseService<Model> {
let incident: Incident | null = data.incident || null;
if (!incident) {
const IncidentService = (await import("./IncidentService")).default;
const IncidentService: typeof import("./IncidentService").default = (
await import("./IncidentService")
).default;
incident = await IncidentService.findOneById({
id: data.incidentId,
@@ -138,9 +140,7 @@ export class Service extends DatabaseService<Model> {
});
if (rules.length === 0) {
logger.debug(
`No enabled SLA rules found for project ${data.projectId}`,
);
logger.debug(`No enabled SLA rules found for project ${data.projectId}`);
return null;
}
@@ -156,9 +156,7 @@ export class Service extends DatabaseService<Model> {
}
}
logger.debug(
`Incident ${data.incidentId} did not match any SLA rules`,
);
logger.debug(`Incident ${data.incidentId} did not match any SLA rules`);
return null;
}
@@ -177,11 +175,9 @@ export class Service extends DatabaseService<Model> {
return false;
}
const ruleMonitorIds: Array<string> = rule.monitors.map(
(m: Monitor) => {
return m.id?.toString() || "";
},
);
const ruleMonitorIds: Array<string> = rule.monitors.map((m: Monitor) => {
return m.id?.toString() || "";
});
const incidentMonitorIds: Array<string> = incident.monitors.map(
(m: Monitor) => {
@@ -238,11 +234,9 @@ export class Service extends DatabaseService<Model> {
},
);
const hasMatchingLabel: boolean = ruleLabelIds.some(
(labelId: string) => {
return incidentLabelIds.includes(labelId);
},
);
const hasMatchingLabel: boolean = ruleLabelIds.some((labelId: string) => {
return incidentLabelIds.includes(labelId);
});
if (!hasMatchingLabel) {
return false;

View File

@@ -104,7 +104,9 @@ export class Service extends DatabaseService<Model> {
return createdSla;
} catch (error) {
logger.error(`Error creating SLA record for incident ${data.incidentId}: ${error}`);
logger.error(
`Error creating SLA record for incident ${data.incidentId}: ${error}`,
);
return null;
}
}
@@ -150,9 +152,7 @@ export class Service extends DatabaseService<Model> {
},
});
logger.info(
`Marked SLA ${sla.id} as responded at ${data.respondedAt}`,
);
logger.info(`Marked SLA ${sla.id} as responded at ${data.respondedAt}`);
}
}
}
@@ -238,12 +238,12 @@ export class Service extends DatabaseService<Model> {
public async recalculateDeadlines(data: {
incidentId: ObjectID;
}): Promise<void> {
logger.debug(
`Recalculating deadlines for incident ${data.incidentId}`,
);
logger.debug(`Recalculating deadlines for incident ${data.incidentId}`);
// Get the incident to find the new severity and project
const IncidentService = (await import("./IncidentService")).default;
const IncidentService: typeof import("./IncidentService").default = (
await import("./IncidentService")
).default;
const incident: Incident | null = await IncidentService.findOneById({
id: data.incidentId,
@@ -355,10 +355,12 @@ export class Service extends DatabaseService<Model> {
public async getIncidentsNeedingInternalNoteReminder(): Promise<
Array<Model>
> {
// Find SLAs where:
// - Not resolved
// - Has internal note reminder interval configured
// - Last reminder was sent more than interval ago OR never sent
/*
* Find SLAs where:
* - Not resolved
* - Has internal note reminder interval configured
* - Last reminder was sent more than interval ago OR never sent
*/
const now: Date = OneUptimeDate.getCurrentDate();
const slaRecords: Array<Model> = await this.findBy({
@@ -405,10 +407,11 @@ export class Service extends DatabaseService<Model> {
return timeSinceStart >= interval;
}
const timeSinceLastReminder: number = OneUptimeDate.getDifferenceInMinutes(
now,
sla.lastInternalNoteReminderSentAt,
);
const timeSinceLastReminder: number =
OneUptimeDate.getDifferenceInMinutes(
now,
sla.lastInternalNoteReminderSentAt,
);
return timeSinceLastReminder >= interval;
});
@@ -464,10 +467,11 @@ export class Service extends DatabaseService<Model> {
return timeSinceStart >= interval;
}
const timeSinceLastReminder: number = OneUptimeDate.getDifferenceInMinutes(
now,
sla.lastPublicNoteReminderSentAt,
);
const timeSinceLastReminder: number =
OneUptimeDate.getDifferenceInMinutes(
now,
sla.lastPublicNoteReminderSentAt,
);
return timeSinceLastReminder >= interval;
});

View File

@@ -697,12 +697,15 @@ ${createdItem.rootCause}`,
previousStateWasResolved: boolean;
}): Promise<void> {
try {
const IncidentSlaService = (await import("./IncidentSlaService")).default;
const IncidentSlaService: typeof import("./IncidentSlaService").default =
(await import("./IncidentSlaService")).default;
// Check if incident is being reopened (previous state was resolved, current state is not resolved)
if (data.previousStateWasResolved && !data.isResolvedState) {
// Incident is being reopened - create a new SLA record
const IncidentService = (await import("./IncidentService")).default;
const IncidentService: typeof import("./IncidentService").default = (
await import("./IncidentService")
).default;
const incident: Incident | null = await IncidentService.findOneById({
id: data.incidentId,

View File

@@ -70,10 +70,7 @@ const IconPicker: FunctionComponent<ComponentProps> = (
className="flex items-center justify-center h-5 w-5 cursor-pointer"
>
{selectedIcon ? (
<Icon
icon={selectedIcon}
className="h-5 w-5 text-gray-600"
/>
<Icon icon={selectedIcon} className="h-5 w-5 text-gray-600" />
) : (
<div className="h-5 w-5 border border-dashed border-gray-300 rounded"></div>
)}
@@ -150,10 +147,7 @@ const IconPicker: FunctionComponent<ComponentProps> = (
}`}
title={icon}
>
<Icon
icon={icon}
className="h-5 w-5 text-gray-600"
/>
<Icon icon={icon} className="h-5 w-5 text-gray-600" />
</div>
);
})}

View File

@@ -49,7 +49,10 @@ const NotificationBellDropdown: (props: ComponentProps) => ReactElement = (
)}
{errorItems.length > 0 && (
<NotificationBellSection title="Critical" alertType={HeaderAlertType.ERROR}>
<NotificationBellSection
title="Critical"
alertType={HeaderAlertType.ERROR}
>
{errorItems.map((item: NotificationItem) => {
return (
<NotificationBellItem
@@ -65,7 +68,10 @@ const NotificationBellDropdown: (props: ComponentProps) => ReactElement = (
)}
{successItems.length > 0 && (
<NotificationBellSection title="On-Call" alertType={HeaderAlertType.SUCCESS}>
<NotificationBellSection
title="On-Call"
alertType={HeaderAlertType.SUCCESS}
>
{successItems.map((item: NotificationItem) => {
return (
<NotificationBellItem
@@ -81,7 +87,10 @@ const NotificationBellDropdown: (props: ComponentProps) => ReactElement = (
)}
{infoItems.length > 0 && (
<NotificationBellSection title="Information" alertType={HeaderAlertType.INFO}>
<NotificationBellSection
title="Information"
alertType={HeaderAlertType.INFO}
>
{infoItems.map((item: NotificationItem) => {
return (
<NotificationBellItem

View File

@@ -45,11 +45,7 @@ const RoleLabel: FunctionComponent<ComponentProps> = (
backgroundColor: resolvedColor.toString(),
}}
>
<Icon
icon={resolvedIcon}
className="h-4 w-4"
color={iconColor}
/>
<Icon icon={resolvedIcon} className="h-4 w-4" color={iconColor} />
</div>
) : (
<div

View File

@@ -71,61 +71,64 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
const [showCurrentOnCallPolicyModal, setShowCurrentOnCallPolicyModal] =
useState<boolean>(false);
const fetchIncidentsCount: PromiseVoidFunction = useCallback(async (): Promise<void> => {
try {
const count: number = await ModelAPI.count<Incident>({
modelType: Incident,
query: {
currentIncidentState: {
order: 1,
const fetchIncidentsCount: PromiseVoidFunction =
useCallback(async (): Promise<void> => {
try {
const count: number = await ModelAPI.count<Incident>({
modelType: Incident,
query: {
currentIncidentState: {
order: 1,
},
},
},
requestOptions: {
isMultiTenantRequest: true,
},
});
setIncidentsCount(count);
} catch (err) {
setIncidentsCount(0);
}
}, []);
const fetchAlertsCount: PromiseVoidFunction = useCallback(async (): Promise<void> => {
try {
const count: number = await ModelAPI.count<Alert>({
modelType: Alert,
query: {
currentAlertState: {
order: 1,
requestOptions: {
isMultiTenantRequest: true,
},
},
requestOptions: {
isMultiTenantRequest: true,
},
});
setAlertsCount(count);
} catch (err) {
setAlertsCount(0);
}
}, []);
});
setIncidentsCount(count);
} catch {
setIncidentsCount(0);
}
}, []);
const fetchInvitationsCount: PromiseVoidFunction = useCallback(async (): Promise<void> => {
try {
const count: number = await ModelAPI.count<TeamMember>({
modelType: TeamMember,
query: {
userId: User.getUserId(),
hasAcceptedInvitation: false,
},
requestOptions: {
isMultiTenantRequest: true,
},
});
setInvitationsCount(count);
} catch (err) {
setInvitationsCount(0);
}
}, []);
const fetchAlertsCount: PromiseVoidFunction =
useCallback(async (): Promise<void> => {
try {
const count: number = await ModelAPI.count<Alert>({
modelType: Alert,
query: {
currentAlertState: {
order: 1,
},
},
requestOptions: {
isMultiTenantRequest: true,
},
});
setAlertsCount(count);
} catch {
setAlertsCount(0);
}
}, []);
const fetchInvitationsCount: PromiseVoidFunction =
useCallback(async (): Promise<void> => {
try {
const count: number = await ModelAPI.count<TeamMember>({
modelType: TeamMember,
query: {
userId: User.getUserId(),
hasAcceptedInvitation: false,
},
requestOptions: {
isMultiTenantRequest: true,
},
});
setInvitationsCount(count);
} catch {
setInvitationsCount(0);
}
}, []);
const refreshIncidentCount: VoidFunction = () => {
fetchIncidentsCount().catch(() => {
@@ -436,77 +439,81 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
)
: 0;
const buildNotificationItems: () => Array<NotificationItem> = (): Array<NotificationItem> => {
const items: Array<NotificationItem> = [];
const buildNotificationItems: () => Array<NotificationItem> =
(): Array<NotificationItem> => {
const items: Array<NotificationItem> = [];
// Incidents - ERROR type
items.push({
id: "incidents",
icon: IconProp.Alert,
title: `${incidentsCount} Active ${incidentsCount === 1 ? "Incident" : "Incidents"}`,
count: incidentsCount,
alertType: HeaderAlertType.ERROR,
tooltip: "View all active incidents",
});
// Alerts - ERROR type
items.push({
id: "alerts",
icon: IconProp.ExclaimationCircle,
title: `${alertsCount} Active ${alertsCount === 1 ? "Alert" : "Alerts"}`,
count: alertsCount,
alertType: HeaderAlertType.ERROR,
tooltip: "View all active alerts",
});
// On-Call Policies - SUCCESS type
if (props.selectedProject && currentOnCallPolicies.length > 0) {
// Incidents - ERROR type
items.push({
id: "oncall",
icon: IconProp.Call,
title: `On duty for ${currentOnCallPolicies.length} ${currentOnCallPolicies.length === 1 ? "policy" : "policies"}`,
count: currentOnCallPolicies.length,
alertType: HeaderAlertType.SUCCESS,
tooltip: "On-call policies you are currently on duty for",
id: "incidents",
icon: IconProp.Alert,
title: `${incidentsCount} Active ${incidentsCount === 1 ? "Incident" : "Incidents"}`,
count: incidentsCount,
alertType: HeaderAlertType.ERROR,
tooltip: "View all active incidents",
});
}
// Invitations - INFO type
items.push({
id: "invitations",
icon: IconProp.Folder,
title: `${invitationsCount} Pending ${invitationsCount === 1 ? "Invitation" : "Invitations"}`,
count: invitationsCount,
alertType: HeaderAlertType.INFO,
tooltip: "Looks like you have pending project invitations. Please click here to review and accept them.",
});
// Trial Days - INFO type (only if showTrialButton is true)
if (showTrialButton && trialDaysRemaining > 0) {
// Alerts - ERROR type
items.push({
id: "trial",
icon: IconProp.Clock,
title: `Trial ends in ${trialDaysRemaining} ${trialDaysRemaining === 1 ? "day" : "days"}`,
count: trialDaysRemaining,
id: "alerts",
icon: IconProp.ExclaimationCircle,
title: `${alertsCount} Active ${alertsCount === 1 ? "Alert" : "Alerts"}`,
count: alertsCount,
alertType: HeaderAlertType.ERROR,
tooltip: "View all active alerts",
});
// On-Call Policies - SUCCESS type
if (props.selectedProject && currentOnCallPolicies.length > 0) {
items.push({
id: "oncall",
icon: IconProp.Call,
title: `On duty for ${currentOnCallPolicies.length} ${currentOnCallPolicies.length === 1 ? "policy" : "policies"}`,
count: currentOnCallPolicies.length,
alertType: HeaderAlertType.SUCCESS,
tooltip: "On-call policies you are currently on duty for",
});
}
// Invitations - INFO type
items.push({
id: "invitations",
icon: IconProp.Folder,
title: `${invitationsCount} Pending ${invitationsCount === 1 ? "Invitation" : "Invitations"}`,
count: invitationsCount,
alertType: HeaderAlertType.INFO,
tooltip: "Your trial ends soon. Add card details to continue using the service.",
tooltip:
"Looks like you have pending project invitations. Please click here to review and accept them.",
});
}
// Add Card Details - INFO type (only if showAddCardButton is true)
if (showAddCardButton) {
items.push({
id: "addcard",
icon: IconProp.Billing,
title: "Add Card Details",
count: 1,
alertType: HeaderAlertType.INFO,
tooltip: "Add your payment card details to continue using the service.",
});
}
// Trial Days - INFO type (only if showTrialButton is true)
if (showTrialButton && trialDaysRemaining > 0) {
items.push({
id: "trial",
icon: IconProp.Clock,
title: `Trial ends in ${trialDaysRemaining} ${trialDaysRemaining === 1 ? "day" : "days"}`,
count: trialDaysRemaining,
alertType: HeaderAlertType.INFO,
tooltip:
"Your trial ends soon. Add card details to continue using the service.",
});
}
return items;
};
// Add Card Details - INFO type (only if showAddCardButton is true)
if (showAddCardButton) {
items.push({
id: "addcard",
icon: IconProp.Billing,
title: "Add Card Details",
count: 1,
alertType: HeaderAlertType.INFO,
tooltip:
"Add your payment card details to continue using the service.",
});
}
return items;
};
const handleNotificationItemClick: (item: NotificationItem) => void = (
item: NotificationItem,

View File

@@ -13,10 +13,14 @@ import SortOrder from "Common/Types/BaseDatabase/SortOrder";
import ProjectUtil from "Common/UI/Utils/Project";
import OneUptimeDate from "Common/Types/Date";
const IncidentViewSla: FunctionComponent<PageComponentProps> = (): ReactElement => {
const IncidentViewSla: FunctionComponent<
PageComponentProps
> = (): ReactElement => {
const modelId: ObjectID = Navigation.getLastParamAsObjectID(1);
const getStatusColor = (status: IncidentSlaStatus | undefined): Color => {
const getStatusColor: (status: IncidentSlaStatus | undefined) => Color = (
status: IncidentSlaStatus | undefined,
): Color => {
switch (status) {
case IncidentSlaStatus.OnTrack:
return Green;
@@ -32,7 +36,9 @@ const IncidentViewSla: FunctionComponent<PageComponentProps> = (): ReactElement
}
};
const formatTimeRemaining = (deadline: Date | undefined): string => {
const formatTimeRemaining: (deadline: Date | undefined) => string = (
deadline: Date | undefined,
): string => {
if (!deadline) {
return "N/A";
}
@@ -107,7 +113,8 @@ const IncidentViewSla: FunctionComponent<PageComponentProps> = (): ReactElement
type: FieldType.Text,
getElement: (item: IncidentSla): ReactElement => {
const ruleName: string =
(item.incidentSlaRule as { name?: string })?.name || "Unknown Rule";
(item.incidentSlaRule as { name?: string })?.name ||
"Unknown Rule";
return <span>{ruleName}</span>;
},
},
@@ -138,7 +145,7 @@ const IncidentViewSla: FunctionComponent<PageComponentProps> = (): ReactElement
return <span className="text-gray-400">Not configured</span>;
}
const isResponded: boolean = !!item.respondedAt;
const isResponded: boolean = Boolean(item.respondedAt);
const deadline: Date = item.responseDeadline;
const formattedDeadline: string =
OneUptimeDate.getDateAsLocalFormattedString(deadline);
@@ -152,9 +159,7 @@ const IncidentViewSla: FunctionComponent<PageComponentProps> = (): ReactElement
return (
<div>
<span
className={
wasOnTime ? "text-green-600" : "text-red-600"
}
className={wasOnTime ? "text-green-600" : "text-red-600"}
>
{wasOnTime ? "Met" : "Missed"}
</span>
@@ -190,7 +195,7 @@ const IncidentViewSla: FunctionComponent<PageComponentProps> = (): ReactElement
return <span className="text-gray-400">Not configured</span>;
}
const isResolved: boolean = !!item.resolvedAt;
const isResolved: boolean = Boolean(item.resolvedAt);
const deadline: Date = item.resolutionDeadline;
const formattedDeadline: string =
OneUptimeDate.getDateAsLocalFormattedString(deadline);
@@ -204,9 +209,7 @@ const IncidentViewSla: FunctionComponent<PageComponentProps> = (): ReactElement
return (
<div>
<span
className={
wasOnTime ? "text-green-600" : "text-red-600"
}
className={wasOnTime ? "text-green-600" : "text-red-600"}
>
{wasOnTime ? "Met" : "Missed"}
</span>

View File

@@ -74,142 +74,146 @@ const Teams: FunctionComponent<PageComponentProps> = (
)}
<ModelTable<TeamMember>
modelType={TeamMember}
id="teams-table"
name="Settings > Users"
userPreferencesKey="users-table"
isDeleteable={!isPushGroupsManaged}
bulkActions={
!isPushGroupsManaged
? {
buttons: [ModalTableBulkDefaultActions.Delete],
}
: undefined
}
isEditable={false}
isCreateable={false}
onFilterApplied={(isApplied: boolean) => {
setIsFilterApplied(isApplied);
}}
isViewable={true}
onBeforeDelete={async (item: TeamMember): Promise<TeamMember> => {
if (isPushGroupsManaged) {
throw new BadDataException(
"Cannot remove team members while SCIM Push Groups is enabled for this project. Disable Push Groups to manage members from OneUptime.",
);
}
return item;
}}
cardProps={{
title: "Users",
description:
"Here is a list of all the team members in this project.",
buttons: [
{
title: "Invite User",
buttonStyle: ButtonStyleType.NORMAL,
icon: IconProp.Add,
onClick: () => {
if (isPushGroupsManaged) {
setShowScimErrorModal(true);
} else {
setShowInviteUserModal(true);
}
},
},
],
}}
noItemsMessage={
isFilterApplied
? "No users found"
: "Please wait, we are refreshing the list of users for this project. Please try again in sometime."
}
query={{
projectId: ProjectUtil.getCurrentProjectId()!,
}}
showRefreshButton={true}
onViewPage={(item: TeamMember) => {
const viewPageRoute: string =
RouteUtil.populateRouteParams(props.pageRoute).toString() +
"/" +
item.user?.id?.toString();
// add user id to the route
return Promise.resolve(new Route(viewPageRoute));
}}
filters={[
{
field: {
team: {
name: true,
},
},
title: "Team",
type: FieldType.Entity,
filterEntityType: Team,
filterQuery: {
projectId: ProjectUtil.getCurrentProjectId()!,
},
filterDropdownField: {
label: "name",
value: "_id",
},
},
{
field: {
hasAcceptedInvitation: true,
},
title: "Status",
type: FieldType.Boolean,
},
]}
columns={[
{
field: {
user: {
name: true,
email: true,
profilePictureId: true,
},
},
title: "User",
type: FieldType.Element,
getElement: (item: TeamMember) => {
if (!item.user) {
return <p>User not found</p>;
}
return <UserElement user={item.user!} />;
},
},
{
field: {
team: {
name: true,
_id: true,
},
},
title: "Team",
type: FieldType.Element,
getElement: (item: TeamMember) => {
if (!item.team) {
return <p>No team assigned</p>;
}
return <TeamElement team={item.team!} />;
},
},
{
field: {
hasAcceptedInvitation: true,
},
title: "Status",
type: FieldType.Element,
getElement: (item: TeamMember) => {
if (item.hasAcceptedInvitation) {
return <Pill text="Member" color={Green} />;
}
return <Pill text="Invitation Sent" color={Yellow} />;
},
},
]}
modelType={TeamMember}
id="teams-table"
name="Settings > Users"
userPreferencesKey="users-table"
isDeleteable={!isPushGroupsManaged}
bulkActions={
!isPushGroupsManaged
? {
buttons: [ModalTableBulkDefaultActions.Delete],
}
: undefined
}
isEditable={false}
isCreateable={false}
onFilterApplied={(isApplied: boolean) => {
setIsFilterApplied(isApplied);
}}
isViewable={true}
onBeforeDelete={async (
item: TeamMember,
): Promise<TeamMember> => {
if (isPushGroupsManaged) {
throw new BadDataException(
"Cannot remove team members while SCIM Push Groups is enabled for this project. Disable Push Groups to manage members from OneUptime.",
);
}
return item;
}}
cardProps={{
title: "Users",
description:
"Here is a list of all the team members in this project.",
buttons: [
{
title: "Invite User",
buttonStyle: ButtonStyleType.NORMAL,
icon: IconProp.Add,
onClick: () => {
if (isPushGroupsManaged) {
setShowScimErrorModal(true);
} else {
setShowInviteUserModal(true);
}
},
},
],
}}
noItemsMessage={
isFilterApplied
? "No users found"
: "Please wait, we are refreshing the list of users for this project. Please try again in sometime."
}
query={{
projectId: ProjectUtil.getCurrentProjectId()!,
}}
showRefreshButton={true}
onViewPage={(item: TeamMember) => {
const viewPageRoute: string =
RouteUtil.populateRouteParams(
props.pageRoute,
).toString() +
"/" +
item.user?.id?.toString();
// add user id to the route
return Promise.resolve(new Route(viewPageRoute));
}}
filters={[
{
field: {
team: {
name: true,
},
},
title: "Team",
type: FieldType.Entity,
filterEntityType: Team,
filterQuery: {
projectId: ProjectUtil.getCurrentProjectId()!,
},
filterDropdownField: {
label: "name",
value: "_id",
},
},
{
field: {
hasAcceptedInvitation: true,
},
title: "Status",
type: FieldType.Boolean,
},
]}
columns={[
{
field: {
user: {
name: true,
email: true,
profilePictureId: true,
},
},
title: "User",
type: FieldType.Element,
getElement: (item: TeamMember) => {
if (!item.user) {
return <p>User not found</p>;
}
return <UserElement user={item.user!} />;
},
},
{
field: {
team: {
name: true,
_id: true,
},
},
title: "Team",
type: FieldType.Element,
getElement: (item: TeamMember) => {
if (!item.team) {
return <p>No team assigned</p>;
}
return <TeamElement team={item.team!} />;
},
},
{
field: {
hasAcceptedInvitation: true,
},
title: "Status",
type: FieldType.Element,
getElement: (item: TeamMember) => {
if (item.hasAcceptedInvitation) {
return <Pill text="Member" color={Green} />;
}
return <Pill text="Invitation Sent" color={Yellow} />;
},
},
]}
/>
{showInviteUserModal && !isPushGroupsManaged && (
<ModelFormModal<TeamMember>

View File

@@ -81,7 +81,10 @@ const UserSettingsCustomFields: FunctionComponent<
newProfile.userId = userId;
const response: HTTPResponse<
JSONObject | JSONArray | ProjectUserProfile | Array<ProjectUserProfile>
| JSONObject
| JSONArray
| ProjectUserProfile
| Array<ProjectUserProfile>
> = await ModelAPI.create<ProjectUserProfile>({
model: newProfile,
modelType: ProjectUserProfile,

View File

@@ -566,9 +566,7 @@ const IncidentsRoutes: FunctionComponent<ComponentProps> = (
/>
<PageRoute
path={
IncidentsRoutePath[PageMap.INCIDENTS_SETTINGS_SLA_RULES] || ""
}
path={IncidentsRoutePath[PageMap.INCIDENTS_SETTINGS_SLA_RULES] || ""}
element={
<Suspense fallback={Loader}>
<IncidentSettingsSlaRules

View File

@@ -94,12 +94,16 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
}
/>
<PageRoute
path={UserSettingsRoutePath[PageMap.USER_SETTINGS_CUSTOM_FIELDS] || ""}
path={
UserSettingsRoutePath[PageMap.USER_SETTINGS_CUSTOM_FIELDS] || ""
}
element={
<Suspense fallback={Loader}>
<UserSettingsCustomFields
{...props}
pageRoute={RouteMap[PageMap.USER_SETTINGS_CUSTOM_FIELDS] as Route}
pageRoute={
RouteMap[PageMap.USER_SETTINGS_CUSTOM_FIELDS] as Route
}
/>
</Suspense>
}

View File

@@ -63,10 +63,11 @@ RunCron(
breachType = "response";
} else if (sla.status === IncidentSlaStatus.OnTrack) {
// Check if at risk for response
const totalResponseTime: number = OneUptimeDate.getDifferenceInMinutes(
sla.responseDeadline,
sla.slaStartedAt,
);
const totalResponseTime: number =
OneUptimeDate.getDifferenceInMinutes(
sla.responseDeadline,
sla.slaStartedAt,
);
const elapsedTime: number = OneUptimeDate.getDifferenceInMinutes(
now,
sla.slaStartedAt,