@oneuptime/common 14.0.6 → 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 (556) 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/InventoryItem.ts +23 -12
  6. package/Models/DatabaseModels/StatusPage.ts +55 -0
  7. package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
  8. package/Server/API/IncidentAPI.ts +162 -0
  9. package/Server/API/StatusPageAPI.ts +487 -171
  10. package/Server/API/StatusPageSubscriberAPI.ts +63 -15
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.ts +217 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +16 -0
  20. package/Server/Infrastructure/Semaphore.ts +10 -0
  21. package/Server/Middleware/IdentityRateLimit.ts +108 -3
  22. package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
  23. package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
  24. package/Server/Services/AlertService.ts +32 -36
  25. package/Server/Services/DatabaseService.ts +93 -10
  26. package/Server/Services/IncidentAlertService.ts +609 -2
  27. package/Server/Services/IncidentCustomFieldService.ts +276 -1
  28. package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
  29. package/Server/Services/IncidentEpisodeService.ts +15 -0
  30. package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
  31. package/Server/Services/IncidentPublicNoteService.ts +30 -1
  32. package/Server/Services/IncidentService.ts +1663 -103
  33. package/Server/Services/IncidentStateTimelineService.ts +13 -0
  34. package/Server/Services/IncidentTemplateService.ts +109 -0
  35. package/Server/Services/InventoryItemService.ts +38 -0
  36. package/Server/Services/IoTDeviceCredentialService.ts +13 -4
  37. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
  38. package/Server/Services/ScheduledMaintenanceService.ts +118 -64
  39. package/Server/Services/SmsService.ts +10 -0
  40. package/Server/Services/StatusPageService.ts +65 -8
  41. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
  42. package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
  43. package/Server/Services/StatusPageSubscriberService.ts +1161 -64
  44. package/Server/Services/UserNotificationRuleService.ts +55 -53
  45. package/Server/Services/WorkspaceNotificationSummaryService.ts +38 -20
  46. package/Server/Types/Markdown.ts +153 -6
  47. package/Server/Types/Workflow/Components/Email.ts +61 -2
  48. package/Server/Utils/AffectedResources/LinkedAffectedResources.ts +576 -0
  49. package/Server/Utils/Alert/AlertStateChangeAuthorization.ts +129 -0
  50. package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
  51. package/Server/Utils/DataSource/EgressGuard.ts +66 -21
  52. package/Server/Utils/Inventory/InventoryOverviewAggregation.ts +111 -0
  53. package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
  54. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
  55. package/Server/Utils/Response.ts +31 -0
  56. package/Server/Utils/SSRFProtection.ts +76 -16
  57. package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
  58. package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
  59. package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
  60. package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
  61. package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
  62. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
  63. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
  64. package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
  65. package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
  66. package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
  67. package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
  68. package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
  69. package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
  70. package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
  71. package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
  72. package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
  73. package/Server/Utils/StatusPageResource.ts +51 -20
  74. package/Server/Utils/Topology/TopologyConcurrencyLimiter.ts +229 -0
  75. package/Server/Utils/Topology/TopologyQueries.ts +1350 -0
  76. package/Server/Utils/Topology/TopologyRequest.ts +463 -0
  77. package/Server/Utils/Topology/TopologyResponseCache.ts +183 -0
  78. package/Server/Utils/Topology/TopologySql.ts +1024 -0
  79. package/Server/Utils/VM/VMAPI.ts +1 -0
  80. package/Server/Utils/VM/VMRunner.ts +10 -0
  81. package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
  82. package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
  83. package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
  84. package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
  85. package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
  86. package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
  87. package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
  88. package/Tests/App/Dashboard/AcknowledgeAlertsOnDeclare.test.ts +369 -0
  89. package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +1 -1
  90. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +510 -123
  91. package/Tests/App/Dashboard/AlertsTableAffectedResources.test.tsx +490 -0
  92. package/Tests/App/Dashboard/ChangeAlertStateDeclareIncident.test.tsx +886 -0
  93. package/Tests/App/Dashboard/CreateReviewStepRoleSummary.test.tsx +1250 -0
  94. package/Tests/App/Dashboard/CreateReviewStepSelectionSummary.test.tsx +738 -0
  95. package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
  96. package/Tests/App/Dashboard/DeclareIncidentFromAlert.test.ts +417 -0
  97. package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +1948 -229
  98. package/Tests/App/Dashboard/EntityDetailPanelLifecycle.test.tsx +493 -0
  99. package/Tests/App/Dashboard/EntityDetailPanelNavigation.test.tsx +439 -0
  100. package/Tests/App/Dashboard/EventNotes.test.tsx +776 -0
  101. package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
  102. package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
  103. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +534 -6
  104. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +798 -2
  105. package/Tests/App/Dashboard/FetchStateAndSeverityElements.test.tsx +669 -0
  106. package/Tests/App/Dashboard/FetchUsers.test.tsx +230 -0
  107. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
  108. package/Tests/App/Dashboard/IncidentCreateAcknowledgeAlerts.test.tsx +1611 -0
  109. package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
  110. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
  111. package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
  112. package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
  113. package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
  114. package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
  115. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
  116. package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
  117. package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
  118. package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
  119. package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
  120. package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +1365 -57
  121. package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +964 -23
  122. package/Tests/App/Dashboard/InventoryRelationships.test.tsx +885 -0
  123. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
  124. package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +201 -15
  125. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +508 -36
  126. package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
  127. package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
  128. package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
  129. package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
  130. package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
  131. package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
  132. package/Tests/App/Dashboard/TopologyDataLifecycle.test.tsx +583 -0
  133. package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +982 -218
  134. package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +818 -114
  135. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
  136. package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
  137. package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
  138. package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
  139. package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
  140. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
  141. package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
  142. package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
  143. package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
  144. package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
  145. package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
  146. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
  147. package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
  148. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
  149. package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
  150. package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
  151. package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
  152. package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
  153. package/Tests/Server/Infrastructure/Postgres/RenameInventoryItemMigration.test.ts +90 -21
  154. package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
  155. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
  156. package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
  157. package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
  158. package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
  159. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
  160. package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
  161. package/Tests/Server/Services/DomainService.test.ts +525 -0
  162. package/Tests/Server/Services/IncidentAlertAcknowledgeOnDeclare.test.ts +2630 -0
  163. package/Tests/Server/Services/IncidentAlertPostgres.test.ts +1625 -1
  164. package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
  165. package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
  166. package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
  167. package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
  168. package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
  169. package/Tests/Server/Services/IncidentDeclareAcknowledgeAlerts.test.ts +2189 -0
  170. package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
  171. package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
  172. package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
  173. package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
  174. package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
  175. package/Tests/Server/Services/InventoryItemServiceOverviewCounts.test.ts +345 -0
  176. package/Tests/Server/Services/InventoryOverviewPostgres.test.ts +254 -0
  177. package/Tests/Server/Services/IoTDeviceCredentialService.test.ts +819 -0
  178. package/Tests/Server/Services/LinkedAffectedResourcesCreatedFeed.test.ts +420 -0
  179. package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
  180. package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
  181. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
  182. package/Tests/Server/Services/SloAffectedResourceCreatedFeed.test.ts +92 -36
  183. package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
  184. package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
  185. package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
  186. package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
  187. package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
  188. package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
  189. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
  190. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
  191. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
  192. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
  193. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
  194. package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
  195. package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
  196. package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
  197. package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
  198. package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
  199. package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
  200. package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
  201. package/Tests/Server/Utils/AffectedResources/LinkedAffectedResources.test.ts +858 -0
  202. package/Tests/Server/Utils/Alert/AlertStateChangeAuthorization.test.ts +1172 -0
  203. package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
  204. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
  205. package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
  206. package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
  207. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
  208. package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
  209. package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
  210. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
  211. package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
  212. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
  213. package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
  214. package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
  215. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
  216. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
  217. package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
  218. package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
  219. package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
  220. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
  221. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
  222. package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
  223. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
  224. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
  225. package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
  226. package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
  227. package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
  228. package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
  229. package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
  230. package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
  231. package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigration.test.ts +386 -0
  232. package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigrationPostgres.test.ts +430 -0
  233. package/Tests/Server/Utils/Topology/TopologyActivityParityPostgres.test.ts +279 -0
  234. package/Tests/Server/Utils/Topology/TopologyConcurrencyLimiter.test.ts +534 -0
  235. package/Tests/Server/Utils/Topology/TopologyEstateGenerator.ts +624 -0
  236. package/Tests/Server/Utils/Topology/TopologyJsonResponse.test.ts +90 -0
  237. package/Tests/Server/Utils/Topology/TopologyQueries.test.ts +1634 -0
  238. package/Tests/Server/Utils/Topology/TopologyQueriesDifferentialPostgres.test.ts +683 -0
  239. package/Tests/Server/Utils/Topology/TopologyQueriesPostgres.test.ts +2624 -0
  240. package/Tests/Server/Utils/Topology/TopologyReference.ts +1018 -0
  241. package/Tests/Server/Utils/Topology/TopologyRequest.test.ts +643 -0
  242. package/Tests/Server/Utils/Topology/TopologyResponseCache.test.ts +305 -0
  243. package/Tests/Server/Utils/Topology/TopologySql.test.ts +973 -0
  244. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
  245. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
  246. package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
  247. package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
  248. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
  249. package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
  250. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
  251. package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
  252. package/Tests/Types/SafeHtml.test.ts +102 -0
  253. package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
  254. package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
  255. package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
  256. package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
  257. package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
  258. package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
  259. package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
  260. package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
  261. package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
  262. package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
  263. package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
  264. package/Tests/Types/Topology/TopologyTypeRules.test.ts +176 -0
  265. package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
  266. package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
  267. package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
  268. package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
  269. package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
  270. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
  271. package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
  272. package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +302 -0
  273. package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
  274. package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
  275. package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
  276. package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
  277. package/Types/CustomField/CustomFieldOrder.ts +55 -0
  278. package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
  279. package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
  280. package/Types/CustomField/CustomFieldType.ts +14 -0
  281. package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
  282. package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
  283. package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
  284. package/Types/Incident/IncidentAlertLink.ts +19 -0
  285. package/Types/SafeHtml.ts +93 -0
  286. package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
  287. package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
  288. package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
  289. package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
  290. package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
  291. package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
  292. package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
  293. package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
  294. package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
  295. package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
  296. package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
  297. package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
  298. package/Types/Telemetry/InventoryLiveness.ts +26 -0
  299. package/Types/Topology/TopologyApi.ts +428 -0
  300. package/Types/Topology/TopologyTypeRules.ts +191 -0
  301. package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
  302. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
  303. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
  304. package/UI/Components/Forms/ModelForm.tsx +70 -8
  305. package/UI/Components/Forms/Validation.ts +1 -1
  306. package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
  307. package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
  308. package/UI/Components/ModelTable/BaseModelTable.tsx +9 -8
  309. package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
  310. package/UI/Components/ModelTable/ModelTable.tsx +6 -7
  311. package/UI/Utils/SensitiveUrlToken.ts +10 -5
  312. package/Utils/API.ts +247 -2
  313. package/Utils/Incident/IncidentFromAlerts.ts +78 -0
  314. package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
  315. package/Utils/Markdown/MarkdownEscape.ts +65 -0
  316. package/Utils/ProbeNetworkFailureUtil.ts +673 -0
  317. package/build/dist/Models/DatabaseModels/Incident.js +267 -1
  318. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  319. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
  320. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  321. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
  322. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  323. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
  324. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  325. package/build/dist/Models/DatabaseModels/InventoryItem.js +20 -11
  326. package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
  327. package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
  328. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  329. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
  330. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  331. package/build/dist/Server/API/IncidentAPI.js +100 -1
  332. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  333. package/build/dist/Server/API/StatusPageAPI.js +417 -176
  334. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  335. package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
  336. package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
  337. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js +165 -0
  338. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js.map +1 -0
  339. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
  340. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
  341. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
  342. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
  343. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
  344. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
  345. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
  346. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
  347. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
  348. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
  349. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
  350. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
  351. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
  352. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
  353. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +16 -0
  354. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  355. package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
  356. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  357. package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
  358. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
  359. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
  360. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
  361. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
  362. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
  363. package/build/dist/Server/Services/AlertService.js +21 -33
  364. package/build/dist/Server/Services/AlertService.js.map +1 -1
  365. package/build/dist/Server/Services/DatabaseService.js +56 -7
  366. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  367. package/build/dist/Server/Services/IncidentAlertService.js +457 -3
  368. package/build/dist/Server/Services/IncidentAlertService.js.map +1 -1
  369. package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
  370. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  371. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
  372. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  373. package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
  374. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  375. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
  376. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
  377. package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
  378. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  379. package/build/dist/Server/Services/IncidentService.js +1148 -42
  380. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  381. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  382. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  383. package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
  384. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  385. package/build/dist/Server/Services/InventoryItemService.js +31 -0
  386. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  387. package/build/dist/Server/Services/IoTDeviceCredentialService.js +12 -5
  388. package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -1
  389. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
  390. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  391. package/build/dist/Server/Services/ScheduledMaintenanceService.js +84 -57
  392. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  393. package/build/dist/Server/Services/SmsService.js +2 -22
  394. package/build/dist/Server/Services/SmsService.js.map +1 -1
  395. package/build/dist/Server/Services/StatusPageService.js +47 -9
  396. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  397. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
  398. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  399. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
  400. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
  401. package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
  402. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  403. package/build/dist/Server/Services/UserNotificationRuleService.js +55 -51
  404. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  405. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +42 -25
  406. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
  407. package/build/dist/Server/Types/Markdown.js +110 -6
  408. package/build/dist/Server/Types/Markdown.js.map +1 -1
  409. package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
  410. package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
  411. package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js +405 -0
  412. package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js.map +1 -0
  413. package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js +112 -0
  414. package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js.map +1 -0
  415. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
  416. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
  417. package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
  418. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  419. package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js +81 -0
  420. package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js.map +1 -0
  421. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
  422. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
  423. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
  424. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  425. package/build/dist/Server/Utils/Response.js +30 -0
  426. package/build/dist/Server/Utils/Response.js.map +1 -1
  427. package/build/dist/Server/Utils/SSRFProtection.js +48 -6
  428. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  429. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
  430. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
  431. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
  432. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
  433. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
  434. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
  435. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
  436. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
  437. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
  438. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
  439. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
  440. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
  441. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
  442. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
  443. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
  444. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
  445. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
  446. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
  447. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
  448. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
  449. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
  450. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
  451. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
  452. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
  453. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
  454. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
  455. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
  456. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
  457. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
  458. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
  459. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
  460. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
  461. package/build/dist/Server/Utils/StatusPageResource.js +39 -7
  462. package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
  463. package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js +178 -0
  464. package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js.map +1 -0
  465. package/build/dist/Server/Utils/Topology/TopologyQueries.js +884 -0
  466. package/build/dist/Server/Utils/Topology/TopologyQueries.js.map +1 -0
  467. package/build/dist/Server/Utils/Topology/TopologyRequest.js +275 -0
  468. package/build/dist/Server/Utils/Topology/TopologyRequest.js.map +1 -0
  469. package/build/dist/Server/Utils/Topology/TopologyResponseCache.js +146 -0
  470. package/build/dist/Server/Utils/Topology/TopologyResponseCache.js.map +1 -0
  471. package/build/dist/Server/Utils/Topology/TopologySql.js +688 -0
  472. package/build/dist/Server/Utils/Topology/TopologySql.js.map +1 -0
  473. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  474. package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
  475. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  476. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
  477. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
  478. package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
  479. package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
  480. package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
  481. package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
  482. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
  483. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
  484. package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
  485. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  486. package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
  487. package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
  488. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
  489. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
  490. package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
  491. package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
  492. package/build/dist/Types/Incident/IncidentAlertLink.js +17 -0
  493. package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -1
  494. package/build/dist/Types/SafeHtml.js +84 -0
  495. package/build/dist/Types/SafeHtml.js.map +1 -0
  496. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
  497. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
  498. package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
  499. package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
  500. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
  501. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
  502. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
  503. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
  504. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
  505. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
  506. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
  507. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
  508. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
  509. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
  510. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
  511. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
  512. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
  513. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
  514. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
  515. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
  516. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
  517. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
  518. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
  519. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
  520. package/build/dist/Types/Telemetry/InventoryLiveness.js +23 -0
  521. package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -1
  522. package/build/dist/Types/Topology/TopologyApi.js +55 -0
  523. package/build/dist/Types/Topology/TopologyApi.js.map +1 -0
  524. package/build/dist/Types/Topology/TopologyTypeRules.js +165 -0
  525. package/build/dist/Types/Topology/TopologyTypeRules.js.map +1 -0
  526. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
  527. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
  528. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
  529. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
  530. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
  531. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  532. package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
  533. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  534. package/build/dist/UI/Components/Forms/Validation.js +1 -1
  535. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  536. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  537. package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
  538. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
  539. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  540. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
  541. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  542. package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
  543. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  544. package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
  545. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
  546. package/build/dist/Utils/API.js +177 -1
  547. package/build/dist/Utils/API.js.map +1 -1
  548. package/build/dist/Utils/Incident/IncidentFromAlerts.js +38 -0
  549. package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -1
  550. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
  551. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
  552. package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
  553. package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
  554. package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
  555. package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
  556. package/package.json +1 -1
@@ -17,7 +17,7 @@ import {
17
17
  waitFor,
18
18
  within,
19
19
  } from "@testing-library/react";
20
- import React, { ReactElement, ReactNode } from "react";
20
+ import React, { FunctionComponent, ReactElement, ReactNode } from "react";
21
21
  import getJestMockFunction, { MockFunction } from "../../MockType";
22
22
 
23
23
  /*
@@ -32,6 +32,7 @@ import getJestMockFunction, { MockFunction } from "../../MockType";
32
32
  const getListMock: MockFunction = getJestMockFunction();
33
33
  const getItemMock: MockFunction = getJestMockFunction();
34
34
  const updateByIdMock: MockFunction = getJestMockFunction();
35
+ const createOrUpdateMock: MockFunction = getJestMockFunction();
35
36
 
36
37
  const recordedProps: Record<string, Array<Record<string, unknown>>> = {};
37
38
  const mountCounts: Record<string, number> = {};
@@ -92,6 +93,9 @@ jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
92
93
  updateById: (...args: Array<unknown>) => {
93
94
  return updateByIdMock(...args);
94
95
  },
96
+ createOrUpdate: (...args: Array<unknown>) => {
97
+ return createOrUpdateMock(...args);
98
+ },
95
99
  },
96
100
  };
97
101
  });
@@ -318,6 +322,7 @@ import IncidentState from "../../../Models/DatabaseModels/IncidentState";
318
322
  import IncidentStateTimeline from "../../../Models/DatabaseModels/IncidentStateTimeline";
319
323
  import Monitor from "../../../Models/DatabaseModels/Monitor";
320
324
  import Probe from "../../../Models/DatabaseModels/Probe";
325
+ import ServiceLevelObjective from "../../../Models/DatabaseModels/ServiceLevelObjective";
321
326
  import AIRunHumanVerdict from "../../../Types/AI/AIRunHumanVerdict";
322
327
  import AIRunStatus from "../../../Types/AI/AIRunStatus";
323
328
  import Route from "../../../Types/API/Route";
@@ -325,8 +330,15 @@ import Color from "../../../Types/Color";
325
330
  import OneUptimeDate from "../../../Types/Date";
326
331
  import ObjectID from "../../../Types/ObjectID";
327
332
  import StatusPageSubscriberNotificationStatus from "../../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
333
+ import IncidentCreatedResend from "../../../Types/StatusPage/IncidentCreatedResend";
334
+ import { FormType } from "../../../UI/Components/Forms/ModelForm";
335
+ import SubscriberNotificationResendCopy from "../../../../App/FeatureSet/Dashboard/src/Components/StatusPageSubscribers/SubscriberNotificationResendCopy";
328
336
  import { DetailStyle } from "../../../UI/Components/Detail/Detail";
337
+ import FormFieldSchemaType from "../../../UI/Components/Forms/Types/FormFieldSchemaType";
329
338
  import Navigation from "../../../UI/Utils/Navigation";
339
+ import PermissionUtil from "../../../UI/Utils/Permission";
340
+ import User from "../../../UI/Utils/User";
341
+ import Permission from "../../../Types/Permission";
330
342
 
331
343
  const EVENT_ID: string = "11111111-1111-4111-8111-111111111111";
332
344
  const OTHER_EVENT_ID: string = "22222222-2222-4222-8222-222222222222";
@@ -376,6 +388,11 @@ function propsHistory<T>(key: string): Array<T> {
376
388
  return (recordedProps[key] || []) as unknown as Array<T>;
377
389
  }
378
390
 
391
+ // What the incident overview hands the notification status badge.
392
+ type ResendStatusProps = {
393
+ onResendNotification: (options: { isToAllStatusPages: boolean }) => void;
394
+ };
395
+
379
396
  function latestProps<T>(key: string): T {
380
397
  const history: Array<T> = propsHistory<T>(key);
381
398
 
@@ -532,6 +549,8 @@ const INCIDENT_CASE: PageCase = {
532
549
  "Declared By",
533
550
  "On-Call Duty Policies",
534
551
  "Subscriber Notification Status",
552
+ // The status pages the incident is limited to, read only.
553
+ "Status Page Scope",
535
554
  "Labels",
536
555
  "Incident Number",
537
556
  "Incident ID",
@@ -756,14 +775,22 @@ const itemRequestId: ItemRequestIdFunction = (args: Array<unknown>): string => {
756
775
  return (args[0] as { id: ObjectID }).id.toString();
757
776
  };
758
777
 
778
+ // What the signed-in user may do; a project member unless a test says so.
779
+ let currentPermissions: Array<Permission> = [Permission.ProjectMember];
780
+
759
781
  beforeEach(() => {
760
782
  currentEventId = EVENT_ID;
783
+ currentPermissions = [Permission.ProjectMember];
761
784
 
762
785
  jest
763
786
  .spyOn(Navigation, "getLastParamAsObjectID")
764
787
  .mockImplementation((): ObjectID => {
765
788
  return new ObjectID(currentEventId);
766
789
  });
790
+ jest.spyOn(PermissionUtil, "getAllPermissions").mockImplementation(() => {
791
+ return currentPermissions;
792
+ });
793
+ jest.spyOn(User, "isMasterAdmin").mockReturnValue(false);
767
794
  });
768
795
 
769
796
  afterEach(() => {
@@ -771,6 +798,7 @@ afterEach(() => {
771
798
  getListMock.mockReset();
772
799
  getItemMock.mockReset();
773
800
  updateByIdMock.mockReset();
801
+ createOrUpdateMock.mockReset();
774
802
 
775
803
  for (const key of Object.keys(recordedProps)) {
776
804
  delete recordedProps[key];
@@ -1849,6 +1877,90 @@ describe.each([
1849
1877
  });
1850
1878
  });
1851
1879
 
1880
+ /*
1881
+ * The Affected Resources card. CardModelDetail is stubbed, so the card's
1882
+ * display field is read from its latest props and rendered here the way the
1883
+ * real card renders it. AffectedResourcesDisplay is stubbed for the page too,
1884
+ * so the element its getElement returns is re-rendered with the real
1885
+ * display: what is asserted is what a reader of the card would see.
1886
+ */
1887
+ interface ResourcesFormFieldProps {
1888
+ field?: Record<string, unknown>;
1889
+ fieldType?: FormFieldSchemaType;
1890
+ showIf?: (values: unknown) => boolean;
1891
+ getCustomElement?: (values: unknown, elementProps: unknown) => ReactElement;
1892
+ }
1893
+
1894
+ interface ResourcesCardProps {
1895
+ cardProps: { description?: string };
1896
+ formFields: Array<ResourcesFormFieldProps>;
1897
+ modelDetailProps: { fields: Array<DetailFieldProps> };
1898
+ }
1899
+
1900
+ type ResourcesCardFunction = () => ResourcesCardProps;
1901
+
1902
+ const resourcesCard: ResourcesCardFunction = (): ResourcesCardProps => {
1903
+ return latestProps<ResourcesCardProps>("CardModelDetail:Affected Resources");
1904
+ };
1905
+
1906
+ type ResourcesDisplayFieldFunction = () => DetailFieldProps;
1907
+
1908
+ const resourcesDisplayField: ResourcesDisplayFieldFunction =
1909
+ (): DetailFieldProps => {
1910
+ const displayField: DetailFieldProps | undefined =
1911
+ resourcesCard().modelDetailProps.fields.find(
1912
+ (field: DetailFieldProps): boolean => {
1913
+ return Boolean(field.getElement);
1914
+ },
1915
+ );
1916
+
1917
+ if (!displayField) {
1918
+ throw new Error("The Affected Resources card has no display field");
1919
+ }
1920
+
1921
+ return displayField;
1922
+ };
1923
+
1924
+ type RenderResourcesDisplayFunction = (item: Incident | Alert) => RenderResult;
1925
+
1926
+ const renderResourcesDisplay: RenderResourcesDisplayFunction = (
1927
+ item: Incident | Alert,
1928
+ ): RenderResult => {
1929
+ const RealAffectedResourcesDisplay: FunctionComponent<
1930
+ Record<string, unknown>
1931
+ > = (
1932
+ jest.requireActual(
1933
+ "../../../../App/FeatureSet/Dashboard/src/Components/AffectedResources/AffectedResourcesDisplay",
1934
+ ) as { default: FunctionComponent<Record<string, unknown>> }
1935
+ ).default;
1936
+
1937
+ const display: ReactElement = resourcesDisplayField().getElement!(item);
1938
+
1939
+ return render(
1940
+ <RealAffectedResourcesDisplay
1941
+ {...(display.props as Record<string, unknown>)}
1942
+ />,
1943
+ );
1944
+ };
1945
+
1946
+ type NamedMonitorFunction = (name: string) => Monitor;
1947
+
1948
+ const namedMonitor: NamedMonitorFunction = (name: string): Monitor => {
1949
+ const monitor: Monitor = new Monitor();
1950
+ monitor.id = new ObjectID(MONITOR_ID);
1951
+ monitor.name = name;
1952
+ return monitor;
1953
+ };
1954
+
1955
+ type NamedSloFunction = (name: string) => ServiceLevelObjective;
1956
+
1957
+ const namedSlo: NamedSloFunction = (name: string): ServiceLevelObjective => {
1958
+ const slo: ServiceLevelObjective = new ServiceLevelObjective();
1959
+ slo.id = new ObjectID("dddddddd-dddd-4ddd-8ddd-ddddddddddd1");
1960
+ slo.name = name;
1961
+ return slo;
1962
+ };
1963
+
1852
1964
  describe("incident-only behaviour", () => {
1853
1965
  test("the header names who declared the incident once the details card has read it", async () => {
1854
1966
  serve(INCIDENT_CASE, {
@@ -2021,9 +2133,9 @@ describe("incident-only behaviour", () => {
2021
2133
  const readsBefore: number = countItemReads();
2022
2134
 
2023
2135
  await act(async () => {
2024
- latestProps<{ onResendNotification: () => void }>(
2136
+ latestProps<ResendStatusProps>(
2025
2137
  "SubscriberNotificationStatus",
2026
- ).onResendNotification();
2138
+ ).onResendNotification({ isToAllStatusPages: false });
2027
2139
  });
2028
2140
 
2029
2141
  await waitFor(() => {
@@ -2033,6 +2145,7 @@ describe("incident-only behaviour", () => {
2033
2145
  ).toBe(!refresherBefore);
2034
2146
  });
2035
2147
 
2148
+ // Retry: back to Pending, and the server keeps the record so it resumes.
2036
2149
  expect(updateByIdMock).toHaveBeenCalledTimes(1);
2037
2150
  expect(
2038
2151
  (updateByIdMock.mock.calls[0]![0] as { data: Record<string, unknown> })
@@ -2040,12 +2153,222 @@ describe("incident-only behaviour", () => {
2040
2153
  ).toEqual({
2041
2154
  subscriberNotificationStatusOnIncidentCreated:
2042
2155
  StatusPageSubscriberNotificationStatus.Pending,
2043
- subscriberNotificationStatusMessage: "Notification queued for resending",
2156
+ subscriberNotificationStatusMessage:
2157
+ IncidentCreatedResend.retryQueuedMessage,
2044
2158
  });
2159
+ expect(createOrUpdateMock).not.toHaveBeenCalled();
2045
2160
  expect(countItemReads()).toBe(readsBefore);
2046
2161
  expect(mountCounts["InvestigationPanel"]).toBe(1);
2047
2162
  });
2048
2163
 
2164
+ test("resending to every status page asks the server to, and re-reads only the details card", async () => {
2165
+ serve(INCIDENT_CASE, {
2166
+ timeline: REOPENED_TIMELINE,
2167
+ title: "Checkout slow",
2168
+ });
2169
+ createOrUpdateMock.mockResolvedValue({});
2170
+
2171
+ INCIDENT_CASE.renderPage();
2172
+ await waitForPage();
2173
+
2174
+ const refresherBefore: boolean | undefined =
2175
+ latestProps<CardModelDetailProps>(
2176
+ "CardModelDetail:Incident Details",
2177
+ ).refresher;
2178
+
2179
+ renderStatusField();
2180
+
2181
+ await act(async () => {
2182
+ latestProps<ResendStatusProps>(
2183
+ "SubscriberNotificationStatus",
2184
+ ).onResendNotification({ isToAllStatusPages: true });
2185
+ });
2186
+
2187
+ await waitFor(() => {
2188
+ expect(
2189
+ latestProps<CardModelDetailProps>("CardModelDetail:Incident Details")
2190
+ .refresher,
2191
+ ).toBe(!refresherBefore);
2192
+ });
2193
+
2194
+ expect(updateByIdMock).not.toHaveBeenCalled();
2195
+ expect(createOrUpdateMock).toHaveBeenCalledTimes(1);
2196
+
2197
+ const request: {
2198
+ model: Incident;
2199
+ modelType: unknown;
2200
+ formType: FormType;
2201
+ miscDataProps: Record<string, unknown>;
2202
+ } = createOrUpdateMock.mock.calls[0]![0] as {
2203
+ model: Incident;
2204
+ modelType: unknown;
2205
+ formType: FormType;
2206
+ miscDataProps: Record<string, unknown>;
2207
+ };
2208
+
2209
+ expect(request.modelType).toBe(Incident);
2210
+ expect(request.formType).toBe(FormType.Update);
2211
+ expect(request.model._id?.toString()).toBe(EVENT_ID);
2212
+ expect(request.model.subscriberNotificationStatusOnIncidentCreated).toBe(
2213
+ StatusPageSubscriberNotificationStatus.Pending,
2214
+ );
2215
+ expect(request.miscDataProps).toEqual(
2216
+ IncidentCreatedResend.getMiscDataProps(),
2217
+ );
2218
+ });
2219
+
2220
+ test("offers Resend after a success, confirmed with who this incident reaches now", async () => {
2221
+ serve(INCIDENT_CASE, {
2222
+ timeline: REOPENED_TIMELINE,
2223
+ title: "Checkout slow",
2224
+ });
2225
+
2226
+ INCIDENT_CASE.renderPage();
2227
+ await waitForPage();
2228
+
2229
+ renderStatusField();
2230
+
2231
+ const confirmation: {
2232
+ resendDescription: string;
2233
+ retryDescription: string;
2234
+ retryToAllStatusPagesLabel?: string;
2235
+ retryToAllStatusPagesDescription?: string;
2236
+ audience: ReactElement;
2237
+ } = latestProps<{
2238
+ resendConfirmation: {
2239
+ resendDescription: string;
2240
+ retryDescription: string;
2241
+ retryToAllStatusPagesLabel?: string;
2242
+ retryToAllStatusPagesDescription?: string;
2243
+ audience: ReactElement;
2244
+ };
2245
+ }>("SubscriberNotificationStatus").resendConfirmation;
2246
+
2247
+ expect(confirmation.resendDescription).toBe(
2248
+ SubscriberNotificationResendCopy.incidentCreatedResendDescription,
2249
+ );
2250
+ expect(confirmation.retryDescription).toBe(
2251
+ SubscriberNotificationResendCopy.incidentCreatedRetryDescription,
2252
+ );
2253
+ expect(confirmation.retryToAllStatusPagesLabel).toBe(
2254
+ SubscriberNotificationResendCopy.incidentCreatedRetryToAllStatusPagesLabel,
2255
+ );
2256
+ expect(confirmation.retryToAllStatusPagesDescription).toBe(
2257
+ SubscriberNotificationResendCopy.incidentCreatedResendToAllStatusPagesDescription,
2258
+ );
2259
+
2260
+ const audienceProps: {
2261
+ request: { incidentId: { toString: () => string } };
2262
+ } = confirmation.audience.props as {
2263
+ request: { incidentId: { toString: () => string } };
2264
+ };
2265
+
2266
+ expect(audienceProps.request.incidentId.toString()).toBe(EVENT_ID);
2267
+ expect(audienceProps.request).not.toHaveProperty(
2268
+ "excludeStatusPagesNotifiedOnCreation",
2269
+ );
2270
+ });
2271
+
2272
+ /*
2273
+ * Retry resumes after the pages already sent it in full, so its
2274
+ * confirmation's "Will notify" must not list them: it asks for the audience
2275
+ * without them. Resend, and Retry to every page, keep the full one.
2276
+ */
2277
+ test("Retry's confirmation shows who Retry reaches: without the pages already sent it in full", async () => {
2278
+ serve(INCIDENT_CASE, {
2279
+ timeline: REOPENED_TIMELINE,
2280
+ title: "Checkout slow",
2281
+ });
2282
+
2283
+ INCIDENT_CASE.renderPage();
2284
+ await waitForPage();
2285
+
2286
+ renderStatusField();
2287
+
2288
+ const confirmation: { retryAudience?: ReactElement } = latestProps<{
2289
+ resendConfirmation: { retryAudience?: ReactElement };
2290
+ }>("SubscriberNotificationStatus").resendConfirmation;
2291
+
2292
+ const retryAudienceProps: {
2293
+ request: {
2294
+ incidentId: { toString: () => string };
2295
+ excludeStatusPagesNotifiedOnCreation?: boolean;
2296
+ };
2297
+ } = confirmation.retryAudience!.props as {
2298
+ request: {
2299
+ incidentId: { toString: () => string };
2300
+ excludeStatusPagesNotifiedOnCreation?: boolean;
2301
+ };
2302
+ };
2303
+
2304
+ expect(retryAudienceProps.request.incidentId.toString()).toBe(EVENT_ID);
2305
+ expect(
2306
+ retryAudienceProps.request.excludeStatusPagesNotifiedOnCreation,
2307
+ ).toBe(true);
2308
+ });
2309
+
2310
+ /*
2311
+ * Retry and Resend write the notification's status. A role that may not
2312
+ * is offered neither - the details card used to offer them to everyone,
2313
+ * read-only viewers included, and let the server refuse.
2314
+ */
2315
+ test.each([[[Permission.Viewer]], [[Permission.IncidentViewer]], [[]]])(
2316
+ "a user with %j is offered neither Resend nor Retry",
2317
+ async (permissions: Array<Permission>) => {
2318
+ currentPermissions = permissions;
2319
+ serve(INCIDENT_CASE, {
2320
+ timeline: REOPENED_TIMELINE,
2321
+ title: "Checkout slow",
2322
+ });
2323
+
2324
+ INCIDENT_CASE.renderPage();
2325
+ await waitForPage();
2326
+
2327
+ renderStatusField();
2328
+
2329
+ const statusProps: {
2330
+ onResendNotification?: unknown;
2331
+ resendConfirmation?: unknown;
2332
+ } = latestProps<{
2333
+ onResendNotification?: unknown;
2334
+ resendConfirmation?: unknown;
2335
+ }>("SubscriberNotificationStatus");
2336
+
2337
+ expect(statusProps.onResendNotification).toBeUndefined();
2338
+ expect(statusProps.resendConfirmation).toBeUndefined();
2339
+ },
2340
+ );
2341
+
2342
+ test.each([
2343
+ [[Permission.IncidentMember]],
2344
+ [[Permission.EditProjectIncident]],
2345
+ ])(
2346
+ "a user with %j is offered them",
2347
+ async (permissions: Array<Permission>) => {
2348
+ currentPermissions = permissions;
2349
+ serve(INCIDENT_CASE, {
2350
+ timeline: REOPENED_TIMELINE,
2351
+ title: "Checkout slow",
2352
+ });
2353
+
2354
+ INCIDENT_CASE.renderPage();
2355
+ await waitForPage();
2356
+
2357
+ renderStatusField();
2358
+
2359
+ const statusProps: {
2360
+ onResendNotification?: unknown;
2361
+ resendConfirmation?: unknown;
2362
+ } = latestProps<{
2363
+ onResendNotification?: unknown;
2364
+ resendConfirmation?: unknown;
2365
+ }>("SubscriberNotificationStatus");
2366
+
2367
+ expect(statusProps.onResendNotification).toBeDefined();
2368
+ expect(statusProps.resendConfirmation).toBeDefined();
2369
+ },
2370
+ );
2371
+
2049
2372
  /*
2050
2373
  * The details card is stubbed, so the status row is rendered here from the
2051
2374
  * card's latest props, the way the real card renders it on every page
@@ -2072,9 +2395,9 @@ describe("incident-only behaviour", () => {
2072
2395
 
2073
2396
  const resend: ResendFunction = async (): Promise<void> => {
2074
2397
  await act(async () => {
2075
- latestProps<{ onResendNotification: () => void }>(
2398
+ latestProps<ResendStatusProps>(
2076
2399
  "SubscriberNotificationStatus",
2077
- ).onResendNotification();
2400
+ ).onResendNotification({ isToAllStatusPages: false });
2078
2401
  });
2079
2402
  await flush();
2080
2403
  };
@@ -2301,6 +2624,42 @@ describe("incident-only behaviour", () => {
2301
2624
  })?.value,
2302
2625
  ).toBe("Probe AP");
2303
2626
  });
2627
+
2628
+ /*
2629
+ * The alert card's counterpart: Incident.monitors is ManyToMany and was
2630
+ * always read and shown here, so the two cards agree on what an affected
2631
+ * monitor looks like.
2632
+ */
2633
+ test("the Affected Resources card reads the incident's monitors and lists them under Monitors", async () => {
2634
+ serve(INCIDENT_CASE, {
2635
+ timeline: REOPENED_TIMELINE,
2636
+ title: "Checkout slow",
2637
+ });
2638
+
2639
+ INCIDENT_CASE.renderPage();
2640
+ await waitForPage();
2641
+
2642
+ expect(resourcesDisplayField().field?.["monitors"]).toEqual({
2643
+ name: true,
2644
+ _id: true,
2645
+ });
2646
+
2647
+ const incident: Incident = new Incident();
2648
+ incident.monitors = [namedMonitor("Developer portal")];
2649
+
2650
+ const view: RenderResult = renderResourcesDisplay(incident);
2651
+ const grid: HTMLElement = within(view.container).getByTestId(
2652
+ "affected-resources-grid",
2653
+ );
2654
+
2655
+ expect(within(view.container).queryByText("No resources affected.")).toBe(
2656
+ null,
2657
+ );
2658
+ expect(within(grid).getByText("Monitors")).toBeInTheDocument();
2659
+ expect(within(grid).getByTestId("monitor-element")).toHaveTextContent(
2660
+ "Developer portal",
2661
+ );
2662
+ });
2304
2663
  });
2305
2664
 
2306
2665
  describe("alert-only behaviour", () => {
@@ -2447,4 +2806,173 @@ describe("alert-only behaviour", () => {
2447
2806
  ).toEqual(["Created"]);
2448
2807
  }
2449
2808
  });
2809
+
2810
+ /*
2811
+ * An alert is raised on one monitor (Alert.monitor, singular, set when the
2812
+ * alert is created), and the alert's "created" feed item lists that
2813
+ * monitor under Resources Affected. The Affected Resources card used to
2814
+ * hide monitors and never read the relation, so an alert raised on the
2815
+ * "Developer portal" monitor said "No resources affected." right beside a
2816
+ * feed item naming that monitor.
2817
+ */
2818
+ describe("the Affected Resources card", () => {
2819
+ beforeEach(async () => {
2820
+ serve(ALERT_CASE, {
2821
+ timeline: REOPENED_TIMELINE,
2822
+ title: "Checkout slow",
2823
+ });
2824
+
2825
+ ALERT_CASE.renderPage();
2826
+ await waitForPage();
2827
+ });
2828
+
2829
+ test("reads the alert's monitor alongside the other resources", () => {
2830
+ const select: Record<string, unknown> =
2831
+ resourcesDisplayField().field || {};
2832
+
2833
+ expect(select["monitor"]).toEqual({ name: true, _id: true });
2834
+ expect(select).toEqual(
2835
+ expect.objectContaining({
2836
+ hosts: { name: true, _id: true },
2837
+ services: { name: true, _id: true, serviceColor: true },
2838
+ serviceLevelObjectives: { name: true, _id: true },
2839
+ }),
2840
+ );
2841
+ });
2842
+
2843
+ test("lists the monitor an alert was raised on under Monitors, never 'No resources affected.'", () => {
2844
+ const alert: Alert = new Alert();
2845
+ alert.monitor = namedMonitor("Developer portal");
2846
+
2847
+ const view: RenderResult = renderResourcesDisplay(alert);
2848
+
2849
+ expect(
2850
+ within(view.container).queryByText("No resources affected."),
2851
+ ).toBeNull();
2852
+
2853
+ const grid: HTMLElement = within(view.container).getByTestId(
2854
+ "affected-resources-grid",
2855
+ );
2856
+
2857
+ expect(grid.children).toHaveLength(1);
2858
+ expect(within(grid).getByText("Monitors")).toBeInTheDocument();
2859
+ expect(
2860
+ within(grid).getByTestId("affected-resource-item"),
2861
+ ).toHaveAttribute("title", "Developer portal");
2862
+ expect(within(grid).getByTestId("monitor-element")).toHaveTextContent(
2863
+ "Developer portal",
2864
+ );
2865
+ expect(within(view.container).getByText("1 resource")).toBeVisible();
2866
+ });
2867
+
2868
+ test("shows both the monitor and an SLO, the monitor first", () => {
2869
+ const alert: Alert = new Alert();
2870
+ alert.monitor = namedMonitor("Developer portal");
2871
+ alert.serviceLevelObjectives = [namedSlo("Checkout availability")];
2872
+
2873
+ const view: RenderResult = renderResourcesDisplay(alert);
2874
+ const grid: HTMLElement = within(view.container).getByTestId(
2875
+ "affected-resources-grid",
2876
+ );
2877
+ const categories: Array<HTMLElement> = Array.from(
2878
+ grid.children,
2879
+ ) as Array<HTMLElement>;
2880
+
2881
+ expect(categories).toHaveLength(2);
2882
+ expect(within(categories[0]!).getByText("Monitors")).toBeVisible();
2883
+ expect(
2884
+ within(categories[0]!).getByTestId("monitor-element"),
2885
+ ).toHaveTextContent("Developer portal");
2886
+ expect(within(categories[1]!).getByText("SLOs")).toBeVisible();
2887
+ expect(
2888
+ within(categories[1]!).getByText("Checkout availability"),
2889
+ ).toBeVisible();
2890
+ expect(within(view.container).getByText("2 resources")).toBeVisible();
2891
+ expect(
2892
+ within(view.container).getByText("across 2 categories"),
2893
+ ).toBeVisible();
2894
+ });
2895
+
2896
+ test("an alert with no monitor and nothing else is still 'No resources affected.'", () => {
2897
+ const view: RenderResult = renderResourcesDisplay(new Alert());
2898
+
2899
+ expect(
2900
+ within(view.container).getByText("No resources affected."),
2901
+ ).toBeVisible();
2902
+ expect(
2903
+ within(view.container).queryByTestId("affected-resources-grid"),
2904
+ ).toBeNull();
2905
+ expect(within(view.container).queryByTestId("monitor-element")).toBe(
2906
+ null,
2907
+ );
2908
+ });
2909
+
2910
+ /*
2911
+ * The monitor is shown, never edited: ModelForm loads and saves only the
2912
+ * fields registered here, so leaving the monitor out means saving the
2913
+ * card can neither move the alert to another monitor nor clear it.
2914
+ */
2915
+ test("its edit form never loads the monitor, so saving cannot change or clear it", () => {
2916
+ const formFields: Array<ResourcesFormFieldProps> =
2917
+ resourcesCard().formFields;
2918
+ const keysOf: (field: ResourcesFormFieldProps) => Array<string> = (
2919
+ field: ResourcesFormFieldProps,
2920
+ ): Array<string> => {
2921
+ return Object.keys(field.field || {});
2922
+ };
2923
+
2924
+ const formKeys: Array<string> = formFields.flatMap(keysOf);
2925
+
2926
+ expect(formKeys).not.toContain("monitor");
2927
+ expect(formKeys).not.toContain("monitors");
2928
+
2929
+ const visibleFields: Array<ResourcesFormFieldProps> = formFields.filter(
2930
+ (field: ResourcesFormFieldProps): boolean => {
2931
+ return !field.showIf || field.showIf({});
2932
+ },
2933
+ );
2934
+ const hiddenFields: Array<ResourcesFormFieldProps> = formFields.filter(
2935
+ (field: ResourcesFormFieldProps): boolean => {
2936
+ return Boolean(field.showIf) && !field.showIf!({});
2937
+ },
2938
+ );
2939
+
2940
+ // The one visible field is the resource picker, registered on hosts.
2941
+ expect(visibleFields.map(keysOf)).toEqual([["hosts"]]);
2942
+ expect(visibleFields[0]!.fieldType).toBe(
2943
+ FormFieldSchemaType.CustomComponent,
2944
+ );
2945
+ // Hidden registrations so the form still loads the other relations.
2946
+ expect(hiddenFields.flatMap(keysOf)).toEqual([
2947
+ "kubernetesClusters",
2948
+ "dockerHosts",
2949
+ "podmanHosts",
2950
+ "proxmoxClusters",
2951
+ "vmwareVCenters",
2952
+ "cephClusters",
2953
+ "dockerSwarmClusters",
2954
+ "iotFleets",
2955
+ "databaseServers",
2956
+ "services",
2957
+ ]);
2958
+
2959
+ // The picker it renders offers no monitors to attach either.
2960
+ render(visibleFields[0]!.getCustomElement!({}, {}));
2961
+
2962
+ const picker: { monitors?: unknown; resourceTypes?: Array<string> } =
2963
+ latestProps<{ monitors?: unknown; resourceTypes?: Array<string> }>(
2964
+ "AffectedResourcesPicker",
2965
+ );
2966
+
2967
+ expect(picker.monitors).toBeUndefined();
2968
+ expect(picker.resourceTypes).toContain("Host");
2969
+ expect(picker.resourceTypes).not.toContain("Monitor");
2970
+ });
2971
+
2972
+ test("says it covers monitors", () => {
2973
+ expect(resourcesCard().cardProps.description).toBe(
2974
+ "Monitors, services, infrastructure and SLOs this alert affects.",
2975
+ );
2976
+ });
2977
+ });
2450
2978
  });