@oneuptime/common 14.0.8 → 14.0.9

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 (639) hide show
  1. package/Models/DatabaseModels/Index.ts +2 -0
  2. package/Models/DatabaseModels/KubernetesAiAgent.ts +364 -0
  3. package/Models/DatabaseModels/KubernetesCluster.ts +3 -3
  4. package/Models/DatabaseModels/Project.ts +55 -5
  5. package/Models/DatabaseModels/ProxmoxResource.ts +49 -1
  6. package/Models/DatabaseModels/RunnerJob.ts +75 -0
  7. package/Models/DatabaseModels/TeamComplianceSetting.ts +143 -2
  8. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +17 -0
  9. package/Server/API/AIChatAPI.ts +6 -3
  10. package/Server/API/AIInvestigationAPI.ts +17 -10
  11. package/Server/API/AutoRemediationAPI.ts +207 -25
  12. package/Server/API/KubernetesClusterAiAccessAPI.ts +623 -21
  13. package/Server/API/MicrosoftTeamsAPI.ts +93 -14
  14. package/Server/API/ProxmoxResourceAPI.ts +244 -14
  15. package/Server/Infrastructure/GlobalCache.ts +32 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.ts +99 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.ts +137 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.ts +42 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  20. package/Server/Middleware/TelemetryIngest.ts +41 -18
  21. package/Server/Services/AIService.ts +70 -1
  22. package/Server/Services/AlertService.ts +352 -11
  23. package/Server/Services/AlertSeverityService.ts +65 -15
  24. package/Server/Services/AutoRemediationRuleService.ts +1 -1
  25. package/Server/Services/IncidentService.ts +280 -104
  26. package/Server/Services/IncidentSeverityService.ts +66 -15
  27. package/Server/Services/KubernetesAiAgentJobService.ts +185 -0
  28. package/Server/Services/KubernetesAiAgentService.ts +1634 -0
  29. package/Server/Services/KubernetesClusterAiAccessService.ts +1118 -451
  30. package/Server/Services/KubernetesClusterService.ts +129 -21
  31. package/Server/Services/ProjectService.ts +32 -0
  32. package/Server/Services/ProxmoxResourceService.ts +322 -5
  33. package/Server/Services/RunnerJobService.ts +241 -104
  34. package/Server/Services/RunnerService.ts +1 -1
  35. package/Server/Services/ScheduledMaintenanceService.ts +737 -1
  36. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +414 -56
  37. package/Server/Services/TeamComplianceSettingService.ts +1125 -9
  38. package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +67 -9
  39. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +39 -10
  40. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +14 -3
  41. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +37 -15
  42. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +67 -24
  43. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +48 -5
  44. package/Server/Utils/AI/SRE/IncidentPostmortemRunner.ts +40 -8
  45. package/Server/Utils/AI/SRE/InvestigationEligibility.ts +13 -2
  46. package/Server/Utils/AI/SRE/InvestigationGrader.ts +1 -1
  47. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +6 -1
  48. package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +133 -7
  49. package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +58 -4
  50. package/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.ts +447 -0
  51. package/Server/Utils/Telemetry/ProxmoxNativePush.ts +903 -0
  52. package/Server/Utils/Telemetry/TelemetryEntity.ts +87 -27
  53. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +684 -47
  54. package/Tests/App/AdminDashboard/RowActionPlacementOverrides.test.tsx +278 -0
  55. package/Tests/App/Dashboard/AIChatChartWidgetZoom.test.tsx +738 -0
  56. package/Tests/App/Dashboard/AIFeaturesSettingsPointers.test.tsx +147 -0
  57. package/Tests/App/Dashboard/AIInsightsKubernetesClusterPage.test.tsx +1523 -0
  58. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +463 -3
  59. package/Tests/App/Dashboard/AffectedResourcesPickerDropdownPlacement.test.tsx +958 -0
  60. package/Tests/App/Dashboard/AffectedResourcesPickerFocusLeave.test.tsx +595 -0
  61. package/Tests/App/Dashboard/AskAiAvailability.test.ts +20 -3
  62. package/Tests/App/Dashboard/AskAiDisabled.test.tsx +8 -3
  63. package/Tests/App/Dashboard/CephRateChartReload.test.tsx +1456 -0
  64. package/Tests/App/Dashboard/CephTimeRangeZoom.test.tsx +1229 -0
  65. package/Tests/App/Dashboard/ChartCardTimeRangeZoom.test.tsx +151 -0
  66. package/Tests/App/Dashboard/ChartCardZoomAffordances.test.tsx +257 -0
  67. package/Tests/App/Dashboard/ChartRefetchFrame.test.tsx +141 -0
  68. package/Tests/App/Dashboard/ChartZoomHarness.tsx +249 -0
  69. package/Tests/App/Dashboard/ChartZoomStandIn.tsx +131 -0
  70. package/Tests/App/Dashboard/CloudServerlessSlowLoads.test.tsx +628 -0
  71. package/Tests/App/Dashboard/CloudServerlessTimeRangeZoom.test.tsx +607 -0
  72. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +91 -19
  73. package/Tests/App/Dashboard/CompanionMetricsTabZoom.test.tsx +632 -0
  74. package/Tests/App/Dashboard/ContainerChartZoomStandIn.tsx +195 -0
  75. package/Tests/App/Dashboard/ContainerHostOverviewSlowLoads.test.tsx +542 -0
  76. package/Tests/App/Dashboard/ContainerHostOverviewTimeRangeZoom.test.tsx +848 -0
  77. package/Tests/App/Dashboard/ContainerMetricsTimeRangeZoom.test.tsx +561 -0
  78. package/Tests/App/Dashboard/DashboardBoardWideZoomShell.test.tsx +1147 -0
  79. package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +3 -2
  80. package/Tests/App/Dashboard/DashboardHistogramWidgetDragCursor.test.tsx +399 -0
  81. package/Tests/App/Dashboard/DashboardHistogramWidgetZoom.test.tsx +985 -0
  82. package/Tests/App/Dashboard/DashboardHistogramWidgetZoomHint.test.tsx +803 -0
  83. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +1 -0
  84. package/Tests/App/Dashboard/DashboardSettingsPreviewZoom.test.tsx +679 -0
  85. package/Tests/App/Dashboard/DashboardSloAndDataSourceChartZoom.test.tsx +881 -0
  86. package/Tests/App/Dashboard/DashboardTraceStatusWidgets.test.tsx +878 -0
  87. package/Tests/App/Dashboard/DatabaseMetricChartModalTimeRangeZoom.test.tsx +442 -0
  88. package/Tests/App/Dashboard/DatabaseOverviewTimeRangeZoom.test.tsx +831 -0
  89. package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +43 -0
  90. package/Tests/App/Dashboard/DockerSwarmInsightsTimeRangeZoom.test.tsx +524 -0
  91. package/Tests/App/Dashboard/DockerSwarmRateChartRefresh.test.tsx +259 -0
  92. package/Tests/App/Dashboard/EdgeDetailPanelHistory.test.tsx +763 -0
  93. package/Tests/App/Dashboard/EdgeDetailPanelTimeRangeZoom.test.tsx +547 -0
  94. package/Tests/App/Dashboard/EdgeHistoryBucketsCases.tsx +565 -0
  95. package/Tests/App/Dashboard/EdgeHistoryBucketsKathmandu.test.tsx +73 -0
  96. package/Tests/App/Dashboard/EdgeHistoryBucketsKolkata.test.tsx +74 -0
  97. package/Tests/App/Dashboard/EdgeHistoryBucketsNewYork.test.tsx +72 -0
  98. package/Tests/App/Dashboard/EdgeHistoryBucketsUtc.test.tsx +72 -0
  99. package/Tests/App/Dashboard/EmbeddedMetricCardRefresh.test.tsx +310 -0
  100. package/Tests/App/Dashboard/EmbeddedMetricCardTimeRangeZoom.test.tsx +536 -0
  101. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +3 -1
  102. package/Tests/App/Dashboard/EscalationRuleRowActions.test.tsx +660 -0
  103. package/Tests/App/Dashboard/EventNotes.test.tsx +2 -2
  104. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +587 -13
  105. package/Tests/App/Dashboard/EventOverviewSnapshotExplorerZoom.test.tsx +1139 -0
  106. package/Tests/App/Dashboard/EventOverviewSnapshotZoomAcrossTabs.test.tsx +1057 -0
  107. package/Tests/App/Dashboard/EventOverviewTelemetrySnapshotZoom.test.tsx +757 -0
  108. package/Tests/App/Dashboard/ExceptionOccurrenceTrendZoom.test.tsx +675 -0
  109. package/Tests/App/Dashboard/ExceptionOccurrencesZoomSurvivesViewSwitch.test.tsx +405 -0
  110. package/Tests/App/Dashboard/ExceptionSignalPages.test.tsx +67 -3
  111. package/Tests/App/Dashboard/ExceptionTablesSpanStatus.test.tsx +515 -0
  112. package/Tests/App/Dashboard/ExplorerOwnZoomRegression.test.tsx +739 -0
  113. package/Tests/App/Dashboard/FlowBandwidthAxisCases.tsx +461 -0
  114. package/Tests/App/Dashboard/FlowBandwidthAxisKathmandu.test.tsx +25 -0
  115. package/Tests/App/Dashboard/FlowBandwidthAxisKolkata.test.tsx +25 -0
  116. package/Tests/App/Dashboard/FlowBandwidthAxisNewYork.test.tsx +25 -0
  117. package/Tests/App/Dashboard/FlowBandwidthAxisUtc.test.tsx +24 -0
  118. package/Tests/App/Dashboard/FlowTopTalkersZoomRefetch.test.tsx +722 -0
  119. package/Tests/App/Dashboard/FlowViewportGuard.test.tsx +2526 -0
  120. package/Tests/App/Dashboard/HostPagesSlowLoads.test.tsx +872 -0
  121. package/Tests/App/Dashboard/HostPagesTimeRangeZoom.test.tsx +1208 -0
  122. package/Tests/App/Dashboard/IncidentRootCauseTimeRangeZoom.test.tsx +358 -0
  123. package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +100 -9
  124. package/Tests/App/Dashboard/InfrastructureMetricsTabTimeRangeZoom.test.tsx +485 -0
  125. package/Tests/App/Dashboard/InvestigationDrawerCompanionZoom.test.tsx +655 -0
  126. package/Tests/App/Dashboard/InvestigationDrawerZoom.test.tsx +830 -0
  127. package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +338 -2
  128. package/Tests/App/Dashboard/InvoicesPayInvoice.test.tsx +454 -16
  129. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +799 -819
  130. package/Tests/App/Dashboard/KubernetesClusterAiAgentOverviewCard.test.tsx +367 -0
  131. package/Tests/App/Dashboard/KubernetesClusterAiAgentStatus.test.ts +1202 -0
  132. package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +106 -0
  133. package/Tests/App/Dashboard/KubernetesClusterAiNavigation.test.tsx +354 -0
  134. package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +1884 -2054
  135. package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +478 -179
  136. package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +50 -0
  137. package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +2 -1
  138. package/Tests/App/Dashboard/KubernetesClusterOverviewZoom.test.tsx +1217 -0
  139. package/Tests/App/Dashboard/KubernetesClusterPagesZoom.test.tsx +731 -0
  140. package/Tests/App/Dashboard/KubernetesCostsLoadRecovery.test.tsx +869 -0
  141. package/Tests/App/Dashboard/KubernetesCostsZoom.test.tsx +1214 -0
  142. package/Tests/App/Dashboard/KubernetesCostsZoomExactHours.test.tsx +692 -0
  143. package/Tests/App/Dashboard/KubernetesNetworkThroughputReload.test.tsx +902 -0
  144. package/Tests/App/Dashboard/KubernetesNetworkZoomBucketEdges.test.tsx +571 -0
  145. package/Tests/App/Dashboard/KubernetesOverviewZoomBucketEdges.test.tsx +697 -0
  146. package/Tests/App/Dashboard/KubernetesResourceMetricsTabZoom.test.tsx +633 -0
  147. package/Tests/App/Dashboard/LogsExplorerTimeRangeZoom.test.tsx +470 -0
  148. package/Tests/App/Dashboard/LogsInsightsTimeRangeZoom.test.tsx +948 -0
  149. package/Tests/App/Dashboard/LogsViewerPinnedWindowZoom.test.tsx +486 -0
  150. package/Tests/App/Dashboard/MetricChartsBucketInspectorDoubleClick.test.tsx +1001 -0
  151. package/Tests/App/Dashboard/MetricExplorerInvestigationAutoRefresh.test.tsx +514 -0
  152. package/Tests/App/Dashboard/MetricExplorerSavedViewZoomRoundTrip.test.tsx +581 -0
  153. package/Tests/App/Dashboard/MetricExplorerTimeRangeZoom.test.tsx +1162 -0
  154. package/Tests/App/Dashboard/MetricMonitorPreviewZoomLabel.test.ts +72 -0
  155. package/Tests/App/Dashboard/MetricRowSparklineTimeRangeZoom.test.tsx +204 -0
  156. package/Tests/App/Dashboard/MetricViewFirstResultLands.test.tsx +408 -0
  157. package/Tests/App/Dashboard/MetricViewOwnZoomResetPlacement.test.tsx +952 -0
  158. package/Tests/App/Dashboard/MetricViewTimeRange.test.ts +139 -0
  159. package/Tests/App/Dashboard/MetricViewTimeRangeZoom.test.tsx +556 -0
  160. package/Tests/App/Dashboard/MonitorMetricsChartWrappersZoom.test.tsx +552 -0
  161. package/Tests/App/Dashboard/MonitorMetricsTabsTimeRangeZoom.test.tsx +740 -0
  162. package/Tests/App/Dashboard/MonitorOverviewChartsTimeRangeZoom.test.tsx +735 -0
  163. package/Tests/App/Dashboard/MonitorStepPreviewsTimeRangeZoom.test.tsx +835 -0
  164. package/Tests/App/Dashboard/NetworkDeviceTimeRangeZoom.test.tsx +1115 -0
  165. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +186 -17
  166. package/Tests/App/Dashboard/OnCallRulesDeleteGuard.test.tsx +155 -46
  167. package/Tests/App/Dashboard/PasskeySettings.test.tsx +87 -2
  168. package/Tests/App/Dashboard/ProjectAISettingsPages.test.tsx +884 -0
  169. package/Tests/App/Dashboard/ProxmoxNodeRemove.test.tsx +621 -0
  170. package/Tests/App/Dashboard/ProxmoxOverviewSlowLoads.test.tsx +584 -0
  171. package/Tests/App/Dashboard/ProxmoxPagesTimeRangeZoom.test.tsx +823 -0
  172. package/Tests/App/Dashboard/ProxmoxRateChartReload.test.tsx +1253 -0
  173. package/Tests/App/Dashboard/PublicDashboardBoardWideZoom.test.tsx +605 -0
  174. package/Tests/App/Dashboard/RealRowsLineChart.tsx +250 -0
  175. package/Tests/App/Dashboard/RechartsHostsPlotCursor.test.tsx +513 -0
  176. package/Tests/App/Dashboard/RowActionPlacementOverrides.test.tsx +865 -0
  177. package/Tests/App/Dashboard/RumOverviewTimeRangeZoom.test.tsx +877 -0
  178. package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +20 -4
  179. package/Tests/App/Dashboard/RunnerSupersededByAiAgentNote.test.tsx +296 -0
  180. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +146 -36
  181. package/Tests/App/Dashboard/ServiceDatabaseSlowLoads.test.tsx +1166 -0
  182. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +1243 -104
  183. package/Tests/App/Dashboard/ServiceOverviewTimeRangeZoom.test.tsx +792 -0
  184. package/Tests/App/Dashboard/SloBudgetBurnDownZoom.test.tsx +771 -0
  185. package/Tests/App/Dashboard/SloBudgetBurnDownZoomAffordances.test.tsx +380 -0
  186. package/Tests/App/Dashboard/SloEventMetricsBarChartZoom.test.tsx +369 -0
  187. package/Tests/App/Dashboard/SloHistoryChartsTimeRangeZoom.test.tsx +694 -0
  188. package/Tests/App/Dashboard/SloHistoryChartsZoomAffordances.test.tsx +497 -0
  189. package/Tests/App/Dashboard/SloMetricsTimeRangeZoom.test.tsx +541 -0
  190. package/Tests/App/Dashboard/SlowLoadHarness.ts +123 -0
  191. package/Tests/App/Dashboard/SnapshotExplorerPrimaryZoom.test.tsx +1194 -0
  192. package/Tests/App/Dashboard/SnapshotViewerPinnedWindow.test.tsx +620 -0
  193. package/Tests/App/Dashboard/TelemetrySnapshotPanelTimeRangeZoom.test.tsx +765 -0
  194. package/Tests/App/Dashboard/TelemetrySnapshotZoom.test.tsx +516 -0
  195. package/Tests/App/Dashboard/TelemetrySnapshotZoomAcrossTabs.test.tsx +827 -0
  196. package/Tests/App/Dashboard/TimeRangeZoomPageHarness.tsx +463 -0
  197. package/Tests/App/Dashboard/TraceChartEditorStatusSplit.test.tsx +543 -0
  198. package/Tests/App/Dashboard/TraceStatusPresentation.test.tsx +967 -0
  199. package/Tests/App/Dashboard/TraceTimelineMinimapZoom.test.tsx +315 -0
  200. package/Tests/App/Dashboard/TracesAnalyticsStatusSplit.test.tsx +778 -0
  201. package/Tests/App/Dashboard/TracesAnalyticsViewZoom.test.tsx +349 -0
  202. package/Tests/App/Dashboard/TracesExplorerTimeRangeZoom.test.tsx +551 -0
  203. package/Tests/App/Dashboard/TracesStatusChartAndFacet.test.tsx +687 -0
  204. package/Tests/App/Dashboard/TracesViewerStaleResponses.test.tsx +458 -0
  205. package/Tests/App/Dashboard/UptimeStripsExcludedFromZoom.test.tsx +406 -0
  206. package/Tests/App/Dashboard/VMwareOverviewSlowLoads.test.tsx +535 -0
  207. package/Tests/App/Dashboard/VMwarePagesTimeRangeZoom.test.tsx +606 -0
  208. package/Tests/App/Dashboard/ValueWidgetSparklineStaleHover.test.tsx +1292 -0
  209. package/Tests/App/Dashboard/ValueWidgetSparklineZoom.test.tsx +765 -0
  210. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +98 -0
  211. package/Tests/Models/DatabaseModels/KubernetesAiAgentModel.test.ts +295 -0
  212. package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +347 -0
  213. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +58 -0
  214. package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +1 -1
  215. package/Tests/Server/API/AIInvestigationAPI.test.ts +123 -45
  216. package/Tests/Server/API/AutoRemediationApproveClusterRound.test.ts +1329 -0
  217. package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +25 -2
  218. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -0
  219. package/Tests/Server/API/KubernetesClusterAiAccessAPIAgent.test.ts +903 -0
  220. package/Tests/Server/API/MicrosoftTeamsChatsRefreshRoute.test.ts +667 -0
  221. package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +294 -6
  222. package/Tests/Server/API/ProxmoxResourceAPIRemoveNode.test.ts +1932 -0
  223. package/Tests/Server/Infrastructure/GlobalCache.test.ts +195 -0
  224. package/Tests/Server/Infrastructure/Postgres/AddKubernetesAiAgentAndAiDefaultsMigration.test.ts +623 -0
  225. package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +87 -10
  226. package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleScopeMigration.test.ts +622 -0
  227. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +61 -4
  228. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +98 -2
  229. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +105 -2
  230. package/Tests/Server/Services/AIServiceBalanceBlocker.test.ts +282 -0
  231. package/Tests/Server/Services/AlertMonitorClearWritesNull.test.ts +409 -0
  232. package/Tests/Server/Services/AlertMonitorEditFeed.test.ts +474 -0
  233. package/Tests/Server/Services/AlertMonitorEditGuard.test.ts +610 -0
  234. package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +2 -0
  235. package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +2 -1
  236. package/Tests/Server/Services/IncidentAffectedMonitorsEdit.test.ts +1360 -0
  237. package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +3 -1
  238. package/Tests/Server/Services/IncidentSeverityDeletePausesComplianceRules.test.ts +488 -0
  239. package/Tests/Server/Services/KubernetesAiAgentJobService.test.ts +329 -0
  240. package/Tests/Server/Services/KubernetesAiAgentServiceHelpers.test.ts +618 -0
  241. package/Tests/Server/Services/KubernetesAiAgentServiceLifecycle.test.ts +1444 -0
  242. package/Tests/Server/Services/KubernetesAiAgentServiceRegister.test.ts +1666 -0
  243. package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +140 -111
  244. package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +267 -105
  245. package/Tests/Server/Services/KubernetesClusterAiAccessLegacySuperseded.test.ts +440 -0
  246. package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +567 -411
  247. package/Tests/Server/Services/KubernetesClusterAiAccessTarget.test.ts +1168 -0
  248. package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +410 -12
  249. package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +55 -0
  250. package/Tests/Server/Services/ProjectServiceNewProjectAiDefaults.test.ts +288 -0
  251. package/Tests/Server/Services/ProxmoxResourcePostgres.test.ts +5633 -0
  252. package/Tests/Server/Services/ProxmoxResourceService.test.ts +6458 -5
  253. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +48 -15
  254. package/Tests/Server/Services/RunnerJobEnqueueKubectlAiAgent.test.ts +620 -0
  255. package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +170 -3
  256. package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +72 -0
  257. package/Tests/Server/Services/RunnerServiceAgentName.test.ts +6 -4
  258. package/Tests/Server/Services/ScheduledMaintenanceAttachmentEdit.test.ts +2113 -0
  259. package/Tests/Server/Services/ScheduledMaintenanceMonitorRelease.test.ts +972 -0
  260. package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +2237 -0
  261. package/Tests/Server/Services/TeamComplianceSettingService.test.ts +3988 -138
  262. package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +107 -1
  263. package/Tests/Server/Utils/AI/IncidentPostmortemRunner.test.ts +351 -0
  264. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +2 -0
  265. package/Tests/Server/Utils/AI/InvestigationEligibility.test.ts +310 -0
  266. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +70 -0
  267. package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +58 -0
  268. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +2 -0
  269. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +2 -0
  270. package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +2 -0
  271. package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +125 -1
  272. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +252 -3
  273. package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +2 -0
  274. package/Tests/Server/Utils/AI/RemediationExecutionRunnerProjectGates.test.ts +240 -0
  275. package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +2 -0
  276. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +2 -0
  277. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +2 -0
  278. package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +2 -0
  279. package/Tests/Server/Utils/Telemetry/HostAssetAttributesFromOtlp.test.ts +68 -0
  280. package/Tests/Server/Utils/Telemetry/InventoryMirrorPostgres.test.ts +370 -0
  281. package/Tests/Server/Utils/Telemetry/NetworkDeviceInventoryAttributes.test.ts +522 -0
  282. package/Tests/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.test.ts +155 -0
  283. package/Tests/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.test.ts +8631 -0
  284. package/Tests/Server/Utils/Telemetry/ProxmoxNativePush.test.ts +2852 -0
  285. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +367 -1
  286. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +45 -3
  287. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +25 -0
  288. package/Tests/Server/Utils/Workspace/MicrosoftTeamsGroupChatNames.test.ts +3119 -0
  289. package/Tests/Server/Utils/Workspace/MicrosoftTeamsGroupChatNamesPostgres.test.ts +1721 -0
  290. package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +581 -113
  291. package/Tests/Types/Kubernetes/KubernetesAiAgentAccessContract.test.ts +510 -0
  292. package/Tests/Types/Team/ComplianceRule.test.ts +1029 -0
  293. package/Tests/Types/Team/TeamComplianceStatus.test.ts +176 -0
  294. package/Tests/UI/Components/ActionButton/RowActions.test.tsx +641 -0
  295. package/Tests/UI/Components/ActionButton/RowActionsAccessibility.test.tsx +414 -0
  296. package/Tests/UI/Components/ActionButton/SplitActionButtons.test.ts +565 -0
  297. package/Tests/UI/Components/Charts/BarChartDragToSelect.test.tsx +386 -0
  298. package/Tests/UI/Components/Charts/ChartDoubleClickResetWithoutDblclick.test.tsx +1025 -0
  299. package/Tests/UI/Components/Charts/ChartGroupPageZoomHint.test.tsx +196 -0
  300. package/Tests/UI/Components/Charts/ChartPlaceholdersTakeDoubleClick.test.tsx +1861 -0
  301. package/Tests/UI/Components/Charts/ChartPlotClicksWhileResetArmed.test.tsx +382 -0
  302. package/Tests/UI/Components/Charts/ChartRangeSelection.test.tsx +704 -0
  303. package/Tests/UI/Components/Charts/ChartRangeSelectionDoubleClickReset.test.tsx +1481 -0
  304. package/Tests/UI/Components/Charts/ChartRangeSelectionRealRecharts.test.tsx +918 -0
  305. package/Tests/UI/Components/Charts/ChartRowBucketStart.test.ts +350 -0
  306. package/Tests/UI/Components/Charts/DoubleClickReset.test.tsx +996 -0
  307. package/Tests/UI/Components/Charts/HistogramDoubleClickResetRealRecharts.test.tsx +965 -0
  308. package/Tests/UI/Components/Charts/HistogramDriftThenRefetch.test.tsx +277 -0
  309. package/Tests/UI/Components/Charts/HistogramRangeSelectionDataChange.test.tsx +1757 -0
  310. package/Tests/UI/Components/Charts/HistogramRangeSelectionRealRecharts.test.tsx +560 -0
  311. package/Tests/UI/Components/Charts/TimeRangeZoom/ChartPageTimeRangeZoom.test.tsx +513 -0
  312. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.test.tsx +845 -0
  313. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.test.tsx +119 -0
  314. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHintTailwind.test.tsx +274 -0
  315. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.test.ts +433 -0
  316. package/Tests/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.test.tsx +863 -0
  317. package/Tests/UI/Components/Charts/TimeRangeZoom/ZoomDocsPromises.test.tsx +1147 -0
  318. package/Tests/UI/Components/DisabledButtonTooltip.test.tsx +14 -3
  319. package/Tests/UI/Components/EntityDropdownEscape.test.tsx +454 -0
  320. package/Tests/UI/Components/EntityDropdownFocusLeave.test.tsx +420 -0
  321. package/Tests/UI/Components/Forms/FormFieldDropdownDisabled.test.tsx +233 -0
  322. package/Tests/UI/Components/Input.test.tsx +80 -1
  323. package/Tests/UI/Components/LogsAnalyticsViewZoom.test.tsx +947 -0
  324. package/Tests/UI/Components/LogsHistogramDragTooltip.test.tsx +17 -5
  325. package/Tests/UI/Components/LogsViewerAnalyticsZoom.test.tsx +501 -0
  326. package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +1 -1
  327. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +6 -4
  328. package/Tests/UI/Components/ModelTable/BaseModelTablePermissionGating.test.tsx +60 -8
  329. package/Tests/UI/Components/ModelTable/BaseModelTableRowActions.test.tsx +476 -0
  330. package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +7 -5
  331. package/Tests/UI/Components/MoreMenuPortal.test.tsx +623 -0
  332. package/Tests/UI/Components/StatusPage/ResourceGridActions.test.tsx +538 -0
  333. package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +14 -4
  334. package/Tests/UI/Components/TableCellWrapping.test.tsx +3 -3
  335. package/Tests/UI/Components/TableRowActions.test.tsx +472 -0
  336. package/Tests/UI/Components/TelemetryHistogramDragTooltip.test.tsx +1 -1
  337. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +1 -1
  338. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerZoomScope.test.tsx +470 -0
  339. package/Tests/UI/Components/TelemetryViewer/UseViewerTimeRangeZoom.test.tsx +571 -0
  340. package/Tests/UI/Components/TelemetryViewer/ViewerDoubleClickResetUnderDataChange.test.tsx +928 -0
  341. package/Tests/UI/Components/TelemetryViewer/ViewerFollowsEnclosingZoom.test.tsx +1569 -0
  342. package/Tests/UI/Components/Toggle.test.tsx +66 -0
  343. package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardRefreshNames.test.tsx +1023 -0
  344. package/Tests/UI/Rum/ChunkLoader.test.ts +201 -0
  345. package/Tests/UI/Rum/FidelityNotices.test.ts +54 -0
  346. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +72 -0
  347. package/Tests/UI/Rum/ReplayFrameCapture.test.ts +1009 -9
  348. package/Tests/UI/Rum/ReplayRecordedAssets.test.ts +1069 -0
  349. package/Tests/UI/Rum/ReplayStage.test.tsx +913 -2
  350. package/Tests/UI/Rum/SessionReplayTable.test.tsx +443 -8
  351. package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +439 -9
  352. package/Tests/UI/Rum/UserFlowTablesRowActions.test.tsx +501 -0
  353. package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +47 -19
  354. package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +2 -0
  355. package/Tests/Utils/AiRemediation/KubernetesAiAgentPolicyCopyParity.test.ts +396 -0
  356. package/Tests/Utils/Dashboard/DashboardTimeRangeZoom.test.ts +104 -1
  357. package/Types/AI/AIRunType.ts +9 -4
  358. package/Types/AI/InvestigationNotStartedReason.ts +6 -0
  359. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +14 -16
  360. package/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.ts +28 -0
  361. package/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.ts +4 -2
  362. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +263 -32
  363. package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +20 -16
  364. package/Types/Kubernetes/KubernetesClusterAiInsights.ts +81 -0
  365. package/Types/Monitor/ProxmoxAlertTemplates.ts +4 -4
  366. package/Types/Team/ComplianceNotificationChannel.ts +22 -0
  367. package/Types/Team/ComplianceRule.ts +434 -0
  368. package/Types/Team/ComplianceRuleType.ts +21 -0
  369. package/Types/Team/TeamComplianceStatus.ts +81 -0
  370. package/Types/Telemetry/TelemetryIngestSurface.ts +28 -0
  371. package/UI/Components/ActionButton/ActionButtonSchema.ts +21 -0
  372. package/UI/Components/ActionButton/RowActions.tsx +238 -0
  373. package/UI/Components/ActionButton/SplitActionButtons.ts +173 -0
  374. package/UI/Components/Charts/Area/AreaChart.tsx +32 -2
  375. package/UI/Components/Charts/Bar/BarChart.tsx +40 -3
  376. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +37 -11
  377. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +80 -243
  378. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +122 -31
  379. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +95 -244
  380. package/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.ts +214 -0
  381. package/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.ts +32 -0
  382. package/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.ts +599 -0
  383. package/UI/Components/Charts/Line/LineChart.tsx +32 -2
  384. package/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.tsx +70 -0
  385. package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.tsx +226 -0
  386. package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.tsx +73 -0
  387. package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.ts +163 -0
  388. package/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.ts +215 -0
  389. package/UI/Components/Charts/Utils/DataPoint.ts +20 -8
  390. package/UI/Components/Charts/Utils/XAxis.ts +75 -0
  391. package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +493 -59
  392. package/UI/Components/EntityDropdown/EntityDropdown.tsx +107 -11
  393. package/UI/Components/Forms/Fields/FormField.tsx +10 -0
  394. package/UI/Components/Input/Input.tsx +90 -57
  395. package/UI/Components/List/ListRow.tsx +8 -74
  396. package/UI/Components/LogsViewer/LogsViewer.tsx +40 -11
  397. package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +22 -6
  398. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +209 -6
  399. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +127 -84
  400. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +3 -0
  401. package/UI/Components/ModelTable/BaseModelTable.tsx +12 -1
  402. package/UI/Components/MoreMenu/MoreMenu.tsx +365 -30
  403. package/UI/Components/MoreMenu/MoreMenuItem.tsx +70 -17
  404. package/UI/Components/OrderedStatesList/Item.tsx +7 -72
  405. package/UI/Components/StatusPage/ResourceGrid.tsx +126 -77
  406. package/UI/Components/Table/TableBody.tsx +8 -2
  407. package/UI/Components/Table/TableRow.tsx +20 -140
  408. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +41 -10
  409. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +47 -9
  410. package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +25 -6
  411. package/UI/Components/TelemetryViewer/types.ts +2 -0
  412. package/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.ts +448 -0
  413. package/UI/Components/Toggle/Toggle.tsx +26 -0
  414. package/UI/Components/Tooltip/Tooltip.tsx +8 -1
  415. package/UI/Styles/Theme.css +14 -2
  416. package/Utils/AiRemediation/CommandPolicy.ts +1 -1
  417. package/Utils/AiRemediation/KubectlPolicy.ts +1 -1
  418. package/Utils/Dashboard/DashboardTimeRangeZoom.ts +46 -2
  419. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  420. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  421. package/build/dist/Models/DatabaseModels/KubernetesAiAgent.js +385 -0
  422. package/build/dist/Models/DatabaseModels/KubernetesAiAgent.js.map +1 -0
  423. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +3 -3
  424. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  425. package/build/dist/Models/DatabaseModels/Project.js +56 -5
  426. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  427. package/build/dist/Models/DatabaseModels/ProxmoxResource.js +51 -1
  428. package/build/dist/Models/DatabaseModels/ProxmoxResource.js.map +1 -1
  429. package/build/dist/Models/DatabaseModels/RunnerJob.js +74 -0
  430. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  431. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +134 -3
  432. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
  433. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  434. package/build/dist/Server/API/AIChatAPI.js +6 -1
  435. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  436. package/build/dist/Server/API/AIInvestigationAPI.js +17 -10
  437. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  438. package/build/dist/Server/API/AutoRemediationAPI.js +144 -24
  439. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  440. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +436 -22
  441. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -1
  442. package/build/dist/Server/API/MicrosoftTeamsAPI.js +69 -13
  443. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  444. package/build/dist/Server/API/ProxmoxResourceAPI.js +187 -14
  445. package/build/dist/Server/API/ProxmoxResourceAPI.js.map +1 -1
  446. package/build/dist/Server/Infrastructure/GlobalCache.js +27 -0
  447. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  448. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.js +50 -0
  449. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.js.map +1 -0
  450. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.js +84 -0
  451. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.js.map +1 -0
  452. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.js +31 -0
  453. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.js.map +1 -0
  454. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  455. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  456. package/build/dist/Server/Middleware/TelemetryIngest.js +34 -19
  457. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  458. package/build/dist/Server/Services/AIService.js +59 -1
  459. package/build/dist/Server/Services/AIService.js.map +1 -1
  460. package/build/dist/Server/Services/AlertService.js +248 -13
  461. package/build/dist/Server/Services/AlertService.js.map +1 -1
  462. package/build/dist/Server/Services/AlertSeverityService.js +51 -15
  463. package/build/dist/Server/Services/AlertSeverityService.js.map +1 -1
  464. package/build/dist/Server/Services/AutoRemediationRuleService.js +1 -1
  465. package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
  466. package/build/dist/Server/Services/IncidentService.js +199 -72
  467. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  468. package/build/dist/Server/Services/IncidentSeverityService.js +51 -15
  469. package/build/dist/Server/Services/IncidentSeverityService.js.map +1 -1
  470. package/build/dist/Server/Services/KubernetesAiAgentJobService.js +158 -0
  471. package/build/dist/Server/Services/KubernetesAiAgentJobService.js.map +1 -0
  472. package/build/dist/Server/Services/KubernetesAiAgentService.js +1145 -0
  473. package/build/dist/Server/Services/KubernetesAiAgentService.js.map +1 -0
  474. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +842 -371
  475. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -1
  476. package/build/dist/Server/Services/KubernetesClusterService.js +86 -17
  477. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  478. package/build/dist/Server/Services/ProjectService.js +22 -0
  479. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  480. package/build/dist/Server/Services/ProxmoxResourceService.js +258 -3
  481. package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -1
  482. package/build/dist/Server/Services/RunnerJobService.js +178 -92
  483. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  484. package/build/dist/Server/Services/RunnerService.js +1 -1
  485. package/build/dist/Server/Services/RunnerService.js.map +1 -1
  486. package/build/dist/Server/Services/ScheduledMaintenanceService.js +535 -3
  487. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  488. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +316 -46
  489. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  490. package/build/dist/Server/Services/TeamComplianceSettingService.js +833 -7
  491. package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
  492. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +52 -9
  493. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -1
  494. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +13 -9
  495. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
  496. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +7 -3
  497. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
  498. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +29 -15
  499. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  500. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +56 -20
  501. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  502. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +39 -5
  503. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  504. package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js +30 -3
  505. package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js.map +1 -1
  506. package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js +13 -2
  507. package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js.map +1 -1
  508. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +1 -1
  509. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +4 -2
  510. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  511. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +111 -6
  512. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
  513. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +40 -4
  514. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -1
  515. package/build/dist/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.js +296 -0
  516. package/build/dist/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.js.map +1 -0
  517. package/build/dist/Server/Utils/Telemetry/ProxmoxNativePush.js +699 -0
  518. package/build/dist/Server/Utils/Telemetry/ProxmoxNativePush.js.map +1 -0
  519. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +77 -19
  520. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  521. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +505 -42
  522. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  523. package/build/dist/Types/AI/AIRunType.js +9 -4
  524. package/build/dist/Types/AI/AIRunType.js.map +1 -1
  525. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +10 -16
  526. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  527. package/build/dist/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.js +28 -0
  528. package/build/dist/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.js.map +1 -0
  529. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +72 -16
  530. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
  531. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +20 -16
  532. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -1
  533. package/build/dist/Types/Kubernetes/KubernetesClusterAiInsights.js +17 -0
  534. package/build/dist/Types/Kubernetes/KubernetesClusterAiInsights.js.map +1 -0
  535. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +4 -4
  536. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
  537. package/build/dist/Types/Team/ComplianceNotificationChannel.js +23 -0
  538. package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -0
  539. package/build/dist/Types/Team/ComplianceRule.js +304 -0
  540. package/build/dist/Types/Team/ComplianceRule.js.map +1 -0
  541. package/build/dist/Types/Team/ComplianceRuleType.js +21 -0
  542. package/build/dist/Types/Team/ComplianceRuleType.js.map +1 -1
  543. package/build/dist/Types/Team/TeamComplianceStatus.js +2 -0
  544. package/build/dist/Types/Team/TeamComplianceStatus.js.map +1 -0
  545. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +25 -0
  546. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  547. package/build/dist/UI/Components/ActionButton/ActionButtonSchema.js +20 -1
  548. package/build/dist/UI/Components/ActionButton/ActionButtonSchema.js.map +1 -1
  549. package/build/dist/UI/Components/ActionButton/RowActions.js +113 -0
  550. package/build/dist/UI/Components/ActionButton/RowActions.js.map +1 -0
  551. package/build/dist/UI/Components/ActionButton/SplitActionButtons.js +71 -0
  552. package/build/dist/UI/Components/ActionButton/SplitActionButtons.js.map +1 -0
  553. package/build/dist/UI/Components/Charts/Area/AreaChart.js +16 -1
  554. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  555. package/build/dist/UI/Components/Charts/Bar/BarChart.js +16 -1
  556. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  557. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +27 -5
  558. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  559. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +61 -194
  560. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  561. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +84 -26
  562. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  563. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +75 -196
  564. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  565. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js +133 -0
  566. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js.map +1 -1
  567. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.js +26 -0
  568. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.js.map +1 -0
  569. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.js +371 -0
  570. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.js.map +1 -0
  571. package/build/dist/UI/Components/Charts/Line/LineChart.js +16 -1
  572. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  573. package/build/dist/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.js +35 -0
  574. package/build/dist/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.js.map +1 -0
  575. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.js +107 -0
  576. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.js.map +1 -0
  577. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.js +41 -0
  578. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.js.map +1 -0
  579. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.js +117 -0
  580. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.js.map +1 -0
  581. package/build/dist/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.js +121 -0
  582. package/build/dist/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.js.map +1 -0
  583. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -7
  584. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  585. package/build/dist/UI/Components/Charts/Utils/XAxis.js +70 -0
  586. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  587. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +305 -38
  588. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -1
  589. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +89 -14
  590. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  591. package/build/dist/UI/Components/Forms/Fields/FormField.js +11 -2
  592. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  593. package/build/dist/UI/Components/Input/Input.js +69 -54
  594. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  595. package/build/dist/UI/Components/List/ListRow.js +4 -39
  596. package/build/dist/UI/Components/List/ListRow.js.map +1 -1
  597. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +31 -8
  598. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  599. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +10 -1
  600. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
  601. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +139 -21
  602. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  603. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +30 -8
  604. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  605. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
  606. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  607. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +10 -0
  608. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  609. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +253 -14
  610. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  611. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +43 -13
  612. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  613. package/build/dist/UI/Components/OrderedStatesList/Item.js +2 -38
  614. package/build/dist/UI/Components/OrderedStatesList/Item.js.map +1 -1
  615. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +53 -15
  616. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
  617. package/build/dist/UI/Components/Table/TableBody.js +6 -2
  618. package/build/dist/UI/Components/Table/TableBody.js.map +1 -1
  619. package/build/dist/UI/Components/Table/TableRow.js +12 -75
  620. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  621. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +32 -7
  622. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  623. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +27 -9
  624. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  625. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +11 -1
  626. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
  627. package/build/dist/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.js +272 -0
  628. package/build/dist/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.js.map +1 -0
  629. package/build/dist/UI/Components/Toggle/Toggle.js +14 -1
  630. package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
  631. package/build/dist/UI/Components/Tooltip/Tooltip.js +1 -1
  632. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  633. package/build/dist/Utils/AiRemediation/CommandPolicy.js +1 -1
  634. package/build/dist/Utils/AiRemediation/CommandPolicy.js.map +1 -1
  635. package/build/dist/Utils/AiRemediation/KubectlPolicy.js +1 -1
  636. package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -1
  637. package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js +27 -1
  638. package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js.map +1 -1
  639. package/package.json +1 -1
@@ -0,0 +1,948 @@
1
+ /** @timezone UTC */
2
+
3
+ import "@testing-library/jest-dom";
4
+ import {
5
+ afterEach,
6
+ beforeEach,
7
+ describe,
8
+ expect,
9
+ jest,
10
+ test,
11
+ } from "@jest/globals";
12
+ import {
13
+ act,
14
+ cleanup,
15
+ fireEvent,
16
+ render,
17
+ screen,
18
+ waitFor,
19
+ within,
20
+ } from "@testing-library/react";
21
+ import * as React from "react";
22
+ import { MemoryRouter } from "react-router-dom";
23
+ import getJestMockFunction, { MockFunction } from "../../MockType";
24
+
25
+ /*
26
+ * Issue #4105 on Logs > Insights. The page owns one time range; every panel
27
+ * on it (stat cards, severity split, top errors, sources) and the error
28
+ * drawer are fetched for it. The drawer's "When it happened" timeline is the
29
+ * page's time chart: a drag across it retimes the WHOLE page, the drawer
30
+ * stays open and follows, the picker reads Custom and offers Reset zoom, and
31
+ * a double-click (or Reset zoom) puts the page back. A range picked from the
32
+ * picker is still a new starting point that closes the drawer.
33
+ *
34
+ * The page's data layer (LogsInsightsApi) is mocked so every request's
35
+ * scope can be read back; recharts is stood in for with a chart that lays
36
+ * each bucket out as a div (see LogsHistogramDragTooltip.test.tsx).
37
+ */
38
+
39
+ const histogramMock: MockFunction = getJestMockFunction();
40
+ const patternsMock: MockFunction = getJestMockFunction();
41
+ const breakdownMock: MockFunction = getJestMockFunction();
42
+ const facetsMock: MockFunction = getJestMockFunction();
43
+ const correlationMock: MockFunction = getJestMockFunction();
44
+
45
+ jest.mock(
46
+ "../../../../App/FeatureSet/Dashboard/src/Components/Logs/LogsInsightsApi",
47
+ () => {
48
+ return {
49
+ __esModule: true,
50
+ fetchInsightsHistogram: (...args: Array<any>) => {
51
+ return histogramMock(...args);
52
+ },
53
+ fetchTopErrorPatterns: (...args: Array<any>) => {
54
+ return patternsMock(...args);
55
+ },
56
+ fetchResourceBreakdown: (...args: Array<any>) => {
57
+ return breakdownMock(...args);
58
+ },
59
+ fetchScopeFacets: (...args: Array<any>) => {
60
+ return facetsMock(...args);
61
+ },
62
+ fetchErrorPatternCorrelation: (...args: Array<any>) => {
63
+ return correlationMock(...args);
64
+ },
65
+ };
66
+ },
67
+ );
68
+
69
+ jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
70
+ return {
71
+ __esModule: true,
72
+ default: {
73
+ getList: async () => {
74
+ return { data: [], count: 0 };
75
+ },
76
+ getItem: async () => {
77
+ return null;
78
+ },
79
+ getCommonHeaders: () => {
80
+ return {};
81
+ },
82
+ },
83
+ };
84
+ });
85
+
86
+ jest.mock("../../../UI/Utils/Project", () => {
87
+ return {
88
+ __esModule: true,
89
+ default: {
90
+ getCurrentProjectId: () => {
91
+ const ObjectIDModule: { default: new (id: string) => unknown } =
92
+ jest.requireActual("../../../Types/ObjectID") as {
93
+ default: new (id: string) => unknown;
94
+ };
95
+ return new ObjectIDModule.default(
96
+ "11111111-1111-4111-8111-111111111111",
97
+ );
98
+ },
99
+ },
100
+ };
101
+ });
102
+
103
+ jest.mock("../../../UI/Utils/Telemetry/UseTelemetryEntityNames", () => {
104
+ return {
105
+ __esModule: true,
106
+ default: () => {
107
+ return new Map();
108
+ },
109
+ };
110
+ });
111
+
112
+ jest.mock(
113
+ "../../../../App/FeatureSet/Dashboard/src/Components/Metrics/Utils/UseEventTimeReferenceLines",
114
+ () => {
115
+ return {
116
+ __esModule: true,
117
+ default: () => {
118
+ return { lines: [], markerCount: 0 };
119
+ },
120
+ };
121
+ },
122
+ );
123
+
124
+ jest.mock("recharts", () => {
125
+ const react: typeof React = jest.requireActual("react") as typeof React;
126
+
127
+ interface StubRow {
128
+ time: string;
129
+ }
130
+
131
+ interface StubChartProps {
132
+ data: Array<StubRow>;
133
+ children?: React.ReactNode;
134
+ onMouseDown?: (state: { activeLabel: string }) => void;
135
+ onMouseMove?: (state: { activeLabel: string }) => void;
136
+ onMouseUp?: (state: { activeLabel: string }) => void;
137
+ }
138
+
139
+ const nothing: () => null = (): null => {
140
+ return null;
141
+ };
142
+
143
+ return {
144
+ __esModule: true,
145
+ ResponsiveContainer: (props: { children: React.ReactNode }) => {
146
+ return react.createElement("div", null, props.children);
147
+ },
148
+ BarChart: (props: StubChartProps) => {
149
+ return react.createElement(
150
+ "div",
151
+ { "data-testid": "timeline-bars" },
152
+ props.data.map((row: StubRow) => {
153
+ return react.createElement("div", {
154
+ key: row.time,
155
+ "data-testid": `bar-${row.time}`,
156
+ onMouseDown: () => {
157
+ props.onMouseDown?.({ activeLabel: row.time });
158
+ },
159
+ onMouseMove: () => {
160
+ props.onMouseMove?.({ activeLabel: row.time });
161
+ },
162
+ onMouseUp: () => {
163
+ props.onMouseUp?.({ activeLabel: row.time });
164
+ },
165
+ });
166
+ }),
167
+ props.children,
168
+ );
169
+ },
170
+ Bar: nothing,
171
+ XAxis: nothing,
172
+ YAxis: nothing,
173
+ Tooltip: nothing,
174
+ ReferenceArea: nothing,
175
+ };
176
+ });
177
+
178
+ import LogsDashboard from "../../../../App/FeatureSet/Dashboard/src/Components/Logs/LogsDashboard";
179
+ import { ERROR_PATTERN_TIMELINE_TEST_ID } from "../../../../App/FeatureSet/Dashboard/src/Components/Logs/ErrorPatternDetail";
180
+ import {
181
+ LogsInsightsScope,
182
+ TopErrorPatternRow,
183
+ } from "../../../../App/FeatureSet/Dashboard/src/Utils/LogsInsights";
184
+ import { RESET_TIME_RANGE_ZOOM_BUTTON_TEST_ID } from "../../../UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton";
185
+ import { TIME_RANGE_ZOOM_HINT_TEST_ID } from "../../../UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint";
186
+ import { getTimeRangeButtonLabel } from "../../../UI/Components/Date/TimeRangePickerDropdown";
187
+ import InBetween from "../../../Types/BaseDatabase/InBetween";
188
+ import OneUptimeDate from "../../../Types/Date";
189
+ import TimeRange from "../../../Types/Time/TimeRange";
190
+
191
+ const NOW: Date = new Date("2026-09-28T12:00:00.000Z");
192
+ const PATTERN_TEXT: string = "connection refused to <ip>";
193
+
194
+ // The count the list reports, per window: a zoomed window counts fewer.
195
+ function patternRow(count: number, firstSeen: string): TopErrorPatternRow {
196
+ return {
197
+ pattern: PATTERN_TEXT,
198
+ sampleBody: "connection refused to 10.0.0.5",
199
+ count: count,
200
+ firstSeenAt: new Date(firstSeen),
201
+ lastSeenAt: new Date("2026-09-28T11:11:30.000Z"),
202
+ resourceCount: 1,
203
+ resourceIds: [],
204
+ severities: ["Error"],
205
+ traceCount: 0,
206
+ sampleTraceIds: [],
207
+ };
208
+ }
209
+
210
+ function isCustom(scope: LogsInsightsScope): boolean {
211
+ return scope.timeRange.range === TimeRange.CUSTOM;
212
+ }
213
+
214
+ function windowOf(scope: LogsInsightsScope): string {
215
+ if (!isCustom(scope)) {
216
+ return scope.timeRange.range;
217
+ }
218
+ return `${scope.timeRange.startAndEndDate!.startValue.toISOString()}..${scope.timeRange.startAndEndDate!.endValue.toISOString()}`;
219
+ }
220
+
221
+ function lastScope(mock: MockFunction): string {
222
+ const calls: Array<Array<unknown>> = mock.mock.calls;
223
+ expect(calls.length).toBeGreaterThan(0);
224
+ return windowOf(calls[calls.length - 1]![0] as LogsInsightsScope);
225
+ }
226
+
227
+ const ZOOMED: string = "2026-09-28T11:10:00.000Z..2026-09-28T11:12:00.000Z";
228
+
229
+ function pickerLabel(): string {
230
+ return (
231
+ screen.getByTestId("telemetry-time-range-picker-button").textContent || ""
232
+ ).trim();
233
+ }
234
+
235
+ function drawer(): HTMLElement | null {
236
+ return screen.queryByRole("dialog");
237
+ }
238
+
239
+ // The page's Reset zoom: the one beside the header picker, outside the drawer.
240
+ function pageResetButton(): HTMLElement | null {
241
+ const panel: HTMLElement | null = drawer();
242
+
243
+ return (
244
+ screen
245
+ .queryAllByRole("button", { name: "Reset zoom" })
246
+ .find((button: HTMLElement): boolean => {
247
+ return !panel || !panel.contains(button);
248
+ }) || null
249
+ );
250
+ }
251
+
252
+ // The drawer's own Reset zoom, above its timeline.
253
+ function drawerResetButton(): HTMLElement | null {
254
+ const panel: HTMLElement | null = drawer();
255
+
256
+ return panel
257
+ ? within(panel).queryByRole("button", { name: "Reset zoom" })
258
+ : null;
259
+ }
260
+
261
+ async function renderPage(): Promise<void> {
262
+ await act(async () => {
263
+ render(
264
+ <MemoryRouter>
265
+ <LogsDashboard />
266
+ </MemoryRouter>,
267
+ );
268
+ });
269
+
270
+ await waitFor(() => {
271
+ expect(
272
+ screen.getByText("connection refused to 10.0.0.5", {
273
+ selector: "p, span, div",
274
+ }),
275
+ ).toBeInTheDocument();
276
+ });
277
+ }
278
+
279
+ async function openDrawer(): Promise<void> {
280
+ fireEvent.click(
281
+ screen
282
+ .getAllByText("connection refused to 10.0.0.5")[0]!
283
+ .closest("button")!,
284
+ );
285
+
286
+ await waitFor(() => {
287
+ expect(
288
+ screen.getByTestId(ERROR_PATTERN_TIMELINE_TEST_ID),
289
+ ).toBeInTheDocument();
290
+ });
291
+ }
292
+
293
+ function dragTimeline(fromIso: string, toIso: string): void {
294
+ fireEvent.mouseDown(screen.getByTestId(`bar-${fromIso}`));
295
+ fireEvent.mouseMove(screen.getByTestId(`bar-${toIso}`));
296
+ fireEvent.mouseUp(screen.getByTestId(`bar-${toIso}`));
297
+ }
298
+
299
+ async function waitForPageOn(window: string): Promise<void> {
300
+ for (const mock of [histogramMock, patternsMock, breakdownMock, facetsMock]) {
301
+ await waitFor(() => {
302
+ expect(lastScope(mock)).toBe(window);
303
+ });
304
+ }
305
+ }
306
+
307
+ beforeEach(() => {
308
+ jest.useFakeTimers();
309
+ jest.setSystemTime(NOW);
310
+ window.history.replaceState({}, "", "/");
311
+
312
+ for (const mock of [
313
+ histogramMock,
314
+ patternsMock,
315
+ breakdownMock,
316
+ facetsMock,
317
+ correlationMock,
318
+ ]) {
319
+ mock.mockReset();
320
+ }
321
+
322
+ histogramMock.mockImplementation(async () => {
323
+ return [
324
+ { time: "2026-09-28 11:10:00", severity: "Error", count: 8 },
325
+ { time: "2026-09-28 11:10:00", severity: "Information", count: 40 },
326
+ ];
327
+ });
328
+ patternsMock.mockImplementation(async (scope: LogsInsightsScope) => {
329
+ return isCustom(scope)
330
+ ? [patternRow(8, "2026-09-28T11:10:05.000Z")]
331
+ : [patternRow(42, "2026-09-28T11:00:05.000Z")];
332
+ });
333
+ breakdownMock.mockImplementation(async () => {
334
+ return [];
335
+ });
336
+ facetsMock.mockImplementation(async () => {
337
+ return {};
338
+ });
339
+ correlationMock.mockImplementation(async () => {
340
+ return {
341
+ pattern: PATTERN_TEXT,
342
+ bucketSizeInMinutes: 1,
343
+ timeline: [
344
+ { time: new Date("2026-09-28T11:10:00.000Z"), count: 3 },
345
+ { time: new Date("2026-09-28T11:11:00.000Z"), count: 5 },
346
+ ],
347
+ coOccurringPatterns: [],
348
+ attributes: [],
349
+ resources: [],
350
+ traces: [],
351
+ samples: [],
352
+ };
353
+ });
354
+ });
355
+
356
+ afterEach(() => {
357
+ cleanup();
358
+ jest.useRealTimers();
359
+ window.history.replaceState({}, "", "/");
360
+ });
361
+
362
+ describe("the error drawer's timeline zooms the Insights page", () => {
363
+ test("the timeline draws every minute of the window, quiet ones included", async () => {
364
+ await renderPage();
365
+ await openDrawer();
366
+
367
+ expect(
368
+ screen.getByTestId("bar-2026-09-28T11:10:00.000Z"),
369
+ ).toBeInTheDocument();
370
+ expect(
371
+ screen.getByTestId("bar-2026-09-28T11:00:00.000Z"),
372
+ ).toBeInTheDocument();
373
+ expect(
374
+ screen.getByTestId("bar-2026-09-28T11:59:00.000Z"),
375
+ ).toBeInTheDocument();
376
+ expect(screen.getByTestId(TIME_RANGE_ZOOM_HINT_TEST_ID)).toHaveTextContent(
377
+ "Drag to zoom",
378
+ );
379
+ });
380
+
381
+ test("a drag re-fetches every panel on the page for the dragged window, and the drawer follows", async () => {
382
+ await renderPage();
383
+ await openDrawer();
384
+
385
+ expect(lastScope(histogramMock)).toBe(TimeRange.PAST_ONE_HOUR);
386
+ expect(lastScope(correlationMock)).toBe(TimeRange.PAST_ONE_HOUR);
387
+
388
+ dragTimeline("2026-09-28T11:10:00.000Z", "2026-09-28T11:11:00.000Z");
389
+
390
+ await waitForPageOn(ZOOMED);
391
+ await waitFor(() => {
392
+ expect(lastScope(correlationMock)).toBe(ZOOMED);
393
+ });
394
+
395
+ /*
396
+ * The drawer stayed open through the page's reload - and stayed
397
+ * MOUNTED: one correlation for the opening, one for the zoom. A drawer
398
+ * unmounted by the loading state and mounted again would have asked a
399
+ * third time.
400
+ */
401
+ expect(drawer()).not.toBeNull();
402
+ act(() => {
403
+ jest.advanceTimersByTime(1000);
404
+ });
405
+ expect(correlationMock).toHaveBeenCalledTimes(2);
406
+ expect(pickerLabel()).toBe(
407
+ getTimeRangeButtonLabel({
408
+ range: TimeRange.CUSTOM,
409
+ startAndEndDate: new InBetween<Date>(
410
+ new Date("2026-09-28T11:10:00.000Z"),
411
+ new Date("2026-09-28T11:12:00.000Z"),
412
+ ),
413
+ }),
414
+ );
415
+ expect(pageResetButton()).not.toBeNull();
416
+ });
417
+
418
+ test("the zoomed drawer takes its row from the reloaded list and counts its own window", async () => {
419
+ await renderPage();
420
+ await openDrawer();
421
+
422
+ dragTimeline("2026-09-28T11:10:00.000Z", "2026-09-28T11:11:00.000Z");
423
+ await waitFor(() => {
424
+ expect(lastScope(correlationMock)).toBe(ZOOMED);
425
+ });
426
+
427
+ // 3 + 5 in the correlation fetched for the zoomed window.
428
+ await waitFor(() => {
429
+ expect(
430
+ within(drawer()!).getByText(/^8 times in the selected time range/),
431
+ ).toBeInTheDocument();
432
+ });
433
+
434
+ // First seen as the zoomed window's list reports it.
435
+ expect(drawer()!).toHaveTextContent(
436
+ `First seen ${OneUptimeDate.getDateAsLocalFormattedString(
437
+ new Date("2026-09-28T11:10:05.000Z"),
438
+ )}`,
439
+ );
440
+ });
441
+
442
+ test("a double-click on the timeline puts the page back, drawer still open", async () => {
443
+ await renderPage();
444
+ await openDrawer();
445
+
446
+ dragTimeline("2026-09-28T11:10:00.000Z", "2026-09-28T11:11:00.000Z");
447
+ await waitForPageOn(ZOOMED);
448
+ await waitFor(() => {
449
+ expect(
450
+ screen.getByTestId(ERROR_PATTERN_TIMELINE_TEST_ID),
451
+ ).toBeInTheDocument();
452
+ });
453
+ expect(screen.getByTestId(TIME_RANGE_ZOOM_HINT_TEST_ID)).toHaveTextContent(
454
+ "Double-click to reset",
455
+ );
456
+
457
+ fireEvent.doubleClick(screen.getByTestId(ERROR_PATTERN_TIMELINE_TEST_ID));
458
+
459
+ await waitForPageOn(TimeRange.PAST_ONE_HOUR);
460
+ await waitFor(() => {
461
+ expect(lastScope(correlationMock)).toBe(TimeRange.PAST_ONE_HOUR);
462
+ });
463
+ expect(drawer()).not.toBeNull();
464
+ expect(pickerLabel()).toBe("Past 1 Hour");
465
+ expect(
466
+ screen.queryByTestId(RESET_TIME_RANGE_ZOOM_BUTTON_TEST_ID),
467
+ ).toBeNull();
468
+ });
469
+
470
+ test("Reset zoom beside the picker puts the page back too", async () => {
471
+ await renderPage();
472
+ await openDrawer();
473
+
474
+ dragTimeline("2026-09-28T11:10:00.000Z", "2026-09-28T11:11:00.000Z");
475
+ await waitForPageOn(ZOOMED);
476
+
477
+ fireEvent.click(pageResetButton()!);
478
+
479
+ await waitForPageOn(TimeRange.PAST_ONE_HOUR);
480
+ expect(pickerLabel()).toBe("Past 1 Hour");
481
+ expect(drawer()).not.toBeNull();
482
+ });
483
+
484
+ test("a range picked from the picker is a new starting point: the zoom ends and the drawer closes", async () => {
485
+ await renderPage();
486
+ await openDrawer();
487
+
488
+ dragTimeline("2026-09-28T11:10:00.000Z", "2026-09-28T11:11:00.000Z");
489
+ await waitForPageOn(ZOOMED);
490
+
491
+ fireEvent.click(screen.getByTestId("telemetry-time-range-picker-button"));
492
+ fireEvent.click(
493
+ within(
494
+ screen.getByTestId("telemetry-time-range-picker-dropdown"),
495
+ ).getByText("Past 1 Day"),
496
+ );
497
+
498
+ await waitForPageOn(TimeRange.PAST_ONE_DAY);
499
+ await waitFor(() => {
500
+ expect(drawer()).toBeNull();
501
+ });
502
+ expect(
503
+ screen.queryByTestId(RESET_TIME_RANGE_ZOOM_BUTTON_TEST_ID),
504
+ ).toBeNull();
505
+ });
506
+
507
+ test("a drag across two bars zooms the page to exactly those two buckets, right to left too", async () => {
508
+ await renderPage();
509
+ await openDrawer();
510
+
511
+ dragTimeline("2026-09-28T11:11:00.000Z", "2026-09-28T11:10:00.000Z");
512
+
513
+ await waitForPageOn(ZOOMED);
514
+ });
515
+
516
+ test("a drag across three bars keeps the last one whole", async () => {
517
+ await renderPage();
518
+ await openDrawer();
519
+
520
+ dragTimeline("2026-09-28T11:20:00.000Z", "2026-09-28T11:22:00.000Z");
521
+
522
+ await waitForPageOn("2026-09-28T11:20:00.000Z..2026-09-28T11:23:00.000Z");
523
+ });
524
+ });
525
+
526
+ describe("a plain click on the drawer's timeline is not a zoom", () => {
527
+ /*
528
+ * The timeline sits in a drawer and retimes the whole Insights page, so a
529
+ * click on a bar - to read its tooltip, or on the way to something else -
530
+ * must not reload every panel on the page for one bucket.
531
+ */
532
+ function clickBar(iso: string): void {
533
+ fireEvent.mouseDown(screen.getByTestId(`bar-${iso}`));
534
+ fireEvent.mouseUp(screen.getByTestId(`bar-${iso}`));
535
+ }
536
+
537
+ function requestCounts(): Array<number> {
538
+ return [histogramMock, patternsMock, breakdownMock, facetsMock].map(
539
+ (mock: MockFunction): number => {
540
+ return mock.mock.calls.length;
541
+ },
542
+ );
543
+ }
544
+
545
+ test("one click on a bar leaves the page, the picker and the drawer as they were", async () => {
546
+ await renderPage();
547
+ await openDrawer();
548
+ const before: Array<number> = requestCounts();
549
+
550
+ clickBar("2026-09-28T11:10:00.000Z");
551
+ act(() => {
552
+ jest.advanceTimersByTime(1000);
553
+ });
554
+
555
+ expect(requestCounts()).toEqual(before);
556
+ expect(correlationMock).toHaveBeenCalledTimes(1);
557
+ expect(pickerLabel()).toBe("Past 1 Hour");
558
+ expect(
559
+ screen.queryByTestId(RESET_TIME_RANGE_ZOOM_BUTTON_TEST_ID),
560
+ ).toBeNull();
561
+ expect(screen.getByTestId(TIME_RANGE_ZOOM_HINT_TEST_ID)).toHaveTextContent(
562
+ /^Drag to zoom$/,
563
+ );
564
+ });
565
+
566
+ test("while zoomed, a click on a bar still zooms nothing, even after the double-click wait", async () => {
567
+ await renderPage();
568
+ await openDrawer();
569
+ dragTimeline("2026-09-28T11:10:00.000Z", "2026-09-28T11:11:00.000Z");
570
+ await waitForPageOn(ZOOMED);
571
+ await waitFor(() => {
572
+ expect(
573
+ screen.getByTestId(ERROR_PATTERN_TIMELINE_TEST_ID),
574
+ ).toBeInTheDocument();
575
+ });
576
+ const before: Array<number> = requestCounts();
577
+
578
+ clickBar("2026-09-28T11:10:00.000Z");
579
+ act(() => {
580
+ jest.advanceTimersByTime(1000);
581
+ });
582
+
583
+ expect(requestCounts()).toEqual(before);
584
+ expect(lastScope(histogramMock)).toBe(ZOOMED);
585
+ expect(pageResetButton()).not.toBeNull();
586
+ });
587
+
588
+ test("a zoom into a stretch the error skipped: the message takes the double-click back, and selects no text", async () => {
589
+ await renderPage();
590
+ await openDrawer();
591
+
592
+ correlationMock.mockImplementation(async () => {
593
+ return {
594
+ pattern: PATTERN_TEXT,
595
+ bucketSizeInMinutes: 1,
596
+ timeline: [],
597
+ coOccurringPatterns: [],
598
+ attributes: [],
599
+ resources: [],
600
+ traces: [],
601
+ samples: [],
602
+ };
603
+ });
604
+ dragTimeline("2026-09-28T11:10:00.000Z", "2026-09-28T11:11:00.000Z");
605
+ await waitForPageOn(ZOOMED);
606
+
607
+ const message: HTMLElement = await screen.findByText(
608
+ "No bucketed occurrences to chart in this window.",
609
+ );
610
+ expect(message).toHaveClass("select-none");
611
+
612
+ fireEvent.doubleClick(message);
613
+
614
+ await waitForPageOn(TimeRange.PAST_ONE_HOUR);
615
+ });
616
+ });
617
+
618
+ describe("the drawer offers its own way back from a zoom made in it", () => {
619
+ /*
620
+ * A zoom made on the drawer's timeline keeps the drawer open, and the
621
+ * wide drawer covers the header picker and the Reset zoom beside it. So
622
+ * the timeline's heading carries a Reset zoom of its own while the page
623
+ * is zoomed: undoing the zoom needs neither the double-click nor the
624
+ * drawer closed, and works from the keyboard.
625
+ */
626
+ async function zoomFromTheDrawer(): Promise<void> {
627
+ await renderPage();
628
+ await openDrawer();
629
+
630
+ dragTimeline("2026-09-28T11:10:00.000Z", "2026-09-28T11:11:00.000Z");
631
+ await waitForPageOn(ZOOMED);
632
+ // The drawer's body is back once the zoomed correlation has landed.
633
+ await waitFor(() => {
634
+ expect(
635
+ screen.getByTestId(ERROR_PATTERN_TIMELINE_TEST_ID),
636
+ ).toBeInTheDocument();
637
+ });
638
+ }
639
+
640
+ test("before any zoom the timeline's heading names the gesture and offers no reset", async () => {
641
+ await renderPage();
642
+ await openDrawer();
643
+
644
+ expect(drawerResetButton()).toBeNull();
645
+ expect(
646
+ within(drawer()!).getByTestId(TIME_RANGE_ZOOM_HINT_TEST_ID),
647
+ ).toHaveTextContent(/^Drag to zoom$/);
648
+ });
649
+
650
+ test("after a drag, Reset zoom sits beside the timeline's hint, naming the range it goes back to", async () => {
651
+ await zoomFromTheDrawer();
652
+
653
+ const button: HTMLElement | null = drawerResetButton();
654
+ expect(button).not.toBeNull();
655
+
656
+ // In the "When it happened" heading row, next to the hint.
657
+ const hint: HTMLElement = within(drawer()!).getByTestId(
658
+ TIME_RANGE_ZOOM_HINT_TEST_ID,
659
+ );
660
+ expect(hint).toHaveTextContent("Double-click to reset");
661
+ expect(button!.parentElement).toBe(hint.parentElement);
662
+ expect(hint.parentElement!.parentElement!).toHaveTextContent(
663
+ "When it happened",
664
+ );
665
+
666
+ // It reads the page's zoom: the way back is to the page's own preset.
667
+ expect(button).toHaveAttribute(
668
+ "title",
669
+ "Go back to Past 1 Hour, the time range before the zoom",
670
+ );
671
+ // The page keeps its own Reset zoom beside the picker as well.
672
+ expect(pageResetButton()).not.toBeNull();
673
+ });
674
+
675
+ test("it puts the whole page back, and the drawer stays open on the original range", async () => {
676
+ await zoomFromTheDrawer();
677
+ const correlationsBefore: number = correlationMock.mock.calls.length;
678
+
679
+ fireEvent.click(drawerResetButton()!);
680
+
681
+ await waitForPageOn(TimeRange.PAST_ONE_HOUR);
682
+ await waitFor(() => {
683
+ expect(lastScope(correlationMock)).toBe(TimeRange.PAST_ONE_HOUR);
684
+ });
685
+ expect(correlationMock).toHaveBeenCalledTimes(correlationsBefore + 1);
686
+ expect(pickerLabel()).toBe("Past 1 Hour");
687
+ expect(drawer()).not.toBeNull();
688
+ await waitFor(() => {
689
+ expect(
690
+ screen.getByTestId(ERROR_PATTERN_TIMELINE_TEST_ID),
691
+ ).toBeInTheDocument();
692
+ });
693
+
694
+ // Nothing left to undo, in the drawer or beside the picker.
695
+ expect(drawerResetButton()).toBeNull();
696
+ expect(pageResetButton()).toBeNull();
697
+ expect(
698
+ within(drawer()!).getByTestId(TIME_RANGE_ZOOM_HINT_TEST_ID),
699
+ ).toHaveTextContent(/^Drag to zoom$/);
700
+ });
701
+
702
+ test("it is a real button, so the keyboard reaches it with the drawer open", async () => {
703
+ await zoomFromTheDrawer();
704
+
705
+ const button: HTMLElement = drawerResetButton()!;
706
+ expect(button.tagName).toBe("BUTTON");
707
+ expect(button).toHaveAttribute("type", "button");
708
+
709
+ button.focus();
710
+ expect(document.activeElement).toBe(button);
711
+ });
712
+
713
+ test("the page's own Reset zoom takes the drawer's away too", async () => {
714
+ await zoomFromTheDrawer();
715
+
716
+ fireEvent.click(pageResetButton()!);
717
+
718
+ await waitForPageOn(TimeRange.PAST_ONE_HOUR);
719
+ await waitFor(() => {
720
+ expect(
721
+ screen.getByTestId(ERROR_PATTERN_TIMELINE_TEST_ID),
722
+ ).toBeInTheDocument();
723
+ });
724
+ expect(drawerResetButton()).toBeNull();
725
+ });
726
+ });
727
+
728
+ describe("a superseded correlation never paints over the window the page is on", () => {
729
+ /*
730
+ * The drawer stays open while a zoom made on its timeline, or the reset
731
+ * of one, moves the page, and each move asks for the drawer's correlation
732
+ * again. A wide window answers slower than a narrow one, so the answers
733
+ * can land in either order. Whichever does, the drawer describes the
734
+ * window the page and its picker are on.
735
+ */
736
+ interface PendingCorrelation {
737
+ window: string;
738
+ resolve: (value: unknown) => void;
739
+ reject: (error: Error) => void;
740
+ }
741
+
742
+ const pending: Array<PendingCorrelation> = [];
743
+
744
+ // One error bar at 11:10 and one at 11:11, with these counts.
745
+ function correlationWith(
746
+ first: number,
747
+ second: number,
748
+ ): Record<string, unknown> {
749
+ return {
750
+ pattern: PATTERN_TEXT,
751
+ bucketSizeInMinutes: 1,
752
+ timeline: [
753
+ { time: new Date("2026-09-28T11:10:00.000Z"), count: first },
754
+ { time: new Date("2026-09-28T11:11:00.000Z"), count: second },
755
+ ],
756
+ coOccurringPatterns: [],
757
+ attributes: [],
758
+ resources: [],
759
+ traces: [],
760
+ samples: [],
761
+ };
762
+ }
763
+
764
+ // What the hour holds, and what the zoomed two minutes hold.
765
+ const HOUR_ANSWER: Record<string, unknown> = correlationWith(20, 22);
766
+ const ZOOMED_ANSWER: Record<string, unknown> = correlationWith(3, 5);
767
+
768
+ function answerLater(): void {
769
+ pending.length = 0;
770
+ correlationMock.mockImplementation((scope: LogsInsightsScope) => {
771
+ return new Promise(
772
+ (resolve: (value: unknown) => void, reject: (error: Error) => void) => {
773
+ pending.push({ window: windowOf(scope), resolve, reject });
774
+ },
775
+ );
776
+ });
777
+ }
778
+
779
+ function drawerLoader(): HTMLElement | null {
780
+ return within(drawer()!).queryByTestId("component-loader");
781
+ }
782
+
783
+ function drawerCount(pattern: RegExp): HTMLElement | null {
784
+ return within(drawer()!).queryByText(pattern);
785
+ }
786
+
787
+ /*
788
+ * The reader zoomed from the drawer (its correlation still out) and put
789
+ * the page back with Reset zoom before it landed (that one out too).
790
+ */
791
+ async function zoomThenResetWhileBothAreOut(): Promise<{
792
+ zoomed: PendingCorrelation;
793
+ reset: PendingCorrelation;
794
+ }> {
795
+ await renderPage();
796
+ await openDrawer();
797
+ answerLater();
798
+
799
+ dragTimeline("2026-09-28T11:10:00.000Z", "2026-09-28T11:11:00.000Z");
800
+ await waitForPageOn(ZOOMED);
801
+ await waitFor(() => {
802
+ expect(pending).toHaveLength(1);
803
+ });
804
+ expect(drawerLoader()).not.toBeNull();
805
+
806
+ fireEvent.click(pageResetButton()!);
807
+ await waitForPageOn(TimeRange.PAST_ONE_HOUR);
808
+ await waitFor(() => {
809
+ expect(pending).toHaveLength(2);
810
+ });
811
+
812
+ const [zoomed, reset] = pending as [PendingCorrelation, PendingCorrelation];
813
+ expect(zoomed.window).toBe(ZOOMED);
814
+ expect(reset.window).toBe(TimeRange.PAST_ONE_HOUR);
815
+ return { zoomed, reset };
816
+ }
817
+
818
+ test("the zoomed window answering last does not replace the hour's correlation", async () => {
819
+ const { zoomed, reset } = await zoomThenResetWhileBothAreOut();
820
+
821
+ await act(async () => {
822
+ reset.resolve(HOUR_ANSWER);
823
+ });
824
+ await waitFor(() => {
825
+ expect(drawerCount(/^42 times in the past 1 hour/)).not.toBeNull();
826
+ });
827
+
828
+ await act(async () => {
829
+ zoomed.resolve(ZOOMED_ANSWER);
830
+ });
831
+
832
+ expect(drawerCount(/^42 times in the past 1 hour/)).not.toBeNull();
833
+ expect(drawerCount(/^8 times/)).toBeNull();
834
+ expect(drawerLoader()).toBeNull();
835
+ });
836
+
837
+ test("the zoomed window answering first neither paints nor takes the loader down", async () => {
838
+ const { zoomed, reset } = await zoomThenResetWhileBothAreOut();
839
+
840
+ await act(async () => {
841
+ zoomed.resolve(ZOOMED_ANSWER);
842
+ });
843
+
844
+ // Still waiting for the hour: no two-minute numbers under its heading.
845
+ expect(drawerLoader()).not.toBeNull();
846
+ expect(drawerCount(/^8 times/)).toBeNull();
847
+ expect(screen.queryByTestId(ERROR_PATTERN_TIMELINE_TEST_ID)).toBeNull();
848
+
849
+ await act(async () => {
850
+ reset.resolve(HOUR_ANSWER);
851
+ });
852
+
853
+ await waitFor(() => {
854
+ expect(drawerCount(/^42 times in the past 1 hour/)).not.toBeNull();
855
+ });
856
+ expect(drawerLoader()).toBeNull();
857
+ });
858
+
859
+ test("the zoomed window failing late does not put its error over the hour's correlation", async () => {
860
+ const { zoomed, reset } = await zoomThenResetWhileBothAreOut();
861
+
862
+ await act(async () => {
863
+ reset.resolve(HOUR_ANSWER);
864
+ });
865
+ await waitFor(() => {
866
+ expect(drawerCount(/^42 times in the past 1 hour/)).not.toBeNull();
867
+ });
868
+
869
+ await act(async () => {
870
+ zoomed.reject(new Error("The correlation timed out"));
871
+ });
872
+
873
+ expect(drawerCount(/^42 times in the past 1 hour/)).not.toBeNull();
874
+ expect(
875
+ within(drawer()!).queryByText("The correlation timed out"),
876
+ ).toBeNull();
877
+ });
878
+
879
+ test("the zoomed window failing first neither shows its error nor ends the wait", async () => {
880
+ const { zoomed, reset } = await zoomThenResetWhileBothAreOut();
881
+
882
+ await act(async () => {
883
+ zoomed.reject(new Error("The correlation timed out"));
884
+ });
885
+
886
+ expect(drawerLoader()).not.toBeNull();
887
+ expect(
888
+ within(drawer()!).queryByText("The correlation timed out"),
889
+ ).toBeNull();
890
+
891
+ await act(async () => {
892
+ reset.resolve(HOUR_ANSWER);
893
+ });
894
+
895
+ await waitFor(() => {
896
+ expect(drawerCount(/^42 times in the past 1 hour/)).not.toBeNull();
897
+ });
898
+ expect(drawerLoader()).toBeNull();
899
+ });
900
+
901
+ test("the current window's own failure is still shown, with its retry", async () => {
902
+ const { zoomed, reset } = await zoomThenResetWhileBothAreOut();
903
+
904
+ await act(async () => {
905
+ zoomed.resolve(ZOOMED_ANSWER);
906
+ });
907
+ await act(async () => {
908
+ reset.reject(new Error("The correlation timed out"));
909
+ });
910
+
911
+ await waitFor(() => {
912
+ expect(
913
+ within(drawer()!).getByText("The correlation timed out"),
914
+ ).toBeInTheDocument();
915
+ });
916
+ expect(drawerLoader()).toBeNull();
917
+ expect(drawerCount(/^8 times/)).toBeNull();
918
+
919
+ // The retry is the newest request, so its answer is the one shown.
920
+ fireEvent.click(within(drawer()!).getByTestId("refresh-button"));
921
+ await waitFor(() => {
922
+ expect(pending).toHaveLength(3);
923
+ });
924
+ expect(pending[2]!.window).toBe(TimeRange.PAST_ONE_HOUR);
925
+ expect(drawerLoader()).not.toBeNull();
926
+
927
+ await act(async () => {
928
+ pending[2]!.resolve(HOUR_ANSWER);
929
+ });
930
+ await waitFor(() => {
931
+ expect(drawerCount(/^42 times in the past 1 hour/)).not.toBeNull();
932
+ });
933
+ expect(
934
+ within(drawer()!).queryByText("The correlation timed out"),
935
+ ).toBeNull();
936
+ });
937
+ });
938
+
939
+ describe("the page without a chart zoom", () => {
940
+ test("with the drawer closed, the page offers no zoom until a chart makes one", async () => {
941
+ await renderPage();
942
+
943
+ expect(
944
+ screen.queryByTestId(RESET_TIME_RANGE_ZOOM_BUTTON_TEST_ID),
945
+ ).toBeNull();
946
+ expect(pickerLabel()).toBe("Past 1 Hour");
947
+ });
948
+ });