@oneuptime/common 13.0.7 → 14.0.0

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 (759) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +23 -15
  2. package/Models/DatabaseModels/GlobalConfig.ts +24 -0
  3. package/Models/DatabaseModels/Monitor.ts +3 -2
  4. package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
  5. package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +1 -1
  6. package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +1 -1
  7. package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +1 -1
  8. package/Scripts/generate-service-worker.js +65 -4
  9. package/Server/API/AIBillingAPI.ts +1 -0
  10. package/Server/API/AIInsightAPI.ts +1 -4
  11. package/Server/API/AIInvestigationAPI.ts +1 -4
  12. package/Server/API/AIReadinessAPI.ts +4 -5
  13. package/Server/API/AlertAPI.ts +1 -0
  14. package/Server/API/AutoRemediationAPI.ts +1 -4
  15. package/Server/API/BaseAPI.ts +34 -0
  16. package/Server/API/BaseAnalyticsAPI.ts +80 -9
  17. package/Server/API/BillingAPI.ts +2 -0
  18. package/Server/API/BillingInvoiceAPI.ts +1 -0
  19. package/Server/API/BillingPaymentMethodAPI.ts +2 -0
  20. package/Server/API/CodeFixRunAPI.ts +1 -3
  21. package/Server/API/CommonAPI.ts +68 -4
  22. package/Server/API/DashboardAPI.ts +12 -12
  23. package/Server/API/GlobalConfigAPI.ts +243 -460
  24. package/Server/API/IncidentAPI.ts +2 -0
  25. package/Server/API/IncidentEpisodeAPI.ts +1 -0
  26. package/Server/API/NotificationAPI.ts +1 -0
  27. package/Server/API/OnCallCalendarAPI.ts +4 -5
  28. package/Server/API/OnCallDutyPolicyAPI.ts +7 -0
  29. package/Server/API/OnCallReadinessAPI.ts +4 -1
  30. package/Server/API/OnCallScheduleTimelineAPI.ts +731 -0
  31. package/Server/API/ProjectAPI.ts +1 -0
  32. package/Server/API/ProjectOIDC.ts +25 -16
  33. package/Server/API/ProjectSSO.ts +24 -16
  34. package/Server/API/ScheduledMaintenanceAPI.ts +1 -0
  35. package/Server/API/StatusPageAPI.ts +261 -74
  36. package/Server/API/TeamMemberAPI.ts +13 -1
  37. package/Server/API/UserCallAPI.ts +2 -0
  38. package/Server/API/UserEmailAPI.ts +2 -0
  39. package/Server/API/UserIncomingCallNumberAPI.ts +2 -0
  40. package/Server/API/UserMicrosoftTeamsAPI.ts +1 -0
  41. package/Server/API/UserSlackAPI.ts +1 -0
  42. package/Server/API/UserSmsAPI.ts +2 -0
  43. package/Server/API/UserTotpAuthAPI.ts +1 -0
  44. package/Server/API/UserWebAuthnAPI.ts +2 -0
  45. package/Server/API/UserWebhookAPI.ts +1 -0
  46. package/Server/API/UserWhatsAppAPI.ts +2 -0
  47. package/Server/Enterprise/EnterpriseEdition.ts +649 -0
  48. package/Server/Enterprise/EnterpriseFeature.ts +48 -0
  49. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
  50. package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
  51. package/Server/EnvironmentConfig.ts +147 -2
  52. package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
  53. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  54. package/Server/Middleware/MasterAdminAuthorization.ts +13 -2
  55. package/Server/Middleware/UserAuthorization.ts +117 -21
  56. package/Server/Services/ApiKeyPermissionService.ts +101 -4
  57. package/Server/Services/AuditLogService.ts +84 -1079
  58. package/Server/Services/DatabaseService.ts +245 -0
  59. package/Server/Services/DetectionRuleService.ts +5 -4
  60. package/Server/Services/EnterpriseLicenseService.ts +38 -0
  61. package/Server/Services/GlobalConfigService.ts +80 -1
  62. package/Server/Services/MonitorProbeService.ts +116 -20
  63. package/Server/Services/MonitorService.ts +56 -4
  64. package/Server/Services/MonitorStatusTimelineService.ts +284 -0
  65. package/Server/Services/MonitorTemplateService.ts +26 -0
  66. package/Server/Services/OnCallDutyPolicyChildService.ts +261 -0
  67. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -2
  68. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -2
  69. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -2
  70. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -2
  71. package/Server/Services/PayAsYouGoBillingService.ts +23 -28
  72. package/Server/Services/ProjectService.ts +302 -0
  73. package/Server/Services/RumSessionPinService.ts +293 -22
  74. package/Server/Services/StatusPagePrivateUserService.ts +7 -3
  75. package/Server/Services/StatusPageService.ts +78 -1
  76. package/Server/Services/TeamMemberService.ts +11 -0
  77. package/Server/Services/TeamPermissionService.ts +120 -26
  78. package/Server/Services/TeamService.ts +10 -0
  79. package/Server/Services/ThreatIntelFeedService.ts +6 -3
  80. package/Server/Services/UserService.ts +10 -17
  81. package/Server/Types/Database/Permissions/BasePermission.ts +9 -7
  82. package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
  83. package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
  84. package/Server/Types/Database/Permissions/Index.ts +75 -11
  85. package/Server/Types/Database/Permissions/TablePermission.ts +34 -31
  86. package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
  87. package/Server/Types/Markdown.ts +41 -0
  88. package/Server/Utils/AI/AIChatPrivacyFilter.ts +8 -0
  89. package/Server/Utils/AI/AIRunPrivacyFilter.ts +8 -0
  90. package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
  91. package/Server/Utils/EditionEnforcement.ts +233 -0
  92. package/Server/Utils/FrontendEnvironment.ts +41 -2
  93. package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
  94. package/Server/Utils/MasterAdminPageAccess.ts +61 -0
  95. package/Server/Utils/Monitor/AffectedResourceList.ts +190 -0
  96. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
  97. package/Server/Utils/Monitor/MonitorAlert.ts +3 -1
  98. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +543 -333
  99. package/Server/Utils/Monitor/MonitorIncident.ts +3 -1
  100. package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
  101. package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1 -1
  102. package/Server/Utils/Realtime.ts +163 -45
  103. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +11 -28
  104. package/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.ts +170 -0
  105. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +1 -1
  106. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +6 -2
  107. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.ts +10 -9
  108. package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
  109. package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
  110. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
  111. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
  112. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
  113. package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
  114. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
  115. package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
  116. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +1059 -0
  117. package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +376 -0
  118. package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +757 -0
  119. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +307 -0
  120. package/Tests/App/Dashboard/ArgumentsFormGroupByUnlistedAttributes.test.tsx +131 -0
  121. package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
  122. package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +1 -1
  123. package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +9 -1
  124. package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +24 -0
  125. package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +162 -8
  126. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
  127. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
  128. package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +105 -6
  129. package/Tests/App/Dashboard/EntityFilterDropdownUnlistedSelection.test.tsx +434 -0
  130. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +276 -1
  131. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
  132. package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +9 -1
  133. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
  134. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +58 -42
  135. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +42 -5
  136. package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +34 -23
  137. package/Tests/App/Dashboard/ScheduleTimeline.test.tsx +1580 -0
  138. package/Tests/App/Dashboard/ScheduleTimelineAPI.test.ts +280 -0
  139. package/Tests/App/Dashboard/ScheduleTimelineModel.test.ts +673 -0
  140. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +133 -70
  141. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
  142. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
  143. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +86 -3
  144. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -58
  145. package/Tests/App/Dashboard/SecurityEventsGuideContent.test.ts +1313 -0
  146. package/Tests/App/Dashboard/SecurityEventsHowItWorksCard.test.tsx +536 -0
  147. package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
  148. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +222 -0
  149. package/Tests/App/Dashboard/SecurityEventsThreatIntelPage.test.tsx +199 -0
  150. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
  151. package/Tests/App/Dashboard/SloOverviewHero.test.tsx +171 -36
  152. package/Tests/App/Dashboard/SloViewSideMenu.test.tsx +215 -0
  153. package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +40 -3
  154. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
  155. package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +12 -4
  156. package/Tests/App/PublicDashboard/PublicDashboardWidgetListAuth.test.tsx +623 -0
  157. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
  158. package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
  159. package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
  160. package/Tests/Models/OnCallCalendarFeedModels.test.ts +23 -1
  161. package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
  162. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +138 -5
  163. package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +187 -0
  164. package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +51 -3
  165. package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +55 -2
  166. package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
  167. package/Tests/Server/API/BaseAnalyticsAPIAggregateCache.test.ts +729 -0
  168. package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +93 -7
  169. package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +36 -3
  170. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +1003 -24
  171. package/Tests/Server/API/DashboardPublicRateLimit.test.ts +6 -3
  172. package/Tests/Server/API/ExpiredSessionAIRoutes.test.ts +708 -0
  173. package/Tests/Server/API/ExpiredSessionCustomRoutes.test.ts +928 -0
  174. package/Tests/Server/API/ExpiredSessionMonitorTemplate.test.ts +319 -0
  175. package/Tests/Server/API/ExpiredSessionOnCallDutyPolicy.test.ts +336 -0
  176. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +820 -0
  177. package/Tests/Server/API/GlobalConfigLicense.test.ts +766 -381
  178. package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +115 -12
  179. package/Tests/Server/API/OnCallCalendarAPI.test.ts +375 -8
  180. package/Tests/Server/API/OnCallReadinessAPI.test.ts +196 -912
  181. package/Tests/Server/API/OnCallScheduleTimelineAPI.test.ts +1513 -0
  182. package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +119 -7
  183. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +111 -4
  184. package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +615 -0
  185. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +89 -2
  186. package/Tests/Server/API/SessionReplayAPI.test.ts +121 -0
  187. package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
  188. package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +4 -2
  189. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +441 -0
  190. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +664 -0
  191. package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
  192. package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +7 -0
  193. package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +6 -0
  194. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +65 -4
  195. package/Tests/Server/API/UserProjectsAPI.test.ts +63 -3
  196. package/Tests/Server/API/UserTotpAuthAPI.test.ts +48 -2
  197. package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +11 -2
  198. package/Tests/Server/API/UserWebAuthnBackupCodeMinting.test.ts +46 -3
  199. package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +18 -2
  200. package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +24 -7
  201. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
  202. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
  203. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
  204. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
  205. package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
  206. package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
  207. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
  208. package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
  209. package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
  210. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
  211. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
  212. package/Tests/Server/Middleware/ExpiredSessionUserMiddleware.test.ts +563 -0
  213. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +299 -19
  214. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +453 -0
  215. package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
  216. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
  217. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +24 -0
  218. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +2 -0
  219. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +3 -3
  220. package/Tests/Server/Services/AuditLogService.test.ts +460 -990
  221. package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
  222. package/Tests/Server/Services/DatabaseServiceCreateSuppliedId.test.ts +147 -0
  223. package/Tests/Server/Services/DatabaseServiceLoginBeforeHooks.test.ts +1078 -0
  224. package/Tests/Server/Services/DatabaseServiceTenantRelationGuard.test.ts +259 -0
  225. package/Tests/Server/Services/DatabaseServiceWriteOperatorValues.test.ts +147 -0
  226. package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
  227. package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
  228. package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
  229. package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +115 -1
  230. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
  231. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
  232. package/Tests/Server/Services/OnCallChildCreateAuthorizationPostgres.test.ts +711 -0
  233. package/Tests/Server/Services/OnCallDutyPolicyChildService.test.ts +733 -0
  234. package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +190 -140
  235. package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +4 -9
  236. package/Tests/Server/Services/PermissionBlockDeletion.test.ts +780 -0
  237. package/Tests/Server/Services/PermissionBlockDeletionPostgres.test.ts +628 -0
  238. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
  239. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
  240. package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +77 -1
  241. package/Tests/Server/Services/RumSessionPinCreatePermission.test.ts +715 -0
  242. package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
  243. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
  244. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
  245. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
  246. package/Tests/Server/Services/TeamMemberMultiTenantReadPostgres.test.ts +394 -0
  247. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +6 -0
  248. package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +131 -0
  249. package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
  250. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +13 -2
  251. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
  252. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
  253. package/Tests/Server/Types/Database/Permissions/ModelPermissionAnonymousRefusal.test.ts +518 -0
  254. package/Tests/Server/Types/Database/Permissions/MultiTenantPermissions.test.ts +350 -0
  255. package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +282 -25
  256. package/Tests/Server/Types/Database/Permissions/TableLevelBlockPermission.test.ts +459 -0
  257. package/Tests/Server/Types/Markdown.test.ts +181 -0
  258. package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +101 -9
  259. package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +88 -4
  260. package/Tests/Server/Utils/AI/Toolbox/ExceptionTools.test.ts +459 -0
  261. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +794 -0
  262. package/Tests/Server/Utils/AI/Toolbox/RecentChangesTools.test.ts +574 -0
  263. package/Tests/Server/Utils/AI/Toolbox/SecurityEventTools.test.ts +596 -0
  264. package/Tests/Server/Utils/CaptchaRequestAndLogging.test.ts +395 -0
  265. package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
  266. package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
  267. package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
  268. package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
  269. package/Tests/Server/Utils/MasterAdminPageAccess.test.ts +251 -0
  270. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
  271. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
  272. package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +616 -0
  273. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +934 -96
  274. package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
  275. package/Tests/Server/Utils/Realtime.test.ts +502 -0
  276. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorSeverity.test.ts +216 -0
  277. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +142 -0
  278. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.test.ts +140 -0
  279. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepairClickhouseIntegration.test.ts +542 -0
  280. package/Tests/Server/Utils/Telemetry/ChangeEventRow.test.ts +743 -0
  281. package/Tests/Server/Utils/Telemetry/RuntimeMetrics.test.ts +465 -0
  282. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.test.ts +202 -0
  283. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.test.ts +194 -0
  284. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.test.ts +231 -0
  285. package/Tests/Server/Utils/Workspace/Slack/Messages/Alert.test.ts +194 -0
  286. package/Tests/Server/Utils/Workspace/Slack/Messages/AlertEpisode.test.ts +194 -0
  287. package/Tests/Server/Utils/Workspace/Slack/Messages/Incident.test.ts +194 -0
  288. package/Tests/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.test.ts +194 -0
  289. package/Tests/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.test.ts +247 -0
  290. package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
  291. package/Tests/Types/AI/AIInsightEvidence.test.ts +206 -0
  292. package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
  293. package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
  294. package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtilAnonymous.test.ts +144 -0
  295. package/Tests/Types/Call/CallProvider.test.ts +528 -0
  296. package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
  297. package/Tests/Types/Kubernetes/KubernetesCostIngest.test.ts +236 -0
  298. package/Tests/Types/OnCallDutyPolicy/ScheduleTimeline.test.ts +736 -0
  299. package/Tests/Types/OnCallDutyPolicy/ScheduleTimelineLayout.test.ts +996 -0
  300. package/Tests/Types/SecurityEvent/SigmaRule.test.ts +142 -0
  301. package/Tests/Types/Workflow/Components/JSON.test.ts +182 -0
  302. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +116 -1
  303. package/Tests/UI/Components/Dropdown/DropdownAsyncOptions.test.tsx +81 -0
  304. package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
  305. package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
  306. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +165 -171
  307. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
  308. package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
  309. package/Tests/UI/Components/EventAttachmentList.test.tsx +174 -0
  310. package/Tests/UI/Components/Forms/BasicFormBurnRateTemplateDefaults.test.tsx +395 -0
  311. package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +286 -0
  312. package/Tests/UI/Components/Forms/FormSummary.test.tsx +128 -0
  313. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
  314. package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
  315. package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
  316. package/Tests/UI/Components/ModelTable/BaseModelTableQueryChange.test.tsx +365 -0
  317. package/Tests/UI/Components/OpenAuthenticatedUrl.test.ts +358 -0
  318. package/Tests/UI/Components/SessionAwareImage.test.tsx +496 -0
  319. package/Tests/UI/Components/TelemetryHistogramZeroBuckets.test.tsx +190 -0
  320. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
  321. package/Tests/UI/Components/TooltipInteractive.test.tsx +97 -0
  322. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
  323. package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardInstallGuidance.test.tsx +1 -1
  324. package/Tests/UI/Monitor/EvaluationLogListTimestamps.test.tsx +367 -0
  325. package/Tests/UI/Utils/API/BaseAPIRefreshSession.test.ts +1087 -0
  326. package/Tests/UI/Utils/API/DashboardHost.ts +12 -0
  327. package/Tests/UI/Utils/API/FakeAxiosServer.ts +183 -0
  328. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
  329. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  330. package/Tests/UI/Utils/Cookie.test.ts +440 -0
  331. package/Tests/UI/Utils/ModelAPIRequestClient.test.ts +278 -0
  332. package/Tests/UI/Utils/Navigation.test.ts +33 -0
  333. package/Tests/UI/Utils/PricingPlan.test.ts +295 -0
  334. package/Tests/UI/Utils/Realtime.test.ts +759 -0
  335. package/Tests/UI/Utils/Telemetry/Telemetry.test.ts +500 -0
  336. package/Tests/Utils/APIInstanceDispatch.test.ts +311 -0
  337. package/Tests/Utils/HostAddressUtil.test.ts +138 -0
  338. package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
  339. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
  340. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizerSeverity.test.ts +565 -0
  341. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
  342. package/Types/API/Hostname.ts +63 -16
  343. package/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.ts +40 -0
  344. package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
  345. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
  346. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
  347. package/Types/Database/CanonicalModelInstance.ts +102 -0
  348. package/Types/Database/TableColumn.ts +20 -6
  349. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
  350. package/Types/IP/IPv6.ts +6 -1
  351. package/Types/Monitor/MonitorEvaluationSummary.ts +3 -0
  352. package/Types/Monitor/MonitorStep.ts +6 -1
  353. package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
  354. package/Types/OnCallDutyPolicy/ScheduleTimeline.ts +507 -0
  355. package/Types/OnCallDutyPolicy/ScheduleTimelineLayout.ts +589 -0
  356. package/Types/Realtime/EventName.ts +11 -0
  357. package/Types/SecurityEvent/DetectionFindingConstants.ts +14 -0
  358. package/Types/SecurityEvent/OcsfSeverity.ts +31 -26
  359. package/Types/SecurityEvent/SigmaRule.ts +51 -0
  360. package/Types/SecurityEvent/ThreatIntelConstants.ts +18 -0
  361. package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
  362. package/UI/Components/AttachmentList/EventAttachmentList.tsx +30 -2
  363. package/UI/Components/Dashboard/DashboardVariableControl.tsx +12 -2
  364. package/UI/Components/Dropdown/Dropdown.tsx +6 -1
  365. package/UI/Components/EditionLabel/EditionLabel.tsx +808 -1195
  366. package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
  367. package/UI/Components/EventItem/EventItem.tsx +12 -1
  368. package/UI/Components/Forms/BasicForm.tsx +151 -126
  369. package/UI/Components/Forms/CollapsibleFormSection.tsx +63 -0
  370. package/UI/Components/Forms/Fields/FormField.tsx +10 -4
  371. package/UI/Components/Forms/FormSummary.tsx +7 -0
  372. package/UI/Components/Forms/Types/Field.ts +10 -0
  373. package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
  374. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  375. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +2 -1
  376. package/UI/Components/Markdown.tsx/SessionAwareImage.tsx +122 -0
  377. package/UI/Components/ModelList/ModelList.tsx +11 -1
  378. package/UI/Components/ModelTable/BaseModelTable.tsx +34 -5
  379. package/UI/Components/ModelTable/TableView.tsx +1 -1
  380. package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
  381. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
  382. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +8 -1
  383. package/UI/Components/Tooltip/Tooltip.tsx +8 -1
  384. package/UI/Utils/API/API.ts +173 -12
  385. package/UI/Utils/API/RequestOptions.ts +11 -0
  386. package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +31 -7
  387. package/UI/Utils/ModelAPI/ModelAPI.ts +30 -9
  388. package/UI/Utils/Navigation.ts +9 -0
  389. package/UI/Utils/OpenAuthenticatedUrl.ts +154 -0
  390. package/UI/Utils/Realtime.ts +176 -30
  391. package/UI/esbuild-enterprise.js +263 -0
  392. package/Utils/API.ts +14 -5
  393. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
  394. package/Utils/HostAddressUtil.ts +94 -0
  395. package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
  396. package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
  397. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +157 -7
  398. package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +9 -17
  399. package/Utils/Slo/SloBurnRateTemplate.ts +2 -2
  400. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
  401. package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
  402. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  403. package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
  404. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  405. package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
  406. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  407. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
  408. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  409. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +1 -1
  410. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -1
  411. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +1 -1
  412. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -1
  413. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +1 -1
  414. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -1
  415. package/build/dist/Server/API/AIBillingAPI.js +1 -1
  416. package/build/dist/Server/API/AIBillingAPI.js.map +1 -1
  417. package/build/dist/Server/API/AIInsightAPI.js +1 -4
  418. package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
  419. package/build/dist/Server/API/AIInvestigationAPI.js +1 -4
  420. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  421. package/build/dist/Server/API/AIReadinessAPI.js +1 -3
  422. package/build/dist/Server/API/AIReadinessAPI.js.map +1 -1
  423. package/build/dist/Server/API/AlertAPI.js +1 -1
  424. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  425. package/build/dist/Server/API/AutoRemediationAPI.js +1 -4
  426. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  427. package/build/dist/Server/API/BaseAPI.js +33 -0
  428. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  429. package/build/dist/Server/API/BaseAnalyticsAPI.js +55 -10
  430. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  431. package/build/dist/Server/API/BillingAPI.js +2 -2
  432. package/build/dist/Server/API/BillingAPI.js.map +1 -1
  433. package/build/dist/Server/API/BillingInvoiceAPI.js +1 -1
  434. package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
  435. package/build/dist/Server/API/BillingPaymentMethodAPI.js +2 -2
  436. package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
  437. package/build/dist/Server/API/CodeFixRunAPI.js +1 -3
  438. package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
  439. package/build/dist/Server/API/CommonAPI.js +50 -5
  440. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  441. package/build/dist/Server/API/DashboardAPI.js +12 -12
  442. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  443. package/build/dist/Server/API/GlobalConfigAPI.js +158 -342
  444. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  445. package/build/dist/Server/API/IncidentAPI.js +2 -2
  446. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  447. package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
  448. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  449. package/build/dist/Server/API/NotificationAPI.js +1 -1
  450. package/build/dist/Server/API/NotificationAPI.js.map +1 -1
  451. package/build/dist/Server/API/OnCallCalendarAPI.js +1 -4
  452. package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -1
  453. package/build/dist/Server/API/OnCallDutyPolicyAPI.js +6 -0
  454. package/build/dist/Server/API/OnCallDutyPolicyAPI.js.map +1 -1
  455. package/build/dist/Server/API/OnCallReadinessAPI.js +4 -1
  456. package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -1
  457. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +494 -0
  458. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -0
  459. package/build/dist/Server/API/ProjectAPI.js +1 -1
  460. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  461. package/build/dist/Server/API/ProjectOIDC.js +24 -16
  462. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  463. package/build/dist/Server/API/ProjectSSO.js +24 -16
  464. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  465. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
  466. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  467. package/build/dist/Server/API/StatusPageAPI.js +218 -76
  468. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  469. package/build/dist/Server/API/TeamMemberAPI.js +11 -4
  470. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  471. package/build/dist/Server/API/UserCallAPI.js +2 -2
  472. package/build/dist/Server/API/UserCallAPI.js.map +1 -1
  473. package/build/dist/Server/API/UserEmailAPI.js +2 -2
  474. package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
  475. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +2 -2
  476. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
  477. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +1 -1
  478. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -1
  479. package/build/dist/Server/API/UserSlackAPI.js +1 -1
  480. package/build/dist/Server/API/UserSlackAPI.js.map +1 -1
  481. package/build/dist/Server/API/UserSmsAPI.js +2 -2
  482. package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
  483. package/build/dist/Server/API/UserTotpAuthAPI.js +1 -1
  484. package/build/dist/Server/API/UserTotpAuthAPI.js.map +1 -1
  485. package/build/dist/Server/API/UserWebAuthnAPI.js +2 -2
  486. package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
  487. package/build/dist/Server/API/UserWebhookAPI.js +1 -1
  488. package/build/dist/Server/API/UserWebhookAPI.js.map +1 -1
  489. package/build/dist/Server/API/UserWhatsAppAPI.js +2 -2
  490. package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
  491. package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
  492. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
  493. package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
  494. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
  495. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
  496. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
  497. package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
  498. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
  499. package/build/dist/Server/EnvironmentConfig.js +84 -2
  500. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  501. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
  502. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
  503. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  504. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  505. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -2
  506. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  507. package/build/dist/Server/Middleware/UserAuthorization.js +94 -15
  508. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  509. package/build/dist/Server/Services/ApiKeyPermissionService.js +80 -4
  510. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  511. package/build/dist/Server/Services/AuditLogService.js +71 -740
  512. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  513. package/build/dist/Server/Services/DatabaseService.js +171 -0
  514. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  515. package/build/dist/Server/Services/DetectionRuleService.js +4 -4
  516. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  517. package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
  518. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  519. package/build/dist/Server/Services/GlobalConfigService.js +63 -0
  520. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  521. package/build/dist/Server/Services/MonitorProbeService.js +90 -17
  522. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  523. package/build/dist/Server/Services/MonitorService.js +45 -4
  524. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  525. package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
  526. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  527. package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
  528. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  529. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js +170 -0
  530. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js.map +1 -0
  531. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -2
  532. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  533. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +2 -2
  534. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  535. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -2
  536. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  537. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -2
  538. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  539. package/build/dist/Server/Services/PayAsYouGoBillingService.js +20 -27
  540. package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -1
  541. package/build/dist/Server/Services/ProjectService.js +231 -0
  542. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  543. package/build/dist/Server/Services/RumSessionPinService.js +198 -16
  544. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  545. package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
  546. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  547. package/build/dist/Server/Services/StatusPageService.js +71 -0
  548. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  549. package/build/dist/Server/Services/TeamMemberService.js +10 -0
  550. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  551. package/build/dist/Server/Services/TeamPermissionService.js +89 -27
  552. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  553. package/build/dist/Server/Services/TeamService.js +9 -0
  554. package/build/dist/Server/Services/TeamService.js.map +1 -1
  555. package/build/dist/Server/Services/ThreatIntelFeedService.js +5 -4
  556. package/build/dist/Server/Services/ThreatIntelFeedService.js.map +1 -1
  557. package/build/dist/Server/Services/UserService.js +10 -16
  558. package/build/dist/Server/Services/UserService.js.map +1 -1
  559. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +9 -6
  560. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  561. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
  562. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  563. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
  564. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  565. package/build/dist/Server/Types/Database/Permissions/Index.js +60 -6
  566. package/build/dist/Server/Types/Database/Permissions/Index.js.map +1 -1
  567. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +24 -16
  568. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  569. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
  570. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  571. package/build/dist/Server/Types/Markdown.js +31 -0
  572. package/build/dist/Server/Types/Markdown.js.map +1 -1
  573. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +7 -0
  574. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -1
  575. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +7 -0
  576. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -1
  577. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
  578. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
  579. package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
  580. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
  581. package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
  582. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
  583. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
  584. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
  585. package/build/dist/Server/Utils/MasterAdminPageAccess.js +39 -0
  586. package/build/dist/Server/Utils/MasterAdminPageAccess.js.map +1 -0
  587. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +96 -0
  588. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
  589. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  590. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  591. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +3 -1
  592. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  593. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +449 -261
  594. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  595. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +3 -1
  596. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  597. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
  598. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
  599. package/build/dist/Server/Utils/Realtime.js +126 -37
  600. package/build/dist/Server/Utils/Realtime.js.map +1 -1
  601. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +7 -25
  602. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  603. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js +127 -0
  604. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js.map +1 -0
  605. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +1 -1
  606. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  607. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +3 -2
  608. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js.map +1 -1
  609. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js +4 -8
  610. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js.map +1 -1
  611. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
  612. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  613. package/build/dist/Types/API/Hostname.js +59 -11
  614. package/build/dist/Types/API/Hostname.js.map +1 -1
  615. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js +31 -1
  616. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js.map +1 -1
  617. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
  618. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  619. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
  620. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  621. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
  622. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
  623. package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
  624. package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
  625. package/build/dist/Types/Database/TableColumn.js +19 -6
  626. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  627. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
  628. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
  629. package/build/dist/Types/IP/IPv6.js +6 -1
  630. package/build/dist/Types/IP/IPv6.js.map +1 -1
  631. package/build/dist/Types/Monitor/MonitorStep.js +5 -0
  632. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  633. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
  634. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js +321 -0
  635. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js.map +1 -0
  636. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js +372 -0
  637. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js.map +1 -0
  638. package/build/dist/Types/Realtime/EventName.js +10 -0
  639. package/build/dist/Types/Realtime/EventName.js.map +1 -1
  640. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +11 -0
  641. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  642. package/build/dist/Types/SecurityEvent/OcsfSeverity.js +30 -25
  643. package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -1
  644. package/build/dist/Types/SecurityEvent/SigmaRule.js +47 -0
  645. package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -1
  646. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js +14 -0
  647. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js.map +1 -1
  648. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
  649. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
  650. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js +9 -4
  651. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js.map +1 -1
  652. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +10 -2
  653. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -1
  654. package/build/dist/UI/Components/Dropdown/Dropdown.js +5 -1
  655. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  656. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +425 -585
  657. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  658. package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
  659. package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
  660. package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
  661. package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
  662. package/build/dist/UI/Components/Forms/BasicForm.js +70 -64
  663. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  664. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +27 -0
  665. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -0
  666. package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -7
  667. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  668. package/build/dist/UI/Components/Forms/FormSummary.js +7 -0
  669. package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
  670. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
  671. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  672. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  673. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  674. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +2 -1
  675. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  676. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js +84 -0
  677. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js.map +1 -0
  678. package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
  679. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  680. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +14 -1
  681. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  682. package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
  683. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  684. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
  685. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  686. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
  687. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  688. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -1
  689. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  690. package/build/dist/UI/Components/Tooltip/Tooltip.js +2 -1
  691. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  692. package/build/dist/UI/Utils/API/API.js +143 -19
  693. package/build/dist/UI/Utils/API/API.js.map +1 -1
  694. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +21 -7
  695. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
  696. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +26 -9
  697. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  698. package/build/dist/UI/Utils/Navigation.js +8 -0
  699. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  700. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js +92 -0
  701. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js.map +1 -0
  702. package/build/dist/UI/Utils/Realtime.js +120 -15
  703. package/build/dist/UI/Utils/Realtime.js.map +1 -1
  704. package/build/dist/Utils/API.js +13 -5
  705. package/build/dist/Utils/API.js.map +1 -1
  706. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
  707. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  708. package/build/dist/Utils/HostAddressUtil.js +80 -0
  709. package/build/dist/Utils/HostAddressUtil.js.map +1 -0
  710. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
  711. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
  712. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
  713. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
  714. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +123 -6
  715. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
  716. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +4 -18
  717. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -1
  718. package/build/dist/Utils/Slo/SloBurnRateTemplate.js +2 -2
  719. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  720. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
  721. package/jest.config.json +3 -1
  722. package/package.json +1 -1
  723. package/test-setup.sh +103 -34
  724. package/tsconfig.json +13 -0
  725. package/Server/API/EnterpriseLicenseAPI.ts +0 -925
  726. package/Server/API/TeamComplianceAPI.ts +0 -158
  727. package/Server/Middleware/SCIMAuthorization.ts +0 -141
  728. package/Server/Services/TeamComplianceService.ts +0 -733
  729. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
  730. package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
  731. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
  732. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
  733. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
  734. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
  735. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
  736. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
  737. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
  738. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
  739. package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
  740. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
  741. package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
  742. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
  743. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
  744. package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
  745. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
  746. package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
  747. package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
  748. package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
  749. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
  750. package/build/dist/Server/Services/TeamComplianceService.js +0 -537
  751. package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
  752. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
  753. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
  754. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
  755. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
  756. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
  757. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
  758. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
  759. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
@@ -30,6 +30,10 @@ import ExternalStatusPageMonitorCriteria from "./Criteria/ExternalStatusPageMoni
30
30
  import MonitorCriteriaMessageBuilder from "./MonitorCriteriaMessageBuilder";
31
31
  import MonitorCriteriaDataExtractor from "./MonitorCriteriaDataExtractor";
32
32
  import MonitorCriteriaMessageFormatter from "./MonitorCriteriaMessageFormatter";
33
+ import AffectedResourceList, {
34
+ AffectedResourceListDetail,
35
+ AffectedResourceListEntry,
36
+ } from "./AffectedResourceList";
33
37
  import DataToProcess from "./DataToProcess";
34
38
  import Monitor from "../../../Models/DatabaseModels/Monitor";
35
39
  import MonitorCriteria from "../../../Types/Monitor/MonitorCriteria";
@@ -2018,7 +2022,7 @@ ${contextBlock}
2018
2022
  }
2019
2023
 
2020
2024
  /**
2021
- * The unit for a value in a per-platform "Affected Resources" table.
2025
+ * The unit for a value in a per-platform "Affected Resources" list.
2022
2026
  *
2023
2027
  * These rows are NOT the same numbers as the criteria's breaching
2024
2028
  * samples: the worker collects them with a raw `MetricService.findBy`
@@ -2060,10 +2064,11 @@ ${contextBlock}
2060
2064
  }
2061
2065
 
2062
2066
  /**
2063
- * Render one cell of a platform breakdown table's Value column.
2067
+ * Render the value of one resource in a platform "Affected Resources"
2068
+ * list.
2064
2069
  *
2065
- * Bold, because that is how these tables have always drawn the value —
2066
- * it is the one number in the row a reader scans for.
2070
+ * Bold, because that is how the breakdown has always drawn the value —
2071
+ * it is the one number on the line a reader scans for.
2067
2072
  */
2068
2073
  private static formatPlatformResourceValue(input: {
2069
2074
  platform: "kubernetes" | "proxmox" | "vmware" | "dockerSwarm" | "ceph";
@@ -2080,6 +2085,89 @@ ${contextBlock}
2080
2085
  })}**`;
2081
2086
  }
2082
2087
 
2088
+ /*
2089
+ * One Kubernetes resource as an "Affected Resources" list item.
2090
+ *
2091
+ * The item is titled by the most specific object the series names —
2092
+ * container, then pod, then workload, then node, then namespace — because
2093
+ * that is the thing that is actually breaching; everything above it in
2094
+ * the hierarchy is listed underneath as context. A series with no
2095
+ * Kubernetes identity at all is a cluster-level series, so it is titled
2096
+ * by the cluster.
2097
+ *
2098
+ * A container is titled together with its pod. Every replica of a
2099
+ * workload runs a container of the same name, so "Container `checkout`"
2100
+ * alone would title three crash-looping replicas identically and leave
2101
+ * the pod that tells them apart buried in the bullets.
2102
+ */
2103
+ private static getKubernetesAffectedResourceEntry(input: {
2104
+ resource: KubernetesAffectedResource;
2105
+ clusterName: string;
2106
+ value: string;
2107
+ }): AffectedResourceListEntry {
2108
+ const resource: KubernetesAffectedResource = input.resource;
2109
+
2110
+ // "Deployment", "StatefulSet", ... — the worker only ever sets one of those.
2111
+ const workloadLabel: string = resource.workloadType || "Workload";
2112
+
2113
+ let kind: string = "Cluster";
2114
+ let name: string = AffectedResourceList.code(input.clusterName);
2115
+
2116
+ if (resource.containerName) {
2117
+ kind = "Container";
2118
+ name = resource.podName
2119
+ ? `${AffectedResourceList.code(resource.containerName)} in pod ${AffectedResourceList.code(resource.podName)}`
2120
+ : AffectedResourceList.code(resource.containerName);
2121
+ } else if (resource.podName) {
2122
+ kind = "Pod";
2123
+ name = AffectedResourceList.code(resource.podName);
2124
+ } else if (resource.workloadName) {
2125
+ kind = workloadLabel;
2126
+ name = AffectedResourceList.code(resource.workloadName);
2127
+ } else if (resource.nodeName) {
2128
+ kind = "Node";
2129
+ name = AffectedResourceList.code(resource.nodeName);
2130
+ } else if (resource.namespace) {
2131
+ kind = "Namespace";
2132
+ name = AffectedResourceList.code(resource.namespace);
2133
+ }
2134
+
2135
+ const details: Array<AffectedResourceListDetail> = [];
2136
+
2137
+ if (resource.namespace && kind !== "Namespace") {
2138
+ details.push({
2139
+ label: "Namespace",
2140
+ value: AffectedResourceList.code(resource.namespace),
2141
+ });
2142
+ }
2143
+
2144
+ const titledByWorkload: boolean =
2145
+ !resource.containerName &&
2146
+ !resource.podName &&
2147
+ Boolean(resource.workloadName);
2148
+
2149
+ if (resource.workloadName && !titledByWorkload) {
2150
+ details.push({
2151
+ label: workloadLabel,
2152
+ value: AffectedResourceList.code(resource.workloadName),
2153
+ });
2154
+ }
2155
+
2156
+ if (resource.nodeName && kind !== "Node") {
2157
+ details.push({
2158
+ label: "Node",
2159
+ value: AffectedResourceList.code(resource.nodeName),
2160
+ });
2161
+ }
2162
+
2163
+ return {
2164
+ kind: kind,
2165
+ name: name,
2166
+ value: input.value,
2167
+ details: details,
2168
+ };
2169
+ }
2170
+
2083
2171
  private static async buildKubernetesRootCauseContext(input: {
2084
2172
  dataToProcess: DataToProcess;
2085
2173
  monitorStep: MonitorStep;
@@ -2116,8 +2204,6 @@ ${contextBlock}
2116
2204
 
2117
2205
  // Affected resources
2118
2206
  if (breakdown.affectedResources && breakdown.affectedResources.length > 0) {
2119
- const resourceLines: Array<string> = [];
2120
-
2121
2207
  // Sort by metric value descending (worst first) and filter out zero-value resources
2122
2208
  const sortedResources: Array<KubernetesAffectedResource> = [
2123
2209
  ...breakdown.affectedResources,
@@ -2137,108 +2223,31 @@ ${contextBlock}
2137
2223
 
2138
2224
  // Show top 10 affected resources
2139
2225
  const resourcesToShow: Array<KubernetesAffectedResource> =
2140
- sortedResources.slice(0, 10);
2141
-
2142
- // Determine which columns are present across all resources
2143
- const hasNamespace: boolean = resourcesToShow.some(
2144
- (r: KubernetesAffectedResource) => {
2145
- return r.namespace;
2146
- },
2147
- );
2148
- const hasWorkload: boolean = resourcesToShow.some(
2149
- (r: KubernetesAffectedResource) => {
2150
- return r.workloadType && r.workloadName;
2151
- },
2152
- );
2153
- const hasPod: boolean = resourcesToShow.some(
2154
- (r: KubernetesAffectedResource) => {
2155
- return r.podName;
2156
- },
2157
- );
2158
- const hasContainer: boolean = resourcesToShow.some(
2159
- (r: KubernetesAffectedResource) => {
2160
- return r.containerName;
2161
- },
2162
- );
2163
- const hasNode: boolean = resourcesToShow.some(
2164
- (r: KubernetesAffectedResource) => {
2165
- return r.nodeName;
2166
- },
2167
- );
2168
-
2169
- // Build table header
2170
- const headerCells: Array<string> = [];
2171
- if (hasNamespace) {
2172
- headerCells.push("Namespace");
2173
- }
2174
- if (hasWorkload) {
2175
- headerCells.push("Workload Type");
2176
- headerCells.push("Workload");
2177
- }
2178
- if (hasPod) {
2179
- headerCells.push("Pod");
2180
- }
2181
- if (hasContainer) {
2182
- headerCells.push("Container");
2183
- }
2184
- if (hasNode) {
2185
- headerCells.push("Node");
2186
- }
2187
- headerCells.push("Value");
2188
-
2189
- const headerRow: string = `| ${headerCells.join(" | ")} |`;
2190
- const separatorRow: string = `| ${headerCells
2191
- .map(() => {
2192
- return "---";
2193
- })
2194
- .join(" | ")} |`;
2195
-
2196
- resourceLines.push(headerRow);
2197
- resourceLines.push(separatorRow);
2198
-
2199
- for (const resource of resourcesToShow) {
2200
- const cells: Array<string> = [];
2201
-
2202
- if (hasNamespace) {
2203
- cells.push(resource.namespace ? `\`${resource.namespace}\`` : "-");
2204
- }
2205
- if (hasWorkload) {
2206
- cells.push(resource.workloadType ? `${resource.workloadType}` : "-");
2207
- cells.push(
2208
- resource.workloadName ? `\`${resource.workloadName}\`` : "-",
2209
- );
2210
- }
2211
- if (hasPod) {
2212
- cells.push(resource.podName ? `\`${resource.podName}\`` : "-");
2213
- }
2214
- if (hasContainer) {
2215
- cells.push(
2216
- resource.containerName ? `\`${resource.containerName}\`` : "-",
2217
- );
2218
- }
2219
- if (hasNode) {
2220
- cells.push(resource.nodeName ? `\`${resource.nodeName}\`` : "-");
2221
- }
2222
-
2223
- cells.push(
2224
- MonitorCriteriaEvaluator.formatPlatformResourceValue({
2225
- platform: "kubernetes",
2226
- metricName: breakdown.metricName,
2227
- value: resource.metricValue,
2228
- }),
2229
- );
2230
-
2231
- resourceLines.push(`| ${cells.join(" | ")} |`);
2232
- }
2233
-
2234
- if (sortedResources.length > 10) {
2235
- resourceLines.push(
2236
- `\n*... and ${sortedResources.length - 10} more affected resources*`,
2237
- );
2238
- }
2226
+ sortedResources.slice(0, AffectedResourceList.MAX_ENTRIES);
2239
2227
 
2240
2228
  sections.push(
2241
- `\n\n**Affected Resources** (${sortedResources.length} total)\n\n${resourceLines.join("\n")}`,
2229
+ AffectedResourceList.render({
2230
+ heading: "Affected Resources",
2231
+ overflowNoun: "affected resources",
2232
+ totalCount: sortedResources.length,
2233
+ entries: resourcesToShow.map(
2234
+ (
2235
+ resource: KubernetesAffectedResource,
2236
+ ): AffectedResourceListEntry => {
2237
+ return MonitorCriteriaEvaluator.getKubernetesAffectedResourceEntry(
2238
+ {
2239
+ resource: resource,
2240
+ clusterName: breakdown.clusterName,
2241
+ value: MonitorCriteriaEvaluator.formatPlatformResourceValue({
2242
+ platform: "kubernetes",
2243
+ metricName: breakdown.metricName,
2244
+ value: resource.metricValue,
2245
+ }),
2246
+ },
2247
+ );
2248
+ },
2249
+ ),
2250
+ }),
2242
2251
  );
2243
2252
 
2244
2253
  // Add root cause analysis based on metric type
@@ -2509,6 +2518,92 @@ ${contextBlock}
2509
2518
  return sections.length > 0 ? sections.join("\n") : null;
2510
2519
  }
2511
2520
 
2521
+ /*
2522
+ * What a Proxmox resource is, from the `pve.type` / `pve.scope` the
2523
+ * agent's transform/pve-identity processor derives from its `id`
2524
+ * (node/…, qemu/…, lxc/…, storage/…, cluster/…). A value that processor
2525
+ * does not produce is shown as it arrived rather than guessed at.
2526
+ */
2527
+ private static getProxmoxAffectedResourceKind(
2528
+ resource: ProxmoxAffectedResource,
2529
+ ): string {
2530
+ switch (resource.resourceType) {
2531
+ case "qemu":
2532
+ return "Virtual Machine";
2533
+ case "lxc":
2534
+ return "Container";
2535
+ case "node":
2536
+ return "Node";
2537
+ case "storage":
2538
+ return "Storage";
2539
+ default:
2540
+ break;
2541
+ }
2542
+
2543
+ switch (resource.scope) {
2544
+ case "guest":
2545
+ return "Guest";
2546
+ case "node":
2547
+ return "Node";
2548
+ case "storage":
2549
+ return "Storage";
2550
+ case "cluster":
2551
+ return "Cluster";
2552
+ default:
2553
+ break;
2554
+ }
2555
+
2556
+ return resource.resourceType || resource.scope || "Resource";
2557
+ }
2558
+
2559
+ /*
2560
+ * One Proxmox resource as an "Affected Resources" list item: its kind,
2561
+ * its name next to its `qemu/100`-style id, and the node it runs on.
2562
+ */
2563
+ private static getProxmoxAffectedResourceEntry(input: {
2564
+ resource: ProxmoxAffectedResource;
2565
+ clusterName: string;
2566
+ value: string;
2567
+ }): AffectedResourceListEntry {
2568
+ const resource: ProxmoxAffectedResource = input.resource;
2569
+
2570
+ let kind: string =
2571
+ MonitorCriteriaEvaluator.getProxmoxAffectedResourceKind(resource);
2572
+ let name: string = AffectedResourceList.codeWithId({
2573
+ name: resource.resourceName,
2574
+ id: resource.resourceId,
2575
+ });
2576
+
2577
+ if (!name && resource.nodeName) {
2578
+ // A per-node series that carries no id of its own.
2579
+ kind = "Node";
2580
+ name = AffectedResourceList.code(resource.nodeName);
2581
+ }
2582
+
2583
+ if (!name) {
2584
+ // Nothing narrower than the cluster — a cluster-wide series.
2585
+ kind = "Cluster";
2586
+ name = AffectedResourceList.code(input.clusterName);
2587
+ }
2588
+
2589
+ const details: Array<AffectedResourceListDetail> = [];
2590
+
2591
+ // A node's own row would only repeat its name as "Node: …".
2592
+ if (resource.nodeName && kind !== "Node") {
2593
+ details.push({
2594
+ label: "Node",
2595
+ value: AffectedResourceList.code(resource.nodeName),
2596
+ });
2597
+ }
2598
+
2599
+ return {
2600
+ kind: kind,
2601
+ name: name,
2602
+ value: input.value,
2603
+ details: details,
2604
+ };
2605
+ }
2606
+
2512
2607
  private static buildProxmoxRootCauseContext(input: {
2513
2608
  dataToProcess: DataToProcess;
2514
2609
  monitorStep: MonitorStep;
@@ -2577,8 +2672,8 @@ ${contextBlock}
2577
2672
  );
2578
2673
  }
2579
2674
 
2580
- // Affected resources (Resource / Type / Node / Value)
2581
- let renderedBreakdownTable: boolean = false;
2675
+ // Affected resources: a ranked list of kind, name and node
2676
+ let renderedBreakdownList: boolean = false;
2582
2677
 
2583
2678
  if (breakdown && breakdown.affectedResources.length > 0) {
2584
2679
  /*
@@ -2586,7 +2681,7 @@ ${contextBlock}
2586
2681
  * first, top 10. Note that for availability metrics (pve_up)
2587
2682
  * zero-valued rows ARE the down resources — those still drive
2588
2683
  * alerting through the per-series criteria evaluation; this
2589
- * table is supplementary context only.
2684
+ * list is supplementary context only.
2590
2685
  */
2591
2686
  const sortedResources: Array<ProxmoxAffectedResource> = [
2592
2687
  ...breakdown.affectedResources,
@@ -2599,7 +2694,7 @@ ${contextBlock}
2599
2694
  });
2600
2695
 
2601
2696
  /*
2602
- * Skip the table when no row carries any identity label
2697
+ * Skip the list when no row carries any identity label
2603
2698
  * (cluster-wide series) — it would add nothing.
2604
2699
  */
2605
2700
  const hasIdentity: boolean = sortedResources.some(
@@ -2610,55 +2705,41 @@ ${contextBlock}
2610
2705
 
2611
2706
  if (sortedResources.length > 0 && hasIdentity) {
2612
2707
  const resourcesToShow: Array<ProxmoxAffectedResource> =
2613
- sortedResources.slice(0, 10);
2614
-
2615
- const resourceLines: Array<string> = [];
2616
- resourceLines.push(`| Resource | Type | Node | Value |`);
2617
- resourceLines.push(`| --- | --- | --- | --- |`);
2618
-
2619
- for (const resource of resourcesToShow) {
2620
- let resourceCell: string = "-";
2621
- if (resource.resourceName && resource.resourceId) {
2622
- resourceCell = `\`${resource.resourceName}\` (\`${resource.resourceId}\`)`;
2623
- } else if (resource.resourceId) {
2624
- resourceCell = `\`${resource.resourceId}\``;
2625
- } else if (resource.resourceName) {
2626
- resourceCell = `\`${resource.resourceName}\``;
2627
- }
2628
-
2629
- const typeCell: string =
2630
- resource.resourceType || resource.scope || "-";
2631
- const nodeCell: string = resource.nodeName
2632
- ? `\`${resource.nodeName}\``
2633
- : "-";
2634
-
2635
- resourceLines.push(
2636
- `| ${resourceCell} | ${typeCell} | ${nodeCell} | ${MonitorCriteriaEvaluator.formatPlatformResourceValue(
2637
- {
2638
- platform: "proxmox",
2639
- metricName: breakdown.metricName,
2640
- value: resource.metricValue,
2641
- },
2642
- )} |`,
2643
- );
2644
- }
2645
-
2646
- if (sortedResources.length > 10) {
2647
- resourceLines.push(
2648
- `\n*... and ${sortedResources.length - 10} more affected resources*`,
2649
- );
2650
- }
2708
+ sortedResources.slice(0, AffectedResourceList.MAX_ENTRIES);
2651
2709
 
2652
2710
  sections.push(
2653
- `\n\n**Affected Resources** (${sortedResources.length} total)\n\n${resourceLines.join("\n")}`,
2711
+ AffectedResourceList.render({
2712
+ heading: "Affected Resources",
2713
+ overflowNoun: "affected resources",
2714
+ totalCount: sortedResources.length,
2715
+ entries: resourcesToShow.map(
2716
+ (
2717
+ resource: ProxmoxAffectedResource,
2718
+ ): AffectedResourceListEntry => {
2719
+ return MonitorCriteriaEvaluator.getProxmoxAffectedResourceEntry(
2720
+ {
2721
+ resource: resource,
2722
+ clusterName: breakdown.clusterName,
2723
+ value: MonitorCriteriaEvaluator.formatPlatformResourceValue(
2724
+ {
2725
+ platform: "proxmox",
2726
+ metricName: breakdown.metricName,
2727
+ value: resource.metricValue,
2728
+ },
2729
+ ),
2730
+ },
2731
+ );
2732
+ },
2733
+ ),
2734
+ }),
2654
2735
  );
2655
- renderedBreakdownTable = true;
2736
+ renderedBreakdownList = true;
2656
2737
  }
2657
2738
  }
2658
2739
 
2659
- // Metric results summary (fallback context when no table rendered)
2740
+ // Metric results summary (fallback context when no list rendered)
2660
2741
  if (
2661
- !renderedBreakdownTable &&
2742
+ !renderedBreakdownList &&
2662
2743
  metricResponse.metricResult &&
2663
2744
  metricResponse.metricResult.length > 0
2664
2745
  ) {
@@ -2684,8 +2765,8 @@ ${contextBlock}
2684
2765
  * Which vSphere object one VMware breakdown row describes, resolved
2685
2766
  * from the identity attributes the vcenter receiver stamped on it —
2686
2767
  * most specific first, in the same order the ingest inventory scan
2687
- * uses, so the Kind column here and the inventory's `kind` never
2688
- * disagree about the same series. A VM row carries its parent host
2768
+ * uses, so the kind an Affected Resources item is titled with and the
2769
+ * inventory's `kind` never disagree about the same series. A VM row carries its parent host
2689
2770
  * (and often a resource pool), so the VM check must run before the
2690
2771
  * host and pool checks.
2691
2772
  */
@@ -2719,6 +2800,98 @@ ${contextBlock}
2719
2800
  return undefined;
2720
2801
  }
2721
2802
 
2803
+ /*
2804
+ * One vSphere object as an "Affected Resources" list item, titled by
2805
+ * the object itself, with the ESXi host and cluster it sits under
2806
+ * listed beneath it.
2807
+ */
2808
+ private static getVMwareAffectedResourceEntry(input: {
2809
+ resource: VMwareAffectedResource;
2810
+ vcenterName: string;
2811
+ value: string;
2812
+ }): AffectedResourceListEntry {
2813
+ const resource: VMwareAffectedResource = input.resource;
2814
+
2815
+ const kind: string | undefined =
2816
+ MonitorCriteriaEvaluator.getVMwareAffectedResourceKind(resource);
2817
+
2818
+ let name: string = "";
2819
+ let showHost: boolean = false;
2820
+
2821
+ switch (kind) {
2822
+ case "Virtual Machine":
2823
+ /*
2824
+ * The VM's display name, falling back to its instance UUID
2825
+ * (`vcenter.vm.id`) when the receiver stamped no name. The Host
2826
+ * detail is the ESXi host the VM is running on.
2827
+ */
2828
+ name = AffectedResourceList.code(resource.vmName || resource.vmId);
2829
+ showHost = true;
2830
+ break;
2831
+ case "Resource Pool":
2832
+ /*
2833
+ * Pool names are only unique within a parent, so the inventory
2834
+ * path is shown next to the name. The Host detail is the owner
2835
+ * host for a pool on a standalone ESXi host (pools under a
2836
+ * cluster show the cluster).
2837
+ */
2838
+ name = AffectedResourceList.codeWithId({
2839
+ name: resource.resourcePoolName,
2840
+ id: resource.resourcePoolPath,
2841
+ });
2842
+ showHost = true;
2843
+ break;
2844
+ case "Host":
2845
+ // The host IS the resource; a "Host:" detail would repeat it.
2846
+ name = AffectedResourceList.code(resource.hostName);
2847
+ break;
2848
+ case "Datastore":
2849
+ name = AffectedResourceList.code(resource.datastoreName);
2850
+ break;
2851
+ case "Cluster":
2852
+ name = AffectedResourceList.code(resource.clusterName);
2853
+ break;
2854
+ case "Datacenter":
2855
+ name = AffectedResourceList.code(resource.datacenterName);
2856
+ break;
2857
+ default:
2858
+ break;
2859
+ }
2860
+
2861
+ const details: Array<AffectedResourceListDetail> = [];
2862
+
2863
+ if (showHost && resource.hostName) {
2864
+ details.push({
2865
+ label: "Host",
2866
+ value: AffectedResourceList.code(resource.hostName),
2867
+ });
2868
+ }
2869
+
2870
+ if (kind !== "Cluster" && resource.clusterName) {
2871
+ details.push({
2872
+ label: "Cluster",
2873
+ value: AffectedResourceList.code(resource.clusterName),
2874
+ });
2875
+ }
2876
+
2877
+ if (!kind || !name) {
2878
+ // No vSphere identity on the series — it describes the vCenter as a whole.
2879
+ return {
2880
+ kind: "vCenter",
2881
+ name: AffectedResourceList.code(input.vcenterName),
2882
+ value: input.value,
2883
+ details: details,
2884
+ };
2885
+ }
2886
+
2887
+ return {
2888
+ kind: kind,
2889
+ name: name,
2890
+ value: input.value,
2891
+ details: details,
2892
+ };
2893
+ }
2894
+
2722
2895
  private static buildVMwareRootCauseContext(input: {
2723
2896
  dataToProcess: DataToProcess;
2724
2897
  monitorStep: MonitorStep;
@@ -2802,18 +2975,18 @@ ${contextBlock}
2802
2975
  sections.push(`**vCenter Details**\n${vcenterDetails.join("\n")}`);
2803
2976
  }
2804
2977
 
2805
- // Affected resources (Resource / Kind / Host / Cluster / Value)
2806
- let renderedBreakdownTable: boolean = false;
2978
+ // Affected resources: a ranked list of object, host and cluster
2979
+ let renderedBreakdownList: boolean = false;
2807
2980
 
2808
2981
  if (breakdown && breakdown.affectedResources.length > 0) {
2809
2982
  /*
2810
2983
  * K8s/Proxmox-parity render: drop zero-value rows, worst (highest)
2811
2984
  * first, top 10. For count metrics filtered to an unhealthy state
2812
2985
  * (`vcenter.datacenter.host.count{status=red}`) the non-zero rows
2813
- * ARE the objects with a problem, so the table reads correctly;
2986
+ * ARE the objects with a problem, so the list reads correctly;
2814
2987
  * a zero row means "nothing in that state" and adds nothing. The
2815
2988
  * per-series criteria evaluation is what actually alerts; this
2816
- * table is supplementary context only.
2989
+ * list is supplementary context only.
2817
2990
  */
2818
2991
  const sortedResources: Array<VMwareAffectedResource> = [
2819
2992
  ...breakdown.affectedResources,
@@ -2826,7 +2999,7 @@ ${contextBlock}
2826
2999
  });
2827
3000
 
2828
3001
  /*
2829
- * Skip the table when no row carries any identity attribute — it
3002
+ * Skip the list when no row carries any identity attribute — it
2830
3003
  * would add nothing. Every vcenter-receiver series carries at
2831
3004
  * least `vcenter.datacenter.name`, so this only trips on a
2832
3005
  * breakdown the worker could not attribute at all.
@@ -2841,96 +3014,35 @@ ${contextBlock}
2841
3014
 
2842
3015
  if (sortedResources.length > 0 && hasIdentity) {
2843
3016
  const resourcesToShow: Array<VMwareAffectedResource> =
2844
- sortedResources.slice(0, 10);
2845
-
2846
- const resourceLines: Array<string> = [];
2847
- resourceLines.push(`| Resource | Kind | Host | Cluster | Value |`);
2848
- resourceLines.push(`| --- | --- | --- | --- | --- |`);
2849
-
2850
- for (const resource of resourcesToShow) {
2851
- const kind: string | undefined =
2852
- MonitorCriteriaEvaluator.getVMwareAffectedResourceKind(resource);
2853
-
2854
- let resourceCell: string = "-";
2855
- let hostCell: string = "-";
2856
-
2857
- switch (kind) {
2858
- case "Virtual Machine":
2859
- /*
2860
- * The VM's display name, falling back to its instance
2861
- * UUID (`vcenter.vm.id`) when the receiver stamped no
2862
- * name. The Host column carries the ESXi host the VM is
2863
- * running on.
2864
- */
2865
- resourceCell = resource.vmName
2866
- ? `\`${resource.vmName}\``
2867
- : `\`${resource.vmId}\``;
2868
- hostCell = resource.hostName ? `\`${resource.hostName}\`` : "-";
2869
- break;
2870
- case "Resource Pool":
2871
- /*
2872
- * Pool names are only unique within a parent, so the
2873
- * inventory path is shown next to the name. The Host
2874
- * column is the owner host for a pool on a standalone
2875
- * ESXi host (pools under a cluster show the cluster).
2876
- */
2877
- if (resource.resourcePoolName && resource.resourcePoolPath) {
2878
- resourceCell = `\`${resource.resourcePoolName}\` (\`${resource.resourcePoolPath}\`)`;
2879
- } else {
2880
- resourceCell = `\`${resource.resourcePoolPath || resource.resourcePoolName}\``;
2881
- }
2882
- hostCell = resource.hostName ? `\`${resource.hostName}\`` : "-";
2883
- break;
2884
- case "Host":
2885
- // The host IS the resource; repeating it in the Host column adds nothing.
2886
- resourceCell = `\`${resource.hostName}\``;
2887
- break;
2888
- case "Datastore":
2889
- resourceCell = `\`${resource.datastoreName}\``;
2890
- break;
2891
- case "Cluster":
2892
- resourceCell = `\`${resource.clusterName}\``;
2893
- break;
2894
- case "Datacenter":
2895
- resourceCell = `\`${resource.datacenterName}\``;
2896
- break;
2897
- default:
2898
- break;
2899
- }
2900
-
2901
- const kindCell: string = kind || "-";
2902
- const clusterCell: string =
2903
- kind !== "Cluster" && resource.clusterName
2904
- ? `\`${resource.clusterName}\``
2905
- : "-";
2906
-
2907
- resourceLines.push(
2908
- `| ${resourceCell} | ${kindCell} | ${hostCell} | ${clusterCell} | ${MonitorCriteriaEvaluator.formatPlatformResourceValue(
2909
- {
2910
- platform: "vmware",
2911
- metricName: breakdown.metricName,
2912
- value: resource.metricValue,
2913
- },
2914
- )} |`,
2915
- );
2916
- }
2917
-
2918
- if (sortedResources.length > 10) {
2919
- resourceLines.push(
2920
- `\n*... and ${sortedResources.length - 10} more affected resources*`,
2921
- );
2922
- }
3017
+ sortedResources.slice(0, AffectedResourceList.MAX_ENTRIES);
2923
3018
 
2924
3019
  sections.push(
2925
- `\n\n**Affected Resources** (${sortedResources.length} total)\n\n${resourceLines.join("\n")}`,
3020
+ AffectedResourceList.render({
3021
+ heading: "Affected Resources",
3022
+ overflowNoun: "affected resources",
3023
+ totalCount: sortedResources.length,
3024
+ entries: resourcesToShow.map(
3025
+ (resource: VMwareAffectedResource): AffectedResourceListEntry => {
3026
+ return MonitorCriteriaEvaluator.getVMwareAffectedResourceEntry({
3027
+ resource: resource,
3028
+ vcenterName: breakdown.vcenterName,
3029
+ value: MonitorCriteriaEvaluator.formatPlatformResourceValue({
3030
+ platform: "vmware",
3031
+ metricName: breakdown.metricName,
3032
+ value: resource.metricValue,
3033
+ }),
3034
+ });
3035
+ },
3036
+ ),
3037
+ }),
2926
3038
  );
2927
- renderedBreakdownTable = true;
3039
+ renderedBreakdownList = true;
2928
3040
  }
2929
3041
  }
2930
3042
 
2931
- // Metric results summary (fallback context when no table rendered)
3043
+ // Metric results summary (fallback context when no list rendered)
2932
3044
  if (
2933
- !renderedBreakdownTable &&
3045
+ !renderedBreakdownList &&
2934
3046
  metricResponse.metricResult &&
2935
3047
  metricResponse.metricResult.length > 0
2936
3048
  ) {
@@ -2952,6 +3064,55 @@ ${contextBlock}
2952
3064
  return sections.length > 0 ? sections.join("\n") : null;
2953
3065
  }
2954
3066
 
3067
+ /*
3068
+ * One Docker Swarm task as an "Affected Tasks" list item, with the
3069
+ * service it belongs to and the node it is scheduled on beneath it.
3070
+ */
3071
+ private static getDockerSwarmAffectedResourceEntry(input: {
3072
+ resource: DockerSwarmAffectedResource;
3073
+ clusterName: string;
3074
+ value: string;
3075
+ }): AffectedResourceListEntry {
3076
+ const resource: DockerSwarmAffectedResource = input.resource;
3077
+
3078
+ let kind: string = "Cluster";
3079
+ let name: string = AffectedResourceList.code(input.clusterName);
3080
+
3081
+ if (resource.containerName) {
3082
+ kind = "Task";
3083
+ name = AffectedResourceList.code(resource.containerName);
3084
+ } else if (resource.serviceName) {
3085
+ kind = "Service";
3086
+ name = AffectedResourceList.code(resource.serviceName);
3087
+ } else if (resource.nodeName) {
3088
+ kind = "Node";
3089
+ name = AffectedResourceList.code(resource.nodeName);
3090
+ }
3091
+
3092
+ const details: Array<AffectedResourceListDetail> = [];
3093
+
3094
+ if (resource.serviceName && kind !== "Service") {
3095
+ details.push({
3096
+ label: "Service",
3097
+ value: AffectedResourceList.code(resource.serviceName),
3098
+ });
3099
+ }
3100
+
3101
+ if (resource.nodeName && kind !== "Node") {
3102
+ details.push({
3103
+ label: "Node",
3104
+ value: AffectedResourceList.code(resource.nodeName),
3105
+ });
3106
+ }
3107
+
3108
+ return {
3109
+ kind: kind,
3110
+ name: name,
3111
+ value: input.value,
3112
+ details: details,
3113
+ };
3114
+ }
3115
+
2955
3116
  private static buildDockerSwarmRootCauseContext(input: {
2956
3117
  dataToProcess: DataToProcess;
2957
3118
  monitorStep: MonitorStep;
@@ -3020,15 +3181,15 @@ ${contextBlock}
3020
3181
  );
3021
3182
  }
3022
3183
 
3023
- // Affected resources (Task / Service / Node / Value)
3024
- let renderedBreakdownTable: boolean = false;
3184
+ // Affected tasks: a ranked list of task, service and node
3185
+ let renderedBreakdownList: boolean = false;
3025
3186
 
3026
3187
  if (breakdown && breakdown.affectedResources.length > 0) {
3027
3188
  /*
3028
3189
  * K8s/Proxmox-parity render: drop zero-value rows, worst (highest)
3029
3190
  * first, top 10. For the task-down template the breaching rows ARE
3030
3191
  * the zero-uptime ones — those still drive alerting through the
3031
- * per-series criteria evaluation; this table is supplementary
3192
+ * per-series criteria evaluation; this list is supplementary
3032
3193
  * context only.
3033
3194
  */
3034
3195
  const sortedResources: Array<DockerSwarmAffectedResource> = [
@@ -3044,7 +3205,7 @@ ${contextBlock}
3044
3205
  );
3045
3206
 
3046
3207
  /*
3047
- * Skip the table when no row carries any identity label
3208
+ * Skip the list when no row carries any identity label
3048
3209
  * (cluster-wide series) — it would add nothing.
3049
3210
  */
3050
3211
  const hasIdentity: boolean = sortedResources.some(
@@ -3055,50 +3216,41 @@ ${contextBlock}
3055
3216
 
3056
3217
  if (sortedResources.length > 0 && hasIdentity) {
3057
3218
  const resourcesToShow: Array<DockerSwarmAffectedResource> =
3058
- sortedResources.slice(0, 10);
3059
-
3060
- const resourceLines: Array<string> = [];
3061
- resourceLines.push(`| Task / Container | Service | Node | Value |`);
3062
- resourceLines.push(`| --- | --- | --- | --- |`);
3063
-
3064
- for (const resource of resourcesToShow) {
3065
- const taskCell: string = resource.containerName
3066
- ? `\`${resource.containerName}\``
3067
- : "-";
3068
- const serviceCell: string = resource.serviceName
3069
- ? `\`${resource.serviceName}\``
3070
- : "-";
3071
- const nodeCell: string = resource.nodeName
3072
- ? `\`${resource.nodeName}\``
3073
- : "-";
3074
-
3075
- resourceLines.push(
3076
- `| ${taskCell} | ${serviceCell} | ${nodeCell} | ${MonitorCriteriaEvaluator.formatPlatformResourceValue(
3077
- {
3078
- platform: "dockerSwarm",
3079
- metricName: breakdown.metricName,
3080
- value: resource.metricValue,
3081
- },
3082
- )} |`,
3083
- );
3084
- }
3085
-
3086
- if (sortedResources.length > 10) {
3087
- resourceLines.push(
3088
- `\n*... and ${sortedResources.length - 10} more affected tasks*`,
3089
- );
3090
- }
3219
+ sortedResources.slice(0, AffectedResourceList.MAX_ENTRIES);
3091
3220
 
3092
3221
  sections.push(
3093
- `\n\n**Affected Tasks** (${sortedResources.length} total)\n\n${resourceLines.join("\n")}`,
3222
+ AffectedResourceList.render({
3223
+ heading: "Affected Tasks",
3224
+ overflowNoun: "affected tasks",
3225
+ totalCount: sortedResources.length,
3226
+ entries: resourcesToShow.map(
3227
+ (
3228
+ resource: DockerSwarmAffectedResource,
3229
+ ): AffectedResourceListEntry => {
3230
+ return MonitorCriteriaEvaluator.getDockerSwarmAffectedResourceEntry(
3231
+ {
3232
+ resource: resource,
3233
+ clusterName: breakdown.clusterName,
3234
+ value: MonitorCriteriaEvaluator.formatPlatformResourceValue(
3235
+ {
3236
+ platform: "dockerSwarm",
3237
+ metricName: breakdown.metricName,
3238
+ value: resource.metricValue,
3239
+ },
3240
+ ),
3241
+ },
3242
+ );
3243
+ },
3244
+ ),
3245
+ }),
3094
3246
  );
3095
- renderedBreakdownTable = true;
3247
+ renderedBreakdownList = true;
3096
3248
  }
3097
3249
  }
3098
3250
 
3099
- // Metric results summary (fallback context when no table rendered)
3251
+ // Metric results summary (fallback context when no list rendered)
3100
3252
  if (
3101
- !renderedBreakdownTable &&
3253
+ !renderedBreakdownList &&
3102
3254
  metricResponse.metricResult &&
3103
3255
  metricResponse.metricResult.length > 0
3104
3256
  ) {
@@ -3121,21 +3273,21 @@ ${contextBlock}
3121
3273
  }
3122
3274
 
3123
3275
  /*
3124
- * Which rows of the Ceph affected-resources table actually BREACHED.
3276
+ * Which rows of the Ceph affected-resources list actually BREACHED.
3125
3277
  *
3126
3278
  * The blanket `metricValue > 0` below is right for every count- or
3127
3279
  * level-style criteria ("> 0 active health checks", "> 85 % used"), but
3128
3280
  * it is exactly backwards for the availability signals: the OSD Down /
3129
3281
  * OSD Out / Quorum Degraded criteria fire on `< 1` over ceph_osd_up /
3130
3282
  * ceph_osd_in / ceph_mon_quorum_status, so the ZERO rows are the down
3131
- * daemons. Dropping them rendered a table of the HEALTHY daemons under
3283
+ * daemons. Dropping them rendered a list of the HEALTHY daemons under
3132
3284
  * an incident that tells the reader to "check the root cause for the
3133
3285
  * affected ceph_daemon label".
3134
3286
  *
3135
3287
  * Invert only for a criteria that fires when the metric FALLS.
3136
3288
  * Everything else — every `> 0` health check, PG count, latency and
3137
3289
  * capacity ratio, and every `= 0` recovery criteria — keeps the
3138
- * existing `> 0`, worst-highest-first table byte for byte.
3290
+ * existing `> 0`, worst-highest-first list byte for byte.
3139
3291
  */
3140
3292
  private static getCephBreachPredicate(
3141
3293
  criteriaInstance?: MonitorCriteriaInstance | undefined,
@@ -3182,6 +3334,85 @@ ${contextBlock}
3182
3334
  };
3183
3335
  }
3184
3336
 
3337
+ /*
3338
+ * One Ceph daemon or pool as an "Affected Resources" list item, with
3339
+ * the pool and host it belongs to beneath it.
3340
+ */
3341
+ private static getCephAffectedResourceEntry(input: {
3342
+ resource: CephAffectedResource;
3343
+ clusterName: string;
3344
+ metricName: string;
3345
+ value: string;
3346
+ }): AffectedResourceListEntry {
3347
+ const resource: CephAffectedResource = input.resource;
3348
+
3349
+ /*
3350
+ * The worker stores every series' `name` label as poolName, but only
3351
+ * ceph_pool_metadata's `name` is a pool — and that series always
3352
+ * carries pool_id too. On ceph_health_detail, `name` is the health
3353
+ * check (RECENT_CRASH, OSD_NEARFULL, ...), and titling it "Pool" told
3354
+ * the reader a pool called OSD_NEARFULL was the problem. So a name is
3355
+ * treated as a pool only when it arrives with a pool id.
3356
+ */
3357
+ const pool: string = resource.poolId
3358
+ ? AffectedResourceList.codeWithId({
3359
+ name: resource.poolName,
3360
+ id: resource.poolId,
3361
+ })
3362
+ : "";
3363
+
3364
+ const otherName: string = resource.poolId
3365
+ ? ""
3366
+ : AffectedResourceList.code(resource.poolName);
3367
+
3368
+ const otherNameKind: string =
3369
+ input.metricName === "ceph_health_detail" ? "Health Check" : "Resource";
3370
+
3371
+ let kind: string = "Cluster";
3372
+ let name: string = AffectedResourceList.code(input.clusterName);
3373
+
3374
+ if (resource.daemon) {
3375
+ kind = "Daemon";
3376
+ name = AffectedResourceList.code(resource.daemon);
3377
+ } else if (pool) {
3378
+ kind = "Pool";
3379
+ name = pool;
3380
+ } else if (otherName) {
3381
+ kind = otherNameKind;
3382
+ name = otherName;
3383
+ } else if (resource.hostname) {
3384
+ kind = "Host";
3385
+ name = AffectedResourceList.code(resource.hostname);
3386
+ }
3387
+
3388
+ const details: Array<AffectedResourceListDetail> = [];
3389
+
3390
+ if (pool && name !== pool) {
3391
+ details.push({ label: "Pool", value: pool });
3392
+ }
3393
+
3394
+ if (otherName && name !== otherName) {
3395
+ details.push({
3396
+ label: otherNameKind === "Resource" ? "Name" : otherNameKind,
3397
+ value: otherName,
3398
+ });
3399
+ }
3400
+
3401
+ if (resource.hostname && kind !== "Host") {
3402
+ details.push({
3403
+ label: "Host",
3404
+ value: AffectedResourceList.code(resource.hostname),
3405
+ });
3406
+ }
3407
+
3408
+ return {
3409
+ kind: kind,
3410
+ name: name,
3411
+ value: input.value,
3412
+ details: details,
3413
+ };
3414
+ }
3415
+
3185
3416
  private static buildCephRootCauseContext(input: {
3186
3417
  dataToProcess: DataToProcess;
3187
3418
  monitorStep: MonitorStep;
@@ -3237,8 +3468,8 @@ ${contextBlock}
3237
3468
  sections.push(`**Ceph Cluster Details**\n${clusterDetails.join("\n")}`);
3238
3469
  }
3239
3470
 
3240
- // Affected resources (Daemon / Pool / Host / Value)
3241
- let renderedBreakdownTable: boolean = false;
3471
+ // Affected resources: a ranked list of daemon, pool and host
3472
+ let renderedBreakdownList: boolean = false;
3242
3473
 
3243
3474
  if (breakdown && breakdown.affectedResources.length > 0) {
3244
3475
  /*
@@ -3267,7 +3498,7 @@ ${contextBlock}
3267
3498
  });
3268
3499
 
3269
3500
  /*
3270
- * Skip the table when no row carries any identity label
3501
+ * Skip the list when no row carries any identity label
3271
3502
  * (cluster-wide series like ceph_health_status) — it would add
3272
3503
  * nothing.
3273
3504
  */
@@ -3279,57 +3510,36 @@ ${contextBlock}
3279
3510
 
3280
3511
  if (sortedResources.length > 0 && hasIdentity) {
3281
3512
  const resourcesToShow: Array<CephAffectedResource> =
3282
- sortedResources.slice(0, 10);
3283
-
3284
- const resourceLines: Array<string> = [];
3285
- resourceLines.push(`| Daemon | Pool | Host | Value |`);
3286
- resourceLines.push(`| --- | --- | --- | --- |`);
3287
-
3288
- for (const resource of resourcesToShow) {
3289
- const daemonCell: string = resource.daemon
3290
- ? `\`${resource.daemon}\``
3291
- : "-";
3292
-
3293
- let poolCell: string = "-";
3294
- if (resource.poolName && resource.poolId) {
3295
- poolCell = `\`${resource.poolName}\` (\`${resource.poolId}\`)`;
3296
- } else if (resource.poolName) {
3297
- poolCell = `\`${resource.poolName}\``;
3298
- } else if (resource.poolId) {
3299
- poolCell = `\`${resource.poolId}\``;
3300
- }
3301
-
3302
- const hostCell: string = resource.hostname
3303
- ? `\`${resource.hostname}\``
3304
- : "-";
3305
-
3306
- resourceLines.push(
3307
- `| ${daemonCell} | ${poolCell} | ${hostCell} | ${MonitorCriteriaEvaluator.formatPlatformResourceValue(
3308
- {
3309
- platform: "ceph",
3310
- metricName: breakdown.metricName,
3311
- value: resource.metricValue,
3312
- },
3313
- )} |`,
3314
- );
3315
- }
3316
-
3317
- if (sortedResources.length > 10) {
3318
- resourceLines.push(
3319
- `\n*... and ${sortedResources.length - 10} more affected resources*`,
3320
- );
3321
- }
3513
+ sortedResources.slice(0, AffectedResourceList.MAX_ENTRIES);
3322
3514
 
3323
3515
  sections.push(
3324
- `\n\n**Affected Resources** (${sortedResources.length} total)\n\n${resourceLines.join("\n")}`,
3516
+ AffectedResourceList.render({
3517
+ heading: "Affected Resources",
3518
+ overflowNoun: "affected resources",
3519
+ totalCount: sortedResources.length,
3520
+ entries: resourcesToShow.map(
3521
+ (resource: CephAffectedResource): AffectedResourceListEntry => {
3522
+ return MonitorCriteriaEvaluator.getCephAffectedResourceEntry({
3523
+ resource: resource,
3524
+ clusterName: breakdown.clusterName,
3525
+ metricName: breakdown.metricName,
3526
+ value: MonitorCriteriaEvaluator.formatPlatformResourceValue({
3527
+ platform: "ceph",
3528
+ metricName: breakdown.metricName,
3529
+ value: resource.metricValue,
3530
+ }),
3531
+ });
3532
+ },
3533
+ ),
3534
+ }),
3325
3535
  );
3326
- renderedBreakdownTable = true;
3536
+ renderedBreakdownList = true;
3327
3537
  }
3328
3538
  }
3329
3539
 
3330
- // Metric results summary (fallback context when no table rendered)
3540
+ // Metric results summary (fallback context when no list rendered)
3331
3541
  if (
3332
- !renderedBreakdownTable &&
3542
+ !renderedBreakdownList &&
3333
3543
  metricResponse.metricResult &&
3334
3544
  metricResponse.metricResult.length > 0
3335
3545
  ) {