@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.
Files changed (673) hide show
  1. package/Models/DatabaseModels/Index.ts +4 -0
  2. package/Models/DatabaseModels/RumApplication.ts +1 -1
  3. package/Models/DatabaseModels/SecurityEventConnection.ts +457 -0
  4. package/Models/DatabaseModels/SecurityEventConnectionRun.ts +263 -0
  5. package/Models/DatabaseModels/TelemetryIngestionKey.ts +2 -2
  6. package/Server/API/AIInvestigationAPI.ts +484 -24
  7. package/Server/API/GoogleSecOpsConnectionAPI.ts +249 -8
  8. package/Server/API/SecurityEventConnectionAPI.ts +250 -0
  9. package/Server/API/TelemetryAPI.ts +402 -265
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.ts +99 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  12. package/Server/Middleware/TelemetryIngest.ts +101 -6
  13. package/Server/Services/ExceptionAggregationService.ts +7 -16
  14. package/Server/Services/GoogleSecOpsConnectionService.ts +15 -0
  15. package/Server/Services/Index.ts +4 -0
  16. package/Server/Services/InventoryItemService.ts +28 -0
  17. package/Server/Services/LogAggregationService.ts +17 -23
  18. package/Server/Services/MetricAggregationService.ts +4 -14
  19. package/Server/Services/SecurityEventConnectionRunService.ts +10 -0
  20. package/Server/Services/SecurityEventConnectionService.ts +538 -0
  21. package/Server/Services/TraceAggregationService.ts +77 -28
  22. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
  23. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +13 -1
  24. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +15 -1
  25. package/Server/Utils/AI/SRE/InvestigationEvidence.ts +658 -0
  26. package/Server/Utils/AI/SRE/InvestigationReferences.ts +324 -0
  27. package/Server/Utils/AI/Toolbox/Index.ts +38 -0
  28. package/Server/Utils/AI/Toolbox/TimelineTools.ts +9 -2
  29. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +80 -0
  30. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +5 -3
  31. package/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.ts +1108 -0
  32. package/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.ts +732 -0
  33. package/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.ts +495 -0
  34. package/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.ts +689 -0
  35. package/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.ts +767 -0
  36. package/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.ts +571 -0
  37. package/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.ts +827 -0
  38. package/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.ts +610 -0
  39. package/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.ts +549 -0
  40. package/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.ts +830 -0
  41. package/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.ts +684 -0
  42. package/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.ts +487 -0
  43. package/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.ts +778 -0
  44. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.ts +1002 -0
  45. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.ts +556 -0
  46. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.ts +275 -0
  47. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.ts +53 -0
  48. package/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.ts +709 -0
  49. package/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.ts +596 -0
  50. package/Server/Utils/SecurityEvent/Connectors/Types.ts +191 -0
  51. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.ts +353 -65
  52. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.ts +777 -0
  53. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +747 -148
  54. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.ts +48 -2
  55. package/Server/Utils/SecurityEvent/SecurityEventDedupe.ts +81 -0
  56. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +741 -40
  57. package/Server/Utils/StartServer.ts +10 -0
  58. package/Server/Utils/Telemetry/EntityRegistry.ts +8 -0
  59. package/Server/Utils/Telemetry/KubernetesResourceAttributes.ts +108 -0
  60. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +174 -93
  61. package/Server/Utils/Telemetry/ResourceFacetPlanner.ts +251 -0
  62. package/Server/Utils/Telemetry/ResourceFacetResolver.ts +248 -413
  63. package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +668 -0
  64. package/Server/Utils/Telemetry/TraceContextPropagation.ts +348 -0
  65. package/Server/Utils/Telemetry.ts +18 -0
  66. package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +413 -0
  67. package/Tests/App/Dashboard/AIRootCauseFeedItem.test.tsx +285 -0
  68. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +242 -0
  69. package/Tests/App/Dashboard/AlertEpisodeViewFields.test.tsx +601 -15
  70. package/Tests/App/Dashboard/ChangeAlertStateAIHeader.test.tsx +835 -0
  71. package/Tests/App/Dashboard/CloudResourceTelemetryScope.test.ts +41 -0
  72. package/Tests/App/Dashboard/ConnectionTestModal.test.tsx +604 -0
  73. package/Tests/App/Dashboard/ConnectorTestReportView.test.tsx +738 -0
  74. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +153 -6
  75. package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +165 -0
  76. package/Tests/App/Dashboard/EpisodeChangeState.test.tsx +1069 -0
  77. package/Tests/App/Dashboard/EpisodeMembersCard.test.tsx +772 -0
  78. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +2354 -0
  79. package/Tests/App/Dashboard/EventOverviewSkeleton.test.tsx +210 -0
  80. package/Tests/App/Dashboard/EventStatBar.test.tsx +392 -0
  81. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +247 -0
  82. package/Tests/App/Dashboard/ExceptionAIAssistance.test.tsx +606 -0
  83. package/Tests/App/Dashboard/ExceptionBreadcrumbTimeline.test.tsx +273 -0
  84. package/Tests/App/Dashboard/ExceptionDetailSideMenu.test.tsx +176 -0
  85. package/Tests/App/Dashboard/ExceptionOverviewCards.test.tsx +366 -0
  86. package/Tests/App/Dashboard/ExceptionSignalPages.test.tsx +371 -0
  87. package/Tests/App/Dashboard/ExceptionStackFrameViewer.test.tsx +440 -0
  88. package/Tests/App/Dashboard/ExceptionSummary.test.tsx +381 -0
  89. package/Tests/App/Dashboard/ExceptionTriage.test.tsx +306 -0
  90. package/Tests/App/Dashboard/ExceptionsResourceFacets.test.tsx +604 -0
  91. package/Tests/App/Dashboard/ExceptionsViewerEntityChips.test.tsx +706 -0
  92. package/Tests/App/Dashboard/FeedOrdering.test.ts +32 -0
  93. package/Tests/App/Dashboard/GoogleSecOpsConnectionForm.test.tsx +838 -0
  94. package/Tests/App/Dashboard/GoogleSecOpsConnectionsErrors.test.tsx +18 -0
  95. package/Tests/App/Dashboard/GoogleSecOpsDiagnostics.test.tsx +297 -20
  96. package/Tests/App/Dashboard/IncidentEpisodeViewFields.test.tsx +618 -13
  97. package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +254 -207
  98. package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +303 -135
  99. package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +1251 -0
  100. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +303 -0
  101. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +876 -8
  102. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +35 -0
  103. package/Tests/App/Dashboard/InvestigationReferenceLink.test.tsx +177 -0
  104. package/Tests/App/Dashboard/InvestigationReportView.test.tsx +1295 -0
  105. package/Tests/App/Dashboard/KubernetesImageReferenceView.test.tsx +114 -0
  106. package/Tests/App/Dashboard/KubernetesLogsTabChips.test.tsx +285 -0
  107. package/Tests/App/Dashboard/LogsEntityChipNames.test.tsx +316 -0
  108. package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +361 -0
  109. package/Tests/App/Dashboard/ProfileTableEntityNames.test.tsx +432 -0
  110. package/Tests/App/Dashboard/ProfileViewEntityName.test.tsx +250 -0
  111. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +10 -0
  112. package/Tests/App/Dashboard/ResourceLogsTabsBareLayout.test.tsx +700 -0
  113. package/Tests/App/Dashboard/ResourcePageEntityNameProps.test.tsx +803 -0
  114. package/Tests/App/Dashboard/RumSessionReplaySideMenu.test.tsx +11 -1
  115. package/Tests/App/Dashboard/ScheduledMaintenanceChangeState.test.tsx +1026 -0
  116. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +436 -0
  117. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +1195 -0
  118. package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +1022 -0
  119. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +905 -0
  120. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +247 -0
  121. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +375 -274
  122. package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +410 -0
  123. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +774 -0
  124. package/Tests/App/Dashboard/TopErrorsPanelResourceNames.test.tsx +316 -0
  125. package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +30 -0
  126. package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +88 -24
  127. package/Tests/App/Dashboard/TraceExplorer.test.tsx +1590 -0
  128. package/Tests/App/Dashboard/TraceWaterfall.test.tsx +488 -0
  129. package/Tests/App/Dashboard/TracesAnalyticsSeriesLabels.test.tsx +367 -0
  130. package/Tests/App/Dashboard/TracesEntityNames.test.tsx +585 -0
  131. package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +613 -0
  132. package/Tests/App/Dashboard/UseServiceNames.test.tsx +359 -0
  133. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +7 -0
  134. package/Tests/Models/InventoryItemNaming.test.ts +132 -16
  135. package/Tests/Models/SecurityDomainAccessControl.test.ts +61 -17
  136. package/Tests/Server/API/AIInvestigationAPI.test.ts +611 -2
  137. package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +1098 -0
  138. package/Tests/Server/API/GoogleSecOpsConnectionAPI.test.ts +409 -0
  139. package/Tests/Server/API/SecurityEventConnectionAPI.test.ts +856 -0
  140. package/Tests/Server/API/SessionReplayAPI.test.ts +528 -1
  141. package/Tests/Server/API/TelemetryFacetsAPI.test.ts +810 -0
  142. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +240 -0
  143. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +229 -0
  144. package/Tests/Server/Services/InventoryItemDisplayName.test.ts +66 -0
  145. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
  146. package/Tests/Server/Services/SecurityEventConnectionService.test.ts +1233 -0
  147. package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +53 -0
  148. package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +218 -0
  149. package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +155 -1
  150. package/Tests/Server/Services/TraceAggregationExceptionScope.test.ts +142 -0
  151. package/Tests/Server/Services/TraceAnalyticsResourceDisplayNames.test.ts +85 -24
  152. package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +33 -0
  153. package/Tests/Server/Utils/AI/InvestigationEvidence.test.ts +1395 -0
  154. package/Tests/Server/Utils/AI/InvestigationReferences.test.ts +616 -0
  155. package/Tests/Server/Utils/AI/TimelineTools.test.ts +119 -0
  156. package/Tests/Server/Utils/AI/Toolbox/AIToolbox.test.ts +151 -0
  157. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +65 -0
  158. package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorExceptionScope.test.ts +224 -0
  159. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPerSeriesFanout.test.ts +55 -2
  160. package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.test.ts +1240 -0
  161. package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.test.ts +1853 -0
  162. package/Tests/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.test.ts +1129 -0
  163. package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.test.ts +1066 -0
  164. package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.test.ts +1568 -0
  165. package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.test.ts +930 -0
  166. package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.test.ts +1409 -0
  167. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.test.ts +763 -0
  168. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.test.ts +1296 -0
  169. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.test.ts +1102 -0
  170. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.test.ts +1174 -0
  171. package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.test.ts +1032 -0
  172. package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.test.ts +1558 -0
  173. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.test.ts +3041 -0
  174. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.test.ts +1168 -0
  175. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.test.ts +906 -0
  176. package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.test.ts +1068 -0
  177. package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.test.ts +1004 -0
  178. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.test.ts +784 -0
  179. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +113 -1
  180. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +5 -1
  181. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +93 -13
  182. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsHttpIntegration.test.ts +23 -1
  183. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +25 -3
  184. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +22 -8
  185. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +82 -16
  186. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSearchDetections.test.ts +730 -0
  187. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsThreePassPoller.test.ts +1577 -0
  188. package/Tests/Server/Utils/SessionReplay/SessionReplayOriginAllowlist.test.ts +41 -0
  189. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1453 -18
  190. package/Tests/Server/Utils/Telemetry/KubernetesResourceAttributes.test.ts +162 -0
  191. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +460 -13
  192. package/Tests/Server/Utils/Telemetry/ResourceFacetPlanner.test.ts +678 -0
  193. package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +348 -2
  194. package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +525 -0
  195. package/Tests/Server/Utils/Telemetry/TraceContextPropagation.test.ts +420 -0
  196. package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +73 -0
  197. package/Tests/Types/Rum/SessionReplayTransportContracts.test.ts +95 -0
  198. package/Tests/Types/SecurityEvent/Connectors/ConnectorDiagnostics.test.ts +82 -0
  199. package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +314 -0
  200. package/Tests/Types/Telemetry/ExceptionSpanScope.test.ts +89 -0
  201. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +96 -0
  202. package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +304 -0
  203. package/Tests/UI/Components/ActiveFilterChipsLockedFilters.test.tsx +357 -0
  204. package/Tests/UI/Components/Card.test.tsx +312 -1
  205. package/Tests/UI/Components/CardModelDetailHeaderLayout.test.tsx +253 -0
  206. package/Tests/UI/Components/CardModelDetailRefresher.test.tsx +342 -0
  207. package/Tests/UI/Components/Checkbox.test.tsx +79 -0
  208. package/Tests/UI/Components/CopyTextButton.test.tsx +142 -0
  209. package/Tests/UI/Components/DetailCompactStyle.test.tsx +621 -0
  210. package/Tests/UI/Components/ErrorBoundary.test.tsx +60 -0
  211. package/Tests/UI/Components/FacetSections.test.tsx +581 -0
  212. package/Tests/UI/Components/FacetSidebarControls.test.tsx +812 -0
  213. package/Tests/UI/Components/FacetVisibility.test.ts +429 -0
  214. package/Tests/UI/Components/LockedFilterActions.test.tsx +396 -0
  215. package/Tests/UI/Components/LockedFilterChip.test.tsx +651 -0
  216. package/Tests/UI/Components/LogsEntityNames.test.ts +1769 -0
  217. package/Tests/UI/Components/LogsEntityNamesComponents.test.tsx +696 -0
  218. package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +600 -0
  219. package/Tests/UI/Components/LogsViewerEntityNames.test.tsx +713 -0
  220. package/Tests/UI/Components/MarkdownInlineReferences.test.tsx +2079 -0
  221. package/Tests/UI/Components/MemberRoleAssignment.test.tsx +446 -0
  222. package/Tests/UI/Components/ModelDetailRefetch.test.tsx +397 -0
  223. package/Tests/UI/Components/ModelListRefetch.test.tsx +233 -0
  224. package/Tests/UI/Components/ModelPageModelChange.test.tsx +409 -0
  225. package/Tests/UI/Components/PaginationIntegration.test.tsx +25 -0
  226. package/Tests/UI/Components/ResourceFacetConfigs.test.ts +172 -0
  227. package/Tests/UI/Components/SavedViewsSidebarIntegration.test.tsx +32 -14
  228. package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +44 -1
  229. package/Tests/UI/Components/TelemetryActiveFilterChipsLockedFilters.test.tsx +304 -0
  230. package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +718 -0
  231. package/Tests/UI/Monitor/EvaluationLogList.test.tsx +303 -0
  232. package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +55 -1
  233. package/Tests/UI/Rum/FidelityNotices.test.ts +22 -0
  234. package/Tests/UI/Rum/RecordingHealthCard.test.tsx +120 -136
  235. package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +988 -0
  236. package/Tests/UI/Rum/ReplayCard.test.tsx +32 -0
  237. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +709 -12
  238. package/Tests/UI/Rum/ReplayHeader.test.tsx +50 -1
  239. package/Tests/UI/Rum/ReplayPinControl.test.tsx +67 -10
  240. package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +41 -12
  241. package/Tests/UI/Rum/ReplayStage.test.tsx +663 -1
  242. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +173 -0
  243. package/Tests/UI/Rum/ReplayUi.test.tsx +189 -2
  244. package/Tests/UI/Rum/ReplayUserSessionsMenu.test.tsx +91 -0
  245. package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +1 -1
  246. package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +585 -0
  247. package/Tests/UI/Rum/SessionReplayTable.test.tsx +844 -51
  248. package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +29 -1
  249. package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +288 -0
  250. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +31 -1
  251. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +6 -0
  252. package/Tests/UI/Utils/Clipboard.test.ts +154 -0
  253. package/Tests/UI/Utils/Navigation.test.ts +24 -0
  254. package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +2205 -0
  255. package/Tests/UI/Utils/Telemetry/UseTelemetryEntityNames.test.tsx +844 -0
  256. package/Tests/Utils/AI/InvestigationReport.test.ts +2430 -0
  257. package/Tests/Utils/APIOutgoingRequestTracer.test.ts +137 -0
  258. package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +40 -0
  259. package/Tests/Utils/Rum/SessionReplayRecordingEnded.test.ts +619 -0
  260. package/Tests/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.test.ts +631 -0
  261. package/Tests/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.test.ts +479 -0
  262. package/Tests/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.test.ts +507 -0
  263. package/Tests/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.test.ts +686 -0
  264. package/Tests/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.test.ts +474 -0
  265. package/Tests/Utils/SecurityEvent/Connectors/OktaNormalizer.test.ts +736 -0
  266. package/Tests/Utils/SecurityEvent/Connectors/SplunkNormalizer.test.ts +407 -0
  267. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.test.ts +129 -0
  268. package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +57 -1
  269. package/Tests/Utils/Telemetry/EntityRelationship.test.ts +36 -0
  270. package/Tests/Utils/Telemetry/LockedFilterSearch.test.ts +600 -0
  271. package/Tests/Utils/Telemetry/NetworkHost.test.ts +48 -0
  272. package/Tests/Utils/Telemetry/OriginAllowList.test.ts +154 -0
  273. package/Tests/Utils/Traces/CriticalPath.test.ts +25 -0
  274. package/Types/AI/AIChatTypes.ts +8 -0
  275. package/Types/AI/InvestigationEvidence.ts +96 -0
  276. package/Types/Monitor/MonitorEvaluationSummary.ts +5 -0
  277. package/Types/Permission.ts +2 -2
  278. package/Types/Rum/SessionReplay.ts +109 -0
  279. package/Types/Rum/SessionReplayApi.ts +31 -0
  280. package/Types/SecurityEvent/Connectors/ConnectorDiagnostics.ts +111 -0
  281. package/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.ts +87 -0
  282. package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +492 -0
  283. package/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.ts +41 -0
  284. package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +56 -1
  285. package/Types/SecurityEvent/GoogleSecOpsRegion.ts +34 -0
  286. package/Types/Telemetry/EntityType.ts +14 -0
  287. package/Types/Telemetry/ExceptionSpanScope.ts +83 -0
  288. package/Types/Telemetry/LockedFilterDetail.ts +46 -0
  289. package/Types/Telemetry/ResourceEntityFacet.ts +17 -10
  290. package/Types/Telemetry/ResourceFacetCatalog.ts +171 -0
  291. package/UI/Components/Card/Card.tsx +118 -83
  292. package/UI/Components/Checkbox/Checkbox.tsx +8 -5
  293. package/UI/Components/CopyTextButton/CopyTextButton.tsx +7 -1
  294. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +4 -1
  295. package/UI/Components/Detail/Detail.tsx +137 -22
  296. package/UI/Components/ErrorBoundary.tsx +38 -0
  297. package/UI/Components/LogsViewer/LogsEntityNames.ts +912 -0
  298. package/UI/Components/LogsViewer/LogsViewer.tsx +156 -77
  299. package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +28 -11
  300. package/UI/Components/LogsViewer/components/FacetSection.tsx +66 -79
  301. package/UI/Components/LogsViewer/components/FacetValueRow.tsx +17 -2
  302. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +45 -5
  303. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +100 -19
  304. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +156 -39
  305. package/UI/Components/LogsViewer/components/LogsTable.tsx +30 -8
  306. package/UI/Components/LogsViewer/types.ts +6 -0
  307. package/UI/Components/Markdown.tsx/InlineReferences.tsx +628 -0
  308. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +385 -312
  309. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +50 -22
  310. package/UI/Components/ModelDetail/CardModelDetail.tsx +15 -0
  311. package/UI/Components/ModelDetail/ModelDetail.tsx +64 -19
  312. package/UI/Components/ModelList/ModelList.tsx +33 -8
  313. package/UI/Components/Page/ModelPage.tsx +119 -54
  314. package/UI/Components/Table/Table.tsx +8 -0
  315. package/UI/Components/Table/TableRow.tsx +13 -5
  316. package/UI/Components/TelemetryViewer/FacetVisibility.ts +229 -0
  317. package/UI/Components/TelemetryViewer/ResourceFacetConfigs.ts +46 -0
  318. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +11 -0
  319. package/UI/Components/TelemetryViewer/components/FacetSearchInput.tsx +79 -0
  320. package/UI/Components/TelemetryViewer/components/FacetSectionHeader.tsx +69 -0
  321. package/UI/Components/TelemetryViewer/components/FacetShowMoreButton.tsx +36 -0
  322. package/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.tsx +88 -0
  323. package/UI/Components/TelemetryViewer/components/LockedFilterActions.tsx +205 -0
  324. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +496 -0
  325. package/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.tsx +30 -10
  326. package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +203 -10
  327. package/UI/Components/TelemetryViewer/components/TelemetryFacetSection.tsx +60 -73
  328. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +94 -7
  329. package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +17 -2
  330. package/UI/Components/TelemetryViewer/types.ts +19 -0
  331. package/UI/Components/TelemetryViewer/useFacetSearchExemptions.ts +158 -0
  332. package/UI/Components/TelemetryViewer/useFacetSectionSearch.ts +102 -0
  333. package/UI/Utils/Clipboard.ts +68 -2
  334. package/UI/Utils/Navigation.ts +17 -2
  335. package/UI/Utils/Telemetry/TelemetryEntityNames.ts +620 -0
  336. package/UI/Utils/Telemetry/UseTelemetryEntityNames.ts +151 -0
  337. package/Utils/AI/InvestigationReport.ts +1789 -0
  338. package/Utils/API.ts +90 -1
  339. package/Utils/Rum/SessionReplayHealth.ts +11 -0
  340. package/Utils/Rum/SessionReplayRecordingEnded.ts +134 -0
  341. package/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.ts +427 -0
  342. package/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.ts +197 -0
  343. package/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.ts +464 -0
  344. package/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.ts +567 -0
  345. package/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.ts +299 -0
  346. package/Utils/SecurityEvent/Connectors/OktaNormalizer.ts +467 -0
  347. package/Utils/SecurityEvent/Connectors/SplunkNormalizer.ts +439 -0
  348. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +124 -12
  349. package/Utils/Telemetry/CrossSignalScope.ts +22 -8
  350. package/Utils/Telemetry/EntityRelationship.ts +8 -0
  351. package/Utils/Telemetry/LockedFilterSearch.ts +412 -0
  352. package/Utils/Telemetry/NetworkHost.ts +43 -0
  353. package/Utils/Telemetry/OriginAllowList.ts +139 -4
  354. package/Utils/Traces/CriticalPath.ts +10 -4
  355. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  356. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  357. package/build/dist/Models/DatabaseModels/RumApplication.js +1 -1
  358. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  359. package/build/dist/Models/DatabaseModels/SecurityEventConnection.js +490 -0
  360. package/build/dist/Models/DatabaseModels/SecurityEventConnection.js.map +1 -0
  361. package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js +287 -0
  362. package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js.map +1 -0
  363. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +2 -2
  364. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
  365. package/build/dist/Server/API/AIInvestigationAPI.js +336 -27
  366. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  367. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +182 -7
  368. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +1 -1
  369. package/build/dist/Server/API/SecurityEventConnectionAPI.js +171 -0
  370. package/build/dist/Server/API/SecurityEventConnectionAPI.js.map +1 -0
  371. package/build/dist/Server/API/TelemetryAPI.js +248 -170
  372. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  373. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js +40 -0
  374. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js.map +1 -0
  375. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  376. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  377. package/build/dist/Server/Middleware/TelemetryIngest.js +57 -4
  378. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  379. package/build/dist/Server/Services/ExceptionAggregationService.js +7 -16
  380. package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
  381. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +8 -0
  382. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -1
  383. package/build/dist/Server/Services/Index.js +4 -0
  384. package/build/dist/Server/Services/Index.js.map +1 -1
  385. package/build/dist/Server/Services/InventoryItemService.js +22 -0
  386. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  387. package/build/dist/Server/Services/LogAggregationService.js +8 -17
  388. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  389. package/build/dist/Server/Services/MetricAggregationService.js +4 -14
  390. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  391. package/build/dist/Server/Services/SecurityEventConnectionRunService.js +9 -0
  392. package/build/dist/Server/Services/SecurityEventConnectionRunService.js.map +1 -0
  393. package/build/dist/Server/Services/SecurityEventConnectionService.js +356 -0
  394. package/build/dist/Server/Services/SecurityEventConnectionService.js.map +1 -0
  395. package/build/dist/Server/Services/TraceAggregationService.js +51 -25
  396. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  397. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
  398. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  399. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  400. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  401. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +14 -7
  402. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  403. package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js +468 -0
  404. package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js.map +1 -0
  405. package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js +230 -0
  406. package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js.map +1 -0
  407. package/build/dist/Server/Utils/AI/Toolbox/Index.js +32 -0
  408. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  409. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js +6 -2
  410. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js.map +1 -1
  411. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +59 -0
  412. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  413. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +5 -3
  414. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  415. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js +752 -0
  416. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js.map +1 -0
  417. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js +493 -0
  418. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js.map +1 -0
  419. package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js +352 -0
  420. package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js.map +1 -0
  421. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js +405 -0
  422. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js.map +1 -0
  423. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js +466 -0
  424. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js.map +1 -0
  425. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js +344 -0
  426. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js.map +1 -0
  427. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js +511 -0
  428. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js.map +1 -0
  429. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js +406 -0
  430. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js.map +1 -0
  431. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js +336 -0
  432. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js.map +1 -0
  433. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js +474 -0
  434. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js.map +1 -0
  435. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js +417 -0
  436. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js.map +1 -0
  437. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js +314 -0
  438. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js.map +1 -0
  439. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js +494 -0
  440. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js.map +1 -0
  441. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js +719 -0
  442. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js.map +1 -0
  443. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js +404 -0
  444. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js.map +1 -0
  445. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js +209 -0
  446. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js.map +1 -0
  447. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js +40 -0
  448. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js.map +1 -0
  449. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js +494 -0
  450. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js.map +1 -0
  451. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js +379 -0
  452. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js.map +1 -0
  453. package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js +27 -0
  454. package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js.map +1 -0
  455. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +234 -61
  456. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -1
  457. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js +537 -0
  458. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js.map +1 -0
  459. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +572 -115
  460. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -1
  461. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +35 -1
  462. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +1 -1
  463. package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js +52 -0
  464. package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js.map +1 -0
  465. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +521 -32
  466. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  467. package/build/dist/Server/Utils/StartServer.js +10 -0
  468. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  469. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +8 -0
  470. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  471. package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js +80 -0
  472. package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js.map +1 -0
  473. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +122 -67
  474. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  475. package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js +146 -0
  476. package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js.map +1 -0
  477. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +174 -248
  478. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
  479. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +492 -0
  480. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -0
  481. package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js +259 -0
  482. package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js.map +1 -0
  483. package/build/dist/Server/Utils/Telemetry.js +11 -5
  484. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  485. package/build/dist/Types/AI/InvestigationEvidence.js +2 -0
  486. package/build/dist/Types/AI/InvestigationEvidence.js.map +1 -0
  487. package/build/dist/Types/Permission.js +2 -2
  488. package/build/dist/Types/Permission.js.map +1 -1
  489. package/build/dist/Types/Rum/SessionReplay.js +95 -0
  490. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  491. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
  492. package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js +18 -0
  493. package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js.map +1 -0
  494. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js +2 -0
  495. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js.map +1 -0
  496. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +374 -0
  497. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -0
  498. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js +35 -0
  499. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js.map +1 -0
  500. package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js +35 -0
  501. package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js.map +1 -0
  502. package/build/dist/Types/Telemetry/EntityType.js +14 -0
  503. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  504. package/build/dist/Types/Telemetry/ExceptionSpanScope.js +59 -0
  505. package/build/dist/Types/Telemetry/ExceptionSpanScope.js.map +1 -0
  506. package/build/dist/Types/Telemetry/LockedFilterDetail.js +16 -0
  507. package/build/dist/Types/Telemetry/LockedFilterDetail.js.map +1 -0
  508. package/build/dist/Types/Telemetry/ResourceEntityFacet.js +16 -10
  509. package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -1
  510. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +119 -0
  511. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -0
  512. package/build/dist/UI/Components/Card/Card.js +34 -17
  513. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  514. package/build/dist/UI/Components/Checkbox/Checkbox.js +6 -4
  515. package/build/dist/UI/Components/Checkbox/Checkbox.js.map +1 -1
  516. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
  517. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
  518. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +1 -1
  519. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  520. package/build/dist/UI/Components/Detail/Detail.js +63 -13
  521. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  522. package/build/dist/UI/Components/ErrorBoundary.js +34 -0
  523. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  524. package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js +535 -0
  525. package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js.map +1 -0
  526. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +117 -57
  527. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  528. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +5 -7
  529. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
  530. package/build/dist/UI/Components/LogsViewer/components/FacetSection.js +31 -44
  531. package/build/dist/UI/Components/LogsViewer/components/FacetSection.js.map +1 -1
  532. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +17 -3
  533. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
  534. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +19 -3
  535. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  536. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +64 -18
  537. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  538. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +100 -41
  539. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  540. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +13 -5
  541. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
  542. package/build/dist/UI/Components/LogsViewer/types.js.map +1 -1
  543. package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js +403 -0
  544. package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js.map +1 -0
  545. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +197 -179
  546. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  547. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +30 -21
  548. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  549. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +12 -0
  550. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  551. package/build/dist/UI/Components/ModelDetail/ModelDetail.js +46 -12
  552. package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
  553. package/build/dist/UI/Components/ModelList/ModelList.js +26 -7
  554. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  555. package/build/dist/UI/Components/Page/ModelPage.js +62 -34
  556. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  557. package/build/dist/UI/Components/Table/Table.js +3 -1
  558. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  559. package/build/dist/UI/Components/Table/TableRow.js +8 -1
  560. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  561. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +111 -0
  562. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -0
  563. package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js +22 -0
  564. package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js.map +1 -0
  565. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
  566. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  567. package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js +36 -0
  568. package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js.map +1 -0
  569. package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js +21 -0
  570. package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js.map +1 -0
  571. package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js +14 -0
  572. package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js.map +1 -0
  573. package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js +27 -0
  574. package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js.map +1 -0
  575. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js +88 -0
  576. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js.map +1 -0
  577. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +228 -0
  578. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -0
  579. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js +6 -6
  580. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js.map +1 -1
  581. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +111 -12
  582. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
  583. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js +27 -40
  584. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js.map +1 -1
  585. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +70 -10
  586. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  587. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +17 -3
  588. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
  589. package/build/dist/UI/Components/TelemetryViewer/types.js +0 -4
  590. package/build/dist/UI/Components/TelemetryViewer/types.js.map +1 -1
  591. package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js +70 -0
  592. package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js.map +1 -0
  593. package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js +52 -0
  594. package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js.map +1 -0
  595. package/build/dist/UI/Utils/Clipboard.js +59 -2
  596. package/build/dist/UI/Utils/Clipboard.js.map +1 -1
  597. package/build/dist/UI/Utils/Navigation.js +11 -2
  598. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  599. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +471 -0
  600. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -0
  601. package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js +113 -0
  602. package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js.map +1 -0
  603. package/build/dist/Utils/AI/InvestigationReport.js +1241 -0
  604. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -0
  605. package/build/dist/Utils/API.js +25 -0
  606. package/build/dist/Utils/API.js.map +1 -1
  607. package/build/dist/Utils/Rum/SessionReplayHealth.js +10 -0
  608. package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -1
  609. package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js +54 -0
  610. package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js.map +1 -0
  611. package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js +311 -0
  612. package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js.map +1 -0
  613. package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js +150 -0
  614. package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js.map +1 -0
  615. package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js +328 -0
  616. package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js.map +1 -0
  617. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js +405 -0
  618. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js.map +1 -0
  619. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js +212 -0
  620. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js.map +1 -0
  621. package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js +351 -0
  622. package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js.map +1 -0
  623. package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js +348 -0
  624. package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js.map +1 -0
  625. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +103 -10
  626. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
  627. package/build/dist/Utils/Telemetry/CrossSignalScope.js +16 -5
  628. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
  629. package/build/dist/Utils/Telemetry/EntityRelationship.js +7 -0
  630. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  631. package/build/dist/Utils/Telemetry/LockedFilterSearch.js +277 -0
  632. package/build/dist/Utils/Telemetry/LockedFilterSearch.js.map +1 -0
  633. package/build/dist/Utils/Telemetry/NetworkHost.js +39 -0
  634. package/build/dist/Utils/Telemetry/NetworkHost.js.map +1 -0
  635. package/build/dist/Utils/Telemetry/OriginAllowList.js +105 -4
  636. package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -1
  637. package/build/dist/Utils/Traces/CriticalPath.js +9 -4
  638. package/build/dist/Utils/Traces/CriticalPath.js.map +1 -1
  639. package/package.json +1 -1
  640. package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +0 -600
  641. package/UI/Components/GanttChart/Bar/BarLabel.tsx +0 -17
  642. package/UI/Components/GanttChart/Bar/Index.tsx +0 -149
  643. package/UI/Components/GanttChart/ChartContainer.tsx +0 -50
  644. package/UI/Components/GanttChart/Index.tsx +0 -90
  645. package/UI/Components/GanttChart/Row/Index.tsx +0 -22
  646. package/UI/Components/GanttChart/Row/Row.tsx +0 -231
  647. package/UI/Components/GanttChart/Row/RowLabel.tsx +0 -30
  648. package/UI/Components/GanttChart/Rows.tsx +0 -59
  649. package/UI/Components/GanttChart/Timeline/Index.tsx +0 -46
  650. package/UI/Components/GanttChart/Timeline/TimelineInterval.tsx +0 -33
  651. package/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.tsx +0 -43
  652. package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js +0 -8
  653. package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js.map +0 -1
  654. package/build/dist/UI/Components/GanttChart/Bar/Index.js +0 -77
  655. package/build/dist/UI/Components/GanttChart/Bar/Index.js.map +0 -1
  656. package/build/dist/UI/Components/GanttChart/ChartContainer.js +0 -33
  657. package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +0 -1
  658. package/build/dist/UI/Components/GanttChart/Index.js +0 -39
  659. package/build/dist/UI/Components/GanttChart/Index.js.map +0 -1
  660. package/build/dist/UI/Components/GanttChart/Row/Index.js +0 -7
  661. package/build/dist/UI/Components/GanttChart/Row/Index.js.map +0 -1
  662. package/build/dist/UI/Components/GanttChart/Row/Row.js +0 -106
  663. package/build/dist/UI/Components/GanttChart/Row/Row.js.map +0 -1
  664. package/build/dist/UI/Components/GanttChart/Row/RowLabel.js +0 -10
  665. package/build/dist/UI/Components/GanttChart/Row/RowLabel.js.map +0 -1
  666. package/build/dist/UI/Components/GanttChart/Rows.js +0 -19
  667. package/build/dist/UI/Components/GanttChart/Rows.js.map +0 -1
  668. package/build/dist/UI/Components/GanttChart/Timeline/Index.js +0 -16
  669. package/build/dist/UI/Components/GanttChart/Timeline/Index.js.map +0 -1
  670. package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js +0 -13
  671. package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js.map +0 -1
  672. package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js +0 -13
  673. package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js.map +0 -1
@@ -0,0 +1,1251 @@
1
+ import "@testing-library/jest-dom";
2
+ import {
3
+ afterEach,
4
+ beforeEach,
5
+ describe,
6
+ expect,
7
+ jest,
8
+ test,
9
+ } from "@jest/globals";
10
+ import {
11
+ act,
12
+ cleanup,
13
+ fireEvent,
14
+ render,
15
+ screen,
16
+ waitFor,
17
+ within,
18
+ } from "@testing-library/react";
19
+ import * as React from "react";
20
+ import getJestMockFunction, { MockFunction } from "../../MockType";
21
+
22
+ /*
23
+ * "Evidence checked" is where a responder verifies the AI: which queries ran,
24
+ * what each one asked, and the rows behind it. Loading rows re-runs a query
25
+ * with the viewer's own permissions, so these tests pin the request contract
26
+ * (one POST per citation per run, the exact body, stale responses ignored)
27
+ * as well as what each state tells the reader.
28
+ */
29
+
30
+ const postMock: MockFunction = getJestMockFunction();
31
+ const getFriendlyMessageMock: MockFunction = getJestMockFunction();
32
+ const getCommonHeadersMock: MockFunction = getJestMockFunction();
33
+ const widgetRendererMock: MockFunction = getJestMockFunction();
34
+
35
+ jest.mock("../../../UI/Utils/API/API", () => {
36
+ return {
37
+ __esModule: true,
38
+ default: {
39
+ post: (...args: Array<unknown>) => {
40
+ return postMock(...args);
41
+ },
42
+ getFriendlyMessage: (...args: Array<unknown>) => {
43
+ return getFriendlyMessageMock(...args);
44
+ },
45
+ },
46
+ };
47
+ });
48
+
49
+ jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
50
+ return {
51
+ __esModule: true,
52
+ default: {
53
+ getCommonHeaders: (...args: Array<unknown>) => {
54
+ return getCommonHeadersMock(...args);
55
+ },
56
+ },
57
+ };
58
+ });
59
+
60
+ jest.mock(
61
+ "../../../../App/FeatureSet/Dashboard/src/Components/AIChat/Widgets/WidgetRenderer",
62
+ () => {
63
+ return {
64
+ __esModule: true,
65
+ default: (props: {
66
+ widgets: Array<AIChatWidget>;
67
+ }): React.ReactElement => {
68
+ widgetRendererMock(props);
69
+ return React.createElement(
70
+ "div",
71
+ { "data-testid": "evidence-widget" },
72
+ props.widgets
73
+ .map((widget: AIChatWidget): string => {
74
+ return widget.title;
75
+ })
76
+ .join(","),
77
+ );
78
+ },
79
+ };
80
+ },
81
+ );
82
+
83
+ import InvestigationEvidenceList, {
84
+ ComponentProps as EvidenceListProps,
85
+ EVIDENCE_HIGHLIGHT_DURATION_MS,
86
+ EvidenceFocusRequest,
87
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/AI/InvestigationReport/InvestigationEvidenceList";
88
+ import {
89
+ AIChatCitationTargetType,
90
+ AIChatWidget,
91
+ AIChatWidgetType,
92
+ } from "../../../Types/AI/AIChatTypes";
93
+ import { InvestigationEvidenceItem } from "../../../Types/AI/InvestigationEvidence";
94
+ import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
95
+ import { JSONObject } from "../../../Types/JSON";
96
+ import { InvestigationEvidenceCheckedEntry } from "../../../Utils/AI/InvestigationReport";
97
+ import { formatEvidenceLabel } from "../../../../App/FeatureSet/Dashboard/src/Utils/InvestigationEvidenceFormat";
98
+
99
+ interface PostRequest {
100
+ url: { toString: () => string };
101
+ data: JSONObject;
102
+ headers: JSONObject;
103
+ }
104
+
105
+ interface Deferred<T> {
106
+ promise: Promise<T>;
107
+ resolve: (value: T) => void;
108
+ }
109
+
110
+ const RUN_ID: string = "11111111-1111-4111-8111-111111111111";
111
+ const NEXT_RUN_ID: string = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
112
+ const INCIDENT_ID: string = "33333333-3333-4333-8333-333333333333";
113
+ const OTHER_INCIDENT_ID: string = "55555555-5555-4555-8555-555555555555";
114
+ const EXECUTED_AT: string = "2026-09-14T18:01:00.000Z";
115
+
116
+ const incidentsItem: InvestigationEvidenceItem = {
117
+ citationId: "C1",
118
+ toolName: "query_incidents",
119
+ label: "Active incidents (7 total)",
120
+ rowCount: 7,
121
+ durationInMs: 1234,
122
+ queryArguments: { state: "active", limit: 20 },
123
+ target: { type: AIChatCitationTargetType.Incidents },
124
+ executedAt: EXECUTED_AT,
125
+ canLoadRows: true,
126
+ };
127
+
128
+ const logsItem: InvestigationEvidenceItem = {
129
+ citationId: "C2",
130
+ toolName: "search_logs",
131
+ label: "Logs 2026-09-14T17:20:00Z – 2026-09-14T18:20:00Z (1 shown)",
132
+ rowCount: 1,
133
+ durationInMs: 340,
134
+ queryArguments: {
135
+ startTime: "2026-09-14T17:20:00.000Z",
136
+ endTime: "2026-09-14T18:20:00.000Z",
137
+ bodySearchText: "timeout",
138
+ },
139
+ target: { type: AIChatCitationTargetType.Logs },
140
+ executedAt: EXECUTED_AT,
141
+ canLoadRows: true,
142
+ };
143
+
144
+ const emptyItem: InvestigationEvidenceItem = {
145
+ citationId: "C3",
146
+ toolName: "top_exceptions",
147
+ label: "Top exceptions, last 24h (0 found)",
148
+ rowCount: 0,
149
+ queryArguments: {},
150
+ canLoadRows: false,
151
+ };
152
+
153
+ const incidentViewItem: InvestigationEvidenceItem = {
154
+ citationId: "C4",
155
+ toolName: "get_incident_timeline",
156
+ label: "Incident #6954 timeline (12 entries)",
157
+ rowCount: 12,
158
+ queryArguments: { incidentId: INCIDENT_ID },
159
+ target: {
160
+ type: AIChatCitationTargetType.IncidentView,
161
+ params: { incidentId: INCIDENT_ID },
162
+ },
163
+ canLoadRows: true,
164
+ };
165
+
166
+ const legacyEntries: Array<InvestigationEvidenceCheckedEntry> = [
167
+ { citationId: "C1", label: "Active incidents (7 total)", rowCount: 7 },
168
+ { citationId: "C2", label: "Monitors (2 found)", rowCount: 0 },
169
+ ];
170
+
171
+ function createDeferred<T>(): Deferred<T> {
172
+ let resolvePromise: ((value: T) => void) | undefined;
173
+ const promise: Promise<T> = new Promise<T>((resolve: (value: T) => void) => {
174
+ resolvePromise = resolve;
175
+ });
176
+
177
+ return {
178
+ promise,
179
+ resolve: (value: T): void => {
180
+ resolvePromise!(value);
181
+ },
182
+ };
183
+ }
184
+
185
+ function rowsResponse(overrides: JSONObject = {}): { data: JSONObject } {
186
+ return {
187
+ data: {
188
+ citationId: "C1",
189
+ toolName: "query_incidents",
190
+ label: "Active incidents (7 total)",
191
+ rowCount: 7,
192
+ isTruncated: false,
193
+ executedAt: "2026-09-15T09:00:00.000Z",
194
+ isPinnedToInvestigationTime: false,
195
+ investigatedAt: EXECUTED_AT,
196
+ text: "id | title\n1 | Checkout down",
197
+ ...overrides,
198
+ },
199
+ };
200
+ }
201
+
202
+ function renderList(
203
+ overrides: Partial<EvidenceListProps> = {},
204
+ ): ReturnType<typeof render> {
205
+ return render(<InvestigationEvidenceList {...listProps(overrides)} />);
206
+ }
207
+
208
+ function listProps(
209
+ overrides: Partial<EvidenceListProps> = {},
210
+ ): EvidenceListProps {
211
+ return {
212
+ items: [incidentsItem, logsItem, emptyItem],
213
+ legacyEntries: [],
214
+ subjectType: "incident",
215
+ subjectId: INCIDENT_ID,
216
+ runId: RUN_ID,
217
+ focusRequest: null,
218
+ ...overrides,
219
+ };
220
+ }
221
+
222
+ function rowToggle(label: string | RegExp): HTMLElement {
223
+ return screen.getByRole("button", { name: label });
224
+ }
225
+
226
+ /*
227
+ * The logs label carries ISO timestamps, which the row shows as local times.
228
+ * The expected text is derived with the same formatter so these tests hold in
229
+ * whatever timezone and clock the suite runs under.
230
+ */
231
+ const LOGS_DISPLAY_LABEL: string = formatEvidenceLabel(logsItem.label);
232
+
233
+ function logsToggle(): HTMLElement {
234
+ return screen.getByRole("button", {
235
+ name: (accessibleName: string): boolean => {
236
+ return accessibleName.includes(LOGS_DISPLAY_LABEL);
237
+ },
238
+ });
239
+ }
240
+
241
+ function postRequestAt(index: number): PostRequest {
242
+ return postMock.mock.calls[index]![0] as PostRequest;
243
+ }
244
+
245
+ async function flush(): Promise<void> {
246
+ await act(async (): Promise<void> => {
247
+ await Promise.resolve();
248
+ await Promise.resolve();
249
+ await Promise.resolve();
250
+ });
251
+ }
252
+
253
+ const scrollIntoViewMock: MockFunction = getJestMockFunction();
254
+
255
+ beforeEach(() => {
256
+ getCommonHeadersMock.mockReturnValue({ tenantid: "project-id" });
257
+ getFriendlyMessageMock.mockImplementation((error: unknown): string => {
258
+ if (error instanceof HTTPErrorResponse) {
259
+ return error.message;
260
+ }
261
+
262
+ return "Request failed";
263
+ });
264
+ Object.defineProperty(Element.prototype, "scrollIntoView", {
265
+ configurable: true,
266
+ writable: true,
267
+ value: scrollIntoViewMock,
268
+ });
269
+ });
270
+
271
+ afterEach(() => {
272
+ cleanup();
273
+ jest.useRealTimers();
274
+ postMock.mockReset();
275
+ getFriendlyMessageMock.mockReset();
276
+ getCommonHeadersMock.mockReset();
277
+ widgetRendererMock.mockReset();
278
+ scrollIntoViewMock.mockReset();
279
+ delete (Element.prototype as unknown as { scrollIntoView?: unknown })
280
+ .scrollIntoView;
281
+ delete (window as unknown as { matchMedia?: unknown }).matchMedia;
282
+ });
283
+
284
+ describe("InvestigationEvidenceList rows", () => {
285
+ test("renders nothing without evidence or legacy entries", () => {
286
+ const { container } = renderList({ items: [], legacyEntries: [] });
287
+
288
+ expect(container).toBeEmptyDOMElement();
289
+ });
290
+
291
+ test("frames every query with a header, description and query count", () => {
292
+ renderList();
293
+
294
+ const section: HTMLElement = screen.getByRole("region", {
295
+ name: "Evidence checked",
296
+ });
297
+ expect(
298
+ within(section).getByRole("heading", { name: "Evidence checked" }),
299
+ ).toBeInTheDocument();
300
+ expect(section).toHaveTextContent(
301
+ "Every query OneUptime AI ran while investigating. Expand one to see what it asked and the rows it returned.",
302
+ );
303
+ expect(within(section).getByText("3 queries")).toBeInTheDocument();
304
+ expect(within(section).getAllByRole("listitem")).toHaveLength(3);
305
+ });
306
+
307
+ test("uses the singular for a single query", () => {
308
+ renderList({ items: [incidentsItem] });
309
+
310
+ expect(screen.getByText("1 query")).toBeInTheDocument();
311
+ });
312
+
313
+ test("each row says what was checked, how and what it found", () => {
314
+ renderList();
315
+
316
+ const toggle: HTMLElement = rowToggle(/Active incidents \(7 total\)/);
317
+ expect(toggle.tagName).toBe("BUTTON");
318
+ expect(toggle).toHaveAttribute("type", "button");
319
+ expect(toggle).toHaveAttribute("aria-expanded", "false");
320
+ expect(within(toggle).getByText("C1")).toHaveClass(
321
+ "bg-gray-900",
322
+ "text-white",
323
+ "tabular-nums",
324
+ );
325
+ expect(
326
+ within(toggle).getByText("Active incidents (7 total)"),
327
+ ).toHaveAttribute("title", "Active incidents (7 total)");
328
+ // Two lines on a phone, one clamped line from the sm breakpoint.
329
+ expect(within(toggle).getByText("Active incidents (7 total)")).toHaveClass(
330
+ "line-clamp-2",
331
+ "sm:line-clamp-1",
332
+ );
333
+ expect(toggle).toHaveTextContent("Searched incidents");
334
+ expect(within(toggle).getByText("7 rows")).toBeInTheDocument();
335
+
336
+ expect(within(logsToggle()).getByText("1 row")).toBeInTheDocument();
337
+ expect(logsToggle()).toHaveTextContent("Searched logs");
338
+ });
339
+
340
+ test("shows a timestamped label in local time and keeps the raw label as its tooltip", () => {
341
+ renderList();
342
+
343
+ const toggle: HTMLElement = logsToggle();
344
+ const label: HTMLElement = within(toggle).getByText(LOGS_DISPLAY_LABEL);
345
+
346
+ expect(LOGS_DISPLAY_LABEL).not.toBe(logsItem.label);
347
+ expect(LOGS_DISPLAY_LABEL).toMatch(/^Logs Sep 1[45], .+ – .+ \(1 shown\)$/);
348
+ expect(label).toHaveAttribute("title", logsItem.label);
349
+ expect(toggle).not.toHaveTextContent("2026-09-14T");
350
+ expect(toggle).not.toHaveTextContent("00Z");
351
+
352
+ // The details region is named after what the row shows.
353
+ fireEvent.click(toggle);
354
+ expect(
355
+ screen.getByRole("region", { name: `${LOGS_DISPLAY_LABEL} details` }),
356
+ ).toBeInTheDocument();
357
+ });
358
+
359
+ test("shows a label without timestamps exactly as written", () => {
360
+ renderList({ items: [incidentViewItem] });
361
+
362
+ expect(
363
+ within(rowToggle(/Incident #6954 timeline/)).getByText(
364
+ "Incident #6954 timeline (12 entries)",
365
+ ),
366
+ ).toHaveAttribute("title", "Incident #6954 timeline (12 entries)");
367
+ });
368
+
369
+ test("mutes a query that found nothing", () => {
370
+ renderList();
371
+
372
+ const toggle: HTMLElement = rowToggle(/Top exceptions/);
373
+ expect(within(toggle).getByText("C3")).toHaveClass(
374
+ "bg-gray-200",
375
+ "text-gray-600",
376
+ );
377
+ expect(within(toggle).getByText("No rows")).toHaveClass("text-gray-400");
378
+ });
379
+
380
+ test("points aria-controls at a hidden details region until expanded", () => {
381
+ renderList();
382
+
383
+ const toggle: HTMLElement = rowToggle(/Active incidents/);
384
+ const detailsId: string = toggle.getAttribute("aria-controls")!;
385
+ const details: HTMLElement = document.getElementById(detailsId)!;
386
+
387
+ expect(details).not.toBeNull();
388
+ expect(details).toHaveAttribute("hidden");
389
+ expect(
390
+ screen.queryByRole("region", {
391
+ name: "Active incidents (7 total) details",
392
+ }),
393
+ ).toBeNull();
394
+
395
+ fireEvent.click(toggle);
396
+
397
+ expect(toggle).toHaveAttribute("aria-expanded", "true");
398
+ expect(
399
+ screen.getByRole("region", {
400
+ name: "Active incidents (7 total) details",
401
+ }),
402
+ ).toBe(details);
403
+ expect(details).not.toHaveAttribute("hidden");
404
+ });
405
+
406
+ test("renders hostile labels and arguments as text", () => {
407
+ postMock.mockReturnValue(new Promise(() => {}) as never);
408
+ const hostile: string = '<img src=x onerror="window.__evidencePwned=1">';
409
+
410
+ const { container } = renderList({
411
+ items: [
412
+ {
413
+ ...incidentsItem,
414
+ label: hostile,
415
+ queryArguments: { searchText: hostile },
416
+ },
417
+ ],
418
+ });
419
+ fireEvent.click(screen.getByRole("button", { name: /img src/ }));
420
+
421
+ expect(container.querySelector("img")).toBeNull();
422
+ expect(container).toHaveTextContent(hostile);
423
+ expect(
424
+ (window as unknown as { __evidencePwned?: number }).__evidencePwned,
425
+ ).toBeUndefined();
426
+ });
427
+ });
428
+
429
+ describe("InvestigationEvidenceList details", () => {
430
+ test("lists what was queried with friendly labels, run time, duration and tool", () => {
431
+ postMock.mockReturnValue(new Promise(() => {}) as never);
432
+ renderList();
433
+
434
+ fireEvent.click(logsToggle());
435
+
436
+ const details: HTMLElement = screen.getByRole("region", {
437
+ name: `${LOGS_DISPLAY_LABEL} details`,
438
+ });
439
+ expect(within(details).getByText("What was queried")).toBeInTheDocument();
440
+
441
+ const terms: Array<string> = Array.from(
442
+ details.querySelectorAll("dl dt"),
443
+ ).map((term: Element): string => {
444
+ return term.textContent || "";
445
+ });
446
+ expect(terms).toEqual(["Time window", "Search", "Ran at", "Took", "Tool"]);
447
+ expect(within(details).getByText("“timeout”")).toBeInTheDocument();
448
+ expect(within(details).getByText("340 ms")).toBeInTheDocument();
449
+ expect(within(details).getByText("search_logs")).toBeInTheDocument();
450
+ });
451
+
452
+ test("says when a query ran with its defaults", () => {
453
+ renderList();
454
+
455
+ fireEvent.click(rowToggle(/Top exceptions/));
456
+
457
+ expect(
458
+ screen.getByText("No filters — the query ran with its defaults."),
459
+ ).toBeInTheDocument();
460
+ });
461
+
462
+ test("offers Open in <page> for a query with a target", () => {
463
+ postMock.mockReturnValue(new Promise(() => {}) as never);
464
+ renderList({ items: [incidentViewItem] });
465
+
466
+ fireEvent.click(rowToggle(/Incident #6954 timeline/));
467
+
468
+ const link: HTMLElement = screen.getByRole("link", {
469
+ name: /Open in Incident/,
470
+ });
471
+ expect(link.getAttribute("href")).toMatch(
472
+ new RegExp(`/incidents/${INCIDENT_ID}$`),
473
+ );
474
+ });
475
+
476
+ test("offers a list page for a query targeting a list", () => {
477
+ postMock.mockReturnValue(new Promise(() => {}) as never);
478
+ renderList({ items: [logsItem] });
479
+
480
+ fireEvent.click(logsToggle());
481
+
482
+ expect(
483
+ screen.getByRole("link", { name: /Open in Logs/ }).getAttribute("href"),
484
+ ).toMatch(/\/logs$/);
485
+ });
486
+
487
+ test("has no Open link without a target", () => {
488
+ renderList({ items: [emptyItem] });
489
+
490
+ fireEvent.click(rowToggle(/Top exceptions/));
491
+
492
+ expect(screen.queryByRole("link")).toBeNull();
493
+ });
494
+
495
+ test("explains why rows are unavailable and never requests them", () => {
496
+ renderList({ items: [emptyItem] });
497
+
498
+ fireEvent.click(rowToggle(/Top exceptions/));
499
+
500
+ expect(
501
+ screen.getByText(/can't be re-run from the dashboard/),
502
+ ).toBeInTheDocument();
503
+ expect(postMock).not.toHaveBeenCalled();
504
+ });
505
+ });
506
+
507
+ describe("InvestigationEvidenceList loading rows", () => {
508
+ test("the first expand POSTs exactly once with the run-bound body", async () => {
509
+ postMock.mockResolvedValue(rowsResponse() as never);
510
+ renderList();
511
+
512
+ fireEvent.click(rowToggle(/Active incidents/));
513
+ await flush();
514
+
515
+ expect(postMock).toHaveBeenCalledTimes(1);
516
+ const request: PostRequest = postRequestAt(0);
517
+ expect(request.url.toString()).toContain("/ai-investigation/evidence");
518
+ expect(request.data).toEqual({
519
+ subjectType: "incident",
520
+ subjectId: INCIDENT_ID,
521
+ investigationRunId: RUN_ID,
522
+ citationId: "C1",
523
+ });
524
+ expect(request.headers).toEqual({ tenantid: "project-id" });
525
+ });
526
+
527
+ test("sends the alert subject for an alert investigation", async () => {
528
+ postMock.mockResolvedValue(rowsResponse() as never);
529
+ renderList({ subjectType: "alert" });
530
+
531
+ fireEvent.click(rowToggle(/Active incidents/));
532
+ await flush();
533
+
534
+ expect(postRequestAt(0).data["subjectType"]).toBe("alert");
535
+ });
536
+
537
+ test("shows a loading placeholder while the rows load", async () => {
538
+ const pending: Deferred<unknown> = createDeferred<unknown>();
539
+ postMock.mockReturnValue(pending.promise as never);
540
+ renderList();
541
+
542
+ fireEvent.click(rowToggle(/Active incidents/));
543
+
544
+ const details: HTMLElement = screen.getByRole("region", {
545
+ name: "Active incidents (7 total) details",
546
+ });
547
+ const status: HTMLElement = within(details).getByRole("status");
548
+ expect(status).toHaveTextContent("Loading rows");
549
+ expect(status).toHaveAttribute("aria-live", "polite");
550
+
551
+ await act(async (): Promise<void> => {
552
+ pending.resolve(rowsResponse());
553
+ await Promise.resolve();
554
+ });
555
+
556
+ await waitFor(() => {
557
+ expect(within(details).queryByRole("status")).toBeNull();
558
+ });
559
+ });
560
+
561
+ test("caches rows across collapse and re-expand", async () => {
562
+ postMock.mockResolvedValue(rowsResponse() as never);
563
+ renderList();
564
+
565
+ const toggle: HTMLElement = rowToggle(/Active incidents/);
566
+ fireEvent.click(toggle);
567
+ expect(await screen.findByText(/Checkout down/)).toBeInTheDocument();
568
+
569
+ fireEvent.click(toggle);
570
+ expect(toggle).toHaveAttribute("aria-expanded", "false");
571
+ fireEvent.click(toggle);
572
+ await flush();
573
+
574
+ expect(toggle).toHaveAttribute("aria-expanded", "true");
575
+ expect(screen.getByText(/Checkout down/)).toBeInTheDocument();
576
+ expect(postMock).toHaveBeenCalledTimes(1);
577
+ });
578
+
579
+ test("does not start a duplicate request when toggled quickly", async () => {
580
+ const pending: Deferred<unknown> = createDeferred<unknown>();
581
+ postMock.mockReturnValue(pending.promise as never);
582
+ renderList();
583
+
584
+ const toggle: HTMLElement = rowToggle(/Active incidents/);
585
+ fireEvent.click(toggle);
586
+ fireEvent.click(toggle);
587
+ fireEvent.click(toggle);
588
+
589
+ expect(postMock).toHaveBeenCalledTimes(1);
590
+ });
591
+
592
+ test("loads each citation independently", async () => {
593
+ postMock
594
+ .mockResolvedValueOnce(rowsResponse() as never)
595
+ .mockResolvedValueOnce(
596
+ rowsResponse({
597
+ citationId: "C2",
598
+ text: "18:01 ERROR upstream timeout",
599
+ rowCount: 1,
600
+ }) as never,
601
+ );
602
+ renderList();
603
+
604
+ fireEvent.click(rowToggle(/Active incidents/));
605
+ fireEvent.click(logsToggle());
606
+
607
+ expect(await screen.findByText(/upstream timeout/)).toBeInTheDocument();
608
+ expect(postMock).toHaveBeenCalledTimes(2);
609
+ expect(postRequestAt(1).data["citationId"]).toBe("C2");
610
+ });
611
+
612
+ test("renders a widget through the chat widget renderer", async () => {
613
+ const widget: JSONObject = {
614
+ id: "W1",
615
+ citationId: "C1",
616
+ type: AIChatWidgetType.IncidentList,
617
+ title: "Active incidents",
618
+ data: { items: [{ id: INCIDENT_ID, title: "Checkout down" }] },
619
+ };
620
+ postMock.mockResolvedValue(
621
+ rowsResponse({ widget, text: undefined }) as never,
622
+ );
623
+ renderList();
624
+
625
+ fireEvent.click(rowToggle(/Active incidents/));
626
+
627
+ expect(await screen.findByTestId("evidence-widget")).toHaveTextContent(
628
+ "Active incidents",
629
+ );
630
+ const props: { widgets: Array<AIChatWidget> } = widgetRendererMock.mock
631
+ .calls[0]![0] as { widgets: Array<AIChatWidget> };
632
+ expect(props.widgets).toHaveLength(1);
633
+ expect(props.widgets[0]).toEqual(
634
+ expect.objectContaining({
635
+ id: "W1",
636
+ type: AIChatWidgetType.IncidentList,
637
+ title: "Active incidents",
638
+ }),
639
+ );
640
+ expect(document.querySelector("pre")).toBeNull();
641
+ });
642
+
643
+ test("renders plain-text rows in a scrollable pre when there is no widget", async () => {
644
+ postMock.mockResolvedValue(rowsResponse() as never);
645
+ renderList();
646
+
647
+ fireEvent.click(rowToggle(/Active incidents/));
648
+
649
+ const text: HTMLElement = await screen.findByText(/Checkout down/);
650
+ expect(text.tagName).toBe("PRE");
651
+ expect(text).toHaveClass("max-h-80", "overflow-auto");
652
+ expect(text.textContent).toBe("id | title\n1 | Checkout down");
653
+ expect(screen.queryByTestId("evidence-widget")).toBeNull();
654
+ });
655
+
656
+ test("shows an empty state when the re-run returns no rows", async () => {
657
+ postMock.mockResolvedValue(
658
+ rowsResponse({ rowCount: 0, text: "[]" }) as never,
659
+ );
660
+ renderList();
661
+
662
+ fireEvent.click(rowToggle(/Active incidents/));
663
+
664
+ expect(await screen.findByText("No rows returned.")).toBeInTheDocument();
665
+ expect(document.querySelector("pre")).toBeNull();
666
+ });
667
+
668
+ test("keeps the server's explanation next to an empty re-run", async () => {
669
+ const message: string =
670
+ 'No monitor status matches "Degraded". Statuses in this project: Operational, Offline.';
671
+ postMock.mockResolvedValue(
672
+ rowsResponse({ rowCount: 0, text: `\n${message} ` }) as never,
673
+ );
674
+ renderList();
675
+
676
+ fireEvent.click(rowToggle(/Active incidents/));
677
+
678
+ const details: HTMLElement = screen.getByRole("region", {
679
+ name: "Active incidents (7 total) details",
680
+ });
681
+ const emptyState: HTMLElement =
682
+ await within(details).findByText("No rows returned.");
683
+ const explanation: HTMLElement = within(details).getByText(message);
684
+
685
+ expect(explanation.tagName).toBe("P");
686
+ expect(explanation.textContent).toBe(message);
687
+ expect(explanation).toHaveClass("text-gray-500", "break-words");
688
+ // Read after the empty state, inside the same box.
689
+ expect(emptyState.parentElement).toBe(explanation.parentElement);
690
+ expect(
691
+ emptyState.compareDocumentPosition(explanation) &
692
+ Node.DOCUMENT_POSITION_FOLLOWING,
693
+ ).toBeTruthy();
694
+ // Still an empty state, not a result.
695
+ expect(document.querySelector("pre")).toBeNull();
696
+ expect(screen.queryByTestId("evidence-widget")).toBeNull();
697
+ });
698
+
699
+ test("keeps the line breaks of a multi-line explanation", async () => {
700
+ const message: string =
701
+ "file: src/pool.ts\nrepository: acme/api@main\n\n(this file is empty — 0 bytes)";
702
+ postMock.mockResolvedValue(
703
+ rowsResponse({ rowCount: 0, text: message }) as never,
704
+ );
705
+ renderList();
706
+
707
+ fireEvent.click(rowToggle(/Active incidents/));
708
+
709
+ expect(await screen.findByText("No rows returned.")).toBeInTheDocument();
710
+ const explanation: HTMLElement = screen.getByText(/this file is empty/);
711
+ expect(explanation.textContent).toBe(message);
712
+ expect(explanation).toHaveClass("whitespace-pre-line");
713
+ });
714
+
715
+ test.each([
716
+ ["an empty JSON list", "[]"],
717
+ ["an empty JSON object", "{}"],
718
+ ["the serializer's empty rows", "(no rows found)"],
719
+ ["the serializer's empty text", " (no data found)\n"],
720
+ ["blank text", " "],
721
+ ])(
722
+ "adds nothing to an empty re-run whose text is %s",
723
+ async (_description: string, text: string) => {
724
+ postMock.mockResolvedValue(rowsResponse({ rowCount: 0, text }) as never);
725
+ renderList();
726
+
727
+ fireEvent.click(rowToggle(/Active incidents/));
728
+
729
+ const emptyState: HTMLElement =
730
+ await screen.findByText("No rows returned.");
731
+ expect(emptyState.tagName).toBe("P");
732
+ expect(emptyState).toHaveClass("text-center");
733
+ expect(emptyState.textContent).toBe("No rows returned.");
734
+
735
+ const rows: HTMLElement = screen.getByRole("group", { name: "Rows" });
736
+ expect(rows.querySelectorAll("p")).toHaveLength(1);
737
+
738
+ if (text.trim()) {
739
+ expect(rows).not.toHaveTextContent(text.trim());
740
+ }
741
+ },
742
+ );
743
+
744
+ test("shows only the empty state when an empty re-run has no text", async () => {
745
+ postMock.mockResolvedValue(
746
+ rowsResponse({ rowCount: 0, text: undefined }) as never,
747
+ );
748
+ renderList();
749
+
750
+ fireEvent.click(rowToggle(/Active incidents/));
751
+
752
+ expect(await screen.findByText("No rows returned.")).toHaveClass(
753
+ "text-center",
754
+ );
755
+ expect(
756
+ screen.getByRole("group", { name: "Rows" }).querySelectorAll("p"),
757
+ ).toHaveLength(1);
758
+ });
759
+
760
+ test("tells the reader when rows come from the same time window", async () => {
761
+ postMock.mockResolvedValue(
762
+ rowsResponse({ isPinnedToInvestigationTime: true }) as never,
763
+ );
764
+ renderList();
765
+
766
+ fireEvent.click(rowToggle(/Active incidents/));
767
+
768
+ expect(
769
+ await screen.findByText(
770
+ "Re-run with your permissions over the same time window the AI used.",
771
+ ),
772
+ ).toBeInTheDocument();
773
+ expect(screen.queryByText(/Shows current data/)).toBeNull();
774
+ });
775
+
776
+ test("warns that live rows may differ from what the AI saw", async () => {
777
+ postMock.mockResolvedValue(rowsResponse() as never);
778
+ renderList();
779
+
780
+ fireEvent.click(rowToggle(/Active incidents/));
781
+
782
+ const notice: HTMLElement = await screen.findByText(
783
+ /Shows current data with your permissions — it may differ from what the AI saw at /,
784
+ );
785
+ expect(notice.textContent).toMatch(/at .+\.$/);
786
+ expect(
787
+ screen.queryByText(
788
+ "Re-run with your permissions over the same time window the AI used.",
789
+ ),
790
+ ).toBeNull();
791
+ });
792
+
793
+ test("notes a truncated result", async () => {
794
+ postMock.mockResolvedValue(rowsResponse({ isTruncated: true }) as never);
795
+ renderList();
796
+
797
+ fireEvent.click(rowToggle(/Active incidents/));
798
+
799
+ expect(
800
+ await screen.findByText(
801
+ "The result was long, so only part of it is shown.",
802
+ ),
803
+ ).toBeInTheDocument();
804
+ });
805
+
806
+ test("shows the API error and retries on Try again", async () => {
807
+ postMock
808
+ .mockResolvedValueOnce(
809
+ new HTTPErrorResponse(
810
+ 400,
811
+ { message: "This evidence is no longer available." },
812
+ {},
813
+ ) as never,
814
+ )
815
+ .mockResolvedValueOnce(rowsResponse() as never);
816
+ renderList();
817
+
818
+ fireEvent.click(rowToggle(/Active incidents/));
819
+
820
+ const alert: HTMLElement = await screen.findByRole("alert");
821
+ expect(alert).toHaveTextContent("Could not load these rows");
822
+ expect(alert).toHaveTextContent("This evidence is no longer available.");
823
+ expect(screen.queryByText(/Checkout down/)).toBeNull();
824
+
825
+ fireEvent.click(screen.getByRole("button", { name: "Try again" }));
826
+
827
+ expect(await screen.findByText(/Checkout down/)).toBeInTheDocument();
828
+ expect(screen.queryByRole("alert")).toBeNull();
829
+ expect(postMock).toHaveBeenCalledTimes(2);
830
+ expect(postRequestAt(1).data).toEqual(postRequestAt(0).data);
831
+ });
832
+
833
+ test("keeps keyboard focus inside the details while a retry loads", async () => {
834
+ const retry: Deferred<unknown> = createDeferred<unknown>();
835
+ postMock
836
+ .mockResolvedValueOnce(
837
+ new HTTPErrorResponse(
838
+ 400,
839
+ { message: "This evidence is no longer available." },
840
+ {},
841
+ ) as never,
842
+ )
843
+ .mockReturnValueOnce(retry.promise as never);
844
+ renderList();
845
+
846
+ fireEvent.click(rowToggle(/Active incidents/));
847
+ await screen.findByRole("alert");
848
+
849
+ const details: HTMLElement = screen.getByRole("region", {
850
+ name: "Active incidents (7 total) details",
851
+ });
852
+ const rows: HTMLElement = within(details).getByRole("group", {
853
+ name: "Rows",
854
+ });
855
+ expect(rows).toHaveAttribute("tabindex", "-1");
856
+
857
+ const tryAgain: HTMLElement = within(details).getByRole("button", {
858
+ name: "Try again",
859
+ });
860
+ tryAgain.focus();
861
+ expect(document.activeElement).toBe(tryAgain);
862
+
863
+ fireEvent.click(tryAgain);
864
+
865
+ // The button is gone while the rows reload; focus stays on the Rows block.
866
+ expect(within(rows).getByRole("status")).toHaveTextContent("Loading rows");
867
+ expect(tryAgain).not.toBeInTheDocument();
868
+ expect(document.activeElement).not.toBe(document.body);
869
+ expect(document.activeElement).toBe(rows);
870
+ expect(details).toContainElement(document.activeElement as HTMLElement);
871
+
872
+ await act(async (): Promise<void> => {
873
+ retry.resolve(rowsResponse());
874
+ await Promise.resolve();
875
+ });
876
+
877
+ expect(await within(rows).findByText(/Checkout down/)).toBeInTheDocument();
878
+ expect(document.activeElement).toBe(rows);
879
+ expect(postMock).toHaveBeenCalledTimes(2);
880
+ });
881
+
882
+ test("keeps focus on the Rows block when a retry fails again", async () => {
883
+ postMock.mockRejectedValue(new Error("offline") as never);
884
+ renderList();
885
+
886
+ fireEvent.click(rowToggle(/Active incidents/));
887
+ await screen.findByRole("alert");
888
+
889
+ const rows: HTMLElement = screen.getByRole("group", { name: "Rows" });
890
+ const tryAgain: HTMLElement = within(rows).getByRole("button", {
891
+ name: "Try again",
892
+ });
893
+ tryAgain.focus();
894
+ fireEvent.click(tryAgain);
895
+
896
+ expect(await within(rows).findByRole("alert")).toHaveTextContent(
897
+ "Request failed",
898
+ );
899
+ expect(document.activeElement).toBe(rows);
900
+ // The next Tab reaches a fresh Try again inside the same block.
901
+ expect(
902
+ within(rows).getByRole("button", { name: "Try again" }),
903
+ ).toBeInTheDocument();
904
+ expect(postMock).toHaveBeenCalledTimes(2);
905
+ });
906
+
907
+ test("shows a network failure as an error", async () => {
908
+ postMock.mockRejectedValue(new Error("offline") as never);
909
+ renderList();
910
+
911
+ fireEvent.click(rowToggle(/Active incidents/));
912
+
913
+ expect(await screen.findByRole("alert")).toHaveTextContent(
914
+ "Request failed",
915
+ );
916
+ });
917
+
918
+ test("treats a response that is not rows as an error", async () => {
919
+ postMock.mockResolvedValue({ data: { nope: true } } as never);
920
+ renderList();
921
+
922
+ fireEvent.click(rowToggle(/Active incidents/));
923
+
924
+ expect(await screen.findByRole("alert")).toHaveTextContent(
925
+ "The rows for this query could not be read.",
926
+ );
927
+ });
928
+
929
+ test("never requests rows without a run id", async () => {
930
+ renderList({ runId: null });
931
+
932
+ fireEvent.click(rowToggle(/Active incidents/));
933
+ await flush();
934
+
935
+ expect(postMock).not.toHaveBeenCalled();
936
+ expect(screen.getByRole("alert")).toHaveTextContent(
937
+ "The investigation run could not be identified.",
938
+ );
939
+ });
940
+
941
+ test("ignores a response that lands after the subject changed", async () => {
942
+ const stale: Deferred<unknown> = createDeferred<unknown>();
943
+ postMock
944
+ .mockReturnValueOnce(stale.promise as never)
945
+ .mockResolvedValueOnce(
946
+ rowsResponse({ text: "id | title\n2 | Other subject rows" }) as never,
947
+ );
948
+ const view: ReturnType<typeof render> = renderList();
949
+
950
+ fireEvent.click(rowToggle(/Active incidents/));
951
+ expect(postMock).toHaveBeenCalledTimes(1);
952
+
953
+ view.rerender(
954
+ <InvestigationEvidenceList
955
+ {...listProps({ subjectId: OTHER_INCIDENT_ID })}
956
+ />,
957
+ );
958
+ await flush();
959
+
960
+ // Nothing expanded for the previous subject carries over.
961
+ expect(rowToggle(/Active incidents/)).toHaveAttribute(
962
+ "aria-expanded",
963
+ "false",
964
+ );
965
+
966
+ await act(async (): Promise<void> => {
967
+ stale.resolve(rowsResponse());
968
+ await Promise.resolve();
969
+ await Promise.resolve();
970
+ });
971
+
972
+ fireEvent.click(rowToggle(/Active incidents/));
973
+
974
+ expect(await screen.findByText(/Other subject rows/)).toBeInTheDocument();
975
+ expect(screen.queryByText(/Checkout down/)).toBeNull();
976
+ expect(postMock).toHaveBeenCalledTimes(2);
977
+ expect(postRequestAt(1).data).toEqual({
978
+ subjectType: "incident",
979
+ subjectId: OTHER_INCIDENT_ID,
980
+ investigationRunId: RUN_ID,
981
+ citationId: "C1",
982
+ });
983
+ });
984
+
985
+ test("does not reuse cached rows for a new run on the same subject", async () => {
986
+ postMock
987
+ .mockResolvedValueOnce(rowsResponse() as never)
988
+ .mockResolvedValueOnce(
989
+ rowsResponse({
990
+ text: "id | title\n3 | Rows from the new run",
991
+ }) as never,
992
+ );
993
+ const view: ReturnType<typeof render> = renderList();
994
+
995
+ fireEvent.click(rowToggle(/Active incidents/));
996
+ expect(await screen.findByText(/Checkout down/)).toBeInTheDocument();
997
+
998
+ view.rerender(
999
+ <InvestigationEvidenceList {...listProps({ runId: NEXT_RUN_ID })} />,
1000
+ );
1001
+ await flush();
1002
+
1003
+ expect(screen.queryByText(/Checkout down/)).toBeNull();
1004
+ fireEvent.click(rowToggle(/Active incidents/));
1005
+
1006
+ expect(
1007
+ await screen.findByText(/Rows from the new run/),
1008
+ ).toBeInTheDocument();
1009
+ expect(postRequestAt(1).data["investigationRunId"]).toBe(NEXT_RUN_ID);
1010
+ });
1011
+
1012
+ test("ignores a response that lands after unmount", async () => {
1013
+ const pending: Deferred<unknown> = createDeferred<unknown>();
1014
+ postMock.mockReturnValue(pending.promise as never);
1015
+ const errorSpy: ReturnType<typeof jest.spyOn> = jest
1016
+ .spyOn(console, "error")
1017
+ .mockImplementation(() => {
1018
+ return undefined;
1019
+ });
1020
+ const view: ReturnType<typeof render> = renderList();
1021
+
1022
+ fireEvent.click(rowToggle(/Active incidents/));
1023
+ view.unmount();
1024
+
1025
+ await act(async (): Promise<void> => {
1026
+ pending.resolve(rowsResponse());
1027
+ await Promise.resolve();
1028
+ });
1029
+
1030
+ expect(errorSpy).not.toHaveBeenCalled();
1031
+ errorSpy.mockRestore();
1032
+ });
1033
+ });
1034
+
1035
+ describe("InvestigationEvidenceList focus requests", () => {
1036
+ function focus(citationId: string, requestId: number): EvidenceFocusRequest {
1037
+ return { citationId, requestId };
1038
+ }
1039
+
1040
+ test("expands, scrolls to and briefly highlights the requested citation", async () => {
1041
+ jest.useFakeTimers();
1042
+ postMock.mockResolvedValue(
1043
+ rowsResponse({ citationId: "C2", text: "18:01 ERROR timeout" }) as never,
1044
+ );
1045
+ const view: ReturnType<typeof render> = renderList();
1046
+
1047
+ view.rerender(
1048
+ <InvestigationEvidenceList
1049
+ {...listProps({ focusRequest: focus("C2", 1) })}
1050
+ />,
1051
+ );
1052
+ await flush();
1053
+
1054
+ const toggle: HTMLElement = logsToggle();
1055
+ const row: HTMLElement = toggle.closest("li")!;
1056
+ expect(toggle).toHaveAttribute("aria-expanded", "true");
1057
+ expect(row).toHaveAttribute("data-highlighted", "true");
1058
+ expect(row).toHaveClass("ring-2", "ring-indigo-400");
1059
+ expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);
1060
+ expect(scrollIntoViewMock).toHaveBeenCalledWith({
1061
+ block: "nearest",
1062
+ behavior: "smooth",
1063
+ });
1064
+ expect(document.activeElement).toBe(toggle);
1065
+ expect(postMock).toHaveBeenCalledTimes(1);
1066
+ expect(postRequestAt(0).data["citationId"]).toBe("C2");
1067
+ expect(jest.getTimerCount()).toBe(1);
1068
+
1069
+ await act(async (): Promise<void> => {
1070
+ jest.advanceTimersByTime(EVIDENCE_HIGHLIGHT_DURATION_MS);
1071
+ });
1072
+
1073
+ expect(row).not.toHaveAttribute("data-highlighted");
1074
+ expect(toggle).toHaveAttribute("aria-expanded", "true");
1075
+ expect(jest.getTimerCount()).toBe(0);
1076
+ });
1077
+
1078
+ test("respects reduced motion when scrolling", async () => {
1079
+ Object.defineProperty(window, "matchMedia", {
1080
+ configurable: true,
1081
+ writable: true,
1082
+ value: (query: string): { matches: boolean } => {
1083
+ return { matches: query === "(prefers-reduced-motion: reduce)" };
1084
+ },
1085
+ });
1086
+ postMock.mockReturnValue(new Promise(() => {}) as never);
1087
+
1088
+ renderList({ focusRequest: focus("C1", 1) });
1089
+ await flush();
1090
+
1091
+ expect(scrollIntoViewMock).toHaveBeenCalledWith({
1092
+ block: "nearest",
1093
+ behavior: "auto",
1094
+ });
1095
+ });
1096
+
1097
+ test("keeps a single highlight timer across repeated requests and clears it on unmount", async () => {
1098
+ jest.useFakeTimers();
1099
+ postMock.mockReturnValue(new Promise(() => {}) as never);
1100
+ const view: ReturnType<typeof render> = renderList({
1101
+ focusRequest: focus("C1", 1),
1102
+ });
1103
+ await flush();
1104
+ expect(jest.getTimerCount()).toBe(1);
1105
+
1106
+ view.rerender(
1107
+ <InvestigationEvidenceList
1108
+ {...listProps({ focusRequest: focus("C3", 2) })}
1109
+ />,
1110
+ );
1111
+ await flush();
1112
+
1113
+ expect(jest.getTimerCount()).toBe(1);
1114
+ expect(rowToggle(/Top exceptions/).closest("li")).toHaveAttribute(
1115
+ "data-highlighted",
1116
+ "true",
1117
+ );
1118
+ expect(rowToggle(/Active incidents/).closest("li")).not.toHaveAttribute(
1119
+ "data-highlighted",
1120
+ );
1121
+
1122
+ view.unmount();
1123
+ expect(jest.getTimerCount()).toBe(0);
1124
+ });
1125
+
1126
+ test("repeats a request for the same citation with a new id", async () => {
1127
+ postMock.mockReturnValue(new Promise(() => {}) as never);
1128
+ const view: ReturnType<typeof render> = renderList({
1129
+ focusRequest: focus("C1", 1),
1130
+ });
1131
+ await flush();
1132
+
1133
+ // The reader collapses it, then clicks the same chip again.
1134
+ fireEvent.click(rowToggle(/Active incidents/));
1135
+ expect(rowToggle(/Active incidents/)).toHaveAttribute(
1136
+ "aria-expanded",
1137
+ "false",
1138
+ );
1139
+
1140
+ view.rerender(
1141
+ <InvestigationEvidenceList
1142
+ {...listProps({ focusRequest: focus("C1", 2) })}
1143
+ />,
1144
+ );
1145
+ await flush();
1146
+
1147
+ expect(rowToggle(/Active incidents/)).toHaveAttribute(
1148
+ "aria-expanded",
1149
+ "true",
1150
+ );
1151
+ expect(scrollIntoViewMock).toHaveBeenCalledTimes(2);
1152
+ // Still one request for that citation on this run.
1153
+ expect(postMock).toHaveBeenCalledTimes(1);
1154
+ });
1155
+
1156
+ test("does nothing for a citation that is not in the list", async () => {
1157
+ jest.useFakeTimers();
1158
+ renderList({ focusRequest: focus("C42", 1) });
1159
+ await flush();
1160
+
1161
+ expect(scrollIntoViewMock).not.toHaveBeenCalled();
1162
+ expect(jest.getTimerCount()).toBe(0);
1163
+ expect(document.querySelector('[data-highlighted="true"]')).toBeNull();
1164
+ });
1165
+
1166
+ test("a re-render with the same request does not scroll again", async () => {
1167
+ postMock.mockReturnValue(new Promise(() => {}) as never);
1168
+ const request: EvidenceFocusRequest = focus("C1", 1);
1169
+ const view: ReturnType<typeof render> = renderList({
1170
+ focusRequest: request,
1171
+ });
1172
+ await flush();
1173
+
1174
+ view.rerender(
1175
+ <InvestigationEvidenceList
1176
+ {...listProps({ focusRequest: { ...request } })}
1177
+ />,
1178
+ );
1179
+ await flush();
1180
+
1181
+ expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);
1182
+ });
1183
+ });
1184
+
1185
+ describe("InvestigationEvidenceList legacy reports", () => {
1186
+ test("lists the report's own evidence entries without expanding rows", () => {
1187
+ renderList({ items: [], legacyEntries });
1188
+
1189
+ const section: HTMLElement = screen.getByRole("region", {
1190
+ name: "Evidence checked",
1191
+ });
1192
+ expect(section).toHaveTextContent(
1193
+ "Every query OneUptime AI ran while investigating.",
1194
+ );
1195
+ expect(section).not.toHaveTextContent("Expand one");
1196
+ expect(within(section).getByText("2 queries")).toBeInTheDocument();
1197
+ expect(within(section).queryAllByRole("button")).toHaveLength(0);
1198
+ expect(
1199
+ within(section).getByText("Active incidents (7 total)"),
1200
+ ).toHaveAttribute("title", "Active incidents (7 total)");
1201
+ expect(within(section).getByText("7 rows")).toBeInTheDocument();
1202
+ expect(within(section).getByText("No rows")).toBeInTheDocument();
1203
+ expect(within(section).getByText("C2")).toHaveClass("bg-gray-200");
1204
+ });
1205
+
1206
+ test("shows a legacy entry's timestamps in local time with the raw label as its tooltip", () => {
1207
+ const rawLabel: string =
1208
+ "Changes 2026-09-13T18:02:00.000Z → 2026-09-14T18:02:00.000Z (3 events)";
1209
+
1210
+ renderList({
1211
+ items: [],
1212
+ legacyEntries: [{ citationId: "C5", label: rawLabel, rowCount: 3 }],
1213
+ });
1214
+
1215
+ const section: HTMLElement = screen.getByRole("region", {
1216
+ name: "Evidence checked",
1217
+ });
1218
+ const label: HTMLElement = within(section).getByText(
1219
+ formatEvidenceLabel(rawLabel),
1220
+ );
1221
+
1222
+ expect(label).toHaveAttribute("title", rawLabel);
1223
+ expect(label.textContent).toMatch(
1224
+ /^Changes Sep 1[34], .+ → Sep 1[45], .+ \(3 events\)$/,
1225
+ );
1226
+ expect(section).not.toHaveTextContent("2026-09-13T");
1227
+ });
1228
+
1229
+ test("prefers structured evidence over the legacy entries", () => {
1230
+ renderList({ items: [incidentsItem], legacyEntries });
1231
+
1232
+ expect(screen.getByText("1 query")).toBeInTheDocument();
1233
+ expect(screen.queryByText("Monitors (2 found)")).toBeNull();
1234
+ });
1235
+
1236
+ test("highlights a legacy entry for a focus request without requesting rows", async () => {
1237
+ renderList({
1238
+ items: [],
1239
+ legacyEntries,
1240
+ focusRequest: { citationId: "C2", requestId: 1 },
1241
+ });
1242
+ await flush();
1243
+
1244
+ const row: HTMLElement = screen
1245
+ .getByText("Monitors (2 found)")
1246
+ .closest("li")!;
1247
+ expect(row).toHaveAttribute("data-highlighted", "true");
1248
+ expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);
1249
+ expect(postMock).not.toHaveBeenCalled();
1250
+ });
1251
+ });