@oneuptime/common 12.0.1 → 12.0.3

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 (385) hide show
  1. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
  2. package/Models/DatabaseModels/Host.ts +12 -4
  3. package/Models/DatabaseModels/Index.ts +2 -0
  4. package/Models/DatabaseModels/KubernetesContainer.ts +5 -4
  5. package/Models/DatabaseModels/KubernetesResource.ts +8 -7
  6. package/Models/DatabaseModels/LogDropFilter.ts +9 -20
  7. package/Models/DatabaseModels/PodmanResource.ts +6 -6
  8. package/Models/DatabaseModels/ServiceLevelObjective.ts +91 -0
  9. package/Models/DatabaseModels/StatusPage.ts +95 -0
  10. package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
  11. package/Models/DatabaseModels/StatusPageResource.ts +73 -0
  12. package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
  13. package/Server/API/BaseAPI.ts +13 -2
  14. package/Server/API/DashboardAPI.ts +39 -0
  15. package/Server/API/TeamMemberAPI.ts +85 -0
  16. package/Server/EnvironmentConfig.ts +31 -1
  17. package/Server/Infrastructure/GlobalCache.ts +115 -0
  18. package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.ts +84 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.ts +40 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.ts +131 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.ts +25 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  25. package/Server/Middleware/ProjectAuthorization.ts +66 -4
  26. package/Server/Services/AlertStateTimelineService.ts +20 -0
  27. package/Server/Services/BillingService.ts +600 -51
  28. package/Server/Services/CephClusterService.ts +27 -45
  29. package/Server/Services/CephResourceService.ts +43 -4
  30. package/Server/Services/CloudResourceService.ts +24 -42
  31. package/Server/Services/DatabaseService.ts +198 -6
  32. package/Server/Services/DockerHostService.ts +20 -38
  33. package/Server/Services/DockerResourceService.ts +62 -8
  34. package/Server/Services/DockerSwarmClusterService.ts +28 -46
  35. package/Server/Services/DockerSwarmResourceService.ts +53 -4
  36. package/Server/Services/HostService.ts +47 -57
  37. package/Server/Services/IncidentStateTimelineService.ts +20 -0
  38. package/Server/Services/Index.ts +2 -0
  39. package/Server/Services/IoTDeviceService.ts +1 -17
  40. package/Server/Services/IoTFleetService.ts +20 -38
  41. package/Server/Services/KubernetesClusterService.ts +18 -36
  42. package/Server/Services/KubernetesContainerService.ts +50 -9
  43. package/Server/Services/KubernetesResourceService.ts +53 -7
  44. package/Server/Services/LabelService.ts +153 -1
  45. package/Server/Services/MetricTypeService.ts +84 -0
  46. package/Server/Services/MonitorService.ts +146 -14
  47. package/Server/Services/MonitorStatusTimelineService.ts +29 -0
  48. package/Server/Services/MonitorTemplateService.ts +65 -0
  49. package/Server/Services/PodmanHostService.ts +20 -38
  50. package/Server/Services/PodmanResourceService.ts +62 -8
  51. package/Server/Services/ProjectService.ts +165 -35
  52. package/Server/Services/ProxmoxClusterService.ts +24 -42
  53. package/Server/Services/ProxmoxResourceService.ts +43 -4
  54. package/Server/Services/RumApplicationService.ts +20 -38
  55. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
  56. package/Server/Services/ServerlessFunctionService.ts +25 -43
  57. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +426 -0
  58. package/Server/Services/ServiceLevelObjectiveService.ts +39 -0
  59. package/Server/Services/ServiceService.ts +299 -73
  60. package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
  61. package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
  62. package/Server/Services/StatusPageService.ts +95 -36
  63. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +18 -1
  64. package/Server/Services/StatusPageSubscriberService.ts +3 -0
  65. package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
  66. package/Server/Services/TelemetryEntityService.ts +1 -0
  67. package/Server/Types/Database/JSONColumnQuery.ts +621 -0
  68. package/Server/Types/Database/Permissions/PublicPermission.ts +9 -2
  69. package/Server/Types/Database/QueryHelper.ts +17 -32
  70. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
  71. package/Server/Utils/Database/TruncateColumnValue.ts +84 -0
  72. package/Server/Utils/Monitor/MonitorResource.ts +63 -36
  73. package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
  74. package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
  75. package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
  76. package/Server/Utils/SingleFlight.ts +83 -0
  77. package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +46 -0
  78. package/Server/Utils/Telemetry/EntityRegistry.ts +107 -26
  79. package/Server/Utils/Telemetry/ResourceHeartbeat.ts +314 -0
  80. package/Server/Utils/Telemetry/Telemetry.ts +351 -122
  81. package/Tests/App/Dashboard/UsersTableGroupsByPerson.test.tsx +448 -0
  82. package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
  83. package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
  84. package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
  85. package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
  86. package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +704 -0
  87. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
  88. package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +303 -0
  89. package/Tests/Server/Infrastructure/GlobalCache.test.ts +226 -0
  90. package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
  91. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +350 -0
  92. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyHeader.test.ts +362 -0
  93. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +687 -0
  94. package/Tests/Server/Services/BillingService.test.ts +78 -3
  95. package/Tests/Server/Services/BillingServiceChangePlanCancel.test.ts +645 -0
  96. package/Tests/Server/Services/BillingServiceTrialPlanChange.test.ts +1005 -0
  97. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
  98. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
  99. package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +503 -0
  100. package/Tests/Server/Services/HostIpAddressesColumnWidth.test.ts +198 -0
  101. package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +658 -0
  102. package/Tests/Server/Services/InventoryResourceNameColumnWidth.test.ts +500 -0
  103. package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +586 -0
  104. package/Tests/Server/Services/InventoryUpsertTruncationGuard.test.ts +1242 -0
  105. package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
  106. package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
  107. package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
  108. package/Tests/Server/Services/ProjectServiceChangePlan.test.ts +650 -0
  109. package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +1 -0
  110. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +636 -0
  111. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +770 -0
  112. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +130 -0
  113. package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -0
  114. package/Tests/Server/Services/SloMonitorLabelRuleHooks.test.ts +352 -0
  115. package/Tests/Server/Services/StatusPageMonitorRuleEngineService.test.ts +1719 -0
  116. package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +1212 -0
  117. package/Tests/Server/Services/StatusPageMonitorRuleMonitorCreateHook.test.ts +228 -0
  118. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +29 -13
  119. package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +69 -8
  120. package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +593 -0
  121. package/Tests/Server/Types/Database/Permissions/PublicPermission.test.ts +495 -0
  122. package/Tests/Server/Types/Database/QueryUtil.test.ts +113 -0
  123. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
  124. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
  125. package/Tests/Server/Utils/Database/TruncateColumnValue.test.ts +179 -0
  126. package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
  127. package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
  128. package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
  129. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
  130. package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
  131. package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
  132. package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
  133. package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
  134. package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
  135. package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
  136. package/Tests/Types/Decimal.test.ts +37 -0
  137. package/Tests/Types/Events/Recurring.test.ts +157 -0
  138. package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
  139. package/Tests/Types/Port.test.ts +38 -0
  140. package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
  141. package/Tests/UI/Components/ModelTable/ModelTableGroupsProjectUsers.test.tsx +375 -0
  142. package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +196 -0
  143. package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
  144. package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
  145. package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +739 -0
  146. package/Tests/UI/Utils/TeamMembersByUser.test.ts +633 -0
  147. package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
  148. package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
  149. package/Tests/Utils/StatusPage/ReportPeriod.test.ts +218 -0
  150. package/Tests/Utils/Telemetry/HostIpAddresses.test.ts +291 -0
  151. package/Types/CustomField/CustomFieldDefinition.ts +24 -0
  152. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  153. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  154. package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
  155. package/Types/Dashboard/DashboardTemplates.ts +397 -0
  156. package/Types/Database/BigIntColumnTransformer.ts +74 -0
  157. package/Types/Database/DatabaseProperty.ts +26 -0
  158. package/Types/Database/NumericColumnValue.ts +128 -0
  159. package/Types/Date.ts +112 -0
  160. package/Types/Decimal.ts +16 -4
  161. package/Types/Events/Recurring.ts +99 -1
  162. package/Types/Permission.ts +48 -0
  163. package/Types/Port.ts +16 -4
  164. package/Types/StatusPage/StatusPageReport.ts +11 -0
  165. package/Types/StatusPage/StatusPageReportPeriodType.ts +21 -0
  166. package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
  167. package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
  168. package/UI/Components/ModelTable/CustomFieldColumns.tsx +2 -6
  169. package/UI/Components/ModelTable/useCustomFieldColumns.ts +21 -2
  170. package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +305 -0
  171. package/UI/Utils/TeamMembersByUser.ts +302 -0
  172. package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
  173. package/Utils/Dashboard/Components/Index.ts +7 -0
  174. package/Utils/StatusPage/ReportPeriod.ts +236 -0
  175. package/Utils/Telemetry/HostIpAddresses.ts +98 -0
  176. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
  177. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  178. package/build/dist/Models/DatabaseModels/Host.js +12 -4
  179. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  180. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  181. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  182. package/build/dist/Models/DatabaseModels/KubernetesContainer.js +4 -4
  183. package/build/dist/Models/DatabaseModels/KubernetesContainer.js.map +1 -1
  184. package/build/dist/Models/DatabaseModels/KubernetesResource.js +7 -7
  185. package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
  187. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/PodmanResource.js +6 -6
  189. package/build/dist/Models/DatabaseModels/PodmanResource.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js +87 -0
  191. package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/StatusPage.js +98 -0
  193. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
  195. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
  196. package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
  197. package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
  199. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  200. package/build/dist/Server/API/BaseAPI.js +11 -1
  201. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  202. package/build/dist/Server/API/DashboardAPI.js +39 -0
  203. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  204. package/build/dist/Server/API/TeamMemberAPI.js +57 -2
  205. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  206. package/build/dist/Server/EnvironmentConfig.js +27 -1
  207. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  208. package/build/dist/Server/Infrastructure/GlobalCache.js +91 -0
  209. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  210. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
  211. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
  212. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.js +45 -0
  213. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.js.map +1 -0
  214. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.js +31 -0
  215. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.js.map +1 -0
  216. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.js +90 -0
  217. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.js.map +1 -0
  218. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.js +14 -0
  219. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.js.map +1 -0
  220. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
  221. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
  222. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  223. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  224. package/build/dist/Server/Middleware/ProjectAuthorization.js +59 -4
  225. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  226. package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
  227. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  228. package/build/dist/Server/Services/BillingService.js +466 -36
  229. package/build/dist/Server/Services/BillingService.js.map +1 -1
  230. package/build/dist/Server/Services/CephClusterService.js +26 -39
  231. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  232. package/build/dist/Server/Services/CephResourceService.js +28 -3
  233. package/build/dist/Server/Services/CephResourceService.js.map +1 -1
  234. package/build/dist/Server/Services/CloudResourceService.js +23 -36
  235. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  236. package/build/dist/Server/Services/DatabaseService.js +155 -2
  237. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  238. package/build/dist/Server/Services/DockerHostService.js +19 -32
  239. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  240. package/build/dist/Server/Services/DockerResourceService.js +34 -4
  241. package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
  242. package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -40
  243. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  244. package/build/dist/Server/Services/DockerSwarmResourceService.js +28 -3
  245. package/build/dist/Server/Services/DockerSwarmResourceService.js.map +1 -1
  246. package/build/dist/Server/Services/HostService.js +58 -64
  247. package/build/dist/Server/Services/HostService.js.map +1 -1
  248. package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
  249. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  250. package/build/dist/Server/Services/Index.js +2 -0
  251. package/build/dist/Server/Services/Index.js.map +1 -1
  252. package/build/dist/Server/Services/IoTDeviceService.js +1 -8
  253. package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
  254. package/build/dist/Server/Services/IoTFleetService.js +19 -32
  255. package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
  256. package/build/dist/Server/Services/KubernetesClusterService.js +17 -30
  257. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  258. package/build/dist/Server/Services/KubernetesContainerService.js +29 -3
  259. package/build/dist/Server/Services/KubernetesContainerService.js.map +1 -1
  260. package/build/dist/Server/Services/KubernetesResourceService.js +32 -4
  261. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  262. package/build/dist/Server/Services/LabelService.js +127 -0
  263. package/build/dist/Server/Services/LabelService.js.map +1 -1
  264. package/build/dist/Server/Services/MetricTypeService.js +74 -0
  265. package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
  266. package/build/dist/Server/Services/MonitorService.js +128 -9
  267. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  268. package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
  269. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  270. package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
  271. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  272. package/build/dist/Server/Services/PodmanHostService.js +19 -32
  273. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  274. package/build/dist/Server/Services/PodmanResourceService.js +34 -4
  275. package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
  276. package/build/dist/Server/Services/ProjectService.js +135 -21
  277. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  278. package/build/dist/Server/Services/ProxmoxClusterService.js +23 -36
  279. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  280. package/build/dist/Server/Services/ProxmoxResourceService.js +28 -3
  281. package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -1
  282. package/build/dist/Server/Services/RumApplicationService.js +19 -32
  283. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  284. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
  285. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  286. package/build/dist/Server/Services/ServerlessFunctionService.js +24 -37
  287. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  288. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +347 -0
  289. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -0
  290. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +33 -1
  291. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  292. package/build/dist/Server/Services/ServiceService.js +236 -61
  293. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  294. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
  295. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
  296. package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
  297. package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
  298. package/build/dist/Server/Services/StatusPageService.js +69 -46
  299. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  300. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +17 -1
  301. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  302. package/build/dist/Server/Services/StatusPageSubscriberService.js +3 -0
  303. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  304. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
  305. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
  306. package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
  307. package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
  308. package/build/dist/Server/Types/Database/JSONColumnQuery.js +402 -0
  309. package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -0
  310. package/build/dist/Server/Types/Database/Permissions/PublicPermission.js +9 -2
  311. package/build/dist/Server/Types/Database/Permissions/PublicPermission.js.map +1 -1
  312. package/build/dist/Server/Types/Database/QueryHelper.js +17 -27
  313. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  314. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
  315. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  316. package/build/dist/Server/Utils/Database/TruncateColumnValue.js +32 -0
  317. package/build/dist/Server/Utils/Database/TruncateColumnValue.js.map +1 -0
  318. package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
  319. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  320. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
  321. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
  322. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
  323. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
  324. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
  325. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
  326. package/build/dist/Server/Utils/SingleFlight.js +76 -0
  327. package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
  328. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
  329. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
  330. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
  331. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  332. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
  333. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
  334. package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
  335. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  336. package/build/dist/Types/CustomField/CustomFieldDefinition.js +2 -0
  337. package/build/dist/Types/CustomField/CustomFieldDefinition.js.map +1 -0
  338. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  339. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  340. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  341. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  342. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
  343. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
  344. package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
  345. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  346. package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
  347. package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
  348. package/build/dist/Types/Database/DatabaseProperty.js +25 -0
  349. package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
  350. package/build/dist/Types/Database/NumericColumnValue.js +97 -0
  351. package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
  352. package/build/dist/Types/Date.js +68 -0
  353. package/build/dist/Types/Date.js.map +1 -1
  354. package/build/dist/Types/Decimal.js +14 -3
  355. package/build/dist/Types/Decimal.js.map +1 -1
  356. package/build/dist/Types/Events/Recurring.js +63 -0
  357. package/build/dist/Types/Events/Recurring.js.map +1 -1
  358. package/build/dist/Types/Permission.js +42 -0
  359. package/build/dist/Types/Permission.js.map +1 -1
  360. package/build/dist/Types/Port.js +15 -5
  361. package/build/dist/Types/Port.js.map +1 -1
  362. package/build/dist/Types/StatusPage/StatusPageReportPeriodType.js +22 -0
  363. package/build/dist/Types/StatusPage/StatusPageReportPeriodType.js.map +1 -0
  364. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
  365. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
  366. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
  367. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
  368. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  369. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +18 -2
  370. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
  371. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +213 -0
  372. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -0
  373. package/build/dist/UI/Utils/TeamMembersByUser.js +195 -0
  374. package/build/dist/UI/Utils/TeamMembersByUser.js.map +1 -0
  375. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
  376. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
  377. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  378. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  379. package/build/dist/Utils/StatusPage/ReportPeriod.js +131 -0
  380. package/build/dist/Utils/StatusPage/ReportPeriod.js.map +1 -0
  381. package/build/dist/Utils/Telemetry/HostIpAddresses.js +82 -0
  382. package/build/dist/Utils/Telemetry/HostIpAddresses.js.map +1 -0
  383. package/jest.config.json +2 -0
  384. package/package.json +1 -1
  385. package/tsconfig.json +12 -1
@@ -0,0 +1,152 @@
1
+ import { describe, expect, test } from "@jest/globals";
2
+ import SnmpVersion, {
3
+ SnmpVersionUtil,
4
+ } from "../../../Types/Monitor/SnmpMonitor/SnmpVersion";
5
+
6
+ /*
7
+ * snmpVersion is a free-text column with two live spellings: the enum VALUES
8
+ * ("1"/"2c"/"3") that the probe contract uses, and the enum KEYS ("V1"/"V2c"/
9
+ * "V3") that every form writes and the column default holds. SnmpVersionUtil is
10
+ * the seam that reconciles them. Reading the column any other way silently takes
11
+ * the wrong branch — a stored "V3" is not === SnmpVersion.V3 ("3"), so a v3
12
+ * device would read as v2c and be polled in cleartext.
13
+ *
14
+ * Unlike the SnmpV3 protocol parsers, parse() cannot return undefined: the probe
15
+ * must pick exactly one session type, so an unreadable value falls back to v2c
16
+ * rather than refusing. These tests pin both the recognized spellings and that
17
+ * deliberate default so a future edit cannot widen or narrow it unnoticed.
18
+ */
19
+
20
+ describe("SnmpVersionUtil.parse", () => {
21
+ test.each([
22
+ ["1", SnmpVersion.V1],
23
+ ["2c", SnmpVersion.V2c],
24
+ ["3", SnmpVersion.V3],
25
+ ])(
26
+ "reads the probe-contract value spelling %j",
27
+ (stored: string, expected: SnmpVersion) => {
28
+ expect(SnmpVersionUtil.parse(stored)).toBe(expected);
29
+ },
30
+ );
31
+
32
+ /*
33
+ * The stored spelling — what forms write and the column default holds. This
34
+ * is the spelling the bare-cast bug got wrong, so it is the one that most
35
+ * needs a test.
36
+ */
37
+ test.each([
38
+ ["V1", SnmpVersion.V1],
39
+ ["V2c", SnmpVersion.V2c],
40
+ ["V3", SnmpVersion.V3],
41
+ ])(
42
+ "reads the stored enum-key spelling %j",
43
+ (stored: string, expected: SnmpVersion) => {
44
+ expect(SnmpVersionUtil.parse(stored)).toBe(expected);
45
+ },
46
+ );
47
+
48
+ test.each([
49
+ ["V1", SnmpVersion.V1],
50
+ ["v1", SnmpVersion.V1],
51
+ [" 1 ", SnmpVersion.V1],
52
+ ["\tv3\n", SnmpVersion.V3],
53
+ ["V3", SnmpVersion.V3],
54
+ ["v3", SnmpVersion.V3],
55
+ ])(
56
+ "tolerates case and surrounding whitespace in %j",
57
+ (stored: string, expected: SnmpVersion) => {
58
+ expect(SnmpVersionUtil.parse(stored)).toBe(expected);
59
+ },
60
+ );
61
+
62
+ /*
63
+ * v2c is the fallback branch, so every v2c spelling AND every value the parser
64
+ * does not recognize must land here. The two are indistinguishable by design:
65
+ * there is no "undefined version", the probe always needs a session type, and
66
+ * v2c is the safe historic default. Anything that stops mapping to v2c here is
67
+ * a behavior change, not a bug fix.
68
+ */
69
+ test.each([
70
+ ["2c", "an exact value"],
71
+ ["V2c", "the stored key"],
72
+ ["v2c", "lowercased key"],
73
+ ["2", "the version number without the c"],
74
+ ["V2", "the key without the c"],
75
+ [undefined, "an undefined column"],
76
+ [null, "a null column"],
77
+ ["", "an empty string"],
78
+ [" ", "whitespace only"],
79
+ ["nonsense", "garbage"],
80
+ ["v4", "a version that does not exist"],
81
+ ["0", "a zero"],
82
+ ])(
83
+ "falls back to v2c for %j (%s)",
84
+ (stored: string | undefined | null, _description: string) => {
85
+ expect(SnmpVersionUtil.parse(stored)).toBe(SnmpVersion.V2c);
86
+ },
87
+ );
88
+ });
89
+
90
+ describe("SnmpVersionUtil.isV3", () => {
91
+ test.each([["3"], ["v3"], ["V3"], [" V3 "], ["\tv3\n"]])(
92
+ "is true for the v3 spelling %j",
93
+ (stored: string) => {
94
+ expect(SnmpVersionUtil.isV3(stored)).toBe(true);
95
+ },
96
+ );
97
+
98
+ /*
99
+ * The consequential direction: everything that is not v3 must read as not-v3,
100
+ * because isV3 gates whether auth/priv credentials are applied. A false
101
+ * positive would be harmless; a false negative strands a v3 device in a v2c
102
+ * branch and polls it without credentials.
103
+ */
104
+ test.each([
105
+ ["1"],
106
+ ["V1"],
107
+ ["2c"],
108
+ ["V2c"],
109
+ ["v2c"],
110
+ ["2"],
111
+ [undefined],
112
+ [null],
113
+ [""],
114
+ [" "],
115
+ ["nonsense"],
116
+ ])(
117
+ "is false for the non-v3 value %j",
118
+ (stored: string | undefined | null) => {
119
+ expect(SnmpVersionUtil.isV3(stored)).toBe(false);
120
+ },
121
+ );
122
+
123
+ test("agrees with parse() for every recognized spelling", () => {
124
+ for (const spelling of ["1", "v1", "V1", "2c", "V2c", "3", "v3", "V3"]) {
125
+ expect(SnmpVersionUtil.isV3(spelling)).toBe(
126
+ SnmpVersionUtil.parse(spelling) === SnmpVersion.V3,
127
+ );
128
+ }
129
+ });
130
+ });
131
+
132
+ describe("every enum member survives a round trip", () => {
133
+ /*
134
+ * Exhaustive over the enum rather than a fixed list, so adding a version
135
+ * without teaching parse() its value AND key spelling fails here instead of
136
+ * silently collapsing to v2c in production.
137
+ */
138
+ test("each value spelling parses back to itself", () => {
139
+ for (const member of Object.values(SnmpVersion)) {
140
+ expect(SnmpVersionUtil.parse(member)).toBe(member);
141
+ }
142
+ });
143
+
144
+ test("each key spelling parses to its member", () => {
145
+ for (const key of Object.keys(SnmpVersion)) {
146
+ // Keys are "V1"/"V2c"/"V3"; the member is looked up by that key.
147
+ const expected: SnmpVersion =
148
+ SnmpVersion[key as keyof typeof SnmpVersion];
149
+ expect(SnmpVersionUtil.parse(key)).toBe(expected);
150
+ }
151
+ });
152
+ });
@@ -36,4 +36,42 @@ describe("Testing class port", () => {
36
36
  const value: Port = new Port("6000");
37
37
  expect(typeof value.port.positiveNumber).toBe("number");
38
38
  });
39
+
40
+ /*
41
+ * A port column is declared `TableColumnType.Number`, so whatever reaches
42
+ * the transformer may be a Port, a string, or a plain number depending on
43
+ * how far the request body got through deserialization. A raw number used
44
+ * to fall off the end of `toDatabase` and return null, which wrote NULL
45
+ * over an SMTP port the user had just typed — silently, since null is a
46
+ * legal value for the column.
47
+ */
48
+ describe("getDatabaseTransformer().to", () => {
49
+ const transformer: ReturnType<typeof Port.getDatabaseTransformer> =
50
+ Port.getDatabaseTransformer();
51
+
52
+ test("stores a Port instance as its number", () => {
53
+ expect(transformer.to(new Port(587))).toBe(587);
54
+ });
55
+
56
+ test("stores a raw string port as a number", () => {
57
+ expect(transformer.to("587")).toBe(587);
58
+ });
59
+
60
+ test("stores a raw number port rather than dropping it", () => {
61
+ expect(transformer.to(587)).toBe(587);
62
+ expect(transformer.to(0)).toBe(0);
63
+ expect(transformer.to(65535)).toBe(65535);
64
+ });
65
+
66
+ test("keeps undefined distinct from null so a column DEFAULT applies", () => {
67
+ expect(transformer.to(undefined)).toBeUndefined();
68
+ expect(transformer.to(null)).toBeNull();
69
+ });
70
+
71
+ test("rejects a port outside the valid range instead of storing null", () => {
72
+ expect(() => {
73
+ return transformer.to(70000);
74
+ }).toThrow(BadDataException);
75
+ });
76
+ });
39
77
  });
@@ -0,0 +1,276 @@
1
+ /** @timezone UTC */
2
+
3
+ import LogsHistogram from "../../../UI/Components/LogsViewer/components/LogsHistogram";
4
+ import { HistogramBucket } from "../../../UI/Components/LogsViewer/types";
5
+ import LogSeverity from "../../../Types/Log/LogSeverity";
6
+ import { render, screen } from "@testing-library/react";
7
+ import React from "react";
8
+ import { describe, expect, test } from "@jest/globals";
9
+
10
+ /*
11
+ * ResponsiveContainer measures its parent, which is always 0x0 in jsdom, so the
12
+ * chart renders nothing without a fixed size.
13
+ */
14
+ jest.mock("recharts", () => {
15
+ const actual: Record<string, any> = jest.requireActual("recharts");
16
+ return {
17
+ ...actual,
18
+ ResponsiveContainer: ({ children }: { children: React.ReactElement }) => {
19
+ return React.cloneElement(children, { width: 600, height: 300 });
20
+ },
21
+ };
22
+ });
23
+
24
+ function bucket(
25
+ time: string,
26
+ severity: string,
27
+ count: number,
28
+ ): HistogramBucket {
29
+ return { time, severity, count };
30
+ }
31
+
32
+ /** One bar rectangle is drawn per severity per bucket that has a count. */
33
+ function barCount(container: HTMLElement): number {
34
+ return container.querySelectorAll(".recharts-bar-rectangle").length;
35
+ }
36
+
37
+ /** One <g> per stacked series, i.e. per severity present in the data. */
38
+ function seriesCount(container: HTMLElement): number {
39
+ return container.querySelectorAll(".recharts-bar").length;
40
+ }
41
+
42
+ const CLOCK_LABEL: RegExp = /^\d{2}:\d{2}$/;
43
+
44
+ /*
45
+ * Recharts portals tick labels out of their axis group, so the two axes are
46
+ * told apart by what they render: the time axis is formatted as a clock, the
47
+ * count axis as a number.
48
+ */
49
+ function axisLabels(
50
+ container: HTMLElement,
51
+ axis: "time" | "count",
52
+ ): Array<string> {
53
+ const labels: Array<string> = Array.from(
54
+ container.querySelectorAll(".recharts-cartesian-axis-tick-value"),
55
+ ).map((tick: Element): string => {
56
+ return tick.textContent || "";
57
+ });
58
+
59
+ return labels.filter((label: string): boolean => {
60
+ return CLOCK_LABEL.test(label) === (axis === "time");
61
+ });
62
+ }
63
+
64
+ const ONE_SEVERITY: Array<HistogramBucket> = [
65
+ bucket("2026-08-05T11:58:00Z", LogSeverity.Error, 3),
66
+ bucket("2026-08-05T11:59:00Z", LogSeverity.Error, 5),
67
+ bucket("2026-08-05T12:00:00Z", LogSeverity.Error, 7),
68
+ ];
69
+
70
+ describe("LogsHistogram", () => {
71
+ describe("empty and loading states", () => {
72
+ test("renders nothing when the window holds no logs", () => {
73
+ const { container } = render(
74
+ <LogsHistogram buckets={[]} isLoading={false} />,
75
+ );
76
+
77
+ expect(container.innerHTML).toBe("");
78
+ });
79
+
80
+ test("shows the loader on the very first load", () => {
81
+ render(<LogsHistogram buckets={[]} isLoading={true} />);
82
+
83
+ expect(screen.queryByTestId("component-loader")).not.toBeNull();
84
+ });
85
+
86
+ /*
87
+ * Live mode refreshes the histogram every few seconds. Swapping the chart
88
+ * for a loader on each poll would make it flash; the chart already on
89
+ * screen stays until the new buckets land.
90
+ */
91
+ test("keeps the chart on screen while a refresh is in flight", () => {
92
+ const { container } = render(
93
+ <LogsHistogram buckets={ONE_SEVERITY} isLoading={true} />,
94
+ );
95
+
96
+ expect(screen.queryByTestId("component-loader")).toBeNull();
97
+ expect(screen.queryByText("Log Volume")).not.toBeNull();
98
+ expect(barCount(container)).toBe(3);
99
+ });
100
+ });
101
+
102
+ describe("drawing the buckets", () => {
103
+ test("draws one bar per bucket", () => {
104
+ const { container } = render(
105
+ <LogsHistogram buckets={ONE_SEVERITY} isLoading={false} />,
106
+ );
107
+
108
+ expect(barCount(container)).toBe(3);
109
+ expect(seriesCount(container)).toBe(1);
110
+ });
111
+
112
+ test("stacks a bar per severity inside a bucket", () => {
113
+ const { container } = render(
114
+ <LogsHistogram
115
+ buckets={[
116
+ bucket("2026-08-05T12:00:00Z", LogSeverity.Error, 4),
117
+ bucket("2026-08-05T12:00:00Z", LogSeverity.Warning, 6),
118
+ bucket("2026-08-05T12:00:00Z", LogSeverity.Information, 9),
119
+ ]}
120
+ isLoading={false}
121
+ />,
122
+ );
123
+
124
+ expect(seriesCount(container)).toBe(3);
125
+ expect(barCount(container)).toBe(3);
126
+ });
127
+
128
+ test("labels the time axis in the reader's clock", () => {
129
+ const { container } = render(
130
+ <LogsHistogram buckets={ONE_SEVERITY} isLoading={false} />,
131
+ );
132
+
133
+ expect(axisLabels(container, "time")).toContain("12:00");
134
+ });
135
+
136
+ test("lists only the severities present in the window", () => {
137
+ render(
138
+ <LogsHistogram
139
+ buckets={[
140
+ bucket("2026-08-05T12:00:00Z", LogSeverity.Error, 4),
141
+ bucket("2026-08-05T12:00:00Z", LogSeverity.Debug, 1),
142
+ ]}
143
+ isLoading={false}
144
+ />,
145
+ );
146
+
147
+ expect(screen.queryByText("Error")).not.toBeNull();
148
+ expect(screen.queryByText("Debug")).not.toBeNull();
149
+ expect(screen.queryByText("Fatal")).toBeNull();
150
+ });
151
+ });
152
+
153
+ /*
154
+ * What live mode looks like from the chart's side: the same component is
155
+ * handed a fresh set of buckets every poll and has to redraw.
156
+ */
157
+ describe("when a live refresh brings new data", () => {
158
+ test("adds a bar as a new bucket opens", () => {
159
+ const view: ReturnType<typeof render> = render(
160
+ <LogsHistogram buckets={ONE_SEVERITY} isLoading={false} />,
161
+ );
162
+
163
+ expect(barCount(view.container)).toBe(3);
164
+
165
+ view.rerender(
166
+ <LogsHistogram
167
+ buckets={[
168
+ ...ONE_SEVERITY,
169
+ bucket("2026-08-05T12:01:00Z", LogSeverity.Error, 2),
170
+ ]}
171
+ isLoading={false}
172
+ />,
173
+ );
174
+
175
+ expect(barCount(view.container)).toBe(4);
176
+ });
177
+
178
+ test("follows the window as it slides off the oldest bucket", () => {
179
+ const view: ReturnType<typeof render> = render(
180
+ <LogsHistogram buckets={ONE_SEVERITY} isLoading={false} />,
181
+ );
182
+
183
+ expect(axisLabels(view.container, "time")).toContain("11:58");
184
+
185
+ view.rerender(
186
+ <LogsHistogram
187
+ buckets={[
188
+ ...ONE_SEVERITY.slice(1),
189
+ bucket("2026-08-05T12:01:00Z", LogSeverity.Error, 2),
190
+ ]}
191
+ isLoading={false}
192
+ />,
193
+ );
194
+
195
+ const labels: Array<string> = axisLabels(view.container, "time");
196
+ expect(labels).not.toContain("11:58");
197
+ expect(labels).toContain("12:01");
198
+ });
199
+
200
+ test("rescales the count axis as the newest bucket fills up", () => {
201
+ const view: ReturnType<typeof render> = render(
202
+ <LogsHistogram buckets={ONE_SEVERITY} isLoading={false} />,
203
+ );
204
+
205
+ const before: Array<string> = axisLabels(view.container, "count");
206
+
207
+ view.rerender(
208
+ <LogsHistogram
209
+ buckets={[
210
+ ...ONE_SEVERITY.slice(0, 2),
211
+ bucket("2026-08-05T12:00:00Z", LogSeverity.Error, 400),
212
+ ]}
213
+ isLoading={false}
214
+ />,
215
+ );
216
+
217
+ const after: Array<string> = axisLabels(view.container, "count");
218
+
219
+ expect(after).not.toEqual(before);
220
+ expect(Number(after[after.length - 1])).toBeGreaterThan(
221
+ Number(before[before.length - 1]),
222
+ );
223
+ });
224
+
225
+ test("adds a series and a legend entry when a new severity shows up", () => {
226
+ const view: ReturnType<typeof render> = render(
227
+ <LogsHistogram buckets={ONE_SEVERITY} isLoading={false} />,
228
+ );
229
+
230
+ expect(screen.queryByText("Fatal")).toBeNull();
231
+
232
+ view.rerender(
233
+ <LogsHistogram
234
+ buckets={[
235
+ ...ONE_SEVERITY,
236
+ bucket("2026-08-05T12:00:00Z", LogSeverity.Fatal, 1),
237
+ ]}
238
+ isLoading={false}
239
+ />,
240
+ );
241
+
242
+ expect(screen.queryByText("Fatal")).not.toBeNull();
243
+ expect(seriesCount(view.container)).toBe(2);
244
+ });
245
+
246
+ test("empties the chart when the refreshed window has no logs", () => {
247
+ const view: ReturnType<typeof render> = render(
248
+ <LogsHistogram buckets={ONE_SEVERITY} isLoading={false} />,
249
+ );
250
+
251
+ view.rerender(<LogsHistogram buckets={[]} isLoading={false} />);
252
+
253
+ expect(view.container.innerHTML).toBe("");
254
+ });
255
+ });
256
+
257
+ describe("drag to zoom", () => {
258
+ test("offers the affordance when the parent can act on a selection", () => {
259
+ render(
260
+ <LogsHistogram
261
+ buckets={ONE_SEVERITY}
262
+ isLoading={false}
263
+ onTimeRangeSelect={() => {}}
264
+ />,
265
+ );
266
+
267
+ expect(screen.queryByText("Drag to zoom")).not.toBeNull();
268
+ });
269
+
270
+ test("hides the affordance when there is nothing to zoom into", () => {
271
+ render(<LogsHistogram buckets={ONE_SEVERITY} isLoading={false} />);
272
+
273
+ expect(screen.queryByText("Drag to zoom")).toBeNull();
274
+ });
275
+ });
276
+ });