@oneuptime/common 13.0.5 → 13.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1091) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +81 -1
  2. package/Models/AnalyticsModels/SecurityEvent.ts +4 -4
  3. package/Models/DatabaseModels/Alert.ts +62 -0
  4. package/Models/DatabaseModels/GlobalConfig.ts +1 -1
  5. package/Models/DatabaseModels/Incident.ts +66 -0
  6. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +74 -0
  7. package/Models/DatabaseModels/IncidentPublicNote.ts +74 -0
  8. package/Models/DatabaseModels/Index.ts +6 -4
  9. package/Models/DatabaseModels/NetworkDevice.ts +67 -0
  10. package/Models/DatabaseModels/NetworkDeviceDiagnostic.ts +746 -0
  11. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +151 -0
  12. package/Models/DatabaseModels/NetworkSiteAssignmentRule.ts +1 -1
  13. package/Models/DatabaseModels/Project.ts +41 -0
  14. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +74 -0
  15. package/Models/DatabaseModels/SecurityEventConnection.ts +11 -11
  16. package/Models/DatabaseModels/ServiceLevelObjective.ts +185 -8
  17. package/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.ts +746 -43
  18. package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +575 -0
  19. package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +582 -0
  20. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.ts +16 -0
  21. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.ts +16 -0
  22. package/Models/DatabaseModels/StatusPageAnnouncement.ts +75 -0
  23. package/Models/DatabaseModels/ThreatIntelFeed.ts +1 -1
  24. package/Server/API/BaseAPI.ts +17 -0
  25. package/Server/API/BillingInvoiceAPI.ts +343 -30
  26. package/Server/API/BillingPaymentMethodAPI.ts +126 -5
  27. package/Server/API/DashboardAPI.ts +96 -2
  28. package/Server/API/SecurityEventConnectionAPI.ts +141 -11
  29. package/Server/API/StatusPageAPI.ts +308 -199
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1792800000000-AddNetworkDeviceDiagnostic.ts +83 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1792900000000-AddNetworkDeviceDnsNameAndShortDeviceNames.ts +36 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1793000000000-AddNetbiosLookupToNetworkDeviceDiscoveryScan.ts +29 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1793100000000-SloProductOverhaul.ts +516 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1793200000000-BackfillSloMonitorRulesAndAffectedResources.ts +98 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1793300000000-AddDataResidencyToProject.ts +27 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/1793400000000-AddSubscriberUpdateNotificationStatus.ts +97 -0
  37. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
  38. package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +138 -67
  39. package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +213 -84
  40. package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +112 -35
  41. package/Server/Services/AlertLabelRuleEngineService.ts +299 -217
  42. package/Server/Services/AlertOwnerRuleEngineService.ts +572 -396
  43. package/Server/Services/AlertPrivacyRuleEngineService.ts +116 -40
  44. package/Server/Services/AlertService.ts +111 -4
  45. package/Server/Services/AuditLogService.ts +612 -59
  46. package/Server/Services/BillingInvoiceService.ts +112 -102
  47. package/Server/Services/BillingService.ts +539 -11
  48. package/Server/Services/CephClusterLabelRuleEngineService.ts +170 -109
  49. package/Server/Services/CephClusterOwnerRuleEngineService.ts +233 -115
  50. package/Server/Services/CloudResourceLabelRuleEngineService.ts +163 -100
  51. package/Server/Services/CloudResourceOwnerRuleEngineService.ts +236 -115
  52. package/Server/Services/DashboardLabelRuleEngineService.ts +145 -84
  53. package/Server/Services/DashboardOwnerRuleEngineService.ts +213 -95
  54. package/Server/Services/DatabaseService.ts +171 -21
  55. package/Server/Services/DockerHostLabelRuleEngineService.ts +171 -110
  56. package/Server/Services/DockerHostOwnerRuleEngineService.ts +233 -115
  57. package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +181 -112
  58. package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +243 -118
  59. package/Server/Services/HostLabelRuleEngineService.ts +167 -106
  60. package/Server/Services/HostOwnerRuleEngineService.ts +229 -111
  61. package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +141 -67
  62. package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +272 -72
  63. package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +112 -35
  64. package/Server/Services/IncidentEpisodePublicNoteService.ts +24 -0
  65. package/Server/Services/IncidentLabelRuleEngineService.ts +279 -204
  66. package/Server/Services/IncidentOwnerRuleEngineService.ts +595 -425
  67. package/Server/Services/IncidentPrivacyRuleEngineService.ts +117 -44
  68. package/Server/Services/IncidentPublicNoteService.ts +24 -0
  69. package/Server/Services/IncidentService.ts +114 -3
  70. package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +147 -83
  71. package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +221 -100
  72. package/Server/Services/Index.ts +6 -4
  73. package/Server/Services/IoTFleetLabelRuleEngineService.ts +145 -84
  74. package/Server/Services/IoTFleetOwnerRuleEngineService.ts +213 -95
  75. package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +181 -112
  76. package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +243 -118
  77. package/Server/Services/LabelService.ts +23 -28
  78. package/Server/Services/MonitorLabelRuleEngineService.ts +152 -92
  79. package/Server/Services/MonitorOwnerRuleEngineService.ts +220 -104
  80. package/Server/Services/MonitorProbeService.ts +20 -2
  81. package/Server/Services/MonitorService.ts +11 -9
  82. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +376 -5
  83. package/Server/Services/NetworkDeviceDiagnosticService.ts +417 -0
  84. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +147 -83
  85. package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +218 -97
  86. package/Server/Services/NetworkDeviceService.ts +39 -2
  87. package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +151 -80
  88. package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +222 -97
  89. package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +154 -83
  90. package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +225 -100
  91. package/Server/Services/PodmanHostLabelRuleEngineService.ts +171 -110
  92. package/Server/Services/PodmanHostOwnerRuleEngineService.ts +235 -115
  93. package/Server/Services/ProjectService.ts +111 -10
  94. package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +174 -110
  95. package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +239 -116
  96. package/Server/Services/RumApplicationLabelRuleEngineService.ts +137 -73
  97. package/Server/Services/RumApplicationOwnerRuleEngineService.ts +200 -83
  98. package/Server/Services/RunbookLabelRuleEngineService.ts +146 -84
  99. package/Server/Services/RunbookOwnerRuleEngineService.ts +216 -95
  100. package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +324 -230
  101. package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +613 -428
  102. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +24 -0
  103. package/Server/Services/ScheduledMaintenanceService.ts +43 -14
  104. package/Server/Services/SecurityEventConnectionService.ts +56 -4
  105. package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +143 -74
  106. package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +206 -85
  107. package/Server/Services/ServiceLabelRuleEngineService.ts +172 -110
  108. package/Server/Services/ServiceLevelObjectiveBurnRateRuleService.ts +1057 -18
  109. package/Server/Services/ServiceLevelObjectiveFeedService.ts +108 -0
  110. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +793 -97
  111. package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +1069 -0
  112. package/Server/Services/ServiceLevelObjectiveOwnerTeamService.ts +240 -1
  113. package/Server/Services/ServiceLevelObjectiveOwnerUserService.ts +257 -1
  114. package/Server/Services/ServiceLevelObjectiveService.ts +1356 -56
  115. package/Server/Services/ServiceOwnerRuleEngineService.ts +238 -116
  116. package/Server/Services/StatusPageAnnouncementService.ts +13 -0
  117. package/Server/Services/StatusPageLabelRuleEngineService.ts +146 -85
  118. package/Server/Services/StatusPageOwnerRuleEngineService.ts +210 -99
  119. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +28 -232
  120. package/Server/Services/StatusPageSubscriberService.ts +6 -0
  121. package/Server/Services/TelemetryUsageBillingService.ts +38 -7
  122. package/Server/Services/ThreatIntelFeedService.ts +1 -1
  123. package/Server/Services/VMwareVCenterLabelRuleEngineService.ts +173 -110
  124. package/Server/Services/VMwareVCenterOwnerRuleEngineService.ts +238 -116
  125. package/Server/Services/WorkflowLabelRuleEngineService.ts +145 -84
  126. package/Server/Services/WorkflowOwnerRuleEngineService.ts +215 -95
  127. package/Server/Types/Database/UpdateByID.ts +3 -0
  128. package/Server/Types/Database/UpdateOneBy.ts +7 -0
  129. package/Server/Utils/AI/AlertAIContextBuilder.ts +19 -0
  130. package/Server/Utils/AI/IncidentAIContextBuilder.ts +39 -0
  131. package/Server/Utils/AI/Toolbox/AlertTools.ts +37 -1
  132. package/Server/Utils/AI/Toolbox/IncidentTools.ts +22 -1
  133. package/Server/Utils/AI/Toolbox/SloTools.ts +416 -51
  134. package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +151 -13
  135. package/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.ts +17 -4
  136. package/Server/Utils/Dashboard/PublicDashboardSloWidget.ts +155 -8
  137. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +16 -0
  138. package/Server/Utils/Database/RelationValueUtil.ts +106 -0
  139. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +6 -1
  140. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +22 -27
  141. package/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.ts +3 -1
  142. package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +50 -20
  143. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +13 -1
  144. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +6 -11
  145. package/Server/Utils/Rules/MonitorRulePatternValidator.ts +51 -0
  146. package/Server/Utils/Rules/OwnerRuleAssignment.ts +110 -0
  147. package/Server/Utils/Rules/RuleRun/RuleApplication.ts +81 -0
  148. package/Server/Utils/Rules/RuleRun/RuleRunPermission.ts +188 -0
  149. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +803 -0
  150. package/Server/Utils/Rules/RuleRun/RuleRunner.ts +341 -0
  151. package/Server/Utils/SecurityEvent/ConnectorErrorMessage.ts +3 -2
  152. package/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.ts +6 -4
  153. package/Server/Utils/SecurityEvent/{GoogleSecOps → Connectors/GoogleSecOps}/GoogleSecOpsClient.ts +263 -16
  154. package/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnector.ts +2101 -0
  155. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.ts +194 -14
  156. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.ts +1 -2
  157. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.ts +38 -7
  158. package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.ts +2 -0
  159. package/Server/Utils/SecurityEvent/Connectors/Types.ts +242 -2
  160. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +1 -1
  161. package/Server/Utils/SecurityEvent/SecurityEventDedupe.ts +3 -3
  162. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +2 -2
  163. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +217 -56
  164. package/Server/Utils/Slo/SloFeedUtil.ts +200 -0
  165. package/Server/Utils/Slo/SloLegacyMonitorLabelAdoption.ts +173 -0
  166. package/Server/Utils/Slo/SloMetricUtil.ts +327 -0
  167. package/Server/Utils/Slo/SloOwnerReferenceValidator.ts +208 -0
  168. package/Server/Utils/Slo/SloRecordReferenceValidator.ts +169 -0
  169. package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +6 -43
  170. package/Server/Utils/StatusPageResource.ts +50 -5
  171. package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +664 -15
  172. package/Tests/App/Dashboard/AddWidgetModal.test.tsx +4 -1
  173. package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +307 -0
  174. package/Tests/App/Dashboard/ArchiveResourceCard.test.tsx +289 -0
  175. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +598 -0
  176. package/Tests/App/Dashboard/BillingDefaultPaymentMethod.test.tsx +1046 -0
  177. package/Tests/App/Dashboard/BillingPaidUsageFlow.test.tsx +3 -0
  178. package/Tests/App/Dashboard/BillingPaymentMethodForm.test.tsx +201 -7
  179. package/Tests/App/Dashboard/BooleanSeriesCriteriaFilterText.test.ts +82 -0
  180. package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +16 -1
  181. package/Tests/App/Dashboard/ChangeAlertStateAIHeader.test.tsx +116 -8
  182. package/Tests/App/Dashboard/ChatActivityFeed.test.tsx +168 -1
  183. package/Tests/App/Dashboard/ConnectionTestModal.test.tsx +1 -1
  184. package/Tests/App/Dashboard/ConnectorTestReportView.test.tsx +20 -3
  185. package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +1095 -1
  186. package/Tests/App/Dashboard/CorrelateFilterChips.test.tsx +910 -0
  187. package/Tests/App/Dashboard/CorrelateGraph.test.tsx +3747 -25
  188. package/Tests/App/Dashboard/CorrelateGraphHelpers.test.ts +1085 -0
  189. package/Tests/App/Dashboard/CorrelateInspector.test.tsx +1534 -0
  190. package/Tests/App/Dashboard/CorrelateNodeCard.test.tsx +965 -0
  191. package/Tests/App/Dashboard/CorrelateResultSummary.test.tsx +1525 -0
  192. package/Tests/App/Dashboard/CorrelationGraph.test.ts +1030 -0
  193. package/Tests/App/Dashboard/CorrelationGraphLayout.test.ts +526 -0
  194. package/Tests/App/Dashboard/DeviceDiagnostics.test.tsx +787 -0
  195. package/Tests/App/Dashboard/DeviceLatencyTrend.test.tsx +278 -0
  196. package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +279 -0
  197. package/Tests/App/Dashboard/DiscoveryScanEditForm.test.tsx +87 -0
  198. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +443 -8
  199. package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +340 -0
  200. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +98 -2
  201. package/Tests/App/Dashboard/ExceptionSegmentedControl.test.tsx +1020 -0
  202. package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +268 -47
  203. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1114 -76
  204. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +124 -2
  205. package/Tests/App/Dashboard/InvestigationReportView.test.tsx +279 -176
  206. package/Tests/App/Dashboard/InvestigationRunDetails.test.tsx +1166 -0
  207. package/Tests/App/Dashboard/InvoicesPayInvoice.test.tsx +437 -0
  208. package/Tests/App/Dashboard/NetworkDeviceBulkDelete.test.tsx +65 -0
  209. package/Tests/App/Dashboard/NetworkTopologyLiveView.test.tsx +5 -0
  210. package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +74 -0
  211. package/Tests/App/Dashboard/ResourceFeed.test.tsx +125 -5
  212. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
  213. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +1764 -0
  214. package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +1000 -64
  215. package/Tests/App/Dashboard/SecurityEventConnectionsEmptyState.test.tsx +448 -0
  216. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +739 -189
  217. package/Tests/App/Dashboard/SecurityEventSeverityPill.test.tsx +233 -0
  218. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +282 -0
  219. package/Tests/App/Dashboard/SloActiveBurnEventsCard.test.tsx +538 -0
  220. package/Tests/App/Dashboard/SloBulkActionsArchive.test.tsx +252 -0
  221. package/Tests/App/Dashboard/SloDashboardTemplateWidgets.test.tsx +322 -518
  222. package/Tests/App/Dashboard/SloElement.test.tsx +194 -0
  223. package/Tests/App/Dashboard/SloFeed.test.tsx +289 -0
  224. package/Tests/App/Dashboard/SloHistoryCharts.test.tsx +471 -0
  225. package/Tests/App/Dashboard/SloHistorySeries.test.tsx +607 -0
  226. package/Tests/App/Dashboard/SloListWidget.test.tsx +783 -0
  227. package/Tests/App/Dashboard/SloMetricsPage.test.tsx +346 -0
  228. package/Tests/App/Dashboard/SloMonitorsPage.test.tsx +661 -0
  229. package/Tests/App/Dashboard/SloMonitorsSummaryCard.test.tsx +489 -0
  230. package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +437 -0
  231. package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +305 -0
  232. package/Tests/App/Dashboard/SloOverviewData.test.tsx +563 -0
  233. package/Tests/App/Dashboard/SloOverviewHero.test.tsx +311 -0
  234. package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +426 -0
  235. package/Tests/App/Dashboard/SloOverviewSidebarCards.test.tsx +493 -0
  236. package/Tests/App/Dashboard/SloSettings.test.tsx +633 -0
  237. package/Tests/App/Dashboard/SloStatusSummaryCards.test.tsx +403 -0
  238. package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +373 -0
  239. package/Tests/App/Dashboard/SloWidgetVariableBinding.test.tsx +689 -0
  240. package/Tests/App/Dashboard/TopologyConnectivitySection.test.tsx +206 -0
  241. package/Tests/App/Dashboard/TracesEntityNames.test.tsx +47 -15
  242. package/Tests/App/Dashboard/UseBulkShortenDeviceNames.test.tsx +1312 -0
  243. package/Tests/App/Dashboard/WidgetCatalog.test.ts +9 -1
  244. package/Tests/Models/AnalyticsModels/RumSessionReplayColumns.test.ts +14 -16
  245. package/Tests/Models/DatabaseModels/AuditLogModelConfiguration.test.ts +442 -0
  246. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +9 -10
  247. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +48 -1
  248. package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +835 -0
  249. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +3 -2
  250. package/Tests/Models/DiscoveryScanNetbiosLookupColumn.test.ts +328 -0
  251. package/Tests/Models/DiscoveryScanShortDeviceNamesColumn.test.ts +335 -0
  252. package/Tests/Models/NetworkDeviceDiagnosticContract.test.ts +194 -0
  253. package/Tests/Models/NetworkDeviceDnsNameColumn.test.ts +321 -0
  254. package/Tests/Models/ProjectDataResidencyColumn.test.ts +154 -0
  255. package/Tests/Models/SecurityDomainAccessControl.test.ts +181 -50
  256. package/Tests/Server/API/BaseAPI.test.ts +6 -0
  257. package/Tests/Server/API/BaseAPIUpdateMiscDataProps.test.ts +217 -0
  258. package/Tests/Server/API/BillingInvoiceAPI.test.ts +7 -0
  259. package/Tests/Server/API/BillingInvoiceAPIPaymentStates.test.ts +990 -0
  260. package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +498 -0
  261. package/Tests/Server/API/DashboardPublicSloAPI.test.ts +405 -0
  262. package/Tests/Server/API/SecurityEventConnectionAPI.test.ts +901 -7
  263. package/Tests/Server/API/SessionReplayAPI.test.ts +116 -0
  264. package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +857 -0
  265. package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +1084 -0
  266. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +33 -3
  267. package/Tests/Server/Infrastructure/Postgres/AddDataResidencyToProjectMigration.test.ts +202 -0
  268. package/Tests/Server/Infrastructure/Postgres/AddNetbiosLookupToNetworkDeviceDiscoveryScanMigration.test.ts +330 -0
  269. package/Tests/Server/Infrastructure/Postgres/AddNetworkDeviceDnsNameAndShortDeviceNamesMigration.test.ts +340 -0
  270. package/Tests/Server/Infrastructure/Postgres/BackfillSloMonitorRulesAndAffectedResourcesMigration.test.ts +343 -0
  271. package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +801 -0
  272. package/Tests/Server/Services/AddSubscriberUpdateNotificationStatusMigration.test.ts +307 -0
  273. package/Tests/Server/Services/AuditLogService.test.ts +1124 -0
  274. package/Tests/Server/Services/AutoImportScanCredentialSelect.test.ts +200 -1
  275. package/Tests/Server/Services/BillingInvoiceServiceMutexRelease.test.ts +254 -0
  276. package/Tests/Server/Services/BillingService.test.ts +70 -0
  277. package/Tests/Server/Services/BillingServicePayInvoiceStates.test.ts +723 -0
  278. package/Tests/Server/Services/BillingServicePaymentMethodReads.test.ts +14 -2
  279. package/Tests/Server/Services/BillingServiceSubscriptionPaymentMethodSync.test.ts +1634 -0
  280. package/Tests/Server/Services/DatabaseServiceAuditRelationDiff.test.ts +492 -0
  281. package/Tests/Server/Services/DatabaseServicePasswordFieldSecrets.test.ts +629 -0
  282. package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +431 -0
  283. package/Tests/Server/Services/IncidentAlertSloReferenceGuard.test.ts +358 -0
  284. package/Tests/Server/Services/MonitorProbeServicePastDueMonitoring.test.ts +362 -0
  285. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +1460 -1
  286. package/Tests/Server/Services/NetworkDeviceDiagnosticService.test.ts +962 -0
  287. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +106 -0
  288. package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +10 -1
  289. package/Tests/Server/Services/NetworkDeviceServicePastDueMonitoring.test.ts +335 -0
  290. package/Tests/Server/Services/NetworkDeviceSiteRuleDnsName.test.ts +568 -0
  291. package/Tests/Server/Services/ProjectDataResidencyPostgres.test.ts +344 -0
  292. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +187 -0
  293. package/Tests/Server/Services/ProjectServiceDataResidency.test.ts +369 -0
  294. package/Tests/Server/Services/ProjectServiceDataResidencySelfHosted.test.ts +176 -0
  295. package/Tests/Server/Services/ProjectServicePastDueMonitoring.test.ts +289 -0
  296. package/Tests/Server/Services/ResourceFeedServices.test.ts +24 -8
  297. package/Tests/Server/Services/RuleRun/IncidentAlertMaintenanceRuleEnginesRun.test.ts +1396 -0
  298. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupARun.test.ts +917 -0
  299. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +1262 -0
  300. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupARun.test.ts +902 -0
  301. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +1163 -0
  302. package/Tests/Server/Services/RuleRun/PrivacyRuleEnginesRun.test.ts +843 -0
  303. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +465 -0
  304. package/Tests/Server/Services/SecurityEventConnectionService.test.ts +525 -4
  305. package/Tests/Server/Services/SecurityEventLastErrorColumnWidth.test.ts +77 -23
  306. package/Tests/Server/Services/ServiceLevelObjectiveBurnRateRuleFeedWrites.test.ts +777 -0
  307. package/Tests/Server/Services/ServiceLevelObjectiveBurnRateRuleOptions.test.ts +1399 -0
  308. package/Tests/Server/Services/ServiceLevelObjectiveBurnRateRuleService.test.ts +67 -74
  309. package/Tests/Server/Services/ServiceLevelObjectiveChildRowTenancy.test.ts +906 -0
  310. package/Tests/Server/Services/ServiceLevelObjectiveDeleteTenancy.test.ts +1029 -0
  311. package/Tests/Server/Services/ServiceLevelObjectiveFeedService.test.ts +313 -0
  312. package/Tests/Server/Services/ServiceLevelObjectiveFeedWrites.test.ts +1214 -0
  313. package/Tests/Server/Services/ServiceLevelObjectiveMarkdownLink.test.ts +289 -0
  314. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +1455 -430
  315. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleLegacyLabelAdoption.test.ts +634 -0
  316. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +1193 -0
  317. package/Tests/Server/Services/{SloMonitorLabelRuleHooks.test.ts → ServiceLevelObjectiveMonitorRuleTriggers.test.ts} +135 -41
  318. package/Tests/Server/Services/ServiceLevelObjectiveOwnerFeedWrites.test.ts +671 -0
  319. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +180 -85
  320. package/Tests/Server/Services/ServiceLevelObjectiveServiceArchive.test.ts +537 -0
  321. package/Tests/Server/Services/ServiceLevelObjectiveServiceLegacyMonitorLabelWrite.test.ts +870 -0
  322. package/Tests/Server/Services/ServiceLevelObjectiveServiceMonitorRuleGuard.test.ts +343 -0
  323. package/Tests/Server/Services/ServiceLevelObjectiveServiceReEvaluation.test.ts +246 -0
  324. package/Tests/Server/Services/SloAffectedResourceCreatedFeed.test.ts +501 -0
  325. package/Tests/Server/Services/SloAffectedResourceLinkContract.test.ts +86 -0
  326. package/Tests/Server/Services/SloAffectedResourceMetricAttributes.test.ts +547 -0
  327. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +10 -4
  328. package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +7 -2
  329. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +174 -0
  330. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateServiceVariables.test.ts +40 -0
  331. package/Tests/Server/Services/SubscriberUpdateNotificationHooks.test.ts +541 -0
  332. package/Tests/Server/Services/TelemetryUsageBillingSloExclusion.test.ts +288 -0
  333. package/Tests/Server/TestingUtils/PastDueMonitoringClaimSql.ts +177 -0
  334. package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +51 -10
  335. package/Tests/Server/TestingUtils/__mocks__/Stripe.mock.ts +16 -1
  336. package/Tests/Server/Types/Database/Permissions/ProjectDataResidencyColumn.test.ts +386 -0
  337. package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +26 -36
  338. package/Tests/Server/Utils/AI/SloAffectedResourceAIContext.test.ts +445 -0
  339. package/Tests/Server/Utils/AI/SloTools.test.ts +423 -1
  340. package/Tests/Server/Utils/AI/SloToolsArchive.test.ts +294 -0
  341. package/Tests/Server/Utils/AI/SloToolsRuleReadPermissions.test.ts +297 -0
  342. package/Tests/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.test.ts +255 -10
  343. package/Tests/Server/Utils/Dashboard/SloTemplatePublicDashboard.test.ts +404 -750
  344. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +45 -0
  345. package/Tests/Server/Utils/Database/RelationValueUtil.test.ts +157 -0
  346. package/Tests/Server/Utils/Monitor/Criteria/BooleanSeriesEvaluateOverTime.test.ts +260 -0
  347. package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +181 -0
  348. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +147 -30
  349. package/Tests/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.test.ts +17 -0
  350. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +136 -0
  351. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidatorLoadOrder.test.ts +472 -0
  352. package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +48 -2
  353. package/Tests/Server/Utils/Monitor/SloTemplateMetricEmitterContract.test.ts +435 -475
  354. package/Tests/Server/Utils/Rules/MonitorRulePatternValidator.test.ts +77 -0
  355. package/Tests/Server/Utils/Rules/OwnerRuleAssignment.test.ts +177 -0
  356. package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +365 -0
  357. package/Tests/Server/Utils/Rules/RuleRun/RuleRunRegistry.test.ts +173 -0
  358. package/Tests/Server/Utils/Rules/RuleRun/RuleRunner.test.ts +675 -0
  359. package/Tests/Server/Utils/SecurityEvent/ConnectorErrorMessage.test.ts +8 -8
  360. package/Tests/Server/Utils/SecurityEvent/Connectors/ConnectorFetchSummary.test.ts +261 -0
  361. package/Tests/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.test.ts +68 -13
  362. package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsAuth.test.ts → Connectors/GoogleSecOps/GoogleSecOpsAuth.test.ts} +5 -5
  363. package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsClient.test.ts → Connectors/GoogleSecOps/GoogleSecOpsClient.test.ts} +4 -4
  364. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnector.test.ts +483 -0
  365. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorCuratedAndLateAlerts.test.ts +676 -0
  366. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorFetchEvents.test.ts +1994 -0
  367. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorFixtures.ts +332 -0
  368. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorHttpIntegration.test.ts +680 -0
  369. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorRequestContract.test.ts +1206 -0
  370. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorTestConnection.test.ts +1136 -0
  371. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsCuratedRuleCounts.test.ts +407 -0
  372. package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsErrorHandling.test.ts → Connectors/GoogleSecOps/GoogleSecOpsErrorHandling.test.ts} +5 -5
  373. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingAdaptiveCatchUp.test.ts +730 -0
  374. package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsClickhouseIntegration.test.ts → Connectors/GoogleSecOps/GoogleSecOpsPollingClickhouseIntegration.test.ts} +130 -35
  375. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingFailureTaxonomy.test.ts +772 -0
  376. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingFixtures.ts +648 -0
  377. package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsHttpIntegration.test.ts → Connectors/GoogleSecOps/GoogleSecOpsPollingHttpIntegration.test.ts} +230 -225
  378. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingIntegration.test.ts +1390 -0
  379. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingLoop.test.ts +981 -0
  380. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsPollingNothingImportedRegression.test.ts +290 -0
  381. package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsRequestContract.test.ts → Connectors/GoogleSecOps/GoogleSecOpsRequestContract.test.ts} +2 -2
  382. package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsResponseParsing.test.ts → Connectors/GoogleSecOps/GoogleSecOpsResponseParsing.test.ts} +5 -5
  383. package/Tests/Server/Utils/SecurityEvent/{GoogleSecOpsSearchDetections.test.ts → Connectors/GoogleSecOps/GoogleSecOpsSearchDetections.test.ts} +38 -5
  384. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsTesterIntegration.test.ts +421 -0
  385. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.test.ts +1445 -3
  386. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.test.ts +14 -4
  387. package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.test.ts +313 -4
  388. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +352 -0
  389. package/Tests/Server/Utils/Slo/SloFeedUtil.test.ts +326 -0
  390. package/Tests/Server/Utils/Slo/SloLegacyMonitorLabelAdoption.test.ts +260 -0
  391. package/Tests/Server/Utils/Slo/SloMetricUtil.test.ts +592 -0
  392. package/Tests/Server/Utils/Slo/SloRecordReferenceValidator.test.ts +311 -0
  393. package/Tests/Server/Utils/StatusPageResource.test.ts +91 -3
  394. package/Tests/Types/Billing/SubscriptionStatus.test.ts +176 -0
  395. package/Tests/Types/Billing/SubscriptionStatusPastDueMonitoring.test.ts +187 -0
  396. package/Tests/Types/Dashboard/DashboardTemplateInvariants.test.ts +53 -7
  397. package/Tests/Types/Dashboard/SloDashboardTemplate.test.ts +816 -792
  398. package/Tests/Types/Monitor/CriteriaFilter.test.ts +216 -24
  399. package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +14 -1
  400. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +14 -1
  401. package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +14 -1
  402. package/Tests/Types/Monitor/MonitorStepRetriesParsing.test.ts +201 -0
  403. package/Tests/Types/Rules/RuleRun.test.ts +315 -0
  404. package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +60 -0
  405. package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +29 -4
  406. package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +217 -0
  407. package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +200 -0
  408. package/Tests/UI/Components/ActiveFilterChipsLockedFilters.test.tsx +141 -87
  409. package/Tests/UI/Components/AlertBanner.test.tsx +319 -0
  410. package/Tests/UI/Components/BulkArchiveActionsCopy.test.tsx +310 -0
  411. package/Tests/UI/Components/Detail/DetailIdIsUnique.test.tsx +87 -0
  412. package/Tests/UI/Components/Dropdown/DropdownClearable.test.tsx +393 -0
  413. package/Tests/UI/Components/Dropdown/DropdownMultiSelectChipAccessibleName.test.tsx +64 -0
  414. package/Tests/UI/Components/EmptyState/EmptyState.test.tsx +335 -4
  415. package/Tests/UI/Components/EmptyState/EmptyStateGuideLinks.test.tsx +337 -0
  416. package/Tests/UI/Components/Forms/ModelFormJsonColumns.test.tsx +21 -20
  417. package/Tests/UI/Components/LabelRuleImportExport.test.tsx +15 -2
  418. package/Tests/UI/Components/LockedFilterChip.test.tsx +281 -144
  419. package/Tests/UI/Components/MoreMenu.test.tsx +133 -0
  420. package/Tests/UI/Components/MoreMenuMotion.test.tsx +84 -3
  421. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  422. package/Tests/UI/Components/RuleRun/RuleDetailFields.test.tsx +336 -0
  423. package/Tests/UI/Components/RuleRun/RuleTable.test.tsx +304 -0
  424. package/Tests/UI/Components/RuleRun/RunRuleNowModal.test.tsx +231 -0
  425. package/Tests/UI/Components/RuleRun/RunRulesBulkAction.test.ts +213 -0
  426. package/Tests/UI/Components/TelemetryActiveFilterChipsLockedFilters.test.tsx +124 -61
  427. package/Tests/UI/Rum/ReplayEngine.test.ts +154 -0
  428. package/Tests/UI/Rum/ReplayHeader.test.tsx +234 -123
  429. package/Tests/UI/Rum/ReplayPinControl.test.tsx +122 -0
  430. package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +245 -0
  431. package/Tests/UI/Rum/ReplayRail.test.tsx +294 -0
  432. package/Tests/UI/Rum/ReplayScrubber.test.tsx +213 -1
  433. package/Tests/UI/Rum/ReplayStage.test.tsx +565 -172
  434. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +260 -3
  435. package/Tests/UI/Rum/ReplayTabSwitcher.test.tsx +1391 -0
  436. package/Tests/UI/Rum/ReplayTimeline.test.tsx +222 -0
  437. package/Tests/UI/Utils/DashboardStackingLayers.test.ts +8 -1
  438. package/Tests/UI/Utils/RuleRunClient.test.ts +303 -0
  439. package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +1 -0
  440. package/Tests/Utils/Dashboard/Components/DashboardComponentDefaults.test.ts +2 -0
  441. package/Tests/Utils/Dashboard/Components/DashboardSloListComponent.test.ts +206 -0
  442. package/Tests/Utils/Dashboard/DashboardSloComponent.test.ts +36 -2
  443. package/Tests/Utils/Dashboard/SloTemplateVariableScoping.test.ts +409 -588
  444. package/Tests/Utils/Dashboard/SloWidgetSource.test.ts +351 -0
  445. package/Tests/Utils/Markdown/MarkdownEscape.test.ts +361 -0
  446. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +1425 -118
  447. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +188 -3
  448. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +661 -13
  449. package/Tests/Utils/NetworkDiscovery/NetbiosNameUtil.test.ts +349 -0
  450. package/Tests/Utils/NetworkDiscovery/RunImportedDeviceNaming.test.ts +656 -0
  451. package/Tests/Utils/NetworkDiscovery/ShortDeviceNamePlanner.test.ts +1020 -0
  452. package/Tests/Utils/NetworkDiscovery/ShortHostnameUtil.test.ts +619 -0
  453. package/Tests/Utils/NetworkSite/CidrMatchUtil.test.ts +317 -0
  454. package/Tests/Utils/Project/DataResidency.test.ts +198 -0
  455. package/Tests/Utils/Rules/RuleRunSummary.test.ts +394 -0
  456. package/Tests/Utils/Slo/SloAffectedResourceMarkdown.test.ts +302 -0
  457. package/Tests/Utils/Slo/SloBurnRateTemplate.test.ts +468 -0
  458. package/Tests/Utils/Slo/SloEvaluation.test.ts +20 -4
  459. package/Tests/Utils/Slo/SloFeedMarkdown.test.ts +1185 -0
  460. package/Tests/Utils/Slo/SloHealth.test.ts +262 -0
  461. package/Tests/Utils/Slo/SloHistoryMetricName.test.ts +102 -0
  462. package/Tests/Utils/Slo/SloListWidgetFormat.test.ts +522 -0
  463. package/Tests/Utils/Slo/SloMetricType.test.ts +355 -0
  464. package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +387 -0
  465. package/Tests/Utils/Slo/SloMonitorStatusSummary.test.ts +210 -0
  466. package/Tests/Utils/Slo/SloOverviewText.test.ts +226 -0
  467. package/Tests/Utils/Slo/SloProjection.test.ts +1039 -0
  468. package/Tests/Utils/Slo/SloWidgetFormat.test.ts +47 -0
  469. package/Tests/Utils/Telemetry/LockedFilterSearch.test.ts +1 -80
  470. package/Types/BaseDatabase/EnableAuditLogOn.ts +41 -0
  471. package/Types/Billing/SubscriptionStatus.ts +39 -4
  472. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  473. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +5 -0
  474. package/Types/Dashboard/DashboardComponents/DashboardSloComponent.ts +10 -0
  475. package/Types/Dashboard/DashboardComponents/DashboardSloListComponent.ts +29 -0
  476. package/Types/Dashboard/DashboardTemplates.ts +290 -297
  477. package/Types/Database/EnableAuditLog.ts +23 -1
  478. package/Types/Email/EmailTemplateType.ts +4 -0
  479. package/Types/Monitor/CriteriaFilter.ts +55 -8
  480. package/Types/Monitor/MonitorStep.ts +5 -2
  481. package/Types/Monitor/MonitorStepDnsMonitor.ts +3 -1
  482. package/Types/Monitor/MonitorStepDnssecMonitor.ts +3 -1
  483. package/Types/Monitor/MonitorStepDomainMonitor.ts +3 -1
  484. package/Types/Monitor/MonitorStepExternalStatusPageMonitor.ts +3 -1
  485. package/Types/Monitor/MonitorStepRetries.ts +59 -0
  486. package/Types/Monitor/MonitorStepSnmpMonitor.ts +9 -2
  487. package/Types/NetworkDevice/NetworkDeviceDiagnosticResult.ts +104 -0
  488. package/Types/NetworkDevice/NetworkDeviceDiagnosticStatus.ts +47 -0
  489. package/Types/NetworkDevice/NetworkDeviceDiagnosticType.ts +47 -0
  490. package/Types/NetworkDevice/NetworkDevicePingMetricNames.ts +20 -0
  491. package/Types/Permission.ts +127 -0
  492. package/Types/Rules/RuleCriteriaFieldRegistry.ts +5 -0
  493. package/Types/Rules/RuleRun.ts +518 -0
  494. package/Types/Rum/SessionReplayApi.ts +18 -0
  495. package/Types/SecurityEvent/Connectors/ConnectorDiagnostics.ts +6 -0
  496. package/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.ts +30 -4
  497. package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +108 -1
  498. package/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.ts +6 -2
  499. package/Types/ServiceLevelObjective/SloHistoryMetricName.ts +25 -0
  500. package/Types/ServiceLevelObjective/SloMetricType.ts +49 -0
  501. package/Types/StatusPage/StatusPageSubscriberNotificationEventType.ts +4 -0
  502. package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +331 -0
  503. package/Types/StatusPage/SubscriberNotificationTrigger.ts +12 -0
  504. package/Types/StatusPage/SubscriberUpdateNotification.ts +89 -0
  505. package/Types/Telemetry/LockedFilterDetail.ts +7 -28
  506. package/Types/Telemetry/ServiceType.ts +7 -0
  507. package/Typings/Index.d.ts +53 -3
  508. package/UI/Components/AlertBanner/AlertBanner.tsx +85 -27
  509. package/UI/Components/BulkUpdate/BulkArchiveActions.tsx +21 -2
  510. package/UI/Components/Detail/Detail.tsx +9 -2
  511. package/UI/Components/Dropdown/Dropdown.tsx +64 -1
  512. package/UI/Components/EmptyState/EmptyState.tsx +27 -3
  513. package/UI/Components/EmptyState/EmptyStateGuideLinks.tsx +124 -0
  514. package/UI/Components/Forms/ModelForm.tsx +6 -5
  515. package/UI/Components/LabelRule/LabelRuleTable.tsx +8 -2
  516. package/UI/Components/LogsViewer/LogsViewer.tsx +2 -6
  517. package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +2 -13
  518. package/UI/Components/LogsViewer/types.ts +2 -2
  519. package/UI/Components/MoreMenu/MoreMenu.tsx +14 -3
  520. package/UI/Components/RuleRun/RuleDetailFields.tsx +359 -0
  521. package/UI/Components/RuleRun/RuleTable.tsx +183 -0
  522. package/UI/Components/RuleRun/RuleView.tsx +170 -0
  523. package/UI/Components/RuleRun/RunRuleNowModal.tsx +147 -0
  524. package/UI/Components/RuleRun/RunRulesBulkAction.ts +103 -0
  525. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +2 -6
  526. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +38 -104
  527. package/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.tsx +2 -18
  528. package/UI/Components/TelemetryViewer/types.ts +2 -2
  529. package/UI/Utils/Rules/RuleRunClient.ts +178 -0
  530. package/UI/Utils/Telemetry/TelemetryEntityNames.ts +8 -0
  531. package/Utils/Dashboard/Components/DashboardSloComponent.ts +19 -2
  532. package/Utils/Dashboard/Components/DashboardSloListComponent.ts +126 -0
  533. package/Utils/Dashboard/Components/Index.ts +7 -0
  534. package/Utils/Dashboard/SloWidgetSource.ts +188 -0
  535. package/Utils/Markdown/MarkdownEscape.ts +63 -0
  536. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +161 -36
  537. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +25 -0
  538. package/Utils/NetworkDiscovery/NetbiosNameUtil.ts +146 -0
  539. package/Utils/NetworkDiscovery/RunImportedDeviceNaming.ts +390 -0
  540. package/Utils/NetworkDiscovery/ShortDeviceNamePlanner.ts +291 -0
  541. package/Utils/NetworkDiscovery/ShortHostnameUtil.ts +91 -0
  542. package/Utils/NetworkSite/CidrMatchUtil.ts +37 -12
  543. package/Utils/Project/DataResidency.ts +63 -0
  544. package/Utils/Rules/RuleRunSummary.ts +323 -0
  545. package/Utils/Slo/SloAffectedResourceMarkdown.ts +123 -0
  546. package/Utils/Slo/SloBurnRateTemplate.ts +373 -0
  547. package/Utils/Slo/SloFeedMarkdown.ts +1507 -0
  548. package/Utils/Slo/SloHealth.ts +96 -9
  549. package/Utils/Slo/SloListWidgetFormat.ts +370 -0
  550. package/Utils/Slo/SloMetricType.ts +237 -0
  551. package/Utils/Slo/SloMonitorRuleCriteria.ts +364 -0
  552. package/Utils/Slo/SloMonitorStatusSummary.ts +210 -0
  553. package/Utils/Slo/SloOverviewText.ts +265 -0
  554. package/Utils/Slo/SloProjection.ts +967 -0
  555. package/Utils/Slo/SloWidgetFormat.ts +12 -2
  556. package/Utils/Telemetry/LockedFilterSearch.ts +3 -49
  557. package/build/dist/Models/AnalyticsModels/AuditLog.js +70 -1
  558. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  559. package/build/dist/Models/AnalyticsModels/SecurityEvent.js +4 -4
  560. package/build/dist/Models/DatabaseModels/Alert.js +60 -0
  561. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  562. package/build/dist/Models/DatabaseModels/GlobalConfig.js +1 -1
  563. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  564. package/build/dist/Models/DatabaseModels/Incident.js +64 -0
  565. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  566. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +75 -0
  567. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  568. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +75 -0
  569. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  570. package/build/dist/Models/DatabaseModels/Index.js +6 -4
  571. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  572. package/build/dist/Models/DatabaseModels/NetworkDevice.js +68 -0
  573. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  574. package/build/dist/Models/DatabaseModels/NetworkDeviceDiagnostic.js +772 -0
  575. package/build/dist/Models/DatabaseModels/NetworkDeviceDiagnostic.js.map +1 -0
  576. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +140 -0
  577. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  578. package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js +1 -1
  579. package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js.map +1 -1
  580. package/build/dist/Models/DatabaseModels/Project.js +42 -0
  581. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  582. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +75 -0
  583. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  584. package/build/dist/Models/DatabaseModels/SecurityEventConnection.js +11 -11
  585. package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js +192 -10
  586. package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js.map +1 -1
  587. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.js +798 -96
  588. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.js.map +1 -1
  589. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +596 -0
  590. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -0
  591. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +590 -0
  592. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -0
  593. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js +16 -0
  594. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js.map +1 -1
  595. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js +16 -0
  596. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js.map +1 -1
  597. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +75 -0
  598. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  599. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +1 -1
  600. package/build/dist/Server/API/BaseAPI.js +14 -0
  601. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  602. package/build/dist/Server/API/BillingInvoiceAPI.js +233 -19
  603. package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
  604. package/build/dist/Server/API/BillingPaymentMethodAPI.js +86 -5
  605. package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
  606. package/build/dist/Server/API/DashboardAPI.js +72 -2
  607. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  608. package/build/dist/Server/API/SecurityEventConnectionAPI.js +102 -10
  609. package/build/dist/Server/API/SecurityEventConnectionAPI.js.map +1 -1
  610. package/build/dist/Server/API/StatusPageAPI.js +236 -154
  611. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  612. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792800000000-AddNetworkDeviceDiagnostic.js +34 -0
  613. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792800000000-AddNetworkDeviceDiagnostic.js.map +1 -0
  614. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792900000000-AddNetworkDeviceDnsNameAndShortDeviceNames.js +24 -0
  615. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792900000000-AddNetworkDeviceDnsNameAndShortDeviceNames.js.map +1 -0
  616. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793000000000-AddNetbiosLookupToNetworkDeviceDiscoveryScan.js +21 -0
  617. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793000000000-AddNetbiosLookupToNetworkDeviceDiscoveryScan.js.map +1 -0
  618. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793100000000-SloProductOverhaul.js +207 -0
  619. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793100000000-SloProductOverhaul.js.map +1 -0
  620. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793200000000-BackfillSloMonitorRulesAndAffectedResources.js +72 -0
  621. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793200000000-BackfillSloMonitorRulesAndAffectedResources.js.map +1 -0
  622. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793300000000-AddDataResidencyToProject.js +20 -0
  623. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793300000000-AddDataResidencyToProject.js.map +1 -0
  624. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793400000000-AddSubscriberUpdateNotificationStatus.js +46 -0
  625. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793400000000-AddSubscriberUpdateNotificationStatus.js.map +1 -0
  626. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
  627. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  628. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +112 -56
  629. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
  630. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +167 -68
  631. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
  632. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +87 -26
  633. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
  634. package/build/dist/Server/Services/AlertLabelRuleEngineService.js +270 -203
  635. package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
  636. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +498 -354
  637. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
  638. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +97 -34
  639. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
  640. package/build/dist/Server/Services/AlertService.js +91 -8
  641. package/build/dist/Server/Services/AlertService.js.map +1 -1
  642. package/build/dist/Server/Services/AuditLogService.js +408 -44
  643. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  644. package/build/dist/Server/Services/BillingInvoiceService.js +94 -85
  645. package/build/dist/Server/Services/BillingInvoiceService.js.map +1 -1
  646. package/build/dist/Server/Services/BillingService.js +406 -14
  647. package/build/dist/Server/Services/BillingService.js.map +1 -1
  648. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +141 -92
  649. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
  650. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +189 -101
  651. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
  652. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +135 -86
  653. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
  654. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +189 -100
  655. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
  656. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +117 -69
  657. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
  658. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +171 -83
  659. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
  660. package/build/dist/Server/Services/DatabaseService.js +125 -18
  661. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  662. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +141 -92
  663. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
  664. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +189 -101
  665. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
  666. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +145 -91
  667. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
  668. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +191 -101
  669. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
  670. package/build/dist/Server/Services/HostLabelRuleEngineService.js +141 -92
  671. package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
  672. package/build/dist/Server/Services/HostOwnerRuleEngineService.js +190 -102
  673. package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
  674. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +112 -56
  675. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
  676. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +220 -63
  677. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
  678. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +87 -26
  679. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
  680. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
  681. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  682. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +258 -192
  683. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
  684. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +519 -376
  685. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
  686. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +95 -32
  687. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
  688. package/build/dist/Server/Services/IncidentPublicNoteService.js +24 -0
  689. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  690. package/build/dist/Server/Services/IncidentService.js +90 -5
  691. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  692. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +113 -65
  693. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
  694. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +171 -83
  695. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
  696. package/build/dist/Server/Services/Index.js +6 -4
  697. package/build/dist/Server/Services/Index.js.map +1 -1
  698. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +117 -69
  699. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
  700. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +171 -83
  701. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
  702. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +145 -91
  703. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
  704. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +191 -101
  705. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
  706. package/build/dist/Server/Services/LabelService.js +20 -25
  707. package/build/dist/Server/Services/LabelService.js.map +1 -1
  708. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +123 -77
  709. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
  710. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +167 -82
  711. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
  712. package/build/dist/Server/Services/MonitorProbeService.js +18 -2
  713. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  714. package/build/dist/Server/Services/MonitorService.js +11 -9
  715. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  716. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +287 -5
  717. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  718. package/build/dist/Server/Services/NetworkDeviceDiagnosticService.js +333 -0
  719. package/build/dist/Server/Services/NetworkDeviceDiagnosticService.js.map +1 -0
  720. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +117 -69
  721. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
  722. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +171 -83
  723. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
  724. package/build/dist/Server/Services/NetworkDeviceService.js +36 -2
  725. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  726. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +117 -64
  727. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
  728. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +173 -83
  729. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
  730. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +116 -65
  731. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
  732. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +171 -83
  733. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
  734. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +141 -92
  735. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
  736. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +189 -101
  737. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
  738. package/build/dist/Server/Services/ProjectService.js +82 -10
  739. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  740. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +141 -92
  741. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
  742. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +189 -101
  743. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
  744. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +111 -63
  745. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
  746. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +161 -77
  747. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
  748. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +117 -69
  749. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
  750. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +171 -83
  751. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
  752. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +280 -209
  753. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
  754. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +521 -376
  755. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
  756. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +24 -0
  757. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  758. package/build/dist/Server/Services/ScheduledMaintenanceService.js +24 -8
  759. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  760. package/build/dist/Server/Services/SecurityEventConnectionService.js +43 -3
  761. package/build/dist/Server/Services/SecurityEventConnectionService.js.map +1 -1
  762. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +115 -62
  763. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
  764. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +163 -77
  765. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
  766. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +141 -92
  767. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
  768. package/build/dist/Server/Services/ServiceLevelObjectiveBurnRateRuleService.js +769 -18
  769. package/build/dist/Server/Services/ServiceLevelObjectiveBurnRateRuleService.js.map +1 -1
  770. package/build/dist/Server/Services/ServiceLevelObjectiveFeedService.js +96 -0
  771. package/build/dist/Server/Services/ServiceLevelObjectiveFeedService.js.map +1 -0
  772. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +614 -87
  773. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
  774. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +844 -0
  775. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -0
  776. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerTeamService.js +207 -1
  777. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerTeamService.js.map +1 -1
  778. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerUserService.js +221 -1
  779. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerUserService.js.map +1 -1
  780. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +997 -50
  781. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  782. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +191 -102
  783. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
  784. package/build/dist/Server/Services/StatusPageAnnouncementService.js +12 -0
  785. package/build/dist/Server/Services/StatusPageAnnouncementService.js.map +1 -1
  786. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +118 -70
  787. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
  788. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +158 -76
  789. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
  790. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +19 -215
  791. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  792. package/build/dist/Server/Services/StatusPageSubscriberService.js +6 -0
  793. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  794. package/build/dist/Server/Services/TelemetryUsageBillingService.js +27 -5
  795. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  796. package/build/dist/Server/Services/ThreatIntelFeedService.js +1 -1
  797. package/build/dist/Server/Services/VMwareVCenterLabelRuleEngineService.js +141 -92
  798. package/build/dist/Server/Services/VMwareVCenterLabelRuleEngineService.js.map +1 -1
  799. package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js +189 -101
  800. package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js.map +1 -1
  801. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +117 -69
  802. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
  803. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +171 -83
  804. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
  805. package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js +17 -0
  806. package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js.map +1 -1
  807. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js +31 -0
  808. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js.map +1 -1
  809. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +24 -1
  810. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
  811. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +21 -1
  812. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -1
  813. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +337 -53
  814. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
  815. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +108 -15
  816. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
  817. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.js +2 -2
  818. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.js.map +1 -1
  819. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloWidget.js +115 -6
  820. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloWidget.js.map +1 -1
  821. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +13 -0
  822. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  823. package/build/dist/Server/Utils/Database/RelationValueUtil.js +82 -0
  824. package/build/dist/Server/Utils/Database/RelationValueUtil.js.map +1 -0
  825. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +10 -6
  826. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
  827. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +17 -21
  828. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  829. package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js +5 -4
  830. package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js.map +1 -1
  831. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +50 -10
  832. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
  833. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +13 -1
  834. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  835. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +6 -10
  836. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  837. package/build/dist/Server/Utils/Rules/MonitorRulePatternValidator.js +34 -0
  838. package/build/dist/Server/Utils/Rules/MonitorRulePatternValidator.js.map +1 -0
  839. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +69 -0
  840. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -0
  841. package/build/dist/Server/Utils/Rules/RuleRun/RuleApplication.js +25 -0
  842. package/build/dist/Server/Utils/Rules/RuleRun/RuleApplication.js.map +1 -0
  843. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunPermission.js +128 -0
  844. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunPermission.js.map +1 -0
  845. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +746 -0
  846. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -0
  847. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunner.js +221 -0
  848. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunner.js.map +1 -0
  849. package/build/dist/Server/Utils/SecurityEvent/ConnectorErrorMessage.js +3 -2
  850. package/build/dist/Server/Utils/SecurityEvent/ConnectorErrorMessage.js.map +1 -1
  851. package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js +6 -4
  852. package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js.map +1 -1
  853. package/build/dist/Server/Utils/SecurityEvent/{GoogleSecOps → Connectors/GoogleSecOps}/GoogleSecOpsClient.js +174 -14
  854. package/build/dist/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsClient.js.map +1 -0
  855. package/build/dist/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnector.js +1417 -0
  856. package/build/dist/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnector.js.map +1 -0
  857. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js +138 -18
  858. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js.map +1 -1
  859. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js +1 -2
  860. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js.map +1 -1
  861. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js +23 -18
  862. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js.map +1 -1
  863. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js +2 -0
  864. package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js.map +1 -1
  865. package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js +95 -0
  866. package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js.map +1 -1
  867. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +1 -1
  868. package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js +3 -3
  869. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +2 -2
  870. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +118 -40
  871. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  872. package/build/dist/Server/Utils/Slo/SloFeedUtil.js +150 -0
  873. package/build/dist/Server/Utils/Slo/SloFeedUtil.js.map +1 -0
  874. package/build/dist/Server/Utils/Slo/SloLegacyMonitorLabelAdoption.js +136 -0
  875. package/build/dist/Server/Utils/Slo/SloLegacyMonitorLabelAdoption.js.map +1 -0
  876. package/build/dist/Server/Utils/Slo/SloMetricUtil.js +269 -0
  877. package/build/dist/Server/Utils/Slo/SloMetricUtil.js.map +1 -0
  878. package/build/dist/Server/Utils/Slo/SloOwnerReferenceValidator.js +134 -0
  879. package/build/dist/Server/Utils/Slo/SloOwnerReferenceValidator.js.map +1 -0
  880. package/build/dist/Server/Utils/Slo/SloRecordReferenceValidator.js +137 -0
  881. package/build/dist/Server/Utils/Slo/SloRecordReferenceValidator.js.map +1 -0
  882. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +6 -26
  883. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -1
  884. package/build/dist/Server/Utils/StatusPageResource.js +31 -5
  885. package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
  886. package/build/dist/Types/Billing/SubscriptionStatus.js +37 -3
  887. package/build/dist/Types/Billing/SubscriptionStatus.js.map +1 -1
  888. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  889. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  890. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +5 -0
  891. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  892. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSloListComponent.js +2 -0
  893. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSloListComponent.js.map +1 -0
  894. package/build/dist/Types/Dashboard/DashboardTemplates.js +275 -286
  895. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  896. package/build/dist/Types/Database/EnableAuditLog.js +19 -1
  897. package/build/dist/Types/Database/EnableAuditLog.js.map +1 -1
  898. package/build/dist/Types/Email/EmailTemplateType.js +4 -0
  899. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  900. package/build/dist/Types/Monitor/CriteriaFilter.js +45 -6
  901. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  902. package/build/dist/Types/Monitor/MonitorStep.js +2 -0
  903. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  904. package/build/dist/Types/Monitor/MonitorStepDnsMonitor.js +3 -1
  905. package/build/dist/Types/Monitor/MonitorStepDnsMonitor.js.map +1 -1
  906. package/build/dist/Types/Monitor/MonitorStepDnssecMonitor.js +3 -1
  907. package/build/dist/Types/Monitor/MonitorStepDnssecMonitor.js.map +1 -1
  908. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +3 -1
  909. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -1
  910. package/build/dist/Types/Monitor/MonitorStepExternalStatusPageMonitor.js +3 -1
  911. package/build/dist/Types/Monitor/MonitorStepExternalStatusPageMonitor.js.map +1 -1
  912. package/build/dist/Types/Monitor/MonitorStepRetries.js +47 -0
  913. package/build/dist/Types/Monitor/MonitorStepRetries.js.map +1 -0
  914. package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js +3 -1
  915. package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js.map +1 -1
  916. package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticResult.js +29 -0
  917. package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticResult.js.map +1 -0
  918. package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticStatus.js +37 -0
  919. package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticStatus.js.map +1 -0
  920. package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticType.js +42 -0
  921. package/build/dist/Types/NetworkDevice/NetworkDeviceDiagnosticType.js.map +1 -0
  922. package/build/dist/Types/NetworkDevice/NetworkDevicePingMetricNames.js +20 -0
  923. package/build/dist/Types/NetworkDevice/NetworkDevicePingMetricNames.js.map +1 -0
  924. package/build/dist/Types/Permission.js +114 -0
  925. package/build/dist/Types/Permission.js.map +1 -1
  926. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +5 -0
  927. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  928. package/build/dist/Types/Rules/RuleRun.js +267 -0
  929. package/build/dist/Types/Rules/RuleRun.js.map +1 -0
  930. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
  931. package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js.map +1 -1
  932. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js +16 -1
  933. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js.map +1 -1
  934. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +65 -0
  935. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -1
  936. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js +6 -2
  937. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js.map +1 -1
  938. package/build/dist/Types/ServiceLevelObjective/SloHistoryMetricName.js +26 -0
  939. package/build/dist/Types/ServiceLevelObjective/SloHistoryMetricName.js.map +1 -0
  940. package/build/dist/Types/ServiceLevelObjective/SloMetricType.js +45 -0
  941. package/build/dist/Types/ServiceLevelObjective/SloMetricType.js.map +1 -0
  942. package/build/dist/Types/StatusPage/StatusPageSubscriberNotificationEventType.js +4 -0
  943. package/build/dist/Types/StatusPage/StatusPageSubscriberNotificationEventType.js.map +1 -1
  944. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +295 -0
  945. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -0
  946. package/build/dist/Types/StatusPage/SubscriberNotificationTrigger.js +13 -0
  947. package/build/dist/Types/StatusPage/SubscriberNotificationTrigger.js.map +1 -0
  948. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +67 -0
  949. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -0
  950. package/build/dist/Types/Telemetry/LockedFilterDetail.js +7 -7
  951. package/build/dist/Types/Telemetry/ServiceType.js +7 -0
  952. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  953. package/build/dist/UI/Components/AlertBanner/AlertBanner.js +48 -19
  954. package/build/dist/UI/Components/AlertBanner/AlertBanner.js.map +1 -1
  955. package/build/dist/UI/Components/BulkUpdate/BulkArchiveActions.js +10 -2
  956. package/build/dist/UI/Components/BulkUpdate/BulkArchiveActions.js.map +1 -1
  957. package/build/dist/UI/Components/Detail/Detail.js +12 -3
  958. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  959. package/build/dist/UI/Components/Dropdown/Dropdown.js +33 -5
  960. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  961. package/build/dist/UI/Components/EmptyState/EmptyState.js +3 -3
  962. package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
  963. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js +47 -0
  964. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js.map +1 -0
  965. package/build/dist/UI/Components/Forms/ModelForm.js +6 -5
  966. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  967. package/build/dist/UI/Components/LabelRule/LabelRuleTable.js +6 -2
  968. package/build/dist/UI/Components/LabelRule/LabelRuleTable.js.map +1 -1
  969. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +1 -1
  970. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  971. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +0 -2
  972. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
  973. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +3 -1
  974. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  975. package/build/dist/UI/Components/RuleRun/RuleDetailFields.js +226 -0
  976. package/build/dist/UI/Components/RuleRun/RuleDetailFields.js.map +1 -0
  977. package/build/dist/UI/Components/RuleRun/RuleTable.js +97 -0
  978. package/build/dist/UI/Components/RuleRun/RuleTable.js.map +1 -0
  979. package/build/dist/UI/Components/RuleRun/RuleView.js +83 -0
  980. package/build/dist/UI/Components/RuleRun/RuleView.js.map +1 -0
  981. package/build/dist/UI/Components/RuleRun/RunRuleNowModal.js +74 -0
  982. package/build/dist/UI/Components/RuleRun/RunRuleNowModal.js.map +1 -0
  983. package/build/dist/UI/Components/RuleRun/RunRulesBulkAction.js +78 -0
  984. package/build/dist/UI/Components/RuleRun/RunRulesBulkAction.js.map +1 -0
  985. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
  986. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  987. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +24 -50
  988. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -1
  989. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js +0 -4
  990. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js.map +1 -1
  991. package/build/dist/UI/Utils/Rules/RuleRunClient.js +98 -0
  992. package/build/dist/UI/Utils/Rules/RuleRunClient.js.map +1 -0
  993. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +8 -0
  994. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -1
  995. package/build/dist/Utils/Dashboard/Components/DashboardSloComponent.js +16 -2
  996. package/build/dist/Utils/Dashboard/Components/DashboardSloComponent.js.map +1 -1
  997. package/build/dist/Utils/Dashboard/Components/DashboardSloListComponent.js +94 -0
  998. package/build/dist/Utils/Dashboard/Components/DashboardSloListComponent.js.map +1 -0
  999. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  1000. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  1001. package/build/dist/Utils/Dashboard/SloWidgetSource.js +125 -0
  1002. package/build/dist/Utils/Dashboard/SloWidgetSource.js.map +1 -0
  1003. package/build/dist/Utils/Markdown/MarkdownEscape.js +49 -0
  1004. package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -0
  1005. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +112 -34
  1006. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  1007. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +22 -0
  1008. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
  1009. package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js +129 -0
  1010. package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js.map +1 -0
  1011. package/build/dist/Utils/NetworkDiscovery/RunImportedDeviceNaming.js +255 -0
  1012. package/build/dist/Utils/NetworkDiscovery/RunImportedDeviceNaming.js.map +1 -0
  1013. package/build/dist/Utils/NetworkDiscovery/ShortDeviceNamePlanner.js +184 -0
  1014. package/build/dist/Utils/NetworkDiscovery/ShortDeviceNamePlanner.js.map +1 -0
  1015. package/build/dist/Utils/NetworkDiscovery/ShortHostnameUtil.js +79 -0
  1016. package/build/dist/Utils/NetworkDiscovery/ShortHostnameUtil.js.map +1 -0
  1017. package/build/dist/Utils/NetworkSite/CidrMatchUtil.js +21 -12
  1018. package/build/dist/Utils/NetworkSite/CidrMatchUtil.js.map +1 -1
  1019. package/build/dist/Utils/Project/DataResidency.js +51 -0
  1020. package/build/dist/Utils/Project/DataResidency.js.map +1 -0
  1021. package/build/dist/Utils/Rules/RuleRunSummary.js +197 -0
  1022. package/build/dist/Utils/Rules/RuleRunSummary.js.map +1 -0
  1023. package/build/dist/Utils/Slo/SloAffectedResourceMarkdown.js +51 -0
  1024. package/build/dist/Utils/Slo/SloAffectedResourceMarkdown.js.map +1 -0
  1025. package/build/dist/Utils/Slo/SloBurnRateTemplate.js +228 -0
  1026. package/build/dist/Utils/Slo/SloBurnRateTemplate.js.map +1 -0
  1027. package/build/dist/Utils/Slo/SloFeedMarkdown.js +934 -0
  1028. package/build/dist/Utils/Slo/SloFeedMarkdown.js.map +1 -0
  1029. package/build/dist/Utils/Slo/SloHealth.js +75 -9
  1030. package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
  1031. package/build/dist/Utils/Slo/SloListWidgetFormat.js +217 -0
  1032. package/build/dist/Utils/Slo/SloListWidgetFormat.js.map +1 -0
  1033. package/build/dist/Utils/Slo/SloMetricType.js +212 -0
  1034. package/build/dist/Utils/Slo/SloMetricType.js.map +1 -0
  1035. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +216 -0
  1036. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -0
  1037. package/build/dist/Utils/Slo/SloMonitorStatusSummary.js +129 -0
  1038. package/build/dist/Utils/Slo/SloMonitorStatusSummary.js.map +1 -0
  1039. package/build/dist/Utils/Slo/SloOverviewText.js +110 -0
  1040. package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -0
  1041. package/build/dist/Utils/Slo/SloProjection.js +448 -0
  1042. package/build/dist/Utils/Slo/SloProjection.js.map +1 -0
  1043. package/build/dist/Utils/Slo/SloWidgetFormat.js +4 -2
  1044. package/build/dist/Utils/Slo/SloWidgetFormat.js.map +1 -1
  1045. package/build/dist/Utils/Telemetry/LockedFilterSearch.js +1 -26
  1046. package/build/dist/Utils/Telemetry/LockedFilterSearch.js.map +1 -1
  1047. package/package.json +1 -1
  1048. package/Models/DatabaseModels/GoogleSecOpsConnection.ts +0 -447
  1049. package/Models/DatabaseModels/GoogleSecOpsConnectionRun.ts +0 -263
  1050. package/Server/API/GoogleSecOpsConnectionAPI.ts +0 -320
  1051. package/Server/Services/GoogleSecOpsConnectionRunService.ts +0 -10
  1052. package/Server/Services/GoogleSecOpsConnectionService.ts +0 -116
  1053. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.ts +0 -777
  1054. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +0 -1373
  1055. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.ts +0 -512
  1056. package/Tests/App/Dashboard/GoogleSecOpsConnectionForm.test.tsx +0 -838
  1057. package/Tests/App/Dashboard/GoogleSecOpsConnectionsErrors.test.tsx +0 -441
  1058. package/Tests/App/Dashboard/GoogleSecOpsDiagnostics.test.tsx +0 -1001
  1059. package/Tests/Server/API/GoogleSecOpsConnectionAPI.test.ts +0 -657
  1060. package/Tests/Server/Services/GoogleSecOpsDiagnosticsModel.test.ts +0 -153
  1061. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.test.ts +0 -784
  1062. package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +0 -823
  1063. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +0 -918
  1064. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +0 -738
  1065. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +0 -874
  1066. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +0 -1297
  1067. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsThreePassPoller.test.ts +0 -1577
  1068. package/Tests/UI/Components/LockedFilterActions.test.tsx +0 -396
  1069. package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +0 -111
  1070. package/UI/Components/TelemetryViewer/components/LockedFilterActions.tsx +0 -205
  1071. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +0 -478
  1072. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +0 -1
  1073. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnectionRun.js +0 -287
  1074. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnectionRun.js.map +0 -1
  1075. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +0 -231
  1076. package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +0 -1
  1077. package/build/dist/Server/Services/GoogleSecOpsConnectionRunService.js +0 -9
  1078. package/build/dist/Server/Services/GoogleSecOpsConnectionRunService.js.map +0 -1
  1079. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +0 -70
  1080. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +0 -1
  1081. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +0 -1
  1082. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js +0 -537
  1083. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js.map +0 -1
  1084. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +0 -1034
  1085. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +0 -1
  1086. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +0 -410
  1087. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +0 -1
  1088. package/build/dist/Types/SecurityEvent/GoogleSecOpsDiagnostics.js +0 -2
  1089. package/build/dist/Types/SecurityEvent/GoogleSecOpsDiagnostics.js.map +0 -1
  1090. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js +0 -88
  1091. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js.map +0 -1
@@ -79,13 +79,16 @@ jest.mock("../../../UI/Components/Markdown.tsx/LazyMarkdownViewer", () => {
79
79
  });
80
80
 
81
81
  /*
82
- * The feed owns the "will this draw any steps?" predicate, because several
83
- * event types only close a step an earlier event opened. The panel asks it
84
- * instead of counting raw events, so the mock has to answer too — and
85
- * hasRenderableActivityMock lets a test make the two disagree, which is the
86
- * case that used to render an empty framed box.
82
+ * The feed owns "how many steps will this draw?", because several event
83
+ * types only close a step an earlier event opened. The panel and its run
84
+ * details ask it instead of counting raw events, so the mock has to answer
85
+ * too. countActivityStepsMock lets a test make events and steps disagree
86
+ * the case that used to frame an empty box — and hasRenderableActivityMock
87
+ * follows it by default, exactly as the real predicate does, so the two
88
+ * exports can never contradict each other unless a test says so.
87
89
  */
88
90
  const hasRenderableActivityMock: MockFunction = getJestMockFunction();
91
+ const countActivityStepsMock: MockFunction = getJestMockFunction();
89
92
 
90
93
  // Evidence rows render through the chat widgets; their output is not under test.
91
94
  jest.mock(
@@ -115,6 +118,9 @@ jest.mock(
115
118
  hasRenderableActivity: (events: Array<AIRunEvent>): boolean => {
116
119
  return hasRenderableActivityMock(events) as boolean;
117
120
  },
121
+ countActivitySteps: (events: Array<AIRunEvent>): number => {
122
+ return countActivityStepsMock(events) as number;
123
+ },
118
124
  };
119
125
  },
120
126
  );
@@ -126,6 +132,7 @@ import AIRunEvent from "../../../Models/DatabaseModels/AIRunEvent";
126
132
  import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
127
133
  import AIRunCodeFixRecommendation from "../../../Types/AI/AIRunCodeFixRecommendation";
128
134
  import AIRunEventType from "../../../Types/AI/AIRunEventType";
135
+ import AIRunHumanVerdict from "../../../Types/AI/AIRunHumanVerdict";
129
136
  import AIRunStatus from "../../../Types/AI/AIRunStatus";
130
137
  import { JSONArray, JSONObject } from "../../../Types/JSON";
131
138
  import ObjectID from "../../../Types/ObjectID";
@@ -301,6 +308,7 @@ function renderPanel(data?: {
301
308
  onAnalysisAvailable?: (() => void) | undefined;
302
309
  onStatusChange?: ((status: AIRunStatus | null) => void) | undefined;
303
310
  onReportSummaryChange?: ((summary: string | null) => void) | undefined;
311
+ onVerdictChange?: ((verdict: AIRunHumanVerdict | null) => void) | undefined;
304
312
  }): ReturnType<typeof render> {
305
313
  return render(
306
314
  <InvestigationPanel
@@ -309,6 +317,7 @@ function renderPanel(data?: {
309
317
  onAnalysisAvailable={data?.onAnalysisAvailable}
310
318
  onStatusChange={data?.onStatusChange}
311
319
  onReportSummaryChange={data?.onReportSummaryChange}
320
+ onVerdictChange={data?.onVerdictChange}
312
321
  />,
313
322
  );
314
323
  }
@@ -372,17 +381,59 @@ function lastActivityProps(): ActivityFeedProps {
372
381
  return calls[calls.length - 1]![0]!;
373
382
  }
374
383
 
384
+ /*
385
+ * A completed run ends with one collapsed section holding its evidence, its
386
+ * activity and what it cost. Its body stays mounted while collapsed, so the
387
+ * role queries below (which skip hidden content) only find what a reader
388
+ * could actually reach; tests open the section before reaching inside it.
389
+ */
390
+ function runDetails(): HTMLElement {
391
+ return screen.getByTestId("investigation-details");
392
+ }
393
+
394
+ function detailsToggle(): HTMLElement {
395
+ return screen.getByTestId("investigation-details-toggle");
396
+ }
397
+
398
+ function detailsBody(): HTMLElement {
399
+ const bodyId: string | null = detailsToggle().getAttribute("aria-controls");
400
+ expect(bodyId).toBeTruthy();
401
+ return document.getElementById(bodyId!)!;
402
+ }
403
+
404
+ function openDetails(): void {
405
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "false");
406
+ fireEvent.click(detailsToggle());
407
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "true");
408
+ }
409
+
410
+ function detailsTab(name: RegExp): HTMLElement {
411
+ return within(
412
+ screen.getByRole("tablist", { name: "Investigation details" }),
413
+ ).getByRole("tab", { name });
414
+ }
415
+
416
+ function evidenceList(): HTMLElement {
417
+ return screen.getByRole("list", { name: "Evidence checked" });
418
+ }
419
+
375
420
  beforeEach(() => {
376
421
  jest.useFakeTimers();
377
422
  jest.setSystemTime(new Date(COMPLETED_AT));
378
423
  getCommonHeadersMock.mockReturnValue({});
379
424
  /*
380
425
  * Default to the real component's behaviour for the ordinary event shapes
381
- * these tests use: every step-opening event draws a step.
426
+ * these tests use: every step-opening event draws a step, and there is
427
+ * activity to render exactly when at least one step is drawn.
382
428
  */
429
+ countActivityStepsMock.mockImplementation(
430
+ (events: Array<AIRunEvent>): number => {
431
+ return events.length;
432
+ },
433
+ );
383
434
  hasRenderableActivityMock.mockImplementation(
384
435
  (events: Array<AIRunEvent>): boolean => {
385
- return events.length > 0;
436
+ return (countActivityStepsMock(events) as number) > 0;
386
437
  },
387
438
  );
388
439
  getFriendlyMessageMock.mockImplementation((error: unknown): string => {
@@ -409,6 +460,7 @@ afterEach(() => {
409
460
  markdownViewerMock.mockReset();
410
461
  activityFeedMock.mockReset();
411
462
  hasRenderableActivityMock.mockReset();
463
+ countActivityStepsMock.mockReset();
412
464
  widgetRendererMock.mockReset();
413
465
  });
414
466
 
@@ -459,7 +511,7 @@ describe("InvestigationPanel report lifecycle", () => {
459
511
  expect(getCommonHeadersMock).toHaveBeenCalledTimes(1);
460
512
  });
461
513
 
462
- test("renders the completed report safely and demotes activity to a disclosure", async () => {
514
+ test("renders the completed report safely and folds its activity into a collapsed section", async () => {
463
515
  const onAnalysisAvailable: MockFunction = getJestMockFunction();
464
516
  postMock.mockResolvedValue(completedResponse() as never);
465
517
 
@@ -487,21 +539,29 @@ describe("InvestigationPanel report lifecycle", () => {
487
539
  expect(
488
540
  screen.getByRole("heading", { level: 4, name: "Root cause" }),
489
541
  ).toBeInTheDocument();
490
- expect(screen.getByText("Investigation activity")).toBeInTheDocument();
542
+ /*
543
+ * This report carries no evidence, so the section is only the activity
544
+ * and is named for it. It starts collapsed: the report is the answer.
545
+ */
546
+ expect(detailsToggle()).toHaveTextContent("Investigation activity");
547
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "false");
548
+ expect(detailsBody()).not.toBeVisible();
491
549
  expect(lastActivityProps()).toEqual(
492
550
  expect.objectContaining({
493
551
  hideChrome: true,
494
552
  showLiveIndicator: false,
495
- maxVisibleSteps: 10,
496
553
  }),
497
554
  );
498
555
 
499
556
  const usage: HTMLElement = screen.getByLabelText("Investigation usage");
557
+ expect(usage).toBeVisible();
500
558
  expect(usage).toHaveTextContent("2 telemetry queries");
501
- expect(usage).toHaveTextContent("1,234 tokens");
502
559
  expect(usage).toHaveTextContent(
503
560
  "Read-only — nothing in your systems was changed",
504
561
  );
562
+ expect(screen.getByLabelText("Model and tokens")).toHaveTextContent(
563
+ "1,234 tokens",
564
+ );
505
565
  expect(fixButton()).toBeEnabled();
506
566
  expect(screen.getByRole("button", { name: "Confirmed" })).toBeEnabled();
507
567
  expect(screen.getByRole("button", { name: "Rejected" })).toBeEnabled();
@@ -531,6 +591,8 @@ describe("InvestigationPanel report lifecycle", () => {
531
591
  expect(screen.getByText("Preparing investigation report…")).toBeVisible();
532
592
  expect(screen.getByText("Preparing the final report")).toBeVisible();
533
593
  expect(screen.queryByTestId("investigation-markdown")).toBeNull();
594
+ // The steps can already be checked while the report is being written.
595
+ expect(detailsToggle()).toHaveTextContent("Investigation activity");
534
596
  expect(onAnalysisAvailable).not.toHaveBeenCalled();
535
597
 
536
598
  /* Status, run id, events and recommendation remain identical. */
@@ -678,6 +740,19 @@ describe("InvestigationPanel report lifecycle", () => {
678
740
  expect(
679
741
  screen.getByText("No investigation report was published."),
680
742
  ).toBeVisible();
743
+ /*
744
+ * No steps were recorded, so the notice does not point at an activity
745
+ * section that is not there, and there is nothing to expand: the run's
746
+ * usage is all that is left to say.
747
+ */
748
+ expect(
749
+ screen.getByText("The run finished without a final analysis."),
750
+ ).toBeVisible();
751
+ expect(screen.queryByText(/Investigation activity/)).toBeNull();
752
+ expect(screen.queryByTestId("investigation-details-toggle")).toBeNull();
753
+ expect(screen.getByLabelText("Investigation usage")).toHaveTextContent(
754
+ "0 telemetry queries",
755
+ );
681
756
  expect(fixButton()).toBeDisabled();
682
757
  expect(screen.getByRole("button", { name: "Confirmed" })).toBeDisabled();
683
758
  expect(screen.getByRole("button", { name: "Rejected" })).toBeDisabled();
@@ -771,14 +846,16 @@ describe("InvestigationPanel card states", () => {
771
846
  expect(screen.getByText("Starting investigation…")).toBeVisible();
772
847
  });
773
848
 
774
- test("puts a copy control on the report so it can be pasted elsewhere", async () => {
849
+ test("puts a copy control and a verify-first note on the report", async () => {
775
850
  postMock.mockResolvedValue(completedResponse() as never);
776
851
 
777
852
  renderPanel();
778
853
  await flush();
779
854
 
780
855
  const report: HTMLElement = screen.getByLabelText("Investigation report");
781
- expect(report).toHaveTextContent("AI generated");
856
+ expect(report).toHaveTextContent(
857
+ "AI-generated first pass — verify before acting.",
858
+ );
782
859
  expect(report).toContainElement(
783
860
  screen.getByRole("button", { name: "Copy report" }),
784
861
  );
@@ -813,6 +890,45 @@ describe("InvestigationPanel card states", () => {
813
890
  },
814
891
  );
815
892
 
893
+ /*
894
+ * A failed run has no report and no collapsed details, so what it ran and
895
+ * the read-only guarantee close its own activity frame instead — a reader
896
+ * deciding whether a half-finished run touched anything finds the answer
897
+ * right under the steps it took.
898
+ */
899
+ test("ends a failed run's activity with what it ran and that it changed nothing", async () => {
900
+ postMock.mockResolvedValue(
901
+ successfulResponse(
902
+ investigationPayload({
903
+ status: AIRunStatus.Error,
904
+ errorMessage: "The model provider timed out.",
905
+ events: [activityEvent],
906
+ toolCallCount: 3,
907
+ totalTokens: 900,
908
+ }),
909
+ ) as never,
910
+ );
911
+
912
+ renderPanel();
913
+ await flush();
914
+
915
+ const activity: HTMLElement = screen.getByRole("region", {
916
+ name: "Investigation activity",
917
+ });
918
+ const usage: HTMLElement = within(activity).getByRole("list", {
919
+ name: "Investigation usage",
920
+ });
921
+ expect(activity.lastElementChild).toBe(usage);
922
+ expect(usage).toBeVisible();
923
+ expect(usage).toHaveTextContent("3 telemetry queries");
924
+ expect(usage).toHaveTextContent("900 tokens");
925
+ expect(usage).toHaveTextContent(
926
+ "Read-only — nothing in your systems was changed",
927
+ );
928
+ expect(screen.queryByTestId("investigation-details")).toBeNull();
929
+ expect(screen.getAllByLabelText("Investigation usage")).toHaveLength(1);
930
+ });
931
+
816
932
  /*
817
933
  * Events and rendered steps are not the same thing: RunFailed and the
818
934
  * completion halves of tool/LLM calls only close a step an earlier event
@@ -821,7 +937,7 @@ describe("InvestigationPanel card states", () => {
821
937
  * an empty panel instead of saying what happened.
822
938
  */
823
939
  test("explains an empty trail instead of framing a blank panel", async () => {
824
- hasRenderableActivityMock.mockReturnValue(false);
940
+ countActivityStepsMock.mockReturnValue(0);
825
941
  postMock.mockResolvedValue(
826
942
  successfulResponse(
827
943
  investigationPayload({
@@ -841,8 +957,14 @@ describe("InvestigationPanel card states", () => {
841
957
  ).toBeVisible();
842
958
  });
843
959
 
844
- test("hides the completed activity disclosure when no step would render", async () => {
845
- hasRenderableActivityMock.mockReturnValue(false);
960
+ /*
961
+ * The same event/step mismatch on a completed run: with no evidence and no
962
+ * step to draw, a collapsed section would open onto nothing. The run's
963
+ * usage is all there is, so it stands alone — tokens included, since there
964
+ * is no body to hold them.
965
+ */
966
+ test("offers nothing to expand when a completed run has no evidence and no step would render", async () => {
967
+ countActivityStepsMock.mockReturnValue(0);
846
968
  postMock.mockResolvedValue(completedResponse() as never);
847
969
 
848
970
  renderPanel();
@@ -850,9 +972,17 @@ describe("InvestigationPanel card states", () => {
850
972
 
851
973
  expect(screen.getByLabelText("Investigation report")).toBeInTheDocument();
852
974
  expect(screen.queryByText("Investigation activity")).toBeNull();
975
+ expect(screen.queryByTestId("investigation-details-toggle")).toBeNull();
976
+ expect(screen.queryByTestId("investigation-activity")).toBeNull();
977
+
978
+ const usage: HTMLElement = screen.getByLabelText("Investigation usage");
979
+ expect(usage).toBeVisible();
980
+ expect(usage).toHaveTextContent("2 telemetry queries");
981
+ expect(usage).toHaveTextContent("1,234 tokens");
982
+ expect(usage).not.toHaveTextContent("step");
853
983
  });
854
984
 
855
- test("reports a single query without pluralising it", async () => {
985
+ test("reports a single query and step without pluralising them", async () => {
856
986
  postMock.mockResolvedValue(
857
987
  completedResponse({ toolCallCount: 1, totalTokens: 0 }) as never,
858
988
  );
@@ -862,8 +992,50 @@ describe("InvestigationPanel card states", () => {
862
992
 
863
993
  const usage: HTMLElement = screen.getByLabelText("Investigation usage");
864
994
  expect(usage).toHaveTextContent("1 telemetry query");
995
+ expect(usage).not.toHaveTextContent("queries");
996
+ expect(usage).toHaveTextContent("1 step");
997
+ expect(usage).not.toHaveTextContent("steps");
865
998
  expect(usage).not.toHaveTextContent("tokens");
866
999
  });
1000
+
1001
+ /*
1002
+ * The no-report notice used to send every reader to "the activity below",
1003
+ * even when no step had been recorded and there was nothing below to read.
1004
+ */
1005
+ test("points the no-report notice at the activity only when there is some", async () => {
1006
+ postMock.mockResolvedValue(
1007
+ completedResponse({
1008
+ analysisMarkdown: null,
1009
+ isAnalysisPending: false,
1010
+ }) as never,
1011
+ );
1012
+
1013
+ renderPanel();
1014
+ await flush();
1015
+
1016
+ expect(
1017
+ screen.getByText(
1018
+ "The run finished without a final analysis. Its steps are under Investigation activity below.",
1019
+ ),
1020
+ ).toBeVisible();
1021
+
1022
+ /*
1023
+ * Evidence only exists beside a report, so the section is the activity
1024
+ * alone: named for it, and without tabs once opened.
1025
+ */
1026
+ expect(detailsToggle()).toHaveTextContent("Investigation activity");
1027
+ expect(detailsToggle()).not.toHaveTextContent("Evidence");
1028
+ expect(screen.getByLabelText("Investigation usage")).toHaveTextContent(
1029
+ "2 telemetry queries",
1030
+ );
1031
+
1032
+ openDetails();
1033
+
1034
+ expect(screen.queryByRole("tablist")).toBeNull();
1035
+ expect(screen.queryByRole("tabpanel")).toBeNull();
1036
+ expect(screen.queryByLabelText("Evidence checked")).toBeNull();
1037
+ expect(screen.getByTestId("investigation-activity")).toBeVisible();
1038
+ });
867
1039
  });
868
1040
 
869
1041
  /*
@@ -1956,18 +2128,25 @@ describe("InvestigationPanel structured report", () => {
1956
2128
  renderPanel();
1957
2129
  await flush();
1958
2130
 
1959
- const evidence: HTMLElement = screen.getByRole("region", {
1960
- name: "Evidence checked",
1961
- });
1962
- expect(within(evidence).getByText("2 queries")).toBeVisible();
1963
- expect(
1964
- within(evidence).getByRole("button", { name: /Active incidents/ }),
1965
- ).toHaveAttribute("aria-expanded", "false");
1966
2131
  expect(
1967
2132
  screen
1968
2133
  .getByLabelText("Investigation report")
1969
- .compareDocumentPosition(evidence) & Node.DOCUMENT_POSITION_FOLLOWING,
2134
+ .compareDocumentPosition(runDetails()) &
2135
+ Node.DOCUMENT_POSITION_FOLLOWING,
1970
2136
  ).toBeTruthy();
2137
+
2138
+ openDetails();
2139
+
2140
+ // The tab carries the query count the old list header used to show.
2141
+ expect(detailsTab(/^Evidence checked/)).toHaveTextContent(
2142
+ "Evidence checked2",
2143
+ );
2144
+ const evidence: HTMLElement = evidenceList();
2145
+ expect(runDetails()).toContainElement(evidence);
2146
+ expect(within(evidence).getAllByRole("listitem")).toHaveLength(2);
2147
+ expect(
2148
+ within(evidence).getByRole("button", { name: /Active incidents/ }),
2149
+ ).toHaveAttribute("aria-expanded", "false");
1971
2150
  // Rendering evidence never re-runs anything by itself.
1972
2151
  expect(evidencePosts()).toHaveLength(0);
1973
2152
  expect(jest.getTimerCount()).toBe(1);
@@ -1987,6 +2166,7 @@ describe("InvestigationPanel structured report", () => {
1987
2166
 
1988
2167
  renderPanel();
1989
2168
  await flush();
2169
+ openDetails();
1990
2170
 
1991
2171
  const toggle: HTMLElement = screen.getByRole("button", {
1992
2172
  name: /Active incidents \(7 total\)/,
@@ -2019,10 +2199,12 @@ describe("InvestigationPanel structured report", () => {
2019
2199
 
2020
2200
  renderPanel();
2021
2201
  await flush();
2202
+ openDetails();
2022
2203
 
2023
- const evidence: HTMLElement = screen.getByRole("region", {
2024
- name: "Evidence checked",
2025
- });
2204
+ const evidence: HTMLElement = evidenceList();
2205
+ expect(detailsTab(/^Evidence checked/)).toHaveTextContent(
2206
+ "Evidence checked2",
2207
+ );
2026
2208
  expect(evidence).toHaveTextContent("Active incidents (7 total)");
2027
2209
  expect(evidence).toHaveTextContent("Logs 17:20 – 18:20 (1 shown)");
2028
2210
  expect(within(evidence).queryAllByRole("button")).toHaveLength(0);
@@ -2045,17 +2227,15 @@ describe("InvestigationPanel structured report", () => {
2045
2227
 
2046
2228
  renderPanel();
2047
2229
  await flush();
2048
- expect(
2049
- within(screen.getByLabelText("Evidence checked")).queryAllByRole(
2050
- "button",
2051
- ),
2052
- ).toHaveLength(0);
2230
+ openDetails();
2231
+ expect(within(evidenceList()).getAllByRole("listitem")).toHaveLength(2);
2232
+ expect(within(evidenceList()).queryAllByRole("button")).toHaveLength(0);
2053
2233
 
2054
2234
  await tick(SETTLED_POLL_INTERVAL_MS);
2055
2235
 
2056
- expect(
2057
- within(screen.getByLabelText("Evidence checked")).getAllByRole("button"),
2058
- ).toHaveLength(2);
2236
+ // Still open on the same list, now with a toggle per query.
2237
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "true");
2238
+ expect(within(evidenceList()).getAllByRole("button")).toHaveLength(2);
2059
2239
  });
2060
2240
 
2061
2241
  test("never shows evidence without the report it belongs to", async () => {
@@ -2073,6 +2253,13 @@ describe("InvestigationPanel structured report", () => {
2073
2253
 
2074
2254
  expect(screen.getByText("Preparing the final report")).toBeVisible();
2075
2255
  expect(screen.queryByLabelText("Evidence checked")).toBeNull();
2256
+
2257
+ // The section still offers the run's steps, and only those.
2258
+ expect(detailsToggle()).toHaveTextContent("Investigation activity");
2259
+ openDetails();
2260
+ expect(screen.queryByRole("tablist")).toBeNull();
2261
+ expect(screen.queryByLabelText("Evidence checked")).toBeNull();
2262
+ expect(screen.getByTestId("investigation-activity")).toBeVisible();
2076
2263
  });
2077
2264
 
2078
2265
  test("drops evidence when the report disappears on a later poll", async () => {
@@ -2085,10 +2272,12 @@ describe("InvestigationPanel structured report", () => {
2085
2272
  renderPanel();
2086
2273
  await flush();
2087
2274
  expect(screen.getByLabelText("Evidence checked")).toBeInTheDocument();
2275
+ expect(detailsToggle()).toHaveTextContent("Evidence and activity");
2088
2276
 
2089
2277
  await tick(SETTLED_POLL_INTERVAL_MS);
2090
2278
 
2091
2279
  expect(screen.queryByLabelText("Evidence checked")).toBeNull();
2280
+ expect(detailsToggle()).toHaveTextContent("Investigation activity");
2092
2281
  expect(
2093
2282
  screen.getByText("No investigation report was published."),
2094
2283
  ).toBeVisible();
@@ -2110,13 +2299,11 @@ describe("InvestigationPanel structured report", () => {
2110
2299
 
2111
2300
  renderPanel();
2112
2301
  await flush();
2302
+ openDetails();
2113
2303
 
2114
2304
  // Nothing valid survived, so the legacy list and plain numbers are used.
2115
- expect(
2116
- within(screen.getByLabelText("Evidence checked")).queryAllByRole(
2117
- "button",
2118
- ),
2119
- ).toHaveLength(0);
2305
+ expect(within(evidenceList()).getAllByRole("listitem")).toHaveLength(2);
2306
+ expect(within(evidenceList()).queryAllByRole("button")).toHaveLength(0);
2120
2307
  expect(
2121
2308
  lastInlineReferences().renderEventReference!({
2122
2309
  kind: "incident",
@@ -2126,7 +2313,27 @@ describe("InvestigationPanel structured report", () => {
2126
2313
  ).toBeNull();
2127
2314
  });
2128
2315
 
2129
- test("a citation chip expands, scrolls to and highlights its evidence row", async () => {
2316
+ /*
2317
+ * The report's chips are rendered by the markdown viewer, which is mocked
2318
+ * here, so render the panel's own chip renderer output and click it the
2319
+ * way a reader would.
2320
+ */
2321
+ function clickCitation(citationId: string, name: string): void {
2322
+ const chip: React.ReactElement | null =
2323
+ lastInlineReferences().renderCitation!(citationId);
2324
+ expect(chip).not.toBeNull();
2325
+ render(chip!);
2326
+
2327
+ const chipButton: HTMLElement = screen.getByRole("button", { name });
2328
+ fireEvent.click(chipButton);
2329
+ }
2330
+
2331
+ /*
2332
+ * The evidence sits in a section that starts collapsed, so a chip that only
2333
+ * highlighted its row would highlight something nobody can see. The chip
2334
+ * has to open the section on the Evidence tab first.
2335
+ */
2336
+ test("a citation chip opens the collapsed details and expands, scrolls to and highlights its row", async () => {
2130
2337
  routePosts({
2131
2338
  investigation: (): unknown => {
2132
2339
  return Promise.resolve(structuredResponse());
@@ -2136,6 +2343,8 @@ describe("InvestigationPanel structured report", () => {
2136
2343
  renderPanel();
2137
2344
  await flush();
2138
2345
  expect(jest.getTimerCount()).toBe(1);
2346
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "false");
2347
+ expect(detailsBody()).not.toBeVisible();
2139
2348
 
2140
2349
  const chip: React.ReactElement | null =
2141
2350
  lastInlineReferences().renderCitation!("C2");
@@ -2150,10 +2359,19 @@ describe("InvestigationPanel structured report", () => {
2150
2359
  fireEvent.click(chipButton);
2151
2360
  await flush();
2152
2361
 
2153
- const toggle: HTMLElement = within(
2154
- screen.getByLabelText("Evidence checked"),
2155
- ).getByRole("button", { name: /Logs 17:20/ });
2362
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "true");
2363
+ expect(detailsBody()).toBeVisible();
2364
+ expect(detailsTab(/^Evidence checked/)).toHaveAttribute(
2365
+ "aria-selected",
2366
+ "true",
2367
+ );
2368
+
2369
+ const toggle: HTMLElement = within(evidenceList()).getByRole("button", {
2370
+ name: /Logs 17:20/,
2371
+ });
2372
+ expect(toggle).toBeVisible();
2156
2373
  expect(toggle).toHaveAttribute("aria-expanded", "true");
2374
+ expect(toggle).toHaveFocus();
2157
2375
  expect(toggle.closest("li")).toHaveAttribute("data-highlighted", "true");
2158
2376
  expect(scrollIntoViewMock).toHaveBeenCalledWith({
2159
2377
  block: "nearest",
@@ -2168,6 +2386,157 @@ describe("InvestigationPanel structured report", () => {
2168
2386
 
2169
2387
  expect(toggle.closest("li")).not.toHaveAttribute("data-highlighted");
2170
2388
  expect(jest.getTimerCount()).toBe(1);
2389
+ // The highlight fades; the section the reader was taken to stays open.
2390
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "true");
2391
+ });
2392
+
2393
+ test("a citation chip switches an open section from Activity to Evidence", async () => {
2394
+ routePosts({
2395
+ investigation: (): unknown => {
2396
+ return Promise.resolve(structuredResponse());
2397
+ },
2398
+ });
2399
+
2400
+ renderPanel();
2401
+ await flush();
2402
+ openDetails();
2403
+ fireEvent.click(detailsTab(/^Activity/));
2404
+ expect(screen.getByTestId("investigation-activity")).toBeVisible();
2405
+ expect(screen.queryByRole("list", { name: "Evidence checked" })).toBeNull();
2406
+
2407
+ clickCitation("C1", "Citation C1: Active incidents (7 total)");
2408
+ await flush();
2409
+
2410
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "true");
2411
+ expect(detailsTab(/^Evidence checked/)).toHaveAttribute(
2412
+ "aria-selected",
2413
+ "true",
2414
+ );
2415
+ expect(detailsTab(/^Activity/)).toHaveAttribute("aria-selected", "false");
2416
+ expect(screen.getByTestId("investigation-activity")).not.toBeVisible();
2417
+
2418
+ const toggle: HTMLElement = within(evidenceList()).getByRole("button", {
2419
+ name: /Active incidents/,
2420
+ });
2421
+ expect(toggle).toBeVisible();
2422
+ expect(toggle).toHaveAttribute("aria-expanded", "true");
2423
+ expect(toggle).toHaveFocus();
2424
+ expect(toggle.closest("li")).toHaveAttribute("data-highlighted", "true");
2425
+ expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);
2426
+ });
2427
+
2428
+ /*
2429
+ * An older API sends no structured evidence, so the report's own list is
2430
+ * shown and its rows have no toggle. The row itself takes focus, or a
2431
+ * keyboard or screen-reader user would be left on the chip.
2432
+ */
2433
+ test("a citation chip on an older report reveals and focuses its plain row", async () => {
2434
+ postMock.mockResolvedValue(
2435
+ completedResponse({ analysisMarkdown: STRUCTURED_REPORT }) as never,
2436
+ );
2437
+
2438
+ renderPanel();
2439
+ await flush();
2440
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "false");
2441
+
2442
+ clickCitation("C2", "Citation C2: Logs 17:20 – 18:20 (1 shown)");
2443
+ await flush();
2444
+
2445
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "true");
2446
+ expect(detailsTab(/^Evidence checked/)).toHaveAttribute(
2447
+ "aria-selected",
2448
+ "true",
2449
+ );
2450
+
2451
+ const row: HTMLElement = within(evidenceList())
2452
+ .getAllByRole("listitem")
2453
+ .find((item: HTMLElement): boolean => {
2454
+ return item.textContent?.includes("Logs 17:20") === true;
2455
+ })!;
2456
+ expect(row).toBeVisible();
2457
+ expect(row).toHaveFocus();
2458
+ expect(row).toHaveAttribute("data-highlighted", "true");
2459
+ expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);
2460
+ // A plain row has nothing to re-run.
2461
+ expect(evidencePosts()).toHaveLength(0);
2462
+ });
2463
+
2464
+ /*
2465
+ * A chip's request lives in the panel, so it outlives the evidence list
2466
+ * when the report briefly disappears between polls. When the list comes
2467
+ * back it must not replay that old request — scrolling the page and
2468
+ * stealing focus with no click behind it.
2469
+ */
2470
+ test("does not replay a chip when the evidence comes back on a later poll", async () => {
2471
+ let investigationCalls: number = 0;
2472
+ routePosts({
2473
+ investigation: (): unknown => {
2474
+ investigationCalls += 1;
2475
+ return Promise.resolve(
2476
+ investigationCalls === 2
2477
+ ? structuredResponse({ analysisMarkdown: null })
2478
+ : structuredResponse(),
2479
+ );
2480
+ },
2481
+ });
2482
+
2483
+ renderPanel();
2484
+ await flush();
2485
+ clickCitation("C2", "Citation C2: Logs 17:20 – 18:20 (1 shown)");
2486
+ await flush();
2487
+ expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);
2488
+ await tick(2000);
2489
+
2490
+ await tick(SETTLED_POLL_INTERVAL_MS);
2491
+ expect(screen.queryByLabelText("Evidence checked")).toBeNull();
2492
+ expect(screen.getByTestId("investigation-activity")).toBeVisible();
2493
+
2494
+ await tick(SETTLED_POLL_INTERVAL_MS);
2495
+ expect(investigationPostCount()).toBe(3);
2496
+
2497
+ const toggle: HTMLElement = within(evidenceList()).getByRole("button", {
2498
+ name: /Logs 17:20/,
2499
+ });
2500
+ expect(toggle).toBeVisible();
2501
+ expect(toggle).toHaveAttribute("aria-expanded", "false");
2502
+ expect(toggle).not.toHaveFocus();
2503
+ expect(document.querySelector('[data-highlighted="true"]')).toBeNull();
2504
+ expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);
2505
+ expect(evidencePosts()).toHaveLength(1);
2506
+ });
2507
+
2508
+ test("a new run on the same subject starts collapsed, even after a chip opened the last one", async () => {
2509
+ let investigationCalls: number = 0;
2510
+ routePosts({
2511
+ investigation: (): unknown => {
2512
+ investigationCalls += 1;
2513
+ return Promise.resolve(
2514
+ investigationCalls === 1
2515
+ ? structuredResponse()
2516
+ : structuredResponse({ runId: NEXT_RUN_ID }),
2517
+ );
2518
+ },
2519
+ });
2520
+
2521
+ renderPanel();
2522
+ await flush();
2523
+ clickCitation("C2", "Citation C2: Logs 17:20 – 18:20 (1 shown)");
2524
+ await flush();
2525
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "true");
2526
+
2527
+ await tick(SETTLED_POLL_INTERVAL_MS);
2528
+
2529
+ expect(investigationPostCount()).toBe(2);
2530
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "false");
2531
+ expect(detailsBody()).not.toBeVisible();
2532
+
2533
+ openDetails();
2534
+
2535
+ expect(
2536
+ within(evidenceList()).getByRole("button", { name: /Logs 17:20/ }),
2537
+ ).toHaveAttribute("aria-expanded", "false");
2538
+ expect(document.querySelector('[data-highlighted="true"]')).toBeNull();
2539
+ expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);
2171
2540
  });
2172
2541
 
2173
2542
  test("leaves a citation that is not in the evidence as plain text", async () => {
@@ -2255,6 +2624,7 @@ describe("InvestigationPanel structured report", () => {
2255
2624
 
2256
2625
  const view: ReturnType<typeof render> = renderPanel();
2257
2626
  await flush();
2627
+ openDetails();
2258
2628
  fireEvent.click(
2259
2629
  screen.getByRole("button", { name: /Active incidents \(7 total\)/ }),
2260
2630
  );
@@ -2271,6 +2641,8 @@ describe("InvestigationPanel structured report", () => {
2271
2641
  );
2272
2642
 
2273
2643
  expect(screen.queryByText(/Previous subject rows/)).toBeNull();
2644
+ // The new subject's details start collapsed like any other.
2645
+ openDetails();
2274
2646
  const toggle: HTMLElement = screen.getByRole("button", {
2275
2647
  name: /Active incidents \(7 total\)/,
2276
2648
  });
@@ -2315,18 +2687,40 @@ describe("InvestigationPanel structured report", () => {
2315
2687
  ).toBeUndefined();
2316
2688
  });
2317
2689
 
2318
- test("names the model and asks for verification in the usage strip", async () => {
2690
+ /*
2691
+ * Collapsed, the header answers "what did it do, and did it touch
2692
+ * anything?". What the run cost and which model wrote the report are for
2693
+ * the reader who opens the details, and the verify-first note belongs on
2694
+ * the report it qualifies.
2695
+ */
2696
+ test("names the model and its tokens inside the details, not in the collapsed header", async () => {
2319
2697
  postMock.mockResolvedValue(structuredResponse() as never);
2320
2698
 
2321
2699
  renderPanel();
2322
2700
  await flush();
2323
2701
 
2324
2702
  const usage: HTMLElement = screen.getByLabelText("Investigation usage");
2325
- expect(usage).toHaveTextContent("Model gpt-5");
2326
- expect(usage).toHaveTextContent(
2703
+ expect(usage).toBeVisible();
2704
+ expect(usage).toHaveTextContent("2 telemetry queries");
2705
+ expect(usage).not.toHaveTextContent("tokens");
2706
+ expect(usage).not.toHaveTextContent("gpt-5");
2707
+
2708
+ const cost: HTMLElement = screen.getByLabelText("Model and tokens");
2709
+ expect(detailsBody()).toContainElement(cost);
2710
+ expect(cost).not.toBeVisible();
2711
+ expect(cost).toHaveTextContent("1,234 tokens");
2712
+ expect(cost).toHaveTextContent("Model gpt-5");
2713
+ // Counts and the guarantee are already in the header; no repeats.
2714
+ expect(cost).not.toHaveTextContent("telemetry");
2715
+ expect(cost).not.toHaveTextContent("Read-only");
2716
+
2717
+ openDetails();
2718
+
2719
+ expect(screen.getByRole("list", { name: "Model and tokens" })).toBe(cost);
2720
+ expect(cost).toBeVisible();
2721
+ expect(screen.getByLabelText("Investigation report")).toHaveTextContent(
2327
2722
  "AI-generated first pass — verify before acting.",
2328
2723
  );
2329
- expect(usage).toHaveTextContent("2 telemetry queries");
2330
2724
  });
2331
2725
 
2332
2726
  test("does not ask to verify a report that does not exist", async () => {
@@ -2344,8 +2738,10 @@ describe("InvestigationPanel structured report", () => {
2344
2738
  await flush();
2345
2739
 
2346
2740
  const usage: HTMLElement = screen.getByLabelText("Investigation usage");
2347
- expect(usage).not.toHaveTextContent("verify before acting");
2741
+ expect(usage).toHaveTextContent("3 telemetry queries");
2348
2742
  expect(usage).not.toHaveTextContent("Model");
2743
+ expect(screen.queryByText(/verify before acting/)).toBeNull();
2744
+ expect(screen.queryByLabelText("Model and tokens")).toBeNull();
2349
2745
  });
2350
2746
 
2351
2747
  test("titles the act and rate blocks with headings instead of icon-in-paragraph", async () => {
@@ -2364,45 +2760,339 @@ describe("InvestigationPanel structured report", () => {
2364
2760
  });
2365
2761
  });
2366
2762
 
2367
- describe("InvestigationPanel report summary callback", () => {
2368
- function nonNullCalls(callback: MockFunction): Array<unknown> {
2369
- return callback.mock.calls
2370
- .map((call: Array<unknown>): unknown => {
2371
- return call[0];
2372
- })
2373
- .filter((value: unknown): boolean => {
2374
- return value !== null;
2763
+ /*
2764
+ * "Evidence checked", "Investigation activity" and the usage strip used to be
2765
+ * three stacked boxes under the report. They are now one section that starts
2766
+ * collapsed: the report is the answer, this is its working. Collapsed, it
2767
+ * still has to say what the run did and that it changed nothing, because a
2768
+ * responder asks that before trusting the report at all.
2769
+ */
2770
+ describe("InvestigationPanel run details", () => {
2771
+ function tabNames(): Array<string> {
2772
+ return within(
2773
+ screen.getByRole("tablist", { name: "Investigation details" }),
2774
+ )
2775
+ .getAllByRole("tab")
2776
+ .map((tab: HTMLElement): string => {
2777
+ return tab.textContent || "";
2375
2778
  });
2376
2779
  }
2377
2780
 
2378
- test("reports the TL;DR of a completed report", async () => {
2379
- const onReportSummaryChange: MockFunction = getJestMockFunction();
2380
- postMock.mockResolvedValue(
2381
- structuredResponse({ analysisTldr: TLDR }) as never,
2382
- );
2781
+ test("starts collapsed and still says what the run did in its header", async () => {
2782
+ postMock.mockResolvedValue(structuredResponse() as never);
2383
2783
 
2384
- renderPanel({ onReportSummaryChange });
2784
+ renderPanel();
2385
2785
  await flush();
2386
2786
 
2387
- expect(onReportSummaryChange).toHaveBeenLastCalledWith(TLDR);
2388
- expect(nonNullCalls(onReportSummaryChange)).toEqual([TLDR]);
2787
+ const section: HTMLElement = screen.getByRole("region", {
2788
+ name: "Evidence and activity",
2789
+ });
2790
+ expect(section).toBe(runDetails());
2791
+
2792
+ /*
2793
+ * The toggle is named by the title alone: the usage line beside it is
2794
+ * not part of the button, so a screen reader hears a short name.
2795
+ */
2796
+ const toggle: HTMLElement = within(section).getByRole("button", {
2797
+ name: "Evidence and activity",
2798
+ });
2799
+ expect(toggle).toBe(detailsToggle());
2800
+ expect(
2801
+ within(section).getByRole("heading", {
2802
+ level: 3,
2803
+ name: "Evidence and activity",
2804
+ }),
2805
+ ).toContainElement(toggle);
2806
+ expect(toggle).toHaveAttribute("aria-expanded", "false");
2807
+ expect(detailsBody()).not.toBeVisible();
2808
+ expect(section).toContainElement(detailsBody());
2809
+ expect(screen.queryByRole("tablist")).toBeNull();
2810
+ expect(screen.queryByRole("list", { name: "Evidence checked" })).toBeNull();
2811
+ expect(screen.getByTestId("investigation-activity")).not.toBeVisible();
2812
+
2813
+ const usage: HTMLElement = within(section).getByRole("list", {
2814
+ name: "Investigation usage",
2815
+ });
2816
+ expect(usage).toBeVisible();
2817
+ expect(
2818
+ within(usage)
2819
+ .getAllByRole("listitem")
2820
+ .map((item: HTMLElement): string => {
2821
+ return item.textContent || "";
2822
+ }),
2823
+ ).toEqual([
2824
+ "2 telemetry queries",
2825
+ "1 step",
2826
+ "Read-only — nothing in your systems was changed",
2827
+ ]);
2389
2828
  });
2390
2829
 
2391
- test("falls back to the report's Summary as plain text without a TL;DR", async () => {
2392
- const onReportSummaryChange: MockFunction = getJestMockFunction();
2393
- postMock.mockResolvedValue(structuredResponse() as never);
2830
+ /*
2831
+ * The run's tool-call count also includes calls that failed and never
2832
+ * became evidence. Inside a section whose Evidence tab lists the queries,
2833
+ * the header has to count the same queries, or the two numbers a reader
2834
+ * sees side by side disagree. Without evidence the run's own count is all
2835
+ * there is.
2836
+ */
2837
+ test("counts the queries the Evidence tab lists, not the run's raw call count", async () => {
2838
+ postMock
2839
+ .mockResolvedValueOnce(structuredResponse({ toolCallCount: 3 }) as never)
2840
+ .mockResolvedValue(
2841
+ structuredResponse({ toolCallCount: 3, evidence: [] }) as never,
2842
+ );
2394
2843
 
2395
- renderPanel({ onReportSummaryChange });
2844
+ renderPanel();
2396
2845
  await flush();
2397
2846
 
2398
- expect(onReportSummaryChange).toHaveBeenLastCalledWith(REPORT_SUMMARY);
2847
+ expect(screen.getByLabelText("Investigation usage")).toHaveTextContent(
2848
+ "2 telemetry queries",
2849
+ );
2850
+ openDetails();
2851
+ expect(detailsTab(/^Evidence checked/)).toHaveTextContent(
2852
+ "Evidence checked2",
2853
+ );
2854
+
2855
+ /*
2856
+ * An older API: the report's own list still names the queries, so the
2857
+ * header follows it rather than the raw call count.
2858
+ */
2859
+ await tick(SETTLED_POLL_INTERVAL_MS);
2860
+
2861
+ expect(within(evidenceList()).queryAllByRole("button")).toHaveLength(0);
2862
+ expect(screen.getByLabelText("Investigation usage")).toHaveTextContent(
2863
+ "2 telemetry queries",
2864
+ );
2399
2865
  });
2400
2866
 
2401
- test("bounds a long Summary", async () => {
2402
- const onReportSummaryChange: MockFunction = getJestMockFunction();
2867
+ test("falls back to the run's call count when there is no evidence at all", async () => {
2403
2868
  postMock.mockResolvedValue(
2404
- completedResponse({
2405
- analysisMarkdown: `**Summary** — ${"pool exhausted ".repeat(60)}\n\n**Root cause** — a deploy.`,
2869
+ completedResponse({ toolCallCount: 3 }) as never,
2870
+ );
2871
+
2872
+ renderPanel();
2873
+ await flush();
2874
+
2875
+ expect(detailsToggle()).toHaveTextContent("Investigation activity");
2876
+ expect(screen.getByLabelText("Investigation usage")).toHaveTextContent(
2877
+ "3 telemetry queries",
2878
+ );
2879
+ });
2880
+
2881
+ test("opening reveals the tabs and the evidence list, and closing hides them again", async () => {
2882
+ postMock.mockResolvedValue(structuredResponse() as never);
2883
+
2884
+ renderPanel();
2885
+ await flush();
2886
+ openDetails();
2887
+
2888
+ expect(detailsBody()).toBeVisible();
2889
+ expect(tabNames()).toEqual(["Evidence checked2", "Activity1"]);
2890
+
2891
+ const evidenceTab: HTMLElement = detailsTab(/^Evidence checked/);
2892
+ expect(evidenceTab).toHaveAttribute("aria-selected", "true");
2893
+ expect(evidenceTab).toHaveAttribute("tabindex", "0");
2894
+ expect(detailsTab(/^Activity/)).toHaveAttribute("aria-selected", "false");
2895
+ expect(detailsTab(/^Activity/)).toHaveAttribute("tabindex", "-1");
2896
+
2897
+ // Only the selected panel is reachable, and it is named by its tab.
2898
+ const panel: HTMLElement = screen.getByRole("tabpanel");
2899
+ expect(panel).toBe(
2900
+ screen.getByRole("tabpanel", { name: /^Evidence checked/ }),
2901
+ );
2902
+ expect(evidenceTab).toHaveAttribute("aria-controls", panel.id);
2903
+ expect(panel).toHaveAttribute("tabindex", "0");
2904
+ expect(panel).toContainElement(evidenceList());
2905
+ expect(
2906
+ within(evidenceList()).getByRole("button", { name: /Active incidents/ }),
2907
+ ).toBeVisible();
2908
+ expect(
2909
+ within(evidenceList()).getByRole("button", { name: /Logs 17:20/ }),
2910
+ ).toBeVisible();
2911
+ expect(screen.getByTestId("investigation-activity")).not.toBeVisible();
2912
+
2913
+ fireEvent.click(detailsToggle());
2914
+
2915
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "false");
2916
+ expect(detailsBody()).not.toBeVisible();
2917
+ expect(screen.queryByRole("tablist")).toBeNull();
2918
+ expect(screen.queryByRole("tabpanel")).toBeNull();
2919
+ expect(screen.queryByRole("list", { name: "Evidence checked" })).toBeNull();
2920
+ // The header's summary does not depend on the body being open.
2921
+ expect(screen.getByLabelText("Investigation usage")).toBeVisible();
2922
+ });
2923
+
2924
+ test("switches between the evidence and activity tabs", async () => {
2925
+ postMock.mockResolvedValue(structuredResponse() as never);
2926
+
2927
+ renderPanel();
2928
+ await flush();
2929
+ openDetails();
2930
+
2931
+ fireEvent.click(detailsTab(/^Activity/));
2932
+
2933
+ expect(detailsTab(/^Activity/)).toHaveAttribute("aria-selected", "true");
2934
+ expect(detailsTab(/^Evidence checked/)).toHaveAttribute(
2935
+ "aria-selected",
2936
+ "false",
2937
+ );
2938
+ const activityPanel: HTMLElement = screen.getByRole("tabpanel", {
2939
+ name: /^Activity/,
2940
+ });
2941
+ expect(activityPanel).toContainElement(
2942
+ screen.getByTestId("investigation-activity"),
2943
+ );
2944
+ expect(screen.getByTestId("investigation-activity")).toBeVisible();
2945
+ expect(screen.queryByRole("list", { name: "Evidence checked" })).toBeNull();
2946
+
2947
+ // The footer belongs to the body, not to one tab.
2948
+ expect(
2949
+ screen.getByRole("list", { name: "Model and tokens" }),
2950
+ ).toBeVisible();
2951
+
2952
+ fireEvent.click(detailsTab(/^Evidence checked/));
2953
+
2954
+ expect(evidenceList()).toBeVisible();
2955
+ expect(screen.getByTestId("investigation-activity")).not.toBeVisible();
2956
+ });
2957
+
2958
+ /*
2959
+ * The old disclosure advertised the raw event count and showed only the
2960
+ * last ten steps. Several event types only close a step, so the count the
2961
+ * reader sees has to be the steps the feed draws — and a finished run is
2962
+ * short enough to show its whole trail.
2963
+ */
2964
+ test("counts the steps the feed draws and shows the whole finished trail", async () => {
2965
+ const events: JSONArray = [];
2966
+
2967
+ for (let index: number = 0; index < 24; index++) {
2968
+ events.push({
2969
+ _id: `55555555-5555-4555-8555-${String(index).padStart(12, "0")}`,
2970
+ sequence: index + 1,
2971
+ eventType:
2972
+ index % 2 === 0
2973
+ ? AIRunEventType.ToolCallStarted
2974
+ : AIRunEventType.ToolCallCompleted,
2975
+ toolName: "search_logs",
2976
+ createdAt: new Date("2026-08-07T10:00:00.000Z"),
2977
+ });
2978
+ }
2979
+
2980
+ countActivityStepsMock.mockReturnValue(12);
2981
+ postMock.mockResolvedValue(structuredResponse({ events }) as never);
2982
+
2983
+ renderPanel();
2984
+ await flush();
2985
+
2986
+ const usage: HTMLElement = screen.getByLabelText("Investigation usage");
2987
+ expect(usage).toHaveTextContent("12 steps");
2988
+ expect(usage).not.toHaveTextContent("24");
2989
+
2990
+ openDetails();
2991
+
2992
+ expect(tabNames()).toEqual(["Evidence checked2", "Activity12"]);
2993
+ expect(lastActivityProps().events).toHaveLength(24);
2994
+ expect(lastActivityProps()).toEqual(
2995
+ expect.objectContaining({
2996
+ hideChrome: true,
2997
+ showLiveIndicator: false,
2998
+ maxVisibleSteps: 12,
2999
+ }),
3000
+ );
3001
+ });
3002
+
3003
+ /*
3004
+ * Evidence can land on a later poll than the report. A reader who opened
3005
+ * the section onto the activity is reading it; the arriving evidence adds
3006
+ * a tab beside it rather than yanking the view to the new first tab.
3007
+ */
3008
+ test("keeps a reader on the activity when evidence arrives after they opened it", async () => {
3009
+ postMock
3010
+ .mockResolvedValueOnce(completedResponse() as never)
3011
+ .mockResolvedValue(structuredResponse() as never);
3012
+
3013
+ renderPanel();
3014
+ await flush();
3015
+ openDetails();
3016
+
3017
+ expect(detailsToggle()).toHaveTextContent("Investigation activity");
3018
+ expect(screen.queryByRole("tablist")).toBeNull();
3019
+ expect(screen.getByTestId("investigation-activity")).toBeVisible();
3020
+
3021
+ await tick(SETTLED_POLL_INTERVAL_MS);
3022
+
3023
+ expect(detailsToggle()).toHaveTextContent("Evidence and activity");
3024
+ expect(detailsToggle()).toHaveAttribute("aria-expanded", "true");
3025
+ expect(tabNames()).toEqual(["Evidence checked2", "Activity1"]);
3026
+ expect(detailsTab(/^Activity/)).toHaveAttribute("aria-selected", "true");
3027
+ expect(detailsTab(/^Evidence checked/)).toHaveAttribute(
3028
+ "aria-selected",
3029
+ "false",
3030
+ );
3031
+ expect(screen.getByTestId("investigation-activity")).toBeVisible();
3032
+ expect(screen.queryByRole("list", { name: "Evidence checked" })).toBeNull();
3033
+ });
3034
+
3035
+ /*
3036
+ * The counterpart: nobody has looked yet, so there is nothing to keep, and
3037
+ * the section opens on the evidence like any report that has some.
3038
+ */
3039
+ test("opens on the evidence when it arrived before the reader looked", async () => {
3040
+ postMock
3041
+ .mockResolvedValueOnce(completedResponse() as never)
3042
+ .mockResolvedValue(structuredResponse() as never);
3043
+
3044
+ renderPanel();
3045
+ await flush();
3046
+ await tick(SETTLED_POLL_INTERVAL_MS);
3047
+ openDetails();
3048
+
3049
+ expect(detailsTab(/^Evidence checked/)).toHaveAttribute(
3050
+ "aria-selected",
3051
+ "true",
3052
+ );
3053
+ expect(evidenceList()).toBeVisible();
3054
+ });
3055
+ });
3056
+
3057
+ describe("InvestigationPanel report summary callback", () => {
3058
+ function nonNullCalls(callback: MockFunction): Array<unknown> {
3059
+ return callback.mock.calls
3060
+ .map((call: Array<unknown>): unknown => {
3061
+ return call[0];
3062
+ })
3063
+ .filter((value: unknown): boolean => {
3064
+ return value !== null;
3065
+ });
3066
+ }
3067
+
3068
+ test("reports the TL;DR of a completed report", async () => {
3069
+ const onReportSummaryChange: MockFunction = getJestMockFunction();
3070
+ postMock.mockResolvedValue(
3071
+ structuredResponse({ analysisTldr: TLDR }) as never,
3072
+ );
3073
+
3074
+ renderPanel({ onReportSummaryChange });
3075
+ await flush();
3076
+
3077
+ expect(onReportSummaryChange).toHaveBeenLastCalledWith(TLDR);
3078
+ expect(nonNullCalls(onReportSummaryChange)).toEqual([TLDR]);
3079
+ });
3080
+
3081
+ test("falls back to the report's Summary as plain text without a TL;DR", async () => {
3082
+ const onReportSummaryChange: MockFunction = getJestMockFunction();
3083
+ postMock.mockResolvedValue(structuredResponse() as never);
3084
+
3085
+ renderPanel({ onReportSummaryChange });
3086
+ await flush();
3087
+
3088
+ expect(onReportSummaryChange).toHaveBeenLastCalledWith(REPORT_SUMMARY);
3089
+ });
3090
+
3091
+ test("bounds a long Summary", async () => {
3092
+ const onReportSummaryChange: MockFunction = getJestMockFunction();
3093
+ postMock.mockResolvedValue(
3094
+ completedResponse({
3095
+ analysisMarkdown: `**Summary** — ${"pool exhausted ".repeat(60)}\n\n**Root cause** — a deploy.`,
2406
3096
  }) as never,
2407
3097
  );
2408
3098
 
@@ -2410,10 +3100,28 @@ describe("InvestigationPanel report summary callback", () => {
2410
3100
  await flush();
2411
3101
 
2412
3102
  const summary: string = nonNullCalls(onReportSummaryChange)[0] as string;
2413
- expect(summary.length).toBeLessThanOrEqual(280);
3103
+ // Bounded by the analysisTldr column; the header clamps it on screen.
3104
+ expect(summary.length).toBeLessThanOrEqual(500);
3105
+ expect(summary.length).toBeGreaterThan(280);
2414
3106
  expect(summary.endsWith("…")).toBe(true);
2415
3107
  });
2416
3108
 
3109
+ test("reports a TL;DR at the server's 320-character cap whole", async () => {
3110
+ const onReportSummaryChange: MockFunction = getJestMockFunction();
3111
+ const longTldr: string =
3112
+ "checkout-api release 2026.09.14-2 restarted at 17:52:04 with DB_POOL_MAX=10 instead of 40, so requests waited up to 2s in pg.pool.connect for an orders-db connection and p95 latency rose from ~310 ms to 2.35 s (db.client.connections.usage pinned at 10/10). Rolling back to 2026.09.14-1 cleared it, as in #1017 and #1029.";
3113
+
3114
+ expect(longTldr).toHaveLength(320);
3115
+ postMock.mockResolvedValue(
3116
+ structuredResponse({ analysisTldr: longTldr }) as never,
3117
+ );
3118
+
3119
+ renderPanel({ onReportSummaryChange });
3120
+ await flush();
3121
+
3122
+ expect(nonNullCalls(onReportSummaryChange)).toEqual([longTldr]);
3123
+ });
3124
+
2417
3125
  test("reports null when a report has neither a TL;DR nor a Summary", async () => {
2418
3126
  const onReportSummaryChange: MockFunction = getJestMockFunction();
2419
3127
  postMock.mockResolvedValue(completedResponse() as never);
@@ -2561,3 +3269,333 @@ describe("InvestigationPanel report summary callback", () => {
2561
3269
  expect(second).toHaveBeenLastCalledWith("A newer summary.");
2562
3270
  });
2563
3271
  });
3272
+
3273
+ /*
3274
+ * The header shows a responder's verdict next to the report's summary, so the
3275
+ * panel reports it on the summary's terms: once per change, null until a
3276
+ * report is on screen, and afresh for every subject.
3277
+ */
3278
+ describe("InvestigationPanel verdict callback", () => {
3279
+ function reportedVerdicts(callback: MockFunction): Array<unknown> {
3280
+ return callback.mock.calls.map((call: Array<unknown>): unknown => {
3281
+ return call[0];
3282
+ });
3283
+ }
3284
+
3285
+ function nonNullVerdicts(callback: MockFunction): Array<unknown> {
3286
+ return reportedVerdicts(callback).filter((value: unknown): boolean => {
3287
+ return value !== null;
3288
+ });
3289
+ }
3290
+
3291
+ test.each(Object.values(AIRunHumanVerdict))(
3292
+ "reports a %s verdict saved with the completed report",
3293
+ async (verdict: AIRunHumanVerdict) => {
3294
+ const onVerdictChange: MockFunction = getJestMockFunction();
3295
+ postMock.mockResolvedValue(
3296
+ structuredResponse({ humanVerdict: verdict }) as never,
3297
+ );
3298
+
3299
+ renderPanel({ onVerdictChange });
3300
+ await flush();
3301
+
3302
+ expect(onVerdictChange).toHaveBeenLastCalledWith(verdict);
3303
+ expect(nonNullVerdicts(onVerdictChange)).toEqual([verdict]);
3304
+ },
3305
+ );
3306
+
3307
+ test("reports null for a report nobody has rated", async () => {
3308
+ const onVerdictChange: MockFunction = getJestMockFunction();
3309
+ postMock.mockResolvedValue(structuredResponse() as never);
3310
+
3311
+ renderPanel({ onVerdictChange });
3312
+ await flush();
3313
+
3314
+ expect(onVerdictChange).toHaveBeenCalledWith(null);
3315
+ expect(nonNullVerdicts(onVerdictChange)).toEqual([]);
3316
+ });
3317
+
3318
+ test("reports no verdict it cannot name", async () => {
3319
+ const onVerdictChange: MockFunction = getJestMockFunction();
3320
+ postMock.mockResolvedValue(
3321
+ structuredResponse({ humanVerdict: "Edited" }) as never,
3322
+ );
3323
+
3324
+ renderPanel({ onVerdictChange });
3325
+ await flush();
3326
+
3327
+ expect(nonNullVerdicts(onVerdictChange)).toEqual([]);
3328
+ });
3329
+
3330
+ test.each([
3331
+ [
3332
+ "while a new run is in flight",
3333
+ (): ApiResponse => {
3334
+ return successfulResponse(
3335
+ investigationPayload({
3336
+ status: AIRunStatus.Running,
3337
+ humanVerdict: AIRunHumanVerdict.Confirmed,
3338
+ }),
3339
+ );
3340
+ },
3341
+ ],
3342
+ [
3343
+ "while the report is still being prepared",
3344
+ (): ApiResponse => {
3345
+ return completedResponse({
3346
+ analysisMarkdown: null,
3347
+ isAnalysisPending: true,
3348
+ humanVerdict: AIRunHumanVerdict.Confirmed,
3349
+ });
3350
+ },
3351
+ ],
3352
+ ])(
3353
+ "reports no verdict %s",
3354
+ async (_label: string, response: () => ApiResponse) => {
3355
+ const onVerdictChange: MockFunction = getJestMockFunction();
3356
+ postMock.mockResolvedValue(response() as never);
3357
+
3358
+ renderPanel({ onVerdictChange });
3359
+ await flush();
3360
+
3361
+ expect(nonNullVerdicts(onVerdictChange)).toEqual([]);
3362
+ },
3363
+ );
3364
+
3365
+ test("reports a rating the moment it is made, and a changed one", async () => {
3366
+ const onVerdictChange: MockFunction = getJestMockFunction();
3367
+ postMock
3368
+ .mockResolvedValueOnce(structuredResponse() as never)
3369
+ .mockResolvedValueOnce(successfulResponse({}) as never)
3370
+ .mockResolvedValueOnce(successfulResponse({}) as never);
3371
+
3372
+ renderPanel({ onVerdictChange });
3373
+ await flush();
3374
+ expect(nonNullVerdicts(onVerdictChange)).toEqual([]);
3375
+
3376
+ fireEvent.click(screen.getByRole("button", { name: "Confirmed" }));
3377
+ // Optimistic, like the panel's own pill: before the save resolves.
3378
+ expect(onVerdictChange).toHaveBeenLastCalledWith(
3379
+ AIRunHumanVerdict.Confirmed,
3380
+ );
3381
+ await flush();
3382
+
3383
+ fireEvent.click(screen.getByRole("button", { name: "Change" }));
3384
+ fireEvent.click(screen.getByRole("button", { name: "Rejected" }));
3385
+ await flush();
3386
+
3387
+ expect(nonNullVerdicts(onVerdictChange)).toEqual([
3388
+ AIRunHumanVerdict.Confirmed,
3389
+ AIRunHumanVerdict.Rejected,
3390
+ ]);
3391
+ expect(onVerdictChange).toHaveBeenLastCalledWith(
3392
+ AIRunHumanVerdict.Rejected,
3393
+ );
3394
+ });
3395
+
3396
+ test("takes a rating back out when the save fails", async () => {
3397
+ const onVerdictChange: MockFunction = getJestMockFunction();
3398
+ postMock
3399
+ .mockResolvedValueOnce(structuredResponse() as never)
3400
+ .mockResolvedValueOnce(
3401
+ new HTTPErrorResponse(
3402
+ 500,
3403
+ { message: "Verdict storage is unavailable." },
3404
+ {},
3405
+ ) as never,
3406
+ );
3407
+
3408
+ renderPanel({ onVerdictChange });
3409
+ await flush();
3410
+ fireEvent.click(screen.getByRole("button", { name: "Rejected" }));
3411
+ await flush();
3412
+
3413
+ expect(screen.getByRole("alert")).toHaveTextContent(
3414
+ "Could not save your verdict",
3415
+ );
3416
+ expect(nonNullVerdicts(onVerdictChange)).toEqual([
3417
+ AIRunHumanVerdict.Rejected,
3418
+ ]);
3419
+ expect(onVerdictChange).toHaveBeenLastCalledWith(null);
3420
+ });
3421
+
3422
+ test("a poll started before a rating saved cannot flip the reported verdict", async () => {
3423
+ const onVerdictChange: MockFunction = getJestMockFunction();
3424
+ const stalePoll: Deferred<ApiResponse> = createDeferred<ApiResponse>();
3425
+ postMock
3426
+ .mockResolvedValueOnce(structuredResponse() as never)
3427
+ .mockReturnValueOnce(stalePoll.promise as never)
3428
+ .mockResolvedValueOnce(successfulResponse({}) as never);
3429
+
3430
+ renderPanel({ onVerdictChange });
3431
+ await flush();
3432
+ await tick(SETTLED_POLL_INTERVAL_MS);
3433
+ expect(postMock).toHaveBeenCalledTimes(2);
3434
+
3435
+ fireEvent.click(screen.getByRole("button", { name: "Confirmed" }));
3436
+ await flush();
3437
+ const callsAfterRating: number = onVerdictChange.mock.calls.length;
3438
+
3439
+ await resolveDeferred(
3440
+ stalePoll,
3441
+ structuredResponse({ humanVerdict: null }),
3442
+ );
3443
+
3444
+ expect(onVerdictChange).toHaveBeenCalledTimes(callsAfterRating);
3445
+ expect(onVerdictChange).toHaveBeenLastCalledWith(
3446
+ AIRunHumanVerdict.Confirmed,
3447
+ );
3448
+ });
3449
+
3450
+ test("follows a verdict another responder saves", async () => {
3451
+ const onVerdictChange: MockFunction = getJestMockFunction();
3452
+ postMock
3453
+ .mockResolvedValueOnce(structuredResponse() as never)
3454
+ .mockResolvedValue(
3455
+ structuredResponse({
3456
+ humanVerdict: AIRunHumanVerdict.Rejected,
3457
+ }) as never,
3458
+ );
3459
+
3460
+ renderPanel({ onVerdictChange });
3461
+ await flush();
3462
+ expect(nonNullVerdicts(onVerdictChange)).toEqual([]);
3463
+
3464
+ await tick(SETTLED_POLL_INTERVAL_MS);
3465
+
3466
+ expect(onVerdictChange).toHaveBeenLastCalledWith(
3467
+ AIRunHumanVerdict.Rejected,
3468
+ );
3469
+ });
3470
+
3471
+ test("does not repeat an unchanged verdict across polls", async () => {
3472
+ const onVerdictChange: MockFunction = getJestMockFunction();
3473
+ postMock.mockResolvedValue(
3474
+ structuredResponse({
3475
+ humanVerdict: AIRunHumanVerdict.Confirmed,
3476
+ }) as never,
3477
+ );
3478
+
3479
+ renderPanel({ onVerdictChange });
3480
+ await flush();
3481
+ const callsAfterLoad: number = onVerdictChange.mock.calls.length;
3482
+
3483
+ await tick(SETTLED_POLL_INTERVAL_MS);
3484
+ await tick(SETTLED_POLL_INTERVAL_MS);
3485
+
3486
+ expect(investigationPostCount()).toBe(3);
3487
+ expect(onVerdictChange).toHaveBeenCalledTimes(callsAfterLoad);
3488
+ expect(nonNullVerdicts(onVerdictChange)).toEqual([
3489
+ AIRunHumanVerdict.Confirmed,
3490
+ ]);
3491
+ });
3492
+
3493
+ test("drops the verdict when a new run starts", async () => {
3494
+ const onVerdictChange: MockFunction = getJestMockFunction();
3495
+ postMock
3496
+ .mockResolvedValueOnce(
3497
+ structuredResponse({
3498
+ humanVerdict: AIRunHumanVerdict.Confirmed,
3499
+ }) as never,
3500
+ )
3501
+ .mockResolvedValue(
3502
+ successfulResponse(
3503
+ investigationPayload({
3504
+ status: AIRunStatus.Queued,
3505
+ runId: NEXT_RUN_ID,
3506
+ }),
3507
+ ) as never,
3508
+ );
3509
+
3510
+ renderPanel({ onVerdictChange });
3511
+ await flush();
3512
+ expect(onVerdictChange).toHaveBeenLastCalledWith(
3513
+ AIRunHumanVerdict.Confirmed,
3514
+ );
3515
+
3516
+ await tick(SETTLED_POLL_INTERVAL_MS);
3517
+
3518
+ expect(onVerdictChange).toHaveBeenLastCalledWith(null);
3519
+ });
3520
+
3521
+ test("reports null the moment the subject changes, then the new verdict", async () => {
3522
+ const onVerdictChange: MockFunction = getJestMockFunction();
3523
+ const nextSubject: Deferred<ApiResponse> = createDeferred<ApiResponse>();
3524
+ postMock
3525
+ .mockResolvedValueOnce(
3526
+ structuredResponse({
3527
+ humanVerdict: AIRunHumanVerdict.Confirmed,
3528
+ }) as never,
3529
+ )
3530
+ .mockReturnValueOnce(nextSubject.promise as never);
3531
+
3532
+ const view: ReturnType<typeof render> = renderPanel({ onVerdictChange });
3533
+ await flush();
3534
+ expect(onVerdictChange).toHaveBeenLastCalledWith(
3535
+ AIRunHumanVerdict.Confirmed,
3536
+ );
3537
+
3538
+ view.rerender(
3539
+ <InvestigationPanel
3540
+ subjectType="alert"
3541
+ subjectId={ALERT_ID}
3542
+ onVerdictChange={onVerdictChange}
3543
+ />,
3544
+ );
3545
+ await flush();
3546
+
3547
+ // Before the alert's report arrives, and without a stale confirmation.
3548
+ expect(onVerdictChange).toHaveBeenLastCalledWith(null);
3549
+
3550
+ await resolveDeferred(
3551
+ nextSubject,
3552
+ structuredResponse({
3553
+ runId: NEXT_RUN_ID,
3554
+ humanVerdict: AIRunHumanVerdict.Rejected,
3555
+ }),
3556
+ );
3557
+
3558
+ expect(onVerdictChange).toHaveBeenLastCalledWith(
3559
+ AIRunHumanVerdict.Rejected,
3560
+ );
3561
+ expect(nonNullVerdicts(onVerdictChange)).toEqual([
3562
+ AIRunHumanVerdict.Confirmed,
3563
+ AIRunHumanVerdict.Rejected,
3564
+ ]);
3565
+ });
3566
+
3567
+ test("uses the latest callback without re-reporting", async () => {
3568
+ const first: MockFunction = getJestMockFunction();
3569
+ const second: MockFunction = getJestMockFunction();
3570
+ postMock.mockResolvedValue(
3571
+ structuredResponse({
3572
+ humanVerdict: AIRunHumanVerdict.Confirmed,
3573
+ }) as never,
3574
+ );
3575
+
3576
+ const view: ReturnType<typeof render> = renderPanel({
3577
+ onVerdictChange: first,
3578
+ });
3579
+ await flush();
3580
+ expect(first).toHaveBeenLastCalledWith(AIRunHumanVerdict.Confirmed);
3581
+ const firstCallCount: number = first.mock.calls.length;
3582
+
3583
+ view.rerender(
3584
+ <InvestigationPanel
3585
+ subjectType="incident"
3586
+ subjectId={INCIDENT_ID}
3587
+ onVerdictChange={second}
3588
+ />,
3589
+ );
3590
+ await flush();
3591
+ expect(second).not.toHaveBeenCalled();
3592
+
3593
+ postMock.mockResolvedValue(
3594
+ structuredResponse({ humanVerdict: AIRunHumanVerdict.Rejected }) as never,
3595
+ );
3596
+ await tick(SETTLED_POLL_INTERVAL_MS);
3597
+
3598
+ expect(reportedVerdicts(second)).toEqual([AIRunHumanVerdict.Rejected]);
3599
+ expect(first).toHaveBeenCalledTimes(firstCallCount);
3600
+ });
3601
+ });