@oneuptime/common 13.0.4 → 13.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/Index.ts +4 -0
- package/Models/DatabaseModels/RumApplication.ts +1 -1
- package/Models/DatabaseModels/SecurityEventConnection.ts +457 -0
- package/Models/DatabaseModels/SecurityEventConnectionRun.ts +263 -0
- package/Models/DatabaseModels/TelemetryIngestionKey.ts +2 -2
- package/Server/API/AIInvestigationAPI.ts +484 -24
- package/Server/API/GoogleSecOpsConnectionAPI.ts +249 -8
- package/Server/API/SecurityEventConnectionAPI.ts +250 -0
- package/Server/API/TelemetryAPI.ts +402 -265
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.ts +99 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Middleware/TelemetryIngest.ts +101 -6
- package/Server/Services/ExceptionAggregationService.ts +7 -16
- package/Server/Services/GoogleSecOpsConnectionService.ts +15 -0
- package/Server/Services/Index.ts +4 -0
- package/Server/Services/InventoryItemService.ts +28 -0
- package/Server/Services/LogAggregationService.ts +17 -23
- package/Server/Services/MetricAggregationService.ts +4 -14
- package/Server/Services/SecurityEventConnectionRunService.ts +10 -0
- package/Server/Services/SecurityEventConnectionService.ts +538 -0
- package/Server/Services/TraceAggregationService.ts +77 -28
- package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
- package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +13 -1
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +15 -1
- package/Server/Utils/AI/SRE/InvestigationEvidence.ts +658 -0
- package/Server/Utils/AI/SRE/InvestigationReferences.ts +324 -0
- package/Server/Utils/AI/Toolbox/Index.ts +38 -0
- package/Server/Utils/AI/Toolbox/TimelineTools.ts +9 -2
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +80 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +5 -3
- package/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.ts +1108 -0
- package/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.ts +732 -0
- package/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.ts +495 -0
- package/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.ts +689 -0
- package/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.ts +767 -0
- package/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.ts +571 -0
- package/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.ts +827 -0
- package/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.ts +610 -0
- package/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.ts +549 -0
- package/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.ts +830 -0
- package/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.ts +684 -0
- package/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.ts +487 -0
- package/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.ts +778 -0
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.ts +1002 -0
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.ts +556 -0
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.ts +275 -0
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.ts +53 -0
- package/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.ts +709 -0
- package/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.ts +596 -0
- package/Server/Utils/SecurityEvent/Connectors/Types.ts +191 -0
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.ts +353 -65
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.ts +777 -0
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +747 -148
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.ts +48 -2
- package/Server/Utils/SecurityEvent/SecurityEventDedupe.ts +81 -0
- package/Server/Utils/SessionReplay/SessionReplayReadService.ts +741 -40
- package/Server/Utils/StartServer.ts +10 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +8 -0
- package/Server/Utils/Telemetry/KubernetesResourceAttributes.ts +108 -0
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +174 -93
- package/Server/Utils/Telemetry/ResourceFacetPlanner.ts +251 -0
- package/Server/Utils/Telemetry/ResourceFacetResolver.ts +248 -413
- package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +668 -0
- package/Server/Utils/Telemetry/TraceContextPropagation.ts +348 -0
- package/Server/Utils/Telemetry.ts +18 -0
- package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +413 -0
- package/Tests/App/Dashboard/AIRootCauseFeedItem.test.tsx +285 -0
- package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +242 -0
- package/Tests/App/Dashboard/AlertEpisodeViewFields.test.tsx +601 -15
- package/Tests/App/Dashboard/ChangeAlertStateAIHeader.test.tsx +835 -0
- package/Tests/App/Dashboard/CloudResourceTelemetryScope.test.ts +41 -0
- package/Tests/App/Dashboard/ConnectionTestModal.test.tsx +604 -0
- package/Tests/App/Dashboard/ConnectorTestReportView.test.tsx +738 -0
- package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +153 -6
- package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +165 -0
- package/Tests/App/Dashboard/EpisodeChangeState.test.tsx +1069 -0
- package/Tests/App/Dashboard/EpisodeMembersCard.test.tsx +772 -0
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +2354 -0
- package/Tests/App/Dashboard/EventOverviewSkeleton.test.tsx +210 -0
- package/Tests/App/Dashboard/EventStatBar.test.tsx +392 -0
- package/Tests/App/Dashboard/EventStatusPanel.test.tsx +247 -0
- package/Tests/App/Dashboard/ExceptionAIAssistance.test.tsx +606 -0
- package/Tests/App/Dashboard/ExceptionBreadcrumbTimeline.test.tsx +273 -0
- package/Tests/App/Dashboard/ExceptionDetailSideMenu.test.tsx +176 -0
- package/Tests/App/Dashboard/ExceptionOverviewCards.test.tsx +366 -0
- package/Tests/App/Dashboard/ExceptionSignalPages.test.tsx +371 -0
- package/Tests/App/Dashboard/ExceptionStackFrameViewer.test.tsx +440 -0
- package/Tests/App/Dashboard/ExceptionSummary.test.tsx +381 -0
- package/Tests/App/Dashboard/ExceptionTriage.test.tsx +306 -0
- package/Tests/App/Dashboard/ExceptionsResourceFacets.test.tsx +604 -0
- package/Tests/App/Dashboard/ExceptionsViewerEntityChips.test.tsx +706 -0
- package/Tests/App/Dashboard/FeedOrdering.test.ts +32 -0
- package/Tests/App/Dashboard/GoogleSecOpsConnectionForm.test.tsx +838 -0
- package/Tests/App/Dashboard/GoogleSecOpsConnectionsErrors.test.tsx +18 -0
- package/Tests/App/Dashboard/GoogleSecOpsDiagnostics.test.tsx +297 -20
- package/Tests/App/Dashboard/IncidentEpisodeViewFields.test.tsx +618 -13
- package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +254 -207
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +303 -135
- package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +1251 -0
- package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +303 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +876 -8
- package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +35 -0
- package/Tests/App/Dashboard/InvestigationReferenceLink.test.tsx +177 -0
- package/Tests/App/Dashboard/InvestigationReportView.test.tsx +1295 -0
- package/Tests/App/Dashboard/KubernetesImageReferenceView.test.tsx +114 -0
- package/Tests/App/Dashboard/KubernetesLogsTabChips.test.tsx +285 -0
- package/Tests/App/Dashboard/LogsEntityChipNames.test.tsx +316 -0
- package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +361 -0
- package/Tests/App/Dashboard/ProfileTableEntityNames.test.tsx +432 -0
- package/Tests/App/Dashboard/ProfileViewEntityName.test.tsx +250 -0
- package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +10 -0
- package/Tests/App/Dashboard/ResourceLogsTabsBareLayout.test.tsx +700 -0
- package/Tests/App/Dashboard/ResourcePageEntityNameProps.test.tsx +803 -0
- package/Tests/App/Dashboard/RumSessionReplaySideMenu.test.tsx +11 -1
- package/Tests/App/Dashboard/ScheduledMaintenanceChangeState.test.tsx +1026 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +436 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +1195 -0
- package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +1022 -0
- package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +905 -0
- package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +247 -0
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +375 -274
- package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +410 -0
- package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +774 -0
- package/Tests/App/Dashboard/TopErrorsPanelResourceNames.test.tsx +316 -0
- package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +30 -0
- package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +88 -24
- package/Tests/App/Dashboard/TraceExplorer.test.tsx +1590 -0
- package/Tests/App/Dashboard/TraceWaterfall.test.tsx +488 -0
- package/Tests/App/Dashboard/TracesAnalyticsSeriesLabels.test.tsx +367 -0
- package/Tests/App/Dashboard/TracesEntityNames.test.tsx +585 -0
- package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +613 -0
- package/Tests/App/Dashboard/UseServiceNames.test.tsx +359 -0
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +7 -0
- package/Tests/Models/InventoryItemNaming.test.ts +132 -16
- package/Tests/Models/SecurityDomainAccessControl.test.ts +61 -17
- package/Tests/Server/API/AIInvestigationAPI.test.ts +611 -2
- package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +1098 -0
- package/Tests/Server/API/GoogleSecOpsConnectionAPI.test.ts +409 -0
- package/Tests/Server/API/SecurityEventConnectionAPI.test.ts +856 -0
- package/Tests/Server/API/SessionReplayAPI.test.ts +528 -1
- package/Tests/Server/API/TelemetryFacetsAPI.test.ts +810 -0
- package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +240 -0
- package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +229 -0
- package/Tests/Server/Services/InventoryItemDisplayName.test.ts +66 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
- package/Tests/Server/Services/SecurityEventConnectionService.test.ts +1233 -0
- package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +53 -0
- package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +218 -0
- package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +155 -1
- package/Tests/Server/Services/TraceAggregationExceptionScope.test.ts +142 -0
- package/Tests/Server/Services/TraceAnalyticsResourceDisplayNames.test.ts +85 -24
- package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +33 -0
- package/Tests/Server/Utils/AI/InvestigationEvidence.test.ts +1395 -0
- package/Tests/Server/Utils/AI/InvestigationReferences.test.ts +616 -0
- package/Tests/Server/Utils/AI/TimelineTools.test.ts +119 -0
- package/Tests/Server/Utils/AI/Toolbox/AIToolbox.test.ts +151 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +65 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorExceptionScope.test.ts +224 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPerSeriesFanout.test.ts +55 -2
- package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.test.ts +1240 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.test.ts +1853 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.test.ts +1129 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.test.ts +1066 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.test.ts +1568 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.test.ts +930 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.test.ts +1409 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.test.ts +763 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.test.ts +1296 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.test.ts +1102 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.test.ts +1174 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.test.ts +1032 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.test.ts +1558 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.test.ts +3041 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.test.ts +1168 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.test.ts +906 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.test.ts +1068 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.test.ts +1004 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.test.ts +784 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +113 -1
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +5 -1
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +93 -13
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsHttpIntegration.test.ts +23 -1
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +25 -3
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +22 -8
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +82 -16
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSearchDetections.test.ts +730 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsThreePassPoller.test.ts +1577 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayOriginAllowlist.test.ts +41 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1453 -18
- package/Tests/Server/Utils/Telemetry/KubernetesResourceAttributes.test.ts +162 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +460 -13
- package/Tests/Server/Utils/Telemetry/ResourceFacetPlanner.test.ts +678 -0
- package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +348 -2
- package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +525 -0
- package/Tests/Server/Utils/Telemetry/TraceContextPropagation.test.ts +420 -0
- package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +73 -0
- package/Tests/Types/Rum/SessionReplayTransportContracts.test.ts +95 -0
- package/Tests/Types/SecurityEvent/Connectors/ConnectorDiagnostics.test.ts +82 -0
- package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +314 -0
- package/Tests/Types/Telemetry/ExceptionSpanScope.test.ts +89 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +96 -0
- package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +304 -0
- package/Tests/UI/Components/ActiveFilterChipsLockedFilters.test.tsx +357 -0
- package/Tests/UI/Components/Card.test.tsx +312 -1
- package/Tests/UI/Components/CardModelDetailHeaderLayout.test.tsx +253 -0
- package/Tests/UI/Components/CardModelDetailRefresher.test.tsx +342 -0
- package/Tests/UI/Components/Checkbox.test.tsx +79 -0
- package/Tests/UI/Components/CopyTextButton.test.tsx +142 -0
- package/Tests/UI/Components/DetailCompactStyle.test.tsx +621 -0
- package/Tests/UI/Components/ErrorBoundary.test.tsx +60 -0
- package/Tests/UI/Components/FacetSections.test.tsx +581 -0
- package/Tests/UI/Components/FacetSidebarControls.test.tsx +812 -0
- package/Tests/UI/Components/FacetVisibility.test.ts +429 -0
- package/Tests/UI/Components/LockedFilterActions.test.tsx +396 -0
- package/Tests/UI/Components/LockedFilterChip.test.tsx +651 -0
- package/Tests/UI/Components/LogsEntityNames.test.ts +1769 -0
- package/Tests/UI/Components/LogsEntityNamesComponents.test.tsx +696 -0
- package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +600 -0
- package/Tests/UI/Components/LogsViewerEntityNames.test.tsx +713 -0
- package/Tests/UI/Components/MarkdownInlineReferences.test.tsx +2079 -0
- package/Tests/UI/Components/MemberRoleAssignment.test.tsx +446 -0
- package/Tests/UI/Components/ModelDetailRefetch.test.tsx +397 -0
- package/Tests/UI/Components/ModelListRefetch.test.tsx +233 -0
- package/Tests/UI/Components/ModelPageModelChange.test.tsx +409 -0
- package/Tests/UI/Components/PaginationIntegration.test.tsx +25 -0
- package/Tests/UI/Components/ResourceFacetConfigs.test.ts +172 -0
- package/Tests/UI/Components/SavedViewsSidebarIntegration.test.tsx +32 -14
- package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +44 -1
- package/Tests/UI/Components/TelemetryActiveFilterChipsLockedFilters.test.tsx +304 -0
- package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +718 -0
- package/Tests/UI/Monitor/EvaluationLogList.test.tsx +303 -0
- package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +55 -1
- package/Tests/UI/Rum/FidelityNotices.test.ts +22 -0
- package/Tests/UI/Rum/RecordingHealthCard.test.tsx +120 -136
- package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +988 -0
- package/Tests/UI/Rum/ReplayCard.test.tsx +32 -0
- package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +709 -12
- package/Tests/UI/Rum/ReplayHeader.test.tsx +50 -1
- package/Tests/UI/Rum/ReplayPinControl.test.tsx +67 -10
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +41 -12
- package/Tests/UI/Rum/ReplayStage.test.tsx +663 -1
- package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +173 -0
- package/Tests/UI/Rum/ReplayUi.test.tsx +189 -2
- package/Tests/UI/Rum/ReplayUserSessionsMenu.test.tsx +91 -0
- package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +1 -1
- package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +585 -0
- package/Tests/UI/Rum/SessionReplayTable.test.tsx +844 -51
- package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +29 -1
- package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +288 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +31 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +6 -0
- package/Tests/UI/Utils/Clipboard.test.ts +154 -0
- package/Tests/UI/Utils/Navigation.test.ts +24 -0
- package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +2205 -0
- package/Tests/UI/Utils/Telemetry/UseTelemetryEntityNames.test.tsx +844 -0
- package/Tests/Utils/AI/InvestigationReport.test.ts +2430 -0
- package/Tests/Utils/APIOutgoingRequestTracer.test.ts +137 -0
- package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +40 -0
- package/Tests/Utils/Rum/SessionReplayRecordingEnded.test.ts +619 -0
- package/Tests/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.test.ts +631 -0
- package/Tests/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.test.ts +479 -0
- package/Tests/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.test.ts +507 -0
- package/Tests/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.test.ts +686 -0
- package/Tests/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.test.ts +474 -0
- package/Tests/Utils/SecurityEvent/Connectors/OktaNormalizer.test.ts +736 -0
- package/Tests/Utils/SecurityEvent/Connectors/SplunkNormalizer.test.ts +407 -0
- package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.test.ts +129 -0
- package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +57 -1
- package/Tests/Utils/Telemetry/EntityRelationship.test.ts +36 -0
- package/Tests/Utils/Telemetry/LockedFilterSearch.test.ts +600 -0
- package/Tests/Utils/Telemetry/NetworkHost.test.ts +48 -0
- package/Tests/Utils/Telemetry/OriginAllowList.test.ts +154 -0
- package/Tests/Utils/Traces/CriticalPath.test.ts +25 -0
- package/Types/AI/AIChatTypes.ts +8 -0
- package/Types/AI/InvestigationEvidence.ts +96 -0
- package/Types/Monitor/MonitorEvaluationSummary.ts +5 -0
- package/Types/Permission.ts +2 -2
- package/Types/Rum/SessionReplay.ts +109 -0
- package/Types/Rum/SessionReplayApi.ts +31 -0
- package/Types/SecurityEvent/Connectors/ConnectorDiagnostics.ts +111 -0
- package/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.ts +87 -0
- package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +492 -0
- package/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.ts +41 -0
- package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +56 -1
- package/Types/SecurityEvent/GoogleSecOpsRegion.ts +34 -0
- package/Types/Telemetry/EntityType.ts +14 -0
- package/Types/Telemetry/ExceptionSpanScope.ts +83 -0
- package/Types/Telemetry/LockedFilterDetail.ts +46 -0
- package/Types/Telemetry/ResourceEntityFacet.ts +17 -10
- package/Types/Telemetry/ResourceFacetCatalog.ts +171 -0
- package/UI/Components/Card/Card.tsx +118 -83
- package/UI/Components/Checkbox/Checkbox.tsx +8 -5
- package/UI/Components/CopyTextButton/CopyTextButton.tsx +7 -1
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +4 -1
- package/UI/Components/Detail/Detail.tsx +137 -22
- package/UI/Components/ErrorBoundary.tsx +38 -0
- package/UI/Components/LogsViewer/LogsEntityNames.ts +912 -0
- package/UI/Components/LogsViewer/LogsViewer.tsx +156 -77
- package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +28 -11
- package/UI/Components/LogsViewer/components/FacetSection.tsx +66 -79
- package/UI/Components/LogsViewer/components/FacetValueRow.tsx +17 -2
- package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +45 -5
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +100 -19
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +156 -39
- package/UI/Components/LogsViewer/components/LogsTable.tsx +30 -8
- package/UI/Components/LogsViewer/types.ts +6 -0
- package/UI/Components/Markdown.tsx/InlineReferences.tsx +628 -0
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +385 -312
- package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +50 -22
- package/UI/Components/ModelDetail/CardModelDetail.tsx +15 -0
- package/UI/Components/ModelDetail/ModelDetail.tsx +64 -19
- package/UI/Components/ModelList/ModelList.tsx +33 -8
- package/UI/Components/Page/ModelPage.tsx +119 -54
- package/UI/Components/Table/Table.tsx +8 -0
- package/UI/Components/Table/TableRow.tsx +13 -5
- package/UI/Components/TelemetryViewer/FacetVisibility.ts +229 -0
- package/UI/Components/TelemetryViewer/ResourceFacetConfigs.ts +46 -0
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +11 -0
- package/UI/Components/TelemetryViewer/components/FacetSearchInput.tsx +79 -0
- package/UI/Components/TelemetryViewer/components/FacetSectionHeader.tsx +69 -0
- package/UI/Components/TelemetryViewer/components/FacetShowMoreButton.tsx +36 -0
- package/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.tsx +88 -0
- package/UI/Components/TelemetryViewer/components/LockedFilterActions.tsx +205 -0
- package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +496 -0
- package/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.tsx +30 -10
- package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +203 -10
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSection.tsx +60 -73
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +94 -7
- package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +17 -2
- package/UI/Components/TelemetryViewer/types.ts +19 -0
- package/UI/Components/TelemetryViewer/useFacetSearchExemptions.ts +158 -0
- package/UI/Components/TelemetryViewer/useFacetSectionSearch.ts +102 -0
- package/UI/Utils/Clipboard.ts +68 -2
- package/UI/Utils/Navigation.ts +17 -2
- package/UI/Utils/Telemetry/TelemetryEntityNames.ts +620 -0
- package/UI/Utils/Telemetry/UseTelemetryEntityNames.ts +151 -0
- package/Utils/AI/InvestigationReport.ts +1789 -0
- package/Utils/API.ts +90 -1
- package/Utils/Rum/SessionReplayHealth.ts +11 -0
- package/Utils/Rum/SessionReplayRecordingEnded.ts +134 -0
- package/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.ts +427 -0
- package/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.ts +197 -0
- package/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.ts +464 -0
- package/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.ts +567 -0
- package/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.ts +299 -0
- package/Utils/SecurityEvent/Connectors/OktaNormalizer.ts +467 -0
- package/Utils/SecurityEvent/Connectors/SplunkNormalizer.ts +439 -0
- package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +124 -12
- package/Utils/Telemetry/CrossSignalScope.ts +22 -8
- package/Utils/Telemetry/EntityRelationship.ts +8 -0
- package/Utils/Telemetry/LockedFilterSearch.ts +412 -0
- package/Utils/Telemetry/NetworkHost.ts +43 -0
- package/Utils/Telemetry/OriginAllowList.ts +139 -4
- package/Utils/Traces/CriticalPath.ts +10 -4
- package/build/dist/Models/DatabaseModels/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
- package/build/dist/Models/DatabaseModels/SecurityEventConnection.js +490 -0
- package/build/dist/Models/DatabaseModels/SecurityEventConnection.js.map +1 -0
- package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js +287 -0
- package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +2 -2
- package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +336 -27
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +182 -7
- package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +1 -1
- package/build/dist/Server/API/SecurityEventConnectionAPI.js +171 -0
- package/build/dist/Server/API/SecurityEventConnectionAPI.js.map +1 -0
- package/build/dist/Server/API/TelemetryAPI.js +248 -170
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +57 -4
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/ExceptionAggregationService.js +7 -16
- package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
- package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +8 -0
- package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +4 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +22 -0
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +8 -17
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricAggregationService.js +4 -14
- package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
- package/build/dist/Server/Services/SecurityEventConnectionRunService.js +9 -0
- package/build/dist/Server/Services/SecurityEventConnectionRunService.js.map +1 -0
- package/build/dist/Server/Services/SecurityEventConnectionService.js +356 -0
- package/build/dist/Server/Services/SecurityEventConnectionService.js.map +1 -0
- package/build/dist/Server/Services/TraceAggregationService.js +51 -25
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.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/SRE/AIInvestigationEngine.js +14 -7
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js +468 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js +230 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/Index.js +32 -0
- package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js +6 -2
- package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +59 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +5 -3
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js +752 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js +493 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js +352 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js +405 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js +466 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js +344 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js +511 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js +406 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js +336 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js +474 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js +417 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js +314 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js +494 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js +719 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js +404 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js +209 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js +40 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js +494 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js +379 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js +27 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +234 -61
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js +537 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +572 -115
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +35 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js +52 -0
- package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +521 -32
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +10 -0
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +8 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js +80 -0
- package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +122 -67
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js +146 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +174 -248
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +492 -0
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js +259 -0
- package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry.js +11 -5
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Types/AI/InvestigationEvidence.js +2 -0
- package/build/dist/Types/AI/InvestigationEvidence.js.map +1 -0
- package/build/dist/Types/Permission.js +2 -2
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplay.js +95 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
- package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js +18 -0
- package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js.map +1 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js +2 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js.map +1 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +374 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js +35 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js.map +1 -0
- package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js +35 -0
- package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js.map +1 -0
- package/build/dist/Types/Telemetry/EntityType.js +14 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/ExceptionSpanScope.js +59 -0
- package/build/dist/Types/Telemetry/ExceptionSpanScope.js.map +1 -0
- package/build/dist/Types/Telemetry/LockedFilterDetail.js +16 -0
- package/build/dist/Types/Telemetry/LockedFilterDetail.js.map +1 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js +16 -10
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -1
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +119 -0
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -0
- package/build/dist/UI/Components/Card/Card.js +34 -17
- package/build/dist/UI/Components/Card/Card.js.map +1 -1
- package/build/dist/UI/Components/Checkbox/Checkbox.js +6 -4
- package/build/dist/UI/Components/Checkbox/Checkbox.js.map +1 -1
- package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
- package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Detail/Detail.js +63 -13
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/ErrorBoundary.js +34 -0
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js +535 -0
- package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +117 -57
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +5 -7
- package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetSection.js +31 -44
- package/build/dist/UI/Components/LogsViewer/components/FacetSection.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +17 -3
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +19 -3
- package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +64 -18
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +100 -41
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +13 -5
- package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/types.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js +403 -0
- package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js.map +1 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +197 -179
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +30 -21
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +12 -0
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/ModelDetail.js +46 -12
- package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelList/ModelList.js +26 -7
- package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
- package/build/dist/UI/Components/Page/ModelPage.js +62 -34
- package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
- package/build/dist/UI/Components/Table/Table.js +3 -1
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +8 -1
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +111 -0
- package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js +22 -0
- package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js +36 -0
- package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js +21 -0
- package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js +14 -0
- package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js +27 -0
- package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js +88 -0
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +228 -0
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js +6 -6
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +111 -12
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js +27 -40
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +70 -10
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +17 -3
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/types.js +0 -4
- package/build/dist/UI/Components/TelemetryViewer/types.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js +70 -0
- package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js +52 -0
- package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js.map +1 -0
- package/build/dist/UI/Utils/Clipboard.js +59 -2
- package/build/dist/UI/Utils/Clipboard.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +11 -2
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +471 -0
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -0
- package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js +113 -0
- package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js.map +1 -0
- package/build/dist/Utils/AI/InvestigationReport.js +1241 -0
- package/build/dist/Utils/AI/InvestigationReport.js.map +1 -0
- package/build/dist/Utils/API.js +25 -0
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Rum/SessionReplayHealth.js +10 -0
- package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -1
- package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js +54 -0
- package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js +311 -0
- package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js +150 -0
- package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js +328 -0
- package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js +405 -0
- package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js +212 -0
- package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js +351 -0
- package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js +348 -0
- package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +103 -10
- package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
- package/build/dist/Utils/Telemetry/CrossSignalScope.js +16 -5
- package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
- package/build/dist/Utils/Telemetry/EntityRelationship.js +7 -0
- package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
- package/build/dist/Utils/Telemetry/LockedFilterSearch.js +277 -0
- package/build/dist/Utils/Telemetry/LockedFilterSearch.js.map +1 -0
- package/build/dist/Utils/Telemetry/NetworkHost.js +39 -0
- package/build/dist/Utils/Telemetry/NetworkHost.js.map +1 -0
- package/build/dist/Utils/Telemetry/OriginAllowList.js +105 -4
- package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -1
- package/build/dist/Utils/Traces/CriticalPath.js +9 -4
- package/build/dist/Utils/Traces/CriticalPath.js.map +1 -1
- package/package.json +1 -1
- package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +0 -600
- package/UI/Components/GanttChart/Bar/BarLabel.tsx +0 -17
- package/UI/Components/GanttChart/Bar/Index.tsx +0 -149
- package/UI/Components/GanttChart/ChartContainer.tsx +0 -50
- package/UI/Components/GanttChart/Index.tsx +0 -90
- package/UI/Components/GanttChart/Row/Index.tsx +0 -22
- package/UI/Components/GanttChart/Row/Row.tsx +0 -231
- package/UI/Components/GanttChart/Row/RowLabel.tsx +0 -30
- package/UI/Components/GanttChart/Rows.tsx +0 -59
- package/UI/Components/GanttChart/Timeline/Index.tsx +0 -46
- package/UI/Components/GanttChart/Timeline/TimelineInterval.tsx +0 -33
- package/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.tsx +0 -43
- package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js +0 -8
- package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Bar/Index.js +0 -77
- package/build/dist/UI/Components/GanttChart/Bar/Index.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/ChartContainer.js +0 -33
- package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Index.js +0 -39
- package/build/dist/UI/Components/GanttChart/Index.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Row/Index.js +0 -7
- package/build/dist/UI/Components/GanttChart/Row/Index.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Row/Row.js +0 -106
- package/build/dist/UI/Components/GanttChart/Row/Row.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Row/RowLabel.js +0 -10
- package/build/dist/UI/Components/GanttChart/Row/RowLabel.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Rows.js +0 -19
- package/build/dist/UI/Components/GanttChart/Rows.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Timeline/Index.js +0 -16
- package/build/dist/UI/Components/GanttChart/Timeline/Index.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js +0 -13
- package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js +0 -13
- package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js.map +0 -1
|
@@ -7,7 +7,15 @@ import {
|
|
|
7
7
|
jest,
|
|
8
8
|
test,
|
|
9
9
|
} from "@jest/globals";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
act,
|
|
12
|
+
cleanup,
|
|
13
|
+
fireEvent,
|
|
14
|
+
render,
|
|
15
|
+
screen,
|
|
16
|
+
waitFor,
|
|
17
|
+
within,
|
|
18
|
+
} from "@testing-library/react";
|
|
11
19
|
import React from "react";
|
|
12
20
|
import { Location } from "react-router-dom";
|
|
13
21
|
import getJestMockFunction, { MockFunction } from "../../MockType";
|
|
@@ -32,16 +40,35 @@ import getJestMockFunction, { MockFunction } from "../../MockType";
|
|
|
32
40
|
* guard must NOT be what makes these pass: every case asserts the page never
|
|
33
41
|
* logged "threw and was ignored", which is how a regression at the page level
|
|
34
42
|
* stays visible instead of being quietly absorbed by the framework.
|
|
43
|
+
*
|
|
44
|
+
* The overview itself was later redesigned (header, stat bar, member list,
|
|
45
|
+
* compact details column), so the last describe blocks pin that layout's
|
|
46
|
+
* behaviour against the same fake server.
|
|
35
47
|
*/
|
|
36
48
|
|
|
37
49
|
const EPISODE_ID: string = "11111111-1111-4111-8111-111111111111";
|
|
38
50
|
const PROJECT_ID: string = "22222222-2222-4222-8222-222222222222";
|
|
51
|
+
const ACK_STATE_ID: string = "66666666-6666-4666-8666-666666666666";
|
|
52
|
+
const RESOLVED_STATE_ID: string = "77777777-7777-4777-8777-777777777777";
|
|
39
53
|
|
|
40
54
|
const getItemMock: MockFunction = getJestMockFunction();
|
|
41
55
|
const getListMock: MockFunction = getJestMockFunction();
|
|
42
56
|
const getCommonHeadersMock: MockFunction = getJestMockFunction();
|
|
43
57
|
const loggerErrorMock: MockFunction = getJestMockFunction();
|
|
44
58
|
|
|
59
|
+
// The last props the stubbed header was rendered with.
|
|
60
|
+
const changeStateProps: { current: Record<string, any> | null } = {
|
|
61
|
+
current: null,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Every set of props the stubbed header was rendered with, in order.
|
|
65
|
+
const changeStateHistory: Array<Record<string, any>> = [];
|
|
66
|
+
|
|
67
|
+
// The last props the stubbed roles card was rendered with.
|
|
68
|
+
const rolesProps: { current: Record<string, any> | null } = {
|
|
69
|
+
current: null,
|
|
70
|
+
};
|
|
71
|
+
|
|
45
72
|
/*
|
|
46
73
|
* The arrow wrappers are load bearing: jest.mock is hoisted above the compiled
|
|
47
74
|
* requires, so the mock consts above are still unassigned when the factory
|
|
@@ -87,14 +114,17 @@ jest.mock("../../../UI/Utils/Logger", () => {
|
|
|
87
114
|
/*
|
|
88
115
|
* The page's three heavy children each drive their own API traffic and none of
|
|
89
116
|
* them renders a detail field. Stubbing them keeps this suite pointed at the
|
|
90
|
-
* Episode Details card, which is where #3374 lives.
|
|
117
|
+
* Episode Details card, which is where #3374 lives. The header stub records
|
|
118
|
+
* its props so the layout tests can drive a state change.
|
|
91
119
|
*/
|
|
92
120
|
jest.mock(
|
|
93
121
|
"../../../../App/FeatureSet/Dashboard/src/Components/IncidentEpisode/ChangeState",
|
|
94
122
|
() => {
|
|
95
123
|
return {
|
|
96
124
|
__esModule: true,
|
|
97
|
-
default: () => {
|
|
125
|
+
default: (props: Record<string, any>) => {
|
|
126
|
+
changeStateProps.current = props;
|
|
127
|
+
changeStateHistory.push(props);
|
|
98
128
|
return null;
|
|
99
129
|
},
|
|
100
130
|
};
|
|
@@ -106,7 +136,8 @@ jest.mock(
|
|
|
106
136
|
() => {
|
|
107
137
|
return {
|
|
108
138
|
__esModule: true,
|
|
109
|
-
default: () => {
|
|
139
|
+
default: (props: Record<string, any>) => {
|
|
140
|
+
rolesProps.current = props;
|
|
110
141
|
return null;
|
|
111
142
|
},
|
|
112
143
|
};
|
|
@@ -127,10 +158,13 @@ jest.mock(
|
|
|
127
158
|
|
|
128
159
|
import IncidentEpisodeView from "../../../../App/FeatureSet/Dashboard/src/Pages/Incidents/EpisodeView/Index";
|
|
129
160
|
import PageComponentProps from "../../../../App/FeatureSet/Dashboard/src/Pages/PageComponentProps";
|
|
161
|
+
import Incident from "../../../Models/DatabaseModels/Incident";
|
|
130
162
|
import IncidentEpisode from "../../../Models/DatabaseModels/IncidentEpisode";
|
|
163
|
+
import IncidentEpisodeStateTimeline from "../../../Models/DatabaseModels/IncidentEpisodeStateTimeline";
|
|
131
164
|
import IncidentSeverity from "../../../Models/DatabaseModels/IncidentSeverity";
|
|
132
165
|
import IncidentState from "../../../Models/DatabaseModels/IncidentState";
|
|
133
166
|
import Route from "../../../Types/API/Route";
|
|
167
|
+
import SortOrder from "../../../Types/BaseDatabase/SortOrder";
|
|
134
168
|
import Color from "../../../Types/Color";
|
|
135
169
|
import ObjectID from "../../../Types/ObjectID";
|
|
136
170
|
import Permission from "../../../Types/Permission";
|
|
@@ -225,6 +259,22 @@ const buildEpisode: BuildEpisodeFunction = (
|
|
|
225
259
|
return episode;
|
|
226
260
|
};
|
|
227
261
|
|
|
262
|
+
type EmptyListFunction = () => {
|
|
263
|
+
data: Array<unknown>;
|
|
264
|
+
count: number;
|
|
265
|
+
skip: number;
|
|
266
|
+
limit: number;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const emptyList: EmptyListFunction = () => {
|
|
270
|
+
return {
|
|
271
|
+
data: [],
|
|
272
|
+
count: 0,
|
|
273
|
+
skip: 0,
|
|
274
|
+
limit: 0,
|
|
275
|
+
};
|
|
276
|
+
};
|
|
277
|
+
|
|
228
278
|
type RenderPageFunction = (spec: EpisodeSpec) => Promise<void>;
|
|
229
279
|
|
|
230
280
|
const renderPage: RenderPageFunction = async (
|
|
@@ -243,6 +293,7 @@ const renderPage: RenderPageFunction = async (
|
|
|
243
293
|
* Detail renders each field as <container><FieldLabel/><value/></container>,
|
|
244
294
|
* and FieldLabel's root is the only div.space-y-1 in that subtree. Walking up
|
|
245
295
|
* from the label and taking the sibling is what a person reading the row does.
|
|
296
|
+
* The compact style the overview uses keeps exactly that shape.
|
|
246
297
|
*/
|
|
247
298
|
type FieldValueFunction = (title: string) => string;
|
|
248
299
|
|
|
@@ -281,6 +332,16 @@ const pillFor: PillForFunction = (title: string): HTMLElement => {
|
|
|
281
332
|
return pill;
|
|
282
333
|
};
|
|
283
334
|
|
|
335
|
+
// A stat bar cell: label span -> label row -> cell; the value is the 2nd child.
|
|
336
|
+
type StatValueFunction = (label: string) => string;
|
|
337
|
+
|
|
338
|
+
const statValue: StatValueFunction = (label: string): string => {
|
|
339
|
+
const cell: HTMLElement | null | undefined =
|
|
340
|
+
screen.getByText(label).parentElement?.parentElement;
|
|
341
|
+
|
|
342
|
+
return (cell?.children[1]?.textContent || "").trim();
|
|
343
|
+
};
|
|
344
|
+
|
|
284
345
|
type ExpectNoCrashFunction = () => void;
|
|
285
346
|
|
|
286
347
|
/*
|
|
@@ -302,18 +363,26 @@ const expectNoCrash: ExpectNoCrashFunction = (): void => {
|
|
|
302
363
|
expect(swallowed).toEqual([]);
|
|
303
364
|
};
|
|
304
365
|
|
|
366
|
+
type CallsForModelFunction = (modelType: unknown) => Array<Array<any>>;
|
|
367
|
+
|
|
368
|
+
const listCallsFor: CallsForModelFunction = (
|
|
369
|
+
modelType: unknown,
|
|
370
|
+
): Array<Array<any>> => {
|
|
371
|
+
return getListMock.mock.calls.filter((call: Array<any>): boolean => {
|
|
372
|
+
return call[0]?.modelType === modelType;
|
|
373
|
+
});
|
|
374
|
+
};
|
|
375
|
+
|
|
305
376
|
beforeEach((): void => {
|
|
306
377
|
getItemMock.mockReset();
|
|
307
378
|
getListMock.mockReset();
|
|
308
379
|
getCommonHeadersMock.mockReset();
|
|
309
380
|
loggerErrorMock.mockReset();
|
|
381
|
+
changeStateProps.current = null;
|
|
382
|
+
changeStateHistory.length = 0;
|
|
383
|
+
rolesProps.current = null;
|
|
310
384
|
|
|
311
|
-
getListMock.mockResolvedValue(
|
|
312
|
-
data: [],
|
|
313
|
-
count: 0,
|
|
314
|
-
skip: 0,
|
|
315
|
-
limit: 0,
|
|
316
|
-
} as never);
|
|
385
|
+
getListMock.mockResolvedValue(emptyList() as never);
|
|
317
386
|
getCommonHeadersMock.mockReturnValue({} as never);
|
|
318
387
|
|
|
319
388
|
const path: string = `/dashboard/${PROJECT_ID}/incidents/episodes/${EPISODE_ID}`;
|
|
@@ -368,12 +437,13 @@ describe("Incident Episode detail page: severity (issue #3374)", () => {
|
|
|
368
437
|
test("still renders the rest of the episode when severity is missing", async () => {
|
|
369
438
|
await renderPage({ state: buildState("Created", new Color("#4b5563")) });
|
|
370
439
|
|
|
371
|
-
expect(screen.getByText("Episode Title")).toBeInTheDocument();
|
|
372
|
-
expect(fieldValue("Episode Title")).toEqual("episode without severity");
|
|
373
440
|
expect(fieldValue("Episode Number")).toContain("#7");
|
|
374
441
|
expect(fieldValue("Incident Count")).toEqual("0");
|
|
375
442
|
// No createdByUser on an API-created episode.
|
|
376
443
|
expect(fieldValue("Created By")).toEqual("System");
|
|
444
|
+
// An episode with no grouping rule is a manual one, not a crash.
|
|
445
|
+
expect(fieldValue("Grouping Rule")).toEqual("Manual Episode");
|
|
446
|
+
expect(fieldValue("Episode ID")).toContain(EPISODE_ID);
|
|
377
447
|
expectNoCrash();
|
|
378
448
|
});
|
|
379
449
|
|
|
@@ -468,7 +538,542 @@ describe("Incident Episode detail page: both relations missing", () => {
|
|
|
468
538
|
|
|
469
539
|
expect(fieldValue("Episode Severity")).toEqual("-");
|
|
470
540
|
expect(fieldValue("Current State")).toEqual("-");
|
|
471
|
-
expect(fieldValue("Episode
|
|
541
|
+
expect(fieldValue("Episode Number")).toContain("#7");
|
|
542
|
+
expectNoCrash();
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
describe("Incident Episode overview: details column", () => {
|
|
547
|
+
test("uses the compact single-column style with the episode ID last", async () => {
|
|
548
|
+
await renderPage({ state: buildState("Created", new Color("#4b5563")) });
|
|
549
|
+
|
|
550
|
+
const numberRow: HTMLElement | null | undefined = screen
|
|
551
|
+
.getByText("Episode Number")
|
|
552
|
+
.closest("div.space-y-1")?.parentElement;
|
|
553
|
+
const grid: HTMLElement | null | undefined = numberRow?.parentElement;
|
|
554
|
+
|
|
555
|
+
expect(grid).toHaveClass("grid", "grid-cols-1", "divide-y");
|
|
556
|
+
expect(grid).toHaveClass("sm:grid-cols-1");
|
|
557
|
+
expect(numberRow).toHaveClass("py-3");
|
|
558
|
+
|
|
559
|
+
const rowTitles: Array<string> = Array.from(grid!.children).map(
|
|
560
|
+
(row: Element): string => {
|
|
561
|
+
return (row.querySelector("label")?.textContent || "").trim();
|
|
562
|
+
},
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
expect(rowTitles).toEqual([
|
|
566
|
+
"Episode Number",
|
|
567
|
+
"Current State",
|
|
568
|
+
"Episode Severity",
|
|
569
|
+
"Incident Count",
|
|
570
|
+
"Grouping Rule",
|
|
571
|
+
"Created By",
|
|
572
|
+
"On-Call Duty Policies",
|
|
573
|
+
"Created At",
|
|
574
|
+
"Labels",
|
|
575
|
+
"Episode ID",
|
|
576
|
+
]);
|
|
577
|
+
expectNoCrash();
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
test("no longer repeats the title the header already shows", async () => {
|
|
581
|
+
await renderPage({ state: buildState("Created", new Color("#4b5563")) });
|
|
582
|
+
|
|
583
|
+
expect(screen.queryByText("Episode Title")).toBeNull();
|
|
584
|
+
expect(screen.queryByText("Last Incident Added At")).toBeNull();
|
|
585
|
+
// The number is plain text now, not a hand-rolled SVG chip.
|
|
586
|
+
const numberRow: HTMLElement | null | undefined = screen
|
|
587
|
+
.getByText("Episode Number")
|
|
588
|
+
.closest("div.space-y-1")?.parentElement;
|
|
589
|
+
|
|
590
|
+
expect(numberRow?.querySelector("svg")).toBeNull();
|
|
591
|
+
});
|
|
592
|
+
/*
|
|
593
|
+
* The details card sits in a ~300px column. Its old side-by-side header put
|
|
594
|
+
* "Edit Incident Episode" beside the title and squeezed the title and description
|
|
595
|
+
* into a column a word or two wide.
|
|
596
|
+
*/
|
|
597
|
+
test("stacks the details card header and keeps a short, gated Edit button", async () => {
|
|
598
|
+
await renderPage({ state: buildState("Created", new Color("#4b5563")) });
|
|
599
|
+
|
|
600
|
+
const header: HTMLElement = await waitFor(() => {
|
|
601
|
+
return screen.getByTestId("card-header");
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
expect(header).toHaveAttribute("data-header-layout", "stacked");
|
|
605
|
+
expect(within(header).getByText("Episode Details")).toBeInTheDocument();
|
|
606
|
+
expect(
|
|
607
|
+
within(header).getByText("Key facts about this episode."),
|
|
608
|
+
).toBeInTheDocument();
|
|
609
|
+
|
|
610
|
+
const actions: HTMLElement = await waitFor(() => {
|
|
611
|
+
return screen.getByTestId("card-header-actions");
|
|
612
|
+
});
|
|
613
|
+
const edit: HTMLElement = within(actions).getByRole("button", {
|
|
614
|
+
name: "Edit",
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
expect(edit).not.toBeDisabled();
|
|
618
|
+
expect(screen.queryByText("Edit Incident Episode")).toBeNull();
|
|
619
|
+
expect(
|
|
620
|
+
screen.queryByText("Here are more details for this episode."),
|
|
621
|
+
).toBeNull();
|
|
622
|
+
// The roles card shares the column and stacks the same way.
|
|
623
|
+
expect(rolesProps.current?.["headerLayout"]).toBe("stacked");
|
|
624
|
+
expectNoCrash();
|
|
625
|
+
});
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
describe("Incident Episode overview: loading and layout", () => {
|
|
629
|
+
test("shows the overview skeleton and fires every page request at once", async () => {
|
|
630
|
+
getListMock.mockReturnValue(new Promise<never>(() => {}) as never);
|
|
631
|
+
getItemMock.mockReturnValue(new Promise<never>(() => {}) as never);
|
|
632
|
+
|
|
633
|
+
render(<IncidentEpisodeView {...pageProps} />);
|
|
634
|
+
|
|
635
|
+
const status: HTMLElement = screen.getByRole("status");
|
|
636
|
+
|
|
637
|
+
expect(status).toHaveTextContent("Loading episode");
|
|
638
|
+
expect(
|
|
639
|
+
screen
|
|
640
|
+
.getByTestId("event-overview-skeleton-stats")
|
|
641
|
+
.querySelectorAll(".bg-white"),
|
|
642
|
+
).toHaveLength(4);
|
|
643
|
+
|
|
644
|
+
// Nothing below the skeleton mounts (and fetches) until the page is ready.
|
|
645
|
+
expect(screen.queryByText("Episode Severity")).toBeNull();
|
|
646
|
+
expect(changeStateProps.current).toBeNull();
|
|
647
|
+
|
|
648
|
+
// All four requests are in flight together rather than one after another.
|
|
649
|
+
expect(listCallsFor(Incident)).toHaveLength(1);
|
|
650
|
+
expect(listCallsFor(IncidentEpisodeStateTimeline)).toHaveLength(1);
|
|
651
|
+
expect(listCallsFor(IncidentState)).toHaveLength(1);
|
|
652
|
+
expect(getItemMock).toHaveBeenCalledTimes(1);
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
test("still reads the first member's telemetry snapshot, earliest declared", async () => {
|
|
656
|
+
await renderPage({});
|
|
657
|
+
|
|
658
|
+
const firstMemberCall: Array<any> = listCallsFor(Incident).find(
|
|
659
|
+
(call: Array<any>): boolean => {
|
|
660
|
+
return call[0].limit === 1;
|
|
661
|
+
},
|
|
662
|
+
)!;
|
|
663
|
+
|
|
664
|
+
expect(firstMemberCall[0].query.incidentEpisodeId.toString()).toBe(
|
|
665
|
+
EPISODE_ID,
|
|
666
|
+
);
|
|
667
|
+
expect(firstMemberCall[0].select).toEqual({
|
|
668
|
+
_id: true,
|
|
669
|
+
telemetryQuery: true,
|
|
670
|
+
seriesLabels: true,
|
|
671
|
+
});
|
|
672
|
+
expect(firstMemberCall[0].sort).toEqual({
|
|
673
|
+
declaredAt: SortOrder.Ascending,
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
test("renders the header, a four-cell stat bar and the member list", async () => {
|
|
678
|
+
await renderPage({ state: buildState("Created", new Color("#4b5563")) });
|
|
679
|
+
|
|
680
|
+
expect(changeStateProps.current?.["episodeId"].toString()).toBe(EPISODE_ID);
|
|
681
|
+
|
|
682
|
+
const statBar: HTMLElement = screen.getByRole("group", {
|
|
683
|
+
name: "Episode timing",
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
expect(within(statBar).getByText("Acknowledged in")).toBeInTheDocument();
|
|
687
|
+
expect(within(statBar).getByText("Resolved in")).toBeInTheDocument();
|
|
688
|
+
expect(within(statBar).getByText("Duration")).toBeInTheDocument();
|
|
689
|
+
expect(within(statBar).getByText("Incidents")).toBeInTheDocument();
|
|
690
|
+
expect(statValue("Incidents")).toBe("0");
|
|
691
|
+
|
|
692
|
+
await waitFor((): void => {
|
|
693
|
+
expect(
|
|
694
|
+
screen.getByText("No incidents in this episode yet"),
|
|
695
|
+
).toBeInTheDocument();
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
const memberCall: Array<any> = listCallsFor(Incident).find(
|
|
699
|
+
(call: Array<any>): boolean => {
|
|
700
|
+
return call[0].limit === 8;
|
|
701
|
+
},
|
|
702
|
+
)!;
|
|
703
|
+
|
|
704
|
+
expect(memberCall[0].query.incidentEpisodeId.toString()).toBe(EPISODE_ID);
|
|
705
|
+
expect(memberCall[0].sort).toEqual({ declaredAt: SortOrder.Descending });
|
|
706
|
+
expectNoCrash();
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
test("measures the stat bar from declaredAt with the project's state names", async () => {
|
|
710
|
+
const declaredAt: Date = new Date("2026-09-14T18:00:00.000Z");
|
|
711
|
+
|
|
712
|
+
const ackState: IncidentState = new IncidentState();
|
|
713
|
+
ackState.id = new ObjectID(ACK_STATE_ID);
|
|
714
|
+
ackState.name = "Triaged";
|
|
715
|
+
ackState.isAcknowledgedState = true;
|
|
716
|
+
|
|
717
|
+
const resolvedState: IncidentState = new IncidentState();
|
|
718
|
+
resolvedState.id = new ObjectID(RESOLVED_STATE_ID);
|
|
719
|
+
resolvedState.name = "Fixed";
|
|
720
|
+
resolvedState.isResolvedState = true;
|
|
721
|
+
|
|
722
|
+
const ackTimeline: IncidentEpisodeStateTimeline =
|
|
723
|
+
new IncidentEpisodeStateTimeline();
|
|
724
|
+
ackTimeline.incidentStateId = new ObjectID(ACK_STATE_ID);
|
|
725
|
+
// Written long after creation, so a first-timeline start would be wrong.
|
|
726
|
+
ackTimeline.startsAt = new Date(declaredAt.getTime() + 42 * 60 * 1000);
|
|
727
|
+
|
|
728
|
+
const resolvedTimeline: IncidentEpisodeStateTimeline =
|
|
729
|
+
new IncidentEpisodeStateTimeline();
|
|
730
|
+
resolvedTimeline.incidentStateId = new ObjectID(RESOLVED_STATE_ID);
|
|
731
|
+
resolvedTimeline.startsAt = new Date(
|
|
732
|
+
declaredAt.getTime() + 125 * 60 * 1000,
|
|
733
|
+
);
|
|
734
|
+
|
|
735
|
+
getListMock.mockImplementation((...args: Array<any>) => {
|
|
736
|
+
const modelType: unknown = args[0]?.modelType;
|
|
737
|
+
|
|
738
|
+
if (modelType === IncidentState) {
|
|
739
|
+
return Promise.resolve({
|
|
740
|
+
data: [ackState, resolvedState],
|
|
741
|
+
count: 2,
|
|
742
|
+
skip: 0,
|
|
743
|
+
limit: 2,
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
if (modelType === IncidentEpisodeStateTimeline) {
|
|
748
|
+
return Promise.resolve({
|
|
749
|
+
data: [resolvedTimeline, ackTimeline],
|
|
750
|
+
count: 2,
|
|
751
|
+
skip: 0,
|
|
752
|
+
limit: 2,
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
return Promise.resolve(emptyList());
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
const episode: IncidentEpisode = buildEpisode({});
|
|
760
|
+
episode.declaredAt = declaredAt;
|
|
761
|
+
episode.createdAt = new Date(declaredAt.getTime() - 3 * 24 * 3600 * 1000);
|
|
762
|
+
episode.incidentCount = 3;
|
|
763
|
+
|
|
764
|
+
getItemMock.mockResolvedValue(episode as never);
|
|
765
|
+
|
|
766
|
+
render(<IncidentEpisodeView {...pageProps} />);
|
|
767
|
+
|
|
768
|
+
await waitFor((): void => {
|
|
769
|
+
expect(screen.getByText("Triaged in")).toBeInTheDocument();
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
expect(statValue("Triaged in")).toBe("42 minutes");
|
|
773
|
+
expect(statValue("Fixed in")).toBe("2 hours, 5 minutes");
|
|
774
|
+
// Resolved now, so the duration is closed: declared -> resolved.
|
|
775
|
+
expect(statValue("Duration")).toBe("2 hours, 5 minutes");
|
|
776
|
+
expect(statValue("Incidents")).toBe("3");
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
test("a state change refreshes the page in place instead of unmounting it", async () => {
|
|
780
|
+
await renderPage({ state: buildState("Created", new Color("#4b5563")) });
|
|
781
|
+
|
|
782
|
+
await waitFor((): void => {
|
|
783
|
+
expect(
|
|
784
|
+
screen.getByText("No incidents in this episode yet"),
|
|
785
|
+
).toBeInTheDocument();
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
const timelineCallsBefore: number = listCallsFor(
|
|
789
|
+
IncidentEpisodeStateTimeline,
|
|
790
|
+
).length;
|
|
791
|
+
const memberCallsBefore: number = listCallsFor(Incident).filter(
|
|
792
|
+
(call: Array<any>): boolean => {
|
|
793
|
+
return call[0].limit === 8;
|
|
794
|
+
},
|
|
795
|
+
).length;
|
|
796
|
+
const detailFetchesBefore: number = getItemMock.mock.calls.length;
|
|
797
|
+
|
|
798
|
+
let pending: Promise<void> | undefined;
|
|
799
|
+
|
|
800
|
+
act(() => {
|
|
801
|
+
pending = changeStateProps.current!["onActionComplete"]();
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
// No skeleton, no loader: the stat bar and header stay on screen.
|
|
805
|
+
expect(screen.queryByText("Loading episode")).toBeNull();
|
|
806
|
+
expect(
|
|
807
|
+
screen.getByRole("group", { name: "Episode timing" }),
|
|
808
|
+
).toBeInTheDocument();
|
|
809
|
+
|
|
810
|
+
await act(async () => {
|
|
811
|
+
await pending;
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
await waitFor((): void => {
|
|
815
|
+
expect(listCallsFor(IncidentEpisodeStateTimeline).length).toBe(
|
|
816
|
+
timelineCallsBefore + 1,
|
|
817
|
+
);
|
|
818
|
+
// The member list reloads too: member states moved with the episode.
|
|
819
|
+
expect(
|
|
820
|
+
listCallsFor(Incident).filter((call: Array<any>): boolean => {
|
|
821
|
+
return call[0].limit === 8;
|
|
822
|
+
}).length,
|
|
823
|
+
).toBe(memberCallsBefore + 1);
|
|
824
|
+
// Page timing getItem plus the details card reload.
|
|
825
|
+
expect(getItemMock.mock.calls.length).toBeGreaterThanOrEqual(
|
|
826
|
+
detailFetchesBefore + 2,
|
|
827
|
+
);
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
expect(screen.getByText("Episode Severity")).toBeInTheDocument();
|
|
831
|
+
expectNoCrash();
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
test("a failed first load offers a retry that recovers", async () => {
|
|
835
|
+
getItemMock.mockResolvedValue(buildEpisode({}) as never);
|
|
836
|
+
getListMock.mockRejectedValueOnce(new Error("Episode service down"));
|
|
837
|
+
|
|
838
|
+
render(<IncidentEpisodeView {...pageProps} />);
|
|
839
|
+
|
|
840
|
+
await waitFor((): void => {
|
|
841
|
+
expect(screen.getByText("Episode service down")).toBeInTheDocument();
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
fireEvent.click(screen.getByTestId("refresh-button"));
|
|
845
|
+
|
|
846
|
+
await waitFor((): void => {
|
|
847
|
+
expect(screen.getByText("Episode Severity")).toBeInTheDocument();
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
expect(screen.queryByText("Episode service down")).toBeNull();
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
test("a failed refresh keeps the page and says so inline", async () => {
|
|
854
|
+
await renderPage({ state: buildState("Created", new Color("#4b5563")) });
|
|
855
|
+
|
|
856
|
+
getListMock.mockRejectedValueOnce(new Error("Timeline unavailable"));
|
|
857
|
+
|
|
858
|
+
await act(async () => {
|
|
859
|
+
await changeStateProps.current!["onActionComplete"]();
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
await waitFor((): void => {
|
|
863
|
+
expect(screen.getByRole("alert")).toHaveTextContent(
|
|
864
|
+
"Couldn't refresh episode timings: Timeline unavailable",
|
|
865
|
+
);
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
expect(
|
|
869
|
+
screen.getByRole("group", { name: "Episode timing" }),
|
|
870
|
+
).toBeInTheDocument();
|
|
871
|
+
expect(screen.getByText("Episode Severity")).toBeInTheDocument();
|
|
872
|
+
});
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
describe("Incident Episode overview: moving to another episode on the same route", () => {
|
|
876
|
+
/*
|
|
877
|
+
* The overview is an index route inside the episode layout, so moving to
|
|
878
|
+
* another episode re-renders this page with a new id instead of remounting
|
|
879
|
+
* it. The first render for the new id used to mount the header, the member
|
|
880
|
+
* list and the details card for the new id over the previous episode's
|
|
881
|
+
* numbers (each one fetching) before an effect flipped back to the skeleton.
|
|
882
|
+
*/
|
|
883
|
+
const OTHER_EPISODE_ID: string = "99999999-9999-4999-8999-999999999999";
|
|
884
|
+
|
|
885
|
+
type NavigateToFunction = (episodeId: string) => void;
|
|
886
|
+
|
|
887
|
+
const navigateTo: NavigateToFunction = (episodeId: string): void => {
|
|
888
|
+
const path: string = `/dashboard/${PROJECT_ID}/incidents/episodes/${episodeId}`;
|
|
889
|
+
|
|
890
|
+
window.history.pushState({}, "", path);
|
|
891
|
+
Navigation.setLocation({
|
|
892
|
+
pathname: path,
|
|
893
|
+
search: "",
|
|
894
|
+
hash: "",
|
|
895
|
+
state: null,
|
|
896
|
+
key: "other",
|
|
897
|
+
} as Location);
|
|
898
|
+
};
|
|
899
|
+
|
|
900
|
+
// The page's own timing read asks for resolvedAt; the details card does not.
|
|
901
|
+
type IsPageReadFunction = (call: Array<any>) => boolean;
|
|
902
|
+
|
|
903
|
+
const isPageRead: IsPageReadFunction = (call: Array<any>): boolean => {
|
|
904
|
+
return call[0]?.select?.resolvedAt === true;
|
|
905
|
+
};
|
|
906
|
+
|
|
907
|
+
type ReadsForFunction = (
|
|
908
|
+
episodeId: string,
|
|
909
|
+
predicate: IsPageReadFunction,
|
|
910
|
+
) => number;
|
|
911
|
+
|
|
912
|
+
const readsFor: ReadsForFunction = (
|
|
913
|
+
episodeId: string,
|
|
914
|
+
predicate: IsPageReadFunction,
|
|
915
|
+
): number => {
|
|
916
|
+
return getItemMock.mock.calls.filter((call: Array<any>): boolean => {
|
|
917
|
+
return call[0]?.id?.toString() === episodeId && predicate(call);
|
|
918
|
+
}).length;
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
type ServeEpisodesFunction = (
|
|
922
|
+
otherPageRead: Promise<IncidentEpisode>,
|
|
923
|
+
) => void;
|
|
924
|
+
|
|
925
|
+
const serveEpisodes: ServeEpisodesFunction = (
|
|
926
|
+
otherPageRead: Promise<IncidentEpisode>,
|
|
927
|
+
): void => {
|
|
928
|
+
getItemMock.mockImplementation((...args: Array<any>) => {
|
|
929
|
+
const request: Record<string, any> = args[0];
|
|
930
|
+
|
|
931
|
+
if (request["id"]?.toString() === OTHER_EPISODE_ID && isPageRead(args)) {
|
|
932
|
+
return otherPageRead;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
const episode: IncidentEpisode = buildEpisode({
|
|
936
|
+
state: buildState("Created", new Color("#4b5563")),
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
if (request["id"]?.toString() === OTHER_EPISODE_ID) {
|
|
940
|
+
episode.id = new ObjectID(OTHER_EPISODE_ID);
|
|
941
|
+
episode.incidentCount = 5;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
return Promise.resolve(episode);
|
|
945
|
+
});
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
test("shows the skeleton first and renders nothing for the new id before its numbers land", async () => {
|
|
949
|
+
let resolveOther: (episode: IncidentEpisode) => void = (): void => {};
|
|
950
|
+
const otherPageRead: Promise<IncidentEpisode> =
|
|
951
|
+
new Promise<IncidentEpisode>(
|
|
952
|
+
(resolve: (episode: IncidentEpisode) => void) => {
|
|
953
|
+
resolveOther = resolve;
|
|
954
|
+
},
|
|
955
|
+
);
|
|
956
|
+
|
|
957
|
+
serveEpisodes(otherPageRead);
|
|
958
|
+
|
|
959
|
+
const view: ReturnType<typeof render> = render(
|
|
960
|
+
<IncidentEpisodeView {...pageProps} />,
|
|
961
|
+
);
|
|
962
|
+
|
|
963
|
+
await waitFor((): void => {
|
|
964
|
+
expect(screen.getByText("Episode Severity")).toBeInTheDocument();
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
const headerRendersBefore: number = changeStateHistory.length;
|
|
968
|
+
|
|
969
|
+
navigateTo(OTHER_EPISODE_ID);
|
|
970
|
+
view.rerender(<IncidentEpisodeView {...pageProps} />);
|
|
971
|
+
|
|
972
|
+
expect(screen.getByRole("status")).toHaveTextContent("Loading episode");
|
|
973
|
+
expect(screen.queryByText("Episode Severity")).toBeNull();
|
|
974
|
+
|
|
975
|
+
await waitFor((): void => {
|
|
976
|
+
expect(readsFor(OTHER_EPISODE_ID, isPageRead)).toBe(1);
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
// Neither the header nor the details card rendered for the new id yet.
|
|
980
|
+
expect(
|
|
981
|
+
changeStateHistory
|
|
982
|
+
.slice(headerRendersBefore)
|
|
983
|
+
.filter((props: Record<string, any>): boolean => {
|
|
984
|
+
return props["episodeId"]?.toString() === OTHER_EPISODE_ID;
|
|
985
|
+
}),
|
|
986
|
+
).toEqual([]);
|
|
987
|
+
expect(
|
|
988
|
+
readsFor(OTHER_EPISODE_ID, (call: Array<any>): boolean => {
|
|
989
|
+
return !isPageRead(call);
|
|
990
|
+
}),
|
|
991
|
+
).toBe(0);
|
|
992
|
+
|
|
993
|
+
const otherEpisode: IncidentEpisode = buildEpisode({});
|
|
994
|
+
otherEpisode.id = new ObjectID(OTHER_EPISODE_ID);
|
|
995
|
+
otherEpisode.incidentCount = 5;
|
|
996
|
+
|
|
997
|
+
await act(async () => {
|
|
998
|
+
resolveOther(otherEpisode);
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
await waitFor((): void => {
|
|
1002
|
+
expect(statValue("Incidents")).toBe("5");
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
expect(changeStateProps.current?.["episodeId"].toString()).toBe(
|
|
1006
|
+
OTHER_EPISODE_ID,
|
|
1007
|
+
);
|
|
1008
|
+
|
|
1009
|
+
await waitFor((): void => {
|
|
1010
|
+
expect(screen.getByText("Episode Severity")).toBeInTheDocument();
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
// The details card mounted once for the new episode: one read, not two.
|
|
1014
|
+
expect(
|
|
1015
|
+
readsFor(OTHER_EPISODE_ID, (call: Array<any>): boolean => {
|
|
1016
|
+
return !isPageRead(call);
|
|
1017
|
+
}),
|
|
1018
|
+
).toBe(1);
|
|
472
1019
|
expectNoCrash();
|
|
473
1020
|
});
|
|
1021
|
+
|
|
1022
|
+
test("an action on the previous episode that finishes after the switch cannot cancel the next one's load", async () => {
|
|
1023
|
+
let resolveOther: (episode: IncidentEpisode) => void = (): void => {};
|
|
1024
|
+
const otherPageRead: Promise<IncidentEpisode> =
|
|
1025
|
+
new Promise<IncidentEpisode>(
|
|
1026
|
+
(resolve: (episode: IncidentEpisode) => void) => {
|
|
1027
|
+
resolveOther = resolve;
|
|
1028
|
+
},
|
|
1029
|
+
);
|
|
1030
|
+
|
|
1031
|
+
serveEpisodes(otherPageRead);
|
|
1032
|
+
|
|
1033
|
+
const view: ReturnType<typeof render> = render(
|
|
1034
|
+
<IncidentEpisodeView {...pageProps} />,
|
|
1035
|
+
);
|
|
1036
|
+
|
|
1037
|
+
await waitFor((): void => {
|
|
1038
|
+
expect(screen.getByText("Episode Severity")).toBeInTheDocument();
|
|
1039
|
+
});
|
|
1040
|
+
|
|
1041
|
+
// Handed to the previous episode's header, which can still call it.
|
|
1042
|
+
const previousOnActionComplete: () => Promise<void> =
|
|
1043
|
+
changeStateProps.current!["onActionComplete"];
|
|
1044
|
+
|
|
1045
|
+
navigateTo(OTHER_EPISODE_ID);
|
|
1046
|
+
view.rerender(<IncidentEpisodeView {...pageProps} />);
|
|
1047
|
+
|
|
1048
|
+
await waitFor((): void => {
|
|
1049
|
+
expect(readsFor(OTHER_EPISODE_ID, isPageRead)).toBe(1);
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
const timelineReadsBefore: number = listCallsFor(
|
|
1053
|
+
IncidentEpisodeStateTimeline,
|
|
1054
|
+
).length;
|
|
1055
|
+
const previousPageReadsBefore: number = readsFor(EPISODE_ID, isPageRead);
|
|
1056
|
+
|
|
1057
|
+
await act(async () => {
|
|
1058
|
+
await previousOnActionComplete();
|
|
1059
|
+
});
|
|
1060
|
+
|
|
1061
|
+
// Nothing was read again for the episode the reader already left.
|
|
1062
|
+
expect(listCallsFor(IncidentEpisodeStateTimeline).length).toBe(
|
|
1063
|
+
timelineReadsBefore,
|
|
1064
|
+
);
|
|
1065
|
+
expect(readsFor(EPISODE_ID, isPageRead)).toBe(previousPageReadsBefore);
|
|
1066
|
+
|
|
1067
|
+
const otherEpisode: IncidentEpisode = buildEpisode({});
|
|
1068
|
+
otherEpisode.id = new ObjectID(OTHER_EPISODE_ID);
|
|
1069
|
+
otherEpisode.incidentCount = 5;
|
|
1070
|
+
|
|
1071
|
+
await act(async () => {
|
|
1072
|
+
resolveOther(otherEpisode);
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
await waitFor((): void => {
|
|
1076
|
+
expect(statValue("Incidents")).toBe("5");
|
|
1077
|
+
});
|
|
1078
|
+
});
|
|
474
1079
|
});
|