@oneuptime/common 14.0.0 → 14.0.2

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 (1270) hide show
  1. package/Models/DatabaseModels/AlertEpisodeMember.ts +8 -1
  2. package/Models/DatabaseModels/AutoRemediationSuggestion.ts +63 -0
  3. package/Models/DatabaseModels/IncidentEpisodeMember.ts +8 -1
  4. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +9 -2
  5. package/Models/DatabaseModels/IncidentPublicNote.ts +9 -2
  6. package/Models/DatabaseModels/Index.ts +4 -0
  7. package/Models/DatabaseModels/KubernetesCluster.ts +429 -0
  8. package/Models/DatabaseModels/Monitor.ts +48 -0
  9. package/Models/DatabaseModels/Runner.ts +5 -4
  10. package/Models/DatabaseModels/RunnerJob.ts +66 -0
  11. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +10 -2
  12. package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
  13. package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
  14. package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
  15. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
  16. package/Models/DatabaseModels/WorkflowVariable.ts +479 -2
  17. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +79 -25
  18. package/Server/API/AIInvestigationAPI.ts +341 -0
  19. package/Server/API/AutoRemediationAPI.ts +184 -2
  20. package/Server/API/CommonAPI.ts +70 -0
  21. package/Server/API/KubernetesClusterAiAccessAPI.ts +793 -0
  22. package/Server/API/MicrosoftTeamsAPI.ts +770 -315
  23. package/Server/API/MonitorAPI.ts +140 -0
  24. package/Server/API/OnCallScheduleTimelineAPI.ts +5 -21
  25. package/Server/API/SlackAPI.ts +447 -99
  26. package/Server/API/StatusPageAPI.ts +146 -26
  27. package/Server/API/TelemetryAPI.ts +216 -5
  28. package/Server/API/UserTwoFactorBackupCodeAPI.ts +1 -0
  29. package/Server/API/WorkflowVariableAPI.ts +156 -0
  30. package/Server/Infrastructure/GlobalCache.ts +35 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.ts +97 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.ts +129 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.ts +25 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.ts +20 -0
  37. package/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.ts +38 -0
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
  39. package/Server/Middleware/MasterAdminAuthorization.ts +28 -0
  40. package/Server/Middleware/TelemetryIngest.ts +47 -2
  41. package/Server/Middleware/UserAuthorization.ts +56 -2
  42. package/Server/Services/AIAgentService.ts +1 -0
  43. package/Server/Services/AccessTokenService.ts +121 -48
  44. package/Server/Services/AlertEpisodeMemberService.ts +9 -0
  45. package/Server/Services/AlertEpisodeService.ts +14 -1
  46. package/Server/Services/AlertService.ts +134 -22
  47. package/Server/Services/AutoRemediationRuleEngineService.ts +968 -39
  48. package/Server/Services/AutoRemediationRuleService.ts +118 -0
  49. package/Server/Services/BillingService.ts +1 -0
  50. package/Server/Services/DatabaseService.ts +10 -0
  51. package/Server/Services/InboundEmail/Providers/SendGridInboundProvider.ts +16 -22
  52. package/Server/Services/IncidentEpisodeMemberService.ts +9 -0
  53. package/Server/Services/IncidentEpisodePublicNoteService.ts +66 -0
  54. package/Server/Services/IncidentEpisodeRoleMemberService.ts +27 -0
  55. package/Server/Services/IncidentEpisodeService.ts +14 -1
  56. package/Server/Services/IncidentGroupingEngineService.ts +11 -0
  57. package/Server/Services/IncidentMemberService.ts +21 -0
  58. package/Server/Services/IncidentPublicNoteService.ts +63 -0
  59. package/Server/Services/IncidentService.ts +120 -20
  60. package/Server/Services/IncidentStateTimelineService.ts +15 -0
  61. package/Server/Services/IncidentTemplateService.ts +83 -3
  62. package/Server/Services/Index.ts +4 -0
  63. package/Server/Services/KubernetesClusterAiAccessService.ts +1943 -0
  64. package/Server/Services/KubernetesClusterService.ts +1570 -1
  65. package/Server/Services/LogAggregationService.ts +14 -6
  66. package/Server/Services/MonitorService.ts +654 -54
  67. package/Server/Services/MonitorStatusTimelineService.ts +639 -2
  68. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -0
  69. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -0
  70. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -0
  71. package/Server/Services/OnCallDutyPolicyScheduleService.ts +3 -0
  72. package/Server/Services/OnCallNotificationAlertingService.ts +36 -12
  73. package/Server/Services/OnCallSetupReminderService.ts +1 -0
  74. package/Server/Services/ProbeService.ts +7 -1
  75. package/Server/Services/ProjectService.ts +11 -1
  76. package/Server/Services/RunbookCredentialService.ts +26 -1
  77. package/Server/Services/RunbookSecretService.ts +36 -0
  78. package/Server/Services/RunnerJobService.ts +941 -23
  79. package/Server/Services/RunnerService.ts +439 -6
  80. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +66 -0
  81. package/Server/Services/ScheduledMaintenanceService.ts +124 -19
  82. package/Server/Services/ScheduledMaintenanceTemplateService.ts +82 -3
  83. package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
  84. package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
  85. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
  86. package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
  87. package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
  88. package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
  89. package/Server/Services/ServiceLevelObjectiveService.ts +42 -1
  90. package/Server/Services/StatusPagePrivateUserService.ts +1 -0
  91. package/Server/Services/StatusPageService.ts +301 -74
  92. package/Server/Services/StatusPageSubscriberService.ts +4 -0
  93. package/Server/Services/TeamMemberService.ts +309 -7
  94. package/Server/Services/TraceAggregationService.ts +10 -6
  95. package/Server/Services/UserEmailService.ts +1 -0
  96. package/Server/Services/UserNotificationMethodAdminService.ts +1 -0
  97. package/Server/Services/UserNotificationRuleAdminService.ts +1 -0
  98. package/Server/Services/UserNotificationRuleService.ts +4 -0
  99. package/Server/Services/UserService.ts +122 -1
  100. package/Server/Services/WorkflowVariableService.ts +593 -8
  101. package/Server/Services/WorkspaceNotificationRuleService.ts +588 -8
  102. package/Server/Services/WorkspaceProjectAuthTokenService.ts +170 -1
  103. package/Server/Types/Database/QueryHelper.ts +22 -0
  104. package/Server/Types/Markdown.ts +502 -27
  105. package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
  106. package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +182 -0
  107. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +525 -0
  108. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +854 -0
  109. package/Server/Utils/AI/CodeFix/CodeFixAgentAuth.ts +22 -2
  110. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1916 -307
  111. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +1601 -74
  112. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +139 -7
  113. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +58 -1
  114. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +54 -1
  115. package/Server/Utils/AI/Toolbox/AIActionTools.ts +14 -6
  116. package/Server/Utils/AI/Toolbox/ResourceTools.ts +4 -2
  117. package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
  118. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +1341 -150
  119. package/Server/Utils/AutoRemediation/RemediationVerifier.ts +375 -4
  120. package/Server/Utils/Database/AffectedResourceRelations.ts +127 -0
  121. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +240 -1
  122. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +1 -0
  123. package/Server/Utils/Monitor/AffectedResourceList.ts +31 -73
  124. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
  125. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
  126. package/Server/Utils/Monitor/MonitorAlert.ts +83 -9
  127. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +181 -136
  128. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +5 -1
  129. package/Server/Utils/Monitor/MonitorIncident.ts +104 -9
  130. package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +124 -7
  131. package/Server/Utils/Monitor/ProbeMonitorsNotification.ts +407 -0
  132. package/Server/Utils/Monitor/RootCauseList.ts +139 -0
  133. package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +1 -0
  134. package/Server/Utils/PushNotificationUtil.ts +45 -0
  135. package/Server/Utils/Rules/OwnerRuleAssignment.ts +40 -3
  136. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
  137. package/Server/Utils/Runbook/RunbookExecutePermission.ts +56 -6
  138. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +223 -33
  139. package/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.ts +559 -0
  140. package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
  141. package/Server/Utils/StartServer.ts +4 -3
  142. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +528 -0
  143. package/Server/Utils/TwoFactorBackupCodeNotification.ts +1 -0
  144. package/Server/Utils/UserPermission/UserPermission.ts +16 -0
  145. package/Server/Utils/Workflow/OAuth2TokenClient.ts +704 -0
  146. package/Server/Utils/Workflow/WorkflowVariableOAuthToken.ts +318 -0
  147. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +47 -7
  148. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +57 -16
  149. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +193 -214
  150. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +57 -13
  151. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.ts +54 -17
  152. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +179 -161
  153. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +281 -167
  154. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.ts +114 -0
  155. package/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.ts +895 -0
  156. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +7 -9
  157. package/Server/Utils/Workspace/Slack/Actions/Alert.ts +96 -227
  158. package/Server/Utils/Workspace/Slack/Actions/AlertEpisode.ts +93 -214
  159. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +30 -3
  160. package/Server/Utils/Workspace/Slack/Actions/Authorization.ts +99 -0
  161. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +117 -283
  162. package/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.ts +101 -196
  163. package/Server/Utils/Workspace/Slack/Actions/ReactionNote.ts +329 -0
  164. package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +111 -287
  165. package/Server/Utils/Workspace/Slack/Slack.ts +86 -17
  166. package/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
  167. package/Server/Utils/Workspace/Workspace.ts +171 -54
  168. package/Server/Utils/Workspace/WorkspaceActionAuthorization.ts +252 -0
  169. package/Server/Utils/Workspace/WorkspaceBase.ts +39 -0
  170. package/Server/Utils/Workspace/WorkspaceOAuthState.ts +280 -0
  171. package/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.ts +96 -0
  172. package/Server/Utils/Workspace/WorkspaceReactionNote.ts +620 -0
  173. package/Tests/App/Dashboard/AttributesJSONDashboardSurfaces.test.tsx +496 -0
  174. package/Tests/App/Dashboard/AutoRemediationRulesTableCommandRunners.test.tsx +152 -0
  175. package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +32 -0
  176. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +794 -0
  177. package/Tests/App/Dashboard/CreateOAuthWorkflowVariableModal.test.tsx +840 -0
  178. package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +653 -0
  179. package/Tests/App/Dashboard/DatabaseMonitorStepForm.test.tsx +197 -0
  180. package/Tests/App/Dashboard/DatabaseMonitorView.test.tsx +376 -0
  181. package/Tests/App/Dashboard/DisabledWarningRobustness.test.tsx +262 -0
  182. package/Tests/App/Dashboard/EventNotes.test.tsx +2080 -0
  183. package/Tests/App/Dashboard/EventNotesPages.test.tsx +486 -0
  184. package/Tests/App/Dashboard/EventNotesUtil.test.ts +933 -0
  185. package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +218 -0
  186. package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
  187. package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
  188. package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
  189. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +665 -0
  190. package/Tests/App/Dashboard/IncidentEpisodeFeedPublicNoteNotifyDefault.test.tsx +494 -0
  191. package/Tests/App/Dashboard/IncidentEpisodeOverviewNotifyDefault.test.tsx +706 -0
  192. package/Tests/App/Dashboard/IncidentFeedPublicNoteNotifyDefault.test.tsx +472 -0
  193. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +858 -0
  194. package/Tests/App/Dashboard/IncomingEmailAddressSettings.test.tsx +567 -0
  195. package/Tests/App/Dashboard/InvestigationClusterToolFormat.test.ts +241 -0
  196. package/Tests/App/Dashboard/InvestigationEvidenceKubectl.test.tsx +322 -0
  197. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
  198. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +606 -3
  199. package/Tests/App/Dashboard/InvestigationPanelClusterAccess.test.tsx +476 -0
  200. package/Tests/App/Dashboard/InvestigationRunDetailsKubectl.test.tsx +383 -0
  201. package/Tests/App/Dashboard/KubectlActivitySummary.test.tsx +366 -0
  202. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +2886 -0
  203. package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +2688 -0
  204. package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +915 -0
  205. package/Tests/App/Dashboard/LayerDateTimeFieldTimezoneName.test.tsx +66 -0
  206. package/Tests/App/Dashboard/LogMonitorPreview.test.tsx +174 -0
  207. package/Tests/App/Dashboard/MonitorFeedRefresh.test.tsx +279 -0
  208. package/Tests/App/Dashboard/MonitorMetricQueryConfig.test.ts +244 -0
  209. package/Tests/App/Dashboard/MonitorOpenWorkCard.test.tsx +381 -0
  210. package/Tests/App/Dashboard/MonitorOpenWorkHook.test.tsx +784 -0
  211. package/Tests/App/Dashboard/MonitorOverviewData.test.tsx +2199 -0
  212. package/Tests/App/Dashboard/MonitorOverviewHero.test.tsx +1169 -0
  213. package/Tests/App/Dashboard/MonitorOverviewInput.test.ts +1127 -0
  214. package/Tests/App/Dashboard/MonitorOverviewPage.test.tsx +2136 -0
  215. package/Tests/App/Dashboard/MonitorOverviewSelectReadable.test.ts +368 -0
  216. package/Tests/App/Dashboard/MonitorOverviewStatBar.test.tsx +526 -0
  217. package/Tests/App/Dashboard/MonitorOverviewSupportingCards.test.tsx +542 -0
  218. package/Tests/App/Dashboard/MonitorOwnersCombine.test.ts +299 -0
  219. package/Tests/App/Dashboard/MonitorProbesCard.test.tsx +602 -0
  220. package/Tests/App/Dashboard/MonitorResponseTimeCard.test.tsx +386 -0
  221. package/Tests/App/Dashboard/MonitorSetupAndConnectionCards.test.tsx +612 -0
  222. package/Tests/App/Dashboard/MonitorStatusChangesCard.test.tsx +257 -0
  223. package/Tests/App/Dashboard/MonitorSummaryTestMonitorButton.test.tsx +360 -1
  224. package/Tests/App/Dashboard/MonitorUptimeHistoryCard.test.tsx +835 -0
  225. package/Tests/App/Dashboard/MonitorUptimeSummaryHook.test.tsx +971 -0
  226. package/Tests/App/Dashboard/MonitorViewLayout.test.tsx +580 -0
  227. package/Tests/App/Dashboard/OnCallLayerRestrictionTimesPreserved.test.tsx +441 -0
  228. package/Tests/App/Dashboard/OnCallNavbar.test.tsx +214 -0
  229. package/Tests/App/Dashboard/OnCallSchedulePreviewCalendarDisplay.test.tsx +1389 -0
  230. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +205 -1
  231. package/Tests/App/Dashboard/OnCallScheduleTimeInputsSettingsZone.test.tsx +198 -0
  232. package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
  233. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +524 -0
  234. package/Tests/App/Dashboard/RemediationSuggestionCardApproval.test.tsx +702 -0
  235. package/Tests/App/Dashboard/RemoveUserFromProject.test.tsx +427 -0
  236. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +4 -0
  237. package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
  238. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
  239. package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
  240. package/Tests/App/Dashboard/RumSessionReplaySideMenu.test.tsx +3 -1
  241. package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +166 -0
  242. package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +622 -0
  243. package/Tests/App/Dashboard/ScheduledMaintenanceChangeStateNotifyDefault.test.tsx +1491 -0
  244. package/Tests/App/Dashboard/ScheduledMaintenanceFeedPublicNoteNotifyDefault.test.tsx +489 -0
  245. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
  246. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewNotifyDefault.test.tsx +909 -0
  247. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +14 -0
  248. package/Tests/App/Dashboard/ScheduledMaintenanceWindowStatsTranslation.test.tsx +307 -0
  249. package/Tests/App/Dashboard/SecurityEventAttributeColumnPicker.test.tsx +542 -0
  250. package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +174 -0
  251. package/Tests/App/Dashboard/SecurityEventConnectionsEmptyState.test.tsx +973 -212
  252. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +491 -52
  253. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +301 -0
  254. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +158 -1
  255. package/Tests/App/Dashboard/SecurityEventProviderTile.test.tsx +869 -0
  256. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +959 -94
  257. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +2 -0
  258. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +274 -1
  259. package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
  260. package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
  261. package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
  262. package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
  263. package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
  264. package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
  265. package/Tests/App/Dashboard/TeamMembershipRemoval.test.ts +900 -0
  266. package/Tests/App/Dashboard/TeamMembershipRemovalPages.test.tsx +460 -0
  267. package/Tests/App/Dashboard/TimezoneElements.test.tsx +321 -0
  268. package/Tests/App/Dashboard/TimezoneSelectButton.test.tsx +634 -0
  269. package/Tests/App/Dashboard/TraceExplorer.test.tsx +260 -0
  270. package/Tests/App/Dashboard/TraceMonitorPreview.test.tsx +182 -0
  271. package/Tests/App/Dashboard/UserTimezoneInit.test.tsx +544 -0
  272. package/Tests/App/Dashboard/WorkflowVariableModals.test.tsx +1630 -0
  273. package/Tests/App/Dashboard/WorkflowVariableRoutes.test.tsx +603 -0
  274. package/Tests/App/Dashboard/WorkflowVariableTokenStatus.test.tsx +589 -0
  275. package/Tests/App/Dashboard/WorkflowVariableUtil.test.ts +1543 -0
  276. package/Tests/App/Dashboard/WorkflowVariableView.test.tsx +3227 -0
  277. package/Tests/App/Dashboard/WorkflowVariablesTable.test.tsx +1277 -395
  278. package/Tests/App/StatusPage/StatusPageOverviewMonitorGroupUptime.test.tsx +714 -0
  279. package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.NewYork.test.tsx +1009 -0
  280. package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.test.tsx +1092 -0
  281. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +5 -0
  282. package/Tests/Models/DatabaseModels/KubernetesClusterAiAccessColumns.test.ts +520 -0
  283. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +66 -2
  284. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
  285. package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
  286. package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
  287. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  288. package/Tests/Models/DatabaseModels/WorkspaceProjectAuthTokenAccessControl.test.ts +236 -0
  289. package/Tests/Models/IncidentEpisodePublicNoteNotifyColumnContract.test.ts +103 -0
  290. package/Tests/Models/IncidentPublicNoteNotifyColumnContract.test.ts +96 -0
  291. package/Tests/Models/ScheduledMaintenancePublicNoteNotifyColumnContract.test.ts +111 -0
  292. package/Tests/Server/API/AIInvestigationAPI.test.ts +976 -0
  293. package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +836 -0
  294. package/Tests/Server/API/CommonAPIAssertCanCreateTable.test.ts +565 -0
  295. package/Tests/Server/API/CommonAPIAssertCanReadTable.test.ts +282 -0
  296. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +1744 -0
  297. package/Tests/Server/API/LogHistogramAPI.test.ts +371 -0
  298. package/Tests/Server/API/MicrosoftTeamsLegacyWebhookRemoval.test.ts +125 -30
  299. package/Tests/Server/API/MicrosoftTeamsOAuthState.test.ts +1121 -0
  300. package/Tests/Server/API/MonitorUptimeSummaryAPI.test.ts +685 -0
  301. package/Tests/Server/API/SessionReplayAPI.test.ts +602 -1
  302. package/Tests/Server/API/SlackChannelCacheAPI.test.ts +358 -0
  303. package/Tests/Server/API/SlackOAuthState.test.ts +688 -0
  304. package/Tests/Server/API/StatusPageOverviewMonitorGroupUptime.test.ts +527 -0
  305. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +2 -0
  306. package/Tests/Server/API/StatusPageUptimeAPI.test.ts +427 -0
  307. package/Tests/Server/API/UserProjectsAPI.test.ts +4 -0
  308. package/Tests/Server/API/WorkflowVariableAPI.test.ts +404 -0
  309. package/Tests/Server/API/WorkspaceOAuthTestHelpers.ts +289 -0
  310. package/Tests/Server/API/WorkspaceSendTestNotificationRoutes.test.ts +2064 -0
  311. package/Tests/Server/Infrastructure/GlobalCache.test.ts +86 -0
  312. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  313. package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +589 -0
  314. package/Tests/Server/Infrastructure/Postgres/AddOAuth2WorkflowVariablesMigration.test.ts +254 -0
  315. package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
  316. package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
  317. package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
  318. package/Tests/Server/Middleware/BlockedUserMiddleware.test.ts +403 -0
  319. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +13 -0
  320. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +2 -0
  321. package/Tests/Server/Middleware/RemovedProjectMemberAuthorization.test.ts +469 -0
  322. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +77 -1
  323. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +211 -0
  324. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +358 -0
  325. package/Tests/Server/Middleware/UserAuthorization.test.ts +97 -0
  326. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +2 -0
  327. package/Tests/Server/Services/AccessTokenProjectUserGrant.test.ts +14 -2
  328. package/Tests/Server/Services/AccessTokenRemovedMemberAccess.test.ts +1044 -0
  329. package/Tests/Server/Services/AddOwnersIdempotency.test.ts +5 -0
  330. package/Tests/Server/Services/AlertEpisodeMemberCreatePermission.test.ts +139 -0
  331. package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +1361 -0
  332. package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +375 -0
  333. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +2384 -0
  334. package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
  335. package/Tests/Server/Services/FindOwnersProjectMembership.test.ts +267 -0
  336. package/Tests/Server/Services/InboundEmail/SendGridInboundProviderAddress.test.ts +90 -0
  337. package/Tests/Server/Services/IncidentEpisodeMemberCreatePermission.test.ts +143 -0
  338. package/Tests/Server/Services/IncidentEpisodePublicNoteNotifyDefault.test.ts +805 -0
  339. package/Tests/Server/Services/IncidentPublicNoteNotifyDefault.test.ts +724 -0
  340. package/Tests/Server/Services/IncidentRoleProjectMembership.test.ts +233 -0
  341. package/Tests/Server/Services/KubernetesClusterAiAccessAgentRunnerAssignments.test.ts +372 -0
  342. package/Tests/Server/Services/KubernetesClusterAiAccessBindingGuard.test.ts +1876 -0
  343. package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +620 -0
  344. package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +421 -0
  345. package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +3662 -0
  346. package/Tests/Server/Services/KubernetesClusterAiAccessSubjectClusters.test.ts +405 -0
  347. package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +975 -0
  348. package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +497 -0
  349. package/Tests/Server/Services/KubernetesClusterServiceDeleteSettlesRemediation.test.ts +328 -0
  350. package/Tests/Server/Services/LogAggregationService.test.ts +99 -0
  351. package/Tests/Server/Services/MonitorServiceIncomingEmailCustomAddress.test.ts +447 -0
  352. package/Tests/Server/Services/MonitorServiceProbeFlagSync.test.ts +1334 -0
  353. package/Tests/Server/Services/MonitorServiceProbeStatusGrouping.test.ts +1640 -0
  354. package/Tests/Server/Services/MonitorServiceRefreshCurrentStatus.test.ts +225 -0
  355. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +8 -8
  356. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +264 -1
  357. package/Tests/Server/Services/MonitorStatusTimelineMergedDowntime.test.ts +284 -0
  358. package/Tests/Server/Services/MonitorUptimeSummaryService.test.ts +1043 -0
  359. package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +5 -0
  360. package/Tests/Server/Services/OnCallUndeliverablePageOwnerMembership.test.ts +359 -0
  361. package/Tests/Server/Services/ProbeServiceDashboardLink.test.ts +191 -0
  362. package/Tests/Server/Services/ProjectOwnersProjectMembership.test.ts +221 -0
  363. package/Tests/Server/Services/RuleRun/IncidentAlertMaintenanceRuleEnginesRun.test.ts +5 -0
  364. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
  365. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupARun.test.ts +28 -0
  366. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +39 -1
  367. package/Tests/Server/Services/RunnerJobEnqueueAiCommandAgentRunner.test.ts +230 -0
  368. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +978 -0
  369. package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +866 -0
  370. package/Tests/Server/Services/RunnerJobSubmitResultRedaction.test.ts +322 -0
  371. package/Tests/Server/Services/RunnerJobSubmitResultUnstorableText.test.ts +357 -0
  372. package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +227 -0
  373. package/Tests/Server/Services/RunnerServiceAgentName.test.ts +581 -0
  374. package/Tests/Server/Services/ScheduledMaintenancePublicNoteNotifyDefault.test.ts +802 -0
  375. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +53 -0
  376. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1175 -0
  377. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
  378. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
  379. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
  380. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
  381. package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
  382. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +174 -0
  383. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
  384. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +1176 -1
  385. package/Tests/Server/Services/TeamMemberBillingSeatSync.test.ts +9 -0
  386. package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +18 -0
  387. package/Tests/Server/Services/TeamMemberProjectMembership.test.ts +255 -0
  388. package/Tests/Server/Services/TeamMemberRemovalRevokesProjectAccess.test.ts +600 -0
  389. package/Tests/Server/Services/TeamMemberResourceCleanup.test.ts +731 -0
  390. package/Tests/Server/Services/TeamMemberWorkspaceAccountCleanup.test.ts +164 -0
  391. package/Tests/Server/Services/TraceAggregationService.test.ts +64 -0
  392. package/Tests/Server/Services/UserServiceBlockedUser.test.ts +293 -0
  393. package/Tests/Server/Services/WorkflowVariableOAuthHooks.test.ts +1016 -0
  394. package/Tests/Server/Services/WorkflowVariableOAuthPostgres.test.ts +543 -0
  395. package/Tests/Server/Services/WorkflowVariableRenameUniqueness.test.ts +16 -5
  396. package/Tests/Server/Services/WorkspaceNotificationRuleNoteDelivery.test.ts +473 -0
  397. package/Tests/Server/Services/WorkspaceNotificationRuleSendTestNotification.test.ts +3690 -0
  398. package/Tests/Server/Services/WorkspaceProjectAuthTokenMiscDataSecrets.test.ts +374 -0
  399. package/Tests/Server/Services/WorkspaceProjectAuthTokenSlackChannelCache.test.ts +143 -0
  400. package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
  401. package/Tests/Server/Types/Database/Permissions/WorkflowVariableOAuthColumnPermission.test.ts +250 -0
  402. package/Tests/Server/Types/Database/QueryHelperJsonContains.test.ts +96 -0
  403. package/Tests/Server/Types/Markdown.test.ts +1035 -1
  404. package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
  405. package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
  406. package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +285 -0
  407. package/Tests/Server/Utils/AI/CodeFix/CodeFixAgentAuth.test.ts +159 -1
  408. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +752 -0
  409. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +1840 -0
  410. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +1067 -0
  411. package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +355 -0
  412. package/Tests/Server/Utils/AI/PostIncidentStatusUpdateTool.test.ts +496 -0
  413. package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +305 -0
  414. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +1365 -0
  415. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +639 -0
  416. package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +1585 -0
  417. package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +1065 -0
  418. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +2138 -1
  419. package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +1035 -0
  420. package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +517 -0
  421. package/Tests/Server/Utils/AI/ResourceTools.test.ts +27 -1
  422. package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
  423. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +1371 -24
  424. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorRollbackRace.test.ts +962 -0
  425. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +518 -0
  426. package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +939 -2
  427. package/Tests/Server/Utils/Database/ProjectScopedRelationReferences.test.ts +371 -0
  428. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +64 -0
  429. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
  430. package/Tests/Server/Utils/Monitor/DatabaseMetricObservationRemediation.test.ts +102 -0
  431. package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +362 -0
  432. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +405 -0
  433. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1156 -0
  434. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
  435. package/Tests/Server/Utils/Monitor/MonitorEmailAddressRedaction.test.ts +255 -0
  436. package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +347 -0
  437. package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +203 -0
  438. package/Tests/Server/Utils/Monitor/ProbeMonitorsNotification.test.ts +1147 -0
  439. package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
  440. package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +79 -0
  441. package/Tests/Server/Utils/ResourceFeed/ResourceFeedUtil.test.ts +21 -1
  442. package/Tests/Server/Utils/Rules/OwnerRuleAssignment.test.ts +155 -1
  443. package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
  444. package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
  445. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +288 -0
  446. package/Tests/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.test.ts +304 -0
  447. package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
  448. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +40 -3
  449. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
  450. package/Tests/Server/Utils/Workflow/OAuth2TokenClient.test.ts +702 -0
  451. package/Tests/Server/Utils/Workflow/OAuth2TokenClientHttpIntegration.test.ts +507 -0
  452. package/Tests/Server/Utils/Workflow/WorkflowVariableOAuthToken.test.ts +831 -0
  453. package/Tests/Server/Utils/Workspace/MicrosoftTeamsActionAuthorization.test.ts +63 -1
  454. package/Tests/Server/Utils/Workspace/MicrosoftTeamsAppAccessToken.test.ts +256 -0
  455. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +60 -0
  456. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChatActionAuthorization.test.ts +442 -0
  457. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +44 -2
  458. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +55 -0
  459. package/Tests/Server/Utils/Workspace/MicrosoftTeamsReactionNoteSync.test.ts +1522 -0
  460. package/Tests/Server/Utils/Workspace/MicrosoftTeamsServiceUrl.test.ts +130 -0
  461. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +4 -4
  462. package/Tests/Server/Utils/Workspace/Slack/SlackActionAuthorization.test.ts +691 -0
  463. package/Tests/Server/Utils/Workspace/Slack/SlackMessageByTimestamp.test.ts +253 -0
  464. package/Tests/Server/Utils/Workspace/Slack/SlackReactionNote.test.ts +574 -0
  465. package/Tests/Server/Utils/Workspace/WorkspaceActionAuthorization.test.ts +488 -0
  466. package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +861 -0
  467. package/Tests/Server/Utils/Workspace/WorkspaceMessageAuthor.test.ts +635 -0
  468. package/Tests/Server/Utils/Workspace/WorkspaceOAuthState.test.ts +548 -0
  469. package/Tests/Server/Utils/Workspace/WorkspaceReactionNote.test.ts +839 -0
  470. package/Tests/Server/Utils/Workspace/WorkspaceSendErrorMessage.test.ts +725 -0
  471. package/Tests/Types/API/Route.test.ts +56 -0
  472. package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
  473. package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +283 -9
  474. package/Tests/Types/DateBrowserLocalWallClock.test.ts +280 -0
  475. package/Tests/Types/DateLocalShortMonthNameFallback.test.ts +389 -0
  476. package/Tests/Types/DateUserTimezone.test.ts +177 -4
  477. package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +306 -0
  478. package/Tests/Types/Kubernetes/KubernetesClusterAiAccess.test.ts +283 -0
  479. package/Tests/Types/Kubernetes/KubernetesRunnerPostureWriteScope.test.ts +68 -0
  480. package/Tests/Types/Monitor/DatabaseMonitor/SqlServerPlatform.test.ts +144 -0
  481. package/Tests/Types/Monitor/MonitorStepExceptionMonitor.test.ts +160 -0
  482. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +53 -0
  483. package/Tests/Types/Runbook/RunbookStepType.test.ts +91 -16
  484. package/Tests/Types/Runner/RunnerLiveStatus.test.ts +14 -3
  485. package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +15 -0
  486. package/Tests/Types/StatusPage/PublicNoteSubscriberNotificationDefault.test.ts +1868 -0
  487. package/Tests/Types/Timezone.test.ts +5 -0
  488. package/Tests/Types/TimezoneAlias.test.ts +1034 -0
  489. package/Tests/Types/Workflow/JiraTemplateFixtures.ts +833 -0
  490. package/Tests/Types/Workflow/JiraTemplateScripts.test.ts +5414 -0
  491. package/Tests/Types/Workflow/JiraTemplateSimulation.test.ts +4803 -0
  492. package/Tests/Types/Workflow/JiraTemplates.test.ts +5429 -0
  493. package/Tests/Types/Workflow/Templates.test.ts +79 -4
  494. package/Tests/Types/Workflow/WorkflowVariableOAuth.test.ts +520 -0
  495. package/Tests/Types/Workspace/WorkspaceNoteReaction.test.ts +177 -0
  496. package/Tests/UI/Components/AttributesJSON/AttributesJSONView.test.tsx +390 -0
  497. package/Tests/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.test.tsx +566 -0
  498. package/Tests/UI/Components/AttributesJSON/JSONHighlight.test.ts +131 -0
  499. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +276 -1
  500. package/Tests/UI/Components/Calendar/Calendar.test.tsx +1611 -0
  501. package/Tests/UI/Components/Calendar/CalendarDayLayout.test.ts +1486 -0
  502. package/Tests/UI/Components/Calendar/CalendarDayLayoutDst.test.ts +632 -0
  503. package/Tests/UI/Components/Calendar/CalendarDst.test.tsx +388 -0
  504. package/Tests/UI/Components/Charts/ChartGroupPlotFloor.test.tsx +170 -0
  505. package/Tests/UI/Components/Charts/HistogramSelection.test.ts +282 -0
  506. package/Tests/UI/Components/CustomTimeRangeModal.test.tsx +6 -0
  507. package/Tests/UI/Components/CustomTimeRangeModalTimezoneTranslation.test.tsx +285 -0
  508. package/Tests/UI/Components/Dropdown.test.tsx +999 -2
  509. package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
  510. package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
  511. package/Tests/UI/Components/Forms/FormFieldCheckboxTranslation.test.tsx +216 -0
  512. package/Tests/UI/Components/Forms/FormFieldTimezoneDescriptionTranslation.test.tsx +461 -0
  513. package/Tests/UI/Components/Forms/IncidentEpisodePublicNoteNotifyPayload.test.tsx +641 -0
  514. package/Tests/UI/Components/Forms/IncidentPublicNoteNotifyPayload.test.tsx +346 -0
  515. package/Tests/UI/Components/Forms/ScheduledMaintenancePublicNoteNotifyPayload.test.tsx +493 -0
  516. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +911 -2
  517. package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.NewYork.test.tsx +730 -0
  518. package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.Tokyo.test.tsx +506 -0
  519. package/Tests/UI/Components/HistogramClickToZoom.test.tsx +619 -0
  520. package/Tests/UI/Components/Icon.test.tsx +26 -0
  521. package/Tests/UI/Components/LogDetailsPanelAttributesJSON.test.tsx +248 -0
  522. package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +47 -1
  523. package/Tests/UI/Components/LogsViewerSmallScreens.test.tsx +620 -0
  524. package/Tests/UI/Components/ModelPageModelChange.test.tsx +242 -3
  525. package/Tests/UI/Components/ModelTable/BaseModelTableDeleteConfirmation.test.tsx +521 -0
  526. package/Tests/UI/Components/MonitorGraphs/Uptime.test.tsx +406 -2
  527. package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +169 -2
  528. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  529. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +266 -0
  530. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerSmallScreens.test.tsx +439 -0
  531. package/Tests/UI/Components/TimezoneDropdownLegacyValues.test.tsx +704 -0
  532. package/Tests/UI/Components/UseHistogramZoom.test.tsx +89 -1
  533. package/Tests/UI/Components/UseLogsHistogram.test.tsx +175 -0
  534. package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
  535. package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
  536. package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +5 -5
  537. package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +28 -0
  538. package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +51 -0
  539. package/Tests/UI/Utils/Timezone.test.ts +747 -33
  540. package/Tests/UI/Workspace/SendTestNotificationButton.test.tsx +1854 -0
  541. package/Tests/UI/Workspace/WorkspaceCardsSendTestNotification.test.tsx +1864 -0
  542. package/Tests/Utils/AI/InvestigationReport.test.ts +435 -7
  543. package/Tests/Utils/AiRemediation/KubectlAllowlistValidatorParity.test.ts +1084 -0
  544. package/Tests/Utils/AiRemediation/KubectlOutputRedactor.test.ts +2531 -0
  545. package/Tests/Utils/AiRemediation/KubectlPolicy.test.ts +1895 -0
  546. package/Tests/Utils/AiRemediation/KubectlPolicyAllowlist.test.ts +428 -0
  547. package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +828 -0
  548. package/Tests/Utils/AiRemediation/KubectlPolicyCustomResourceScope.test.ts +573 -0
  549. package/Tests/Utils/AiRemediation/KubectlPolicyDenials.test.ts +1525 -0
  550. package/Tests/Utils/AiRemediation/KubectlPolicyExposeOverrides.test.ts +275 -0
  551. package/Tests/Utils/AiRemediation/KubectlPolicyNodePatch.test.ts +428 -0
  552. package/Tests/Utils/AiRemediation/KubectlPolicyObjectWords.test.ts +195 -0
  553. package/Tests/Utils/AiRemediation/KubectlPolicyPatchParents.test.ts +637 -0
  554. package/Tests/Utils/AiRemediation/KubectlPolicyPodSecurityBaseline.test.ts +322 -0
  555. package/Tests/Utils/AiRemediation/KubectlPolicySafeWriteScope.test.ts +1026 -0
  556. package/Tests/Utils/AiRemediation/KubectlWaitBudget.test.ts +267 -0
  557. package/Tests/Utils/AiRemediation/KubectlWriteScope.test.ts +390 -0
  558. package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +777 -0
  559. package/Tests/Utils/AiRemediation/KubectlWriteScopeClusterScoped.test.ts +613 -0
  560. package/Tests/Utils/AiRemediation/KubectlWriteScopeEntryPoint.test.ts +576 -0
  561. package/Tests/Utils/AiRemediation/KubectlWriteScopeKubectlSpellings.test.ts +752 -0
  562. package/Tests/Utils/AiRemediation/KubectlWriteScopeObjectWords.test.ts +358 -0
  563. package/Tests/Utils/AiRemediation/KubectlWriteScopeOverrides.test.ts +293 -0
  564. package/Tests/Utils/AiRemediation/KubectlWriteScopeParityCases.ts +598 -0
  565. package/Tests/Utils/AiRemediation/KubectlWriteScopePolicyParity.test.ts +403 -0
  566. package/Tests/Utils/Dashboard/DashboardClockComponent.test.ts +154 -5
  567. package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
  568. package/Tests/Utils/Monitor/IncomingEmailMonitorAddress.test.ts +478 -0
  569. package/Tests/Utils/Monitor/MonitorCheckScheduleUtil.test.ts +646 -0
  570. package/Tests/Utils/Monitor/MonitorOverviewCriteriaUtil.test.ts +292 -0
  571. package/Tests/Utils/Monitor/MonitorOverviewFamily.test.ts +274 -0
  572. package/Tests/Utils/Monitor/MonitorOverviewPresentationUtil.test.ts +3100 -0
  573. package/Tests/Utils/Monitor/MonitorOverviewProbeUtil.test.ts +1412 -0
  574. package/Tests/Utils/Monitor/MonitorOverviewTargetUtil.test.ts +374 -0
  575. package/Tests/Utils/Monitor/MonitorStatusHistoryUtil.test.ts +332 -0
  576. package/Tests/Utils/Monitor/MonitorUptimeSummaryUtil.test.ts +946 -0
  577. package/Tests/Utils/Rum/SessionIdentity.test.ts +94 -0
  578. package/Tests/Utils/Rum/SessionReplayWafCompatibility.test.ts +840 -0
  579. package/Tests/Utils/Rum/SessionReplayWireEncoding.test.ts +208 -0
  580. package/Tests/Utils/Rum/UserFlow.test.ts +1010 -0
  581. package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
  582. package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
  583. package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
  584. package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
  585. package/Tests/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.test.ts +217 -0
  586. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +1272 -1
  587. package/Tests/Utils/StatusPage/UptimeDailyAggregateTotals.test.ts +298 -0
  588. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +649 -1
  589. package/Tests/Utils/StatusPage/UptimeDailyAggregateWindow.test.ts +314 -0
  590. package/Tests/Utils/Telemetry/AttributesJSON.test.ts +454 -0
  591. package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +418 -2
  592. package/Tests/Utils/Uptime/DayUptimeGraphUtilMidnightDst.test.ts +160 -0
  593. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Auckland.test.ts +45 -0
  594. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Kolkata.test.ts +40 -0
  595. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.London.test.ts +147 -0
  596. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.NewYork.test.ts +48 -0
  597. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Tokyo.test.ts +39 -0
  598. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezoneCases.ts +1015 -0
  599. package/Tests/Utils/Uptime/UptimeUtil.test.ts +75 -0
  600. package/Tests/Utils/Uptime/UptimeUtilChronologicalOrder.test.ts +1279 -0
  601. package/Types/API/Route.ts +19 -2
  602. package/Types/API/URL.ts +26 -2
  603. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +203 -5
  604. package/Types/Date.ts +121 -7
  605. package/Types/Email/EmailMessage.ts +8 -0
  606. package/Types/Email/EmailTemplateType.ts +1 -0
  607. package/Types/Exception/ExceptionMessages.ts +1 -0
  608. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +488 -0
  609. package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +54 -0
  610. package/Types/Kubernetes/KubernetesClusterAiAccessToolNames.ts +17 -0
  611. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +9 -0
  612. package/Types/Monitor/DatabaseMonitor/SqlServerPlatform.ts +117 -0
  613. package/Types/Monitor/KubernetesAlertTemplates.ts +6 -5
  614. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
  615. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
  616. package/Types/Monitor/MonitorStepExceptionMonitor.ts +56 -0
  617. package/Types/Monitor/MonitorUptimeSummary.ts +113 -0
  618. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +11 -0
  619. package/Types/Permission.ts +90 -0
  620. package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
  621. package/Types/Rules/RuleRun.ts +4 -0
  622. package/Types/Rum/SessionReplay.ts +55 -2
  623. package/Types/Rum/SessionReplayApi.ts +44 -1
  624. package/Types/Rum/UserFlow.ts +187 -0
  625. package/Types/Runbook/RunbookStepType.ts +10 -0
  626. package/Types/Runbook/RunnerJobOrigin.ts +15 -0
  627. package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +6 -2
  628. package/Types/StatusPage/MergedDowntimeTotals.ts +17 -0
  629. package/Types/StatusPage/PublicNoteSubscriberNotificationDefault.ts +148 -0
  630. package/Types/StatusPage/UptimeDailyAggregate.ts +15 -0
  631. package/Types/Telemetry/TelemetryIngestSurface.ts +9 -0
  632. package/Types/Timezone.ts +5 -0
  633. package/Types/TimezoneAlias.ts +385 -0
  634. package/Types/Workflow/Templates.ts +3041 -2
  635. package/Types/Workflow/WorkflowVariableOAuth.ts +476 -0
  636. package/Types/Workspace/WorkspaceNoteReaction.ts +132 -0
  637. package/Typings/Index.d.ts +24 -0
  638. package/UI/Components/AttributesJSON/AttributesJSONPreferences.ts +175 -0
  639. package/UI/Components/AttributesJSON/AttributesJSONView.tsx +138 -0
  640. package/UI/Components/AttributesJSON/AttributesViewToggle.tsx +79 -0
  641. package/UI/Components/AttributesJSON/BracesGlyph.tsx +30 -0
  642. package/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.tsx +491 -0
  643. package/UI/Components/AttributesJSON/JSONHighlight.ts +77 -0
  644. package/UI/Components/Calendar/Calendar.css +83 -0
  645. package/UI/Components/Calendar/Calendar.tsx +136 -7
  646. package/UI/Components/Calendar/CalendarDayLayout.ts +236 -0
  647. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +23 -1
  648. package/UI/Components/Charts/Utils/HistogramSelection.ts +117 -0
  649. package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +269 -0
  650. package/UI/Components/Charts/Utils/useHistogramZoom.ts +26 -2
  651. package/UI/Components/Date/CustomTimeRangeModal.tsx +26 -3
  652. package/UI/Components/Dropdown/Dropdown.tsx +58 -9
  653. package/UI/Components/Feed/FeedOptions.ts +427 -0
  654. package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
  655. package/UI/Components/Feed/useFeedItems.ts +28 -9
  656. package/UI/Components/Feed/useFeedOptions.ts +225 -0
  657. package/UI/Components/Forms/Fields/FormField.tsx +49 -14
  658. package/UI/Components/Graphs/DayUptimeGraph.tsx +166 -25
  659. package/UI/Components/Graphs/UptimeBarTooltip.tsx +10 -2
  660. package/UI/Components/Graphs/UptimeDaySummary.tsx +8 -0
  661. package/UI/Components/Icon/Icon.tsx +1 -1
  662. package/UI/Components/LogsViewer/LogsViewer.tsx +52 -5
  663. package/UI/Components/LogsViewer/components/ColumnSelector.tsx +13 -2
  664. package/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.tsx +13 -1
  665. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +91 -76
  666. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +15 -1
  667. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +28 -106
  668. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +54 -6
  669. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +8 -2
  670. package/UI/Components/LogsViewer/useLogsHistogram.ts +39 -6
  671. package/UI/Components/ModelTable/BaseModelTable.tsx +66 -14
  672. package/UI/Components/MonitorGraphs/Uptime.tsx +12 -0
  673. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +10 -2
  674. package/UI/Components/Page/ModelPage.tsx +59 -3
  675. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +69 -5
  676. package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +12 -1
  677. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +15 -1
  678. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +36 -104
  679. package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +9 -1
  680. package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +19 -1
  681. package/UI/Utils/Timezone.ts +69 -28
  682. package/Utils/AI/InvestigationReport.ts +195 -25
  683. package/Utils/AiRemediation/KubectlOutputRedactor.ts +1724 -0
  684. package/Utils/AiRemediation/KubectlPolicy.ts +4136 -0
  685. package/Utils/AiRemediation/KubectlWaitBudget.ts +156 -0
  686. package/Utils/AiRemediation/KubectlWriteScope.ts +1964 -0
  687. package/Utils/Dashboard/Components/DashboardClockComponent.ts +7 -6
  688. package/Utils/LabelRuleImportExport.ts +27 -9
  689. package/Utils/Monitor/IncomingEmailMonitorAddress.ts +292 -0
  690. package/Utils/Monitor/MetricValueFormatter.ts +2 -2
  691. package/Utils/Monitor/MonitorCheckScheduleUtil.ts +654 -0
  692. package/Utils/Monitor/MonitorOverviewCriteriaUtil.ts +188 -0
  693. package/Utils/Monitor/MonitorOverviewFamily.ts +263 -0
  694. package/Utils/Monitor/MonitorOverviewPresentationUtil.ts +1958 -0
  695. package/Utils/Monitor/MonitorOverviewProbeUtil.ts +979 -0
  696. package/Utils/Monitor/MonitorOverviewTargetUtil.ts +299 -0
  697. package/Utils/Monitor/MonitorStatusHistoryUtil.ts +201 -0
  698. package/Utils/Monitor/MonitorUptimeSummaryUtil.ts +638 -0
  699. package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
  700. package/Utils/Rum/SessionIdentity.ts +44 -0
  701. package/Utils/Rum/SessionReplayWireEncoding.ts +137 -0
  702. package/Utils/Rum/UserFlow.ts +1527 -0
  703. package/Utils/Slo/SloDuration.ts +22 -6
  704. package/Utils/Slo/SloHealth.ts +8 -7
  705. package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
  706. package/Utils/Slo/SloOverviewText.ts +33 -0
  707. package/Utils/Slo/SloProjection.ts +4 -3
  708. package/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.ts +107 -0
  709. package/Utils/StatusPage/ResourceUptime.ts +99 -0
  710. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +197 -0
  711. package/Utils/Telemetry/AttributesJSON.ts +367 -0
  712. package/Utils/Uptime/DayUptimeGraphUtil.ts +165 -0
  713. package/Utils/Uptime/UptimeUtil.ts +122 -38
  714. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js +8 -1
  715. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js.map +1 -1
  716. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
  717. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
  718. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js +8 -1
  719. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js.map +1 -1
  720. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +10 -3
  721. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  722. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +10 -3
  723. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  724. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  725. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  726. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +434 -0
  727. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  728. package/build/dist/Models/DatabaseModels/Monitor.js +49 -0
  729. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  730. package/build/dist/Models/DatabaseModels/Runner.js +4 -4
  731. package/build/dist/Models/DatabaseModels/Runner.js.map +1 -1
  732. package/build/dist/Models/DatabaseModels/RunnerJob.js +66 -0
  733. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  734. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +11 -3
  735. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  736. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
  737. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
  738. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
  739. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
  740. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
  741. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
  742. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
  743. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
  744. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +487 -3
  745. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  746. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js +64 -16
  747. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  748. package/build/dist/Server/API/AIInvestigationAPI.js +205 -0
  749. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  750. package/build/dist/Server/API/AutoRemediationAPI.js +115 -2
  751. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  752. package/build/dist/Server/API/CommonAPI.js +49 -0
  753. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  754. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +564 -0
  755. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -0
  756. package/build/dist/Server/API/MicrosoftTeamsAPI.js +465 -176
  757. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  758. package/build/dist/Server/API/MonitorAPI.js +107 -1
  759. package/build/dist/Server/API/MonitorAPI.js.map +1 -1
  760. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +5 -16
  761. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -1
  762. package/build/dist/Server/API/SlackAPI.js +322 -78
  763. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  764. package/build/dist/Server/API/StatusPageAPI.js +123 -17
  765. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  766. package/build/dist/Server/API/TelemetryAPI.js +144 -5
  767. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  768. package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js +1 -0
  769. package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js.map +1 -1
  770. package/build/dist/Server/API/WorkflowVariableAPI.js +109 -0
  771. package/build/dist/Server/API/WorkflowVariableAPI.js.map +1 -0
  772. package/build/dist/Server/Infrastructure/GlobalCache.js +29 -0
  773. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  774. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
  775. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
  776. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
  777. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
  778. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js +38 -0
  779. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js.map +1 -0
  780. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js +54 -0
  781. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js.map +1 -0
  782. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js +14 -0
  783. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js.map +1 -0
  784. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js +12 -0
  785. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js.map +1 -0
  786. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js +32 -0
  787. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js.map +1 -0
  788. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
  789. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  790. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +21 -0
  791. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  792. package/build/dist/Server/Middleware/TelemetryIngest.js +32 -2
  793. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  794. package/build/dist/Server/Middleware/UserAuthorization.js +39 -6
  795. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  796. package/build/dist/Server/Services/AIAgentService.js +1 -0
  797. package/build/dist/Server/Services/AIAgentService.js.map +1 -1
  798. package/build/dist/Server/Services/AccessTokenService.js +87 -42
  799. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  800. package/build/dist/Server/Services/AlertEpisodeMemberService.js +4 -0
  801. package/build/dist/Server/Services/AlertEpisodeMemberService.js.map +1 -1
  802. package/build/dist/Server/Services/AlertEpisodeService.js +12 -1
  803. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  804. package/build/dist/Server/Services/AlertService.js +110 -23
  805. package/build/dist/Server/Services/AlertService.js.map +1 -1
  806. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +716 -30
  807. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  808. package/build/dist/Server/Services/AutoRemediationRuleService.js +100 -0
  809. package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
  810. package/build/dist/Server/Services/BillingService.js +1 -0
  811. package/build/dist/Server/Services/BillingService.js.map +1 -1
  812. package/build/dist/Server/Services/DatabaseService.js +7 -0
  813. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  814. package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js +11 -16
  815. package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js.map +1 -1
  816. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +4 -0
  817. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  818. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +48 -0
  819. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  820. package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js +21 -0
  821. package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js.map +1 -1
  822. package/build/dist/Server/Services/IncidentEpisodeService.js +12 -1
  823. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  824. package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -0
  825. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  826. package/build/dist/Server/Services/IncidentMemberService.js +14 -0
  827. package/build/dist/Server/Services/IncidentMemberService.js.map +1 -1
  828. package/build/dist/Server/Services/IncidentPublicNoteService.js +48 -0
  829. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  830. package/build/dist/Server/Services/IncidentService.js +99 -21
  831. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  832. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  833. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  834. package/build/dist/Server/Services/IncidentTemplateService.js +68 -4
  835. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  836. package/build/dist/Server/Services/Index.js +4 -0
  837. package/build/dist/Server/Services/Index.js.map +1 -1
  838. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +1470 -0
  839. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -0
  840. package/build/dist/Server/Services/KubernetesClusterService.js +1097 -0
  841. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  842. package/build/dist/Server/Services/LogAggregationService.js +14 -6
  843. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  844. package/build/dist/Server/Services/MonitorService.js +490 -50
  845. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  846. package/build/dist/Server/Services/MonitorStatusTimelineService.js +540 -3
  847. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  848. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -0
  849. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  850. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -0
  851. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  852. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -0
  853. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  854. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +3 -0
  855. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  856. package/build/dist/Server/Services/OnCallNotificationAlertingService.js +29 -7
  857. package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -1
  858. package/build/dist/Server/Services/OnCallSetupReminderService.js +1 -0
  859. package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -1
  860. package/build/dist/Server/Services/ProbeService.js +7 -1
  861. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  862. package/build/dist/Server/Services/ProjectService.js +11 -1
  863. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  864. package/build/dist/Server/Services/RunbookCredentialService.js +24 -0
  865. package/build/dist/Server/Services/RunbookCredentialService.js.map +1 -1
  866. package/build/dist/Server/Services/RunbookSecretService.js +44 -0
  867. package/build/dist/Server/Services/RunbookSecretService.js.map +1 -1
  868. package/build/dist/Server/Services/RunnerJobService.js +641 -21
  869. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  870. package/build/dist/Server/Services/RunnerService.js +344 -5
  871. package/build/dist/Server/Services/RunnerService.js.map +1 -1
  872. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +48 -0
  873. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  874. package/build/dist/Server/Services/ScheduledMaintenanceService.js +102 -20
  875. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  876. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +67 -4
  877. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  878. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
  879. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
  880. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
  881. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
  882. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
  883. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
  884. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
  885. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
  886. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
  887. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
  888. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
  889. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
  890. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +33 -1
  891. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  892. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -0
  893. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  894. package/build/dist/Server/Services/StatusPageService.js +230 -32
  895. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  896. package/build/dist/Server/Services/StatusPageSubscriberService.js +4 -0
  897. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  898. package/build/dist/Server/Services/TeamMemberService.js +270 -11
  899. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  900. package/build/dist/Server/Services/TraceAggregationService.js +10 -6
  901. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  902. package/build/dist/Server/Services/UserEmailService.js +1 -0
  903. package/build/dist/Server/Services/UserEmailService.js.map +1 -1
  904. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1 -0
  905. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  906. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +1 -0
  907. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  908. package/build/dist/Server/Services/UserNotificationRuleService.js +4 -0
  909. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  910. package/build/dist/Server/Services/UserService.js +107 -1
  911. package/build/dist/Server/Services/UserService.js.map +1 -1
  912. package/build/dist/Server/Services/WorkflowVariableService.js +396 -7
  913. package/build/dist/Server/Services/WorkflowVariableService.js.map +1 -1
  914. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +463 -7
  915. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  916. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +144 -2
  917. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  918. package/build/dist/Server/Types/Database/QueryHelper.js +20 -0
  919. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  920. package/build/dist/Server/Types/Markdown.js +394 -27
  921. package/build/dist/Server/Types/Markdown.js.map +1 -1
  922. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
  923. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
  924. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +123 -0
  925. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -0
  926. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +344 -0
  927. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -0
  928. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +587 -0
  929. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -0
  930. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js +18 -2
  931. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js.map +1 -1
  932. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1380 -239
  933. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  934. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +1099 -68
  935. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  936. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +88 -6
  937. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  938. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +45 -11
  939. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  940. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +41 -11
  941. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  942. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js +11 -4
  943. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -1
  944. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +4 -2
  945. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
  946. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
  947. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
  948. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +997 -141
  949. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  950. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +299 -4
  951. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
  952. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +120 -0
  953. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -0
  954. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +160 -1
  955. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  956. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +1 -0
  957. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
  958. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +22 -51
  959. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -1
  960. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
  961. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
  962. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +59 -12
  963. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  964. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +139 -109
  965. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  966. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +5 -1
  967. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  968. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +84 -22
  969. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  970. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +70 -5
  971. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -1
  972. package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js +249 -0
  973. package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js.map +1 -0
  974. package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
  975. package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
  976. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1 -0
  977. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -1
  978. package/build/dist/Server/Utils/PushNotificationUtil.js +27 -0
  979. package/build/dist/Server/Utils/PushNotificationUtil.js.map +1 -1
  980. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +26 -3
  981. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -1
  982. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
  983. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  984. package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js +38 -3
  985. package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js.map +1 -1
  986. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +143 -23
  987. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  988. package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js +406 -0
  989. package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js.map +1 -0
  990. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
  991. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
  992. package/build/dist/Server/Utils/StartServer.js +4 -3
  993. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  994. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +382 -0
  995. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -0
  996. package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js +1 -0
  997. package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js.map +1 -1
  998. package/build/dist/Server/Utils/UserPermission/UserPermission.js +10 -0
  999. package/build/dist/Server/Utils/UserPermission/UserPermission.js.map +1 -1
  1000. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +447 -0
  1001. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -0
  1002. package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js +202 -0
  1003. package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js.map +1 -0
  1004. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +39 -1
  1005. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
  1006. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +44 -4
  1007. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
  1008. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +150 -191
  1009. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  1010. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +44 -4
  1011. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  1012. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js +39 -17
  1013. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js.map +1 -1
  1014. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +151 -145
  1015. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
  1016. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +221 -127
  1017. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  1018. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js +91 -0
  1019. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js.map +1 -0
  1020. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js +673 -0
  1021. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js.map +1 -0
  1022. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +3 -9
  1023. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
  1024. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +65 -166
  1025. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -1
  1026. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js +63 -157
  1027. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js.map +1 -1
  1028. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +23 -3
  1029. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
  1030. package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js +92 -0
  1031. package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js.map +1 -0
  1032. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +81 -210
  1033. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
  1034. package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js +68 -138
  1035. package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js.map +1 -1
  1036. package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js +240 -0
  1037. package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js.map +1 -0
  1038. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +85 -212
  1039. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -1
  1040. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +60 -17
  1041. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  1042. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
  1043. package/build/dist/Server/Utils/Workspace/Workspace.js +134 -41
  1044. package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
  1045. package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js +197 -0
  1046. package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js.map +1 -0
  1047. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +32 -0
  1048. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  1049. package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js +199 -0
  1050. package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js.map +1 -0
  1051. package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js +91 -0
  1052. package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js.map +1 -0
  1053. package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js +450 -0
  1054. package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js.map +1 -0
  1055. package/build/dist/Types/API/Route.js +18 -2
  1056. package/build/dist/Types/API/Route.js.map +1 -1
  1057. package/build/dist/Types/API/URL.js +23 -2
  1058. package/build/dist/Types/API/URL.js.map +1 -1
  1059. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +103 -5
  1060. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  1061. package/build/dist/Types/Date.js +97 -7
  1062. package/build/dist/Types/Date.js.map +1 -1
  1063. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  1064. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  1065. package/build/dist/Types/Exception/ExceptionMessages.js +1 -0
  1066. package/build/dist/Types/Exception/ExceptionMessages.js.map +1 -1
  1067. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +245 -0
  1068. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -0
  1069. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +49 -0
  1070. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -0
  1071. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js +16 -0
  1072. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js.map +1 -0
  1073. package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js +104 -0
  1074. package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js.map +1 -0
  1075. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +6 -5
  1076. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  1077. package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js +32 -0
  1078. package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js.map +1 -1
  1079. package/build/dist/Types/Monitor/MonitorUptimeSummary.js +52 -0
  1080. package/build/dist/Types/Monitor/MonitorUptimeSummary.js.map +1 -0
  1081. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +9 -1
  1082. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  1083. package/build/dist/Types/Permission.js +84 -0
  1084. package/build/dist/Types/Permission.js.map +1 -1
  1085. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -0
  1086. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  1087. package/build/dist/Types/Rules/RuleRun.js +4 -0
  1088. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  1089. package/build/dist/Types/Rum/SessionReplay.js +52 -2
  1090. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  1091. package/build/dist/Types/Rum/SessionReplayApi.js +11 -0
  1092. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
  1093. package/build/dist/Types/Rum/UserFlow.js +115 -0
  1094. package/build/dist/Types/Rum/UserFlow.js.map +1 -0
  1095. package/build/dist/Types/Runbook/RunbookStepType.js +10 -0
  1096. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  1097. package/build/dist/Types/Runbook/RunnerJobOrigin.js +14 -0
  1098. package/build/dist/Types/Runbook/RunnerJobOrigin.js.map +1 -1
  1099. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +2 -2
  1100. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -1
  1101. package/build/dist/Types/StatusPage/MergedDowntimeTotals.js +2 -0
  1102. package/build/dist/Types/StatusPage/MergedDowntimeTotals.js.map +1 -0
  1103. package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js +65 -0
  1104. package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js.map +1 -0
  1105. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +8 -0
  1106. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  1107. package/build/dist/Types/Timezone.js +5 -0
  1108. package/build/dist/Types/Timezone.js.map +1 -1
  1109. package/build/dist/Types/TimezoneAlias.js +340 -0
  1110. package/build/dist/Types/TimezoneAlias.js.map +1 -0
  1111. package/build/dist/Types/Workflow/Templates.js +2694 -2
  1112. package/build/dist/Types/Workflow/Templates.js.map +1 -1
  1113. package/build/dist/Types/Workflow/WorkflowVariableOAuth.js +314 -0
  1114. package/build/dist/Types/Workflow/WorkflowVariableOAuth.js.map +1 -0
  1115. package/build/dist/Types/Workspace/WorkspaceNoteReaction.js +98 -0
  1116. package/build/dist/Types/Workspace/WorkspaceNoteReaction.js.map +1 -0
  1117. package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js +95 -0
  1118. package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js.map +1 -0
  1119. package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js +44 -0
  1120. package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js.map +1 -0
  1121. package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js +27 -0
  1122. package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js.map +1 -0
  1123. package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js +9 -0
  1124. package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js.map +1 -0
  1125. package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js +260 -0
  1126. package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js.map +1 -0
  1127. package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js +56 -0
  1128. package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js.map +1 -0
  1129. package/build/dist/UI/Components/Calendar/Calendar.js +94 -7
  1130. package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
  1131. package/build/dist/UI/Components/Calendar/CalendarDayLayout.js +136 -0
  1132. package/build/dist/UI/Components/Calendar/CalendarDayLayout.js.map +1 -0
  1133. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +1 -1
  1134. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  1135. package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js +72 -0
  1136. package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js.map +1 -0
  1137. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +178 -0
  1138. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -0
  1139. package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js +13 -1
  1140. package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js.map +1 -1
  1141. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js +20 -4
  1142. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js.map +1 -1
  1143. package/build/dist/UI/Components/Dropdown/Dropdown.js +33 -9
  1144. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  1145. package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
  1146. package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
  1147. package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
  1148. package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
  1149. package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
  1150. package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
  1151. package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
  1152. package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
  1153. package/build/dist/UI/Components/Forms/Fields/FormField.js +36 -13
  1154. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  1155. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +117 -11
  1156. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  1157. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -1
  1158. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  1159. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -1
  1160. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  1161. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  1162. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +36 -8
  1163. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  1164. package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js +10 -2
  1165. package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js.map +1 -1
  1166. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js +9 -1
  1167. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js.map +1 -1
  1168. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +16 -15
  1169. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  1170. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
  1171. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  1172. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +14 -74
  1173. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  1174. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +22 -5
  1175. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  1176. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +9 -2
  1177. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  1178. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +16 -5
  1179. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -1
  1180. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +23 -8
  1181. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1182. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +7 -1
  1183. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  1184. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +5 -1
  1185. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  1186. package/build/dist/UI/Components/Page/ModelPage.js +37 -3
  1187. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  1188. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +27 -6
  1189. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1190. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +7 -1
  1191. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
  1192. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
  1193. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  1194. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +17 -77
  1195. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  1196. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +10 -1
  1197. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -1
  1198. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +15 -1
  1199. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -1
  1200. package/build/dist/UI/Utils/Timezone.js +52 -17
  1201. package/build/dist/UI/Utils/Timezone.js.map +1 -1
  1202. package/build/dist/Utils/AI/InvestigationReport.js +116 -21
  1203. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
  1204. package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js +1209 -0
  1205. package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js.map +1 -0
  1206. package/build/dist/Utils/AiRemediation/KubectlPolicy.js +2973 -0
  1207. package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -0
  1208. package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js +99 -0
  1209. package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js.map +1 -0
  1210. package/build/dist/Utils/AiRemediation/KubectlWriteScope.js +1429 -0
  1211. package/build/dist/Utils/AiRemediation/KubectlWriteScope.js.map +1 -0
  1212. package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js +7 -6
  1213. package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js.map +1 -1
  1214. package/build/dist/Utils/LabelRuleImportExport.js +22 -6
  1215. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  1216. package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js +214 -0
  1217. package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js.map +1 -0
  1218. package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
  1219. package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js +471 -0
  1220. package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js.map +1 -0
  1221. package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js +107 -0
  1222. package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js.map +1 -0
  1223. package/build/dist/Utils/Monitor/MonitorOverviewFamily.js +191 -0
  1224. package/build/dist/Utils/Monitor/MonitorOverviewFamily.js.map +1 -0
  1225. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js +1259 -0
  1226. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js.map +1 -0
  1227. package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js +593 -0
  1228. package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js.map +1 -0
  1229. package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js +195 -0
  1230. package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js.map +1 -0
  1231. package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js +127 -0
  1232. package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js.map +1 -0
  1233. package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js +464 -0
  1234. package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js.map +1 -0
  1235. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
  1236. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
  1237. package/build/dist/Utils/Rum/SessionIdentity.js +31 -1
  1238. package/build/dist/Utils/Rum/SessionIdentity.js.map +1 -1
  1239. package/build/dist/Utils/Rum/SessionReplayWireEncoding.js +128 -0
  1240. package/build/dist/Utils/Rum/SessionReplayWireEncoding.js.map +1 -0
  1241. package/build/dist/Utils/Rum/UserFlow.js +941 -0
  1242. package/build/dist/Utils/Rum/UserFlow.js.map +1 -0
  1243. package/build/dist/Utils/Slo/SloDuration.js +13 -5
  1244. package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
  1245. package/build/dist/Utils/Slo/SloHealth.js +8 -7
  1246. package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
  1247. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
  1248. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
  1249. package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
  1250. package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
  1251. package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
  1252. package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js +82 -0
  1253. package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js.map +1 -0
  1254. package/build/dist/Utils/StatusPage/ResourceUptime.js +46 -0
  1255. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  1256. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  1257. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -1
  1258. package/build/dist/Utils/Telemetry/AttributesJSON.js +245 -0
  1259. package/build/dist/Utils/Telemetry/AttributesJSON.js.map +1 -0
  1260. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +103 -0
  1261. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -1
  1262. package/build/dist/Utils/Uptime/UptimeUtil.js +91 -27
  1263. package/build/dist/Utils/Uptime/UptimeUtil.js.map +1 -1
  1264. package/jest.config.json +2 -1
  1265. package/package.json +2 -1
  1266. package/tsconfig.tests.json +36 -0
  1267. package/Tests/UI/Components/EmptyState/EmptyStateGuideLinks.test.tsx +0 -337
  1268. package/UI/Components/EmptyState/EmptyStateGuideLinks.tsx +0 -124
  1269. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js +0 -47
  1270. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js.map +0 -1
@@ -0,0 +1,2199 @@
1
+ /** @timezone UTC */
2
+
3
+ import { act, cleanup, renderHook } from "@testing-library/react";
4
+ import useMonitorOverviewData, {
5
+ MONITOR_OVERVIEW_ACCESS_REASONS,
6
+ MONITOR_OVERVIEW_EVALUATION_RETRY_POLLS,
7
+ MONITOR_OVERVIEW_HEAVY_PROBE_RELOAD_MS,
8
+ MONITOR_OVERVIEW_NOT_FOUND_MESSAGE,
9
+ MONITOR_OVERVIEW_PROBE_RESULTS_UNREADABLE_MESSAGE,
10
+ MONITOR_OVERVIEW_REFRESH_INTERVAL_MS,
11
+ MONITOR_OVERVIEW_SLOW_FETCH_MESSAGE,
12
+ MONITOR_OVERVIEW_SLOW_FETCH_MS,
13
+ MONITOR_OVERVIEW_STALLED_FETCH_MS,
14
+ UseMonitorOverviewDataResult,
15
+ getSettledClaimCutoff,
16
+ isEvaluationCaughtUp,
17
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/Overview/useMonitorOverviewData";
18
+ import {
19
+ MONITOR_OVERVIEW_BASE_SELECT,
20
+ MONITOR_OVERVIEW_PROBE_FULL_SELECT,
21
+ MONITOR_OVERVIEW_PROBE_LIGHT_SELECT,
22
+ MONITOR_OVERVIEW_STATUS_ROW_LIMIT,
23
+ MONITOR_OVERVIEW_STATUS_ROW_SELECT,
24
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/Overview/MonitorOverviewSelect";
25
+ import MonitorLog from "../../../Models/AnalyticsModels/MonitorLog";
26
+ import Monitor from "../../../Models/DatabaseModels/Monitor";
27
+ import MonitorProbe, {
28
+ MonitorStepProbeResponse,
29
+ } from "../../../Models/DatabaseModels/MonitorProbe";
30
+ import MonitorStatus from "../../../Models/DatabaseModels/MonitorStatus";
31
+ import MonitorStatusTimeline from "../../../Models/DatabaseModels/MonitorStatusTimeline";
32
+ import Probe, {
33
+ ProbeConnectionStatus,
34
+ } from "../../../Models/DatabaseModels/Probe";
35
+ import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
36
+ import HTTPResponse from "../../../Types/API/HTTPResponse";
37
+ import URL from "../../../Types/API/URL";
38
+ import SortOrder from "../../../Types/BaseDatabase/SortOrder";
39
+ import Color from "../../../Types/Color";
40
+ import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
41
+ import Dictionary from "../../../Types/Dictionary";
42
+ import { JSONObject } from "../../../Types/JSON";
43
+ import MonitorSteps from "../../../Types/Monitor/MonitorSteps";
44
+ import MonitorType from "../../../Types/Monitor/MonitorType";
45
+ import ObjectID from "../../../Types/ObjectID";
46
+ import Permission from "../../../Types/Permission";
47
+ import API from "../../../UI/Utils/API/API";
48
+ import AnalyticsModelAPI from "../../../UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI";
49
+ import ModelAPI from "../../../UI/Utils/ModelAPI/ModelAPI";
50
+ import PermissionUtil from "../../../UI/Utils/Permission";
51
+ import ProjectUtil from "../../../UI/Utils/Project";
52
+
53
+ /*
54
+ * useMonitorOverviewData owns every read the monitor overview makes of the
55
+ * monitor itself, and its one poll. The tests count requests, because that
56
+ * is what the redesign changed:
57
+ * - refresh-status fires once per monitor and is never awaited or polled;
58
+ * - the Monitor row, the probe rows and the newest status rows start
59
+ * together, and only the Monitor row can fail the page;
60
+ * - polls read probes without their (screenshot-heavy) results unless a
61
+ * probe has claimed a newer check, and synthetic results are capped;
62
+ * - the evaluation log is re-read only when a new signal arrived;
63
+ * - a tick never cancels a load still in flight, and a load that is slow
64
+ * to land says so;
65
+ * - a slow or stale response never overwrites newer data or leaks one
66
+ * monitor's data onto another.
67
+ */
68
+
69
+ const NOW: Date = new Date("2026-09-21T12:00:00.000Z");
70
+ // Real UUIDs: ObjectID and ProjectUtil ignore values that are not.
71
+ const PROJECT_ID: ObjectID = new ObjectID(
72
+ "7d3f1a2b-4c5d-4e6f-8a9b-0c1d2e3f4a5b",
73
+ );
74
+ const MONITOR_ID: ObjectID = new ObjectID(
75
+ "9a1f0c2e-5b3d-4c7a-8e1f-2d3c4b5a6978",
76
+ );
77
+ const OTHER_MONITOR_ID: ObjectID = new ObjectID(
78
+ "4e5f6071-8293-4a4b-b5c6-d7e8f90a1b2c",
79
+ );
80
+ const OPERATIONAL_ID: string = "1b2c3d4e-5f60-4718-8293-a4b5c6d7e8f9";
81
+ const OFFLINE_ID: string = "2c3d4e5f-6071-4829-93a4-b5c6d7e8f901";
82
+ const ROW_ONE_ID: string = "3d4e5f60-7182-493a-a4b5-c6d7e8f90a1b";
83
+ const ROW_TWO_ID: string = "5f607182-93a4-4b5c-86d7-e8f90a1b2c3d";
84
+ const STEP_ID: string = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
85
+ const PROBE_A: string = "11111111-1111-4111-8111-111111111111";
86
+ const PROBE_B: string = "22222222-2222-4222-8222-222222222222";
87
+
88
+ const SECRET_KEY_COLUMNS: Array<string> = [
89
+ "serverMonitorSecretKey",
90
+ "incomingRequestSecretKey",
91
+ "incomingEmailSecretKey",
92
+ ];
93
+
94
+ const STEPS: MonitorSteps = {
95
+ data: {
96
+ monitorStepsInstanceArray: [{ data: { id: STEP_ID } }],
97
+ },
98
+ } as unknown as MonitorSteps;
99
+
100
+ interface ListRequest {
101
+ modelType: unknown;
102
+ query: Record<string, unknown>;
103
+ select: Record<string, unknown>;
104
+ sort: Record<string, unknown>;
105
+ limit: number;
106
+ skip: number;
107
+ }
108
+
109
+ interface ItemRequest {
110
+ modelType: unknown;
111
+ id: ObjectID;
112
+ select: Record<string, unknown>;
113
+ }
114
+
115
+ interface ApiGetRequest {
116
+ url: URL;
117
+ headers: Dictionary<string>;
118
+ }
119
+
120
+ interface ProbeSpec {
121
+ probeId: string;
122
+ isEnabled?: boolean;
123
+ lastPingAt?: Date;
124
+ nextPingAt?: Date;
125
+ monitoredAt?: Date;
126
+ connectionStatus?: ProbeConnectionStatus;
127
+ }
128
+
129
+ interface FakeServer {
130
+ monitors: Dictionary<Monitor | null>;
131
+ monitorError: Error | null;
132
+ probes: Array<ProbeSpec>;
133
+ probeError: Error | null;
134
+ fullProbeError: Error | null;
135
+ // A full probe read parked until the test releases it.
136
+ heldFullProbeRead: Deferred<void> | null;
137
+ statusRows: Array<MonitorStatusTimeline>;
138
+ statusRowsError: Error | null;
139
+ logs: Array<MonitorLog>;
140
+ logError: Error | null;
141
+ }
142
+
143
+ interface Deferred<T> {
144
+ promise: Promise<T>;
145
+ resolve: (value: T) => void;
146
+ reject: (reason: unknown) => void;
147
+ }
148
+
149
+ function createDeferred<T>(): Deferred<T> {
150
+ let resolve: (value: T) => void = (): void => {};
151
+ let reject: (reason: unknown) => void = (): void => {};
152
+ const promise: Promise<T> = new Promise<T>(
153
+ (
154
+ promiseResolve: (value: T) => void,
155
+ promiseReject: (reason: unknown) => void,
156
+ ): void => {
157
+ resolve = promiseResolve;
158
+ reject = promiseReject;
159
+ },
160
+ );
161
+
162
+ return { promise: promise, resolve: resolve, reject: reject };
163
+ }
164
+
165
+ /*
166
+ * Rejections are made by an async function, so they are native promises.
167
+ * The UI telemetry in the import graph loads zone.js, whose Promise reports
168
+ * a rejection as unhandled when a native await subscribes to it a tick
169
+ * later, which would fill the log with false alarms.
170
+ */
171
+ async function rejectWith(error: unknown): Promise<never> {
172
+ throw error;
173
+ }
174
+
175
+ function secondsFromNow(seconds: number): Date {
176
+ return new Date(NOW.getTime() + seconds * 1000);
177
+ }
178
+
179
+ function buildStatus(statusId: string): MonitorStatus {
180
+ const status: MonitorStatus = new MonitorStatus();
181
+ status._id = statusId;
182
+ status.name = statusId === OFFLINE_ID ? "Offline" : "Operational";
183
+ status.color = new Color(statusId === OFFLINE_ID ? "#ef4444" : "#10b981");
184
+ status.isOperationalState = statusId !== OFFLINE_ID;
185
+ status.isOfflineState = statusId === OFFLINE_ID;
186
+ return status;
187
+ }
188
+
189
+ // Partial<T> under exactOptionalPropertyTypes forbids an explicit undefined.
190
+ type MonitorOverrides = {
191
+ [K in keyof Monitor]?: Monitor[K] | undefined;
192
+ };
193
+
194
+ function buildMonitor(data?: {
195
+ id?: ObjectID;
196
+ type?: MonitorType;
197
+ statusId?: string;
198
+ overrides?: MonitorOverrides;
199
+ }): Monitor {
200
+ const statusId: string = data?.statusId || OPERATIONAL_ID;
201
+ const monitor: Monitor = new Monitor();
202
+ monitor._id = (data?.id || MONITOR_ID).toString();
203
+ monitor.monitorType = data?.type || MonitorType.API;
204
+ monitor.monitorSteps = STEPS;
205
+ monitor.monitoringInterval = "* * * * *";
206
+ monitor.createdAt = new Date("2026-01-01T00:00:00.000Z");
207
+ monitor.currentMonitorStatusId = new ObjectID(statusId);
208
+ monitor.currentMonitorStatus = buildStatus(statusId);
209
+ Object.assign(monitor, data?.overrides || {});
210
+ return monitor;
211
+ }
212
+
213
+ function buildStatusRow(data: {
214
+ id: string;
215
+ statusId: string;
216
+ startsAt: Date;
217
+ endsAt?: Date;
218
+ }): MonitorStatusTimeline {
219
+ const row: MonitorStatusTimeline = new MonitorStatusTimeline();
220
+ row._id = data.id;
221
+ row.monitorStatusId = new ObjectID(data.statusId);
222
+ row.monitorStatus = buildStatus(data.statusId);
223
+ row.startsAt = data.startsAt;
224
+
225
+ if (data.endsAt) {
226
+ row.endsAt = data.endsAt;
227
+ }
228
+
229
+ return row;
230
+ }
231
+
232
+ function buildProbeRow(spec: ProbeSpec, isFull: boolean): MonitorProbe {
233
+ const row: MonitorProbe = new MonitorProbe();
234
+ row.createdAt = NOW;
235
+ row.probeId = new ObjectID(spec.probeId);
236
+ row.isEnabled = spec.isEnabled !== false;
237
+
238
+ if (spec.lastPingAt) {
239
+ row.lastPingAt = spec.lastPingAt;
240
+ }
241
+
242
+ if (spec.nextPingAt) {
243
+ row.nextPingAt = spec.nextPingAt;
244
+ }
245
+
246
+ const probe: Probe = new Probe();
247
+ probe._id = spec.probeId;
248
+ probe.name = spec.probeId === PROBE_A ? "Frankfurt" : "Virginia";
249
+
250
+ if (spec.connectionStatus) {
251
+ probe.connectionStatus = spec.connectionStatus;
252
+ }
253
+
254
+ row.probe = probe;
255
+
256
+ if (isFull && spec.monitoredAt) {
257
+ row.lastMonitoringLog = {
258
+ [STEP_ID]: {
259
+ monitoredAt: spec.monitoredAt.toISOString(),
260
+ isOnline: true,
261
+ responseTimeInMs: 100,
262
+ },
263
+ } as unknown as MonitorStepProbeResponse;
264
+ }
265
+
266
+ return row;
267
+ }
268
+
269
+ function buildLog(data: { probeId: string; time: Date }): MonitorLog {
270
+ const log: MonitorLog = new MonitorLog();
271
+ log.time = data.time;
272
+ log.logBody = {
273
+ probeId: data.probeId,
274
+ evaluationSummary: {
275
+ criteriaResults: [{ criteriaId: "up", criteriaName: "Up", met: true }],
276
+ events: [],
277
+ },
278
+ } as unknown as JSONObject;
279
+ return log;
280
+ }
281
+
282
+ function listOf<T>(data: Array<T>): {
283
+ data: Array<T>;
284
+ count: number;
285
+ skip: number;
286
+ limit: number;
287
+ } {
288
+ return { data: data, count: data.length, skip: 0, limit: data.length };
289
+ }
290
+
291
+ let server: FakeServer;
292
+ let permissions: Array<Permission>;
293
+ let visibilityState: DocumentVisibilityState;
294
+ let getItemSpy: jest.SpyInstance;
295
+ let getListSpy: jest.SpyInstance;
296
+ let analyticsGetListSpy: jest.SpyInstance;
297
+ let apiGetSpy: jest.SpyInstance;
298
+
299
+ function listRequests(modelType: unknown): Array<ListRequest> {
300
+ return getListSpy.mock.calls
301
+ .map((call: Array<unknown>) => {
302
+ return call[0] as ListRequest;
303
+ })
304
+ .filter((request: ListRequest) => {
305
+ return request.modelType === modelType;
306
+ });
307
+ }
308
+
309
+ function probeRequestWeights(): Array<string> {
310
+ return listRequests(MonitorProbe).map((request: ListRequest) => {
311
+ return request.select["lastMonitoringLog"] ? "full" : "light";
312
+ });
313
+ }
314
+
315
+ function itemRequests(): Array<ItemRequest> {
316
+ return getItemSpy.mock.calls.map((call: Array<unknown>) => {
317
+ return call[0] as ItemRequest;
318
+ });
319
+ }
320
+
321
+ function apiGetRequests(): Array<ApiGetRequest> {
322
+ return apiGetSpy.mock.calls.map((call: Array<unknown>) => {
323
+ return call[0] as ApiGetRequest;
324
+ });
325
+ }
326
+
327
+ // Lets every settled promise run its continuations, inside act.
328
+ async function flush(): Promise<void> {
329
+ await act(async () => {
330
+ for (let i: number = 0; i < 50; i++) {
331
+ await Promise.resolve();
332
+ }
333
+ });
334
+ }
335
+
336
+ async function advance(milliseconds: number): Promise<void> {
337
+ await act(async () => {
338
+ jest.advanceTimersByTime(milliseconds);
339
+ });
340
+ await flush();
341
+ }
342
+
343
+ async function poll(): Promise<void> {
344
+ await advance(MONITOR_OVERVIEW_REFRESH_INTERVAL_MS);
345
+ }
346
+
347
+ type RenderedHook = {
348
+ result: { current: UseMonitorOverviewDataResult };
349
+ rerender: (props: { monitorId: ObjectID }) => void;
350
+ unmount: () => void;
351
+ };
352
+
353
+ function renderData(monitorId: ObjectID = MONITOR_ID): RenderedHook {
354
+ return renderHook(
355
+ (props: { monitorId: ObjectID }): UseMonitorOverviewDataResult => {
356
+ return useMonitorOverviewData({ monitorId: props.monitorId });
357
+ },
358
+ { initialProps: { monitorId: monitorId } },
359
+ );
360
+ }
361
+
362
+ async function renderLoaded(
363
+ monitorId: ObjectID = MONITOR_ID,
364
+ ): Promise<RenderedHook> {
365
+ const rendered: RenderedHook = renderData(monitorId);
366
+ await flush();
367
+ expect(rendered.result.current.hasLoaded).toBe(true);
368
+ return rendered;
369
+ }
370
+
371
+ beforeEach(() => {
372
+ jest.useFakeTimers({ doNotFake: ["performance"] });
373
+ jest.setSystemTime(NOW);
374
+
375
+ server = {
376
+ monitors: {
377
+ [MONITOR_ID.toString()]: buildMonitor(),
378
+ [OTHER_MONITOR_ID.toString()]: buildMonitor({ id: OTHER_MONITOR_ID }),
379
+ },
380
+ monitorError: null,
381
+ probes: [
382
+ {
383
+ probeId: PROBE_A,
384
+ lastPingAt: secondsFromNow(-60),
385
+ monitoredAt: secondsFromNow(-30),
386
+ nextPingAt: secondsFromNow(30),
387
+ },
388
+ {
389
+ probeId: PROBE_B,
390
+ lastPingAt: secondsFromNow(-50),
391
+ monitoredAt: secondsFromNow(-20),
392
+ },
393
+ ],
394
+ probeError: null,
395
+ fullProbeError: null,
396
+ heldFullProbeRead: null,
397
+ statusRows: [
398
+ buildStatusRow({
399
+ id: ROW_ONE_ID,
400
+ statusId: OPERATIONAL_ID,
401
+ startsAt: secondsFromNow(-3600),
402
+ }),
403
+ ],
404
+ statusRowsError: null,
405
+ // Newest first, as the server sorts it: each result's own verdict.
406
+ logs: [
407
+ buildLog({ probeId: PROBE_B, time: secondsFromNow(-20) }),
408
+ buildLog({ probeId: PROBE_A, time: secondsFromNow(-30) }),
409
+ ],
410
+ logError: null,
411
+ };
412
+ permissions = [Permission.ProjectOwner];
413
+ visibilityState = "visible";
414
+
415
+ Object.defineProperty(document, "visibilityState", {
416
+ configurable: true,
417
+ get: (): DocumentVisibilityState => {
418
+ return visibilityState;
419
+ },
420
+ });
421
+
422
+ jest.spyOn(ProjectUtil, "getCurrentProjectId").mockReturnValue(PROJECT_ID);
423
+ jest.spyOn(PermissionUtil, "getAllPermissions").mockImplementation(() => {
424
+ return permissions;
425
+ });
426
+
427
+ getItemSpy = jest.spyOn(ModelAPI, "getItem");
428
+ getItemSpy.mockImplementation((...args: Array<unknown>): Promise<unknown> => {
429
+ if (server.monitorError) {
430
+ return rejectWith(server.monitorError);
431
+ }
432
+
433
+ const request: ItemRequest = args[0] as ItemRequest;
434
+ return Promise.resolve(server.monitors[request.id.toString()] ?? null);
435
+ });
436
+
437
+ getListSpy = jest.spyOn(ModelAPI, "getList");
438
+ getListSpy.mockImplementation((...args: Array<unknown>): Promise<unknown> => {
439
+ const request: ListRequest = args[0] as ListRequest;
440
+
441
+ if (request.modelType === MonitorProbe) {
442
+ const isFull: boolean = Boolean(request.select["lastMonitoringLog"]);
443
+ const failure: Error | null = isFull
444
+ ? server.fullProbeError || server.probeError
445
+ : server.probeError;
446
+
447
+ if (failure) {
448
+ return rejectWith(failure);
449
+ }
450
+
451
+ const respond: () => unknown = (): unknown => {
452
+ return listOf(
453
+ server.probes.map((spec: ProbeSpec) => {
454
+ return buildProbeRow(spec, isFull);
455
+ }),
456
+ );
457
+ };
458
+ const held: Deferred<void> | null = isFull
459
+ ? server.heldFullProbeRead
460
+ : null;
461
+
462
+ if (held) {
463
+ server.heldFullProbeRead = null;
464
+ return held.promise.then(respond);
465
+ }
466
+
467
+ return Promise.resolve(respond());
468
+ }
469
+
470
+ if (request.modelType === MonitorStatusTimeline) {
471
+ if (server.statusRowsError) {
472
+ return rejectWith(server.statusRowsError);
473
+ }
474
+
475
+ return Promise.resolve(listOf(server.statusRows));
476
+ }
477
+
478
+ return Promise.resolve(listOf([]));
479
+ });
480
+
481
+ analyticsGetListSpy = jest.spyOn(AnalyticsModelAPI, "getList");
482
+ analyticsGetListSpy.mockImplementation((): Promise<unknown> => {
483
+ if (server.logError) {
484
+ return rejectWith(server.logError);
485
+ }
486
+
487
+ return Promise.resolve(listOf(server.logs));
488
+ });
489
+
490
+ apiGetSpy = jest.spyOn(API, "get");
491
+ apiGetSpy.mockImplementation((): Promise<unknown> => {
492
+ return Promise.resolve(new HTTPResponse<JSONObject>(200, {}, {}));
493
+ });
494
+ });
495
+
496
+ afterEach(() => {
497
+ cleanup();
498
+ jest.restoreAllMocks();
499
+ jest.useRealTimers();
500
+ });
501
+
502
+ describe("useMonitorOverviewData: the first load", () => {
503
+ test("R1, R2 and R3 start together, and the page commits once all three land", async () => {
504
+ const monitorDeferred: Deferred<Monitor | null> =
505
+ createDeferred<Monitor | null>();
506
+ getItemSpy.mockImplementationOnce(() => {
507
+ return monitorDeferred.promise;
508
+ });
509
+
510
+ const { result } = renderData();
511
+
512
+ // All three requests are out before the Monitor row has answered.
513
+ expect(getItemSpy).toHaveBeenCalledTimes(1);
514
+ expect(listRequests(MonitorProbe)).toHaveLength(1);
515
+ expect(listRequests(MonitorStatusTimeline)).toHaveLength(1);
516
+
517
+ const probeRequest: ListRequest = listRequests(MonitorProbe)[0]!;
518
+ expect(probeRequest.query).toEqual({ monitorId: MONITOR_ID });
519
+ expect(probeRequest.select).toBe(MONITOR_OVERVIEW_PROBE_FULL_SELECT);
520
+ expect(probeRequest.sort).toEqual({ createdAt: SortOrder.Descending });
521
+ expect(probeRequest.limit).toBe(LIMIT_PER_PROJECT);
522
+
523
+ const statusRequest: ListRequest = listRequests(MonitorStatusTimeline)[0]!;
524
+ expect(statusRequest.query).toEqual({
525
+ monitorId: MONITOR_ID,
526
+ projectId: PROJECT_ID,
527
+ });
528
+ expect(statusRequest.select).toBe(MONITOR_OVERVIEW_STATUS_ROW_SELECT);
529
+ expect(statusRequest.sort).toEqual({ startsAt: SortOrder.Descending });
530
+ expect(statusRequest.limit).toBe(MONITOR_OVERVIEW_STATUS_ROW_LIMIT);
531
+
532
+ await flush();
533
+
534
+ // Probes and status rows are in, but nothing is shown without the row.
535
+ expect(result.current.hasLoaded).toBe(false);
536
+ expect(result.current.monitor).toBeNull();
537
+ expect(result.current.probes.status).toBe("loading");
538
+ expect(analyticsGetListSpy).not.toHaveBeenCalled();
539
+
540
+ await act(async () => {
541
+ monitorDeferred.resolve(server.monitors[MONITOR_ID.toString()]!);
542
+ });
543
+ await flush();
544
+
545
+ expect(result.current.hasLoaded).toBe(true);
546
+ expect(result.current.error).toBe("");
547
+ expect(result.current.monitor?._id?.toString()).toBe(MONITOR_ID.toString());
548
+ expect(result.current.refreshCount).toBe(1);
549
+ expect(result.current.lastLoadedAt).toEqual(NOW);
550
+ expect(result.current.isRefreshing).toBe(false);
551
+ expect(result.current.probes.status).toBe("loaded");
552
+ expect(result.current.probes.value!.rows).toHaveLength(2);
553
+ expect(result.current.probes.value!.fullLoadedAt).toEqual(NOW);
554
+ expect(
555
+ result.current.probes.value!.attached.probes.map((probe: Probe) => {
556
+ return probe.name;
557
+ }),
558
+ ).toEqual(["Frankfurt", "Virginia"]);
559
+ expect(result.current.statusRows.status).toBe("loaded");
560
+ expect(result.current.statusRows.value).toHaveLength(1);
561
+ expect(result.current.statusFingerprint).toBe(
562
+ `${OPERATIONAL_ID}|${ROW_ONE_ID}|`,
563
+ );
564
+ expect(result.current.resultFingerprint).toBe(
565
+ secondsFromNow(-20).toISOString(),
566
+ );
567
+ });
568
+
569
+ test("refresh-status fires once per id with tenantid and is not awaited", async () => {
570
+ // A refresh-status that never answers must not hold up the page.
571
+ apiGetSpy.mockImplementation(() => {
572
+ return new Promise<never>(() => {
573
+ // Never settles.
574
+ });
575
+ });
576
+
577
+ const { result, rerender } = renderData();
578
+ await flush();
579
+
580
+ expect(result.current.hasLoaded).toBe(true);
581
+ expect(apiGetRequests()).toHaveLength(1);
582
+
583
+ const request: ApiGetRequest = apiGetRequests()[0]!;
584
+ expect(request.url.toString()).toContain(
585
+ `/monitor/refresh-status/${MONITOR_ID.toString()}`,
586
+ );
587
+ expect(request.headers["tenantid"]).toBe(PROJECT_ID.toString());
588
+
589
+ act(() => {
590
+ result.current.refresh();
591
+ });
592
+ await flush();
593
+ act(() => {
594
+ result.current.retryFirstLoad();
595
+ });
596
+ await flush();
597
+
598
+ expect(getItemSpy).toHaveBeenCalledTimes(3);
599
+ expect(apiGetRequests()).toHaveLength(1);
600
+
601
+ rerender({ monitorId: OTHER_MONITOR_ID });
602
+ await flush();
603
+
604
+ expect(apiGetRequests()).toHaveLength(2);
605
+ expect(apiGetRequests()[1]!.url.toString()).toContain(
606
+ `/monitor/refresh-status/${OTHER_MONITOR_ID.toString()}`,
607
+ );
608
+ });
609
+
610
+ test("refresh-status is never sent on a poll or on a visibility catch-up", async () => {
611
+ await renderLoaded();
612
+
613
+ await poll();
614
+ await poll();
615
+ await poll();
616
+
617
+ // Hidden across a tick, then back: one catch-up.
618
+ visibilityState = "hidden";
619
+ await poll();
620
+ visibilityState = "visible";
621
+ act(() => {
622
+ document.dispatchEvent(new Event("visibilitychange"));
623
+ });
624
+ await flush();
625
+
626
+ expect(getItemSpy).toHaveBeenCalledTimes(5);
627
+ expect(apiGetRequests()).toHaveLength(1);
628
+ });
629
+
630
+ test("a rejected refresh-status still loads", async () => {
631
+ apiGetSpy.mockImplementation(() => {
632
+ return rejectWith(new Error("refresh-status is down"));
633
+ });
634
+
635
+ const { result } = await renderLoaded();
636
+
637
+ expect(result.current.error).toBe("");
638
+ expect(result.current.monitor).not.toBeNull();
639
+ });
640
+
641
+ test("a refresh-status that resolves with an error response still loads", async () => {
642
+ apiGetSpy.mockImplementation(() => {
643
+ return Promise.resolve(
644
+ new HTTPErrorResponse(422, { message: "Not a member." }, {}),
645
+ );
646
+ });
647
+
648
+ const { result } = await renderLoaded();
649
+
650
+ expect(result.current.error).toBe("");
651
+ expect(result.current.refreshError).toBe("");
652
+ });
653
+
654
+ test("an R1 failure fails the first load; retryFirstLoad recovers without refresh-status", async () => {
655
+ server.monitorError = new Error("You do not have permission.");
656
+
657
+ const { result } = renderData();
658
+ await flush();
659
+
660
+ expect(result.current.hasLoaded).toBe(true);
661
+ expect(result.current.error).toBe("You do not have permission.");
662
+ expect(result.current.refreshError).toBe("");
663
+ expect(result.current.monitor).toBeNull();
664
+
665
+ // No poll retries a page that never loaded; the retry button does.
666
+ await poll();
667
+ expect(getItemSpy).toHaveBeenCalledTimes(1);
668
+ expect(result.current.pollCount).toBe(0);
669
+
670
+ server.monitorError = null;
671
+ act(() => {
672
+ result.current.retryFirstLoad();
673
+ });
674
+
675
+ // Straight back to the skeleton.
676
+ expect(result.current.hasLoaded).toBe(false);
677
+ expect(result.current.error).toBe("");
678
+
679
+ await flush();
680
+
681
+ expect(result.current.hasLoaded).toBe(true);
682
+ expect(result.current.error).toBe("");
683
+ expect(result.current.monitor).not.toBeNull();
684
+ expect(apiGetRequests()).toHaveLength(1);
685
+ });
686
+
687
+ test("an error response from the row read is reported with its own message", async () => {
688
+ server.monitorError = new HTTPErrorResponse(
689
+ 403,
690
+ { message: "You are not authorized to access this project's data." },
691
+ {},
692
+ ) as unknown as Error;
693
+
694
+ const { result } = renderData();
695
+ await flush();
696
+
697
+ expect(result.current.error).toBe(
698
+ "You are not authorized to access this project's data.",
699
+ );
700
+ });
701
+
702
+ test("a null row gives the not-found text", async () => {
703
+ server.monitors[MONITOR_ID.toString()] = null;
704
+
705
+ const { result } = renderData();
706
+ await flush();
707
+
708
+ expect(result.current.hasLoaded).toBe(true);
709
+ expect(result.current.monitor).toBeNull();
710
+ expect(result.current.error).toBe(MONITOR_OVERVIEW_NOT_FOUND_MESSAGE);
711
+ expect(MONITOR_OVERVIEW_NOT_FOUND_MESSAGE).toBe(
712
+ "This monitor could not be found. It may have been deleted, or you may not have permission to view it.",
713
+ );
714
+ });
715
+
716
+ test("R2/R3 failures stay in their sections and never fail the page", async () => {
717
+ server.probeError = new Error("Probes are unavailable.");
718
+ server.statusRowsError = new Error("The timeline is unavailable.");
719
+
720
+ const { result } = await renderLoaded();
721
+
722
+ expect(result.current.error).toBe("");
723
+ expect(result.current.monitor).not.toBeNull();
724
+ expect(result.current.probes.status).toBe("error");
725
+ expect(result.current.probes.value).toBeNull();
726
+ expect(result.current.probes.error).toBe("Probes are unavailable.");
727
+ expect(result.current.statusRows.status).toBe("error");
728
+ expect(result.current.statusRows.value).toBeNull();
729
+ expect(result.current.statusRows.error).toBe(
730
+ "The timeline is unavailable.",
731
+ );
732
+ // With no rows there is no status row to fingerprint.
733
+ expect(result.current.statusFingerprint).toBe(`${OPERATIONAL_ID}||`);
734
+ });
735
+
736
+ test("a definite gate denial sends no request; the section is forbidden, never empty", async () => {
737
+ permissions = [Permission.ReadProjectMonitor];
738
+
739
+ const { result } = await renderLoaded();
740
+
741
+ expect(getItemSpy).toHaveBeenCalledTimes(1);
742
+ expect(listRequests(MonitorProbe)).toHaveLength(0);
743
+ expect(listRequests(MonitorStatusTimeline)).toHaveLength(0);
744
+ expect(result.current.probes.status).toBe("forbidden");
745
+ expect(result.current.probes.value).toBeNull();
746
+ expect(result.current.probes.error).toBe(
747
+ MONITOR_OVERVIEW_ACCESS_REASONS.probes,
748
+ );
749
+ expect(result.current.statusRows.status).toBe("forbidden");
750
+ expect(result.current.statusRows.error).toBe(
751
+ MONITOR_OVERVIEW_ACCESS_REASONS.statusRows,
752
+ );
753
+
754
+ // ReadProjectMonitor may read MonitorLog, so the evaluation still loads.
755
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(1);
756
+ expect(result.current.evaluation.status).toBe("loaded");
757
+
758
+ // A poll respects the gate too.
759
+ await poll();
760
+ expect(listRequests(MonitorProbe)).toHaveLength(0);
761
+ expect(listRequests(MonitorStatusTimeline)).toHaveLength(0);
762
+ });
763
+
764
+ test("an empty permission snapshot cannot decide, so every read is still sent", async () => {
765
+ permissions = [];
766
+
767
+ const { result } = await renderLoaded();
768
+
769
+ expect(listRequests(MonitorProbe)).toHaveLength(1);
770
+ expect(listRequests(MonitorStatusTimeline)).toHaveLength(1);
771
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(1);
772
+ expect(result.current.probes.status).toBe("loaded");
773
+ expect(result.current.statusRows.status).toBe("loaded");
774
+ });
775
+
776
+ test("the secret-key select is spread at call time, not frozen into a constant", async () => {
777
+ const { result } = await renderLoaded();
778
+
779
+ const ownerSelect: Record<string, unknown> = itemRequests()[0]!.select;
780
+
781
+ for (const key of Object.keys(MONITOR_OVERVIEW_BASE_SELECT)) {
782
+ expect(ownerSelect).toHaveProperty(key);
783
+ }
784
+
785
+ for (const column of SECRET_KEY_COLUMNS) {
786
+ expect(ownerSelect[column]).toBe(true);
787
+ }
788
+
789
+ // The snapshot changes (a Viewer): the next read must not ask for keys.
790
+ permissions = [Permission.Viewer];
791
+ act(() => {
792
+ result.current.refresh();
793
+ });
794
+ await flush();
795
+
796
+ const viewerSelect: Record<string, unknown> = itemRequests()[1]!.select;
797
+
798
+ for (const column of SECRET_KEY_COLUMNS) {
799
+ expect(viewerSelect).not.toHaveProperty(column);
800
+ }
801
+
802
+ expect(Object.keys(viewerSelect).sort()).toEqual(
803
+ Object.keys(MONITOR_OVERVIEW_BASE_SELECT).sort(),
804
+ );
805
+
806
+ // And the shared constant was never written to.
807
+ for (const column of SECRET_KEY_COLUMNS) {
808
+ expect(MONITOR_OVERVIEW_BASE_SELECT).not.toHaveProperty(column);
809
+ }
810
+ });
811
+ });
812
+
813
+ describe("useMonitorOverviewData: drift", () => {
814
+ test("drift triggers exactly one background refresh, after refresh-status resolves", async () => {
815
+ // The newest row says Offline; the Monitor row still says Operational.
816
+ server.statusRows = [
817
+ buildStatusRow({
818
+ id: ROW_TWO_ID,
819
+ statusId: OFFLINE_ID,
820
+ startsAt: secondsFromNow(-120),
821
+ }),
822
+ ];
823
+
824
+ const refreshStatus: Deferred<unknown> = createDeferred<unknown>();
825
+ apiGetSpy.mockImplementation(() => {
826
+ return refreshStatus.promise;
827
+ });
828
+
829
+ const { result } = await renderLoaded();
830
+
831
+ // The page is up, drifted, and waiting for the repair.
832
+ expect(getItemSpy).toHaveBeenCalledTimes(1);
833
+ expect(result.current.monitor?.currentMonitorStatusId?.toString()).toBe(
834
+ OPERATIONAL_ID,
835
+ );
836
+
837
+ // The server repairs the row.
838
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
839
+ statusId: OFFLINE_ID,
840
+ });
841
+
842
+ await act(async () => {
843
+ refreshStatus.resolve(new HTTPResponse<JSONObject>(200, {}, {}));
844
+ });
845
+ await flush();
846
+
847
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
848
+ expect(result.current.monitor?.currentMonitorStatusId?.toString()).toBe(
849
+ OFFLINE_ID,
850
+ );
851
+ // The heal is a background refresh: light probes, no refresh-status.
852
+ expect(probeRequestWeights()).toEqual(["full", "light"]);
853
+ expect(apiGetRequests()).toHaveLength(1);
854
+ expect(result.current.statusChangeCount).toBe(1);
855
+
856
+ await flush();
857
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
858
+ });
859
+
860
+ test("drift is healed at most once, even if the repair did not take", async () => {
861
+ server.statusRows = [
862
+ buildStatusRow({
863
+ id: ROW_TWO_ID,
864
+ statusId: OFFLINE_ID,
865
+ startsAt: secondsFromNow(-120),
866
+ }),
867
+ ];
868
+
869
+ await renderLoaded();
870
+ await flush();
871
+
872
+ // refresh-status resolved at once: one heal, and no second one.
873
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
874
+
875
+ await flush();
876
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
877
+ });
878
+
879
+ test("no drift, no extra refresh", async () => {
880
+ await renderLoaded();
881
+ await flush();
882
+
883
+ expect(getItemSpy).toHaveBeenCalledTimes(1);
884
+ });
885
+
886
+ test("a newer load that already ran makes the heal unnecessary", async () => {
887
+ server.statusRows = [
888
+ buildStatusRow({
889
+ id: ROW_TWO_ID,
890
+ statusId: OFFLINE_ID,
891
+ startsAt: secondsFromNow(-120),
892
+ }),
893
+ ];
894
+
895
+ const refreshStatus: Deferred<unknown> = createDeferred<unknown>();
896
+ apiGetSpy.mockImplementation(() => {
897
+ return refreshStatus.promise;
898
+ });
899
+
900
+ const { result } = await renderLoaded();
901
+
902
+ act(() => {
903
+ result.current.refresh();
904
+ });
905
+ await flush();
906
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
907
+
908
+ await act(async () => {
909
+ refreshStatus.resolve(new HTTPResponse<JSONObject>(200, {}, {}));
910
+ });
911
+ await flush();
912
+
913
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
914
+ });
915
+ });
916
+
917
+ describe("useMonitorOverviewData: the poll", () => {
918
+ test("one poll per 60 s; a hidden tab is skipped; visibilitychange catches up; unmount stops it", async () => {
919
+ const { result, unmount } = await renderLoaded();
920
+
921
+ await advance(MONITOR_OVERVIEW_REFRESH_INTERVAL_MS - 1);
922
+ expect(getItemSpy).toHaveBeenCalledTimes(1);
923
+ expect(result.current.pollCount).toBe(0);
924
+
925
+ await advance(1);
926
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
927
+ expect(result.current.pollCount).toBe(1);
928
+ expect(result.current.refreshCount).toBe(2);
929
+
930
+ visibilityState = "hidden";
931
+ await poll();
932
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
933
+ expect(result.current.pollCount).toBe(1);
934
+
935
+ visibilityState = "visible";
936
+ act(() => {
937
+ document.dispatchEvent(new Event("visibilitychange"));
938
+ });
939
+ await flush();
940
+
941
+ expect(getItemSpy).toHaveBeenCalledTimes(3);
942
+ expect(result.current.pollCount).toBe(2);
943
+
944
+ unmount();
945
+ await poll();
946
+ act(() => {
947
+ document.dispatchEvent(new Event("visibilitychange"));
948
+ });
949
+ await flush();
950
+
951
+ expect(getItemSpy).toHaveBeenCalledTimes(3);
952
+ });
953
+
954
+ test("polls read probes LIGHT, and lay the light fields over the last full results", async () => {
955
+ const { result } = await renderLoaded();
956
+
957
+ server.probes[0]!.nextPingAt = secondsFromNow(90);
958
+ await poll();
959
+
960
+ expect(probeRequestWeights()).toEqual(["full", "light"]);
961
+ expect(listRequests(MonitorProbe)[1]!.select).toBe(
962
+ MONITOR_OVERVIEW_PROBE_LIGHT_SELECT,
963
+ );
964
+ expect(MONITOR_OVERVIEW_PROBE_LIGHT_SELECT).not.toHaveProperty(
965
+ "lastMonitoringLog",
966
+ );
967
+
968
+ const rowA: MonitorProbe = result.current.probes.value!.rows.find(
969
+ (row: MonitorProbe) => {
970
+ return row.probeId?.toString() === PROBE_A;
971
+ },
972
+ )!;
973
+
974
+ // The light field is new, the result is the one from the full read.
975
+ expect(rowA.nextPingAt).toEqual(secondsFromNow(90));
976
+ expect(rowA.lastMonitoringLog).toBeDefined();
977
+ expect(result.current.probes.value!.fullLoadedAt).toEqual(NOW);
978
+ expect(result.current.probes.value!.attached.probeResponses).toHaveLength(
979
+ 2,
980
+ );
981
+ });
982
+
983
+ test("a probe that claimed a check newer than its last result triggers one FULL read", async () => {
984
+ const { result } = await renderLoaded();
985
+
986
+ // Probe A claims a check after its last result, and the result lands.
987
+ server.probes[0]!.lastPingAt = secondsFromNow(40);
988
+ server.probes[0]!.monitoredAt = secondsFromNow(45);
989
+ await poll();
990
+
991
+ expect(probeRequestWeights()).toEqual(["full", "light", "full"]);
992
+
993
+ const rowA: MonitorProbe = result.current.probes.value!.rows.find(
994
+ (row: MonitorProbe) => {
995
+ return row.probeId?.toString() === PROBE_A;
996
+ },
997
+ )!;
998
+ const log: JSONObject = rowA.lastMonitoringLog![
999
+ STEP_ID
1000
+ ] as unknown as JSONObject;
1001
+
1002
+ expect(log["monitoredAt"]).toBe(secondsFromNow(45).toISOString());
1003
+ expect(result.current.probes.value!.fullLoadedAt).toEqual(
1004
+ secondsFromNow(60),
1005
+ );
1006
+
1007
+ // Nothing pending any more: the next poll is light only.
1008
+ await poll();
1009
+ expect(probeRequestWeights()).toEqual(["full", "light", "full", "light"]);
1010
+ });
1011
+
1012
+ test("switching a probe off counts as pending and re-reads in full", async () => {
1013
+ const { result } = await renderLoaded();
1014
+
1015
+ server.probes[1]!.isEnabled = false;
1016
+ await poll();
1017
+
1018
+ expect(probeRequestWeights()).toEqual(["full", "light", "full"]);
1019
+ expect(result.current.probes.value!.attached.disabledProbeIds).toEqual([
1020
+ PROBE_B,
1021
+ ]);
1022
+ });
1023
+
1024
+ test("SyntheticMonitor FULL reloads are capped at one per 5 minutes", async () => {
1025
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
1026
+ type: MonitorType.SyntheticMonitor,
1027
+ });
1028
+ // Always a claim newer than the result held: always "pending".
1029
+ server.probes[0]!.lastPingAt = secondsFromNow(24 * 3600);
1030
+
1031
+ await renderLoaded();
1032
+
1033
+ for (let i: number = 0; i < 4; i++) {
1034
+ await poll();
1035
+ }
1036
+
1037
+ // Four minutes in: light reads only, the screenshots are not re-sent.
1038
+ expect(probeRequestWeights()).toEqual([
1039
+ "full",
1040
+ "light",
1041
+ "light",
1042
+ "light",
1043
+ "light",
1044
+ ]);
1045
+
1046
+ await poll();
1047
+
1048
+ expect(MONITOR_OVERVIEW_HEAVY_PROBE_RELOAD_MS).toBe(5 * 60 * 1000);
1049
+ expect(probeRequestWeights()).toEqual([
1050
+ "full",
1051
+ "light",
1052
+ "light",
1053
+ "light",
1054
+ "light",
1055
+ "light",
1056
+ "full",
1057
+ ]);
1058
+ });
1059
+
1060
+ test("other probe checks re-read in full on every poll that has something pending", async () => {
1061
+ server.probes[0]!.lastPingAt = secondsFromNow(24 * 3600);
1062
+
1063
+ await renderLoaded();
1064
+ await poll();
1065
+ await poll();
1066
+
1067
+ expect(probeRequestWeights()).toEqual([
1068
+ "full",
1069
+ "light",
1070
+ "full",
1071
+ "light",
1072
+ "full",
1073
+ ]);
1074
+ });
1075
+
1076
+ test("a failed FULL read on a poll keeps the merged rows and records the failure", async () => {
1077
+ const { result } = await renderLoaded();
1078
+
1079
+ server.probes[0]!.lastPingAt = secondsFromNow(40);
1080
+ server.fullProbeError = new Error("Results are unavailable.");
1081
+ await poll();
1082
+
1083
+ expect(result.current.probes.status).toBe("loaded");
1084
+ expect(result.current.probes.refreshError).toBe("Results are unavailable.");
1085
+ expect(result.current.probes.value!.rows).toHaveLength(2);
1086
+ expect(result.current.probes.value!.fullLoadedAt).toEqual(NOW);
1087
+ });
1088
+
1089
+ test("types that are not probe checks read probes on the first load only", async () => {
1090
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
1091
+ type: MonitorType.IncomingRequest,
1092
+ });
1093
+
1094
+ const { result } = await renderLoaded();
1095
+
1096
+ // The type is unknown until the row lands, so the first load reads them.
1097
+ expect(probeRequestWeights()).toEqual(["full"]);
1098
+
1099
+ await poll();
1100
+ act(() => {
1101
+ result.current.refresh();
1102
+ });
1103
+ await flush();
1104
+
1105
+ expect(probeRequestWeights()).toEqual(["full"]);
1106
+ expect(result.current.probes.status).toBe("loaded");
1107
+ expect(listRequests(MonitorStatusTimeline)).toHaveLength(3);
1108
+ });
1109
+
1110
+ test("a failed poll keeps the last row and reports itself", async () => {
1111
+ const { result } = await renderLoaded();
1112
+
1113
+ server.monitorError = new Error("Network error.");
1114
+ await poll();
1115
+
1116
+ expect(result.current.refreshError).toBe("Network error.");
1117
+ expect(result.current.error).toBe("");
1118
+ expect(result.current.hasLoaded).toBe(true);
1119
+ expect(result.current.monitor).not.toBeNull();
1120
+ expect(result.current.refreshCount).toBe(1);
1121
+ expect(result.current.isRefreshing).toBe(false);
1122
+
1123
+ server.monitorError = null;
1124
+ await poll();
1125
+
1126
+ expect(result.current.refreshError).toBe("");
1127
+ expect(result.current.refreshCount).toBe(2);
1128
+ });
1129
+
1130
+ test("a failed section refresh keeps the last value and records refreshError", async () => {
1131
+ const { result } = await renderLoaded();
1132
+
1133
+ server.statusRowsError = new Error("The timeline is unavailable.");
1134
+ await poll();
1135
+
1136
+ expect(result.current.statusRows.status).toBe("loaded");
1137
+ expect(result.current.statusRows.value).toHaveLength(1);
1138
+ expect(result.current.statusRows.refreshError).toBe(
1139
+ "The timeline is unavailable.",
1140
+ );
1141
+ expect(result.current.refreshError).toBe("");
1142
+ });
1143
+ });
1144
+
1145
+ async function setVisibility(state: DocumentVisibilityState): Promise<void> {
1146
+ visibilityState = state;
1147
+ act(() => {
1148
+ document.dispatchEvent(new Event("visibilitychange"));
1149
+ });
1150
+ await flush();
1151
+ }
1152
+
1153
+ describe("useMonitorOverviewData: coming back to the tab", () => {
1154
+ test("switching away and back within the minute does not poll", async () => {
1155
+ const { result } = await renderLoaded();
1156
+
1157
+ await advance(20 * 1000);
1158
+ await setVisibility("hidden");
1159
+ await advance(10 * 1000);
1160
+ await setVisibility("visible");
1161
+
1162
+ expect(getItemSpy).toHaveBeenCalledTimes(1);
1163
+ expect(result.current.pollCount).toBe(0);
1164
+
1165
+ // The regular tick still comes a minute after the load.
1166
+ await advance(30 * 1000);
1167
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1168
+ expect(result.current.pollCount).toBe(1);
1169
+ });
1170
+
1171
+ test("a tick missed while hidden is caught up once, and the next tick is a full interval later", async () => {
1172
+ const { result } = await renderLoaded();
1173
+
1174
+ await setVisibility("hidden");
1175
+ await advance(65 * 1000);
1176
+ expect(getItemSpy).toHaveBeenCalledTimes(1);
1177
+
1178
+ await setVisibility("visible");
1179
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1180
+ expect(result.current.pollCount).toBe(1);
1181
+
1182
+ // Not at 120 s, 55 s after the catch-up, but a whole interval after it.
1183
+ await advance(55 * 1000);
1184
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1185
+
1186
+ await advance(5 * 1000);
1187
+ expect(getItemSpy).toHaveBeenCalledTimes(3);
1188
+ expect(result.current.pollCount).toBe(2);
1189
+ });
1190
+
1191
+ test("a hidden tab's throttled timer that never ran is caught up by the time that passed", async () => {
1192
+ await renderLoaded();
1193
+
1194
+ await setVisibility("hidden");
1195
+ // The clock moves on; the timer does not run.
1196
+ jest.setSystemTime(secondsFromNow(90));
1197
+ await setVisibility("visible");
1198
+
1199
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1200
+ });
1201
+ });
1202
+
1203
+ describe("useMonitorOverviewData: a poll during a Refresh", () => {
1204
+ test("a tick while a Refresh is out waits for it rather than cancel it", async () => {
1205
+ const { result } = await renderLoaded();
1206
+
1207
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(1);
1208
+
1209
+ const slowRead: Deferred<Monitor | null> = createDeferred<Monitor | null>();
1210
+ getItemSpy.mockImplementationOnce(() => {
1211
+ return slowRead.promise;
1212
+ });
1213
+
1214
+ act(() => {
1215
+ result.current.refresh();
1216
+ });
1217
+ await flush();
1218
+
1219
+ expect(probeRequestWeights()).toEqual(["full", "full"]);
1220
+
1221
+ // The minute tick lands while the Refresh is still out: nothing is sent.
1222
+ await poll();
1223
+
1224
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1225
+ expect(probeRequestWeights()).toEqual(["full", "full"]);
1226
+ expect(result.current.pollCount).toBe(0);
1227
+ expect(result.current.isRefreshing).toBe(true);
1228
+ // A minute in, the page says it is still waiting.
1229
+ expect(result.current.refreshError).toBe(
1230
+ MONITOR_OVERVIEW_SLOW_FETCH_MESSAGE,
1231
+ );
1232
+
1233
+ await act(async () => {
1234
+ slowRead.resolve(server.monitors[MONITOR_ID.toString()]!);
1235
+ });
1236
+ await flush();
1237
+
1238
+ // The Refresh lands, with everything it read: fresh verdicts too.
1239
+ expect(result.current.refreshCount).toBe(2);
1240
+ expect(result.current.refreshError).toBe("");
1241
+ expect(result.current.isRefreshing).toBe(false);
1242
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(2);
1243
+
1244
+ // With nothing in flight, the next tick polls, lightly.
1245
+ await poll();
1246
+ expect(probeRequestWeights()).toEqual(["full", "full", "light"]);
1247
+ expect(result.current.pollCount).toBe(1);
1248
+ });
1249
+
1250
+ test("a details save in flight is not cancelled by a tick either", async () => {
1251
+ const { result } = await renderLoaded();
1252
+
1253
+ const slowRead: Deferred<Monitor | null> = createDeferred<Monitor | null>();
1254
+ getItemSpy.mockImplementationOnce(() => {
1255
+ return slowRead.promise;
1256
+ });
1257
+
1258
+ act(() => {
1259
+ result.current.refresh({ reason: "details-saved" });
1260
+ });
1261
+ await poll();
1262
+
1263
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1264
+ expect(probeRequestWeights()).toEqual(["full", "full"]);
1265
+
1266
+ await act(async () => {
1267
+ slowRead.resolve(server.monitors[MONITOR_ID.toString()]!);
1268
+ });
1269
+ await flush();
1270
+
1271
+ expect(result.current.refreshCount).toBe(2);
1272
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(2);
1273
+ expect(result.current.manualRefreshCount).toBe(0);
1274
+ });
1275
+ });
1276
+
1277
+ /*
1278
+ * A load that takes longer than the poll interval: a synthetic monitor's
1279
+ * screenshots on a slow link, or an API under strain. Were each tick to
1280
+ * cancel the load in flight, the next load would be cancelled in turn and
1281
+ * nothing would ever land, while the hero (judged at the last commit) kept
1282
+ * its old verdict without a word.
1283
+ */
1284
+ describe("useMonitorOverviewData: a fetch slower than the poll", () => {
1285
+ test("slow responses spanning several ticks are waited for, land, and are called late meanwhile", async () => {
1286
+ const { result } = await renderLoaded();
1287
+
1288
+ const slowRead: Deferred<Monitor | null> = createDeferred<Monitor | null>();
1289
+ getItemSpy.mockImplementationOnce(() => {
1290
+ return slowRead.promise;
1291
+ });
1292
+
1293
+ // The tick at 60 s starts a poll whose Monitor read is slow.
1294
+ await poll();
1295
+
1296
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1297
+ expect(result.current.pollCount).toBe(1);
1298
+ expect(result.current.isRefreshing).toBe(true);
1299
+ expect(result.current.refreshError).toBe("");
1300
+
1301
+ // The ticks at 120 and 180 s find it still out, and send nothing.
1302
+ await poll();
1303
+
1304
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1305
+ expect(result.current.refreshError).toBe(
1306
+ MONITOR_OVERVIEW_SLOW_FETCH_MESSAGE,
1307
+ );
1308
+
1309
+ await poll();
1310
+
1311
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1312
+ expect(listRequests(MonitorStatusTimeline)).toHaveLength(2);
1313
+ expect(result.current.pollCount).toBe(1);
1314
+ expect(result.current.refreshCount).toBe(1);
1315
+
1316
+ // It lands at last, and the page moves on.
1317
+ await act(async () => {
1318
+ slowRead.resolve(server.monitors[MONITOR_ID.toString()]!);
1319
+ });
1320
+ await flush();
1321
+
1322
+ expect(result.current.refreshCount).toBe(2);
1323
+ expect(result.current.refreshError).toBe("");
1324
+ expect(result.current.isRefreshing).toBe(false);
1325
+ expect(result.current.lastLoadedAt).toEqual(secondsFromNow(180));
1326
+
1327
+ await poll();
1328
+
1329
+ expect(getItemSpy).toHaveBeenCalledTimes(3);
1330
+ expect(result.current.pollCount).toBe(2);
1331
+ expect(result.current.refreshCount).toBe(3);
1332
+ });
1333
+
1334
+ test("a fetch out for less than a minute is waited for without a word", async () => {
1335
+ const { result } = await renderLoaded();
1336
+
1337
+ const slowRead: Deferred<Monitor | null> = createDeferred<Monitor | null>();
1338
+ getItemSpy.mockImplementationOnce(() => {
1339
+ return slowRead.promise;
1340
+ });
1341
+
1342
+ // A Refresh at 30 s, still out at the tick at 60 s.
1343
+ await advance(30 * 1000);
1344
+ act(() => {
1345
+ result.current.refresh();
1346
+ });
1347
+ await advance(30 * 1000);
1348
+
1349
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1350
+ expect(result.current.refreshError).toBe("");
1351
+
1352
+ await poll();
1353
+
1354
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1355
+ expect(MONITOR_OVERVIEW_SLOW_FETCH_MS).toBe(
1356
+ MONITOR_OVERVIEW_REFRESH_INTERVAL_MS,
1357
+ );
1358
+ expect(result.current.refreshError).toBe(
1359
+ MONITOR_OVERVIEW_SLOW_FETCH_MESSAGE,
1360
+ );
1361
+
1362
+ await act(async () => {
1363
+ slowRead.resolve(server.monitors[MONITOR_ID.toString()]!);
1364
+ });
1365
+ await flush();
1366
+
1367
+ expect(result.current.refreshError).toBe("");
1368
+ });
1369
+
1370
+ test("a synthetic monitor's full read slower than a minute lands, and moves the reload cap", async () => {
1371
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
1372
+ type: MonitorType.SyntheticMonitor,
1373
+ });
1374
+ // Always a claim newer than the result held: always "pending".
1375
+ server.probes[0]!.lastPingAt = secondsFromNow(24 * 3600);
1376
+
1377
+ const { result } = await renderLoaded();
1378
+
1379
+ // The ticks at 60, 120, 180 and 240 s: light reads only.
1380
+ for (let i: number = 0; i < 4; i++) {
1381
+ await poll();
1382
+ }
1383
+
1384
+ // At 300 s the capped full read is due, and its screenshots are slow.
1385
+ const slowFull: Deferred<void> = createDeferred<void>();
1386
+ server.heldFullProbeRead = slowFull;
1387
+ await poll();
1388
+
1389
+ const weightsWhileOut: Array<string> = [
1390
+ "full",
1391
+ "light",
1392
+ "light",
1393
+ "light",
1394
+ "light",
1395
+ "light",
1396
+ "full",
1397
+ ];
1398
+
1399
+ expect(probeRequestWeights()).toEqual(weightsWhileOut);
1400
+
1401
+ // The ticks at 360 and 420 s neither cancel it nor start another.
1402
+ await poll();
1403
+ await poll();
1404
+
1405
+ expect(probeRequestWeights()).toEqual(weightsWhileOut);
1406
+ expect(result.current.refreshError).toBe(
1407
+ MONITOR_OVERVIEW_SLOW_FETCH_MESSAGE,
1408
+ );
1409
+
1410
+ await act(async () => {
1411
+ slowFull.resolve();
1412
+ });
1413
+ await flush();
1414
+
1415
+ // It lands, stamped when it was sent, so the cap is five minutes on.
1416
+ expect(result.current.refreshError).toBe("");
1417
+ expect(result.current.probes.status).toBe("loaded");
1418
+ expect(result.current.probes.value!.fullLoadedAt).toEqual(
1419
+ secondsFromNow(300),
1420
+ );
1421
+
1422
+ await poll();
1423
+
1424
+ expect(probeRequestWeights()).toEqual([...weightsWhileOut, "light"]);
1425
+ });
1426
+
1427
+ test("a fetch presumed lost is replaced, reading everything a lost Refresh would have", async () => {
1428
+ const { result } = await renderLoaded();
1429
+
1430
+ // A Refresh whose Monitor read never comes back.
1431
+ const lostRead: Deferred<Monitor | null> = createDeferred<Monitor | null>();
1432
+ getItemSpy.mockImplementationOnce(() => {
1433
+ return lostRead.promise;
1434
+ });
1435
+
1436
+ act(() => {
1437
+ result.current.refresh();
1438
+ });
1439
+ await flush();
1440
+
1441
+ const ticksBeforeStalled: number =
1442
+ MONITOR_OVERVIEW_STALLED_FETCH_MS / MONITOR_OVERVIEW_REFRESH_INTERVAL_MS -
1443
+ 1;
1444
+
1445
+ expect(MONITOR_OVERVIEW_STALLED_FETCH_MS).toBe(10 * 60 * 1000);
1446
+
1447
+ for (let i: number = 0; i < ticksBeforeStalled; i++) {
1448
+ await poll();
1449
+ }
1450
+
1451
+ // Nine minutes of ticks: nothing sent, the page says it is waiting.
1452
+ expect(getItemSpy).toHaveBeenCalledTimes(2);
1453
+ expect(result.current.isRefreshing).toBe(true);
1454
+ expect(result.current.refreshError).toBe(
1455
+ MONITOR_OVERVIEW_SLOW_FETCH_MESSAGE,
1456
+ );
1457
+
1458
+ // Ten minutes: the tick replaces it, in full, as the Refresh would have.
1459
+ await poll();
1460
+
1461
+ expect(getItemSpy).toHaveBeenCalledTimes(3);
1462
+ expect(probeRequestWeights()).toEqual(["full", "full", "full"]);
1463
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(2);
1464
+ expect(result.current.refreshCount).toBe(2);
1465
+ expect(result.current.refreshError).toBe("");
1466
+ expect(result.current.isRefreshing).toBe(false);
1467
+
1468
+ // The lost answer turning up after all changes nothing.
1469
+ await act(async () => {
1470
+ lostRead.resolve(server.monitors[MONITOR_ID.toString()]!);
1471
+ });
1472
+ await flush();
1473
+
1474
+ expect(result.current.refreshCount).toBe(2);
1475
+ });
1476
+
1477
+ test("a fetch still out for the monitor the reader left never holds up the next one", async () => {
1478
+ const { result, rerender } = await renderLoaded();
1479
+
1480
+ const lostRead: Deferred<Monitor | null> = createDeferred<Monitor | null>();
1481
+ getItemSpy.mockImplementationOnce(() => {
1482
+ return lostRead.promise;
1483
+ });
1484
+
1485
+ // A poll for monitor A is out when the reader moves to monitor B.
1486
+ await poll();
1487
+ rerender({ monitorId: OTHER_MONITOR_ID });
1488
+ await flush();
1489
+
1490
+ expect(result.current.hasLoaded).toBe(true);
1491
+ expect(result.current.monitor?._id?.toString()).toBe(
1492
+ OTHER_MONITOR_ID.toString(),
1493
+ );
1494
+
1495
+ const readsForB: () => number = (): number => {
1496
+ return itemRequests().filter((request: ItemRequest) => {
1497
+ return request.id.toString() === OTHER_MONITOR_ID.toString();
1498
+ }).length;
1499
+ };
1500
+
1501
+ expect(readsForB()).toBe(1);
1502
+
1503
+ // B's first tick polls B, whatever A's fetch is doing.
1504
+ await poll();
1505
+
1506
+ expect(readsForB()).toBe(2);
1507
+ expect(result.current.refreshError).toBe("");
1508
+ });
1509
+ });
1510
+
1511
+ describe("useMonitorOverviewData: probe results that could not be read", () => {
1512
+ test("light rows are never shown without results: the section stays an error until a full read works", async () => {
1513
+ // The first load's full read fails (a synthetic payload that times out).
1514
+ server.fullProbeError = new Error("Results are unavailable.");
1515
+
1516
+ const { result } = await renderLoaded();
1517
+
1518
+ expect(result.current.probes.status).toBe("error");
1519
+
1520
+ // The poll's light read works; the full read it leads to fails again.
1521
+ await poll();
1522
+
1523
+ expect(probeRequestWeights()).toEqual(["full", "light", "full"]);
1524
+ expect(result.current.probes.status).toBe("error");
1525
+ expect(result.current.probes.value).toBeNull();
1526
+ expect(result.current.probes.error).toBe("Results are unavailable.");
1527
+ expect(MONITOR_OVERVIEW_PROBE_RESULTS_UNREADABLE_MESSAGE).toBe(
1528
+ "The probe results could not be read.",
1529
+ );
1530
+
1531
+ server.fullProbeError = null;
1532
+ await poll();
1533
+
1534
+ expect(result.current.probes.status).toBe("loaded");
1535
+ expect(result.current.probes.value!.rows).toHaveLength(2);
1536
+ expect(result.current.probes.value!.fullLoadedAt).toEqual(
1537
+ secondsFromNow(120),
1538
+ );
1539
+ });
1540
+
1541
+ test("a monitor with no probes attached is still a known empty list", async () => {
1542
+ server.fullProbeError = new Error("Results are unavailable.");
1543
+ server.probes = [];
1544
+
1545
+ const { result } = await renderLoaded();
1546
+
1547
+ server.fullProbeError = null;
1548
+ await poll();
1549
+
1550
+ // Nothing is attached, so there are no results to be missing.
1551
+ expect(probeRequestWeights()).toEqual(["full", "light"]);
1552
+ expect(result.current.probes.status).toBe("loaded");
1553
+ expect(result.current.probes.value!.rows).toEqual([]);
1554
+ });
1555
+ });
1556
+
1557
+ describe("useMonitorOverviewData: the synthetic reload cap", () => {
1558
+ test("is timed from when the full read was sent, so a slow download does not push it to the sixth poll", async () => {
1559
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
1560
+ type: MonitorType.SyntheticMonitor,
1561
+ });
1562
+ // Always a claim newer than the result held: always "pending".
1563
+ server.probes[0]!.lastPingAt = secondsFromNow(24 * 3600);
1564
+
1565
+ // The first load's screenshots take 20 seconds to download.
1566
+ const slowFull: Deferred<void> = createDeferred<void>();
1567
+ server.heldFullProbeRead = slowFull;
1568
+
1569
+ const { result } = renderData();
1570
+ await flush();
1571
+ await advance(20 * 1000);
1572
+ await act(async () => {
1573
+ slowFull.resolve();
1574
+ });
1575
+ await flush();
1576
+
1577
+ expect(result.current.hasLoaded).toBe(true);
1578
+ // Stamped when it was sent, not when it arrived.
1579
+ expect(result.current.probes.value!.fullLoadedAt).toEqual(NOW);
1580
+
1581
+ // The ticks at 60, 120, 180 and 240 s: light reads only.
1582
+ for (let i: number = 0; i < 4; i++) {
1583
+ await poll();
1584
+ }
1585
+
1586
+ expect(probeRequestWeights()).toEqual([
1587
+ "full",
1588
+ "light",
1589
+ "light",
1590
+ "light",
1591
+ "light",
1592
+ ]);
1593
+
1594
+ // The tick at 300 s, five minutes after the full read was sent.
1595
+ await poll();
1596
+
1597
+ expect(probeRequestWeights()).toEqual([
1598
+ "full",
1599
+ "light",
1600
+ "light",
1601
+ "light",
1602
+ "light",
1603
+ "light",
1604
+ "full",
1605
+ ]);
1606
+ });
1607
+ });
1608
+
1609
+ describe("useMonitorOverviewData: which probe claims are followed", () => {
1610
+ test("a disconnected probe that never reported does not cost a full read on every poll", async () => {
1611
+ server.probes[1] = {
1612
+ probeId: PROBE_B,
1613
+ lastPingAt: secondsFromNow(-50),
1614
+ connectionStatus: ProbeConnectionStatus.Disconnected,
1615
+ };
1616
+
1617
+ await renderLoaded();
1618
+ await poll();
1619
+ await poll();
1620
+ await poll();
1621
+
1622
+ expect(probeRequestWeights()).toEqual(["full", "light", "light", "light"]);
1623
+ });
1624
+
1625
+ test("a probe that never reported is followed only while its claim could still produce a result", async () => {
1626
+ // Probe B claimed its first check 50 s ago and has not reported yet.
1627
+ server.probes[1] = { probeId: PROBE_B, lastPingAt: secondsFromNow(-50) };
1628
+
1629
+ await renderLoaded();
1630
+
1631
+ // Up to one cadence plus grace (60 + 300 s) after the claim.
1632
+ for (let i: number = 0; i < 5; i++) {
1633
+ await poll();
1634
+ }
1635
+
1636
+ expect(probeRequestWeights()).toEqual([
1637
+ "full",
1638
+ "light",
1639
+ "full",
1640
+ "light",
1641
+ "full",
1642
+ "light",
1643
+ "full",
1644
+ "light",
1645
+ "full",
1646
+ "light",
1647
+ "full",
1648
+ ]);
1649
+
1650
+ // Past that the probe is late (the Probes card says so), not pending.
1651
+ await poll();
1652
+ await poll();
1653
+
1654
+ expect(probeRequestWeights().slice(-2)).toEqual(["light", "light"]);
1655
+ });
1656
+
1657
+ test("a claim the last full read saw before its result landed is followed on the next poll", async () => {
1658
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
1659
+ overrides: { monitoringInterval: "*/5 * * * *" },
1660
+ });
1661
+
1662
+ const { result } = await renderLoaded();
1663
+
1664
+ // Probe A claims its next check just before the poll; it is still running.
1665
+ server.probes[0]!.lastPingAt = secondsFromNow(50);
1666
+ await poll();
1667
+
1668
+ expect(probeRequestWeights()).toEqual(["full", "light", "full"]);
1669
+
1670
+ // Its result lands after that full read was sent.
1671
+ server.probes[0]!.monitoredAt = secondsFromNow(65);
1672
+ await poll();
1673
+
1674
+ // Read now, not when the probe next claims, five minutes later.
1675
+ expect(probeRequestWeights()).toEqual([
1676
+ "full",
1677
+ "light",
1678
+ "full",
1679
+ "light",
1680
+ "full",
1681
+ ]);
1682
+ expect(result.current.resultFingerprint).toBe(
1683
+ secondsFromNow(65).toISOString(),
1684
+ );
1685
+ });
1686
+
1687
+ test("a claim that is never answered stops costing a full read once it is older than cadence plus grace", async () => {
1688
+ await renderLoaded();
1689
+
1690
+ // Probe A claims a check 30 s in and dies before reporting it.
1691
+ server.probes[0]!.lastPingAt = secondsFromNow(30);
1692
+
1693
+ // 60 to 360 s: the result could still land, so every poll reads it.
1694
+ for (let i: number = 0; i < 6; i++) {
1695
+ await poll();
1696
+ }
1697
+
1698
+ expect(
1699
+ probeRequestWeights().filter((weight: string) => {
1700
+ return weight === "full";
1701
+ }),
1702
+ ).toHaveLength(7);
1703
+
1704
+ await poll();
1705
+ await poll();
1706
+
1707
+ expect(probeRequestWeights().slice(-2)).toEqual(["light", "light"]);
1708
+ });
1709
+
1710
+ test("a browser clock minutes fast does not make a young claim look settled", async () => {
1711
+ // The browser believes it is seven minutes later than the server does.
1712
+ jest.setSystemTime(secondsFromNow(7 * 60));
1713
+ // Probe B claimed its first check 50 s ago by the server's clock.
1714
+ server.probes[1] = { probeId: PROBE_B, lastPingAt: secondsFromNow(-50) };
1715
+
1716
+ const { result } = await renderLoaded();
1717
+
1718
+ act(() => {
1719
+ result.current.setServerClockOffset(-7 * 60 * 1000);
1720
+ });
1721
+
1722
+ expect(result.current.serverClockOffsetMs).toBe(-7 * 60 * 1000);
1723
+
1724
+ await poll();
1725
+
1726
+ // 110 s old on the server's clock: its result may be in, so it is read.
1727
+ expect(probeRequestWeights()).toEqual(["full", "light", "full"]);
1728
+ });
1729
+ });
1730
+
1731
+ describe("useMonitorOverviewData: the evaluation log catching up", () => {
1732
+ test("a verdict still in the worker's buffer is read again until it lands", async () => {
1733
+ const { result } = await renderLoaded();
1734
+
1735
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(1);
1736
+
1737
+ // Probe B reports; its verdict is not in the log yet.
1738
+ server.probes[1]!.lastPingAt = secondsFromNow(100);
1739
+ server.probes[1]!.monitoredAt = new Date(
1740
+ secondsFromNow(105).getTime() + 700,
1741
+ );
1742
+ await poll();
1743
+
1744
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(2);
1745
+ expect(result.current.evaluation.value!.latestAt).toEqual(
1746
+ secondsFromNow(-20),
1747
+ );
1748
+
1749
+ // Still the previous verdict: read again on the next poll.
1750
+ await poll();
1751
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(3);
1752
+
1753
+ // The verdict lands, stamped without its milliseconds.
1754
+ server.logs = [
1755
+ buildLog({ probeId: PROBE_B, time: secondsFromNow(105) }),
1756
+ ...server.logs,
1757
+ ];
1758
+ await poll();
1759
+
1760
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(4);
1761
+ expect(result.current.evaluation.value!.latestAt).toEqual(
1762
+ secondsFromNow(105),
1763
+ );
1764
+
1765
+ // Caught up: nothing more until the next result.
1766
+ await poll();
1767
+ await poll();
1768
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(4);
1769
+ });
1770
+
1771
+ test("a result whose verdict never lands costs a few extra reads, not one per poll", async () => {
1772
+ await renderLoaded();
1773
+
1774
+ server.probes[1]!.lastPingAt = secondsFromNow(100);
1775
+ server.probes[1]!.monitoredAt = secondsFromNow(105);
1776
+ await poll();
1777
+
1778
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(2);
1779
+
1780
+ for (
1781
+ let i: number = 0;
1782
+ i < MONITOR_OVERVIEW_EVALUATION_RETRY_POLLS + 3;
1783
+ i++
1784
+ ) {
1785
+ await poll();
1786
+ }
1787
+
1788
+ expect(MONITOR_OVERVIEW_EVALUATION_RETRY_POLLS).toBe(3);
1789
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(
1790
+ 2 + MONITOR_OVERVIEW_EVALUATION_RETRY_POLLS,
1791
+ );
1792
+ });
1793
+ });
1794
+
1795
+ describe("getSettledClaimCutoff", () => {
1796
+ const rowsClaimedAt: (seconds: Array<number>) => Array<MonitorProbe> = (
1797
+ seconds: Array<number>,
1798
+ ): Array<MonitorProbe> => {
1799
+ return seconds.map((offset: number, index: number) => {
1800
+ return buildProbeRow(
1801
+ {
1802
+ probeId: index === 0 ? PROBE_A : PROBE_B,
1803
+ lastPingAt: secondsFromNow(offset),
1804
+ },
1805
+ true,
1806
+ );
1807
+ });
1808
+ };
1809
+
1810
+ test("a claim settles only once the last full read saw it and it is older than cadence plus grace", () => {
1811
+ const fullRows: Array<MonitorProbe> = rowsClaimedAt([-50, 30]);
1812
+
1813
+ /*
1814
+ * At 100 s the newest claim seen (30 s) is young: only claims before
1815
+ * 100 - (60 + 300) s have settled.
1816
+ */
1817
+ expect(
1818
+ getSettledClaimCutoff({
1819
+ fullRows: fullRows,
1820
+ now: secondsFromNow(100),
1821
+ cadenceSeconds: 60,
1822
+ }),
1823
+ ).toEqual(secondsFromNow(-260));
1824
+
1825
+ // At 500 s everything the read saw has settled, and nothing after it.
1826
+ expect(
1827
+ getSettledClaimCutoff({
1828
+ fullRows: fullRows,
1829
+ now: secondsFromNow(500),
1830
+ cadenceSeconds: 60,
1831
+ }),
1832
+ ).toEqual(secondsFromNow(30));
1833
+ });
1834
+
1835
+ test("with no full read there is nothing settled", () => {
1836
+ expect(
1837
+ getSettledClaimCutoff({
1838
+ fullRows: [],
1839
+ now: NOW,
1840
+ cadenceSeconds: 60,
1841
+ }),
1842
+ ).toBeNull();
1843
+ });
1844
+ });
1845
+
1846
+ describe("isEvaluationCaughtUp", () => {
1847
+ test("compares to the second, and a missing log never covers a signal", () => {
1848
+ const signal: Date = new Date(secondsFromNow(105).getTime() + 700);
1849
+
1850
+ expect(
1851
+ isEvaluationCaughtUp({ latestAt: secondsFromNow(105), signalAt: signal }),
1852
+ ).toBe(true);
1853
+ expect(
1854
+ isEvaluationCaughtUp({ latestAt: secondsFromNow(104), signalAt: signal }),
1855
+ ).toBe(false);
1856
+ expect(
1857
+ isEvaluationCaughtUp({ latestAt: undefined, signalAt: signal }),
1858
+ ).toBe(false);
1859
+ // Nothing to judge: nothing to wait for.
1860
+ expect(
1861
+ isEvaluationCaughtUp({ latestAt: undefined, signalAt: undefined }),
1862
+ ).toBe(true);
1863
+ });
1864
+ });
1865
+
1866
+ describe("useMonitorOverviewData: the evaluation log", () => {
1867
+ test("R4 runs after the first commit, again only on a result change, and always on a manual refresh", async () => {
1868
+ const monitorDeferred: Deferred<Monitor | null> =
1869
+ createDeferred<Monitor | null>();
1870
+ getItemSpy.mockImplementationOnce(() => {
1871
+ return monitorDeferred.promise;
1872
+ });
1873
+
1874
+ const { result } = renderData();
1875
+ await flush();
1876
+ expect(analyticsGetListSpy).not.toHaveBeenCalled();
1877
+
1878
+ await act(async () => {
1879
+ monitorDeferred.resolve(server.monitors[MONITOR_ID.toString()]!);
1880
+ });
1881
+ await flush();
1882
+
1883
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(1);
1884
+
1885
+ const request: ListRequest = analyticsGetListSpy.mock
1886
+ .calls[0]![0] as ListRequest;
1887
+ expect(request.modelType).toBe(MonitorLog);
1888
+ expect(request.query).toEqual({
1889
+ projectId: PROJECT_ID.toString(),
1890
+ monitorId: MONITOR_ID.toString(),
1891
+ });
1892
+ // Two enabled probes: twice as many rows, so each probe's newest is found.
1893
+ expect(request.limit).toBe(4);
1894
+ expect(request.select).toEqual({ time: true, logBody: true });
1895
+ expect(request.sort).toEqual({ time: SortOrder.Descending });
1896
+
1897
+ expect(result.current.evaluation.status).toBe("loaded");
1898
+ expect(
1899
+ Object.keys(result.current.evaluation.value!.byProbeId).sort(),
1900
+ ).toEqual([PROBE_A, PROBE_B].sort());
1901
+ expect(result.current.evaluation.value!.latestAt).toEqual(
1902
+ secondsFromNow(-20),
1903
+ );
1904
+
1905
+ // Nothing new came in: no second read.
1906
+ await poll();
1907
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(1);
1908
+
1909
+ // A new result lands (a claim, then a full read with a newer result).
1910
+ server.probes[1]!.lastPingAt = secondsFromNow(100);
1911
+ server.probes[1]!.monitoredAt = secondsFromNow(110);
1912
+ await poll();
1913
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(2);
1914
+ expect(result.current.resultFingerprint).toBe(
1915
+ secondsFromNow(110).toISOString(),
1916
+ );
1917
+
1918
+ act(() => {
1919
+ result.current.refresh();
1920
+ });
1921
+ await flush();
1922
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(3);
1923
+ });
1924
+
1925
+ test("never for Manual, where nothing is evaluated", async () => {
1926
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
1927
+ type: MonitorType.Manual,
1928
+ });
1929
+
1930
+ const { result } = await renderLoaded();
1931
+ await poll();
1932
+ act(() => {
1933
+ result.current.refresh();
1934
+ });
1935
+ await flush();
1936
+
1937
+ expect(analyticsGetListSpy).not.toHaveBeenCalled();
1938
+ expect(result.current.evaluation.status).toBe("loaded");
1939
+ expect(result.current.evaluation.value).toEqual({ byProbeId: {} });
1940
+ });
1941
+
1942
+ test("telemetry monitors re-read the log when the last evaluation moves", async () => {
1943
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
1944
+ type: MonitorType.Logs,
1945
+ overrides: { telemetryMonitorLastMonitorAt: secondsFromNow(-40) },
1946
+ });
1947
+
1948
+ await renderLoaded();
1949
+
1950
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(1);
1951
+ expect((analyticsGetListSpy.mock.calls[0]![0] as ListRequest).limit).toBe(
1952
+ 1,
1953
+ );
1954
+
1955
+ await poll();
1956
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(1);
1957
+
1958
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
1959
+ type: MonitorType.Logs,
1960
+ overrides: { telemetryMonitorLastMonitorAt: secondsFromNow(20) },
1961
+ });
1962
+ await poll();
1963
+
1964
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(2);
1965
+ });
1966
+
1967
+ test("network device monitors re-read the log on every fifth poll", async () => {
1968
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
1969
+ type: MonitorType.NetworkDevice,
1970
+ });
1971
+
1972
+ await renderLoaded();
1973
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(1);
1974
+
1975
+ for (let i: number = 0; i < 4; i++) {
1976
+ await poll();
1977
+ }
1978
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(1);
1979
+
1980
+ await poll();
1981
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(2);
1982
+ });
1983
+
1984
+ test("a failed evaluation read is an error section, retried on the next poll", async () => {
1985
+ server.logError = new Error("Logs are unavailable.");
1986
+
1987
+ const { result } = await renderLoaded();
1988
+
1989
+ expect(result.current.error).toBe("");
1990
+ expect(result.current.evaluation.status).toBe("error");
1991
+ expect(result.current.evaluation.error).toBe("Logs are unavailable.");
1992
+
1993
+ server.logError = null;
1994
+ await poll();
1995
+
1996
+ expect(analyticsGetListSpy).toHaveBeenCalledTimes(2);
1997
+ expect(result.current.evaluation.status).toBe("loaded");
1998
+ });
1999
+
2000
+ test("a forbidden evaluation log is a forbidden section", async () => {
2001
+ // Incident access only: no MonitorLog read.
2002
+ permissions = [Permission.IncidentViewer];
2003
+
2004
+ const { result } = await renderLoaded();
2005
+
2006
+ expect(analyticsGetListSpy).not.toHaveBeenCalled();
2007
+ expect(result.current.evaluation.status).toBe("forbidden");
2008
+ expect(result.current.evaluation.error).toBe(
2009
+ MONITOR_OVERVIEW_ACCESS_REASONS.evaluation,
2010
+ );
2011
+ });
2012
+ });
2013
+
2014
+ describe("useMonitorOverviewData: counters and refreshes", () => {
2015
+ test("statusChangeCount bumps on a fingerprint change only", async () => {
2016
+ const { result } = await renderLoaded();
2017
+
2018
+ expect(result.current.statusChangeCount).toBe(0);
2019
+
2020
+ await poll();
2021
+ expect(result.current.statusChangeCount).toBe(0);
2022
+
2023
+ // The monitor goes offline: a new newest row and a new current status.
2024
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
2025
+ statusId: OFFLINE_ID,
2026
+ });
2027
+ server.statusRows = [
2028
+ buildStatusRow({
2029
+ id: ROW_TWO_ID,
2030
+ statusId: OFFLINE_ID,
2031
+ startsAt: secondsFromNow(100),
2032
+ }),
2033
+ buildStatusRow({
2034
+ id: ROW_ONE_ID,
2035
+ statusId: OPERATIONAL_ID,
2036
+ startsAt: secondsFromNow(-3600),
2037
+ endsAt: secondsFromNow(100),
2038
+ }),
2039
+ ];
2040
+ await poll();
2041
+
2042
+ expect(result.current.statusChangeCount).toBe(1);
2043
+ expect(result.current.statusFingerprint).toBe(
2044
+ `${OFFLINE_ID}|${ROW_TWO_ID}|`,
2045
+ );
2046
+
2047
+ await poll();
2048
+ expect(result.current.statusChangeCount).toBe(1);
2049
+
2050
+ // The newest row closes.
2051
+ server.statusRows = [
2052
+ buildStatusRow({
2053
+ id: ROW_TWO_ID,
2054
+ statusId: OFFLINE_ID,
2055
+ startsAt: secondsFromNow(100),
2056
+ endsAt: secondsFromNow(200),
2057
+ }),
2058
+ ];
2059
+ await poll();
2060
+
2061
+ expect(result.current.statusChangeCount).toBe(2);
2062
+ });
2063
+
2064
+ test("manual refresh reads probes in full and bumps manualRefreshCount; details-saved does not", async () => {
2065
+ const { result } = await renderLoaded();
2066
+
2067
+ const monitorDeferred: Deferred<Monitor | null> =
2068
+ createDeferred<Monitor | null>();
2069
+ getItemSpy.mockImplementationOnce(() => {
2070
+ return monitorDeferred.promise;
2071
+ });
2072
+
2073
+ act(() => {
2074
+ result.current.refresh();
2075
+ });
2076
+
2077
+ expect(result.current.manualRefreshCount).toBe(1);
2078
+ expect(result.current.isRefreshing).toBe(true);
2079
+ // A refresh never goes back to the skeleton.
2080
+ expect(result.current.hasLoaded).toBe(true);
2081
+ expect(result.current.monitor).not.toBeNull();
2082
+
2083
+ await act(async () => {
2084
+ monitorDeferred.resolve(server.monitors[MONITOR_ID.toString()]!);
2085
+ });
2086
+ await flush();
2087
+
2088
+ expect(result.current.isRefreshing).toBe(false);
2089
+ expect(result.current.refreshCount).toBe(2);
2090
+ expect(probeRequestWeights()).toEqual(["full", "full"]);
2091
+
2092
+ act(() => {
2093
+ result.current.refresh({ reason: "details-saved" });
2094
+ });
2095
+ await flush();
2096
+
2097
+ expect(result.current.manualRefreshCount).toBe(1);
2098
+ expect(result.current.refreshCount).toBe(3);
2099
+ expect(probeRequestWeights()).toEqual(["full", "full", "full"]);
2100
+ expect(apiGetRequests()).toHaveLength(1);
2101
+ });
2102
+
2103
+ test("an older generation landing last is ignored", async () => {
2104
+ const { result } = await renderLoaded();
2105
+
2106
+ // A manual refresh whose Monitor read is slow...
2107
+ const slowRead: Deferred<Monitor | null> = createDeferred<Monitor | null>();
2108
+ getItemSpy.mockImplementationOnce(() => {
2109
+ return slowRead.promise;
2110
+ });
2111
+ act(() => {
2112
+ result.current.refresh();
2113
+ });
2114
+
2115
+ // ...is overtaken by a details save that sees the monitor go offline.
2116
+ server.monitors[MONITOR_ID.toString()] = buildMonitor({
2117
+ statusId: OFFLINE_ID,
2118
+ });
2119
+ act(() => {
2120
+ result.current.refresh({ reason: "details-saved" });
2121
+ });
2122
+ await flush();
2123
+
2124
+ expect(result.current.monitor?.currentMonitorStatusId?.toString()).toBe(
2125
+ OFFLINE_ID,
2126
+ );
2127
+ const refreshCountAfterSave: number = result.current.refreshCount;
2128
+
2129
+ // The slow, older answer lands last and must not win.
2130
+ await act(async () => {
2131
+ slowRead.resolve(buildMonitor({ statusId: OPERATIONAL_ID }));
2132
+ });
2133
+ await flush();
2134
+
2135
+ expect(result.current.monitor?.currentMonitorStatusId?.toString()).toBe(
2136
+ OFFLINE_ID,
2137
+ );
2138
+ expect(result.current.refreshCount).toBe(refreshCountAfterSave);
2139
+ expect(result.current.isRefreshing).toBe(false);
2140
+ });
2141
+
2142
+ test("an id change resets and never leaks the previous monitor", async () => {
2143
+ const { result, rerender } = await renderLoaded();
2144
+
2145
+ // A refresh for monitor A that is still in flight when the user leaves.
2146
+ const lateA: Deferred<Monitor | null> = createDeferred<Monitor | null>();
2147
+ const slowB: Deferred<Monitor | null> = createDeferred<Monitor | null>();
2148
+ getItemSpy
2149
+ .mockImplementationOnce(() => {
2150
+ return lateA.promise;
2151
+ })
2152
+ .mockImplementationOnce(() => {
2153
+ return slowB.promise;
2154
+ });
2155
+
2156
+ act(() => {
2157
+ result.current.refresh();
2158
+ });
2159
+
2160
+ rerender({ monitorId: OTHER_MONITOR_ID });
2161
+
2162
+ // Monitor B: skeleton at once, and nothing of A's.
2163
+ expect(result.current.hasLoaded).toBe(false);
2164
+ expect(result.current.monitor).toBeNull();
2165
+ expect(result.current.probes.status).toBe("loading");
2166
+ expect(result.current.probes.value).toBeNull();
2167
+ expect(result.current.statusRows.status).toBe("loading");
2168
+ expect(result.current.evaluation.status).toBe("loading");
2169
+ expect(result.current.statusFingerprint).toBe("");
2170
+ expect(result.current.resultFingerprint).toBe("");
2171
+ expect(result.current.lastLoadedAt).toBeNull();
2172
+
2173
+ // A's late answer lands on B's page and is dropped.
2174
+ await act(async () => {
2175
+ lateA.resolve(server.monitors[MONITOR_ID.toString()]!);
2176
+ });
2177
+ await flush();
2178
+
2179
+ expect(result.current.hasLoaded).toBe(false);
2180
+ expect(result.current.monitor).toBeNull();
2181
+
2182
+ await act(async () => {
2183
+ slowB.resolve(server.monitors[OTHER_MONITOR_ID.toString()]!);
2184
+ });
2185
+ await flush();
2186
+
2187
+ expect(result.current.hasLoaded).toBe(true);
2188
+ expect(result.current.monitor?._id?.toString()).toBe(
2189
+ OTHER_MONITOR_ID.toString(),
2190
+ );
2191
+ expect(result.current.statusChangeCount).toBe(0);
2192
+ expect(result.current.probes.loadedFor).toBe(OTHER_MONITOR_ID.toString());
2193
+
2194
+ // B's first load was a first load: full probes for B.
2195
+ const lastProbeRequest: ListRequest = listRequests(MonitorProbe).pop()!;
2196
+ expect(lastProbeRequest.query).toEqual({ monitorId: OTHER_MONITOR_ID });
2197
+ expect(lastProbeRequest.select).toBe(MONITOR_OVERVIEW_PROBE_FULL_SELECT);
2198
+ });
2199
+ });