@oneuptime/common 14.0.13 → 14.0.14

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 (1045) hide show
  1. package/Models/DatabaseModels/AlertGroupingRule.ts +10 -6
  2. package/Models/DatabaseModels/File.ts +41 -2
  3. package/Models/DatabaseModels/Form.ts +126 -0
  4. package/Models/DatabaseModels/IncidentGroupingRule.ts +10 -6
  5. package/Models/DatabaseModels/LogDropFilter.ts +1 -0
  6. package/Models/DatabaseModels/LogPipeline.ts +1 -0
  7. package/Models/DatabaseModels/LogScrubRule.ts +14 -8
  8. package/Models/DatabaseModels/MetricRecordingRule.ts +2 -1
  9. package/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.ts +4 -2
  10. package/Models/DatabaseModels/OnCallDutyPolicyUserOverride.ts +22 -9
  11. package/Models/DatabaseModels/ProjectCallSMSConfig.ts +6 -1
  12. package/Models/DatabaseModels/StatusPage.ts +8 -4
  13. package/Models/DatabaseModels/TraceDropFilter.ts +1 -0
  14. package/Models/DatabaseModels/TracePipeline.ts +1 -0
  15. package/Models/DatabaseModels/TraceRecordingRule.ts +2 -1
  16. package/Models/DatabaseModels/TraceScrubRule.ts +14 -8
  17. package/Models/DatabaseModels/UserOnCallLog.ts +4 -2
  18. package/Server/API/CustomDomainRoutes.ts +251 -0
  19. package/Server/API/DashboardAPI.ts +33 -4
  20. package/Server/API/DashboardDomainAPI.ts +63 -93
  21. package/Server/API/StatusPageAPI.ts +92 -0
  22. package/Server/API/StatusPageDomainAPI.ts +59 -96
  23. package/Server/Infrastructure/GlobalCache.ts +84 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1797700000000-AddFormBranding.ts +47 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  26. package/Server/Services/AlertGroupingEngineService.ts +48 -70
  27. package/Server/Services/AlertGroupingRuleService.ts +38 -0
  28. package/Server/Services/CephClusterService.ts +25 -0
  29. package/Server/Services/CloudResourceService.ts +42 -0
  30. package/Server/Services/DashboardDomainService.ts +640 -214
  31. package/Server/Services/DashboardService.ts +30 -8
  32. package/Server/Services/DatabaseService.ts +143 -12
  33. package/Server/Services/DockerHostService.ts +60 -0
  34. package/Server/Services/DockerSwarmClusterService.ts +25 -0
  35. package/Server/Services/FileService.ts +60 -0
  36. package/Server/Services/FormService.ts +212 -2
  37. package/Server/Services/GlobalOidcService.ts +10 -0
  38. package/Server/Services/GlobalSsoService.ts +10 -0
  39. package/Server/Services/HostService.ts +58 -0
  40. package/Server/Services/IncidentGroupingEngineService.ts +48 -70
  41. package/Server/Services/IncidentGroupingRuleService.ts +38 -0
  42. package/Server/Services/IoTFleetService.ts +26 -0
  43. package/Server/Services/KubernetesClusterService.ts +64 -0
  44. package/Server/Services/LabelService.ts +6 -17
  45. package/Server/Services/LogScrubRuleService.ts +50 -0
  46. package/Server/Services/OnCallDutyPolicyScheduleService.ts +264 -0
  47. package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +9 -1
  48. package/Server/Services/OnCallNotificationAlertingService.ts +24 -29
  49. package/Server/Services/OnCallSetupReminderService.ts +41 -40
  50. package/Server/Services/PodmanHostService.ts +60 -0
  51. package/Server/Services/ProfileAggregationService.ts +38 -0
  52. package/Server/Services/ProjectCallSMSConfigService.ts +76 -3
  53. package/Server/Services/ProjectOidcService.ts +20 -0
  54. package/Server/Services/ProjectSsoService.ts +20 -0
  55. package/Server/Services/ProxmoxClusterService.ts +25 -0
  56. package/Server/Services/RumApplicationService.ts +45 -0
  57. package/Server/Services/ScheduledMaintenanceService.ts +9 -23
  58. package/Server/Services/ServerlessFunctionService.ts +47 -0
  59. package/Server/Services/ServiceService.ts +33 -10
  60. package/Server/Services/StatusPageDomainService.ts +622 -213
  61. package/Server/Services/StatusPageOidcService.ts +20 -0
  62. package/Server/Services/StatusPageResourceService.ts +89 -34
  63. package/Server/Services/StatusPageService.ts +270 -54
  64. package/Server/Services/StatusPageSsoService.ts +20 -0
  65. package/Server/Services/TraceScrubRuleService.ts +50 -0
  66. package/Server/Services/UserIncomingCallNumberService.ts +28 -14
  67. package/Server/Services/VMwareVCenterService.ts +25 -0
  68. package/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.ts +3 -3
  69. package/Server/Utils/Greenlock/CertificateOrder.ts +482 -0
  70. package/Server/Utils/Greenlock/CertificateOrderBudget.ts +134 -0
  71. package/Server/Utils/Greenlock/CertificateOrderFailures.ts +288 -0
  72. package/Server/Utils/Greenlock/CertificateOrderLock.ts +163 -0
  73. package/Server/Utils/Greenlock/CertificateOrderOutcome.ts +29 -0
  74. package/Server/Utils/Greenlock/CertificateOwners.ts +72 -0
  75. package/Server/Utils/Greenlock/CertificateReissueOrder.ts +99 -0
  76. package/Server/Utils/Greenlock/CustomDomainOrders.ts +397 -0
  77. package/Server/Utils/Greenlock/Greenlock.ts +839 -203
  78. package/Server/Utils/Rules/GroupingRuleEpisodeOwners.ts +551 -0
  79. package/Server/Utils/Rules/OwnerRuleAssignment.ts +8 -1
  80. package/Server/Utils/ScrubRuleValidation.ts +248 -0
  81. package/Server/Utils/StatusPage/AffectedStatusPageResources.ts +138 -0
  82. package/Server/Utils/StatusPage/StatusPagesListingMonitorsBuilder.ts +294 -0
  83. package/Server/Utils/Telemetry/DiscoveredResourceCreate.ts +275 -0
  84. package/Server/Utils/Telemetry/DiscoveredResourceUpdate.ts +217 -0
  85. package/Server/Utils/Telemetry/MessageQueueDiscovery.ts +8 -2
  86. package/Tests/App/Accounts/FormPage.test.tsx +238 -0
  87. package/Tests/App/Accounts/FormUtils.test.ts +108 -0
  88. package/Tests/App/AdminDashboard/AdminAddToProjectMembersTeam.test.tsx +1087 -0
  89. package/Tests/App/AdminDashboard/AdminAuthenticationRequireSso.test.tsx +140 -138
  90. package/Tests/App/AdminDashboard/AdminAuthenticationSsoCardLocales.test.tsx +144 -145
  91. package/Tests/App/AdminDashboard/AdminSettingsFormsOnePage.test.tsx +907 -0
  92. package/Tests/App/AdminDashboard/AdminSettingsSwitches.test.tsx +906 -0
  93. package/Tests/App/AdminDashboard/AdminSmtpSettingsForm.test.tsx +823 -0
  94. package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +341 -368
  95. package/Tests/App/AdminDashboard/GlobalSsoOidcPages.test.tsx +199 -54
  96. package/Tests/App/AdminDashboard/ProjectScopedTeamsPicker.test.tsx +991 -0
  97. package/Tests/App/Dashboard/AIInvestigationSettingsLimits.test.tsx +147 -90
  98. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +224 -104
  99. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +302 -0
  100. package/Tests/App/Dashboard/AdminUserOnCallPages.test.tsx +408 -152
  101. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +55 -0
  102. package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +206 -115
  103. package/Tests/App/Dashboard/AffectedResourcesPickerFocusLeave.test.tsx +32 -0
  104. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +206 -71
  105. package/Tests/App/Dashboard/AlertEpisodeViewFields.test.tsx +45 -9
  106. package/Tests/App/Dashboard/AnnouncementCreateForm.test.tsx +1208 -0
  107. package/Tests/App/Dashboard/AnnouncementEditAndTemplateForms.test.tsx +693 -0
  108. package/Tests/App/Dashboard/AnnouncementFormsStructure.test.ts +546 -0
  109. package/Tests/App/Dashboard/AnnouncementStatusPageSuggestions.test.tsx +425 -0
  110. package/Tests/App/Dashboard/AnnouncementsTableCreateLinks.test.tsx +267 -0
  111. package/Tests/App/Dashboard/ApiKeyCreateForm.test.ts +68 -51
  112. package/Tests/App/Dashboard/ApiKeyViewPermissions.test.tsx +11 -9
  113. package/Tests/App/Dashboard/ApiKeysCreateAccess.test.tsx +24 -16
  114. package/Tests/App/Dashboard/BulkChangeStateModalOnePage.test.tsx +333 -0
  115. package/Tests/App/Dashboard/CardDescriptionsSayWhatFor.test.tsx +307 -0
  116. package/Tests/App/Dashboard/ChangeAlertStateAIHeader.test.tsx +18 -4
  117. package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +7 -2
  118. package/Tests/App/Dashboard/ColorFieldsPrefilledPages.test.tsx +453 -0
  119. package/Tests/App/Dashboard/CreateFromRecordBreadcrumbs.test.ts +272 -0
  120. package/Tests/App/Dashboard/CreateFromRecordLinks.test.tsx +495 -0
  121. package/Tests/App/Dashboard/CreateFromRecordPages.test.tsx +1026 -0
  122. package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +65 -23
  123. package/Tests/App/Dashboard/CriteriaName.test.ts +5 -1
  124. package/Tests/App/Dashboard/CustomDomainCreateFlow.test.tsx +516 -0
  125. package/Tests/App/Dashboard/CustomDomainDnsSetupModal.test.tsx +547 -0
  126. package/Tests/App/Dashboard/CustomDomainsPages.test.tsx +1077 -0
  127. package/Tests/App/Dashboard/CustomFieldSimpleCreate.test.tsx +2 -2
  128. package/Tests/App/Dashboard/CustomFieldSimpleCreateRender.test.tsx +12 -6
  129. package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +1 -1
  130. package/Tests/App/Dashboard/CustomSmtpConfigForm.test.tsx +969 -0
  131. package/Tests/App/Dashboard/DashboardBlankCanvasAddWidget.test.tsx +425 -0
  132. package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +400 -0
  133. package/Tests/App/Dashboard/DashboardComponentsMRTranslation.test.tsx +4 -3
  134. package/Tests/App/Dashboard/DashboardCreateForm.test.ts +375 -0
  135. package/Tests/App/Dashboard/DashboardCreateFromTemplate.test.tsx +727 -0
  136. package/Tests/App/Dashboard/DashboardEmptyCanvasAddWidget.test.tsx +86 -0
  137. package/Tests/App/Dashboard/DashboardPhoneProductsMenu.test.tsx +99 -9
  138. package/Tests/App/Dashboard/DashboardSharingCard.test.tsx +1226 -0
  139. package/Tests/App/Dashboard/DashboardSharingEntryPoints.test.tsx +383 -0
  140. package/Tests/App/Dashboard/DashboardSharingPage.test.tsx +478 -0
  141. package/Tests/App/Dashboard/DeclareFormsAdvancedRender.test.tsx +90 -34
  142. package/Tests/App/Dashboard/DeclareIncidentMonitorsApart.test.tsx +1028 -0
  143. package/Tests/App/Dashboard/DefaultSsoTeams.test.tsx +215 -0
  144. package/Tests/App/Dashboard/DisabledWarningArchived.test.tsx +3 -3
  145. package/Tests/App/Dashboard/DisabledWarningRobustness.test.tsx +15 -12
  146. package/Tests/App/Dashboard/DiscoveredResourceCreateForms.test.tsx +936 -0
  147. package/Tests/App/Dashboard/EmbeddedMetricCardGroup.test.tsx +720 -0
  148. package/Tests/App/Dashboard/EpisodeMemberRoleAssignmentsFormField.test.tsx +331 -0
  149. package/Tests/App/Dashboard/EpisodePostmortemPage.test.tsx +327 -0
  150. package/Tests/App/Dashboard/EscalationRuleForm.test.ts +2 -2
  151. package/Tests/App/Dashboard/EscalationRuleFormGuard.test.ts +6 -2
  152. package/Tests/App/Dashboard/EscalationRuleOneStep.test.tsx +8 -4
  153. package/Tests/App/Dashboard/EventMeasurements.test.ts +1175 -0
  154. package/Tests/App/Dashboard/EventMeasurementsCard.test.tsx +993 -0
  155. package/Tests/App/Dashboard/EventNoteComposerDialog.test.tsx +939 -0
  156. package/Tests/App/Dashboard/EventNotes.test.tsx +34 -1
  157. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +186 -1
  158. package/Tests/App/Dashboard/EventSettingsSwitchPages.test.tsx +625 -0
  159. package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +6 -2
  160. package/Tests/App/Dashboard/FeedNoteComposerDialog.test.tsx +1327 -0
  161. package/Tests/App/Dashboard/FeedNoteDialogHelpers.ts +109 -0
  162. package/Tests/App/Dashboard/FilterChipClearButton.test.tsx +356 -0
  163. package/Tests/App/Dashboard/FormBrandingSection.test.tsx +504 -0
  164. package/Tests/App/Dashboard/FormBrandingValues.test.ts +255 -0
  165. package/Tests/App/Dashboard/FormBuilderParts.test.tsx +38 -1
  166. package/Tests/App/Dashboard/FormBuilderUi.test.tsx +176 -2
  167. package/Tests/App/Dashboard/FormMappingCard.test.tsx +33 -13
  168. package/Tests/App/Dashboard/FormsMovedPagesAndSubmissions.test.tsx +1 -1
  169. package/Tests/App/Dashboard/GeneratedKeyForms.test.tsx +30 -7
  170. package/Tests/App/Dashboard/GlobalProbesOnNewMonitorsCard.test.tsx +258 -0
  171. package/Tests/App/Dashboard/GroupingRuleFormFlow.test.tsx +653 -37
  172. package/Tests/App/Dashboard/GroupingRulePages.test.tsx +218 -9
  173. package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +52 -4
  174. package/Tests/App/Dashboard/IncidentEpisodeFeedPublicNoteNotifyDefault.test.tsx +230 -338
  175. package/Tests/App/Dashboard/IncidentEpisodeViewFields.test.tsx +45 -9
  176. package/Tests/App/Dashboard/IncidentFeedPublicNoteNotifyDefault.test.tsx +227 -295
  177. package/Tests/App/Dashboard/IncidentLinkedAlertsSettingsPage.test.tsx +157 -181
  178. package/Tests/App/Dashboard/IncidentPostmortemPage.test.tsx +775 -0
  179. package/Tests/App/Dashboard/IncidentRoleFormField.test.tsx +379 -15
  180. package/Tests/App/Dashboard/IncidentRolesSettingsPage.test.tsx +148 -32
  181. package/Tests/App/Dashboard/IncidentTemplateInitialState.test.tsx +430 -0
  182. package/Tests/App/Dashboard/IncidentTemplateMonitorsApart.test.tsx +492 -0
  183. package/Tests/App/Dashboard/IncomingCallEscalationOneStep.test.tsx +830 -0
  184. package/Tests/App/Dashboard/IncomingCallEscalationRuleForm.test.ts +510 -0
  185. package/Tests/App/Dashboard/IncomingCallEscalationRuleFormGuard.test.ts +378 -0
  186. package/Tests/App/Dashboard/IngestionKeyForm.test.ts +664 -0
  187. package/Tests/App/Dashboard/IngestionKeySelectorCreate.test.tsx +523 -0
  188. package/Tests/App/Dashboard/InventoryTypeAndStatusFacets.test.tsx +130 -9
  189. package/Tests/App/Dashboard/IpAllowlistCopy.test.ts +122 -0
  190. package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +19 -3
  191. package/Tests/App/Dashboard/KubernetesMetricsSetupEmptyState.test.tsx +275 -0
  192. package/Tests/App/Dashboard/KubernetesMetricsSetupHints.test.tsx +720 -0
  193. package/Tests/App/Dashboard/LabelsFormField.test.tsx +18 -13
  194. package/Tests/App/Dashboard/LegacyDefaultAssigneeNote.test.tsx +359 -0
  195. package/Tests/App/Dashboard/LogMonitorAttributeOperatorPreview.test.tsx +10 -10
  196. package/Tests/App/Dashboard/MarkdownTemplateDialogsWide.test.tsx +42 -20
  197. package/Tests/App/Dashboard/MeasurementForms.test.tsx +191 -5
  198. package/Tests/App/Dashboard/MeasurementPagesI18n.test.ts +2 -0
  199. package/Tests/App/Dashboard/MeasurementSetup.test.ts +5 -2
  200. package/Tests/App/Dashboard/MenuSpecificFoldedSections.test.tsx +38 -12
  201. package/Tests/App/Dashboard/MessageQueueRulePages.test.tsx +34 -11
  202. package/Tests/App/Dashboard/MetricAndRecordingRuleFormsRender.test.tsx +1206 -0
  203. package/Tests/App/Dashboard/MetricResultsState.test.ts +248 -0
  204. package/Tests/App/Dashboard/MetricViewResultsState.test.tsx +404 -0
  205. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +1 -1
  206. package/Tests/App/Dashboard/MonitorCriteriaAdvancedOptions.test.tsx +77 -27
  207. package/Tests/App/Dashboard/MonitorCriteriaAttributeFilter.test.tsx +5 -8
  208. package/Tests/App/Dashboard/MonitorCriteriaHeaderControls.test.tsx +228 -0
  209. package/Tests/App/Dashboard/MonitorCriteriaIncidentRoles.test.tsx +411 -0
  210. package/Tests/App/Dashboard/MonitorFeedRefresh.test.tsx +5 -1
  211. package/Tests/App/Dashboard/MonitorFormIncidentRoles.test.tsx +460 -0
  212. package/Tests/App/Dashboard/MonitorIntervalRedirect.test.tsx +299 -0
  213. package/Tests/App/Dashboard/MonitorOverviewHero.test.tsx +243 -2
  214. package/Tests/App/Dashboard/MonitorProbesAndIntervalPage.test.tsx +638 -0
  215. package/Tests/App/Dashboard/MonitorStepsDefaultStatusAdvanced.test.tsx +2 -2
  216. package/Tests/App/Dashboard/MonitorSummaryTestMonitorButton.test.tsx +2 -2
  217. package/Tests/App/Dashboard/MonitoringIntervalCard.test.tsx +493 -0
  218. package/Tests/App/Dashboard/MonitoringSwitch.test.tsx +597 -0
  219. package/Tests/App/Dashboard/MovedRunnerSettingsRedirects.test.tsx +4 -5
  220. package/Tests/App/Dashboard/NotificationChannelOffSwitchLists.test.tsx +636 -0
  221. package/Tests/App/Dashboard/OnCallPolicyCreateFormGuard.test.ts +8 -4
  222. package/Tests/App/Dashboard/OnCallPolicyFirstResponders.test.tsx +1 -1
  223. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +54 -0
  224. package/Tests/App/Dashboard/OnCallRulesDeleteGuard.test.tsx +43 -24
  225. package/Tests/App/Dashboard/OnCallRulesRedirects.test.tsx +530 -0
  226. package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +158 -74
  227. package/Tests/App/Dashboard/OnCallRulesTabs.test.tsx +511 -0
  228. package/Tests/App/Dashboard/OnCallScheduleAddLayerDefaults.test.tsx +236 -0
  229. package/Tests/App/Dashboard/OnCallScheduleCreateFormGuard.test.ts +633 -0
  230. package/Tests/App/Dashboard/OnCallScheduleOverrideClarity.test.tsx +13 -2
  231. package/Tests/App/Dashboard/OnCallScheduleWhoTakesTurns.test.tsx +771 -0
  232. package/Tests/App/Dashboard/OnCallSharedCalendarFeedSettingsForm.test.tsx +357 -0
  233. package/Tests/App/Dashboard/OnCallShiftRemindersAndUpcomingShifts.test.tsx +16 -6
  234. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +112 -23
  235. package/Tests/App/Dashboard/PageSearchIndexCoversMenus.test.tsx +594 -0
  236. package/Tests/App/Dashboard/PageSearchIndexCoversRoutes.test.tsx +271 -0
  237. package/Tests/App/Dashboard/PageSearchRanking.test.tsx +373 -0
  238. package/Tests/App/Dashboard/PostmortemPageParts.test.tsx +548 -0
  239. package/Tests/App/Dashboard/ProbeAgreementCard.test.tsx +483 -0
  240. package/Tests/App/Dashboard/ProductOrientation.test.tsx +9 -2
  241. package/Tests/App/Dashboard/ProjectAISettingsPages.test.tsx +282 -404
  242. package/Tests/App/Dashboard/ProjectAiSettingsSwitchPages.test.tsx +1414 -0
  243. package/Tests/App/Dashboard/ProjectNotificationChannels.test.tsx +1191 -0
  244. package/Tests/App/Dashboard/ProjectSettingsSwitchCards.test.tsx +603 -0
  245. package/Tests/App/Dashboard/RemindersCard.test.tsx +477 -0
  246. package/Tests/App/Dashboard/ResourceDetailsCard.test.tsx +458 -0
  247. package/Tests/App/Dashboard/ResourceRuleForm.test.ts +525 -0
  248. package/Tests/App/Dashboard/ResourceRuleFormsRender.test.tsx +803 -0
  249. package/Tests/App/Dashboard/RoleAccess.test.ts +753 -0
  250. package/Tests/App/Dashboard/RoleCardSelectOptions.test.ts +13 -6
  251. package/Tests/App/Dashboard/RouteUtilPageRoute.test.ts +116 -0
  252. package/Tests/App/Dashboard/RowActionPlacementOverrides.test.tsx +1 -1
  253. package/Tests/App/Dashboard/RumSessionReplayRetentionSettings.test.tsx +172 -219
  254. package/Tests/App/Dashboard/RunbookStepHeaderControls.test.tsx +269 -0
  255. package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +45 -85
  256. package/Tests/App/Dashboard/RunnerSupersededByAiAgentNote.test.tsx +16 -23
  257. package/Tests/App/Dashboard/ScheduledMaintenanceAffectedResourcesEditForm.test.tsx +485 -0
  258. package/Tests/App/Dashboard/ScheduledMaintenanceChangeStateNotifyDefault.test.tsx +27 -2
  259. package/Tests/App/Dashboard/ScheduledMaintenanceCreateForm.test.tsx +65 -28
  260. package/Tests/App/Dashboard/ScheduledMaintenanceFeedPublicNoteNotifyDefault.test.tsx +208 -309
  261. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +36 -53
  262. package/Tests/App/Dashboard/ScheduledMaintenanceFormsStructure.test.ts +83 -14
  263. package/Tests/App/Dashboard/ScheduledMaintenanceMonitorsApart.test.tsx +1085 -0
  264. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +378 -25
  265. package/Tests/App/Dashboard/ScheduledMaintenanceStatusPageSuggestions.test.tsx +513 -0
  266. package/Tests/App/Dashboard/ScheduledMaintenanceTemplateForm.test.tsx +31 -9
  267. package/Tests/App/Dashboard/ScheduledMaintenanceTemplateMonitorsApart.test.tsx +760 -0
  268. package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +11 -13
  269. package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +228 -69
  270. package/Tests/App/Dashboard/SelectedProjectSwitches.test.tsx +359 -0
  271. package/Tests/App/Dashboard/ServerlessSetupGuide.test.ts +1 -1
  272. package/Tests/App/Dashboard/SessionReplayAllowedCard.test.tsx +297 -0
  273. package/Tests/App/Dashboard/SetupGuideCard.test.tsx +7 -1
  274. package/Tests/App/Dashboard/ShortFormsOnePage.test.tsx +591 -0
  275. package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +253 -6
  276. package/Tests/App/Dashboard/SloOverviewData.test.tsx +99 -0
  277. package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +3 -1
  278. package/Tests/App/Dashboard/SloSettings.test.tsx +257 -4
  279. package/Tests/App/Dashboard/SsoPages.test.tsx +448 -52
  280. package/Tests/App/Dashboard/StateChangeDialogsFolded.test.tsx +695 -0
  281. package/Tests/App/Dashboard/StateChangeFormFields.test.ts +376 -0
  282. package/Tests/App/Dashboard/StatusPageAccessCard.test.tsx +1088 -0
  283. package/Tests/App/Dashboard/StatusPageAccessCopy.test.ts +450 -0
  284. package/Tests/App/Dashboard/StatusPageAccessMenu.test.tsx +137 -0
  285. package/Tests/App/Dashboard/StatusPageAccessPage.test.tsx +458 -0
  286. package/Tests/App/Dashboard/StatusPageAdvancedSettingsPage.test.tsx +30 -86
  287. package/Tests/App/Dashboard/StatusPageBrandingPage.test.tsx +28 -15
  288. package/Tests/App/Dashboard/StatusPageDisplaySettingsCard.test.tsx +949 -14
  289. package/Tests/App/Dashboard/StatusPagePrivateUsersNotice.test.tsx +233 -0
  290. package/Tests/App/Dashboard/StatusPageReportsCard.test.tsx +1001 -0
  291. package/Tests/App/Dashboard/StatusPageRequireSsoCard.test.tsx +247 -0
  292. package/Tests/App/Dashboard/StatusPageSubscriberSettingsPages.test.tsx +4 -17
  293. package/Tests/App/Dashboard/StatusPageSuggestions.test.tsx +930 -0
  294. package/Tests/App/Dashboard/StatusPageSwitchCardPages.test.tsx +335 -0
  295. package/Tests/App/Dashboard/TeamBlockPermissionsRedirect.test.tsx +332 -0
  296. package/Tests/App/Dashboard/TeamCreateForm.test.ts +206 -0
  297. package/Tests/App/Dashboard/TeamViewPermissions.test.tsx +713 -0
  298. package/Tests/App/Dashboard/TeamViewSideMenuBlockPermissions.test.tsx +113 -0
  299. package/Tests/App/Dashboard/TeamsCreateAccess.test.tsx +799 -0
  300. package/Tests/App/Dashboard/TelemetryDataRuleForms.test.ts +655 -0
  301. package/Tests/App/Dashboard/TelemetryDataRuleFormsRender.test.tsx +1014 -0
  302. package/Tests/App/Dashboard/TelemetryIngestionKeyEdit.test.tsx +6 -3
  303. package/Tests/App/Dashboard/TelemetryIngestionKeyForm.test.tsx +446 -446
  304. package/Tests/App/Dashboard/TelemetryMonitorFiltersFold.test.tsx +613 -0
  305. package/Tests/App/Dashboard/TelemetryRetentionShells.test.tsx +37 -2
  306. package/Tests/App/Dashboard/TemplateFormsNoInternalDataWarning.test.tsx +3 -3
  307. package/Tests/App/Dashboard/TraceExplorer.test.tsx +338 -0
  308. package/Tests/App/Dashboard/TwilioConfigFirstDefault.test.tsx +786 -0
  309. package/Tests/App/Dashboard/UpcomingShiftGetCover.test.tsx +306 -0
  310. package/Tests/App/Dashboard/UseBulkShortenDeviceNames.test.tsx +36 -11
  311. package/Tests/App/Dashboard/UserOverrideForm.test.ts +505 -0
  312. package/Tests/App/Dashboard/UserOverrideFormGuard.test.ts +334 -0
  313. package/Tests/App/Dashboard/UserOverrideWhoIsAway.test.tsx +999 -0
  314. package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +33 -11
  315. package/Tests/App/Dashboard/UserSettingsSetupChecklistPage.test.tsx +49 -4
  316. package/Tests/App/Dashboard/UsersPageEmptyState.test.tsx +245 -0
  317. package/Tests/App/Dashboard/WorkflowVariableOAuthSettingsEditSteps.test.tsx +13 -6
  318. package/Tests/App/Dashboard/WorkspaceMenusConnected.test.tsx +0 -2
  319. package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +108 -86
  320. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +397 -0
  321. package/Tests/App/StatusPage/StatusPageResourceForm.test.tsx +931 -0
  322. package/Tests/App/StatusPage/StatusPageSubscribeOnePage.test.tsx +686 -0
  323. package/Tests/DialogActionRules.ts +16 -5
  324. package/Tests/Helpers/CardHeaderScan.ts +258 -0
  325. package/Tests/Helpers/FormStepsScan.ts +576 -11
  326. package/Tests/Helpers/MonitorGroupStatusPageRows.ts +237 -0
  327. package/Tests/Helpers/NestedControls.ts +184 -0
  328. package/Tests/Helpers/NestedControlsScan.ts +414 -0
  329. package/Tests/Helpers/SteppedFooterScan.ts +722 -0
  330. package/Tests/Models/DatabaseModels/FormModel.test.ts +31 -7
  331. package/Tests/Models/DatabaseModels/UserOverrideColumnDescriptions.test.ts +123 -0
  332. package/Tests/Models/TelemetryDataRuleColumnDefaults.test.ts +239 -0
  333. package/Tests/ResponsiveFlexLayout.test.ts +111 -0
  334. package/Tests/ResponsiveFlexLayout.ts +165 -0
  335. package/Tests/Server/API/DashboardDomainOrderSslAPI.test.ts +372 -0
  336. package/Tests/Server/API/DashboardDomainVerifyCnameAPI.test.ts +921 -0
  337. package/Tests/Server/API/DashboardSharingPublicRoutes.test.ts +559 -0
  338. package/Tests/Server/API/FormBrandingPublicRoutes.test.ts +680 -0
  339. package/Tests/Server/API/ProjectAPICreateWithTenantHeader.test.ts +300 -0
  340. package/Tests/Server/API/ProjectCreateTestHelpers.ts +211 -0
  341. package/Tests/Server/API/ProjectCreateWithTenantHeaderPostgres.test.ts +387 -0
  342. package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +29 -12
  343. package/Tests/Server/API/StatusPageDomainVerifyCnameAPI.test.ts +1090 -0
  344. package/Tests/Server/API/StatusPageMasterPageAccess.test.ts +254 -0
  345. package/Tests/Server/API/StatusPageReportScheduleWrites.test.ts +829 -0
  346. package/Tests/Server/API/StatusPageUptimeSettingsWrites.test.ts +417 -0
  347. package/Tests/Server/API/StatusPagesListingMonitorsAPI.test.ts +1029 -0
  348. package/Tests/Server/API/StatusPagesListingMonitorsRoute.test.ts +286 -0
  349. package/Tests/Server/Infrastructure/GlobalCache.test.ts +156 -0
  350. package/Tests/Server/Infrastructure/Postgres/MigrateIncidentFormsToFormsMigration.test.ts +52 -1
  351. package/Tests/Server/Services/CustomDomainCertificateLifecycle.test.ts +1559 -0
  352. package/Tests/Server/Services/CustomDomainCertificateReissue.test.ts +186 -16
  353. package/Tests/Server/Services/DashboardAccessChoice.test.ts +657 -0
  354. package/Tests/Server/Services/DashboardCreateFromTemplate.test.ts +200 -0
  355. package/Tests/Server/Services/DashboardDomainCertificateSweeps.test.ts +1142 -0
  356. package/Tests/Server/Services/DiscoveredResourceCreate.test.ts +864 -0
  357. package/Tests/Server/Services/DiscoveredResourceUpdate.test.ts +822 -0
  358. package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +3 -4
  359. package/Tests/Server/Services/FileServiceProject.test.ts +345 -0
  360. package/Tests/Server/Services/FormBranding.test.ts +982 -0
  361. package/Tests/Server/Services/FormPublicForm.test.ts +15 -0
  362. package/Tests/Server/Services/GroupingRuleEpisodeOwners.test.ts +857 -0
  363. package/Tests/Server/Services/IncidentFormPostgres.test.ts +297 -1
  364. package/Tests/Server/Services/MachinePickedColors.test.ts +202 -0
  365. package/Tests/Server/Services/OidcProviderCreateDefaults.test.ts +252 -0
  366. package/Tests/Server/Services/OnCallDutyPolicyScheduleFirstLayer.test.ts +799 -0
  367. package/Tests/Server/Services/OnCallDutyPolicyScheduleFirstLayerPlans.test.ts +172 -0
  368. package/Tests/Server/Services/OnCallDutyPolicyUserOverrideWhoIsAway.test.ts +571 -0
  369. package/Tests/Server/Services/OnCallSetupReminder.test.ts +35 -13
  370. package/Tests/Server/Services/OnCallUndeliverablePageRulesLink.test.ts +217 -0
  371. package/Tests/Server/Services/ProfileAggregationService.test.ts +213 -4
  372. package/Tests/Server/Services/ProjectCallSMSConfigFirstDefault.test.ts +699 -0
  373. package/Tests/Server/Services/ProjectCallSMSConfigFirstDefaultBilling.test.ts +247 -0
  374. package/Tests/Server/Services/SamlProviderCreateDefaults.test.ts +255 -0
  375. package/Tests/Server/Services/ScheduledMaintenanceSubscriberMonitorGroups.test.ts +333 -0
  376. package/Tests/Server/Services/ScrubRuleSaveValidation.test.ts +947 -0
  377. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +17 -4
  378. package/Tests/Server/Services/StatusPageAccessChoice.test.ts +548 -0
  379. package/Tests/Server/Services/StatusPageDomainCertificateSweeps.test.ts +1238 -0
  380. package/Tests/Server/Services/TeamCreateAccessGrant.test.ts +607 -0
  381. package/Tests/Server/Services/TwilioConfigSendersGuard.test.ts +249 -0
  382. package/Tests/Server/Services/VerificationCodesUseProjectTwilioConfig.test.ts +264 -0
  383. package/Tests/Server/Types/Database/Permissions/FormBrandingColumns.test.ts +270 -0
  384. package/Tests/Server/Utils/Greenlock/CertificateCleanup.test.ts +526 -0
  385. package/Tests/Server/Utils/Greenlock/CertificateOrder.test.ts +1062 -0
  386. package/Tests/Server/Utils/Greenlock/CertificateOrderBudget.test.ts +243 -0
  387. package/Tests/Server/Utils/Greenlock/CertificateOrderFailures.test.ts +293 -0
  388. package/Tests/Server/Utils/Greenlock/CertificateOrderLock.test.ts +152 -0
  389. package/Tests/Server/Utils/Greenlock/CertificateOwnersGuard.test.ts +119 -0
  390. package/Tests/Server/Utils/Greenlock/CertificateRenewalOwnership.test.ts +1170 -0
  391. package/Tests/Server/Utils/Greenlock/CertificateRenewalSafety.test.ts +368 -0
  392. package/Tests/Server/Utils/Greenlock/CertificateRenewalSchedule.test.ts +188 -11
  393. package/Tests/Server/Utils/Greenlock/CustomDomainOrders.test.ts +723 -0
  394. package/Tests/Server/Utils/Greenlock/InMemoryRedis.ts +189 -0
  395. package/Tests/Server/Utils/Greenlock/NginxAcmeCertificatesToDisk.test.ts +242 -0
  396. package/Tests/Server/Utils/Greenlock/NginxCustomCertificatesToDisk.test.ts +305 -0
  397. package/Tests/Server/Utils/Greenlock/OrderCertGuards.test.ts +583 -0
  398. package/Tests/Server/Utils/Greenlock/OrderCertStorage.test.ts +203 -0
  399. package/Tests/Server/Utils/StatusPage/AffectedStatusPageResources.test.ts +700 -0
  400. package/Tests/Server/Utils/StatusPage/StatusPagesListingMonitorsBuilder.test.ts +744 -0
  401. package/Tests/Types/CustomDomain/CustomDomainCertificates.test.ts +106 -0
  402. package/Tests/Types/CustomDomain/CustomDomainVerification.test.ts +94 -0
  403. package/Tests/Types/Dashboard/DashboardAccess.test.ts +460 -0
  404. package/Tests/Types/Filter/FilterConditionUtil.test.ts +59 -0
  405. package/Tests/Types/Form/FormBranding.test.ts +760 -0
  406. package/Tests/Types/IncomingCall/IncomingCallRingTime.test.ts +80 -0
  407. package/Tests/Types/NotificationRule/OnCallRuleKind.test.ts +271 -0
  408. package/Tests/Types/OnCallDutyPolicy/ScheduleFirstLayer.test.ts +300 -0
  409. package/Tests/Types/OnCallDutyPolicy/ScheduleLayerDefaults.test.ts +316 -0
  410. package/Tests/Types/OnCallDutyPolicy/UserOverrideCoverRequest.test.ts +257 -0
  411. package/Tests/Types/SSO/OidcProviderDefaults.test.ts +474 -0
  412. package/Tests/Types/SSO/SamlProviderDefaults.test.ts +150 -0
  413. package/Tests/Types/SSO/SsoProviderDefaults.test.ts +181 -0
  414. package/Tests/Types/StatusPage/StatusPageAccess.test.ts +393 -0
  415. package/Tests/Types/StatusPage/StatusPagesListingMonitors.test.ts +149 -0
  416. package/Tests/Types/Telemetry/ScrubRule.test.ts +375 -0
  417. package/Tests/UI/Components/AdvancedPageSection.test.tsx +201 -61
  418. package/Tests/UI/Components/BasicFormModalSteps.test.tsx +129 -153
  419. package/Tests/UI/Components/Card.test.tsx +354 -367
  420. package/Tests/UI/Components/CardHeaderActionsGuard.test.tsx +605 -0
  421. package/Tests/UI/Components/CardModelDetailHeaderLayout.test.tsx +23 -8
  422. package/Tests/UI/Components/CardModelDetailOnBeforeUpdate.test.tsx +224 -0
  423. package/Tests/UI/Components/CardModelDetailPageButtons.test.tsx +231 -0
  424. package/Tests/UI/Components/ChoiceRows.test.tsx +365 -0
  425. package/Tests/UI/Components/CommandPalette/CommandPalette.test.tsx +341 -5
  426. package/Tests/UI/Components/CommandPalette/PaletteFilter.test.ts +655 -64
  427. package/Tests/UI/Components/Detail/DetailCreatedOnIdLine.test.tsx +669 -0
  428. package/Tests/UI/Components/Detail/DetailIdLineDarkMode.test.ts +34 -7
  429. package/Tests/UI/Components/Detail/DetailIdLineInLocale.test.tsx +71 -0
  430. package/Tests/UI/Components/Detail/DetailRecordIdLine.test.tsx +26 -7
  431. package/Tests/UI/Components/Detail/DetailRecordLine.test.tsx +326 -0
  432. package/Tests/UI/Components/Detail/DetailRecordTime.test.ts +324 -0
  433. package/Tests/UI/Components/DetailCompactStyle.test.tsx +7 -3
  434. package/Tests/UI/Components/Dropdown/DropdownChange.test.ts +163 -0
  435. package/Tests/UI/Components/EntityDropdown.test.tsx +103 -1
  436. package/Tests/UI/Components/EntityDropdownClearButton.test.tsx +638 -0
  437. package/Tests/UI/Components/EntityDropdownEscape.test.tsx +6 -6
  438. package/Tests/UI/Components/EntityDropdownFocusLeave.test.tsx +21 -4
  439. package/Tests/UI/Components/EntityDropdownQuery.test.tsx +411 -0
  440. package/Tests/UI/Components/EntityDropdownQueryHelpers.test.ts +131 -0
  441. package/Tests/UI/Components/FilePicker.test.tsx +220 -1
  442. package/Tests/UI/Components/FoldedSection/FoldedSection.test.tsx +582 -0
  443. package/Tests/UI/Components/FoldedSection/FoldedSectionDarkMode.test.ts +197 -0
  444. package/Tests/UI/Components/FoldedSection/FoldedSectionItem.test.ts +247 -0
  445. package/Tests/UI/Components/FoldedSection/FoldedSectionQueries.ts +86 -0
  446. package/Tests/UI/Components/Forms/AdvancedStepsGuard.test.ts +358 -32
  447. package/Tests/UI/Components/Forms/AnchoredFieldPopupPlacement.test.tsx +195 -0
  448. package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +187 -23
  449. package/Tests/UI/Components/Forms/BasicFormFillsInOnShow.test.tsx +246 -0
  450. package/Tests/UI/Components/Forms/BasicFormFooterSetValue.test.tsx +283 -0
  451. package/Tests/UI/Components/Forms/BasicFormPrimaryActionLastStep.test.tsx +780 -0
  452. package/Tests/UI/Components/Forms/BasicFormSingleStep.test.tsx +232 -0
  453. package/Tests/UI/Components/Forms/BasicFormStepValidation.test.tsx +7 -4
  454. package/Tests/UI/Components/Forms/BasicFormSubmitAllSteps.test.tsx +4 -3
  455. package/Tests/UI/Components/Forms/CreateFormDefaultsGuard.test.ts +252 -7
  456. package/Tests/UI/Components/Forms/DeclareAndCreateFormsGuard.test.ts +247 -7
  457. package/Tests/UI/Components/Forms/DiscoveredResourceCreateFormsGuard.test.ts +492 -0
  458. package/Tests/UI/Components/Forms/FilterConditionOnlyWithTwoFiltersGuard.test.ts +333 -0
  459. package/Tests/UI/Components/Forms/FoldedEditorWidthTiming.test.tsx +127 -0
  460. package/Tests/UI/Components/Forms/FoldedSectionsGuard.test.ts +523 -0
  461. package/Tests/UI/Components/Forms/FollowPickName.test.ts +88 -0
  462. package/Tests/UI/Components/Forms/FormFieldDropdownChange.test.tsx +294 -0
  463. package/Tests/UI/Components/Forms/FormModalWidth.test.tsx +237 -2
  464. package/Tests/UI/Components/Forms/FormSummary.test.tsx +181 -0
  465. package/Tests/UI/Components/Forms/IncidentEpisodePublicNoteNotifyPayload.test.tsx +110 -86
  466. package/Tests/UI/Components/Forms/LabelsFormFieldGuard.test.ts +101 -96
  467. package/Tests/UI/Components/Forms/LongFormStepsGuard.test.ts +559 -10
  468. package/Tests/UI/Components/Forms/MarkdownFormsAreWide.test.ts +56 -4
  469. package/Tests/UI/Components/Forms/MetricAndRecordingRuleFormsGuard.test.ts +400 -0
  470. package/Tests/UI/Components/Forms/ModelFormColorDefaults.test.tsx +659 -0
  471. package/Tests/UI/Components/Forms/ModelFormCreateDefaults.test.tsx +108 -4
  472. package/Tests/UI/Components/Forms/ModelFormDropdownQuery.test.tsx +403 -0
  473. package/Tests/UI/Components/Forms/ModelFormPreservesUserInput.test.tsx +126 -0
  474. package/Tests/UI/Components/Forms/ModelFormSinglePickPeoplePicker.test.tsx +453 -0
  475. package/Tests/UI/Components/Forms/OidcProviderFormsGuard.test.ts +321 -0
  476. package/Tests/UI/Components/Forms/OneIncidentRolePickerGuard.test.ts +823 -0
  477. package/Tests/UI/Components/Forms/OneSwitchCardsGuard.test.ts +739 -0
  478. package/Tests/UI/Components/Forms/OpenFormSections.test.tsx +169 -0
  479. package/Tests/UI/Components/Forms/OverloadedFormStepsGuard.test.ts +21 -9
  480. package/Tests/UI/Components/Forms/PrimaryActionLastStepGuard.test.ts +478 -0
  481. package/Tests/UI/Components/Forms/ProjectTeamFormsGuard.test.ts +240 -0
  482. package/Tests/UI/Components/Forms/ResourceDetailsOnePlaceGuard.test.ts +936 -0
  483. package/Tests/UI/Components/Forms/ResourceRuleFormsGuard.test.ts +527 -0
  484. package/Tests/UI/Components/Forms/SamlProviderFormsGuard.test.ts +387 -0
  485. package/Tests/UI/Components/Forms/SmallWizardsOnePageGuard.test.ts +331 -0
  486. package/Tests/UI/Components/Forms/SmtpConfigFormsGuard.test.ts +470 -0
  487. package/Tests/UI/Components/Forms/StateChangeDialogsFoldTheNote.test.ts +322 -0
  488. package/Tests/UI/Components/Forms/StatusPageResourceFormsGuard.test.ts +381 -0
  489. package/Tests/UI/Components/Forms/SteppedFormFooter.test.ts +225 -0
  490. package/Tests/UI/Components/Forms/SteppedFormFooterTiming.test.tsx +82 -40
  491. package/Tests/UI/Components/Forms/SwitchCardsGuard.test.ts +339 -0
  492. package/Tests/UI/Components/Forms/TelemetryDataRuleFormsGuard.test.ts +383 -0
  493. package/Tests/UI/Components/Forms/UniqueName.test.ts +163 -0
  494. package/Tests/UI/Components/Forms/Utils/AdvancedFormSection.test.ts +131 -11
  495. package/Tests/UI/Components/Forms/Utils/CreateFormColorDefaults.test.ts +373 -0
  496. package/Tests/UI/Components/Forms/Utils/FoldedFormFields.test.ts +482 -0
  497. package/Tests/UI/Components/LabelRuleImportExport.test.tsx +32 -0
  498. package/Tests/UI/Components/MemberRoleAssignment.test.tsx +51 -7
  499. package/Tests/UI/Components/ModalSecondaryButton.test.tsx +60 -3
  500. package/Tests/UI/Components/ModelFormDraftValues.test.tsx +255 -0
  501. package/Tests/UI/Components/ModelPageHeaderChanged.test.tsx +293 -0
  502. package/Tests/UI/Components/ModelSwitchCard.test.tsx +813 -0
  503. package/Tests/UI/Components/ModelSwitchEvents.test.ts +188 -0
  504. package/Tests/UI/Components/ModelSwitchRow.test.tsx +861 -0
  505. package/Tests/UI/Components/ModelSwitchUtil.test.ts +239 -0
  506. package/Tests/UI/Components/ModelSwitchesCard.test.tsx +699 -0
  507. package/Tests/UI/Components/NavBar.test.tsx +41 -2
  508. package/Tests/UI/Components/NavBarCategoryToggleDarkMode.test.ts +12 -0
  509. package/Tests/UI/Components/NavBarMenuCatalog.test.tsx +197 -30
  510. package/Tests/UI/Components/NavBarMenuFolding.test.tsx +221 -39
  511. package/Tests/UI/Components/NavBarMenuSearch.test.tsx +15 -10
  512. package/Tests/UI/Components/NestedControlsGuard.test.ts +300 -0
  513. package/Tests/UI/Components/PageBreadcrumbOverride.test.tsx +202 -0
  514. package/Tests/UI/Components/PeoplePicker/OwnersFieldGuard.test.ts +269 -5
  515. package/Tests/UI/Components/PeoplePicker/PeoplePickerChange.test.tsx +414 -0
  516. package/Tests/UI/Components/PeoplePicker/PeoplePickerExcludePicks.test.tsx +582 -0
  517. package/Tests/UI/Components/PeoplePicker/PeoplePickerSinglePick.test.tsx +519 -0
  518. package/Tests/UI/Components/PeoplePicker/PeoplePickerSinglePickTypes.test.ts +174 -0
  519. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +8 -3
  520. package/Tests/UI/Components/RuleCriteria/RuleCriteriaNamesGuard.test.ts +14 -6
  521. package/Tests/UI/Components/RuleRun/RuleViewDescription.test.tsx +107 -0
  522. package/Tests/UI/Components/SaveStatus.test.tsx +81 -0
  523. package/Tests/UI/Components/SmtpConfig/SmtpConfigFormFields.test.ts +1078 -0
  524. package/Tests/UI/Components/Sso/OidcProviderForm.test.tsx +608 -0
  525. package/Tests/UI/Components/Sso/OidcProviderFormFields.test.ts +698 -0
  526. package/Tests/UI/Components/Sso/SamlProviderForm.test.tsx +583 -0
  527. package/Tests/UI/Components/Sso/SamlProviderFormFields.test.ts +619 -0
  528. package/Tests/UI/Components/SteppedEditFormSave.test.tsx +199 -141
  529. package/Tests/UI/Components/Table/TableEmptyStateComponent.test.tsx +143 -0
  530. package/Tests/UI/Components/UseSaveModelSwitch.test.tsx +409 -0
  531. package/Tests/UI/Components/Workflow/ArgumentsForm.test.tsx +3 -3
  532. package/Tests/UI/Components/Workflow/ArgumentsFormAdvancedSettings.test.tsx +83 -27
  533. package/Tests/UI/Components/Workflow/WorkflowLogModal.test.tsx +7 -2
  534. package/Tests/UI/Components/useSaveOnChange.test.tsx +341 -0
  535. package/Tests/UI/Monitor/MonitorStepRetrySettings.test.tsx +1 -1
  536. package/Tests/UI/Rum/ReplayTimeline.test.tsx +75 -5
  537. package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +97 -0
  538. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +12 -39
  539. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +1 -6
  540. package/Tests/{App/Dashboard → UI/Utils}/DefaultInviteTeam.test.ts +126 -4
  541. package/Tests/UI/Utils/GrantablePermission.test.ts +172 -0
  542. package/Tests/UI/Utils/PermissionGateColumnUpdate.test.ts +211 -0
  543. package/Tests/UI/Utils/TranslateTemplate.test.ts +31 -0
  544. package/Tests/Utils/DistinctColor.test.ts +446 -0
  545. package/Tests/Utils/Monitor/MonitorOverviewPresentationUtil.test.ts +14 -2
  546. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +1 -1
  547. package/Tests/Utils/NetworkDiscovery/ShortHostnameUtil.test.ts +2 -2
  548. package/Tests/Utils/Slo/SloHealth.test.ts +28 -6
  549. package/Tests/Utils/StatusPage/ReportSchedule.test.ts +867 -0
  550. package/Tests/Utils/Telemetry/DiscoveredResourceName.test.ts +189 -0
  551. package/Tests/Utils/WordMatch.test.ts +104 -0
  552. package/Types/BrandColors.ts +10 -0
  553. package/Types/CustomDomain/CustomDomainCertificates.ts +128 -0
  554. package/Types/CustomDomain/CustomDomainVerification.ts +78 -0
  555. package/Types/Dashboard/DashboardAccess.ts +250 -0
  556. package/Types/Dashboard/DashboardTemplates.ts +33 -0
  557. package/Types/Filter/FilterConditionUtil.ts +29 -0
  558. package/Types/Form/FormBranding.ts +475 -0
  559. package/Types/Form/FormPublic.ts +26 -0
  560. package/Types/IncomingCall/IncomingCallRingTime.ts +48 -0
  561. package/Types/Log/LogScrubField.ts +14 -0
  562. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +1 -1
  563. package/Types/NotificationRule/OnCallRuleKind.ts +194 -0
  564. package/Types/OnCallDutyPolicy/FirstResponders.ts +3 -32
  565. package/Types/OnCallDutyPolicy/MiscDataId.ts +38 -0
  566. package/Types/OnCallDutyPolicy/ScheduleFirstLayer.ts +165 -0
  567. package/Types/OnCallDutyPolicy/ScheduleLayerDefaults.ts +160 -0
  568. package/Types/OnCallDutyPolicy/UserOverrideCoverRequest.ts +148 -0
  569. package/Types/SSO/OidcProviderDefaults.ts +282 -0
  570. package/Types/SSO/SamlProviderDefaults.ts +77 -0
  571. package/Types/SSO/SsoProviderDefaults.ts +101 -0
  572. package/Types/StatusPage/StatusPageAccess.ts +215 -0
  573. package/Types/StatusPage/StatusPagesListingMonitors.ts +150 -0
  574. package/Types/Telemetry/ScrubRule.ts +240 -0
  575. package/UI/Components/AdvancedPageSection/AdvancedPageSection.tsx +59 -29
  576. package/UI/Components/Card/Card.tsx +139 -80
  577. package/UI/Components/ChoiceRows/ChoiceRows.tsx +249 -0
  578. package/UI/Components/CommandPalette/CommandPalette.tsx +28 -12
  579. package/UI/Components/CommandPalette/PaletteFilter.ts +962 -75
  580. package/UI/Components/CommandPalette/PaletteRow.tsx +35 -3
  581. package/UI/Components/CommandPalette/Types.ts +37 -1
  582. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +6 -0
  583. package/UI/Components/Detail/Detail.tsx +52 -15
  584. package/UI/Components/Detail/DetailRecordLine.tsx +96 -0
  585. package/UI/Components/Detail/DetailRecordTime.ts +196 -0
  586. package/UI/Components/Dropdown/DropdownChange.ts +198 -0
  587. package/UI/Components/EntityDropdown/EntityDropdown.tsx +270 -106
  588. package/UI/Components/EntityDropdown/EntityDropdownQuery.ts +119 -0
  589. package/UI/Components/FilePicker/FilePicker.tsx +90 -6
  590. package/UI/Components/FoldedSection/FoldedSection.tsx +370 -0
  591. package/UI/Components/FoldedSection/FoldedSectionItem.ts +141 -0
  592. package/UI/Components/FoldedSection/FoldedSectionTitles.ts +39 -0
  593. package/UI/Components/FormModal/BasicFormModal.tsx +40 -67
  594. package/UI/Components/Forms/BasicForm.tsx +218 -119
  595. package/UI/Components/Forms/BasicModelForm.tsx +0 -2
  596. package/UI/Components/Forms/CollapsibleFormSection.tsx +108 -18
  597. package/UI/Components/Forms/Fields/FormField.tsx +62 -15
  598. package/UI/Components/Forms/Fields/GeneratedKeyField.tsx +1 -5
  599. package/UI/Components/Forms/FormSummary.tsx +5 -3
  600. package/UI/Components/Forms/ModelForm.tsx +123 -16
  601. package/UI/Components/Forms/Types/Field.ts +98 -16
  602. package/UI/Components/Forms/Utils/AdvancedFormSection.ts +102 -31
  603. package/UI/Components/Forms/Utils/CreateFormDefaults.ts +158 -17
  604. package/UI/Components/Forms/Utils/FoldedFormFields.ts +393 -0
  605. package/UI/Components/Forms/Utils/FollowPickName.ts +52 -0
  606. package/UI/Components/Forms/Utils/FormModalWidth.ts +35 -4
  607. package/UI/Components/Forms/Utils/OpenFormSections.ts +104 -0
  608. package/UI/Components/Forms/Utils/SteppedFormFooter.ts +151 -0
  609. package/UI/Components/Forms/Utils/UniqueName.ts +81 -0
  610. package/UI/Components/LabelRule/ImportLabelRulesModal.tsx +22 -3
  611. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +6 -5
  612. package/UI/Components/Modal/ModalFooter.tsx +10 -1
  613. package/UI/Components/ModelDetail/CardModelDetail.tsx +33 -8
  614. package/UI/Components/ModelFormModal/ModelFormModal.tsx +44 -58
  615. package/UI/Components/ModelSwitch/ModelSwitchCard.tsx +305 -0
  616. package/UI/Components/ModelSwitch/ModelSwitchEvents.ts +109 -0
  617. package/UI/Components/ModelSwitch/ModelSwitchRow.tsx +438 -0
  618. package/UI/Components/ModelSwitch/ModelSwitchUtil.ts +120 -0
  619. package/UI/Components/ModelSwitch/ModelSwitchesCard.tsx +265 -0
  620. package/UI/Components/ModelSwitch/useSaveModelSwitch.ts +144 -0
  621. package/UI/Components/ModelTable/BaseModelTable.tsx +6 -0
  622. package/UI/Components/ModelTable/ModelTable.tsx +5 -0
  623. package/UI/Components/Navbar/NavBar.tsx +10 -9
  624. package/UI/Components/Navbar/NavBarMenuCatalog.ts +57 -22
  625. package/UI/Components/Navbar/NavBarMenuModal.tsx +17 -13
  626. package/UI/Components/Navbar/NavBarMobileMenu.tsx +40 -23
  627. package/UI/Components/Page/ModelHeaderEvents.ts +75 -0
  628. package/UI/Components/Page/ModelPage.tsx +21 -1
  629. package/UI/Components/Page/Page.tsx +68 -13
  630. package/UI/Components/PeoplePicker/PeoplePicker.tsx +150 -45
  631. package/UI/Components/PeoplePicker/PeoplePickerTypes.ts +193 -4
  632. package/UI/Components/PeoplePicker/PeopleSearchPopup.tsx +37 -10
  633. package/UI/Components/PublicForm/PublicFormFavicon.ts +99 -0
  634. package/UI/Components/PublicForm/PublicFormLogo.tsx +81 -0
  635. package/UI/Components/RuleCriteria/RuleCriteriaBuilder.tsx +5 -3
  636. package/UI/Components/RuleRun/RuleView.tsx +2 -5
  637. package/UI/Components/SaveStatus/SaveStatus.tsx +76 -0
  638. package/UI/Components/SaveStatus/useSaveOnChange.ts +178 -0
  639. package/UI/Components/SmtpConfig/SmtpConfigFormFields.ts +815 -0
  640. package/UI/Components/Sso/OidcProviderFormFields.ts +481 -0
  641. package/UI/Components/Sso/SamlProviderFormFields.ts +322 -0
  642. package/UI/Components/Sso/SsoProviderFormFields.ts +331 -0
  643. package/UI/Components/Table/TableEmptyState.tsx +39 -5
  644. package/UI/Components/Workflow/ArgumentsForm.tsx +21 -78
  645. package/UI/Components/Workflow/ComponentPicker/ComponentSearch.ts +18 -145
  646. package/UI/Components/Workflow/WorkflowLogModal.tsx +1 -3
  647. package/UI/Types/UseAnchoredFieldPopup.ts +46 -4
  648. package/UI/Utils/DefaultInviteTeam.ts +306 -0
  649. package/UI/Utils/GrantablePermission.ts +46 -0
  650. package/UI/Utils/PermissionGate.ts +80 -7
  651. package/UI/Utils/TranslateTemplate.ts +22 -0
  652. package/Utils/DistinctColor.ts +223 -0
  653. package/Utils/Monitor/MonitorOverviewPresentationUtil.ts +47 -2
  654. package/Utils/Slo/SloHealth.ts +9 -3
  655. package/Utils/StatusPage/ReportSchedule.ts +462 -0
  656. package/Utils/Telemetry/DiscoveredResourceName.ts +95 -0
  657. package/Utils/WordMatch.ts +185 -0
  658. package/build/dist/Models/DatabaseModels/AlertGroupingRule.js +6 -6
  659. package/build/dist/Models/DatabaseModels/AlertGroupingRule.js.map +1 -1
  660. package/build/dist/Models/DatabaseModels/File.js +47 -1
  661. package/build/dist/Models/DatabaseModels/File.js.map +1 -1
  662. package/build/dist/Models/DatabaseModels/Form.js +125 -0
  663. package/build/dist/Models/DatabaseModels/Form.js.map +1 -1
  664. package/build/dist/Models/DatabaseModels/IncidentGroupingRule.js +6 -6
  665. package/build/dist/Models/DatabaseModels/IncidentGroupingRule.js.map +1 -1
  666. package/build/dist/Models/DatabaseModels/LogDropFilter.js +1 -0
  667. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  668. package/build/dist/Models/DatabaseModels/LogPipeline.js +1 -0
  669. package/build/dist/Models/DatabaseModels/LogPipeline.js.map +1 -1
  670. package/build/dist/Models/DatabaseModels/LogScrubRule.js +14 -8
  671. package/build/dist/Models/DatabaseModels/LogScrubRule.js.map +1 -1
  672. package/build/dist/Models/DatabaseModels/MetricRecordingRule.js +1 -1
  673. package/build/dist/Models/DatabaseModels/MetricRecordingRule.js.map +1 -1
  674. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js +2 -2
  675. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js.map +1 -1
  676. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js +20 -9
  677. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js.map +1 -1
  678. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js +6 -1
  679. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
  680. package/build/dist/Models/DatabaseModels/StatusPage.js +4 -4
  681. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  682. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +1 -0
  683. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  684. package/build/dist/Models/DatabaseModels/TracePipeline.js +1 -0
  685. package/build/dist/Models/DatabaseModels/TracePipeline.js.map +1 -1
  686. package/build/dist/Models/DatabaseModels/TraceRecordingRule.js +1 -1
  687. package/build/dist/Models/DatabaseModels/TraceRecordingRule.js.map +1 -1
  688. package/build/dist/Models/DatabaseModels/TraceScrubRule.js +14 -8
  689. package/build/dist/Models/DatabaseModels/TraceScrubRule.js.map +1 -1
  690. package/build/dist/Models/DatabaseModels/UserOnCallLog.js +2 -2
  691. package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
  692. package/build/dist/Server/API/CustomDomainRoutes.js +124 -0
  693. package/build/dist/Server/API/CustomDomainRoutes.js.map +1 -0
  694. package/build/dist/Server/API/DashboardAPI.js +22 -4
  695. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  696. package/build/dist/Server/API/DashboardDomainAPI.js +56 -49
  697. package/build/dist/Server/API/DashboardDomainAPI.js.map +1 -1
  698. package/build/dist/Server/API/StatusPageAPI.js +101 -39
  699. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  700. package/build/dist/Server/API/StatusPageDomainAPI.js +52 -51
  701. package/build/dist/Server/API/StatusPageDomainAPI.js.map +1 -1
  702. package/build/dist/Server/Infrastructure/GlobalCache.js +63 -0
  703. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  704. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1797700000000-AddFormBranding.js +36 -0
  705. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1797700000000-AddFormBranding.js.map +1 -0
  706. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  707. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  708. package/build/dist/Server/Services/AlertGroupingEngineService.js +44 -61
  709. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
  710. package/build/dist/Server/Services/AlertGroupingRuleService.js +45 -0
  711. package/build/dist/Server/Services/AlertGroupingRuleService.js.map +1 -1
  712. package/build/dist/Server/Services/CephClusterService.js +23 -0
  713. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  714. package/build/dist/Server/Services/CloudResourceService.js +39 -0
  715. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  716. package/build/dist/Server/Services/DashboardDomainService.js +510 -172
  717. package/build/dist/Server/Services/DashboardDomainService.js.map +1 -1
  718. package/build/dist/Server/Services/DashboardService.js +22 -9
  719. package/build/dist/Server/Services/DashboardService.js.map +1 -1
  720. package/build/dist/Server/Services/DatabaseService.js +114 -10
  721. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  722. package/build/dist/Server/Services/DockerHostService.js +51 -0
  723. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  724. package/build/dist/Server/Services/DockerSwarmClusterService.js +23 -0
  725. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  726. package/build/dist/Server/Services/FileService.js +45 -0
  727. package/build/dist/Server/Services/FileService.js.map +1 -1
  728. package/build/dist/Server/Services/FormService.js +158 -14
  729. package/build/dist/Server/Services/FormService.js.map +1 -1
  730. package/build/dist/Server/Services/GlobalOidcService.js +9 -0
  731. package/build/dist/Server/Services/GlobalOidcService.js.map +1 -1
  732. package/build/dist/Server/Services/GlobalSsoService.js +9 -0
  733. package/build/dist/Server/Services/GlobalSsoService.js.map +1 -1
  734. package/build/dist/Server/Services/HostService.js +50 -0
  735. package/build/dist/Server/Services/HostService.js.map +1 -1
  736. package/build/dist/Server/Services/IncidentGroupingEngineService.js +45 -62
  737. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  738. package/build/dist/Server/Services/IncidentGroupingRuleService.js +45 -0
  739. package/build/dist/Server/Services/IncidentGroupingRuleService.js.map +1 -1
  740. package/build/dist/Server/Services/IoTFleetService.js +23 -0
  741. package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
  742. package/build/dist/Server/Services/KubernetesClusterService.js +54 -0
  743. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  744. package/build/dist/Server/Services/LabelService.js +6 -16
  745. package/build/dist/Server/Services/LabelService.js.map +1 -1
  746. package/build/dist/Server/Services/LogScrubRuleService.js +31 -0
  747. package/build/dist/Server/Services/LogScrubRuleService.js.map +1 -1
  748. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +202 -0
  749. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  750. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +7 -1
  751. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
  752. package/build/dist/Server/Services/OnCallNotificationAlertingService.js +17 -24
  753. package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -1
  754. package/build/dist/Server/Services/OnCallSetupReminderService.js +32 -38
  755. package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -1
  756. package/build/dist/Server/Services/PodmanHostService.js +51 -0
  757. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  758. package/build/dist/Server/Services/ProfileAggregationService.js +34 -0
  759. package/build/dist/Server/Services/ProfileAggregationService.js.map +1 -1
  760. package/build/dist/Server/Services/ProjectCallSMSConfigService.js +53 -3
  761. package/build/dist/Server/Services/ProjectCallSMSConfigService.js.map +1 -1
  762. package/build/dist/Server/Services/ProjectOidcService.js +28 -0
  763. package/build/dist/Server/Services/ProjectOidcService.js.map +1 -1
  764. package/build/dist/Server/Services/ProjectSsoService.js +28 -0
  765. package/build/dist/Server/Services/ProjectSsoService.js.map +1 -1
  766. package/build/dist/Server/Services/ProxmoxClusterService.js +23 -0
  767. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  768. package/build/dist/Server/Services/RumApplicationService.js +42 -0
  769. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  770. package/build/dist/Server/Services/ScheduledMaintenanceService.js +18 -26
  771. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  772. package/build/dist/Server/Services/ServerlessFunctionService.js +44 -0
  773. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  774. package/build/dist/Server/Services/ServiceService.js +30 -4
  775. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  776. package/build/dist/Server/Services/StatusPageDomainService.js +495 -174
  777. package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
  778. package/build/dist/Server/Services/StatusPageOidcService.js +28 -0
  779. package/build/dist/Server/Services/StatusPageOidcService.js.map +1 -1
  780. package/build/dist/Server/Services/StatusPageResourceService.js +82 -46
  781. package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
  782. package/build/dist/Server/Services/StatusPageService.js +174 -45
  783. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  784. package/build/dist/Server/Services/StatusPageSsoService.js +28 -0
  785. package/build/dist/Server/Services/StatusPageSsoService.js.map +1 -1
  786. package/build/dist/Server/Services/TraceScrubRuleService.js +31 -0
  787. package/build/dist/Server/Services/TraceScrubRuleService.js.map +1 -1
  788. package/build/dist/Server/Services/UserIncomingCallNumberService.js +20 -10
  789. package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -1
  790. package/build/dist/Server/Services/VMwareVCenterService.js +23 -0
  791. package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
  792. package/build/dist/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.js +3 -3
  793. package/build/dist/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.js.map +1 -1
  794. package/build/dist/Server/Utils/Greenlock/CertificateOrder.js +353 -0
  795. package/build/dist/Server/Utils/Greenlock/CertificateOrder.js.map +1 -0
  796. package/build/dist/Server/Utils/Greenlock/CertificateOrderBudget.js +119 -0
  797. package/build/dist/Server/Utils/Greenlock/CertificateOrderBudget.js.map +1 -0
  798. package/build/dist/Server/Utils/Greenlock/CertificateOrderFailures.js +208 -0
  799. package/build/dist/Server/Utils/Greenlock/CertificateOrderFailures.js.map +1 -0
  800. package/build/dist/Server/Utils/Greenlock/CertificateOrderLock.js +111 -0
  801. package/build/dist/Server/Utils/Greenlock/CertificateOrderLock.js.map +1 -0
  802. package/build/dist/Server/Utils/Greenlock/CertificateOrderOutcome.js +30 -0
  803. package/build/dist/Server/Utils/Greenlock/CertificateOrderOutcome.js.map +1 -0
  804. package/build/dist/Server/Utils/Greenlock/CertificateOwners.js +52 -0
  805. package/build/dist/Server/Utils/Greenlock/CertificateOwners.js.map +1 -0
  806. package/build/dist/Server/Utils/Greenlock/CertificateReissueOrder.js +80 -0
  807. package/build/dist/Server/Utils/Greenlock/CertificateReissueOrder.js.map +1 -0
  808. package/build/dist/Server/Utils/Greenlock/CustomDomainOrders.js +296 -0
  809. package/build/dist/Server/Utils/Greenlock/CustomDomainOrders.js.map +1 -0
  810. package/build/dist/Server/Utils/Greenlock/Greenlock.js +595 -146
  811. package/build/dist/Server/Utils/Greenlock/Greenlock.js.map +1 -1
  812. package/build/dist/Server/Utils/Rules/GroupingRuleEpisodeOwners.js +366 -0
  813. package/build/dist/Server/Utils/Rules/GroupingRuleEpisodeOwners.js.map +1 -0
  814. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +7 -0
  815. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -1
  816. package/build/dist/Server/Utils/ScrubRuleValidation.js +127 -0
  817. package/build/dist/Server/Utils/ScrubRuleValidation.js.map +1 -0
  818. package/build/dist/Server/Utils/StatusPage/AffectedStatusPageResources.js +97 -0
  819. package/build/dist/Server/Utils/StatusPage/AffectedStatusPageResources.js.map +1 -0
  820. package/build/dist/Server/Utils/StatusPage/StatusPagesListingMonitorsBuilder.js +195 -0
  821. package/build/dist/Server/Utils/StatusPage/StatusPagesListingMonitorsBuilder.js.map +1 -0
  822. package/build/dist/Server/Utils/Telemetry/DiscoveredResourceCreate.js +177 -0
  823. package/build/dist/Server/Utils/Telemetry/DiscoveredResourceCreate.js.map +1 -0
  824. package/build/dist/Server/Utils/Telemetry/DiscoveredResourceUpdate.js +129 -0
  825. package/build/dist/Server/Utils/Telemetry/DiscoveredResourceUpdate.js.map +1 -0
  826. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js +8 -2
  827. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js.map +1 -1
  828. package/build/dist/Types/BrandColors.js +9 -0
  829. package/build/dist/Types/BrandColors.js.map +1 -1
  830. package/build/dist/Types/CustomDomain/CustomDomainCertificates.js +71 -0
  831. package/build/dist/Types/CustomDomain/CustomDomainCertificates.js.map +1 -0
  832. package/build/dist/Types/CustomDomain/CustomDomainVerification.js +58 -0
  833. package/build/dist/Types/CustomDomain/CustomDomainVerification.js.map +1 -0
  834. package/build/dist/Types/Dashboard/DashboardAccess.js +157 -0
  835. package/build/dist/Types/Dashboard/DashboardAccess.js.map +1 -0
  836. package/build/dist/Types/Dashboard/DashboardTemplates.js +26 -0
  837. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  838. package/build/dist/Types/Filter/FilterConditionUtil.js +24 -0
  839. package/build/dist/Types/Filter/FilterConditionUtil.js.map +1 -0
  840. package/build/dist/Types/Form/FormBranding.js +266 -0
  841. package/build/dist/Types/Form/FormBranding.js.map +1 -0
  842. package/build/dist/Types/Form/FormPublic.js +6 -0
  843. package/build/dist/Types/Form/FormPublic.js.map +1 -1
  844. package/build/dist/Types/IncomingCall/IncomingCallRingTime.js +37 -0
  845. package/build/dist/Types/IncomingCall/IncomingCallRingTime.js.map +1 -0
  846. package/build/dist/Types/Log/LogScrubField.js +15 -0
  847. package/build/dist/Types/Log/LogScrubField.js.map +1 -0
  848. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +1 -1
  849. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
  850. package/build/dist/Types/NotificationRule/OnCallRuleKind.js +134 -0
  851. package/build/dist/Types/NotificationRule/OnCallRuleKind.js.map +1 -0
  852. package/build/dist/Types/OnCallDutyPolicy/FirstResponders.js +2 -23
  853. package/build/dist/Types/OnCallDutyPolicy/FirstResponders.js.map +1 -1
  854. package/build/dist/Types/OnCallDutyPolicy/MiscDataId.js +30 -0
  855. package/build/dist/Types/OnCallDutyPolicy/MiscDataId.js.map +1 -0
  856. package/build/dist/Types/OnCallDutyPolicy/ScheduleFirstLayer.js +113 -0
  857. package/build/dist/Types/OnCallDutyPolicy/ScheduleFirstLayer.js.map +1 -0
  858. package/build/dist/Types/OnCallDutyPolicy/ScheduleLayerDefaults.js +95 -0
  859. package/build/dist/Types/OnCallDutyPolicy/ScheduleLayerDefaults.js.map +1 -0
  860. package/build/dist/Types/OnCallDutyPolicy/UserOverrideCoverRequest.js +99 -0
  861. package/build/dist/Types/OnCallDutyPolicy/UserOverrideCoverRequest.js.map +1 -0
  862. package/build/dist/Types/SSO/OidcProviderDefaults.js +189 -0
  863. package/build/dist/Types/SSO/OidcProviderDefaults.js.map +1 -0
  864. package/build/dist/Types/SSO/SamlProviderDefaults.js +55 -0
  865. package/build/dist/Types/SSO/SamlProviderDefaults.js.map +1 -0
  866. package/build/dist/Types/SSO/SsoProviderDefaults.js +67 -0
  867. package/build/dist/Types/SSO/SsoProviderDefaults.js.map +1 -0
  868. package/build/dist/Types/StatusPage/StatusPageAccess.js +132 -0
  869. package/build/dist/Types/StatusPage/StatusPageAccess.js.map +1 -0
  870. package/build/dist/Types/StatusPage/StatusPagesListingMonitors.js +84 -0
  871. package/build/dist/Types/StatusPage/StatusPagesListingMonitors.js.map +1 -0
  872. package/build/dist/Types/Telemetry/ScrubRule.js +180 -0
  873. package/build/dist/Types/Telemetry/ScrubRule.js.map +1 -0
  874. package/build/dist/UI/Components/AdvancedPageSection/AdvancedPageSection.js +9 -7
  875. package/build/dist/UI/Components/AdvancedPageSection/AdvancedPageSection.js.map +1 -1
  876. package/build/dist/UI/Components/Card/Card.js +81 -35
  877. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  878. package/build/dist/UI/Components/ChoiceRows/ChoiceRows.js +54 -0
  879. package/build/dist/UI/Components/ChoiceRows/ChoiceRows.js.map +1 -0
  880. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +25 -12
  881. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  882. package/build/dist/UI/Components/CommandPalette/PaletteFilter.js +632 -64
  883. package/build/dist/UI/Components/CommandPalette/PaletteFilter.js.map +1 -1
  884. package/build/dist/UI/Components/CommandPalette/PaletteRow.js +7 -1
  885. package/build/dist/UI/Components/CommandPalette/PaletteRow.js.map +1 -1
  886. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +7 -1
  887. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  888. package/build/dist/UI/Components/Detail/Detail.js +26 -13
  889. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  890. package/build/dist/UI/Components/Detail/DetailRecordLine.js +32 -0
  891. package/build/dist/UI/Components/Detail/DetailRecordLine.js.map +1 -0
  892. package/build/dist/UI/Components/Detail/DetailRecordTime.js +134 -0
  893. package/build/dist/UI/Components/Detail/DetailRecordTime.js.map +1 -0
  894. package/build/dist/UI/Components/Dropdown/DropdownChange.js +102 -0
  895. package/build/dist/UI/Components/Dropdown/DropdownChange.js.map +1 -0
  896. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +134 -57
  897. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  898. package/build/dist/UI/Components/EntityDropdown/EntityDropdownQuery.js +78 -0
  899. package/build/dist/UI/Components/EntityDropdown/EntityDropdownQuery.js.map +1 -0
  900. package/build/dist/UI/Components/FilePicker/FilePicker.js +55 -6
  901. package/build/dist/UI/Components/FilePicker/FilePicker.js.map +1 -1
  902. package/build/dist/UI/Components/FoldedSection/FoldedSection.js +139 -0
  903. package/build/dist/UI/Components/FoldedSection/FoldedSection.js.map +1 -0
  904. package/build/dist/UI/Components/FoldedSection/FoldedSectionItem.js +58 -0
  905. package/build/dist/UI/Components/FoldedSection/FoldedSectionItem.js.map +1 -0
  906. package/build/dist/UI/Components/FoldedSection/FoldedSectionTitles.js +34 -0
  907. package/build/dist/UI/Components/FoldedSection/FoldedSectionTitles.js.map +1 -0
  908. package/build/dist/UI/Components/FormModal/BasicFormModal.js +29 -45
  909. package/build/dist/UI/Components/FormModal/BasicFormModal.js.map +1 -1
  910. package/build/dist/UI/Components/Forms/BasicForm.js +148 -89
  911. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  912. package/build/dist/UI/Components/Forms/BasicModelForm.js +1 -1
  913. package/build/dist/UI/Components/Forms/BasicModelForm.js.map +1 -1
  914. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +49 -10
  915. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -1
  916. package/build/dist/UI/Components/Forms/Fields/FormField.js +25 -11
  917. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  918. package/build/dist/UI/Components/Forms/Fields/GeneratedKeyField.js +2 -5
  919. package/build/dist/UI/Components/Forms/Fields/GeneratedKeyField.js.map +1 -1
  920. package/build/dist/UI/Components/Forms/FormSummary.js +5 -3
  921. package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
  922. package/build/dist/UI/Components/Forms/ModelForm.js +72 -14
  923. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  924. package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
  925. package/build/dist/UI/Components/Forms/Utils/AdvancedFormSection.js +80 -23
  926. package/build/dist/UI/Components/Forms/Utils/AdvancedFormSection.js.map +1 -1
  927. package/build/dist/UI/Components/Forms/Utils/CreateFormDefaults.js +91 -9
  928. package/build/dist/UI/Components/Forms/Utils/CreateFormDefaults.js.map +1 -1
  929. package/build/dist/UI/Components/Forms/Utils/FoldedFormFields.js +243 -0
  930. package/build/dist/UI/Components/Forms/Utils/FoldedFormFields.js.map +1 -0
  931. package/build/dist/UI/Components/Forms/Utils/FollowPickName.js +32 -0
  932. package/build/dist/UI/Components/Forms/Utils/FollowPickName.js.map +1 -0
  933. package/build/dist/UI/Components/Forms/Utils/FormModalWidth.js +25 -5
  934. package/build/dist/UI/Components/Forms/Utils/FormModalWidth.js.map +1 -1
  935. package/build/dist/UI/Components/Forms/Utils/OpenFormSections.js +32 -0
  936. package/build/dist/UI/Components/Forms/Utils/OpenFormSections.js.map +1 -0
  937. package/build/dist/UI/Components/Forms/Utils/SteppedFormFooter.js +71 -0
  938. package/build/dist/UI/Components/Forms/Utils/SteppedFormFooter.js.map +1 -0
  939. package/build/dist/UI/Components/Forms/Utils/UniqueName.js +56 -0
  940. package/build/dist/UI/Components/Forms/Utils/UniqueName.js.map +1 -0
  941. package/build/dist/UI/Components/LabelRule/ImportLabelRulesModal.js +17 -1
  942. package/build/dist/UI/Components/LabelRule/ImportLabelRulesModal.js.map +1 -1
  943. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
  944. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  945. package/build/dist/UI/Components/Modal/ModalFooter.js +8 -1
  946. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  947. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +19 -6
  948. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  949. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js +33 -43
  950. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  951. package/build/dist/UI/Components/ModelSwitch/ModelSwitchCard.js +151 -0
  952. package/build/dist/UI/Components/ModelSwitch/ModelSwitchCard.js.map +1 -0
  953. package/build/dist/UI/Components/ModelSwitch/ModelSwitchEvents.js +54 -0
  954. package/build/dist/UI/Components/ModelSwitch/ModelSwitchEvents.js.map +1 -0
  955. package/build/dist/UI/Components/ModelSwitch/ModelSwitchRow.js +201 -0
  956. package/build/dist/UI/Components/ModelSwitch/ModelSwitchRow.js.map +1 -0
  957. package/build/dist/UI/Components/ModelSwitch/ModelSwitchUtil.js +60 -0
  958. package/build/dist/UI/Components/ModelSwitch/ModelSwitchUtil.js.map +1 -0
  959. package/build/dist/UI/Components/ModelSwitch/ModelSwitchesCard.js +116 -0
  960. package/build/dist/UI/Components/ModelSwitch/ModelSwitchesCard.js.map +1 -0
  961. package/build/dist/UI/Components/ModelSwitch/useSaveModelSwitch.js +68 -0
  962. package/build/dist/UI/Components/ModelSwitch/useSaveModelSwitch.js.map +1 -0
  963. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -0
  964. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  965. package/build/dist/UI/Components/ModelTable/ModelTable.js +3 -1
  966. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  967. package/build/dist/UI/Components/Navbar/NavBar.js +2 -2
  968. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  969. package/build/dist/UI/Components/Navbar/NavBarMenuCatalog.js +21 -10
  970. package/build/dist/UI/Components/Navbar/NavBarMenuCatalog.js.map +1 -1
  971. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +10 -7
  972. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  973. package/build/dist/UI/Components/Navbar/NavBarMobileMenu.js +17 -9
  974. package/build/dist/UI/Components/Navbar/NavBarMobileMenu.js.map +1 -1
  975. package/build/dist/UI/Components/Page/ModelHeaderEvents.js +43 -0
  976. package/build/dist/UI/Components/Page/ModelHeaderEvents.js.map +1 -0
  977. package/build/dist/UI/Components/Page/ModelPage.js +19 -1
  978. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  979. package/build/dist/UI/Components/Page/Page.js +31 -13
  980. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  981. package/build/dist/UI/Components/PeoplePicker/PeoplePicker.js +62 -20
  982. package/build/dist/UI/Components/PeoplePicker/PeoplePicker.js.map +1 -1
  983. package/build/dist/UI/Components/PeoplePicker/PeoplePickerTypes.js +98 -1
  984. package/build/dist/UI/Components/PeoplePicker/PeoplePickerTypes.js.map +1 -1
  985. package/build/dist/UI/Components/PeoplePicker/PeopleSearchPopup.js +35 -14
  986. package/build/dist/UI/Components/PeoplePicker/PeopleSearchPopup.js.map +1 -1
  987. package/build/dist/UI/Components/PublicForm/PublicFormFavicon.js +66 -0
  988. package/build/dist/UI/Components/PublicForm/PublicFormFavicon.js.map +1 -0
  989. package/build/dist/UI/Components/PublicForm/PublicFormLogo.js +38 -0
  990. package/build/dist/UI/Components/PublicForm/PublicFormLogo.js.map +1 -0
  991. package/build/dist/UI/Components/RuleCriteria/RuleCriteriaBuilder.js +5 -3
  992. package/build/dist/UI/Components/RuleCriteria/RuleCriteriaBuilder.js.map +1 -1
  993. package/build/dist/UI/Components/RuleRun/RuleView.js +2 -2
  994. package/build/dist/UI/Components/RuleRun/RuleView.js.map +1 -1
  995. package/build/dist/UI/Components/SaveStatus/SaveStatus.js +46 -0
  996. package/build/dist/UI/Components/SaveStatus/SaveStatus.js.map +1 -0
  997. package/build/dist/UI/Components/SaveStatus/useSaveOnChange.js +98 -0
  998. package/build/dist/UI/Components/SaveStatus/useSaveOnChange.js.map +1 -0
  999. package/build/dist/UI/Components/SmtpConfig/SmtpConfigFormFields.js +503 -0
  1000. package/build/dist/UI/Components/SmtpConfig/SmtpConfigFormFields.js.map +1 -0
  1001. package/build/dist/UI/Components/Sso/OidcProviderFormFields.js +283 -0
  1002. package/build/dist/UI/Components/Sso/OidcProviderFormFields.js.map +1 -0
  1003. package/build/dist/UI/Components/Sso/SamlProviderFormFields.js +182 -0
  1004. package/build/dist/UI/Components/Sso/SamlProviderFormFields.js.map +1 -0
  1005. package/build/dist/UI/Components/Sso/SsoProviderFormFields.js +208 -0
  1006. package/build/dist/UI/Components/Sso/SsoProviderFormFields.js.map +1 -0
  1007. package/build/dist/UI/Components/Table/TableEmptyState.js +17 -4
  1008. package/build/dist/UI/Components/Table/TableEmptyState.js.map +1 -1
  1009. package/build/dist/UI/Components/Workflow/ArgumentsForm.js +17 -52
  1010. package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
  1011. package/build/dist/UI/Components/Workflow/ComponentPicker/ComponentSearch.js +7 -89
  1012. package/build/dist/UI/Components/Workflow/ComponentPicker/ComponentSearch.js.map +1 -1
  1013. package/build/dist/UI/Components/Workflow/WorkflowLogModal.js +1 -1
  1014. package/build/dist/UI/Components/Workflow/WorkflowLogModal.js.map +1 -1
  1015. package/build/dist/UI/Types/UseAnchoredFieldPopup.js +22 -3
  1016. package/build/dist/UI/Types/UseAnchoredFieldPopup.js.map +1 -1
  1017. package/build/dist/UI/Utils/DefaultInviteTeam.js +207 -0
  1018. package/build/dist/UI/Utils/DefaultInviteTeam.js.map +1 -0
  1019. package/build/dist/UI/Utils/GrantablePermission.js +31 -0
  1020. package/build/dist/UI/Utils/GrantablePermission.js.map +1 -1
  1021. package/build/dist/UI/Utils/PermissionGate.js +54 -3
  1022. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  1023. package/build/dist/UI/Utils/TranslateTemplate.js +16 -0
  1024. package/build/dist/UI/Utils/TranslateTemplate.js.map +1 -1
  1025. package/build/dist/Utils/DistinctColor.js +151 -0
  1026. package/build/dist/Utils/DistinctColor.js.map +1 -0
  1027. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js +12 -1
  1028. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js.map +1 -1
  1029. package/build/dist/Utils/Slo/SloHealth.js +9 -3
  1030. package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
  1031. package/build/dist/Utils/StatusPage/ReportSchedule.js +304 -0
  1032. package/build/dist/Utils/StatusPage/ReportSchedule.js.map +1 -0
  1033. package/build/dist/Utils/Telemetry/DiscoveredResourceName.js +65 -0
  1034. package/build/dist/Utils/Telemetry/DiscoveredResourceName.js.map +1 -0
  1035. package/build/dist/Utils/WordMatch.js +115 -0
  1036. package/build/dist/Utils/WordMatch.js.map +1 -0
  1037. package/package.json +1 -1
  1038. package/Tests/App/Dashboard/BulkChangeStateModalSteps.test.ts +0 -109
  1039. package/Tests/App/StatusPage/StatusPageSubscribeFromFirstStep.test.tsx +0 -382
  1040. package/Tests/UI/Components/Forms/BasicFormFinishFromAnyStep.test.tsx +0 -729
  1041. package/Tests/UI/Components/Forms/FinishFromAnyStep.test.ts +0 -571
  1042. package/Tests/UI/Components/Forms/FinishFromAnyStepGuard.test.ts +0 -566
  1043. package/UI/Components/Forms/Utils/FinishFromAnyStep.ts +0 -284
  1044. package/build/dist/UI/Components/Forms/Utils/FinishFromAnyStep.js +0 -132
  1045. package/build/dist/UI/Components/Forms/Utils/FinishFromAnyStep.js.map +0 -1
@@ -0,0 +1,1208 @@
1
+ import "@testing-library/jest-dom";
2
+ import {
3
+ afterEach,
4
+ beforeAll,
5
+ beforeEach,
6
+ describe,
7
+ expect,
8
+ jest,
9
+ test,
10
+ } from "@jest/globals";
11
+ import {
12
+ act,
13
+ cleanup,
14
+ fireEvent,
15
+ render,
16
+ screen,
17
+ waitFor,
18
+ within,
19
+ } from "@testing-library/react";
20
+ import userEvent from "@testing-library/user-event";
21
+ import fs from "fs";
22
+ import { createInstance, i18n } from "i18next";
23
+ import path from "path";
24
+ import React, { ReactElement, ReactNode } from "react";
25
+ import { I18nextProvider } from "react-i18next";
26
+ import { MemoryRouter } from "react-router-dom";
27
+ import getJestMockFunction, { MockFunction } from "../../MockType";
28
+
29
+ /*
30
+ * Creating an announcement takes two steps, and from a status page that
31
+ * page is already picked.
32
+ *
33
+ * "Make software as simple as possible to use and reduce decision
34
+ * paralysis." - the maintainer.
35
+ *
36
+ * Create Announcement walked four steps and a review, and from a status
37
+ * page's own Announcements tab it opened the project-wide form: the page
38
+ * you had been standing on had to be picked again, and Create left you on
39
+ * the project's list. The real page is drawn here, through the real
40
+ * ModelForm and BasicForm, with only the network, the clock and the
41
+ * signed-in user stubbed:
42
+ *
43
+ * - two steps (Announcement, Status Pages) and the review;
44
+ * - the title and the description are asked for first - the server
45
+ * refuses an announcement without a description, so the form does too;
46
+ * attachments wait under Advanced;
47
+ * - the start, the end and the notify switch are folded to the one line
48
+ * that says what happens, the line follows them, and the review step
49
+ * shows it;
50
+ * - opened from a status page, that page is picked, so the title and
51
+ * the description are all it asks for - Next walks the rest, and
52
+ * Create is on the review, the last step - and it goes back to the
53
+ * page's tab;
54
+ * - a template's pages are kept beside that page, and its notify choice
55
+ * shows in the line.
56
+ */
57
+
58
+ jest.mock("../../../UI/Utils/Permission", () => {
59
+ const actualPermission: Record<string, unknown> = jest.requireActual(
60
+ "../../../Types/Permission",
61
+ ) as Record<string, unknown>;
62
+ const PermissionEnum: Record<string, string> = actualPermission[
63
+ "default"
64
+ ] as Record<string, string>;
65
+ const granted: Array<string> = [
66
+ PermissionEnum["ProjectOwner"]!,
67
+ PermissionEnum["User"]!,
68
+ PermissionEnum["Public"]!,
69
+ ];
70
+
71
+ return {
72
+ __esModule: true,
73
+ default: {
74
+ getAllPermissions: (): Array<string> => {
75
+ return granted;
76
+ },
77
+ getProjectPermissions: (): null => {
78
+ return null;
79
+ },
80
+ getGlobalPermissions: (): { globalPermissions: Array<string> } => {
81
+ return { globalPermissions: granted };
82
+ },
83
+ },
84
+ };
85
+ });
86
+
87
+ jest.mock("../../../UI/Utils/User", () => {
88
+ return {
89
+ __esModule: true,
90
+ default: {
91
+ isMasterAdmin: (): boolean => {
92
+ return false;
93
+ },
94
+ getUserId: (): null => {
95
+ return null;
96
+ },
97
+ },
98
+ };
99
+ });
100
+
101
+ const getListMock: MockFunction = getJestMockFunction();
102
+ const getItemMock: MockFunction = getJestMockFunction();
103
+ const createOrUpdateMock: MockFunction = getJestMockFunction();
104
+
105
+ jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
106
+ return {
107
+ __esModule: true,
108
+ default: {
109
+ getList: (...args: Array<unknown>) => {
110
+ return getListMock(...args);
111
+ },
112
+ getItem: (...args: Array<unknown>) => {
113
+ return getItemMock(...args);
114
+ },
115
+ count: async (): Promise<number> => {
116
+ return 0;
117
+ },
118
+ getCommonHeaders: (): Record<string, string> => {
119
+ return {};
120
+ },
121
+ createOrUpdate: (...args: Array<unknown>) => {
122
+ return createOrUpdateMock(...args);
123
+ },
124
+ },
125
+ };
126
+ });
127
+
128
+ import AnnouncementCreate from "../../../../App/FeatureSet/Dashboard/src/Pages/StatusPages/AnnouncementCreate";
129
+ import PageComponentProps from "../../../../App/FeatureSet/Dashboard/src/Pages/PageComponentProps";
130
+ import {
131
+ ANNOUNCEMENT_ENDS_BEFORE_IT_STARTS_ERROR,
132
+ ANNOUNCEMENT_ENDS_IN_THE_PAST_ERROR,
133
+ ANNOUNCEMENT_SCHEDULE_SUMMARIES,
134
+ ANNOUNCEMENT_SUBSCRIBERS_NOTIFIED_SUMMARY,
135
+ ANNOUNCEMENT_SUBSCRIBERS_NOT_NOTIFIED_SUMMARY,
136
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/Announcement/AnnouncementForm";
137
+ import BaseModel, {
138
+ DatabaseBaseModelType,
139
+ } from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
140
+ import Monitor from "../../../Models/DatabaseModels/Monitor";
141
+ import StatusPage from "../../../Models/DatabaseModels/StatusPage";
142
+ import StatusPageAnnouncement from "../../../Models/DatabaseModels/StatusPageAnnouncement";
143
+ import StatusPageAnnouncementTemplate from "../../../Models/DatabaseModels/StatusPageAnnouncementTemplate";
144
+ import Route from "../../../Types/API/Route";
145
+ import OneUptimeDate from "../../../Types/Date";
146
+ import Timezone from "../../../Types/Timezone";
147
+ import Navigation from "../../../UI/Utils/Navigation";
148
+ import PermissionGate from "../../../UI/Utils/PermissionGate";
149
+ import { setChips } from "../../UI/Components/FoldedSection/FoldedSectionQueries";
150
+
151
+ const NOW: Date = new Date("2026-10-03T09:20:00.000Z");
152
+ const PROJECT_ID: string = "00000000-0000-4000-8000-000000000001";
153
+ const STATUS_PAGE_ID: string = "22222222-2222-4222-8222-222222222222";
154
+ const OTHER_STATUS_PAGE_ID: string = "33333333-3333-4333-8333-333333333333";
155
+ const TEMPLATE_ID: string = "11111111-1111-4111-8111-111111111111";
156
+ const MONITOR_ID: string = "44444444-4444-4444-8444-444444444444";
157
+
158
+ const DEFAULT_LINE: string = `${ANNOUNCEMENT_SCHEDULE_SUMMARIES.nowUntilEnded} ${ANNOUNCEMENT_SUBSCRIBERS_NOTIFIED_SUMMARY}`;
159
+
160
+ const PAGE_PROPS: PageComponentProps = {
161
+ pageRoute: new Route("/dashboard/project/status-pages/announcements/create"),
162
+ currentProject: null,
163
+ hasPaymentMethod: true,
164
+ };
165
+
166
+ const LOCALES_DIR: string = path.join(
167
+ __dirname,
168
+ "..",
169
+ "..",
170
+ "..",
171
+ "..",
172
+ "App",
173
+ "FeatureSet",
174
+ "Dashboard",
175
+ "src",
176
+ "Locales",
177
+ );
178
+
179
+ const german: i18n = createInstance();
180
+
181
+ // The address the page is opened with.
182
+ let queryInUrl: Record<string, string> = {};
183
+
184
+ /*
185
+ * What the server answers for STATUS_PAGE_ID: the page, an empty record (the
186
+ * API's answer for a page that is gone or in another project), or a refusal.
187
+ */
188
+ let statusPageOnServer: StatusPage | Error = new StatusPage();
189
+
190
+ // What the server answers for TEMPLATE_ID.
191
+ let templateOnServer: StatusPageAnnouncementTemplate | Error =
192
+ new StatusPageAnnouncementTemplate();
193
+
194
+ // The language the page is drawn in; labels are looked up in it.
195
+ let pageLanguage: i18n | null = null;
196
+
197
+ function inPageLanguage(english: string): string {
198
+ return pageLanguage ? pageLanguage.t(english) : english;
199
+ }
200
+
201
+ function listOf<T extends BaseModel>(
202
+ items: Array<T>,
203
+ ): {
204
+ data: Array<T>;
205
+ count: number;
206
+ skip: number;
207
+ limit: number;
208
+ } {
209
+ return { data: items, count: items.length, skip: 0, limit: 100 };
210
+ }
211
+
212
+ function makeStatusPage(id: string, name: string): StatusPage {
213
+ const statusPage: StatusPage = new StatusPage();
214
+ statusPage._id = id;
215
+ statusPage.name = name;
216
+ return statusPage;
217
+ }
218
+
219
+ function makeMonitor(): Monitor {
220
+ const monitor: Monitor = new Monitor();
221
+ monitor._id = MONITOR_ID;
222
+ monitor.name = "Checkout API";
223
+ return monitor;
224
+ }
225
+
226
+ function makeTemplate(): StatusPageAnnouncementTemplate {
227
+ const template: StatusPageAnnouncementTemplate =
228
+ new StatusPageAnnouncementTemplate();
229
+ template._id = TEMPLATE_ID;
230
+ template.title = "Planned database upgrade";
231
+ template.description = "The database is upgraded on Sunday.";
232
+ template.statusPages = [
233
+ makeStatusPage(OTHER_STATUS_PAGE_ID, "Internal Status"),
234
+ ];
235
+ template.monitors = [];
236
+ template.shouldStatusPageSubscribersBeNotified = false;
237
+ return template;
238
+ }
239
+
240
+ async function renderPage(language?: i18n): Promise<void> {
241
+ pageLanguage = language || null;
242
+
243
+ const Wrapper: (props: { children?: ReactNode }) => ReactElement = (props: {
244
+ children?: ReactNode;
245
+ }): ReactElement => {
246
+ return language ? (
247
+ <I18nextProvider i18n={language}>{props.children}</I18nextProvider>
248
+ ) : (
249
+ <>{props.children}</>
250
+ );
251
+ };
252
+
253
+ render(
254
+ <MemoryRouter>
255
+ <AnnouncementCreate {...PAGE_PROPS} />
256
+ </MemoryRouter>,
257
+ { wrapper: Wrapper },
258
+ );
259
+
260
+ await screen.findByRole("navigation", { name: inPageLanguage("Progress") });
261
+ await waitFor(() => {
262
+ expect(labelText("Title")).not.toBe("");
263
+ });
264
+ /*
265
+ * The form starts from its defaults in an effect after the fields are
266
+ * drawn, which React runs in a task of its own: typing before it has run
267
+ * would keep it from running at all (a person cannot type that fast).
268
+ */
269
+ await act(async () => {
270
+ await new Promise<void>((resolve: () => void) => {
271
+ setTimeout(resolve, 0);
272
+ });
273
+ });
274
+ }
275
+
276
+ function form(): HTMLElement {
277
+ return document.getElementById("create-announcement-form")!;
278
+ }
279
+
280
+ function stepTitles(): Array<string> {
281
+ return within(
282
+ screen.getByRole("navigation", { name: inPageLanguage("Progress") }),
283
+ )
284
+ .getAllByRole("listitem")
285
+ .map((item: HTMLElement): string => {
286
+ return (item.textContent || "").trim();
287
+ });
288
+ }
289
+
290
+ function currentStepTitle(): string {
291
+ const current: Element | null = screen
292
+ .getByRole("navigation", { name: inPageLanguage("Progress") })
293
+ .querySelector("[aria-current='step']");
294
+
295
+ return (current?.textContent || "").trim();
296
+ }
297
+
298
+ function findLabel(labelStart: string): HTMLLabelElement | undefined {
299
+ return Array.from(form().querySelectorAll("label")).find(
300
+ (candidate: HTMLLabelElement): boolean => {
301
+ return (candidate.textContent || "")
302
+ .trim()
303
+ .startsWith(inPageLanguage(labelStart));
304
+ },
305
+ );
306
+ }
307
+
308
+ function labelText(labelStart: string): string {
309
+ return (findLabel(labelStart)?.textContent || "").trim();
310
+ }
311
+
312
+ function labelledInput(labelStart: string): HTMLInputElement {
313
+ const label: HTMLLabelElement | undefined = findLabel(labelStart);
314
+
315
+ expect(`${labelStart}: ${Boolean(label)}`).toBe(`${labelStart}: true`);
316
+
317
+ return form().querySelector(
318
+ `[id="${label!.getAttribute("for")}"]`,
319
+ ) as HTMLInputElement;
320
+ }
321
+
322
+ function startsAtInput(): HTMLInputElement {
323
+ return labelledInput("Start Showing Announcement At");
324
+ }
325
+
326
+ function endsAtInput(): HTMLInputElement {
327
+ return labelledInput("End Showing Announcement At");
328
+ }
329
+
330
+ function createButton(): HTMLElement {
331
+ return screen.getByRole("button", {
332
+ name: inPageLanguage("Create Announcement"),
333
+ });
334
+ }
335
+
336
+ function queryCreateButton(): HTMLElement | null {
337
+ return screen.queryByRole("button", {
338
+ name: inPageLanguage("Create Announcement"),
339
+ });
340
+ }
341
+
342
+ function nextButton(): HTMLElement {
343
+ return screen.getByRole("button", { name: inPageLanguage("Next") });
344
+ }
345
+
346
+ /*
347
+ * Create Announcement is on the last step - the review - only: walks there
348
+ * with Next, then presses it.
349
+ */
350
+ async function createFromTheReview(): Promise<void> {
351
+ for (let step: number = 0; step < 5 && !queryCreateButton(); step++) {
352
+ fireEvent.click(nextButton());
353
+ await act(async () => {});
354
+ }
355
+
356
+ await waitFor(() => {
357
+ expect(currentStepTitle()).toBe(inPageLanguage("Summary"));
358
+ });
359
+
360
+ fireEvent.click(createButton());
361
+ }
362
+
363
+ async function typeTitle(title: string): Promise<void> {
364
+ fireEvent.change(labelledInput("Title"), { target: { value: title } });
365
+ await act(async () => {});
366
+ }
367
+
368
+ /*
369
+ * The description, written in its editor's Markdown source: the editor
370
+ * opens in its visual mode, and its Markdown button shows the source as a
371
+ * textarea - the step's only one.
372
+ */
373
+ async function typeDescription(text: string): Promise<void> {
374
+ const toolbar: HTMLElement = within(form()).getByTestId(
375
+ "markdown-editor-toolbar",
376
+ );
377
+
378
+ fireEvent.click(
379
+ within(toolbar).getByRole("button", { name: inPageLanguage("Markdown") }),
380
+ );
381
+
382
+ const sources: Array<HTMLTextAreaElement> = Array.from(
383
+ form().querySelectorAll<HTMLTextAreaElement>("textarea"),
384
+ );
385
+
386
+ expect(sources).toHaveLength(1);
387
+
388
+ fireEvent.change(sources[0]!, { target: { value: text } });
389
+ await act(async () => {});
390
+ }
391
+
392
+ async function writeAnnouncement(): Promise<void> {
393
+ await typeTitle("Planned database upgrade");
394
+ await typeDescription("The database is upgraded on Sunday at 02:00 UTC.");
395
+ }
396
+
397
+ async function goToNextStep(expectedTitle: string): Promise<void> {
398
+ fireEvent.click(nextButton());
399
+
400
+ await waitFor(() => {
401
+ expect(currentStepTitle()).toBe(inPageLanguage(expectedTitle));
402
+ });
403
+ }
404
+
405
+ function sectionHeader(title: string): HTMLElement {
406
+ return screen.getByRole("button", { name: inPageLanguage(title) });
407
+ }
408
+
409
+ // What a folded section holds: the body its header controls.
410
+ function sectionBody(header: HTMLElement): HTMLElement {
411
+ return document.getElementById(header.getAttribute("aria-controls")!)!;
412
+ }
413
+
414
+ // The fields in an element, by the labels they are drawn with.
415
+ function fieldLabelsIn(element: HTMLElement): Array<string> {
416
+ return Array.from(element.querySelectorAll("label"))
417
+ .map((label: HTMLLabelElement): string => {
418
+ return (label.textContent || "").replace("(Optional)", "").trim();
419
+ })
420
+ .filter((text: string, index: number, all: Array<string>): boolean => {
421
+ return Boolean(text) && all.indexOf(text) === index;
422
+ });
423
+ }
424
+
425
+ function sectionLine(): string {
426
+ return (
427
+ screen.getByTestId("collapsible-section-summary").textContent || ""
428
+ ).trim();
429
+ }
430
+
431
+ /*
432
+ * The line is drawn while the section is folded: fold it, read the line,
433
+ * and open it again to go on answering.
434
+ */
435
+ function lineOfOpenSection(header: HTMLElement): string {
436
+ fireEvent.click(header);
437
+ expect(header).toHaveAttribute("aria-expanded", "false");
438
+
439
+ const line: string = sectionLine();
440
+
441
+ fireEvent.click(header);
442
+ expect(header).toHaveAttribute("aria-expanded", "true");
443
+
444
+ return line;
445
+ }
446
+
447
+ function createdModel(): StatusPageAnnouncement {
448
+ expect(createOrUpdateMock).toHaveBeenCalledTimes(1);
449
+
450
+ const call: Array<unknown> = createOrUpdateMock.mock
451
+ .calls[0] as Array<unknown>;
452
+
453
+ return (call[0] as { model: StatusPageAnnouncement }).model;
454
+ }
455
+
456
+ function idsOf(items: unknown): Array<string> {
457
+ return ((items as Array<{ _id?: string; id?: unknown }>) || []).map(
458
+ (item: { _id?: string; id?: unknown }): string => {
459
+ return (item._id || item.id || "").toString();
460
+ },
461
+ );
462
+ }
463
+
464
+ function isoOf(value: unknown): string {
465
+ return OneUptimeDate.fromString(value as string).toISOString();
466
+ }
467
+
468
+ function navigatedTo(): string {
469
+ const navigate: MockFunction = Navigation.navigate as unknown as MockFunction;
470
+
471
+ expect(navigate).toHaveBeenCalledTimes(1);
472
+
473
+ return (navigate.mock.calls[0]![0] as Route).toString();
474
+ }
475
+
476
+ function breadcrumbs(): Array<{ title: string; href: string | null }> {
477
+ return Array.from(
478
+ screen
479
+ .getByRole("navigation", { name: inPageLanguage("Breadcrumb") })
480
+ .querySelectorAll("li"),
481
+ ).map((item: HTMLLIElement) => {
482
+ return {
483
+ title: (item.textContent || "").trim(),
484
+ href: item.querySelector("a")?.getAttribute("href") || null,
485
+ };
486
+ });
487
+ }
488
+
489
+ beforeAll(async () => {
490
+ await german.init({
491
+ lng: "de",
492
+ fallbackLng: "de",
493
+ resources: {
494
+ de: {
495
+ translation: JSON.parse(
496
+ fs.readFileSync(path.join(LOCALES_DIR, "de.json"), "utf8"),
497
+ ) as Record<string, string>,
498
+ },
499
+ },
500
+ interpolation: { escapeValue: false },
501
+ });
502
+ });
503
+
504
+ beforeEach(() => {
505
+ queryInUrl = {};
506
+ statusPageOnServer = makeStatusPage(STATUS_PAGE_ID, "Acme Public Status");
507
+ templateOnServer = makeTemplate();
508
+ getListMock.mockReset();
509
+ getItemMock.mockReset();
510
+ createOrUpdateMock.mockReset();
511
+ PermissionGate.clearPermissionPropsCache();
512
+
513
+ jest.spyOn(OneUptimeDate, "getCurrentDate").mockReturnValue(NOW);
514
+ OneUptimeDate.setUserTimezone(Timezone.UTC);
515
+
516
+ jest
517
+ .spyOn(Navigation, "getQueryStringByName")
518
+ .mockImplementation((name: string): string | null => {
519
+ return queryInUrl[name] || null;
520
+ });
521
+ jest.spyOn(Navigation, "navigate").mockImplementation((): void => {});
522
+
523
+ getListMock.mockImplementation(
524
+ async (args: unknown): Promise<ReturnType<typeof listOf>> => {
525
+ const modelType: DatabaseBaseModelType = (
526
+ args as { modelType: DatabaseBaseModelType }
527
+ ).modelType;
528
+
529
+ if (modelType === StatusPage) {
530
+ return listOf([
531
+ makeStatusPage(STATUS_PAGE_ID, "Acme Public Status"),
532
+ makeStatusPage(OTHER_STATUS_PAGE_ID, "Internal Status"),
533
+ ]);
534
+ }
535
+
536
+ if (modelType === Monitor) {
537
+ return listOf([makeMonitor()]);
538
+ }
539
+
540
+ return listOf([]);
541
+ },
542
+ );
543
+
544
+ getItemMock.mockImplementation(
545
+ async (args: unknown): Promise<BaseModel | null> => {
546
+ const modelType: DatabaseBaseModelType = (
547
+ args as { modelType: DatabaseBaseModelType }
548
+ ).modelType;
549
+
550
+ if (modelType === StatusPage) {
551
+ if (statusPageOnServer instanceof Error) {
552
+ throw statusPageOnServer;
553
+ }
554
+
555
+ return statusPageOnServer;
556
+ }
557
+
558
+ if (modelType === StatusPageAnnouncementTemplate) {
559
+ if (templateOnServer instanceof Error) {
560
+ throw templateOnServer;
561
+ }
562
+
563
+ return templateOnServer;
564
+ }
565
+
566
+ return null;
567
+ },
568
+ );
569
+
570
+ createOrUpdateMock.mockImplementation(
571
+ async (data: unknown): Promise<{ data: Record<string, unknown> }> => {
572
+ return {
573
+ data: {
574
+ ...BaseModel.toJSON(
575
+ (data as { model: StatusPageAnnouncement }).model,
576
+ StatusPageAnnouncement,
577
+ ),
578
+ _id: "55555555-5555-4555-8555-555555555555",
579
+ },
580
+ };
581
+ },
582
+ );
583
+ });
584
+
585
+ afterEach(() => {
586
+ cleanup();
587
+ jest.restoreAllMocks();
588
+ OneUptimeDate.setUserTimezone(null);
589
+ pageLanguage = null;
590
+ });
591
+
592
+ describe("Create Announcement, from the project's Announcements list", () => {
593
+ test("walks two steps and the review", async () => {
594
+ await renderPage();
595
+
596
+ expect(stepTitles()).toEqual(["Announcement", "Status Pages", "Summary"]);
597
+ expect(currentStepTitle()).toBe("Announcement");
598
+ // Nothing is picked: no status page is asked for.
599
+ expect(getItemMock).not.toHaveBeenCalled();
600
+ });
601
+
602
+ test("asks for the title and the description, with attachments under Advanced", async () => {
603
+ await renderPage();
604
+
605
+ // Both required: the server refuses an announcement without a description.
606
+ expect(labelText("Title")).not.toContain("(Optional)");
607
+ expect(labelText("Description")).not.toContain("(Optional)");
608
+
609
+ const advanced: HTMLElement = sectionHeader("More fields");
610
+ // The picker inside draws a label of its own ("Upload files").
611
+ const folded: Array<string> = fieldLabelsIn(sectionBody(advanced));
612
+
613
+ expect(advanced).toHaveAttribute("aria-expanded", "false");
614
+ expect(folded).toContain("Attachments");
615
+ expect(folded).not.toContain("Title");
616
+ expect(folded).not.toContain("Description");
617
+ expect(setChips()).toEqual([]);
618
+ });
619
+
620
+ test("will not walk on without a title and a description", async () => {
621
+ await renderPage();
622
+
623
+ // The status pages are still to be picked, so Next is the only way on.
624
+ expect(queryCreateButton()).toBeNull();
625
+
626
+ fireEvent.click(nextButton());
627
+
628
+ expect(await screen.findByText("Title is required.")).toBeInTheDocument();
629
+ expect(screen.getByText("Description is required.")).toBeInTheDocument();
630
+ expect(currentStepTitle()).toBe("Announcement");
631
+ });
632
+
633
+ test("Status Pages shows the pages, the monitors and one line about the schedule and the notifications", async () => {
634
+ await renderPage();
635
+ await writeAnnouncement();
636
+ await goToNextStep("Status Pages");
637
+
638
+ expect(labelText("Show announcement on these status pages")).not.toContain(
639
+ "(Optional)",
640
+ );
641
+ // "(Optional)" once: the label says it, the title does not repeat it.
642
+ expect(labelText("Monitors Affected")).toBe("Monitors Affected (Optional)");
643
+
644
+ const schedule: HTMLElement = sectionHeader("Schedule & Notifications");
645
+
646
+ expect(schedule).toHaveAttribute("aria-expanded", "false");
647
+ expect(schedule).toHaveAccessibleDescription(DEFAULT_LINE);
648
+ expect(sectionLine()).toBe(DEFAULT_LINE);
649
+ expect(fieldLabelsIn(sectionBody(schedule))).toEqual([
650
+ "Start Showing Announcement At",
651
+ "End Showing Announcement At",
652
+ "Notify Status Page Subscribers",
653
+ ]);
654
+ // Folded, the switch is out of sight; the line says what it does.
655
+ expect(
656
+ screen.getByRole("checkbox", {
657
+ name: "Notify Status Page Subscribers",
658
+ hidden: true,
659
+ }),
660
+ ).not.toBeVisible();
661
+ expect(setChips()).toEqual([]);
662
+ });
663
+
664
+ test("starts now, with no end, telling the subscribers", async () => {
665
+ await renderPage();
666
+ await writeAnnouncement();
667
+ await goToNextStep("Status Pages");
668
+
669
+ fireEvent.click(sectionHeader("Schedule & Notifications"));
670
+
671
+ expect(startsAtInput().value).toMatch(/^2026-10-03T09:20/);
672
+ expect(endsAtInput().value).toBe("");
673
+ expect(
674
+ screen.getByRole("checkbox", { name: "Notify Status Page Subscribers" }),
675
+ ).toBeChecked();
676
+ });
677
+
678
+ test("the line follows the answers", async () => {
679
+ await renderPage();
680
+ await writeAnnouncement();
681
+ await goToNextStep("Status Pages");
682
+
683
+ const schedule: HTMLElement = sectionHeader("Schedule & Notifications");
684
+
685
+ fireEvent.click(schedule);
686
+
687
+ // An end: it stays until then.
688
+ fireEvent.change(endsAtInput(), { target: { value: "2026-10-05T14:00" } });
689
+ await act(async () => {});
690
+
691
+ const endsAt: string =
692
+ OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
693
+ new Date("2026-10-05T14:00:00.000Z"),
694
+ );
695
+
696
+ expect(lineOfOpenSection(schedule)).toBe(
697
+ `Shows now and stays until ${endsAt}. ${ANNOUNCEMENT_SUBSCRIBERS_NOTIFIED_SUMMARY}`,
698
+ );
699
+
700
+ // A later start: it shows from then.
701
+ fireEvent.change(startsAtInput(), {
702
+ target: { value: "2026-10-04T08:00" },
703
+ });
704
+ await act(async () => {});
705
+
706
+ const startsAt: string =
707
+ OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
708
+ new Date("2026-10-04T08:00:00.000Z"),
709
+ );
710
+
711
+ expect(lineOfOpenSection(schedule)).toBe(
712
+ `Shows from ${startsAt} until ${endsAt}. ${ANNOUNCEMENT_SUBSCRIBERS_NOTIFIED_SUMMARY}`,
713
+ );
714
+
715
+ // No end again, and nobody told.
716
+ fireEvent.change(endsAtInput(), { target: { value: "" } });
717
+ fireEvent.click(
718
+ screen.getByRole("checkbox", { name: "Notify Status Page Subscribers" }),
719
+ );
720
+ await act(async () => {});
721
+
722
+ // Folded, the line says it in place of a "Configured" badge.
723
+ fireEvent.click(schedule);
724
+
725
+ expect(schedule).toHaveAttribute("aria-expanded", "false");
726
+ expect(sectionLine()).toBe(
727
+ `Shows from ${startsAt} and stays until you end it. ${ANNOUNCEMENT_SUBSCRIBERS_NOT_NOTIFIED_SUMMARY}`,
728
+ );
729
+ expect(setChips()).toEqual([]);
730
+ });
731
+
732
+ test("creates it on the pages picked, with the defaults, and goes back to the project's list", async () => {
733
+ const user: ReturnType<typeof userEvent.setup> = userEvent.setup();
734
+
735
+ await renderPage();
736
+ await writeAnnouncement();
737
+ await goToNextStep("Status Pages");
738
+
739
+ await user.click(
740
+ screen.getByRole("combobox", {
741
+ name: /Show announcement on these status pages/,
742
+ }),
743
+ );
744
+ await user.click(
745
+ await screen.findByRole("option", { name: /Acme Public Status/ }),
746
+ );
747
+
748
+ await createFromTheReview();
749
+
750
+ await waitFor(() => {
751
+ expect(createOrUpdateMock).toHaveBeenCalledTimes(1);
752
+ });
753
+
754
+ const model: StatusPageAnnouncement = createdModel();
755
+
756
+ expect(model.title).toBe("Planned database upgrade");
757
+ expect(model.description).toBe(
758
+ "The database is upgraded on Sunday at 02:00 UTC.",
759
+ );
760
+ expect(idsOf(model.statusPages)).toEqual([STATUS_PAGE_ID]);
761
+ expect(isoOf(model.showAnnouncementAt)).toBe(NOW.toISOString());
762
+ expect(model.endAnnouncementAt || null).toBeNull();
763
+ expect(model.shouldStatusPageSubscribersBeNotified).toBe(true);
764
+
765
+ await waitFor(() => {
766
+ expect(Navigation.navigate).toHaveBeenCalled();
767
+ });
768
+ expect(navigatedTo()).toMatch(/\/status-pages\/announcements$/);
769
+ });
770
+
771
+ test("the review step reviews the schedule and the notifications by their line", async () => {
772
+ await renderPage();
773
+ await writeAnnouncement();
774
+ await goToNextStep("Status Pages");
775
+
776
+ // Picked on the way, so the step lets the review open.
777
+ const user: ReturnType<typeof userEvent.setup> = userEvent.setup();
778
+
779
+ await user.click(
780
+ screen.getByRole("combobox", {
781
+ name: /Show announcement on these status pages/,
782
+ }),
783
+ );
784
+ await user.click(
785
+ await screen.findByRole("option", { name: /Acme Public Status/ }),
786
+ );
787
+
788
+ await goToNextStep("Summary");
789
+
790
+ for (const heading of ["Announcement", "Status Pages"]) {
791
+ expect(
792
+ within(form()).getByRole("heading", { level: 2, name: heading }),
793
+ ).toBeInTheDocument();
794
+ }
795
+
796
+ expect(
797
+ within(form()).getByText("Planned database upgrade"),
798
+ ).toBeInTheDocument();
799
+ expect(
800
+ within(form()).getByText("Schedule & Notifications"),
801
+ ).toBeInTheDocument();
802
+ expect(
803
+ within(form()).getByTestId("form-summary-section-summary"),
804
+ ).toHaveTextContent(DEFAULT_LINE);
805
+ // The folded fields are reviewed by that line, not one row each.
806
+ expect(
807
+ within(form()).queryByText("Notify Status Page Subscribers"),
808
+ ).toBeNull();
809
+ // Advanced options nobody touched are left out of the review.
810
+ expect(within(form()).queryByText("Attachments")).toBeNull();
811
+ });
812
+
813
+ test("the breadcrumbs go back through the project's Announcements list", async () => {
814
+ await renderPage();
815
+
816
+ expect(
817
+ breadcrumbs().map((link: { title: string }): string => {
818
+ return link.title;
819
+ }),
820
+ ).toEqual([
821
+ "Project",
822
+ "Status Pages",
823
+ "Announcements",
824
+ "Create Announcement",
825
+ ]);
826
+ // From the project, as every page's trail starts.
827
+ expect(breadcrumbs()[0]!.href).toMatch(/\/home\/?$/);
828
+ expect(breadcrumbs()[2]!.href).toMatch(/\/status-pages\/announcements$/);
829
+ });
830
+ });
831
+
832
+ describe("Create Announcement, from a status page's Announcements tab", () => {
833
+ beforeEach(() => {
834
+ queryInUrl = { statusPageId: STATUS_PAGE_ID };
835
+ });
836
+
837
+ test("picks that page, so the title and the description are all it takes", async () => {
838
+ await renderPage();
839
+
840
+ expect(getItemMock).toHaveBeenCalledWith(
841
+ expect.objectContaining({ modelType: StatusPage }),
842
+ );
843
+ expect(
844
+ (
845
+ getItemMock.mock.calls[0]![0] as { id: { toString: () => string } }
846
+ ).id.toString(),
847
+ ).toBe(STATUS_PAGE_ID);
848
+
849
+ /*
850
+ * Every step after this one holds valid answers, and still Create waits
851
+ * for the review, the last step: Next here.
852
+ */
853
+ expect(queryCreateButton()).toBeNull();
854
+ expect(nextButton()).toBeInTheDocument();
855
+
856
+ await writeAnnouncement();
857
+ await createFromTheReview();
858
+
859
+ await waitFor(() => {
860
+ expect(createOrUpdateMock).toHaveBeenCalledTimes(1);
861
+ });
862
+
863
+ const model: StatusPageAnnouncement = createdModel();
864
+
865
+ expect(model.title).toBe("Planned database upgrade");
866
+ expect(idsOf(model.statusPages)).toEqual([STATUS_PAGE_ID]);
867
+ expect(isoOf(model.showAnnouncementAt)).toBe(NOW.toISOString());
868
+ expect(model.shouldStatusPageSubscribersBeNotified).toBe(true);
869
+ });
870
+
871
+ test("goes back to that page's Announcements tab", async () => {
872
+ await renderPage();
873
+ await writeAnnouncement();
874
+ await createFromTheReview();
875
+
876
+ await waitFor(() => {
877
+ expect(Navigation.navigate).toHaveBeenCalled();
878
+ });
879
+ expect(navigatedTo()).toMatch(
880
+ new RegExp(`/status-pages/${STATUS_PAGE_ID}/announcements$`),
881
+ );
882
+ });
883
+
884
+ test("shows the page as picked on its step", async () => {
885
+ await renderPage();
886
+ await writeAnnouncement();
887
+ await goToNextStep("Status Pages");
888
+
889
+ // The picker's menu is closed: the only "Acme Public Status" is its pick.
890
+ await waitFor(() => {
891
+ expect(within(form()).getByText("Acme Public Status")).toBeVisible();
892
+ });
893
+ expect(within(form()).queryByText("Internal Status")).toBeNull();
894
+ });
895
+
896
+ test("the breadcrumbs go back through the status page", async () => {
897
+ await renderPage();
898
+
899
+ const links: Array<{ title: string; href: string | null }> = breadcrumbs();
900
+
901
+ expect(
902
+ links.map((link: { title: string }): string => {
903
+ return link.title;
904
+ }),
905
+ ).toEqual([
906
+ "Project",
907
+ "Status Pages",
908
+ "View Status Page",
909
+ "Announcements",
910
+ "Create Announcement",
911
+ ]);
912
+ expect(links[1]!.href).toMatch(/\/status-pages$/);
913
+ expect(links[2]!.href).toMatch(
914
+ new RegExp(`/status-pages/${STATUS_PAGE_ID}$`),
915
+ );
916
+ expect(links[3]!.href).toMatch(
917
+ new RegExp(`/status-pages/${STATUS_PAGE_ID}/announcements$`),
918
+ );
919
+ });
920
+
921
+ test("will not create an announcement that ends before it starts, and opens the section to say so", async () => {
922
+ await renderPage();
923
+ await writeAnnouncement();
924
+ await goToNextStep("Status Pages");
925
+
926
+ const schedule: HTMLElement = sectionHeader("Schedule & Notifications");
927
+
928
+ fireEvent.click(schedule);
929
+ fireEvent.change(endsAtInput(), { target: { value: "2026-10-03T08:00" } });
930
+ await act(async () => {});
931
+ // Folded again before pressing Next.
932
+ fireEvent.click(schedule);
933
+ expect(schedule).toHaveAttribute("aria-expanded", "false");
934
+
935
+ fireEvent.click(nextButton());
936
+
937
+ expect(
938
+ await screen.findByText(ANNOUNCEMENT_ENDS_BEFORE_IT_STARTS_ERROR),
939
+ ).toBeInTheDocument();
940
+ await waitFor(() => {
941
+ expect(schedule).toHaveAttribute("aria-expanded", "true");
942
+ });
943
+ expect(createOrUpdateMock).not.toHaveBeenCalled();
944
+ });
945
+
946
+ test("a template keeps its own pages beside this one, and its notify choice shows in the line", async () => {
947
+ queryInUrl = {
948
+ statusPageId: STATUS_PAGE_ID,
949
+ announcementTemplateId: TEMPLATE_ID,
950
+ };
951
+
952
+ await renderPage();
953
+
954
+ expect(getItemMock).toHaveBeenCalledWith(
955
+ expect.objectContaining({ modelType: StatusPageAnnouncementTemplate }),
956
+ );
957
+ expect((labelledInput("Title") as HTMLInputElement).value).toBe(
958
+ "Planned database upgrade",
959
+ );
960
+
961
+ await goToNextStep("Status Pages");
962
+
963
+ expect(sectionLine()).toBe(
964
+ `${ANNOUNCEMENT_SCHEDULE_SUMMARIES.nowUntilEnded} ${ANNOUNCEMENT_SUBSCRIBERS_NOT_NOTIFIED_SUMMARY}`,
965
+ );
966
+ // Folded all the same: the line says the subscribers are not told.
967
+ expect(sectionHeader("Schedule & Notifications")).toHaveAttribute(
968
+ "aria-expanded",
969
+ "false",
970
+ );
971
+
972
+ await createFromTheReview();
973
+
974
+ await waitFor(() => {
975
+ expect(createOrUpdateMock).toHaveBeenCalledTimes(1);
976
+ });
977
+
978
+ const model: StatusPageAnnouncement = createdModel();
979
+
980
+ expect(idsOf(model.statusPages)).toEqual([
981
+ STATUS_PAGE_ID,
982
+ OTHER_STATUS_PAGE_ID,
983
+ ]);
984
+ expect(model.description).toBe("The database is upgraded on Sunday.");
985
+ expect(model.shouldStatusPageSubscribersBeNotified).toBe(false);
986
+ // A template holds no time of its own: the announcement shows now.
987
+ expect(isoOf(model.showAnnouncementAt)).toBe(NOW.toISOString());
988
+
989
+ await waitFor(() => {
990
+ expect(Navigation.navigate).toHaveBeenCalled();
991
+ });
992
+ expect(navigatedTo()).toMatch(
993
+ new RegExp(`/status-pages/${STATUS_PAGE_ID}/announcements$`),
994
+ );
995
+ });
996
+
997
+ test("a page that is not there is not picked: the pages are asked for, and the trail goes through the project's list", async () => {
998
+ // The API answers an empty record for a page it cannot find.
999
+ statusPageOnServer = new StatusPage();
1000
+
1001
+ await renderPage();
1002
+
1003
+ // The pages are still to be picked.
1004
+ expect(queryCreateButton()).toBeNull();
1005
+ expect(
1006
+ breadcrumbs().map((link: { title: string }): string => {
1007
+ return link.title;
1008
+ }),
1009
+ ).toEqual([
1010
+ "Project",
1011
+ "Status Pages",
1012
+ "Announcements",
1013
+ "Create Announcement",
1014
+ ]);
1015
+
1016
+ await writeAnnouncement();
1017
+ await goToNextStep("Status Pages");
1018
+
1019
+ fireEvent.click(screen.getByRole("button", { name: "Next" }));
1020
+
1021
+ expect(
1022
+ await screen.findByText(
1023
+ "Show announcement on these status pages is required.",
1024
+ ),
1025
+ ).toBeInTheDocument();
1026
+ });
1027
+
1028
+ test("a page that cannot be read leaves the form as the project's list opens it, without an error", async () => {
1029
+ statusPageOnServer = new Error("You do not have permission to read this.");
1030
+
1031
+ await renderPage();
1032
+
1033
+ expect(
1034
+ screen.queryByText("You do not have permission to read this."),
1035
+ ).toBeNull();
1036
+ expect(queryCreateButton()).toBeNull();
1037
+ expect(
1038
+ breadcrumbs().map((link: { title: string }): string => {
1039
+ return link.title;
1040
+ }),
1041
+ ).toEqual([
1042
+ "Project",
1043
+ "Status Pages",
1044
+ "Announcements",
1045
+ "Create Announcement",
1046
+ ]);
1047
+ });
1048
+
1049
+ test("a template that cannot be read says so above the form, which still opens with the page picked", async () => {
1050
+ queryInUrl = {
1051
+ statusPageId: STATUS_PAGE_ID,
1052
+ announcementTemplateId: TEMPLATE_ID,
1053
+ };
1054
+ templateOnServer = new Error("This template was deleted.");
1055
+
1056
+ await renderPage();
1057
+
1058
+ expect(screen.getByText("This template was deleted.")).toBeInTheDocument();
1059
+ // Nothing of the template, but the page it was opened from is picked.
1060
+ expect(labelledInput("Title").value).toBe("");
1061
+ // The form opens on its first step all the same: Next, not Create.
1062
+ expect(queryCreateButton()).toBeNull();
1063
+ expect(nextButton()).toBeInTheDocument();
1064
+
1065
+ await writeAnnouncement();
1066
+ await createFromTheReview();
1067
+
1068
+ await waitFor(() => {
1069
+ expect(createOrUpdateMock).toHaveBeenCalledTimes(1);
1070
+ });
1071
+ expect(idsOf(createdModel().statusPages)).toEqual([STATUS_PAGE_ID]);
1072
+ });
1073
+
1074
+ test("an end that has already passed is refused: the announcement would never show", async () => {
1075
+ await renderPage();
1076
+ await writeAnnouncement();
1077
+ await goToNextStep("Status Pages");
1078
+
1079
+ const schedule: HTMLElement = sectionHeader("Schedule & Notifications");
1080
+
1081
+ fireEvent.click(schedule);
1082
+ fireEvent.change(startsAtInput(), {
1083
+ target: { value: "2026-10-01T08:00" },
1084
+ });
1085
+ fireEvent.change(endsAtInput(), { target: { value: "2026-10-02T08:00" } });
1086
+ await act(async () => {});
1087
+ fireEvent.click(schedule);
1088
+
1089
+ fireEvent.click(nextButton());
1090
+
1091
+ expect(
1092
+ await screen.findByText(ANNOUNCEMENT_ENDS_IN_THE_PAST_ERROR),
1093
+ ).toBeInTheDocument();
1094
+ await waitFor(() => {
1095
+ expect(schedule).toHaveAttribute("aria-expanded", "true");
1096
+ });
1097
+ expect(createOrUpdateMock).not.toHaveBeenCalled();
1098
+ });
1099
+
1100
+ test("with that page unpicked on the way, Create goes to the project's list, which shows the announcement", async () => {
1101
+ const user: ReturnType<typeof userEvent.setup> = userEvent.setup();
1102
+
1103
+ await renderPage();
1104
+ await writeAnnouncement();
1105
+ await goToNextStep("Status Pages");
1106
+
1107
+ // Another page instead of the one it was opened from.
1108
+ await user.click(
1109
+ screen.getByRole("combobox", {
1110
+ name: /Show announcement on these status pages/,
1111
+ }),
1112
+ );
1113
+ await user.click(
1114
+ await screen.findByRole("option", { name: /Internal Status/ }),
1115
+ );
1116
+ await user.click(
1117
+ screen.getByRole("button", { name: /Remove Acme Public Status/ }),
1118
+ );
1119
+
1120
+ await createFromTheReview();
1121
+
1122
+ await waitFor(() => {
1123
+ expect(createOrUpdateMock).toHaveBeenCalledTimes(1);
1124
+ });
1125
+ expect(idsOf(createdModel().statusPages)).toEqual([OTHER_STATUS_PAGE_ID]);
1126
+
1127
+ await waitFor(() => {
1128
+ expect(Navigation.navigate).toHaveBeenCalled();
1129
+ });
1130
+ expect(navigatedTo()).toMatch(/\/status-pages\/announcements$/);
1131
+ });
1132
+
1133
+ test("the last crumb is this page, drawn as text, so the address keeps what it was opened with", async () => {
1134
+ window.history.replaceState(
1135
+ null,
1136
+ "",
1137
+ `/dashboard/${PROJECT_ID}/status-pages/announcements/create?statusPageId=${STATUS_PAGE_ID}`,
1138
+ );
1139
+
1140
+ try {
1141
+ await renderPage();
1142
+
1143
+ const links: Array<{ title: string; href: string | null }> =
1144
+ breadcrumbs();
1145
+
1146
+ expect(links[links.length - 1]).toEqual({
1147
+ title: "Create Announcement",
1148
+ href: null,
1149
+ });
1150
+ expect(links[3]!.href).toBe(
1151
+ `/dashboard/${PROJECT_ID}/status-pages/${STATUS_PAGE_ID}/announcements`,
1152
+ );
1153
+ } finally {
1154
+ window.history.replaceState(null, "", "/");
1155
+ }
1156
+ });
1157
+
1158
+ test("an address that names no real page asks the server for nothing", async () => {
1159
+ queryInUrl = { statusPageId: "not-a-status-page" };
1160
+
1161
+ await renderPage();
1162
+
1163
+ expect(getItemMock).not.toHaveBeenCalled();
1164
+ expect(queryCreateButton()).toBeNull();
1165
+ });
1166
+ });
1167
+
1168
+ describe("Create Announcement, in the reader's language", () => {
1169
+ test("reads in German", async () => {
1170
+ queryInUrl = { statusPageId: STATUS_PAGE_ID };
1171
+
1172
+ await renderPage(german);
1173
+
1174
+ const germanText: (key: string) => string = (key: string): string => {
1175
+ return german.t(key);
1176
+ };
1177
+
1178
+ expect(stepTitles()).toEqual([
1179
+ germanText("Announcement"),
1180
+ germanText("Status Pages"),
1181
+ germanText("Summary"),
1182
+ ]);
1183
+ expect(germanText("Status Pages")).not.toBe("Status Pages");
1184
+
1185
+ await writeAnnouncement();
1186
+ await goToNextStep("Status Pages");
1187
+
1188
+ const line: string = [
1189
+ ANNOUNCEMENT_SCHEDULE_SUMMARIES.nowUntilEnded,
1190
+ ANNOUNCEMENT_SUBSCRIBERS_NOTIFIED_SUMMARY,
1191
+ ]
1192
+ .map((sentence: string): string => {
1193
+ return germanText(sentence);
1194
+ })
1195
+ .join(" ");
1196
+
1197
+ expect(line).not.toContain("Subscribers");
1198
+ expect(sectionLine()).toBe(line);
1199
+ expect(
1200
+ screen.getByRole("button", {
1201
+ name: germanText("Schedule & Notifications"),
1202
+ }),
1203
+ ).toBeInTheDocument();
1204
+ expect(germanText("Schedule & Notifications")).not.toBe(
1205
+ "Schedule & Notifications",
1206
+ );
1207
+ });
1208
+ });