@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
@@ -24,17 +24,23 @@ import { getJestSpyOn } from "../../Spy";
24
24
  * "What your status page shows", the one card on a status page's Advanced
25
25
  * Settings for what visitors see: a switch per list (incidents, episodes,
26
26
  * announcements, scheduled maintenance), how far back each goes, its labels,
27
- * the uptime history window and the "Powered by OneUptime" line.
27
+ * the page's uptime - the uptime history window, the overall uptime
28
+ * percentage with its precision, and which statuses count as downtime - and
29
+ * the "Powered by OneUptime" line.
28
30
  *
29
- * It replaced six cards with an Edit dialog each. Every control saves its
31
+ * It replaced eight cards with an Edit dialog each. Every control saves its
30
32
  * own column at once: switches when pressed, a number of days when the box
31
- * is left or Enter is pressed. A list that is off does not offer its history
32
- * and labels. Controls are locked while they save and for someone who may
33
- * not edit the page, roll back with the reason when the server refuses, and
34
- * name the plan they need.
33
+ * is left or Enter is pressed, a precision or a status when it is picked. A
34
+ * list that is off does not offer its history and labels, and the overall
35
+ * uptime percentage that is off does not offer its precision. Switches and
36
+ * boxes are locked while they save, the dropdowns never (a pick made
37
+ * meanwhile waits its turn), and all are locked for someone who may not edit
38
+ * the page, roll back with the reason when the server refuses, and name the
39
+ * plan they need.
35
40
  *
36
41
  * Only the network, the permission gate and the plan are stubbed; the card,
37
- * its rows, the switches and the number boxes are the real ones.
42
+ * its rows, the switches, the number boxes and the dropdowns (react-select)
43
+ * are the real ones.
38
44
  */
39
45
 
40
46
  /*
@@ -43,6 +49,7 @@ import { getJestSpyOn } from "../../Spy";
43
49
  * reports a rejected one as unhandled although the card catches it.
44
50
  */
45
51
  const getItemMock: MockFunction = getJestMockFunction();
52
+ const getListMock: MockFunction = getJestMockFunction();
46
53
  const updateByIdMock: MockFunction = getJestMockFunction();
47
54
 
48
55
  jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
@@ -52,6 +59,9 @@ jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
52
59
  getItem: (...args: Array<unknown>): unknown => {
53
60
  return getItemMock(...args);
54
61
  },
62
+ getList: (...args: Array<unknown>): unknown => {
63
+ return getListMock(...args);
64
+ },
55
65
  updateById: (...args: Array<unknown>): unknown => {
56
66
  return updateByIdMock(...args);
57
67
  },
@@ -63,26 +73,37 @@ import StatusPageDisplaySettingsCard, {
63
73
  STATUS_PAGE_DISPLAY_SETTINGS_CARD_TEST_ID,
64
74
  } from "../../../../App/FeatureSet/Dashboard/src/Components/StatusPage/StatusPageDisplaySettingsCard";
65
75
  import StatusPageDisplaySettingsCopy, {
76
+ DISPLAY_CHOICES,
66
77
  DISPLAY_DAYS,
67
78
  DISPLAY_SECTIONS,
68
79
  DISPLAY_SETTING_COLUMNS,
80
+ DISPLAY_STATUSES,
69
81
  DISPLAY_SWITCHES,
82
+ DisplayChoiceColumn,
70
83
  DisplayDaysColumn,
71
84
  DisplayDaysDefinition,
72
85
  DisplaySectionDefinition,
73
86
  DisplaySettingColumn,
87
+ DisplayStatusesColumn,
74
88
  DisplaySwitchColumn,
75
89
  DisplaySwitchDefinition,
90
+ DisplayValueColumn,
91
+ getDisplayChoiceTestId,
76
92
  getDisplayDaysTestId,
77
93
  getDisplaySectionTestId,
94
+ getDisplayStatusesTestId,
78
95
  getDisplaySwitchTestId,
79
96
  } from "../../../../App/FeatureSet/Dashboard/src/Components/StatusPage/StatusPageDisplaySettingsCopy";
80
97
  import IncidentStatusPageScopeCopy from "../../../../App/FeatureSet/Dashboard/src/Components/Incident/IncidentStatusPageScopeCopy";
98
+ import MonitorStatus from "../../../Models/DatabaseModels/MonitorStatus";
81
99
  import StatusPage from "../../../Models/DatabaseModels/StatusPage";
100
+ import SortOrder from "../../../Types/BaseDatabase/SortOrder";
82
101
  import SubscriptionPlan, {
83
102
  PlanType,
84
103
  } from "../../../Types/Billing/SubscriptionPlan";
104
+ import Color from "../../../Types/Color";
85
105
  import ObjectID from "../../../Types/ObjectID";
106
+ import UptimePrecision from "../../../Types/StatusPage/UptimePrecision";
86
107
  import PermissionGate, {
87
108
  ModelAction,
88
109
  PermissionGateResult,
@@ -91,7 +112,9 @@ import ProjectUtil from "../../../UI/Utils/Project";
91
112
 
92
113
  const STATUS_PAGE_ID: string = "5b5b5b5b-0000-4000-8000-0000000000bb";
93
114
 
94
- type StoredColumns = Partial<Record<DisplaySettingColumn, boolean | number>>;
115
+ type StoredColumns = Partial<
116
+ Record<DisplayValueColumn, boolean | number | string>
117
+ >;
95
118
 
96
119
  // A new status page, as the columns' defaults leave it.
97
120
  const NEW_PAGE: StoredColumns = {
@@ -108,15 +131,77 @@ const NEW_PAGE: StoredColumns = {
108
131
  showScheduledEventHistoryInDays: 14,
109
132
  showScheduledEventLabelsOnStatusPage: false,
110
133
  showUptimeHistoryInDays: 90,
134
+ showOverallUptimePercentOnStatusPage: false,
135
+ overallUptimePercentPrecision: UptimePrecision.TWO_DECIMAL,
111
136
  hidePoweredByOneUptimeBranding: false,
112
137
  };
113
138
 
139
+ // The project's monitor statuses, as the server lists them.
140
+ const OPERATIONAL_ID: string = "6c6c6c6c-0000-4000-8000-000000000001";
141
+ const DEGRADED_ID: string = "6c6c6c6c-0000-4000-8000-000000000002";
142
+ const OFFLINE_ID: string = "6c6c6c6c-0000-4000-8000-000000000003";
143
+ const MAINTENANCE_ID: string = "6c6c6c6c-0000-4000-8000-000000000004";
144
+
145
+ function monitorStatus(data: {
146
+ id: string;
147
+ name: string;
148
+ color: string;
149
+ priority: number;
150
+ }): MonitorStatus {
151
+ const status: MonitorStatus = new MonitorStatus();
152
+ status._id = data.id;
153
+ status.name = data.name;
154
+ status.color = new Color(data.color);
155
+ status.priority = data.priority;
156
+ return status;
157
+ }
158
+
159
+ const PROJECT_STATUSES: Array<MonitorStatus> = [
160
+ monitorStatus({
161
+ id: OPERATIONAL_ID,
162
+ name: "Operational",
163
+ color: "#22c55e",
164
+ priority: 1,
165
+ }),
166
+ monitorStatus({
167
+ id: DEGRADED_ID,
168
+ name: "Degraded",
169
+ color: "#eab308",
170
+ priority: 2,
171
+ }),
172
+ monitorStatus({
173
+ id: OFFLINE_ID,
174
+ name: "Offline",
175
+ color: "#ef4444",
176
+ priority: 3,
177
+ }),
178
+ monitorStatus({
179
+ id: MAINTENANCE_ID,
180
+ name: "Under Maintenance",
181
+ color: "#6366f1",
182
+ priority: 4,
183
+ }),
184
+ ];
185
+
186
+ function statusesNamed(...names: Array<string>): Array<MonitorStatus> {
187
+ return names.map((name: string): MonitorStatus => {
188
+ return PROJECT_STATUSES.find((status: MonitorStatus): boolean => {
189
+ return status.name === name;
190
+ })!;
191
+ });
192
+ }
193
+
114
194
  let stored: StoredColumns | null | Error = null;
195
+ // What a new page counts as downtime: the statuses that are not operational.
196
+ let storedStatuses: Array<MonitorStatus> = [];
197
+ let projectStatuses: Array<MonitorStatus> | Error = PROJECT_STATUSES;
115
198
  let gate: PermissionGateResult = { isAllowed: true };
116
199
  let plan: PlanType | null = null;
117
200
 
118
201
  beforeEach(() => {
119
202
  stored = { ...NEW_PAGE };
203
+ storedStatuses = statusesNamed("Degraded", "Offline");
204
+ projectStatuses = PROJECT_STATUSES;
120
205
  gate = { isAllowed: true };
121
206
  plan = null;
122
207
 
@@ -137,9 +222,25 @@ beforeEach(() => {
137
222
  (page as unknown as Record<string, unknown>)[column] = value;
138
223
  }
139
224
 
225
+ page.downtimeMonitorStatuses = storedStatuses;
226
+
140
227
  return page;
141
228
  });
142
229
 
230
+ getListMock.mockReset();
231
+ getListMock.mockImplementation(async (): Promise<unknown> => {
232
+ if (projectStatuses instanceof Error) {
233
+ throw projectStatuses;
234
+ }
235
+
236
+ return {
237
+ data: projectStatuses,
238
+ count: projectStatuses.length,
239
+ skip: 0,
240
+ limit: 10000,
241
+ };
242
+ });
243
+
143
244
  updateByIdMock.mockReset();
144
245
  updateByIdMock.mockResolvedValue({} as never);
145
246
 
@@ -207,6 +308,116 @@ function daysRowFor(column: DisplayDaysColumn): HTMLElement {
207
308
  return screen.getByTestId(`${getDisplayDaysTestId(column)}-row`);
208
309
  }
209
310
 
311
+ const PRECISION: DisplayChoiceColumn = "overallUptimePercentPrecision";
312
+ const DOWNTIME: DisplayStatusesColumn = "downtimeMonitorStatuses";
313
+ const OVERALL: DisplaySwitchColumn = "showOverallUptimePercentOnStatusPage";
314
+
315
+ function choiceRowFor(column: DisplayChoiceColumn): HTMLElement {
316
+ return screen.getByTestId(`${getDisplayChoiceTestId(column)}-row`);
317
+ }
318
+
319
+ function queryChoiceRowFor(column: DisplayChoiceColumn): HTMLElement | null {
320
+ return screen.queryByTestId(`${getDisplayChoiceTestId(column)}-row`);
321
+ }
322
+
323
+ function statusesRowFor(column: DisplayStatusesColumn): HTMLElement {
324
+ return screen.getByTestId(`${getDisplayStatusesTestId(column)}-row`);
325
+ }
326
+
327
+ /*
328
+ * The dropdowns' inputs, found in their rows. A locked react-select hides
329
+ * its input (visibility: hidden), which takes its name out of the
330
+ * accessibility tree, so the names are checked where the dropdowns are not
331
+ * locked.
332
+ */
333
+ function precisionBox(): HTMLElement {
334
+ return within(choiceRowFor(PRECISION)).getByRole("combobox", {
335
+ hidden: true,
336
+ });
337
+ }
338
+
339
+ function downtimeBox(): HTMLElement {
340
+ return within(statusesRowFor(DOWNTIME)).getByRole("combobox", {
341
+ hidden: true,
342
+ });
343
+ }
344
+
345
+ // What the precision dropdown shows as picked.
346
+ function shownPrecision(): string {
347
+ const row: HTMLElement = choiceRowFor(PRECISION);
348
+
349
+ return (
350
+ row.querySelector(".ou-select__single-value")?.textContent ||
351
+ row.querySelector(".ou-select__placeholder")?.textContent ||
352
+ ""
353
+ );
354
+ }
355
+
356
+ // The names on the downtime chips, in order.
357
+ function downtimeChips(): Array<string> {
358
+ return Array.from(
359
+ statusesRowFor(DOWNTIME).querySelectorAll(".ou-select__multi-value__label"),
360
+ ).map((chip: Element): string => {
361
+ return (chip.textContent || "").trim();
362
+ });
363
+ }
364
+
365
+ async function flush(): Promise<void> {
366
+ await act(async () => {
367
+ for (let i: number = 0; i < 10; i++) {
368
+ await Promise.resolve();
369
+ }
370
+ });
371
+ }
372
+
373
+ // The options a dropdown offers, read from its open menu.
374
+ function offeredBy(box: HTMLElement): Array<string> {
375
+ fireEvent.keyDown(box, { key: "ArrowDown", code: "ArrowDown" });
376
+
377
+ const labels: Array<string> = screen
378
+ .queryAllByRole("option")
379
+ .map((option: HTMLElement): string => {
380
+ return (option.textContent || "").trim();
381
+ });
382
+
383
+ fireEvent.keyDown(box, { key: "Escape", code: "Escape" });
384
+
385
+ return labels;
386
+ }
387
+
388
+ async function pickFrom(box: HTMLElement, label: string): Promise<void> {
389
+ fireEvent.keyDown(box, { key: "ArrowDown", code: "ArrowDown" });
390
+
391
+ const option: HTMLElement = screen.getByRole("option", { name: label });
392
+
393
+ fireEvent.mouseDown(option);
394
+ fireEvent.click(option);
395
+ await flush();
396
+ }
397
+
398
+ async function removeChip(name: string): Promise<void> {
399
+ const remove: HTMLElement = within(statusesRowFor(DOWNTIME)).getByRole(
400
+ "button",
401
+ { name: `Remove ${name}` },
402
+ );
403
+
404
+ fireEvent.click(remove);
405
+ await flush();
406
+ }
407
+
408
+ function updatesOf(column: string): Array<Record<string, unknown>> {
409
+ return updateByIdMock.mock.calls
410
+ .map((call: Array<unknown>): Record<string, unknown> => {
411
+ return (call[0] as Record<string, unknown>)["data"] as Record<
412
+ string,
413
+ unknown
414
+ >;
415
+ })
416
+ .filter((data: Record<string, unknown>): boolean => {
417
+ return column in data;
418
+ });
419
+ }
420
+
210
421
  function definitionOf(column: DisplaySwitchColumn): DisplaySwitchDefinition {
211
422
  return DISPLAY_SWITCHES.find(
212
423
  (candidate: DisplaySwitchDefinition): boolean => {
@@ -264,7 +475,7 @@ const LIST_SWITCHES: Array<DisplaySwitchColumn> = [
264
475
  ];
265
476
 
266
477
  describe("reading the status page", () => {
267
- test("asks once for the card's fourteen columns and nothing else", async () => {
478
+ test("asks once for the card's seventeen columns and nothing else", async () => {
268
479
  await renderCard();
269
480
  await loaded();
270
481
 
@@ -289,9 +500,33 @@ describe("reading the status page", () => {
289
500
  showScheduledEventHistoryInDays: true,
290
501
  showScheduledEventLabelsOnStatusPage: true,
291
502
  showUptimeHistoryInDays: true,
503
+ showOverallUptimePercentOnStatusPage: true,
504
+ overallUptimePercentPrecision: true,
505
+ // What each chip shows.
506
+ downtimeMonitorStatuses: { _id: true, name: true, color: true },
292
507
  hidePoweredByOneUptimeBranding: true,
293
508
  });
294
- expect(DISPLAY_SETTING_COLUMNS).toHaveLength(14);
509
+ expect(DISPLAY_SETTING_COLUMNS).toHaveLength(17);
510
+ });
511
+
512
+ test("asks once for the project's monitor statuses, in their colours and priority order, for the downtime picker", async () => {
513
+ await renderCard();
514
+ await loaded();
515
+ await flush();
516
+
517
+ expect(getListMock).toHaveBeenCalledTimes(1);
518
+
519
+ const request: Record<string, unknown> = getListMock.mock
520
+ .calls[0]![0] as Record<string, unknown>;
521
+
522
+ expect(request["modelType"]).toBe(MonitorStatus);
523
+ expect(request["select"]).toEqual({
524
+ _id: true,
525
+ name: true,
526
+ color: true,
527
+ priority: true,
528
+ });
529
+ expect(request["sort"]).toEqual({ priority: SortOrder.Ascending });
295
530
  });
296
531
 
297
532
  test("is one card, saying what it is for", async () => {
@@ -368,8 +603,11 @@ describe("reading the status page", () => {
368
603
  );
369
604
  }
370
605
 
371
- expect(screen.getAllByRole("switch")).toHaveLength(9);
606
+ expect(screen.getAllByRole("switch")).toHaveLength(10);
372
607
  expect(screen.getAllByRole("spinbutton")).toHaveLength(5);
608
+
609
+ // The downtime picker; the precision only while the overall % is on.
610
+ expect(screen.getAllByRole("combobox")).toEqual([downtimeBox()]);
373
611
  });
374
612
 
375
613
  test("keeps the names the settings have always had, and the scope switch's own copy", async () => {
@@ -386,6 +624,7 @@ describe("reading the status page", () => {
386
624
  "Show Announcements",
387
625
  "Show Scheduled Maintenance Events",
388
626
  "Show Event Labels",
627
+ "Show Overall Uptime Percent",
389
628
  "Show Powered By OneUptime Branding",
390
629
  ]);
391
630
 
@@ -427,6 +666,13 @@ describe("reading the status page", () => {
427
666
 
428
667
  expect(daysFor("showUptimeHistoryInDays")).toHaveValue(90);
429
668
 
669
+ // No overall uptime percentage, so no precision to pick.
670
+ expect(switchFor(OVERALL)).toHaveAttribute("aria-checked", "false");
671
+ expect(queryChoiceRowFor(PRECISION)).toBeNull();
672
+
673
+ // The statuses that are not operational count as downtime.
674
+ expect(downtimeChips()).toEqual(["Degraded", "Offline"]);
675
+
430
676
  // Stored as "do not hide it", shown as a switch that is on.
431
677
  expect(switchFor("hidePoweredByOneUptimeBranding")).toHaveAttribute(
432
678
  "aria-checked",
@@ -435,8 +681,11 @@ describe("reading the status page", () => {
435
681
  });
436
682
 
437
683
  test("shows each setting as the page has it", async () => {
684
+ storedStatuses = statusesNamed("Offline");
438
685
  stored = {
439
686
  ...NEW_PAGE,
687
+ showOverallUptimePercentOnStatusPage: true,
688
+ overallUptimePercentPrecision: UptimePrecision.THREE_DECIMAL,
440
689
  showIncidentHistoryInDays: 30,
441
690
  showIncidentLabelsOnStatusPage: true,
442
691
  onlyShowScopedIncidents: true,
@@ -467,6 +716,10 @@ describe("reading the status page", () => {
467
716
  expect(daysFor("showScheduledEventHistoryInDays")).toHaveValue(7);
468
717
  expect(daysFor("showUptimeHistoryInDays")).toHaveValue(45);
469
718
 
719
+ expect(switchFor(OVERALL)).toHaveAttribute("aria-checked", "true");
720
+ expect(shownPrecision()).toBe("99.999%");
721
+ expect(downtimeChips()).toEqual(["Offline"]);
722
+
470
723
  // Hidden: the switch that shows it is off.
471
724
  expect(switchFor("hidePoweredByOneUptimeBranding")).toHaveAttribute(
472
725
  "aria-checked",
@@ -475,11 +728,14 @@ describe("reading the status page", () => {
475
728
  });
476
729
 
477
730
  test("a page with no value for a setting shows the model's default for it", async () => {
478
- stored = {};
731
+ stored = { showOverallUptimePercentOnStatusPage: true };
479
732
 
480
733
  await renderCard();
481
734
  await loaded();
482
735
 
736
+ // Two decimals: the precision's own default.
737
+ expect(shownPrecision()).toBe("99.99%");
738
+
483
739
  for (const column of LIST_SWITCHES) {
484
740
  expect(switchFor(column)).toHaveAttribute("aria-checked", "true");
485
741
  }
@@ -496,6 +752,16 @@ describe("reading the status page", () => {
496
752
  );
497
753
  });
498
754
 
755
+ test("a page with no value for any setting shows the overall uptime percentage off, the default", async () => {
756
+ stored = {};
757
+
758
+ await renderCard();
759
+ await loaded();
760
+
761
+ expect(switchFor(OVERALL)).toHaveAttribute("aria-checked", "false");
762
+ expect(queryChoiceRowFor(PRECISION)).toBeNull();
763
+ });
764
+
499
765
  test("a page that is not there says so, with nothing to change", async () => {
500
766
  stored = null;
501
767
 
@@ -1148,8 +1414,10 @@ describe("how many days", () => {
1148
1414
  daysFor("showUptimeHistoryInDays").getAttribute("aria-describedby"),
1149
1415
  ).toBe(description.id);
1150
1416
 
1151
- // No switch: the uptime bars are always there.
1152
- expect(within(section).queryByRole("switch")).toBeNull();
1417
+ // No switch of its own, the uptime bars are always there: only the overall %.
1418
+ expect(within(section).getAllByRole("switch")).toEqual([
1419
+ switchFor(OVERALL),
1420
+ ]);
1153
1421
  });
1154
1422
 
1155
1423
  test("is locked while it saves, then says Saved", async () => {
@@ -1228,6 +1496,625 @@ describe("how many days", () => {
1228
1496
  });
1229
1497
  });
1230
1498
 
1499
+ describe("the overall uptime percentage", () => {
1500
+ test("sits in the uptime row, under the number of days, saying what visitors see", async () => {
1501
+ await renderCard();
1502
+ await loaded();
1503
+
1504
+ const section: HTMLElement = screen.getByTestId(
1505
+ getDisplaySectionTestId("uptime-history"),
1506
+ );
1507
+
1508
+ expect(
1509
+ within(section).getByRole("switch", {
1510
+ name: "Show Overall Uptime Percent",
1511
+ }),
1512
+ ).toBe(switchFor(OVERALL));
1513
+ expect(
1514
+ within(switchRowFor(OVERALL)).getByText(
1515
+ StatusPageDisplaySettingsCopy.overallUptimeDescription,
1516
+ ),
1517
+ ).toBeInTheDocument();
1518
+
1519
+ // The days first, then the switch.
1520
+ const days: HTMLElement = daysFor("showUptimeHistoryInDays");
1521
+
1522
+ expect(
1523
+ days.compareDocumentPosition(switchFor(OVERALL)) &
1524
+ Node.DOCUMENT_POSITION_FOLLOWING,
1525
+ ).toBeTruthy();
1526
+ });
1527
+
1528
+ test("off, as a new page has it, offers no precision: the precision is of that percentage alone", async () => {
1529
+ await renderCard();
1530
+ await loaded();
1531
+
1532
+ expect(switchFor(OVERALL)).toHaveAttribute("aria-checked", "false");
1533
+ expect(queryChoiceRowFor(PRECISION)).toBeNull();
1534
+ });
1535
+
1536
+ test("turning it on saves the switch alone, and offers the precision the page has", async () => {
1537
+ await renderCard();
1538
+ await loaded();
1539
+
1540
+ await press(OVERALL);
1541
+
1542
+ await waitFor(() => {
1543
+ expect(choiceRowFor(PRECISION)).toBeInTheDocument();
1544
+ });
1545
+
1546
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1547
+ expect(lastUpdate()["data"]).toEqual({
1548
+ showOverallUptimePercentOnStatusPage: true,
1549
+ });
1550
+ expect(shownPrecision()).toBe("99.99%");
1551
+ expect(
1552
+ screen.getByRole("combobox", {
1553
+ name: StatusPageDisplaySettingsCopy.precisionLabel,
1554
+ }),
1555
+ ).toBe(precisionBox());
1556
+ });
1557
+
1558
+ test("turning it off takes the precision away, and saves the switch alone", async () => {
1559
+ stored = { ...NEW_PAGE, showOverallUptimePercentOnStatusPage: true };
1560
+
1561
+ await renderCard();
1562
+ await loaded();
1563
+
1564
+ expect(choiceRowFor(PRECISION)).toBeInTheDocument();
1565
+
1566
+ await press(OVERALL);
1567
+
1568
+ await waitFor(() => {
1569
+ expect(queryChoiceRowFor(PRECISION)).toBeNull();
1570
+ });
1571
+ expect(lastUpdate()["data"]).toEqual({
1572
+ showOverallUptimePercentOnStatusPage: false,
1573
+ });
1574
+ });
1575
+
1576
+ test("offers every precision, fewest decimals first, each as a visitor would read it", async () => {
1577
+ stored = { ...NEW_PAGE, showOverallUptimePercentOnStatusPage: true };
1578
+
1579
+ await renderCard();
1580
+ await loaded();
1581
+
1582
+ expect(offeredBy(precisionBox())).toEqual([
1583
+ "99%",
1584
+ "99.9%",
1585
+ "99.99%",
1586
+ "99.999%",
1587
+ ]);
1588
+ });
1589
+
1590
+ test.each([
1591
+ [UptimePrecision.NO_DECIMAL, "99%"],
1592
+ [UptimePrecision.ONE_DECIMAL, "99.9%"],
1593
+ [UptimePrecision.TWO_DECIMAL, "99.99%"],
1594
+ [UptimePrecision.THREE_DECIMAL, "99.999%"],
1595
+ ])("a page stored with %s shows %s", async (value: string, shown: string) => {
1596
+ stored = {
1597
+ ...NEW_PAGE,
1598
+ showOverallUptimePercentOnStatusPage: true,
1599
+ overallUptimePercentPrecision: value,
1600
+ };
1601
+
1602
+ await renderCard();
1603
+ await loaded();
1604
+
1605
+ expect(shownPrecision()).toBe(shown);
1606
+ });
1607
+
1608
+ test("a precision the list does not know is shown as it is stored", async () => {
1609
+ stored = {
1610
+ ...NEW_PAGE,
1611
+ showOverallUptimePercentOnStatusPage: true,
1612
+ overallUptimePercentPrecision: "Five Decimal",
1613
+ };
1614
+
1615
+ await renderCard();
1616
+ await loaded();
1617
+
1618
+ expect(shownPrecision()).toBe("Five Decimal");
1619
+ expect(offeredBy(precisionBox())).toEqual([
1620
+ "99%",
1621
+ "99.9%",
1622
+ "99.99%",
1623
+ "99.999%",
1624
+ "Five Decimal",
1625
+ ]);
1626
+ });
1627
+
1628
+ test("picking a precision saves that column alone, at once, and says so", async () => {
1629
+ stored = { ...NEW_PAGE, showOverallUptimePercentOnStatusPage: true };
1630
+
1631
+ await renderCard();
1632
+ await loaded();
1633
+
1634
+ await pickFrom(precisionBox(), "99.9%");
1635
+
1636
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1637
+
1638
+ const request: Record<string, unknown> = lastUpdate();
1639
+
1640
+ expect(request["modelType"]).toBe(StatusPage);
1641
+ expect((request["id"] as ObjectID).toString()).toBe(STATUS_PAGE_ID);
1642
+ expect(request["data"]).toEqual({
1643
+ overallUptimePercentPrecision: UptimePrecision.ONE_DECIMAL,
1644
+ });
1645
+ expect(shownPrecision()).toBe("99.9%");
1646
+ expect(
1647
+ screen.getByTestId(`${getDisplayChoiceTestId(PRECISION)}-status`),
1648
+ ).toHaveTextContent(StatusPageDisplaySettingsCopy.saved);
1649
+
1650
+ // No dialog, no Save button.
1651
+ expect(screen.queryByRole("dialog")).toBeNull();
1652
+ expect(screen.queryByRole("button", { name: /save/i })).toBeNull();
1653
+ });
1654
+
1655
+ test("picking what the page has saves nothing", async () => {
1656
+ stored = { ...NEW_PAGE, showOverallUptimePercentOnStatusPage: true };
1657
+
1658
+ await renderCard();
1659
+ await loaded();
1660
+
1661
+ await pickFrom(precisionBox(), "99.99%");
1662
+
1663
+ expect(updateByIdMock).not.toHaveBeenCalled();
1664
+ expect(
1665
+ screen.getByTestId(`${getDisplayChoiceTestId(PRECISION)}-status`),
1666
+ ).toHaveTextContent("");
1667
+ });
1668
+
1669
+ test("says Saving… while the pick is on its way, and stays usable, so a second pick is saved after it and the last one wins", async () => {
1670
+ stored = { ...NEW_PAGE, showOverallUptimePercentOnStatusPage: true };
1671
+
1672
+ const finishers: Array<() => void> = [];
1673
+
1674
+ updateByIdMock.mockImplementation((): Promise<unknown> => {
1675
+ return new Promise<unknown>((resolve: (value: unknown) => void) => {
1676
+ finishers.push((): void => {
1677
+ resolve({});
1678
+ });
1679
+ });
1680
+ });
1681
+
1682
+ await renderCard();
1683
+ await loaded();
1684
+
1685
+ await pickFrom(precisionBox(), "99%");
1686
+
1687
+ expect(
1688
+ screen.getByTestId(`${getDisplayChoiceTestId(PRECISION)}-status`),
1689
+ ).toHaveTextContent(StatusPageDisplaySettingsCopy.saving);
1690
+ expect(precisionBox()).not.toBeDisabled();
1691
+
1692
+ await pickFrom(precisionBox(), "99.9%");
1693
+ await pickFrom(precisionBox(), "99.999%");
1694
+
1695
+ // One request at a time.
1696
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1697
+ expect(shownPrecision()).toBe("99.999%");
1698
+
1699
+ await act(async () => {
1700
+ finishers[0]!();
1701
+ });
1702
+ await flush();
1703
+
1704
+ // Only the last waiting pick is sent.
1705
+ expect(updateByIdMock).toHaveBeenCalledTimes(2);
1706
+ expect(lastUpdate()["data"]).toEqual({
1707
+ overallUptimePercentPrecision: UptimePrecision.THREE_DECIMAL,
1708
+ });
1709
+
1710
+ await act(async () => {
1711
+ finishers[1]!();
1712
+ });
1713
+ await flush();
1714
+
1715
+ expect(shownPrecision()).toBe("99.999%");
1716
+ expect(
1717
+ screen.getByTestId(`${getDisplayChoiceTestId(PRECISION)}-status`),
1718
+ ).toHaveTextContent(StatusPageDisplaySettingsCopy.saved);
1719
+ expect(updateByIdMock).toHaveBeenCalledTimes(2);
1720
+ });
1721
+
1722
+ test("a refused pick goes back to the page's precision, with the reason", async () => {
1723
+ stored = { ...NEW_PAGE, showOverallUptimePercentOnStatusPage: true };
1724
+
1725
+ updateByIdMock.mockImplementation(async (): Promise<unknown> => {
1726
+ throw new Error("You do not have permission to update this Status Page.");
1727
+ });
1728
+
1729
+ await renderCard();
1730
+ await loaded();
1731
+
1732
+ await pickFrom(precisionBox(), "99%");
1733
+
1734
+ const error: HTMLElement = screen.getByTestId(
1735
+ `${getDisplayChoiceTestId(PRECISION)}-error`,
1736
+ );
1737
+
1738
+ expect(error).toHaveAttribute("role", "alert");
1739
+ expect(error).toHaveTextContent(
1740
+ "You do not have permission to update this Status Page.",
1741
+ );
1742
+ expect(shownPrecision()).toBe("99.99%");
1743
+
1744
+ // A new pick clears it.
1745
+ updateByIdMock.mockResolvedValue({} as never);
1746
+ await pickFrom(precisionBox(), "99.9%");
1747
+
1748
+ expect(
1749
+ screen.queryByTestId(`${getDisplayChoiceTestId(PRECISION)}-error`),
1750
+ ).toBeNull();
1751
+ expect(shownPrecision()).toBe("99.9%");
1752
+ });
1753
+
1754
+ test("turned off and on again, the precision is as last saved, not as first read", async () => {
1755
+ stored = { ...NEW_PAGE, showOverallUptimePercentOnStatusPage: true };
1756
+
1757
+ await renderCard();
1758
+ await loaded();
1759
+
1760
+ await pickFrom(precisionBox(), "99%");
1761
+ expect(lastUpdate()["data"]).toEqual({
1762
+ overallUptimePercentPrecision: UptimePrecision.NO_DECIMAL,
1763
+ });
1764
+
1765
+ await press(OVERALL);
1766
+ await waitFor(() => {
1767
+ expect(queryChoiceRowFor(PRECISION)).toBeNull();
1768
+ });
1769
+ await waitFor(() => {
1770
+ expect(switchFor(OVERALL)).not.toHaveAttribute("aria-disabled", "true");
1771
+ });
1772
+
1773
+ await press(OVERALL);
1774
+
1775
+ await waitFor(() => {
1776
+ expect(shownPrecision()).toBe("99%");
1777
+ });
1778
+ });
1779
+
1780
+ test("a refused attempt to turn it on (it needs the Scale plan) offers no precision", async () => {
1781
+ updateByIdMock.mockImplementation(async (): Promise<unknown> => {
1782
+ throw new Error(
1783
+ "Please upgrade your plan to Scale to access this feature",
1784
+ );
1785
+ });
1786
+
1787
+ await renderCard();
1788
+ await loaded();
1789
+
1790
+ await press(OVERALL);
1791
+
1792
+ await waitFor(() => {
1793
+ expect(
1794
+ within(switchRowFor(OVERALL)).getByRole("alert"),
1795
+ ).toHaveTextContent(
1796
+ "Please upgrade your plan to Scale to access this feature",
1797
+ );
1798
+ });
1799
+ expect(switchFor(OVERALL)).toHaveAttribute("aria-checked", "false");
1800
+ expect(queryChoiceRowFor(PRECISION)).toBeNull();
1801
+ });
1802
+
1803
+ /*
1804
+ * The bug this row fixes: the precision shared an Edit dialog with the
1805
+ * switch, the dialog sent both, and the server refuses a write that
1806
+ * carries the Scale plan's switch on a lower plan - so a page whose
1807
+ * overall percentage was on (turned on on Scale, or by the API) could not
1808
+ * have its precision changed at all.
1809
+ */
1810
+ test("on a plan below Scale, the switch names Scale, and the precision still saves, on its own", async () => {
1811
+ plan = PlanType.Growth;
1812
+ stored = { ...NEW_PAGE, showOverallUptimePercentOnStatusPage: true };
1813
+
1814
+ getJestSpyOn(
1815
+ SubscriptionPlan,
1816
+ "isFeatureAccessibleOnCurrentPlan",
1817
+ ).mockImplementation((needed: unknown): boolean => {
1818
+ return needed === PlanType.Free || needed === PlanType.Growth;
1819
+ });
1820
+
1821
+ await renderCard();
1822
+ await loaded();
1823
+
1824
+ expect(within(switchRowFor(OVERALL)).getByTestId("pill")).toHaveTextContent(
1825
+ "Scale Plan",
1826
+ );
1827
+ expect(
1828
+ within(choiceRowFor(PRECISION)).queryByTestId("pill"),
1829
+ ).not.toBeInTheDocument();
1830
+
1831
+ await pickFrom(precisionBox(), "99.999%");
1832
+
1833
+ expect(updatesOf(PRECISION)).toEqual([
1834
+ { overallUptimePercentPrecision: UptimePrecision.THREE_DECIMAL },
1835
+ ]);
1836
+ expect(updatesOf(OVERALL)).toEqual([]);
1837
+ });
1838
+ });
1839
+
1840
+ describe("what counts as downtime", () => {
1841
+ test("is in the uptime row, last, named for what it does, saying what it does", async () => {
1842
+ await renderCard();
1843
+ await loaded();
1844
+ await flush();
1845
+
1846
+ const section: HTMLElement = screen.getByTestId(
1847
+ getDisplaySectionTestId("uptime-history"),
1848
+ );
1849
+
1850
+ expect(
1851
+ within(section).getByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-row`),
1852
+ ).toBe(statusesRowFor(DOWNTIME));
1853
+ expect(
1854
+ screen.getByRole("combobox", {
1855
+ name: StatusPageDisplaySettingsCopy.downtimeLabel,
1856
+ }),
1857
+ ).toBe(downtimeBox());
1858
+ expect(
1859
+ screen.getByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-description`),
1860
+ ).toHaveTextContent(StatusPageDisplaySettingsCopy.downtimeDescription);
1861
+
1862
+ // After the overall uptime percentage.
1863
+ expect(
1864
+ switchFor(OVERALL).compareDocumentPosition(downtimeBox()) &
1865
+ Node.DOCUMENT_POSITION_FOLLOWING,
1866
+ ).toBeTruthy();
1867
+ });
1868
+
1869
+ test("shows the page's statuses as chips, each in its own colour", async () => {
1870
+ await renderCard();
1871
+ await loaded();
1872
+ await flush();
1873
+
1874
+ expect(downtimeChips()).toEqual(["Degraded", "Offline"]);
1875
+
1876
+ const dots: Array<string | null> = Array.from(
1877
+ statusesRowFor(DOWNTIME).querySelectorAll(
1878
+ ".ou-select__multi-value__label [title]",
1879
+ ),
1880
+ ).map((dot: Element): string | null => {
1881
+ return dot.getAttribute("title");
1882
+ });
1883
+
1884
+ expect(dots).toEqual(["#eab308", "#ef4444"]);
1885
+ });
1886
+
1887
+ test("offers the project's other statuses, in priority order", async () => {
1888
+ await renderCard();
1889
+ await loaded();
1890
+ await flush();
1891
+
1892
+ // The picked ones are chips already.
1893
+ expect(offeredBy(downtimeBox())).toEqual([
1894
+ "Operational",
1895
+ "Under Maintenance",
1896
+ ]);
1897
+ });
1898
+
1899
+ test("adding a status saves the statuses alone, by id, at once, and says so", async () => {
1900
+ await renderCard();
1901
+ await loaded();
1902
+ await flush();
1903
+
1904
+ await pickFrom(downtimeBox(), "Under Maintenance");
1905
+
1906
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1907
+
1908
+ const request: Record<string, unknown> = lastUpdate();
1909
+
1910
+ expect(request["modelType"]).toBe(StatusPage);
1911
+ expect((request["id"] as ObjectID).toString()).toBe(STATUS_PAGE_ID);
1912
+ expect(request["data"]).toEqual({
1913
+ downtimeMonitorStatuses: [DEGRADED_ID, OFFLINE_ID, MAINTENANCE_ID],
1914
+ });
1915
+ expect(downtimeChips()).toEqual([
1916
+ "Degraded",
1917
+ "Offline",
1918
+ "Under Maintenance",
1919
+ ]);
1920
+ expect(
1921
+ screen.getByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-status`),
1922
+ ).toHaveTextContent(StatusPageDisplaySettingsCopy.saved);
1923
+ expect(screen.queryByRole("dialog")).toBeNull();
1924
+ });
1925
+
1926
+ test("taking a status off saves the rest", async () => {
1927
+ await renderCard();
1928
+ await loaded();
1929
+ await flush();
1930
+
1931
+ await removeChip("Degraded");
1932
+
1933
+ expect(lastUpdate()["data"]).toEqual({
1934
+ downtimeMonitorStatuses: [OFFLINE_ID],
1935
+ });
1936
+ expect(downtimeChips()).toEqual(["Offline"]);
1937
+ });
1938
+
1939
+ test("the last status cannot be taken off: nothing is sent, the chip stays, and the row says why", async () => {
1940
+ storedStatuses = statusesNamed("Offline");
1941
+
1942
+ await renderCard();
1943
+ await loaded();
1944
+ await flush();
1945
+
1946
+ await removeChip("Offline");
1947
+
1948
+ expect(updateByIdMock).not.toHaveBeenCalled();
1949
+ expect(downtimeChips()).toEqual(["Offline"]);
1950
+
1951
+ const error: HTMLElement = screen.getByTestId(
1952
+ `${getDisplayStatusesTestId(DOWNTIME)}-error`,
1953
+ );
1954
+
1955
+ expect(error).toHaveAttribute("role", "alert");
1956
+ expect(error).toHaveTextContent(
1957
+ StatusPageDisplaySettingsCopy.downtimeKeepOne,
1958
+ );
1959
+
1960
+ // Adding one clears it and saves.
1961
+ await pickFrom(downtimeBox(), "Degraded");
1962
+
1963
+ expect(
1964
+ screen.queryByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-error`),
1965
+ ).toBeNull();
1966
+ expect(lastUpdate()["data"]).toEqual({
1967
+ downtimeMonitorStatuses: [OFFLINE_ID, DEGRADED_ID],
1968
+ });
1969
+ });
1970
+
1971
+ test("has no clear-all control: the list always keeps a status", async () => {
1972
+ await renderCard();
1973
+ await loaded();
1974
+ await flush();
1975
+
1976
+ expect(
1977
+ statusesRowFor(DOWNTIME).querySelector(".ou-select__clear-indicator"),
1978
+ ).toBeNull();
1979
+ });
1980
+
1981
+ test("a refused change puts back the page's statuses, with the reason", async () => {
1982
+ updateByIdMock.mockImplementation(async (): Promise<unknown> => {
1983
+ throw new Error("Monitor status not found.");
1984
+ });
1985
+
1986
+ await renderCard();
1987
+ await loaded();
1988
+ await flush();
1989
+
1990
+ await pickFrom(downtimeBox(), "Operational");
1991
+
1992
+ expect(
1993
+ screen.getByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-error`),
1994
+ ).toHaveTextContent("Monitor status not found.");
1995
+ expect(downtimeChips()).toEqual(["Degraded", "Offline"]);
1996
+ expect(
1997
+ screen.getByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-status`),
1998
+ ).toHaveTextContent("");
1999
+ });
2000
+
2001
+ test("is never locked while it saves: a change made meanwhile is saved after it, and the last one wins", async () => {
2002
+ const finishers: Array<() => void> = [];
2003
+
2004
+ updateByIdMock.mockImplementation((): Promise<unknown> => {
2005
+ return new Promise<unknown>((resolve: (value: unknown) => void) => {
2006
+ finishers.push((): void => {
2007
+ resolve({});
2008
+ });
2009
+ });
2010
+ });
2011
+
2012
+ await renderCard();
2013
+ await loaded();
2014
+ await flush();
2015
+
2016
+ await pickFrom(downtimeBox(), "Under Maintenance");
2017
+
2018
+ expect(downtimeBox()).not.toBeDisabled();
2019
+ expect(
2020
+ screen.getByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-status`),
2021
+ ).toHaveTextContent(StatusPageDisplaySettingsCopy.saving);
2022
+
2023
+ await removeChip("Degraded");
2024
+ await pickFrom(downtimeBox(), "Operational");
2025
+
2026
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
2027
+ expect(downtimeChips()).toEqual([
2028
+ "Offline",
2029
+ "Under Maintenance",
2030
+ "Operational",
2031
+ ]);
2032
+
2033
+ await act(async () => {
2034
+ finishers[0]!();
2035
+ });
2036
+ await flush();
2037
+
2038
+ expect(updateByIdMock).toHaveBeenCalledTimes(2);
2039
+ expect(lastUpdate()["data"]).toEqual({
2040
+ downtimeMonitorStatuses: [OFFLINE_ID, MAINTENANCE_ID, OPERATIONAL_ID],
2041
+ });
2042
+
2043
+ await act(async () => {
2044
+ finishers[1]!();
2045
+ });
2046
+ await flush();
2047
+
2048
+ expect(
2049
+ screen.getByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-status`),
2050
+ ).toHaveTextContent(StatusPageDisplaySettingsCopy.saved);
2051
+ });
2052
+
2053
+ test("a page with none (only the API leaves a page so) says every uptime percentage reads 100%, and a pick saves", async () => {
2054
+ storedStatuses = [];
2055
+
2056
+ await renderCard();
2057
+ await loaded();
2058
+ await flush();
2059
+
2060
+ expect(downtimeChips()).toEqual([]);
2061
+ expect(
2062
+ screen.getByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-description`),
2063
+ ).toHaveTextContent(StatusPageDisplaySettingsCopy.downtimeEmptyDescription);
2064
+ expect(statusesRowFor(DOWNTIME)).toHaveTextContent(
2065
+ StatusPageDisplaySettingsCopy.downtimePlaceholder,
2066
+ );
2067
+
2068
+ await pickFrom(downtimeBox(), "Offline");
2069
+
2070
+ expect(lastUpdate()["data"]).toEqual({
2071
+ downtimeMonitorStatuses: [OFFLINE_ID],
2072
+ });
2073
+ expect(
2074
+ screen.getByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-description`),
2075
+ ).toHaveTextContent(StatusPageDisplaySettingsCopy.downtimeDescription);
2076
+ });
2077
+
2078
+ test("when the project's statuses cannot be read it says why, and the page's chips still show", async () => {
2079
+ projectStatuses = new Error("The server is down for maintenance.");
2080
+
2081
+ await renderCard();
2082
+ await loaded();
2083
+ await flush();
2084
+
2085
+ expect(
2086
+ screen.getByTestId(`${getDisplayStatusesTestId(DOWNTIME)}-load-error`),
2087
+ ).toHaveTextContent("The server is down for maintenance.");
2088
+ expect(downtimeChips()).toEqual(["Degraded", "Offline"]);
2089
+
2090
+ // The rest of the card is untouched.
2091
+ expect(switchFor("showIncidentsOnStatusPage")).toBeInTheDocument();
2092
+ });
2093
+
2094
+ test("a status the project's list leaves out stays a chip of its own, and can be taken off", async () => {
2095
+ const retired: MonitorStatus = monitorStatus({
2096
+ id: "6c6c6c6c-0000-4000-8000-000000000009",
2097
+ name: "Retired",
2098
+ color: "#000000",
2099
+ priority: 9,
2100
+ });
2101
+
2102
+ storedStatuses = [...statusesNamed("Offline"), retired];
2103
+
2104
+ await renderCard();
2105
+ await loaded();
2106
+ await flush();
2107
+
2108
+ expect(downtimeChips()).toEqual(["Offline", "Retired"]);
2109
+
2110
+ await removeChip("Retired");
2111
+
2112
+ expect(lastUpdate()["data"]).toEqual({
2113
+ downtimeMonitorStatuses: [OFFLINE_ID],
2114
+ });
2115
+ });
2116
+ });
2117
+
1231
2118
  describe("who may change them", () => {
1232
2119
  test("the gate is asked about updating a status page", async () => {
1233
2120
  await renderCard();
@@ -1250,6 +2137,7 @@ describe("who may change them", () => {
1250
2137
  isAllowed: false,
1251
2138
  disabledReason: "You do not have permission to update this Status Page.",
1252
2139
  };
2140
+ stored = { ...NEW_PAGE, showOverallUptimePercentOnStatusPage: true };
1253
2141
 
1254
2142
  await renderCard();
1255
2143
  await loaded();
@@ -1265,6 +2153,14 @@ describe("who may change them", () => {
1265
2153
  expect(daysFor(definition.column)).toHaveAttribute("readonly");
1266
2154
  }
1267
2155
 
2156
+ // The precision and the downtime statuses too, still showing their values.
2157
+ expect(precisionBox()).toBeDisabled();
2158
+ expect(shownPrecision()).toBe("99.99%");
2159
+ expect(downtimeBox()).toBeDisabled();
2160
+ expect(downtimeChips()).toEqual(["Degraded", "Offline"]);
2161
+ expect(offeredBy(precisionBox())).toEqual([]);
2162
+ expect(offeredBy(downtimeBox())).toEqual([]);
2163
+
1268
2164
  expect(
1269
2165
  screen.getAllByText(
1270
2166
  "You do not have permission to update this Status Page.",
@@ -1299,6 +2195,8 @@ describe("plans", () => {
1299
2195
 
1300
2196
  test("on the Free plan, each setting the Free plan cannot change names the plan it needs, beside it", async () => {
1301
2197
  plan = PlanType.Free;
2198
+ // On, so its precision is drawn too.
2199
+ stored = { ...NEW_PAGE, showOverallUptimePercentOnStatusPage: true };
1302
2200
 
1303
2201
  getJestSpyOn(
1304
2202
  SubscriptionPlan,
@@ -1316,6 +2214,22 @@ describe("plans", () => {
1316
2214
  const rowOf: (column: DisplaySettingColumn) => HTMLElement = (
1317
2215
  column: DisplaySettingColumn,
1318
2216
  ): HTMLElement => {
2217
+ if (
2218
+ DISPLAY_CHOICES.some((definition: { column: string }) => {
2219
+ return definition.column === column;
2220
+ })
2221
+ ) {
2222
+ return choiceRowFor(column as DisplayChoiceColumn);
2223
+ }
2224
+
2225
+ if (
2226
+ DISPLAY_STATUSES.some((definition: { column: string }) => {
2227
+ return definition.column === column;
2228
+ })
2229
+ ) {
2230
+ return statusesRowFor(column as DisplayStatusesColumn);
2231
+ }
2232
+
1319
2233
  return DISPLAY_DAYS.some((definition: DisplayDaysDefinition) => {
1320
2234
  return definition.column === column;
1321
2235
  })
@@ -1341,6 +2255,20 @@ describe("plans", () => {
1341
2255
  );
1342
2256
  }
1343
2257
 
2258
+ /*
2259
+ * The overall uptime percentage needs Scale to be switched; its
2260
+ * precision and the downtime statuses, every plan.
2261
+ */
2262
+ expect(within(switchRowFor(OVERALL)).getByTestId("pill")).toHaveTextContent(
2263
+ "Scale Plan",
2264
+ );
2265
+ expect(
2266
+ within(choiceRowFor(PRECISION)).queryByTestId("pill"),
2267
+ ).not.toBeInTheDocument();
2268
+ expect(
2269
+ within(statusesRowFor(DOWNTIME)).queryByTestId("pill"),
2270
+ ).not.toBeInTheDocument();
2271
+
1344
2272
  /*
1345
2273
  * As the model has it today: the four lists, their labels and how far
1346
2274
  * back episodes go from Growth; hiding the Powered by line from Scale;
@@ -1405,6 +2333,13 @@ describe("plans", () => {
1405
2333
  expect(lastUpdate()["data"]).toEqual({ onlyShowScopedIncidents: true });
1406
2334
  });
1407
2335
 
2336
+ await pickFrom(downtimeBox(), "Under Maintenance");
2337
+ await waitFor(() => {
2338
+ expect(lastUpdate()["data"]).toEqual({
2339
+ downtimeMonitorStatuses: [DEGRADED_ID, OFFLINE_ID, MAINTENANCE_ID],
2340
+ });
2341
+ });
2342
+
1408
2343
  // Each request carried its own column alone.
1409
2344
  for (const call of updateByIdMock.mock.calls) {
1410
2345
  expect(