@oneuptime/common 7.0.3822 → 7.0.3827

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.
@@ -82,28 +82,65 @@ export class Service extends DatabaseService<AlertStateTimeline> {
82
82
  if (userId) {
83
83
  createBy.data.rootCause = `Alert state created by ${await UserService.getUserMarkdownString(
84
84
  {
85
- userId: userId,
85
+ userId: userId!,
86
86
  projectId: createBy.data.projectId || createBy.props.tenantId!,
87
87
  },
88
88
  )}`;
89
89
  }
90
90
  }
91
91
 
92
- const lastAlertStateTimeline: AlertStateTimeline | null =
93
- await this.findOneBy({
94
- query: {
95
- alertId: createBy.data.alertId,
96
- },
97
- sort: {
98
- createdAt: SortOrder.Descending,
99
- },
100
- props: {
101
- isRoot: true,
102
- },
103
- select: {
104
- _id: true,
105
- },
106
- });
92
+ const stateBeforeThis: AlertStateTimeline | null = await this.findOneBy({
93
+ query: {
94
+ alertId: createBy.data.alertId,
95
+ startsAt: QueryHelper.lessThanEqualTo(createBy.data.startsAt),
96
+ },
97
+ sort: {
98
+ startsAt: SortOrder.Descending,
99
+ },
100
+ props: {
101
+ isRoot: true,
102
+ },
103
+ select: {
104
+ alertStateId: true,
105
+ startsAt: true,
106
+ endsAt: true,
107
+ },
108
+ });
109
+
110
+ logger.debug("State Before this");
111
+ logger.debug(stateBeforeThis);
112
+
113
+ // If this is the first state, then do not notify the owner.
114
+ if (!stateBeforeThis) {
115
+ // since this is the first status, do not notify the owner.
116
+ createBy.data.isOwnerNotified = true;
117
+ }
118
+
119
+ const stateAfterThis: AlertStateTimeline | null = await this.findOneBy({
120
+ query: {
121
+ alertId: createBy.data.alertId,
122
+ startsAt: QueryHelper.greaterThan(createBy.data.startsAt),
123
+ },
124
+ sort: {
125
+ startsAt: SortOrder.Ascending,
126
+ },
127
+ props: {
128
+ isRoot: true,
129
+ },
130
+ select: {
131
+ alertStateId: true,
132
+ startsAt: true,
133
+ endsAt: true,
134
+ },
135
+ });
136
+
137
+ // compute ends at. It's the start of the next status.
138
+ if (stateAfterThis && stateAfterThis.startsAt) {
139
+ createBy.data.endsAt = stateAfterThis.startsAt;
140
+ }
141
+
142
+ logger.debug("State After this");
143
+ logger.debug(stateAfterThis);
107
144
 
108
145
  const internalNote: string | undefined = (
109
146
  createBy.miscDataProps as JSONObject | undefined
@@ -129,7 +166,8 @@ export class Service extends DatabaseService<AlertStateTimeline> {
129
166
  return {
130
167
  createBy,
131
168
  carryForward: {
132
- lastAlertStateTimelineId: lastAlertStateTimeline?.id || null,
169
+ statusTimelineBeforeThisStatus: stateBeforeThis || null,
170
+ statusTimelineAfterThisStatus: stateAfterThis || null,
133
171
  privateNote: privateNote,
134
172
  },
135
173
  };
@@ -147,18 +185,69 @@ export class Service extends DatabaseService<AlertStateTimeline> {
147
185
  throw new BadDataException("alertStateId is null");
148
186
  }
149
187
 
150
- // update the last status as ended.
188
+ logger.debug("Status Timeline Before this");
189
+ logger.debug(onCreate.carryForward.statusTimelineBeforeThisStatus);
190
+
191
+ logger.debug("Status Timeline After this");
192
+ logger.debug(onCreate.carryForward.statusTimelineAfterThisStatus);
151
193
 
152
- if (onCreate.carryForward.lastAlertStateTimelineId) {
194
+ logger.debug("Created Item");
195
+ logger.debug(createdItem);
196
+
197
+ // now there are three cases.
198
+ // 1. This is the first status OR there's no status after this.
199
+ if (!onCreate.carryForward.statusTimelineBeforeThisStatus) {
200
+ // This is the first status, no need to update previous status.
201
+ logger.debug("This is the first status.");
202
+ } else if (!onCreate.carryForward.statusTimelineAfterThisStatus) {
203
+ // 2. This is the last status.
204
+ // Update the previous status to end at the start of this status.
205
+ await this.updateOneById({
206
+ id: onCreate.carryForward.statusTimelineBeforeThisStatus.id!,
207
+ data: {
208
+ endsAt: createdItem.startsAt!,
209
+ },
210
+ props: {
211
+ isRoot: true,
212
+ },
213
+ });
214
+ logger.debug("This is the last status.");
215
+ } else {
216
+ // 3. This is in the middle.
217
+ // Update the previous status to end at the start of this status.
153
218
  await this.updateOneById({
154
- id: onCreate.carryForward.lastAlertStateTimelineId!,
219
+ id: onCreate.carryForward.statusTimelineBeforeThisStatus.id!,
155
220
  data: {
156
- endsAt: createdItem.createdAt || OneUptimeDate.getCurrentDate(),
221
+ endsAt: createdItem.startsAt!,
157
222
  },
158
223
  props: {
159
224
  isRoot: true,
160
225
  },
161
226
  });
227
+
228
+ // Update the next status to start at the end of this status.
229
+ await this.updateOneById({
230
+ id: onCreate.carryForward.statusTimelineAfterThisStatus.id!,
231
+ data: {
232
+ startsAt: createdItem.endsAt!,
233
+ },
234
+ props: {
235
+ isRoot: true,
236
+ },
237
+ });
238
+ logger.debug("This status is in the middle.");
239
+ }
240
+
241
+ if (!createdItem.endsAt) {
242
+ await AlertService.updateOneBy({
243
+ query: {
244
+ _id: createdItem.alertId?.toString(),
245
+ },
246
+ data: {
247
+ currentAlertStateId: createdItem.alertStateId,
248
+ },
249
+ props: onCreate.createBy.props,
250
+ });
162
251
  }
163
252
 
164
253
  const alertState: AlertState | null = await AlertStateService.findOneBy({
@@ -210,7 +299,7 @@ export class Service extends DatabaseService<AlertStateTimeline> {
210
299
  stateName +
211
300
  "**",
212
301
  moreInformationInMarkdown: `**Cause:**
213
- ${createdItem.rootCause}`,
302
+ ${createdItem.rootCause}`,
214
303
  userId: createdItem.createdByUserId || onCreate.createBy.props.userId,
215
304
  workspaceNotification: {
216
305
  sendWorkspaceNotification: true,
@@ -219,16 +308,6 @@ export class Service extends DatabaseService<AlertStateTimeline> {
219
308
  },
220
309
  });
221
310
 
222
- await AlertService.updateOneBy({
223
- query: {
224
- _id: createdItem.alertId?.toString(),
225
- },
226
- data: {
227
- currentAlertStateId: createdItem.alertStateId,
228
- },
229
- props: onCreate.createBy.props,
230
- });
231
-
232
311
  if (onCreate.carryForward.privateNote) {
233
312
  const privateNote: string = onCreate.carryForward.privateNote;
234
313
 
@@ -266,6 +345,7 @@ export class Service extends DatabaseService<AlertStateTimeline> {
266
345
  select: {
267
346
  alertId: true,
268
347
  startsAt: true,
348
+ endsAt: true,
269
349
  },
270
350
  props: {
271
351
  isRoot: true,
@@ -285,78 +365,104 @@ export class Service extends DatabaseService<AlertStateTimeline> {
285
365
  },
286
366
  });
287
367
 
368
+ if (!alertStateTimelineToBeDeleted) {
369
+ throw new BadDataException("Alert state timeline not found.");
370
+ }
371
+
288
372
  if (alertStateTimeline.isOne()) {
289
373
  throw new BadDataException(
290
374
  "Cannot delete the only state timeline. Alert should have at least one state in its timeline.",
291
375
  );
292
376
  }
293
377
 
294
- if (alertStateTimelineToBeDeleted?.startsAt) {
295
- const beforeState: AlertStateTimeline | null = await this.findOneBy({
378
+ // There are three cases.
379
+ // 1. This is the first state.
380
+ // 2. This is the last state.
381
+ // 3. This is in the middle.
382
+
383
+ const stateBeforeThis: AlertStateTimeline | null = await this.findOneBy(
384
+ {
296
385
  query: {
386
+ _id: QueryHelper.notEquals(deleteBy.query._id as string),
297
387
  alertId: alertId,
298
- startsAt: QueryHelper.lessThan(
299
- alertStateTimelineToBeDeleted?.startsAt,
388
+ startsAt: QueryHelper.lessThanEqualTo(
389
+ alertStateTimelineToBeDeleted.startsAt!,
300
390
  ),
301
391
  },
302
392
  sort: {
303
- createdAt: SortOrder.Descending,
393
+ startsAt: SortOrder.Descending,
304
394
  },
305
395
  props: {
306
396
  isRoot: true,
307
397
  },
308
398
  select: {
309
- _id: true,
399
+ alertStateId: true,
310
400
  startsAt: true,
401
+ endsAt: true,
402
+ },
403
+ },
404
+ );
405
+
406
+ const stateAfterThis: AlertStateTimeline | null = await this.findOneBy({
407
+ query: {
408
+ alertId: alertId,
409
+ startsAt: QueryHelper.greaterThan(
410
+ alertStateTimelineToBeDeleted.startsAt!,
411
+ ),
412
+ },
413
+ sort: {
414
+ startsAt: SortOrder.Ascending,
415
+ },
416
+ props: {
417
+ isRoot: true,
418
+ },
419
+ select: {
420
+ alertStateId: true,
421
+ startsAt: true,
422
+ endsAt: true,
423
+ },
424
+ });
425
+
426
+ if (!stateBeforeThis) {
427
+ // This is the first state, no need to update previous state.
428
+ logger.debug("This is the first state.");
429
+ } else if (!stateAfterThis) {
430
+ // This is the last state.
431
+ // Update the previous state to end at the end of this state.
432
+ await this.updateOneById({
433
+ id: stateBeforeThis.id!,
434
+ data: {
435
+ endsAt: alertStateTimelineToBeDeleted.endsAt!,
436
+ },
437
+ props: {
438
+ isRoot: true,
439
+ },
440
+ });
441
+ logger.debug("This is the last state.");
442
+ } else {
443
+ // This state is in the middle.
444
+ // Update the previous state to end at the start of the next state.
445
+ await this.updateOneById({
446
+ id: stateBeforeThis.id!,
447
+ data: {
448
+ endsAt: stateAfterThis.startsAt!,
449
+ },
450
+ props: {
451
+ isRoot: true,
311
452
  },
312
453
  });
313
454
 
314
- if (beforeState) {
315
- const afterState: AlertStateTimeline | null = await this.findOneBy({
316
- query: {
317
- alertId: alertId,
318
- startsAt: QueryHelper.greaterThan(
319
- alertStateTimelineToBeDeleted?.startsAt,
320
- ),
321
- },
322
- sort: {
323
- createdAt: SortOrder.Ascending,
324
- },
325
- props: {
326
- isRoot: true,
327
- },
328
- select: {
329
- _id: true,
330
- startsAt: true,
331
- },
332
- });
333
-
334
- if (!afterState) {
335
- // if there's nothing after then end date of before state is null.
336
-
337
- await this.updateOneById({
338
- id: beforeState.id!,
339
- data: {
340
- endsAt: null as any,
341
- },
342
- props: {
343
- isRoot: true,
344
- },
345
- });
346
- } else {
347
- // if there's something after then end date of before state is start date of after state.
348
-
349
- await this.updateOneById({
350
- id: beforeState.id!,
351
- data: {
352
- endsAt: afterState.startsAt!,
353
- },
354
- props: {
355
- isRoot: true,
356
- },
357
- });
358
- }
359
- }
455
+ // Update the next state to start at the start of this state.
456
+ await this.updateOneById({
457
+ id: stateAfterThis.id!,
458
+ data: {
459
+ startsAt: alertStateTimelineToBeDeleted.startsAt!,
460
+ },
461
+ props: {
462
+ isRoot: true,
463
+ },
464
+ });
465
+ logger.debug("This state is in the middle.");
360
466
  }
361
467
  }
362
468
 
@@ -374,14 +480,14 @@ export class Service extends DatabaseService<AlertStateTimeline> {
374
480
  // this is alertId.
375
481
  const alertId: ObjectID = onDelete.carryForward as ObjectID;
376
482
 
377
- // get last status of this monitor.
483
+ // get last status of this alert.
378
484
  const alertStateTimeline: AlertStateTimeline | null =
379
485
  await this.findOneBy({
380
486
  query: {
381
487
  alertId: alertId,
382
488
  },
383
489
  sort: {
384
- createdAt: SortOrder.Descending,
490
+ startsAt: SortOrder.Descending,
385
491
  },
386
492
  props: {
387
493
  isRoot: true,