@oneuptime/common 12.0.4 → 12.0.5
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 +38 -1
- package/Models/DatabaseModels/AlertFeed.ts +30 -0
- package/Models/DatabaseModels/Dashboard.ts +28 -0
- package/Models/DatabaseModels/Incident.ts +2 -0
- package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
- package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
- package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentFeed.ts +30 -0
- package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
- package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
- package/Models/DatabaseModels/LogSavedView.ts +33 -0
- package/Models/DatabaseModels/Project.ts +231 -9
- package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
- package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
- package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
- package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.ts +4 -4
- package/Models/DatabaseModels/StatusPage.ts +28 -0
- package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
- package/Server/API/AIAgentDataAPI.ts +44 -55
- package/Server/API/AIInvestigationAPI.ts +175 -17
- package/Server/API/DashboardAPI.ts +10 -10
- package/Server/API/StatusPageAPI.ts +38 -19
- package/Server/EnvironmentConfig.ts +16 -0
- package/Server/Infrastructure/ClickhouseConfig.ts +15 -1
- package/Server/Infrastructure/ClickhouseDatabase.ts +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.ts +27 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.ts +89 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.ts +27 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.ts +40 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.ts +26 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Services/AIRunService.ts +78 -10
- package/Server/Services/AIService.ts +94 -22
- package/Server/Services/AlertFeedService.ts +5 -0
- package/Server/Services/AnalyticsDatabaseService.ts +29 -0
- package/Server/Services/DatabaseService.ts +43 -2
- package/Server/Services/IncidentFeedService.ts +5 -0
- package/Server/Services/LlmLogService.ts +46 -2
- package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +6 -0
- package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +4 -0
- package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +8 -5
- package/Server/Utils/AI/CodeFix/FixRunBudget.ts +90 -16
- package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +2 -0
- package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +2 -0
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +223 -22
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +25 -24
- package/Server/Utils/AI/SRE/ConfidenceSignal.ts +182 -71
- package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +252 -43
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +25 -24
- package/Server/Utils/AI/SRE/InstrumentationTaskTrigger.ts +47 -13
- package/Server/Utils/AI/SRE/InvestigationGrader.ts +9 -5
- package/Server/Utils/AI/SRE/InvestigationQueue.ts +141 -24
- package/Server/Utils/AI/SRE/InvestigationSubjectLock.ts +66 -0
- package/Server/Utils/AI/SRE/PostedRootCause.ts +94 -3
- package/Server/Utils/AI/SRE/README.md +1 -1
- package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +132 -10
- package/Server/Utils/AnalyticsDatabase/ClusterConfig.ts +24 -0
- package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +29 -0
- package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +56 -0
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +46 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
- package/Server/Utils/PasswordHash.ts +28 -4
- package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +251 -0
- package/Tests/App/Dashboard/EventStatusPanel.test.tsx +747 -0
- package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +480 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1184 -0
- package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +500 -0
- package/Tests/App/Dashboard/PortMonitorCriteriaFilter.test.ts +93 -0
- package/Tests/App/StatusPage/PublicStatusPageAPIErrorHandling.test.ts +117 -0
- package/Tests/App/StatusPage/StatusPageModelAPIPolymorphism.test.ts +223 -0
- package/Tests/Models/DatabaseModels/PermissionCatalogueCoverage.test.ts +243 -0
- package/Tests/Server/API/AIAgentDataFixFromIncidentContext.test.ts +266 -0
- package/Tests/Server/API/AIInvestigationAPI.test.ts +594 -0
- package/Tests/Server/API/AIInvestigationCreateFixTask.test.ts +80 -0
- package/Tests/Server/API/DashboardMasterPasswordAPI.test.ts +172 -1
- package/Tests/Server/API/StatusPageMasterPasswordAPI.test.ts +335 -0
- package/Tests/Server/Services/AIRunCodeFixClaim.test.ts +59 -5
- package/Tests/Server/Services/AIRunHumanVerdict.test.ts +127 -58
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +396 -20
- package/Tests/Server/Services/AddMasterPasswordSaltMigration.test.ts +283 -0
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +25 -1
- package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +45 -35
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsWithoutHooks.test.ts +54 -0
- package/Tests/Server/Services/FeedAIRunAssociation.test.ts +125 -0
- package/Tests/Server/Services/FixFromIncidentTaskTrigger.test.ts +418 -57
- package/Tests/Server/Services/InstrumentationTaskTrigger.test.ts +173 -14
- package/Tests/Server/Services/MasterPasswordScrypt.test.ts +567 -0
- package/Tests/Server/Services/SeparateIncidentAlertAiSettingsMigration.test.ts +194 -0
- package/Tests/Server/Utils/AI/AIAlertGating.test.ts +37 -4
- package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +330 -29
- package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +25 -0
- package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +293 -5
- package/Tests/Server/Utils/AI/CodeFixAgentCompletion.test.ts +59 -1
- package/Tests/Server/Utils/AI/FixFromIncidentAutoTrigger.test.ts +342 -19
- package/Tests/Server/Utils/AI/FixRunBudget.test.ts +214 -30
- package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +2 -0
- package/Tests/Server/Utils/AI/InvestigationGrader.test.ts +65 -17
- package/Tests/Server/Utils/AI/InvestigationQueueRemediationExecution.test.ts +3 -0
- package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +313 -20
- package/Tests/Server/Utils/AI/PostedRootCause.test.ts +254 -0
- package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +4 -0
- package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +2 -0
- package/Tests/Server/Utils/AI/SubjectCodeFixRunDedupe.test.ts +44 -0
- package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +212 -0
- package/Tests/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.test.ts +401 -0
- package/Tests/Server/Utils/Monitor/MonitorMetricUtilPortTimings.test.ts +243 -0
- package/Tests/Server/Utils/PasswordHash.test.ts +30 -0
- package/Tests/Types/Dashboard/DashboardTemplates.test.ts +111 -0
- package/Tests/Types/Monitor/CephMetricCatalog.test.ts +104 -0
- package/Tests/Types/Monitor/CriteriaFilter.test.ts +4 -0
- package/Tests/Types/Monitor/DockerMetricCatalog.test.ts +109 -0
- package/Tests/Types/Monitor/DockerSwarmMetricCatalog.test.ts +118 -0
- package/Tests/Types/Monitor/HostMetricCatalog.test.ts +104 -0
- package/Tests/Types/Monitor/IotMetricCatalog.test.ts +104 -0
- package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +118 -0
- package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +42 -0
- package/Tests/Types/Monitor/MonitorStep.test.ts +38 -0
- package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +75 -0
- package/Tests/Types/Monitor/PodmanMetricCatalog.test.ts +109 -0
- package/Tests/Types/Monitor/ProxmoxMetricCatalog.test.ts +107 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.test.ts +151 -0
- package/Tests/Types/Permission.test.ts +137 -0
- package/Tests/Types/Rum/SessionReplayMaskingMode.test.ts +101 -0
- package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +5 -5
- package/Tests/UI/Components/CardModelDetailEdit.test.tsx +3 -5
- package/Tests/UI/Components/ErrorBoundary.test.tsx +158 -0
- package/Tests/UI/Components/FeedItemSafeMode.test.tsx +74 -0
- package/Tests/UI/Components/MoreMenu.test.tsx +756 -0
- package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +62 -0
- package/Tests/UI/Monitor/PortMonitorView.test.tsx +237 -0
- package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +91 -0
- package/Tests/UI/Utils/DownloadFile.test.ts +103 -0
- package/Tests/UI/Utils/ErrorSupportBundle.test.ts +582 -0
- package/Tests/UI/Utils/Project.test.ts +31 -0
- package/Tests/UI/Utils/StatusPageModelAPIInjection.test.ts +245 -0
- package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +820 -0
- package/Tests/Utils/Dashboard/DashboardViewConfig.test.ts +329 -0
- package/Tests/Utils/Dashboard/GridLayout.test.ts +951 -0
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +117 -0
- package/Tests/Utils/RecordingRuleExpression.test.ts +327 -0
- package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +186 -0
- package/Tests/Utils/StatusPage/GroupTree.test.ts +456 -0
- package/Tests/Utils/StatusPage/OverviewGroupHierarchyVisibility.test.ts +588 -0
- package/Tests/Utils/Telemetry/SavedViewTimeRange.test.ts +244 -0
- package/Tests/Utils/Telemetry/TelemetryQueryTimeRange.test.ts +825 -0
- package/Types/AI/AIRunCodeFixRecommendation.ts +17 -0
- package/Types/AI/CodeFixTaskContext.ts +63 -3
- package/Types/AI/CodeFixTaskType.ts +3 -3
- package/Types/HashedString.ts +4 -3
- package/Types/Monitor/CriteriaFilter.ts +4 -0
- package/Types/Monitor/DomainMonitor/DomainLookupMethod.ts +23 -0
- package/Types/Monitor/DomainMonitor/DomainMonitorResponse.ts +7 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +24 -7
- package/Types/Monitor/MonitorMetricType.ts +8 -0
- package/Types/Monitor/MonitorStep.ts +10 -1
- package/Types/Monitor/MonitorStepDomainMonitor.ts +21 -0
- package/Types/Monitor/PortMonitor/PortMonitorTimings.ts +10 -0
- package/Types/Permission.ts +23 -175
- package/Types/Probe/ProbeMonitorResponse.ts +6 -0
- package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +2 -3
- package/UI/Components/ErrorBoundary.tsx +138 -11
- package/UI/Components/Feed/FeedItem.tsx +9 -2
- package/UI/Components/ModelDetail/CardModelDetail.tsx +0 -12
- package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +12 -2
- package/UI/Components/MoreMenu/MoreMenu.tsx +285 -97
- package/UI/Components/MoreMenu/MoreMenuItem.tsx +8 -5
- package/UI/Utils/DownloadFile.ts +16 -8
- package/UI/Utils/ErrorSupportBundle.ts +805 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +19 -8
- package/UI/Utils/Project.ts +4 -0
- package/UI/Utils/StatusPage.ts +8 -2
- package/UI/Utils/UseDashboardGridDnd.ts +917 -0
- package/Utils/Dashboard/DashboardViewConfig.ts +80 -36
- package/Utils/Dashboard/GridLayout.ts +523 -0
- package/Utils/Metrics/RecordingRuleExpression.ts +19 -17
- package/Utils/Monitor/MonitorMetricType.ts +44 -2
- package/Utils/StatusPage/GroupNestingLayout.ts +69 -0
- package/Utils/StatusPage/GroupTree.ts +157 -66
- package/Utils/StatusPage/ResourceUptime.ts +37 -2
- package/Utils/Telemetry/SavedViewTimeRange.ts +114 -0
- package/Utils/Telemetry/TelemetryQueryTimeRange.ts +334 -0
- package/build/dist/Models/DatabaseModels/AIRun.js +39 -1
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertFeed.js +32 -0
- package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Dashboard.js +29 -0
- package/build/dist/Models/DatabaseModels/Dashboard.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +2 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentFeed.js +32 -0
- package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogSavedView.js +33 -0
- package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +241 -11
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js +4 -4
- package/build/dist/Models/DatabaseModels/StatusPage.js +29 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +28 -46
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +111 -11
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +8 -5
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +29 -11
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +14 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js +12 -1
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js +36 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +58 -12
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +74 -21
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertFeedService.js +3 -0
- package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +29 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +21 -2
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentFeedService.js +3 -0
- package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
- package/build/dist/Server/Services/LlmLogService.js +22 -1
- package/build/dist/Server/Services/LlmLogService.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +4 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +8 -5
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +63 -24
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +2 -0
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +2 -0
- package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +156 -28
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +21 -19
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +128 -49
- package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +170 -31
- package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +21 -19
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js +33 -9
- package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +9 -5
- package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +121 -41
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js +46 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js +61 -14
- package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +79 -1
- package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js +21 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +20 -3
- package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +43 -0
- package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/PasswordHash.js +25 -4
- package/build/dist/Server/Utils/PasswordHash.js.map +1 -1
- package/build/dist/Types/AI/AIRunCodeFixRecommendation.js +18 -0
- package/build/dist/Types/AI/AIRunCodeFixRecommendation.js.map +1 -0
- package/build/dist/Types/AI/CodeFixTaskContext.js +23 -3
- package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
- package/build/dist/Types/AI/CodeFixTaskType.js +3 -3
- package/build/dist/Types/HashedString.js +4 -3
- package/build/dist/Types/HashedString.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +4 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js +24 -0
- package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +24 -7
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
- package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +6 -1
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +15 -0
- package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js +2 -0
- package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js.map +1 -0
- package/build/dist/Types/Permission.js +23 -155
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +2 -5
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
- package/build/dist/UI/Components/ErrorBoundary.js +67 -8
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +2 -2
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +0 -12
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +12 -2
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +193 -65
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
- package/build/dist/UI/Utils/DownloadFile.js +15 -8
- package/build/dist/UI/Utils/DownloadFile.js.map +1 -1
- package/build/dist/UI/Utils/ErrorSupportBundle.js +476 -0
- package/build/dist/UI/Utils/ErrorSupportBundle.js.map +1 -0
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -8
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/Project.js +3 -0
- package/build/dist/UI/Utils/Project.js.map +1 -1
- package/build/dist/UI/Utils/StatusPage.js +4 -4
- package/build/dist/UI/Utils/StatusPage.js.map +1 -1
- package/build/dist/UI/Utils/UseDashboardGridDnd.js +551 -0
- package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -0
- package/build/dist/Utils/Dashboard/DashboardViewConfig.js +42 -26
- package/build/dist/Utils/Dashboard/DashboardViewConfig.js.map +1 -1
- package/build/dist/Utils/Dashboard/GridLayout.js +338 -0
- package/build/dist/Utils/Dashboard/GridLayout.js.map +1 -0
- package/build/dist/Utils/Metrics/RecordingRuleExpression.js +19 -17
- package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +38 -6
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/StatusPage/GroupNestingLayout.js +46 -0
- package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -1
- package/build/dist/Utils/StatusPage/GroupTree.js +79 -34
- package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -1
- package/build/dist/Utils/StatusPage/ResourceUptime.js +22 -1
- package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
- package/build/dist/Utils/Telemetry/SavedViewTimeRange.js +79 -0
- package/build/dist/Utils/Telemetry/SavedViewTimeRange.js.map +1 -0
- package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js +236 -0
- package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js.map +1 -0
- package/package.json +1 -1
|
@@ -660,6 +660,68 @@ describe("ResourceGroupSection", () => {
|
|
|
660
660
|
});
|
|
661
661
|
});
|
|
662
662
|
|
|
663
|
+
/*
|
|
664
|
+
* A status page whose hierarchy is built but whose monitors are not added
|
|
665
|
+
* yet. This used to be a page that rendered nothing at all; the section has
|
|
666
|
+
* to draw the structure on its own, because that structure is the only thing
|
|
667
|
+
* the operator has put there so far.
|
|
668
|
+
*/
|
|
669
|
+
describe("a hierarchy with no resources anywhere in it", () => {
|
|
670
|
+
type RenderEmptyFunction = (depth: number) => ReactElement;
|
|
671
|
+
|
|
672
|
+
const renderEmpty: RenderEmptyFunction = (depth: number): ReactElement => {
|
|
673
|
+
return (
|
|
674
|
+
<ResourceGroupSection
|
|
675
|
+
depth={depth}
|
|
676
|
+
name={`Level ${depth}`}
|
|
677
|
+
isInitiallyExpanded={true}
|
|
678
|
+
subGroupCount={depth < 3 ? 1 : 0}
|
|
679
|
+
testId={`empty-level-${depth}`}
|
|
680
|
+
subGroupsElement={depth < 3 ? renderEmpty(depth + 1) : undefined}
|
|
681
|
+
hasOwnResources={false}
|
|
682
|
+
/>
|
|
683
|
+
);
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
test("every level is still drawn, and named", () => {
|
|
687
|
+
render(renderEmpty(0));
|
|
688
|
+
|
|
689
|
+
for (let depth: number = 0; depth <= 3; depth++) {
|
|
690
|
+
expect(screen.getByTestId(`empty-level-${depth}`)).toBeInTheDocument();
|
|
691
|
+
expect(screen.getByText(`Level ${depth}`)).toBeInTheDocument();
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
test("each level is still a working disclosure control", () => {
|
|
696
|
+
render(renderEmpty(0));
|
|
697
|
+
|
|
698
|
+
const header: HTMLElement = screen
|
|
699
|
+
.getByTestId("empty-level-1")
|
|
700
|
+
.querySelector("[data-testid='status-page-group-header']")!;
|
|
701
|
+
|
|
702
|
+
expect(header.getAttribute("aria-expanded")).toBe("true");
|
|
703
|
+
expect(screen.getByTestId("empty-level-3")).toBeInTheDocument();
|
|
704
|
+
|
|
705
|
+
fireEvent.click(header);
|
|
706
|
+
|
|
707
|
+
expect(header.getAttribute("aria-expanded")).toBe("false");
|
|
708
|
+
expect(screen.queryByTestId("empty-level-3")).not.toBeInTheDocument();
|
|
709
|
+
expect(screen.getByTestId("empty-level-1")).toBeInTheDocument();
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
/*
|
|
713
|
+
* No resources means no rolled up reading to show. A group header with a
|
|
714
|
+
* number on it that came from nowhere is worse than a header without one.
|
|
715
|
+
*/
|
|
716
|
+
test("no rollup is drawn when the caller has none to give", () => {
|
|
717
|
+
render(renderEmpty(0));
|
|
718
|
+
|
|
719
|
+
expect(
|
|
720
|
+
screen.queryByTestId("status-page-group-rollup"),
|
|
721
|
+
).not.toBeInTheDocument();
|
|
722
|
+
});
|
|
723
|
+
});
|
|
724
|
+
|
|
663
725
|
describe("test ids", () => {
|
|
664
726
|
test("the caller can override the default", () => {
|
|
665
727
|
renderSection({ testId: "my-group" });
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import { describe, expect, it } from "@jest/globals";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import Hostname from "../../../Types/API/Hostname";
|
|
6
|
+
import MonitorType from "../../../Types/Monitor/MonitorType";
|
|
7
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
8
|
+
import Port from "../../../Types/Port";
|
|
9
|
+
import ProbeMonitorResponse from "../../../Types/Probe/ProbeMonitorResponse";
|
|
10
|
+
import { RequestFailedPhase } from "../../../Types/Probe/RequestFailedDetails";
|
|
11
|
+
import SummaryInfo from "../../../../App/FeatureSet/Dashboard/src/Components/Monitor/SummaryView/SummaryInfo";
|
|
12
|
+
|
|
13
|
+
const MONITORED_AT: Date = new Date("2026-08-07T12:30:00.000Z");
|
|
14
|
+
|
|
15
|
+
function buildResponse(
|
|
16
|
+
overrides: Partial<ProbeMonitorResponse> = {},
|
|
17
|
+
): ProbeMonitorResponse {
|
|
18
|
+
return {
|
|
19
|
+
projectId: new ObjectID("11111111-1111-4111-8111-111111111111"),
|
|
20
|
+
monitorId: new ObjectID("22222222-2222-4222-8222-222222222222"),
|
|
21
|
+
monitorStepId: new ObjectID("33333333-3333-4333-8333-333333333333"),
|
|
22
|
+
probeId: new ObjectID("44444444-4444-4444-8444-444444444444"),
|
|
23
|
+
monitorDestination: new Hostname("db.example.com"),
|
|
24
|
+
monitorDestinationPort: new Port(5432),
|
|
25
|
+
isOnline: true,
|
|
26
|
+
responseTimeInMs: 31.27,
|
|
27
|
+
failureCause: "",
|
|
28
|
+
monitoredAt: MONITORED_AT,
|
|
29
|
+
...overrides,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function renderSummary(
|
|
34
|
+
monitorType: MonitorType,
|
|
35
|
+
response: ProbeMonitorResponse,
|
|
36
|
+
): void {
|
|
37
|
+
render(
|
|
38
|
+
<SummaryInfo
|
|
39
|
+
monitorType={monitorType}
|
|
40
|
+
probeMonitorResponses={[response]}
|
|
41
|
+
probeName="London Probe"
|
|
42
|
+
/>,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe("Port monitor summary", () => {
|
|
47
|
+
it("labels the existing response time as the DNS plus TCP total", () => {
|
|
48
|
+
renderSummary(
|
|
49
|
+
MonitorType.Port,
|
|
50
|
+
buildResponse({
|
|
51
|
+
portTimings: {
|
|
52
|
+
dnsLookupInMs: 8.12,
|
|
53
|
+
tcpConnectInMs: 23.15,
|
|
54
|
+
totalConnectionInMs: 31.27,
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
expect(screen.getByText("db.example.com:5432")).toBeInTheDocument();
|
|
60
|
+
expect(
|
|
61
|
+
screen.getByText("Total Connection Time (DNS + TCP)"),
|
|
62
|
+
).toBeInTheDocument();
|
|
63
|
+
expect(screen.getByText("31.27 ms")).toBeInTheDocument();
|
|
64
|
+
expect(screen.queryByText("Response Time (in ms)")).not.toBeInTheDocument();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("shows the measured DNS and TCP phases", () => {
|
|
68
|
+
renderSummary(
|
|
69
|
+
MonitorType.Port,
|
|
70
|
+
buildResponse({
|
|
71
|
+
portTimings: {
|
|
72
|
+
dnsLookupInMs: 8.123,
|
|
73
|
+
tcpConnectInMs: 23.147,
|
|
74
|
+
totalConnectionInMs: 31.27,
|
|
75
|
+
},
|
|
76
|
+
}),
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
expect(screen.getByText("Connection Phase Breakdown")).toBeInTheDocument();
|
|
80
|
+
expect(screen.getByText("DNS Lookup")).toBeInTheDocument();
|
|
81
|
+
expect(screen.getByText("8.12 ms")).toBeInTheDocument();
|
|
82
|
+
expect(screen.getByText("TCP Connect")).toBeInTheDocument();
|
|
83
|
+
expect(screen.getByText("23.15 ms")).toBeInTheDocument();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("omits DNS for an IP target while retaining the TCP phase", () => {
|
|
87
|
+
renderSummary(
|
|
88
|
+
MonitorType.Port,
|
|
89
|
+
buildResponse({
|
|
90
|
+
monitorDestination: new Hostname("192.0.2.10"),
|
|
91
|
+
responseTimeInMs: 4.25,
|
|
92
|
+
portTimings: {
|
|
93
|
+
tcpConnectInMs: 4.25,
|
|
94
|
+
totalConnectionInMs: 4.25,
|
|
95
|
+
},
|
|
96
|
+
}),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
expect(screen.getByText("192.0.2.10:5432")).toBeInTheDocument();
|
|
100
|
+
expect(screen.queryByText("DNS Lookup")).not.toBeInTheDocument();
|
|
101
|
+
expect(screen.getByText("TCP Connect")).toBeInTheDocument();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("renders valid zero-duration measurements instead of missing data", () => {
|
|
105
|
+
renderSummary(
|
|
106
|
+
MonitorType.Port,
|
|
107
|
+
buildResponse({
|
|
108
|
+
responseTimeInMs: 0,
|
|
109
|
+
portTimings: {
|
|
110
|
+
dnsLookupInMs: 0,
|
|
111
|
+
tcpConnectInMs: 0,
|
|
112
|
+
totalConnectionInMs: 0,
|
|
113
|
+
},
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
expect(screen.getAllByText("0 ms")).toHaveLength(3);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("does not invent a missing TCP duration after a DNS-only failure", () => {
|
|
121
|
+
renderSummary(
|
|
122
|
+
MonitorType.Port,
|
|
123
|
+
buildResponse({
|
|
124
|
+
isOnline: false,
|
|
125
|
+
responseTimeInMs: 19,
|
|
126
|
+
failureCause: "DNS lookup failed",
|
|
127
|
+
portTimings: {
|
|
128
|
+
dnsLookupInMs: 19,
|
|
129
|
+
totalConnectionInMs: 19,
|
|
130
|
+
},
|
|
131
|
+
}),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
expect(screen.getByText("DNS Lookup")).toBeInTheDocument();
|
|
135
|
+
expect(screen.queryByText("TCP Connect")).not.toBeInTheDocument();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("keeps older results useful when no phase timings were recorded", () => {
|
|
139
|
+
renderSummary(MonitorType.Port, buildResponse());
|
|
140
|
+
|
|
141
|
+
expect(
|
|
142
|
+
screen.getByText("Total Connection Time (DNS + TCP)"),
|
|
143
|
+
).toBeInTheDocument();
|
|
144
|
+
expect(screen.getByText("31.27 ms")).toBeInTheDocument();
|
|
145
|
+
expect(
|
|
146
|
+
screen.queryByText("Connection Phase Breakdown"),
|
|
147
|
+
).not.toBeInTheDocument();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("uses the compatibility response time for the displayed total", () => {
|
|
151
|
+
renderSummary(
|
|
152
|
+
MonitorType.Port,
|
|
153
|
+
buildResponse({
|
|
154
|
+
responseTimeInMs: 25,
|
|
155
|
+
portTimings: {
|
|
156
|
+
dnsLookupInMs: 5,
|
|
157
|
+
tcpConnectInMs: 20,
|
|
158
|
+
totalConnectionInMs: 999,
|
|
159
|
+
},
|
|
160
|
+
}),
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
expect(screen.getByText("25 ms")).toBeInTheDocument();
|
|
164
|
+
expect(screen.queryByText("999 ms")).not.toBeInTheDocument();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("retains failure details and retry evidence in the dedicated view", () => {
|
|
168
|
+
renderSummary(
|
|
169
|
+
MonitorType.Port,
|
|
170
|
+
buildResponse({
|
|
171
|
+
isOnline: false,
|
|
172
|
+
failureCause: "Connection refused",
|
|
173
|
+
requestFailedDetails: {
|
|
174
|
+
failedPhase: RequestFailedPhase.TCPConnection,
|
|
175
|
+
errorCode: "ECONNREFUSED",
|
|
176
|
+
errorDescription: "The target rejected the TCP connection.",
|
|
177
|
+
},
|
|
178
|
+
probeAttempts: [
|
|
179
|
+
{
|
|
180
|
+
attemptNumber: 1,
|
|
181
|
+
attemptedAt: MONITORED_AT,
|
|
182
|
+
responseReceivedAt: MONITORED_AT,
|
|
183
|
+
responseTimeInMs: 11,
|
|
184
|
+
isOnline: false,
|
|
185
|
+
failureCause: "Connection refused",
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
attemptNumber: 2,
|
|
189
|
+
attemptedAt: MONITORED_AT,
|
|
190
|
+
responseReceivedAt: MONITORED_AT,
|
|
191
|
+
responseTimeInMs: 12,
|
|
192
|
+
isOnline: false,
|
|
193
|
+
failureCause: "Connection refused",
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
totalAttempts: 2,
|
|
197
|
+
}),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
expect(screen.getByText("Offline")).toBeInTheDocument();
|
|
201
|
+
expect(screen.getAllByText("Connection refused").length).toBeGreaterThan(0);
|
|
202
|
+
expect(screen.getByText("TCP Connection")).toBeInTheDocument();
|
|
203
|
+
expect(screen.getByText("ECONNREFUSED")).toBeInTheDocument();
|
|
204
|
+
expect(
|
|
205
|
+
screen.getByText("The target rejected the TCP connection."),
|
|
206
|
+
).toBeInTheDocument();
|
|
207
|
+
expect(screen.getByText("Retry Attempts")).toBeInTheDocument();
|
|
208
|
+
expect(screen.getByText("Attempt 1/2")).toBeInTheDocument();
|
|
209
|
+
expect(screen.getByText("Attempt 2/2")).toBeInTheDocument();
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe("Ping and IP summaries", () => {
|
|
214
|
+
it.each([MonitorType.Ping, MonitorType.IP])(
|
|
215
|
+
"keeps %s on the existing Ping view",
|
|
216
|
+
(monitorType: MonitorType) => {
|
|
217
|
+
renderSummary(
|
|
218
|
+
monitorType,
|
|
219
|
+
buildResponse({
|
|
220
|
+
portTimings: {
|
|
221
|
+
dnsLookupInMs: 8,
|
|
222
|
+
tcpConnectInMs: 23,
|
|
223
|
+
totalConnectionInMs: 31,
|
|
224
|
+
},
|
|
225
|
+
}),
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
expect(screen.getByText("Response Time (in ms)")).toBeInTheDocument();
|
|
229
|
+
expect(
|
|
230
|
+
screen.queryByText("Total Connection Time (DNS + TCP)"),
|
|
231
|
+
).not.toBeInTheDocument();
|
|
232
|
+
expect(
|
|
233
|
+
screen.queryByText("Connection Phase Breakdown"),
|
|
234
|
+
).not.toBeInTheDocument();
|
|
235
|
+
},
|
|
236
|
+
);
|
|
237
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import "@testing-library/jest-dom/extend-expect";
|
|
2
|
+
import { render, RenderResult } from "@testing-library/react";
|
|
3
|
+
/*
|
|
4
|
+
* The Dashboard has its own copy of react, so a component imported from there
|
|
5
|
+
* would otherwise call hooks on a DIFFERENT React instance than the one
|
|
6
|
+
* react-dom renders with. Common's jest moduleNameMapper pins react and
|
|
7
|
+
* react-dom to this project's single copy for every importer, which is what
|
|
8
|
+
* makes importing Dashboard source from here work (same arrangement as
|
|
9
|
+
* Common/Tests/UI/Rum/ReplayStage.test.tsx).
|
|
10
|
+
*/
|
|
11
|
+
import * as React from "react";
|
|
12
|
+
import { describe, expect, it } from "@jest/globals";
|
|
13
|
+
import InBetween from "../../../Types/BaseDatabase/InBetween";
|
|
14
|
+
import OneUptimeDate from "../../../Types/Date";
|
|
15
|
+
import TelemetrySnapshotWindowAlert from "../../../../App/FeatureSet/Dashboard/src/Components/Telemetry/TelemetrySnapshotWindowAlert";
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* The badge that tells someone reading an incident WHICH slice of time the
|
|
19
|
+
* telemetry cards below are showing. Its absence on the log card is a large
|
|
20
|
+
* part of why the rolling-window bug went unnoticed for so long: with nothing
|
|
21
|
+
* on screen claiming a window, an hour of unrelated logs read as the
|
|
22
|
+
* incident's own logs.
|
|
23
|
+
*
|
|
24
|
+
* Two behaviours matter and neither is reachable from a pure test: that it
|
|
25
|
+
* renders the stored window, and that it renders NOTHING when there is no
|
|
26
|
+
* window — the backwards-compatible path for incidents created before monitors
|
|
27
|
+
* stamped one, where a badge would be worse than no badge.
|
|
28
|
+
*/
|
|
29
|
+
describe("TelemetrySnapshotWindowAlert", () => {
|
|
30
|
+
const START_DATE: Date = new Date("2026-08-04T10:00:00.000Z");
|
|
31
|
+
const END_DATE: Date = new Date("2026-08-04T10:01:00.000Z");
|
|
32
|
+
|
|
33
|
+
it("renders the snapshot window", () => {
|
|
34
|
+
const result: RenderResult = render(
|
|
35
|
+
<TelemetrySnapshotWindowAlert
|
|
36
|
+
window={new InBetween<Date>(START_DATE, END_DATE)}
|
|
37
|
+
/>,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
/*
|
|
41
|
+
* Assert against the app's own formatter rather than a hard-coded string:
|
|
42
|
+
* the output is timezone- and 12/24h-preference dependent, and pinning a
|
|
43
|
+
* literal here would make this test a clock/locale trap rather than a
|
|
44
|
+
* check that the window reaches the screen.
|
|
45
|
+
*/
|
|
46
|
+
const expected: string = OneUptimeDate.getInBetweenDatesAsFormattedString(
|
|
47
|
+
new InBetween<Date>(START_DATE, END_DATE),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
expect(result.container.textContent).toContain(expected);
|
|
51
|
+
|
|
52
|
+
// Both edges are named, not just the start.
|
|
53
|
+
expect(expected).toContain(" - ");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("renders nothing when the incident stored no window", () => {
|
|
57
|
+
for (const value of [null, undefined]) {
|
|
58
|
+
const result: RenderResult = render(
|
|
59
|
+
<TelemetrySnapshotWindowAlert window={value} />,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
expect(result.container.textContent).toBe("");
|
|
63
|
+
result.unmount();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("renders a window restored from storage, whose bounds are ISO strings", () => {
|
|
68
|
+
/*
|
|
69
|
+
* The shape the incident page actually holds if hydration were ever
|
|
70
|
+
* skipped. The formatter normalizes strings, so the badge must still show
|
|
71
|
+
* real dates rather than "Invalid Date".
|
|
72
|
+
*/
|
|
73
|
+
const result: RenderResult = render(
|
|
74
|
+
<TelemetrySnapshotWindowAlert
|
|
75
|
+
window={
|
|
76
|
+
new InBetween<Date>(
|
|
77
|
+
START_DATE.toISOString() as unknown as Date,
|
|
78
|
+
END_DATE.toISOString() as unknown as Date,
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
/>,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(result.container.textContent).not.toContain("Invalid Date");
|
|
85
|
+
expect(result.container.textContent).toContain(
|
|
86
|
+
OneUptimeDate.getInBetweenDatesAsFormattedString(
|
|
87
|
+
new InBetween<Date>(START_DATE, END_DATE),
|
|
88
|
+
),
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import downloadFile from "../../../UI/Utils/DownloadFile";
|
|
2
|
+
|
|
3
|
+
describe("downloadFile", () => {
|
|
4
|
+
let createObjectUrlMock: jest.Mock;
|
|
5
|
+
let revokeObjectUrlMock: jest.Mock;
|
|
6
|
+
let clickSpy: jest.SpyInstance;
|
|
7
|
+
let capturedAnchor: HTMLAnchorElement | null;
|
|
8
|
+
let originalCreateObjectUrl: typeof window.URL.createObjectURL | undefined;
|
|
9
|
+
let originalRevokeObjectUrl: typeof window.URL.revokeObjectURL | undefined;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
capturedAnchor = null;
|
|
13
|
+
originalCreateObjectUrl = window.URL.createObjectURL;
|
|
14
|
+
originalRevokeObjectUrl = window.URL.revokeObjectURL;
|
|
15
|
+
createObjectUrlMock = jest.fn().mockReturnValue("blob:support-bundle");
|
|
16
|
+
revokeObjectUrlMock = jest.fn();
|
|
17
|
+
|
|
18
|
+
window.URL.createObjectURL = createObjectUrlMock;
|
|
19
|
+
window.URL.revokeObjectURL = revokeObjectUrlMock;
|
|
20
|
+
|
|
21
|
+
clickSpy = jest
|
|
22
|
+
.spyOn(HTMLAnchorElement.prototype, "click")
|
|
23
|
+
.mockImplementation(() => {});
|
|
24
|
+
|
|
25
|
+
const originalCreateElement: typeof document.createElement =
|
|
26
|
+
document.createElement.bind(document);
|
|
27
|
+
|
|
28
|
+
jest.spyOn(document, "createElement").mockImplementation(((
|
|
29
|
+
tagName: string,
|
|
30
|
+
): HTMLElement => {
|
|
31
|
+
const element: HTMLElement = originalCreateElement(tagName);
|
|
32
|
+
|
|
33
|
+
if (tagName === "a") {
|
|
34
|
+
capturedAnchor = element as HTMLAnchorElement;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return element;
|
|
38
|
+
}) as typeof document.createElement);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
jest.restoreAllMocks();
|
|
43
|
+
|
|
44
|
+
if (originalCreateObjectUrl) {
|
|
45
|
+
window.URL.createObjectURL = originalCreateObjectUrl;
|
|
46
|
+
} else {
|
|
47
|
+
delete (window.URL as { createObjectURL?: unknown }).createObjectURL;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (originalRevokeObjectUrl) {
|
|
51
|
+
window.URL.revokeObjectURL = originalRevokeObjectUrl;
|
|
52
|
+
} else {
|
|
53
|
+
delete (window.URL as { revokeObjectURL?: unknown }).revokeObjectURL;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("creates a Blob with the requested MIME type for string content", () => {
|
|
58
|
+
downloadFile({
|
|
59
|
+
content: "diagnostics",
|
|
60
|
+
filename: "support.json",
|
|
61
|
+
mimeType: "application/json;charset=utf-8;",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const blob: Blob = createObjectUrlMock.mock.calls[0]![0] as Blob;
|
|
65
|
+
expect(blob).toBeInstanceOf(Blob);
|
|
66
|
+
expect(blob.type).toBe("application/json;charset=utf-8;");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("reuses Blob content rather than wrapping it in another Blob", () => {
|
|
70
|
+
const blob: Blob = new Blob(["diagnostics"], {
|
|
71
|
+
type: "application/json",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
downloadFile({ content: blob, filename: "support.json" });
|
|
75
|
+
|
|
76
|
+
expect(createObjectUrlMock).toHaveBeenCalledWith(blob);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("clicks a safe download anchor and cleans it up", () => {
|
|
80
|
+
downloadFile({ content: "diagnostics", filename: "support.json" });
|
|
81
|
+
|
|
82
|
+
expect(clickSpy).toHaveBeenCalledTimes(1);
|
|
83
|
+
expect(capturedAnchor).not.toBeNull();
|
|
84
|
+
expect(capturedAnchor!.href).toContain("blob:support-bundle");
|
|
85
|
+
expect(capturedAnchor!.download).toBe("support.json");
|
|
86
|
+
expect(capturedAnchor!.rel).toBe("noopener");
|
|
87
|
+
expect(document.body.contains(capturedAnchor)).toBe(false);
|
|
88
|
+
expect(revokeObjectUrlMock).toHaveBeenCalledWith("blob:support-bundle");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("still removes the anchor and revokes the object URL when click fails", () => {
|
|
92
|
+
clickSpy.mockImplementation(() => {
|
|
93
|
+
throw new Error("Download blocked");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(() => {
|
|
97
|
+
downloadFile({ content: "diagnostics", filename: "support.json" });
|
|
98
|
+
}).toThrow("Download blocked");
|
|
99
|
+
|
|
100
|
+
expect(document.body.contains(capturedAnchor)).toBe(false);
|
|
101
|
+
expect(revokeObjectUrlMock).toHaveBeenCalledWith("blob:support-bundle");
|
|
102
|
+
});
|
|
103
|
+
});
|