@oneuptime/common 13.0.7 → 13.0.8

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 (463) hide show
  1. package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +1 -1
  2. package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +1 -1
  3. package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +1 -1
  4. package/Server/API/AIBillingAPI.ts +1 -0
  5. package/Server/API/AIInsightAPI.ts +1 -4
  6. package/Server/API/AIInvestigationAPI.ts +1 -4
  7. package/Server/API/AIReadinessAPI.ts +4 -5
  8. package/Server/API/AlertAPI.ts +1 -0
  9. package/Server/API/AutoRemediationAPI.ts +1 -4
  10. package/Server/API/BaseAPI.ts +13 -0
  11. package/Server/API/BaseAnalyticsAPI.ts +80 -9
  12. package/Server/API/BillingAPI.ts +2 -0
  13. package/Server/API/BillingInvoiceAPI.ts +1 -0
  14. package/Server/API/BillingPaymentMethodAPI.ts +2 -0
  15. package/Server/API/CodeFixRunAPI.ts +1 -3
  16. package/Server/API/CommonAPI.ts +68 -4
  17. package/Server/API/DashboardAPI.ts +12 -12
  18. package/Server/API/GlobalConfigAPI.ts +17 -0
  19. package/Server/API/IncidentAPI.ts +2 -0
  20. package/Server/API/IncidentEpisodeAPI.ts +1 -0
  21. package/Server/API/NotificationAPI.ts +1 -0
  22. package/Server/API/OnCallCalendarAPI.ts +4 -5
  23. package/Server/API/OnCallDutyPolicyAPI.ts +7 -0
  24. package/Server/API/OnCallReadinessAPI.ts +4 -1
  25. package/Server/API/OnCallScheduleTimelineAPI.ts +731 -0
  26. package/Server/API/ProjectAPI.ts +1 -0
  27. package/Server/API/ScheduledMaintenanceAPI.ts +1 -0
  28. package/Server/API/StatusPageAPI.ts +161 -32
  29. package/Server/API/TeamMemberAPI.ts +3 -0
  30. package/Server/API/UserCallAPI.ts +2 -0
  31. package/Server/API/UserEmailAPI.ts +2 -0
  32. package/Server/API/UserIncomingCallNumberAPI.ts +2 -0
  33. package/Server/API/UserMicrosoftTeamsAPI.ts +1 -0
  34. package/Server/API/UserSlackAPI.ts +1 -0
  35. package/Server/API/UserSmsAPI.ts +2 -0
  36. package/Server/API/UserTotpAuthAPI.ts +1 -0
  37. package/Server/API/UserWebAuthnAPI.ts +2 -0
  38. package/Server/API/UserWebhookAPI.ts +1 -0
  39. package/Server/API/UserWhatsAppAPI.ts +2 -0
  40. package/Server/Middleware/MasterAdminAuthorization.ts +13 -2
  41. package/Server/Middleware/UserAuthorization.ts +79 -5
  42. package/Server/Services/ApiKeyPermissionService.ts +101 -4
  43. package/Server/Services/DatabaseService.ts +245 -0
  44. package/Server/Services/DetectionRuleService.ts +5 -4
  45. package/Server/Services/OnCallDutyPolicyChildService.ts +261 -0
  46. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -2
  47. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -2
  48. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -2
  49. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -2
  50. package/Server/Services/PayAsYouGoBillingService.ts +23 -28
  51. package/Server/Services/ProjectService.ts +18 -0
  52. package/Server/Services/RumSessionPinService.ts +274 -22
  53. package/Server/Services/TeamPermissionService.ts +120 -26
  54. package/Server/Services/ThreatIntelFeedService.ts +6 -3
  55. package/Server/Types/Database/Permissions/BasePermission.ts +9 -7
  56. package/Server/Types/Database/Permissions/Index.ts +75 -11
  57. package/Server/Types/Database/Permissions/TablePermission.ts +24 -28
  58. package/Server/Utils/AI/AIChatPrivacyFilter.ts +8 -0
  59. package/Server/Utils/AI/AIRunPrivacyFilter.ts +8 -0
  60. package/Server/Utils/MasterAdminPageAccess.ts +61 -0
  61. package/Server/Utils/Monitor/MonitorAlert.ts +3 -1
  62. package/Server/Utils/Monitor/MonitorIncident.ts +3 -1
  63. package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1 -1
  64. package/Server/Utils/Realtime.ts +163 -45
  65. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +11 -28
  66. package/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.ts +170 -0
  67. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +1 -1
  68. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +6 -2
  69. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.ts +10 -9
  70. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +1059 -0
  71. package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +376 -0
  72. package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +757 -0
  73. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +307 -0
  74. package/Tests/App/Dashboard/ArgumentsFormGroupByUnlistedAttributes.test.tsx +131 -0
  75. package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +1 -1
  76. package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +9 -1
  77. package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +24 -0
  78. package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +162 -8
  79. package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +105 -6
  80. package/Tests/App/Dashboard/EntityFilterDropdownUnlistedSelection.test.tsx +434 -0
  81. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +276 -1
  82. package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +9 -1
  83. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +58 -42
  84. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +42 -5
  85. package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +34 -23
  86. package/Tests/App/Dashboard/ScheduleTimeline.test.tsx +1580 -0
  87. package/Tests/App/Dashboard/ScheduleTimelineAPI.test.ts +280 -0
  88. package/Tests/App/Dashboard/ScheduleTimelineModel.test.ts +673 -0
  89. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +95 -68
  90. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +86 -3
  91. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +28 -3
  92. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +761 -0
  93. package/Tests/App/Dashboard/SecurityEventsGuideContent.test.ts +1313 -0
  94. package/Tests/App/Dashboard/SecurityEventsHowItWorksCard.test.tsx +536 -0
  95. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +222 -0
  96. package/Tests/App/Dashboard/SecurityEventsThreatIntelPage.test.tsx +199 -0
  97. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +321 -0
  98. package/Tests/App/Dashboard/SloOverviewHero.test.tsx +171 -36
  99. package/Tests/App/Dashboard/SloViewSideMenu.test.tsx +215 -0
  100. package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +40 -3
  101. package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +12 -4
  102. package/Tests/App/PublicDashboard/PublicDashboardWidgetListAuth.test.tsx +623 -0
  103. package/Tests/Models/OnCallCalendarFeedModels.test.ts +23 -1
  104. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +138 -5
  105. package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +187 -0
  106. package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +51 -3
  107. package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +55 -2
  108. package/Tests/Server/API/BaseAnalyticsAPIAggregateCache.test.ts +729 -0
  109. package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +93 -7
  110. package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +36 -3
  111. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +1003 -24
  112. package/Tests/Server/API/DashboardPublicRateLimit.test.ts +6 -3
  113. package/Tests/Server/API/ExpiredSessionAIRoutes.test.ts +708 -0
  114. package/Tests/Server/API/ExpiredSessionCustomRoutes.test.ts +928 -0
  115. package/Tests/Server/API/ExpiredSessionMonitorTemplate.test.ts +319 -0
  116. package/Tests/Server/API/ExpiredSessionOnCallDutyPolicy.test.ts +336 -0
  117. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +820 -0
  118. package/Tests/Server/API/GlobalConfigLicense.test.ts +140 -0
  119. package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +115 -12
  120. package/Tests/Server/API/OnCallCalendarAPI.test.ts +375 -8
  121. package/Tests/Server/API/OnCallReadinessAPI.test.ts +175 -17
  122. package/Tests/Server/API/OnCallScheduleTimelineAPI.test.ts +1513 -0
  123. package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +119 -7
  124. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +111 -4
  125. package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +615 -0
  126. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +89 -2
  127. package/Tests/Server/API/SessionReplayAPI.test.ts +121 -0
  128. package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +4 -2
  129. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +441 -0
  130. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +664 -0
  131. package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +7 -0
  132. package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +6 -0
  133. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +65 -4
  134. package/Tests/Server/API/UserProjectsAPI.test.ts +63 -3
  135. package/Tests/Server/API/UserTotpAuthAPI.test.ts +48 -2
  136. package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +11 -2
  137. package/Tests/Server/API/UserWebAuthnBackupCodeMinting.test.ts +46 -3
  138. package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +18 -2
  139. package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +24 -7
  140. package/Tests/Server/Middleware/ExpiredSessionUserMiddleware.test.ts +563 -0
  141. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +299 -19
  142. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +453 -0
  143. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +24 -0
  144. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +2 -0
  145. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +3 -3
  146. package/Tests/Server/Services/DatabaseServiceCreateSuppliedId.test.ts +147 -0
  147. package/Tests/Server/Services/DatabaseServiceLoginBeforeHooks.test.ts +1078 -0
  148. package/Tests/Server/Services/DatabaseServiceTenantRelationGuard.test.ts +259 -0
  149. package/Tests/Server/Services/DatabaseServiceWriteOperatorValues.test.ts +147 -0
  150. package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +115 -1
  151. package/Tests/Server/Services/OnCallChildCreateAuthorizationPostgres.test.ts +711 -0
  152. package/Tests/Server/Services/OnCallDutyPolicyChildService.test.ts +733 -0
  153. package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +190 -140
  154. package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +4 -9
  155. package/Tests/Server/Services/PermissionBlockDeletion.test.ts +780 -0
  156. package/Tests/Server/Services/PermissionBlockDeletionPostgres.test.ts +628 -0
  157. package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +77 -1
  158. package/Tests/Server/Services/RumSessionPinCreatePermission.test.ts +715 -0
  159. package/Tests/Server/Services/TeamMemberMultiTenantReadPostgres.test.ts +394 -0
  160. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +6 -0
  161. package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +131 -0
  162. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +13 -2
  163. package/Tests/Server/Types/Database/Permissions/ModelPermissionAnonymousRefusal.test.ts +518 -0
  164. package/Tests/Server/Types/Database/Permissions/MultiTenantPermissions.test.ts +350 -0
  165. package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +282 -25
  166. package/Tests/Server/Types/Database/Permissions/TableLevelBlockPermission.test.ts +459 -0
  167. package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +101 -9
  168. package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +88 -4
  169. package/Tests/Server/Utils/AI/Toolbox/ExceptionTools.test.ts +459 -0
  170. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +794 -0
  171. package/Tests/Server/Utils/AI/Toolbox/RecentChangesTools.test.ts +574 -0
  172. package/Tests/Server/Utils/AI/Toolbox/SecurityEventTools.test.ts +596 -0
  173. package/Tests/Server/Utils/CaptchaRequestAndLogging.test.ts +395 -0
  174. package/Tests/Server/Utils/MasterAdminPageAccess.test.ts +251 -0
  175. package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +616 -0
  176. package/Tests/Server/Utils/Realtime.test.ts +502 -0
  177. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorSeverity.test.ts +216 -0
  178. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +142 -0
  179. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.test.ts +140 -0
  180. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepairClickhouseIntegration.test.ts +542 -0
  181. package/Tests/Server/Utils/Telemetry/ChangeEventRow.test.ts +743 -0
  182. package/Tests/Server/Utils/Telemetry/RuntimeMetrics.test.ts +465 -0
  183. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.test.ts +202 -0
  184. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.test.ts +194 -0
  185. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.test.ts +231 -0
  186. package/Tests/Server/Utils/Workspace/Slack/Messages/Alert.test.ts +194 -0
  187. package/Tests/Server/Utils/Workspace/Slack/Messages/AlertEpisode.test.ts +194 -0
  188. package/Tests/Server/Utils/Workspace/Slack/Messages/Incident.test.ts +194 -0
  189. package/Tests/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.test.ts +194 -0
  190. package/Tests/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.test.ts +247 -0
  191. package/Tests/Types/AI/AIInsightEvidence.test.ts +206 -0
  192. package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtilAnonymous.test.ts +144 -0
  193. package/Tests/Types/Call/CallProvider.test.ts +528 -0
  194. package/Tests/Types/Kubernetes/KubernetesCostIngest.test.ts +236 -0
  195. package/Tests/Types/OnCallDutyPolicy/ScheduleTimeline.test.ts +736 -0
  196. package/Tests/Types/OnCallDutyPolicy/ScheduleTimelineLayout.test.ts +996 -0
  197. package/Tests/Types/SecurityEvent/SigmaRule.test.ts +142 -0
  198. package/Tests/Types/Workflow/Components/JSON.test.ts +182 -0
  199. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +116 -1
  200. package/Tests/UI/Components/Dropdown/DropdownAsyncOptions.test.tsx +81 -0
  201. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +89 -1
  202. package/Tests/UI/Components/EventAttachmentList.test.tsx +174 -0
  203. package/Tests/UI/Components/Forms/BasicFormBurnRateTemplateDefaults.test.tsx +395 -0
  204. package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +286 -0
  205. package/Tests/UI/Components/Forms/FormSummary.test.tsx +128 -0
  206. package/Tests/UI/Components/ModelTable/BaseModelTableQueryChange.test.tsx +365 -0
  207. package/Tests/UI/Components/OpenAuthenticatedUrl.test.ts +358 -0
  208. package/Tests/UI/Components/SessionAwareImage.test.tsx +496 -0
  209. package/Tests/UI/Components/TelemetryHistogramZeroBuckets.test.tsx +190 -0
  210. package/Tests/UI/Components/TooltipInteractive.test.tsx +97 -0
  211. package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardInstallGuidance.test.tsx +1 -1
  212. package/Tests/UI/Monitor/EvaluationLogListTimestamps.test.tsx +367 -0
  213. package/Tests/UI/Utils/API/BaseAPIRefreshSession.test.ts +1087 -0
  214. package/Tests/UI/Utils/API/DashboardHost.ts +12 -0
  215. package/Tests/UI/Utils/API/FakeAxiosServer.ts +183 -0
  216. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
  217. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  218. package/Tests/UI/Utils/Cookie.test.ts +440 -0
  219. package/Tests/UI/Utils/ModelAPIRequestClient.test.ts +278 -0
  220. package/Tests/UI/Utils/Navigation.test.ts +33 -0
  221. package/Tests/UI/Utils/PricingPlan.test.ts +295 -0
  222. package/Tests/UI/Utils/Realtime.test.ts +759 -0
  223. package/Tests/UI/Utils/Telemetry/Telemetry.test.ts +500 -0
  224. package/Tests/Utils/APIInstanceDispatch.test.ts +311 -0
  225. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizerSeverity.test.ts +565 -0
  226. package/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.ts +40 -0
  227. package/Types/Monitor/MonitorEvaluationSummary.ts +3 -0
  228. package/Types/OnCallDutyPolicy/ScheduleTimeline.ts +507 -0
  229. package/Types/OnCallDutyPolicy/ScheduleTimelineLayout.ts +589 -0
  230. package/Types/Realtime/EventName.ts +11 -0
  231. package/Types/SecurityEvent/DetectionFindingConstants.ts +14 -0
  232. package/Types/SecurityEvent/OcsfSeverity.ts +31 -26
  233. package/Types/SecurityEvent/SigmaRule.ts +51 -0
  234. package/Types/SecurityEvent/ThreatIntelConstants.ts +18 -0
  235. package/UI/Components/AttachmentList/EventAttachmentList.tsx +30 -2
  236. package/UI/Components/Dashboard/DashboardVariableControl.tsx +12 -2
  237. package/UI/Components/Dropdown/Dropdown.tsx +6 -1
  238. package/UI/Components/EditionLabel/EditionLabel.tsx +12 -0
  239. package/UI/Components/EventItem/EventItem.tsx +12 -1
  240. package/UI/Components/Forms/BasicForm.tsx +151 -126
  241. package/UI/Components/Forms/CollapsibleFormSection.tsx +63 -0
  242. package/UI/Components/Forms/Fields/FormField.tsx +10 -4
  243. package/UI/Components/Forms/FormSummary.tsx +7 -0
  244. package/UI/Components/Forms/Types/Field.ts +10 -0
  245. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +2 -1
  246. package/UI/Components/Markdown.tsx/SessionAwareImage.tsx +122 -0
  247. package/UI/Components/ModelTable/BaseModelTable.tsx +34 -5
  248. package/UI/Components/ModelTable/TableView.tsx +1 -1
  249. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +8 -1
  250. package/UI/Components/Tooltip/Tooltip.tsx +8 -1
  251. package/UI/Utils/API/API.ts +173 -12
  252. package/UI/Utils/API/RequestOptions.ts +11 -0
  253. package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +31 -7
  254. package/UI/Utils/ModelAPI/ModelAPI.ts +30 -9
  255. package/UI/Utils/Navigation.ts +9 -0
  256. package/UI/Utils/OpenAuthenticatedUrl.ts +154 -0
  257. package/UI/Utils/Realtime.ts +176 -30
  258. package/Utils/API.ts +14 -5
  259. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +157 -7
  260. package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +9 -17
  261. package/Utils/Slo/SloBurnRateTemplate.ts +2 -2
  262. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +1 -1
  263. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -1
  264. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +1 -1
  265. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -1
  266. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +1 -1
  267. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -1
  268. package/build/dist/Server/API/AIBillingAPI.js +1 -1
  269. package/build/dist/Server/API/AIBillingAPI.js.map +1 -1
  270. package/build/dist/Server/API/AIInsightAPI.js +1 -4
  271. package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
  272. package/build/dist/Server/API/AIInvestigationAPI.js +1 -4
  273. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  274. package/build/dist/Server/API/AIReadinessAPI.js +1 -3
  275. package/build/dist/Server/API/AIReadinessAPI.js.map +1 -1
  276. package/build/dist/Server/API/AlertAPI.js +1 -1
  277. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  278. package/build/dist/Server/API/AutoRemediationAPI.js +1 -4
  279. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  280. package/build/dist/Server/API/BaseAPI.js +12 -0
  281. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  282. package/build/dist/Server/API/BaseAnalyticsAPI.js +55 -10
  283. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  284. package/build/dist/Server/API/BillingAPI.js +2 -2
  285. package/build/dist/Server/API/BillingAPI.js.map +1 -1
  286. package/build/dist/Server/API/BillingInvoiceAPI.js +1 -1
  287. package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
  288. package/build/dist/Server/API/BillingPaymentMethodAPI.js +2 -2
  289. package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
  290. package/build/dist/Server/API/CodeFixRunAPI.js +1 -3
  291. package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
  292. package/build/dist/Server/API/CommonAPI.js +50 -5
  293. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  294. package/build/dist/Server/API/DashboardAPI.js +12 -12
  295. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  296. package/build/dist/Server/API/GlobalConfigAPI.js +12 -0
  297. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  298. package/build/dist/Server/API/IncidentAPI.js +2 -2
  299. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  300. package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
  301. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  302. package/build/dist/Server/API/NotificationAPI.js +1 -1
  303. package/build/dist/Server/API/NotificationAPI.js.map +1 -1
  304. package/build/dist/Server/API/OnCallCalendarAPI.js +1 -4
  305. package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -1
  306. package/build/dist/Server/API/OnCallDutyPolicyAPI.js +6 -0
  307. package/build/dist/Server/API/OnCallDutyPolicyAPI.js.map +1 -1
  308. package/build/dist/Server/API/OnCallReadinessAPI.js +4 -1
  309. package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -1
  310. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +494 -0
  311. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -0
  312. package/build/dist/Server/API/ProjectAPI.js +1 -1
  313. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  314. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
  315. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  316. package/build/dist/Server/API/StatusPageAPI.js +125 -33
  317. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  318. package/build/dist/Server/API/TeamMemberAPI.js +3 -3
  319. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  320. package/build/dist/Server/API/UserCallAPI.js +2 -2
  321. package/build/dist/Server/API/UserCallAPI.js.map +1 -1
  322. package/build/dist/Server/API/UserEmailAPI.js +2 -2
  323. package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
  324. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +2 -2
  325. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
  326. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +1 -1
  327. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -1
  328. package/build/dist/Server/API/UserSlackAPI.js +1 -1
  329. package/build/dist/Server/API/UserSlackAPI.js.map +1 -1
  330. package/build/dist/Server/API/UserSmsAPI.js +2 -2
  331. package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
  332. package/build/dist/Server/API/UserTotpAuthAPI.js +1 -1
  333. package/build/dist/Server/API/UserTotpAuthAPI.js.map +1 -1
  334. package/build/dist/Server/API/UserWebAuthnAPI.js +2 -2
  335. package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
  336. package/build/dist/Server/API/UserWebhookAPI.js +1 -1
  337. package/build/dist/Server/API/UserWebhookAPI.js.map +1 -1
  338. package/build/dist/Server/API/UserWhatsAppAPI.js +2 -2
  339. package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
  340. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -2
  341. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  342. package/build/dist/Server/Middleware/UserAuthorization.js +64 -4
  343. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  344. package/build/dist/Server/Services/ApiKeyPermissionService.js +80 -4
  345. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  346. package/build/dist/Server/Services/DatabaseService.js +171 -0
  347. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  348. package/build/dist/Server/Services/DetectionRuleService.js +4 -4
  349. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  350. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js +170 -0
  351. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js.map +1 -0
  352. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -2
  353. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  354. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +2 -2
  355. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  356. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -2
  357. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  358. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -2
  359. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  360. package/build/dist/Server/Services/PayAsYouGoBillingService.js +20 -27
  361. package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -1
  362. package/build/dist/Server/Services/ProjectService.js +17 -0
  363. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  364. package/build/dist/Server/Services/RumSessionPinService.js +180 -16
  365. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  366. package/build/dist/Server/Services/TeamPermissionService.js +89 -27
  367. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  368. package/build/dist/Server/Services/ThreatIntelFeedService.js +5 -4
  369. package/build/dist/Server/Services/ThreatIntelFeedService.js.map +1 -1
  370. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +9 -6
  371. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  372. package/build/dist/Server/Types/Database/Permissions/Index.js +60 -6
  373. package/build/dist/Server/Types/Database/Permissions/Index.js.map +1 -1
  374. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +14 -13
  375. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  376. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +7 -0
  377. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -1
  378. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +7 -0
  379. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -1
  380. package/build/dist/Server/Utils/MasterAdminPageAccess.js +39 -0
  381. package/build/dist/Server/Utils/MasterAdminPageAccess.js.map +1 -0
  382. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +3 -1
  383. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  384. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +3 -1
  385. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  386. package/build/dist/Server/Utils/Realtime.js +126 -37
  387. package/build/dist/Server/Utils/Realtime.js.map +1 -1
  388. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +7 -25
  389. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  390. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js +127 -0
  391. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js.map +1 -0
  392. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +1 -1
  393. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  394. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +3 -2
  395. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js.map +1 -1
  396. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js +4 -8
  397. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js.map +1 -1
  398. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js +31 -1
  399. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js.map +1 -1
  400. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js +321 -0
  401. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js.map +1 -0
  402. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js +372 -0
  403. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js.map +1 -0
  404. package/build/dist/Types/Realtime/EventName.js +10 -0
  405. package/build/dist/Types/Realtime/EventName.js.map +1 -1
  406. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +11 -0
  407. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  408. package/build/dist/Types/SecurityEvent/OcsfSeverity.js +30 -25
  409. package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -1
  410. package/build/dist/Types/SecurityEvent/SigmaRule.js +47 -0
  411. package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -1
  412. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js +14 -0
  413. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js.map +1 -1
  414. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js +9 -4
  415. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js.map +1 -1
  416. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +10 -2
  417. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -1
  418. package/build/dist/UI/Components/Dropdown/Dropdown.js +5 -1
  419. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  420. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +11 -0
  421. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  422. package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
  423. package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
  424. package/build/dist/UI/Components/Forms/BasicForm.js +70 -64
  425. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  426. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +27 -0
  427. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -0
  428. package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -7
  429. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  430. package/build/dist/UI/Components/Forms/FormSummary.js +7 -0
  431. package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
  432. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +2 -1
  433. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  434. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js +84 -0
  435. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js.map +1 -0
  436. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +14 -1
  437. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  438. package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
  439. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  440. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -1
  441. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  442. package/build/dist/UI/Components/Tooltip/Tooltip.js +2 -1
  443. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  444. package/build/dist/UI/Utils/API/API.js +143 -19
  445. package/build/dist/UI/Utils/API/API.js.map +1 -1
  446. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +21 -7
  447. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
  448. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +26 -9
  449. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  450. package/build/dist/UI/Utils/Navigation.js +8 -0
  451. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  452. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js +92 -0
  453. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js.map +1 -0
  454. package/build/dist/UI/Utils/Realtime.js +120 -15
  455. package/build/dist/UI/Utils/Realtime.js.map +1 -1
  456. package/build/dist/Utils/API.js +13 -5
  457. package/build/dist/Utils/API.js.map +1 -1
  458. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +123 -6
  459. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
  460. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +4 -18
  461. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -1
  462. package/build/dist/Utils/Slo/SloBurnRateTemplate.js +2 -2
  463. package/package.json +1 -1
@@ -0,0 +1,321 @@
1
+ /** @timezone UTC */
2
+
3
+ import "@testing-library/jest-dom";
4
+ import { afterEach, describe, expect, jest, test } from "@jest/globals";
5
+ import {
6
+ cleanup,
7
+ fireEvent,
8
+ render,
9
+ screen,
10
+ within,
11
+ } from "@testing-library/react";
12
+ import React from "react";
13
+ import getJestMockFunction, { MockFunction } from "../../MockType";
14
+
15
+ /*
16
+ * The Security Events volume chart: a totals row (how many events, split by
17
+ * severity) over a severity-stacked histogram, plus its three other states -
18
+ * first load, an empty window and a failed count.
19
+ */
20
+
21
+ jest.mock("recharts", () => {
22
+ const react: typeof React = jest.requireActual("react") as typeof React;
23
+
24
+ interface StubRow {
25
+ time: string;
26
+ }
27
+
28
+ return {
29
+ __esModule: true,
30
+ ResponsiveContainer: (props: { children: React.ReactNode }) => {
31
+ return react.createElement("div", null, props.children);
32
+ },
33
+ BarChart: (props: { data: Array<StubRow>; children?: React.ReactNode }) => {
34
+ return react.createElement(
35
+ "div",
36
+ { "data-testid": "bar-chart" },
37
+ props.data.map((row: StubRow) => {
38
+ return react.createElement("div", {
39
+ key: row.time,
40
+ "data-testid": "chart-row",
41
+ });
42
+ }),
43
+ props.children,
44
+ );
45
+ },
46
+ Bar: (props: { dataKey: string; fill: string }) => {
47
+ return react.createElement("div", {
48
+ "data-testid": "bar",
49
+ "data-key": props.dataKey,
50
+ "data-fill": props.fill,
51
+ });
52
+ },
53
+ XAxis: () => {
54
+ return null;
55
+ },
56
+ YAxis: () => {
57
+ return null;
58
+ },
59
+ Tooltip: () => {
60
+ return null;
61
+ },
62
+ ReferenceArea: () => {
63
+ return null;
64
+ },
65
+ };
66
+ });
67
+
68
+ import SecurityEventsVolumeChart, {
69
+ SECURITY_EVENTS_VOLUME_TEST_ID,
70
+ SECURITY_EVENTS_VOLUME_TITLE,
71
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/SecurityEvents/SecurityEventsVolumeChart";
72
+ import {
73
+ SECURITY_EVENT_VOLUME_COLORS,
74
+ SecurityEventVolume,
75
+ buildSecurityEventVolume,
76
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/SecurityEvents/SecurityEventVolume";
77
+ import AggregatedModel from "../../../Types/BaseDatabase/AggregatedModel";
78
+ import OcsfSeverity from "../../../Types/SecurityEvent/OcsfSeverity";
79
+
80
+ const START: Date = new Date("2026-09-17T12:00:00.000Z");
81
+ const END: Date = new Date("2026-09-17T13:00:00.000Z");
82
+
83
+ function volumeOf(
84
+ rows: Array<[string, OcsfSeverity | string, number]>,
85
+ ): SecurityEventVolume {
86
+ return buildSecurityEventVolume({
87
+ rows: rows.map(
88
+ ([timestamp, severityName, value]: [
89
+ string,
90
+ OcsfSeverity | string,
91
+ number,
92
+ ]): AggregatedModel => {
93
+ return {
94
+ timestamp: timestamp as unknown as Date,
95
+ value: value,
96
+ severityName: severityName,
97
+ };
98
+ },
99
+ ),
100
+ startDate: START,
101
+ endDate: END,
102
+ });
103
+ }
104
+
105
+ const VOLUME: SecurityEventVolume = volumeOf([
106
+ ["2026-09-17T12:05:00.000Z", OcsfSeverity.Critical, 2],
107
+ ["2026-09-17T12:05:00.000Z", OcsfSeverity.Low, 40],
108
+ ["2026-09-17T12:40:00.000Z", OcsfSeverity.High, 1],
109
+ ["2026-09-17T12:41:00.000Z", OcsfSeverity.Informational, 1200],
110
+ ]);
111
+
112
+ function renderChart(
113
+ props: Partial<React.ComponentProps<typeof SecurityEventsVolumeChart>> = {},
114
+ ): void {
115
+ render(
116
+ <SecurityEventsVolumeChart volume={VOLUME} isLoading={false} {...props} />,
117
+ );
118
+ }
119
+
120
+ function totalText(): string {
121
+ return (
122
+ screen.getByTestId(`${SECURITY_EVENTS_VOLUME_TEST_ID}-total`).textContent ||
123
+ ""
124
+ );
125
+ }
126
+
127
+ function severityItems(): Array<HTMLElement> {
128
+ return within(
129
+ screen.getByRole("list", { name: "Events by severity" }),
130
+ ).getAllByRole("listitem");
131
+ }
132
+
133
+ function barKeys(): Array<string> {
134
+ return screen.queryAllByTestId("bar").map((bar: HTMLElement): string => {
135
+ return bar.getAttribute("data-key") || "";
136
+ });
137
+ }
138
+
139
+ afterEach(() => {
140
+ cleanup();
141
+ });
142
+
143
+ describe("SecurityEventsVolumeChart totals", () => {
144
+ test("states the window's total with thousands separators", () => {
145
+ renderChart();
146
+
147
+ expect(totalText()).toBe("1,243 events");
148
+ });
149
+
150
+ test("uses the singular for a single event", () => {
151
+ renderChart({
152
+ volume: volumeOf([["2026-09-17T12:05:00.000Z", OcsfSeverity.High, 1]]),
153
+ });
154
+
155
+ expect(totalText()).toBe("1 event");
156
+ });
157
+
158
+ test("splits the total by severity, most severe first, skipping severities with none", () => {
159
+ renderChart();
160
+
161
+ expect(
162
+ severityItems().map((item: HTMLElement): string => {
163
+ return item.textContent || "";
164
+ }),
165
+ ).toEqual(["Critical2", "High1", "Low40", "Informational1,200"]);
166
+ });
167
+
168
+ test("each severity's swatch is the colour of its bars", () => {
169
+ renderChart();
170
+
171
+ const critical: HTMLElement = screen.getByTestId(
172
+ `${SECURITY_EVENTS_VOLUME_TEST_ID}-severity-${OcsfSeverity.Critical}`,
173
+ );
174
+ const swatch: HTMLElement = critical.querySelector(
175
+ "[aria-hidden='true']",
176
+ ) as HTMLElement;
177
+
178
+ expect(swatch).toHaveStyle({
179
+ backgroundColor: SECURITY_EVENT_VOLUME_COLORS[OcsfSeverity.Critical],
180
+ });
181
+ });
182
+
183
+ test("says it is counting before the first count arrives", () => {
184
+ renderChart({ volume: null, isLoading: true });
185
+
186
+ expect(totalText()).toBe("Counting events...");
187
+ expect(
188
+ screen.queryByRole("list", { name: "Events by severity" }),
189
+ ).toBeNull();
190
+ });
191
+
192
+ test("keeps the last totals on screen while a recount runs", () => {
193
+ renderChart({ isLoading: true });
194
+
195
+ expect(totalText()).toBe("1,243 events");
196
+ expect(screen.getByTestId(SECURITY_EVENTS_VOLUME_TEST_ID)).toHaveAttribute(
197
+ "aria-busy",
198
+ "true",
199
+ );
200
+ });
201
+
202
+ test("renders the toolbar at the end of the totals row", () => {
203
+ renderChart({
204
+ toolbar: <button type="button">Past 1 Day</button>,
205
+ });
206
+
207
+ expect(
208
+ screen.getByRole("button", { name: "Past 1 Day" }),
209
+ ).toBeInTheDocument();
210
+ });
211
+ });
212
+
213
+ describe("SecurityEventsVolumeChart histogram", () => {
214
+ test("is titled Security Event Volume", () => {
215
+ renderChart();
216
+
217
+ expect(SECURITY_EVENTS_VOLUME_TITLE).toBe("Security Event Volume");
218
+ expect(screen.getByText(SECURITY_EVENTS_VOLUME_TITLE)).toBeInTheDocument();
219
+ });
220
+
221
+ test("stacks one bar series per severity present, most severe at the bottom", () => {
222
+ renderChart();
223
+
224
+ expect(barKeys()).toEqual([
225
+ OcsfSeverity.Critical,
226
+ OcsfSeverity.High,
227
+ OcsfSeverity.Low,
228
+ OcsfSeverity.Informational,
229
+ ]);
230
+ });
231
+
232
+ test("paints each severity in its own colour", () => {
233
+ renderChart();
234
+
235
+ for (const bar of screen.getAllByTestId("bar")) {
236
+ expect(bar.getAttribute("data-fill")).toBe(
237
+ SECURITY_EVENT_VOLUME_COLORS[
238
+ bar.getAttribute("data-key") as OcsfSeverity
239
+ ],
240
+ );
241
+ }
242
+ });
243
+
244
+ test("gives every minute of the hour its place on the axis", () => {
245
+ renderChart();
246
+
247
+ expect(screen.getAllByTestId("chart-row")).toHaveLength(61);
248
+ });
249
+
250
+ test("offers drag-to-zoom when it can zoom, and zoom-out once it has", () => {
251
+ renderChart({
252
+ onTimeRangeSelect: getJestMockFunction(),
253
+ onZoomOut: getJestMockFunction(),
254
+ });
255
+
256
+ expect(screen.getByText("Drag to zoom")).toBeInTheDocument();
257
+ expect(screen.getByText("Double-click to zoom out")).toBeInTheDocument();
258
+ });
259
+
260
+ test("offers neither without the handlers", () => {
261
+ renderChart();
262
+
263
+ expect(screen.queryByText("Drag to zoom")).toBeNull();
264
+ expect(screen.queryByText("Double-click to zoom out")).toBeNull();
265
+ });
266
+ });
267
+
268
+ describe("SecurityEventsVolumeChart other states", () => {
269
+ test("an empty window says so rather than drawing an empty axis", () => {
270
+ renderChart({ volume: volumeOf([]) });
271
+
272
+ expect(
273
+ screen.getByTestId(`${SECURITY_EVENTS_VOLUME_TEST_ID}-empty`),
274
+ ).toHaveTextContent("No security events in this time range.");
275
+ expect(screen.queryByTestId("bar-chart")).toBeNull();
276
+ expect(totalText()).toBe("0 events");
277
+ expect(
278
+ screen.queryByRole("list", { name: "Events by severity" }),
279
+ ).toBeNull();
280
+ });
281
+
282
+ test("an empty window that is being recounted keeps the chart frame rather than flashing empty", () => {
283
+ renderChart({ volume: volumeOf([]), isLoading: true });
284
+
285
+ expect(
286
+ screen.queryByTestId(`${SECURITY_EVENTS_VOLUME_TEST_ID}-empty`),
287
+ ).toBeNull();
288
+ });
289
+
290
+ test("a failed count shows the error, under the chart's title, with a retry", () => {
291
+ const onRetry: MockFunction = getJestMockFunction();
292
+
293
+ renderChart({ error: "Could not reach ClickHouse", onRetry: onRetry });
294
+
295
+ const error: HTMLElement = screen.getByTestId(
296
+ `${SECURITY_EVENTS_VOLUME_TEST_ID}-error`,
297
+ );
298
+ expect(error).toHaveTextContent(SECURITY_EVENTS_VOLUME_TITLE);
299
+ expect(error).toHaveTextContent("Could not reach ClickHouse");
300
+ expect(screen.queryByTestId("bar-chart")).toBeNull();
301
+
302
+ fireEvent.click(within(error).getByTestId("refresh-button"));
303
+ expect(onRetry).toHaveBeenCalledTimes(1);
304
+ });
305
+
306
+ test("a failed count does not leave stale totals claiming to describe the window", () => {
307
+ renderChart({ error: "Could not reach ClickHouse" });
308
+
309
+ expect(totalText()).toBe("");
310
+ expect(
311
+ screen.queryByRole("list", { name: "Events by severity" }),
312
+ ).toBeNull();
313
+ });
314
+
315
+ test("the first load shows the chart's loader", () => {
316
+ renderChart({ volume: null, isLoading: true });
317
+
318
+ expect(screen.queryByTestId("bar-chart")).toBeNull();
319
+ expect(screen.getByTestId("component-loader")).toBeInTheDocument();
320
+ });
321
+ });
@@ -30,9 +30,8 @@ import SloWindowType from "../../../Types/ServiceLevelObjective/SloWindowType";
30
30
 
31
31
  /*
32
32
  * The SLO overview hero, RENDERED: the verdict, the facts every number below
33
- * depends on, and the owners and labels strip. In particular the "window
34
- * filling" chip that replaced the full-width "Window not yet full" banner
35
- * must appear for a young rolling window and for nothing else.
33
+ * depends on, and ownership. The facts form a labelled definition list,
34
+ * and the window-filling badge appears only for a young rolling window.
36
35
  */
37
36
 
38
37
  const SLO_ID: ObjectID = new ObjectID("5f8b7c1e2d3a4b5c6d7e8f90");
@@ -97,11 +96,11 @@ const renderHero: RenderHeroFunction = (
97
96
  );
98
97
  };
99
98
 
100
- type ChipTextsFunction = () => Array<string>;
99
+ type FactValuesFunction = () => Array<string>;
101
100
 
102
- const getChipTexts: ChipTextsFunction = (): Array<string> => {
103
- return within(screen.getByRole("list", { name: "SLO at a glance" }))
104
- .getAllByRole("listitem")
101
+ const getFactValues: FactValuesFunction = (): Array<string> => {
102
+ return within(screen.getByLabelText("SLO at a glance"))
103
+ .getAllByRole("definition")
105
104
  .map((item: HTMLElement) => {
106
105
  return item.textContent || "";
107
106
  });
@@ -118,13 +117,70 @@ describe("SloOverviewHero", () => {
118
117
  expect(
119
118
  screen.getByText("Customers can pay for their basket."),
120
119
  ).toBeInTheDocument();
121
- expect(getChipTexts()).toEqual([
122
- "Target 99.9%",
120
+ const facts: HTMLElement = screen.getByLabelText("SLO at a glance");
121
+ expect(facts.tagName).toBe("DL");
122
+ expect(
123
+ within(facts)
124
+ .getAllByRole("term")
125
+ .map((term: HTMLElement) => {
126
+ return term.textContent;
127
+ }),
128
+ ).toEqual(["Target", "Compliance window", "Monitors", "Owners"]);
129
+ expect(getFactValues()).toEqual([
130
+ "99.9%",
123
131
  "Rolling 30 days",
124
132
  "3 monitors",
133
+ "Add owners",
125
134
  ]);
126
135
  });
127
136
 
137
+ test.each([
138
+ {
139
+ status: SloStatus.Healthy,
140
+ headline: "Within error budget",
141
+ tone: "text-emerald-800",
142
+ },
143
+ {
144
+ status: SloStatus.AtRisk,
145
+ headline: "Error budget running low",
146
+ tone: "text-amber-800",
147
+ },
148
+ {
149
+ status: SloStatus.BudgetExhausted,
150
+ headline: "Error budget exhausted",
151
+ tone: "text-red-800",
152
+ },
153
+ {
154
+ status: SloStatus.Misconfigured,
155
+ headline: "Cannot be evaluated",
156
+ tone: "text-gray-700",
157
+ },
158
+ {
159
+ status: SloStatus.Paused,
160
+ headline: "Measurement paused",
161
+ tone: "text-gray-700",
162
+ },
163
+ ])(
164
+ "renders $status with a matching headline and soft status badge",
165
+ ({
166
+ status,
167
+ headline,
168
+ tone,
169
+ }: {
170
+ status: SloStatus;
171
+ headline: string;
172
+ tone: string;
173
+ }) => {
174
+ renderHero({ slo: buildSlo({ sloStatus: status }) });
175
+
176
+ expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
177
+ headline,
178
+ );
179
+ expect(screen.getByText(status)).toHaveClass("bg-gradient-to-r", tone);
180
+ expect(screen.queryByRole("img")).toBeNull();
181
+ },
182
+ );
183
+
128
184
  test("says when it was last evaluated, with the exact time on hover", () => {
129
185
  renderHero({});
130
186
 
@@ -132,7 +188,9 @@ describe("SloOverviewHero", () => {
132
188
  "slo-overview-last-evaluated",
133
189
  );
134
190
 
135
- expect(lastEvaluated.textContent).toMatch(/^Evaluated .+ · every 5 min$/);
191
+ expect(lastEvaluated.textContent).toMatch(/^Evaluated .+/);
192
+ expect(lastEvaluated).not.toHaveTextContent("Runs every");
193
+ expect(screen.getByText("Runs every 5 minutes")).toBeInTheDocument();
136
194
 
137
195
  const time: HTMLElement = lastEvaluated.querySelector("time")!;
138
196
  expect(time).toHaveAttribute("dateTime", LAST_EVALUATED_AT.toISOString());
@@ -154,17 +212,21 @@ describe("SloOverviewHero", () => {
154
212
  );
155
213
  expect(screen.queryByText("Unknown")).toBeNull();
156
214
  expect(screen.getByTestId("slo-overview-last-evaluated")).toHaveTextContent(
157
- "Not evaluated yet · runs every 5 min",
215
+ "Not evaluated yet",
158
216
  );
217
+ expect(screen.getByText("Runs every 5 minutes")).toBeInTheDocument();
218
+ expect(screen.getAllByText("Not evaluated yet")).toHaveLength(2);
159
219
 
160
220
  const monitorsChip: HTMLElement = screen.getByTestId(
161
221
  "slo-overview-chip-monitors",
162
222
  );
163
223
  expect(monitorsChip).toHaveTextContent("No monitors");
164
- expect(monitorsChip.querySelector("span")!.className).toContain("amber");
224
+ expect(within(monitorsChip).getByText("No monitors")).toHaveClass(
225
+ "text-yellow-700",
226
+ );
165
227
  });
166
228
 
167
- test("a young rolling window gets a 'window filling' chip instead of a banner", () => {
229
+ test("a young rolling window shows its filling badge alongside its compliance window", () => {
168
230
  renderHero({ slo: buildSlo({ errorBudgetTotalSeconds: 648 }) });
169
231
 
170
232
  const chip: HTMLElement = screen.getByTestId(
@@ -175,12 +237,14 @@ describe("SloOverviewHero", () => {
175
237
  expect(chip.getAttribute("title")).toContain(
176
238
  "younger than its compliance window",
177
239
  );
178
- expect(getChipTexts()).toEqual([
179
- "Target 99.9%",
240
+ const window: HTMLElement = screen.getByTestId("slo-overview-chip-window");
241
+ expect(window).toContainElement(chip);
242
+ expect(within(window).getByRole("term")).toHaveTextContent(
243
+ "Compliance window",
244
+ );
245
+ expect(within(window).getByRole("definition")).toHaveTextContent(
180
246
  "Rolling 30 days",
181
- "Window 25% full",
182
- "3 monitors",
183
- ]);
247
+ );
184
248
  });
185
249
 
186
250
  test("a mature window, a calendar month and an averaged SLO get no window chip", () => {
@@ -196,7 +260,7 @@ describe("SloOverviewHero", () => {
196
260
  }),
197
261
  });
198
262
  expect(screen.queryByTestId("slo-overview-chip-window-fill")).toBeNull();
199
- expect(getChipTexts()).toContain("Calendar month (Europe/Berlin)");
263
+ expect(getFactValues()).toContain("Calendar month (Europe/Berlin)");
200
264
  cleanup();
201
265
 
202
266
  renderHero({
@@ -208,29 +272,80 @@ describe("SloOverviewHero", () => {
208
272
  expect(screen.queryByTestId("slo-overview-chip-window-fill")).toBeNull();
209
273
  });
210
274
 
211
- test("disabled and archived SLOs say so, and never claim a stale verdict", () => {
212
- renderHero({
213
- slo: buildSlo({ isEnabled: false, isArchived: true }),
214
- });
275
+ test.each([
276
+ { isEnabled: false, isArchived: false, status: "Disabled" },
277
+ { isEnabled: true, isArchived: true, status: "Archived" },
278
+ { isEnabled: false, isArchived: true, status: "Archived" },
279
+ ])(
280
+ "$status overrides stale health when enabled=$isEnabled and archived=$isArchived",
281
+ ({
282
+ isEnabled,
283
+ isArchived,
284
+ status,
285
+ }: {
286
+ isEnabled: boolean;
287
+ isArchived: boolean;
288
+ status: string;
289
+ }) => {
290
+ renderHero({ slo: buildSlo({ isEnabled, isArchived }) });
291
+
292
+ expect(screen.getByTestId("slo-overview-headline")).toHaveTextContent(
293
+ `${status} — not being measured`,
294
+ );
295
+ expect(screen.getByText(status, { exact: true })).toHaveClass(
296
+ "text-gray-700",
297
+ );
298
+ expect(screen.queryByText("Healthy", { exact: true })).toBeNull();
299
+ expect(screen.queryByText("Within error budget")).toBeNull();
300
+ if (isArchived) {
301
+ expect(screen.queryByText("Disabled", { exact: true })).toBeNull();
302
+ }
303
+ },
304
+ );
215
305
 
216
- expect(screen.getByTestId("slo-overview-headline")).toHaveTextContent(
217
- "Archived — not being measured",
218
- );
219
- expect(getChipTexts()).toEqual(
220
- expect.arrayContaining(["Disabled", "Archived"]),
221
- );
222
- });
306
+ test.each([undefined, ""])(
307
+ "an empty description (%s) adds no placeholder copy",
308
+ (description: string | undefined) => {
309
+ renderHero({ slo: buildSlo({ description }) });
310
+
311
+ expect(screen.queryByText(/No description/)).toBeNull();
312
+ expect(
313
+ screen.getByTestId("slo-overview-headline").nextElementSibling,
314
+ ).toBeNull();
315
+ },
316
+ );
223
317
 
224
- test("an SLO without a description invites one", () => {
225
- renderHero({ slo: buildSlo({ description: undefined }) });
318
+ test("a missing target is explicit instead of showing an incomplete percentage", () => {
319
+ renderHero({ slo: buildSlo({ targetPercentage: undefined }) });
226
320
 
227
321
  expect(
228
- screen.getByText(
229
- "No description yet. Say what this objective protects in SLO Details below.",
322
+ within(screen.getByTestId("slo-overview-chip-target")).getByRole(
323
+ "definition",
230
324
  ),
231
- ).toBeInTheDocument();
325
+ ).toHaveTextContent("Not set");
232
326
  });
233
327
 
328
+ test.each([
329
+ { count: 0, label: "No monitors" },
330
+ { count: 1, label: "1 monitor" },
331
+ { count: 3, label: "3 monitors" },
332
+ ])(
333
+ "the $label summary links to this SLO's Monitors page",
334
+ ({ count, label }: { count: number; label: string }) => {
335
+ renderHero({ monitorCount: count });
336
+
337
+ const monitorsHref: string = RouteUtil.populateRouteParams(
338
+ RouteMap[PageMap.SLO_VIEW_MONITORS] as Route,
339
+ { modelId: SLO_ID },
340
+ ).toString();
341
+
342
+ expect(screen.getByRole("link", { name: label })).toHaveAttribute(
343
+ "href",
344
+ monitorsHref,
345
+ );
346
+ },
347
+ );
348
+
234
349
  describe("owners", () => {
235
350
  const ownersHref: string = RouteUtil.populateRouteParams(
236
351
  RouteMap[PageMap.SLO_VIEW_OWNERS] as Route,
@@ -286,10 +401,11 @@ describe("SloOverviewHero", () => {
286
401
  expect(screen.queryByText("No labels")).toBeNull();
287
402
  });
288
403
 
289
- test("owners sit beside the evaluation time, labelled", () => {
404
+ test("owners are labelled within the summary facts", () => {
290
405
  renderHero({ owners: [] });
291
406
 
292
407
  const owners: HTMLElement = screen.getByTestId("slo-overview-owners");
408
+ expect(screen.getByLabelText("SLO at a glance")).toContainElement(owners);
293
409
  expect(owners).toHaveTextContent("Owners");
294
410
  expect(
295
411
  within(owners).getByRole("link", { name: "Add owners" }),
@@ -307,5 +423,24 @@ describe("SloOverviewHero", () => {
307
423
  expect(screen.getByRole("alert")).toHaveTextContent(
308
424
  "Could not refresh — showing the last numbers that loaded. Network error.",
309
425
  );
426
+ expect(getFactValues()).toContain("99.9%");
427
+ });
428
+
429
+ test("an in-progress refresh disables duplicate requests and keeps the summary visible", () => {
430
+ const onRefresh: MockFunction = getJestMockFunction();
431
+
432
+ renderHero({ onRefresh, isRefreshing: true });
433
+
434
+ const refreshButton: HTMLElement = screen.getByRole("button", {
435
+ name: "Refresh",
436
+ });
437
+ expect(refreshButton).toBeDisabled();
438
+ expect(refreshButton).toHaveAttribute("aria-disabled", "true");
439
+ fireEvent.click(refreshButton);
440
+ expect(onRefresh).not.toHaveBeenCalled();
441
+ expect(screen.getByTestId("slo-overview-headline")).toHaveTextContent(
442
+ "Within error budget",
443
+ );
444
+ expect(getFactValues()).toContain("99.9%");
310
445
  });
311
446
  });