@oneuptime/common 7.0.3786 → 7.0.3822

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/Models/DatabaseModels/AlertStateTimeline.ts +1 -1
  2. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -1
  3. package/Models/DatabaseModels/MonitorStatusTimeline.ts +1 -1
  4. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -1
  5. package/Models/DatabaseModels/WorkspaceNotificationRule.ts +8 -0
  6. package/Server/API/SlackAPI.ts +68 -0
  7. package/Server/Services/AccessTokenService.ts +21 -0
  8. package/Server/Services/AlertFeedService.ts +98 -0
  9. package/Server/Services/AlertInternalNoteService.ts +49 -8
  10. package/Server/Services/AlertOwnerTeamService.ts +50 -2
  11. package/Server/Services/AlertOwnerUserService.ts +52 -2
  12. package/Server/Services/AlertService.ts +236 -37
  13. package/Server/Services/AlertStateService.ts +24 -0
  14. package/Server/Services/AlertStateTimelineService.ts +30 -2
  15. package/Server/Services/IncidentInternalNoteService.ts +6 -6
  16. package/Server/Services/IncidentPublicNoteService.ts +7 -4
  17. package/Server/Services/IncidentStateTimelineService.ts +2 -1
  18. package/Server/Services/MonitorStatusTimelineService.ts +202 -101
  19. package/Server/Services/ScheduledMaintenanceFeedService.ts +103 -0
  20. package/Server/Services/ScheduledMaintenanceInternalNoteService.ts +50 -6
  21. package/Server/Services/ScheduledMaintenanceOwnerTeamService.ts +37 -0
  22. package/Server/Services/ScheduledMaintenanceOwnerUserService.ts +34 -0
  23. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +49 -7
  24. package/Server/Services/ScheduledMaintenanceService.ts +375 -12
  25. package/Server/Services/ScheduledMaintenanceStateService.ts +122 -34
  26. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +33 -1
  27. package/Server/Services/WorkspaceNotificationRuleService.ts +12 -0
  28. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.ts +38 -0
  29. package/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.ts +116 -0
  30. package/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.ts +36 -115
  31. package/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.ts +108 -0
  32. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +20 -2
  33. package/Server/Utils/Workspace/Slack/Actions/Alert.ts +697 -0
  34. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +9 -2
  35. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +9 -3
  36. package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +956 -0
  37. package/Server/Utils/Workspace/Slack/Messages/Alert.ts +116 -0
  38. package/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.ts +108 -0
  39. package/Server/Utils/Workspace/Slack/Slack.ts +48 -2
  40. package/Server/Utils/Workspace/Slack/app-manifest.json +3 -3
  41. package/Server/Utils/Workspace/WorkspaceBase.ts +14 -0
  42. package/Server/Utils/Workspace/WorkspaceMessages/Alert.ts +69 -0
  43. package/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.ts +73 -0
  44. package/Types/Date.ts +5 -0
  45. package/Types/Workspace/WorkspaceMessagePayload.ts +9 -0
  46. package/UI/Components/Forms/BasicForm.tsx +4 -0
  47. package/UI/Components/Forms/Types/Field.ts +3 -0
  48. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -1
  49. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
  50. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -1
  51. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  52. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js +1 -1
  53. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
  54. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -1
  55. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  56. package/build/dist/Models/DatabaseModels/WorkspaceNotificationRule.js +8 -0
  57. package/build/dist/Models/DatabaseModels/WorkspaceNotificationRule.js.map +1 -1
  58. package/build/dist/Server/API/SlackAPI.js +54 -0
  59. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  60. package/build/dist/Server/Services/AccessTokenService.js +11 -0
  61. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  62. package/build/dist/Server/Services/AlertFeedService.js +60 -0
  63. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  64. package/build/dist/Server/Services/AlertInternalNoteService.js +39 -8
  65. package/build/dist/Server/Services/AlertInternalNoteService.js.map +1 -1
  66. package/build/dist/Server/Services/AlertOwnerTeamService.js +40 -2
  67. package/build/dist/Server/Services/AlertOwnerTeamService.js.map +1 -1
  68. package/build/dist/Server/Services/AlertOwnerUserService.js +41 -3
  69. package/build/dist/Server/Services/AlertOwnerUserService.js.map +1 -1
  70. package/build/dist/Server/Services/AlertService.js +192 -35
  71. package/build/dist/Server/Services/AlertService.js.map +1 -1
  72. package/build/dist/Server/Services/AlertStateService.js +13 -0
  73. package/build/dist/Server/Services/AlertStateService.js.map +1 -1
  74. package/build/dist/Server/Services/AlertStateTimelineService.js +26 -2
  75. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  76. package/build/dist/Server/Services/IncidentInternalNoteService.js +6 -6
  77. package/build/dist/Server/Services/IncidentInternalNoteService.js.map +1 -1
  78. package/build/dist/Server/Services/IncidentPublicNoteService.js +5 -4
  79. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  80. package/build/dist/Server/Services/IncidentStateTimelineService.js +1 -1
  81. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  82. package/build/dist/Server/Services/MonitorStatusTimelineService.js +168 -72
  83. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  84. package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js +60 -0
  85. package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js.map +1 -1
  86. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js +36 -6
  87. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js.map +1 -1
  88. package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js +24 -0
  89. package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js.map +1 -1
  90. package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js +22 -0
  91. package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js.map +1 -1
  92. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +36 -7
  93. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  94. package/build/dist/Server/Services/ScheduledMaintenanceService.js +275 -13
  95. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  96. package/build/dist/Server/Services/ScheduledMaintenanceStateService.js +52 -4
  97. package/build/dist/Server/Services/ScheduledMaintenanceStateService.js.map +1 -1
  98. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +28 -1
  99. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  100. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +10 -0
  101. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  102. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js +37 -0
  103. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js.map +1 -0
  104. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.js +82 -0
  105. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.js.map +1 -0
  106. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js +33 -99
  107. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js.map +1 -1
  108. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.js +74 -0
  109. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.js.map +1 -0
  110. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +20 -2
  111. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
  112. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +425 -0
  113. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -0
  114. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +2 -0
  115. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
  116. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +5 -2
  117. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
  118. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +599 -0
  119. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -0
  120. package/build/dist/Server/Utils/Workspace/Slack/Messages/Alert.js +82 -0
  121. package/build/dist/Server/Utils/Workspace/Slack/Messages/Alert.js.map +1 -0
  122. package/build/dist/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.js +74 -0
  123. package/build/dist/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.js.map +1 -0
  124. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +34 -0
  125. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  126. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +3 -3
  127. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +8 -0
  128. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  129. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Alert.js +48 -0
  130. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Alert.js.map +1 -0
  131. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.js +47 -0
  132. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.js.map +1 -0
  133. package/build/dist/Types/Date.js +4 -0
  134. package/build/dist/Types/Date.js.map +1 -1
  135. package/build/dist/UI/Components/Forms/BasicForm.js +3 -0
  136. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  137. package/package.json +2 -2
@@ -47,6 +47,10 @@ import AlertSeverity from "../../Models/DatabaseModels/AlertSeverity";
47
47
  import AlertSeverityService from "./AlertSeverityService";
48
48
  import WorkspaceType from "../../Types/Workspace/WorkspaceType";
49
49
  import NotificationRuleWorkspaceChannel from "../../Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel";
50
+ import AlertWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/Alert";
51
+ import Monitor from "../../Models/DatabaseModels/Monitor";
52
+ import MonitorService from "./MonitorService";
53
+ import { MessageBlocksByWorkspaceType } from "./WorkspaceNotificationRuleService";
50
54
 
51
55
  export class Service extends DatabaseService<Model> {
52
56
  public constructor() {
@@ -260,46 +264,125 @@ export class Service extends DatabaseService<Model> {
260
264
  throw new BadDataException("currentAlertStateId is required");
261
265
  }
262
266
 
267
+ const alert: Model | null = await this.findOneById({
268
+ id: createdItem.id,
269
+ select: {
270
+ projectId: true,
271
+ alertNumber: true,
272
+ title: true,
273
+ description: true,
274
+ alertSeverity: {
275
+ name: true,
276
+ },
277
+ rootCause: true,
278
+ remediationNotes: true,
279
+ currentAlertState: {
280
+ name: true,
281
+ },
282
+ monitor: {
283
+ name: true,
284
+ _id: true,
285
+ },
286
+ },
287
+ props: {
288
+ isRoot: true,
289
+ },
290
+ });
291
+
292
+ if (!alert) {
293
+ throw new BadDataException("Alert not found");
294
+ }
295
+
263
296
  const createdByUserId: ObjectID | undefined | null =
264
297
  createdItem.createdByUserId || createdItem.createdByUser?.id;
265
298
 
266
- await AlertFeedService.createAlertFeedItem({
267
- alertId: createdItem.id!,
268
- projectId: createdItem.projectId!,
269
- alertFeedEventType: AlertFeedEventType.AlertCreated,
270
- displayColor: Red500,
271
- feedInfoInMarkdown: `**Alert #${createdItem.alertNumber?.toString()} Created**:
272
-
273
- **Alert Title**:
274
-
275
- ${createdItem.title || "No title provided."}
276
-
277
- **Description**:
278
-
279
- ${createdItem.description || "No description provided."}
280
-
281
- `,
282
- userId: createdByUserId || undefined,
283
- });
299
+ // send message to workspaces - slack, teams, etc.
300
+ const workspaceResult: {
301
+ channelsCreated: Array<NotificationRuleWorkspaceChannel>;
302
+ } | null =
303
+ await AlertWorkspaceMessages.createChannelsAndInviteUsersToChannels({
304
+ projectId: createdItem.projectId,
305
+ alertId: createdItem.id!,
306
+ alertNumber: createdItem.alertNumber!,
307
+ });
284
308
 
285
- await AlertFeedService.createAlertFeedItem({
286
- alertId: createdItem.id!,
287
- projectId: createdItem.projectId!,
288
- alertFeedEventType: AlertFeedEventType.RootCause,
289
- displayColor: Red500,
290
- feedInfoInMarkdown: `**Root Cause**
291
-
292
- ${createdItem.rootCause || "No root cause provided."}`,
293
- });
309
+ logger.debug("Alert created. Workspace result:");
310
+ logger.debug(workspaceResult);
311
+
312
+ if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
313
+ // update alert with these channels.
314
+ await this.updateOneById({
315
+ id: createdItem.id!,
316
+ data: {
317
+ postUpdatesToWorkspaceChannels: workspaceResult.channelsCreated || [],
318
+ },
319
+ props: {
320
+ isRoot: true,
321
+ },
322
+ });
323
+ }
324
+
325
+ let feedInfoInMarkdown: string = `#### 🚨 Alert ${createdItem.alertNumber?.toString()} Created:
326
+
327
+ **${createdItem.title || "No title provided."}**:
328
+
329
+ ${createdItem.description || "No description provided."}
330
+
331
+ `;
332
+
333
+ if (alert.currentAlertState?.name) {
334
+ feedInfoInMarkdown += `🔴 **Alert State**: ${alert.currentAlertState.name} \n\n`;
335
+ }
336
+
337
+ if (alert.alertSeverity?.name) {
338
+ feedInfoInMarkdown += `⚠️ **Severity**: ${alert.alertSeverity.name} \n\n`;
339
+ }
340
+
341
+ if (alert.monitor) {
342
+ feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
343
+
344
+ const monitor: Monitor = alert.monitor;
345
+ feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(createdItem.projectId!, monitor.id!)).toString()})\n`;
346
+
347
+ feedInfoInMarkdown += `\n\n`;
348
+ }
349
+
350
+ if (createdItem.rootCause) {
351
+ feedInfoInMarkdown += `\n
352
+ 📄 **Root Cause**:
353
+
354
+ ${createdItem.rootCause || "No root cause provided."}
355
+
356
+ `;
357
+ }
358
+
359
+ if (createdItem.remediationNotes) {
360
+ feedInfoInMarkdown += `\n
361
+ 🎯 **Remediation Notes**:
362
+
363
+ ${createdItem.remediationNotes || "No remediation notes provided."}
364
+
365
+
366
+ `;
367
+ }
368
+
369
+ const alertCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
370
+ await AlertWorkspaceMessages.getAlertCreateMessageBlocks({
371
+ alertId: createdItem.id!,
372
+ projectId: createdItem.projectId!,
373
+ });
294
374
 
295
375
  await AlertFeedService.createAlertFeedItem({
296
376
  alertId: createdItem.id!,
297
377
  projectId: createdItem.projectId!,
298
- alertFeedEventType: AlertFeedEventType.RemediationNotes,
378
+ alertFeedEventType: AlertFeedEventType.AlertCreated,
299
379
  displayColor: Red500,
300
- feedInfoInMarkdown: `**Remediation Notes**
301
-
302
- ${createdItem.remediationNotes || "No remediation notes provided."}`,
380
+ feedInfoInMarkdown: feedInfoInMarkdown,
381
+ userId: createdByUserId || undefined,
382
+ workspaceNotification: {
383
+ appendMessageBlocks: alertCreateMessageBlocks,
384
+ sendWorkspaceNotification: true,
385
+ },
303
386
  });
304
387
 
305
388
  await this.changeAlertState({
@@ -366,7 +449,7 @@ ${createdItem.remediationNotes || "No remediation notes provided."}`,
366
449
  });
367
450
 
368
451
  if (!alert) {
369
- throw new BadDataException("Incident not found.");
452
+ throw new BadDataException("Alert not found.");
370
453
  }
371
454
 
372
455
  return (alert.postUpdatesToWorkspaceChannels || []).filter(
@@ -555,7 +638,22 @@ ${createdItem.remediationNotes || "No remediation notes provided."}`,
555
638
  if (updatedItemIds.length > 0) {
556
639
  for (const alertId of updatedItemIds) {
557
640
  let shouldAddAlertFeed: boolean = false;
558
- let feedInfoInMarkdown: string = "**Alert was updated.**";
641
+
642
+ const alert: Model | null = await this.findOneById({
643
+ id: alertId,
644
+ select: {
645
+ projectId: true,
646
+ alertNumber: true,
647
+ },
648
+ props: {
649
+ isRoot: true,
650
+ },
651
+ });
652
+
653
+ const projectId: ObjectID = alert!.projectId!;
654
+ const alertNumber: number = alert!.alertNumber!;
655
+
656
+ let feedInfoInMarkdown: string = `**[Alert ${alertNumber}](${(await this.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) was updated.**`;
559
657
 
560
658
  const createdByUserId: ObjectID | undefined | null =
561
659
  onUpdate.updateBy.props.userId;
@@ -573,7 +671,7 @@ ${onUpdate.updateBy.data.title || "No title provided."}
573
671
  if (onUpdate.updateBy.data.title) {
574
672
  // add alert feed.
575
673
 
576
- feedInfoInMarkdown += `\n\n**Root Cause**:
674
+ feedInfoInMarkdown += `\n\n**📄 Root Cause**:
577
675
  ${onUpdate.updateBy.data.rootCause || "No root cause provided."}
578
676
  `;
579
677
  shouldAddAlertFeed = true;
@@ -592,7 +690,7 @@ ${onUpdate.updateBy.data.rootCause || "No root cause provided."}
592
690
  if (onUpdate.updateBy.data.remediationNotes) {
593
691
  // add alert feed.
594
692
 
595
- feedInfoInMarkdown += `\n\n**Remediation Notes**:
693
+ feedInfoInMarkdown += `\n\n**🎯 Remediation Notes**:
596
694
  ${onUpdate.updateBy.data.remediationNotes || "No remediation notes provided."}
597
695
  `;
598
696
  shouldAddAlertFeed = true;
@@ -632,7 +730,7 @@ ${onUpdate.updateBy.data.remediationNotes || "No remediation notes provided."}
632
730
  });
633
731
 
634
732
  if (labels.length > 0) {
635
- feedInfoInMarkdown += `\n\n**Labels**:
733
+ feedInfoInMarkdown += `\n\n**🏷️ Labels**:
636
734
 
637
735
  ${labels
638
736
  .map((label: Label) => {
@@ -665,7 +763,7 @@ ${labels
665
763
  });
666
764
 
667
765
  if (alertSeverity) {
668
- feedInfoInMarkdown += `\n\n**Alert Severity**:
766
+ feedInfoInMarkdown += `\n\n**⚠️ Alert Severity**:
669
767
  ${alertSeverity.name}
670
768
  `;
671
769
 
@@ -681,6 +779,9 @@ ${alertSeverity.name}
681
779
  displayColor: Gray500,
682
780
  feedInfoInMarkdown: feedInfoInMarkdown,
683
781
  userId: createdByUserId || undefined,
782
+ workspaceNotification: {
783
+ sendWorkspaceNotification: true,
784
+ },
684
785
  });
685
786
  }
686
787
  }
@@ -1076,6 +1177,48 @@ ${alertSeverity.name}
1076
1177
  });
1077
1178
  }
1078
1179
 
1180
+ public async isAlertResolved(data: { alertId: ObjectID }): Promise<boolean> {
1181
+ const alert: Model | null = await this.findOneBy({
1182
+ query: {
1183
+ _id: data.alertId,
1184
+ },
1185
+ select: {
1186
+ projectId: true,
1187
+ currentAlertState: {
1188
+ order: true,
1189
+ },
1190
+ },
1191
+ props: {
1192
+ isRoot: true,
1193
+ },
1194
+ });
1195
+
1196
+ if (!alert) {
1197
+ throw new BadDataException("Alert not found");
1198
+ }
1199
+
1200
+ if (!alert.projectId) {
1201
+ throw new BadDataException("Incient Project ID not found");
1202
+ }
1203
+
1204
+ const resolvedAlertState: AlertState =
1205
+ await AlertStateService.getResolvedAlertState({
1206
+ projectId: alert.projectId,
1207
+ props: {
1208
+ isRoot: true,
1209
+ },
1210
+ });
1211
+
1212
+ const currentAlertStateOrder: number = alert.currentAlertState!.order!;
1213
+ const resolvedAlertStateOrder: number = resolvedAlertState.order!;
1214
+
1215
+ if (currentAlertStateOrder >= resolvedAlertStateOrder) {
1216
+ return true;
1217
+ }
1218
+
1219
+ return false;
1220
+ }
1221
+
1079
1222
  public async getAlertNumber(data: {
1080
1223
  alertId: ObjectID;
1081
1224
  }): Promise<number | null> {
@@ -1095,5 +1238,61 @@ ${alertSeverity.name}
1095
1238
 
1096
1239
  return alert.alertNumber || null;
1097
1240
  }
1241
+
1242
+ public async resolveAlert(
1243
+ alertId: ObjectID,
1244
+ resolvedByUserId: ObjectID,
1245
+ ): Promise<Model> {
1246
+ const alert: Model | null = await this.findOneById({
1247
+ id: alertId,
1248
+ select: {
1249
+ projectId: true,
1250
+ alertNumber: true,
1251
+ },
1252
+ props: {
1253
+ isRoot: true,
1254
+ },
1255
+ });
1256
+
1257
+ if (!alert || !alert.projectId) {
1258
+ throw new BadDataException("Alert not found.");
1259
+ }
1260
+
1261
+ const alertState: AlertState | null = await AlertStateService.findOneBy({
1262
+ query: {
1263
+ projectId: alert.projectId,
1264
+ isResolvedState: true,
1265
+ },
1266
+ select: {
1267
+ _id: true,
1268
+ },
1269
+ props: {
1270
+ isRoot: true,
1271
+ },
1272
+ });
1273
+
1274
+ if (!alertState || !alertState.id) {
1275
+ throw new BadDataException(
1276
+ "Acknowledged state not found for this project. Please add acknowledged state from settings.",
1277
+ );
1278
+ }
1279
+
1280
+ const alertStateTimeline: AlertStateTimeline = new AlertStateTimeline();
1281
+ alertStateTimeline.projectId = alert.projectId;
1282
+ alertStateTimeline.alertId = alertId;
1283
+ alertStateTimeline.alertStateId = alertState.id;
1284
+ alertStateTimeline.createdByUserId = resolvedByUserId;
1285
+
1286
+ await AlertStateTimelineService.create({
1287
+ data: alertStateTimeline,
1288
+ props: {
1289
+ isRoot: true,
1290
+ },
1291
+ });
1292
+
1293
+ // store alert metric
1294
+
1295
+ return alert;
1296
+ }
1098
1297
  }
1099
1298
  export default new Service();
@@ -200,6 +200,30 @@ export class Service extends DatabaseService<AlertState> {
200
200
  return unresolvedAlertStates;
201
201
  }
202
202
 
203
+ public async getResolvedAlertState(data: {
204
+ projectId: ObjectID;
205
+ props: DatabaseCommonInteractionProps;
206
+ }): Promise<AlertState> {
207
+ const alertStates: Array<AlertState> = await this.getAllAlertStates({
208
+ projectId: data.projectId,
209
+ props: data.props,
210
+ });
211
+
212
+ const resolvedAlertState: AlertState | undefined = alertStates.find(
213
+ (alertState: AlertState) => {
214
+ return alertState?.isResolvedState;
215
+ },
216
+ );
217
+
218
+ if (!resolvedAlertState) {
219
+ throw new BadDataException(
220
+ "Resolved Alert State not found for this project",
221
+ );
222
+ }
223
+
224
+ return resolvedAlertState;
225
+ }
226
+
203
227
  public async getAcknowledgedAlertState(data: {
204
228
  projectId: ObjectID;
205
229
  props: DatabaseCommonInteractionProps;
@@ -179,16 +179,44 @@ export class Service extends DatabaseService<AlertStateTimeline> {
179
179
  });
180
180
 
181
181
  const stateName: string = alertState?.name || "";
182
+ let stateEmoji: string = "➡️";
183
+
184
+ // if resolved state then change emoji to ✅.
185
+
186
+ if (alertState?.isResolvedState) {
187
+ stateEmoji = "✅";
188
+ } else if (alertState?.isAcknowledgedState) {
189
+ // eyes emoji for acknowledged state.
190
+ stateEmoji = "👀";
191
+ } else if (alertState?.isCreatedState) {
192
+ stateEmoji = "🔴";
193
+ }
194
+
195
+ const alertNumber: number | null = await AlertService.getAlertNumber({
196
+ alertId: createdItem.alertId,
197
+ });
198
+
199
+ const projectId: ObjectID = createdItem.projectId!;
200
+ const alertId: ObjectID = createdItem.alertId!;
182
201
 
183
202
  await AlertFeedService.createAlertFeedItem({
184
203
  alertId: createdItem.alertId!,
185
204
  projectId: createdItem.projectId!,
186
205
  alertFeedEventType: AlertFeedEventType.AlertStateChanged,
187
206
  displayColor: alertState?.color,
188
- feedInfoInMarkdown: "**Alert State** changed to **" + stateName + "**",
207
+ feedInfoInMarkdown:
208
+ stateEmoji +
209
+ ` Changed **[Alert ${alertNumber}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) State** to **` +
210
+ stateName +
211
+ "**",
189
212
  moreInformationInMarkdown: `**Cause:**
190
- ${createdItem.rootCause}`,
213
+ ${createdItem.rootCause}`,
191
214
  userId: createdItem.createdByUserId || onCreate.createBy.props.userId,
215
+ workspaceNotification: {
216
+ sendWorkspaceNotification: true,
217
+ notifyUserId:
218
+ createdItem.createdByUserId || onCreate.createBy.props.userId,
219
+ },
192
220
  });
193
221
 
194
222
  await AlertService.updateOneBy({
@@ -20,14 +20,14 @@ export class Service extends DatabaseService<Model> {
20
20
  projectId: ObjectID;
21
21
  note: string;
22
22
  }): Promise<Model> {
23
- const publicNote: Model = new Model();
24
- publicNote.createdByUserId = data.userId;
25
- publicNote.incidentId = data.incidentId;
26
- publicNote.projectId = data.projectId;
27
- publicNote.note = data.note;
23
+ const internalNote: Model = new Model();
24
+ internalNote.createdByUserId = data.userId;
25
+ internalNote.incidentId = data.incidentId;
26
+ internalNote.projectId = data.projectId;
27
+ internalNote.note = data.note;
28
28
 
29
29
  return this.create({
30
- data: publicNote,
30
+ data: internalNote,
31
31
  props: {
32
32
  isRoot: true,
33
33
  },
@@ -9,6 +9,7 @@ import { Blue500, Indigo500 } from "../../Types/BrandColors";
9
9
  import ObjectID from "../../Types/ObjectID";
10
10
  import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
11
11
  import IncidentService from "./IncidentService";
12
+ import Incident from "../../Models/DatabaseModels/Incident";
12
13
 
13
14
  export class Service extends DatabaseService<Model> {
14
15
  public constructor() {
@@ -109,17 +110,19 @@ ${createdItem.note}
109
110
  onUpdate.updateBy.props.userId;
110
111
 
111
112
  for (const updatedItem of updatedItems) {
113
+ const incident: Incident = updatedItem.incident!;
114
+
112
115
  await IncidentFeedService.createIncidentFeedItem({
113
116
  incidentId: updatedItem.incidentId!,
114
117
  projectId: updatedItem.projectId!,
115
- incidentFeedEventType: IncidentFeedEventType.PublicNote,
118
+ incidentFeedEventType: IncidentFeedEventType.PrivateNote,
116
119
  displayColor: Blue500,
117
120
  userId: userId || undefined,
118
121
 
119
- feedInfoInMarkdown: `📄 **Updated Public Note**
120
-
122
+ feedInfoInMarkdown: `📄 updated **Public Note** for this [Incident ${incident.incidentNumber}](${(await IncidentService.getIncidentLinkInDashboard(incident.projectId!, incident.id!)).toString()})
123
+
121
124
  ${updatedItem.note}
122
- `,
125
+ `,
123
126
  workspaceNotification: {
124
127
  sendWorkspaceNotification: true,
125
128
  notifyUserId: userId || undefined,
@@ -221,7 +221,8 @@ ${createdItem.rootCause}`,
221
221
  userId: createdItem.createdByUserId || onCreate.createBy.props.userId,
222
222
  workspaceNotification: {
223
223
  sendWorkspaceNotification: true,
224
- notifyUserId: createdItem.createdByUserId,
224
+ notifyUserId:
225
+ createdItem.createdByUserId || onCreate.createBy.props.userId,
225
226
  },
226
227
  });
227
228