@oneuptime/common 9.5.2 → 9.5.4

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 (218) hide show
  1. package/Models/DatabaseModels/Alert.ts +28 -0
  2. package/Models/DatabaseModels/AlertEpisode.ts +27 -0
  3. package/Models/DatabaseModels/AlertEpisodeStateTimeline.ts +1 -0
  4. package/Models/DatabaseModels/AlertStateTimeline.ts +1 -0
  5. package/Models/DatabaseModels/Incident.ts +28 -0
  6. package/Models/DatabaseModels/IncidentEpisode.ts +182 -0
  7. package/Models/DatabaseModels/IncidentEpisodeFeed.ts +2 -0
  8. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +611 -0
  9. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +84 -0
  10. package/Models/DatabaseModels/IncidentGroupingRule.ts +36 -0
  11. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  12. package/Models/DatabaseModels/Index.ts +2 -0
  13. package/Models/DatabaseModels/MonitorStatusTimeline.ts +1 -0
  14. package/Models/DatabaseModels/Project.ts +252 -1
  15. package/Models/DatabaseModels/ProjectCallSMSConfig.ts +1 -0
  16. package/Models/DatabaseModels/ScheduledMaintenance.ts +28 -0
  17. package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +1 -0
  18. package/Models/DatabaseModels/StatusPage.ts +120 -0
  19. package/Server/API/IncidentEpisodePublicNoteAPI.ts +98 -0
  20. package/Server/API/StatusPageAPI.ts +1092 -45
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1770232207959-MigrationName.ts +181 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1770237245069-MigrationName.ts +35 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1770237245070-MigrationName.ts +57 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1770407024682-MigrationName.ts +83 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  26. package/Server/Services/AlertEpisodeMemberService.ts +6 -3
  27. package/Server/Services/AlertEpisodeService.ts +45 -97
  28. package/Server/Services/AlertEpisodeStateTimelineService.ts +4 -2
  29. package/Server/Services/AlertInternalNoteService.ts +5 -2
  30. package/Server/Services/AlertOwnerTeamService.ts +10 -4
  31. package/Server/Services/AlertOwnerUserService.ts +10 -4
  32. package/Server/Services/AlertService.ts +24 -38
  33. package/Server/Services/AlertStateTimelineService.ts +6 -3
  34. package/Server/Services/DatabaseService.ts +12 -0
  35. package/Server/Services/IncidentEpisodeMemberService.ts +8 -4
  36. package/Server/Services/IncidentEpisodePublicNoteService.ts +257 -0
  37. package/Server/Services/IncidentEpisodeService.ts +67 -93
  38. package/Server/Services/IncidentEpisodeStateTimelineService.ts +4 -2
  39. package/Server/Services/IncidentInternalNoteService.ts +10 -5
  40. package/Server/Services/IncidentMemberService.ts +20 -10
  41. package/Server/Services/IncidentOwnerTeamService.ts +20 -10
  42. package/Server/Services/IncidentOwnerUserService.ts +20 -10
  43. package/Server/Services/IncidentPublicNoteService.ts +10 -5
  44. package/Server/Services/IncidentService.ts +34 -110
  45. package/Server/Services/IncidentStateTimelineService.ts +11 -6
  46. package/Server/Services/Index.ts +2 -0
  47. package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +61 -39
  48. package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +31 -19
  49. package/Server/Services/ProjectService.ts +227 -0
  50. package/Server/Services/ScheduledMaintenanceInternalNoteService.ts +9 -6
  51. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +9 -6
  52. package/Server/Services/ScheduledMaintenanceService.ts +27 -39
  53. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +8 -6
  54. package/Server/Services/UserNotificationRuleService.ts +32 -21
  55. package/Server/Utils/AI/IncidentEpisodeAIContextBuilder.ts +4 -2
  56. package/Server/Utils/Browser.ts +28 -20
  57. package/Server/Utils/Monitor/MonitorAlert.ts +5 -0
  58. package/Server/Utils/Monitor/MonitorIncident.ts +13 -0
  59. package/Server/Utils/PushNotificationUtil.ts +69 -26
  60. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +8 -4
  61. package/Server/Utils/Workspace/Slack/Actions/Alert.ts +20 -8
  62. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +42 -22
  63. package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +23 -17
  64. package/Server/Utils/Workspace/WorkspaceMessages/Alert.ts +1 -0
  65. package/Server/Utils/Workspace/WorkspaceMessages/Incident.ts +1 -0
  66. package/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.ts +1 -0
  67. package/Types/Email/EmailTemplateType.ts +4 -0
  68. package/Types/Icon/IconProp.ts +172 -0
  69. package/Types/Monitor/CriteriaIncident.ts +2 -0
  70. package/Types/Monitor/MonitorEvaluationSummary.ts +2 -0
  71. package/Types/Permission.ts +40 -0
  72. package/Types/StatusPage/StatusPageSubscriberNotificationEventType.ts +5 -0
  73. package/UI/Components/Icon/Icon.tsx +1333 -1
  74. package/Utils/Analytics.ts +11 -0
  75. package/build/dist/Models/DatabaseModels/Alert.js +30 -0
  76. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  77. package/build/dist/Models/DatabaseModels/AlertEpisode.js +29 -0
  78. package/build/dist/Models/DatabaseModels/AlertEpisode.js.map +1 -1
  79. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +1 -0
  80. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -1
  81. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -0
  82. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
  83. package/build/dist/Models/DatabaseModels/Incident.js +30 -0
  84. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  85. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +189 -0
  86. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  87. package/build/dist/Models/DatabaseModels/IncidentEpisodeFeed.js +2 -0
  88. package/build/dist/Models/DatabaseModels/IncidentEpisodeFeed.js.map +1 -1
  89. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +626 -0
  90. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -0
  91. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +86 -0
  92. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  93. package/build/dist/Models/DatabaseModels/IncidentGroupingRule.js +37 -0
  94. package/build/dist/Models/DatabaseModels/IncidentGroupingRule.js.map +1 -1
  95. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  96. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  97. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  98. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  99. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js +1 -0
  100. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
  101. package/build/dist/Models/DatabaseModels/Project.js +267 -1
  102. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  103. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js +1 -0
  104. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
  105. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +29 -0
  106. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  107. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +1 -0
  108. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
  109. package/build/dist/Models/DatabaseModels/StatusPage.js +126 -0
  110. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  111. package/build/dist/Server/API/IncidentEpisodePublicNoteAPI.js +68 -0
  112. package/build/dist/Server/API/IncidentEpisodePublicNoteAPI.js.map +1 -0
  113. package/build/dist/Server/API/StatusPageAPI.js +874 -47
  114. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  115. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770232207959-MigrationName.js +68 -0
  116. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770232207959-MigrationName.js.map +1 -0
  117. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770237245069-MigrationName.js +18 -0
  118. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770237245069-MigrationName.js.map +1 -0
  119. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770237245070-MigrationName.js +27 -0
  120. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770237245070-MigrationName.js.map +1 -0
  121. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770407024682-MigrationName.js +34 -0
  122. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770407024682-MigrationName.js.map +1 -0
  123. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  124. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  125. package/build/dist/Server/Services/AlertEpisodeMemberService.js +6 -3
  126. package/build/dist/Server/Services/AlertEpisodeMemberService.js.map +1 -1
  127. package/build/dist/Server/Services/AlertEpisodeService.js +33 -90
  128. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  129. package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js +3 -2
  130. package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js.map +1 -1
  131. package/build/dist/Server/Services/AlertInternalNoteService.js +2 -2
  132. package/build/dist/Server/Services/AlertInternalNoteService.js.map +1 -1
  133. package/build/dist/Server/Services/AlertOwnerTeamService.js +4 -4
  134. package/build/dist/Server/Services/AlertOwnerTeamService.js.map +1 -1
  135. package/build/dist/Server/Services/AlertOwnerUserService.js +4 -4
  136. package/build/dist/Server/Services/AlertOwnerUserService.js.map +1 -1
  137. package/build/dist/Server/Services/AlertService.js +16 -34
  138. package/build/dist/Server/Services/AlertService.js.map +1 -1
  139. package/build/dist/Server/Services/AlertStateTimelineService.js +3 -3
  140. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  141. package/build/dist/Server/Services/DatabaseService.js +9 -0
  142. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  143. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +8 -4
  144. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  145. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +224 -0
  146. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -0
  147. package/build/dist/Server/Services/IncidentEpisodeService.js +47 -82
  148. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  149. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +3 -2
  150. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
  151. package/build/dist/Server/Services/IncidentInternalNoteService.js +4 -2
  152. package/build/dist/Server/Services/IncidentInternalNoteService.js.map +1 -1
  153. package/build/dist/Server/Services/IncidentMemberService.js +8 -4
  154. package/build/dist/Server/Services/IncidentMemberService.js.map +1 -1
  155. package/build/dist/Server/Services/IncidentOwnerTeamService.js +8 -4
  156. package/build/dist/Server/Services/IncidentOwnerTeamService.js.map +1 -1
  157. package/build/dist/Server/Services/IncidentOwnerUserService.js +8 -4
  158. package/build/dist/Server/Services/IncidentOwnerUserService.js.map +1 -1
  159. package/build/dist/Server/Services/IncidentPublicNoteService.js +4 -2
  160. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  161. package/build/dist/Server/Services/IncidentService.js +24 -94
  162. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  163. package/build/dist/Server/Services/IncidentStateTimelineService.js +5 -3
  164. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  165. package/build/dist/Server/Services/Index.js +2 -0
  166. package/build/dist/Server/Services/Index.js.map +1 -1
  167. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +20 -16
  168. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
  169. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +10 -8
  170. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
  171. package/build/dist/Server/Services/ProjectService.js +207 -0
  172. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  173. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js +4 -3
  174. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js.map +1 -1
  175. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +4 -3
  176. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  177. package/build/dist/Server/Services/ScheduledMaintenanceService.js +16 -37
  178. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  179. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +3 -3
  180. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  181. package/build/dist/Server/Services/UserNotificationRuleService.js +33 -25
  182. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  183. package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js +4 -2
  184. package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js.map +1 -1
  185. package/build/dist/Server/Utils/Browser.js +19 -12
  186. package/build/dist/Server/Utils/Browser.js.map +1 -1
  187. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +4 -0
  188. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  189. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +9 -0
  190. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  191. package/build/dist/Server/Utils/PushNotificationUtil.js +36 -28
  192. package/build/dist/Server/Utils/PushNotificationUtil.js.map +1 -1
  193. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +8 -4
  194. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  195. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +8 -8
  196. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -1
  197. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +18 -10
  198. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
  199. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +8 -8
  200. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -1
  201. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Alert.js.map +1 -1
  202. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Incident.js.map +1 -1
  203. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.js.map +1 -1
  204. package/build/dist/Types/Email/EmailTemplateType.js +3 -0
  205. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  206. package/build/dist/Types/Icon/IconProp.js +172 -0
  207. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  208. package/build/dist/Types/Monitor/CriteriaIncident.js +1 -0
  209. package/build/dist/Types/Monitor/CriteriaIncident.js.map +1 -1
  210. package/build/dist/Types/Permission.js +34 -0
  211. package/build/dist/Types/Permission.js.map +1 -1
  212. package/build/dist/Types/StatusPage/StatusPageSubscriberNotificationEventType.js +4 -0
  213. package/build/dist/Types/StatusPage/StatusPageSubscriberNotificationEventType.js.map +1 -1
  214. package/build/dist/UI/Components/Icon/Icon.js +502 -1
  215. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  216. package/build/dist/Utils/Analytics.js +5 -0
  217. package/build/dist/Utils/Analytics.js.map +1 -1
  218. package/package.json +1 -1
@@ -34,10 +34,12 @@ import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
34
34
  import NotificationRuleWorkspaceChannel from "../../Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel";
35
35
  import WorkspaceType from "../../Types/Workspace/WorkspaceType";
36
36
  import IncidentService from "./IncidentService";
37
- import Semaphore, { SemaphoreMutex } from "../Infrastructure/Semaphore";
38
37
  import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
39
38
  import OnCallDutyPolicy from "../../Models/DatabaseModels/OnCallDutyPolicy";
40
39
  import UserNotificationEventType from "../../Types/UserNotification/UserNotificationEventType";
40
+ import IncidentGroupingRuleService from "./IncidentGroupingRuleService";
41
+ import ProjectService from "./ProjectService";
42
+ import IncidentGroupingRule from "../../Models/DatabaseModels/IncidentGroupingRule";
41
43
 
42
44
  export class Service extends DatabaseService<Model> {
43
45
  public constructor() {
@@ -47,32 +49,6 @@ export class Service extends DatabaseService<Model> {
47
49
  }
48
50
  }
49
51
 
50
- @CaptureSpan()
51
- public async getExistingEpisodeNumberForProject(data: {
52
- projectId: ObjectID;
53
- }): Promise<number> {
54
- const lastEpisode: Model | null = await this.findOneBy({
55
- query: {
56
- projectId: data.projectId,
57
- },
58
- select: {
59
- episodeNumber: true,
60
- },
61
- sort: {
62
- episodeNumber: SortOrder.Descending,
63
- },
64
- props: {
65
- isRoot: true,
66
- },
67
- });
68
-
69
- if (!lastEpisode) {
70
- return 0;
71
- }
72
-
73
- return lastEpisode.episodeNumber ? Number(lastEpisode.episodeNumber) : 0;
74
- }
75
-
76
52
  @CaptureSpan()
77
53
  protected override async onBeforeCreate(
78
54
  createBy: CreateBy<Model>,
@@ -86,84 +62,77 @@ export class Service extends DatabaseService<Model> {
86
62
  const projectId: ObjectID =
87
63
  createBy.props.tenantId || createBy.data.projectId!;
88
64
 
89
- let mutex: SemaphoreMutex | null = null;
65
+ // Get the created state for episodes
66
+ const incidentState: IncidentState | null =
67
+ await IncidentStateService.findOneBy({
68
+ query: {
69
+ projectId: projectId,
70
+ isCreatedState: true,
71
+ },
72
+ select: {
73
+ _id: true,
74
+ },
75
+ props: {
76
+ isRoot: true,
77
+ },
78
+ });
90
79
 
91
- try {
92
- // Acquire mutex to prevent race conditions when generating episode numbers
93
- try {
94
- mutex = await Semaphore.lock({
95
- key: projectId.toString(),
96
- namespace: "IncidentEpisode.create",
97
- });
98
- } catch (err) {
99
- logger.error(err);
100
- }
80
+ if (!incidentState || !incidentState.id) {
81
+ throw new BadDataException(
82
+ "Created incident state not found for this project. Please add created incident state from settings.",
83
+ );
84
+ }
101
85
 
102
- // Get the created state for episodes
103
- const incidentState: IncidentState | null =
104
- await IncidentStateService.findOneBy({
105
- query: {
106
- projectId: projectId,
107
- isCreatedState: true,
108
- },
86
+ createBy.data.currentIncidentStateId = incidentState.id;
87
+
88
+ // Auto-generate episode number
89
+ const episodeCounterResult: {
90
+ counter: number;
91
+ prefix: string | undefined;
92
+ } = await ProjectService.incrementAndGetIncidentEpisodeCounter(projectId);
93
+
94
+ createBy.data.episodeNumber = episodeCounterResult.counter;
95
+ createBy.data.episodeNumberWithPrefix = episodeCounterResult.prefix
96
+ ? `${episodeCounterResult.prefix}${episodeCounterResult.counter}`
97
+ : `#${episodeCounterResult.counter}`;
98
+
99
+ // Set initial lastIncidentAddedAt
100
+ if (!createBy.data.lastIncidentAddedAt) {
101
+ createBy.data.lastIncidentAddedAt = OneUptimeDate.getCurrentDate();
102
+ }
103
+
104
+ // Set declaredAt if not provided
105
+ if (!createBy.data.declaredAt) {
106
+ createBy.data.declaredAt = OneUptimeDate.getCurrentDate();
107
+ }
108
+
109
+ // Copy showEpisodeOnStatusPage from grouping rule if available
110
+ if (createBy.data.incidentGroupingRuleId) {
111
+ const groupingRule: IncidentGroupingRule | null =
112
+ await IncidentGroupingRuleService.findOneById({
113
+ id: createBy.data.incidentGroupingRuleId,
109
114
  select: {
110
- _id: true,
115
+ showEpisodeOnStatusPage: true,
111
116
  },
112
117
  props: {
113
118
  isRoot: true,
114
119
  },
115
120
  });
116
121
 
117
- if (!incidentState || !incidentState.id) {
118
- throw new BadDataException(
119
- "Created incident state not found for this project. Please add created incident state from settings.",
120
- );
122
+ if (groupingRule) {
123
+ createBy.data.isVisibleOnStatusPage =
124
+ groupingRule.showEpisodeOnStatusPage ?? true;
121
125
  }
122
-
123
- createBy.data.currentIncidentStateId = incidentState.id;
124
-
125
- // Auto-generate episode number
126
- const episodeNumberForThisEpisode: number =
127
- (await this.getExistingEpisodeNumberForProject({
128
- projectId: projectId,
129
- })) + 1;
130
-
131
- createBy.data.episodeNumber = episodeNumberForThisEpisode;
132
-
133
- // Set initial lastIncidentAddedAt
134
- if (!createBy.data.lastIncidentAddedAt) {
135
- createBy.data.lastIncidentAddedAt = OneUptimeDate.getCurrentDate();
136
- }
137
-
138
- return { createBy, carryForward: { mutex } };
139
- } catch (error) {
140
- // Release the mutex if it was acquired and an error occurred
141
- if (mutex) {
142
- try {
143
- await Semaphore.release(mutex);
144
- } catch (err) {
145
- logger.error(err);
146
- }
147
- }
148
- throw error;
149
126
  }
127
+
128
+ return { createBy, carryForward: null };
150
129
  }
151
130
 
152
131
  @CaptureSpan()
153
132
  protected override async onCreateSuccess(
154
- onCreate: OnCreate<Model>,
133
+ _onCreate: OnCreate<Model>,
155
134
  createdItem: Model,
156
135
  ): Promise<Model> {
157
- // Release the mutex acquired in onBeforeCreate
158
- const mutex: SemaphoreMutex | null = onCreate.carryForward?.mutex || null;
159
- if (mutex) {
160
- try {
161
- await Semaphore.release(mutex);
162
- } catch (err) {
163
- logger.error(err);
164
- }
165
- }
166
-
167
136
  if (!createdItem.projectId) {
168
137
  throw new BadDataException("projectId is required");
169
138
  }
@@ -230,7 +199,7 @@ export class Service extends DatabaseService<Model> {
230
199
  return;
231
200
  }
232
201
 
233
- let feedInfoInMarkdown: string = `#### Episode ${episode.episodeNumber?.toString()} Created
202
+ let feedInfoInMarkdown: string = `#### Episode ${episode.episodeNumberWithPrefix || "#" + episode.episodeNumber?.toString()} Created
234
203
 
235
204
  **${episode.title || "No title provided."}**
236
205
 
@@ -1021,13 +990,15 @@ export class Service extends DatabaseService<Model> {
1021
990
  }
1022
991
 
1023
992
  @CaptureSpan()
1024
- public async getEpisodeNumber(data: {
1025
- episodeId: ObjectID;
1026
- }): Promise<number | null> {
993
+ public async getEpisodeNumber(data: { episodeId: ObjectID }): Promise<{
994
+ number: number | null;
995
+ numberWithPrefix: string | null;
996
+ }> {
1027
997
  const episode: Model | null = await this.findOneById({
1028
998
  id: data.episodeId,
1029
999
  select: {
1030
1000
  episodeNumber: true,
1001
+ episodeNumberWithPrefix: true,
1031
1002
  },
1032
1003
  props: {
1033
1004
  isRoot: true,
@@ -1038,7 +1009,10 @@ export class Service extends DatabaseService<Model> {
1038
1009
  throw new BadDataException("Episode not found.");
1039
1010
  }
1040
1011
 
1041
- return episode.episodeNumber ? Number(episode.episodeNumber) : null;
1012
+ return {
1013
+ number: episode.episodeNumber ? Number(episode.episodeNumber) : null,
1014
+ numberWithPrefix: episode.episodeNumberWithPrefix || null,
1015
+ };
1042
1016
  }
1043
1017
  }
1044
1018
 
@@ -358,13 +358,15 @@ export class Service extends DatabaseService<IncidentEpisodeStateTimeline> {
358
358
  id: createdItem.incidentEpisodeId,
359
359
  select: {
360
360
  episodeNumber: true,
361
+ episodeNumberWithPrefix: true,
361
362
  },
362
363
  props: {
363
364
  isRoot: true,
364
365
  },
365
366
  });
366
367
 
367
- const episodeNumber: number = episode?.episodeNumber || 0;
368
+ const episodeDisplayNumber: string =
369
+ episode?.episodeNumberWithPrefix || "#" + (episode?.episodeNumber || 0);
368
370
 
369
371
  await IncidentEpisodeFeedService.createIncidentEpisodeFeedItem({
370
372
  incidentEpisodeId: createdItem.incidentEpisodeId!,
@@ -374,7 +376,7 @@ export class Service extends DatabaseService<IncidentEpisodeStateTimeline> {
374
376
  displayColor: incidentState?.color,
375
377
  feedInfoInMarkdown:
376
378
  stateEmoji +
377
- ` Changed **Episode ${episodeNumber} State** to **` +
379
+ ` Changed **Episode ${episodeDisplayNumber} State** to **` +
378
380
  stateName +
379
381
  "**",
380
382
  moreInformationInMarkdown: createdItem.rootCause
@@ -85,10 +85,15 @@ export class Service extends DatabaseService<Model> {
85
85
 
86
86
  const incidentId: ObjectID = createdItem.incidentId!;
87
87
 
88
- const incidentNumber: number | null =
89
- await IncidentService.getIncidentNumber({
90
- incidentId: incidentId,
91
- });
88
+ const incidentNumberResult: {
89
+ number: number | null;
90
+ numberWithPrefix: string | null;
91
+ } = await IncidentService.getIncidentNumber({
92
+ incidentId: incidentId,
93
+ });
94
+ const incidentNumberDisplay: string =
95
+ incidentNumberResult.numberWithPrefix ||
96
+ "#" + incidentNumberResult.number;
92
97
 
93
98
  const attachmentsMarkdown: string = await this.getAttachmentsMarkdown(
94
99
  createdItem.id!,
@@ -102,7 +107,7 @@ export class Service extends DatabaseService<Model> {
102
107
  displayColor: Blue500,
103
108
  userId: userId || undefined,
104
109
 
105
- feedInfoInMarkdown: `📄 posted **private note** for this [Incident ${incidentNumber}](${(await IncidentService.getIncidentLinkInDashboard(createdItem.projectId!, incidentId)).toString()}):
110
+ feedInfoInMarkdown: `📄 posted **private note** for this [Incident ${incidentNumberDisplay}](${(await IncidentService.getIncidentLinkInDashboard(createdItem.projectId!, incidentId)).toString()}):
106
111
 
107
112
  ${(createdItem.note || "") + attachmentsMarkdown}
108
113
  `,
@@ -136,10 +136,15 @@ export class Service extends DatabaseService<Model> {
136
136
  }
137
137
  }
138
138
 
139
- const incidentNumber: number | null =
140
- await IncidentService.getIncidentNumber({
141
- incidentId: incidentId,
142
- });
139
+ const incidentNumberResult: {
140
+ number: number | null;
141
+ numberWithPrefix: string | null;
142
+ } = await IncidentService.getIncidentNumber({
143
+ incidentId: incidentId,
144
+ });
145
+ const incidentNumberDisplay: string =
146
+ incidentNumberResult.numberWithPrefix ||
147
+ "#" + incidentNumberResult.number;
143
148
 
144
149
  if (user && user.name) {
145
150
  await IncidentFeedService.createIncidentFeedItem({
@@ -147,7 +152,7 @@ export class Service extends DatabaseService<Model> {
147
152
  projectId: projectId,
148
153
  incidentFeedEventType: IncidentFeedEventType.IncidentMemberRemoved,
149
154
  displayColor: Red500,
150
- feedInfoInMarkdown: `👤 Removed **${user.name.toString()}** (${user.email?.toString()}) as **${roleName}** from [Incident ${incidentNumber}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}).`,
155
+ feedInfoInMarkdown: `👤 Removed **${user.name.toString()}** (${user.email?.toString()}) as **${roleName}** from [Incident ${incidentNumberDisplay}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}).`,
151
156
  userId: deleteByUserId || undefined,
152
157
  workspaceNotification: {
153
158
  sendWorkspaceNotification: true,
@@ -192,10 +197,15 @@ export class Service extends DatabaseService<Model> {
192
197
  }
193
198
  }
194
199
 
195
- const incidentNumber: number | null =
196
- await IncidentService.getIncidentNumber({
197
- incidentId: incidentId,
198
- });
200
+ const incidentNumberResult: {
201
+ number: number | null;
202
+ numberWithPrefix: string | null;
203
+ } = await IncidentService.getIncidentNumber({
204
+ incidentId: incidentId,
205
+ });
206
+ const incidentNumberDisplay: string =
207
+ incidentNumberResult.numberWithPrefix ||
208
+ "#" + incidentNumberResult.number;
199
209
 
200
210
  if (userId) {
201
211
  await IncidentFeedService.createIncidentFeedItem({
@@ -208,7 +218,7 @@ export class Service extends DatabaseService<Model> {
208
218
  userId: userId,
209
219
  projectId: projectId,
210
220
  },
211
- )}** as **${roleName}** to [Incident ${incidentNumber}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}).`,
221
+ )}** as **${roleName}** to [Incident ${incidentNumberDisplay}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}).`,
212
222
  userId: createdByUserId || undefined,
213
223
  workspaceNotification: {
214
224
  sendWorkspaceNotification: true,
@@ -72,10 +72,15 @@ export class Service extends DatabaseService<Model> {
72
72
  },
73
73
  });
74
74
 
75
- const incidentNumber: number | null =
76
- await IncidentService.getIncidentNumber({
77
- incidentId: incidentId,
78
- });
75
+ const incidentNumberResult: {
76
+ number: number | null;
77
+ numberWithPrefix: string | null;
78
+ } = await IncidentService.getIncidentNumber({
79
+ incidentId: incidentId,
80
+ });
81
+ const incidentNumberDisplay: string =
82
+ incidentNumberResult.numberWithPrefix ||
83
+ "#" + incidentNumberResult.number;
79
84
 
80
85
  if (team && team.name) {
81
86
  await IncidentFeedService.createIncidentFeedItem({
@@ -83,7 +88,7 @@ export class Service extends DatabaseService<Model> {
83
88
  projectId: projectId,
84
89
  incidentFeedEventType: IncidentFeedEventType.OwnerTeamRemoved,
85
90
  displayColor: Red500,
86
- feedInfoInMarkdown: `👨🏻‍👩🏻‍👦🏻 Removed team **${team.name}** from the [Incident ${incidentNumber}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) as the owner.`,
91
+ feedInfoInMarkdown: `👨🏻‍👩🏻‍👦🏻 Removed team **${team.name}** from the [Incident ${incidentNumberDisplay}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) as the owner.`,
87
92
  userId: deleteByUserId || undefined,
88
93
  workspaceNotification: {
89
94
  sendWorkspaceNotification: true,
@@ -122,17 +127,22 @@ export class Service extends DatabaseService<Model> {
122
127
  });
123
128
 
124
129
  if (team && team.name) {
125
- const incidentNumber: number | null =
126
- await IncidentService.getIncidentNumber({
127
- incidentId: incidentId,
128
- });
130
+ const incidentNumberResult: {
131
+ number: number | null;
132
+ numberWithPrefix: string | null;
133
+ } = await IncidentService.getIncidentNumber({
134
+ incidentId: incidentId,
135
+ });
136
+ const incidentNumberDisplay: string =
137
+ incidentNumberResult.numberWithPrefix ||
138
+ "#" + incidentNumberResult.number;
129
139
 
130
140
  await IncidentFeedService.createIncidentFeedItem({
131
141
  incidentId: incidentId,
132
142
  projectId: projectId,
133
143
  incidentFeedEventType: IncidentFeedEventType.OwnerTeamAdded,
134
144
  displayColor: Gray500,
135
- feedInfoInMarkdown: `👨🏻‍👩🏻‍👦🏻 Added team **${team.name}** to the [Incident ${incidentNumber}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) as the owner.`,
145
+ feedInfoInMarkdown: `👨🏻‍👩🏻‍👦🏻 Added team **${team.name}** to the [Incident ${incidentNumberDisplay}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) as the owner.`,
136
146
  userId: createdByUserId || undefined,
137
147
  workspaceNotification: {
138
148
  sendWorkspaceNotification: true,
@@ -73,10 +73,15 @@ export class Service extends DatabaseService<Model> {
73
73
  },
74
74
  });
75
75
 
76
- const incidentNumber: number | null =
77
- await IncidentService.getIncidentNumber({
78
- incidentId: incidentId,
79
- });
76
+ const incidentNumberResult: {
77
+ number: number | null;
78
+ numberWithPrefix: string | null;
79
+ } = await IncidentService.getIncidentNumber({
80
+ incidentId: incidentId,
81
+ });
82
+ const incidentNumberDisplay: string =
83
+ incidentNumberResult.numberWithPrefix ||
84
+ "#" + incidentNumberResult.number;
80
85
 
81
86
  if (user && user.name) {
82
87
  await IncidentFeedService.createIncidentFeedItem({
@@ -84,7 +89,7 @@ export class Service extends DatabaseService<Model> {
84
89
  projectId: projectId,
85
90
  incidentFeedEventType: IncidentFeedEventType.OwnerUserRemoved,
86
91
  displayColor: Red500,
87
- feedInfoInMarkdown: `👨🏻‍💻 Removed **${user.name.toString()}** (${user.email?.toString()}) from the [Incident ${incidentNumber}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) as the owner.`,
92
+ feedInfoInMarkdown: `👨🏻‍💻 Removed **${user.name.toString()}** (${user.email?.toString()}) from the [Incident ${incidentNumberDisplay}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) as the owner.`,
88
93
  userId: deleteByUserId || undefined,
89
94
  workspaceNotification: {
90
95
  sendWorkspaceNotification: true,
@@ -112,10 +117,15 @@ export class Service extends DatabaseService<Model> {
112
117
  createdItem.createdByUserId || onCreate.createBy.props.userId;
113
118
 
114
119
  if (incidentId && userId && projectId) {
115
- const incidentNumber: number | null =
116
- await IncidentService.getIncidentNumber({
117
- incidentId: incidentId,
118
- });
120
+ const incidentNumberResult: {
121
+ number: number | null;
122
+ numberWithPrefix: string | null;
123
+ } = await IncidentService.getIncidentNumber({
124
+ incidentId: incidentId,
125
+ });
126
+ const incidentNumberDisplay: string =
127
+ incidentNumberResult.numberWithPrefix ||
128
+ "#" + incidentNumberResult.number;
119
129
 
120
130
  if (userId) {
121
131
  await IncidentFeedService.createIncidentFeedItem({
@@ -128,7 +138,7 @@ export class Service extends DatabaseService<Model> {
128
138
  userId: userId,
129
139
  projectId: projectId,
130
140
  },
131
- )}** to the [Incident ${incidentNumber}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) as the owner.`,
141
+ )}** to the [Incident ${incidentNumberDisplay}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) as the owner.`,
132
142
  userId: createdByUserId || undefined,
133
143
  workspaceNotification: {
134
144
  sendWorkspaceNotification: true,
@@ -118,10 +118,15 @@ export class Service extends DatabaseService<Model> {
118
118
 
119
119
  const incidentId: ObjectID = createdItem.incidentId!;
120
120
  const projectId: ObjectID = createdItem.projectId!;
121
- const incidentNumber: number | null =
122
- await IncidentService.getIncidentNumber({
123
- incidentId: incidentId,
124
- });
121
+ const incidentNumberResult: {
122
+ number: number | null;
123
+ numberWithPrefix: string | null;
124
+ } = await IncidentService.getIncidentNumber({
125
+ incidentId: incidentId,
126
+ });
127
+ const incidentNumberDisplay: string =
128
+ incidentNumberResult.numberWithPrefix ||
129
+ "#" + incidentNumberResult.number;
125
130
 
126
131
  const attachmentsMarkdown: string = await this.getAttachmentsMarkdown(
127
132
  createdItem.id!,
@@ -134,7 +139,7 @@ export class Service extends DatabaseService<Model> {
134
139
  incidentFeedEventType: IncidentFeedEventType.PublicNote,
135
140
  displayColor: Indigo500,
136
141
  userId: userId || undefined,
137
- feedInfoInMarkdown: `📄 posted **public note** for this [Incident ${incidentNumber}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) on status page:
142
+ feedInfoInMarkdown: `📄 posted **public note** for this [Incident ${incidentNumberDisplay}](${(await IncidentService.getIncidentLinkInDashboard(projectId!, incidentId!)).toString()}) on status page:
138
143
 
139
144
  ${(createdItem.note || "") + attachmentsMarkdown}
140
145
  `,