@oneuptime/common 12.0.5 → 12.0.6
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/AIRun.ts +33 -0
- package/Models/DatabaseModels/DataSource.ts +744 -0
- package/Models/DatabaseModels/Index.ts +3 -0
- package/Models/DatabaseModels/ProjectCallSMSConfig.ts +10 -2
- package/Models/DatabaseModels/User.ts +2 -0
- package/Models/DatabaseModels/UserOnCallLog.ts +2 -0
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +2 -0
- package/Models/DatabaseModels/UserSession.ts +2 -0
- package/Models/DatabaseModels/UserTotpAuth.ts +6 -4
- package/Models/DatabaseModels/UserWebAuthn.ts +5 -3
- package/Server/API/AIInsightAPI.ts +47 -4
- package/Server/API/AIInvestigationAPI.ts +25 -0
- package/Server/API/DashboardAPI.ts +176 -492
- package/Server/API/DataSourceAPI.ts +268 -0
- package/Server/API/StatusPageAPI.ts +11 -1
- package/Server/API/UserAPI.ts +119 -0
- package/Server/Infrastructure/ClickhouseConfig.ts +59 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.ts +39 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.ts +24 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.ts +76 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Infrastructure/Queue.ts +26 -0
- package/Server/Infrastructure/QueueWorker.ts +17 -0
- package/Server/Middleware/TelemetryIngest.ts +8 -3
- package/Server/Services/AIInsightService.ts +132 -12
- package/Server/Services/AIRunService.ts +34 -0
- package/Server/Services/AIService.ts +17 -2
- package/Server/Services/AlertService.ts +38 -32
- package/Server/Services/AnalyticsDatabaseService.ts +8 -4
- package/Server/Services/DataSourceService.ts +200 -0
- package/Server/Services/HostService.ts +92 -0
- package/Server/Services/IncidentService.ts +45 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MonitorService.ts +49 -0
- package/Server/Services/MonitorStatusService.ts +166 -0
- package/Server/Services/OpenTelemetryIngestService.ts +255 -184
- package/Server/Services/RumSessionPinService.ts +7 -21
- package/Server/Services/StatusPageSubscriberService.ts +13 -0
- package/Server/Services/UserService.ts +280 -9
- package/Server/Static/Vendor/README.md +62 -0
- package/Server/Static/Vendor/fonts/InterVariable.woff2 +0 -0
- package/Server/Static/Vendor/highlight/highlight.min.js +1244 -0
- package/Server/Static/Vendor/highlight/languages/apache.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/bash.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/c.min.js +41 -0
- package/Server/Static/Vendor/highlight/languages/cpp.min.js +47 -0
- package/Server/Static/Vendor/highlight/languages/csharp.min.js +49 -0
- package/Server/Static/Vendor/highlight/languages/css.min.js +31 -0
- package/Server/Static/Vendor/highlight/languages/diff.min.js +9 -0
- package/Server/Static/Vendor/highlight/languages/dns.min.js +11 -0
- package/Server/Static/Vendor/highlight/languages/dockerfile.min.js +8 -0
- package/Server/Static/Vendor/highlight/languages/go.min.js +20 -0
- package/Server/Static/Vendor/highlight/languages/graphql.min.js +12 -0
- package/Server/Static/Vendor/highlight/languages/http.min.js +14 -0
- package/Server/Static/Vendor/highlight/languages/ini.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/java.min.js +38 -0
- package/Server/Static/Vendor/highlight/languages/javascript.min.js +81 -0
- package/Server/Static/Vendor/highlight/languages/json.min.js +8 -0
- package/Server/Static/Vendor/highlight/languages/kotlin.min.js +46 -0
- package/Server/Static/Vendor/highlight/languages/lua.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/makefile.min.js +14 -0
- package/Server/Static/Vendor/highlight/languages/nginx.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/perl.min.js +41 -0
- package/Server/Static/Vendor/highlight/languages/php.min.js +59 -0
- package/Server/Static/Vendor/highlight/languages/powershell.min.js +39 -0
- package/Server/Static/Vendor/highlight/languages/python.min.js +42 -0
- package/Server/Static/Vendor/highlight/languages/r.min.js +26 -0
- package/Server/Static/Vendor/highlight/languages/ruby.min.js +54 -0
- package/Server/Static/Vendor/highlight/languages/rust.min.js +27 -0
- package/Server/Static/Vendor/highlight/languages/scala.min.js +28 -0
- package/Server/Static/Vendor/highlight/languages/sql.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/swift.min.js +68 -0
- package/Server/Static/Vendor/highlight/languages/typescript.min.js +99 -0
- package/Server/Static/Vendor/highlight/languages/xml.min.js +29 -0
- package/Server/Static/Vendor/highlight/languages/yaml.min.js +28 -0
- package/Server/Static/Vendor/highlight/styles/github-dark.min.css +10 -0
- package/Server/Static/Vendor/highlight/styles/vs2015.min.css +1 -0
- package/Server/Static/Vendor/tailwind/tailwind-3.4.5.js +21028 -0
- package/Server/Types/Database/Permissions/BasePermission.ts +7 -0
- package/Server/Types/Database/Permissions/DeletePermission.ts +2 -0
- package/Server/Types/Database/Permissions/ReadPermission.ts +3 -0
- package/Server/Types/Database/Permissions/TenantPermission.ts +101 -16
- package/Server/Utils/AI/CodeFix/FixRunBudget.ts +2 -2
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +90 -11
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +1 -0
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +1 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.ts +125 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +25 -15
- package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +256 -57
- package/Server/Utils/AI/SRE/Insights/InsightStore.ts +76 -18
- package/Server/Utils/AI/SRE/InvestigationTldr.ts +352 -0
- package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +7 -2
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +1793 -0
- package/Server/Utils/Dashboard/PublicDashboardViewConfig.ts +65 -0
- package/Server/Utils/DataSource/ConnectorRegistry.ts +53 -0
- package/Server/Utils/DataSource/Connectors/ClickHouseConnector.ts +338 -0
- package/Server/Utils/DataSource/Connectors/ElasticsearchConnector.ts +717 -0
- package/Server/Utils/DataSource/Connectors/LokiConnector.ts +606 -0
- package/Server/Utils/DataSource/Connectors/MySqlConnector.ts +307 -0
- package/Server/Utils/DataSource/Connectors/PostgresConnector.ts +260 -0
- package/Server/Utils/DataSource/Connectors/PrometheusConnector.ts +555 -0
- package/Server/Utils/DataSource/Connectors/RestApiConnector.ts +597 -0
- package/Server/Utils/DataSource/Connectors/SqlServerConnector.ts +318 -0
- package/Server/Utils/DataSource/EgressGuard.ts +446 -0
- package/Server/Utils/DataSource/HttpFetch.ts +221 -0
- package/Server/Utils/DataSource/SqlQueryGuard.ts +383 -0
- package/Server/Utils/DataSource/SqlResultShaper.ts +372 -0
- package/Server/Utils/DataSource/Types.ts +93 -0
- package/Server/Utils/Database/PostgresErrorTranslator.ts +172 -17
- package/Server/Utils/InProcessMemo.ts +141 -0
- package/Server/Utils/InstanceHealth/TelemetryIngestion.ts +628 -0
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +58 -0
- package/Server/Utils/Monitor/MonitorResource.ts +14 -0
- package/Server/Utils/Response.ts +12 -1
- package/Server/Utils/SSRFProtection.ts +237 -0
- package/Server/Utils/StartServer.ts +8 -0
- package/Server/Utils/StatusPageSubscriberWebhook.ts +30 -0
- package/Server/Utils/Telemetry/CaptureSpan.ts +30 -18
- package/Server/Utils/Telemetry/IngestionTimestamp.ts +75 -0
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +99 -7
- package/Server/Utils/Telemetry/Telemetry.ts +112 -1
- package/Server/Utils/Telemetry.ts +104 -3
- package/Server/Utils/VendorAssets.ts +165 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +28 -5
- package/Server/Utils/Workspace/Slack/Slack.ts +5 -0
- package/Server/Views/Partials/Head.ejs +21 -7
- package/Tests/App/AdminDashboard/AdminProjectsIdFilter.test.tsx +207 -0
- package/Tests/App/AdminDashboard/AdminUsersIdFilter.test.tsx +216 -0
- package/Tests/App/Dashboard/AIInsightViewActions.test.tsx +422 -0
- package/Tests/App/Dashboard/AddWidgetModal.test.tsx +10 -3
- package/Tests/App/Dashboard/AlertsSideMenu.test.tsx +387 -0
- package/Tests/App/Dashboard/ChatActivityFeed.test.tsx +199 -0
- package/Tests/App/Dashboard/DataSourceChartSyntheticConfig.test.tsx +736 -0
- package/Tests/App/Dashboard/DataSourceQueryEditor.test.tsx +868 -0
- package/Tests/App/Dashboard/DataSourceWidgetCatalog.test.ts +440 -0
- package/Tests/App/Dashboard/DataSourceWidgetFetching.test.tsx +2109 -0
- package/Tests/App/Dashboard/DataSourceWidgetViews.test.tsx +726 -0
- package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +447 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +514 -3
- package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +391 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceSideMenu.test.tsx +326 -0
- package/Tests/App/Dashboard/SideMenuHarness.tsx +187 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +6 -1
- package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +1858 -0
- package/Tests/Models/DatabaseModels/DataSourceModelSecrets.test.ts +70 -0
- package/Tests/Server/API/AIInvestigationAPI.test.ts +187 -0
- package/Tests/Server/API/DashboardPublicDataSourceStrip.test.ts +686 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +585 -823
- package/Tests/Server/API/DataSourceAPIRoutes.test.ts +486 -0
- package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +291 -0
- package/Tests/Server/API/UserAuthenticationAPI.test.ts +641 -0
- package/Tests/Server/Infrastructure/ClickhouseKeepAliveOptions.test.ts +441 -0
- package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +140 -0
- package/Tests/Server/Services/AIInsightService.test.ts +266 -11
- package/Tests/Server/Services/AIRunAnalysisTldrPersistence.test.ts +160 -0
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +4 -0
- package/Tests/Server/Services/AlertMetricResourceAttributes.test.ts +352 -0
- package/Tests/Server/Services/DataSourceServiceSettings.test.ts +244 -0
- package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +397 -0
- package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +41 -2
- package/Tests/Server/Services/IncidentMetricResourceAttributes.test.ts +408 -0
- package/Tests/Server/Services/MonitorStatusServiceDeleteReferenceCleanup.test.ts +351 -0
- package/Tests/Server/Services/MonitorStatusServiceValidation.test.ts +171 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +398 -0
- package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +19 -0
- package/Tests/Server/Services/ProjectCallSMSConfigCredentialUniqueness.test.ts +305 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +36 -1
- package/Tests/Server/Services/RumSessionPinUniqueViolationRecovery.test.ts +163 -0
- package/Tests/Server/Services/UserAuthenticationService.test.ts +973 -0
- package/Tests/Server/Types/Database/ObjectIdColumnQuery.test.ts +262 -0
- package/Tests/Server/Types/Database/Permissions/TenantPermission.test.ts +358 -0
- package/Tests/Server/Utils/AI/FixRunBudget.test.ts +2 -2
- package/Tests/Server/Utils/AI/Insights/ExceptionSpikeDetector.test.ts +6 -1
- package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +121 -4
- package/Tests/Server/Utils/AI/Insights/NewExceptionDetector.test.ts +361 -10
- package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +292 -0
- package/Tests/Server/Utils/AI/InvestigationTldr.test.ts +623 -0
- package/Tests/Server/Utils/AI/InvestigationTldrWiring.test.ts +98 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +857 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardViewConfig.test.ts +480 -0
- package/Tests/Server/Utils/DataSource/ClickHouseConnector.test.ts +759 -0
- package/Tests/Server/Utils/DataSource/ConnectorRegistry.test.ts +37 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +645 -0
- package/Tests/Server/Utils/DataSource/ElasticsearchConnector.test.ts +1206 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +616 -0
- package/Tests/Server/Utils/DataSource/LokiConnector.test.ts +970 -0
- package/Tests/Server/Utils/DataSource/MySqlConnector.test.ts +935 -0
- package/Tests/Server/Utils/DataSource/PostgresConnector.test.ts +854 -0
- package/Tests/Server/Utils/DataSource/PrometheusConnector.test.ts +881 -0
- package/Tests/Server/Utils/DataSource/RestApiConnector.test.ts +1020 -0
- package/Tests/Server/Utils/DataSource/SqlQueryGuard.test.ts +425 -0
- package/Tests/Server/Utils/DataSource/SqlResultShaper.test.ts +555 -0
- package/Tests/Server/Utils/DataSource/SqlServerConnector.test.ts +934 -0
- package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +228 -7
- package/Tests/Server/Utils/InProcessMemo.test.ts +292 -0
- package/Tests/Server/Utils/InstanceHealth/TelemetryIngestion.test.ts +960 -0
- package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +103 -0
- package/Tests/Server/Utils/Monitor/MonitorMetricResourceAttributes.test.ts +336 -0
- package/Tests/Server/Utils/OfflineAssetHygiene.test.ts +521 -0
- package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +143 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +193 -0
- package/Tests/Server/Utils/StatusPageSubscriberWebhook.test.ts +101 -0
- package/Tests/Server/Utils/TailwindBuildCopy.test.ts +225 -0
- package/Tests/Server/Utils/Telemetry/ResourceHeartbeatL1Memo.test.ts +355 -0
- package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +128 -0
- package/Tests/Server/Utils/Telemetry/TelemetryUtilAttributeKeys.test.ts +381 -0
- package/Tests/Server/Utils/Telemetry.test.ts +87 -0
- package/Tests/Server/Utils/VendorAssetIntegrity.test.ts +343 -0
- package/Tests/Server/Utils/VendorAssets.test.ts +671 -0
- package/Tests/Server/Views/OfflineRender.test.ts +297 -0
- package/Tests/Types/Dashboard/DataSourceComponentTypes.test.ts +618 -0
- package/Tests/Types/DateClickhouseFormat.test.ts +192 -0
- package/Tests/Types/Password.test.ts +363 -0
- package/Tests/UI/Components/ConfirmModal.test.tsx +7 -0
- package/Tests/UI/Components/ErrorBoundary.test.tsx +53 -0
- package/Tests/UI/Components/Modal.test.tsx +281 -1
- package/Tests/UI/Components/ObjectIdFilterPipeline.test.tsx +396 -0
- package/Tests/UI/Components/StatusPage/ResourceGroupNavigator.test.tsx +1147 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +116 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Tests/Utils/Analytics.test.ts +23 -0
- package/Tests/Utils/Dashboard/Components/DashboardDataSourceComponents.test.ts +640 -0
- package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +138 -0
- package/Tests/Utils/DataSource/DataSourceValueReducer.test.ts +526 -0
- package/Tests/Utils/Metrics/MetricResourceAttributeUtil.test.ts +691 -0
- package/Tests/Utils/StatusPage/GroupHierarchyView.test.ts +1452 -0
- package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +931 -0
- package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +288 -0
- package/Tests/Utils/Telemetry/IngestionTimestamp.test.ts +170 -0
- package/Types/AI/AIInsightEvidence.ts +6 -0
- package/Types/Analytics/RevenueEvent.ts +31 -0
- package/Types/Dashboard/DashboardComponentType.ts +31 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.ts +27 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.ts +32 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.ts +30 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.ts +55 -0
- package/Types/DataSource/DataSourceLimits.ts +62 -0
- package/Types/DataSource/DataSourceQueryConfig.ts +41 -0
- package/Types/DataSource/DataSourceTableResult.ts +38 -0
- package/Types/DataSource/DataSourceType.ts +213 -0
- package/Types/Date.ts +43 -3
- package/Types/Password.ts +64 -0
- package/Types/Permission.ts +46 -0
- package/Types/UserAuthenticationStatus.ts +34 -0
- package/UI/Components/Button/Button.tsx +1 -1
- package/UI/Components/ErrorBoundary.tsx +459 -108
- package/UI/Components/Icon/Icon.tsx +10 -9
- package/UI/Components/Modal/ConfirmModal.tsx +6 -1
- package/UI/Components/Modal/Modal.tsx +267 -35
- package/UI/Components/Modal/ModalFooter.tsx +6 -1
- package/UI/Components/MoreMenu/MoreMenu.tsx +19 -4
- package/UI/Components/MoreMenu/MoreMenuItem.tsx +6 -1
- package/UI/Components/StatusPage/ResourceGrid.tsx +314 -0
- package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +808 -0
- package/UI/Components/StatusPage/ResourceList.tsx +570 -0
- package/UI/Styles/Theme.css +18 -0
- package/UI/Utils/API/RequestOptions.ts +7 -0
- package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +1 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +1 -0
- package/UI/Utils/TestDataSource.ts +61 -0
- package/UI/esbuild-config.js +45 -0
- package/Utils/Analytics.ts +15 -0
- package/Utils/Dashboard/Components/DashboardDataSourceChartComponent.ts +88 -0
- package/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.ts +123 -0
- package/Utils/Dashboard/Components/DashboardDataSourceShared.ts +16 -0
- package/Utils/Dashboard/Components/DashboardDataSourceTableComponent.ts +72 -0
- package/Utils/Dashboard/Components/DashboardDataSourceValueComponent.ts +126 -0
- package/Utils/Dashboard/Components/Index.ts +28 -0
- package/Utils/DataSource/DataSourceQueryText.ts +94 -0
- package/Utils/DataSource/DataSourceValueReducer.ts +156 -0
- package/Utils/Metrics/MetricResourceAttributeUtil.ts +380 -0
- package/Utils/NetworkDiscovery/ScanTargetUtil.ts +8 -6
- package/Utils/StatusPage/GroupHierarchyView.ts +931 -0
- package/Utils/StatusPage/ResourceExplorer.ts +853 -0
- package/build/dist/Models/DatabaseModels/AIRun.js +34 -0
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DataSource.js +774 -0
- package/build/dist/Models/DatabaseModels/DataSource.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js +14 -4
- package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +2 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js +2 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +2 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSession.js +2 -0
- package/build/dist/Models/DatabaseModels/UserSession.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserTotpAuth.js +6 -4
- package/build/dist/Models/DatabaseModels/UserTotpAuth.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js +5 -3
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
- package/build/dist/Server/API/AIInsightAPI.js +34 -4
- package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +23 -0
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +119 -433
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/DataSourceAPI.js +173 -0
- package/build/dist/Server/API/DataSourceAPI.js.map +1 -0
- package/build/dist/Server/API/StatusPageAPI.js +11 -1
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/UserAPI.js +94 -2
- package/build/dist/Server/API/UserAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js +49 -0
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js +64 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.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/Infrastructure/Queue.js +27 -0
- package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +13 -0
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +8 -3
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AIInsightService.js +110 -10
- package/build/dist/Server/Services/AIInsightService.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +34 -0
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +16 -2
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +28 -35
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +8 -4
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DataSourceService.js +159 -0
- package/build/dist/Server/Services/DataSourceService.js.map +1 -0
- package/build/dist/Server/Services/HostService.js +74 -0
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +35 -24
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +45 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusService.js +129 -0
- package/build/dist/Server/Services/MonitorStatusService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +222 -159
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +7 -15
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +10 -0
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +241 -10
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js +6 -0
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/DeletePermission.js +1 -0
- package/build/dist/Server/Types/Database/Permissions/DeletePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +2 -0
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +68 -12
- package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +2 -2
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +68 -8
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +1 -0
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +1 -0
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js +97 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +17 -15
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +178 -54
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js +65 -16
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js +303 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js.map +1 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +1261 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js +47 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js +42 -0
- package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js +187 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js +493 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js +399 -0
- package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js +195 -0
- package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js +149 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js +362 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js +342 -0
- package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js +186 -0
- package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +305 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js +134 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js +331 -0
- package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/SqlResultShaper.js +280 -0
- package/build/dist/Server/Utils/DataSource/SqlResultShaper.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Types.js +2 -0
- package/build/dist/Server/Utils/DataSource/Types.js.map +1 -0
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +103 -9
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -1
- package/build/dist/Server/Utils/InProcessMemo.js +113 -0
- package/build/dist/Server/Utils/InProcessMemo.js.map +1 -0
- package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js +406 -0
- package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +34 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +14 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +9 -1
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +192 -0
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -0
- package/build/dist/Server/Utils/StartServer.js +7 -0
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js +24 -0
- package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +25 -11
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js +32 -0
- package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +92 -5
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +92 -6
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry.js +93 -6
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/VendorAssets.js +121 -0
- package/build/dist/Server/Utils/VendorAssets.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +25 -4
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +5 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Types/Analytics/RevenueEvent.js +26 -0
- package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js +27 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js +16 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceLimits.js +47 -0
- package/build/dist/Types/DataSource/DataSourceLimits.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceQueryConfig.js +10 -0
- package/build/dist/Types/DataSource/DataSourceQueryConfig.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceTableResult.js +14 -0
- package/build/dist/Types/DataSource/DataSourceTableResult.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceType.js +183 -0
- package/build/dist/Types/DataSource/DataSourceType.js.map +1 -0
- package/build/dist/Types/Date.js +38 -3
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Password.js +56 -0
- package/build/dist/Types/Password.js.map +1 -0
- package/build/dist/Types/Permission.js +42 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/UserAuthenticationStatus.js +2 -0
- package/build/dist/Types/UserAuthenticationStatus.js.map +1 -0
- package/build/dist/UI/Components/ErrorBoundary.js +388 -72
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +10 -4
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +178 -19
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js +3 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +9 -6
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +7 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js +119 -0
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +354 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -0
- package/build/dist/UI/Components/StatusPage/ResourceList.js +203 -0
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -0
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +1 -6
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +3 -8
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/TestDataSource.js +39 -0
- package/build/dist/UI/Utils/TestDataSource.js.map +1 -0
- package/build/dist/Utils/Analytics.js +4 -0
- package/build/dist/Utils/Analytics.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js +79 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js +111 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js +15 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js +62 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js +112 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/DataSource/DataSourceQueryText.js +64 -0
- package/build/dist/Utils/DataSource/DataSourceQueryText.js.map +1 -0
- package/build/dist/Utils/DataSource/DataSourceValueReducer.js +124 -0
- package/build/dist/Utils/DataSource/DataSourceValueReducer.js.map +1 -0
- package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js +281 -0
- package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +8 -6
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
- package/build/dist/Utils/StatusPage/GroupHierarchyView.js +560 -0
- package/build/dist/Utils/StatusPage/GroupHierarchyView.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js +519 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -0
- package/jest.config.json +1 -0
- package/package.json +5 -1
- package/tsconfig.json +12 -10
|
@@ -0,0 +1,736 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import {
|
|
3
|
+
beforeEach,
|
|
4
|
+
afterEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
jest,
|
|
8
|
+
test,
|
|
9
|
+
} from "@jest/globals";
|
|
10
|
+
import { cleanup, render, screen, waitFor } from "@testing-library/react";
|
|
11
|
+
import * as React from "react";
|
|
12
|
+
import getJestMockFunction, { MockFunction } from "../../MockType";
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* The Data Source chart widget does not draw anything itself — it builds a
|
|
16
|
+
* SYNTHETIC MetricViewData and hands it to the same MetricCharts layer the
|
|
17
|
+
* OneUptime-metrics chart uses. That translation object is the entire
|
|
18
|
+
* contract between an external system (PromQL / SQL / LogQL / ES DSL / REST)
|
|
19
|
+
* and a chart layer that otherwise assumes it is looking at OneUptime
|
|
20
|
+
* metrics, so every field of it is behaviour:
|
|
21
|
+
*
|
|
22
|
+
* - `filterData` staying EMPTY is what stops MetricCharts recognising the
|
|
23
|
+
* config as a real metric query and firing metric-exemplar fetches
|
|
24
|
+
* against OneUptime for data that never came from OneUptime;
|
|
25
|
+
* - `groupByAttributeKeys` is what makes the chart split series on each
|
|
26
|
+
* point's `attributes`, and must be undefined rather than [] when there
|
|
27
|
+
* is nothing to group on — an empty array reads as "group by nothing",
|
|
28
|
+
* which is a different chart;
|
|
29
|
+
* - the legend field and the `getSeries` hook are mutually exclusive
|
|
30
|
+
* halves of one decision: a static string names the whole query, a
|
|
31
|
+
* "{{label}}" template has to be resolved per series instead.
|
|
32
|
+
*
|
|
33
|
+
* Nothing here renders a real chart. MetricCharts is stubbed to record its
|
|
34
|
+
* props, because what this component is responsible for is what it ASKS the
|
|
35
|
+
* chart layer to do, not what recharts eventually paints in jsdom.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
const fetchTimeSeriesMock: MockFunction = getJestMockFunction();
|
|
39
|
+
const getAttributeKeysMock: MockFunction = getJestMockFunction();
|
|
40
|
+
const metricChartsRenderMock: MockFunction = getJestMockFunction();
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
* The arrow wrappers are load bearing: jest.mock is hoisted above the
|
|
44
|
+
* compiled requires, so the mock variables above are still unassigned when
|
|
45
|
+
* the factory runs. Dereferencing them lazily, at call time, is what makes
|
|
46
|
+
* this work.
|
|
47
|
+
*
|
|
48
|
+
* getAttributeKeys is a BARE stub returning whatever the test set — it is
|
|
49
|
+
* deliberately not a second implementation of the real key-union logic,
|
|
50
|
+
* because the component's only job with it is to forward the value through
|
|
51
|
+
* to groupByAttributeKeys. Re-deriving the keys in the mock would mean the
|
|
52
|
+
* assertions were checking the mock against itself.
|
|
53
|
+
*/
|
|
54
|
+
jest.mock(
|
|
55
|
+
"../../../../App/FeatureSet/Dashboard/src/Utils/DataSourceQuery",
|
|
56
|
+
() => {
|
|
57
|
+
return {
|
|
58
|
+
__esModule: true,
|
|
59
|
+
default: {
|
|
60
|
+
fetchTimeSeries: (...args: Array<any>) => {
|
|
61
|
+
return fetchTimeSeriesMock(...args);
|
|
62
|
+
},
|
|
63
|
+
fetchTable: () => {
|
|
64
|
+
throw new Error("The chart widget must not use the table endpoint.");
|
|
65
|
+
},
|
|
66
|
+
getAttributeKeys: (...args: Array<any>) => {
|
|
67
|
+
return getAttributeKeysMock(...args);
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
jest.mock(
|
|
75
|
+
"../../../../App/FeatureSet/Dashboard/src/Components/Metrics/MetricCharts",
|
|
76
|
+
() => {
|
|
77
|
+
return {
|
|
78
|
+
__esModule: true,
|
|
79
|
+
default: (props: MetricChartsStubProps): React.ReactElement => {
|
|
80
|
+
metricChartsRenderMock(props);
|
|
81
|
+
return React.createElement(
|
|
82
|
+
"div",
|
|
83
|
+
{ "data-testid": "metric-charts" },
|
|
84
|
+
`results:${props.metricResults.length} configs:${props.metricViewData.queryConfigs.length}`,
|
|
85
|
+
);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
import DashboardDataSourceChartComponentElement from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Components/DashboardDataSourceChartComponent";
|
|
92
|
+
import { DashboardBaseComponentProps } from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Components/DashboardBaseComponent";
|
|
93
|
+
import { setPublicDashboardContext } from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Utils/PublicDashboardContext";
|
|
94
|
+
import AggregatedModel from "../../../Types/BaseDatabase/AggregatedModel";
|
|
95
|
+
import AggregatedResult from "../../../Types/BaseDatabase/AggregatedResult";
|
|
96
|
+
import InBetween from "../../../Types/BaseDatabase/InBetween";
|
|
97
|
+
import DashboardChartType from "../../../Types/Dashboard/Chart/ChartType";
|
|
98
|
+
import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
|
|
99
|
+
import DashboardDataSourceChartComponent from "../../../Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent";
|
|
100
|
+
import DashboardViewConfig from "../../../Types/Dashboard/DashboardViewConfig";
|
|
101
|
+
import DataSourceQueryConfig from "../../../Types/DataSource/DataSourceQueryConfig";
|
|
102
|
+
import { ObjectType } from "../../../Types/JSON";
|
|
103
|
+
import MetricQueryConfigData, {
|
|
104
|
+
ChartSeries,
|
|
105
|
+
MetricChartType,
|
|
106
|
+
} from "../../../Types/Metrics/MetricQueryConfigData";
|
|
107
|
+
import MetricViewData from "../../../Types/Metrics/MetricViewData";
|
|
108
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
109
|
+
import RangeStartAndEndDateTime from "../../../Types/Time/RangeStartAndEndDateTime";
|
|
110
|
+
import TimeRange from "../../../Types/Time/TimeRange";
|
|
111
|
+
|
|
112
|
+
interface MetricChartsStubProps {
|
|
113
|
+
metricResults: Array<AggregatedResult>;
|
|
114
|
+
metricViewData: MetricViewData;
|
|
115
|
+
hideCard?: boolean | undefined;
|
|
116
|
+
topNOverrideScope?: string | undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** One recorded call into the data source query client. */
|
|
120
|
+
interface DataSourceFetchArgs {
|
|
121
|
+
queryConfig: DataSourceQueryConfig;
|
|
122
|
+
startDate: Date;
|
|
123
|
+
endDate: Date;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const COMPONENT_ID: ObjectID = new ObjectID(
|
|
127
|
+
"11111111-1111-4111-8111-111111111111",
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const START_DATE: Date = new Date("2026-08-10T09:00:00.000Z");
|
|
131
|
+
const END_DATE: Date = new Date("2026-08-10T10:00:00.000Z");
|
|
132
|
+
|
|
133
|
+
/*
|
|
134
|
+
* A CUSTOM range pins the window to fixed instants — a relative range would
|
|
135
|
+
* resolve against the wall clock and make the window assertions untestable.
|
|
136
|
+
*/
|
|
137
|
+
const DASHBOARD_RANGE: RangeStartAndEndDateTime = {
|
|
138
|
+
range: TimeRange.CUSTOM,
|
|
139
|
+
startAndEndDate: new InBetween<Date>(START_DATE, END_DATE),
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const DASHBOARD_VIEW_CONFIG: DashboardViewConfig = {
|
|
143
|
+
_type: ObjectType.DashboardViewConfig,
|
|
144
|
+
components: [],
|
|
145
|
+
heightInDashboardUnits: 60,
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/*
|
|
149
|
+
* A value nothing in the component could invent on its own. If it shows up
|
|
150
|
+
* in groupByAttributeKeys, the component forwarded what getAttributeKeys
|
|
151
|
+
* returned rather than deriving anything itself.
|
|
152
|
+
*/
|
|
153
|
+
const SENTINEL_ATTRIBUTE_KEYS: Array<string> = [
|
|
154
|
+
"sentinel.attribute.one",
|
|
155
|
+
"sentinel.attribute.two",
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
type BuildBasePropsFunction = (
|
|
159
|
+
overrides?: Partial<DashboardBaseComponentProps>,
|
|
160
|
+
) => DashboardBaseComponentProps;
|
|
161
|
+
|
|
162
|
+
const buildBaseProps: BuildBasePropsFunction = (
|
|
163
|
+
overrides: Partial<DashboardBaseComponentProps> = {},
|
|
164
|
+
): DashboardBaseComponentProps => {
|
|
165
|
+
return {
|
|
166
|
+
componentId: COMPONENT_ID,
|
|
167
|
+
isEditMode: false,
|
|
168
|
+
isSelected: false,
|
|
169
|
+
key: "data-source-chart-widget",
|
|
170
|
+
onComponentUpdate: (): void => {
|
|
171
|
+
// The chart widget never writes back through this.
|
|
172
|
+
},
|
|
173
|
+
totalCurrentDashboardWidthInPx: 1200,
|
|
174
|
+
dashboardCanvasTopInPx: 0,
|
|
175
|
+
dashboardCanvasLeftInPx: 0,
|
|
176
|
+
dashboardCanvasWidthInPx: 1200,
|
|
177
|
+
dashboardCanvasHeightInPx: 800,
|
|
178
|
+
dashboardComponentHeightInPx: 320,
|
|
179
|
+
dashboardComponentWidthInPx: 480,
|
|
180
|
+
dashboardViewConfig: DASHBOARD_VIEW_CONFIG,
|
|
181
|
+
dashboardStartAndEndDate: DASHBOARD_RANGE,
|
|
182
|
+
metricTypes: [],
|
|
183
|
+
refreshTick: 0,
|
|
184
|
+
variables: undefined,
|
|
185
|
+
...overrides,
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
type BuildPointFunction = (
|
|
190
|
+
value: number,
|
|
191
|
+
timestamp: string,
|
|
192
|
+
attributes?: Record<string, string>,
|
|
193
|
+
) => AggregatedModel;
|
|
194
|
+
|
|
195
|
+
const buildPoint: BuildPointFunction = (
|
|
196
|
+
value: number,
|
|
197
|
+
timestamp: string,
|
|
198
|
+
attributes?: Record<string, string>,
|
|
199
|
+
): AggregatedModel => {
|
|
200
|
+
return {
|
|
201
|
+
timestamp: new Date(timestamp),
|
|
202
|
+
value: value,
|
|
203
|
+
...(attributes ? { attributes: attributes } : {}),
|
|
204
|
+
} as AggregatedModel;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
type BuildSeriesFunction = (points: Array<AggregatedModel>) => AggregatedResult;
|
|
208
|
+
|
|
209
|
+
const buildSeries: BuildSeriesFunction = (
|
|
210
|
+
points: Array<AggregatedModel>,
|
|
211
|
+
): AggregatedResult => {
|
|
212
|
+
return {
|
|
213
|
+
data: points,
|
|
214
|
+
truncated: false,
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
type RenderChartFunction = (
|
|
219
|
+
args: DashboardDataSourceChartComponent["arguments"],
|
|
220
|
+
overrides?: Partial<DashboardBaseComponentProps>,
|
|
221
|
+
) => void;
|
|
222
|
+
|
|
223
|
+
const renderChartWidget: RenderChartFunction = (
|
|
224
|
+
args: DashboardDataSourceChartComponent["arguments"],
|
|
225
|
+
overrides: Partial<DashboardBaseComponentProps> = {},
|
|
226
|
+
): void => {
|
|
227
|
+
const component: DashboardDataSourceChartComponent = {
|
|
228
|
+
_type: ObjectType.DashboardComponent,
|
|
229
|
+
componentId: COMPONENT_ID,
|
|
230
|
+
componentType: DashboardComponentType.DataSourceChart,
|
|
231
|
+
topInDashboardUnits: 0,
|
|
232
|
+
leftInDashboardUnits: 0,
|
|
233
|
+
widthInDashboardUnits: 8,
|
|
234
|
+
heightInDashboardUnits: 6,
|
|
235
|
+
minWidthInDashboardUnits: 4,
|
|
236
|
+
minHeightInDashboardUnits: 3,
|
|
237
|
+
arguments: args,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
render(
|
|
241
|
+
<DashboardDataSourceChartComponentElement
|
|
242
|
+
{...buildBaseProps(overrides)}
|
|
243
|
+
component={component}
|
|
244
|
+
/>,
|
|
245
|
+
);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/** The props of the most recent MetricCharts render. */
|
|
249
|
+
type GetLastChartPropsFunction = () => MetricChartsStubProps;
|
|
250
|
+
|
|
251
|
+
const getLastChartProps: GetLastChartPropsFunction =
|
|
252
|
+
(): MetricChartsStubProps => {
|
|
253
|
+
const calls: Array<Array<unknown>> = metricChartsRenderMock.mock.calls;
|
|
254
|
+
|
|
255
|
+
if (calls.length === 0) {
|
|
256
|
+
throw new Error("MetricCharts was never rendered.");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return calls[calls.length - 1]![0] as MetricChartsStubProps;
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
/*
|
|
263
|
+
* Render, wait for the fetch to settle and the chart layer to be handed its
|
|
264
|
+
* synthetic view data, then return that view data.
|
|
265
|
+
*/
|
|
266
|
+
type RenderAndGetConfigsFunction = (
|
|
267
|
+
args: DashboardDataSourceChartComponent["arguments"],
|
|
268
|
+
) => Promise<Array<MetricQueryConfigData>>;
|
|
269
|
+
|
|
270
|
+
const renderAndGetConfigs: RenderAndGetConfigsFunction = async (
|
|
271
|
+
args: DashboardDataSourceChartComponent["arguments"],
|
|
272
|
+
): Promise<Array<MetricQueryConfigData>> => {
|
|
273
|
+
renderChartWidget(args);
|
|
274
|
+
|
|
275
|
+
await waitFor((): void => {
|
|
276
|
+
expect(screen.getByTestId("metric-charts")).toBeInTheDocument();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
return getLastChartProps().metricViewData.queryConfigs;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const PROM_QUERY: DataSourceQueryConfig = {
|
|
283
|
+
id: "q1",
|
|
284
|
+
dataSourceId: "ds-prom",
|
|
285
|
+
query: "up",
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
beforeEach((): void => {
|
|
289
|
+
jest.clearAllMocks();
|
|
290
|
+
fetchTimeSeriesMock.mockResolvedValue(
|
|
291
|
+
buildSeries([buildPoint(1, "2026-08-10T09:15:00.000Z")]),
|
|
292
|
+
);
|
|
293
|
+
getAttributeKeysMock.mockReturnValue([]);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
afterEach((): void => {
|
|
297
|
+
cleanup();
|
|
298
|
+
setPublicDashboardContext(null);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
describe("Data Source chart synthetic MetricViewData", () => {
|
|
302
|
+
describe("the synthetic config exposes no OneUptime metric surface", () => {
|
|
303
|
+
/*
|
|
304
|
+
* The one clause that keeps the chart layer from treating an external
|
|
305
|
+
* query as a metric query. MetricCharts branches on filterData to decide
|
|
306
|
+
* whether it can fetch exemplars/metadata for the named metric; a
|
|
307
|
+
* populated filterData here means requests to OneUptime for a series
|
|
308
|
+
* that came out of somebody's Prometheus.
|
|
309
|
+
*/
|
|
310
|
+
test("filterData is empty, so no metric-exemplar fetch can be keyed off it", async () => {
|
|
311
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
312
|
+
queries: [PROM_QUERY],
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
expect(configs).toHaveLength(1);
|
|
316
|
+
expect(configs[0]!.metricQueryData.filterData).toEqual({});
|
|
317
|
+
// toEqual treats an explicit `undefined` key as absent; this does not.
|
|
318
|
+
expect(Object.keys(configs[0]!.metricQueryData.filterData)).toHaveLength(
|
|
319
|
+
0,
|
|
320
|
+
);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test("filterData stays empty for every query, not just the first", async () => {
|
|
324
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
325
|
+
queries: [
|
|
326
|
+
PROM_QUERY,
|
|
327
|
+
{ id: "q2", dataSourceId: "ds-pg", query: "select 1" },
|
|
328
|
+
],
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
expect(configs).toHaveLength(2);
|
|
332
|
+
for (const config of configs) {
|
|
333
|
+
expect(Object.keys(config.metricQueryData.filterData)).toHaveLength(0);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test("no formula configs are synthesised for external data", async () => {
|
|
338
|
+
await renderAndGetConfigs({ queries: [PROM_QUERY] });
|
|
339
|
+
|
|
340
|
+
expect(getLastChartProps().metricViewData.formulaConfigs).toEqual([]);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
describe("groupByAttributeKeys is the forwarded attribute-key list", () => {
|
|
345
|
+
test("whatever getAttributeKeys returns is passed straight through", async () => {
|
|
346
|
+
getAttributeKeysMock.mockReturnValue(SENTINEL_ATTRIBUTE_KEYS);
|
|
347
|
+
|
|
348
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
349
|
+
queries: [PROM_QUERY],
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
expect(configs[0]!.metricQueryData.groupByAttributeKeys).toEqual(
|
|
353
|
+
SENTINEL_ATTRIBUTE_KEYS,
|
|
354
|
+
);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test("getAttributeKeys is asked about the result, not the query", async () => {
|
|
358
|
+
const result: AggregatedResult = buildSeries([
|
|
359
|
+
buildPoint(5, "2026-08-10T09:15:00.000Z", { instance: "a:9090" }),
|
|
360
|
+
]);
|
|
361
|
+
fetchTimeSeriesMock.mockResolvedValue(result);
|
|
362
|
+
|
|
363
|
+
await renderAndGetConfigs({ queries: [PROM_QUERY] });
|
|
364
|
+
|
|
365
|
+
const lastCall: Array<unknown> =
|
|
366
|
+
getAttributeKeysMock.mock.calls[
|
|
367
|
+
getAttributeKeysMock.mock.calls.length - 1
|
|
368
|
+
]!;
|
|
369
|
+
expect(lastCall[0]).toBe(result);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
/*
|
|
373
|
+
* `[]` and `undefined` are NOT the same instruction to the chart layer:
|
|
374
|
+
* an empty array is a group-by with no keys, undefined is "do not group
|
|
375
|
+
* at all". A result with no attributes must produce the second.
|
|
376
|
+
*/
|
|
377
|
+
test("no attributes means undefined, never an empty array", async () => {
|
|
378
|
+
getAttributeKeysMock.mockReturnValue([]);
|
|
379
|
+
|
|
380
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
381
|
+
queries: [PROM_QUERY],
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
expect(configs[0]!.metricQueryData.groupByAttributeKeys).toBeUndefined();
|
|
385
|
+
expect(configs[0]!.metricQueryData.groupByAttributeKeys).not.toEqual([]);
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
describe("the legend field is a three-way decision", () => {
|
|
390
|
+
test("no legend falls back to a positional Query N name", async () => {
|
|
391
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
392
|
+
queries: [
|
|
393
|
+
{ id: "q1", dataSourceId: "ds-prom", query: "up" },
|
|
394
|
+
{ id: "q2", dataSourceId: "ds-pg", query: "select 1" },
|
|
395
|
+
],
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
expect(
|
|
399
|
+
configs.map((config: MetricQueryConfigData): string | undefined => {
|
|
400
|
+
return config.metricAliasData?.legend;
|
|
401
|
+
}),
|
|
402
|
+
).toEqual(["Query 1", "Query 2"]);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
test("a literal legend is used verbatim", async () => {
|
|
406
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
407
|
+
queries: [
|
|
408
|
+
{ id: "q1", dataSourceId: "ds-prom", query: "up", legend: "errors" },
|
|
409
|
+
],
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
expect(configs[0]!.metricAliasData?.legend).toBe("errors");
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
/*
|
|
416
|
+
* A template cannot name the whole query — it names each series
|
|
417
|
+
* separately, which only getSeries can do. Leaving the literal
|
|
418
|
+
* "{{instance}}" in the legend would put the raw template in the chart
|
|
419
|
+
* legend for every series.
|
|
420
|
+
*/
|
|
421
|
+
test("a templated legend clears the static legend entirely", async () => {
|
|
422
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
423
|
+
queries: [
|
|
424
|
+
{
|
|
425
|
+
id: "q1",
|
|
426
|
+
dataSourceId: "ds-prom",
|
|
427
|
+
query: "up",
|
|
428
|
+
legend: "{{instance}}",
|
|
429
|
+
},
|
|
430
|
+
],
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
expect(configs[0]!.metricAliasData?.legend).toBeUndefined();
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test("a templated legend does not fall back to Query N either", async () => {
|
|
437
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
438
|
+
queries: [
|
|
439
|
+
{
|
|
440
|
+
id: "q1",
|
|
441
|
+
dataSourceId: "ds-prom",
|
|
442
|
+
query: "up",
|
|
443
|
+
legend: "{{instance}} ({{job}})",
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
expect(configs[0]!.metricAliasData?.legend).not.toBe("Query 1");
|
|
449
|
+
expect(configs[0]!.metricAliasData?.legend).toBeUndefined();
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
test("each query decides for itself, in its own position", async () => {
|
|
453
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
454
|
+
queries: [
|
|
455
|
+
{
|
|
456
|
+
id: "q1",
|
|
457
|
+
dataSourceId: "ds-prom",
|
|
458
|
+
query: "up",
|
|
459
|
+
legend: "{{instance}}",
|
|
460
|
+
},
|
|
461
|
+
{ id: "q2", dataSourceId: "ds-pg", query: "select 1" },
|
|
462
|
+
{
|
|
463
|
+
id: "q3",
|
|
464
|
+
dataSourceId: "ds-prom",
|
|
465
|
+
query: "rate(x[5m])",
|
|
466
|
+
legend: "errors",
|
|
467
|
+
},
|
|
468
|
+
],
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
expect(
|
|
472
|
+
configs.map((config: MetricQueryConfigData): string | undefined => {
|
|
473
|
+
return config.metricAliasData?.legend;
|
|
474
|
+
}),
|
|
475
|
+
).toEqual([undefined, "Query 2", "errors"]);
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
describe("the getSeries hook exists only for templated legends", () => {
|
|
480
|
+
type GetSeriesForFunction = (
|
|
481
|
+
legend: string | undefined,
|
|
482
|
+
) => Promise<MetricQueryConfigData["getSeries"]>;
|
|
483
|
+
|
|
484
|
+
const getSeriesFor: GetSeriesForFunction = async (
|
|
485
|
+
legend: string | undefined,
|
|
486
|
+
): Promise<MetricQueryConfigData["getSeries"]> => {
|
|
487
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
488
|
+
queries: [
|
|
489
|
+
{
|
|
490
|
+
id: "q1",
|
|
491
|
+
dataSourceId: "ds-prom",
|
|
492
|
+
query: "up",
|
|
493
|
+
...(legend === undefined ? {} : { legend: legend }),
|
|
494
|
+
},
|
|
495
|
+
],
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
return configs[0]!.getSeries;
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
test("a templated legend installs the hook", async () => {
|
|
502
|
+
expect(await getSeriesFor("{{instance}}")).toBeDefined();
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
test("a literal legend installs no hook", async () => {
|
|
506
|
+
expect(await getSeriesFor("errors")).toBeUndefined();
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
test("no legend at all installs no hook", async () => {
|
|
510
|
+
expect(await getSeriesFor(undefined)).toBeUndefined();
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
test("the hook names a series from that point's attributes", async () => {
|
|
514
|
+
const getSeries: MetricQueryConfigData["getSeries"] =
|
|
515
|
+
await getSeriesFor("{{instance}}");
|
|
516
|
+
|
|
517
|
+
const series: ChartSeries = getSeries!({
|
|
518
|
+
attributes: { instance: "a:9090" },
|
|
519
|
+
} as unknown as AggregatedModel);
|
|
520
|
+
|
|
521
|
+
expect(series).toEqual({ title: "a:9090" });
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
/*
|
|
525
|
+
* A point that carries no attributes at all still has to get a name —
|
|
526
|
+
* an empty title collapses every such series into one nameless entry.
|
|
527
|
+
*/
|
|
528
|
+
test("a point with empty attributes renders the unset marker", async () => {
|
|
529
|
+
const getSeries: MetricQueryConfigData["getSeries"] =
|
|
530
|
+
await getSeriesFor("{{instance}}");
|
|
531
|
+
|
|
532
|
+
expect(
|
|
533
|
+
getSeries!({ attributes: {} } as unknown as AggregatedModel),
|
|
534
|
+
).toEqual({ title: "(unset)" });
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
test("a point with no attributes object at all renders the unset marker", async () => {
|
|
538
|
+
const getSeries: MetricQueryConfigData["getSeries"] =
|
|
539
|
+
await getSeriesFor("{{instance}}");
|
|
540
|
+
|
|
541
|
+
expect(getSeries!(buildPoint(1, "2026-08-10T09:15:00.000Z"))).toEqual({
|
|
542
|
+
title: "(unset)",
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
test("the hook resolves every placeholder in a multi-token template", async () => {
|
|
547
|
+
const getSeries: MetricQueryConfigData["getSeries"] = await getSeriesFor(
|
|
548
|
+
"{{instance}} ({{job}})",
|
|
549
|
+
);
|
|
550
|
+
|
|
551
|
+
expect(
|
|
552
|
+
getSeries!({
|
|
553
|
+
attributes: { instance: "a:9090", job: "api" },
|
|
554
|
+
} as unknown as AggregatedModel),
|
|
555
|
+
).toEqual({ title: "a:9090 (api)" });
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
describe("the widget's chart type maps onto the chart layer's", () => {
|
|
560
|
+
interface ChartTypeCase {
|
|
561
|
+
label: string;
|
|
562
|
+
dashboardChartType: DashboardChartType | undefined;
|
|
563
|
+
expectedMetricChartType: MetricChartType;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const CHART_TYPE_CASES: Array<ChartTypeCase> = [
|
|
567
|
+
{
|
|
568
|
+
label: "Bar",
|
|
569
|
+
dashboardChartType: DashboardChartType.Bar,
|
|
570
|
+
expectedMetricChartType: MetricChartType.BAR,
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
label: "Area",
|
|
574
|
+
dashboardChartType: DashboardChartType.Area,
|
|
575
|
+
expectedMetricChartType: MetricChartType.AREA,
|
|
576
|
+
},
|
|
577
|
+
/*
|
|
578
|
+
* StackedArea is a one-line branch that shares its return with Area.
|
|
579
|
+
* Drop it from the condition and the widget silently draws lines.
|
|
580
|
+
*/
|
|
581
|
+
{
|
|
582
|
+
label: "Stacked Area",
|
|
583
|
+
dashboardChartType: DashboardChartType.StackedArea,
|
|
584
|
+
expectedMetricChartType: MetricChartType.AREA,
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
label: "Line",
|
|
588
|
+
dashboardChartType: DashboardChartType.Line,
|
|
589
|
+
expectedMetricChartType: MetricChartType.LINE,
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
label: "an unset chart type",
|
|
593
|
+
dashboardChartType: undefined,
|
|
594
|
+
expectedMetricChartType: MetricChartType.LINE,
|
|
595
|
+
},
|
|
596
|
+
];
|
|
597
|
+
|
|
598
|
+
for (const chartTypeCase of CHART_TYPE_CASES) {
|
|
599
|
+
test(`${chartTypeCase.label} becomes ${chartTypeCase.expectedMetricChartType}`, async () => {
|
|
600
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs(
|
|
601
|
+
{
|
|
602
|
+
queries: [PROM_QUERY],
|
|
603
|
+
...(chartTypeCase.dashboardChartType === undefined
|
|
604
|
+
? {}
|
|
605
|
+
: { chartType: chartTypeCase.dashboardChartType }),
|
|
606
|
+
},
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
expect(configs[0]!.chartType).toBe(
|
|
610
|
+
chartTypeCase.expectedMetricChartType,
|
|
611
|
+
);
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
test("the chart type is applied to every query, not only the first", async () => {
|
|
616
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
617
|
+
queries: [
|
|
618
|
+
PROM_QUERY,
|
|
619
|
+
{ id: "q2", dataSourceId: "ds-pg", query: "select 1" },
|
|
620
|
+
],
|
|
621
|
+
chartType: DashboardChartType.Bar,
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
expect(
|
|
625
|
+
configs.map(
|
|
626
|
+
(config: MetricQueryConfigData): MetricChartType | undefined => {
|
|
627
|
+
return config.chartType;
|
|
628
|
+
},
|
|
629
|
+
),
|
|
630
|
+
).toEqual([MetricChartType.BAR, MetricChartType.BAR]);
|
|
631
|
+
});
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
describe("config identity and index alignment", () => {
|
|
635
|
+
/*
|
|
636
|
+
* Chart layers key per-chart UI state (hidden series, Top-N, sort) on
|
|
637
|
+
* config.id. Older persisted widgets predate the stored id, so the
|
|
638
|
+
* synthetic config has to invent a stable one rather than leave it
|
|
639
|
+
* undefined and let two charts share state.
|
|
640
|
+
*/
|
|
641
|
+
test("a stored query with no id gets a positional fallback id", async () => {
|
|
642
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
643
|
+
queries: [
|
|
644
|
+
{ dataSourceId: "ds-prom", query: "up" },
|
|
645
|
+
{ id: "q-b", dataSourceId: "ds-pg", query: "select 1" },
|
|
646
|
+
{ dataSourceId: "ds-prom", query: "rate(x[5m])" },
|
|
647
|
+
],
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
expect(
|
|
651
|
+
configs.map((config: MetricQueryConfigData): string | undefined => {
|
|
652
|
+
return config.id;
|
|
653
|
+
}),
|
|
654
|
+
).toEqual(["data-source-query-0", "q-b", "data-source-query-2"]);
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
test("the fallback id counts configured queries, skipping half-filled cards", async () => {
|
|
658
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
659
|
+
queries: [
|
|
660
|
+
// Source picked, query still empty — the user is mid-edit.
|
|
661
|
+
{ dataSourceId: "ds-prom", query: " " },
|
|
662
|
+
{ dataSourceId: "ds-pg", query: "select 1" },
|
|
663
|
+
],
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
expect(configs).toHaveLength(1);
|
|
667
|
+
expect(configs[0]!.id).toBe("data-source-query-0");
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
/*
|
|
671
|
+
* The synthetic configs and the results array are read together by the
|
|
672
|
+
* chart layer, position by position. If they ever drift, query 1's
|
|
673
|
+
* legend ends up over query 2's data.
|
|
674
|
+
*/
|
|
675
|
+
test("each configured query gets one config, paired with its own result", async () => {
|
|
676
|
+
fetchTimeSeriesMock.mockImplementation(
|
|
677
|
+
(args: DataSourceFetchArgs): Promise<AggregatedResult> => {
|
|
678
|
+
return Promise.resolve(
|
|
679
|
+
buildSeries([
|
|
680
|
+
buildPoint(1, "2026-08-10T09:15:00.000Z", {
|
|
681
|
+
query: args.queryConfig.query,
|
|
682
|
+
}),
|
|
683
|
+
]),
|
|
684
|
+
);
|
|
685
|
+
},
|
|
686
|
+
);
|
|
687
|
+
|
|
688
|
+
const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
|
|
689
|
+
queries: [
|
|
690
|
+
{ id: "q1", dataSourceId: "ds-prom", query: "up" },
|
|
691
|
+
// Never configured — must not consume a position.
|
|
692
|
+
{ id: "q2", dataSourceId: "", query: "select 1" },
|
|
693
|
+
{ id: "q3", dataSourceId: "ds-pg", query: "select count(*) from t" },
|
|
694
|
+
],
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
const lastProps: MetricChartsStubProps = getLastChartProps();
|
|
698
|
+
|
|
699
|
+
expect(configs).toHaveLength(2);
|
|
700
|
+
expect(lastProps.metricResults).toHaveLength(2);
|
|
701
|
+
expect(
|
|
702
|
+
configs.map((config: MetricQueryConfigData): string | undefined => {
|
|
703
|
+
return config.id;
|
|
704
|
+
}),
|
|
705
|
+
).toEqual(["q1", "q3"]);
|
|
706
|
+
|
|
707
|
+
/*
|
|
708
|
+
* Identity, not shape: config[i] was built from result[i], which is
|
|
709
|
+
* the only thing that proves the pairing.
|
|
710
|
+
*/
|
|
711
|
+
const attributeKeyArguments: Array<unknown> =
|
|
712
|
+
getAttributeKeysMock.mock.calls
|
|
713
|
+
.slice(-2)
|
|
714
|
+
.map((call: Array<unknown>): unknown => {
|
|
715
|
+
return call[0];
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
expect(attributeKeyArguments[0]).toBe(lastProps.metricResults[0]);
|
|
719
|
+
expect(attributeKeyArguments[1]).toBe(lastProps.metricResults[1]);
|
|
720
|
+
expect(
|
|
721
|
+
(
|
|
722
|
+
lastProps.metricResults[0]!.data[0] as unknown as {
|
|
723
|
+
attributes: Record<string, string>;
|
|
724
|
+
}
|
|
725
|
+
).attributes["query"],
|
|
726
|
+
).toBe("up");
|
|
727
|
+
expect(
|
|
728
|
+
(
|
|
729
|
+
lastProps.metricResults[1]!.data[0] as unknown as {
|
|
730
|
+
attributes: Record<string, string>;
|
|
731
|
+
}
|
|
732
|
+
).attributes["query"],
|
|
733
|
+
).toBe("select count(*) from t");
|
|
734
|
+
});
|
|
735
|
+
});
|
|
736
|
+
});
|