@oneuptime/common 7.0.3717 → 7.0.3786

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 (203) hide show
  1. package/Models/DatabaseModels/Alert.ts +3 -2
  2. package/Models/DatabaseModels/Incident.ts +3 -2
  3. package/Models/DatabaseModels/Index.ts +3 -0
  4. package/Models/DatabaseModels/ProjectUser.ts +335 -0
  5. package/Models/DatabaseModels/ScheduledMaintenance.ts +3 -2
  6. package/Server/API/SlackAPI.ts +65 -97
  7. package/Server/API/UserOnCallLogTimelineAPI.ts +2 -9
  8. package/Server/Infrastructure/Postgres/SchemaMigrations/1740597525803-MigrationName.ts +17 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1740598793630-MigrationName.ts +17 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/1741031019972-MigrationName.ts +17 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1741209339971-MigrationName.ts +101 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  13. package/Server/Middleware/SlackAuthorization.ts +11 -2
  14. package/Server/Services/AlertFeedService.ts +2 -2
  15. package/Server/Services/AlertInternalNoteService.ts +2 -2
  16. package/Server/Services/AlertOwnerTeamService.ts +4 -4
  17. package/Server/Services/AlertOwnerUserService.ts +3 -3
  18. package/Server/Services/AlertService.ts +62 -20
  19. package/Server/Services/AlertStateTimelineService.ts +8 -18
  20. package/Server/Services/IncidentFeedService.ts +101 -2
  21. package/Server/Services/IncidentInternalNoteService.ts +47 -4
  22. package/Server/Services/IncidentOwnerTeamService.ts +57 -4
  23. package/Server/Services/IncidentOwnerUserService.ts +59 -15
  24. package/Server/Services/IncidentPublicNoteService.ts +41 -4
  25. package/Server/Services/IncidentService.ts +279 -193
  26. package/Server/Services/IncidentStateService.ts +25 -0
  27. package/Server/Services/IncidentStateTimelineService.ts +37 -19
  28. package/Server/Services/MonitorStatusTimelineService.ts +7 -17
  29. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -0
  30. package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +74 -7
  31. package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +63 -4
  32. package/Server/Services/OnCallDutyPolicyService.ts +13 -0
  33. package/Server/Services/ProjectUserService.ts +130 -0
  34. package/Server/Services/ScheduledMaintenanceFeedService.ts +2 -2
  35. package/Server/Services/ScheduledMaintenanceInternalNoteService.ts +12 -10
  36. package/Server/Services/ScheduledMaintenanceOwnerTeamService.ts +22 -18
  37. package/Server/Services/ScheduledMaintenanceOwnerUserService.ts +28 -30
  38. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +12 -10
  39. package/Server/Services/ScheduledMaintenanceService.ts +16 -10
  40. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +1 -1
  41. package/Server/Services/StatusPageSubscriberService.ts +3 -0
  42. package/Server/Services/TeamMemberService.ts +20 -0
  43. package/Server/Services/UserNotificationRuleService.ts +74 -0
  44. package/Server/Services/UserOnCallLogService.ts +1 -1
  45. package/Server/Services/UserService.ts +35 -0
  46. package/Server/Services/WorkspaceNotificationRuleService.ts +508 -149
  47. package/Server/Services/WorkspaceUserAuthTokenService.ts +23 -0
  48. package/Server/Utils/Express.ts +1 -1
  49. package/Server/Utils/StartServer.ts +6 -1
  50. package/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.ts +195 -0
  51. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +20 -0
  52. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +266 -0
  53. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +1117 -0
  54. package/Server/Utils/Workspace/Slack/Messages/Incident.ts +116 -0
  55. package/Server/Utils/Workspace/Slack/Slack.ts +555 -18
  56. package/Server/Utils/Workspace/Slack/app-manifest.json +18 -10
  57. package/Server/Utils/Workspace/Workspace.ts +194 -1
  58. package/Server/Utils/Workspace/WorkspaceBase.ts +145 -19
  59. package/Server/Utils/Workspace/WorkspaceMessages/Incident.ts +68 -0
  60. package/Types/Icon/IconProp.ts +1 -0
  61. package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +2 -1
  62. package/Types/Workspace/NotificationRules/NotificationRuleUtil.ts +251 -121
  63. package/Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel.ts +6 -0
  64. package/Types/Workspace/WorkspaceMessagePayload.ts +71 -2
  65. package/UI/Components/ComingSoon/ComingSoon.tsx +13 -3
  66. package/UI/Components/Forms/Fields/FormField.tsx +2 -2
  67. package/UI/Components/Icon/Icon.tsx +39 -2
  68. package/UI/Components/ModelTable/BaseModelTable.tsx +16 -0
  69. package/UI/Components/Radio/Radio.tsx +11 -2
  70. package/UI/Components/Table/TableCard.tsx +2 -2
  71. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  72. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  73. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  74. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  75. package/build/dist/Models/DatabaseModels/ProjectUser.js +340 -0
  76. package/build/dist/Models/DatabaseModels/ProjectUser.js.map +1 -0
  77. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  78. package/build/dist/Server/API/SlackAPI.js +39 -79
  79. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  80. package/build/dist/Server/API/UserOnCallLogTimelineAPI.js.map +1 -1
  81. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1740597525803-MigrationName.js +12 -0
  82. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1740597525803-MigrationName.js.map +1 -0
  83. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1740598793630-MigrationName.js +12 -0
  84. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1740598793630-MigrationName.js.map +1 -0
  85. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1741031019972-MigrationName.js +12 -0
  86. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1741031019972-MigrationName.js.map +1 -0
  87. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1741209339971-MigrationName.js +42 -0
  88. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1741209339971-MigrationName.js.map +1 -0
  89. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  90. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  91. package/build/dist/Server/Middleware/SlackAuthorization.js +8 -2
  92. package/build/dist/Server/Middleware/SlackAuthorization.js.map +1 -1
  93. package/build/dist/Server/Services/AlertFeedService.js +2 -2
  94. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  95. package/build/dist/Server/Services/AlertInternalNoteService.js +2 -2
  96. package/build/dist/Server/Services/AlertInternalNoteService.js.map +1 -1
  97. package/build/dist/Server/Services/AlertOwnerTeamService.js +4 -4
  98. package/build/dist/Server/Services/AlertOwnerTeamService.js.map +1 -1
  99. package/build/dist/Server/Services/AlertOwnerUserService.js +3 -3
  100. package/build/dist/Server/Services/AlertOwnerUserService.js.map +1 -1
  101. package/build/dist/Server/Services/AlertService.js +44 -19
  102. package/build/dist/Server/Services/AlertService.js.map +1 -1
  103. package/build/dist/Server/Services/AlertStateTimelineService.js +6 -16
  104. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  105. package/build/dist/Server/Services/IncidentFeedService.js +62 -2
  106. package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
  107. package/build/dist/Server/Services/IncidentInternalNoteService.js +35 -4
  108. package/build/dist/Server/Services/IncidentInternalNoteService.js.map +1 -1
  109. package/build/dist/Server/Services/IncidentOwnerTeamService.js +42 -4
  110. package/build/dist/Server/Services/IncidentOwnerTeamService.js.map +1 -1
  111. package/build/dist/Server/Services/IncidentOwnerUserService.js +43 -15
  112. package/build/dist/Server/Services/IncidentOwnerUserService.js.map +1 -1
  113. package/build/dist/Server/Services/IncidentPublicNoteService.js +32 -4
  114. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  115. package/build/dist/Server/Services/IncidentService.js +221 -170
  116. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  117. package/build/dist/Server/Services/IncidentStateService.js +14 -0
  118. package/build/dist/Server/Services/IncidentStateService.js.map +1 -1
  119. package/build/dist/Server/Services/IncidentStateTimelineService.js +31 -17
  120. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  121. package/build/dist/Server/Services/MonitorStatusTimelineService.js +5 -15
  122. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  123. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +1 -0
  124. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  125. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +62 -7
  126. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
  127. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +51 -5
  128. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
  129. package/build/dist/Server/Services/OnCallDutyPolicyService.js +6 -0
  130. package/build/dist/Server/Services/OnCallDutyPolicyService.js.map +1 -1
  131. package/build/dist/Server/Services/ProjectUserService.js +106 -0
  132. package/build/dist/Server/Services/ProjectUserService.js.map +1 -0
  133. package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js +2 -2
  134. package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js.map +1 -1
  135. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js +2 -2
  136. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js.map +1 -1
  137. package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js +4 -4
  138. package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js.map +1 -1
  139. package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js +8 -16
  140. package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js.map +1 -1
  141. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +2 -2
  142. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  143. package/build/dist/Server/Services/ScheduledMaintenanceService.js +5 -2
  144. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  145. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +1 -1
  146. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  147. package/build/dist/Server/Services/StatusPageSubscriberService.js +3 -0
  148. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  149. package/build/dist/Server/Services/TeamMemberService.js +17 -0
  150. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  151. package/build/dist/Server/Services/UserNotificationRuleService.js +52 -0
  152. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  153. package/build/dist/Server/Services/UserOnCallLogService.js +1 -1
  154. package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
  155. package/build/dist/Server/Services/UserService.js +23 -0
  156. package/build/dist/Server/Services/UserService.js.map +1 -1
  157. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +306 -84
  158. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  159. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js +18 -0
  160. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js.map +1 -1
  161. package/build/dist/Server/Utils/StartServer.js +4 -0
  162. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  163. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js +148 -0
  164. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js.map +1 -0
  165. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +19 -0
  166. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -0
  167. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +167 -0
  168. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -0
  169. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +727 -0
  170. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -0
  171. package/build/dist/Server/Utils/Workspace/Slack/Messages/Incident.js +82 -0
  172. package/build/dist/Server/Utils/Workspace/Slack/Messages/Incident.js.map +1 -0
  173. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +397 -14
  174. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  175. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +18 -10
  176. package/build/dist/Server/Utils/Workspace/Workspace.js +126 -0
  177. package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
  178. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +69 -11
  179. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  180. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Incident.js +47 -0
  181. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Incident.js.map +1 -0
  182. package/build/dist/Types/Icon/IconProp.js +1 -0
  183. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  184. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +2 -1
  185. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
  186. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleUtil.js +214 -120
  187. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleUtil.js.map +1 -1
  188. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel.js +2 -0
  189. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel.js.map +1 -0
  190. package/build/dist/UI/Components/ComingSoon/ComingSoon.js +3 -2
  191. package/build/dist/UI/Components/ComingSoon/ComingSoon.js.map +1 -1
  192. package/build/dist/UI/Components/Forms/Fields/FormField.js +2 -2
  193. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  194. package/build/dist/UI/Components/Icon/Icon.js +19 -2
  195. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  196. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +11 -0
  197. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  198. package/build/dist/UI/Components/Radio/Radio.js +5 -2
  199. package/build/dist/UI/Components/Radio/Radio.js.map +1 -1
  200. package/build/dist/UI/Components/Table/TableCard.js +2 -2
  201. package/build/dist/UI/Components/Table/TableCard.js.map +1 -1
  202. package/package.json +3 -2
  203. package/Server/Utils/Workspace/Slack/app-manifest.example.json +0 -198
@@ -54,13 +54,10 @@ import Label from "../../Models/DatabaseModels/Label";
54
54
  import LabelService from "./LabelService";
55
55
  import IncidentSeverity from "../../Models/DatabaseModels/IncidentSeverity";
56
56
  import IncidentSeverityService from "./IncidentSeverityService";
57
- import {
58
- WorkspaceMessageBlock,
59
- WorkspacePayloadMarkdown,
60
- } from "../../Types/Workspace/WorkspaceMessagePayload";
61
- import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService";
62
- import NotificationRuleEventType from "../../Types/Workspace/NotificationRules/EventType";
63
- import { WorkspaceChannel } from "../Utils/Workspace/WorkspaceBase";
57
+ import IncidentWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/Incident";
58
+ import WorkspaceType from "../../Types/Workspace/WorkspaceType";
59
+ import { MessageBlocksByWorkspaceType } from "./WorkspaceNotificationRuleService";
60
+ import NotificationRuleWorkspaceChannel from "../../Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel";
64
61
 
65
62
  export class Service extends DatabaseService<Model> {
66
63
  public constructor() {
@@ -70,6 +67,51 @@ export class Service extends DatabaseService<Model> {
70
67
  }
71
68
  }
72
69
 
70
+ public async isIncidentResolved(data: {
71
+ incidentId: ObjectID;
72
+ }): Promise<boolean> {
73
+ const incident: Model | null = await this.findOneBy({
74
+ query: {
75
+ _id: data.incidentId,
76
+ },
77
+ select: {
78
+ projectId: true,
79
+ currentIncidentState: {
80
+ order: true,
81
+ },
82
+ },
83
+ props: {
84
+ isRoot: true,
85
+ },
86
+ });
87
+
88
+ if (!incident) {
89
+ throw new BadDataException("Incident not found");
90
+ }
91
+
92
+ if (!incident.projectId) {
93
+ throw new BadDataException("Incient Project ID not found");
94
+ }
95
+
96
+ const resolvedIncidentState: IncidentState =
97
+ await IncidentStateService.getResolvedIncidentState({
98
+ projectId: incident.projectId,
99
+ props: {
100
+ isRoot: true,
101
+ },
102
+ });
103
+
104
+ const currentIncidentStateOrder: number =
105
+ incident.currentIncidentState!.order!;
106
+ const resolvedIncidentStateOrder: number = resolvedIncidentState.order!;
107
+
108
+ if (currentIncidentStateOrder >= resolvedIncidentStateOrder) {
109
+ return true;
110
+ }
111
+
112
+ return false;
113
+ }
114
+
73
115
  public async isIncidentAcknowledged(data: {
74
116
  incidentId: ObjectID;
75
117
  }): Promise<boolean> {
@@ -115,14 +157,73 @@ export class Service extends DatabaseService<Model> {
115
157
  return false;
116
158
  }
117
159
 
160
+ public async resolveIncident(
161
+ incidentId: ObjectID,
162
+ resolvedByUserId: ObjectID,
163
+ ): Promise<Model> {
164
+ const incident: Model | null = await this.findOneById({
165
+ id: incidentId,
166
+ select: {
167
+ projectId: true,
168
+ incidentNumber: true,
169
+ },
170
+ props: {
171
+ isRoot: true,
172
+ },
173
+ });
174
+
175
+ if (!incident || !incident.projectId) {
176
+ throw new BadDataException("Incident not found.");
177
+ }
178
+
179
+ const incidentState: IncidentState | null =
180
+ await IncidentStateService.findOneBy({
181
+ query: {
182
+ projectId: incident.projectId,
183
+ isResolvedState: true,
184
+ },
185
+ select: {
186
+ _id: true,
187
+ },
188
+ props: {
189
+ isRoot: true,
190
+ },
191
+ });
192
+
193
+ if (!incidentState || !incidentState.id) {
194
+ throw new BadDataException(
195
+ "Acknowledged state not found for this project. Please add acknowledged state from settings.",
196
+ );
197
+ }
198
+
199
+ const incidentStateTimeline: IncidentStateTimeline =
200
+ new IncidentStateTimeline();
201
+ incidentStateTimeline.projectId = incident.projectId;
202
+ incidentStateTimeline.incidentId = incidentId;
203
+ incidentStateTimeline.incidentStateId = incidentState.id;
204
+ incidentStateTimeline.createdByUserId = resolvedByUserId;
205
+
206
+ await IncidentStateTimelineService.create({
207
+ data: incidentStateTimeline,
208
+ props: {
209
+ isRoot: true,
210
+ },
211
+ });
212
+
213
+ // store incident metric
214
+
215
+ return incident;
216
+ }
217
+
118
218
  public async acknowledgeIncident(
119
219
  incidentId: ObjectID,
120
220
  acknowledgedByUserId: ObjectID,
121
- ): Promise<void> {
221
+ ): Promise<Model> {
122
222
  const incident: Model | null = await this.findOneById({
123
223
  id: incidentId,
124
224
  select: {
125
225
  projectId: true,
226
+ incidentNumber: true,
126
227
  },
127
228
  props: {
128
229
  isRoot: true,
@@ -168,6 +269,8 @@ export class Service extends DatabaseService<Model> {
168
269
  });
169
270
 
170
271
  // store incident metric
272
+
273
+ return incident;
171
274
  }
172
275
 
173
276
  public async getExistingIncidentNumberForProject(data: {
@@ -276,22 +379,13 @@ export class Service extends DatabaseService<Model> {
276
379
  userId = createBy.data.createdByUser.id;
277
380
  }
278
381
 
279
- const user: User | null = await UserService.findOneBy({
280
- query: {
281
- _id: userId?.toString() as string,
282
- },
283
- select: {
284
- _id: true,
285
- name: true,
286
- email: true,
287
- },
288
- props: {
289
- isRoot: true,
290
- },
291
- });
292
-
293
- if (user) {
294
- createBy.data.rootCause = `Incident created by ${user.name} (${user.email})`;
382
+ if (userId) {
383
+ createBy.data.rootCause = `Incident created by ${await UserService.getUserMarkdownString(
384
+ {
385
+ userId: userId!,
386
+ projectId: projectId,
387
+ },
388
+ )}`;
295
389
  }
296
390
  }
297
391
 
@@ -316,6 +410,35 @@ export class Service extends DatabaseService<Model> {
316
410
  throw new BadDataException("id is required");
317
411
  }
318
412
 
413
+ const incident: Model | null = await this.findOneById({
414
+ id: createdItem.id,
415
+ select: {
416
+ projectId: true,
417
+ incidentNumber: true,
418
+ title: true,
419
+ description: true,
420
+ incidentSeverity: {
421
+ name: true,
422
+ },
423
+ rootCause: true,
424
+ remediationNotes: true,
425
+ currentIncidentState: {
426
+ name: true,
427
+ },
428
+ monitors: {
429
+ name: true,
430
+ _id: true,
431
+ },
432
+ },
433
+ props: {
434
+ isRoot: true,
435
+ },
436
+ });
437
+
438
+ if (!incident) {
439
+ throw new BadDataException("Incident not found");
440
+ }
441
+
319
442
  // release the mutex.
320
443
  if (onCreate.carryForward && onCreate.carryForward.mutex) {
321
444
  const mutex: SemaphoreMutex = onCreate.carryForward.mutex;
@@ -343,23 +466,91 @@ export class Service extends DatabaseService<Model> {
343
466
  const createdByUserId: ObjectID | undefined | null =
344
467
  createdItem.createdByUserId || createdItem.createdByUser?.id;
345
468
 
346
- await IncidentFeedService.createIncidentFeed({
347
- incidentId: createdItem.id!,
348
- projectId: createdItem.projectId!,
349
- incidentFeedEventType: IncidentFeedEventType.IncidentCreated,
350
- displayColor: Red500,
351
- feedInfoInMarkdown: `**Incident #${createdItem.incidentNumber?.toString()} Created**:
352
-
353
- **Incident Title**:
469
+ // send message to workspaces - slack, teams, etc.
470
+ const workspaceResult: {
471
+ channelsCreated: Array<NotificationRuleWorkspaceChannel>;
472
+ } | null =
473
+ await IncidentWorkspaceMessages.createChannelsAndInviteUsersToChannels({
474
+ projectId: createdItem.projectId,
475
+ incidentId: createdItem.id!,
476
+ incidentNumber: createdItem.incidentNumber!,
477
+ });
354
478
 
355
- ${createdItem.title || "No title provided."}
479
+ if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
480
+ // update incident with these channels.
481
+ await this.updateOneById({
482
+ id: createdItem.id!,
483
+ data: {
484
+ postUpdatesToWorkspaceChannels: workspaceResult.channelsCreated || [],
485
+ },
486
+ props: {
487
+ isRoot: true,
488
+ },
489
+ });
490
+ }
356
491
 
357
- **Description**:
492
+ let feedInfoInMarkdown: string = `#### 🚨 Incident ${createdItem.incidentNumber?.toString()} Created:
493
+
494
+ **${createdItem.title || "No title provided."}**:
358
495
 
359
496
  ${createdItem.description || "No description provided."}
360
497
 
361
- `,
498
+ `;
499
+
500
+ if (incident.currentIncidentState?.name) {
501
+ feedInfoInMarkdown += `🔴 **Incident State**: ${incident.currentIncidentState.name} \n\n`;
502
+ }
503
+
504
+ if (incident.incidentSeverity?.name) {
505
+ feedInfoInMarkdown += `⚠️ **Severity**: ${incident.incidentSeverity.name} \n\n`;
506
+ }
507
+
508
+ if (incident.monitors && incident.monitors.length > 0) {
509
+ feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
510
+
511
+ for (const monitor of incident.monitors) {
512
+ feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(createdItem.projectId!, monitor.id!)).toString()})\n`;
513
+ }
514
+
515
+ feedInfoInMarkdown += `\n\n`;
516
+ }
517
+
518
+ if (createdItem.rootCause) {
519
+ feedInfoInMarkdown += `\n
520
+ 📄 **Root Cause**:
521
+
522
+ ${createdItem.rootCause || "No root cause provided."}
523
+
524
+ `;
525
+ }
526
+
527
+ if (createdItem.remediationNotes) {
528
+ feedInfoInMarkdown += `\n
529
+ 🎯 **Remediation Notes**:
530
+
531
+ ${createdItem.remediationNotes || "No remediation notes provided."}
532
+
533
+
534
+ `;
535
+ }
536
+
537
+ const incidentCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
538
+ await IncidentWorkspaceMessages.getIncidentCreateMessageBlocks({
539
+ incidentId: createdItem.id!,
540
+ projectId: createdItem.projectId!,
541
+ });
542
+
543
+ await IncidentFeedService.createIncidentFeedItem({
544
+ incidentId: createdItem.id!,
545
+ projectId: createdItem.projectId!,
546
+ incidentFeedEventType: IncidentFeedEventType.IncidentCreated,
547
+ displayColor: Red500,
548
+ feedInfoInMarkdown: feedInfoInMarkdown,
362
549
  userId: createdByUserId || undefined,
550
+ workspaceNotification: {
551
+ appendMessageBlocks: incidentCreateMessageBlocks,
552
+ sendWorkspaceNotification: true,
553
+ },
363
554
  });
364
555
 
365
556
  if (!createdItem.currentIncidentStateId) {
@@ -402,26 +593,6 @@ ${createdItem.description || "No description provided."}
402
593
  },
403
594
  });
404
595
 
405
- await IncidentFeedService.createIncidentFeed({
406
- incidentId: createdItem.id!,
407
- projectId: createdItem.projectId!,
408
- incidentFeedEventType: IncidentFeedEventType.RootCause,
409
- displayColor: Red500,
410
- feedInfoInMarkdown: `**Root Cause**
411
-
412
- ${createdItem.rootCause || "No root cause provided."}`,
413
- });
414
-
415
- await IncidentFeedService.createIncidentFeed({
416
- incidentId: createdItem.id!,
417
- projectId: createdItem.projectId!,
418
- incidentFeedEventType: IncidentFeedEventType.RemediationNotes,
419
- displayColor: Red500,
420
- feedInfoInMarkdown: `**Remediation Notes**
421
-
422
- ${createdItem.remediationNotes || "No remediation notes provided."}`,
423
- });
424
-
425
596
  // add owners.
426
597
 
427
598
  if (
@@ -475,32 +646,6 @@ ${createdItem.remediationNotes || "No remediation notes provided."}`,
475
646
  }
476
647
  }
477
648
 
478
- // // send message to workspaces - slack, teams, etc.
479
- // const createdChannels: {
480
- // channelsCreated: Array<WorkspaceChannel>;
481
- // } | null = await this.notifyWorkspaceOnIncidentCreate({
482
- // projectId: createdItem.projectId,
483
- // incidentId: createdItem.id!,
484
- // incidentNumber: createdItem.incidentNumber!,
485
- // });
486
-
487
- // if (
488
- // createdChannels &&
489
- // createdChannels.channelsCreated &&
490
- // createdChannels.channelsCreated.length > 0
491
- // ) {
492
- // // update incident with these channels.
493
- // await this.updateOneById({
494
- // id: createdItem.id!,
495
- // data: {
496
- // postUpdatesToWorkspaceChannels: createdChannels.channelsCreated,
497
- // },
498
- // props: {
499
- // isRoot: true,
500
- // },
501
- // });
502
- // }
503
-
504
649
  return createdItem;
505
650
  }
506
651
 
@@ -681,8 +826,22 @@ ${createdItem.remediationNotes || "No remediation notes provided."}`,
681
826
 
682
827
  if (updatedItemIds.length > 0) {
683
828
  for (const incidentId of updatedItemIds) {
829
+ const incident: Model | null = await this.findOneById({
830
+ id: incidentId,
831
+ select: {
832
+ projectId: true,
833
+ incidentNumber: true,
834
+ },
835
+ props: {
836
+ isRoot: true,
837
+ },
838
+ });
839
+
840
+ const projectId: ObjectID = incident!.projectId!;
841
+ const incidentNumber: number = incident!.incidentNumber!;
842
+
684
843
  let shouldAddIncidentFeed: boolean = false;
685
- let feedInfoInMarkdown: string = "**Incident was updated.**";
844
+ let feedInfoInMarkdown: string = `**[Incident ${incidentNumber}](${(await this.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) was updated.**`;
686
845
 
687
846
  const createdByUserId: ObjectID | undefined | null =
688
847
  onUpdate.updateBy.props.userId;
@@ -700,7 +859,7 @@ ${onUpdate.updateBy.data.title || "No title provided."}
700
859
  if (onUpdate.updateBy.data.title) {
701
860
  // add incident feed.
702
861
 
703
- feedInfoInMarkdown += `\n\n**Root Cause**:
862
+ feedInfoInMarkdown += `\n\n**📄 Root Cause**:
704
863
  ${onUpdate.updateBy.data.rootCause || "No root cause provided."}
705
864
  `;
706
865
  shouldAddIncidentFeed = true;
@@ -719,7 +878,7 @@ ${onUpdate.updateBy.data.rootCause || "No root cause provided."}
719
878
  if (onUpdate.updateBy.data.remediationNotes) {
720
879
  // add incident feed.
721
880
 
722
- feedInfoInMarkdown += `\n\n**Remediation Notes**:
881
+ feedInfoInMarkdown += `\n\n**🎯 Remediation Notes**:
723
882
  ${onUpdate.updateBy.data.remediationNotes || "No remediation notes provided."}
724
883
  `;
725
884
  shouldAddIncidentFeed = true;
@@ -759,7 +918,7 @@ ${onUpdate.updateBy.data.remediationNotes || "No remediation notes provided."}
759
918
  });
760
919
 
761
920
  if (labels.length > 0) {
762
- feedInfoInMarkdown += `\n\n**Labels**:
921
+ feedInfoInMarkdown += `\n\n**🏷️ Labels**:
763
922
 
764
923
  ${labels
765
924
  .map((label: Label) => {
@@ -794,7 +953,7 @@ ${labels
794
953
  });
795
954
 
796
955
  if (incidentSeverity) {
797
- feedInfoInMarkdown += `\n\n**Incident Severity**:
956
+ feedInfoInMarkdown += `\n\n**⚠️ Incident Severity**:
798
957
  ${incidentSeverity.name}
799
958
  `;
800
959
 
@@ -803,13 +962,16 @@ ${incidentSeverity.name}
803
962
  }
804
963
 
805
964
  if (shouldAddIncidentFeed) {
806
- await IncidentFeedService.createIncidentFeed({
965
+ await IncidentFeedService.createIncidentFeedItem({
807
966
  incidentId: incidentId,
808
967
  projectId: onUpdate.updateBy.props.tenantId as ObjectID,
809
968
  incidentFeedEventType: IncidentFeedEventType.IncidentUpdated,
810
969
  displayColor: Gray500,
811
970
  feedInfoInMarkdown: feedInfoInMarkdown,
812
971
  userId: createdByUserId || undefined,
972
+ workspaceNotification: {
973
+ sendWorkspaceNotification: true,
974
+ },
813
975
  });
814
976
  }
815
977
  }
@@ -1348,53 +1510,14 @@ ${incidentSeverity.name}
1348
1510
  });
1349
1511
  }
1350
1512
 
1351
- public async notifyWorkspaceOnIncidentCreate(data: {
1352
- projectId: ObjectID;
1513
+ public async getWorkspaceChannelForIncident(data: {
1353
1514
  incidentId: ObjectID;
1354
- incidentNumber: number;
1355
- }): Promise<{
1356
- channelsCreated: WorkspaceChannel[];
1357
- } | null> {
1358
- try {
1359
- // we will notify the workspace about the incident creation with the bot tokken which is in WorkspaceProjectAuth Table.
1360
- return await WorkspaceNotificationRuleService.createInviteAndPostToChannelsBasedOnRules(
1361
- {
1362
- projectId: data.projectId,
1363
- notificationFor: {
1364
- incidentId: data.incidentId,
1365
- },
1366
- notificationRuleEventType: NotificationRuleEventType.Incident,
1367
- channelNameSiffix: data.incidentNumber.toString(),
1368
- messageBlocks: await this.getWorkspaceMessageBlocksForIncidentCreate({
1369
- incidentId: data.incidentId,
1370
- }),
1371
- },
1372
- );
1373
- } catch (err) {
1374
- // log the error and continue.
1375
- logger.error(err);
1376
- return null;
1377
- }
1378
- }
1379
-
1380
- public async getWorkspaceMessageBlocksForIncidentCreate(data: {
1381
- incidentId: ObjectID;
1382
- }): Promise<Array<WorkspaceMessageBlock>> {
1515
+ workspaceType?: WorkspaceType | null;
1516
+ }): Promise<Array<NotificationRuleWorkspaceChannel>> {
1383
1517
  const incident: Model | null = await this.findOneById({
1384
1518
  id: data.incidentId,
1385
1519
  select: {
1386
- projectId: true,
1387
- incidentNumber: true,
1388
- title: true,
1389
- description: true,
1390
- incidentSeverity: {
1391
- name: true,
1392
- },
1393
- rootCause: true,
1394
- remediationNotes: true,
1395
- currentIncidentState: {
1396
- name: true,
1397
- },
1520
+ postUpdatesToWorkspaceChannels: true,
1398
1521
  },
1399
1522
  props: {
1400
1523
  isRoot: true,
@@ -1402,76 +1525,39 @@ ${incidentSeverity.name}
1402
1525
  });
1403
1526
 
1404
1527
  if (!incident) {
1405
- throw new BadDataException("Incident not found");
1406
- }
1407
-
1408
- const blocks: Array<WorkspaceMessageBlock> = [];
1409
-
1410
- if (incident.incidentNumber) {
1411
- const markdownBlock1: WorkspacePayloadMarkdown = {
1412
- _type: "WorkspacePayloadMarkdown",
1413
- text: `**Incident #${incident.incidentNumber} Created**`,
1414
- };
1415
- blocks.push(markdownBlock1);
1416
- }
1417
-
1418
- if (incident.title) {
1419
- const markdownBlock2: WorkspacePayloadMarkdown = {
1420
- _type: "WorkspacePayloadMarkdown",
1421
- text: `**Incident Title**:
1422
- ${incident.title}`,
1423
- };
1424
- blocks.push(markdownBlock2);
1425
- }
1426
-
1427
- if (incident.description) {
1428
- const markdownBlock3: WorkspacePayloadMarkdown = {
1429
- _type: "WorkspacePayloadMarkdown",
1430
- text: `**Description**:
1431
- ${incident.description}`,
1432
- };
1433
- blocks.push(markdownBlock3);
1528
+ throw new BadDataException("Incident not found.");
1434
1529
  }
1435
1530
 
1436
- if (incident.incidentSeverity?.name) {
1437
- const markdownBlock4: WorkspacePayloadMarkdown = {
1438
- _type: "WorkspacePayloadMarkdown",
1439
- text: `**Severity**:
1440
- ${incident.incidentSeverity.name}`,
1441
- };
1442
- blocks.push(markdownBlock4);
1443
- }
1531
+ return (incident.postUpdatesToWorkspaceChannels || []).filter(
1532
+ (channel: NotificationRuleWorkspaceChannel) => {
1533
+ if (!data.workspaceType) {
1534
+ return true;
1535
+ }
1444
1536
 
1445
- if (incident.rootCause) {
1446
- const markdownBlock5: WorkspacePayloadMarkdown = {
1447
- _type: "WorkspacePayloadMarkdown",
1448
- text: `**Root Cause**:
1449
- ${incident.rootCause}`,
1450
- };
1451
- blocks.push(markdownBlock5);
1452
- }
1537
+ return channel.workspaceType === data.workspaceType;
1538
+ },
1539
+ );
1540
+ }
1453
1541
 
1454
- if (incident.remediationNotes) {
1455
- const markdownBlock6: WorkspacePayloadMarkdown = {
1456
- _type: "WorkspacePayloadMarkdown",
1457
- text: `**Remediation Notes**:
1458
- ${incident.remediationNotes}`,
1459
- };
1460
- blocks.push(markdownBlock6);
1461
- }
1542
+ public async getIncidentNumber(data: {
1543
+ incidentId: ObjectID;
1544
+ }): Promise<number | null> {
1545
+ const incident: Model | null = await this.findOneById({
1546
+ id: data.incidentId,
1547
+ select: {
1548
+ incidentNumber: true,
1549
+ },
1550
+ props: {
1551
+ isRoot: true,
1552
+ },
1553
+ });
1462
1554
 
1463
- if (incident.currentIncidentState?.name) {
1464
- const markdownBlock7: WorkspacePayloadMarkdown = {
1465
- _type: "WorkspacePayloadMarkdown",
1466
- text: `**Incident State**:
1467
- ${incident.currentIncidentState.name}`,
1468
- };
1469
- blocks.push(markdownBlock7);
1555
+ if (!incident) {
1556
+ throw new BadDataException("Incident not found.");
1470
1557
  }
1471
1558
 
1472
- // TODO: Add buttons to Post Private Note, Ack Incident, Resolve Incident. etc.
1473
-
1474
- return blocks as Array<WorkspaceMessageBlock>;
1559
+ return incident.incidentNumber || null;
1475
1560
  }
1476
1561
  }
1562
+
1477
1563
  export default new Service();
@@ -171,6 +171,7 @@ export class Service extends DatabaseService<IncidentState> {
171
171
  isAcknowledgedState: true,
172
172
  isCreatedState: true,
173
173
  order: true,
174
+ name: true,
174
175
  },
175
176
  props: data.props,
176
177
  });
@@ -201,6 +202,30 @@ export class Service extends DatabaseService<IncidentState> {
201
202
  return unresolvedIncidentStates;
202
203
  }
203
204
 
205
+ public async getResolvedIncidentState(data: {
206
+ projectId: ObjectID;
207
+ props: DatabaseCommonInteractionProps;
208
+ }): Promise<IncidentState> {
209
+ const incidentStates: Array<IncidentState> =
210
+ await this.getAllIncidentStates({
211
+ projectId: data.projectId,
212
+ props: data.props,
213
+ });
214
+
215
+ const resolvedIncidentState: IncidentState | undefined =
216
+ incidentStates.find((incidentState: IncidentState) => {
217
+ return incidentState?.isResolvedState;
218
+ });
219
+
220
+ if (!resolvedIncidentState) {
221
+ throw new BadDataException(
222
+ "Resolved Incident State not found for this project",
223
+ );
224
+ }
225
+
226
+ return resolvedIncidentState;
227
+ }
228
+
204
229
  public async getAcknowledgedIncidentState(data: {
205
230
  projectId: ObjectID;
206
231
  props: DatabaseCommonInteractionProps;