@oneuptime/common 14.0.7 → 14.0.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 (440) hide show
  1. package/Models/DatabaseModels/Incident.ts +267 -1
  2. package/Models/DatabaseModels/IncidentCustomField.ts +202 -0
  3. package/Models/DatabaseModels/IncidentEpisode.ts +30 -0
  4. package/Models/DatabaseModels/IncidentTemplate.ts +126 -1
  5. package/Models/DatabaseModels/StatusPage.ts +55 -0
  6. package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
  7. package/Server/API/IncidentAPI.ts +162 -0
  8. package/Server/API/StatusPageAPI.ts +487 -171
  9. package/Server/API/StatusPageSubscriberAPI.ts +63 -15
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
  18. package/Server/Infrastructure/Semaphore.ts +10 -0
  19. package/Server/Middleware/IdentityRateLimit.ts +108 -3
  20. package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
  21. package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
  22. package/Server/Services/DatabaseService.ts +93 -10
  23. package/Server/Services/IncidentCustomFieldService.ts +276 -1
  24. package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
  25. package/Server/Services/IncidentEpisodeService.ts +15 -0
  26. package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
  27. package/Server/Services/IncidentPublicNoteService.ts +30 -1
  28. package/Server/Services/IncidentService.ts +1535 -65
  29. package/Server/Services/IncidentStateTimelineService.ts +13 -0
  30. package/Server/Services/IncidentTemplateService.ts +109 -0
  31. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
  32. package/Server/Services/ScheduledMaintenanceService.ts +68 -18
  33. package/Server/Services/SmsService.ts +10 -0
  34. package/Server/Services/StatusPageService.ts +65 -8
  35. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
  36. package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
  37. package/Server/Services/StatusPageSubscriberService.ts +1161 -64
  38. package/Server/Types/Markdown.ts +153 -6
  39. package/Server/Types/Workflow/Components/Email.ts +61 -2
  40. package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
  41. package/Server/Utils/DataSource/EgressGuard.ts +66 -21
  42. package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
  43. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
  44. package/Server/Utils/SSRFProtection.ts +76 -16
  45. package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
  46. package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
  47. package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
  48. package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
  49. package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
  50. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
  51. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
  52. package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
  53. package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
  54. package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
  55. package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
  56. package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
  57. package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
  58. package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
  59. package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
  60. package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
  61. package/Server/Utils/StatusPageResource.ts +51 -20
  62. package/Server/Utils/VM/VMAPI.ts +1 -0
  63. package/Server/Utils/VM/VMRunner.ts +10 -0
  64. package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
  65. package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
  66. package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
  67. package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
  68. package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
  69. package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
  70. package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
  71. package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
  72. package/Tests/App/Dashboard/EventNotes.test.tsx +776 -0
  73. package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
  74. package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
  75. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +242 -5
  76. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
  77. package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
  78. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
  79. package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
  80. package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
  81. package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
  82. package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
  83. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
  84. package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
  85. package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
  86. package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
  87. package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
  88. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
  89. package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
  90. package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
  91. package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
  92. package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
  93. package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
  94. package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
  95. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
  96. package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
  97. package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
  98. package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
  99. package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
  100. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
  101. package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
  102. package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
  103. package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
  104. package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
  105. package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
  106. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
  107. package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
  108. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
  109. package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
  110. package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
  111. package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
  112. package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
  113. package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
  114. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
  115. package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
  116. package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
  117. package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
  118. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
  119. package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
  120. package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
  121. package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
  122. package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
  123. package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
  124. package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
  125. package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
  126. package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
  127. package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
  128. package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
  129. package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
  130. package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
  131. package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
  132. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
  133. package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
  134. package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
  135. package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
  136. package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
  137. package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
  138. package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
  139. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
  140. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
  141. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
  142. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
  143. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
  144. package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
  145. package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
  146. package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
  147. package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
  148. package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
  149. package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
  150. package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
  151. package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
  152. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
  153. package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
  154. package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
  155. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
  156. package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
  157. package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
  158. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
  159. package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
  160. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
  161. package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
  162. package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
  163. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
  164. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
  165. package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
  166. package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
  167. package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
  168. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
  169. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
  170. package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
  171. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
  172. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
  173. package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
  174. package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
  175. package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
  176. package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
  177. package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
  178. package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
  179. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
  180. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
  181. package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
  182. package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
  183. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
  184. package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
  185. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
  186. package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
  187. package/Tests/Types/SafeHtml.test.ts +102 -0
  188. package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
  189. package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
  190. package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
  191. package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
  192. package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
  193. package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
  194. package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
  195. package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
  196. package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
  197. package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
  198. package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
  199. package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
  200. package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
  201. package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
  202. package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
  203. package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
  204. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
  205. package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
  206. package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
  207. package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
  208. package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
  209. package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
  210. package/Types/CustomField/CustomFieldOrder.ts +55 -0
  211. package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
  212. package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
  213. package/Types/CustomField/CustomFieldType.ts +14 -0
  214. package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
  215. package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
  216. package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
  217. package/Types/SafeHtml.ts +93 -0
  218. package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
  219. package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
  220. package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
  221. package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
  222. package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
  223. package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
  224. package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
  225. package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
  226. package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
  227. package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
  228. package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
  229. package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
  230. package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
  231. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
  232. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
  233. package/UI/Components/Forms/ModelForm.tsx +70 -8
  234. package/UI/Components/Forms/Validation.ts +1 -1
  235. package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
  236. package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
  237. package/UI/Components/ModelTable/BaseModelTable.tsx +9 -8
  238. package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
  239. package/UI/Components/ModelTable/ModelTable.tsx +6 -7
  240. package/UI/Utils/SensitiveUrlToken.ts +10 -5
  241. package/Utils/API.ts +247 -2
  242. package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
  243. package/Utils/Markdown/MarkdownEscape.ts +65 -0
  244. package/Utils/ProbeNetworkFailureUtil.ts +673 -0
  245. package/build/dist/Models/DatabaseModels/Incident.js +267 -1
  246. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  247. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
  248. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  249. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
  250. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  251. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
  252. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  253. package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
  254. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  255. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
  256. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  257. package/build/dist/Server/API/IncidentAPI.js +100 -1
  258. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  259. package/build/dist/Server/API/StatusPageAPI.js +417 -176
  260. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  261. package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
  262. package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
  263. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
  264. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
  265. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
  266. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
  267. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
  268. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
  269. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
  270. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
  271. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
  272. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
  273. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
  274. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
  275. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
  276. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
  277. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
  278. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  279. package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
  280. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  281. package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
  282. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
  283. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
  284. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
  285. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
  286. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
  287. package/build/dist/Server/Services/DatabaseService.js +56 -7
  288. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  289. package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
  290. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  291. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
  292. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  293. package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
  294. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  295. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
  296. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
  297. package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
  298. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  299. package/build/dist/Server/Services/IncidentService.js +1052 -0
  300. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  301. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  302. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  303. package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
  304. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  305. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
  306. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  307. package/build/dist/Server/Services/ScheduledMaintenanceService.js +47 -17
  308. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  309. package/build/dist/Server/Services/SmsService.js +2 -22
  310. package/build/dist/Server/Services/SmsService.js.map +1 -1
  311. package/build/dist/Server/Services/StatusPageService.js +47 -9
  312. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  313. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
  314. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  315. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
  316. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
  317. package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
  318. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  319. package/build/dist/Server/Types/Markdown.js +110 -6
  320. package/build/dist/Server/Types/Markdown.js.map +1 -1
  321. package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
  322. package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
  323. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
  324. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
  325. package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
  326. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  327. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
  328. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
  329. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
  330. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  331. package/build/dist/Server/Utils/SSRFProtection.js +48 -6
  332. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  333. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
  334. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
  335. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
  336. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
  337. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
  338. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
  339. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
  340. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
  341. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
  342. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
  343. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
  344. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
  345. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
  346. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
  347. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
  348. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
  349. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
  350. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
  351. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
  352. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
  353. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
  354. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
  355. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
  356. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
  357. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
  358. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
  359. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
  360. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
  361. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
  362. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
  363. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
  364. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
  365. package/build/dist/Server/Utils/StatusPageResource.js +39 -7
  366. package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
  367. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  368. package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
  369. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  370. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
  371. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
  372. package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
  373. package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
  374. package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
  375. package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
  376. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
  377. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
  378. package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
  379. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  380. package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
  381. package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
  382. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
  383. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
  384. package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
  385. package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
  386. package/build/dist/Types/SafeHtml.js +84 -0
  387. package/build/dist/Types/SafeHtml.js.map +1 -0
  388. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
  389. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
  390. package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
  391. package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
  392. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
  393. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
  394. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
  395. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
  396. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
  397. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
  398. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
  399. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
  400. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
  401. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
  402. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
  403. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
  404. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
  405. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
  406. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
  407. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
  408. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
  409. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
  410. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
  411. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
  412. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
  413. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
  414. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
  415. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
  416. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
  417. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  418. package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
  419. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  420. package/build/dist/UI/Components/Forms/Validation.js +1 -1
  421. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  422. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  423. package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
  424. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
  425. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  426. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
  427. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  428. package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
  429. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  430. package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
  431. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
  432. package/build/dist/Utils/API.js +177 -1
  433. package/build/dist/Utils/API.js.map +1 -1
  434. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
  435. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
  436. package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
  437. package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
  438. package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
  439. package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
  440. package/package.json +1 -1
@@ -0,0 +1,601 @@
1
+ import "@testing-library/jest-dom";
2
+ import {
3
+ afterEach,
4
+ beforeEach,
5
+ describe,
6
+ expect,
7
+ jest,
8
+ test,
9
+ } from "@jest/globals";
10
+ import { act, cleanup, render, screen, waitFor } from "@testing-library/react";
11
+ import * as React from "react";
12
+ import { MemoryRouter } from "react-router-dom";
13
+ import getJestMockFunction, { MockFunction } from "../../MockType";
14
+
15
+ /*
16
+ * Declaring an incident limited to some status pages: the Create page's
17
+ * status page picker, the warnings it raises with the fields it interacts
18
+ * with, the audience summary on the last step, and the template prefill.
19
+ *
20
+ * ModelForm is stubbed to capture the fields it is handed (as
21
+ * IncidentCreateFromAlerts.test.tsx does); each field's footer and summary
22
+ * are then rendered with the form values a person would have entered.
23
+ */
24
+
25
+ jest.mock("react-i18next", () => {
26
+ return {
27
+ useTranslation: () => {
28
+ return {
29
+ t: (key: string, opts?: { defaultValue?: string }): string => {
30
+ return opts?.defaultValue ?? key;
31
+ },
32
+ };
33
+ },
34
+ };
35
+ });
36
+
37
+ type CapturedField = {
38
+ field?: Record<string, unknown>;
39
+ title?: string;
40
+ description?: string;
41
+ placeholder?: string;
42
+ stepId?: string;
43
+ fieldType?: string;
44
+ dropdownModal?: { type: unknown; labelField: string; valueField: string };
45
+ getFooterElement?: (values: Record<string, unknown>) => unknown;
46
+ getSummaryElement?: (values: Record<string, unknown>) => unknown;
47
+ };
48
+
49
+ type CapturedFormProps = {
50
+ initialValues: Record<string, unknown>;
51
+ fields: Array<CapturedField>;
52
+ };
53
+
54
+ let capturedForms: Array<CapturedFormProps> = [];
55
+
56
+ jest.mock("../../../UI/Components/Forms/ModelForm", () => {
57
+ const actual: Record<string, unknown> = jest.requireActual(
58
+ "../../../UI/Components/Forms/ModelForm",
59
+ ) as Record<string, unknown>;
60
+
61
+ return {
62
+ __esModule: true,
63
+ ...actual,
64
+ default: (props: CapturedFormProps): React.ReactElement => {
65
+ capturedForms.push(props);
66
+ return <div data-testid="model-form" />;
67
+ },
68
+ };
69
+ });
70
+
71
+ const getListMock: MockFunction = getJestMockFunction();
72
+ const getItemMock: MockFunction = getJestMockFunction();
73
+ const countMock: MockFunction = getJestMockFunction();
74
+ const postMock: MockFunction = getJestMockFunction();
75
+
76
+ jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
77
+ return {
78
+ __esModule: true,
79
+ default: {
80
+ getList: (...args: Array<any>) => {
81
+ return getListMock(...args);
82
+ },
83
+ getItem: (...args: Array<any>) => {
84
+ return getItemMock(...args);
85
+ },
86
+ count: (...args: Array<any>) => {
87
+ return countMock(...args);
88
+ },
89
+ getCommonHeaders: (): Record<string, string> => {
90
+ return { tenantid: "project-1" };
91
+ },
92
+ create: async (): Promise<null> => {
93
+ return null;
94
+ },
95
+ },
96
+ };
97
+ });
98
+
99
+ jest.mock("../../../UI/Utils/API/API", () => {
100
+ return {
101
+ __esModule: true,
102
+ default: {
103
+ post: (...args: Array<any>) => {
104
+ return postMock(...args);
105
+ },
106
+ getFriendlyMessage: (): string => {
107
+ return "Something went wrong";
108
+ },
109
+ },
110
+ };
111
+ });
112
+
113
+ import IncidentCreate from "../../../../App/FeatureSet/Dashboard/src/Pages/Incidents/Create";
114
+ import IncidentStatusPageScopeCopy, {
115
+ formatScopeText,
116
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/Incident/IncidentStatusPageScopeCopy";
117
+ import { SUBSCRIBER_AUDIENCE_DEBOUNCE_MS } from "../../../../App/FeatureSet/Dashboard/src/Components/Incident/useSubscriberAudience";
118
+ import IncidentTemplate from "../../../Models/DatabaseModels/IncidentTemplate";
119
+ import StatusPage from "../../../Models/DatabaseModels/StatusPage";
120
+ import HTTPResponse from "../../../Types/API/HTTPResponse";
121
+ import Route from "../../../Types/API/Route";
122
+ import { JSONObject } from "../../../Types/JSON";
123
+ import IncidentSubscriberAudience from "../../../Types/StatusPage/IncidentSubscriberAudience";
124
+ import Navigation from "../../../UI/Utils/Navigation";
125
+
126
+ const TEMPLATE_ID: string = "66666666-6666-4666-8666-000000000001";
127
+ const MONITOR_ID: string = "c0000000-0000-4000-8000-000000000001";
128
+ const SITE_03: string = "b0000000-0000-4000-8000-000000000003";
129
+ const SITE_07: string = "b0000000-0000-4000-8000-000000000007";
130
+ const MONITOR_STATUS_ID: string = "d0000000-0000-4000-8000-000000000001";
131
+
132
+ function page(id: string, name: string): StatusPage {
133
+ const statusPage: StatusPage = new StatusPage();
134
+ statusPage._id = id;
135
+ statusPage.name = name;
136
+ return statusPage;
137
+ }
138
+
139
+ function audienceResponse(): HTTPResponse<JSONObject> {
140
+ return new HTTPResponse<JSONObject>(
141
+ 200,
142
+ IncidentSubscriberAudience.toJSON({
143
+ hasMonitors: true,
144
+ isScoped: true,
145
+ isHiddenFromStatusPages: false,
146
+ statusPages: [
147
+ {
148
+ statusPageId: SITE_03,
149
+ name: "Site 03",
150
+ subscriberCounts: {
151
+ ...IncidentSubscriberAudience.getEmptyCounts(),
152
+ email: 41,
153
+ },
154
+ },
155
+ ],
156
+ hiddenStatusPageCount: 0,
157
+ excludedStatusPages: [],
158
+ selectedStatusPagesNotListingMonitors: [
159
+ { statusPageId: SITE_07, name: "Site 07" },
160
+ ],
161
+ }),
162
+ {},
163
+ );
164
+ }
165
+
166
+ let queryString: Record<string, string> = {};
167
+
168
+ async function renderCreate(): Promise<void> {
169
+ await act(async () => {
170
+ render(
171
+ <MemoryRouter>
172
+ <IncidentCreate
173
+ pageRoute={new Route("/incidents/create")}
174
+ currentProject={null}
175
+ hasPaymentMethod={false}
176
+ />
177
+ </MemoryRouter>,
178
+ );
179
+ });
180
+
181
+ await waitFor(() => {
182
+ expect(capturedForms.length).toBeGreaterThan(0);
183
+ });
184
+ }
185
+
186
+ function lastForm(): CapturedFormProps {
187
+ return capturedForms[capturedForms.length - 1]!;
188
+ }
189
+
190
+ function fieldFor(key: string): CapturedField {
191
+ const field: CapturedField | undefined = lastForm().fields.find(
192
+ (candidate: CapturedField): boolean => {
193
+ return Boolean(candidate.field && key in candidate.field);
194
+ },
195
+ );
196
+
197
+ expect(field).toBeDefined();
198
+ return field!;
199
+ }
200
+
201
+ function indexOfField(key: string): number {
202
+ return lastForm().fields.findIndex((candidate: CapturedField): boolean => {
203
+ return Boolean(candidate.field && key in candidate.field);
204
+ });
205
+ }
206
+
207
+ async function renderElement(element: unknown): Promise<void> {
208
+ await act(async () => {
209
+ render(
210
+ <MemoryRouter>{(element as React.ReactElement) || <></>}</MemoryRouter>,
211
+ );
212
+ });
213
+ }
214
+
215
+ beforeEach(() => {
216
+ capturedForms = [];
217
+ queryString = {};
218
+
219
+ jest
220
+ .spyOn(Navigation, "getQueryStringByName")
221
+ .mockImplementation((name: string): string | null => {
222
+ return queryString[name] || null;
223
+ });
224
+
225
+ getListMock.mockReset();
226
+ getListMock.mockResolvedValue({ data: [], count: 0, skip: 0, limit: 0 });
227
+ getItemMock.mockReset();
228
+ getItemMock.mockResolvedValue(null);
229
+ countMock.mockReset();
230
+ countMock.mockResolvedValue(4);
231
+ postMock.mockReset();
232
+ postMock.mockResolvedValue(audienceResponse());
233
+ });
234
+
235
+ afterEach(() => {
236
+ cleanup();
237
+ jest.restoreAllMocks();
238
+ });
239
+
240
+ describe("the status page picker on the Create page", () => {
241
+ test("sits in the resources step, right after the monitors", async () => {
242
+ await renderCreate();
243
+
244
+ const picker: CapturedField = fieldFor("statusPages");
245
+
246
+ expect(picker.stepId).toBe("resources-affected");
247
+ expect(indexOfField("statusPages")).toBe(indexOfField("monitors") + 1);
248
+ });
249
+
250
+ test("is a status page multi-select, which gives it the Labels tab", async () => {
251
+ await renderCreate();
252
+
253
+ const picker: CapturedField = fieldFor("statusPages");
254
+
255
+ expect(picker.fieldType).toBe("MultiSelectDropdown");
256
+ expect(picker.dropdownModal).toEqual({
257
+ type: StatusPage,
258
+ labelField: "name",
259
+ valueField: "_id",
260
+ });
261
+ expect(picker.title).toBe(IncidentStatusPageScopeCopy.pickerTitle);
262
+ expect(picker.description).toBe(
263
+ IncidentStatusPageScopeCopy.pickerDescription,
264
+ );
265
+ expect(picker.placeholder).toBe(
266
+ IncidentStatusPageScopeCopy.pickerPlaceholder,
267
+ );
268
+ });
269
+
270
+ test("says why it is empty when the person cannot read status pages", async () => {
271
+ countMock.mockRejectedValue(new Error("Not allowed"));
272
+
273
+ await renderCreate();
274
+ await renderElement(
275
+ fieldFor("statusPages").getFooterElement!({ statusPages: [] }),
276
+ );
277
+
278
+ expect(
279
+ screen.getByTestId("status-page-picker-no-access"),
280
+ ).toHaveTextContent(IncidentStatusPageScopeCopy.pickerNoAccessHint);
281
+ });
282
+
283
+ test("no hint when there are status pages to pick", async () => {
284
+ await renderCreate();
285
+ await renderElement(
286
+ fieldFor("statusPages").getFooterElement!({ statusPages: [] }),
287
+ );
288
+
289
+ expect(screen.queryByTestId("status-page-picker-no-access")).toBeNull();
290
+ });
291
+
292
+ test("warns about a picked page that lists none of the chosen monitors", async () => {
293
+ await renderCreate();
294
+ await renderElement(
295
+ fieldFor("statusPages").getFooterElement!({
296
+ monitors: [{ _id: MONITOR_ID, name: "API" }],
297
+ statusPages: [SITE_03, SITE_07],
298
+ }),
299
+ );
300
+
301
+ expect(
302
+ await screen.findByTestId(
303
+ "status-pages-not-listing-monitors",
304
+ undefined,
305
+ {
306
+ timeout: SUBSCRIBER_AUDIENCE_DEBOUNCE_MS + 1000,
307
+ },
308
+ ),
309
+ ).toHaveTextContent(
310
+ formatScopeText(IncidentStatusPageScopeCopy.notListingMonitorsWarning, {
311
+ names: "Site 07",
312
+ }),
313
+ );
314
+ });
315
+
316
+ test("the summary step names the pages, or says it is not limited", async () => {
317
+ await renderCreate();
318
+
319
+ await renderElement(
320
+ fieldFor("statusPages").getSummaryElement!({ statusPages: [] }),
321
+ );
322
+
323
+ expect(
324
+ screen.getByText(IncidentStatusPageScopeCopy.noScopeSummary),
325
+ ).toBeInTheDocument();
326
+ });
327
+ });
328
+
329
+ describe("warnings where the scope meets other fields", () => {
330
+ test("changing monitor status on a scoped incident: it shows on every page", async () => {
331
+ await renderCreate();
332
+
333
+ await renderElement(
334
+ fieldFor("changeMonitorStatusTo").getFooterElement!({
335
+ statusPages: [SITE_03],
336
+ changeMonitorStatusTo: MONITOR_STATUS_ID,
337
+ }),
338
+ );
339
+
340
+ expect(
341
+ screen.getByTestId("incident-create-monitor-status-scope-warning"),
342
+ ).toHaveTextContent(IncidentStatusPageScopeCopy.changeMonitorStatusWarning);
343
+ });
344
+
345
+ test.each([
346
+ ["no status page is picked", { changeMonitorStatusTo: MONITOR_STATUS_ID }],
347
+ ["the monitor status is left alone", { statusPages: [SITE_03] }],
348
+ ])(
349
+ "no monitor status warning when %s",
350
+ async (_label: string, values: Record<string, unknown>) => {
351
+ await renderCreate();
352
+
353
+ expect(
354
+ fieldFor("changeMonitorStatusTo").getFooterElement!(values),
355
+ ).toBeUndefined();
356
+ },
357
+ );
358
+
359
+ test("a private incident with a scope: private wins, and says so", async () => {
360
+ await renderCreate();
361
+
362
+ await renderElement(
363
+ fieldFor("isPrivate").getFooterElement!({
364
+ isPrivate: true,
365
+ statusPages: [SITE_03],
366
+ }),
367
+ );
368
+
369
+ expect(
370
+ screen.getByTestId("incident-create-private-scope-warning"),
371
+ ).toHaveTextContent(IncidentStatusPageScopeCopy.privateIncidentWarning);
372
+ });
373
+
374
+ test.each([
375
+ [
376
+ "the incident is not private",
377
+ { isPrivate: false, statusPages: [SITE_03] },
378
+ ],
379
+ ["no status page is picked", { isPrivate: true, statusPages: [] }],
380
+ ])(
381
+ "no private warning when %s",
382
+ async (_label: string, values: Record<string, unknown>) => {
383
+ await renderCreate();
384
+
385
+ expect(fieldFor("isPrivate").getFooterElement!(values)).toBeUndefined();
386
+ },
387
+ );
388
+ });
389
+
390
+ describe("the audience on the last step", () => {
391
+ const NOTIFY_FIELD: string =
392
+ "shouldStatusPageSubscribersBeNotifiedOnIncidentCreated";
393
+
394
+ test("under the notify box: who the incident will reach, from its monitors and pages", async () => {
395
+ await renderCreate();
396
+
397
+ await renderElement(
398
+ fieldFor(NOTIFY_FIELD).getFooterElement!({
399
+ monitors: [{ _id: MONITOR_ID, name: "API" }],
400
+ statusPages: [SITE_03],
401
+ [NOTIFY_FIELD]: true,
402
+ }),
403
+ );
404
+
405
+ expect(
406
+ await screen.findByText("Site 03 (up to 41 email)", undefined, {
407
+ timeout: SUBSCRIBER_AUDIENCE_DEBOUNCE_MS + 1000,
408
+ }),
409
+ ).toBeInTheDocument();
410
+
411
+ const body: JSONObject = (
412
+ postMock.mock.calls[0]![0] as { data: JSONObject }
413
+ ).data;
414
+ expect(body).toEqual({
415
+ monitorIds: [MONITOR_ID],
416
+ statusPageIds: [SITE_03],
417
+ });
418
+ });
419
+
420
+ test("in the summary step too", async () => {
421
+ await renderCreate();
422
+
423
+ await renderElement(
424
+ fieldFor(NOTIFY_FIELD).getSummaryElement!({
425
+ monitors: [MONITOR_ID],
426
+ statusPages: [],
427
+ [NOTIFY_FIELD]: true,
428
+ }),
429
+ );
430
+
431
+ expect(
432
+ screen.getByTestId("incident-create-subscriber-audience"),
433
+ ).toBeInTheDocument();
434
+ });
435
+
436
+ test("with notifying off it says nobody will be told, and asks nothing", async () => {
437
+ await renderCreate();
438
+
439
+ await renderElement(
440
+ fieldFor(NOTIFY_FIELD).getFooterElement!({
441
+ monitors: [MONITOR_ID],
442
+ statusPages: [SITE_03],
443
+ [NOTIFY_FIELD]: false,
444
+ }),
445
+ );
446
+
447
+ expect(
448
+ screen.getByText(IncidentStatusPageScopeCopy.audienceNotifyOff),
449
+ ).toBeInTheDocument();
450
+
451
+ await new Promise((r: (value: unknown) => void) => {
452
+ setTimeout(r, SUBSCRIBER_AUDIENCE_DEBOUNCE_MS + 50);
453
+ });
454
+
455
+ expect(postMock).not.toHaveBeenCalled();
456
+ });
457
+
458
+ test("a private incident says nothing will be sent", async () => {
459
+ await renderCreate();
460
+
461
+ await renderElement(
462
+ fieldFor(NOTIFY_FIELD).getFooterElement!({
463
+ monitors: [MONITOR_ID],
464
+ statusPages: [SITE_03],
465
+ [NOTIFY_FIELD]: true,
466
+ isPrivate: true,
467
+ }),
468
+ );
469
+
470
+ expect(
471
+ screen.getByText(IncidentStatusPageScopeCopy.audiencePrivateIncident),
472
+ ).toBeInTheDocument();
473
+ });
474
+ });
475
+
476
+ describe("declaring from a template", () => {
477
+ test("reads the template's status pages and starts the picker with them", async () => {
478
+ queryString = { incidentTemplateId: TEMPLATE_ID };
479
+
480
+ const template: IncidentTemplate = new IncidentTemplate();
481
+ template._id = TEMPLATE_ID;
482
+ template.title = "Region East outage";
483
+ template.statusPages = [page(SITE_03, "Site 03"), page(SITE_07, "Site 07")];
484
+ getItemMock.mockResolvedValue(template);
485
+
486
+ await renderCreate();
487
+
488
+ const templateRequest: { modelType: unknown; select: JSONObject } =
489
+ getItemMock.mock.calls.find((call: Array<unknown>): boolean => {
490
+ return (
491
+ (call[0] as { modelType: unknown }).modelType === IncidentTemplate
492
+ );
493
+ })![0] as { modelType: unknown; select: JSONObject };
494
+
495
+ expect(templateRequest.select["statusPages"]).toBe(true);
496
+ expect(lastForm().initialValues["statusPages"]).toEqual([SITE_03, SITE_07]);
497
+ });
498
+
499
+ test("a template without status pages leaves the incident unscoped", async () => {
500
+ queryString = { incidentTemplateId: TEMPLATE_ID };
501
+
502
+ const template: IncidentTemplate = new IncidentTemplate();
503
+ template._id = TEMPLATE_ID;
504
+ template.title = "Site outage";
505
+ getItemMock.mockResolvedValue(template);
506
+
507
+ await renderCreate();
508
+
509
+ expect(lastForm().initialValues["statusPages"]).toBeUndefined();
510
+ });
511
+
512
+ test("declaring without a template starts with no status pages", async () => {
513
+ await renderCreate();
514
+
515
+ expect(lastForm().initialValues["statusPages"]).toBeUndefined();
516
+ });
517
+
518
+ test("reads whether the template is limited to status pages at all", async () => {
519
+ queryString = { incidentTemplateId: TEMPLATE_ID };
520
+
521
+ const template: IncidentTemplate = new IncidentTemplate();
522
+ template._id = TEMPLATE_ID;
523
+ getItemMock.mockResolvedValue(template);
524
+
525
+ await renderCreate();
526
+
527
+ const templateRequest: { select: JSONObject } = getItemMock.mock.calls.find(
528
+ (call: Array<unknown>): boolean => {
529
+ return (
530
+ (call[0] as { modelType: unknown }).modelType === IncidentTemplate
531
+ );
532
+ },
533
+ )![0] as { select: JSONObject };
534
+
535
+ expect(templateRequest.select["isScopedToStatusPages"]).toBe(true);
536
+ });
537
+
538
+ describe("a template whose status pages were all deleted", () => {
539
+ function scopedTemplateWithoutPages(): IncidentTemplate {
540
+ const template: IncidentTemplate = new IncidentTemplate();
541
+ template._id = TEMPLATE_ID;
542
+ template.title = "Region East outage";
543
+ template.isScopedToStatusPages = true;
544
+ template.statusPages = [];
545
+ return template;
546
+ }
547
+
548
+ test("the picker asks for the pages this incident is for", async () => {
549
+ queryString = { incidentTemplateId: TEMPLATE_ID };
550
+ getItemMock.mockResolvedValue(scopedTemplateWithoutPages());
551
+
552
+ await renderCreate();
553
+ await renderElement(
554
+ fieldFor("statusPages").getFooterElement!({ statusPages: [] }),
555
+ );
556
+
557
+ expect(
558
+ screen.getByTestId("incident-create-template-scoped-to-deleted-pages"),
559
+ ).toHaveTextContent(
560
+ IncidentStatusPageScopeCopy.declaringFromTemplateScopedToDeletedPagesWarning,
561
+ );
562
+ });
563
+
564
+ test("the warning goes once pages are picked", async () => {
565
+ queryString = { incidentTemplateId: TEMPLATE_ID };
566
+ getItemMock.mockResolvedValue(scopedTemplateWithoutPages());
567
+
568
+ await renderCreate();
569
+ await renderElement(
570
+ fieldFor("statusPages").getFooterElement!({ statusPages: [SITE_03] }),
571
+ );
572
+
573
+ expect(
574
+ screen.queryByTestId(
575
+ "incident-create-template-scoped-to-deleted-pages",
576
+ ),
577
+ ).toBeNull();
578
+ });
579
+
580
+ test("no warning for a template that was never limited", async () => {
581
+ queryString = { incidentTemplateId: TEMPLATE_ID };
582
+
583
+ const template: IncidentTemplate = new IncidentTemplate();
584
+ template._id = TEMPLATE_ID;
585
+ template.isScopedToStatusPages = false;
586
+ template.statusPages = [];
587
+ getItemMock.mockResolvedValue(template);
588
+
589
+ await renderCreate();
590
+ await renderElement(
591
+ fieldFor("statusPages").getFooterElement!({ statusPages: [] }),
592
+ );
593
+
594
+ expect(
595
+ screen.queryByTestId(
596
+ "incident-create-template-scoped-to-deleted-pages",
597
+ ),
598
+ ).toBeNull();
599
+ });
600
+ });
601
+ });