@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
@@ -19,7 +19,7 @@ export class Service extends DatabaseService<MonitorStatusTimeline> {
19
19
  public constructor() {
20
20
  super(MonitorStatusTimeline);
21
21
  if (IsBillingEnabled) {
22
- this.hardDeleteItemsOlderThanInDays("createdAt", 120);
22
+ this.hardDeleteItemsOlderThanInDays("startsAt", 120);
23
23
  }
24
24
  }
25
25
 
@@ -71,31 +71,64 @@ export class Service extends DatabaseService<MonitorStatusTimeline> {
71
71
  }
72
72
  }
73
73
 
74
- const lastMonitorStatusTimeline: MonitorStatusTimeline | null =
75
- await this.findOneBy({
76
- query: {
77
- monitorId: createBy.data.monitorId,
78
- },
79
- sort: {
80
- createdAt: SortOrder.Descending,
81
- },
82
- props: {
83
- isRoot: true,
84
- },
85
- select: {
86
- _id: true,
87
- },
88
- });
74
+ const stateBeforeThis: MonitorStatusTimeline | null = await this.findOneBy({
75
+ query: {
76
+ monitorId: createBy.data.monitorId,
77
+ startsAt: QueryHelper.lessThanEqualTo(createBy.data.startsAt),
78
+ },
79
+ sort: {
80
+ startsAt: SortOrder.Descending,
81
+ },
82
+ props: {
83
+ isRoot: true,
84
+ },
85
+ select: {
86
+ monitorStatusId: true,
87
+ startsAt: true,
88
+ endsAt: true,
89
+ },
90
+ });
89
91
 
90
- if (!lastMonitorStatusTimeline) {
92
+ logger.debug("State Before this");
93
+ logger.debug(stateBeforeThis);
94
+
95
+ // If this is the first state, then do not notify the owner.
96
+ if (!stateBeforeThis) {
91
97
  // since this is the first status, do not notify the owner.
92
98
  createBy.data.isOwnerNotified = true;
93
99
  }
94
100
 
101
+ const stateAfterThis: MonitorStatusTimeline | null = await this.findOneBy({
102
+ query: {
103
+ monitorId: createBy.data.monitorId,
104
+ startsAt: QueryHelper.greaterThan(createBy.data.startsAt),
105
+ },
106
+ sort: {
107
+ startsAt: SortOrder.Ascending,
108
+ },
109
+ props: {
110
+ isRoot: true,
111
+ },
112
+ select: {
113
+ monitorStatusId: true,
114
+ startsAt: true,
115
+ endsAt: true,
116
+ },
117
+ });
118
+
119
+ // compute ends at. It's the start of the next status.
120
+ if (stateAfterThis && stateAfterThis.startsAt) {
121
+ createBy.data.endsAt = stateAfterThis.startsAt;
122
+ }
123
+
124
+ logger.debug("State After this");
125
+ logger.debug(stateAfterThis);
126
+
95
127
  return {
96
128
  createBy,
97
129
  carryForward: {
98
- lastMonitorStatusTimelineId: lastMonitorStatusTimeline?.id || null,
130
+ statusTimelineBeforeThisStatus: stateBeforeThis || null,
131
+ statusTimelineAfterThisStatus: stateAfterThis || null,
99
132
  mutex: mutex,
100
133
  },
101
134
  };
@@ -115,27 +148,72 @@ export class Service extends DatabaseService<MonitorStatusTimeline> {
115
148
 
116
149
  // update the last status as ended.
117
150
 
118
- if (onCreate.carryForward.lastMonitorStatusTimelineId) {
151
+ logger.debug("Status Timeline Before this");
152
+ logger.debug(onCreate.carryForward.statusTimelineBeforeThisStatus);
153
+
154
+ logger.debug("Status Timeline After this");
155
+ logger.debug(onCreate.carryForward.statusTimelineAfterThisStatus);
156
+
157
+ logger.debug("Created Item");
158
+ logger.debug(createdItem);
159
+
160
+ // now there are three cases.
161
+ // 1. This is the first status OR there's no status after this.
162
+ if (!onCreate.carryForward.statusTimelineBeforeThisStatus) {
163
+ // This is the first status, no need to update previous status.
164
+ logger.debug("This is the first status.");
165
+ } else if (!onCreate.carryForward.statusTimelineAfterThisStatus) {
166
+ // 2. This is the last status.
167
+ // Update the previous status to end at the start of this status.
119
168
  await this.updateOneById({
120
- id: onCreate.carryForward.lastMonitorStatusTimelineId!,
169
+ id: onCreate.carryForward.statusTimelineBeforeThisStatus.id!,
121
170
  data: {
122
- endsAt: createdItem.createdAt || OneUptimeDate.getCurrentDate(),
171
+ endsAt: createdItem.startsAt!,
123
172
  },
124
173
  props: {
125
174
  isRoot: true,
126
175
  },
127
176
  });
177
+ logger.debug("This is the last status.");
178
+ } else {
179
+ // 3. This is in the middle.
180
+ // Update the previous status to end at the start of this status.
181
+ await this.updateOneById({
182
+ id: onCreate.carryForward.statusTimelineBeforeThisStatus.id!,
183
+ data: {
184
+ endsAt: createdItem.startsAt!,
185
+ },
186
+ props: {
187
+ isRoot: true,
188
+ },
189
+ });
190
+
191
+ // Update the next status to start at the end of this status.
192
+ await this.updateOneById({
193
+ id: onCreate.carryForward.statusTimelineAfterThisStatus.id!,
194
+ data: {
195
+ startsAt: createdItem.endsAt!,
196
+ },
197
+ props: {
198
+ isRoot: true,
199
+ },
200
+ });
201
+ logger.debug("This status is in the middle.");
128
202
  }
129
203
 
130
- await MonitorService.updateOneBy({
131
- query: {
132
- _id: createdItem.monitorId?.toString(),
133
- },
134
- data: {
135
- currentMonitorStatusId: createdItem.monitorStatusId,
136
- },
137
- props: onCreate.createBy.props,
138
- });
204
+ if (!createdItem.endsAt) {
205
+ // if this is the last status, then update the monitor status.
206
+
207
+ await MonitorService.updateOneBy({
208
+ query: {
209
+ _id: createdItem.monitorId?.toString(),
210
+ },
211
+ data: {
212
+ currentMonitorStatusId: createdItem.monitorStatusId,
213
+ },
214
+ props: onCreate.createBy.props,
215
+ });
216
+ }
139
217
 
140
218
  if (onCreate.carryForward.mutex) {
141
219
  const mutex: SemaphoreMutex = onCreate.carryForward.mutex;
@@ -155,6 +233,7 @@ export class Service extends DatabaseService<MonitorStatusTimeline> {
155
233
  select: {
156
234
  monitorId: true,
157
235
  startsAt: true,
236
+ endsAt: true,
158
237
  },
159
238
  props: {
160
239
  isRoot: true,
@@ -174,82 +253,104 @@ export class Service extends DatabaseService<MonitorStatusTimeline> {
174
253
  },
175
254
  });
176
255
 
256
+ if (!monitorStatusTimelineToBeDeleted) {
257
+ throw new BadDataException("Monitor status timeline not found.");
258
+ }
259
+
177
260
  if (monitorStatusTimeline.isOne()) {
178
261
  throw new BadDataException(
179
262
  "Cannot delete the only status timeline. Monitor should have at least one status timeline.",
180
263
  );
181
264
  }
182
265
 
183
- // adjust times of other timeline events. get the state before this status timeline.
184
-
185
- if (monitorStatusTimelineToBeDeleted?.startsAt) {
186
- const beforeState: MonitorStatusTimeline | null =
187
- await this.findOneBy({
188
- query: {
189
- monitorId: monitorId,
190
- startsAt: QueryHelper.lessThan(
191
- monitorStatusTimelineToBeDeleted?.startsAt,
192
- ),
193
- },
194
- sort: {
195
- createdAt: SortOrder.Descending,
196
- },
197
- props: {
198
- isRoot: true,
199
- },
200
- select: {
201
- _id: true,
202
- startsAt: true,
203
- },
204
- });
205
-
206
- if (beforeState) {
207
- const afterState: MonitorStatusTimeline | null =
208
- await this.findOneBy({
209
- query: {
210
- monitorId: monitorId,
211
- startsAt: QueryHelper.greaterThan(
212
- monitorStatusTimelineToBeDeleted?.startsAt,
213
- ),
214
- },
215
- sort: {
216
- createdAt: SortOrder.Ascending,
217
- },
218
- props: {
219
- isRoot: true,
220
- },
221
- select: {
222
- _id: true,
223
- startsAt: true,
224
- },
225
- });
226
-
227
- if (!afterState) {
228
- // if there's nothing after then end date of before state is null.
229
-
230
- await this.updateOneById({
231
- id: beforeState.id!,
232
- data: {
233
- endsAt: null as any,
234
- },
235
- props: {
236
- isRoot: true,
237
- },
238
- });
239
- } else {
240
- // if there's something after then end date of before state is start date of after state.
241
-
242
- await this.updateOneById({
243
- id: beforeState.id!,
244
- data: {
245
- endsAt: afterState.startsAt!,
246
- },
247
- props: {
248
- isRoot: true,
249
- },
250
- });
251
- }
252
- }
266
+ // There are three cases.
267
+ // 1. This is the first status.
268
+ // 2. This is the last status.
269
+ // 3. This is in the middle.
270
+
271
+ const stateBeforeThis: MonitorStatusTimeline | null =
272
+ await this.findOneBy({
273
+ query: {
274
+ _id: QueryHelper.notEquals(deleteBy.query._id as string),
275
+ monitorId: monitorId,
276
+ startsAt: QueryHelper.lessThanEqualTo(
277
+ monitorStatusTimelineToBeDeleted.startsAt!,
278
+ ),
279
+ },
280
+ sort: {
281
+ startsAt: SortOrder.Descending,
282
+ },
283
+ props: {
284
+ isRoot: true,
285
+ },
286
+ select: {
287
+ monitorStatusId: true,
288
+ startsAt: true,
289
+ endsAt: true,
290
+ },
291
+ });
292
+
293
+ const stateAfterThis: MonitorStatusTimeline | null =
294
+ await this.findOneBy({
295
+ query: {
296
+ monitorId: monitorId,
297
+ startsAt: QueryHelper.greaterThan(
298
+ monitorStatusTimelineToBeDeleted.startsAt!,
299
+ ),
300
+ },
301
+ sort: {
302
+ startsAt: SortOrder.Ascending,
303
+ },
304
+ props: {
305
+ isRoot: true,
306
+ },
307
+ select: {
308
+ monitorStatusId: true,
309
+ startsAt: true,
310
+ endsAt: true,
311
+ },
312
+ });
313
+
314
+ if (!stateBeforeThis) {
315
+ // This is the first status, no need to update previous status.
316
+ logger.debug("This is the first status.");
317
+ } else if (!stateAfterThis) {
318
+ // This is the last status.
319
+ // Update the previous status to end at the start of this status.
320
+ await this.updateOneById({
321
+ id: stateBeforeThis.id!,
322
+ data: {
323
+ endsAt: monitorStatusTimelineToBeDeleted.endsAt!,
324
+ },
325
+ props: {
326
+ isRoot: true,
327
+ },
328
+ });
329
+ logger.debug("This is the last status.");
330
+ } else {
331
+ // This status is in the middle.
332
+ // Update the previous status to end at the start of this status.
333
+ await this.updateOneById({
334
+ id: stateBeforeThis.id!,
335
+ data: {
336
+ endsAt: stateAfterThis.startsAt!,
337
+ },
338
+ props: {
339
+ isRoot: true,
340
+ },
341
+ });
342
+
343
+ // Update the next status to start at the end of this status.
344
+ await this.updateOneById({
345
+ id: stateAfterThis.id!,
346
+ data: {
347
+ startsAt: monitorStatusTimelineToBeDeleted.startsAt!,
348
+ },
349
+ props: {
350
+ isRoot: true,
351
+ },
352
+ });
353
+ logger.debug("This status is in the middle.");
253
354
  }
254
355
  }
255
356
 
@@ -274,7 +375,7 @@ export class Service extends DatabaseService<MonitorStatusTimeline> {
274
375
  monitorId: monitorId,
275
376
  },
276
377
  sort: {
277
- createdAt: SortOrder.Descending,
378
+ startsAt: SortOrder.Descending,
278
379
  },
279
380
  props: {
280
381
  isRoot: true,
@@ -9,6 +9,15 @@ import DatabaseService from "./DatabaseService";
9
9
  import Model, {
10
10
  ScheduledMaintenanceFeedEventType,
11
11
  } from "Common/Models/DatabaseModels/ScheduledMaintenanceFeed";
12
+ import NotificationRuleEventType from "../../Types/Workspace/NotificationRules/EventType";
13
+ import ScheduledMaintenanceService from "./ScheduledMaintenanceService";
14
+ import { WorkspaceChannel } from "../Utils/Workspace/WorkspaceBase";
15
+ import WorkspaceUtil from "../Utils/Workspace/Workspace";
16
+ import WorkspaceType from "../../Types/Workspace/WorkspaceType";
17
+ import WorkspaceNotificationRuleService, {
18
+ MessageBlocksByWorkspaceType,
19
+ } from "./WorkspaceNotificationRuleService";
20
+ import WorkspaceMessagePayload from "../../Types/Workspace/WorkspaceMessagePayload";
12
21
 
13
22
  export class Service extends DatabaseService<Model> {
14
23
  public constructor() {
@@ -28,6 +37,13 @@ export class Service extends DatabaseService<Model> {
28
37
  displayColor?: Color | undefined;
29
38
  userId?: ObjectID | undefined;
30
39
  postedAt?: Date | undefined;
40
+ workspaceNotification?:
41
+ | {
42
+ notifyUserId?: ObjectID | undefined; // this is oneuptime user id.
43
+ sendWorkspaceNotification: boolean;
44
+ appendMessageBlocks?: Array<MessageBlocksByWorkspaceType> | undefined;
45
+ }
46
+ | undefined;
31
47
  }): Promise<void> {
32
48
  try {
33
49
  if (!data.scheduledMaintenanceId) {
@@ -81,6 +97,93 @@ export class Service extends DatabaseService<Model> {
81
97
  isRoot: true,
82
98
  },
83
99
  });
100
+
101
+ try {
102
+ // send notification to slack and teams
103
+ if (data.workspaceNotification?.sendWorkspaceNotification) {
104
+ let messageBlocksByWorkspaceTypes: Array<MessageBlocksByWorkspaceType> =
105
+ [];
106
+
107
+ // use markdown to create blocks
108
+ messageBlocksByWorkspaceTypes =
109
+ await WorkspaceUtil.getMessageBlocksByMarkdown({
110
+ userId: data.workspaceNotification.notifyUserId,
111
+ markdown: data.feedInfoInMarkdown,
112
+ projectId: data.projectId,
113
+ });
114
+
115
+ if (data.workspaceNotification.appendMessageBlocks) {
116
+ for (const messageBlocksByWorkspaceType of data
117
+ .workspaceNotification.appendMessageBlocks) {
118
+ const workspaceType: WorkspaceType =
119
+ messageBlocksByWorkspaceType.workspaceType;
120
+
121
+ messageBlocksByWorkspaceTypes
122
+ .find(
123
+ (
124
+ messageBlocksByWorkspaceType: MessageBlocksByWorkspaceType,
125
+ ) => {
126
+ return (
127
+ messageBlocksByWorkspaceType.workspaceType ===
128
+ workspaceType
129
+ );
130
+ },
131
+ )
132
+ ?.messageBlocks.push(
133
+ ...messageBlocksByWorkspaceType.messageBlocks,
134
+ );
135
+ }
136
+ }
137
+
138
+ const workspaceNotificationPaylaods: Array<WorkspaceMessagePayload> =
139
+ [];
140
+
141
+ for (const messageBlocksByWorkspaceType of messageBlocksByWorkspaceTypes) {
142
+ const existingChannels: Array<string> =
143
+ await WorkspaceNotificationRuleService.getExistingChannelNamesBasedOnEventType(
144
+ {
145
+ projectId: data.projectId,
146
+ notificationRuleEventType:
147
+ NotificationRuleEventType.ScheduledMaintenance,
148
+ workspaceType: messageBlocksByWorkspaceType.workspaceType,
149
+ },
150
+ );
151
+
152
+ const scheduledMaintenanceChannels: Array<WorkspaceChannel> =
153
+ await ScheduledMaintenanceService.getWorkspaceChannelForScheduledMaintenance(
154
+ {
155
+ scheduledMaintenanceId: data.scheduledMaintenanceId,
156
+ workspaceType: messageBlocksByWorkspaceType.workspaceType,
157
+ },
158
+ );
159
+
160
+ const workspaceMessagePayload: WorkspaceMessagePayload = {
161
+ _type: "WorkspaceMessagePayload",
162
+ workspaceType: messageBlocksByWorkspaceType.workspaceType,
163
+ messageBlocks: messageBlocksByWorkspaceType.messageBlocks,
164
+ channelNames: existingChannels,
165
+ channelIds:
166
+ scheduledMaintenanceChannels.map(
167
+ (channel: WorkspaceChannel) => {
168
+ return channel.id;
169
+ },
170
+ ) || [],
171
+ };
172
+
173
+ workspaceNotificationPaylaods.push(workspaceMessagePayload);
174
+ }
175
+
176
+ await WorkspaceUtil.postMessageToAllWorkspaceChannelsAsBot({
177
+ projectId: data.projectId,
178
+ messagePayloadsByWorkspace: workspaceNotificationPaylaods,
179
+ });
180
+ }
181
+ } catch (e) {
182
+ logger.error("Error in sending notification to slack and teams");
183
+ logger.error(e);
184
+
185
+ // we dont throw this error as it is not a critical error
186
+ }
84
187
  } catch (error) {
85
188
  logger.error(
86
189
  "ScheduledMaintenanceFeedService.createScheduledMaintenanceFeedItem",
@@ -6,12 +6,34 @@ import ScheduledMaintenanceFeedService from "./ScheduledMaintenanceFeedService";
6
6
  import { ScheduledMaintenanceFeedEventType } from "../../Models/DatabaseModels/ScheduledMaintenanceFeed";
7
7
  import { Blue500 } from "../../Types/BrandColors";
8
8
  import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
9
+ import ScheduledMaintenance from "../../Models/DatabaseModels/ScheduledMaintenance";
10
+ import ScheduledMaintenanceService from "./ScheduledMaintenanceService";
9
11
 
10
12
  export class Service extends DatabaseService<Model> {
11
13
  public constructor() {
12
14
  super(Model);
13
15
  }
14
16
 
17
+ public async addNote(data: {
18
+ userId: ObjectID;
19
+ scheduledMaintenanceId: ObjectID;
20
+ projectId: ObjectID;
21
+ note: string;
22
+ }): Promise<Model> {
23
+ const internalNote: Model = new Model();
24
+ internalNote.createdByUserId = data.userId;
25
+ internalNote.scheduledMaintenanceId = data.scheduledMaintenanceId;
26
+ internalNote.projectId = data.projectId;
27
+ internalNote.note = data.note;
28
+
29
+ return this.create({
30
+ data: internalNote,
31
+ props: {
32
+ isRoot: true,
33
+ },
34
+ });
35
+ }
36
+
15
37
  public override async onCreateSuccess(
16
38
  _onCreate: OnCreate<Model>,
17
39
  createdItem: Model,
@@ -19,6 +41,14 @@ export class Service extends DatabaseService<Model> {
19
41
  const userId: ObjectID | null | undefined =
20
42
  createdItem.createdByUserId || createdItem.createdByUser?.id;
21
43
 
44
+ const scheduledMaintenanceId: ObjectID =
45
+ createdItem.scheduledMaintenanceId!;
46
+
47
+ const scheduledMaintenanceNumber: number | null =
48
+ await ScheduledMaintenanceService.getScheduledMaintenanceNumber({
49
+ scheduledMaintenanceId: scheduledMaintenanceId,
50
+ });
51
+
22
52
  await ScheduledMaintenanceFeedService.createScheduledMaintenanceFeedItem({
23
53
  scheduledMaintenanceId: createdItem.scheduledMaintenanceId!,
24
54
  projectId: createdItem.projectId!,
@@ -27,10 +57,14 @@ export class Service extends DatabaseService<Model> {
27
57
  displayColor: Blue500,
28
58
  userId: userId || undefined,
29
59
 
30
- feedInfoInMarkdown: `**Posted Internal / Private Note**
31
-
60
+ feedInfoInMarkdown: `📄 posted **private note** for this [Scheduled Maintenance ${scheduledMaintenanceNumber}](${(await ScheduledMaintenanceService.getScheduledMaintenanceLinkInDashboard(createdItem.projectId!, scheduledMaintenanceId)).toString()}):
61
+
32
62
  ${createdItem.note}
33
- `,
63
+ `,
64
+ workspaceNotification: {
65
+ sendWorkspaceNotification: true,
66
+ notifyUserId: userId || undefined,
67
+ },
34
68
  });
35
69
 
36
70
  return createdItem;
@@ -56,6 +90,9 @@ ${createdItem.note}
56
90
  createdByUser: {
57
91
  _id: true,
58
92
  },
93
+ scheduledMaintenance: {
94
+ scheduledMaintenanceNumber: true,
95
+ },
59
96
  },
60
97
  });
61
98
 
@@ -63,6 +100,9 @@ ${createdItem.note}
63
100
  onUpdate.updateBy.props.userId;
64
101
 
65
102
  for (const updatedItem of updatedItems) {
103
+ const scheduledMaintenance: ScheduledMaintenance =
104
+ updatedItem.scheduledMaintenance!;
105
+
66
106
  await ScheduledMaintenanceFeedService.createScheduledMaintenanceFeedItem(
67
107
  {
68
108
  scheduledMaintenanceId: updatedItem.scheduledMaintenanceId!,
@@ -72,10 +112,14 @@ ${createdItem.note}
72
112
  displayColor: Blue500,
73
113
  userId: userId || undefined,
74
114
 
75
- feedInfoInMarkdown: `**Updated Private Note**
76
-
115
+ feedInfoInMarkdown: `📄 updated **Private Note** for this [Scheduled Maintenance ${scheduledMaintenance.scheduledMaintenanceNumber}](${(await ScheduledMaintenanceService.getScheduledMaintenanceLinkInDashboard(scheduledMaintenance.projectId!, scheduledMaintenance.id!)).toString()})
116
+
77
117
  ${updatedItem.note}
78
- `,
118
+ `,
119
+ workspaceNotification: {
120
+ sendWorkspaceNotification: true,
121
+ notifyUserId: userId || undefined,
122
+ },
79
123
  },
80
124
  );
81
125
  }
@@ -8,6 +8,11 @@ import { ScheduledMaintenanceFeedEventType } from "../../Models/DatabaseModels/S
8
8
  import { Gray500, Red500 } from "../../Types/BrandColors";
9
9
  import { OnCreate, OnDelete } from "../Types/Database/Hooks";
10
10
  import DeleteBy from "../Types/Database/DeleteBy";
11
+ import NotificationRuleEventType from "../../Types/Workspace/NotificationRules/EventType";
12
+ import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService";
13
+ import WorkspaceNotificationRule from "../../Models/DatabaseModels/WorkspaceNotificationRule";
14
+ import logger from "../Utils/Logger";
15
+ import ScheduledMaintenanceService from "./ScheduledMaintenanceService";
11
16
 
12
17
  export class Service extends DatabaseService<Model> {
13
18
  public constructor() {
@@ -123,6 +128,38 @@ export class Service extends DatabaseService<Model> {
123
128
  }
124
129
  }
125
130
 
131
+ // get notification rule where inviteOwners is true.
132
+ const notificationRules: Array<WorkspaceNotificationRule> =
133
+ await WorkspaceNotificationRuleService.getNotificationRulesWhereInviteOwnersIsTrue(
134
+ {
135
+ projectId: projectId!,
136
+ notificationFor: {
137
+ scheduledMaintenanceId: scheduledMaintenanceId,
138
+ },
139
+ notificationRuleEventType:
140
+ NotificationRuleEventType.ScheduledMaintenance,
141
+ },
142
+ );
143
+
144
+ logger.debug(`Notification Rules for ScheduledMaintenance Owner Teams`);
145
+ logger.debug(notificationRules);
146
+
147
+ WorkspaceNotificationRuleService.inviteTeamsBasedOnRulesAndWorkspaceChannels(
148
+ {
149
+ notificationRules: notificationRules,
150
+ projectId: projectId!,
151
+ workspaceChannels:
152
+ await ScheduledMaintenanceService.getWorkspaceChannelForScheduledMaintenance(
153
+ {
154
+ scheduledMaintenanceId: scheduledMaintenanceId!,
155
+ },
156
+ ),
157
+ teamIds: [teamId!],
158
+ },
159
+ ).catch((error: Error) => {
160
+ logger.error(error);
161
+ });
162
+
126
163
  return createdItem;
127
164
  }
128
165
  }