@oneuptime/common 13.0.3 → 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 (687) 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/LoggerCore.test.ts +597 -0
  160. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPerSeriesFanout.test.ts +55 -2
  161. package/Tests/Server/Utils/Monitor/MonitorTemplateUtil.test.ts +1109 -0
  162. package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.test.ts +1240 -0
  163. package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.test.ts +1853 -0
  164. package/Tests/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.test.ts +1129 -0
  165. package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.test.ts +1066 -0
  166. package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.test.ts +1568 -0
  167. package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.test.ts +930 -0
  168. package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.test.ts +1409 -0
  169. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.test.ts +763 -0
  170. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.test.ts +1296 -0
  171. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.test.ts +1102 -0
  172. package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.test.ts +1174 -0
  173. package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.test.ts +1032 -0
  174. package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.test.ts +1558 -0
  175. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.test.ts +3041 -0
  176. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.test.ts +1168 -0
  177. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.test.ts +906 -0
  178. package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.test.ts +1068 -0
  179. package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.test.ts +1004 -0
  180. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.test.ts +784 -0
  181. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +113 -1
  182. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +5 -1
  183. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +93 -13
  184. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsHttpIntegration.test.ts +23 -1
  185. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +25 -3
  186. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +22 -8
  187. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +82 -16
  188. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSearchDetections.test.ts +730 -0
  189. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsThreePassPoller.test.ts +1577 -0
  190. package/Tests/Server/Utils/SessionReplay/SessionReplayOriginAllowlist.test.ts +41 -0
  191. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1453 -18
  192. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +711 -0
  193. package/Tests/Server/Utils/Telemetry/KubernetesResourceAttributes.test.ts +162 -0
  194. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +460 -13
  195. package/Tests/Server/Utils/Telemetry/ResourceFacetPlanner.test.ts +678 -0
  196. package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +868 -0
  197. package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +525 -0
  198. package/Tests/Server/Utils/Telemetry/TraceContextPropagation.test.ts +420 -0
  199. package/Tests/Types/OnCallDutyPolicy/LayerUtilCorePaths.test.ts +1014 -0
  200. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveRotation.test.ts +9 -6
  201. package/Tests/Types/Rules/RuleCriteriaFieldRegistry.test.ts +276 -0
  202. package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +73 -0
  203. package/Tests/Types/Rum/SessionReplayTransportContracts.test.ts +95 -0
  204. package/Tests/Types/SecurityEvent/Connectors/ConnectorDiagnostics.test.ts +82 -0
  205. package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +314 -0
  206. package/Tests/Types/Telemetry/ExceptionSpanScope.test.ts +89 -0
  207. package/Tests/Types/Telemetry/LlmConventions.test.ts +495 -0
  208. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +96 -0
  209. package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +304 -0
  210. package/Tests/UI/Components/ActiveFilterChipsLockedFilters.test.tsx +357 -0
  211. package/Tests/UI/Components/Card.test.tsx +312 -1
  212. package/Tests/UI/Components/CardModelDetailHeaderLayout.test.tsx +253 -0
  213. package/Tests/UI/Components/CardModelDetailRefresher.test.tsx +342 -0
  214. package/Tests/UI/Components/Checkbox.test.tsx +79 -0
  215. package/Tests/UI/Components/CopyTextButton.test.tsx +142 -0
  216. package/Tests/UI/Components/DetailCompactStyle.test.tsx +621 -0
  217. package/Tests/UI/Components/ErrorBoundary.test.tsx +60 -0
  218. package/Tests/UI/Components/FacetSections.test.tsx +581 -0
  219. package/Tests/UI/Components/FacetSidebarControls.test.tsx +812 -0
  220. package/Tests/UI/Components/FacetVisibility.test.ts +429 -0
  221. package/Tests/UI/Components/LockedFilterActions.test.tsx +396 -0
  222. package/Tests/UI/Components/LockedFilterChip.test.tsx +651 -0
  223. package/Tests/UI/Components/LogsEntityNames.test.ts +1769 -0
  224. package/Tests/UI/Components/LogsEntityNamesComponents.test.tsx +696 -0
  225. package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +600 -0
  226. package/Tests/UI/Components/LogsViewerEntityNames.test.tsx +713 -0
  227. package/Tests/UI/Components/MarkdownInlineReferences.test.tsx +2079 -0
  228. package/Tests/UI/Components/MemberRoleAssignment.test.tsx +446 -0
  229. package/Tests/UI/Components/ModelDetailRefetch.test.tsx +397 -0
  230. package/Tests/UI/Components/ModelListRefetch.test.tsx +233 -0
  231. package/Tests/UI/Components/ModelPageModelChange.test.tsx +409 -0
  232. package/Tests/UI/Components/PaginationIntegration.test.tsx +25 -0
  233. package/Tests/UI/Components/ResourceFacetConfigs.test.ts +172 -0
  234. package/Tests/UI/Components/SavedViewsSidebarIntegration.test.tsx +32 -14
  235. package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +44 -1
  236. package/Tests/UI/Components/TelemetryActiveFilterChipsLockedFilters.test.tsx +304 -0
  237. package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +718 -0
  238. package/Tests/UI/Monitor/EvaluationLogList.test.tsx +303 -0
  239. package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +55 -1
  240. package/Tests/UI/Rum/FidelityNotices.test.ts +22 -0
  241. package/Tests/UI/Rum/RecordingHealthCard.test.tsx +120 -136
  242. package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +988 -0
  243. package/Tests/UI/Rum/ReplayCard.test.tsx +32 -0
  244. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +709 -12
  245. package/Tests/UI/Rum/ReplayHeader.test.tsx +50 -1
  246. package/Tests/UI/Rum/ReplayPinControl.test.tsx +67 -10
  247. package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +41 -12
  248. package/Tests/UI/Rum/ReplayStage.test.tsx +663 -1
  249. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +173 -0
  250. package/Tests/UI/Rum/ReplayUi.test.tsx +189 -2
  251. package/Tests/UI/Rum/ReplayUserSessionsMenu.test.tsx +91 -0
  252. package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +1 -1
  253. package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +585 -0
  254. package/Tests/UI/Rum/SessionReplayTable.test.tsx +844 -51
  255. package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +29 -1
  256. package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +288 -0
  257. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +31 -1
  258. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +6 -0
  259. package/Tests/UI/Utils/Clipboard.test.ts +154 -0
  260. package/Tests/UI/Utils/Navigation.test.ts +24 -0
  261. package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +2205 -0
  262. package/Tests/UI/Utils/Telemetry/UseTelemetryEntityNames.test.tsx +844 -0
  263. package/Tests/Utils/AI/InvestigationReport.test.ts +2430 -0
  264. package/Tests/Utils/APIOutgoingRequestTracer.test.ts +137 -0
  265. package/Tests/Utils/Rum/SessionReplayHealth.test.ts +884 -0
  266. package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +40 -0
  267. package/Tests/Utils/Rum/SessionReplayRecordingEnded.test.ts +619 -0
  268. package/Tests/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.test.ts +631 -0
  269. package/Tests/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.test.ts +479 -0
  270. package/Tests/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.test.ts +507 -0
  271. package/Tests/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.test.ts +686 -0
  272. package/Tests/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.test.ts +474 -0
  273. package/Tests/Utils/SecurityEvent/Connectors/OktaNormalizer.test.ts +736 -0
  274. package/Tests/Utils/SecurityEvent/Connectors/SplunkNormalizer.test.ts +407 -0
  275. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.test.ts +129 -0
  276. package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +57 -1
  277. package/Tests/Utils/Telemetry/EntityRelationship.test.ts +36 -0
  278. package/Tests/Utils/Telemetry/LockedFilterSearch.test.ts +600 -0
  279. package/Tests/Utils/Telemetry/NetworkHost.test.ts +48 -0
  280. package/Tests/Utils/Telemetry/OriginAllowList.test.ts +154 -0
  281. package/Tests/Utils/Traces/CriticalPath.test.ts +25 -0
  282. package/Types/AI/AIChatTypes.ts +8 -0
  283. package/Types/AI/InvestigationEvidence.ts +96 -0
  284. package/Types/Monitor/MonitorEvaluationSummary.ts +5 -0
  285. package/Types/OnCallDutyPolicy/Layer.ts +12 -0
  286. package/Types/Permission.ts +2 -2
  287. package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
  288. package/Types/Rum/SessionReplay.ts +109 -0
  289. package/Types/Rum/SessionReplayApi.ts +31 -0
  290. package/Types/SecurityEvent/Connectors/ConnectorDiagnostics.ts +111 -0
  291. package/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.ts +87 -0
  292. package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +492 -0
  293. package/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.ts +41 -0
  294. package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +56 -1
  295. package/Types/SecurityEvent/GoogleSecOpsRegion.ts +34 -0
  296. package/Types/Telemetry/EntityType.ts +14 -0
  297. package/Types/Telemetry/ExceptionSpanScope.ts +83 -0
  298. package/Types/Telemetry/LockedFilterDetail.ts +46 -0
  299. package/Types/Telemetry/ResourceEntityFacet.ts +17 -10
  300. package/Types/Telemetry/ResourceFacetCatalog.ts +171 -0
  301. package/UI/Components/Card/Card.tsx +118 -83
  302. package/UI/Components/Checkbox/Checkbox.tsx +8 -5
  303. package/UI/Components/CopyTextButton/CopyTextButton.tsx +7 -1
  304. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +4 -1
  305. package/UI/Components/Detail/Detail.tsx +137 -22
  306. package/UI/Components/ErrorBoundary.tsx +38 -0
  307. package/UI/Components/LogsViewer/LogsEntityNames.ts +912 -0
  308. package/UI/Components/LogsViewer/LogsViewer.tsx +156 -77
  309. package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +28 -11
  310. package/UI/Components/LogsViewer/components/FacetSection.tsx +66 -79
  311. package/UI/Components/LogsViewer/components/FacetValueRow.tsx +17 -2
  312. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +45 -5
  313. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +100 -19
  314. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +156 -39
  315. package/UI/Components/LogsViewer/components/LogsTable.tsx +30 -8
  316. package/UI/Components/LogsViewer/types.ts +6 -0
  317. package/UI/Components/Markdown.tsx/InlineReferences.tsx +628 -0
  318. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +385 -312
  319. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +50 -22
  320. package/UI/Components/ModelDetail/CardModelDetail.tsx +15 -0
  321. package/UI/Components/ModelDetail/ModelDetail.tsx +64 -19
  322. package/UI/Components/ModelList/ModelList.tsx +33 -8
  323. package/UI/Components/Page/ModelPage.tsx +119 -54
  324. package/UI/Components/Table/Table.tsx +8 -0
  325. package/UI/Components/Table/TableRow.tsx +13 -5
  326. package/UI/Components/TelemetryViewer/FacetVisibility.ts +229 -0
  327. package/UI/Components/TelemetryViewer/ResourceFacetConfigs.ts +46 -0
  328. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +11 -0
  329. package/UI/Components/TelemetryViewer/components/FacetSearchInput.tsx +79 -0
  330. package/UI/Components/TelemetryViewer/components/FacetSectionHeader.tsx +69 -0
  331. package/UI/Components/TelemetryViewer/components/FacetShowMoreButton.tsx +36 -0
  332. package/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.tsx +88 -0
  333. package/UI/Components/TelemetryViewer/components/LockedFilterActions.tsx +205 -0
  334. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +496 -0
  335. package/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.tsx +30 -10
  336. package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +203 -10
  337. package/UI/Components/TelemetryViewer/components/TelemetryFacetSection.tsx +60 -73
  338. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +94 -7
  339. package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +17 -2
  340. package/UI/Components/TelemetryViewer/types.ts +19 -0
  341. package/UI/Components/TelemetryViewer/useFacetSearchExemptions.ts +158 -0
  342. package/UI/Components/TelemetryViewer/useFacetSectionSearch.ts +102 -0
  343. package/UI/Utils/Clipboard.ts +68 -2
  344. package/UI/Utils/Navigation.ts +17 -2
  345. package/UI/Utils/Telemetry/TelemetryEntityNames.ts +620 -0
  346. package/UI/Utils/Telemetry/UseTelemetryEntityNames.ts +151 -0
  347. package/Utils/AI/InvestigationReport.ts +1789 -0
  348. package/Utils/API.ts +90 -1
  349. package/Utils/Rum/SessionReplayHealth.ts +11 -0
  350. package/Utils/Rum/SessionReplayRecordingEnded.ts +134 -0
  351. package/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.ts +427 -0
  352. package/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.ts +197 -0
  353. package/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.ts +464 -0
  354. package/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.ts +567 -0
  355. package/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.ts +299 -0
  356. package/Utils/SecurityEvent/Connectors/OktaNormalizer.ts +467 -0
  357. package/Utils/SecurityEvent/Connectors/SplunkNormalizer.ts +439 -0
  358. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +124 -12
  359. package/Utils/Telemetry/CrossSignalScope.ts +22 -8
  360. package/Utils/Telemetry/EntityRelationship.ts +8 -0
  361. package/Utils/Telemetry/LockedFilterSearch.ts +412 -0
  362. package/Utils/Telemetry/NetworkHost.ts +43 -0
  363. package/Utils/Telemetry/OriginAllowList.ts +139 -4
  364. package/Utils/Traces/CriticalPath.ts +10 -4
  365. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  366. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  367. package/build/dist/Models/DatabaseModels/RumApplication.js +1 -1
  368. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  369. package/build/dist/Models/DatabaseModels/SecurityEventConnection.js +490 -0
  370. package/build/dist/Models/DatabaseModels/SecurityEventConnection.js.map +1 -0
  371. package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js +287 -0
  372. package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js.map +1 -0
  373. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +2 -2
  374. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
  375. package/build/dist/Server/API/AIInvestigationAPI.js +336 -27
  376. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  377. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +182 -7
  378. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +1 -1
  379. package/build/dist/Server/API/SecurityEventConnectionAPI.js +171 -0
  380. package/build/dist/Server/API/SecurityEventConnectionAPI.js.map +1 -0
  381. package/build/dist/Server/API/TelemetryAPI.js +248 -170
  382. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  383. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js +40 -0
  384. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js.map +1 -0
  385. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  386. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  387. package/build/dist/Server/Middleware/TelemetryIngest.js +57 -4
  388. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  389. package/build/dist/Server/Services/ExceptionAggregationService.js +7 -16
  390. package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
  391. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +8 -0
  392. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -1
  393. package/build/dist/Server/Services/Index.js +4 -0
  394. package/build/dist/Server/Services/Index.js.map +1 -1
  395. package/build/dist/Server/Services/InventoryItemService.js +22 -0
  396. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  397. package/build/dist/Server/Services/LogAggregationService.js +8 -17
  398. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  399. package/build/dist/Server/Services/MetricAggregationService.js +4 -14
  400. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  401. package/build/dist/Server/Services/SecurityEventConnectionRunService.js +9 -0
  402. package/build/dist/Server/Services/SecurityEventConnectionRunService.js.map +1 -0
  403. package/build/dist/Server/Services/SecurityEventConnectionService.js +356 -0
  404. package/build/dist/Server/Services/SecurityEventConnectionService.js.map +1 -0
  405. package/build/dist/Server/Services/TraceAggregationService.js +51 -25
  406. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  407. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
  408. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  409. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  410. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  411. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +14 -7
  412. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  413. package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js +468 -0
  414. package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js.map +1 -0
  415. package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js +230 -0
  416. package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js.map +1 -0
  417. package/build/dist/Server/Utils/AI/Toolbox/Index.js +32 -0
  418. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  419. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js +6 -2
  420. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js.map +1 -1
  421. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +59 -0
  422. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  423. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +5 -3
  424. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  425. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js +752 -0
  426. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js.map +1 -0
  427. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js +493 -0
  428. package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js.map +1 -0
  429. package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js +352 -0
  430. package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js.map +1 -0
  431. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js +405 -0
  432. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js.map +1 -0
  433. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js +466 -0
  434. package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js.map +1 -0
  435. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js +344 -0
  436. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js.map +1 -0
  437. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js +511 -0
  438. package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js.map +1 -0
  439. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js +406 -0
  440. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js.map +1 -0
  441. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js +336 -0
  442. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js.map +1 -0
  443. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js +474 -0
  444. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js.map +1 -0
  445. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js +417 -0
  446. package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js.map +1 -0
  447. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js +314 -0
  448. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js.map +1 -0
  449. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js +494 -0
  450. package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js.map +1 -0
  451. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js +719 -0
  452. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js.map +1 -0
  453. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js +404 -0
  454. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js.map +1 -0
  455. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js +209 -0
  456. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js.map +1 -0
  457. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js +40 -0
  458. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js.map +1 -0
  459. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js +494 -0
  460. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js.map +1 -0
  461. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js +379 -0
  462. package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js.map +1 -0
  463. package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js +27 -0
  464. package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js.map +1 -0
  465. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +234 -61
  466. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -1
  467. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js +537 -0
  468. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js.map +1 -0
  469. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +572 -115
  470. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -1
  471. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +35 -1
  472. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +1 -1
  473. package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js +52 -0
  474. package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js.map +1 -0
  475. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +521 -32
  476. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  477. package/build/dist/Server/Utils/StartServer.js +10 -0
  478. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  479. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +8 -0
  480. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  481. package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js +80 -0
  482. package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js.map +1 -0
  483. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +122 -67
  484. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  485. package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js +146 -0
  486. package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js.map +1 -0
  487. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +174 -248
  488. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
  489. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +492 -0
  490. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -0
  491. package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js +259 -0
  492. package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js.map +1 -0
  493. package/build/dist/Server/Utils/Telemetry.js +11 -5
  494. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  495. package/build/dist/Types/AI/InvestigationEvidence.js +2 -0
  496. package/build/dist/Types/AI/InvestigationEvidence.js.map +1 -0
  497. package/build/dist/Types/OnCallDutyPolicy/Layer.js +11 -0
  498. package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
  499. package/build/dist/Types/Permission.js +2 -2
  500. package/build/dist/Types/Permission.js.map +1 -1
  501. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +9 -0
  502. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  503. package/build/dist/Types/Rum/SessionReplay.js +95 -0
  504. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  505. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
  506. package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js +18 -0
  507. package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js.map +1 -0
  508. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js +2 -0
  509. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js.map +1 -0
  510. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +374 -0
  511. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -0
  512. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js +35 -0
  513. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js.map +1 -0
  514. package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js +35 -0
  515. package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js.map +1 -0
  516. package/build/dist/Types/Telemetry/EntityType.js +14 -0
  517. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  518. package/build/dist/Types/Telemetry/ExceptionSpanScope.js +59 -0
  519. package/build/dist/Types/Telemetry/ExceptionSpanScope.js.map +1 -0
  520. package/build/dist/Types/Telemetry/LockedFilterDetail.js +16 -0
  521. package/build/dist/Types/Telemetry/LockedFilterDetail.js.map +1 -0
  522. package/build/dist/Types/Telemetry/ResourceEntityFacet.js +16 -10
  523. package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -1
  524. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +119 -0
  525. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -0
  526. package/build/dist/UI/Components/Card/Card.js +34 -17
  527. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  528. package/build/dist/UI/Components/Checkbox/Checkbox.js +6 -4
  529. package/build/dist/UI/Components/Checkbox/Checkbox.js.map +1 -1
  530. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
  531. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
  532. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +1 -1
  533. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  534. package/build/dist/UI/Components/Detail/Detail.js +63 -13
  535. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  536. package/build/dist/UI/Components/ErrorBoundary.js +34 -0
  537. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  538. package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js +535 -0
  539. package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js.map +1 -0
  540. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +117 -57
  541. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  542. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +5 -7
  543. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
  544. package/build/dist/UI/Components/LogsViewer/components/FacetSection.js +31 -44
  545. package/build/dist/UI/Components/LogsViewer/components/FacetSection.js.map +1 -1
  546. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +17 -3
  547. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
  548. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +19 -3
  549. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  550. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +64 -18
  551. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  552. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +100 -41
  553. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  554. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +13 -5
  555. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
  556. package/build/dist/UI/Components/LogsViewer/types.js.map +1 -1
  557. package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js +403 -0
  558. package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js.map +1 -0
  559. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +197 -179
  560. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  561. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +30 -21
  562. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  563. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +12 -0
  564. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  565. package/build/dist/UI/Components/ModelDetail/ModelDetail.js +46 -12
  566. package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
  567. package/build/dist/UI/Components/ModelList/ModelList.js +26 -7
  568. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  569. package/build/dist/UI/Components/Page/ModelPage.js +62 -34
  570. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  571. package/build/dist/UI/Components/Table/Table.js +3 -1
  572. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  573. package/build/dist/UI/Components/Table/TableRow.js +8 -1
  574. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  575. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +111 -0
  576. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -0
  577. package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js +22 -0
  578. package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js.map +1 -0
  579. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
  580. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  581. package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js +36 -0
  582. package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js.map +1 -0
  583. package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js +21 -0
  584. package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js.map +1 -0
  585. package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js +14 -0
  586. package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js.map +1 -0
  587. package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js +27 -0
  588. package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js.map +1 -0
  589. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js +88 -0
  590. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js.map +1 -0
  591. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +228 -0
  592. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -0
  593. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js +6 -6
  594. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js.map +1 -1
  595. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +111 -12
  596. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
  597. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js +27 -40
  598. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js.map +1 -1
  599. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +70 -10
  600. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  601. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +17 -3
  602. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
  603. package/build/dist/UI/Components/TelemetryViewer/types.js +0 -4
  604. package/build/dist/UI/Components/TelemetryViewer/types.js.map +1 -1
  605. package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js +70 -0
  606. package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js.map +1 -0
  607. package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js +52 -0
  608. package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js.map +1 -0
  609. package/build/dist/UI/Utils/Clipboard.js +59 -2
  610. package/build/dist/UI/Utils/Clipboard.js.map +1 -1
  611. package/build/dist/UI/Utils/Navigation.js +11 -2
  612. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  613. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +471 -0
  614. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -0
  615. package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js +113 -0
  616. package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js.map +1 -0
  617. package/build/dist/Utils/AI/InvestigationReport.js +1241 -0
  618. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -0
  619. package/build/dist/Utils/API.js +25 -0
  620. package/build/dist/Utils/API.js.map +1 -1
  621. package/build/dist/Utils/Rum/SessionReplayHealth.js +10 -0
  622. package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -1
  623. package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js +54 -0
  624. package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js.map +1 -0
  625. package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js +311 -0
  626. package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js.map +1 -0
  627. package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js +150 -0
  628. package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js.map +1 -0
  629. package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js +328 -0
  630. package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js.map +1 -0
  631. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js +405 -0
  632. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js.map +1 -0
  633. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js +212 -0
  634. package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js.map +1 -0
  635. package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js +351 -0
  636. package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js.map +1 -0
  637. package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js +348 -0
  638. package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js.map +1 -0
  639. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +103 -10
  640. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
  641. package/build/dist/Utils/Telemetry/CrossSignalScope.js +16 -5
  642. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
  643. package/build/dist/Utils/Telemetry/EntityRelationship.js +7 -0
  644. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  645. package/build/dist/Utils/Telemetry/LockedFilterSearch.js +277 -0
  646. package/build/dist/Utils/Telemetry/LockedFilterSearch.js.map +1 -0
  647. package/build/dist/Utils/Telemetry/NetworkHost.js +39 -0
  648. package/build/dist/Utils/Telemetry/NetworkHost.js.map +1 -0
  649. package/build/dist/Utils/Telemetry/OriginAllowList.js +105 -4
  650. package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -1
  651. package/build/dist/Utils/Traces/CriticalPath.js +9 -4
  652. package/build/dist/Utils/Traces/CriticalPath.js.map +1 -1
  653. package/package.json +1 -1
  654. package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +0 -600
  655. package/UI/Components/GanttChart/Bar/BarLabel.tsx +0 -17
  656. package/UI/Components/GanttChart/Bar/Index.tsx +0 -149
  657. package/UI/Components/GanttChart/ChartContainer.tsx +0 -50
  658. package/UI/Components/GanttChart/Index.tsx +0 -90
  659. package/UI/Components/GanttChart/Row/Index.tsx +0 -22
  660. package/UI/Components/GanttChart/Row/Row.tsx +0 -231
  661. package/UI/Components/GanttChart/Row/RowLabel.tsx +0 -30
  662. package/UI/Components/GanttChart/Rows.tsx +0 -59
  663. package/UI/Components/GanttChart/Timeline/Index.tsx +0 -46
  664. package/UI/Components/GanttChart/Timeline/TimelineInterval.tsx +0 -33
  665. package/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.tsx +0 -43
  666. package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js +0 -8
  667. package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js.map +0 -1
  668. package/build/dist/UI/Components/GanttChart/Bar/Index.js +0 -77
  669. package/build/dist/UI/Components/GanttChart/Bar/Index.js.map +0 -1
  670. package/build/dist/UI/Components/GanttChart/ChartContainer.js +0 -33
  671. package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +0 -1
  672. package/build/dist/UI/Components/GanttChart/Index.js +0 -39
  673. package/build/dist/UI/Components/GanttChart/Index.js.map +0 -1
  674. package/build/dist/UI/Components/GanttChart/Row/Index.js +0 -7
  675. package/build/dist/UI/Components/GanttChart/Row/Index.js.map +0 -1
  676. package/build/dist/UI/Components/GanttChart/Row/Row.js +0 -106
  677. package/build/dist/UI/Components/GanttChart/Row/Row.js.map +0 -1
  678. package/build/dist/UI/Components/GanttChart/Row/RowLabel.js +0 -10
  679. package/build/dist/UI/Components/GanttChart/Row/RowLabel.js.map +0 -1
  680. package/build/dist/UI/Components/GanttChart/Rows.js +0 -19
  681. package/build/dist/UI/Components/GanttChart/Rows.js.map +0 -1
  682. package/build/dist/UI/Components/GanttChart/Timeline/Index.js +0 -16
  683. package/build/dist/UI/Components/GanttChart/Timeline/Index.js.map +0 -1
  684. package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js +0 -13
  685. package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js.map +0 -1
  686. package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js +0 -13
  687. package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js.map +0 -1
@@ -1,8 +1,21 @@
1
1
  import "@testing-library/jest-dom";
2
- import { fireEvent, render, screen, waitFor } from "@testing-library/react";
2
+ import {
3
+ act,
4
+ fireEvent,
5
+ render,
6
+ screen,
7
+ waitFor,
8
+ } from "@testing-library/react";
3
9
  import * as React from "react";
4
10
  import { MemoryRouter } from "react-router-dom";
5
- import { beforeEach, describe, expect, it, jest } from "@jest/globals";
11
+ import {
12
+ afterEach,
13
+ beforeEach,
14
+ describe,
15
+ expect,
16
+ it,
17
+ jest,
18
+ } from "@jest/globals";
6
19
  import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
7
20
  import HTTPResponse from "../../../Types/API/HTTPResponse";
8
21
  import { JSONObject } from "../../../Types/JSON";
@@ -18,7 +31,11 @@ import getJestMockFunction, { MockFunction } from "../../MockType";
18
31
  * cursor; Next disabled without a cursor; unplayable rows never offer
19
32
  * Watch; the ignored user filter is called out instead of chipped; the
20
33
  * 30-day search cap reads as its fix; the Users page is a navigation away
21
- * and its hand-off lands here as the reference, never as the URL.
34
+ * and its hand-off lands here as the reference, never as the URL; a
35
+ * session whose tabs have all closed reads "Recording ended", and the page
36
+ * re-reads itself while it shows an unfinalized session - for a bounded
37
+ * number of ticks, and never while the viewer's pointer or focus is in the
38
+ * table (issue #3642).
22
39
  */
23
40
 
24
41
  const postMock: MockFunction = getJestMockFunction();
@@ -55,6 +72,8 @@ import SessionReplayTable, {
55
72
  fetchSessionReplayList,
56
73
  parseSessionReplaySummary,
57
74
  SESSION_REPLAY_FRUSTRATION_COUNTERS,
75
+ SESSION_REPLAY_LIST_AUTO_REFRESH_MAX_TICKS,
76
+ SESSION_REPLAY_LIST_AUTO_REFRESH_MS,
58
77
  SESSION_REPLAY_LIST_URL_STORAGE_KEY,
59
78
  SESSION_REPLAY_SIGNAL_BADGES,
60
79
  SessionReplayListResult,
@@ -198,7 +217,10 @@ function mockApi(
198
217
  list: (
199
218
  data: JSONObject,
200
219
  index: number,
201
- ) => HTTPResponse<JSONObject> | HTTPErrorResponse,
220
+ ) =>
221
+ | HTTPResponse<JSONObject>
222
+ | HTTPErrorResponse
223
+ | Promise<HTTPResponse<JSONObject> | HTTPErrorResponse>,
202
224
  status: JSONObject = wireStatus(),
203
225
  ): void {
204
226
  let listCalls: number = 0;
@@ -292,6 +314,27 @@ describe("parseSessionReplaySummary", () => {
292
314
  expect(parseSessionReplaySummary(legacy).visitorId).toBe("");
293
315
  });
294
316
 
317
+ it("reads hasRecordingEnded, and an older server's row without it as false", () => {
318
+ expect(
319
+ parseSessionReplaySummary(
320
+ wireRow({ isFinalized: 0, hasRecordingEnded: true }),
321
+ ).hasRecordingEnded,
322
+ ).toBe(true);
323
+ expect(
324
+ parseSessionReplaySummary(
325
+ wireRow({ isFinalized: 0, hasRecordingEnded: 1 }),
326
+ ).hasRecordingEnded,
327
+ ).toBe(true);
328
+ expect(
329
+ parseSessionReplaySummary(
330
+ wireRow({ isFinalized: 0, hasRecordingEnded: false }),
331
+ ).hasRecordingEnded,
332
+ ).toBe(false);
333
+ expect(
334
+ parseSessionReplaySummary(wireRow({ isFinalized: 0 })).hasRecordingEnded,
335
+ ).toBe(false);
336
+ });
337
+
295
338
  it("an older server's row has undefined counters, never 0", () => {
296
339
  const legacy: JSONObject = wireRow();
297
340
 
@@ -518,6 +561,82 @@ describe("SessionReplayTable rendering", () => {
518
561
  expect(screen.getByTestId("session-row-watch")).toBeInTheDocument();
519
562
  });
520
563
 
564
+ /*
565
+ * Issue #3642: a closed tab kept "Recording now · live" and its pulsing
566
+ * dot for 10-15 minutes, because every unfinalized row read as live.
567
+ * The server now says when every tab has ended.
568
+ */
569
+ it("a session whose every tab has closed says Recording ended, finalizing, with no live dot", async () => {
570
+ mockApi(() => {
571
+ return listResponse([
572
+ wireRow({
573
+ isFinalized: 0,
574
+ hasRecordingEnded: true,
575
+ sealedReason: "final-chunk",
576
+ chunkCount: 0,
577
+ durationMs: 0,
578
+ pageCount: 0,
579
+ errorCount: 0,
580
+ rageClickCount: 0,
581
+ traceCount: 0,
582
+ exceptionGroupCount: 0,
583
+ clickCount: 0,
584
+ activeMs: 0,
585
+ }),
586
+ ]);
587
+ });
588
+
589
+ renderTable();
590
+
591
+ const [row] = await waitForRows(1);
592
+
593
+ const badge: HTMLElement = screen.getByTestId("session-row-playability");
594
+
595
+ expect(badge).toHaveAttribute("data-kind", "ended");
596
+ expect(badge.getAttribute("aria-label")).toContain("Recording ended:");
597
+ expect(row).toHaveTextContent("Recording ended");
598
+ expect(row).toHaveTextContent("finalizing · Always-on");
599
+ expect(row).not.toHaveTextContent("Recording now");
600
+ expect(row).not.toHaveTextContent("live ·");
601
+ expect(screen.queryByTestId("session-row-live")).toBeNull();
602
+ /* Not counted yet is still true: the finalizer has not run. */
603
+ expect(row).toHaveTextContent("Not counted yet");
604
+ expect(screen.getByTestId("session-row-activity")).toHaveTextContent(
605
+ "counting",
606
+ );
607
+ /* The footage is stored and plays. */
608
+ expect(screen.getByTestId("session-row-watch")).toBeInTheDocument();
609
+ });
610
+
611
+ it("a live row and an ended row side by side: only the live one pulses", async () => {
612
+ mockApi(() => {
613
+ return listResponse([
614
+ wireRow({ isFinalized: 0, hasRecordingEnded: false }),
615
+ wireRow({
616
+ sessionId: SESSION_B,
617
+ isFinalized: 0,
618
+ hasRecordingEnded: true,
619
+ }),
620
+ wireRow({ sessionId: SESSION_C, hasRecordingEnded: true }),
621
+ ]);
622
+ });
623
+
624
+ renderTable();
625
+
626
+ const rows: Array<HTMLElement> = await waitForRows(3);
627
+
628
+ const kinds: Array<string | null> = screen
629
+ .getAllByTestId("session-row-playability")
630
+ .map((badge: HTMLElement): string | null => {
631
+ return badge.getAttribute("data-kind");
632
+ });
633
+
634
+ expect(kinds).toEqual(["recording", "ended", "playable"]);
635
+ expect(screen.getAllByTestId("session-row-live")).toHaveLength(1);
636
+ expect(rows[0]).toContainElement(screen.getByTestId("session-row-live"));
637
+ expect(rows[0]).toHaveTextContent("live · Always-on");
638
+ });
639
+
521
640
  it("an unplayable row never offers Watch and keeps the reason reachable by keyboard", async () => {
522
641
  mockApi(() => {
523
642
  return listResponse([
@@ -956,7 +1075,7 @@ describe("SessionReplayTable identity nudge", () => {
956
1075
  });
957
1076
 
958
1077
  describe("SessionReplayTable and the Users page", () => {
959
- it("the Users card button goes to the Users page and nothing else; the default window as absence", async () => {
1078
+ it("keeps navigation in the Session Replay menu and removes the redundant top actions", async () => {
960
1079
  mockApi(() => {
961
1080
  return listResponse([wireRow()]);
962
1081
  });
@@ -965,58 +1084,18 @@ describe("SessionReplayTable and the Users page", () => {
965
1084
 
966
1085
  await waitForRows(1);
967
1086
 
968
- fireEvent.click(screen.getByRole("button", { name: "Users" }));
969
-
970
- expect(navigateMock).toHaveBeenCalledTimes(1);
971
-
972
- const target: string = (
973
- navigateMock.mock.calls[0]![0] as { toString: () => string }
974
- ).toString();
975
-
976
- expect(target.endsWith("/session-replay-users")).toBe(true);
977
- expect(target).not.toContain("?");
978
- expect(target).toContain(APP_ID);
979
- /* The toggle is gone; there is one list and one Refresh for it. */
1087
+ expect(screen.queryByRole("button", { name: "Users" })).toBeNull();
1088
+ expect(
1089
+ screen.queryByRole("button", { name: "Set up recording" }),
1090
+ ).toBeNull();
1091
+ /* The list still has one Refresh and never embeds the Users table. */
980
1092
  expect(screen.queryByTestId("session-view-toggle")).toBeNull();
981
1093
  expect(screen.queryByTestId("session-users-table")).toBeNull();
982
1094
  expect(
983
1095
  screen.getByRole("button", { name: "Refresh sessions" }),
984
1096
  ).toBeInTheDocument();
985
1097
  expect(requestsTo("/session-replay/users").length).toBe(0);
986
- });
987
-
988
- it("the Users card button carries the window the list is on, in the list's own spelling", async () => {
989
- mockApi(() => {
990
- return listResponse([wireRow()]);
991
- });
992
-
993
- /* An incident tile's window: the overview's start/end aliases. */
994
- window.history.replaceState(
995
- null,
996
- "",
997
- "/?start=2026-09-01T00:00:00.000Z&end=2026-09-01T01:00:00.000Z&browser=Chrome",
998
- );
999
-
1000
- renderTable();
1001
-
1002
- await waitForRows(1);
1003
-
1004
- fireEvent.click(screen.getByRole("button", { name: "Users" }));
1005
-
1006
- const target: URL = new URL(
1007
- (navigateMock.mock.calls[0]![0] as { toString: () => string }).toString(),
1008
- "https://dash.example.com",
1009
- );
1010
-
1011
- expect(target.pathname.endsWith("/session-replay-users")).toBe(true);
1012
- expect(target.searchParams.get("startTime")).toBe(
1013
- "2026-09-01T00:00:00.000Z",
1014
- );
1015
- expect(target.searchParams.get("endTime")).toBe("2026-09-01T01:00:00.000Z");
1016
- /* The window and nothing else: the rollup takes no filters. */
1017
- expect(target.searchParams.has("browser")).toBe(false);
1018
- expect(target.searchParams.has("range")).toBe(false);
1019
- expect(target.searchParams.has("start")).toBe(false);
1098
+ expect(navigateMock).not.toHaveBeenCalled();
1020
1099
  });
1021
1100
 
1022
1101
  it("a userKey link with the person's label parked by the Users page reads as the reference", async () => {
@@ -1283,6 +1362,29 @@ describe("SessionReplayTable navigation", () => {
1283
1362
  });
1284
1363
 
1285
1364
  describe("SessionReplayTable search, sort and paging", () => {
1365
+ it("uses the shared ModelTable footer and the replay page-size choices", async () => {
1366
+ mockApi(() => {
1367
+ return listResponse([wireRow()]);
1368
+ });
1369
+
1370
+ renderTable();
1371
+
1372
+ await waitForRows(1);
1373
+
1374
+ const pagination: HTMLElement = screen.getByTestId("session-pagination");
1375
+
1376
+ expect(pagination.parentElement).toHaveClass("bg-gray-50", "md:-mx-6");
1377
+ expect(
1378
+ Array.from(
1379
+ screen
1380
+ .getByTestId("pagination-items-on-page-select")
1381
+ .querySelectorAll("option"),
1382
+ ).map((option: Element): string | null => {
1383
+ return option.getAttribute("value");
1384
+ }),
1385
+ ).toEqual(["20", "50", "100"]);
1386
+ });
1387
+
1286
1388
  it("search is debounced into the request as the server's filter", async () => {
1287
1389
  mockApi(() => {
1288
1390
  return listResponse([wireRow()]);
@@ -1702,3 +1804,694 @@ describe("SessionReplayTable facet integration", () => {
1702
1804
  );
1703
1805
  });
1704
1806
  });
1807
+
1808
+ /*
1809
+ * Issue #3642: the list never refreshed, so a badge read when the page
1810
+ * loaded stayed on screen however long ago its tab had closed. While the
1811
+ * page shows an unfinalized row it now re-reads itself, silently and in
1812
+ * place, every SESSION_REPLAY_LIST_AUTO_REFRESH_MS - and only while the
1813
+ * document is visible.
1814
+ */
1815
+ describe("SessionReplayTable auto-refresh", () => {
1816
+ let visibilityState: DocumentVisibilityState = "visible";
1817
+
1818
+ beforeEach(() => {
1819
+ visibilityState = "visible";
1820
+ Object.defineProperty(document, "visibilityState", {
1821
+ configurable: true,
1822
+ get: (): DocumentVisibilityState => {
1823
+ return visibilityState;
1824
+ },
1825
+ });
1826
+ jest.useFakeTimers({
1827
+ doNotFake: ["nextTick", "queueMicrotask", "setImmediate"],
1828
+ });
1829
+ });
1830
+
1831
+ afterEach(() => {
1832
+ jest.useRealTimers();
1833
+ delete (document as unknown as Record<string, unknown>)["visibilityState"];
1834
+ });
1835
+
1836
+ function listRequestCount(): number {
1837
+ return requestsTo("/session-replay/list").length;
1838
+ }
1839
+
1840
+ async function advance(ms: number): Promise<void> {
1841
+ await act(async (): Promise<void> => {
1842
+ jest.advanceTimersByTime(ms);
1843
+ });
1844
+ }
1845
+
1846
+ function setVisibility(state: DocumentVisibilityState): void {
1847
+ visibilityState = state;
1848
+
1849
+ act((): void => {
1850
+ document.dispatchEvent(new Event("visibilitychange"));
1851
+ });
1852
+ }
1853
+
1854
+ function playabilityKinds(): Array<string | null> {
1855
+ return screen
1856
+ .getAllByTestId("session-row-playability")
1857
+ .map((badge: HTMLElement): string | null => {
1858
+ return badge.getAttribute("data-kind");
1859
+ });
1860
+ }
1861
+
1862
+ interface Deferred {
1863
+ promise: Promise<HTTPResponse<JSONObject> | HTTPErrorResponse>;
1864
+ resolve: (value: HTTPResponse<JSONObject> | HTTPErrorResponse) => void;
1865
+ }
1866
+
1867
+ function deferred(): Deferred {
1868
+ let resolve: (
1869
+ value: HTTPResponse<JSONObject> | HTTPErrorResponse,
1870
+ ) => void = (): void => {
1871
+ /* replaced below */
1872
+ };
1873
+ const promise: Promise<HTTPResponse<JSONObject> | HTTPErrorResponse> =
1874
+ new Promise<HTTPResponse<JSONObject> | HTTPErrorResponse>(
1875
+ (
1876
+ done: (value: HTTPResponse<JSONObject> | HTTPErrorResponse) => void,
1877
+ ): void => {
1878
+ resolve = done;
1879
+ },
1880
+ );
1881
+
1882
+ return { promise: promise, resolve: resolve };
1883
+ }
1884
+
1885
+ it("refreshes every interval while a row is unfinalized, follows the badge, and stops once all are finalized", async () => {
1886
+ mockApi((_data: JSONObject, index: number) => {
1887
+ if (index === 0) {
1888
+ return listResponse([wireRow({ isFinalized: 0, chunkCount: 0 })]);
1889
+ }
1890
+
1891
+ if (index === 1) {
1892
+ return listResponse([
1893
+ wireRow({ isFinalized: 0, chunkCount: 0, hasRecordingEnded: true }),
1894
+ ]);
1895
+ }
1896
+
1897
+ return listResponse([wireRow()]);
1898
+ });
1899
+
1900
+ renderTable();
1901
+
1902
+ await waitForRows(1);
1903
+
1904
+ expect(playabilityKinds()).toEqual(["recording"]);
1905
+ expect(listRequestCount()).toBe(1);
1906
+
1907
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS - 1000);
1908
+
1909
+ expect(listRequestCount()).toBe(1);
1910
+
1911
+ await advance(1000);
1912
+
1913
+ await waitFor(() => {
1914
+ expect(playabilityKinds()).toEqual(["ended"]);
1915
+ });
1916
+
1917
+ expect(listRequestCount()).toBe(2);
1918
+ expect(screen.queryByTestId("session-row-live")).toBeNull();
1919
+
1920
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
1921
+
1922
+ await waitFor(() => {
1923
+ expect(playabilityKinds()).toEqual(["playable"]);
1924
+ });
1925
+
1926
+ expect(listRequestCount()).toBe(3);
1927
+
1928
+ /* Every row is finalized: nothing left to change, nothing polled. */
1929
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS * 4);
1930
+
1931
+ expect(listRequestCount()).toBe(3);
1932
+ });
1933
+
1934
+ it("never polls a page whose rows are all finalized", async () => {
1935
+ mockApi(() => {
1936
+ return listResponse([wireRow(), wireRow({ sessionId: SESSION_B })]);
1937
+ });
1938
+
1939
+ renderTable();
1940
+
1941
+ await waitForRows(2);
1942
+
1943
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS * 3);
1944
+
1945
+ expect(listRequestCount()).toBe(1);
1946
+ });
1947
+
1948
+ it("keeps the page, the cursor, the filters and the sort, and never flashes the skeleton", async () => {
1949
+ const pageOneCursor: JSONObject = {
1950
+ startTimeUnixMs: NOW - 3 * 60_000,
1951
+ sessionId: SESSION_A,
1952
+ };
1953
+ const pageTwoCursor: JSONObject = {
1954
+ startTimeUnixMs: NOW - 9 * 60_000,
1955
+ sessionId: SESSION_B,
1956
+ };
1957
+ const refresh: Deferred = deferred();
1958
+
1959
+ window.history.replaceState(null, "", "/?browser=Firefox");
1960
+
1961
+ mockApi((_data: JSONObject, index: number) => {
1962
+ if (index === 0) {
1963
+ return listResponse([wireRow({ isFinalized: 0 })], pageOneCursor);
1964
+ }
1965
+
1966
+ if (index === 1) {
1967
+ return listResponse(
1968
+ [wireRow({ sessionId: SESSION_B, isFinalized: 0 })],
1969
+ pageTwoCursor,
1970
+ );
1971
+ }
1972
+
1973
+ return refresh.promise;
1974
+ });
1975
+
1976
+ renderTable();
1977
+
1978
+ await waitForRows(1);
1979
+
1980
+ fireEvent.click(screen.getByTestId("pagination-next-button"));
1981
+
1982
+ await waitFor(() => {
1983
+ expect(screen.getAllByTestId("session-row")[0]).toHaveAttribute(
1984
+ "data-session-id",
1985
+ SESSION_B,
1986
+ );
1987
+ });
1988
+
1989
+ expect(window.location.search).toContain("page=2");
1990
+ expect(listRequestCount()).toBe(2);
1991
+
1992
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
1993
+
1994
+ await waitFor(() => {
1995
+ expect(listRequestCount()).toBe(3);
1996
+ });
1997
+
1998
+ const pageTwo: JSONObject = requestsTo("/session-replay/list")[1]!.data;
1999
+ const refreshed: JSONObject = requestsTo("/session-replay/list")[2]!.data;
2000
+
2001
+ /*
2002
+ * The same request as the page on screen, cursor and all. Only the
2003
+ * window's edges may differ: a relative range ("past day") is
2004
+ * re-evaluated against the clock on every read, the Refresh button's
2005
+ * way too.
2006
+ */
2007
+ const withoutWindow: (data: JSONObject) => JSONObject = (
2008
+ data: JSONObject,
2009
+ ): JSONObject => {
2010
+ const copy: JSONObject = { ...data };
2011
+
2012
+ delete copy["startTime"];
2013
+ delete copy["endTime"];
2014
+
2015
+ return copy;
2016
+ };
2017
+
2018
+ expect(refreshed["cursor"]).toEqual(pageOneCursor);
2019
+ expect(refreshed["filters"]).toEqual({ browserNames: ["Firefox"] });
2020
+ expect(withoutWindow(refreshed)).toEqual(withoutWindow(pageTwo));
2021
+ expect(Object.keys(refreshed).sort()).toEqual(Object.keys(pageTwo).sort());
2022
+
2023
+ /* In flight: the rows stay, no skeleton, the page does not move. */
2024
+ expect(screen.queryByTestId("table-skeleton-loader")).toBeNull();
2025
+ expect(screen.getAllByTestId("session-row")).toHaveLength(1);
2026
+ expect(window.location.search).toContain("page=2");
2027
+
2028
+ await act(async (): Promise<void> => {
2029
+ refresh.resolve(
2030
+ listResponse([wireRow({ sessionId: SESSION_B })], pageTwoCursor),
2031
+ );
2032
+ });
2033
+
2034
+ await waitFor(() => {
2035
+ expect(playabilityKinds()).toEqual(["playable"]);
2036
+ });
2037
+
2038
+ expect(screen.queryByTestId("table-skeleton-loader")).toBeNull();
2039
+ expect(window.location.search).toContain("page=2");
2040
+ expect(window.location.search).toContain("browser=Firefox");
2041
+ expect(screen.getByTestId("pagination-next-button")).not.toBeDisabled();
2042
+ expect(
2043
+ screen.getAllByTestId("session-row")[0]?.getAttribute("data-session-id"),
2044
+ ).toBe(SESSION_B);
2045
+ });
2046
+
2047
+ it("does not poll while the document is hidden, and catches up when it is visible again", async () => {
2048
+ mockApi(() => {
2049
+ return listResponse([wireRow({ isFinalized: 0 })]);
2050
+ });
2051
+
2052
+ renderTable();
2053
+
2054
+ await waitForRows(1);
2055
+
2056
+ setVisibility("hidden");
2057
+
2058
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS * 5);
2059
+
2060
+ expect(listRequestCount()).toBe(1);
2061
+
2062
+ /* The rows are minutes old: read them now, not in another 30s. */
2063
+ setVisibility("visible");
2064
+
2065
+ await waitFor(() => {
2066
+ expect(listRequestCount()).toBe(2);
2067
+ });
2068
+
2069
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2070
+
2071
+ await waitFor(() => {
2072
+ expect(listRequestCount()).toBe(3);
2073
+ });
2074
+ });
2075
+
2076
+ it("a quick hide and show does not re-read rows that are still fresh", async () => {
2077
+ mockApi(() => {
2078
+ return listResponse([wireRow({ isFinalized: 0 })]);
2079
+ });
2080
+
2081
+ renderTable();
2082
+
2083
+ await waitForRows(1);
2084
+
2085
+ setVisibility("hidden");
2086
+ await advance(2000);
2087
+ setVisibility("visible");
2088
+ await advance(2000);
2089
+
2090
+ expect(listRequestCount()).toBe(1);
2091
+
2092
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2093
+
2094
+ await waitFor(() => {
2095
+ expect(listRequestCount()).toBe(2);
2096
+ });
2097
+ });
2098
+
2099
+ it("never starts while the document is hidden at mount", async () => {
2100
+ visibilityState = "hidden";
2101
+
2102
+ mockApi(() => {
2103
+ return listResponse([wireRow({ isFinalized: 0 })]);
2104
+ });
2105
+
2106
+ renderTable();
2107
+
2108
+ await waitForRows(1);
2109
+
2110
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS * 3);
2111
+
2112
+ expect(listRequestCount()).toBe(1);
2113
+ });
2114
+
2115
+ it("unmounting clears the timer", async () => {
2116
+ mockApi(() => {
2117
+ return listResponse([wireRow({ isFinalized: 0 })]);
2118
+ });
2119
+
2120
+ const view: ReturnType<typeof render> = renderTable();
2121
+
2122
+ await waitForRows(1);
2123
+
2124
+ view.unmount();
2125
+
2126
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS * 3);
2127
+
2128
+ expect(listRequestCount()).toBe(1);
2129
+
2130
+ /* Nor does a visibility change after unmount start one. */
2131
+ setVisibility("hidden");
2132
+ setVisibility("visible");
2133
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2134
+
2135
+ expect(listRequestCount()).toBe(1);
2136
+ });
2137
+
2138
+ it("a failed refresh keeps the rows, shows no error, and the next tick retries", async () => {
2139
+ mockApi((_data: JSONObject, index: number) => {
2140
+ if (index === 1) {
2141
+ return new HTTPErrorResponse(503, { message: "busy" }, {});
2142
+ }
2143
+
2144
+ return listResponse([wireRow({ isFinalized: 0 })]);
2145
+ });
2146
+
2147
+ renderTable();
2148
+
2149
+ await waitForRows(1);
2150
+
2151
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2152
+
2153
+ await waitFor(() => {
2154
+ expect(listRequestCount()).toBe(2);
2155
+ });
2156
+
2157
+ expect(screen.queryByTestId("list-error")).toBeNull();
2158
+ expect(screen.getAllByTestId("session-row")).toHaveLength(1);
2159
+
2160
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2161
+
2162
+ await waitFor(() => {
2163
+ expect(listRequestCount()).toBe(3);
2164
+ });
2165
+
2166
+ expect(screen.queryByTestId("list-error")).toBeNull();
2167
+ });
2168
+
2169
+ it("a tick never supersedes a load the viewer started", async () => {
2170
+ const manual: Deferred = deferred();
2171
+
2172
+ mockApi((_data: JSONObject, index: number) => {
2173
+ if (index === 1) {
2174
+ return manual.promise;
2175
+ }
2176
+
2177
+ return listResponse([wireRow({ isFinalized: 0 })]);
2178
+ });
2179
+
2180
+ renderTable();
2181
+
2182
+ await waitForRows(1);
2183
+
2184
+ fireEvent.click(screen.getByRole("button", { name: "Refresh sessions" }));
2185
+
2186
+ await waitFor(() => {
2187
+ expect(listRequestCount()).toBe(2);
2188
+ });
2189
+
2190
+ /* The viewer's load is still in the air: the tick stands down. */
2191
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2192
+
2193
+ expect(listRequestCount()).toBe(2);
2194
+
2195
+ await act(async (): Promise<void> => {
2196
+ manual.resolve(
2197
+ listResponse([wireRow({ sessionId: SESSION_B, isFinalized: 0 })]),
2198
+ );
2199
+ });
2200
+
2201
+ await waitFor(() => {
2202
+ expect(screen.getAllByTestId("session-row")[0]).toHaveAttribute(
2203
+ "data-session-id",
2204
+ SESSION_B,
2205
+ );
2206
+ });
2207
+
2208
+ expect(screen.queryByTestId("table-skeleton-loader")).toBeNull();
2209
+ });
2210
+
2211
+ /*
2212
+ * On a busy application the newest page always holds a live session, so
2213
+ * "until every row is finalized" never comes. The refresh is capped at
2214
+ * SESSION_REPLAY_LIST_AUTO_REFRESH_MAX_TICKS since the viewer last
2215
+ * started a load or came back to the tab.
2216
+ */
2217
+ async function exhaustRefreshBudget(): Promise<void> {
2218
+ for (
2219
+ let tick: number = 1;
2220
+ tick <= SESSION_REPLAY_LIST_AUTO_REFRESH_MAX_TICKS;
2221
+ tick++
2222
+ ) {
2223
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2224
+
2225
+ await waitFor(() => {
2226
+ expect(listRequestCount()).toBe(1 + tick);
2227
+ });
2228
+ }
2229
+ }
2230
+
2231
+ it("stops after the maximum number of silent reads on a page that never settles", async () => {
2232
+ expect(
2233
+ SESSION_REPLAY_LIST_AUTO_REFRESH_MAX_TICKS *
2234
+ SESSION_REPLAY_LIST_AUTO_REFRESH_MS,
2235
+ ).toBe(10 * 60_000);
2236
+
2237
+ mockApi(() => {
2238
+ return listResponse([wireRow({ isFinalized: 0 })]);
2239
+ });
2240
+
2241
+ renderTable();
2242
+
2243
+ await waitForRows(1);
2244
+
2245
+ await exhaustRefreshBudget();
2246
+
2247
+ /* Still unfinalized, still visible: and yet nothing more is read. */
2248
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS * 10);
2249
+
2250
+ expect(listRequestCount()).toBe(
2251
+ 1 + SESSION_REPLAY_LIST_AUTO_REFRESH_MAX_TICKS,
2252
+ );
2253
+ expect(screen.getAllByTestId("session-row")).toHaveLength(1);
2254
+ });
2255
+
2256
+ it("a load the viewer starts restores the whole budget and restarts the timer", async () => {
2257
+ mockApi(() => {
2258
+ return listResponse([wireRow({ isFinalized: 0 })]);
2259
+ });
2260
+
2261
+ renderTable();
2262
+
2263
+ await waitForRows(1);
2264
+
2265
+ await exhaustRefreshBudget();
2266
+
2267
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS * 3);
2268
+
2269
+ const exhaustedAt: number = 1 + SESSION_REPLAY_LIST_AUTO_REFRESH_MAX_TICKS;
2270
+
2271
+ expect(listRequestCount()).toBe(exhaustedAt);
2272
+
2273
+ fireEvent.click(screen.getByRole("button", { name: "Refresh sessions" }));
2274
+
2275
+ await waitFor(() => {
2276
+ expect(listRequestCount()).toBe(exhaustedAt + 1);
2277
+ });
2278
+
2279
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2280
+
2281
+ await waitFor(() => {
2282
+ expect(listRequestCount()).toBe(exhaustedAt + 2);
2283
+ });
2284
+
2285
+ /* A whole new budget, not one more tick. */
2286
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2287
+
2288
+ await waitFor(() => {
2289
+ expect(listRequestCount()).toBe(exhaustedAt + 3);
2290
+ });
2291
+ });
2292
+
2293
+ it("coming back to the tab restores the budget", async () => {
2294
+ mockApi(() => {
2295
+ return listResponse([wireRow({ isFinalized: 0 })]);
2296
+ });
2297
+
2298
+ renderTable();
2299
+
2300
+ await waitForRows(1);
2301
+
2302
+ await exhaustRefreshBudget();
2303
+
2304
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS * 3);
2305
+
2306
+ const exhaustedAt: number = 1 + SESSION_REPLAY_LIST_AUTO_REFRESH_MAX_TICKS;
2307
+
2308
+ expect(listRequestCount()).toBe(exhaustedAt);
2309
+
2310
+ setVisibility("hidden");
2311
+ setVisibility("visible");
2312
+
2313
+ /* The rows are stale: read now, then keep going on the timer. */
2314
+ await waitFor(() => {
2315
+ expect(listRequestCount()).toBe(exhaustedAt + 1);
2316
+ });
2317
+
2318
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2319
+
2320
+ await waitFor(() => {
2321
+ expect(listRequestCount()).toBe(exhaustedAt + 2);
2322
+ });
2323
+ });
2324
+
2325
+ /*
2326
+ * Common Table keys rows by position, so a refresh that puts a new
2327
+ * session at the top leaves every row element where it was, carrying
2328
+ * the next session's props. A tick that finds the viewer's pointer or
2329
+ * focus in the table stands down; the next one tries again.
2330
+ */
2331
+ it("a tick stands down while the pointer is over the table, and goes ahead once it leaves", async () => {
2332
+ mockApi((_data: JSONObject, index: number) => {
2333
+ if (index === 0) {
2334
+ return listResponse([wireRow({ isFinalized: 0 })]);
2335
+ }
2336
+
2337
+ return listResponse([
2338
+ wireRow({ sessionId: SESSION_B, isFinalized: 0 }),
2339
+ wireRow({ isFinalized: 0 }),
2340
+ ]);
2341
+ });
2342
+
2343
+ renderTable();
2344
+
2345
+ await waitForRows(1);
2346
+
2347
+ fireEvent.mouseEnter(screen.getByTestId("session-table"));
2348
+
2349
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS * 3);
2350
+
2351
+ expect(listRequestCount()).toBe(1);
2352
+ expect(screen.getAllByTestId("session-row")[0]).toHaveAttribute(
2353
+ "data-session-id",
2354
+ SESSION_A,
2355
+ );
2356
+
2357
+ fireEvent.mouseLeave(screen.getByTestId("session-table"));
2358
+
2359
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2360
+
2361
+ await waitFor(() => {
2362
+ expect(listRequestCount()).toBe(2);
2363
+ });
2364
+
2365
+ await waitForRows(2);
2366
+ });
2367
+
2368
+ it("a tick stands down while a row has focus, so Enter opens the session the viewer focused", async () => {
2369
+ mockApi((_data: JSONObject, index: number) => {
2370
+ if (index === 0) {
2371
+ return listResponse([wireRow({ isFinalized: 0 })]);
2372
+ }
2373
+
2374
+ return listResponse([
2375
+ wireRow({ sessionId: SESSION_B, isFinalized: 0 }),
2376
+ wireRow({ isFinalized: 0 }),
2377
+ ]);
2378
+ });
2379
+
2380
+ renderTable();
2381
+
2382
+ const [row] = await waitForRows(1);
2383
+
2384
+ act((): void => {
2385
+ (row as HTMLElement).focus();
2386
+ });
2387
+
2388
+ expect(document.activeElement).toBe(row);
2389
+
2390
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS * 3);
2391
+
2392
+ expect(listRequestCount()).toBe(1);
2393
+ expect(document.activeElement).toHaveAttribute(
2394
+ "data-session-id",
2395
+ SESSION_A,
2396
+ );
2397
+
2398
+ fireEvent.keyDown(row as HTMLElement, { key: "Enter" });
2399
+
2400
+ expect(navigateMock).toHaveBeenCalledTimes(1);
2401
+ expect(
2402
+ (navigateMock.mock.calls[0]![0] as { toString: () => string }).toString(),
2403
+ ).toContain(SESSION_A);
2404
+
2405
+ /* Focus leaves the table: the next tick reads the page. */
2406
+ act((): void => {
2407
+ (row as HTMLElement).blur();
2408
+ });
2409
+
2410
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2411
+
2412
+ await waitFor(() => {
2413
+ expect(listRequestCount()).toBe(2);
2414
+ });
2415
+
2416
+ await waitForRows(2);
2417
+ });
2418
+
2419
+ it("ticks skipped under the viewer's hand do not spend the budget", async () => {
2420
+ mockApi(() => {
2421
+ return listResponse([wireRow({ isFinalized: 0 })]);
2422
+ });
2423
+
2424
+ renderTable();
2425
+
2426
+ await waitForRows(1);
2427
+
2428
+ fireEvent.mouseEnter(screen.getByTestId("session-table"));
2429
+
2430
+ await advance(
2431
+ SESSION_REPLAY_LIST_AUTO_REFRESH_MS *
2432
+ (SESSION_REPLAY_LIST_AUTO_REFRESH_MAX_TICKS + 5),
2433
+ );
2434
+
2435
+ expect(listRequestCount()).toBe(1);
2436
+
2437
+ fireEvent.mouseLeave(screen.getByTestId("session-table"));
2438
+
2439
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2440
+
2441
+ await waitFor(() => {
2442
+ expect(listRequestCount()).toBe(2);
2443
+ });
2444
+ });
2445
+
2446
+ it("a refresh that lands after the viewer reloaded is thrown away", async () => {
2447
+ const stale: Deferred = deferred();
2448
+
2449
+ mockApi((_data: JSONObject, index: number) => {
2450
+ if (index === 1) {
2451
+ return stale.promise;
2452
+ }
2453
+
2454
+ if (index === 2) {
2455
+ return listResponse([
2456
+ wireRow({ sessionId: SESSION_B, isFinalized: 0 }),
2457
+ ]);
2458
+ }
2459
+
2460
+ return listResponse([wireRow({ isFinalized: 0 })]);
2461
+ });
2462
+
2463
+ renderTable();
2464
+
2465
+ await waitForRows(1);
2466
+
2467
+ await advance(SESSION_REPLAY_LIST_AUTO_REFRESH_MS);
2468
+
2469
+ await waitFor(() => {
2470
+ expect(listRequestCount()).toBe(2);
2471
+ });
2472
+
2473
+ /* The viewer asks for a fresh read while the silent one hangs. */
2474
+ fireEvent.click(screen.getByRole("button", { name: "Refresh sessions" }));
2475
+
2476
+ await waitFor(() => {
2477
+ expect(screen.getAllByTestId("session-row")[0]).toHaveAttribute(
2478
+ "data-session-id",
2479
+ SESSION_B,
2480
+ );
2481
+ });
2482
+
2483
+ await act(async (): Promise<void> => {
2484
+ stale.resolve(
2485
+ listResponse([wireRow({ sessionId: SESSION_C, isFinalized: 0 })]),
2486
+ );
2487
+ });
2488
+
2489
+ await advance(100);
2490
+
2491
+ expect(screen.getAllByTestId("session-row")[0]).toHaveAttribute(
2492
+ "data-session-id",
2493
+ SESSION_B,
2494
+ );
2495
+ expect(screen.queryByTestId("table-skeleton-loader")).toBeNull();
2496
+ });
2497
+ });