@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
@@ -85,7 +85,10 @@ export class Service extends DatabaseService<Model> {
85
85
 
86
86
  const alertId: ObjectID = createdItem.alertId!;
87
87
 
88
- const alertNumber: number | null = await AlertService.getAlertNumber({
88
+ const alertNumberResult: {
89
+ number: number | null;
90
+ numberWithPrefix: string | null;
91
+ } = await AlertService.getAlertNumber({
89
92
  alertId: alertId,
90
93
  });
91
94
 
@@ -101,7 +104,7 @@ export class Service extends DatabaseService<Model> {
101
104
  displayColor: Blue500,
102
105
  userId: userId || undefined,
103
106
 
104
- feedInfoInMarkdown: `📄 posted **private note** for this [Alert ${alertNumber}](${(await AlertService.getAlertLinkInDashboard(createdItem.projectId!, alertId)).toString()}):
107
+ feedInfoInMarkdown: `📄 posted **private note** for this [Alert ${alertNumberResult.numberWithPrefix || "#" + alertNumberResult.number}](${(await AlertService.getAlertLinkInDashboard(createdItem.projectId!, alertId)).toString()}):
105
108
 
106
109
  ${(createdItem.note || "") + attachmentsMarkdown}
107
110
  `,
@@ -73,7 +73,10 @@ export class Service extends DatabaseService<Model> {
73
73
  });
74
74
 
75
75
  if (team && team.name) {
76
- const alertNumber: number | null = await AlertService.getAlertNumber({
76
+ const alertNumberResult: {
77
+ number: number | null;
78
+ numberWithPrefix: string | null;
79
+ } = await AlertService.getAlertNumber({
77
80
  alertId: alertId,
78
81
  });
79
82
  await AlertFeedService.createAlertFeedItem({
@@ -81,7 +84,7 @@ export class Service extends DatabaseService<Model> {
81
84
  projectId: projectId,
82
85
  alertFeedEventType: AlertFeedEventType.OwnerTeamRemoved,
83
86
  displayColor: Red500,
84
- feedInfoInMarkdown: `👨🏻‍👩🏻‍👦🏻 Removed team **${team.name}** from the [Alert ${alertNumber}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) as the owner.`,
87
+ feedInfoInMarkdown: `👨🏻‍👩🏻‍👦🏻 Removed team **${team.name}** from the [Alert ${alertNumberResult.numberWithPrefix || "#" + alertNumberResult.number}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) as the owner.`,
85
88
  userId: deleteByUserId || undefined,
86
89
  workspaceNotification: {
87
90
  sendWorkspaceNotification: true,
@@ -120,7 +123,10 @@ export class Service extends DatabaseService<Model> {
120
123
  });
121
124
 
122
125
  if (team && team.name) {
123
- const alertNumber: number | null = await AlertService.getAlertNumber({
126
+ const alertNumberResult: {
127
+ number: number | null;
128
+ numberWithPrefix: string | null;
129
+ } = await AlertService.getAlertNumber({
124
130
  alertId: alertId,
125
131
  });
126
132
 
@@ -129,7 +135,7 @@ export class Service extends DatabaseService<Model> {
129
135
  projectId: projectId,
130
136
  alertFeedEventType: AlertFeedEventType.OwnerTeamAdded,
131
137
  displayColor: Gray500,
132
- feedInfoInMarkdown: `👨🏻‍👩🏻‍👦🏻 Added team **${team.name}** to the [Alert ${alertNumber}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) as the owner.`,
138
+ feedInfoInMarkdown: `👨🏻‍👩🏻‍👦🏻 Added team **${team.name}** to the [Alert ${alertNumberResult.numberWithPrefix || "#" + alertNumberResult.number}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) as the owner.`,
133
139
  userId: createdByUserId || undefined,
134
140
  workspaceNotification: {
135
141
  sendWorkspaceNotification: true,
@@ -74,7 +74,10 @@ export class Service extends DatabaseService<Model> {
74
74
  });
75
75
 
76
76
  if (user && user.name) {
77
- const alertNumber: number | null = await AlertService.getAlertNumber({
77
+ const alertNumberResult: {
78
+ number: number | null;
79
+ numberWithPrefix: string | null;
80
+ } = await AlertService.getAlertNumber({
78
81
  alertId: alertId,
79
82
  });
80
83
 
@@ -83,7 +86,7 @@ export class Service extends DatabaseService<Model> {
83
86
  projectId: projectId,
84
87
  alertFeedEventType: AlertFeedEventType.OwnerUserRemoved,
85
88
  displayColor: Red500,
86
- feedInfoInMarkdown: `👨🏻‍💻 Removed **${user.name.toString()}** (${user.email?.toString()}) from the [Alert ${alertNumber}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) as the owner.`,
89
+ feedInfoInMarkdown: `👨🏻‍💻 Removed **${user.name.toString()}** (${user.email?.toString()}) from the [Alert ${alertNumberResult.numberWithPrefix || "#" + alertNumberResult.number}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) as the owner.`,
87
90
  userId: deleteByUserId || undefined,
88
91
  workspaceNotification: {
89
92
  sendWorkspaceNotification: true,
@@ -123,7 +126,10 @@ export class Service extends DatabaseService<Model> {
123
126
  });
124
127
 
125
128
  if (user && user.name) {
126
- const alertNumber: number | null = await AlertService.getAlertNumber({
129
+ const alertNumberResult: {
130
+ number: number | null;
131
+ numberWithPrefix: string | null;
132
+ } = await AlertService.getAlertNumber({
127
133
  alertId: alertId,
128
134
  });
129
135
  await AlertFeedService.createAlertFeedItem({
@@ -136,7 +142,7 @@ export class Service extends DatabaseService<Model> {
136
142
  userId: userId,
137
143
  projectId: projectId,
138
144
  },
139
- )}** to the [Alert ${alertNumber}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) as the owner.`,
145
+ )}** to the [Alert ${alertNumberResult.numberWithPrefix || "#" + alertNumberResult.number}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) as the owner.`,
140
146
  userId: createdByUserId || undefined,
141
147
  workspaceNotification: {
142
148
  sendWorkspaceNotification: true,
@@ -55,6 +55,7 @@ import MetricType from "../../Models/DatabaseModels/MetricType";
55
55
  import Dictionary from "../../Types/Dictionary";
56
56
  import OnCallDutyPolicy from "../../Models/DatabaseModels/OnCallDutyPolicy";
57
57
  import AlertGroupingEngineService from "./AlertGroupingEngineService";
58
+ import ProjectService from "./ProjectService";
58
59
 
59
60
  export class Service extends DatabaseService<Model> {
60
61
  public constructor() {
@@ -109,33 +110,6 @@ export class Service extends DatabaseService<Model> {
109
110
  return false;
110
111
  }
111
112
 
112
- @CaptureSpan()
113
- public async getExistingAlertNumberForProject(data: {
114
- projectId: ObjectID;
115
- }): Promise<number> {
116
- // get last alert number.
117
- const lastAlert: Model | null = await this.findOneBy({
118
- query: {
119
- projectId: data.projectId,
120
- },
121
- select: {
122
- alertNumber: true,
123
- },
124
- sort: {
125
- createdAt: SortOrder.Descending,
126
- },
127
- props: {
128
- isRoot: true,
129
- },
130
- });
131
-
132
- if (!lastAlert) {
133
- return 0;
134
- }
135
-
136
- return lastAlert.alertNumber ? Number(lastAlert.alertNumber) : 0;
137
- }
138
-
139
113
  @CaptureSpan()
140
114
  public async acknowledgeAlert(
141
115
  alertId: ObjectID,
@@ -220,12 +194,15 @@ export class Service extends DatabaseService<Model> {
220
194
 
221
195
  createBy.data.currentAlertStateId = alertState.id;
222
196
 
223
- const alertNumberForThisAlert: number =
224
- (await this.getExistingAlertNumberForProject({
225
- projectId: projectId,
226
- })) + 1;
197
+ const alertCounterResult: {
198
+ counter: number;
199
+ prefix: string | undefined;
200
+ } = await ProjectService.incrementAndGetAlertCounter(projectId);
227
201
 
228
- createBy.data.alertNumber = alertNumberForThisAlert;
202
+ createBy.data.alertNumber = alertCounterResult.counter;
203
+ createBy.data.alertNumberWithPrefix = alertCounterResult.prefix
204
+ ? `${alertCounterResult.prefix}${alertCounterResult.counter}`
205
+ : `#${alertCounterResult.counter}`;
229
206
 
230
207
  if (
231
208
  (createBy.data.createdByUserId ||
@@ -424,6 +401,7 @@ export class Service extends DatabaseService<Model> {
424
401
  select: {
425
402
  projectId: true,
426
403
  alertNumber: true,
404
+ alertNumberWithPrefix: true,
427
405
  title: true,
428
406
  description: true,
429
407
  alertSeverity: {
@@ -460,7 +438,7 @@ export class Service extends DatabaseService<Model> {
460
438
  const createdByUserId: ObjectID | undefined | null =
461
439
  alert.createdByUserId || alert.createdByUser?.id;
462
440
 
463
- let feedInfoInMarkdown: string = `#### 🚨 Alert ${alert.alertNumber?.toString()} Created:
441
+ let feedInfoInMarkdown: string = `#### 🚨 Alert ${alert.alertNumberWithPrefix || "#" + alert.alertNumber?.toString()} Created:
464
442
 
465
443
  **${alert.title || "No title provided."}**:
466
444
 
@@ -800,6 +778,7 @@ ${alert.remediationNotes || "No remediation notes provided."}
800
778
  select: {
801
779
  projectId: true,
802
780
  alertNumber: true,
781
+ alertNumberWithPrefix: true,
803
782
  },
804
783
  props: {
805
784
  isRoot: true,
@@ -808,8 +787,10 @@ ${alert.remediationNotes || "No remediation notes provided."}
808
787
 
809
788
  const projectId: ObjectID = alert!.projectId!;
810
789
  const alertNumber: number = alert!.alertNumber!;
790
+ const alertNumberWithPrefix: string | undefined =
791
+ alert!.alertNumberWithPrefix || undefined;
811
792
 
812
- let feedInfoInMarkdown: string = `**[Alert ${alertNumber}](${(await this.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) was updated.**`;
793
+ let feedInfoInMarkdown: string = `**[Alert ${alertNumberWithPrefix || "#" + alertNumber}](${(await this.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) was updated.**`;
813
794
 
814
795
  const createdByUserId: ObjectID | undefined | null =
815
796
  onUpdate.updateBy.props.userId;
@@ -1404,13 +1385,15 @@ ${alertSeverity.name}
1404
1385
  }
1405
1386
 
1406
1387
  @CaptureSpan()
1407
- public async getAlertNumber(data: {
1408
- alertId: ObjectID;
1409
- }): Promise<number | null> {
1388
+ public async getAlertNumber(data: { alertId: ObjectID }): Promise<{
1389
+ number: number | null;
1390
+ numberWithPrefix: string | null;
1391
+ }> {
1410
1392
  const alert: Model | null = await this.findOneById({
1411
1393
  id: data.alertId,
1412
1394
  select: {
1413
1395
  alertNumber: true,
1396
+ alertNumberWithPrefix: true,
1414
1397
  },
1415
1398
  props: {
1416
1399
  isRoot: true,
@@ -1421,7 +1404,10 @@ ${alertSeverity.name}
1421
1404
  throw new BadDataException("Alert not found.");
1422
1405
  }
1423
1406
 
1424
- return alert.alertNumber ? Number(alert.alertNumber) : null;
1407
+ return {
1408
+ number: alert.alertNumber ? Number(alert.alertNumber) : null,
1409
+ numberWithPrefix: alert.alertNumberWithPrefix || null,
1410
+ };
1425
1411
  }
1426
1412
 
1427
1413
  @CaptureSpan()
@@ -400,7 +400,10 @@ export class Service extends DatabaseService<AlertStateTimeline> {
400
400
  stateEmoji = "🔴";
401
401
  }
402
402
 
403
- const alertNumber: number | null = await AlertService.getAlertNumber({
403
+ const alertNumberResult: {
404
+ number: number | null;
405
+ numberWithPrefix: string | null;
406
+ } = await AlertService.getAlertNumber({
404
407
  alertId: createdItem.alertId,
405
408
  });
406
409
 
@@ -414,7 +417,7 @@ export class Service extends DatabaseService<AlertStateTimeline> {
414
417
  displayColor: alertState?.color,
415
418
  feedInfoInMarkdown:
416
419
  stateEmoji +
417
- ` Changed **[Alert ${alertNumber}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) State** to **` +
420
+ ` Changed **[Alert ${alertNumberResult.numberWithPrefix || "#" + alertNumberResult.number}](${(await AlertService.getAlertLinkInDashboard(projectId!, alertId!)).toString()}) State** to **` +
418
421
  stateName +
419
422
  "**",
420
423
  moreInformationInMarkdown: `**Cause:**
@@ -464,7 +467,7 @@ ${createdItem.rootCause}`,
464
467
  },
465
468
  sendMessageBeforeArchiving: {
466
469
  _type: "WorkspacePayloadMarkdown",
467
- text: `**[Alert ${alertNumber}](${(
470
+ text: `**[Alert ${alertNumberResult.numberWithPrefix || "#" + alertNumberResult.number}](${(
468
471
  await AlertService.getAlertLinkInDashboard(
469
472
  createdItem.projectId!,
470
473
  createdItem.alertId!,
@@ -1679,6 +1679,18 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
1679
1679
  });
1680
1680
  }
1681
1681
 
1682
+ @CaptureSpan()
1683
+ protected async atomicIncrementColumnValueByOne(data: {
1684
+ id: ObjectID;
1685
+ columnName: keyof TBaseModel;
1686
+ }): Promise<void> {
1687
+ await this.getRepository().increment(
1688
+ { _id: data.id.toString() } as any,
1689
+ data.columnName as string,
1690
+ 1,
1691
+ );
1692
+ }
1693
+
1682
1694
  @CaptureSpan()
1683
1695
  public async searchBy({
1684
1696
  skip,
@@ -122,6 +122,7 @@ export class Service extends DatabaseService<Model> {
122
122
  id: createdItem.incidentId,
123
123
  select: {
124
124
  incidentNumber: true,
125
+ incidentNumberWithPrefix: true,
125
126
  title: true,
126
127
  },
127
128
  props: {
@@ -135,6 +136,7 @@ export class Service extends DatabaseService<Model> {
135
136
  id: createdItem.incidentEpisodeId,
136
137
  select: {
137
138
  episodeNumber: true,
139
+ episodeNumberWithPrefix: true,
138
140
  title: true,
139
141
  },
140
142
  props: {
@@ -148,7 +150,7 @@ export class Service extends DatabaseService<Model> {
148
150
  projectId: createdItem.projectId,
149
151
  incidentEpisodeFeedEventType: IncidentEpisodeFeedEventType.IncidentAdded,
150
152
  displayColor: Yellow500,
151
- feedInfoInMarkdown: `**Incident #${incident?.incidentNumber || "N/A"}** added to episode: ${incident?.title || "No title"}`,
153
+ feedInfoInMarkdown: `**Incident ${incident?.incidentNumberWithPrefix || "#" + (incident?.incidentNumber || "N/A")}** added to episode: ${incident?.title || "No title"}`,
152
154
  userId: createdItem.addedByUserId || undefined,
153
155
  });
154
156
 
@@ -158,7 +160,7 @@ export class Service extends DatabaseService<Model> {
158
160
  projectId: createdItem.projectId,
159
161
  incidentFeedEventType: IncidentFeedEventType.IncidentUpdated,
160
162
  displayColor: Yellow500,
161
- feedInfoInMarkdown: `Added to **Episode #${episode?.episodeNumber || "N/A"}**: ${episode?.title || "No title"}`,
163
+ feedInfoInMarkdown: `Added to **Episode ${episode?.episodeNumberWithPrefix || "#" + (episode?.episodeNumber || "N/A")}**: ${episode?.title || "No title"}`,
162
164
  userId: createdItem.addedByUserId || undefined,
163
165
  });
164
166
 
@@ -216,6 +218,7 @@ export class Service extends DatabaseService<Model> {
216
218
  id: member.incidentId,
217
219
  select: {
218
220
  incidentNumber: true,
221
+ incidentNumberWithPrefix: true,
219
222
  title: true,
220
223
  },
221
224
  props: {
@@ -231,6 +234,7 @@ export class Service extends DatabaseService<Model> {
231
234
  id: member.incidentEpisodeId,
232
235
  select: {
233
236
  episodeNumber: true,
237
+ episodeNumberWithPrefix: true,
234
238
  title: true,
235
239
  },
236
240
  props: {
@@ -245,7 +249,7 @@ export class Service extends DatabaseService<Model> {
245
249
  incidentEpisodeFeedEventType:
246
250
  IncidentEpisodeFeedEventType.IncidentRemoved,
247
251
  displayColor: Green500,
248
- feedInfoInMarkdown: `**Incident #${incident?.incidentNumber || "N/A"}** removed from episode: ${incident?.title || "No title"}`,
252
+ feedInfoInMarkdown: `**Incident ${incident?.incidentNumberWithPrefix || "#" + (incident?.incidentNumber || "N/A")}** removed from episode: ${incident?.title || "No title"}`,
249
253
  });
250
254
 
251
255
  // Create feed item on incident
@@ -254,7 +258,7 @@ export class Service extends DatabaseService<Model> {
254
258
  projectId: member.projectId,
255
259
  incidentFeedEventType: IncidentFeedEventType.IncidentUpdated,
256
260
  displayColor: Green500,
257
- feedInfoInMarkdown: `Removed from **Episode #${episode?.episodeNumber || "N/A"}**: ${episode?.title || "No title"}`,
261
+ feedInfoInMarkdown: `Removed from **Episode ${episode?.episodeNumberWithPrefix || "#" + (episode?.episodeNumber || "N/A")}**: ${episode?.title || "No title"}`,
258
262
  });
259
263
  }
260
264
  }
@@ -0,0 +1,257 @@
1
+ import CreateBy from "../Types/Database/CreateBy";
2
+ import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
3
+ import DatabaseService from "./DatabaseService";
4
+ import OneUptimeDate from "../../Types/Date";
5
+ import Model from "../../Models/DatabaseModels/IncidentEpisodePublicNote";
6
+ import IncidentEpisodeFeedService from "./IncidentEpisodeFeedService";
7
+ import { IncidentEpisodeFeedEventType } from "../../Models/DatabaseModels/IncidentEpisodeFeed";
8
+ import { Blue500, Indigo500 } from "../../Types/BrandColors";
9
+ import ObjectID from "../../Types/ObjectID";
10
+ import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
11
+ import IncidentEpisodeService from "./IncidentEpisodeService";
12
+ import IncidentEpisode from "../../Models/DatabaseModels/IncidentEpisode";
13
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
14
+ import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
15
+ import File from "../../Models/DatabaseModels/File";
16
+ import FileAttachmentMarkdownUtil from "../Utils/FileAttachmentMarkdownUtil";
17
+
18
+ export class Service extends DatabaseService<Model> {
19
+ public constructor() {
20
+ super(Model);
21
+ }
22
+
23
+ @CaptureSpan()
24
+ public async addNote(data: {
25
+ userId: ObjectID;
26
+ incidentEpisodeId: ObjectID;
27
+ projectId: ObjectID;
28
+ note: string;
29
+ attachmentFileIds?: Array<ObjectID>;
30
+ postedFromSlackMessageId?: string;
31
+ }): Promise<Model> {
32
+ const publicNote: Model = new Model();
33
+ publicNote.createdByUserId = data.userId;
34
+ publicNote.incidentEpisodeId = data.incidentEpisodeId;
35
+ publicNote.projectId = data.projectId;
36
+ publicNote.note = data.note;
37
+ publicNote.postedAt = OneUptimeDate.getCurrentDate();
38
+
39
+ if (data.postedFromSlackMessageId) {
40
+ publicNote.postedFromSlackMessageId = data.postedFromSlackMessageId;
41
+ }
42
+
43
+ if (data.attachmentFileIds && data.attachmentFileIds.length > 0) {
44
+ publicNote.attachments = data.attachmentFileIds.map(
45
+ (fileId: ObjectID) => {
46
+ const file: File = new File();
47
+ file.id = fileId;
48
+ return file;
49
+ },
50
+ );
51
+ }
52
+
53
+ return this.create({
54
+ data: publicNote,
55
+ props: {
56
+ isRoot: true,
57
+ },
58
+ });
59
+ }
60
+
61
+ @CaptureSpan()
62
+ public async hasNoteFromSlackMessage(data: {
63
+ incidentEpisodeId: ObjectID;
64
+ postedFromSlackMessageId: string;
65
+ }): Promise<boolean> {
66
+ const existingNote: Model | null = await this.findOneBy({
67
+ query: {
68
+ incidentEpisodeId: data.incidentEpisodeId,
69
+ postedFromSlackMessageId: data.postedFromSlackMessageId,
70
+ },
71
+ select: {
72
+ _id: true,
73
+ },
74
+ props: {
75
+ isRoot: true,
76
+ },
77
+ });
78
+
79
+ return existingNote !== null;
80
+ }
81
+
82
+ @CaptureSpan()
83
+ protected override async onBeforeCreate(
84
+ createBy: CreateBy<Model>,
85
+ ): Promise<OnCreate<Model>> {
86
+ if (!createBy.data.postedAt) {
87
+ createBy.data.postedAt = OneUptimeDate.getCurrentDate();
88
+ }
89
+
90
+ // Set notification status based on shouldStatusPageSubscribersBeNotifiedOnNoteCreated
91
+ if (
92
+ createBy.data.shouldStatusPageSubscribersBeNotifiedOnNoteCreated === false
93
+ ) {
94
+ createBy.data.subscriberNotificationStatusOnNoteCreated =
95
+ StatusPageSubscriberNotificationStatus.Skipped;
96
+ createBy.data.subscriberNotificationStatusMessage =
97
+ "Notifications skipped as subscribers are not to be notified for this episode note.";
98
+ } else if (
99
+ createBy.data.shouldStatusPageSubscribersBeNotifiedOnNoteCreated === true
100
+ ) {
101
+ createBy.data.subscriberNotificationStatusOnNoteCreated =
102
+ StatusPageSubscriberNotificationStatus.Pending;
103
+ }
104
+
105
+ return {
106
+ createBy: createBy,
107
+ carryForward: null,
108
+ };
109
+ }
110
+
111
+ @CaptureSpan()
112
+ public override async onCreateSuccess(
113
+ _onCreate: OnCreate<Model>,
114
+ createdItem: Model,
115
+ ): Promise<Model> {
116
+ const userId: ObjectID | null | undefined =
117
+ createdItem.createdByUserId || createdItem.createdByUser?.id;
118
+
119
+ const incidentEpisodeId: ObjectID = createdItem.incidentEpisodeId!;
120
+ const projectId: ObjectID = createdItem.projectId!;
121
+ const episodeNumberResult: {
122
+ number: number | null;
123
+ numberWithPrefix: string | null;
124
+ } = await IncidentEpisodeService.getEpisodeNumber({
125
+ episodeId: incidentEpisodeId,
126
+ });
127
+
128
+ const attachmentsMarkdown: string = await this.getAttachmentsMarkdown(
129
+ createdItem.id!,
130
+ "/incident-episode-public-note/attachment",
131
+ );
132
+
133
+ await IncidentEpisodeFeedService.createIncidentEpisodeFeedItem({
134
+ incidentEpisodeId: createdItem.incidentEpisodeId!,
135
+ projectId: createdItem.projectId!,
136
+ incidentEpisodeFeedEventType: IncidentEpisodeFeedEventType.PublicNote,
137
+ displayColor: Indigo500,
138
+ userId: userId || undefined,
139
+ feedInfoInMarkdown: `📄 posted **public note** for this [Episode ${episodeNumberResult.numberWithPrefix || "#" + episodeNumberResult.number}](${(await IncidentEpisodeService.getEpisodeLinkInDashboard(projectId!, incidentEpisodeId!)).toString()}) on status page:
140
+
141
+ ${(createdItem.note || "") + attachmentsMarkdown}
142
+ `,
143
+ });
144
+
145
+ return createdItem;
146
+ }
147
+
148
+ @CaptureSpan()
149
+ public override async onUpdateSuccess(
150
+ onUpdate: OnUpdate<Model>,
151
+ _updatedItemIds: Array<ObjectID>,
152
+ ): Promise<OnUpdate<Model>> {
153
+ if (onUpdate.updateBy.data.note) {
154
+ const updatedItems: Array<Model> = await this.findBy({
155
+ query: onUpdate.updateBy.query,
156
+ limit: LIMIT_PER_PROJECT,
157
+ skip: 0,
158
+ props: {
159
+ isRoot: true,
160
+ },
161
+ select: {
162
+ incidentEpisodeId: true,
163
+ projectId: true,
164
+ incidentEpisode: {
165
+ _id: true,
166
+ episodeNumber: true,
167
+ episodeNumberWithPrefix: true,
168
+ projectId: true,
169
+ },
170
+ note: true,
171
+ createdByUserId: true,
172
+ createdByUser: {
173
+ _id: true,
174
+ },
175
+ },
176
+ });
177
+
178
+ const userId: ObjectID | null | undefined =
179
+ onUpdate.updateBy.props.userId;
180
+
181
+ for (const updatedItem of updatedItems) {
182
+ const episode: IncidentEpisode = updatedItem.incidentEpisode!;
183
+
184
+ const attachmentsMarkdown: string = await this.getAttachmentsMarkdown(
185
+ updatedItem.id!,
186
+ "/incident-episode-public-note/attachment",
187
+ );
188
+
189
+ await IncidentEpisodeFeedService.createIncidentEpisodeFeedItem({
190
+ incidentEpisodeId: updatedItem.incidentEpisodeId!,
191
+ projectId: updatedItem.projectId!,
192
+ incidentEpisodeFeedEventType: IncidentEpisodeFeedEventType.PublicNote,
193
+ displayColor: Blue500,
194
+ userId: userId || undefined,
195
+ feedInfoInMarkdown: `📄 updated **Public Note** for this [Episode ${episode.episodeNumberWithPrefix || "#" + episode.episodeNumber}](${(await IncidentEpisodeService.getEpisodeLinkInDashboard(episode.projectId!, episode.id!)).toString()})
196
+
197
+ ${(updatedItem.note || "") + attachmentsMarkdown}
198
+ `,
199
+ });
200
+ }
201
+ }
202
+ return onUpdate;
203
+ }
204
+
205
+ private async getAttachmentsMarkdown(
206
+ modelId: ObjectID,
207
+ attachmentApiPath: string,
208
+ ): Promise<string> {
209
+ if (!modelId) {
210
+ return "";
211
+ }
212
+
213
+ const noteWithAttachments: Model | null = await this.findOneById({
214
+ id: modelId,
215
+ select: {
216
+ attachments: {
217
+ _id: true,
218
+ },
219
+ },
220
+ props: {
221
+ isRoot: true,
222
+ },
223
+ });
224
+
225
+ if (!noteWithAttachments || !noteWithAttachments.attachments) {
226
+ return "";
227
+ }
228
+
229
+ const attachmentIds: Array<ObjectID> = noteWithAttachments.attachments
230
+ .map((file: File) => {
231
+ if (file.id) {
232
+ return file.id;
233
+ }
234
+
235
+ if (file._id) {
236
+ return new ObjectID(file._id);
237
+ }
238
+
239
+ return null;
240
+ })
241
+ .filter((id: ObjectID | null): id is ObjectID => {
242
+ return Boolean(id);
243
+ });
244
+
245
+ if (!attachmentIds.length) {
246
+ return "";
247
+ }
248
+
249
+ return await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
250
+ modelId,
251
+ attachmentIds,
252
+ attachmentApiPath,
253
+ });
254
+ }
255
+ }
256
+
257
+ export default new Service();