@oneuptime/common 12.0.18 → 12.0.20

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 (262) hide show
  1. package/Models/DatabaseModels/EnterpriseLicense.ts +23 -0
  2. package/Models/DatabaseModels/Index.ts +4 -2
  3. package/Models/DatabaseModels/Monitor.ts +39 -9
  4. package/Models/DatabaseModels/UserMicrosoftTeams.ts +344 -0
  5. package/Models/DatabaseModels/UserNotificationRule.ts +144 -8
  6. package/Models/DatabaseModels/UserNotificationSetting.ts +34 -0
  7. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +95 -0
  8. package/Models/DatabaseModels/UserSlack.ts +341 -0
  9. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +9 -0
  10. package/Server/API/EnterpriseLicenseAPI.ts +94 -19
  11. package/Server/API/UserMicrosoftTeamsAPI.ts +127 -0
  12. package/Server/API/UserSlackAPI.ts +125 -0
  13. package/Server/EnvironmentConfig.ts +29 -107
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.ts +33 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.ts +51 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.ts +117 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.ts +197 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  19. package/Server/Infrastructure/Queue.ts +7 -0
  20. package/Server/Services/EnterpriseLicenseService.ts +60 -0
  21. package/Server/Services/Index.ts +6 -2
  22. package/Server/Services/LlmLogService.ts +25 -9
  23. package/Server/Services/OnCallReadinessService.ts +86 -2
  24. package/Server/Services/ProjectService.ts +171 -0
  25. package/Server/Services/UserMicrosoftTeamsService.ts +208 -0
  26. package/Server/Services/UserNotificationMethodAdminService.ts +167 -5
  27. package/Server/Services/UserNotificationRuleAdminService.ts +40 -6
  28. package/Server/Services/UserNotificationRuleService.ts +589 -11
  29. package/Server/Services/UserNotificationSettingService.ts +138 -0
  30. package/Server/Services/UserService.ts +28 -0
  31. package/Server/Services/UserSlackService.ts +218 -0
  32. package/Server/Services/WorkspaceProjectAuthTokenService.ts +67 -1
  33. package/Server/Services/WorkspaceUserAuthTokenService.ts +73 -0
  34. package/Server/Services/WorkspaceUserNotificationService.ts +190 -0
  35. package/Server/Utils/Marketing/MarketingEventUtil.ts +145 -0
  36. package/Server/Utils/Marketing/MarketingEventWebhook.ts +114 -0
  37. package/Server/Utils/Monitor/MonitorLogUtil.ts +14 -1
  38. package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +321 -0
  39. package/Server/Utils/Response.ts +2 -2
  40. package/Server/Utils/StartServer.ts +2 -2
  41. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +191 -4
  42. package/Server/Views/Partials/AnalyticsConsent.ejs +533 -0
  43. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +22 -14
  44. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +22 -11
  45. package/Tests/App/Dashboard/AlertEpisodeViewFields.test.tsx +465 -0
  46. package/Tests/App/Dashboard/DashboardChartWidgetZoom.test.tsx +302 -0
  47. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +408 -0
  48. package/Tests/App/Dashboard/IncidentEpisodeViewFields.test.tsx +474 -0
  49. package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +368 -0
  50. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +37 -1
  51. package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +18 -10
  52. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +27 -1
  53. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +214 -0
  54. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +763 -0
  55. package/Tests/Server/API/OnCallReadinessAPI.test.ts +145 -26
  56. package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +2 -2
  57. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +11 -1
  58. package/Tests/Server/Services/AdminRuleEditGuards.test.ts +22 -8
  59. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +18 -2
  60. package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +5 -1
  61. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +640 -0
  62. package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +246 -22
  63. package/Tests/Server/Services/NotificationDeletionImpact.test.ts +136 -8
  64. package/Tests/Server/Services/OnCallNotificationFallback.test.ts +191 -8
  65. package/Tests/Server/Services/OnCallReadinessService.test.ts +343 -18
  66. package/Tests/Server/Services/ProjectServiceChangePlan.test.ts +138 -0
  67. package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +516 -0
  68. package/Tests/Server/Services/SeverityRuleBackfill.test.ts +5 -1
  69. package/Tests/Server/Services/UserMicrosoftTeamsService.test.ts +343 -0
  70. package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +209 -8
  71. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +22 -6
  72. package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +12 -6
  73. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +37 -3
  74. package/Tests/Server/Services/UserNotificationRuleWorkspaceDelivery.test.ts +669 -0
  75. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +410 -0
  76. package/Tests/Server/Services/UserSlackService.test.ts +407 -0
  77. package/Tests/Server/Services/WorkspaceProjectAuthTokenDisconnectCascade.test.ts +224 -0
  78. package/Tests/Server/Services/WorkspaceUserAuthTokenNotificationMethodCascade.test.ts +189 -0
  79. package/Tests/Server/Services/WorkspaceUserNotificationService.test.ts +496 -0
  80. package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +30 -17
  81. package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +8 -3
  82. package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +72 -3
  83. package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +22 -18
  84. package/Tests/Server/Types/Database/Permissions/WorkspaceMethodStampedColumnCreate.test.ts +178 -0
  85. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +259 -0
  86. package/Tests/Server/Utils/Marketing/MarketingEventWebhook.test.ts +257 -0
  87. package/Tests/Server/Utils/Monitor/MonitorLogUtilRedaction.test.ts +300 -0
  88. package/Tests/Server/Utils/Monitor/MonitorPayloadRedaction.test.ts +381 -0
  89. package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +53 -0
  90. package/Tests/Server/Utils/Runbook/RunbookExecutePermission.test.ts +228 -0
  91. package/Tests/Server/Utils/SessionReplay/SessionReplayErasureTombstone.test.ts +189 -0
  92. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +205 -0
  93. package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +275 -0
  94. package/Tests/Server/Utils/Telemetry/TelemetryContext.test.ts +279 -0
  95. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +454 -0
  96. package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +241 -0
  97. package/Tests/UI/Components/Charts/ChartTooltipSorted.test.tsx +129 -0
  98. package/Tests/UI/Components/Charts/TooltipEntries.test.ts +155 -0
  99. package/Tests/UI/Components/Detail/DetailFieldErrors.test.tsx +347 -0
  100. package/Tests/UI/Components/Forms/BasicFormStepValidation.test.tsx +392 -0
  101. package/Tests/UI/Components/Forms/ValidationFormSteps.test.ts +549 -0
  102. package/Tests/UI/Utils/NotificationMethodUtil.test.ts +137 -9
  103. package/Tests/UI/Utils/PermissionGate.test.ts +105 -0
  104. package/Tests/Utils/EnterpriseLicenseSync.test.ts +562 -0
  105. package/Types/Analytics/RevenueEvent.ts +1 -0
  106. package/Types/Marketing/MarketingEvent.ts +140 -0
  107. package/UI/Components/Charts/Area/AreaChart.tsx +8 -1
  108. package/UI/Components/Charts/Bar/BarChart.tsx +8 -1
  109. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +19 -4
  110. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +20 -2
  111. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +19 -4
  112. package/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.ts +105 -0
  113. package/UI/Components/Charts/Line/LineChart.tsx +8 -1
  114. package/UI/Components/Detail/Detail.tsx +18 -1
  115. package/UI/Utils/NotificationMethodUtil.ts +41 -1
  116. package/UI/Utils/PermissionGate.ts +56 -0
  117. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +244 -0
  118. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +24 -0
  119. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  120. package/build/dist/Models/DatabaseModels/Index.js +4 -2
  121. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  122. package/build/dist/Models/DatabaseModels/Monitor.js +39 -9
  123. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  124. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js +363 -0
  125. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js.map +1 -0
  126. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +145 -8
  127. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  128. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js +38 -0
  129. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js.map +1 -1
  130. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +96 -0
  131. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  132. package/build/dist/Models/DatabaseModels/UserSlack.js +361 -0
  133. package/build/dist/Models/DatabaseModels/UserSlack.js.map +1 -0
  134. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  135. package/build/dist/Server/API/EnterpriseLicenseAPI.js +66 -12
  136. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  137. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +82 -0
  138. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -0
  139. package/build/dist/Server/API/UserSlackAPI.js +81 -0
  140. package/build/dist/Server/API/UserSlackAPI.js.map +1 -0
  141. package/build/dist/Server/EnvironmentConfig.js +25 -70
  142. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  143. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js +26 -0
  144. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js.map +1 -0
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js +37 -0
  146. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js.map +1 -0
  147. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js +106 -0
  148. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js.map +1 -0
  149. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js +78 -0
  150. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js.map +1 -0
  151. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  152. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  153. package/build/dist/Server/Infrastructure/Queue.js +7 -0
  154. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  155. package/build/dist/Server/Services/EnterpriseLicenseService.js +65 -0
  156. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  157. package/build/dist/Server/Services/Index.js +6 -2
  158. package/build/dist/Server/Services/Index.js.map +1 -1
  159. package/build/dist/Server/Services/LlmLogService.js +25 -9
  160. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  161. package/build/dist/Server/Services/OnCallReadinessService.js +74 -2
  162. package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -1
  163. package/build/dist/Server/Services/ProjectService.js +144 -0
  164. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  165. package/build/dist/Server/Services/UserMicrosoftTeamsService.js +183 -0
  166. package/build/dist/Server/Services/UserMicrosoftTeamsService.js.map +1 -0
  167. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +138 -2
  168. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  169. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +32 -4
  170. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  171. package/build/dist/Server/Services/UserNotificationRuleService.js +499 -67
  172. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  173. package/build/dist/Server/Services/UserNotificationSettingService.js +118 -0
  174. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  175. package/build/dist/Server/Services/UserService.js +26 -1
  176. package/build/dist/Server/Services/UserService.js.map +1 -1
  177. package/build/dist/Server/Services/UserSlackService.js +195 -0
  178. package/build/dist/Server/Services/UserSlackService.js.map +1 -0
  179. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +64 -1
  180. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  181. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js +70 -0
  182. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js.map +1 -1
  183. package/build/dist/Server/Services/WorkspaceUserNotificationService.js +129 -0
  184. package/build/dist/Server/Services/WorkspaceUserNotificationService.js.map +1 -0
  185. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +94 -0
  186. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -0
  187. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js +93 -0
  188. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js.map +1 -0
  189. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js +12 -1
  190. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js.map +1 -1
  191. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +233 -0
  192. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -0
  193. package/build/dist/Server/Utils/Response.js +2 -2
  194. package/build/dist/Server/Utils/Response.js.map +1 -1
  195. package/build/dist/Server/Utils/StartServer.js +2 -2
  196. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  197. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +141 -4
  198. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  199. package/build/dist/Types/Analytics/RevenueEvent.js +1 -0
  200. package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -1
  201. package/build/dist/Types/Marketing/MarketingEvent.js +82 -0
  202. package/build/dist/Types/Marketing/MarketingEvent.js.map +1 -0
  203. package/build/dist/UI/Components/Charts/Area/AreaChart.js +9 -1
  204. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  205. package/build/dist/UI/Components/Charts/Bar/BarChart.js +9 -1
  206. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  207. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +22 -13
  208. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  209. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +27 -15
  210. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  211. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +27 -18
  212. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  213. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.js +71 -0
  214. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.js.map +1 -0
  215. package/build/dist/UI/Components/Charts/Line/LineChart.js +9 -1
  216. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  217. package/build/dist/UI/Components/Detail/Detail.js +17 -1
  218. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  219. package/build/dist/UI/Utils/NotificationMethodUtil.js +33 -1
  220. package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -1
  221. package/build/dist/UI/Utils/PermissionGate.js +32 -0
  222. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  223. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +174 -0
  224. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +1 -0
  225. package/package.json +1 -1
  226. package/Models/DatabaseModels/MarketingConversion.ts +0 -410
  227. package/Server/Services/MarketingConversionService.ts +0 -10
  228. package/Server/Utils/Marketing/ConversionUploadProvider.ts +0 -215
  229. package/Server/Utils/Marketing/ConversionUploadProviders.ts +0 -22
  230. package/Server/Utils/Marketing/Providers/GoogleAds.ts +0 -333
  231. package/Server/Utils/Marketing/Providers/LinkedIn.ts +0 -185
  232. package/Server/Utils/Marketing/Providers/Meta.ts +0 -182
  233. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +0 -223
  234. package/Server/Utils/Marketing/Providers/Reddit.ts +0 -208
  235. package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +0 -315
  236. package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +0 -300
  237. package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +0 -592
  238. package/Tests/Server/Utils/Marketing/LinkedIn.test.ts +0 -282
  239. package/Tests/Server/Utils/Marketing/Meta.test.ts +0 -304
  240. package/Tests/Server/Utils/Marketing/MicrosoftAds.test.ts +0 -263
  241. package/Tests/Server/Utils/Marketing/Reddit.test.ts +0 -259
  242. package/Types/Marketing/MarketingConversion.ts +0 -53
  243. package/build/dist/Models/DatabaseModels/MarketingConversion.js +0 -445
  244. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +0 -1
  245. package/build/dist/Server/Services/MarketingConversionService.js +0 -9
  246. package/build/dist/Server/Services/MarketingConversionService.js.map +0 -1
  247. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +0 -93
  248. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +0 -1
  249. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +0 -20
  250. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +0 -1
  251. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +0 -221
  252. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +0 -1
  253. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +0 -137
  254. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +0 -1
  255. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +0 -133
  256. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +0 -1
  257. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +0 -143
  258. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +0 -1
  259. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +0 -145
  260. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +0 -1
  261. package/build/dist/Types/Marketing/MarketingConversion.js +0 -52
  262. package/build/dist/Types/Marketing/MarketingConversion.js.map +0 -1
@@ -11,6 +11,7 @@ import SmsService from "../../../Server/Services/SmsService";
11
11
  import CallService from "../../../Server/Services/CallService";
12
12
  import WhatsAppService from "../../../Server/Services/WhatsAppService";
13
13
  import TelegramService from "../../../Server/Services/TelegramService";
14
+ import WorkspaceUserNotificationService from "../../../Server/Services/WorkspaceUserNotificationService";
14
15
  import WebhookService from "../../../Server/Services/WebhookService";
15
16
  import PushNotificationService from "../../../Server/Services/PushNotificationService";
16
17
  import logger from "../../../Server/Utils/Logger";
@@ -28,16 +29,20 @@ import BadDataException from "../../../Types/Exception/BadDataException";
28
29
  import PushDeviceType from "../../../Types/PushNotification/PushDeviceType";
29
30
  import UserNotificationEventType from "../../../Types/UserNotification/UserNotificationEventType";
30
31
  import UserNotificationStatus from "../../../Types/UserNotification/UserNotificationStatus";
32
+ import WorkspaceType from "../../../Types/Workspace/WorkspaceType";
31
33
  import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
32
34
 
33
35
  /*
34
36
  * THE SHAPE OF THE BUG THIS FILE EXISTS TO CATCH.
35
37
  *
36
- * `deliverNotificationForRule` is seven independent channel blocks stacked one
37
- * after another - email, SMS, WhatsApp, Telegram, webhook, call, push - and each
38
- * block is itself a stack of `if (eventType === X && entity)` branches, one per
39
- * UserNotificationEventType. That is a 7 x 4 grid written out by hand, twenty
40
- * eight times, with no compiler anywhere insisting the grid is full.
38
+ * `deliverNotificationForRule` is nine independent channel blocks stacked one
39
+ * after another - email, SMS, WhatsApp, Telegram, Slack, Microsoft Teams,
40
+ * webhook, call, push - and each block is itself a stack of
41
+ * `if (eventType === X && entity)` branches, one per UserNotificationEventType
42
+ * (the two workspace channels share one such ladder inside
43
+ * deliverWorkspaceDirectMessageForRule, but each still opens its own gate).
44
+ * That is a 9 x 4 grid written out by hand, thirty six times, with no compiler
45
+ * anywhere insisting the grid is full.
41
46
  *
42
47
  * It was not full. Gap F: `IncidentEpisodeCreated` was wired into the webhook
43
48
  * and push blocks and nowhere else, so a responder whose rule pointed at their
@@ -51,9 +56,9 @@ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
51
56
  * A test that checked "email works" and "SMS works" would not have caught it,
52
57
  * because email and SMS did work - for three of the four event types. Only the
53
58
  * CARTESIAN PRODUCT catches a hole in a grid. So this file is table-driven on
54
- * purpose: it builds {seven channels} x {every member of UserNotificationEventType}
59
+ * purpose: it builds {nine channels} x {every member of UserNotificationEventType}
55
60
  * and asserts every single cell hands a page to its provider and writes a
56
- * timeline row. Adding an eighth channel or a fifth event type without filling
61
+ * timeline row. Adding a tenth channel or a fifth event type without filling
57
62
  * in the new row or column fails here, loudly, in the cell that is missing.
58
63
  *
59
64
  * Two canaries keep the table honest, because a table that quietly stops
@@ -65,7 +70,7 @@ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
65
70
  *
66
71
  * Beyond the grid, three behaviours the grid depends on are pinned:
67
72
  *
68
- * 1. THE FELL-THROUGH GUARD. Phase 1 added a backstop after the seven blocks:
73
+ * 1. THE FELL-THROUGH GUARD. Phase 1 added a backstop after the channel blocks:
69
74
  * if the rule could contact somebody and no branch claimed the event, write
70
75
  * an Error row naming the event type and the channels. That converts the
71
76
  * next Gap F from a silent hole into a visible failure - but only if it
@@ -122,6 +127,13 @@ const TELEGRAM_CHAT_ID: string = "987654321";
122
127
  const WEBHOOK_URL: string = "https://hooks.example.com/on-call";
123
128
  const DEVICE_TOKEN: string = "device-token";
124
129
  const TELEGRAM_BODY: string = "<b>telegram body</b>";
130
+ const SLACK_USER_ID: string = "U0123ABCD";
131
+ const SLACK_USER_NAME: string = "alice";
132
+ const TEAMS_USER_ID: string = "aad-object-0123";
133
+ const TEAMS_USER_NAME: string = "Alice Example";
134
+ const WORKSPACE_BLOCKS: Array<Record<string, unknown>> = [
135
+ { _type: "WorkspacePayloadMarkdown", text: "**workspace body**" },
136
+ ];
125
137
 
126
138
  /* The options bag `executeNotificationRuleItem` takes, without re-declaring it. */
127
139
  type ExecuteOptions = Parameters<
@@ -146,13 +158,18 @@ interface TimelineRow {
146
158
  methodIds: Record<string, ObjectID | undefined>;
147
159
  }
148
160
 
149
- /* Everything the second argument of every sender has in common. */
161
+ /* Everything the options bag handed to every sender has in common. */
150
162
  interface SenderOptions {
151
163
  projectId?: ObjectID | undefined;
152
164
  userId?: ObjectID | undefined;
153
165
  userOnCallLogTimelineId?: ObjectID | undefined;
154
166
  alertEpisodeId?: ObjectID | undefined;
155
167
  incidentEpisodeId?: ObjectID | undefined;
168
+ /*
169
+ * Only the shared workspace sender carries this: it is the ONE thing that
170
+ * says whether a call was a Slack page or a Microsoft Teams page.
171
+ */
172
+ workspaceType?: WorkspaceType | undefined;
156
173
  }
157
174
 
158
175
  interface DeliverySpies {
@@ -174,6 +191,7 @@ interface DeliverySpies {
174
191
  call: jest.SpyInstance;
175
192
  whatsApp: jest.SpyInstance;
176
193
  telegram: jest.SpyInstance;
194
+ workspace: jest.SpyInstance;
177
195
  webhook: jest.SpyInstance;
178
196
  push: jest.SpyInstance;
179
197
  loggerError: jest.SpyInstance;
@@ -279,6 +297,20 @@ interface ChannelSpec {
279
297
  unverifiedMessage: string;
280
298
  /* The provider function the block must call. Read lazily: spies are per-test. */
281
299
  sender: () => jest.SpyInstance;
300
+ /*
301
+ * Where the options bag sits in the sender's arguments. Every legacy
302
+ * provider takes (message, options); the workspace sender takes a single
303
+ * options bag as its only argument.
304
+ */
305
+ senderOptionsArgIndex: number;
306
+ /*
307
+ * Slack and Microsoft Teams share ONE sender -
308
+ * WorkspaceUserNotificationService.sendDirectMessageToUser - so the spy
309
+ * alone cannot say which channel a call was for; the workspaceType argument
310
+ * can, and is asserted wherever the spec's is non-null. Null for channels
311
+ * with a provider of their own.
312
+ */
313
+ workspaceType: WorkspaceType | null;
282
314
  /* The timeline column that attributes the row to this method. */
283
315
  timelineMethodIdField: string;
284
316
  /*
@@ -316,6 +348,8 @@ const CHANNEL_SPECS: Record<string, ChannelSpec> = {
316
348
  sender: (): jest.SpyInstance => {
317
349
  return spies.mail;
318
350
  },
351
+ senderOptionsArgIndex: 1,
352
+ workspaceType: null,
319
353
  timelineMethodIdField: "userEmailId",
320
354
  generatorPrefix: "generateEmailTemplateFor",
321
355
  generatorTimelineIdArgIndex: 2,
@@ -345,6 +379,8 @@ const CHANNEL_SPECS: Record<string, ChannelSpec> = {
345
379
  sender: (): jest.SpyInstance => {
346
380
  return spies.sms;
347
381
  },
382
+ senderOptionsArgIndex: 1,
383
+ workspaceType: null,
348
384
  timelineMethodIdField: "userSmsId",
349
385
  generatorPrefix: "generateSmsTemplateFor",
350
386
  generatorTimelineIdArgIndex: 2,
@@ -374,6 +410,8 @@ const CHANNEL_SPECS: Record<string, ChannelSpec> = {
374
410
  sender: (): jest.SpyInstance => {
375
411
  return spies.whatsApp;
376
412
  },
413
+ senderOptionsArgIndex: 1,
414
+ workspaceType: null,
377
415
  timelineMethodIdField: "userWhatsAppId",
378
416
  generatorPrefix: "generateWhatsAppTemplateFor",
379
417
  generatorTimelineIdArgIndex: 2,
@@ -403,11 +441,88 @@ const CHANNEL_SPECS: Record<string, ChannelSpec> = {
403
441
  sender: (): jest.SpyInstance => {
404
442
  return spies.telegram;
405
443
  },
444
+ senderOptionsArgIndex: 1,
445
+ workspaceType: null,
406
446
  timelineMethodIdField: "userTelegramId",
407
447
  /* Telegram's generator takes (entity, timelineId) - no `to` argument. */
408
448
  generatorPrefix: "generateTelegramBodyFor",
409
449
  generatorTimelineIdArgIndex: 1,
410
450
  },
451
+ Slack: {
452
+ channel: "Slack",
453
+ verifiedMethod: (): Record<string, unknown> => {
454
+ return {
455
+ userSlack: {
456
+ id: METHOD_ID,
457
+ slackUserId: SLACK_USER_ID,
458
+ slackUserName: SLACK_USER_NAME,
459
+ isVerified: true,
460
+ },
461
+ };
462
+ },
463
+ unverifiedMethod: (): Record<string, unknown> => {
464
+ return {
465
+ userSlack: {
466
+ id: METHOD_ID,
467
+ slackUserId: SLACK_USER_ID,
468
+ slackUserName: SLACK_USER_NAME,
469
+ isVerified: false,
470
+ },
471
+ };
472
+ },
473
+ sendingMessage: "Sending Slack message.",
474
+ unverifiedMessage:
475
+ "Slack message not sent because the Slack account is not verified.",
476
+ sender: (): jest.SpyInstance => {
477
+ return spies.workspace;
478
+ },
479
+ /* The workspace sender takes ONE options bag, not (message, options). */
480
+ senderOptionsArgIndex: 0,
481
+ workspaceType: WorkspaceType.Slack,
482
+ timelineMethodIdField: "userSlackId",
483
+ /*
484
+ * One generator family serves BOTH workspace channels: the blocks are
485
+ * plain markdown, slackified or adaptive-carded by the send side. Like
486
+ * Telegram's, the generators take (entity, timelineId).
487
+ */
488
+ generatorPrefix: "generateWorkspaceMessageBlocksFor",
489
+ generatorTimelineIdArgIndex: 1,
490
+ },
491
+ "Microsoft Teams": {
492
+ channel: "Microsoft Teams",
493
+ verifiedMethod: (): Record<string, unknown> => {
494
+ return {
495
+ userMicrosoftTeams: {
496
+ id: METHOD_ID,
497
+ microsoftTeamsUserId: TEAMS_USER_ID,
498
+ microsoftTeamsUserName: TEAMS_USER_NAME,
499
+ isVerified: true,
500
+ },
501
+ };
502
+ },
503
+ unverifiedMethod: (): Record<string, unknown> => {
504
+ return {
505
+ userMicrosoftTeams: {
506
+ id: METHOD_ID,
507
+ microsoftTeamsUserId: TEAMS_USER_ID,
508
+ microsoftTeamsUserName: TEAMS_USER_NAME,
509
+ isVerified: false,
510
+ },
511
+ };
512
+ },
513
+ sendingMessage: "Sending Microsoft Teams message.",
514
+ unverifiedMessage:
515
+ "Microsoft Teams message not sent because the Microsoft Teams account is not verified.",
516
+ sender: (): jest.SpyInstance => {
517
+ return spies.workspace;
518
+ },
519
+ senderOptionsArgIndex: 0,
520
+ workspaceType: WorkspaceType.MicrosoftTeams,
521
+ timelineMethodIdField: "userMicrosoftTeamsId",
522
+ /* Shared with Slack - see the note on that spec. */
523
+ generatorPrefix: "generateWorkspaceMessageBlocksFor",
524
+ generatorTimelineIdArgIndex: 1,
525
+ },
411
526
  Webhook: {
412
527
  channel: "Webhook",
413
528
  verifiedMethod: (): Record<string, unknown> => {
@@ -430,6 +545,8 @@ const CHANNEL_SPECS: Record<string, ChannelSpec> = {
430
545
  sender: (): jest.SpyInstance => {
431
546
  return spies.webhook;
432
547
  },
548
+ senderOptionsArgIndex: 1,
549
+ workspaceType: null,
433
550
  timelineMethodIdField: "userWebhookId",
434
551
  generatorPrefix: null,
435
552
  generatorTimelineIdArgIndex: -1,
@@ -459,6 +576,8 @@ const CHANNEL_SPECS: Record<string, ChannelSpec> = {
459
576
  sender: (): jest.SpyInstance => {
460
577
  return spies.call;
461
578
  },
579
+ senderOptionsArgIndex: 1,
580
+ workspaceType: null,
462
581
  timelineMethodIdField: "userCallId",
463
582
  generatorPrefix: "generateCallTemplateFor",
464
583
  generatorTimelineIdArgIndex: 2,
@@ -490,6 +609,8 @@ const CHANNEL_SPECS: Record<string, ChannelSpec> = {
490
609
  sender: (): jest.SpyInstance => {
491
610
  return spies.push;
492
611
  },
612
+ senderOptionsArgIndex: 1,
613
+ workspaceType: null,
493
614
  timelineMethodIdField: "userPushId",
494
615
  /* Push builds its payload through PushNotificationUtil, not a generator. */
495
616
  generatorPrefix: null,
@@ -596,6 +717,8 @@ const CHANNEL_NAMES: Array<string> = [
596
717
  "SMS",
597
718
  "WhatsApp",
598
719
  "Telegram",
720
+ "Slack",
721
+ "Microsoft Teams",
599
722
  "Webhook",
600
723
  "Call",
601
724
  "Push",
@@ -614,6 +737,8 @@ const GENERATOR_CHANNEL_NAMES: Array<string> = [
614
737
  "SMS",
615
738
  "WhatsApp",
616
739
  "Telegram",
740
+ "Slack",
741
+ "Microsoft Teams",
617
742
  "Call",
618
743
  ];
619
744
 
@@ -623,6 +748,8 @@ const VERIFIABLE_CHANNEL_NAMES: Array<string> = [
623
748
  "SMS",
624
749
  "WhatsApp",
625
750
  "Telegram",
751
+ "Slack",
752
+ "Microsoft Teams",
626
753
  "Call",
627
754
  "Push",
628
755
  ];
@@ -683,6 +810,7 @@ function everySender(): Array<jest.SpyInstance> {
683
810
  spies.call,
684
811
  spies.whatsApp,
685
812
  spies.telegram,
813
+ spies.workspace,
686
814
  spies.webhook,
687
815
  spies.push,
688
816
  ];
@@ -696,9 +824,11 @@ function otherSenders(channel: ChannelSpec): Array<jest.SpyInstance> {
696
824
  });
697
825
  }
698
826
 
699
- /* The options bag - always the second argument - that a sender was handed. */
700
- function senderOptions(sender: jest.SpyInstance): SenderOptions {
701
- return sender.mock.calls[0][1] as SenderOptions;
827
+ /* The options bag a sender was handed - the spec says which argument it is. */
828
+ function senderOptions(channel: ChannelSpec): SenderOptions {
829
+ return channel.sender().mock.calls[0][
830
+ channel.senderOptionsArgIndex
831
+ ] as SenderOptions;
702
832
  }
703
833
 
704
834
  describe("UserNotificationRuleService channel x event coverage", () => {
@@ -731,6 +861,8 @@ describe("UserNotificationRuleService channel x event coverage", () => {
731
861
  userCallId: data.userCallId,
732
862
  userWhatsAppId: data.userWhatsAppId,
733
863
  userTelegramId: data.userTelegramId,
864
+ userSlackId: data.userSlackId,
865
+ userMicrosoftTeamsId: data.userMicrosoftTeamsId,
734
866
  userPushId: data.userPushId,
735
867
  userWebhookId: data.userWebhookId,
736
868
  },
@@ -814,6 +946,10 @@ describe("UserNotificationRuleService channel x event coverage", () => {
814
946
  telegram: jest
815
947
  .spyOn(TelegramService, "sendTelegramMessage")
816
948
  .mockResolvedValue(undefined as never),
949
+ /* ONE sender for BOTH workspace channels - see ChannelSpec.workspaceType. */
950
+ workspace: jest
951
+ .spyOn(WorkspaceUserNotificationService, "sendDirectMessageToUser")
952
+ .mockResolvedValue(undefined as never),
817
953
  webhook: jest
818
954
  .spyOn(WebhookService, "sendWebhook")
819
955
  .mockResolvedValue(undefined as never),
@@ -929,6 +1065,30 @@ describe("UserNotificationRuleService channel x event coverage", () => {
929
1065
  "generateTelegramBodyForIncidentEpisodeCreated",
930
1066
  )
931
1067
  .mockResolvedValue(TELEGRAM_BODY as never),
1068
+ generateWorkspaceMessageBlocksForIncidentCreated: jest
1069
+ .spyOn(
1070
+ UserNotificationRuleService,
1071
+ "generateWorkspaceMessageBlocksForIncidentCreated",
1072
+ )
1073
+ .mockResolvedValue(WORKSPACE_BLOCKS as never),
1074
+ generateWorkspaceMessageBlocksForAlertCreated: jest
1075
+ .spyOn(
1076
+ UserNotificationRuleService,
1077
+ "generateWorkspaceMessageBlocksForAlertCreated",
1078
+ )
1079
+ .mockResolvedValue(WORKSPACE_BLOCKS as never),
1080
+ generateWorkspaceMessageBlocksForAlertEpisodeCreated: jest
1081
+ .spyOn(
1082
+ UserNotificationRuleService,
1083
+ "generateWorkspaceMessageBlocksForAlertEpisodeCreated",
1084
+ )
1085
+ .mockResolvedValue(WORKSPACE_BLOCKS as never),
1086
+ generateWorkspaceMessageBlocksForIncidentEpisodeCreated: jest
1087
+ .spyOn(
1088
+ UserNotificationRuleService,
1089
+ "generateWorkspaceMessageBlocksForIncidentEpisodeCreated",
1090
+ )
1091
+ .mockResolvedValue(WORKSPACE_BLOCKS as never),
932
1092
  generateCallTemplateForIncidentCreated: jest
933
1093
  .spyOn(
934
1094
  UserNotificationRuleService,
@@ -999,7 +1159,7 @@ describe("UserNotificationRuleService channel x event coverage", () => {
999
1159
  /*
1000
1160
  * The canary for the next Gap F. Adding a fifth event type to the enum
1001
1161
  * fails here until it is added to EVENT_SPECS, at which point the matrix
1002
- * grows by seven cells and any channel that forgot the new branch fails.
1162
+ * grows by nine cells and any channel that forgot the new branch fails.
1003
1163
  */
1004
1164
  const members: Array<string> = Object.values(UserNotificationEventType);
1005
1165
 
@@ -1033,7 +1193,7 @@ describe("UserNotificationRuleService channel x event coverage", () => {
1033
1193
  expect(FULL_MATRIX).toHaveLength(
1034
1194
  CHANNEL_NAMES.length * EVENT_NAMES.length,
1035
1195
  );
1036
- expect(FULL_MATRIX).toHaveLength(28);
1196
+ expect(FULL_MATRIX).toHaveLength(36);
1037
1197
  });
1038
1198
  });
1039
1199
 
@@ -1057,6 +1217,17 @@ describe("UserNotificationRuleService channel x event coverage", () => {
1057
1217
  * line with the provider untouched and the timeline empty.
1058
1218
  */
1059
1219
  expect(channel.sender()).toHaveBeenCalledTimes(1);
1220
+
1221
+ /*
1222
+ * Slack and Microsoft Teams share that sender, so "the spy was called"
1223
+ * alone cannot tell a Slack page from a Teams page. The workspaceType
1224
+ * argument can, and must name THIS channel.
1225
+ */
1226
+ if (channel.workspaceType) {
1227
+ expect(senderOptions(channel).workspaceType).toBe(
1228
+ channel.workspaceType,
1229
+ );
1230
+ }
1060
1231
  },
1061
1232
  );
1062
1233
 
@@ -1071,6 +1242,20 @@ describe("UserNotificationRuleService channel x event coverage", () => {
1071
1242
  for (const sender of otherSenders(channel)) {
1072
1243
  expect(sender).not.toHaveBeenCalled();
1073
1244
  }
1245
+
1246
+ /*
1247
+ * otherSenders cannot separate the two channels that share the
1248
+ * workspace sender, so for those the "no other channel" claim is
1249
+ * finished by checking every call on the shared spy was for THIS
1250
+ * workspace and not its sibling.
1251
+ */
1252
+ if (channel.workspaceType) {
1253
+ for (const call of channel.sender().mock.calls) {
1254
+ expect((call[0] as SenderOptions).workspaceType).toBe(
1255
+ channel.workspaceType,
1256
+ );
1257
+ }
1258
+ }
1074
1259
  },
1075
1260
  );
1076
1261
 
@@ -1129,7 +1314,7 @@ describe("UserNotificationRuleService channel x event coverage", () => {
1129
1314
 
1130
1315
  await deliverCell(channel, event);
1131
1316
 
1132
- const options: SenderOptions = senderOptions(channel.sender());
1317
+ const options: SenderOptions = senderOptions(channel);
1133
1318
 
1134
1319
  /*
1135
1320
  * userOnCallLogTimelineId is how the provider's delivery callback finds
@@ -1335,7 +1520,16 @@ describe("UserNotificationRuleService channel x event coverage", () => {
1335
1520
 
1336
1521
  describe("episode ids on the sender options", () => {
1337
1522
  test.each<[string, string]>(
1338
- buildMatrix(["Email", "SMS", "WhatsApp", "Telegram", "Call", "Push"]),
1523
+ buildMatrix([
1524
+ "Email",
1525
+ "SMS",
1526
+ "WhatsApp",
1527
+ "Telegram",
1528
+ "Slack",
1529
+ "Microsoft Teams",
1530
+ "Call",
1531
+ "Push",
1532
+ ]),
1339
1533
  )(
1340
1534
  "%s links the alert episode it is paging about (%s is ignored unless it is the alert episode)",
1341
1535
  async (channelName: string, eventName: string): Promise<void> => {
@@ -1344,7 +1538,7 @@ describe("UserNotificationRuleService channel x event coverage", () => {
1344
1538
 
1345
1539
  await deliverCell(channel, event);
1346
1540
 
1347
- const options: SenderOptions = senderOptions(channel.sender());
1541
+ const options: SenderOptions = senderOptions(channel);
1348
1542
 
1349
1543
  if (event.eventType === UserNotificationEventType.AlertEpisodeCreated) {
1350
1544
  expect(options.alertEpisodeId?.toString()).toBe(
@@ -1371,11 +1565,39 @@ describe("UserNotificationRuleService channel x event coverage", () => {
1371
1565
  * without fixing the transport: every one of these services accepts
1372
1566
  * incidentEpisodeId in its options type and then never serialises it
1373
1567
  * onto the request body. Passing it would read as a link that exists.
1374
- * Contrast with alertEpisodeId above, which does travel.
1568
+ * Contrast with alertEpisodeId above, which does travel - and with the
1569
+ * workspace channels below, which send in-process and DO carry it.
1375
1570
  */
1376
- expect(
1377
- senderOptions(channel.sender()).incidentEpisodeId,
1378
- ).toBeUndefined();
1571
+ expect(senderOptions(channel).incidentEpisodeId).toBeUndefined();
1572
+ },
1573
+ );
1574
+
1575
+ test.each<[string, string]>(buildMatrix(["Slack", "Microsoft Teams"]))(
1576
+ "%s links the incident episode it is paging about (%s is ignored unless it is the incident episode)",
1577
+ async (channelName: string, eventName: string): Promise<void> => {
1578
+ const channel: ChannelSpec = channelSpec(channelName);
1579
+ const event: EventSpec = eventSpec(eventName);
1580
+
1581
+ await deliverCell(channel, event);
1582
+
1583
+ /*
1584
+ * The workspace sender is not an HTTP transport with a lossy request
1585
+ * body: it runs in-process and stamps whatever ids it is handed onto
1586
+ * the workspace notification log. So unlike the six channels above it
1587
+ * is given the incident episode id - and only when the incident
1588
+ * episode is what fired.
1589
+ */
1590
+ const options: SenderOptions = senderOptions(channel);
1591
+
1592
+ if (
1593
+ event.eventType === UserNotificationEventType.IncidentEpisodeCreated
1594
+ ) {
1595
+ expect(options.incidentEpisodeId?.toString()).toBe(
1596
+ INCIDENT_EPISODE_ID.toString(),
1597
+ );
1598
+ } else {
1599
+ expect(options.incidentEpisodeId).toBeUndefined();
1600
+ }
1379
1601
  },
1380
1602
  );
1381
1603
  });
@@ -1472,7 +1694,7 @@ describe("UserNotificationRuleService channel x event coverage", () => {
1472
1694
  * ----------------------------------------------------------------------- *
1473
1695
  * (G) The fell-through guard.
1474
1696
  *
1475
- * With all twenty eight cells wired, no rule reaches this guard today - which
1697
+ * With all thirty six cells wired, no rule reaches this guard today - which
1476
1698
  * is exactly the state it is meant to police, and exactly why it needs a test
1477
1699
  * of its own rather than incidental coverage. The precondition it fires on is
1478
1700
  * "the channel census found somebody reachable, and then no block claimed the
@@ -1690,6 +1912,8 @@ describe("UserNotificationRuleService channel x event coverage", () => {
1690
1912
  ["SMS"],
1691
1913
  ["WhatsApp"],
1692
1914
  ["Telegram"],
1915
+ ["Slack"],
1916
+ ["Microsoft Teams"],
1693
1917
  ["Webhook"],
1694
1918
  ["Call"],
1695
1919
  ["Push"],