@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
|
@@ -74,6 +74,15 @@ jest.mock("../../../UI/Components/Markdown.tsx/MarkdownViewer", () => {
|
|
|
74
74
|
};
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
+
/*
|
|
78
|
+
* The feed owns the "will this draw any steps?" predicate, because several
|
|
79
|
+
* event types only close a step an earlier event opened. The panel asks it
|
|
80
|
+
* instead of counting raw events, so the mock has to answer too — and
|
|
81
|
+
* hasRenderableActivityMock lets a test make the two disagree, which is the
|
|
82
|
+
* case that used to render an empty framed box.
|
|
83
|
+
*/
|
|
84
|
+
const hasRenderableActivityMock: MockFunction = getJestMockFunction();
|
|
85
|
+
|
|
77
86
|
jest.mock(
|
|
78
87
|
"../../../../App/FeatureSet/Dashboard/src/Components/AIChat/ChatActivityFeed",
|
|
79
88
|
() => {
|
|
@@ -85,6 +94,9 @@ jest.mock(
|
|
|
85
94
|
"data-testid": "investigation-activity",
|
|
86
95
|
});
|
|
87
96
|
},
|
|
97
|
+
hasRenderableActivity: (events: Array<AIRunEvent>): boolean => {
|
|
98
|
+
return hasRenderableActivityMock(events) as boolean;
|
|
99
|
+
},
|
|
88
100
|
};
|
|
89
101
|
},
|
|
90
102
|
);
|
|
@@ -110,6 +122,7 @@ interface ActivityFeedProps {
|
|
|
110
122
|
title?: string | undefined;
|
|
111
123
|
showLiveIndicator?: boolean | undefined;
|
|
112
124
|
maxVisibleSteps?: number | undefined;
|
|
125
|
+
hideChrome?: boolean | undefined;
|
|
113
126
|
}
|
|
114
127
|
|
|
115
128
|
interface InvestigationPayloadOptions {
|
|
@@ -117,6 +130,7 @@ interface InvestigationPayloadOptions {
|
|
|
117
130
|
runId?: string | undefined;
|
|
118
131
|
events?: JSONArray | undefined;
|
|
119
132
|
analysisMarkdown?: string | null | undefined;
|
|
133
|
+
analysisTldr?: string | null | undefined;
|
|
120
134
|
isAnalysisPending?: boolean | undefined;
|
|
121
135
|
errorMessage?: string | null | undefined;
|
|
122
136
|
toolCallCount?: number | undefined;
|
|
@@ -158,6 +172,8 @@ const ALERT_ID: ObjectID = new ObjectID("44444444-4444-4444-8444-444444444444");
|
|
|
158
172
|
const EVENT_ID: string = "55555555-5555-4555-8555-555555555555";
|
|
159
173
|
const ANALYSIS: string =
|
|
160
174
|
"## Root cause\n\nThe database connection pool was exhausted.";
|
|
175
|
+
const TLDR: string =
|
|
176
|
+
"Checkout is returning 500s because the database connection pool is exhausted.";
|
|
161
177
|
|
|
162
178
|
const activityEvent: JSONObject = {
|
|
163
179
|
_id: EVENT_ID,
|
|
@@ -191,6 +207,7 @@ function investigationPayload(
|
|
|
191
207
|
run,
|
|
192
208
|
events: options.events || [],
|
|
193
209
|
analysisMarkdown: options.analysisMarkdown ?? null,
|
|
210
|
+
analysisTldr: options.analysisTldr ?? null,
|
|
194
211
|
isAnalysisPending: options.isAnalysisPending === true,
|
|
195
212
|
};
|
|
196
213
|
}
|
|
@@ -205,6 +222,7 @@ function noInvestigationResponse(): ApiResponse {
|
|
|
205
222
|
run: null,
|
|
206
223
|
events: [],
|
|
207
224
|
analysisMarkdown: null,
|
|
225
|
+
analysisTldr: null,
|
|
208
226
|
isAnalysisPending: false,
|
|
209
227
|
},
|
|
210
228
|
};
|
|
@@ -320,6 +338,15 @@ beforeEach(() => {
|
|
|
320
338
|
jest.useFakeTimers();
|
|
321
339
|
jest.setSystemTime(new Date(COMPLETED_AT));
|
|
322
340
|
getCommonHeadersMock.mockReturnValue({});
|
|
341
|
+
/*
|
|
342
|
+
* Default to the real component's behaviour for the ordinary event shapes
|
|
343
|
+
* these tests use: every step-opening event draws a step.
|
|
344
|
+
*/
|
|
345
|
+
hasRenderableActivityMock.mockImplementation(
|
|
346
|
+
(events: Array<AIRunEvent>): boolean => {
|
|
347
|
+
return events.length > 0;
|
|
348
|
+
},
|
|
349
|
+
);
|
|
323
350
|
getFriendlyMessageMock.mockImplementation((error: unknown): string => {
|
|
324
351
|
if (
|
|
325
352
|
typeof error === "object" &&
|
|
@@ -343,6 +370,7 @@ afterEach(() => {
|
|
|
343
370
|
getCommonHeadersMock.mockReset();
|
|
344
371
|
markdownViewerMock.mockReset();
|
|
345
372
|
activityFeedMock.mockReset();
|
|
373
|
+
hasRenderableActivityMock.mockReset();
|
|
346
374
|
});
|
|
347
375
|
|
|
348
376
|
describe("InvestigationPanel report lifecycle", () => {
|
|
@@ -376,7 +404,12 @@ describe("InvestigationPanel report lifecycle", () => {
|
|
|
376
404
|
expect(screen.getByText("Investigating…")).toBeInTheDocument();
|
|
377
405
|
expect(screen.getByTestId("investigation-activity")).toBeInTheDocument();
|
|
378
406
|
expect(lastActivityProps().events).toHaveLength(1);
|
|
379
|
-
|
|
407
|
+
/*
|
|
408
|
+
* The panel frames the feed itself, so the feed drops its own bubble and
|
|
409
|
+
* heading — the "Investigating…" wording must appear exactly once.
|
|
410
|
+
*/
|
|
411
|
+
expect(lastActivityProps().hideChrome).toBe(true);
|
|
412
|
+
expect(screen.getAllByText("Investigating…")).toHaveLength(1);
|
|
380
413
|
expect(
|
|
381
414
|
document.querySelector('[class~="motion-safe:animate-ping"]'),
|
|
382
415
|
).not.toBeNull();
|
|
@@ -406,7 +439,7 @@ describe("InvestigationPanel report lifecycle", () => {
|
|
|
406
439
|
expect(screen.getByText("Investigation activity")).toBeInTheDocument();
|
|
407
440
|
expect(lastActivityProps()).toEqual(
|
|
408
441
|
expect.objectContaining({
|
|
409
|
-
|
|
442
|
+
hideChrome: true,
|
|
410
443
|
showLiveIndicator: false,
|
|
411
444
|
maxVisibleSteps: 10,
|
|
412
445
|
}),
|
|
@@ -415,6 +448,9 @@ describe("InvestigationPanel report lifecycle", () => {
|
|
|
415
448
|
const usage: HTMLElement = screen.getByLabelText("Investigation usage");
|
|
416
449
|
expect(usage).toHaveTextContent("2 telemetry queries");
|
|
417
450
|
expect(usage).toHaveTextContent("1,234 tokens");
|
|
451
|
+
expect(usage).toHaveTextContent(
|
|
452
|
+
"Read-only — nothing in your systems was changed",
|
|
453
|
+
);
|
|
418
454
|
expect(fixButton()).toBeEnabled();
|
|
419
455
|
expect(screen.getByRole("button", { name: "Confirmed" })).toBeEnabled();
|
|
420
456
|
expect(screen.getByRole("button", { name: "Rejected" })).toBeEnabled();
|
|
@@ -612,9 +648,15 @@ describe("InvestigationPanel report lifecycle", () => {
|
|
|
612
648
|
|
|
613
649
|
expect(screen.getByText("Investigation did not finish")).toBeVisible();
|
|
614
650
|
expect(screen.getByText("The model provider timed out.")).toBeVisible();
|
|
651
|
+
expect(
|
|
652
|
+
screen.getByText("The investigation stopped before it could report."),
|
|
653
|
+
).toBeVisible();
|
|
654
|
+
expect(
|
|
655
|
+
screen.getByText("What the investigation got through"),
|
|
656
|
+
).toBeVisible();
|
|
615
657
|
expect(lastActivityProps()).toEqual(
|
|
616
658
|
expect.objectContaining({
|
|
617
|
-
|
|
659
|
+
hideChrome: true,
|
|
618
660
|
showLiveIndicator: false,
|
|
619
661
|
}),
|
|
620
662
|
);
|
|
@@ -637,6 +679,475 @@ describe("InvestigationPanel report lifecycle", () => {
|
|
|
637
679
|
});
|
|
638
680
|
});
|
|
639
681
|
|
|
682
|
+
/*
|
|
683
|
+
* Every state of the card has to stand on its own: a responder can land on it
|
|
684
|
+
* while the run is queued, live, failed, or finished. These tests pin the
|
|
685
|
+
* framing and the plain-language explanation each state owes the reader.
|
|
686
|
+
*/
|
|
687
|
+
describe("InvestigationPanel card states", () => {
|
|
688
|
+
test("frames the live run and says what it is doing and that it cannot change anything", async () => {
|
|
689
|
+
postMock.mockResolvedValue(
|
|
690
|
+
successfulResponse(
|
|
691
|
+
investigationPayload({
|
|
692
|
+
status: AIRunStatus.Running,
|
|
693
|
+
events: [activityEvent],
|
|
694
|
+
}),
|
|
695
|
+
) as never,
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
renderPanel();
|
|
699
|
+
await flush();
|
|
700
|
+
|
|
701
|
+
const live: HTMLElement = screen.getByLabelText("Live investigation");
|
|
702
|
+
expect(live).toHaveTextContent("OneUptime AI is investigating");
|
|
703
|
+
expect(live).toHaveTextContent("Read-only — nothing is changed");
|
|
704
|
+
expect(live).toContainElement(screen.getByTestId("investigation-activity"));
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
test("explains the wait while the run is only queued", async () => {
|
|
708
|
+
postMock.mockResolvedValue(
|
|
709
|
+
successfulResponse(
|
|
710
|
+
investigationPayload({ status: AIRunStatus.Queued }),
|
|
711
|
+
) as never,
|
|
712
|
+
);
|
|
713
|
+
|
|
714
|
+
renderPanel();
|
|
715
|
+
await flush();
|
|
716
|
+
|
|
717
|
+
expect(screen.getByLabelText("Live investigation")).toHaveTextContent(
|
|
718
|
+
"Waiting for a worker to pick this up",
|
|
719
|
+
);
|
|
720
|
+
expect(screen.getByText("Starting investigation…")).toBeVisible();
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
test("puts a copy control on the report so it can be pasted elsewhere", async () => {
|
|
724
|
+
postMock.mockResolvedValue(completedResponse() as never);
|
|
725
|
+
|
|
726
|
+
renderPanel();
|
|
727
|
+
await flush();
|
|
728
|
+
|
|
729
|
+
const report: HTMLElement = screen.getByLabelText("Investigation report");
|
|
730
|
+
expect(report).toHaveTextContent("AI generated");
|
|
731
|
+
expect(report).toContainElement(
|
|
732
|
+
screen.getByRole("button", { name: "Copy report" }),
|
|
733
|
+
);
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
/*
|
|
737
|
+
* A queued run carries a stats object whose counts are all zero, so an
|
|
738
|
+
* ungated strip would tell the reader the AI ran zero queries and changed
|
|
739
|
+
* nothing — a past-tense report on work that has not started, directly
|
|
740
|
+
* under "waiting for a worker".
|
|
741
|
+
*/
|
|
742
|
+
test.each([AIRunStatus.Running, AIRunStatus.Queued])(
|
|
743
|
+
"shows no usage strip while a %s run has not produced anything yet",
|
|
744
|
+
async (status: AIRunStatus) => {
|
|
745
|
+
postMock.mockResolvedValue(
|
|
746
|
+
successfulResponse(
|
|
747
|
+
investigationPayload({
|
|
748
|
+
status,
|
|
749
|
+
toolCallCount: 0,
|
|
750
|
+
totalTokens: 0,
|
|
751
|
+
}),
|
|
752
|
+
) as never,
|
|
753
|
+
);
|
|
754
|
+
|
|
755
|
+
renderPanel();
|
|
756
|
+
await flush();
|
|
757
|
+
|
|
758
|
+
expect(screen.queryByLabelText("Investigation usage")).toBeNull();
|
|
759
|
+
expect(
|
|
760
|
+
screen.queryByText(/nothing in your systems was changed/),
|
|
761
|
+
).toBeNull();
|
|
762
|
+
},
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
/*
|
|
766
|
+
* Events and rendered steps are not the same thing: RunFailed and the
|
|
767
|
+
* completion halves of tool/LLM calls only close a step an earlier event
|
|
768
|
+
* opened. A run whose RunStarted failed to persist and then failed outright
|
|
769
|
+
* carries one event and draws nothing, and counting raw events would frame
|
|
770
|
+
* an empty panel instead of saying what happened.
|
|
771
|
+
*/
|
|
772
|
+
test("explains an empty trail instead of framing a blank panel", async () => {
|
|
773
|
+
hasRenderableActivityMock.mockReturnValue(false);
|
|
774
|
+
postMock.mockResolvedValue(
|
|
775
|
+
successfulResponse(
|
|
776
|
+
investigationPayload({
|
|
777
|
+
status: AIRunStatus.Error,
|
|
778
|
+
errorMessage: "The provider timed out.",
|
|
779
|
+
events: [activityEvent],
|
|
780
|
+
}),
|
|
781
|
+
) as never,
|
|
782
|
+
);
|
|
783
|
+
|
|
784
|
+
renderPanel();
|
|
785
|
+
await flush();
|
|
786
|
+
|
|
787
|
+
expect(screen.queryByTestId("investigation-activity")).toBeNull();
|
|
788
|
+
expect(
|
|
789
|
+
screen.getByText("No investigation steps were recorded."),
|
|
790
|
+
).toBeVisible();
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
test("hides the completed activity disclosure when no step would render", async () => {
|
|
794
|
+
hasRenderableActivityMock.mockReturnValue(false);
|
|
795
|
+
postMock.mockResolvedValue(completedResponse() as never);
|
|
796
|
+
|
|
797
|
+
renderPanel();
|
|
798
|
+
await flush();
|
|
799
|
+
|
|
800
|
+
expect(screen.getByLabelText("Investigation report")).toBeInTheDocument();
|
|
801
|
+
expect(screen.queryByText("Investigation activity")).toBeNull();
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
test("reports a single query without pluralising it", async () => {
|
|
805
|
+
postMock.mockResolvedValue(
|
|
806
|
+
completedResponse({ toolCallCount: 1, totalTokens: 0 }) as never,
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
renderPanel();
|
|
810
|
+
await flush();
|
|
811
|
+
|
|
812
|
+
const usage: HTMLElement = screen.getByLabelText("Investigation usage");
|
|
813
|
+
expect(usage).toHaveTextContent("1 telemetry query");
|
|
814
|
+
expect(usage).not.toHaveTextContent("tokens");
|
|
815
|
+
});
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
/*
|
|
819
|
+
* The TL;DR is the first thing on the card, and it is AI prose about the
|
|
820
|
+
* report below it. So it must never appear without that report, must never be
|
|
821
|
+
* rendered as markdown, and must be dropped the instant the panel changes
|
|
822
|
+
* subject — a summary of the previous incident is worse than no summary.
|
|
823
|
+
*/
|
|
824
|
+
describe("InvestigationPanel TL;DR", () => {
|
|
825
|
+
function markdownTexts(): Array<string> {
|
|
826
|
+
return (
|
|
827
|
+
markdownViewerMock.mock.calls as Array<Array<MarkdownViewerProps>>
|
|
828
|
+
).map((call: Array<MarkdownViewerProps>): string => {
|
|
829
|
+
return call[0]!.text;
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
test("leads the completed card with the AI summary, as plain text above the report", async () => {
|
|
834
|
+
postMock.mockResolvedValue(
|
|
835
|
+
completedResponse({ analysisTldr: TLDR }) as never,
|
|
836
|
+
);
|
|
837
|
+
|
|
838
|
+
renderPanel();
|
|
839
|
+
await flush();
|
|
840
|
+
|
|
841
|
+
const summary: HTMLElement = screen.getByLabelText("Investigation summary");
|
|
842
|
+
expect(summary).toHaveTextContent("TL;DR");
|
|
843
|
+
expect(summary).toHaveTextContent(TLDR);
|
|
844
|
+
|
|
845
|
+
// The summary is never routed through the markdown renderer.
|
|
846
|
+
expect(markdownTexts().length).toBeGreaterThan(0);
|
|
847
|
+
expect(
|
|
848
|
+
markdownTexts().every((text: string): boolean => {
|
|
849
|
+
return text === ANALYSIS;
|
|
850
|
+
}),
|
|
851
|
+
).toBe(true);
|
|
852
|
+
|
|
853
|
+
// It sits above the report it summarizes.
|
|
854
|
+
const report: HTMLElement = screen.getByLabelText("Investigation report");
|
|
855
|
+
expect(
|
|
856
|
+
summary.compareDocumentPosition(report) &
|
|
857
|
+
Node.DOCUMENT_POSITION_FOLLOWING,
|
|
858
|
+
).toBeTruthy();
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
test("omits the block for a run that has no stored summary", async () => {
|
|
862
|
+
postMock.mockResolvedValue(completedResponse() as never);
|
|
863
|
+
|
|
864
|
+
renderPanel();
|
|
865
|
+
await flush();
|
|
866
|
+
|
|
867
|
+
expect(screen.getByLabelText("Investigation report")).toBeInTheDocument();
|
|
868
|
+
expect(screen.queryByLabelText("Investigation summary")).toBeNull();
|
|
869
|
+
expect(screen.queryByText("TL;DR")).toBeNull();
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
test("omits a blank summary rather than rendering an empty banner", async () => {
|
|
873
|
+
postMock.mockResolvedValue(
|
|
874
|
+
completedResponse({ analysisTldr: " \n " }) as never,
|
|
875
|
+
);
|
|
876
|
+
|
|
877
|
+
renderPanel();
|
|
878
|
+
await flush();
|
|
879
|
+
|
|
880
|
+
expect(screen.queryByLabelText("Investigation summary")).toBeNull();
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
test("never shows a summary before the report it describes is published", async () => {
|
|
884
|
+
postMock.mockResolvedValue(
|
|
885
|
+
completedResponse({
|
|
886
|
+
analysisMarkdown: null,
|
|
887
|
+
analysisTldr: TLDR,
|
|
888
|
+
isAnalysisPending: true,
|
|
889
|
+
}) as never,
|
|
890
|
+
);
|
|
891
|
+
|
|
892
|
+
renderPanel();
|
|
893
|
+
await flush();
|
|
894
|
+
|
|
895
|
+
expect(screen.queryByLabelText("Investigation summary")).toBeNull();
|
|
896
|
+
expect(screen.queryByText(TLDR)).toBeNull();
|
|
897
|
+
expect(screen.getByText("Preparing the final report")).toBeVisible();
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
test("appears on the poll that publishes the report", async () => {
|
|
901
|
+
postMock
|
|
902
|
+
.mockResolvedValueOnce(
|
|
903
|
+
completedResponse({
|
|
904
|
+
analysisMarkdown: null,
|
|
905
|
+
analysisTldr: null,
|
|
906
|
+
isAnalysisPending: true,
|
|
907
|
+
}) as never,
|
|
908
|
+
)
|
|
909
|
+
.mockResolvedValue(completedResponse({ analysisTldr: TLDR }) as never);
|
|
910
|
+
|
|
911
|
+
renderPanel();
|
|
912
|
+
await flush();
|
|
913
|
+
expect(screen.queryByLabelText("Investigation summary")).toBeNull();
|
|
914
|
+
|
|
915
|
+
await advanceFastPolls();
|
|
916
|
+
|
|
917
|
+
expect(screen.getByLabelText("Investigation summary")).toHaveTextContent(
|
|
918
|
+
TLDR,
|
|
919
|
+
);
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
test("is not shown for a run that never completed", async () => {
|
|
923
|
+
postMock.mockResolvedValue(
|
|
924
|
+
successfulResponse(
|
|
925
|
+
investigationPayload({
|
|
926
|
+
status: AIRunStatus.Error,
|
|
927
|
+
analysisTldr: TLDR,
|
|
928
|
+
errorMessage: "The provider timed out.",
|
|
929
|
+
}),
|
|
930
|
+
) as never,
|
|
931
|
+
);
|
|
932
|
+
|
|
933
|
+
renderPanel();
|
|
934
|
+
await flush();
|
|
935
|
+
|
|
936
|
+
expect(screen.queryByLabelText("Investigation summary")).toBeNull();
|
|
937
|
+
expect(screen.getByText("The provider timed out.")).toBeVisible();
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
/*
|
|
941
|
+
* The report is recomputed from the feed on every poll, so it can vanish
|
|
942
|
+
* (a deleted feed item) while the run stays Completed. The summary must go
|
|
943
|
+
* with it — a summary of a report the reader cannot see is worse than none.
|
|
944
|
+
* Cadence matters: a settled Recommended run polls at the SETTLED interval,
|
|
945
|
+
* so advancing by the fast interval would make this pass vacuously.
|
|
946
|
+
*/
|
|
947
|
+
test("drops the summary if the report it describes disappears on a later poll", async () => {
|
|
948
|
+
postMock
|
|
949
|
+
.mockResolvedValueOnce(completedResponse({ analysisTldr: TLDR }) as never)
|
|
950
|
+
.mockResolvedValue(
|
|
951
|
+
completedResponse({
|
|
952
|
+
analysisMarkdown: null,
|
|
953
|
+
analysisTldr: TLDR,
|
|
954
|
+
}) as never,
|
|
955
|
+
);
|
|
956
|
+
|
|
957
|
+
renderPanel();
|
|
958
|
+
await flush();
|
|
959
|
+
expect(screen.getByLabelText("Investigation summary")).toHaveTextContent(
|
|
960
|
+
TLDR,
|
|
961
|
+
);
|
|
962
|
+
|
|
963
|
+
await tick(SETTLED_POLL_INTERVAL_MS);
|
|
964
|
+
|
|
965
|
+
expect(postMock).toHaveBeenCalledTimes(2);
|
|
966
|
+
expect(screen.queryByLabelText("Investigation summary")).toBeNull();
|
|
967
|
+
expect(screen.queryByText(TLDR)).toBeNull();
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
/*
|
|
971
|
+
* "Never attributed to the wrong run" — the same subject can be
|
|
972
|
+
* re-investigated, and the previous run's summary must not survive onto the
|
|
973
|
+
* new run's report.
|
|
974
|
+
*/
|
|
975
|
+
test("does not carry a summary over to a new run on the same subject", async () => {
|
|
976
|
+
const nextAnalysis: string = "## Root cause\n\nA second, different cause.";
|
|
977
|
+
postMock
|
|
978
|
+
.mockResolvedValueOnce(completedResponse({ analysisTldr: TLDR }) as never)
|
|
979
|
+
.mockResolvedValue(
|
|
980
|
+
completedResponse({
|
|
981
|
+
runId: NEXT_RUN_ID,
|
|
982
|
+
analysisMarkdown: nextAnalysis,
|
|
983
|
+
analysisTldr: null,
|
|
984
|
+
}) as never,
|
|
985
|
+
);
|
|
986
|
+
|
|
987
|
+
renderPanel();
|
|
988
|
+
await flush();
|
|
989
|
+
expect(screen.getByLabelText("Investigation summary")).toBeInTheDocument();
|
|
990
|
+
|
|
991
|
+
await tick(SETTLED_POLL_INTERVAL_MS);
|
|
992
|
+
|
|
993
|
+
expect(screen.queryByLabelText("Investigation summary")).toBeNull();
|
|
994
|
+
expect(screen.queryByText(TLDR)).toBeNull();
|
|
995
|
+
expect(screen.getByTestId("investigation-markdown")).toHaveTextContent(
|
|
996
|
+
"A second, different cause.",
|
|
997
|
+
);
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
/*
|
|
1001
|
+
* The module's threat model is "the worst a prompt injection achieves is a
|
|
1002
|
+
* misleading sentence". That holds only while the summary is rendered as
|
|
1003
|
+
* inert text — never as markdown, never as HTML.
|
|
1004
|
+
*/
|
|
1005
|
+
test("renders hostile summary content inertly, as text", async () => {
|
|
1006
|
+
const hostile: string =
|
|
1007
|
+
'<img src=x onerror="window.__pwned = true"> **bold** [link](https://evil.example)';
|
|
1008
|
+
postMock.mockResolvedValue(
|
|
1009
|
+
completedResponse({ analysisTldr: hostile }) as never,
|
|
1010
|
+
);
|
|
1011
|
+
|
|
1012
|
+
renderPanel();
|
|
1013
|
+
await flush();
|
|
1014
|
+
|
|
1015
|
+
const summary: HTMLElement = screen.getByLabelText("Investigation summary");
|
|
1016
|
+
expect(summary).toHaveTextContent(hostile);
|
|
1017
|
+
expect(summary.querySelector("img")).toBeNull();
|
|
1018
|
+
expect(summary.querySelector("a")).toBeNull();
|
|
1019
|
+
expect(
|
|
1020
|
+
(window as unknown as { __pwned?: boolean }).__pwned,
|
|
1021
|
+
).toBeUndefined();
|
|
1022
|
+
// The summary never reaches the markdown renderer.
|
|
1023
|
+
expect(
|
|
1024
|
+
markdownTexts().every((text: string): boolean => {
|
|
1025
|
+
return text === ANALYSIS;
|
|
1026
|
+
}),
|
|
1027
|
+
).toBe(true);
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
test("drops the previous subject's summary the moment the subject changes", async () => {
|
|
1031
|
+
const nextSubject: Deferred<ApiResponse> = createDeferred<ApiResponse>();
|
|
1032
|
+
postMock
|
|
1033
|
+
.mockResolvedValueOnce(completedResponse({ analysisTldr: TLDR }) as never)
|
|
1034
|
+
.mockReturnValueOnce(nextSubject.promise as never);
|
|
1035
|
+
|
|
1036
|
+
const view: ReturnType<typeof render> = renderPanel();
|
|
1037
|
+
await flush();
|
|
1038
|
+
expect(screen.getByLabelText("Investigation summary")).toBeInTheDocument();
|
|
1039
|
+
|
|
1040
|
+
view.rerender(
|
|
1041
|
+
<InvestigationPanel subjectType="alert" subjectId={ALERT_ID} />,
|
|
1042
|
+
);
|
|
1043
|
+
await flush();
|
|
1044
|
+
|
|
1045
|
+
expect(screen.queryByLabelText("Investigation summary")).toBeNull();
|
|
1046
|
+
|
|
1047
|
+
await resolveDeferred(
|
|
1048
|
+
nextSubject,
|
|
1049
|
+
completedResponse({
|
|
1050
|
+
runId: NEXT_RUN_ID,
|
|
1051
|
+
analysisTldr: "The alert cleared on its own after the pod restarted.",
|
|
1052
|
+
}),
|
|
1053
|
+
);
|
|
1054
|
+
|
|
1055
|
+
expect(screen.getByLabelText("Investigation summary")).toHaveTextContent(
|
|
1056
|
+
"The alert cleared on its own after the pod restarted.",
|
|
1057
|
+
);
|
|
1058
|
+
});
|
|
1059
|
+
});
|
|
1060
|
+
|
|
1061
|
+
/*
|
|
1062
|
+
* The verdict prompt is a single question with two answers, so both choices
|
|
1063
|
+
* live in one labelled group; once answered it collapses to the recorded
|
|
1064
|
+
* verdict plus a way back. These tests pin that shape — the earlier suites
|
|
1065
|
+
* cover the request/optimistic-state contract behind it.
|
|
1066
|
+
*/
|
|
1067
|
+
describe("InvestigationPanel verdict control", () => {
|
|
1068
|
+
function verdictGroup(): HTMLElement | null {
|
|
1069
|
+
return screen.queryByRole("group", { name: "Rate this investigation" });
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
test("offers both verdicts inside one labelled group", async () => {
|
|
1073
|
+
postMock.mockResolvedValue(completedResponse() as never);
|
|
1074
|
+
|
|
1075
|
+
renderPanel();
|
|
1076
|
+
await flush();
|
|
1077
|
+
|
|
1078
|
+
const group: HTMLElement = verdictGroup()!;
|
|
1079
|
+
expect(group).toBeInTheDocument();
|
|
1080
|
+
expect(
|
|
1081
|
+
screen.getByRole("button", { name: "Confirmed" }),
|
|
1082
|
+
).toBeInTheDocument();
|
|
1083
|
+
expect(
|
|
1084
|
+
screen.getByRole("button", { name: "Rejected" }),
|
|
1085
|
+
).toBeInTheDocument();
|
|
1086
|
+
expect(group).toContainElement(
|
|
1087
|
+
screen.getByRole("button", { name: "Confirmed" }),
|
|
1088
|
+
);
|
|
1089
|
+
expect(group).toContainElement(
|
|
1090
|
+
screen.getByRole("button", { name: "Rejected" }),
|
|
1091
|
+
);
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
test("collapses to the recorded verdict and back again through Change", async () => {
|
|
1095
|
+
postMock
|
|
1096
|
+
.mockResolvedValueOnce(completedResponse() as never)
|
|
1097
|
+
.mockResolvedValueOnce(successfulResponse({}) as never);
|
|
1098
|
+
|
|
1099
|
+
renderPanel();
|
|
1100
|
+
await flush();
|
|
1101
|
+
fireEvent.click(screen.getByRole("button", { name: "Rejected" }));
|
|
1102
|
+
await flush();
|
|
1103
|
+
|
|
1104
|
+
expect(verdictGroup()).toBeNull();
|
|
1105
|
+
expect(screen.getByText(/You rejected this analysis/)).toBeVisible();
|
|
1106
|
+
|
|
1107
|
+
fireEvent.click(screen.getByRole("button", { name: "Change" }));
|
|
1108
|
+
|
|
1109
|
+
expect(verdictGroup()).toBeInTheDocument();
|
|
1110
|
+
expect(screen.getByRole("button", { name: "Confirmed" })).toBeEnabled();
|
|
1111
|
+
expect(screen.getByRole("button", { name: "Rejected" })).toBeEnabled();
|
|
1112
|
+
// Reopening the prompt must not itself save anything.
|
|
1113
|
+
expect(postMock).toHaveBeenCalledTimes(2);
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
test("locks both choices while a verdict is saving", async () => {
|
|
1117
|
+
const save: Deferred<ApiResponse> = createDeferred<ApiResponse>();
|
|
1118
|
+
postMock
|
|
1119
|
+
.mockResolvedValueOnce(completedResponse() as never)
|
|
1120
|
+
.mockReturnValueOnce(save.promise as never);
|
|
1121
|
+
|
|
1122
|
+
renderPanel();
|
|
1123
|
+
await flush();
|
|
1124
|
+
fireEvent.click(screen.getByRole("button", { name: "Confirmed" }));
|
|
1125
|
+
await flush();
|
|
1126
|
+
|
|
1127
|
+
// Optimistic: the pill replaces the prompt immediately.
|
|
1128
|
+
expect(screen.getByText(/You confirmed this analysis/)).toBeVisible();
|
|
1129
|
+
|
|
1130
|
+
fireEvent.click(screen.getByRole("button", { name: "Change" }));
|
|
1131
|
+
expect(screen.getByRole("button", { name: "Confirmed" })).toBeDisabled();
|
|
1132
|
+
expect(screen.getByRole("button", { name: "Rejected" })).toBeDisabled();
|
|
1133
|
+
|
|
1134
|
+
await resolveDeferred(save, successfulResponse({}));
|
|
1135
|
+
|
|
1136
|
+
expect(screen.getByRole("button", { name: "Confirmed" })).toBeEnabled();
|
|
1137
|
+
});
|
|
1138
|
+
|
|
1139
|
+
test("shows the run status as a badge in the card header", async () => {
|
|
1140
|
+
postMock.mockResolvedValue(completedResponse() as never);
|
|
1141
|
+
|
|
1142
|
+
renderPanel();
|
|
1143
|
+
await flush();
|
|
1144
|
+
|
|
1145
|
+
expect(screen.getByLabelText("Investigation status")).toHaveTextContent(
|
|
1146
|
+
"Investigation complete",
|
|
1147
|
+
);
|
|
1148
|
+
});
|
|
1149
|
+
});
|
|
1150
|
+
|
|
640
1151
|
describe("InvestigationPanel code-fix recommendation", () => {
|
|
641
1152
|
test("shows the fix action only for an explicit Recommended decision", async () => {
|
|
642
1153
|
postMock.mockResolvedValue(completedResponse() as never);
|