@oneuptime/common 14.0.1 → 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 (1090) 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/KubernetesCluster.ts +429 -0
  7. package/Models/DatabaseModels/Monitor.ts +48 -0
  8. package/Models/DatabaseModels/Runner.ts +5 -4
  9. package/Models/DatabaseModels/RunnerJob.ts +66 -0
  10. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +10 -2
  11. package/Models/DatabaseModels/WorkflowVariable.ts +479 -2
  12. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +79 -25
  13. package/Server/API/AIInvestigationAPI.ts +341 -0
  14. package/Server/API/AutoRemediationAPI.ts +184 -2
  15. package/Server/API/CommonAPI.ts +70 -0
  16. package/Server/API/KubernetesClusterAiAccessAPI.ts +793 -0
  17. package/Server/API/MicrosoftTeamsAPI.ts +770 -315
  18. package/Server/API/MonitorAPI.ts +140 -0
  19. package/Server/API/OnCallScheduleTimelineAPI.ts +5 -21
  20. package/Server/API/SlackAPI.ts +447 -99
  21. package/Server/API/StatusPageAPI.ts +146 -26
  22. package/Server/API/TelemetryAPI.ts +216 -5
  23. package/Server/API/UserTwoFactorBackupCodeAPI.ts +1 -0
  24. package/Server/API/WorkflowVariableAPI.ts +156 -0
  25. package/Server/Infrastructure/GlobalCache.ts +35 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.ts +97 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.ts +129 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.ts +25 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.ts +20 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.ts +38 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  32. package/Server/Middleware/MasterAdminAuthorization.ts +28 -0
  33. package/Server/Middleware/TelemetryIngest.ts +47 -2
  34. package/Server/Middleware/UserAuthorization.ts +56 -2
  35. package/Server/Services/AIAgentService.ts +1 -0
  36. package/Server/Services/AccessTokenService.ts +121 -48
  37. package/Server/Services/AlertEpisodeMemberService.ts +9 -0
  38. package/Server/Services/AlertEpisodeService.ts +14 -1
  39. package/Server/Services/AlertService.ts +134 -22
  40. package/Server/Services/AutoRemediationRuleEngineService.ts +968 -39
  41. package/Server/Services/AutoRemediationRuleService.ts +118 -0
  42. package/Server/Services/BillingService.ts +1 -0
  43. package/Server/Services/InboundEmail/Providers/SendGridInboundProvider.ts +16 -22
  44. package/Server/Services/IncidentEpisodeMemberService.ts +9 -0
  45. package/Server/Services/IncidentEpisodePublicNoteService.ts +66 -0
  46. package/Server/Services/IncidentEpisodeRoleMemberService.ts +27 -0
  47. package/Server/Services/IncidentEpisodeService.ts +14 -1
  48. package/Server/Services/IncidentGroupingEngineService.ts +11 -0
  49. package/Server/Services/IncidentMemberService.ts +21 -0
  50. package/Server/Services/IncidentPublicNoteService.ts +63 -0
  51. package/Server/Services/IncidentService.ts +120 -20
  52. package/Server/Services/IncidentStateTimelineService.ts +15 -0
  53. package/Server/Services/IncidentTemplateService.ts +83 -3
  54. package/Server/Services/KubernetesClusterAiAccessService.ts +1943 -0
  55. package/Server/Services/KubernetesClusterService.ts +1570 -1
  56. package/Server/Services/LogAggregationService.ts +14 -6
  57. package/Server/Services/MonitorService.ts +651 -52
  58. package/Server/Services/MonitorStatusTimelineService.ts +639 -2
  59. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -0
  60. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -0
  61. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -0
  62. package/Server/Services/OnCallDutyPolicyScheduleService.ts +3 -0
  63. package/Server/Services/OnCallNotificationAlertingService.ts +36 -12
  64. package/Server/Services/OnCallSetupReminderService.ts +1 -0
  65. package/Server/Services/ProbeService.ts +7 -1
  66. package/Server/Services/ProjectService.ts +11 -1
  67. package/Server/Services/RunbookCredentialService.ts +26 -1
  68. package/Server/Services/RunbookSecretService.ts +36 -0
  69. package/Server/Services/RunnerJobService.ts +941 -23
  70. package/Server/Services/RunnerService.ts +439 -6
  71. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +66 -0
  72. package/Server/Services/ScheduledMaintenanceService.ts +124 -19
  73. package/Server/Services/ScheduledMaintenanceTemplateService.ts +82 -3
  74. package/Server/Services/ServiceLevelObjectiveService.ts +14 -1
  75. package/Server/Services/StatusPagePrivateUserService.ts +1 -0
  76. package/Server/Services/StatusPageService.ts +301 -74
  77. package/Server/Services/StatusPageSubscriberService.ts +4 -0
  78. package/Server/Services/TeamMemberService.ts +309 -7
  79. package/Server/Services/TraceAggregationService.ts +10 -6
  80. package/Server/Services/UserEmailService.ts +1 -0
  81. package/Server/Services/UserNotificationMethodAdminService.ts +1 -0
  82. package/Server/Services/UserNotificationRuleAdminService.ts +1 -0
  83. package/Server/Services/UserNotificationRuleService.ts +4 -0
  84. package/Server/Services/UserService.ts +122 -1
  85. package/Server/Services/WorkflowVariableService.ts +593 -8
  86. package/Server/Services/WorkspaceNotificationRuleService.ts +588 -8
  87. package/Server/Services/WorkspaceProjectAuthTokenService.ts +170 -1
  88. package/Server/Types/Database/QueryHelper.ts +22 -0
  89. package/Server/Types/Markdown.ts +502 -27
  90. package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +182 -0
  91. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +525 -0
  92. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +854 -0
  93. package/Server/Utils/AI/CodeFix/CodeFixAgentAuth.ts +22 -2
  94. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1916 -307
  95. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +1601 -74
  96. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +139 -7
  97. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +58 -1
  98. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +54 -1
  99. package/Server/Utils/AI/Toolbox/AIActionTools.ts +14 -6
  100. package/Server/Utils/AI/Toolbox/ResourceTools.ts +4 -2
  101. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +1341 -150
  102. package/Server/Utils/AutoRemediation/RemediationVerifier.ts +375 -4
  103. package/Server/Utils/Database/AffectedResourceRelations.ts +127 -0
  104. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +240 -1
  105. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +1 -0
  106. package/Server/Utils/Monitor/MonitorAlert.ts +83 -9
  107. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +5 -1
  108. package/Server/Utils/Monitor/MonitorIncident.ts +104 -9
  109. package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +124 -7
  110. package/Server/Utils/Monitor/ProbeMonitorsNotification.ts +407 -0
  111. package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +1 -0
  112. package/Server/Utils/PushNotificationUtil.ts +45 -0
  113. package/Server/Utils/Rules/OwnerRuleAssignment.ts +40 -3
  114. package/Server/Utils/Runbook/RunbookExecutePermission.ts +56 -6
  115. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +223 -33
  116. package/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.ts +559 -0
  117. package/Server/Utils/StartServer.ts +4 -3
  118. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +528 -0
  119. package/Server/Utils/TwoFactorBackupCodeNotification.ts +1 -0
  120. package/Server/Utils/UserPermission/UserPermission.ts +16 -0
  121. package/Server/Utils/Workflow/OAuth2TokenClient.ts +704 -0
  122. package/Server/Utils/Workflow/WorkflowVariableOAuthToken.ts +318 -0
  123. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +47 -7
  124. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +57 -16
  125. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +193 -214
  126. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +57 -13
  127. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.ts +54 -17
  128. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +179 -161
  129. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +281 -167
  130. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.ts +114 -0
  131. package/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.ts +895 -0
  132. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +7 -9
  133. package/Server/Utils/Workspace/Slack/Actions/Alert.ts +96 -227
  134. package/Server/Utils/Workspace/Slack/Actions/AlertEpisode.ts +93 -214
  135. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +30 -3
  136. package/Server/Utils/Workspace/Slack/Actions/Authorization.ts +99 -0
  137. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +117 -283
  138. package/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.ts +101 -196
  139. package/Server/Utils/Workspace/Slack/Actions/ReactionNote.ts +329 -0
  140. package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +111 -287
  141. package/Server/Utils/Workspace/Slack/Slack.ts +86 -17
  142. package/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
  143. package/Server/Utils/Workspace/Workspace.ts +171 -54
  144. package/Server/Utils/Workspace/WorkspaceActionAuthorization.ts +252 -0
  145. package/Server/Utils/Workspace/WorkspaceBase.ts +39 -0
  146. package/Server/Utils/Workspace/WorkspaceOAuthState.ts +280 -0
  147. package/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.ts +96 -0
  148. package/Server/Utils/Workspace/WorkspaceReactionNote.ts +620 -0
  149. package/Tests/App/Dashboard/AttributesJSONDashboardSurfaces.test.tsx +496 -0
  150. package/Tests/App/Dashboard/AutoRemediationRulesTableCommandRunners.test.tsx +152 -0
  151. package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +32 -0
  152. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +794 -0
  153. package/Tests/App/Dashboard/CreateOAuthWorkflowVariableModal.test.tsx +840 -0
  154. package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +653 -0
  155. package/Tests/App/Dashboard/DatabaseMonitorStepForm.test.tsx +197 -0
  156. package/Tests/App/Dashboard/DatabaseMonitorView.test.tsx +376 -0
  157. package/Tests/App/Dashboard/DisabledWarningRobustness.test.tsx +262 -0
  158. package/Tests/App/Dashboard/EventNotes.test.tsx +2080 -0
  159. package/Tests/App/Dashboard/EventNotesPages.test.tsx +486 -0
  160. package/Tests/App/Dashboard/EventNotesUtil.test.ts +933 -0
  161. package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +218 -0
  162. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +665 -0
  163. package/Tests/App/Dashboard/IncidentEpisodeFeedPublicNoteNotifyDefault.test.tsx +494 -0
  164. package/Tests/App/Dashboard/IncidentEpisodeOverviewNotifyDefault.test.tsx +706 -0
  165. package/Tests/App/Dashboard/IncidentFeedPublicNoteNotifyDefault.test.tsx +472 -0
  166. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +858 -0
  167. package/Tests/App/Dashboard/IncomingEmailAddressSettings.test.tsx +567 -0
  168. package/Tests/App/Dashboard/InvestigationClusterToolFormat.test.ts +241 -0
  169. package/Tests/App/Dashboard/InvestigationEvidenceKubectl.test.tsx +322 -0
  170. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +12 -0
  171. package/Tests/App/Dashboard/InvestigationPanelClusterAccess.test.tsx +476 -0
  172. package/Tests/App/Dashboard/InvestigationRunDetailsKubectl.test.tsx +383 -0
  173. package/Tests/App/Dashboard/KubectlActivitySummary.test.tsx +366 -0
  174. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +2886 -0
  175. package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +2688 -0
  176. package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +915 -0
  177. package/Tests/App/Dashboard/LayerDateTimeFieldTimezoneName.test.tsx +66 -0
  178. package/Tests/App/Dashboard/LogMonitorPreview.test.tsx +174 -0
  179. package/Tests/App/Dashboard/MonitorFeedRefresh.test.tsx +279 -0
  180. package/Tests/App/Dashboard/MonitorMetricQueryConfig.test.ts +244 -0
  181. package/Tests/App/Dashboard/MonitorOpenWorkCard.test.tsx +381 -0
  182. package/Tests/App/Dashboard/MonitorOpenWorkHook.test.tsx +784 -0
  183. package/Tests/App/Dashboard/MonitorOverviewData.test.tsx +2199 -0
  184. package/Tests/App/Dashboard/MonitorOverviewHero.test.tsx +1169 -0
  185. package/Tests/App/Dashboard/MonitorOverviewInput.test.ts +1127 -0
  186. package/Tests/App/Dashboard/MonitorOverviewPage.test.tsx +2136 -0
  187. package/Tests/App/Dashboard/MonitorOverviewSelectReadable.test.ts +368 -0
  188. package/Tests/App/Dashboard/MonitorOverviewStatBar.test.tsx +526 -0
  189. package/Tests/App/Dashboard/MonitorOverviewSupportingCards.test.tsx +542 -0
  190. package/Tests/App/Dashboard/MonitorOwnersCombine.test.ts +299 -0
  191. package/Tests/App/Dashboard/MonitorProbesCard.test.tsx +602 -0
  192. package/Tests/App/Dashboard/MonitorResponseTimeCard.test.tsx +386 -0
  193. package/Tests/App/Dashboard/MonitorSetupAndConnectionCards.test.tsx +612 -0
  194. package/Tests/App/Dashboard/MonitorStatusChangesCard.test.tsx +257 -0
  195. package/Tests/App/Dashboard/MonitorSummaryTestMonitorButton.test.tsx +360 -1
  196. package/Tests/App/Dashboard/MonitorUptimeHistoryCard.test.tsx +835 -0
  197. package/Tests/App/Dashboard/MonitorUptimeSummaryHook.test.tsx +971 -0
  198. package/Tests/App/Dashboard/MonitorViewLayout.test.tsx +580 -0
  199. package/Tests/App/Dashboard/OnCallLayerRestrictionTimesPreserved.test.tsx +441 -0
  200. package/Tests/App/Dashboard/OnCallNavbar.test.tsx +214 -0
  201. package/Tests/App/Dashboard/OnCallSchedulePreviewCalendarDisplay.test.tsx +1389 -0
  202. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +205 -1
  203. package/Tests/App/Dashboard/OnCallScheduleTimeInputsSettingsZone.test.tsx +198 -0
  204. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +524 -0
  205. package/Tests/App/Dashboard/RemediationSuggestionCardApproval.test.tsx +702 -0
  206. package/Tests/App/Dashboard/RemoveUserFromProject.test.tsx +427 -0
  207. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +4 -0
  208. package/Tests/App/Dashboard/RumSessionReplaySideMenu.test.tsx +3 -1
  209. package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +166 -0
  210. package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +622 -0
  211. package/Tests/App/Dashboard/ScheduledMaintenanceChangeStateNotifyDefault.test.tsx +1491 -0
  212. package/Tests/App/Dashboard/ScheduledMaintenanceFeedPublicNoteNotifyDefault.test.tsx +489 -0
  213. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewNotifyDefault.test.tsx +909 -0
  214. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +14 -0
  215. package/Tests/App/Dashboard/ScheduledMaintenanceWindowStatsTranslation.test.tsx +307 -0
  216. package/Tests/App/Dashboard/SecurityEventAttributeColumnPicker.test.tsx +542 -0
  217. package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +174 -0
  218. package/Tests/App/Dashboard/SecurityEventConnectionsEmptyState.test.tsx +973 -212
  219. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +491 -52
  220. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +301 -0
  221. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +158 -1
  222. package/Tests/App/Dashboard/SecurityEventProviderTile.test.tsx +869 -0
  223. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +959 -94
  224. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +2 -0
  225. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +274 -1
  226. package/Tests/App/Dashboard/TeamMembershipRemoval.test.ts +900 -0
  227. package/Tests/App/Dashboard/TeamMembershipRemovalPages.test.tsx +460 -0
  228. package/Tests/App/Dashboard/TimezoneElements.test.tsx +321 -0
  229. package/Tests/App/Dashboard/TimezoneSelectButton.test.tsx +634 -0
  230. package/Tests/App/Dashboard/TraceExplorer.test.tsx +260 -0
  231. package/Tests/App/Dashboard/TraceMonitorPreview.test.tsx +182 -0
  232. package/Tests/App/Dashboard/UserTimezoneInit.test.tsx +544 -0
  233. package/Tests/App/Dashboard/WorkflowVariableModals.test.tsx +1630 -0
  234. package/Tests/App/Dashboard/WorkflowVariableRoutes.test.tsx +603 -0
  235. package/Tests/App/Dashboard/WorkflowVariableTokenStatus.test.tsx +589 -0
  236. package/Tests/App/Dashboard/WorkflowVariableUtil.test.ts +1543 -0
  237. package/Tests/App/Dashboard/WorkflowVariableView.test.tsx +3227 -0
  238. package/Tests/App/Dashboard/WorkflowVariablesTable.test.tsx +1277 -395
  239. package/Tests/App/StatusPage/StatusPageOverviewMonitorGroupUptime.test.tsx +714 -0
  240. package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.NewYork.test.tsx +1009 -0
  241. package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.test.tsx +1092 -0
  242. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +5 -0
  243. package/Tests/Models/DatabaseModels/KubernetesClusterAiAccessColumns.test.ts +520 -0
  244. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +66 -2
  245. package/Tests/Models/DatabaseModels/WorkspaceProjectAuthTokenAccessControl.test.ts +236 -0
  246. package/Tests/Models/IncidentEpisodePublicNoteNotifyColumnContract.test.ts +103 -0
  247. package/Tests/Models/IncidentPublicNoteNotifyColumnContract.test.ts +96 -0
  248. package/Tests/Models/ScheduledMaintenancePublicNoteNotifyColumnContract.test.ts +111 -0
  249. package/Tests/Server/API/AIInvestigationAPI.test.ts +976 -0
  250. package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +836 -0
  251. package/Tests/Server/API/CommonAPIAssertCanCreateTable.test.ts +565 -0
  252. package/Tests/Server/API/CommonAPIAssertCanReadTable.test.ts +282 -0
  253. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +1744 -0
  254. package/Tests/Server/API/LogHistogramAPI.test.ts +371 -0
  255. package/Tests/Server/API/MicrosoftTeamsLegacyWebhookRemoval.test.ts +125 -30
  256. package/Tests/Server/API/MicrosoftTeamsOAuthState.test.ts +1121 -0
  257. package/Tests/Server/API/MonitorUptimeSummaryAPI.test.ts +685 -0
  258. package/Tests/Server/API/SessionReplayAPI.test.ts +602 -1
  259. package/Tests/Server/API/SlackChannelCacheAPI.test.ts +358 -0
  260. package/Tests/Server/API/SlackOAuthState.test.ts +688 -0
  261. package/Tests/Server/API/StatusPageOverviewMonitorGroupUptime.test.ts +527 -0
  262. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +2 -0
  263. package/Tests/Server/API/StatusPageUptimeAPI.test.ts +427 -0
  264. package/Tests/Server/API/UserProjectsAPI.test.ts +4 -0
  265. package/Tests/Server/API/WorkflowVariableAPI.test.ts +404 -0
  266. package/Tests/Server/API/WorkspaceOAuthTestHelpers.ts +289 -0
  267. package/Tests/Server/API/WorkspaceSendTestNotificationRoutes.test.ts +2064 -0
  268. package/Tests/Server/Infrastructure/GlobalCache.test.ts +86 -0
  269. package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +589 -0
  270. package/Tests/Server/Infrastructure/Postgres/AddOAuth2WorkflowVariablesMigration.test.ts +254 -0
  271. package/Tests/Server/Middleware/BlockedUserMiddleware.test.ts +403 -0
  272. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +13 -0
  273. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +2 -0
  274. package/Tests/Server/Middleware/RemovedProjectMemberAuthorization.test.ts +469 -0
  275. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +77 -1
  276. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +211 -0
  277. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +358 -0
  278. package/Tests/Server/Middleware/UserAuthorization.test.ts +97 -0
  279. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +2 -0
  280. package/Tests/Server/Services/AccessTokenProjectUserGrant.test.ts +14 -2
  281. package/Tests/Server/Services/AccessTokenRemovedMemberAccess.test.ts +1044 -0
  282. package/Tests/Server/Services/AddOwnersIdempotency.test.ts +5 -0
  283. package/Tests/Server/Services/AlertEpisodeMemberCreatePermission.test.ts +139 -0
  284. package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +1361 -0
  285. package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +375 -0
  286. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +2384 -0
  287. package/Tests/Server/Services/FindOwnersProjectMembership.test.ts +267 -0
  288. package/Tests/Server/Services/InboundEmail/SendGridInboundProviderAddress.test.ts +90 -0
  289. package/Tests/Server/Services/IncidentEpisodeMemberCreatePermission.test.ts +143 -0
  290. package/Tests/Server/Services/IncidentEpisodePublicNoteNotifyDefault.test.ts +805 -0
  291. package/Tests/Server/Services/IncidentPublicNoteNotifyDefault.test.ts +724 -0
  292. package/Tests/Server/Services/IncidentRoleProjectMembership.test.ts +233 -0
  293. package/Tests/Server/Services/KubernetesClusterAiAccessAgentRunnerAssignments.test.ts +372 -0
  294. package/Tests/Server/Services/KubernetesClusterAiAccessBindingGuard.test.ts +1876 -0
  295. package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +620 -0
  296. package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +421 -0
  297. package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +3662 -0
  298. package/Tests/Server/Services/KubernetesClusterAiAccessSubjectClusters.test.ts +405 -0
  299. package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +975 -0
  300. package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +497 -0
  301. package/Tests/Server/Services/KubernetesClusterServiceDeleteSettlesRemediation.test.ts +328 -0
  302. package/Tests/Server/Services/LogAggregationService.test.ts +99 -0
  303. package/Tests/Server/Services/MonitorServiceIncomingEmailCustomAddress.test.ts +447 -0
  304. package/Tests/Server/Services/MonitorServiceProbeFlagSync.test.ts +1334 -0
  305. package/Tests/Server/Services/MonitorServiceProbeStatusGrouping.test.ts +1640 -0
  306. package/Tests/Server/Services/MonitorServiceRefreshCurrentStatus.test.ts +225 -0
  307. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +8 -8
  308. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +264 -1
  309. package/Tests/Server/Services/MonitorStatusTimelineMergedDowntime.test.ts +284 -0
  310. package/Tests/Server/Services/MonitorUptimeSummaryService.test.ts +1043 -0
  311. package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +5 -0
  312. package/Tests/Server/Services/OnCallUndeliverablePageOwnerMembership.test.ts +359 -0
  313. package/Tests/Server/Services/ProbeServiceDashboardLink.test.ts +191 -0
  314. package/Tests/Server/Services/ProjectOwnersProjectMembership.test.ts +221 -0
  315. package/Tests/Server/Services/RuleRun/IncidentAlertMaintenanceRuleEnginesRun.test.ts +5 -0
  316. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupARun.test.ts +28 -0
  317. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +9 -1
  318. package/Tests/Server/Services/RunnerJobEnqueueAiCommandAgentRunner.test.ts +230 -0
  319. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +978 -0
  320. package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +866 -0
  321. package/Tests/Server/Services/RunnerJobSubmitResultRedaction.test.ts +322 -0
  322. package/Tests/Server/Services/RunnerJobSubmitResultUnstorableText.test.ts +357 -0
  323. package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +227 -0
  324. package/Tests/Server/Services/RunnerServiceAgentName.test.ts +581 -0
  325. package/Tests/Server/Services/ScheduledMaintenancePublicNoteNotifyDefault.test.ts +802 -0
  326. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +53 -0
  327. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +5 -0
  328. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +12 -0
  329. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +1176 -1
  330. package/Tests/Server/Services/TeamMemberBillingSeatSync.test.ts +9 -0
  331. package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +18 -0
  332. package/Tests/Server/Services/TeamMemberProjectMembership.test.ts +255 -0
  333. package/Tests/Server/Services/TeamMemberRemovalRevokesProjectAccess.test.ts +600 -0
  334. package/Tests/Server/Services/TeamMemberResourceCleanup.test.ts +731 -0
  335. package/Tests/Server/Services/TeamMemberWorkspaceAccountCleanup.test.ts +164 -0
  336. package/Tests/Server/Services/TraceAggregationService.test.ts +64 -0
  337. package/Tests/Server/Services/UserServiceBlockedUser.test.ts +293 -0
  338. package/Tests/Server/Services/WorkflowVariableOAuthHooks.test.ts +1016 -0
  339. package/Tests/Server/Services/WorkflowVariableOAuthPostgres.test.ts +543 -0
  340. package/Tests/Server/Services/WorkflowVariableRenameUniqueness.test.ts +16 -5
  341. package/Tests/Server/Services/WorkspaceNotificationRuleNoteDelivery.test.ts +473 -0
  342. package/Tests/Server/Services/WorkspaceNotificationRuleSendTestNotification.test.ts +3690 -0
  343. package/Tests/Server/Services/WorkspaceProjectAuthTokenMiscDataSecrets.test.ts +374 -0
  344. package/Tests/Server/Services/WorkspaceProjectAuthTokenSlackChannelCache.test.ts +143 -0
  345. package/Tests/Server/Types/Database/Permissions/WorkflowVariableOAuthColumnPermission.test.ts +250 -0
  346. package/Tests/Server/Types/Database/QueryHelperJsonContains.test.ts +96 -0
  347. package/Tests/Server/Types/Markdown.test.ts +1033 -0
  348. package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +285 -0
  349. package/Tests/Server/Utils/AI/CodeFix/CodeFixAgentAuth.test.ts +159 -1
  350. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +752 -0
  351. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +1840 -0
  352. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +1067 -0
  353. package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +355 -0
  354. package/Tests/Server/Utils/AI/PostIncidentStatusUpdateTool.test.ts +496 -0
  355. package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +305 -0
  356. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +1365 -0
  357. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +639 -0
  358. package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +1585 -0
  359. package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +1065 -0
  360. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +2138 -1
  361. package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +1035 -0
  362. package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +517 -0
  363. package/Tests/Server/Utils/AI/ResourceTools.test.ts +27 -1
  364. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +1371 -24
  365. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorRollbackRace.test.ts +962 -0
  366. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +518 -0
  367. package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +939 -2
  368. package/Tests/Server/Utils/Database/ProjectScopedRelationReferences.test.ts +371 -0
  369. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +64 -0
  370. package/Tests/Server/Utils/Monitor/DatabaseMetricObservationRemediation.test.ts +102 -0
  371. package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +362 -0
  372. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +55 -0
  373. package/Tests/Server/Utils/Monitor/MonitorEmailAddressRedaction.test.ts +255 -0
  374. package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +347 -0
  375. package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +203 -0
  376. package/Tests/Server/Utils/Monitor/ProbeMonitorsNotification.test.ts +1147 -0
  377. package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +79 -0
  378. package/Tests/Server/Utils/ResourceFeed/ResourceFeedUtil.test.ts +21 -1
  379. package/Tests/Server/Utils/Rules/OwnerRuleAssignment.test.ts +155 -1
  380. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +288 -0
  381. package/Tests/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.test.ts +304 -0
  382. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +40 -3
  383. package/Tests/Server/Utils/Workflow/OAuth2TokenClient.test.ts +702 -0
  384. package/Tests/Server/Utils/Workflow/OAuth2TokenClientHttpIntegration.test.ts +507 -0
  385. package/Tests/Server/Utils/Workflow/WorkflowVariableOAuthToken.test.ts +831 -0
  386. package/Tests/Server/Utils/Workspace/MicrosoftTeamsActionAuthorization.test.ts +63 -1
  387. package/Tests/Server/Utils/Workspace/MicrosoftTeamsAppAccessToken.test.ts +256 -0
  388. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +60 -0
  389. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChatActionAuthorization.test.ts +442 -0
  390. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +44 -2
  391. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +55 -0
  392. package/Tests/Server/Utils/Workspace/MicrosoftTeamsReactionNoteSync.test.ts +1522 -0
  393. package/Tests/Server/Utils/Workspace/MicrosoftTeamsServiceUrl.test.ts +130 -0
  394. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +4 -4
  395. package/Tests/Server/Utils/Workspace/Slack/SlackActionAuthorization.test.ts +691 -0
  396. package/Tests/Server/Utils/Workspace/Slack/SlackMessageByTimestamp.test.ts +253 -0
  397. package/Tests/Server/Utils/Workspace/Slack/SlackReactionNote.test.ts +574 -0
  398. package/Tests/Server/Utils/Workspace/WorkspaceActionAuthorization.test.ts +488 -0
  399. package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +861 -0
  400. package/Tests/Server/Utils/Workspace/WorkspaceMessageAuthor.test.ts +635 -0
  401. package/Tests/Server/Utils/Workspace/WorkspaceOAuthState.test.ts +548 -0
  402. package/Tests/Server/Utils/Workspace/WorkspaceReactionNote.test.ts +839 -0
  403. package/Tests/Server/Utils/Workspace/WorkspaceSendErrorMessage.test.ts +725 -0
  404. package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +283 -9
  405. package/Tests/Types/DateBrowserLocalWallClock.test.ts +280 -0
  406. package/Tests/Types/DateLocalShortMonthNameFallback.test.ts +389 -0
  407. package/Tests/Types/DateUserTimezone.test.ts +177 -4
  408. package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +306 -0
  409. package/Tests/Types/Kubernetes/KubernetesClusterAiAccess.test.ts +283 -0
  410. package/Tests/Types/Kubernetes/KubernetesRunnerPostureWriteScope.test.ts +68 -0
  411. package/Tests/Types/Monitor/DatabaseMonitor/SqlServerPlatform.test.ts +144 -0
  412. package/Tests/Types/Monitor/MonitorStepExceptionMonitor.test.ts +160 -0
  413. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +53 -0
  414. package/Tests/Types/Runbook/RunbookStepType.test.ts +91 -16
  415. package/Tests/Types/Runner/RunnerLiveStatus.test.ts +14 -3
  416. package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +15 -0
  417. package/Tests/Types/StatusPage/PublicNoteSubscriberNotificationDefault.test.ts +1868 -0
  418. package/Tests/Types/Timezone.test.ts +5 -0
  419. package/Tests/Types/TimezoneAlias.test.ts +1034 -0
  420. package/Tests/Types/Workflow/JiraTemplateFixtures.ts +833 -0
  421. package/Tests/Types/Workflow/JiraTemplateScripts.test.ts +5414 -0
  422. package/Tests/Types/Workflow/JiraTemplateSimulation.test.ts +4803 -0
  423. package/Tests/Types/Workflow/JiraTemplates.test.ts +5429 -0
  424. package/Tests/Types/Workflow/Templates.test.ts +79 -4
  425. package/Tests/Types/Workflow/WorkflowVariableOAuth.test.ts +520 -0
  426. package/Tests/Types/Workspace/WorkspaceNoteReaction.test.ts +177 -0
  427. package/Tests/UI/Components/AttributesJSON/AttributesJSONView.test.tsx +390 -0
  428. package/Tests/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.test.tsx +566 -0
  429. package/Tests/UI/Components/AttributesJSON/JSONHighlight.test.ts +131 -0
  430. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +276 -1
  431. package/Tests/UI/Components/Calendar/Calendar.test.tsx +1611 -0
  432. package/Tests/UI/Components/Calendar/CalendarDayLayout.test.ts +1486 -0
  433. package/Tests/UI/Components/Calendar/CalendarDayLayoutDst.test.ts +632 -0
  434. package/Tests/UI/Components/Calendar/CalendarDst.test.tsx +388 -0
  435. package/Tests/UI/Components/Charts/ChartGroupPlotFloor.test.tsx +170 -0
  436. package/Tests/UI/Components/Charts/HistogramSelection.test.ts +282 -0
  437. package/Tests/UI/Components/CustomTimeRangeModal.test.tsx +6 -0
  438. package/Tests/UI/Components/CustomTimeRangeModalTimezoneTranslation.test.tsx +285 -0
  439. package/Tests/UI/Components/Dropdown.test.tsx +999 -2
  440. package/Tests/UI/Components/Forms/FormFieldCheckboxTranslation.test.tsx +216 -0
  441. package/Tests/UI/Components/Forms/FormFieldTimezoneDescriptionTranslation.test.tsx +461 -0
  442. package/Tests/UI/Components/Forms/IncidentEpisodePublicNoteNotifyPayload.test.tsx +641 -0
  443. package/Tests/UI/Components/Forms/IncidentPublicNoteNotifyPayload.test.tsx +346 -0
  444. package/Tests/UI/Components/Forms/ScheduledMaintenancePublicNoteNotifyPayload.test.tsx +493 -0
  445. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +911 -2
  446. package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.NewYork.test.tsx +730 -0
  447. package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.Tokyo.test.tsx +506 -0
  448. package/Tests/UI/Components/HistogramClickToZoom.test.tsx +619 -0
  449. package/Tests/UI/Components/LogDetailsPanelAttributesJSON.test.tsx +248 -0
  450. package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +47 -1
  451. package/Tests/UI/Components/LogsViewerSmallScreens.test.tsx +620 -0
  452. package/Tests/UI/Components/ModelPageModelChange.test.tsx +242 -3
  453. package/Tests/UI/Components/ModelTable/BaseModelTableDeleteConfirmation.test.tsx +521 -0
  454. package/Tests/UI/Components/MonitorGraphs/Uptime.test.tsx +406 -2
  455. package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +169 -2
  456. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +266 -0
  457. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerSmallScreens.test.tsx +439 -0
  458. package/Tests/UI/Components/TimezoneDropdownLegacyValues.test.tsx +704 -0
  459. package/Tests/UI/Components/UseHistogramZoom.test.tsx +89 -1
  460. package/Tests/UI/Components/UseLogsHistogram.test.tsx +175 -0
  461. package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +5 -5
  462. package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +28 -0
  463. package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +51 -0
  464. package/Tests/UI/Utils/Timezone.test.ts +747 -33
  465. package/Tests/UI/Workspace/SendTestNotificationButton.test.tsx +1854 -0
  466. package/Tests/UI/Workspace/WorkspaceCardsSendTestNotification.test.tsx +1864 -0
  467. package/Tests/Utils/AI/InvestigationReport.test.ts +435 -7
  468. package/Tests/Utils/AiRemediation/KubectlAllowlistValidatorParity.test.ts +1084 -0
  469. package/Tests/Utils/AiRemediation/KubectlOutputRedactor.test.ts +2531 -0
  470. package/Tests/Utils/AiRemediation/KubectlPolicy.test.ts +1895 -0
  471. package/Tests/Utils/AiRemediation/KubectlPolicyAllowlist.test.ts +428 -0
  472. package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +828 -0
  473. package/Tests/Utils/AiRemediation/KubectlPolicyCustomResourceScope.test.ts +573 -0
  474. package/Tests/Utils/AiRemediation/KubectlPolicyDenials.test.ts +1525 -0
  475. package/Tests/Utils/AiRemediation/KubectlPolicyExposeOverrides.test.ts +275 -0
  476. package/Tests/Utils/AiRemediation/KubectlPolicyNodePatch.test.ts +428 -0
  477. package/Tests/Utils/AiRemediation/KubectlPolicyObjectWords.test.ts +195 -0
  478. package/Tests/Utils/AiRemediation/KubectlPolicyPatchParents.test.ts +637 -0
  479. package/Tests/Utils/AiRemediation/KubectlPolicyPodSecurityBaseline.test.ts +322 -0
  480. package/Tests/Utils/AiRemediation/KubectlPolicySafeWriteScope.test.ts +1026 -0
  481. package/Tests/Utils/AiRemediation/KubectlWaitBudget.test.ts +267 -0
  482. package/Tests/Utils/AiRemediation/KubectlWriteScope.test.ts +390 -0
  483. package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +777 -0
  484. package/Tests/Utils/AiRemediation/KubectlWriteScopeClusterScoped.test.ts +613 -0
  485. package/Tests/Utils/AiRemediation/KubectlWriteScopeEntryPoint.test.ts +576 -0
  486. package/Tests/Utils/AiRemediation/KubectlWriteScopeKubectlSpellings.test.ts +752 -0
  487. package/Tests/Utils/AiRemediation/KubectlWriteScopeObjectWords.test.ts +358 -0
  488. package/Tests/Utils/AiRemediation/KubectlWriteScopeOverrides.test.ts +293 -0
  489. package/Tests/Utils/AiRemediation/KubectlWriteScopeParityCases.ts +598 -0
  490. package/Tests/Utils/AiRemediation/KubectlWriteScopePolicyParity.test.ts +403 -0
  491. package/Tests/Utils/Dashboard/DashboardClockComponent.test.ts +154 -5
  492. package/Tests/Utils/Monitor/IncomingEmailMonitorAddress.test.ts +478 -0
  493. package/Tests/Utils/Monitor/MonitorCheckScheduleUtil.test.ts +646 -0
  494. package/Tests/Utils/Monitor/MonitorOverviewCriteriaUtil.test.ts +292 -0
  495. package/Tests/Utils/Monitor/MonitorOverviewFamily.test.ts +274 -0
  496. package/Tests/Utils/Monitor/MonitorOverviewPresentationUtil.test.ts +3100 -0
  497. package/Tests/Utils/Monitor/MonitorOverviewProbeUtil.test.ts +1412 -0
  498. package/Tests/Utils/Monitor/MonitorOverviewTargetUtil.test.ts +374 -0
  499. package/Tests/Utils/Monitor/MonitorStatusHistoryUtil.test.ts +332 -0
  500. package/Tests/Utils/Monitor/MonitorUptimeSummaryUtil.test.ts +946 -0
  501. package/Tests/Utils/Rum/SessionIdentity.test.ts +94 -0
  502. package/Tests/Utils/Rum/SessionReplayWafCompatibility.test.ts +840 -0
  503. package/Tests/Utils/Rum/SessionReplayWireEncoding.test.ts +208 -0
  504. package/Tests/Utils/Rum/UserFlow.test.ts +1010 -0
  505. package/Tests/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.test.ts +217 -0
  506. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +1272 -1
  507. package/Tests/Utils/StatusPage/UptimeDailyAggregateTotals.test.ts +298 -0
  508. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +649 -1
  509. package/Tests/Utils/StatusPage/UptimeDailyAggregateWindow.test.ts +314 -0
  510. package/Tests/Utils/Telemetry/AttributesJSON.test.ts +454 -0
  511. package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +418 -2
  512. package/Tests/Utils/Uptime/DayUptimeGraphUtilMidnightDst.test.ts +160 -0
  513. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Auckland.test.ts +45 -0
  514. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Kolkata.test.ts +40 -0
  515. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.London.test.ts +147 -0
  516. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.NewYork.test.ts +48 -0
  517. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Tokyo.test.ts +39 -0
  518. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezoneCases.ts +1015 -0
  519. package/Tests/Utils/Uptime/UptimeUtil.test.ts +75 -0
  520. package/Tests/Utils/Uptime/UptimeUtilChronologicalOrder.test.ts +1279 -0
  521. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +203 -5
  522. package/Types/Date.ts +121 -7
  523. package/Types/Email/EmailMessage.ts +8 -0
  524. package/Types/Email/EmailTemplateType.ts +1 -0
  525. package/Types/Exception/ExceptionMessages.ts +1 -0
  526. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +488 -0
  527. package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +54 -0
  528. package/Types/Kubernetes/KubernetesClusterAiAccessToolNames.ts +17 -0
  529. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +9 -0
  530. package/Types/Monitor/DatabaseMonitor/SqlServerPlatform.ts +117 -0
  531. package/Types/Monitor/KubernetesAlertTemplates.ts +6 -5
  532. package/Types/Monitor/MonitorStepExceptionMonitor.ts +56 -0
  533. package/Types/Monitor/MonitorUptimeSummary.ts +113 -0
  534. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +11 -0
  535. package/Types/Rum/SessionReplay.ts +55 -2
  536. package/Types/Rum/SessionReplayApi.ts +44 -1
  537. package/Types/Rum/UserFlow.ts +187 -0
  538. package/Types/Runbook/RunbookStepType.ts +10 -0
  539. package/Types/Runbook/RunnerJobOrigin.ts +15 -0
  540. package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +6 -2
  541. package/Types/StatusPage/MergedDowntimeTotals.ts +17 -0
  542. package/Types/StatusPage/PublicNoteSubscriberNotificationDefault.ts +148 -0
  543. package/Types/StatusPage/UptimeDailyAggregate.ts +15 -0
  544. package/Types/Telemetry/TelemetryIngestSurface.ts +9 -0
  545. package/Types/Timezone.ts +5 -0
  546. package/Types/TimezoneAlias.ts +385 -0
  547. package/Types/Workflow/Templates.ts +3041 -2
  548. package/Types/Workflow/WorkflowVariableOAuth.ts +476 -0
  549. package/Types/Workspace/WorkspaceNoteReaction.ts +132 -0
  550. package/Typings/Index.d.ts +24 -0
  551. package/UI/Components/AttributesJSON/AttributesJSONPreferences.ts +175 -0
  552. package/UI/Components/AttributesJSON/AttributesJSONView.tsx +138 -0
  553. package/UI/Components/AttributesJSON/AttributesViewToggle.tsx +79 -0
  554. package/UI/Components/AttributesJSON/BracesGlyph.tsx +30 -0
  555. package/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.tsx +491 -0
  556. package/UI/Components/AttributesJSON/JSONHighlight.ts +77 -0
  557. package/UI/Components/Calendar/Calendar.css +83 -0
  558. package/UI/Components/Calendar/Calendar.tsx +136 -7
  559. package/UI/Components/Calendar/CalendarDayLayout.ts +236 -0
  560. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +23 -1
  561. package/UI/Components/Charts/Utils/HistogramSelection.ts +117 -0
  562. package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +269 -0
  563. package/UI/Components/Charts/Utils/useHistogramZoom.ts +26 -2
  564. package/UI/Components/Date/CustomTimeRangeModal.tsx +26 -3
  565. package/UI/Components/Dropdown/Dropdown.tsx +58 -9
  566. package/UI/Components/Forms/Fields/FormField.tsx +49 -14
  567. package/UI/Components/Graphs/DayUptimeGraph.tsx +166 -25
  568. package/UI/Components/Graphs/UptimeBarTooltip.tsx +10 -2
  569. package/UI/Components/Graphs/UptimeDaySummary.tsx +8 -0
  570. package/UI/Components/LogsViewer/LogsViewer.tsx +52 -5
  571. package/UI/Components/LogsViewer/components/ColumnSelector.tsx +13 -2
  572. package/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.tsx +13 -1
  573. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +91 -76
  574. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +15 -1
  575. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +28 -106
  576. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +54 -6
  577. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +8 -2
  578. package/UI/Components/LogsViewer/useLogsHistogram.ts +39 -6
  579. package/UI/Components/ModelTable/BaseModelTable.tsx +66 -14
  580. package/UI/Components/MonitorGraphs/Uptime.tsx +12 -0
  581. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +10 -2
  582. package/UI/Components/Page/ModelPage.tsx +59 -3
  583. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +69 -5
  584. package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +12 -1
  585. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +15 -1
  586. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +36 -104
  587. package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +9 -1
  588. package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +19 -1
  589. package/UI/Utils/Timezone.ts +69 -28
  590. package/Utils/AI/InvestigationReport.ts +195 -25
  591. package/Utils/AiRemediation/KubectlOutputRedactor.ts +1724 -0
  592. package/Utils/AiRemediation/KubectlPolicy.ts +4136 -0
  593. package/Utils/AiRemediation/KubectlWaitBudget.ts +156 -0
  594. package/Utils/AiRemediation/KubectlWriteScope.ts +1964 -0
  595. package/Utils/Dashboard/Components/DashboardClockComponent.ts +7 -6
  596. package/Utils/Monitor/IncomingEmailMonitorAddress.ts +292 -0
  597. package/Utils/Monitor/MonitorCheckScheduleUtil.ts +654 -0
  598. package/Utils/Monitor/MonitorOverviewCriteriaUtil.ts +188 -0
  599. package/Utils/Monitor/MonitorOverviewFamily.ts +263 -0
  600. package/Utils/Monitor/MonitorOverviewPresentationUtil.ts +1958 -0
  601. package/Utils/Monitor/MonitorOverviewProbeUtil.ts +979 -0
  602. package/Utils/Monitor/MonitorOverviewTargetUtil.ts +299 -0
  603. package/Utils/Monitor/MonitorStatusHistoryUtil.ts +201 -0
  604. package/Utils/Monitor/MonitorUptimeSummaryUtil.ts +638 -0
  605. package/Utils/Rum/SessionIdentity.ts +44 -0
  606. package/Utils/Rum/SessionReplayWireEncoding.ts +137 -0
  607. package/Utils/Rum/UserFlow.ts +1527 -0
  608. package/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.ts +107 -0
  609. package/Utils/StatusPage/ResourceUptime.ts +99 -0
  610. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +197 -0
  611. package/Utils/Telemetry/AttributesJSON.ts +367 -0
  612. package/Utils/Uptime/DayUptimeGraphUtil.ts +165 -0
  613. package/Utils/Uptime/UptimeUtil.ts +122 -38
  614. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js +8 -1
  615. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js.map +1 -1
  616. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
  617. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
  618. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js +8 -1
  619. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js.map +1 -1
  620. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +10 -3
  621. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  622. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +10 -3
  623. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  624. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +434 -0
  625. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  626. package/build/dist/Models/DatabaseModels/Monitor.js +49 -0
  627. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  628. package/build/dist/Models/DatabaseModels/Runner.js +4 -4
  629. package/build/dist/Models/DatabaseModels/Runner.js.map +1 -1
  630. package/build/dist/Models/DatabaseModels/RunnerJob.js +66 -0
  631. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  632. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +11 -3
  633. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  634. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +487 -3
  635. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  636. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js +64 -16
  637. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  638. package/build/dist/Server/API/AIInvestigationAPI.js +205 -0
  639. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  640. package/build/dist/Server/API/AutoRemediationAPI.js +115 -2
  641. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  642. package/build/dist/Server/API/CommonAPI.js +49 -0
  643. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  644. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +564 -0
  645. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -0
  646. package/build/dist/Server/API/MicrosoftTeamsAPI.js +465 -176
  647. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  648. package/build/dist/Server/API/MonitorAPI.js +107 -1
  649. package/build/dist/Server/API/MonitorAPI.js.map +1 -1
  650. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +5 -16
  651. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -1
  652. package/build/dist/Server/API/SlackAPI.js +322 -78
  653. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  654. package/build/dist/Server/API/StatusPageAPI.js +123 -17
  655. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  656. package/build/dist/Server/API/TelemetryAPI.js +144 -5
  657. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  658. package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js +1 -0
  659. package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js.map +1 -1
  660. package/build/dist/Server/API/WorkflowVariableAPI.js +109 -0
  661. package/build/dist/Server/API/WorkflowVariableAPI.js.map +1 -0
  662. package/build/dist/Server/Infrastructure/GlobalCache.js +29 -0
  663. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  664. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js +38 -0
  665. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js.map +1 -0
  666. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js +54 -0
  667. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js.map +1 -0
  668. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js +14 -0
  669. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js.map +1 -0
  670. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js +12 -0
  671. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js.map +1 -0
  672. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js +32 -0
  673. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js.map +1 -0
  674. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  675. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  676. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +21 -0
  677. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  678. package/build/dist/Server/Middleware/TelemetryIngest.js +32 -2
  679. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  680. package/build/dist/Server/Middleware/UserAuthorization.js +39 -6
  681. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  682. package/build/dist/Server/Services/AIAgentService.js +1 -0
  683. package/build/dist/Server/Services/AIAgentService.js.map +1 -1
  684. package/build/dist/Server/Services/AccessTokenService.js +87 -42
  685. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  686. package/build/dist/Server/Services/AlertEpisodeMemberService.js +4 -0
  687. package/build/dist/Server/Services/AlertEpisodeMemberService.js.map +1 -1
  688. package/build/dist/Server/Services/AlertEpisodeService.js +12 -1
  689. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  690. package/build/dist/Server/Services/AlertService.js +110 -23
  691. package/build/dist/Server/Services/AlertService.js.map +1 -1
  692. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +716 -30
  693. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  694. package/build/dist/Server/Services/AutoRemediationRuleService.js +100 -0
  695. package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
  696. package/build/dist/Server/Services/BillingService.js +1 -0
  697. package/build/dist/Server/Services/BillingService.js.map +1 -1
  698. package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js +11 -16
  699. package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js.map +1 -1
  700. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +4 -0
  701. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  702. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +48 -0
  703. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  704. package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js +21 -0
  705. package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js.map +1 -1
  706. package/build/dist/Server/Services/IncidentEpisodeService.js +12 -1
  707. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  708. package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -0
  709. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  710. package/build/dist/Server/Services/IncidentMemberService.js +14 -0
  711. package/build/dist/Server/Services/IncidentMemberService.js.map +1 -1
  712. package/build/dist/Server/Services/IncidentPublicNoteService.js +48 -0
  713. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  714. package/build/dist/Server/Services/IncidentService.js +99 -21
  715. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  716. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  717. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  718. package/build/dist/Server/Services/IncidentTemplateService.js +68 -4
  719. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  720. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +1470 -0
  721. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -0
  722. package/build/dist/Server/Services/KubernetesClusterService.js +1097 -0
  723. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  724. package/build/dist/Server/Services/LogAggregationService.js +14 -6
  725. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  726. package/build/dist/Server/Services/MonitorService.js +487 -48
  727. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  728. package/build/dist/Server/Services/MonitorStatusTimelineService.js +540 -3
  729. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  730. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -0
  731. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  732. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -0
  733. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  734. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -0
  735. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  736. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +3 -0
  737. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  738. package/build/dist/Server/Services/OnCallNotificationAlertingService.js +29 -7
  739. package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -1
  740. package/build/dist/Server/Services/OnCallSetupReminderService.js +1 -0
  741. package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -1
  742. package/build/dist/Server/Services/ProbeService.js +7 -1
  743. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  744. package/build/dist/Server/Services/ProjectService.js +11 -1
  745. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  746. package/build/dist/Server/Services/RunbookCredentialService.js +24 -0
  747. package/build/dist/Server/Services/RunbookCredentialService.js.map +1 -1
  748. package/build/dist/Server/Services/RunbookSecretService.js +44 -0
  749. package/build/dist/Server/Services/RunbookSecretService.js.map +1 -1
  750. package/build/dist/Server/Services/RunnerJobService.js +641 -21
  751. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  752. package/build/dist/Server/Services/RunnerService.js +344 -5
  753. package/build/dist/Server/Services/RunnerService.js.map +1 -1
  754. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +48 -0
  755. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  756. package/build/dist/Server/Services/ScheduledMaintenanceService.js +102 -20
  757. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  758. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +67 -4
  759. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  760. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +12 -1
  761. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  762. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -0
  763. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  764. package/build/dist/Server/Services/StatusPageService.js +230 -32
  765. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  766. package/build/dist/Server/Services/StatusPageSubscriberService.js +4 -0
  767. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  768. package/build/dist/Server/Services/TeamMemberService.js +270 -11
  769. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  770. package/build/dist/Server/Services/TraceAggregationService.js +10 -6
  771. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  772. package/build/dist/Server/Services/UserEmailService.js +1 -0
  773. package/build/dist/Server/Services/UserEmailService.js.map +1 -1
  774. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1 -0
  775. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  776. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +1 -0
  777. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  778. package/build/dist/Server/Services/UserNotificationRuleService.js +4 -0
  779. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  780. package/build/dist/Server/Services/UserService.js +107 -1
  781. package/build/dist/Server/Services/UserService.js.map +1 -1
  782. package/build/dist/Server/Services/WorkflowVariableService.js +396 -7
  783. package/build/dist/Server/Services/WorkflowVariableService.js.map +1 -1
  784. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +463 -7
  785. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  786. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +144 -2
  787. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  788. package/build/dist/Server/Types/Database/QueryHelper.js +20 -0
  789. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  790. package/build/dist/Server/Types/Markdown.js +394 -27
  791. package/build/dist/Server/Types/Markdown.js.map +1 -1
  792. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +123 -0
  793. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -0
  794. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +344 -0
  795. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -0
  796. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +587 -0
  797. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -0
  798. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js +18 -2
  799. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js.map +1 -1
  800. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1380 -239
  801. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  802. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +1099 -68
  803. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  804. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +88 -6
  805. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  806. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +45 -11
  807. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  808. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +41 -11
  809. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  810. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js +11 -4
  811. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -1
  812. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +4 -2
  813. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
  814. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +997 -141
  815. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  816. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +299 -4
  817. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
  818. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +120 -0
  819. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -0
  820. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +160 -1
  821. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  822. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +1 -0
  823. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
  824. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +59 -12
  825. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  826. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +5 -1
  827. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  828. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +84 -22
  829. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  830. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +70 -5
  831. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -1
  832. package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js +249 -0
  833. package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js.map +1 -0
  834. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1 -0
  835. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -1
  836. package/build/dist/Server/Utils/PushNotificationUtil.js +27 -0
  837. package/build/dist/Server/Utils/PushNotificationUtil.js.map +1 -1
  838. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +26 -3
  839. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -1
  840. package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js +38 -3
  841. package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js.map +1 -1
  842. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +143 -23
  843. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  844. package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js +406 -0
  845. package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js.map +1 -0
  846. package/build/dist/Server/Utils/StartServer.js +4 -3
  847. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  848. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +382 -0
  849. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -0
  850. package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js +1 -0
  851. package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js.map +1 -1
  852. package/build/dist/Server/Utils/UserPermission/UserPermission.js +10 -0
  853. package/build/dist/Server/Utils/UserPermission/UserPermission.js.map +1 -1
  854. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +447 -0
  855. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -0
  856. package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js +202 -0
  857. package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js.map +1 -0
  858. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +39 -1
  859. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
  860. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +44 -4
  861. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
  862. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +150 -191
  863. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  864. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +44 -4
  865. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  866. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js +39 -17
  867. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js.map +1 -1
  868. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +151 -145
  869. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
  870. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +221 -127
  871. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  872. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js +91 -0
  873. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js.map +1 -0
  874. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js +673 -0
  875. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js.map +1 -0
  876. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +3 -9
  877. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
  878. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +65 -166
  879. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -1
  880. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js +63 -157
  881. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js.map +1 -1
  882. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +23 -3
  883. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
  884. package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js +92 -0
  885. package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js.map +1 -0
  886. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +81 -210
  887. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
  888. package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js +68 -138
  889. package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js.map +1 -1
  890. package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js +240 -0
  891. package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js.map +1 -0
  892. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +85 -212
  893. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -1
  894. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +60 -17
  895. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  896. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
  897. package/build/dist/Server/Utils/Workspace/Workspace.js +134 -41
  898. package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
  899. package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js +197 -0
  900. package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js.map +1 -0
  901. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +32 -0
  902. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  903. package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js +199 -0
  904. package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js.map +1 -0
  905. package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js +91 -0
  906. package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js.map +1 -0
  907. package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js +450 -0
  908. package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js.map +1 -0
  909. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +103 -5
  910. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  911. package/build/dist/Types/Date.js +97 -7
  912. package/build/dist/Types/Date.js.map +1 -1
  913. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  914. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  915. package/build/dist/Types/Exception/ExceptionMessages.js +1 -0
  916. package/build/dist/Types/Exception/ExceptionMessages.js.map +1 -1
  917. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +245 -0
  918. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -0
  919. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +49 -0
  920. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -0
  921. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js +16 -0
  922. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js.map +1 -0
  923. package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js +104 -0
  924. package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js.map +1 -0
  925. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +6 -5
  926. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  927. package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js +32 -0
  928. package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js.map +1 -1
  929. package/build/dist/Types/Monitor/MonitorUptimeSummary.js +52 -0
  930. package/build/dist/Types/Monitor/MonitorUptimeSummary.js.map +1 -0
  931. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +9 -1
  932. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  933. package/build/dist/Types/Rum/SessionReplay.js +52 -2
  934. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  935. package/build/dist/Types/Rum/SessionReplayApi.js +11 -0
  936. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
  937. package/build/dist/Types/Rum/UserFlow.js +115 -0
  938. package/build/dist/Types/Rum/UserFlow.js.map +1 -0
  939. package/build/dist/Types/Runbook/RunbookStepType.js +10 -0
  940. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  941. package/build/dist/Types/Runbook/RunnerJobOrigin.js +14 -0
  942. package/build/dist/Types/Runbook/RunnerJobOrigin.js.map +1 -1
  943. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +2 -2
  944. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -1
  945. package/build/dist/Types/StatusPage/MergedDowntimeTotals.js +2 -0
  946. package/build/dist/Types/StatusPage/MergedDowntimeTotals.js.map +1 -0
  947. package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js +65 -0
  948. package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js.map +1 -0
  949. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +8 -0
  950. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  951. package/build/dist/Types/Timezone.js +5 -0
  952. package/build/dist/Types/Timezone.js.map +1 -1
  953. package/build/dist/Types/TimezoneAlias.js +340 -0
  954. package/build/dist/Types/TimezoneAlias.js.map +1 -0
  955. package/build/dist/Types/Workflow/Templates.js +2694 -2
  956. package/build/dist/Types/Workflow/Templates.js.map +1 -1
  957. package/build/dist/Types/Workflow/WorkflowVariableOAuth.js +314 -0
  958. package/build/dist/Types/Workflow/WorkflowVariableOAuth.js.map +1 -0
  959. package/build/dist/Types/Workspace/WorkspaceNoteReaction.js +98 -0
  960. package/build/dist/Types/Workspace/WorkspaceNoteReaction.js.map +1 -0
  961. package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js +95 -0
  962. package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js.map +1 -0
  963. package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js +44 -0
  964. package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js.map +1 -0
  965. package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js +27 -0
  966. package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js.map +1 -0
  967. package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js +9 -0
  968. package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js.map +1 -0
  969. package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js +260 -0
  970. package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js.map +1 -0
  971. package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js +56 -0
  972. package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js.map +1 -0
  973. package/build/dist/UI/Components/Calendar/Calendar.js +94 -7
  974. package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
  975. package/build/dist/UI/Components/Calendar/CalendarDayLayout.js +136 -0
  976. package/build/dist/UI/Components/Calendar/CalendarDayLayout.js.map +1 -0
  977. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +1 -1
  978. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  979. package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js +72 -0
  980. package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js.map +1 -0
  981. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +178 -0
  982. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -0
  983. package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js +13 -1
  984. package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js.map +1 -1
  985. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js +20 -4
  986. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js.map +1 -1
  987. package/build/dist/UI/Components/Dropdown/Dropdown.js +33 -9
  988. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  989. package/build/dist/UI/Components/Forms/Fields/FormField.js +36 -13
  990. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  991. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +117 -11
  992. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  993. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -1
  994. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  995. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -1
  996. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +36 -8
  997. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  998. package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js +10 -2
  999. package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js.map +1 -1
  1000. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js +9 -1
  1001. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js.map +1 -1
  1002. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +16 -15
  1003. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  1004. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
  1005. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  1006. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +14 -74
  1007. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  1008. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +22 -5
  1009. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  1010. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +9 -2
  1011. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  1012. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +16 -5
  1013. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -1
  1014. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +23 -8
  1015. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1016. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +7 -1
  1017. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  1018. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +5 -1
  1019. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  1020. package/build/dist/UI/Components/Page/ModelPage.js +37 -3
  1021. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  1022. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +27 -6
  1023. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1024. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +7 -1
  1025. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
  1026. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
  1027. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  1028. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +17 -77
  1029. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  1030. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +10 -1
  1031. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -1
  1032. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +15 -1
  1033. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -1
  1034. package/build/dist/UI/Utils/Timezone.js +52 -17
  1035. package/build/dist/UI/Utils/Timezone.js.map +1 -1
  1036. package/build/dist/Utils/AI/InvestigationReport.js +116 -21
  1037. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
  1038. package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js +1209 -0
  1039. package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js.map +1 -0
  1040. package/build/dist/Utils/AiRemediation/KubectlPolicy.js +2973 -0
  1041. package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -0
  1042. package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js +99 -0
  1043. package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js.map +1 -0
  1044. package/build/dist/Utils/AiRemediation/KubectlWriteScope.js +1429 -0
  1045. package/build/dist/Utils/AiRemediation/KubectlWriteScope.js.map +1 -0
  1046. package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js +7 -6
  1047. package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js.map +1 -1
  1048. package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js +214 -0
  1049. package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js.map +1 -0
  1050. package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js +471 -0
  1051. package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js.map +1 -0
  1052. package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js +107 -0
  1053. package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js.map +1 -0
  1054. package/build/dist/Utils/Monitor/MonitorOverviewFamily.js +191 -0
  1055. package/build/dist/Utils/Monitor/MonitorOverviewFamily.js.map +1 -0
  1056. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js +1259 -0
  1057. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js.map +1 -0
  1058. package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js +593 -0
  1059. package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js.map +1 -0
  1060. package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js +195 -0
  1061. package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js.map +1 -0
  1062. package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js +127 -0
  1063. package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js.map +1 -0
  1064. package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js +464 -0
  1065. package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js.map +1 -0
  1066. package/build/dist/Utils/Rum/SessionIdentity.js +31 -1
  1067. package/build/dist/Utils/Rum/SessionIdentity.js.map +1 -1
  1068. package/build/dist/Utils/Rum/SessionReplayWireEncoding.js +128 -0
  1069. package/build/dist/Utils/Rum/SessionReplayWireEncoding.js.map +1 -0
  1070. package/build/dist/Utils/Rum/UserFlow.js +941 -0
  1071. package/build/dist/Utils/Rum/UserFlow.js.map +1 -0
  1072. package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js +82 -0
  1073. package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js.map +1 -0
  1074. package/build/dist/Utils/StatusPage/ResourceUptime.js +46 -0
  1075. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  1076. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  1077. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -1
  1078. package/build/dist/Utils/Telemetry/AttributesJSON.js +245 -0
  1079. package/build/dist/Utils/Telemetry/AttributesJSON.js.map +1 -0
  1080. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +103 -0
  1081. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -1
  1082. package/build/dist/Utils/Uptime/UptimeUtil.js +91 -27
  1083. package/build/dist/Utils/Uptime/UptimeUtil.js.map +1 -1
  1084. package/jest.config.json +2 -1
  1085. package/package.json +2 -1
  1086. package/tsconfig.tests.json +36 -0
  1087. package/Tests/UI/Components/EmptyState/EmptyStateGuideLinks.test.tsx +0 -337
  1088. package/UI/Components/EmptyState/EmptyStateGuideLinks.tsx +0 -124
  1089. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js +0 -47
  1090. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js.map +0 -1
@@ -0,0 +1,2136 @@
1
+ /** @timezone UTC */
2
+
3
+ import "@testing-library/jest-dom";
4
+ import {
5
+ act,
6
+ cleanup,
7
+ fireEvent,
8
+ render,
9
+ RenderResult,
10
+ screen,
11
+ within,
12
+ } from "@testing-library/react";
13
+ import React, { ReactElement } from "react";
14
+ import {
15
+ MemoryRouter,
16
+ Outlet,
17
+ Route as RouterRoute,
18
+ Routes,
19
+ } from "react-router-dom";
20
+
21
+ /*
22
+ * The monitor overview page, rendered for real over a fake server, with
23
+ * every heavy or self-fetching card stubbed. What is under test is the page
24
+ * itself: the first load and its failures, the order of the cards, which
25
+ * cards each monitor family gets, what each role can see, and the refresh
26
+ * and model-change rules (a refresh never unmounts a card; nothing of the
27
+ * monitor the reader left shows on the next one).
28
+ *
29
+ * The cards, the hooks and the presentation model have their own suites;
30
+ * this one checks that the page wires them together as the spec says.
31
+ */
32
+
33
+ const recordedProps: Record<string, Array<Record<string, unknown>>> = {};
34
+ const mountCounts: Record<string, number> = {};
35
+
36
+ /*
37
+ * Function declarations, so they are hoisted along with the jest.mock calls
38
+ * that use them. Everything they touch is dereferenced lazily, at render
39
+ * time, after the module's consts are initialised.
40
+ */
41
+ function recordProps(key: string, props: Record<string, unknown>): void {
42
+ if (!recordedProps[key]) {
43
+ recordedProps[key] = [];
44
+ }
45
+
46
+ recordedProps[key]!.push(props);
47
+ }
48
+
49
+ function StubBody(data: {
50
+ stubKey: string;
51
+ testId: string;
52
+ props: Record<string, unknown>;
53
+ }): ReactElement {
54
+ recordProps(data.stubKey, data.props);
55
+
56
+ React.useEffect(() => {
57
+ mountCounts[data.stubKey] = (mountCounts[data.stubKey] || 0) + 1;
58
+ }, []);
59
+
60
+ return React.createElement("div", { "data-testid": data.testId });
61
+ }
62
+
63
+ function stubModule(key: string): {
64
+ __esModule: boolean;
65
+ default: (props: Record<string, unknown>) => ReactElement;
66
+ } {
67
+ return {
68
+ __esModule: true,
69
+ default: (props: Record<string, unknown>): ReactElement => {
70
+ return StubBody({ stubKey: key, testId: `stub-${key}`, props: props });
71
+ },
72
+ };
73
+ }
74
+
75
+ jest.mock(
76
+ "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/SummaryView/Summary",
77
+ () => {
78
+ return stubModule("Summary");
79
+ },
80
+ );
81
+ jest.mock(
82
+ "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/MonitorFeed",
83
+ () => {
84
+ return stubModule("MonitorFeed");
85
+ },
86
+ );
87
+ jest.mock(
88
+ "../../../../App/FeatureSet/Dashboard/src/Components/CustomFields/OverviewCustomFields",
89
+ () => {
90
+ return stubModule("OverviewCustomFields");
91
+ },
92
+ );
93
+ jest.mock(
94
+ "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/DependencySuppressionWarning",
95
+ () => {
96
+ return stubModule("DependencySuppressionWarning");
97
+ },
98
+ );
99
+ jest.mock(
100
+ "../../../../App/FeatureSet/Dashboard/src/Components/Metrics/EmbeddedMetricCard",
101
+ () => {
102
+ return stubModule("EmbeddedMetricCard");
103
+ },
104
+ );
105
+ jest.mock("../../../UI/Components/MonitorGraphs/Uptime", () => {
106
+ return stubModule("MonitorUptimeGraph");
107
+ });
108
+ jest.mock(
109
+ "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/LogMonitor/LogMonitorPreview",
110
+ () => {
111
+ return stubModule("LogMonitorPreview");
112
+ },
113
+ );
114
+ jest.mock(
115
+ "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/MetricMonitor/MetricMonitorPreview",
116
+ () => {
117
+ return stubModule("MetricMonitorPreview");
118
+ },
119
+ );
120
+ jest.mock(
121
+ "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/SecurityEventsMonitor/SecurityEventsMonitorPreview",
122
+ () => {
123
+ return stubModule("SecurityEventsMonitorPreview");
124
+ },
125
+ );
126
+ jest.mock(
127
+ "../../../../App/FeatureSet/Dashboard/src/Components/Traces/TraceTable",
128
+ () => {
129
+ return stubModule("TraceTable");
130
+ },
131
+ );
132
+ jest.mock(
133
+ "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/ServerMonitor/Documentation",
134
+ () => {
135
+ return stubModule("ServerMonitorDocumentation");
136
+ },
137
+ );
138
+ jest.mock(
139
+ "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/IncomingEmailMonitor/IncomingEmailMonitorLink",
140
+ () => {
141
+ // The connection card still needs the real address helper.
142
+ return {
143
+ ...jest.requireActual(
144
+ "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/IncomingEmailMonitor/IncomingEmailMonitorLink",
145
+ ),
146
+ ...stubModule("IncomingEmailMonitorLink"),
147
+ };
148
+ },
149
+ );
150
+ jest.mock("../../../UI/Components/ModelDetail/CardModelDetail", () => {
151
+ return {
152
+ __esModule: true,
153
+ default: (props: Record<string, unknown>): ReactElement => {
154
+ const name: string = props["name"] as string;
155
+
156
+ return StubBody({
157
+ stubKey: `CardModelDetail:${name}`,
158
+ testId: `stub-card-${name}`,
159
+ props: props,
160
+ });
161
+ },
162
+ };
163
+ });
164
+
165
+ import MonitorView from "../../../../App/FeatureSet/Dashboard/src/Pages/Monitor/View/Index";
166
+ import MonitorViewOutletContext from "../../../../App/FeatureSet/Dashboard/src/Pages/Monitor/View/MonitorViewOutletContext";
167
+ import PageComponentProps from "../../../../App/FeatureSet/Dashboard/src/Pages/PageComponentProps";
168
+ import {
169
+ MONITOR_OVERVIEW_NOT_FOUND_MESSAGE,
170
+ MONITOR_OVERVIEW_REFRESH_INTERVAL_MS,
171
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/Overview/useMonitorOverviewData";
172
+ import AlertStateUtil from "../../../../App/FeatureSet/Dashboard/src/Utils/AlertState";
173
+ import IncidentStateUtil from "../../../../App/FeatureSet/Dashboard/src/Utils/IncidentState";
174
+ import MonitorLog from "../../../Models/AnalyticsModels/MonitorLog";
175
+ import Alert from "../../../Models/DatabaseModels/Alert";
176
+ import AlertState from "../../../Models/DatabaseModels/AlertState";
177
+ import Incident from "../../../Models/DatabaseModels/Incident";
178
+ import IncidentState from "../../../Models/DatabaseModels/IncidentState";
179
+ import Monitor from "../../../Models/DatabaseModels/Monitor";
180
+ import MonitorOwnerTeam from "../../../Models/DatabaseModels/MonitorOwnerTeam";
181
+ import MonitorOwnerUser from "../../../Models/DatabaseModels/MonitorOwnerUser";
182
+ import MonitorProbe, {
183
+ MonitorStepProbeResponse,
184
+ } from "../../../Models/DatabaseModels/MonitorProbe";
185
+ import MonitorStatus from "../../../Models/DatabaseModels/MonitorStatus";
186
+ import MonitorStatusTimeline from "../../../Models/DatabaseModels/MonitorStatusTimeline";
187
+ import Probe, {
188
+ ProbeConnectionStatus,
189
+ } from "../../../Models/DatabaseModels/Probe";
190
+ import HTTPResponse from "../../../Types/API/HTTPResponse";
191
+ import Route from "../../../Types/API/Route";
192
+ import URL from "../../../Types/API/URL";
193
+ import Color from "../../../Types/Color";
194
+ import Dictionary from "../../../Types/Dictionary";
195
+ import { JSONObject } from "../../../Types/JSON";
196
+ import MonitorEvaluationSummary from "../../../Types/Monitor/MonitorEvaluationSummary";
197
+ import MonitorSteps from "../../../Types/Monitor/MonitorSteps";
198
+ import MonitorType from "../../../Types/Monitor/MonitorType";
199
+ import {
200
+ MonitorUptimeSummary,
201
+ MonitorUptimeWindowKey,
202
+ MonitorUptimeWindowTotal,
203
+ } from "../../../Types/Monitor/MonitorUptimeSummary";
204
+ import ObjectID from "../../../Types/ObjectID";
205
+ import Permission from "../../../Types/Permission";
206
+ import API from "../../../UI/Utils/API/API";
207
+ import AnalyticsModelAPI from "../../../UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI";
208
+ import ModelAPI from "../../../UI/Utils/ModelAPI/ModelAPI";
209
+ import Navigation from "../../../UI/Utils/Navigation";
210
+ import PermissionUtil from "../../../UI/Utils/Permission";
211
+ import ProjectUtil from "../../../UI/Utils/Project";
212
+ import MonitorUptimeSummaryUtil from "../../../Utils/Monitor/MonitorUptimeSummaryUtil";
213
+
214
+ const NOW: Date = new Date("2026-09-21T12:00:00.000Z");
215
+ const DAY_SECONDS: number = 86400;
216
+
217
+ // Real UUIDs: ObjectID and ProjectUtil ignore values that are not.
218
+ const PROJECT_ID: ObjectID = new ObjectID(
219
+ "7d3f1a2b-4c5d-4e6f-8a9b-0c1d2e3f4a5b",
220
+ );
221
+ const MONITOR_A: string = "9a1f0c2e-5b3d-4c7a-8e1f-2d3c4b5a6978";
222
+ const MONITOR_B: string = "4e5f6071-8293-4a4b-b5c6-d7e8f90a1b2c";
223
+ const OPERATIONAL_ID: string = "1b2c3d4e-5f60-4718-8293-a4b5c6d7e8f9";
224
+ const OFFLINE_ID: string = "2c3d4e5f-6071-4829-93a4-b5c6d7e8f901";
225
+ const STATUS_ROW_ID: string = "3d4e5f60-7182-493a-a4b5-c6d7e8f90a1b";
226
+ const STEP_ID: string = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
227
+ const PROBE_FRANKFURT: string = "11111111-1111-4111-8111-111111111111";
228
+ const PROBE_VIRGINIA: string = "22222222-2222-4222-8222-222222222222";
229
+ const DEVICE_ID: string = "66666666-6666-4666-8666-666666666666";
230
+ const INCIDENT_ID: string = "77777777-7777-4777-8777-777777777777";
231
+ const INCIDENT_STATE_ID: string = "88888888-8888-4888-8888-888888888888";
232
+ const ALERT_STATE_ID: string = "99999999-9999-4999-8999-999999999999";
233
+ // The heartbeat secret: it must never reach the DOM of someone who cannot read it.
234
+ const HEARTBEAT_SECRET: string = "5ec2e7a1-0b1c-4d2e-9f30-4a5b6c7d8e9f";
235
+ const SERVER_SECRET: string = "6fd3f8b2-1c2d-4e3f-a041-5b6c7d8e9fa0";
236
+
237
+ const SECRET_KEY_COLUMNS: Array<string> = [
238
+ "serverMonitorSecretKey",
239
+ "incomingRequestSecretKey",
240
+ "incomingEmailSecretKey",
241
+ ];
242
+
243
+ const pageProps: PageComponentProps = {
244
+ pageRoute: new Route("/overview"),
245
+ currentProject: null,
246
+ hasPaymentMethod: false,
247
+ };
248
+
249
+ const secondsAgo: (seconds: number) => Date = (seconds: number): Date => {
250
+ return new Date(NOW.getTime() - seconds * 1000);
251
+ };
252
+
253
+ interface Deferred<T> {
254
+ promise: Promise<T>;
255
+ resolve: (value: T) => void;
256
+ }
257
+
258
+ function createDeferred<T>(): Deferred<T> {
259
+ let resolve: (value: T) => void = (): void => {};
260
+ const promise: Promise<T> = new Promise<T>(
261
+ (promiseResolve: (value: T) => void): void => {
262
+ resolve = promiseResolve;
263
+ },
264
+ );
265
+
266
+ return { promise: promise, resolve: resolve };
267
+ }
268
+
269
+ /*
270
+ * Rejections are made by an async function, so they are native promises.
271
+ * The UI telemetry in the import graph loads zone.js, whose Promise reports
272
+ * a rejection as unhandled when a native await subscribes to it a tick
273
+ * later, which would fill the log with false alarms.
274
+ */
275
+ async function rejectWith(error: unknown): Promise<never> {
276
+ throw error;
277
+ }
278
+
279
+ // Partial<T> under exactOptionalPropertyTypes forbids an explicit undefined.
280
+ type MonitorOverrides = {
281
+ [K in keyof Monitor]?: Monitor[K] | undefined;
282
+ };
283
+
284
+ interface MonitorSpec {
285
+ id: string;
286
+ type: MonitorType;
287
+ statusId: string;
288
+ // Omitted: one plain step. Null: no steps at all.
289
+ stepData?: JSONObject | null;
290
+ overrides?: MonitorOverrides;
291
+ }
292
+
293
+ interface ProbeSpec {
294
+ probeId: string;
295
+ name: string;
296
+ isEnabled: boolean;
297
+ monitoredAt?: Date;
298
+ // Omitted: 20 s from now.
299
+ nextPingAt?: Date;
300
+ }
301
+
302
+ interface FakeServer {
303
+ monitors: Dictionary<MonitorSpec | null>;
304
+ // Each Monitor read takes the next failure, if any.
305
+ monitorFailures: Array<Error>;
306
+ probes: Array<ProbeSpec>;
307
+ statusRows: Array<MonitorStatusTimeline>;
308
+ logs: Array<MonitorLog>;
309
+ openIncidentCount: number;
310
+ // Every probe read (light or full) fails with this, when set.
311
+ probeFailure: Error | null;
312
+ /*
313
+ * Whether each uptime summary is stamped with the server's time when it
314
+ * is sent. Off: every summary says NOW, which is what the clock tests
315
+ * measure a skewed browser against.
316
+ */
317
+ isUptimeStampedLive: boolean;
318
+ }
319
+
320
+ interface ListRequest {
321
+ modelType: unknown;
322
+ query: Record<string, unknown>;
323
+ select: Record<string, unknown>;
324
+ }
325
+
326
+ interface ItemRequest {
327
+ modelType: unknown;
328
+ id: ObjectID;
329
+ select: Record<string, unknown>;
330
+ }
331
+
332
+ interface ApiGetRequest {
333
+ url: URL;
334
+ }
335
+
336
+ let server: FakeServer;
337
+ let permissions: Array<Permission>;
338
+ let currentMonitorId: string;
339
+ // Monitor reads parked until the test releases them, by monitor id.
340
+ let heldMonitorReads: Dictionary<Deferred<void>>;
341
+ let getItemSpy: jest.SpyInstance;
342
+ let getListSpy: jest.SpyInstance;
343
+ let analyticsGetListSpy: jest.SpyInstance;
344
+ let apiGetSpy: jest.SpyInstance;
345
+ let refreshHeaderMock: jest.Mock;
346
+
347
+ function buildStatus(statusId: string): MonitorStatus {
348
+ const status: MonitorStatus = new MonitorStatus();
349
+ status._id = statusId;
350
+ status.name = statusId === OFFLINE_ID ? "Offline" : "Operational";
351
+ status.color = new Color(statusId === OFFLINE_ID ? "#ef4444" : "#10b981");
352
+ status.isOperationalState = statusId !== OFFLINE_ID;
353
+ status.isOfflineState = statusId === OFFLINE_ID;
354
+ status.priority = statusId === OFFLINE_ID ? 2 : 1;
355
+ return status;
356
+ }
357
+
358
+ function stepsOf(stepData: JSONObject): MonitorSteps {
359
+ return {
360
+ data: {
361
+ monitorStepsInstanceArray: [{ data: { id: STEP_ID, ...stepData } }],
362
+ },
363
+ } as unknown as MonitorSteps;
364
+ }
365
+
366
+ // The steps each monitor carries; the same object on every read.
367
+ const stepsByMonitor: Dictionary<MonitorSteps> = {};
368
+
369
+ function getSteps(spec: MonitorSpec): MonitorSteps | undefined {
370
+ if (spec.stepData === null) {
371
+ return undefined;
372
+ }
373
+
374
+ const key: string = `${spec.id}:${JSON.stringify(spec.stepData || {})}`;
375
+
376
+ if (!stepsByMonitor[key]) {
377
+ stepsByMonitor[key] = stepsOf(spec.stepData || {});
378
+ }
379
+
380
+ return stepsByMonitor[key];
381
+ }
382
+
383
+ /*
384
+ * The row as the server would send it: the secret-key columns only when the
385
+ * select asked for them, which the page only does for someone who may read
386
+ * them.
387
+ */
388
+ function buildMonitorRow(
389
+ spec: MonitorSpec,
390
+ select: Record<string, unknown>,
391
+ ): Monitor {
392
+ const monitor: Monitor = new Monitor();
393
+ monitor._id = spec.id;
394
+ monitor.monitorType = spec.type;
395
+
396
+ const steps: MonitorSteps | undefined = getSteps(spec);
397
+
398
+ if (steps) {
399
+ monitor.monitorSteps = steps;
400
+ }
401
+
402
+ monitor.monitoringInterval = "* * * * *";
403
+ monitor.createdAt = new Date("2026-01-01T00:00:00.000Z");
404
+ monitor.currentMonitorStatusId = new ObjectID(spec.statusId);
405
+ monitor.currentMonitorStatus = buildStatus(spec.statusId);
406
+ Object.assign(monitor, spec.overrides || {});
407
+
408
+ if (select["incomingRequestSecretKey"]) {
409
+ monitor.incomingRequestSecretKey = new ObjectID(HEARTBEAT_SECRET);
410
+ }
411
+
412
+ if (select["serverMonitorSecretKey"]) {
413
+ monitor.serverMonitorSecretKey = new ObjectID(SERVER_SECRET);
414
+ }
415
+
416
+ return monitor;
417
+ }
418
+
419
+ function buildProbeRow(spec: ProbeSpec, isFull: boolean): MonitorProbe {
420
+ const row: MonitorProbe = new MonitorProbe();
421
+ row.createdAt = NOW;
422
+ row.probeId = new ObjectID(spec.probeId);
423
+ row.isEnabled = spec.isEnabled;
424
+ row.lastPingAt = secondsAgo(40);
425
+ row.nextPingAt = spec.nextPingAt || secondsAgo(-20);
426
+
427
+ const probe: Probe = new Probe();
428
+ probe._id = spec.probeId;
429
+ probe.name = spec.name;
430
+ probe.connectionStatus = ProbeConnectionStatus.Connected;
431
+ row.probe = probe;
432
+
433
+ if (isFull && spec.monitoredAt) {
434
+ row.lastMonitoringLog = {
435
+ [STEP_ID]: {
436
+ probeId: spec.probeId,
437
+ monitorStepId: STEP_ID,
438
+ monitoredAt: spec.monitoredAt.toISOString(),
439
+ isOnline: true,
440
+ responseTimeInMs: 120,
441
+ responseCode: 200,
442
+ },
443
+ } as unknown as MonitorStepProbeResponse;
444
+ }
445
+
446
+ return row;
447
+ }
448
+
449
+ function buildEvaluation(label: string): MonitorEvaluationSummary {
450
+ return {
451
+ evaluatedAt: secondsAgo(30),
452
+ criteriaResults: [
453
+ {
454
+ criteriaId: label,
455
+ criteriaName: label,
456
+ met: true,
457
+ message: label,
458
+ filters: [],
459
+ },
460
+ ],
461
+ events: [],
462
+ } as unknown as MonitorEvaluationSummary;
463
+ }
464
+
465
+ function buildLog(data: {
466
+ probeId: string;
467
+ time: Date;
468
+ summary: MonitorEvaluationSummary;
469
+ }): MonitorLog {
470
+ const log: MonitorLog = new MonitorLog();
471
+ log.time = data.time;
472
+ log.logBody = {
473
+ probeId: data.probeId,
474
+ evaluationSummary: data.summary,
475
+ } as unknown as JSONObject;
476
+ return log;
477
+ }
478
+
479
+ function buildOpenStatusRow(statusId: string): MonitorStatusTimeline {
480
+ const row: MonitorStatusTimeline = new MonitorStatusTimeline();
481
+ row._id = STATUS_ROW_ID;
482
+ row.monitorStatusId = new ObjectID(statusId);
483
+ row.monitorStatus = buildStatus(statusId);
484
+ row.startsAt = secondsAgo(3 * DAY_SECONDS);
485
+ return row;
486
+ }
487
+
488
+ function buildWindow(
489
+ key: MonitorUptimeWindowKey,
490
+ seconds: number,
491
+ ): MonitorUptimeWindowTotal {
492
+ return {
493
+ key: key,
494
+ startDate: secondsAgo(seconds),
495
+ endDate: NOW,
496
+ windowSeconds: seconds,
497
+ coveredSeconds: seconds,
498
+ statusDurations: [
499
+ { monitorStatusId: new ObjectID(OPERATIONAL_ID), seconds: seconds },
500
+ ],
501
+ };
502
+ }
503
+
504
+ // A fully covered, all-operational history: every window reads "100%".
505
+ function buildUptimeSummary(monitorId: string): MonitorUptimeSummary {
506
+ return {
507
+ monitorId: new ObjectID(monitorId),
508
+ timezone: "UTC",
509
+ generatedAt: NOW,
510
+ startDate: secondsAgo(89 * DAY_SECONDS + 12 * 3600),
511
+ endDate: NOW,
512
+ buckets: [],
513
+ windows: [
514
+ buildWindow(MonitorUptimeWindowKey.Last24Hours, DAY_SECONDS),
515
+ buildWindow(MonitorUptimeWindowKey.Last7Days, 7 * DAY_SECONDS),
516
+ buildWindow(MonitorUptimeWindowKey.Last30Days, 30 * DAY_SECONDS),
517
+ buildWindow(MonitorUptimeWindowKey.Last90Days, 90 * DAY_SECONDS),
518
+ ],
519
+ isComplete: true,
520
+ completeFrom: null,
521
+ statuses: [
522
+ {
523
+ id: new ObjectID(OPERATIONAL_ID),
524
+ name: "Operational",
525
+ color: "#10b981",
526
+ isOperationalState: true,
527
+ isOfflineState: false,
528
+ priority: 1,
529
+ },
530
+ {
531
+ id: new ObjectID(OFFLINE_ID),
532
+ name: "Offline",
533
+ color: "#ef4444",
534
+ isOperationalState: false,
535
+ isOfflineState: true,
536
+ priority: 2,
537
+ },
538
+ ],
539
+ };
540
+ }
541
+
542
+ function listOf<T>(
543
+ data: Array<T>,
544
+ count?: number,
545
+ ): {
546
+ data: Array<T>;
547
+ count: number;
548
+ skip: number;
549
+ limit: number;
550
+ } {
551
+ return {
552
+ data: data,
553
+ count: count ?? data.length,
554
+ skip: 0,
555
+ limit: data.length,
556
+ };
557
+ }
558
+
559
+ const API_MONITOR: MonitorSpec = {
560
+ id: MONITOR_A,
561
+ type: MonitorType.API,
562
+ statusId: OPERATIONAL_ID,
563
+ };
564
+
565
+ function setUpServer(monitor: MonitorSpec): void {
566
+ server.monitors[monitor.id] = monitor;
567
+ }
568
+
569
+ function listRequests(modelType: unknown): Array<ListRequest> {
570
+ return getListSpy.mock.calls
571
+ .map((call: Array<unknown>) => {
572
+ return call[0] as ListRequest;
573
+ })
574
+ .filter((request: ListRequest) => {
575
+ return request.modelType === modelType;
576
+ });
577
+ }
578
+
579
+ function itemRequests(): Array<ItemRequest> {
580
+ return getItemSpy.mock.calls.map((call: Array<unknown>) => {
581
+ return call[0] as ItemRequest;
582
+ });
583
+ }
584
+
585
+ function apiGetUrls(route: string): Array<string> {
586
+ return apiGetSpy.mock.calls
587
+ .map((call: Array<unknown>) => {
588
+ return (call[0] as ApiGetRequest).url.toString();
589
+ })
590
+ .filter((url: string) => {
591
+ return url.includes(route);
592
+ });
593
+ }
594
+
595
+ // Open-work reads, told apart from the uptime overlay by their state filter.
596
+ function openIncidentRequests(): Array<ListRequest> {
597
+ return listRequests(Incident).filter((request: ListRequest) => {
598
+ return Boolean(request.query["currentIncidentStateId"]);
599
+ });
600
+ }
601
+
602
+ function propsHistory<T>(key: string): Array<T> {
603
+ return (recordedProps[key] || []) as unknown as Array<T>;
604
+ }
605
+
606
+ function latestProps<T>(key: string): T {
607
+ const history: Array<T> = propsHistory<T>(key);
608
+
609
+ if (history.length === 0) {
610
+ throw new Error(`${key} was never rendered`);
611
+ }
612
+
613
+ return history[history.length - 1]!;
614
+ }
615
+
616
+ // Lets every settled promise run its continuations, inside act.
617
+ async function flush(): Promise<void> {
618
+ for (let round: number = 0; round < 3; round++) {
619
+ await act(async () => {
620
+ for (let i: number = 0; i < 50; i++) {
621
+ await Promise.resolve();
622
+ }
623
+ });
624
+ }
625
+ }
626
+
627
+ function holdMonitorRead(monitorId: string): Deferred<void> {
628
+ const deferred: Deferred<void> = createDeferred<void>();
629
+ heldMonitorReads[monitorId] = deferred;
630
+ return deferred;
631
+ }
632
+
633
+ async function releaseMonitorRead(monitorId: string): Promise<void> {
634
+ const deferred: Deferred<void> | undefined = heldMonitorReads[monitorId];
635
+ delete heldMonitorReads[monitorId];
636
+
637
+ await act(async () => {
638
+ deferred?.resolve();
639
+ });
640
+ await flush();
641
+ }
642
+
643
+ const outletContext: MonitorViewOutletContext = {
644
+ refreshHeader: (): void => {
645
+ refreshHeaderMock();
646
+ },
647
+ };
648
+
649
+ // The layout's outlet, which hands the page its context.
650
+ function OutletHost(): ReactElement {
651
+ return <Outlet context={outletContext} />;
652
+ }
653
+
654
+ function pageTree(): ReactElement {
655
+ return (
656
+ <MemoryRouter initialEntries={["/dashboard/monitors/view"]}>
657
+ <Routes>
658
+ <RouterRoute element={<OutletHost />}>
659
+ <RouterRoute path="*" element={<MonitorView {...pageProps} />} />
660
+ </RouterRoute>
661
+ </Routes>
662
+ </MemoryRouter>
663
+ );
664
+ }
665
+
666
+ async function renderPage(): Promise<RenderResult> {
667
+ const rendered: RenderResult = render(pageTree());
668
+ await flush();
669
+ return rendered;
670
+ }
671
+
672
+ // Moves the reader to another monitor on the same, still-mounted route.
673
+ async function navigateTo(
674
+ rendered: RenderResult,
675
+ monitorId: string,
676
+ ): Promise<void> {
677
+ currentMonitorId = monitorId;
678
+
679
+ await act(async () => {
680
+ rendered.rerender(pageTree());
681
+ });
682
+ }
683
+
684
+ function getFactKeys(): Array<string> {
685
+ return Array.from(
686
+ within(screen.getByTestId("monitor-overview-facts")).queryAllByTestId(
687
+ /^monitor-overview-fact-/,
688
+ ),
689
+ ).map((element: HTMLElement) => {
690
+ return element
691
+ .getAttribute("data-testid")!
692
+ .replace("monitor-overview-fact-", "");
693
+ });
694
+ }
695
+
696
+ function tile(id: string): HTMLElement {
697
+ const element: HTMLElement | null = document.getElementById(id);
698
+
699
+ if (!element) {
700
+ throw new Error(`No stat tile ${id}`);
701
+ }
702
+
703
+ return element;
704
+ }
705
+
706
+ function isInMainColumn(element: HTMLElement): boolean {
707
+ return Boolean(element.closest('[class~="xl:col-span-2"]'));
708
+ }
709
+
710
+ // Asserts the elements are in the DOM in this order.
711
+ function expectDocumentOrder(elements: Array<HTMLElement>): void {
712
+ for (let index: number = 1; index < elements.length; index++) {
713
+ const previous: HTMLElement = elements[index - 1]!;
714
+ const current: HTMLElement = elements[index]!;
715
+
716
+ expect(
717
+ Boolean(
718
+ previous.compareDocumentPosition(current) &
719
+ Node.DOCUMENT_POSITION_FOLLOWING,
720
+ ),
721
+ ).toBe(true);
722
+ }
723
+ }
724
+
725
+ function heading(name: string): HTMLElement {
726
+ return screen.getByRole("heading", { name: name });
727
+ }
728
+
729
+ beforeEach(() => {
730
+ jest.useFakeTimers({ doNotFake: ["performance"] });
731
+ jest.setSystemTime(NOW);
732
+
733
+ currentMonitorId = MONITOR_A;
734
+ heldMonitorReads = {};
735
+ permissions = [Permission.ProjectOwner];
736
+ refreshHeaderMock = jest.fn();
737
+
738
+ server = {
739
+ monitors: { [MONITOR_A]: API_MONITOR },
740
+ monitorFailures: [],
741
+ probes: [
742
+ {
743
+ probeId: PROBE_FRANKFURT,
744
+ name: "Frankfurt",
745
+ isEnabled: true,
746
+ monitoredAt: secondsAgo(30),
747
+ },
748
+ { probeId: PROBE_VIRGINIA, name: "Virginia", isEnabled: false },
749
+ ],
750
+ statusRows: [buildOpenStatusRow(OPERATIONAL_ID)],
751
+ logs: [
752
+ buildLog({
753
+ probeId: PROBE_FRANKFURT,
754
+ time: secondsAgo(30),
755
+ summary: buildEvaluation("Frankfurt verdict"),
756
+ }),
757
+ ],
758
+ openIncidentCount: 0,
759
+ probeFailure: null,
760
+ isUptimeStampedLive: false,
761
+ };
762
+
763
+ jest
764
+ .spyOn(Navigation, "getLastParamAsObjectID")
765
+ .mockImplementation((): ObjectID => {
766
+ return new ObjectID(currentMonitorId);
767
+ });
768
+ jest.spyOn(ProjectUtil, "getCurrentProjectId").mockReturnValue(PROJECT_ID);
769
+ jest.spyOn(PermissionUtil, "getAllPermissions").mockImplementation(() => {
770
+ return permissions;
771
+ });
772
+
773
+ const incidentState: IncidentState = new IncidentState();
774
+ incidentState._id = INCIDENT_STATE_ID;
775
+ jest
776
+ .spyOn(IncidentStateUtil, "getUnresolvedIncidentStates")
777
+ .mockResolvedValue([incidentState]);
778
+
779
+ const alertState: AlertState = new AlertState();
780
+ alertState._id = ALERT_STATE_ID;
781
+ jest
782
+ .spyOn(AlertStateUtil, "getUnresolvedAlertStates")
783
+ .mockResolvedValue([alertState]);
784
+
785
+ getItemSpy = jest.spyOn(ModelAPI, "getItem");
786
+ getItemSpy.mockImplementation((...args: Array<unknown>): Promise<unknown> => {
787
+ const request: ItemRequest = args[0] as ItemRequest;
788
+ const monitorId: string = request.id.toString();
789
+
790
+ const respond: () => Promise<unknown> = (): Promise<unknown> => {
791
+ const failure: Error | undefined = server.monitorFailures.shift();
792
+
793
+ if (failure) {
794
+ return rejectWith(failure);
795
+ }
796
+
797
+ const spec: MonitorSpec | null | undefined = server.monitors[monitorId];
798
+
799
+ return Promise.resolve(
800
+ spec ? buildMonitorRow(spec, request.select) : null,
801
+ );
802
+ };
803
+
804
+ const held: Deferred<void> | undefined = heldMonitorReads[monitorId];
805
+
806
+ if (held) {
807
+ return held.promise.then(respond);
808
+ }
809
+
810
+ return respond();
811
+ });
812
+
813
+ getListSpy = jest.spyOn(ModelAPI, "getList");
814
+ getListSpy.mockImplementation((...args: Array<unknown>): Promise<unknown> => {
815
+ const request: ListRequest = args[0] as ListRequest;
816
+
817
+ if (request.modelType === MonitorProbe) {
818
+ const isFull: boolean = Boolean(request.select["lastMonitoringLog"]);
819
+
820
+ if (server.probeFailure) {
821
+ return rejectWith(server.probeFailure);
822
+ }
823
+
824
+ return Promise.resolve(
825
+ listOf(
826
+ server.probes.map((spec: ProbeSpec) => {
827
+ return buildProbeRow(spec, isFull);
828
+ }),
829
+ ),
830
+ );
831
+ }
832
+
833
+ if (request.modelType === MonitorStatusTimeline) {
834
+ return Promise.resolve(listOf(server.statusRows));
835
+ }
836
+
837
+ if (
838
+ request.modelType === Incident &&
839
+ request.query["currentIncidentStateId"]
840
+ ) {
841
+ const incidents: Array<Incident> = [];
842
+
843
+ if (server.openIncidentCount > 0) {
844
+ const incident: Incident = new Incident();
845
+ incident._id = INCIDENT_ID;
846
+ incident.title = "Checkout is slow";
847
+ incident.declaredAt = secondsAgo(600);
848
+ incidents.push(incident);
849
+ }
850
+
851
+ return Promise.resolve(listOf(incidents, server.openIncidentCount));
852
+ }
853
+
854
+ if (
855
+ request.modelType === Alert ||
856
+ request.modelType === Incident ||
857
+ request.modelType === MonitorOwnerUser ||
858
+ request.modelType === MonitorOwnerTeam
859
+ ) {
860
+ return Promise.resolve(listOf([]));
861
+ }
862
+
863
+ return rejectWith(new Error("Unexpected list request"));
864
+ });
865
+
866
+ analyticsGetListSpy = jest.spyOn(AnalyticsModelAPI, "getList");
867
+ analyticsGetListSpy.mockImplementation((): Promise<unknown> => {
868
+ return Promise.resolve(listOf(server.logs));
869
+ });
870
+
871
+ apiGetSpy = jest.spyOn(API, "get");
872
+ apiGetSpy.mockImplementation((...args: Array<unknown>): Promise<unknown> => {
873
+ const url: string = (args[0] as ApiGetRequest).url.toString();
874
+
875
+ if (url.includes("/monitor/uptime-summary/")) {
876
+ const monitorId: string = url
877
+ .split("/monitor/uptime-summary/")[1]!
878
+ .split("?")[0]!;
879
+
880
+ return Promise.resolve(
881
+ new HTTPResponse<JSONObject>(
882
+ 200,
883
+ MonitorUptimeSummaryUtil.toJSON({
884
+ ...buildUptimeSummary(monitorId),
885
+ generatedAt: server.isUptimeStampedLive ? new Date() : NOW,
886
+ }),
887
+ {},
888
+ ),
889
+ );
890
+ }
891
+
892
+ return Promise.resolve(new HTTPResponse<JSONObject>(200, {}, {}));
893
+ });
894
+ });
895
+
896
+ afterEach(() => {
897
+ cleanup();
898
+ jest.restoreAllMocks();
899
+ jest.useRealTimers();
900
+
901
+ for (const key of Object.keys(recordedProps)) {
902
+ delete recordedProps[key];
903
+ }
904
+
905
+ for (const key of Object.keys(mountCounts)) {
906
+ delete mountCounts[key];
907
+ }
908
+ });
909
+
910
+ describe("Monitor overview page: the first load", () => {
911
+ test('shows the skeleton "Loading monitor" until the Monitor read resolves, reading the rest in parallel', async () => {
912
+ holdMonitorRead(MONITOR_A);
913
+
914
+ await renderPage();
915
+
916
+ expect(screen.getByRole("status")).toHaveTextContent("Loading monitor");
917
+ expect(screen.queryByTestId("monitor-overview-hero")).toBeNull();
918
+ // No card is mounted over the skeleton, so none fetches for nothing.
919
+ expect(Object.keys(mountCounts)).toEqual([]);
920
+
921
+ // The supplementary reads went out without waiting for the row.
922
+ expect(itemRequests()).toHaveLength(1);
923
+ expect(listRequests(MonitorProbe)).toHaveLength(1);
924
+ expect(listRequests(MonitorStatusTimeline)).toHaveLength(1);
925
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(1);
926
+
927
+ await releaseMonitorRead(MONITOR_A);
928
+
929
+ expect(screen.queryByText("Loading monitor")).toBeNull();
930
+ expect(screen.getByTestId("monitor-overview-hero")).toBeInTheDocument();
931
+
932
+ // Every card mounted exactly once: nothing rendered and then replaced.
933
+ for (const key of [
934
+ "Summary",
935
+ "MonitorFeed",
936
+ "OverviewCustomFields",
937
+ "DependencySuppressionWarning",
938
+ "EmbeddedMetricCard",
939
+ "MonitorUptimeGraph",
940
+ "CardModelDetail:Monitor Details",
941
+ ]) {
942
+ expect({ key, mounts: mountCounts[key] }).toEqual({ key, mounts: 1 });
943
+ }
944
+ });
945
+
946
+ test("a failed first load shows the error with a retry that recovers", async () => {
947
+ server.monitorFailures = [new Error("The database is asleep")];
948
+
949
+ await renderPage();
950
+
951
+ expect(screen.getByText("The database is asleep")).toBeInTheDocument();
952
+ expect(screen.queryByTestId("monitor-overview-hero")).toBeNull();
953
+ expect(screen.queryByTestId("stub-Summary")).toBeNull();
954
+
955
+ await act(async () => {
956
+ fireEvent.click(screen.getByTestId("refresh-button"));
957
+ });
958
+ await flush();
959
+
960
+ expect(screen.queryByText("The database is asleep")).toBeNull();
961
+ expect(screen.getByTestId("monitor-overview-hero")).toBeInTheDocument();
962
+ expect(itemRequests()).toHaveLength(2);
963
+ });
964
+
965
+ test("a monitor that is gone says so, with a retry", async () => {
966
+ server.monitors[MONITOR_A] = null;
967
+
968
+ await renderPage();
969
+
970
+ expect(
971
+ screen.getByText(
972
+ "This monitor could not be found. It may have been deleted, or you may not have permission to view it.",
973
+ ),
974
+ ).toBeInTheDocument();
975
+ expect(MONITOR_OVERVIEW_NOT_FOUND_MESSAGE).toBe(
976
+ "This monitor could not be found. It may have been deleted, or you may not have permission to view it.",
977
+ );
978
+ expect(screen.getByTestId("refresh-button")).toBeInTheDocument();
979
+ expect(screen.queryByTestId("monitor-overview-hero")).toBeNull();
980
+ });
981
+
982
+ test("reads the uptime history and what is open once per visit, not again when the row lands", async () => {
983
+ await renderPage();
984
+
985
+ expect(screen.getByTestId("monitor-overview-hero")).toBeInTheDocument();
986
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(1);
987
+ expect(openIncidentRequests()).toHaveLength(1);
988
+ expect(listRequests(Alert)).toHaveLength(1);
989
+ expect(listRequests(MonitorOwnerUser)).toHaveLength(1);
990
+ expect(apiGetUrls("/monitor/refresh-status/")).toHaveLength(1);
991
+ });
992
+ });
993
+
994
+ describe("Monitor overview page: layout", () => {
995
+ test("lays the main and side column cards out in the spec's order", async () => {
996
+ await renderPage();
997
+
998
+ const main: Array<HTMLElement> = [
999
+ heading("Uptime history"),
1000
+ screen.getByTestId("stub-EmbeddedMetricCard"),
1001
+ screen.getByTestId("stub-Summary"),
1002
+ screen.getByTestId("stub-MonitorFeed"),
1003
+ ];
1004
+ const side: Array<HTMLElement> = [
1005
+ heading("Open incidents & alerts"),
1006
+ heading("Recent status changes"),
1007
+ heading("Probes"),
1008
+ screen.getByTestId("stub-card-Monitor Details"),
1009
+ screen.getByTestId("stub-OverviewCustomFields"),
1010
+ ];
1011
+
1012
+ for (const element of main) {
1013
+ expect(isInMainColumn(element)).toBe(true);
1014
+ }
1015
+
1016
+ for (const element of side) {
1017
+ expect(isInMainColumn(element)).toBe(false);
1018
+ }
1019
+
1020
+ expectDocumentOrder([...main, ...side]);
1021
+
1022
+ // The custom fields card is stacked like every other side card.
1023
+ expect(
1024
+ latestProps<{ headerLayout?: string }>("OverviewCustomFields"),
1025
+ ).toMatchObject({ headerLayout: "stacked" });
1026
+ });
1027
+
1028
+ test("puts the telemetry preview after the summary and before the activity", async () => {
1029
+ setUpServer({
1030
+ id: MONITOR_A,
1031
+ type: MonitorType.Logs,
1032
+ statusId: OPERATIONAL_ID,
1033
+ stepData: { logMonitor: { body: "OutOfMemory" } },
1034
+ overrides: {
1035
+ telemetryMonitorLastMonitorAt: secondsAgo(30),
1036
+ telemetryMonitorNextMonitorAt: secondsAgo(-30),
1037
+ },
1038
+ });
1039
+ server.probes = [];
1040
+
1041
+ await renderPage();
1042
+
1043
+ expectDocumentOrder([
1044
+ heading("Uptime history"),
1045
+ screen.getByTestId("stub-Summary"),
1046
+ heading("Logs preview"),
1047
+ screen.getByTestId("stub-LogMonitorPreview"),
1048
+ screen.getByTestId("stub-MonitorFeed"),
1049
+ ]);
1050
+ expect(isInMainColumn(screen.getByTestId("stub-LogMonitorPreview"))).toBe(
1051
+ true,
1052
+ );
1053
+ });
1054
+
1055
+ test("the stat bar sits between the hero and the grid", async () => {
1056
+ await renderPage();
1057
+
1058
+ const hero: HTMLElement = screen.getByTestId("monitor-overview-hero");
1059
+ const statBar: HTMLElement = screen.getByRole("group", {
1060
+ name: "Uptime and open work",
1061
+ });
1062
+ const mainColumn: HTMLElement = screen
1063
+ .getByTestId("stub-Summary")
1064
+ .closest('[class~="xl:col-span-2"]') as HTMLElement;
1065
+ const notice: HTMLElement = screen.getByTestId(
1066
+ "stub-DependencySuppressionWarning",
1067
+ );
1068
+
1069
+ expectDocumentOrder([notice, hero, statBar, mainColumn]);
1070
+ expect(hero.contains(statBar)).toBe(false);
1071
+ expect(mainColumn.contains(statBar)).toBe(false);
1072
+ });
1073
+ });
1074
+
1075
+ describe("Monitor overview page: refresh", () => {
1076
+ test("a manual Refresh re-reads in place and keeps every card mounted", async () => {
1077
+ await renderPage();
1078
+
1079
+ const feedTokenBefore: number = latestProps<{ refreshToken: number }>(
1080
+ "MonitorFeed",
1081
+ ).refreshToken;
1082
+ const mountsBefore: Record<string, number> = { ...mountCounts };
1083
+
1084
+ expect(Object.keys(mountsBefore).length).toBeGreaterThanOrEqual(7);
1085
+
1086
+ await act(async () => {
1087
+ fireEvent.click(screen.getByTestId("monitor-overview-refresh"));
1088
+ });
1089
+ await flush();
1090
+
1091
+ expect(itemRequests()).toHaveLength(2);
1092
+ expect(mountCounts).toEqual(mountsBefore);
1093
+ expect(screen.queryByText("Loading monitor")).toBeNull();
1094
+
1095
+ // Everything the Refresh button promises is read again...
1096
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(2);
1097
+ expect(listRequests(MonitorOwnerUser)).toHaveLength(2);
1098
+ expect(openIncidentRequests()).toHaveLength(2);
1099
+ expect(
1100
+ latestProps<{ refreshToken: number }>("MonitorFeed").refreshToken,
1101
+ ).toBe(feedTokenBefore + 1);
1102
+ expect(
1103
+ latestProps<{ refresher: boolean }>("CardModelDetail:Monitor Details")
1104
+ .refresher,
1105
+ ).toBe(true);
1106
+ expect(
1107
+ latestProps<{ refreshToggle: string }>("DependencySuppressionWarning")
1108
+ .refreshToggle,
1109
+ ).toBe("0|1");
1110
+
1111
+ // ...but the status repair is never sent twice for one visit.
1112
+ expect(apiGetUrls("/monitor/refresh-status/")).toHaveLength(1);
1113
+ });
1114
+
1115
+ test("a failed refresh keeps the page and says so in the hero", async () => {
1116
+ await renderPage();
1117
+
1118
+ const mountsBefore: Record<string, number> = { ...mountCounts };
1119
+ server.monitorFailures = [new Error("Gateway timed out")];
1120
+
1121
+ await act(async () => {
1122
+ fireEvent.click(screen.getByTestId("monitor-overview-refresh"));
1123
+ });
1124
+ await flush();
1125
+
1126
+ const alert: HTMLElement = screen.getByTestId(
1127
+ "monitor-overview-refresh-error",
1128
+ );
1129
+
1130
+ expect(alert).toHaveAttribute("role", "alert");
1131
+ expect(alert).toHaveTextContent("Gateway timed out");
1132
+ expect(screen.getByTestId("monitor-overview-hero")).toBeInTheDocument();
1133
+ expect(screen.getByTestId("stub-Summary")).toBeInTheDocument();
1134
+ expect(mountCounts).toEqual(mountsBefore);
1135
+ });
1136
+
1137
+ test("open work follows every poll; the uptime history every fifth", async () => {
1138
+ await renderPage();
1139
+
1140
+ expect(openIncidentRequests()).toHaveLength(1);
1141
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(1);
1142
+
1143
+ await act(async () => {
1144
+ jest.advanceTimersByTime(MONITOR_OVERVIEW_REFRESH_INTERVAL_MS);
1145
+ });
1146
+ await flush();
1147
+
1148
+ expect(itemRequests()).toHaveLength(2);
1149
+ expect(openIncidentRequests()).toHaveLength(2);
1150
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(1);
1151
+ // Owners are not part of "is it healthy"; the poll leaves them alone.
1152
+ expect(listRequests(MonitorOwnerUser)).toHaveLength(1);
1153
+
1154
+ for (let tick: number = 0; tick < 4; tick++) {
1155
+ await act(async () => {
1156
+ jest.advanceTimersByTime(MONITOR_OVERVIEW_REFRESH_INTERVAL_MS);
1157
+ });
1158
+ await flush();
1159
+ }
1160
+
1161
+ // The first load, then one per poll; the fifth poll reloads the history.
1162
+ expect(openIncidentRequests()).toHaveLength(6);
1163
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(2);
1164
+ expect(listRequests(MonitorOwnerUser)).toHaveLength(1);
1165
+ });
1166
+
1167
+ test("a status change reloads the uptime history and the feed at once", async () => {
1168
+ await renderPage();
1169
+
1170
+ const feedTokenBefore: number = latestProps<{ refreshToken: number }>(
1171
+ "MonitorFeed",
1172
+ ).refreshToken;
1173
+
1174
+ setUpServer({ ...API_MONITOR, statusId: OFFLINE_ID });
1175
+ server.statusRows = [buildOpenStatusRow(OFFLINE_ID)];
1176
+
1177
+ await act(async () => {
1178
+ jest.advanceTimersByTime(MONITOR_OVERVIEW_REFRESH_INTERVAL_MS);
1179
+ });
1180
+ await flush();
1181
+
1182
+ expect(
1183
+ within(screen.getByTestId("monitor-overview-badge")).getByText("Offline"),
1184
+ ).toBeInTheDocument();
1185
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(2);
1186
+ expect(
1187
+ latestProps<{ refreshToken: number }>("MonitorFeed").refreshToken,
1188
+ ).toBe(feedTokenBefore + 1);
1189
+ expect(
1190
+ latestProps<{ refreshToggle: string }>("DependencySuppressionWarning")
1191
+ .refreshToggle,
1192
+ ).toBe("1|0");
1193
+ });
1194
+ });
1195
+
1196
+ interface FamilyCase {
1197
+ name: string;
1198
+ monitor: MonitorSpec;
1199
+ probes?: Array<ProbeSpec>;
1200
+ facts: Array<string>;
1201
+ hasStatBar: boolean;
1202
+ hasUptimeHistory: boolean;
1203
+ hasSummary: boolean;
1204
+ hasResponseTime: boolean;
1205
+ // The side card's heading, or null for none.
1206
+ sideCard: string | null;
1207
+ // The setup card's heading, or null for none.
1208
+ setup: string | null;
1209
+ // A stub the main column shows, beyond the ones every family gets.
1210
+ extraStub: string | null;
1211
+ }
1212
+
1213
+ const FAMILY_CASES: Array<FamilyCase> = [
1214
+ {
1215
+ name: "a probe check",
1216
+ monitor: API_MONITOR,
1217
+ facts: ["latest-result", "probes", "owners"],
1218
+ hasStatBar: true,
1219
+ hasUptimeHistory: true,
1220
+ hasSummary: true,
1221
+ hasResponseTime: true,
1222
+ sideCard: "Probes",
1223
+ setup: null,
1224
+ extraStub: null,
1225
+ },
1226
+ {
1227
+ name: "a heartbeat waiting for its first request",
1228
+ monitor: {
1229
+ id: MONITOR_A,
1230
+ type: MonitorType.IncomingRequest,
1231
+ statusId: OPERATIONAL_ID,
1232
+ },
1233
+ probes: [],
1234
+ facts: ["missing-window", "heartbeat-check", "owners"],
1235
+ hasStatBar: false,
1236
+ hasUptimeHistory: false,
1237
+ hasSummary: false,
1238
+ hasResponseTime: false,
1239
+ sideCard: null,
1240
+ setup: "Send the first heartbeat",
1241
+ extraStub: null,
1242
+ },
1243
+ {
1244
+ name: "a heartbeat that has reported",
1245
+ monitor: {
1246
+ id: MONITOR_A,
1247
+ type: MonitorType.IncomingRequest,
1248
+ statusId: OPERATIONAL_ID,
1249
+ overrides: {
1250
+ incomingMonitorRequest: {
1251
+ incomingRequestReceivedAt: secondsAgo(120),
1252
+ requestMethod: "POST",
1253
+ } as unknown as Monitor["incomingMonitorRequest"],
1254
+ incomingRequestMonitorHeartbeatCheckedAt: secondsAgo(60),
1255
+ },
1256
+ },
1257
+ probes: [],
1258
+ facts: ["missing-window", "heartbeat-check", "owners"],
1259
+ hasStatBar: true,
1260
+ hasUptimeHistory: true,
1261
+ hasSummary: true,
1262
+ hasResponseTime: false,
1263
+ sideCard: "Heartbeat URL",
1264
+ setup: null,
1265
+ extraStub: null,
1266
+ },
1267
+ {
1268
+ name: "a server agent waiting for its first report",
1269
+ monitor: {
1270
+ id: MONITOR_A,
1271
+ type: MonitorType.Server,
1272
+ statusId: OPERATIONAL_ID,
1273
+ },
1274
+ probes: [],
1275
+ facts: ["host", "cpu", "memory", "owners"],
1276
+ hasStatBar: false,
1277
+ hasUptimeHistory: false,
1278
+ hasSummary: false,
1279
+ hasResponseTime: false,
1280
+ sideCard: null,
1281
+ setup: null,
1282
+ extraStub: "ServerMonitorDocumentation",
1283
+ },
1284
+ {
1285
+ name: "a server agent that has reported",
1286
+ monitor: {
1287
+ id: MONITOR_A,
1288
+ type: MonitorType.Server,
1289
+ statusId: OPERATIONAL_ID,
1290
+ overrides: {
1291
+ serverMonitorRequestReceivedAt: secondsAgo(60),
1292
+ serverMonitorResponse: {
1293
+ hostname: "web-01",
1294
+ basicInfrastructureMetrics: {
1295
+ cpuMetrics: { percentUsed: 12 },
1296
+ memoryMetrics: { percentUsed: 48 },
1297
+ },
1298
+ } as unknown as Monitor["serverMonitorResponse"],
1299
+ },
1300
+ },
1301
+ probes: [],
1302
+ facts: ["host", "cpu", "memory", "owners"],
1303
+ hasStatBar: true,
1304
+ hasUptimeHistory: true,
1305
+ hasSummary: true,
1306
+ hasResponseTime: false,
1307
+ sideCard: "Server agent",
1308
+ setup: null,
1309
+ extraStub: null,
1310
+ },
1311
+ {
1312
+ name: "a telemetry monitor",
1313
+ monitor: {
1314
+ id: MONITOR_A,
1315
+ type: MonitorType.Logs,
1316
+ statusId: OPERATIONAL_ID,
1317
+ stepData: { logMonitor: { body: "OutOfMemory" } },
1318
+ overrides: {
1319
+ telemetryMonitorLastMonitorAt: secondsAgo(30),
1320
+ telemetryMonitorNextMonitorAt: secondsAgo(-30),
1321
+ },
1322
+ },
1323
+ probes: [],
1324
+ facts: ["evaluates", "criteria", "owners"],
1325
+ hasStatBar: true,
1326
+ hasUptimeHistory: true,
1327
+ hasSummary: true,
1328
+ hasResponseTime: false,
1329
+ sideCard: null,
1330
+ setup: null,
1331
+ extraStub: "LogMonitorPreview",
1332
+ },
1333
+ {
1334
+ name: "an infrastructure monitor",
1335
+ monitor: {
1336
+ id: MONITOR_A,
1337
+ type: MonitorType.Kubernetes,
1338
+ statusId: OPERATIONAL_ID,
1339
+ overrides: {
1340
+ telemetryMonitorLastMonitorAt: secondsAgo(30),
1341
+ telemetryMonitorNextMonitorAt: secondsAgo(-30),
1342
+ },
1343
+ },
1344
+ probes: [],
1345
+ facts: ["evaluates", "criteria", "owners"],
1346
+ hasStatBar: true,
1347
+ hasUptimeHistory: true,
1348
+ hasSummary: true,
1349
+ hasResponseTime: false,
1350
+ sideCard: null,
1351
+ setup: null,
1352
+ extraStub: null,
1353
+ },
1354
+ {
1355
+ name: "a network device monitor",
1356
+ monitor: {
1357
+ id: MONITOR_A,
1358
+ type: MonitorType.NetworkDevice,
1359
+ statusId: OPERATIONAL_ID,
1360
+ stepData: { networkDeviceMonitor: { networkDeviceId: DEVICE_ID } },
1361
+ },
1362
+ probes: [],
1363
+ facts: ["device", "evaluated", "owners"],
1364
+ hasStatBar: true,
1365
+ hasUptimeHistory: true,
1366
+ hasSummary: true,
1367
+ hasResponseTime: false,
1368
+ sideCard: null,
1369
+ setup: null,
1370
+ extraStub: null,
1371
+ },
1372
+ {
1373
+ name: "a manual monitor",
1374
+ monitor: {
1375
+ id: MONITOR_A,
1376
+ type: MonitorType.Manual,
1377
+ statusId: OPERATIONAL_ID,
1378
+ stepData: null,
1379
+ },
1380
+ probes: [],
1381
+ facts: ["checks", "owners"],
1382
+ hasStatBar: true,
1383
+ hasUptimeHistory: true,
1384
+ hasSummary: false,
1385
+ hasResponseTime: false,
1386
+ sideCard: "Manual monitor",
1387
+ setup: null,
1388
+ extraStub: null,
1389
+ },
1390
+ ];
1391
+
1392
+ const SIDE_CARD_HEADINGS: Array<string> = [
1393
+ "Probes",
1394
+ "Heartbeat URL",
1395
+ "Server agent",
1396
+ "Manual monitor",
1397
+ ];
1398
+
1399
+ describe.each(FAMILY_CASES)(
1400
+ "Monitor overview page for $name",
1401
+ (familyCase: FamilyCase) => {
1402
+ test("shows the family's facts and exactly its cards", async () => {
1403
+ setUpServer(familyCase.monitor);
1404
+
1405
+ if (familyCase.probes) {
1406
+ server.probes = familyCase.probes;
1407
+ }
1408
+
1409
+ await renderPage();
1410
+
1411
+ expect(getFactKeys()).toEqual(familyCase.facts);
1412
+
1413
+ expect(
1414
+ screen.queryByRole("group", { name: "Uptime and open work" }) !== null,
1415
+ ).toBe(familyCase.hasStatBar);
1416
+ expect(
1417
+ screen.queryByRole("heading", { name: "Uptime history" }) !== null,
1418
+ ).toBe(familyCase.hasUptimeHistory);
1419
+ expect(screen.queryByTestId("stub-Summary") !== null).toBe(
1420
+ familyCase.hasSummary,
1421
+ );
1422
+ expect(screen.queryByTestId("stub-EmbeddedMetricCard") !== null).toBe(
1423
+ familyCase.hasResponseTime,
1424
+ );
1425
+
1426
+ for (const sideHeading of SIDE_CARD_HEADINGS) {
1427
+ expect({
1428
+ sideHeading,
1429
+ shown: screen.queryByRole("heading", { name: sideHeading }) !== null,
1430
+ }).toEqual({
1431
+ sideHeading,
1432
+ shown: sideHeading === familyCase.sideCard,
1433
+ });
1434
+ }
1435
+
1436
+ if (familyCase.sideCard) {
1437
+ expect(isInMainColumn(heading(familyCase.sideCard))).toBe(false);
1438
+ }
1439
+
1440
+ if (familyCase.setup) {
1441
+ expect(isInMainColumn(heading(familyCase.setup))).toBe(true);
1442
+ } else {
1443
+ expect(
1444
+ screen.queryByRole("heading", { name: "Send the first heartbeat" }),
1445
+ ).toBeNull();
1446
+ }
1447
+
1448
+ if (familyCase.extraStub) {
1449
+ expect(
1450
+ isInMainColumn(screen.getByTestId(`stub-${familyCase.extraStub}`)),
1451
+ ).toBe(true);
1452
+ }
1453
+
1454
+ // Every family gets the feed, open work, recent changes and details.
1455
+ expect(screen.getByTestId("stub-MonitorFeed")).toBeInTheDocument();
1456
+ expect(heading("Open incidents & alerts")).toBeInTheDocument();
1457
+ expect(heading("Recent status changes")).toBeInTheDocument();
1458
+ expect(
1459
+ screen.getByTestId("stub-card-Monitor Details"),
1460
+ ).toBeInTheDocument();
1461
+ expect(
1462
+ screen.getByTestId("stub-OverviewCustomFields"),
1463
+ ).toBeInTheDocument();
1464
+ });
1465
+ },
1466
+ );
1467
+
1468
+ describe("Monitor overview page: roles", () => {
1469
+ const HEARTBEAT_AWAITING: MonitorSpec = {
1470
+ id: MONITOR_A,
1471
+ type: MonitorType.IncomingRequest,
1472
+ statusId: OPERATIONAL_ID,
1473
+ };
1474
+
1475
+ test("an owner sees everything, including the heartbeat URL with its secret", async () => {
1476
+ await renderPage();
1477
+
1478
+ for (const id of [
1479
+ "monitor-uptime-24h",
1480
+ "monitor-uptime-7d",
1481
+ "monitor-uptime-30d",
1482
+ ]) {
1483
+ expect(within(tile(id)).getByText("100%")).toBeInTheDocument();
1484
+ }
1485
+
1486
+ expect(
1487
+ within(tile("monitor-open-now")).getByText("Nothing open"),
1488
+ ).toBeInTheDocument();
1489
+ expect(screen.getByTestId("stub-EmbeddedMetricCard")).toBeInTheDocument();
1490
+ expect(screen.getByTestId("stub-MonitorFeed")).toBeInTheDocument();
1491
+ expect(
1492
+ within(screen.getByTestId("monitor-overview-fact-owners")).getByText(
1493
+ "No owners",
1494
+ ),
1495
+ ).toBeInTheDocument();
1496
+ // Probes read in full on the first load, with their results.
1497
+ expect(
1498
+ latestProps<{ probeLoadError?: string }>("Summary").probeLoadError,
1499
+ ).toBeUndefined();
1500
+
1501
+ cleanup();
1502
+ setUpServer(HEARTBEAT_AWAITING);
1503
+ server.probes = [];
1504
+
1505
+ const rendered: RenderResult = await renderPage();
1506
+
1507
+ expect(itemRequests().pop()!.select).toMatchObject({
1508
+ incomingRequestSecretKey: true,
1509
+ });
1510
+ expect(rendered.container.innerHTML).toContain(HEARTBEAT_SECRET);
1511
+ expect(screen.queryByText("Setup details are hidden")).toBeNull();
1512
+ });
1513
+
1514
+ test("a Viewer never gets the secret: not in the select, not in the DOM", async () => {
1515
+ permissions = [Permission.Viewer];
1516
+ setUpServer(HEARTBEAT_AWAITING);
1517
+ server.probes = [];
1518
+
1519
+ const rendered: RenderResult = await renderPage();
1520
+
1521
+ for (const column of SECRET_KEY_COLUMNS) {
1522
+ expect({
1523
+ column,
1524
+ selected: Boolean(itemRequests()[0]!.select[column]),
1525
+ }).toEqual({ column, selected: false });
1526
+ }
1527
+
1528
+ expect(screen.getByText("Setup details are hidden")).toBeInTheDocument();
1529
+ expect(rendered.container.innerHTML).not.toContain(HEARTBEAT_SECRET);
1530
+ });
1531
+
1532
+ test("a MonitorViewer gets the page without incidents, alerts or metrics, and never a false zero", async () => {
1533
+ permissions = [Permission.MonitorViewer];
1534
+
1535
+ await renderPage();
1536
+
1537
+ expect(screen.getByTestId("monitor-overview-hero")).toBeInTheDocument();
1538
+ expect(screen.getByTestId("stub-Summary")).toBeInTheDocument();
1539
+
1540
+ // Neither list is asked for; the gate already knows the answer.
1541
+ expect(listRequests(Incident)).toHaveLength(0);
1542
+ expect(listRequests(Alert)).toHaveLength(0);
1543
+
1544
+ const openNow: HTMLElement = tile("monitor-open-now");
1545
+
1546
+ expect(within(openNow).getAllByText("—").length).toBeGreaterThan(0);
1547
+ expect(openNow).toHaveTextContent("Incidents and alerts hidden: no access");
1548
+ expect(openNow).not.toHaveTextContent("0 incidents");
1549
+ expect(openNow).not.toHaveTextContent("Nothing open");
1550
+
1551
+ // The response-time chart needs telemetry access; the card says so.
1552
+ expect(screen.queryByTestId("stub-EmbeddedMetricCard")).toBeNull();
1553
+ expect(
1554
+ screen.getByText(
1555
+ "Response-time history needs permission to read telemetry.",
1556
+ ),
1557
+ ).toBeInTheDocument();
1558
+ });
1559
+
1560
+ test("ReadProjectMonitor gets the row alone: no probe, timeline, uptime or feed reads", async () => {
1561
+ permissions = [Permission.ReadProjectMonitor];
1562
+
1563
+ await renderPage();
1564
+
1565
+ expect(screen.getByTestId("monitor-overview-hero")).toBeInTheDocument();
1566
+
1567
+ expect(listRequests(MonitorProbe)).toHaveLength(0);
1568
+ expect(listRequests(MonitorStatusTimeline)).toHaveLength(0);
1569
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(0);
1570
+ expect(screen.queryByTestId("stub-MonitorFeed")).toBeNull();
1571
+ expect(screen.getByText("Activity is hidden")).toBeInTheDocument();
1572
+
1573
+ // The status is shown, but no duration it cannot vouch for.
1574
+ expect(screen.getByTestId("monitor-overview-headline")).toHaveTextContent(
1575
+ /^Operational$/,
1576
+ );
1577
+
1578
+ for (const id of [
1579
+ "monitor-uptime-24h",
1580
+ "monitor-uptime-7d",
1581
+ "monitor-uptime-30d",
1582
+ ]) {
1583
+ expect(within(tile(id)).getByText("—")).toBeInTheDocument();
1584
+ expect(tile(id)).toHaveTextContent("No access to status history");
1585
+ expect(tile(id)).not.toHaveTextContent("100%");
1586
+ }
1587
+
1588
+ // Unreadable probes are not "no probes".
1589
+ expect(
1590
+ latestProps<{ probeLoadError?: string }>("Summary").probeLoadError,
1591
+ ).toBe("You need permission to read this monitor's probes.");
1592
+ expect(
1593
+ within(screen.getByTestId("monitor-overview-fact-owners")).getByText(
1594
+ "Unavailable",
1595
+ ),
1596
+ ).toBeInTheDocument();
1597
+ });
1598
+ });
1599
+
1600
+ describe("Monitor overview page: moving between monitors", () => {
1601
+ test("shows the skeleton at once and never shows monitor A's data on B", async () => {
1602
+ setUpServer({ id: MONITOR_B, type: MonitorType.API, statusId: OFFLINE_ID });
1603
+
1604
+ const rendered: RenderResult = await renderPage();
1605
+
1606
+ expect(
1607
+ within(screen.getByTestId("monitor-overview-badge")).getByText(
1608
+ "Operational",
1609
+ ),
1610
+ ).toBeInTheDocument();
1611
+
1612
+ const summaryRendersForA: number = propsHistory("Summary").length;
1613
+ holdMonitorRead(MONITOR_B);
1614
+
1615
+ await navigateTo(rendered, MONITOR_B);
1616
+
1617
+ // The first render for B is the skeleton, not A's page.
1618
+ expect(screen.getByRole("status")).toHaveTextContent("Loading monitor");
1619
+ expect(screen.queryByTestId("monitor-overview-hero")).toBeNull();
1620
+ expect(screen.queryByText("Operational")).toBeNull();
1621
+ expect(propsHistory("Summary")).toHaveLength(summaryRendersForA);
1622
+
1623
+ await flush();
1624
+
1625
+ expect(screen.queryByTestId("monitor-overview-hero")).toBeNull();
1626
+
1627
+ await releaseMonitorRead(MONITOR_B);
1628
+
1629
+ expect(
1630
+ within(screen.getByTestId("monitor-overview-badge")).getByText("Offline"),
1631
+ ).toBeInTheDocument();
1632
+
1633
+ // Everything rendered since the switch was for B.
1634
+ for (const props of propsHistory<{ monitorId?: ObjectID }>("Summary").slice(
1635
+ summaryRendersForA,
1636
+ )) {
1637
+ expect(props.monitorId?.toString()).toBe(MONITOR_B);
1638
+ }
1639
+
1640
+ expect(
1641
+ latestProps<{ monitorId: ObjectID }>("MonitorFeed").monitorId.toString(),
1642
+ ).toBe(MONITOR_B);
1643
+ expect(apiGetUrls(`/monitor/uptime-summary/${MONITOR_B}`)).toHaveLength(1);
1644
+ expect(apiGetUrls(`/monitor/refresh-status/${MONITOR_B}`)).toHaveLength(1);
1645
+ });
1646
+
1647
+ test("a late save from the previous monitor's details card is ignored", async () => {
1648
+ setUpServer({ id: MONITOR_B, type: MonitorType.API, statusId: OFFLINE_ID });
1649
+
1650
+ const rendered: RenderResult = await renderPage();
1651
+
1652
+ const saveForA: () => void = latestProps<{ onSaveSuccess: () => void }>(
1653
+ "CardModelDetail:Monitor Details",
1654
+ ).onSaveSuccess;
1655
+
1656
+ holdMonitorRead(MONITOR_B);
1657
+ await navigateTo(rendered, MONITOR_B);
1658
+ await flush();
1659
+
1660
+ const readsBefore: number = itemRequests().length;
1661
+
1662
+ await act(async () => {
1663
+ saveForA();
1664
+ });
1665
+ await flush();
1666
+
1667
+ // No header refresh and no re-read of A, which would cancel B's load.
1668
+ expect(refreshHeaderMock).not.toHaveBeenCalled();
1669
+ expect(itemRequests()).toHaveLength(readsBefore);
1670
+
1671
+ await releaseMonitorRead(MONITOR_B);
1672
+
1673
+ expect(
1674
+ within(screen.getByTestId("monitor-overview-badge")).getByText("Offline"),
1675
+ ).toBeInTheDocument();
1676
+ });
1677
+ });
1678
+
1679
+ describe("Monitor overview page: wiring", () => {
1680
+ test("saving details refreshes the header, re-reads the row and bumps the feed token", async () => {
1681
+ await renderPage();
1682
+
1683
+ const details: { onSaveSuccess: () => void; refresher: boolean } =
1684
+ latestProps<{ onSaveSuccess: () => void; refresher: boolean }>(
1685
+ "CardModelDetail:Monitor Details",
1686
+ );
1687
+ const feedTokenBefore: number = latestProps<{ refreshToken: number }>(
1688
+ "MonitorFeed",
1689
+ ).refreshToken;
1690
+ const readsBefore: number = itemRequests().length;
1691
+
1692
+ await act(async () => {
1693
+ details.onSaveSuccess();
1694
+ });
1695
+ await flush();
1696
+
1697
+ expect(refreshHeaderMock).toHaveBeenCalledTimes(1);
1698
+ expect(itemRequests()).toHaveLength(readsBefore + 1);
1699
+ expect(
1700
+ latestProps<{ refreshToken: number }>("MonitorFeed").refreshToken,
1701
+ ).toBe(feedTokenBefore + 1);
1702
+
1703
+ // Not a manual refresh: the details card is not told to re-read itself.
1704
+ expect(
1705
+ latestProps<{ refresher: boolean }>("CardModelDetail:Monitor Details")
1706
+ .refresher,
1707
+ ).toBe(details.refresher);
1708
+ expect(listRequests(MonitorOwnerUser)).toHaveLength(1);
1709
+ });
1710
+
1711
+ test("the Summary gets the monitor's own probes, the switched-off ones, its steps and each probe's verdict", async () => {
1712
+ server.logs = [
1713
+ buildLog({
1714
+ probeId: PROBE_FRANKFURT,
1715
+ time: secondsAgo(30),
1716
+ summary: buildEvaluation("Frankfurt verdict"),
1717
+ }),
1718
+ ];
1719
+
1720
+ await renderPage();
1721
+
1722
+ interface SummaryProps {
1723
+ monitorType: MonitorType;
1724
+ probes: Array<Probe>;
1725
+ disabledProbeIds: Array<string>;
1726
+ monitorSteps: MonitorSteps | undefined;
1727
+ monitorId: ObjectID;
1728
+ description: string;
1729
+ probeLoadError?: string;
1730
+ probeMonitorResponses?: Array<MonitorStepProbeResponse>;
1731
+ evaluationSummariesByProbeId?: Dictionary<MonitorEvaluationSummary>;
1732
+ evaluationSummary?: MonitorEvaluationSummary;
1733
+ }
1734
+
1735
+ const props: SummaryProps = latestProps<SummaryProps>("Summary");
1736
+
1737
+ expect(props.monitorType).toBe(MonitorType.API);
1738
+ expect(
1739
+ props.probes.map((probe: Probe) => {
1740
+ return [probe._id?.toString(), probe.name];
1741
+ }),
1742
+ ).toEqual([
1743
+ [PROBE_FRANKFURT, "Frankfurt"],
1744
+ [PROBE_VIRGINIA, "Virginia"],
1745
+ ]);
1746
+ expect(props.disabledProbeIds).toEqual([PROBE_VIRGINIA]);
1747
+ expect(props.monitorSteps).toBe(getSteps(API_MONITOR));
1748
+ expect(props.monitorId.toString()).toBe(MONITOR_A);
1749
+ expect(props.description).toBe(
1750
+ "What each probe saw on its most recent check.",
1751
+ );
1752
+ expect(props.probeLoadError).toBeUndefined();
1753
+ expect(props.probeMonitorResponses).toHaveLength(1);
1754
+ expect(Object.keys(props.evaluationSummariesByProbeId || {})).toEqual([
1755
+ PROBE_FRANKFURT,
1756
+ ]);
1757
+ expect(
1758
+ props.evaluationSummariesByProbeId?.[PROBE_FRANKFURT]?.criteriaResults[0]
1759
+ ?.criteriaName,
1760
+ ).toBe("Frankfurt verdict");
1761
+ // The newest verdict is that same probe's.
1762
+ expect(props.evaluationSummary).toEqual(
1763
+ props.evaluationSummariesByProbeId?.[PROBE_FRANKFURT],
1764
+ );
1765
+ expect(props.evaluationSummary).toBeDefined();
1766
+ });
1767
+
1768
+ test("the hero and the probes card agree on the probe count", async () => {
1769
+ await renderPage();
1770
+
1771
+ // One of the two attached probes is switched off.
1772
+ expect(
1773
+ screen.getByTestId("monitor-overview-fact-probes"),
1774
+ ).toHaveTextContent(/1 of 1/);
1775
+ const probesCard: HTMLElement = heading("Probes").closest(
1776
+ '[data-testid="card"]',
1777
+ ) as HTMLElement;
1778
+
1779
+ expect(within(probesCard).getByText("Frankfurt")).toBeInTheDocument();
1780
+ expect(within(probesCard).getByText("Virginia")).toBeInTheDocument();
1781
+ expect(
1782
+ within(probesCard).getByText("Turned off for this monitor"),
1783
+ ).toBeInTheDocument();
1784
+ });
1785
+ });
1786
+
1787
+ describe("Monitor overview page: the moment it is judged at", () => {
1788
+ afterEach(() => {
1789
+ // Back to jsdom's own (visible) document.
1790
+ delete (document as unknown as Record<string, unknown>)["visibilityState"];
1791
+ });
1792
+
1793
+ test("a browser clock seven minutes fast is corrected by the server's clock", async () => {
1794
+ // The server stamped every time around NOW; the browser says 12:07.
1795
+ jest.setSystemTime(new Date(NOW.getTime() + 7 * 60 * 1000));
1796
+
1797
+ await renderPage();
1798
+
1799
+ // The result is 30 s old on the server's clock, not 7m30s.
1800
+ expect(
1801
+ within(screen.getByTestId("monitor-overview-badge")).getByText(
1802
+ "Operational",
1803
+ ),
1804
+ ).toBeInTheDocument();
1805
+ expect(screen.queryByText("Checks overdue")).toBeNull();
1806
+
1807
+ const probesCard: HTMLElement = heading("Probes").closest(
1808
+ '[data-testid="card"]',
1809
+ ) as HTMLElement;
1810
+ expect(within(probesCard).queryByText("Late")).toBeNull();
1811
+ });
1812
+
1813
+ test("coming back to a tab hidden for ten minutes does not flash 'overdue' before the poll lands", async () => {
1814
+ await renderPage();
1815
+
1816
+ expect(screen.queryByText("Checks overdue")).toBeNull();
1817
+
1818
+ // Hidden for ten minutes: the ticks are skipped, nothing is re-read.
1819
+ Object.defineProperty(document, "visibilityState", {
1820
+ configurable: true,
1821
+ get: (): DocumentVisibilityState => {
1822
+ return "hidden";
1823
+ },
1824
+ });
1825
+ await act(async () => {
1826
+ jest.advanceTimersByTime(10 * 60 * 1000);
1827
+ });
1828
+ await flush();
1829
+
1830
+ expect(itemRequests()).toHaveLength(1);
1831
+
1832
+ // Back to the tab: the catch-up poll starts, its Monitor read is slow.
1833
+ holdMonitorRead(MONITOR_A);
1834
+ Object.defineProperty(document, "visibilityState", {
1835
+ configurable: true,
1836
+ get: (): DocumentVisibilityState => {
1837
+ return "visible";
1838
+ },
1839
+ });
1840
+ await act(async () => {
1841
+ document.dispatchEvent(new Event("visibilitychange"));
1842
+ });
1843
+ await flush();
1844
+
1845
+ expect(itemRequests()).toHaveLength(2);
1846
+
1847
+ /*
1848
+ * The page re-rendered for the poll, but still judges what it holds at
1849
+ * the moment it loaded it.
1850
+ */
1851
+ expect(
1852
+ within(screen.getByTestId("monitor-overview-badge")).getByText(
1853
+ "Operational",
1854
+ ),
1855
+ ).toBeInTheDocument();
1856
+ expect(screen.queryByText("Checks overdue")).toBeNull();
1857
+
1858
+ await releaseMonitorRead(MONITOR_A);
1859
+ });
1860
+
1861
+ test("the Probes card judges a next check on the same clock as the hero", async () => {
1862
+ // The browser's clock is ten minutes slow.
1863
+ jest.setSystemTime(secondsAgo(10 * 60));
1864
+ server.probes = [
1865
+ {
1866
+ probeId: PROBE_FRANKFURT,
1867
+ name: "Frankfurt",
1868
+ isEnabled: true,
1869
+ monitoredAt: secondsAgo(30),
1870
+ // Due two minutes ago on the server's clock; eight minutes away on the browser's.
1871
+ nextPingAt: secondsAgo(120),
1872
+ },
1873
+ ];
1874
+
1875
+ await renderPage();
1876
+
1877
+ const probesCard: HTMLElement = heading("Probes").closest(
1878
+ '[data-testid="card"]',
1879
+ ) as HTMLElement;
1880
+ const row: HTMLElement =
1881
+ within(probesCard).getByTestId("monitor-probe-row");
1882
+
1883
+ // The hero promises no next check for a run that is past, and nor does the card.
1884
+ expect(row).toHaveTextContent("Checked");
1885
+ expect(row).not.toHaveTextContent("next");
1886
+ expect(within(probesCard).queryByText("Late")).toBeNull();
1887
+ });
1888
+
1889
+ test("an uptime summary replayed from a cache does not wind the page's clock back", async () => {
1890
+ await renderPage();
1891
+
1892
+ /*
1893
+ * The probes stop reporting. Every uptime reload (each fifth poll) comes
1894
+ * back with the summary stamped at the first load, as the service
1895
+ * worker's cache would answer it: taken at face value, each would put
1896
+ * the server's clock minutes behind and hide the overdue checks.
1897
+ */
1898
+ for (let tick: number = 0; tick < 12; tick++) {
1899
+ await act(async () => {
1900
+ jest.advanceTimersByTime(MONITOR_OVERVIEW_REFRESH_INTERVAL_MS);
1901
+ });
1902
+ await flush();
1903
+ }
1904
+
1905
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(3);
1906
+ expect(screen.getByText("Checks overdue")).toBeInTheDocument();
1907
+ });
1908
+
1909
+ test("probe results the page cannot re-read are judged as of their read, never 'Checks overdue'", async () => {
1910
+ // The clocks agree all along, so every reload measures no offset.
1911
+ server.isUptimeStampedLive = true;
1912
+
1913
+ await renderPage();
1914
+
1915
+ expect(screen.queryByText("Checks overdue")).toBeNull();
1916
+
1917
+ // Every probe read fails from here on; the Monitor row keeps refreshing.
1918
+ server.probeFailure = new Error("Probe results timed out.");
1919
+
1920
+ for (let tick: number = 0; tick < 12; tick++) {
1921
+ await act(async () => {
1922
+ jest.advanceTimersByTime(MONITOR_OVERVIEW_REFRESH_INTERVAL_MS);
1923
+ });
1924
+ await flush();
1925
+ }
1926
+
1927
+ expect(itemRequests()).toHaveLength(13);
1928
+
1929
+ // Twelve minutes on, the result read at the first load is still not "late".
1930
+ expect(screen.queryByText("Checks overdue")).toBeNull();
1931
+
1932
+ const probesCard: HTMLElement = heading("Probes").closest(
1933
+ '[data-testid="card"]',
1934
+ ) as HTMLElement;
1935
+
1936
+ expect(within(probesCard).queryByText("Late")).toBeNull();
1937
+ // The card says why the results are old.
1938
+ expect(
1939
+ within(probesCard).getByText(
1940
+ "Couldn't refresh probes. Probe results timed out.",
1941
+ ),
1942
+ ).toBeInTheDocument();
1943
+
1944
+ /*
1945
+ * Their next checks passed long ago. Judged at the read, they would
1946
+ * still read as upcoming; whether a check is still ahead is a question
1947
+ * about now, so neither the hero nor any probe row offers a "next".
1948
+ */
1949
+ const cadence: HTMLElement | null = screen.queryByTestId(
1950
+ "monitor-overview-cadence",
1951
+ );
1952
+
1953
+ if (cadence) {
1954
+ expect(cadence).not.toHaveTextContent("next");
1955
+ }
1956
+
1957
+ for (const row of within(probesCard).getAllByTestId("monitor-probe-row")) {
1958
+ expect(row).not.toHaveTextContent("next");
1959
+ }
1960
+
1961
+ /*
1962
+ * A read that works and brings back the same old result is judged at
1963
+ * the commit: that result is overdue, and now the page can say so.
1964
+ */
1965
+ server.probeFailure = null;
1966
+
1967
+ await act(async () => {
1968
+ jest.advanceTimersByTime(MONITOR_OVERVIEW_REFRESH_INTERVAL_MS);
1969
+ });
1970
+ await flush();
1971
+
1972
+ expect(screen.getByText("Checks overdue")).toBeInTheDocument();
1973
+ });
1974
+ });
1975
+
1976
+ describe("Monitor overview page: the Summary card's last check", () => {
1977
+ interface TelemetrySummaryProps {
1978
+ telemetryMonitorSummary: {
1979
+ lastCheckedAt?: Date | undefined;
1980
+ nextCheckAt?: Date | undefined;
1981
+ lastCheckedLabel?: string | undefined;
1982
+ };
1983
+ }
1984
+
1985
+ // The worker stamped a run 40 s ago; the newest evaluation is 14 minutes old.
1986
+ const setUpStalledKubernetes: () => void = (): void => {
1987
+ setUpServer({
1988
+ id: MONITOR_A,
1989
+ type: MonitorType.Kubernetes,
1990
+ statusId: OPERATIONAL_ID,
1991
+ overrides: {
1992
+ telemetryMonitorLastMonitorAt: secondsAgo(40),
1993
+ telemetryMonitorNextMonitorAt: secondsAgo(-20),
1994
+ },
1995
+ });
1996
+ server.probes = [];
1997
+ server.logs = [
1998
+ buildLog({
1999
+ probeId: PROBE_FRANKFURT,
2000
+ time: secondsAgo(14 * 60),
2001
+ summary: buildEvaluation("Pods are running"),
2002
+ }),
2003
+ ];
2004
+ };
2005
+
2006
+ test("a telemetry monitor's is the newest evaluation, as in the hero, not the scheduler's stamp", async () => {
2007
+ setUpStalledKubernetes();
2008
+
2009
+ await renderPage();
2010
+
2011
+ expect(screen.getByText("Checks overdue")).toBeInTheDocument();
2012
+
2013
+ const props: TelemetrySummaryProps =
2014
+ latestProps<TelemetrySummaryProps>("Summary");
2015
+
2016
+ expect(props.telemetryMonitorSummary.lastCheckedAt).toEqual(
2017
+ secondsAgo(14 * 60),
2018
+ );
2019
+ expect(props.telemetryMonitorSummary.lastCheckedLabel).toBe("Evaluated At");
2020
+ expect(props.telemetryMonitorSummary.nextCheckAt).toEqual(secondsAgo(-20));
2021
+ });
2022
+
2023
+ test("until the evaluation log can be read, it is the scheduler's stamp", async () => {
2024
+ setUpStalledKubernetes();
2025
+ analyticsGetListSpy.mockImplementation((): Promise<unknown> => {
2026
+ return rejectWith(new Error("Logs are unavailable."));
2027
+ });
2028
+
2029
+ await renderPage();
2030
+
2031
+ const props: TelemetrySummaryProps =
2032
+ latestProps<TelemetrySummaryProps>("Summary");
2033
+
2034
+ expect(props.telemetryMonitorSummary.lastCheckedAt).toEqual(secondsAgo(40));
2035
+ expect(props.telemetryMonitorSummary.lastCheckedLabel).toBe("Scheduled At");
2036
+ });
2037
+ });
2038
+
2039
+ describe("Monitor overview page: the uptime caveat", () => {
2040
+ test("a manual monitor with an incident declared on it gets no 'paused time' caveat", async () => {
2041
+ setUpServer({
2042
+ id: MONITOR_A,
2043
+ type: MonitorType.Manual,
2044
+ statusId: OPERATIONAL_ID,
2045
+ stepData: null,
2046
+ overrides: { disableActiveMonitoringBecauseOfManualIncident: true },
2047
+ });
2048
+ server.probes = [];
2049
+
2050
+ await renderPage();
2051
+
2052
+ for (const id of [
2053
+ "monitor-uptime-24h",
2054
+ "monitor-uptime-7d",
2055
+ "monitor-uptime-30d",
2056
+ ]) {
2057
+ expect(tile(id)).toHaveTextContent("100%");
2058
+ expect(tile(id)).not.toHaveTextContent("includes paused time");
2059
+ }
2060
+ });
2061
+
2062
+ test("a paused probe check's windows include paused time", async () => {
2063
+ setUpServer({
2064
+ ...API_MONITOR,
2065
+ overrides: { disableActiveMonitoring: true },
2066
+ });
2067
+
2068
+ await renderPage();
2069
+
2070
+ for (const id of [
2071
+ "monitor-uptime-24h",
2072
+ "monitor-uptime-7d",
2073
+ "monitor-uptime-30d",
2074
+ ]) {
2075
+ expect(tile(id)).toHaveTextContent("No downtime · includes paused time");
2076
+ }
2077
+ });
2078
+ });
2079
+
2080
+ describe("Monitor overview page: a history the page hides", () => {
2081
+ test("the uptime history is read once and not reloaded while the monitor waits for data, then once when it shows", async () => {
2082
+ setUpServer({
2083
+ id: MONITOR_A,
2084
+ type: MonitorType.IncomingRequest,
2085
+ statusId: OPERATIONAL_ID,
2086
+ });
2087
+ server.probes = [];
2088
+
2089
+ await renderPage();
2090
+
2091
+ // Waiting for its first heartbeat: no stat bar, no history.
2092
+ expect(
2093
+ screen.queryByRole("heading", { name: "Uptime history" }),
2094
+ ).toBeNull();
2095
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(1);
2096
+
2097
+ // Five polls and a Refresh would each reload a shown history.
2098
+ for (let tick: number = 0; tick < 5; tick++) {
2099
+ await act(async () => {
2100
+ jest.advanceTimersByTime(MONITOR_OVERVIEW_REFRESH_INTERVAL_MS);
2101
+ });
2102
+ await flush();
2103
+ }
2104
+
2105
+ await act(async () => {
2106
+ fireEvent.click(screen.getByTestId("monitor-overview-refresh"));
2107
+ });
2108
+ await flush();
2109
+
2110
+ expect(itemRequests()).toHaveLength(7);
2111
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(1);
2112
+
2113
+ // The first heartbeat arrives: the history shows, and is read once.
2114
+ setUpServer({
2115
+ id: MONITOR_A,
2116
+ type: MonitorType.IncomingRequest,
2117
+ statusId: OPERATIONAL_ID,
2118
+ overrides: {
2119
+ incomingMonitorRequest: {
2120
+ incomingRequestReceivedAt: new Date(
2121
+ NOW.getTime() + 6 * MONITOR_OVERVIEW_REFRESH_INTERVAL_MS - 5000,
2122
+ ),
2123
+ requestMethod: "POST",
2124
+ } as unknown as Monitor["incomingMonitorRequest"],
2125
+ },
2126
+ });
2127
+
2128
+ await act(async () => {
2129
+ jest.advanceTimersByTime(MONITOR_OVERVIEW_REFRESH_INTERVAL_MS);
2130
+ });
2131
+ await flush();
2132
+
2133
+ expect(heading("Uptime history")).toBeInTheDocument();
2134
+ expect(apiGetUrls("/monitor/uptime-summary/")).toHaveLength(2);
2135
+ });
2136
+ });