@oneuptime/common 9.4.7 → 9.4.8

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 (304) hide show
  1. package/Models/DatabaseModels/Alert.ts +76 -0
  2. package/Models/DatabaseModels/AlertEpisode.ts +1201 -0
  3. package/Models/DatabaseModels/AlertEpisodeFeed.ts +529 -0
  4. package/Models/DatabaseModels/AlertEpisodeInternalNote.ts +455 -0
  5. package/Models/DatabaseModels/AlertEpisodeMember.ts +586 -0
  6. package/Models/DatabaseModels/AlertEpisodeOwnerTeam.ts +421 -0
  7. package/Models/DatabaseModels/AlertEpisodeOwnerUser.ts +419 -0
  8. package/Models/DatabaseModels/AlertEpisodeStateTimeline.ts +523 -0
  9. package/Models/DatabaseModels/AlertFeed.ts +1 -0
  10. package/Models/DatabaseModels/AlertGroupingRule.ts +1432 -0
  11. package/Models/DatabaseModels/Index.ts +18 -0
  12. package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +70 -0
  13. package/Models/DatabaseModels/StatusPageDomain.ts +2 -0
  14. package/Models/DatabaseModels/WorkspaceNotificationLog.ts +57 -0
  15. package/Server/API/SlackAPI.ts +21 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1768938069147-MigrationName.ts +751 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1769125561322-MigrationName.ts +41 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1769170578688-MigrationName.ts +29 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1769172358833-MigrationName.ts +177 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1769176450526-MigrationName.ts +71 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1769190495840-MigrationName.ts +35 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1769199303656-MigrationName.ts +29 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1769202898645-MigrationName.ts +29 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1769428619414-MigrationName.ts +35 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1769428821686-MigrationName.ts +47 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +20 -0
  27. package/Server/Services/AlertEpisodeFeedService.ts +94 -0
  28. package/Server/Services/AlertEpisodeInternalNoteService.ts +71 -0
  29. package/Server/Services/AlertEpisodeMemberService.ts +267 -0
  30. package/Server/Services/AlertEpisodeOwnerTeamService.ts +10 -0
  31. package/Server/Services/AlertEpisodeOwnerUserService.ts +10 -0
  32. package/Server/Services/AlertEpisodeService.ts +988 -0
  33. package/Server/Services/AlertEpisodeStateTimelineService.ts +557 -0
  34. package/Server/Services/AlertGroupingEngineService.ts +1120 -0
  35. package/Server/Services/AlertGroupingRuleService.ts +14 -0
  36. package/Server/Services/AlertService.ts +12 -0
  37. package/Server/Services/CallService.ts +2 -0
  38. package/Server/Services/Index.ts +21 -0
  39. package/Server/Services/MailService.ts +5 -0
  40. package/Server/Services/OnCallDutyPolicyService.ts +5 -0
  41. package/Server/Services/SmsService.ts +2 -0
  42. package/Server/Services/UserNotificationSettingService.ts +23 -0
  43. package/Server/Services/WhatsAppService.ts +5 -0
  44. package/Server/Services/WorkspaceNotificationRuleService.ts +26 -0
  45. package/Server/Utils/AnalyticsDatabase/Statement.ts +6 -2
  46. package/Server/Utils/WhatsAppTemplateUtil.ts +13 -0
  47. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.ts +18 -0
  48. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +689 -0
  49. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +16 -0
  50. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +11 -0
  51. package/Server/Utils/Workspace/Slack/Actions/AlertEpisode.ts +915 -0
  52. package/Server/Utils/Workspace/Slack/Messages/AlertEpisode.ts +120 -0
  53. package/Server/Utils/Workspace/WorkspaceMessages/AlertEpisode.ts +74 -0
  54. package/Tests/Server/Services/AlertEpisodeMemberService.test.ts +200 -0
  55. package/Tests/Server/Services/AlertEpisodeService.test.ts +240 -0
  56. package/Tests/Server/Services/AlertGroupingEngineService.test.ts +542 -0
  57. package/Tests/Server/Services/AlertGroupingRuleService.test.ts +383 -0
  58. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +1 -1
  59. package/Tests/UI/Components/Input.test.tsx +1 -1
  60. package/Tests/UI/Components/TextArea.test.tsx +2 -2
  61. package/Types/BaseDatabase/SortOrder.ts +9 -0
  62. package/Types/Email/EmailTemplateType.ts +5 -0
  63. package/Types/NotificationRule/NotificationRuleType.ts +1 -0
  64. package/Types/NotificationSetting/NotificationSettingEventType.ts +7 -0
  65. package/Types/Permission.ts +309 -0
  66. package/Types/UserNotification/UserNotificationEventType.ts +1 -0
  67. package/Types/WhatsApp/WhatsAppTemplates.ts +20 -0
  68. package/Types/Workspace/NotificationRules/EventType.ts +1 -0
  69. package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +32 -3
  70. package/UI/Components/Accordion/Accordion.tsx +20 -2
  71. package/UI/Components/Alerts/Alert.tsx +1 -0
  72. package/UI/Components/Button/Button.tsx +29 -0
  73. package/UI/Components/CardSelect/CardSelect.tsx +5 -1
  74. package/UI/Components/Checkbox/Checkbox.tsx +7 -3
  75. package/UI/Components/ColorCircle/ColorCircle.tsx +2 -0
  76. package/UI/Components/ColorViewer/ColorViewer.tsx +19 -3
  77. package/UI/Components/CopyableButton/CopyableButton.tsx +22 -5
  78. package/UI/Components/Detail/Detail.tsx +1 -1
  79. package/UI/Components/Dropdown/Dropdown.tsx +14 -1
  80. package/UI/Components/Forms/Fields/FormField.tsx +28 -0
  81. package/UI/Components/FullPageModal/FullPageModal.tsx +35 -4
  82. package/UI/Components/Input/Input.tsx +14 -2
  83. package/UI/Components/Link/Link.tsx +1 -0
  84. package/UI/Components/Loader/Loader.tsx +8 -2
  85. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +76 -1
  86. package/UI/Components/Modal/Modal.tsx +47 -3
  87. package/UI/Components/ModelTable/BaseModelTable.tsx +42 -1
  88. package/UI/Components/MoreMenu/MoreMenu.tsx +84 -2
  89. package/UI/Components/OrderedStatesList/OrderedStatesList.tsx +30 -8
  90. package/UI/Components/Pagination/Pagination.tsx +113 -8
  91. package/UI/Components/ProgressBar/ProgressBar.tsx +12 -2
  92. package/UI/Components/Radio/Radio.tsx +21 -3
  93. package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +54 -27
  94. package/UI/Components/StatusBubble/StatusBubble.tsx +7 -2
  95. package/UI/Components/Table/TableHeader.tsx +20 -3
  96. package/UI/Components/Tabs/Tab.tsx +16 -1
  97. package/UI/Components/Tabs/Tabs.tsx +12 -1
  98. package/UI/Components/TextArea/TextArea.tsx +12 -2
  99. package/UI/Components/Toggle/Toggle.tsx +14 -3
  100. package/UI/Components/Tooltip/Tooltip.tsx +11 -1
  101. package/UI/Components/TopAlert/TopAlert.tsx +2 -0
  102. package/build/dist/Models/DatabaseModels/Alert.js +77 -0
  103. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  104. package/build/dist/Models/DatabaseModels/AlertEpisode.js +1225 -0
  105. package/build/dist/Models/DatabaseModels/AlertEpisode.js.map +1 -0
  106. package/build/dist/Models/DatabaseModels/AlertEpisodeFeed.js +553 -0
  107. package/build/dist/Models/DatabaseModels/AlertEpisodeFeed.js.map +1 -0
  108. package/build/dist/Models/DatabaseModels/AlertEpisodeInternalNote.js +467 -0
  109. package/build/dist/Models/DatabaseModels/AlertEpisodeInternalNote.js.map +1 -0
  110. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js +607 -0
  111. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js.map +1 -0
  112. package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerTeam.js +437 -0
  113. package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerTeam.js.map +1 -0
  114. package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerUser.js +436 -0
  115. package/build/dist/Models/DatabaseModels/AlertEpisodeOwnerUser.js.map +1 -0
  116. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +546 -0
  117. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -0
  118. package/build/dist/Models/DatabaseModels/AlertFeed.js +1 -0
  119. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  120. package/build/dist/Models/DatabaseModels/AlertGroupingRule.js +1437 -0
  121. package/build/dist/Models/DatabaseModels/AlertGroupingRule.js.map +1 -0
  122. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  123. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  124. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +69 -0
  125. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
  126. package/build/dist/Models/DatabaseModels/StatusPageDomain.js +2 -0
  127. package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
  128. package/build/dist/Models/DatabaseModels/WorkspaceNotificationLog.js +58 -0
  129. package/build/dist/Models/DatabaseModels/WorkspaceNotificationLog.js.map +1 -1
  130. package/build/dist/Server/API/SlackAPI.js +18 -0
  131. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  132. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768938069147-MigrationName.js +266 -0
  133. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768938069147-MigrationName.js.map +1 -0
  134. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769125561322-MigrationName.js +20 -0
  135. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769125561322-MigrationName.js.map +1 -0
  136. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769170578688-MigrationName.js +16 -0
  137. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769170578688-MigrationName.js.map +1 -0
  138. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769172358833-MigrationName.js +68 -0
  139. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769172358833-MigrationName.js.map +1 -0
  140. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769176450526-MigrationName.js +30 -0
  141. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769176450526-MigrationName.js.map +1 -0
  142. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769190495840-MigrationName.js +18 -0
  143. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769190495840-MigrationName.js.map +1 -0
  144. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769199303656-MigrationName.js +16 -0
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769199303656-MigrationName.js.map +1 -0
  146. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769202898645-MigrationName.js +16 -0
  147. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769202898645-MigrationName.js.map +1 -0
  148. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769428619414-MigrationName.js +18 -0
  149. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769428619414-MigrationName.js.map +1 -0
  150. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769428821686-MigrationName.js +22 -0
  151. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769428821686-MigrationName.js.map +1 -0
  152. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +20 -0
  153. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  154. package/build/dist/Server/Services/AlertEpisodeFeedService.js +83 -0
  155. package/build/dist/Server/Services/AlertEpisodeFeedService.js.map +1 -0
  156. package/build/dist/Server/Services/AlertEpisodeInternalNoteService.js +70 -0
  157. package/build/dist/Server/Services/AlertEpisodeInternalNoteService.js.map +1 -0
  158. package/build/dist/Server/Services/AlertEpisodeMemberService.js +256 -0
  159. package/build/dist/Server/Services/AlertEpisodeMemberService.js.map +1 -0
  160. package/build/dist/Server/Services/AlertEpisodeOwnerTeamService.js +9 -0
  161. package/build/dist/Server/Services/AlertEpisodeOwnerTeamService.js.map +1 -0
  162. package/build/dist/Server/Services/AlertEpisodeOwnerUserService.js +9 -0
  163. package/build/dist/Server/Services/AlertEpisodeOwnerUserService.js.map +1 -0
  164. package/build/dist/Server/Services/AlertEpisodeService.js +885 -0
  165. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -0
  166. package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js +494 -0
  167. package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js.map +1 -0
  168. package/build/dist/Server/Services/AlertGroupingEngineService.js +893 -0
  169. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -0
  170. package/build/dist/Server/Services/AlertGroupingRuleService.js +13 -0
  171. package/build/dist/Server/Services/AlertGroupingRuleService.js.map +1 -0
  172. package/build/dist/Server/Services/AlertService.js +11 -0
  173. package/build/dist/Server/Services/AlertService.js.map +1 -1
  174. package/build/dist/Server/Services/CallService.js +11 -10
  175. package/build/dist/Server/Services/CallService.js.map +1 -1
  176. package/build/dist/Server/Services/Index.js +18 -0
  177. package/build/dist/Server/Services/Index.js.map +1 -1
  178. package/build/dist/Server/Services/MailService.js +3 -0
  179. package/build/dist/Server/Services/MailService.js.map +1 -1
  180. package/build/dist/Server/Services/OnCallDutyPolicyService.js +3 -0
  181. package/build/dist/Server/Services/OnCallDutyPolicyService.js.map +1 -1
  182. package/build/dist/Server/Services/SmsService.js +11 -10
  183. package/build/dist/Server/Services/SmsService.js.map +1 -1
  184. package/build/dist/Server/Services/UserNotificationSettingService.js +9 -0
  185. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  186. package/build/dist/Server/Services/WhatsAppService.js +3 -0
  187. package/build/dist/Server/Services/WhatsAppService.js.map +1 -1
  188. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +25 -0
  189. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  190. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +4 -2
  191. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  192. package/build/dist/Server/Utils/WhatsAppTemplateUtil.js +8 -0
  193. package/build/dist/Server/Utils/WhatsAppTemplateUtil.js.map +1 -1
  194. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js +17 -0
  195. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js.map +1 -1
  196. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +545 -0
  197. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -0
  198. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +13 -0
  199. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  200. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +10 -0
  201. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
  202. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js +651 -0
  203. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js.map +1 -0
  204. package/build/dist/Server/Utils/Workspace/Slack/Messages/AlertEpisode.js +100 -0
  205. package/build/dist/Server/Utils/Workspace/Slack/Messages/AlertEpisode.js.map +1 -0
  206. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/AlertEpisode.js +70 -0
  207. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/AlertEpisode.js.map +1 -0
  208. package/build/dist/Tests/Server/Services/AlertEpisodeMemberService.test.js +165 -0
  209. package/build/dist/Tests/Server/Services/AlertEpisodeMemberService.test.js.map +1 -0
  210. package/build/dist/Tests/Server/Services/AlertEpisodeService.test.js +193 -0
  211. package/build/dist/Tests/Server/Services/AlertEpisodeService.test.js.map +1 -0
  212. package/build/dist/Tests/Server/Services/AlertGroupingEngineService.test.js +412 -0
  213. package/build/dist/Tests/Server/Services/AlertGroupingEngineService.test.js.map +1 -0
  214. package/build/dist/Tests/Server/Services/AlertGroupingRuleService.test.js +308 -0
  215. package/build/dist/Tests/Server/Services/AlertGroupingRuleService.test.js.map +1 -0
  216. package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js +1 -1
  217. package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js.map +1 -1
  218. package/build/dist/Tests/UI/Components/Input.test.js +1 -1
  219. package/build/dist/Tests/UI/Components/Input.test.js.map +1 -1
  220. package/build/dist/Tests/UI/Components/TextArea.test.js +2 -2
  221. package/build/dist/Tests/UI/Components/TextArea.test.js.map +1 -1
  222. package/build/dist/Types/BaseDatabase/SortOrder.js +5 -0
  223. package/build/dist/Types/BaseDatabase/SortOrder.js.map +1 -1
  224. package/build/dist/Types/Email/EmailTemplateType.js +4 -0
  225. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  226. package/build/dist/Types/NotificationRule/NotificationRuleType.js +1 -0
  227. package/build/dist/Types/NotificationRule/NotificationRuleType.js.map +1 -1
  228. package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +5 -0
  229. package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
  230. package/build/dist/Types/Permission.js +264 -0
  231. package/build/dist/Types/Permission.js.map +1 -1
  232. package/build/dist/Types/UserNotification/UserNotificationEventType.js +1 -0
  233. package/build/dist/Types/UserNotification/UserNotificationEventType.js.map +1 -1
  234. package/build/dist/Types/WhatsApp/WhatsAppTemplates.js +12 -0
  235. package/build/dist/Types/WhatsApp/WhatsAppTemplates.js.map +1 -1
  236. package/build/dist/Types/Workspace/NotificationRules/EventType.js +1 -0
  237. package/build/dist/Types/Workspace/NotificationRules/EventType.js.map +1 -1
  238. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +28 -3
  239. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
  240. package/build/dist/UI/Components/Accordion/Accordion.js +10 -3
  241. package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
  242. package/build/dist/UI/Components/Alerts/Alert.js +1 -1
  243. package/build/dist/UI/Components/Alerts/Alert.js.map +1 -1
  244. package/build/dist/UI/Components/Button/Button.js +8 -2
  245. package/build/dist/UI/Components/Button/Button.js.map +1 -1
  246. package/build/dist/UI/Components/CardSelect/CardSelect.js +1 -1
  247. package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
  248. package/build/dist/UI/Components/Checkbox/Checkbox.js +2 -2
  249. package/build/dist/UI/Components/Checkbox/Checkbox.js.map +1 -1
  250. package/build/dist/UI/Components/ColorCircle/ColorCircle.js +1 -1
  251. package/build/dist/UI/Components/ColorCircle/ColorCircle.js.map +1 -1
  252. package/build/dist/UI/Components/ColorViewer/ColorViewer.js +12 -3
  253. package/build/dist/UI/Components/ColorViewer/ColorViewer.js.map +1 -1
  254. package/build/dist/UI/Components/CopyableButton/CopyableButton.js +12 -5
  255. package/build/dist/UI/Components/CopyableButton/CopyableButton.js.map +1 -1
  256. package/build/dist/UI/Components/Detail/Detail.js +1 -1
  257. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  258. package/build/dist/UI/Components/Dropdown/Dropdown.js +5 -3
  259. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  260. package/build/dist/UI/Components/Forms/Fields/FormField.js +19 -1
  261. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  262. package/build/dist/UI/Components/FullPageModal/FullPageModal.js +24 -5
  263. package/build/dist/UI/Components/FullPageModal/FullPageModal.js.map +1 -1
  264. package/build/dist/UI/Components/Input/Input.js +3 -3
  265. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  266. package/build/dist/UI/Components/Link/Link.js +1 -1
  267. package/build/dist/UI/Components/Link/Link.js.map +1 -1
  268. package/build/dist/UI/Components/Loader/Loader.js +6 -4
  269. package/build/dist/UI/Components/Loader/Loader.js.map +1 -1
  270. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +56 -3
  271. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  272. package/build/dist/UI/Components/Modal/Modal.js +28 -3
  273. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  274. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +23 -1
  275. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  276. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +67 -6
  277. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  278. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js +14 -3
  279. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js.map +1 -1
  280. package/build/dist/UI/Components/Pagination/Pagination.js +69 -13
  281. package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
  282. package/build/dist/UI/Components/ProgressBar/ProgressBar.js +2 -2
  283. package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
  284. package/build/dist/UI/Components/Radio/Radio.js +8 -5
  285. package/build/dist/UI/Components/Radio/Radio.js.map +1 -1
  286. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +23 -4
  287. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
  288. package/build/dist/UI/Components/StatusBubble/StatusBubble.js +2 -2
  289. package/build/dist/UI/Components/StatusBubble/StatusBubble.js.map +1 -1
  290. package/build/dist/UI/Components/Table/TableHeader.js +12 -4
  291. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  292. package/build/dist/UI/Components/Tabs/Tab.js +8 -1
  293. package/build/dist/UI/Components/Tabs/Tab.js.map +1 -1
  294. package/build/dist/UI/Components/Tabs/Tabs.js +4 -3
  295. package/build/dist/UI/Components/Tabs/Tabs.js.map +1 -1
  296. package/build/dist/UI/Components/TextArea/TextArea.js +3 -3
  297. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  298. package/build/dist/UI/Components/Toggle/Toggle.js +7 -4
  299. package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
  300. package/build/dist/UI/Components/Tooltip/Tooltip.js +4 -1
  301. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  302. package/build/dist/UI/Components/TopAlert/TopAlert.js +1 -1
  303. package/build/dist/UI/Components/TopAlert/TopAlert.js.map +1 -1
  304. package/package.json +2 -1
@@ -0,0 +1,893 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import ObjectID from "../../Types/ObjectID";
11
+ import AlertGroupingRule from "../../Models/DatabaseModels/AlertGroupingRule";
12
+ import Alert from "../../Models/DatabaseModels/Alert";
13
+ import AlertEpisode from "../../Models/DatabaseModels/AlertEpisode";
14
+ import AlertEpisodeMember, { AlertEpisodeMemberAddedBy, } from "../../Models/DatabaseModels/AlertEpisodeMember";
15
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
16
+ import logger from "../Utils/Logger";
17
+ import SortOrder from "../../Types/BaseDatabase/SortOrder";
18
+ import OneUptimeDate from "../../Types/Date";
19
+ import QueryHelper from "../Types/Database/QueryHelper";
20
+ import AlertGroupingRuleService from "./AlertGroupingRuleService";
21
+ import AlertEpisodeService from "./AlertEpisodeService";
22
+ import AlertEpisodeMemberService from "./AlertEpisodeMemberService";
23
+ import MonitorService from "./MonitorService";
24
+ import ServiceMonitorService from "./ServiceMonitorService";
25
+ import Semaphore from "../Infrastructure/Semaphore";
26
+ import AlertEpisodeFeedService from "./AlertEpisodeFeedService";
27
+ import AlertFeedService from "./AlertFeedService";
28
+ import { AlertEpisodeFeedEventType } from "../../Models/DatabaseModels/AlertEpisodeFeed";
29
+ import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
30
+ import { Green500, Purple500 } from "../../Types/BrandColors";
31
+ class AlertGroupingEngineServiceClass {
32
+ async processAlert(alert) {
33
+ logger.debug(`Processing alert ${alert.id} for grouping`);
34
+ try {
35
+ if (!alert.id || !alert.projectId) {
36
+ logger.warn("Alert missing id or projectId, skipping grouping");
37
+ return { grouped: false };
38
+ }
39
+ // If alert already has an episode, don't reprocess
40
+ if (alert.alertEpisodeId) {
41
+ return { grouped: true, episodeId: alert.alertEpisodeId };
42
+ }
43
+ // Get enabled rules sorted by priority
44
+ const rules = await AlertGroupingRuleService.findBy({
45
+ query: {
46
+ projectId: alert.projectId,
47
+ isEnabled: true,
48
+ },
49
+ sort: {
50
+ priority: SortOrder.Ascending,
51
+ },
52
+ props: {
53
+ isRoot: true,
54
+ },
55
+ select: {
56
+ _id: true,
57
+ name: true,
58
+ priority: true,
59
+ // Match criteria fields
60
+ monitors: {
61
+ _id: true,
62
+ },
63
+ alertSeverities: {
64
+ _id: true,
65
+ },
66
+ alertLabels: {
67
+ _id: true,
68
+ },
69
+ monitorLabels: {
70
+ _id: true,
71
+ },
72
+ alertTitlePattern: true,
73
+ alertDescriptionPattern: true,
74
+ monitorNamePattern: true,
75
+ monitorDescriptionPattern: true,
76
+ // Group by fields
77
+ groupByMonitor: true,
78
+ groupBySeverity: true,
79
+ groupByAlertTitle: true,
80
+ groupByService: true,
81
+ // Time settings
82
+ enableTimeWindow: true,
83
+ timeWindowMinutes: true,
84
+ episodeTitleTemplate: true,
85
+ episodeDescriptionTemplate: true,
86
+ enableResolveDelay: true,
87
+ resolveDelayMinutes: true,
88
+ enableReopenWindow: true,
89
+ reopenWindowMinutes: true,
90
+ enableInactivityTimeout: true,
91
+ inactivityTimeoutMinutes: true,
92
+ defaultAssignToUserId: true,
93
+ defaultAssignToTeamId: true,
94
+ onCallDutyPolicies: {
95
+ _id: true,
96
+ },
97
+ },
98
+ limit: 100,
99
+ skip: 0,
100
+ });
101
+ if (rules.length === 0) {
102
+ logger.debug(`No enabled grouping rules found for project ${alert.projectId}`);
103
+ return { grouped: false };
104
+ }
105
+ logger.debug(`Found ${rules.length} enabled grouping rules for project ${alert.projectId}`);
106
+ // Find first matching rule
107
+ for (const rule of rules) {
108
+ const matches = await this.doesAlertMatchRule(alert, rule);
109
+ if (matches) {
110
+ logger.debug(`Alert ${alert.id} matches rule ${rule.name || rule.id}`);
111
+ // Try to find existing episode or create new one
112
+ const result = await this.groupAlertWithRule(alert, rule);
113
+ return result;
114
+ }
115
+ }
116
+ logger.debug(`Alert ${alert.id} did not match any grouping rules`);
117
+ return { grouped: false };
118
+ }
119
+ catch (error) {
120
+ logger.error(`Error processing alert for grouping: ${error}`);
121
+ return { grouped: false };
122
+ }
123
+ }
124
+ async doesAlertMatchRule(alert, rule) {
125
+ logger.debug(`Checking if alert ${alert.id} matches rule ${rule.name || rule.id}`);
126
+ // Check monitor IDs - if monitors are specified, alert must be from one of them
127
+ if (rule.monitors && rule.monitors.length > 0) {
128
+ if (!alert.monitorId) {
129
+ return false;
130
+ }
131
+ const monitorIds = rule.monitors.map((m) => {
132
+ var _a;
133
+ return ((_a = m.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
134
+ });
135
+ const alertMonitorIdStr = alert.monitorId.toString();
136
+ if (!monitorIds.includes(alertMonitorIdStr)) {
137
+ return false;
138
+ }
139
+ }
140
+ // Check alert severity IDs - if severities are specified, alert must have one of them
141
+ if (rule.alertSeverities && rule.alertSeverities.length > 0) {
142
+ if (!alert.alertSeverityId) {
143
+ return false;
144
+ }
145
+ const severityIds = rule.alertSeverities.map((s) => {
146
+ var _a;
147
+ return ((_a = s.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
148
+ });
149
+ const alertSeverityIdStr = alert.alertSeverityId.toString();
150
+ if (!severityIds.includes(alertSeverityIdStr)) {
151
+ return false;
152
+ }
153
+ }
154
+ // Check alert label IDs - if alert labels are specified, alert must have at least one of them
155
+ if (rule.alertLabels && rule.alertLabels.length > 0) {
156
+ if (!alert.labels || alert.labels.length === 0) {
157
+ return false;
158
+ }
159
+ const ruleLabelIds = rule.alertLabels.map((l) => {
160
+ var _a;
161
+ return ((_a = l.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
162
+ });
163
+ const alertLabelIds = alert.labels.map((l) => {
164
+ var _a;
165
+ return ((_a = l.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
166
+ });
167
+ const hasMatchingLabel = ruleLabelIds.some((labelId) => {
168
+ return alertLabelIds.includes(labelId);
169
+ });
170
+ if (!hasMatchingLabel) {
171
+ return false;
172
+ }
173
+ }
174
+ // Check monitor-related criteria (labels, name pattern, description pattern)
175
+ const hasMonitorCriteria = Boolean((rule.monitorLabels && rule.monitorLabels.length > 0) ||
176
+ rule.monitorNamePattern ||
177
+ rule.monitorDescriptionPattern);
178
+ if (hasMonitorCriteria) {
179
+ if (!alert.monitorId) {
180
+ return false;
181
+ }
182
+ // Load monitor with all needed fields
183
+ const monitor = await MonitorService.findOneById({
184
+ id: alert.monitorId,
185
+ select: {
186
+ name: true,
187
+ description: true,
188
+ labels: {
189
+ _id: true,
190
+ },
191
+ },
192
+ props: {
193
+ isRoot: true,
194
+ },
195
+ });
196
+ if (!monitor) {
197
+ return false;
198
+ }
199
+ // Check monitor labels
200
+ if (rule.monitorLabels && rule.monitorLabels.length > 0) {
201
+ if (!monitor.labels || monitor.labels.length === 0) {
202
+ return false;
203
+ }
204
+ const ruleMonitorLabelIds = rule.monitorLabels.map((l) => {
205
+ var _a;
206
+ return ((_a = l.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
207
+ });
208
+ const monitorLabelIds = monitor.labels.map((l) => {
209
+ var _a;
210
+ return ((_a = l.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
211
+ });
212
+ const hasMatchingMonitorLabel = ruleMonitorLabelIds.some((labelId) => {
213
+ return monitorLabelIds.includes(labelId);
214
+ });
215
+ if (!hasMatchingMonitorLabel) {
216
+ return false;
217
+ }
218
+ }
219
+ // Check monitor name pattern (regex)
220
+ if (rule.monitorNamePattern) {
221
+ if (!monitor.name) {
222
+ return false;
223
+ }
224
+ try {
225
+ const regex = new RegExp(rule.monitorNamePattern, "i");
226
+ if (!regex.test(monitor.name)) {
227
+ return false;
228
+ }
229
+ }
230
+ catch (_a) {
231
+ logger.warn(`Invalid regex pattern in rule ${rule.id}: ${rule.monitorNamePattern}`);
232
+ return false;
233
+ }
234
+ }
235
+ // Check monitor description pattern (regex)
236
+ if (rule.monitorDescriptionPattern) {
237
+ if (!monitor.description) {
238
+ return false;
239
+ }
240
+ try {
241
+ const regex = new RegExp(rule.monitorDescriptionPattern, "i");
242
+ if (!regex.test(monitor.description)) {
243
+ return false;
244
+ }
245
+ }
246
+ catch (_b) {
247
+ logger.warn(`Invalid regex pattern in rule ${rule.id}: ${rule.monitorDescriptionPattern}`);
248
+ return false;
249
+ }
250
+ }
251
+ }
252
+ // Check alert title pattern (regex)
253
+ if (rule.alertTitlePattern) {
254
+ if (!alert.title) {
255
+ return false;
256
+ }
257
+ try {
258
+ const regex = new RegExp(rule.alertTitlePattern, "i");
259
+ if (!regex.test(alert.title)) {
260
+ return false;
261
+ }
262
+ }
263
+ catch (_c) {
264
+ logger.warn(`Invalid regex pattern in rule ${rule.id}: ${rule.alertTitlePattern}`);
265
+ return false;
266
+ }
267
+ }
268
+ // Check alert description pattern (regex)
269
+ if (rule.alertDescriptionPattern) {
270
+ if (!alert.description) {
271
+ return false;
272
+ }
273
+ try {
274
+ const regex = new RegExp(rule.alertDescriptionPattern, "i");
275
+ if (!regex.test(alert.description)) {
276
+ return false;
277
+ }
278
+ }
279
+ catch (_d) {
280
+ logger.warn(`Invalid regex pattern in rule ${rule.id}: ${rule.alertDescriptionPattern}`);
281
+ return false;
282
+ }
283
+ }
284
+ // If no criteria specified (all fields empty), rule matches all alerts
285
+ logger.debug(`Rule ${rule.name || rule.id} matched alert ${alert.id} (all criteria passed)`);
286
+ return true;
287
+ }
288
+ async groupAlertWithRule(alert, rule) {
289
+ var _a, _b;
290
+ // Build the grouping key based on groupBy fields
291
+ const groupingKey = await this.buildGroupingKey(alert, rule);
292
+ // Create mutex key to prevent race conditions when creating episodes
293
+ const mutexKey = `${(_a = alert.projectId) === null || _a === void 0 ? void 0 : _a.toString()}-${(_b = rule.id) === null || _b === void 0 ? void 0 : _b.toString()}-${groupingKey}`;
294
+ let mutex = null;
295
+ try {
296
+ /*
297
+ * Acquire mutex to prevent concurrent episode creation for the same grouping key
298
+ * This is critical - we must have the lock before proceeding to prevent race conditions
299
+ */
300
+ logger.debug(`Acquiring mutex for grouping key: ${mutexKey} for alert ${alert.id}`);
301
+ mutex = await Semaphore.lock({
302
+ key: mutexKey,
303
+ namespace: "AlertGroupingEngine.groupAlertWithRule",
304
+ lockTimeout: 30000, // 30 seconds - enough time to complete episode creation
305
+ acquireTimeout: 60000, // Wait up to 60 seconds to acquire the lock
306
+ });
307
+ logger.debug(`Acquired mutex for grouping key: ${mutexKey} for alert ${alert.id}`);
308
+ // Calculate time window cutoff (only if time window is enabled)
309
+ let timeWindowCutoff = null;
310
+ if (rule.enableTimeWindow) {
311
+ const timeWindowMinutes = rule.timeWindowMinutes || 60;
312
+ timeWindowCutoff = OneUptimeDate.getSomeMinutesAgo(timeWindowMinutes);
313
+ }
314
+ // Find existing active episode that matches
315
+ const existingEpisode = await this.findMatchingActiveEpisode(alert.projectId, rule.id, groupingKey, timeWindowCutoff);
316
+ if (existingEpisode && existingEpisode.id) {
317
+ // Add alert to existing episode
318
+ await this.addAlertToEpisode(alert, existingEpisode.id, AlertEpisodeMemberAddedBy.Rule, rule.id, rule, false, // isNewEpisode
319
+ false);
320
+ // Update episode severity if alert has higher severity
321
+ if (alert.alertSeverityId) {
322
+ await AlertEpisodeService.updateEpisodeSeverity({
323
+ episodeId: existingEpisode.id,
324
+ severityId: alert.alertSeverityId,
325
+ onlyIfHigher: true,
326
+ });
327
+ }
328
+ return {
329
+ grouped: true,
330
+ episodeId: existingEpisode.id,
331
+ isNewEpisode: false,
332
+ };
333
+ }
334
+ // Check if we can reopen a recently resolved episode (only if enabled)
335
+ if (rule.enableReopenWindow) {
336
+ const reopenWindowMinutes = rule.reopenWindowMinutes || 0;
337
+ if (reopenWindowMinutes > 0) {
338
+ const reopenCutoff = OneUptimeDate.getSomeMinutesAgo(reopenWindowMinutes);
339
+ const recentlyResolvedEpisode = await this.findRecentlyResolvedEpisode(alert.projectId, rule.id, groupingKey, reopenCutoff);
340
+ if (recentlyResolvedEpisode && recentlyResolvedEpisode.id) {
341
+ // Reopen the episode
342
+ await AlertEpisodeService.reopenEpisode(recentlyResolvedEpisode.id);
343
+ // Add alert to reopened episode
344
+ await this.addAlertToEpisode(alert, recentlyResolvedEpisode.id, AlertEpisodeMemberAddedBy.Rule, rule.id, rule, false, // isNewEpisode
345
+ true);
346
+ // Update episode severity if alert has higher severity
347
+ if (alert.alertSeverityId) {
348
+ await AlertEpisodeService.updateEpisodeSeverity({
349
+ episodeId: recentlyResolvedEpisode.id,
350
+ severityId: alert.alertSeverityId,
351
+ onlyIfHigher: true,
352
+ });
353
+ }
354
+ return {
355
+ grouped: true,
356
+ episodeId: recentlyResolvedEpisode.id,
357
+ isNewEpisode: false,
358
+ wasReopened: true,
359
+ };
360
+ }
361
+ }
362
+ }
363
+ // Create new episode
364
+ const newEpisode = await this.createNewEpisode(alert, rule, groupingKey);
365
+ if (newEpisode && newEpisode.id) {
366
+ // Add alert to new episode
367
+ await this.addAlertToEpisode(alert, newEpisode.id, AlertEpisodeMemberAddedBy.Rule, rule.id, rule, true, // isNewEpisode
368
+ false);
369
+ return { grouped: true, episodeId: newEpisode.id, isNewEpisode: true };
370
+ }
371
+ return { grouped: false };
372
+ }
373
+ finally {
374
+ // Release mutex
375
+ if (mutex) {
376
+ try {
377
+ logger.debug(`Releasing mutex for grouping key: ${mutexKey} for alert ${alert.id}`);
378
+ await Semaphore.release(mutex);
379
+ logger.debug(`Released mutex for grouping key: ${mutexKey} for alert ${alert.id}`);
380
+ }
381
+ catch (err) {
382
+ logger.error(`Error releasing mutex for grouping key: ${mutexKey}: ${err}`);
383
+ }
384
+ }
385
+ }
386
+ }
387
+ async buildGroupingKey(alert, rule) {
388
+ const parts = [];
389
+ /*
390
+ * Group by service - only if explicitly enabled
391
+ * Must be checked before monitor since service contains multiple monitors
392
+ */
393
+ if (rule.groupByService && alert.monitorId) {
394
+ const serviceMonitor = await ServiceMonitorService.findOneBy({
395
+ query: {
396
+ monitorId: alert.monitorId,
397
+ },
398
+ select: {
399
+ serviceId: true,
400
+ },
401
+ props: {
402
+ isRoot: true,
403
+ },
404
+ });
405
+ if (serviceMonitor === null || serviceMonitor === void 0 ? void 0 : serviceMonitor.serviceId) {
406
+ parts.push(`service:${serviceMonitor.serviceId.toString()}`);
407
+ }
408
+ }
409
+ // Group by monitor - only if explicitly enabled
410
+ if (rule.groupByMonitor && alert.monitorId) {
411
+ parts.push(`monitor:${alert.monitorId.toString()}`);
412
+ }
413
+ // Group by severity - only if explicitly enabled
414
+ if (rule.groupBySeverity && alert.alertSeverityId) {
415
+ parts.push(`severity:${alert.alertSeverityId.toString()}`);
416
+ }
417
+ // Group by alert title - only if explicitly enabled
418
+ if (rule.groupByAlertTitle && alert.title) {
419
+ // Normalize title for grouping (remove numbers, etc.)
420
+ const normalizedTitle = alert.title
421
+ .toLowerCase()
422
+ .replace(/\d+/g, "X");
423
+ parts.push(`title:${normalizedTitle}`);
424
+ }
425
+ // If no group by options are enabled, all matching alerts go into a single episode
426
+ return parts.join("|") || "default";
427
+ }
428
+ async findMatchingActiveEpisode(projectId, ruleId, groupingKey, timeWindowCutoff) {
429
+ const query = {
430
+ projectId: projectId,
431
+ alertGroupingRuleId: ruleId,
432
+ groupingKey: groupingKey,
433
+ resolvedAt: null, // Only find active (non-resolved) episodes
434
+ };
435
+ // Only add time window filter if enabled
436
+ if (timeWindowCutoff) {
437
+ query.lastAlertAddedAt = QueryHelper.greaterThanEqualTo(timeWindowCutoff);
438
+ }
439
+ const episode = await AlertEpisodeService.findOneBy({
440
+ query: query,
441
+ sort: {
442
+ lastAlertAddedAt: SortOrder.Descending,
443
+ },
444
+ select: {
445
+ _id: true,
446
+ lastAlertAddedAt: true,
447
+ },
448
+ props: {
449
+ isRoot: true,
450
+ },
451
+ });
452
+ return episode;
453
+ }
454
+ async findRecentlyResolvedEpisode(projectId, ruleId, groupingKey, reopenCutoff) {
455
+ // Find recently resolved episode with matching rule and grouping key
456
+ const episode = await AlertEpisodeService.findOneBy({
457
+ query: {
458
+ projectId: projectId,
459
+ alertGroupingRuleId: ruleId,
460
+ groupingKey: groupingKey,
461
+ resolvedAt: QueryHelper.greaterThanEqualTo(reopenCutoff),
462
+ },
463
+ sort: {
464
+ resolvedAt: SortOrder.Descending,
465
+ },
466
+ select: {
467
+ _id: true,
468
+ resolvedAt: true,
469
+ },
470
+ props: {
471
+ isRoot: true,
472
+ },
473
+ });
474
+ return episode;
475
+ }
476
+ async createNewEpisode(alert, rule, groupingKey) {
477
+ // Generate episode title from template (with initial alertCount of 1)
478
+ const title = this.generateEpisodeTitle(alert, rule.episodeTitleTemplate, 1);
479
+ // Generate episode description from template (with initial alertCount of 1)
480
+ const description = this.generateEpisodeDescription(alert, rule.episodeDescriptionTemplate, 1);
481
+ const newEpisode = new AlertEpisode();
482
+ newEpisode.projectId = alert.projectId;
483
+ newEpisode.title = title;
484
+ if (description) {
485
+ newEpisode.description = description;
486
+ }
487
+ /*
488
+ * Store preprocessed templates for dynamic variable updates
489
+ * Static variables are replaced, dynamic ones (like {{alertCount}}) remain as placeholders
490
+ */
491
+ if (rule.episodeTitleTemplate) {
492
+ newEpisode.titleTemplate = this.preprocessTemplate(alert, rule.episodeTitleTemplate);
493
+ }
494
+ if (rule.episodeDescriptionTemplate) {
495
+ newEpisode.descriptionTemplate = this.preprocessTemplate(alert, rule.episodeDescriptionTemplate);
496
+ }
497
+ newEpisode.alertGroupingRuleId = rule.id;
498
+ newEpisode.groupingKey = groupingKey;
499
+ newEpisode.isManuallyCreated = false;
500
+ // Set severity from alert
501
+ if (alert.alertSeverityId) {
502
+ newEpisode.alertSeverityId = alert.alertSeverityId;
503
+ }
504
+ // Set default ownership from rule
505
+ if (rule.defaultAssignToUserId) {
506
+ newEpisode.assignedToUserId = rule.defaultAssignToUserId;
507
+ }
508
+ if (rule.defaultAssignToTeamId) {
509
+ newEpisode.assignedToTeamId = rule.defaultAssignToTeamId;
510
+ }
511
+ // Copy on-call policies from rule
512
+ if (rule.onCallDutyPolicies && rule.onCallDutyPolicies.length > 0) {
513
+ newEpisode.onCallDutyPolicies = rule.onCallDutyPolicies;
514
+ }
515
+ try {
516
+ const createdEpisode = await AlertEpisodeService.create({
517
+ data: newEpisode,
518
+ props: {
519
+ isRoot: true,
520
+ },
521
+ });
522
+ // Add episode feed entry for episode creation
523
+ if (createdEpisode.id) {
524
+ const groupByParts = [];
525
+ if (rule.groupByMonitor) {
526
+ groupByParts.push("Monitor");
527
+ }
528
+ if (rule.groupBySeverity) {
529
+ groupByParts.push("Severity");
530
+ }
531
+ if (rule.groupByAlertTitle) {
532
+ groupByParts.push("Alert Title");
533
+ }
534
+ if (rule.groupByService) {
535
+ groupByParts.push("Service");
536
+ }
537
+ const groupByDescription = groupByParts.length > 0
538
+ ? `Grouping by: ${groupByParts.join(", ")}`
539
+ : "Grouping all matching alerts together";
540
+ let moreInfo = `**Rule:** ${rule.name || "Unnamed Rule"}\n\n`;
541
+ moreInfo += `**Grouping Key:** \`${groupingKey}\`\n\n`;
542
+ moreInfo += `**${groupByDescription}**`;
543
+ if (rule.enableTimeWindow && rule.timeWindowMinutes) {
544
+ moreInfo += `\n\n**Time Window:** ${rule.timeWindowMinutes} minutes`;
545
+ }
546
+ try {
547
+ await AlertEpisodeFeedService.createAlertEpisodeFeedItem({
548
+ alertEpisodeId: createdEpisode.id,
549
+ projectId: alert.projectId,
550
+ alertEpisodeFeedEventType: AlertEpisodeFeedEventType.EpisodeCreated,
551
+ displayColor: Green500,
552
+ feedInfoInMarkdown: `🔔 **Episode Created** by grouping rule **${rule.name || "Unnamed Rule"}**`,
553
+ moreInformationInMarkdown: moreInfo,
554
+ });
555
+ }
556
+ catch (feedError) {
557
+ logger.error(`Error creating episode feed for episode creation: ${feedError}`);
558
+ }
559
+ }
560
+ return createdEpisode;
561
+ }
562
+ catch (error) {
563
+ logger.error(`Error creating new episode: ${error}`);
564
+ return null;
565
+ }
566
+ }
567
+ generateEpisodeTitle(alert, template, alertCount = 1) {
568
+ var _a;
569
+ if (!template) {
570
+ // Default title based on alert
571
+ if ((_a = alert.monitor) === null || _a === void 0 ? void 0 : _a.name) {
572
+ return `Alert Episode: ${alert.monitor.name}`;
573
+ }
574
+ if (alert.title) {
575
+ return `Alert Episode: ${alert.title.substring(0, 50)}`;
576
+ }
577
+ return "Alert Episode";
578
+ }
579
+ return (this.replaceTemplatePlaceholders(alert, template, alertCount) ||
580
+ "Alert Episode");
581
+ }
582
+ generateEpisodeDescription(alert, template, alertCount = 1) {
583
+ if (!template) {
584
+ return undefined;
585
+ }
586
+ return (this.replaceTemplatePlaceholders(alert, template, alertCount) || undefined);
587
+ }
588
+ replaceTemplatePlaceholders(alert, template, alertCount = 1) {
589
+ var _a, _b;
590
+ let result = template;
591
+ /*
592
+ * Static variables (from first alert)
593
+ * {{alertTitle}}
594
+ */
595
+ if (alert.title) {
596
+ result = result.replace(/\{\{alertTitle\}\}/g, alert.title);
597
+ }
598
+ // {{alertDescription}}
599
+ if (alert.description) {
600
+ result = result.replace(/\{\{alertDescription\}\}/g, alert.description);
601
+ }
602
+ // {{monitorName}}
603
+ if ((_a = alert.monitor) === null || _a === void 0 ? void 0 : _a.name) {
604
+ result = result.replace(/\{\{monitorName\}\}/g, alert.monitor.name);
605
+ }
606
+ // {{alertSeverity}}
607
+ if ((_b = alert.alertSeverity) === null || _b === void 0 ? void 0 : _b.name) {
608
+ result = result.replace(/\{\{alertSeverity\}\}/g, alert.alertSeverity.name);
609
+ }
610
+ /*
611
+ * Dynamic variables (updated when alerts are added/removed)
612
+ * {{alertCount}}
613
+ */
614
+ result = result.replace(/\{\{alertCount\}\}/g, alertCount.toString());
615
+ // Clean up any remaining unknown placeholders
616
+ result = result.replace(/\{\{[^}]+\}\}/g, "");
617
+ return result;
618
+ }
619
+ /*
620
+ * Preprocess template: replace static variables but keep dynamic ones as placeholders
621
+ * This is stored on the episode so we can re-render with updated dynamic values later
622
+ */
623
+ preprocessTemplate(alert, template) {
624
+ var _a, _b;
625
+ let result = template;
626
+ /*
627
+ * Replace static variables (from first alert)
628
+ * {{alertTitle}}
629
+ */
630
+ if (alert.title) {
631
+ result = result.replace(/\{\{alertTitle\}\}/g, alert.title);
632
+ }
633
+ // {{alertDescription}}
634
+ if (alert.description) {
635
+ result = result.replace(/\{\{alertDescription\}\}/g, alert.description);
636
+ }
637
+ // {{monitorName}}
638
+ if ((_a = alert.monitor) === null || _a === void 0 ? void 0 : _a.name) {
639
+ result = result.replace(/\{\{monitorName\}\}/g, alert.monitor.name);
640
+ }
641
+ // {{alertSeverity}}
642
+ if ((_b = alert.alertSeverity) === null || _b === void 0 ? void 0 : _b.name) {
643
+ result = result.replace(/\{\{alertSeverity\}\}/g, alert.alertSeverity.name);
644
+ }
645
+ /*
646
+ * Keep dynamic variables as placeholders (e.g., {{alertCount}})
647
+ * They will be replaced when title/description is re-rendered
648
+ */
649
+ return result;
650
+ }
651
+ async addAlertToEpisode(alert, episodeId, addedBy, ruleId, rule, isNewEpisode, wasReopened) {
652
+ const member = new AlertEpisodeMember();
653
+ member.projectId = alert.projectId;
654
+ member.alertEpisodeId = episodeId;
655
+ member.alertId = alert.id;
656
+ member.addedBy = addedBy;
657
+ if (ruleId) {
658
+ member.matchedRuleId = ruleId;
659
+ }
660
+ try {
661
+ await AlertEpisodeMemberService.create({
662
+ data: member,
663
+ props: {
664
+ isRoot: true,
665
+ },
666
+ });
667
+ // Create feed entries for alert being added to episode
668
+ await this.createAlertAddedFeedEntries({
669
+ alert,
670
+ episodeId,
671
+ addedBy,
672
+ rule,
673
+ isNewEpisode,
674
+ wasReopened,
675
+ });
676
+ }
677
+ catch (error) {
678
+ // Check if it's a duplicate error (alert already in episode)
679
+ if (error instanceof Error &&
680
+ error.message.includes("already a member")) {
681
+ logger.debug(`Alert ${alert.id} is already in episode ${episodeId}`);
682
+ return;
683
+ }
684
+ throw error;
685
+ }
686
+ }
687
+ async createAlertAddedFeedEntries(data) {
688
+ const { alert, episodeId, addedBy, rule, isNewEpisode, wasReopened, addedByUserId, } = data;
689
+ // Fetch episode number for feed entry
690
+ const episode = await AlertEpisodeService.findOneById({
691
+ id: episodeId,
692
+ select: {
693
+ episodeNumber: true,
694
+ },
695
+ props: {
696
+ isRoot: true,
697
+ },
698
+ });
699
+ const episodeNumber = (episode === null || episode === void 0 ? void 0 : episode.episodeNumber) || 0;
700
+ const alertNumber = alert.alertNumber || 0;
701
+ // Build explanation of why the alert was added
702
+ let matchReason = "";
703
+ let alertFeedMessage = "";
704
+ let episodeFeedMessage = "";
705
+ if (addedBy === AlertEpisodeMemberAddedBy.Rule && rule) {
706
+ const matchCriteria = [];
707
+ if (rule.monitors && rule.monitors.length > 0) {
708
+ matchCriteria.push("monitor matches rule criteria");
709
+ }
710
+ if (rule.alertSeverities && rule.alertSeverities.length > 0) {
711
+ matchCriteria.push("severity matches rule criteria");
712
+ }
713
+ if (rule.alertLabels && rule.alertLabels.length > 0) {
714
+ matchCriteria.push("alert labels match rule criteria");
715
+ }
716
+ if (rule.monitorLabels && rule.monitorLabels.length > 0) {
717
+ matchCriteria.push("monitor labels match rule criteria");
718
+ }
719
+ if (rule.alertTitlePattern) {
720
+ matchCriteria.push(`alert title matches pattern \`${rule.alertTitlePattern}\``);
721
+ }
722
+ if (rule.alertDescriptionPattern) {
723
+ matchCriteria.push(`alert description matches pattern \`${rule.alertDescriptionPattern}\``);
724
+ }
725
+ if (rule.monitorNamePattern) {
726
+ matchCriteria.push(`monitor name matches pattern \`${rule.monitorNamePattern}\``);
727
+ }
728
+ if (rule.monitorDescriptionPattern) {
729
+ matchCriteria.push(`monitor description matches pattern \`${rule.monitorDescriptionPattern}\``);
730
+ }
731
+ if (matchCriteria.length === 0) {
732
+ matchCriteria.push("all criteria matched (rule matches all alerts)");
733
+ }
734
+ matchReason = `**Match Criteria:**\n- ${matchCriteria.join("\n- ")}`;
735
+ if (wasReopened) {
736
+ alertFeedMessage = `➕ **Added to Episode #${episodeNumber}** (reopened) by rule **${rule.name || "Unnamed Rule"}**`;
737
+ episodeFeedMessage = `➕ **Alert #${alertNumber}** added (episode reopened) by rule **${rule.name || "Unnamed Rule"}**`;
738
+ }
739
+ else if (isNewEpisode) {
740
+ alertFeedMessage = `➕ **Added to new Episode #${episodeNumber}** by rule **${rule.name || "Unnamed Rule"}**`;
741
+ episodeFeedMessage = `➕ **Alert #${alertNumber}** added (initial alert) by rule **${rule.name || "Unnamed Rule"}**`;
742
+ }
743
+ else {
744
+ alertFeedMessage = `➕ **Added to Episode #${episodeNumber}** by rule **${rule.name || "Unnamed Rule"}**`;
745
+ episodeFeedMessage = `➕ **Alert #${alertNumber}** added by rule **${rule.name || "Unnamed Rule"}**`;
746
+ }
747
+ }
748
+ else {
749
+ // Manual addition
750
+ alertFeedMessage = `➕ **Manually added to Episode #${episodeNumber}**`;
751
+ episodeFeedMessage = `➕ **Alert #${alertNumber}** manually added`;
752
+ matchReason = "**Reason:** Manually added by user";
753
+ }
754
+ // Create alert feed entry
755
+ try {
756
+ await AlertFeedService.createAlertFeedItem({
757
+ alertId: alert.id,
758
+ projectId: alert.projectId,
759
+ alertFeedEventType: AlertFeedEventType.AddedToEpisode,
760
+ displayColor: Purple500,
761
+ feedInfoInMarkdown: alertFeedMessage,
762
+ moreInformationInMarkdown: matchReason,
763
+ userId: addedByUserId,
764
+ });
765
+ }
766
+ catch (feedError) {
767
+ logger.error(`Error creating alert feed for alert added to episode: ${feedError}`);
768
+ }
769
+ // Create episode feed entry
770
+ try {
771
+ let moreInfo = `**Alert:** #${alertNumber}`;
772
+ if (alert.title) {
773
+ moreInfo += ` - ${alert.title}`;
774
+ }
775
+ moreInfo += `\n\n${matchReason}`;
776
+ await AlertEpisodeFeedService.createAlertEpisodeFeedItem({
777
+ alertEpisodeId: episodeId,
778
+ projectId: alert.projectId,
779
+ alertEpisodeFeedEventType: AlertEpisodeFeedEventType.AlertAdded,
780
+ displayColor: Purple500,
781
+ feedInfoInMarkdown: episodeFeedMessage,
782
+ moreInformationInMarkdown: moreInfo,
783
+ userId: addedByUserId,
784
+ });
785
+ }
786
+ catch (feedError) {
787
+ logger.error(`Error creating episode feed for alert added: ${feedError}`);
788
+ }
789
+ }
790
+ async addAlertToEpisodeManually(alert, episodeId, addedByUserId) {
791
+ const member = new AlertEpisodeMember();
792
+ member.projectId = alert.projectId;
793
+ member.alertEpisodeId = episodeId;
794
+ member.alertId = alert.id;
795
+ member.addedBy = AlertEpisodeMemberAddedBy.Manual;
796
+ if (addedByUserId) {
797
+ member.addedByUserId = addedByUserId;
798
+ }
799
+ await AlertEpisodeMemberService.create({
800
+ data: member,
801
+ props: {
802
+ isRoot: true,
803
+ },
804
+ });
805
+ // Create feed entries for manual addition
806
+ await this.createAlertAddedFeedEntries({
807
+ alert,
808
+ episodeId,
809
+ addedBy: AlertEpisodeMemberAddedBy.Manual,
810
+ addedByUserId,
811
+ });
812
+ // Update episode severity if needed
813
+ if (alert.alertSeverityId) {
814
+ await AlertEpisodeService.updateEpisodeSeverity({
815
+ episodeId: episodeId,
816
+ severityId: alert.alertSeverityId,
817
+ onlyIfHigher: true,
818
+ });
819
+ }
820
+ }
821
+ }
822
+ __decorate([
823
+ CaptureSpan(),
824
+ __metadata("design:type", Function),
825
+ __metadata("design:paramtypes", [Alert]),
826
+ __metadata("design:returntype", Promise)
827
+ ], AlertGroupingEngineServiceClass.prototype, "processAlert", null);
828
+ __decorate([
829
+ CaptureSpan(),
830
+ __metadata("design:type", Function),
831
+ __metadata("design:paramtypes", [Alert,
832
+ AlertGroupingRule]),
833
+ __metadata("design:returntype", Promise)
834
+ ], AlertGroupingEngineServiceClass.prototype, "doesAlertMatchRule", null);
835
+ __decorate([
836
+ CaptureSpan(),
837
+ __metadata("design:type", Function),
838
+ __metadata("design:paramtypes", [Alert,
839
+ AlertGroupingRule]),
840
+ __metadata("design:returntype", Promise)
841
+ ], AlertGroupingEngineServiceClass.prototype, "groupAlertWithRule", null);
842
+ __decorate([
843
+ CaptureSpan(),
844
+ __metadata("design:type", Function),
845
+ __metadata("design:paramtypes", [Alert,
846
+ AlertGroupingRule]),
847
+ __metadata("design:returntype", Promise)
848
+ ], AlertGroupingEngineServiceClass.prototype, "buildGroupingKey", null);
849
+ __decorate([
850
+ CaptureSpan(),
851
+ __metadata("design:type", Function),
852
+ __metadata("design:paramtypes", [ObjectID,
853
+ ObjectID, String, Object]),
854
+ __metadata("design:returntype", Promise)
855
+ ], AlertGroupingEngineServiceClass.prototype, "findMatchingActiveEpisode", null);
856
+ __decorate([
857
+ CaptureSpan(),
858
+ __metadata("design:type", Function),
859
+ __metadata("design:paramtypes", [ObjectID,
860
+ ObjectID, String, Date]),
861
+ __metadata("design:returntype", Promise)
862
+ ], AlertGroupingEngineServiceClass.prototype, "findRecentlyResolvedEpisode", null);
863
+ __decorate([
864
+ CaptureSpan(),
865
+ __metadata("design:type", Function),
866
+ __metadata("design:paramtypes", [Alert,
867
+ AlertGroupingRule, String]),
868
+ __metadata("design:returntype", Promise)
869
+ ], AlertGroupingEngineServiceClass.prototype, "createNewEpisode", null);
870
+ __decorate([
871
+ CaptureSpan(),
872
+ __metadata("design:type", Function),
873
+ __metadata("design:paramtypes", [Alert,
874
+ ObjectID, String, ObjectID,
875
+ AlertGroupingRule, Boolean, Boolean]),
876
+ __metadata("design:returntype", Promise)
877
+ ], AlertGroupingEngineServiceClass.prototype, "addAlertToEpisode", null);
878
+ __decorate([
879
+ CaptureSpan(),
880
+ __metadata("design:type", Function),
881
+ __metadata("design:paramtypes", [Object]),
882
+ __metadata("design:returntype", Promise)
883
+ ], AlertGroupingEngineServiceClass.prototype, "createAlertAddedFeedEntries", null);
884
+ __decorate([
885
+ CaptureSpan(),
886
+ __metadata("design:type", Function),
887
+ __metadata("design:paramtypes", [Alert,
888
+ ObjectID,
889
+ ObjectID]),
890
+ __metadata("design:returntype", Promise)
891
+ ], AlertGroupingEngineServiceClass.prototype, "addAlertToEpisodeManually", null);
892
+ export default new AlertGroupingEngineServiceClass();
893
+ //# sourceMappingURL=AlertGroupingEngineService.js.map