@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.
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/KubernetesAiAgent.ts +364 -0
- package/Models/DatabaseModels/KubernetesCluster.ts +3 -3
- package/Models/DatabaseModels/Project.ts +55 -5
- package/Models/DatabaseModels/ProxmoxResource.ts +49 -1
- package/Models/DatabaseModels/RunnerJob.ts +75 -0
- package/Models/DatabaseModels/TeamComplianceSetting.ts +143 -2
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +17 -0
- package/Server/API/AIChatAPI.ts +6 -3
- package/Server/API/AIInvestigationAPI.ts +17 -10
- package/Server/API/AutoRemediationAPI.ts +207 -25
- package/Server/API/KubernetesClusterAiAccessAPI.ts +623 -21
- package/Server/API/MicrosoftTeamsAPI.ts +93 -14
- package/Server/API/ProxmoxResourceAPI.ts +244 -14
- package/Server/Infrastructure/GlobalCache.ts +32 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.ts +99 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.ts +137 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.ts +42 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/TelemetryIngest.ts +41 -18
- package/Server/Services/AIService.ts +70 -1
- package/Server/Services/AlertService.ts +352 -11
- package/Server/Services/AlertSeverityService.ts +65 -15
- package/Server/Services/AutoRemediationRuleService.ts +1 -1
- package/Server/Services/IncidentService.ts +280 -104
- package/Server/Services/IncidentSeverityService.ts +66 -15
- package/Server/Services/KubernetesAiAgentJobService.ts +185 -0
- package/Server/Services/KubernetesAiAgentService.ts +1634 -0
- package/Server/Services/KubernetesClusterAiAccessService.ts +1118 -451
- package/Server/Services/KubernetesClusterService.ts +129 -21
- package/Server/Services/ProjectService.ts +32 -0
- package/Server/Services/ProxmoxResourceService.ts +322 -5
- package/Server/Services/RunnerJobService.ts +241 -104
- package/Server/Services/RunnerService.ts +1 -1
- package/Server/Services/ScheduledMaintenanceService.ts +737 -1
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +414 -56
- package/Server/Services/TeamComplianceSettingService.ts +1125 -9
- package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +67 -9
- package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +39 -10
- package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +14 -3
- package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +37 -15
- package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +67 -24
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +48 -5
- package/Server/Utils/AI/SRE/IncidentPostmortemRunner.ts +40 -8
- package/Server/Utils/AI/SRE/InvestigationEligibility.ts +13 -2
- package/Server/Utils/AI/SRE/InvestigationGrader.ts +1 -1
- package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +6 -1
- package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +133 -7
- package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +58 -4
- package/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.ts +447 -0
- package/Server/Utils/Telemetry/ProxmoxNativePush.ts +903 -0
- package/Server/Utils/Telemetry/TelemetryEntity.ts +87 -27
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +684 -47
- package/Tests/App/AdminDashboard/RowActionPlacementOverrides.test.tsx +278 -0
- package/Tests/App/Dashboard/AIChatChartWidgetZoom.test.tsx +738 -0
- package/Tests/App/Dashboard/AIFeaturesSettingsPointers.test.tsx +147 -0
- package/Tests/App/Dashboard/AIInsightsKubernetesClusterPage.test.tsx +1523 -0
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +463 -3
- package/Tests/App/Dashboard/AffectedResourcesPickerDropdownPlacement.test.tsx +958 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerFocusLeave.test.tsx +595 -0
- package/Tests/App/Dashboard/AskAiAvailability.test.ts +20 -3
- package/Tests/App/Dashboard/AskAiDisabled.test.tsx +8 -3
- package/Tests/App/Dashboard/CephRateChartReload.test.tsx +1456 -0
- package/Tests/App/Dashboard/CephTimeRangeZoom.test.tsx +1229 -0
- package/Tests/App/Dashboard/ChartCardTimeRangeZoom.test.tsx +151 -0
- package/Tests/App/Dashboard/ChartCardZoomAffordances.test.tsx +257 -0
- package/Tests/App/Dashboard/ChartRefetchFrame.test.tsx +141 -0
- package/Tests/App/Dashboard/ChartZoomHarness.tsx +249 -0
- package/Tests/App/Dashboard/ChartZoomStandIn.tsx +131 -0
- package/Tests/App/Dashboard/CloudServerlessSlowLoads.test.tsx +628 -0
- package/Tests/App/Dashboard/CloudServerlessTimeRangeZoom.test.tsx +607 -0
- package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +91 -19
- package/Tests/App/Dashboard/CompanionMetricsTabZoom.test.tsx +632 -0
- package/Tests/App/Dashboard/ContainerChartZoomStandIn.tsx +195 -0
- package/Tests/App/Dashboard/ContainerHostOverviewSlowLoads.test.tsx +542 -0
- package/Tests/App/Dashboard/ContainerHostOverviewTimeRangeZoom.test.tsx +848 -0
- package/Tests/App/Dashboard/ContainerMetricsTimeRangeZoom.test.tsx +561 -0
- package/Tests/App/Dashboard/DashboardBoardWideZoomShell.test.tsx +1147 -0
- package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +3 -2
- package/Tests/App/Dashboard/DashboardHistogramWidgetDragCursor.test.tsx +399 -0
- package/Tests/App/Dashboard/DashboardHistogramWidgetZoom.test.tsx +985 -0
- package/Tests/App/Dashboard/DashboardHistogramWidgetZoomHint.test.tsx +803 -0
- package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +1 -0
- package/Tests/App/Dashboard/DashboardSettingsPreviewZoom.test.tsx +679 -0
- package/Tests/App/Dashboard/DashboardSloAndDataSourceChartZoom.test.tsx +881 -0
- package/Tests/App/Dashboard/DashboardTraceStatusWidgets.test.tsx +878 -0
- package/Tests/App/Dashboard/DatabaseMetricChartModalTimeRangeZoom.test.tsx +442 -0
- package/Tests/App/Dashboard/DatabaseOverviewTimeRangeZoom.test.tsx +831 -0
- package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +43 -0
- package/Tests/App/Dashboard/DockerSwarmInsightsTimeRangeZoom.test.tsx +524 -0
- package/Tests/App/Dashboard/DockerSwarmRateChartRefresh.test.tsx +259 -0
- package/Tests/App/Dashboard/EdgeDetailPanelHistory.test.tsx +763 -0
- package/Tests/App/Dashboard/EdgeDetailPanelTimeRangeZoom.test.tsx +547 -0
- package/Tests/App/Dashboard/EdgeHistoryBucketsCases.tsx +565 -0
- package/Tests/App/Dashboard/EdgeHistoryBucketsKathmandu.test.tsx +73 -0
- package/Tests/App/Dashboard/EdgeHistoryBucketsKolkata.test.tsx +74 -0
- package/Tests/App/Dashboard/EdgeHistoryBucketsNewYork.test.tsx +72 -0
- package/Tests/App/Dashboard/EdgeHistoryBucketsUtc.test.tsx +72 -0
- package/Tests/App/Dashboard/EmbeddedMetricCardRefresh.test.tsx +310 -0
- package/Tests/App/Dashboard/EmbeddedMetricCardTimeRangeZoom.test.tsx +536 -0
- package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +3 -1
- package/Tests/App/Dashboard/EscalationRuleRowActions.test.tsx +660 -0
- package/Tests/App/Dashboard/EventNotes.test.tsx +2 -2
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +587 -13
- package/Tests/App/Dashboard/EventOverviewSnapshotExplorerZoom.test.tsx +1139 -0
- package/Tests/App/Dashboard/EventOverviewSnapshotZoomAcrossTabs.test.tsx +1057 -0
- package/Tests/App/Dashboard/EventOverviewTelemetrySnapshotZoom.test.tsx +757 -0
- package/Tests/App/Dashboard/ExceptionOccurrenceTrendZoom.test.tsx +675 -0
- package/Tests/App/Dashboard/ExceptionOccurrencesZoomSurvivesViewSwitch.test.tsx +405 -0
- package/Tests/App/Dashboard/ExceptionSignalPages.test.tsx +67 -3
- package/Tests/App/Dashboard/ExceptionTablesSpanStatus.test.tsx +515 -0
- package/Tests/App/Dashboard/ExplorerOwnZoomRegression.test.tsx +739 -0
- package/Tests/App/Dashboard/FlowBandwidthAxisCases.tsx +461 -0
- package/Tests/App/Dashboard/FlowBandwidthAxisKathmandu.test.tsx +25 -0
- package/Tests/App/Dashboard/FlowBandwidthAxisKolkata.test.tsx +25 -0
- package/Tests/App/Dashboard/FlowBandwidthAxisNewYork.test.tsx +25 -0
- package/Tests/App/Dashboard/FlowBandwidthAxisUtc.test.tsx +24 -0
- package/Tests/App/Dashboard/FlowTopTalkersZoomRefetch.test.tsx +722 -0
- package/Tests/App/Dashboard/FlowViewportGuard.test.tsx +2526 -0
- package/Tests/App/Dashboard/HostPagesSlowLoads.test.tsx +872 -0
- package/Tests/App/Dashboard/HostPagesTimeRangeZoom.test.tsx +1208 -0
- package/Tests/App/Dashboard/IncidentRootCauseTimeRangeZoom.test.tsx +358 -0
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +100 -9
- package/Tests/App/Dashboard/InfrastructureMetricsTabTimeRangeZoom.test.tsx +485 -0
- package/Tests/App/Dashboard/InvestigationDrawerCompanionZoom.test.tsx +655 -0
- package/Tests/App/Dashboard/InvestigationDrawerZoom.test.tsx +830 -0
- package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +338 -2
- package/Tests/App/Dashboard/InvoicesPayInvoice.test.tsx +454 -16
- package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +799 -819
- package/Tests/App/Dashboard/KubernetesClusterAiAgentOverviewCard.test.tsx +367 -0
- package/Tests/App/Dashboard/KubernetesClusterAiAgentStatus.test.ts +1202 -0
- package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +106 -0
- package/Tests/App/Dashboard/KubernetesClusterAiNavigation.test.tsx +354 -0
- package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +1884 -2054
- package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +478 -179
- package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +50 -0
- package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +2 -1
- package/Tests/App/Dashboard/KubernetesClusterOverviewZoom.test.tsx +1217 -0
- package/Tests/App/Dashboard/KubernetesClusterPagesZoom.test.tsx +731 -0
- package/Tests/App/Dashboard/KubernetesCostsLoadRecovery.test.tsx +869 -0
- package/Tests/App/Dashboard/KubernetesCostsZoom.test.tsx +1214 -0
- package/Tests/App/Dashboard/KubernetesCostsZoomExactHours.test.tsx +692 -0
- package/Tests/App/Dashboard/KubernetesNetworkThroughputReload.test.tsx +902 -0
- package/Tests/App/Dashboard/KubernetesNetworkZoomBucketEdges.test.tsx +571 -0
- package/Tests/App/Dashboard/KubernetesOverviewZoomBucketEdges.test.tsx +697 -0
- package/Tests/App/Dashboard/KubernetesResourceMetricsTabZoom.test.tsx +633 -0
- package/Tests/App/Dashboard/LogsExplorerTimeRangeZoom.test.tsx +470 -0
- package/Tests/App/Dashboard/LogsInsightsTimeRangeZoom.test.tsx +948 -0
- package/Tests/App/Dashboard/LogsViewerPinnedWindowZoom.test.tsx +486 -0
- package/Tests/App/Dashboard/MetricChartsBucketInspectorDoubleClick.test.tsx +1001 -0
- package/Tests/App/Dashboard/MetricExplorerInvestigationAutoRefresh.test.tsx +514 -0
- package/Tests/App/Dashboard/MetricExplorerSavedViewZoomRoundTrip.test.tsx +581 -0
- package/Tests/App/Dashboard/MetricExplorerTimeRangeZoom.test.tsx +1162 -0
- package/Tests/App/Dashboard/MetricMonitorPreviewZoomLabel.test.ts +72 -0
- package/Tests/App/Dashboard/MetricRowSparklineTimeRangeZoom.test.tsx +204 -0
- package/Tests/App/Dashboard/MetricViewFirstResultLands.test.tsx +408 -0
- package/Tests/App/Dashboard/MetricViewOwnZoomResetPlacement.test.tsx +952 -0
- package/Tests/App/Dashboard/MetricViewTimeRange.test.ts +139 -0
- package/Tests/App/Dashboard/MetricViewTimeRangeZoom.test.tsx +556 -0
- package/Tests/App/Dashboard/MonitorMetricsChartWrappersZoom.test.tsx +552 -0
- package/Tests/App/Dashboard/MonitorMetricsTabsTimeRangeZoom.test.tsx +740 -0
- package/Tests/App/Dashboard/MonitorOverviewChartsTimeRangeZoom.test.tsx +735 -0
- package/Tests/App/Dashboard/MonitorStepPreviewsTimeRangeZoom.test.tsx +835 -0
- package/Tests/App/Dashboard/NetworkDeviceTimeRangeZoom.test.tsx +1115 -0
- package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +186 -17
- package/Tests/App/Dashboard/OnCallRulesDeleteGuard.test.tsx +155 -46
- package/Tests/App/Dashboard/PasskeySettings.test.tsx +87 -2
- package/Tests/App/Dashboard/ProjectAISettingsPages.test.tsx +884 -0
- package/Tests/App/Dashboard/ProxmoxNodeRemove.test.tsx +621 -0
- package/Tests/App/Dashboard/ProxmoxOverviewSlowLoads.test.tsx +584 -0
- package/Tests/App/Dashboard/ProxmoxPagesTimeRangeZoom.test.tsx +823 -0
- package/Tests/App/Dashboard/ProxmoxRateChartReload.test.tsx +1253 -0
- package/Tests/App/Dashboard/PublicDashboardBoardWideZoom.test.tsx +605 -0
- package/Tests/App/Dashboard/RealRowsLineChart.tsx +250 -0
- package/Tests/App/Dashboard/RechartsHostsPlotCursor.test.tsx +513 -0
- package/Tests/App/Dashboard/RowActionPlacementOverrides.test.tsx +865 -0
- package/Tests/App/Dashboard/RumOverviewTimeRangeZoom.test.tsx +877 -0
- package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +20 -4
- package/Tests/App/Dashboard/RunnerSupersededByAiAgentNote.test.tsx +296 -0
- package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +146 -36
- package/Tests/App/Dashboard/ServiceDatabaseSlowLoads.test.tsx +1166 -0
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +1243 -104
- package/Tests/App/Dashboard/ServiceOverviewTimeRangeZoom.test.tsx +792 -0
- package/Tests/App/Dashboard/SloBudgetBurnDownZoom.test.tsx +771 -0
- package/Tests/App/Dashboard/SloBudgetBurnDownZoomAffordances.test.tsx +380 -0
- package/Tests/App/Dashboard/SloEventMetricsBarChartZoom.test.tsx +369 -0
- package/Tests/App/Dashboard/SloHistoryChartsTimeRangeZoom.test.tsx +694 -0
- package/Tests/App/Dashboard/SloHistoryChartsZoomAffordances.test.tsx +497 -0
- package/Tests/App/Dashboard/SloMetricsTimeRangeZoom.test.tsx +541 -0
- package/Tests/App/Dashboard/SlowLoadHarness.ts +123 -0
- package/Tests/App/Dashboard/SnapshotExplorerPrimaryZoom.test.tsx +1194 -0
- package/Tests/App/Dashboard/SnapshotViewerPinnedWindow.test.tsx +620 -0
- package/Tests/App/Dashboard/TelemetrySnapshotPanelTimeRangeZoom.test.tsx +765 -0
- package/Tests/App/Dashboard/TelemetrySnapshotZoom.test.tsx +516 -0
- package/Tests/App/Dashboard/TelemetrySnapshotZoomAcrossTabs.test.tsx +827 -0
- package/Tests/App/Dashboard/TimeRangeZoomPageHarness.tsx +463 -0
- package/Tests/App/Dashboard/TraceChartEditorStatusSplit.test.tsx +543 -0
- package/Tests/App/Dashboard/TraceStatusPresentation.test.tsx +967 -0
- package/Tests/App/Dashboard/TraceTimelineMinimapZoom.test.tsx +315 -0
- package/Tests/App/Dashboard/TracesAnalyticsStatusSplit.test.tsx +778 -0
- package/Tests/App/Dashboard/TracesAnalyticsViewZoom.test.tsx +349 -0
- package/Tests/App/Dashboard/TracesExplorerTimeRangeZoom.test.tsx +551 -0
- package/Tests/App/Dashboard/TracesStatusChartAndFacet.test.tsx +687 -0
- package/Tests/App/Dashboard/TracesViewerStaleResponses.test.tsx +458 -0
- package/Tests/App/Dashboard/UptimeStripsExcludedFromZoom.test.tsx +406 -0
- package/Tests/App/Dashboard/VMwareOverviewSlowLoads.test.tsx +535 -0
- package/Tests/App/Dashboard/VMwarePagesTimeRangeZoom.test.tsx +606 -0
- package/Tests/App/Dashboard/ValueWidgetSparklineStaleHover.test.tsx +1292 -0
- package/Tests/App/Dashboard/ValueWidgetSparklineZoom.test.tsx +765 -0
- package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +98 -0
- package/Tests/Models/DatabaseModels/KubernetesAiAgentModel.test.ts +295 -0
- package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +347 -0
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +58 -0
- package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +1 -1
- package/Tests/Server/API/AIInvestigationAPI.test.ts +123 -45
- package/Tests/Server/API/AutoRemediationApproveClusterRound.test.ts +1329 -0
- package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +25 -2
- package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -0
- package/Tests/Server/API/KubernetesClusterAiAccessAPIAgent.test.ts +903 -0
- package/Tests/Server/API/MicrosoftTeamsChatsRefreshRoute.test.ts +667 -0
- package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +294 -6
- package/Tests/Server/API/ProxmoxResourceAPIRemoveNode.test.ts +1932 -0
- package/Tests/Server/Infrastructure/GlobalCache.test.ts +195 -0
- package/Tests/Server/Infrastructure/Postgres/AddKubernetesAiAgentAndAiDefaultsMigration.test.ts +623 -0
- package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +87 -10
- package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleScopeMigration.test.ts +622 -0
- package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +61 -4
- package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +98 -2
- package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +105 -2
- package/Tests/Server/Services/AIServiceBalanceBlocker.test.ts +282 -0
- package/Tests/Server/Services/AlertMonitorClearWritesNull.test.ts +409 -0
- package/Tests/Server/Services/AlertMonitorEditFeed.test.ts +474 -0
- package/Tests/Server/Services/AlertMonitorEditGuard.test.ts +610 -0
- package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +2 -0
- package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +2 -1
- package/Tests/Server/Services/IncidentAffectedMonitorsEdit.test.ts +1360 -0
- package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +3 -1
- package/Tests/Server/Services/IncidentSeverityDeletePausesComplianceRules.test.ts +488 -0
- package/Tests/Server/Services/KubernetesAiAgentJobService.test.ts +329 -0
- package/Tests/Server/Services/KubernetesAiAgentServiceHelpers.test.ts +618 -0
- package/Tests/Server/Services/KubernetesAiAgentServiceLifecycle.test.ts +1444 -0
- package/Tests/Server/Services/KubernetesAiAgentServiceRegister.test.ts +1666 -0
- package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +140 -111
- package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +267 -105
- package/Tests/Server/Services/KubernetesClusterAiAccessLegacySuperseded.test.ts +440 -0
- package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +567 -411
- package/Tests/Server/Services/KubernetesClusterAiAccessTarget.test.ts +1168 -0
- package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +410 -12
- package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +55 -0
- package/Tests/Server/Services/ProjectServiceNewProjectAiDefaults.test.ts +288 -0
- package/Tests/Server/Services/ProxmoxResourcePostgres.test.ts +5633 -0
- package/Tests/Server/Services/ProxmoxResourceService.test.ts +6458 -5
- package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +48 -15
- package/Tests/Server/Services/RunnerJobEnqueueKubectlAiAgent.test.ts +620 -0
- package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +170 -3
- package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +72 -0
- package/Tests/Server/Services/RunnerServiceAgentName.test.ts +6 -4
- package/Tests/Server/Services/ScheduledMaintenanceAttachmentEdit.test.ts +2113 -0
- package/Tests/Server/Services/ScheduledMaintenanceMonitorRelease.test.ts +972 -0
- package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +2237 -0
- package/Tests/Server/Services/TeamComplianceSettingService.test.ts +3988 -138
- package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +107 -1
- package/Tests/Server/Utils/AI/IncidentPostmortemRunner.test.ts +351 -0
- package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +2 -0
- package/Tests/Server/Utils/AI/InvestigationEligibility.test.ts +310 -0
- package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +70 -0
- package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +58 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +2 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +2 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +2 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +125 -1
- package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +252 -3
- package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +2 -0
- package/Tests/Server/Utils/AI/RemediationExecutionRunnerProjectGates.test.ts +240 -0
- package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +2 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +2 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +2 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +2 -0
- package/Tests/Server/Utils/Telemetry/HostAssetAttributesFromOtlp.test.ts +68 -0
- package/Tests/Server/Utils/Telemetry/InventoryMirrorPostgres.test.ts +370 -0
- package/Tests/Server/Utils/Telemetry/NetworkDeviceInventoryAttributes.test.ts +522 -0
- package/Tests/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.test.ts +155 -0
- package/Tests/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.test.ts +8631 -0
- package/Tests/Server/Utils/Telemetry/ProxmoxNativePush.test.ts +2852 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +367 -1
- package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +45 -3
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +25 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsGroupChatNames.test.ts +3119 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsGroupChatNamesPostgres.test.ts +1721 -0
- package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +581 -113
- package/Tests/Types/Kubernetes/KubernetesAiAgentAccessContract.test.ts +510 -0
- package/Tests/Types/Team/ComplianceRule.test.ts +1029 -0
- package/Tests/Types/Team/TeamComplianceStatus.test.ts +176 -0
- package/Tests/UI/Components/ActionButton/RowActions.test.tsx +641 -0
- package/Tests/UI/Components/ActionButton/RowActionsAccessibility.test.tsx +414 -0
- package/Tests/UI/Components/ActionButton/SplitActionButtons.test.ts +565 -0
- package/Tests/UI/Components/Charts/BarChartDragToSelect.test.tsx +386 -0
- package/Tests/UI/Components/Charts/ChartDoubleClickResetWithoutDblclick.test.tsx +1025 -0
- package/Tests/UI/Components/Charts/ChartGroupPageZoomHint.test.tsx +196 -0
- package/Tests/UI/Components/Charts/ChartPlaceholdersTakeDoubleClick.test.tsx +1861 -0
- package/Tests/UI/Components/Charts/ChartPlotClicksWhileResetArmed.test.tsx +382 -0
- package/Tests/UI/Components/Charts/ChartRangeSelection.test.tsx +704 -0
- package/Tests/UI/Components/Charts/ChartRangeSelectionDoubleClickReset.test.tsx +1481 -0
- package/Tests/UI/Components/Charts/ChartRangeSelectionRealRecharts.test.tsx +918 -0
- package/Tests/UI/Components/Charts/ChartRowBucketStart.test.ts +350 -0
- package/Tests/UI/Components/Charts/DoubleClickReset.test.tsx +996 -0
- package/Tests/UI/Components/Charts/HistogramDoubleClickResetRealRecharts.test.tsx +965 -0
- package/Tests/UI/Components/Charts/HistogramDriftThenRefetch.test.tsx +277 -0
- package/Tests/UI/Components/Charts/HistogramRangeSelectionDataChange.test.tsx +1757 -0
- package/Tests/UI/Components/Charts/HistogramRangeSelectionRealRecharts.test.tsx +560 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/ChartPageTimeRangeZoom.test.tsx +513 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.test.tsx +845 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.test.tsx +119 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHintTailwind.test.tsx +274 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.test.ts +433 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.test.tsx +863 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/ZoomDocsPromises.test.tsx +1147 -0
- package/Tests/UI/Components/DisabledButtonTooltip.test.tsx +14 -3
- package/Tests/UI/Components/EntityDropdownEscape.test.tsx +454 -0
- package/Tests/UI/Components/EntityDropdownFocusLeave.test.tsx +420 -0
- package/Tests/UI/Components/Forms/FormFieldDropdownDisabled.test.tsx +233 -0
- package/Tests/UI/Components/Input.test.tsx +80 -1
- package/Tests/UI/Components/LogsAnalyticsViewZoom.test.tsx +947 -0
- package/Tests/UI/Components/LogsHistogramDragTooltip.test.tsx +17 -5
- package/Tests/UI/Components/LogsViewerAnalyticsZoom.test.tsx +501 -0
- package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +6 -4
- package/Tests/UI/Components/ModelTable/BaseModelTablePermissionGating.test.tsx +60 -8
- package/Tests/UI/Components/ModelTable/BaseModelTableRowActions.test.tsx +476 -0
- package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +7 -5
- package/Tests/UI/Components/MoreMenuPortal.test.tsx +623 -0
- package/Tests/UI/Components/StatusPage/ResourceGridActions.test.tsx +538 -0
- package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +14 -4
- package/Tests/UI/Components/TableCellWrapping.test.tsx +3 -3
- package/Tests/UI/Components/TableRowActions.test.tsx +472 -0
- package/Tests/UI/Components/TelemetryHistogramDragTooltip.test.tsx +1 -1
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +1 -1
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerZoomScope.test.tsx +470 -0
- package/Tests/UI/Components/TelemetryViewer/UseViewerTimeRangeZoom.test.tsx +571 -0
- package/Tests/UI/Components/TelemetryViewer/ViewerDoubleClickResetUnderDataChange.test.tsx +928 -0
- package/Tests/UI/Components/TelemetryViewer/ViewerFollowsEnclosingZoom.test.tsx +1569 -0
- package/Tests/UI/Components/Toggle.test.tsx +66 -0
- package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardRefreshNames.test.tsx +1023 -0
- package/Tests/UI/Rum/ChunkLoader.test.ts +201 -0
- package/Tests/UI/Rum/FidelityNotices.test.ts +54 -0
- package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +72 -0
- package/Tests/UI/Rum/ReplayFrameCapture.test.ts +1009 -9
- package/Tests/UI/Rum/ReplayRecordedAssets.test.ts +1069 -0
- package/Tests/UI/Rum/ReplayStage.test.tsx +913 -2
- package/Tests/UI/Rum/SessionReplayTable.test.tsx +443 -8
- package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +439 -9
- package/Tests/UI/Rum/UserFlowTablesRowActions.test.tsx +501 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +47 -19
- package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +2 -0
- package/Tests/Utils/AiRemediation/KubernetesAiAgentPolicyCopyParity.test.ts +396 -0
- package/Tests/Utils/Dashboard/DashboardTimeRangeZoom.test.ts +104 -1
- package/Types/AI/AIRunType.ts +9 -4
- package/Types/AI/InvestigationNotStartedReason.ts +6 -0
- package/Types/AutoRemediation/AiRemediationCommandPlan.ts +14 -16
- package/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.ts +28 -0
- package/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.ts +4 -2
- package/Types/Kubernetes/KubernetesClusterAiAccess.ts +263 -32
- package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +20 -16
- package/Types/Kubernetes/KubernetesClusterAiInsights.ts +81 -0
- package/Types/Monitor/ProxmoxAlertTemplates.ts +4 -4
- package/Types/Team/ComplianceNotificationChannel.ts +22 -0
- package/Types/Team/ComplianceRule.ts +434 -0
- package/Types/Team/ComplianceRuleType.ts +21 -0
- package/Types/Team/TeamComplianceStatus.ts +81 -0
- package/Types/Telemetry/TelemetryIngestSurface.ts +28 -0
- package/UI/Components/ActionButton/ActionButtonSchema.ts +21 -0
- package/UI/Components/ActionButton/RowActions.tsx +238 -0
- package/UI/Components/ActionButton/SplitActionButtons.ts +173 -0
- package/UI/Components/Charts/Area/AreaChart.tsx +32 -2
- package/UI/Components/Charts/Bar/BarChart.tsx +40 -3
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +37 -11
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +80 -243
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +122 -31
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +95 -244
- package/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.ts +214 -0
- package/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.ts +32 -0
- package/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.ts +599 -0
- package/UI/Components/Charts/Line/LineChart.tsx +32 -2
- package/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.tsx +70 -0
- package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.tsx +226 -0
- package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.tsx +73 -0
- package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.ts +163 -0
- package/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.ts +215 -0
- package/UI/Components/Charts/Utils/DataPoint.ts +20 -8
- package/UI/Components/Charts/Utils/XAxis.ts +75 -0
- package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +493 -59
- package/UI/Components/EntityDropdown/EntityDropdown.tsx +107 -11
- package/UI/Components/Forms/Fields/FormField.tsx +10 -0
- package/UI/Components/Input/Input.tsx +90 -57
- package/UI/Components/List/ListRow.tsx +8 -74
- package/UI/Components/LogsViewer/LogsViewer.tsx +40 -11
- package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +22 -6
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +209 -6
- package/UI/Components/LogsViewer/components/LogsHistogram.tsx +127 -84
- package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +3 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +12 -1
- package/UI/Components/MoreMenu/MoreMenu.tsx +365 -30
- package/UI/Components/MoreMenu/MoreMenuItem.tsx +70 -17
- package/UI/Components/OrderedStatesList/Item.tsx +7 -72
- package/UI/Components/StatusPage/ResourceGrid.tsx +126 -77
- package/UI/Components/Table/TableBody.tsx +8 -2
- package/UI/Components/Table/TableRow.tsx +20 -140
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +41 -10
- package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +47 -9
- package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +25 -6
- package/UI/Components/TelemetryViewer/types.ts +2 -0
- package/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.ts +448 -0
- package/UI/Components/Toggle/Toggle.tsx +26 -0
- package/UI/Components/Tooltip/Tooltip.tsx +8 -1
- package/UI/Styles/Theme.css +14 -2
- package/Utils/AiRemediation/CommandPolicy.ts +1 -1
- package/Utils/AiRemediation/KubectlPolicy.ts +1 -1
- package/Utils/Dashboard/DashboardTimeRangeZoom.ts +46 -2
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesAiAgent.js +385 -0
- package/build/dist/Models/DatabaseModels/KubernetesAiAgent.js.map +1 -0
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +3 -3
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +56 -5
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxResource.js +51 -1
- package/build/dist/Models/DatabaseModels/ProxmoxResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunnerJob.js +74 -0
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +134 -3
- package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +6 -1
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +17 -10
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/AutoRemediationAPI.js +144 -24
- package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
- package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +436 -22
- package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +69 -13
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/ProxmoxResourceAPI.js +187 -14
- package/build/dist/Server/API/ProxmoxResourceAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/GlobalCache.js +27 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.js +50 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.js +84 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.js +31 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +34 -19
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +59 -1
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +248 -13
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AlertSeverityService.js +51 -15
- package/build/dist/Server/Services/AlertSeverityService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleService.js +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +199 -72
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentSeverityService.js +51 -15
- package/build/dist/Server/Services/IncidentSeverityService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesAiAgentJobService.js +158 -0
- package/build/dist/Server/Services/KubernetesAiAgentJobService.js.map +1 -0
- package/build/dist/Server/Services/KubernetesAiAgentService.js +1145 -0
- package/build/dist/Server/Services/KubernetesAiAgentService.js.map +1 -0
- package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +842 -371
- package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterService.js +86 -17
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +22 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxResourceService.js +258 -3
- package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -1
- package/build/dist/Server/Services/RunnerJobService.js +178 -92
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
- package/build/dist/Server/Services/RunnerService.js +1 -1
- package/build/dist/Server/Services/RunnerService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +535 -3
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +316 -46
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/TeamComplianceSettingService.js +833 -7
- package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
- package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +52 -9
- package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -1
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +13 -9
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +7 -3
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +29 -15
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +56 -20
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +39 -5
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js +30 -3
- package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js +13 -2
- package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +1 -1
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +4 -2
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +111 -6
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +40 -4
- package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.js +296 -0
- package/build/dist/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ProxmoxNativePush.js +699 -0
- package/build/dist/Server/Utils/Telemetry/ProxmoxNativePush.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +77 -19
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +505 -42
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/AI/AIRunType.js +9 -4
- package/build/dist/Types/AI/AIRunType.js.map +1 -1
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +10 -16
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.js +28 -0
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.js.map +1 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +72 -16
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +20 -16
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -1
- package/build/dist/Types/Kubernetes/KubernetesClusterAiInsights.js +17 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiInsights.js.map +1 -0
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +4 -4
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
- package/build/dist/Types/Team/ComplianceNotificationChannel.js +23 -0
- package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -0
- package/build/dist/Types/Team/ComplianceRule.js +304 -0
- package/build/dist/Types/Team/ComplianceRule.js.map +1 -0
- package/build/dist/Types/Team/ComplianceRuleType.js +21 -0
- package/build/dist/Types/Team/ComplianceRuleType.js.map +1 -1
- package/build/dist/Types/Team/TeamComplianceStatus.js +2 -0
- package/build/dist/Types/Team/TeamComplianceStatus.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +25 -0
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
- package/build/dist/UI/Components/ActionButton/ActionButtonSchema.js +20 -1
- package/build/dist/UI/Components/ActionButton/ActionButtonSchema.js.map +1 -1
- package/build/dist/UI/Components/ActionButton/RowActions.js +113 -0
- package/build/dist/UI/Components/ActionButton/RowActions.js.map +1 -0
- package/build/dist/UI/Components/ActionButton/SplitActionButtons.js +71 -0
- package/build/dist/UI/Components/ActionButton/SplitActionButtons.js.map +1 -0
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +16 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +16 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +27 -5
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +61 -194
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +84 -26
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +75 -196
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js +133 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.js +26 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.js +371 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.js.map +1 -0
- package/build/dist/UI/Components/Charts/Line/LineChart.js +16 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.js +35 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.js.map +1 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.js +107 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.js.map +1 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.js +41 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.js.map +1 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.js +117 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.js.map +1 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.js +121 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.js.map +1 -0
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -7
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/XAxis.js +70 -0
- package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +305 -38
- package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +89 -14
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +11 -2
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +69 -54
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/List/ListRow.js +4 -39
- package/build/dist/UI/Components/List/ListRow.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +31 -8
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +10 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +139 -21
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +30 -8
- package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +10 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +253 -14
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +43 -13
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
- package/build/dist/UI/Components/OrderedStatesList/Item.js +2 -38
- package/build/dist/UI/Components/OrderedStatesList/Item.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js +53 -15
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
- package/build/dist/UI/Components/Table/TableBody.js +6 -2
- package/build/dist/UI/Components/Table/TableBody.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +12 -75
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +32 -7
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +27 -9
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +11 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.js +272 -0
- package/build/dist/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.js.map +1 -0
- package/build/dist/UI/Components/Toggle/Toggle.js +14 -1
- package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
- package/build/dist/Utils/AiRemediation/CommandPolicy.js +1 -1
- package/build/dist/Utils/AiRemediation/CommandPolicy.js.map +1 -1
- package/build/dist/Utils/AiRemediation/KubectlPolicy.js +1 -1
- package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -1
- package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js +27 -1
- package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,1001 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import {
|
|
3
|
+
afterEach,
|
|
4
|
+
beforeEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
jest,
|
|
8
|
+
test,
|
|
9
|
+
} from "@jest/globals";
|
|
10
|
+
import {
|
|
11
|
+
act,
|
|
12
|
+
cleanup,
|
|
13
|
+
fireEvent,
|
|
14
|
+
render,
|
|
15
|
+
screen,
|
|
16
|
+
} from "@testing-library/react";
|
|
17
|
+
import * as React from "react";
|
|
18
|
+
import getJestMockFunction, { MockFunction } from "../../MockType";
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* The bucket inspector ("Investigate this moment") and a double-click on a
|
|
22
|
+
* chart that has no zoom to reset (issue #4105, found driving Kubernetes
|
|
23
|
+
* Insights in a real browser).
|
|
24
|
+
*
|
|
25
|
+
* With no reset on offer, a chart acts on a click at once, so the first
|
|
26
|
+
* click of a double-click opens the inspector at the pointer. Clamped into
|
|
27
|
+
* the viewport, the inspector covers the pointer, and the rest of the
|
|
28
|
+
* double-click landed on it: its second press selected the word under the
|
|
29
|
+
* pointer ("Pod" of "Pod CPU Utilization"), and its click pressed whatever
|
|
30
|
+
* button was there - "Investigate this moment" opened the drawer. The
|
|
31
|
+
* inspector now ignores the rest of the click sequence that opened it, and
|
|
32
|
+
* its chrome is not selectable at all. Its values still are.
|
|
33
|
+
*
|
|
34
|
+
* On a ZOOMED chart the same thing happens to a slow double-click (issue
|
|
35
|
+
* #4116). A chart that offers a reset holds a click back for
|
|
36
|
+
* DOUBLE_CLICK_DISAMBIGUATION_MS, waiting for a second one; a double-click
|
|
37
|
+
* slower than that - still well inside the platforms' own double-click
|
|
38
|
+
* time - let its first click through as a bucket click, which opened the
|
|
39
|
+
* inspector under the pointer, and its second press landed on the
|
|
40
|
+
* inspector, which swallowed it: the zoom stayed. That press is still the
|
|
41
|
+
* way back out of the zoom. It closes the inspector and resets the zoom,
|
|
42
|
+
* once - with the reset the charts themselves end up with, the host's or
|
|
43
|
+
* else the page's - and it is still no word selection and no button press.
|
|
44
|
+
* Nothing else on the inspector resets: not a double-click of its own, nor
|
|
45
|
+
* a triple-click's third press, nor its buttons, nor a press of another
|
|
46
|
+
* button than the main one that the browser counts 2 - a right-button one
|
|
47
|
+
* opens a context menu, as on the charts (commit b6ec899df4; before it, a
|
|
48
|
+
* right-button press counted 2 closed the inspector and reset the zoom).
|
|
49
|
+
*
|
|
50
|
+
* Real MetricCharts on real recharts (ResponsiveContainer given a size):
|
|
51
|
+
* the plot click resolves a bucket exactly as it does in the page.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
jest.mock("recharts", () => {
|
|
55
|
+
const actual: Record<string, any> = jest.requireActual("recharts") as Record<
|
|
56
|
+
string,
|
|
57
|
+
any
|
|
58
|
+
>;
|
|
59
|
+
return {
|
|
60
|
+
...actual,
|
|
61
|
+
ResponsiveContainer: ({ children }: { children: React.ReactElement }) => {
|
|
62
|
+
return React.cloneElement(children, {
|
|
63
|
+
width: 600,
|
|
64
|
+
height: 300,
|
|
65
|
+
} as Record<string, unknown>);
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const fetchExemplarsMock: MockFunction = getJestMockFunction();
|
|
71
|
+
|
|
72
|
+
jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
|
|
73
|
+
return {
|
|
74
|
+
__esModule: true,
|
|
75
|
+
default: {
|
|
76
|
+
getList: () => {
|
|
77
|
+
return Promise.resolve({ data: [] });
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
jest.mock(
|
|
84
|
+
"../../../../App/FeatureSet/Dashboard/src/Components/Metrics/Utils/Metrics",
|
|
85
|
+
() => {
|
|
86
|
+
return {
|
|
87
|
+
__esModule: true,
|
|
88
|
+
default: {
|
|
89
|
+
fetchExemplars: (...args: Array<any>) => {
|
|
90
|
+
fetchExemplarsMock(...args);
|
|
91
|
+
// Never settles: no exemplar dots, no late setState.
|
|
92
|
+
return new Promise(() => {
|
|
93
|
+
// Intentionally never settles.
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
setQueryTopNOverride: () => {
|
|
97
|
+
return undefined;
|
|
98
|
+
},
|
|
99
|
+
getQueryConfigTopNKey: (
|
|
100
|
+
_queryConfig: unknown,
|
|
101
|
+
index: number,
|
|
102
|
+
scope?: string,
|
|
103
|
+
) => {
|
|
104
|
+
return `${scope || ""}:${index}`;
|
|
105
|
+
},
|
|
106
|
+
clearQueryTopNOverridesForScope: () => {
|
|
107
|
+
return undefined;
|
|
108
|
+
},
|
|
109
|
+
serializeAttributeFiltersForKey: (attributes: unknown) => {
|
|
110
|
+
return JSON.stringify(attributes || {});
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
DEFAULT_TOP_N_SERIES: 10,
|
|
114
|
+
SHOW_ALL_SERIES_TOP_N: 10_000,
|
|
115
|
+
sanitizeAttributeFilters: (attributes: unknown) => {
|
|
116
|
+
return attributes;
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// What the drawer shows is not the point here, only whether it opened.
|
|
123
|
+
jest.mock(
|
|
124
|
+
"../../../../App/FeatureSet/Dashboard/src/Components/Telemetry/InvestigationDrawer",
|
|
125
|
+
() => {
|
|
126
|
+
return {
|
|
127
|
+
__esModule: true,
|
|
128
|
+
default: (props: { title: string }) => {
|
|
129
|
+
return <div data-testid="investigation-drawer-stub">{props.title}</div>;
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
},
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
import MetricCharts from "../../../../App/FeatureSet/Dashboard/src/Components/Metrics/MetricCharts";
|
|
136
|
+
import AggregatedResult from "../../../Types/BaseDatabase/AggregatedResult";
|
|
137
|
+
import InBetween from "../../../Types/BaseDatabase/InBetween";
|
|
138
|
+
import MetricsAggregationType from "../../../Types/Metrics/MetricsAggregationType";
|
|
139
|
+
import MetricQueryConfigData from "../../../Types/Metrics/MetricQueryConfigData";
|
|
140
|
+
import MetricViewData from "../../../Types/Metrics/MetricViewData";
|
|
141
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
142
|
+
import RangeStartAndEndDateTime from "../../../Types/Time/RangeStartAndEndDateTime";
|
|
143
|
+
import TimeRange from "../../../Types/Time/TimeRange";
|
|
144
|
+
import { DOUBLE_CLICK_DISAMBIGUATION_MS } from "../../../UI/Components/Charts/ChartLibrary/Utils/DoubleClick";
|
|
145
|
+
import {
|
|
146
|
+
TimeRangeZoomProvider,
|
|
147
|
+
TimeRangeZoomScope,
|
|
148
|
+
} from "../../../UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext";
|
|
149
|
+
import { TimeRangeZoom } from "../../../UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom";
|
|
150
|
+
import ProjectUtil from "../../../UI/Utils/Project";
|
|
151
|
+
|
|
152
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
153
|
+
"77777777-1111-4111-8111-777777777777",
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const WINDOW_START: Date = new Date("2026-08-20T10:00:00.000Z");
|
|
157
|
+
const WINDOW_END: Date = new Date("2026-08-20T10:30:00.000Z");
|
|
158
|
+
const MINUTE_MS: number = 60 * 1000;
|
|
159
|
+
|
|
160
|
+
function buildViewData(): MetricViewData {
|
|
161
|
+
return {
|
|
162
|
+
queryConfigs: [
|
|
163
|
+
{
|
|
164
|
+
metricAliasData: {
|
|
165
|
+
metricVariable: "a",
|
|
166
|
+
title: "Pod CPU Utilization",
|
|
167
|
+
description: "",
|
|
168
|
+
legend: "",
|
|
169
|
+
legendUnit: "",
|
|
170
|
+
},
|
|
171
|
+
metricQueryData: {
|
|
172
|
+
filterData: {
|
|
173
|
+
metricName: "k8s.pod.cpu.utilization",
|
|
174
|
+
attributes: {},
|
|
175
|
+
aggegationType: MetricsAggregationType.Avg,
|
|
176
|
+
},
|
|
177
|
+
groupByAttributeKeys: ["k8s.pod.name"],
|
|
178
|
+
},
|
|
179
|
+
} as unknown as MetricQueryConfigData,
|
|
180
|
+
],
|
|
181
|
+
formulaConfigs: [],
|
|
182
|
+
startAndEndDate: new InBetween<Date>(WINDOW_START, WINDOW_END),
|
|
183
|
+
} as MetricViewData;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Two pods, one point a minute across the whole window.
|
|
187
|
+
function buildResults(): Array<AggregatedResult> {
|
|
188
|
+
const data: Array<Record<string, unknown>> = [];
|
|
189
|
+
for (const pod of ["api-7d9f", "worker-5c2b"]) {
|
|
190
|
+
for (let minute: number = 0; minute < 30; minute++) {
|
|
191
|
+
data.push({
|
|
192
|
+
timestamp: new Date(WINDOW_START.getTime() + minute * MINUTE_MS),
|
|
193
|
+
value: pod === "api-7d9f" ? 40 + minute : 10 + minute,
|
|
194
|
+
attributes: { "k8s.pod.name": pod },
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return [{ data, truncated: false } as unknown as AggregatedResult];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// What the charts' host hands them, and the page around them.
|
|
202
|
+
interface ChartsHost {
|
|
203
|
+
onTimeRangeSelect?: ((startTime: Date, endTime: Date) => void) | undefined;
|
|
204
|
+
onTimeRangeReset?: (() => void) | undefined;
|
|
205
|
+
// The zoom the enclosing page offers (see TimeRangeZoomScope), if any.
|
|
206
|
+
pageZoom?: TimeRangeZoom | undefined;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function renderChartsIn(host: ChartsHost): HTMLElement {
|
|
210
|
+
const charts: React.ReactElement = (
|
|
211
|
+
<MetricCharts
|
|
212
|
+
metricViewData={buildViewData()}
|
|
213
|
+
metricResults={buildResults()}
|
|
214
|
+
metricTypes={[]}
|
|
215
|
+
onTimeRangeSelect={host.onTimeRangeSelect}
|
|
216
|
+
onTimeRangeReset={host.onTimeRangeReset}
|
|
217
|
+
/>
|
|
218
|
+
);
|
|
219
|
+
const { container } = render(
|
|
220
|
+
host.pageZoom ? (
|
|
221
|
+
<TimeRangeZoomProvider zoom={host.pageZoom}>
|
|
222
|
+
{charts}
|
|
223
|
+
</TimeRangeZoomProvider>
|
|
224
|
+
) : (
|
|
225
|
+
charts
|
|
226
|
+
),
|
|
227
|
+
);
|
|
228
|
+
return container;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function renderCharts(): HTMLElement {
|
|
232
|
+
return renderChartsIn({
|
|
233
|
+
/*
|
|
234
|
+
* As MetricView hands them over while nothing is zoomed: a drag
|
|
235
|
+
* zooms, and there is no reset, so a click is acted on at once.
|
|
236
|
+
*/
|
|
237
|
+
onTimeRangeSelect: () => {
|
|
238
|
+
return undefined;
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// A page's zoom, as TimeRangeZoomScope offers it to the charts below.
|
|
244
|
+
function pageZoomOf(isZoomed: boolean, resetZoom: () => void): TimeRangeZoom {
|
|
245
|
+
return {
|
|
246
|
+
isZoomed: isZoomed,
|
|
247
|
+
rangeBeforeZoom: isZoomed ? { range: TimeRange.PAST_ONE_HOUR } : null,
|
|
248
|
+
zoomToTimeRange: () => {
|
|
249
|
+
return undefined;
|
|
250
|
+
},
|
|
251
|
+
resetZoom: resetZoom,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// The element recharts listens on; the plot's events all reach it.
|
|
256
|
+
function plotWrapper(container: HTMLElement): Element {
|
|
257
|
+
const wrapper: Element | null = container.querySelector(".recharts-wrapper");
|
|
258
|
+
if (!wrapper) {
|
|
259
|
+
throw new Error("the chart did not render its plot");
|
|
260
|
+
}
|
|
261
|
+
return wrapper;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/*
|
|
265
|
+
* The pointer x of each bucket recharts labelled: where it drew the tick,
|
|
266
|
+
* in the whole pixels a mouse event reports in jsdom. getBoundingClientRect
|
|
267
|
+
* is all zeroes in jsdom, so recharts reads the bucket under the pointer
|
|
268
|
+
* straight off clientX.
|
|
269
|
+
*/
|
|
270
|
+
function tickXs(container: HTMLElement): Array<number> {
|
|
271
|
+
const xs: Array<number> = Array.from(
|
|
272
|
+
container.querySelectorAll(
|
|
273
|
+
".recharts-xAxis-tick-labels text.recharts-cartesian-axis-tick-value",
|
|
274
|
+
),
|
|
275
|
+
).map((tick: Element): number => {
|
|
276
|
+
return Math.round(Number(tick.getAttribute("x")));
|
|
277
|
+
});
|
|
278
|
+
if (xs.length < 4) {
|
|
279
|
+
throw new Error("the chart did not render its plot");
|
|
280
|
+
}
|
|
281
|
+
return xs;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
interface PlotSpot {
|
|
285
|
+
clientX: number;
|
|
286
|
+
clientY: number;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Where the clicks below land: over the plot's second labelled bucket.
|
|
290
|
+
function plotSpot(container: HTMLElement): PlotSpot {
|
|
291
|
+
return { clientX: tickXs(container)[1]!, clientY: 60 };
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// A lone click on the plot, as the browser delivers it.
|
|
295
|
+
function clickPlotOnce(container: HTMLElement): PlotSpot {
|
|
296
|
+
const wrapper: Element = plotWrapper(container);
|
|
297
|
+
const at: PlotSpot = plotSpot(container);
|
|
298
|
+
|
|
299
|
+
fireEvent.mouseMove(wrapper, at);
|
|
300
|
+
fireEvent.mouseDown(wrapper, { ...at, button: 0, detail: 1 });
|
|
301
|
+
fireEvent.mouseUp(wrapper, { ...at, button: 0, detail: 1 });
|
|
302
|
+
fireEvent.click(wrapper, { ...at, button: 0, detail: 1 });
|
|
303
|
+
|
|
304
|
+
return at;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/*
|
|
308
|
+
* The first click of a double-click on the plot: it opens the inspector,
|
|
309
|
+
* as a lone click does.
|
|
310
|
+
*/
|
|
311
|
+
function clickPlot(container: HTMLElement): HTMLElement {
|
|
312
|
+
clickPlotOnce(container);
|
|
313
|
+
|
|
314
|
+
return screen.getByRole("dialog", { name: /^Values at/ });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/*
|
|
318
|
+
* The first click of a SLOW double-click on a zoomed chart. The chart holds
|
|
319
|
+
* it back, waiting for a second one, and acts on it as a bucket click once
|
|
320
|
+
* DOUBLE_CLICK_DISAMBIGUATION_MS pass: the inspector opens at the pointer,
|
|
321
|
+
* before the second press comes down there.
|
|
322
|
+
*/
|
|
323
|
+
function clickPlotSlowly(container: HTMLElement): HTMLElement {
|
|
324
|
+
clickPlotOnce(container);
|
|
325
|
+
act(() => {
|
|
326
|
+
jest.advanceTimersByTime(DOUBLE_CLICK_DISAMBIGUATION_MS);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
return screen.getByRole("dialog", { name: /^Values at/ });
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/*
|
|
333
|
+
* The release of a press whose inspector went away under it: it lands on
|
|
334
|
+
* the plot the inspector covered. The browser follows it with no click
|
|
335
|
+
* and no dblclick, as the node the press landed on is gone.
|
|
336
|
+
*/
|
|
337
|
+
function releaseOnPlot(container: HTMLElement, clickCount: number): void {
|
|
338
|
+
fireEvent.mouseUp(plotWrapper(container), {
|
|
339
|
+
...plotSpot(container),
|
|
340
|
+
button: 0,
|
|
341
|
+
detail: clickCount,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Long enough for anything a chart holds back or arms to have run.
|
|
346
|
+
function letTimePass(): void {
|
|
347
|
+
act(() => {
|
|
348
|
+
jest.advanceTimersByTime(DOUBLE_CLICK_DISAMBIGUATION_MS * 4);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function queryInspector(): HTMLElement | null {
|
|
353
|
+
return screen.queryByRole("dialog", { name: /^Values at/ });
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function drawerOpened(): boolean {
|
|
357
|
+
return screen.queryByTestId("investigation-drawer-stub") !== null;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
interface InspectorParts {
|
|
361
|
+
title: HTMLElement;
|
|
362
|
+
window: HTMLElement;
|
|
363
|
+
rowNumber: HTMLElement;
|
|
364
|
+
seriesName: HTMLElement;
|
|
365
|
+
value: HTMLElement;
|
|
366
|
+
close: HTMLElement;
|
|
367
|
+
investigate: HTMLElement;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function partsOf(inspector: HTMLElement): InspectorParts {
|
|
371
|
+
const paragraphs: Array<HTMLElement> = Array.from(
|
|
372
|
+
inspector.querySelectorAll("p"),
|
|
373
|
+
);
|
|
374
|
+
const rowNumber: HTMLElement | undefined = Array.from(
|
|
375
|
+
inspector.querySelectorAll("span"),
|
|
376
|
+
).find((span: HTMLElement): boolean => {
|
|
377
|
+
return span.textContent === "1.";
|
|
378
|
+
});
|
|
379
|
+
const seriesName: HTMLElement | undefined = rowNumber?.parentElement as
|
|
380
|
+
| HTMLElement
|
|
381
|
+
| undefined;
|
|
382
|
+
const value: HTMLElement | undefined = seriesName?.nextElementSibling as
|
|
383
|
+
| HTMLElement
|
|
384
|
+
| undefined;
|
|
385
|
+
const buttons: Array<HTMLElement> = Array.from(
|
|
386
|
+
inspector.querySelectorAll("button"),
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
if (
|
|
390
|
+
paragraphs.length < 2 ||
|
|
391
|
+
!rowNumber ||
|
|
392
|
+
!seriesName ||
|
|
393
|
+
!value ||
|
|
394
|
+
buttons.length !== 2
|
|
395
|
+
) {
|
|
396
|
+
throw new Error("the inspector is not laid out as expected");
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return {
|
|
400
|
+
title: paragraphs[0]!,
|
|
401
|
+
window: paragraphs[1]!,
|
|
402
|
+
rowNumber: rowNumber,
|
|
403
|
+
seriesName: seriesName,
|
|
404
|
+
value: value,
|
|
405
|
+
close: buttons[0]!,
|
|
406
|
+
investigate: buttons[1]!,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Every part of the inspector the rest of a double-click can land on.
|
|
411
|
+
const INSPECTOR_PART_NAMES: Array<[string, keyof InspectorParts]> = [
|
|
412
|
+
["the title", "title"],
|
|
413
|
+
["the bucket's window", "window"],
|
|
414
|
+
["a row number", "rowNumber"],
|
|
415
|
+
["a series name", "seriesName"],
|
|
416
|
+
["a value", "value"],
|
|
417
|
+
["the Close button", "close"],
|
|
418
|
+
["the Investigate button", "investigate"],
|
|
419
|
+
];
|
|
420
|
+
|
|
421
|
+
// A press; false when something prevented its default (no selection).
|
|
422
|
+
function press(target: HTMLElement, clickCount: number): boolean {
|
|
423
|
+
return fireEvent.mouseDown(target, { button: 0, detail: clickCount });
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// A whole press-release-click at one spot, counted as `clickCount`.
|
|
427
|
+
function pressAndClick(target: HTMLElement, clickCount: number): void {
|
|
428
|
+
press(target, clickCount);
|
|
429
|
+
fireEvent.mouseUp(target, { button: 0, detail: clickCount });
|
|
430
|
+
fireEvent.click(target, { button: 0, detail: clickCount });
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
beforeEach(() => {
|
|
434
|
+
fetchExemplarsMock.mockReset();
|
|
435
|
+
jest.spyOn(ProjectUtil, "getCurrentProjectId").mockReturnValue(PROJECT_ID);
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
afterEach(() => {
|
|
439
|
+
jest.restoreAllMocks();
|
|
440
|
+
cleanup();
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
describe("the bucket inspector a click on an unzoomed chart opens", () => {
|
|
444
|
+
test("a lone click on the plot opens it, with the chart's title, the bucket's window and each series' value", () => {
|
|
445
|
+
const container: HTMLElement = renderCharts();
|
|
446
|
+
|
|
447
|
+
const inspector: HTMLElement = clickPlot(container);
|
|
448
|
+
const parts: InspectorParts = partsOf(inspector);
|
|
449
|
+
|
|
450
|
+
expect(parts.title).toHaveTextContent("Pod CPU Utilization");
|
|
451
|
+
expect(parts.window.textContent).toMatch(/\S/);
|
|
452
|
+
expect(parts.seriesName.textContent).toContain("api-7d9f");
|
|
453
|
+
expect(parts.investigate).toHaveTextContent("Investigate this moment");
|
|
454
|
+
expect(drawerOpened()).toBe(false);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
test.each(INSPECTOR_PART_NAMES)(
|
|
458
|
+
"the second press of the double-click that opened it selects no word of %s",
|
|
459
|
+
(_label: string, part: string) => {
|
|
460
|
+
const container: HTMLElement = renderCharts();
|
|
461
|
+
const parts: InspectorParts = partsOf(clickPlot(container));
|
|
462
|
+
|
|
463
|
+
const target: HTMLElement = parts[part as keyof InspectorParts];
|
|
464
|
+
|
|
465
|
+
// Its default is a word selection: prevented.
|
|
466
|
+
expect(press(target, 2)).toBe(false);
|
|
467
|
+
},
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
test("the rest of that double-click presses no button: Investigate this moment opens no drawer", () => {
|
|
471
|
+
const container: HTMLElement = renderCharts();
|
|
472
|
+
const parts: InspectorParts = partsOf(clickPlot(container));
|
|
473
|
+
|
|
474
|
+
pressAndClick(parts.investigate, 2);
|
|
475
|
+
fireEvent.doubleClick(parts.investigate, { button: 0, detail: 2 });
|
|
476
|
+
|
|
477
|
+
expect(drawerOpened()).toBe(false);
|
|
478
|
+
// The inspector the first click opened is still there to use.
|
|
479
|
+
expect(queryInspector()).toBe(parts.investigate.closest('[role="dialog"]'));
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
test("...and Close does not close the inspector the first click opened", () => {
|
|
483
|
+
const container: HTMLElement = renderCharts();
|
|
484
|
+
const parts: InspectorParts = partsOf(clickPlot(container));
|
|
485
|
+
|
|
486
|
+
pressAndClick(parts.close, 2);
|
|
487
|
+
|
|
488
|
+
expect(queryInspector()).not.toBeNull();
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
test("a triple-click's third press and click are ignored the same way", () => {
|
|
492
|
+
const container: HTMLElement = renderCharts();
|
|
493
|
+
const parts: InspectorParts = partsOf(clickPlot(container));
|
|
494
|
+
|
|
495
|
+
pressAndClick(parts.investigate, 2);
|
|
496
|
+
expect(press(parts.investigate, 3)).toBe(false);
|
|
497
|
+
fireEvent.mouseUp(parts.investigate, { button: 0, detail: 3 });
|
|
498
|
+
fireEvent.click(parts.investigate, { button: 0, detail: 3 });
|
|
499
|
+
|
|
500
|
+
expect(drawerOpened()).toBe(false);
|
|
501
|
+
expect(queryInspector()).not.toBeNull();
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
test("once pressed afresh it is an ordinary card: a double-click may select a value's word", () => {
|
|
505
|
+
const container: HTMLElement = renderCharts();
|
|
506
|
+
const parts: InspectorParts = partsOf(clickPlot(container));
|
|
507
|
+
|
|
508
|
+
expect(press(parts.seriesName, 1)).toBe(true);
|
|
509
|
+
expect(press(parts.seriesName, 2)).toBe(true);
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
test("once pressed afresh, a click presses its button: Investigate this moment opens the drawer", () => {
|
|
513
|
+
const container: HTMLElement = renderCharts();
|
|
514
|
+
const parts: InspectorParts = partsOf(clickPlot(container));
|
|
515
|
+
|
|
516
|
+
pressAndClick(parts.investigate, 1);
|
|
517
|
+
|
|
518
|
+
expect(drawerOpened()).toBe(true);
|
|
519
|
+
expect(screen.getByTestId("investigation-drawer-stub")).toHaveTextContent(
|
|
520
|
+
"Pod CPU Utilization",
|
|
521
|
+
);
|
|
522
|
+
expect(queryInspector()).toBeNull();
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
test("once pressed afresh, Close closes it", () => {
|
|
526
|
+
const container: HTMLElement = renderCharts();
|
|
527
|
+
const parts: InspectorParts = partsOf(clickPlot(container));
|
|
528
|
+
|
|
529
|
+
pressAndClick(parts.close, 1);
|
|
530
|
+
|
|
531
|
+
expect(queryInspector()).toBeNull();
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
test("a button pressed from the keyboard (a click counted 0) works with no press at all", () => {
|
|
535
|
+
const container: HTMLElement = renderCharts();
|
|
536
|
+
const parts: InspectorParts = partsOf(clickPlot(container));
|
|
537
|
+
|
|
538
|
+
fireEvent.click(parts.investigate, { detail: 0 });
|
|
539
|
+
|
|
540
|
+
expect(drawerOpened()).toBe(true);
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
test("each opening starts over: a press on the last inspector lets no later double-click through", () => {
|
|
544
|
+
const container: HTMLElement = renderCharts();
|
|
545
|
+
const first: InspectorParts = partsOf(clickPlot(container));
|
|
546
|
+
|
|
547
|
+
// Used, then closed.
|
|
548
|
+
expect(press(first.seriesName, 1)).toBe(true);
|
|
549
|
+
pressAndClick(first.close, 1);
|
|
550
|
+
expect(queryInspector()).toBeNull();
|
|
551
|
+
|
|
552
|
+
// A later double-click opens a new one, whose rest is ignored again.
|
|
553
|
+
const second: InspectorParts = partsOf(clickPlot(container));
|
|
554
|
+
expect(press(second.title, 2)).toBe(false);
|
|
555
|
+
pressAndClick(second.investigate, 2);
|
|
556
|
+
expect(drawerOpened()).toBe(false);
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
test("its chrome is not selectable; the window, the series names and the values are", () => {
|
|
560
|
+
const container: HTMLElement = renderCharts();
|
|
561
|
+
const inspector: HTMLElement = clickPlot(container);
|
|
562
|
+
const parts: InspectorParts = partsOf(inspector);
|
|
563
|
+
|
|
564
|
+
expect(inspector).toHaveClass("select-none");
|
|
565
|
+
for (const chrome of [
|
|
566
|
+
parts.title,
|
|
567
|
+
parts.close,
|
|
568
|
+
parts.investigate,
|
|
569
|
+
] as Array<HTMLElement>) {
|
|
570
|
+
expect(chrome).not.toHaveClass("select-text");
|
|
571
|
+
}
|
|
572
|
+
// The row number sits inside the selectable name, so it opts out.
|
|
573
|
+
expect(parts.rowNumber).toHaveClass("select-none");
|
|
574
|
+
|
|
575
|
+
for (const value of [
|
|
576
|
+
parts.window,
|
|
577
|
+
parts.seriesName,
|
|
578
|
+
parts.value,
|
|
579
|
+
] as Array<HTMLElement>) {
|
|
580
|
+
expect(value).toHaveClass("select-text");
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
// The charts, and the reset they offer while zoomed.
|
|
586
|
+
interface ZoomedCharts {
|
|
587
|
+
container: HTMLElement;
|
|
588
|
+
reset: MockFunction;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
interface ZoomedHost {
|
|
592
|
+
name: string;
|
|
593
|
+
render: () => ZoomedCharts;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/*
|
|
597
|
+
* The two ways charts end up offering a reset, resolved as the charts
|
|
598
|
+
* resolve theirs (resolveChartTimeRangeZoom).
|
|
599
|
+
*/
|
|
600
|
+
const ZOOMED_HOSTS: Array<ZoomedHost> = [
|
|
601
|
+
{
|
|
602
|
+
name: "the host's reset (as MetricView hands one over while zoomed)",
|
|
603
|
+
render: (): ZoomedCharts => {
|
|
604
|
+
const reset: MockFunction = getJestMockFunction();
|
|
605
|
+
const container: HTMLElement = renderChartsIn({
|
|
606
|
+
onTimeRangeSelect: getJestMockFunction(),
|
|
607
|
+
onTimeRangeReset: reset,
|
|
608
|
+
});
|
|
609
|
+
return { container: container, reset: reset };
|
|
610
|
+
},
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
name: "the page's reset (a zoomed page around charts handed no zoom of their own)",
|
|
614
|
+
render: (): ZoomedCharts => {
|
|
615
|
+
const reset: MockFunction = getJestMockFunction();
|
|
616
|
+
const container: HTMLElement = renderChartsIn({
|
|
617
|
+
pageZoom: pageZoomOf(true, reset),
|
|
618
|
+
});
|
|
619
|
+
return { container: container, reset: reset };
|
|
620
|
+
},
|
|
621
|
+
},
|
|
622
|
+
];
|
|
623
|
+
|
|
624
|
+
// The range the page below shows before any zoom: the charts' window.
|
|
625
|
+
const PAGE_RANGE: RangeStartAndEndDateTime = {
|
|
626
|
+
range: TimeRange.CUSTOM,
|
|
627
|
+
startAndEndDate: new InBetween<Date>(WINDOW_START, WINDOW_END),
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
interface ZoomablePageProps {
|
|
631
|
+
onTimeRangeChange: (timeRange: RangeStartAndEndDateTime) => void;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/*
|
|
635
|
+
* A page with page-wide drag-to-zoom (TimeRangeZoomScope) around charts
|
|
636
|
+
* handed no zoom of their own: a drag on a chart retimes the page.
|
|
637
|
+
*/
|
|
638
|
+
function ZoomablePage(props: ZoomablePageProps): React.ReactElement {
|
|
639
|
+
const [timeRange, setTimeRange] =
|
|
640
|
+
React.useState<RangeStartAndEndDateTime>(PAGE_RANGE);
|
|
641
|
+
|
|
642
|
+
return (
|
|
643
|
+
<TimeRangeZoomScope
|
|
644
|
+
timeRange={timeRange}
|
|
645
|
+
onTimeRangeChange={(next: RangeStartAndEndDateTime) => {
|
|
646
|
+
props.onTimeRangeChange(next);
|
|
647
|
+
setTimeRange(next);
|
|
648
|
+
}}
|
|
649
|
+
>
|
|
650
|
+
<MetricCharts
|
|
651
|
+
metricViewData={buildViewData()}
|
|
652
|
+
metricResults={buildResults()}
|
|
653
|
+
metricTypes={[]}
|
|
654
|
+
/>
|
|
655
|
+
</TimeRangeZoomScope>
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// A drag across the plot, from its second labelled bucket to its fourth.
|
|
660
|
+
function dragAcrossPlot(container: HTMLElement): void {
|
|
661
|
+
const wrapper: Element = plotWrapper(container);
|
|
662
|
+
const xs: Array<number> = tickXs(container);
|
|
663
|
+
const from: PlotSpot = { clientX: xs[1]!, clientY: 60 };
|
|
664
|
+
const to: PlotSpot = { clientX: xs[3]!, clientY: 60 };
|
|
665
|
+
|
|
666
|
+
fireEvent.mouseMove(wrapper, { ...from, buttons: 0 });
|
|
667
|
+
fireEvent.mouseDown(wrapper, { ...from, button: 0, buttons: 1, detail: 1 });
|
|
668
|
+
fireEvent.mouseMove(wrapper, { ...to, buttons: 1 });
|
|
669
|
+
fireEvent.mouseUp(wrapper, { ...to, button: 0, buttons: 0, detail: 1 });
|
|
670
|
+
fireEvent.click(wrapper, { ...to, button: 0, detail: 1 });
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
describe("the rest of a slow double-click on a zoomed chart, landing on the inspector its first click opened (issue #4116)", () => {
|
|
674
|
+
beforeEach(() => {
|
|
675
|
+
jest.useFakeTimers();
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
afterEach(() => {
|
|
679
|
+
cleanup();
|
|
680
|
+
jest.useRealTimers();
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
for (const host of ZOOMED_HOSTS) {
|
|
684
|
+
describe(`with ${host.name}`, () => {
|
|
685
|
+
test("the chart holds the first click back, then opens the inspector under the pointer", () => {
|
|
686
|
+
const charts: ZoomedCharts = host.render();
|
|
687
|
+
|
|
688
|
+
const pointer: PlotSpot = clickPlotOnce(charts.container);
|
|
689
|
+
|
|
690
|
+
// Waiting to see whether a second click comes.
|
|
691
|
+
act(() => {
|
|
692
|
+
jest.advanceTimersByTime(DOUBLE_CLICK_DISAMBIGUATION_MS - 1);
|
|
693
|
+
});
|
|
694
|
+
expect(queryInspector()).toBeNull();
|
|
695
|
+
|
|
696
|
+
act(() => {
|
|
697
|
+
jest.advanceTimersByTime(1);
|
|
698
|
+
});
|
|
699
|
+
const inspector: HTMLElement = screen.getByRole("dialog", {
|
|
700
|
+
name: /^Values at/,
|
|
701
|
+
});
|
|
702
|
+
// Where the second press of a slow double-click comes down.
|
|
703
|
+
expect(inspector.style.left).toBe(`${pointer.clientX}px`);
|
|
704
|
+
expect(inspector.style.top).toBe(`${pointer.clientY}px`);
|
|
705
|
+
expect(charts.reset).not.toHaveBeenCalled();
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
test.each(INSPECTOR_PART_NAMES)(
|
|
709
|
+
"the second press, landing on %s, closes the inspector and resets the zoom, once",
|
|
710
|
+
(_label: string, part: keyof InspectorParts) => {
|
|
711
|
+
const charts: ZoomedCharts = host.render();
|
|
712
|
+
const parts: InspectorParts = partsOf(
|
|
713
|
+
clickPlotSlowly(charts.container),
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
// Still no word selection on the inspector.
|
|
717
|
+
expect(press(parts[part], 2)).toBe(false);
|
|
718
|
+
|
|
719
|
+
expect(queryInspector()).toBeNull();
|
|
720
|
+
expect(charts.reset).toHaveBeenCalledTimes(1);
|
|
721
|
+
|
|
722
|
+
// Its release, on the plot the inspector covered, adds nothing.
|
|
723
|
+
releaseOnPlot(charts.container, 2);
|
|
724
|
+
letTimePass();
|
|
725
|
+
|
|
726
|
+
expect(charts.reset).toHaveBeenCalledTimes(1);
|
|
727
|
+
expect(queryInspector()).toBeNull();
|
|
728
|
+
expect(drawerOpened()).toBe(false);
|
|
729
|
+
},
|
|
730
|
+
);
|
|
731
|
+
|
|
732
|
+
test("...and presses no button: Investigate this moment opens no drawer", () => {
|
|
733
|
+
const charts: ZoomedCharts = host.render();
|
|
734
|
+
const parts: InspectorParts = partsOf(
|
|
735
|
+
clickPlotSlowly(charts.container),
|
|
736
|
+
);
|
|
737
|
+
|
|
738
|
+
/*
|
|
739
|
+
* Even were the rest of that double-click - its release, click and
|
|
740
|
+
* dblclick - delivered to the button the press landed on.
|
|
741
|
+
*/
|
|
742
|
+
pressAndClick(parts.investigate, 2);
|
|
743
|
+
fireEvent.doubleClick(parts.investigate, { button: 0, detail: 2 });
|
|
744
|
+
letTimePass();
|
|
745
|
+
|
|
746
|
+
expect(drawerOpened()).toBe(false);
|
|
747
|
+
expect(queryInspector()).toBeNull();
|
|
748
|
+
expect(charts.reset).toHaveBeenCalledTimes(1);
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
test("a double-click of its own, after a press of its own, resets nothing: it may select a word", () => {
|
|
752
|
+
const charts: ZoomedCharts = host.render();
|
|
753
|
+
const parts: InspectorParts = partsOf(
|
|
754
|
+
clickPlotSlowly(charts.container),
|
|
755
|
+
);
|
|
756
|
+
|
|
757
|
+
// A click of its own: counted afresh...
|
|
758
|
+
expect(press(parts.seriesName, 1)).toBe(true);
|
|
759
|
+
fireEvent.mouseUp(parts.seriesName, { button: 0, detail: 1 });
|
|
760
|
+
fireEvent.click(parts.seriesName, { button: 0, detail: 1 });
|
|
761
|
+
// ...and the second press of a double-click inside the inspector.
|
|
762
|
+
expect(press(parts.seriesName, 2)).toBe(true);
|
|
763
|
+
fireEvent.mouseUp(parts.seriesName, { button: 0, detail: 2 });
|
|
764
|
+
fireEvent.click(parts.seriesName, { button: 0, detail: 2 });
|
|
765
|
+
fireEvent.doubleClick(parts.seriesName, { button: 0, detail: 2 });
|
|
766
|
+
letTimePass();
|
|
767
|
+
|
|
768
|
+
expect(charts.reset).not.toHaveBeenCalled();
|
|
769
|
+
expect(queryInspector()).not.toBeNull();
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
test("a triple-click's third press on it resets nothing: only a double-click's second press does", () => {
|
|
773
|
+
const charts: ZoomedCharts = host.render();
|
|
774
|
+
const parts: InspectorParts = partsOf(
|
|
775
|
+
clickPlotSlowly(charts.container),
|
|
776
|
+
);
|
|
777
|
+
|
|
778
|
+
// Still the rest of a click sequence: no word selected...
|
|
779
|
+
expect(press(parts.investigate, 3)).toBe(false);
|
|
780
|
+
fireEvent.mouseUp(parts.investigate, { button: 0, detail: 3 });
|
|
781
|
+
fireEvent.click(parts.investigate, { button: 0, detail: 3 });
|
|
782
|
+
letTimePass();
|
|
783
|
+
|
|
784
|
+
// ...no button pressed, and no reset: the inspector stays.
|
|
785
|
+
expect(drawerOpened()).toBe(false);
|
|
786
|
+
expect(charts.reset).not.toHaveBeenCalled();
|
|
787
|
+
expect(queryInspector()).not.toBeNull();
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
/*
|
|
791
|
+
* The browser counts presses of any button, but only the main
|
|
792
|
+
* button's second press is a double-click's, as on the charts
|
|
793
|
+
* (isSecondPressOfDoubleClick): a right-button one opens a context
|
|
794
|
+
* menu. Before commit b6ec899df4 it closed the inspector and reset
|
|
795
|
+
* the zoom.
|
|
796
|
+
*/
|
|
797
|
+
test.each(INSPECTOR_PART_NAMES)(
|
|
798
|
+
"a right-button press counted 2, landing on %s, resets nothing and closes nothing, and still selects no word",
|
|
799
|
+
(_label: string, part: keyof InspectorParts) => {
|
|
800
|
+
const charts: ZoomedCharts = host.render();
|
|
801
|
+
const parts: InspectorParts = partsOf(
|
|
802
|
+
clickPlotSlowly(charts.container),
|
|
803
|
+
);
|
|
804
|
+
|
|
805
|
+
expect(
|
|
806
|
+
fireEvent.mouseDown(parts[part], { button: 2, detail: 2 }),
|
|
807
|
+
).toBe(false);
|
|
808
|
+
|
|
809
|
+
expect(queryInspector()).not.toBeNull();
|
|
810
|
+
expect(charts.reset).not.toHaveBeenCalled();
|
|
811
|
+
|
|
812
|
+
fireEvent.mouseUp(parts[part], { button: 2, detail: 2 });
|
|
813
|
+
fireEvent.contextMenu(parts[part], { button: 2 });
|
|
814
|
+
letTimePass();
|
|
815
|
+
|
|
816
|
+
expect(charts.reset).not.toHaveBeenCalled();
|
|
817
|
+
expect(queryInspector()).not.toBeNull();
|
|
818
|
+
expect(drawerOpened()).toBe(false);
|
|
819
|
+
},
|
|
820
|
+
);
|
|
821
|
+
|
|
822
|
+
test("a middle-button press counted 2 on it resets nothing and closes nothing either", () => {
|
|
823
|
+
const charts: ZoomedCharts = host.render();
|
|
824
|
+
const parts: InspectorParts = partsOf(
|
|
825
|
+
clickPlotSlowly(charts.container),
|
|
826
|
+
);
|
|
827
|
+
|
|
828
|
+
expect(fireEvent.mouseDown(parts.title, { button: 1, detail: 2 })).toBe(
|
|
829
|
+
false,
|
|
830
|
+
);
|
|
831
|
+
fireEvent.mouseUp(parts.title, { button: 1, detail: 2 });
|
|
832
|
+
letTimePass();
|
|
833
|
+
|
|
834
|
+
expect(charts.reset).not.toHaveBeenCalled();
|
|
835
|
+
expect(queryInspector()).not.toBeNull();
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
test("once pressed afresh, its buttons work and reset nothing: Investigate this moment opens the drawer", () => {
|
|
839
|
+
const charts: ZoomedCharts = host.render();
|
|
840
|
+
const parts: InspectorParts = partsOf(
|
|
841
|
+
clickPlotSlowly(charts.container),
|
|
842
|
+
);
|
|
843
|
+
|
|
844
|
+
pressAndClick(parts.investigate, 1);
|
|
845
|
+
letTimePass();
|
|
846
|
+
|
|
847
|
+
expect(drawerOpened()).toBe(true);
|
|
848
|
+
expect(queryInspector()).toBeNull();
|
|
849
|
+
expect(charts.reset).not.toHaveBeenCalled();
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
test("...and Close closes it, resetting nothing", () => {
|
|
853
|
+
const charts: ZoomedCharts = host.render();
|
|
854
|
+
const parts: InspectorParts = partsOf(
|
|
855
|
+
clickPlotSlowly(charts.container),
|
|
856
|
+
);
|
|
857
|
+
|
|
858
|
+
pressAndClick(parts.close, 1);
|
|
859
|
+
letTimePass();
|
|
860
|
+
|
|
861
|
+
expect(queryInspector()).toBeNull();
|
|
862
|
+
expect(drawerOpened()).toBe(false);
|
|
863
|
+
expect(charts.reset).not.toHaveBeenCalled();
|
|
864
|
+
});
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
test("the host's reset wins over the page's, as it does for the charts", () => {
|
|
869
|
+
const hostReset: MockFunction = getJestMockFunction();
|
|
870
|
+
const pageReset: MockFunction = getJestMockFunction();
|
|
871
|
+
const container: HTMLElement = renderChartsIn({
|
|
872
|
+
onTimeRangeSelect: getJestMockFunction(),
|
|
873
|
+
onTimeRangeReset: hostReset,
|
|
874
|
+
pageZoom: pageZoomOf(true, pageReset),
|
|
875
|
+
});
|
|
876
|
+
const parts: InspectorParts = partsOf(clickPlotSlowly(container));
|
|
877
|
+
|
|
878
|
+
expect(press(parts.title, 2)).toBe(false);
|
|
879
|
+
|
|
880
|
+
expect(hostReset).toHaveBeenCalledTimes(1);
|
|
881
|
+
expect(pageReset).not.toHaveBeenCalled();
|
|
882
|
+
expect(queryInspector()).toBeNull();
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
test("a page zoomed by a drag on the chart itself is put back on the range it had", () => {
|
|
886
|
+
const onTimeRangeChange: MockFunction = getJestMockFunction();
|
|
887
|
+
const { container } = render(
|
|
888
|
+
<ZoomablePage onTimeRangeChange={onTimeRangeChange} />,
|
|
889
|
+
);
|
|
890
|
+
|
|
891
|
+
// A drag across the plot zooms the page...
|
|
892
|
+
dragAcrossPlot(container);
|
|
893
|
+
expect(onTimeRangeChange).toHaveBeenCalledTimes(1);
|
|
894
|
+
expect(
|
|
895
|
+
(onTimeRangeChange.mock.calls[0]![0] as RangeStartAndEndDateTime).range,
|
|
896
|
+
).toBe(TimeRange.CUSTOM);
|
|
897
|
+
expect(
|
|
898
|
+
screen.getByText("Drag to zoom · double-click to reset"),
|
|
899
|
+
).toBeInTheDocument();
|
|
900
|
+
// ...and the reader looks at it for a moment.
|
|
901
|
+
letTimePass();
|
|
902
|
+
|
|
903
|
+
// The slow double-click.
|
|
904
|
+
const parts: InspectorParts = partsOf(clickPlotSlowly(container));
|
|
905
|
+
expect(press(parts.title, 2)).toBe(false);
|
|
906
|
+
releaseOnPlot(container, 2);
|
|
907
|
+
letTimePass();
|
|
908
|
+
|
|
909
|
+
expect(queryInspector()).toBeNull();
|
|
910
|
+
expect(onTimeRangeChange).toHaveBeenCalledTimes(2);
|
|
911
|
+
expect(onTimeRangeChange).toHaveBeenLastCalledWith(PAGE_RANGE);
|
|
912
|
+
expect(screen.getByText("Drag to zoom")).toBeInTheDocument();
|
|
913
|
+
|
|
914
|
+
// Nothing left to reset: a click is acted on at once again.
|
|
915
|
+
clickPlotOnce(container);
|
|
916
|
+
expect(queryInspector()).not.toBeNull();
|
|
917
|
+
});
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
// The charts with no reset on offer, and every handler the press must leave be.
|
|
921
|
+
interface UnzoomedCharts {
|
|
922
|
+
container: HTMLElement;
|
|
923
|
+
handlers: Array<MockFunction>;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
interface UnzoomedHost {
|
|
927
|
+
name: string;
|
|
928
|
+
render: () => UnzoomedCharts;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
const UNZOOMED_HOSTS: Array<UnzoomedHost> = [
|
|
932
|
+
{
|
|
933
|
+
name: "a host with nothing to reset yet",
|
|
934
|
+
render: (): UnzoomedCharts => {
|
|
935
|
+
const onTimeRangeSelect: MockFunction = getJestMockFunction();
|
|
936
|
+
const container: HTMLElement = renderChartsIn({
|
|
937
|
+
onTimeRangeSelect: onTimeRangeSelect,
|
|
938
|
+
});
|
|
939
|
+
return { container: container, handlers: [onTimeRangeSelect] };
|
|
940
|
+
},
|
|
941
|
+
},
|
|
942
|
+
{
|
|
943
|
+
name: "a page that is not zoomed",
|
|
944
|
+
render: (): UnzoomedCharts => {
|
|
945
|
+
const resetZoom: MockFunction = getJestMockFunction();
|
|
946
|
+
const container: HTMLElement = renderChartsIn({
|
|
947
|
+
pageZoom: pageZoomOf(false, resetZoom),
|
|
948
|
+
});
|
|
949
|
+
return { container: container, handlers: [resetZoom] };
|
|
950
|
+
},
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
/*
|
|
954
|
+
* A host that zooms its own way resets its own way: the charts do not
|
|
955
|
+
* borrow the page's reset, and neither does the inspector.
|
|
956
|
+
*/
|
|
957
|
+
name: "a host with nothing to reset, on a zoomed page",
|
|
958
|
+
render: (): UnzoomedCharts => {
|
|
959
|
+
const onTimeRangeSelect: MockFunction = getJestMockFunction();
|
|
960
|
+
const resetZoom: MockFunction = getJestMockFunction();
|
|
961
|
+
const container: HTMLElement = renderChartsIn({
|
|
962
|
+
onTimeRangeSelect: onTimeRangeSelect,
|
|
963
|
+
pageZoom: pageZoomOf(true, resetZoom),
|
|
964
|
+
});
|
|
965
|
+
return {
|
|
966
|
+
container: container,
|
|
967
|
+
handlers: [onTimeRangeSelect, resetZoom],
|
|
968
|
+
};
|
|
969
|
+
},
|
|
970
|
+
},
|
|
971
|
+
];
|
|
972
|
+
|
|
973
|
+
describe("the rest of a double-click on a chart with no zoom to reset", () => {
|
|
974
|
+
beforeEach(() => {
|
|
975
|
+
jest.useFakeTimers();
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
afterEach(() => {
|
|
979
|
+
cleanup();
|
|
980
|
+
jest.useRealTimers();
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
for (const host of UNZOOMED_HOSTS) {
|
|
984
|
+
test(`with ${host.name}, is still only swallowed: the inspector stays, nothing is reset`, () => {
|
|
985
|
+
const charts: UnzoomedCharts = host.render();
|
|
986
|
+
|
|
987
|
+
// Nothing to wait for: the first click opens the inspector at once.
|
|
988
|
+
const parts: InspectorParts = partsOf(clickPlot(charts.container));
|
|
989
|
+
|
|
990
|
+
expect(press(parts.title, 2)).toBe(false);
|
|
991
|
+
fireEvent.mouseUp(parts.title, { button: 0, detail: 2 });
|
|
992
|
+
fireEvent.click(parts.title, { button: 0, detail: 2 });
|
|
993
|
+
letTimePass();
|
|
994
|
+
|
|
995
|
+
expect(queryInspector()).not.toBeNull();
|
|
996
|
+
for (const handler of charts.handlers) {
|
|
997
|
+
expect(handler).not.toHaveBeenCalled();
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
});
|