@oneuptime/common 12.0.2 → 12.0.4

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 (384) hide show
  1. package/Models/DatabaseModels/CephCluster.ts +14 -0
  2. package/Models/DatabaseModels/CodeRepository.ts +14 -6
  3. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
  4. package/Models/DatabaseModels/DockerHost.ts +14 -0
  5. package/Models/DatabaseModels/GlobalOidcProject.ts +18 -0
  6. package/Models/DatabaseModels/GlobalSsoProject.ts +18 -0
  7. package/Models/DatabaseModels/Index.ts +2 -0
  8. package/Models/DatabaseModels/IoTFleet.ts +14 -0
  9. package/Models/DatabaseModels/KubernetesCluster.ts +14 -0
  10. package/Models/DatabaseModels/LogDropFilter.ts +9 -20
  11. package/Models/DatabaseModels/NetworkDevice.ts +14 -0
  12. package/Models/DatabaseModels/NetworkInterface.ts +18 -0
  13. package/Models/DatabaseModels/Project.ts +16 -2
  14. package/Models/DatabaseModels/ProxmoxCluster.ts +14 -0
  15. package/Models/DatabaseModels/Service.ts +30 -0
  16. package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
  17. package/Models/DatabaseModels/StatusPagePrivateUser.ts +30 -0
  18. package/Models/DatabaseModels/StatusPageResource.ts +73 -0
  19. package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
  20. package/Models/DatabaseModels/User.ts +30 -0
  21. package/Server/API/AIAgentDataAPI.ts +31 -0
  22. package/Server/API/BaseAPI.ts +13 -2
  23. package/Server/API/DashboardAPI.ts +458 -12
  24. package/Server/API/GitHubAPI.ts +119 -283
  25. package/Server/API/UserAPI.ts +263 -1
  26. package/Server/EnvironmentConfig.ts +38 -4
  27. package/Server/Infrastructure/GlobalCache.ts +152 -0
  28. package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.ts +21 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.ts +68 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.ts +100 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.ts +214 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.ts +69 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  36. package/Server/Services/AlertStateTimelineService.ts +20 -0
  37. package/Server/Services/AnalyticsDatabaseService.ts +72 -1
  38. package/Server/Services/CephClusterService.ts +26 -86
  39. package/Server/Services/CloudResourceService.ts +23 -83
  40. package/Server/Services/CodeRepositoryService.ts +105 -2
  41. package/Server/Services/DatabaseService.ts +296 -2
  42. package/Server/Services/DockerHostService.ts +19 -79
  43. package/Server/Services/DockerSwarmClusterService.ts +27 -88
  44. package/Server/Services/HostService.ts +46 -99
  45. package/Server/Services/IncidentStateTimelineService.ts +20 -0
  46. package/Server/Services/Index.ts +2 -0
  47. package/Server/Services/IoTFleetService.ts +19 -79
  48. package/Server/Services/KubernetesClusterService.ts +17 -78
  49. package/Server/Services/LabelService.ts +57 -10
  50. package/Server/Services/MetricTypeService.ts +84 -0
  51. package/Server/Services/MonitorService.ts +89 -14
  52. package/Server/Services/MonitorStatusTimelineService.ts +29 -0
  53. package/Server/Services/MonitorTemplateService.ts +65 -0
  54. package/Server/Services/OpenTelemetryIngestService.ts +230 -26
  55. package/Server/Services/PodmanHostService.ts +19 -79
  56. package/Server/Services/ProxmoxClusterService.ts +23 -83
  57. package/Server/Services/RumApplicationService.ts +19 -80
  58. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
  59. package/Server/Services/ServerlessFunctionService.ts +24 -85
  60. package/Server/Services/ServiceService.ts +299 -73
  61. package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
  62. package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
  63. package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
  64. package/Server/Services/TelemetryEntityService.ts +1 -0
  65. package/Server/Services/UserService.ts +184 -0
  66. package/Server/Utils/AI/Toolbox/CodeTools.ts +45 -4
  67. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +13 -0
  68. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +157 -4
  69. package/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.ts +130 -0
  70. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
  71. package/Server/Utils/Monitor/MonitorResource.ts +63 -36
  72. package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
  73. package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
  74. package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
  75. package/Server/Utils/PasswordHash.ts +306 -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/OverviewCustomFields.test.tsx +333 -0
  82. package/Tests/App/Dashboard/UserCustomFields.test.tsx +392 -0
  83. package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
  84. package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
  85. package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
  86. package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
  87. package/Tests/Server/API/AIAgentDataRepositoryToken.test.ts +381 -0
  88. package/Tests/Server/API/DashboardPublicAttributeValuesAPI.test.ts +943 -0
  89. package/Tests/Server/API/DashboardPublicMetricsAggregateAPI.test.ts +1296 -0
  90. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
  91. package/Tests/Server/API/DashboardPublicTemplatePayloads.test.ts +598 -0
  92. package/Tests/Server/API/GitHubAppInstallationBindingAPI.test.ts +539 -0
  93. package/Tests/Server/API/Helpers.ts +6 -1
  94. package/Tests/Server/API/UserProjectsAPI.test.ts +852 -0
  95. package/Tests/Server/Infrastructure/GlobalCache.test.ts +354 -0
  96. package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
  97. package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +215 -0
  98. package/Tests/Server/Services/AddPerUserPasswordSaltMigration.test.ts +178 -0
  99. package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +582 -0
  100. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +5 -0
  101. package/Tests/Server/Services/CodeRepositoryInstallationBinding.test.ts +305 -0
  102. package/Tests/Server/Services/CodeRepositoryResolutionBinding.test.ts +147 -0
  103. package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +870 -0
  104. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
  105. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
  106. package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +163 -15
  107. package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
  108. package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
  109. package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
  110. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +568 -0
  111. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +305 -56
  112. package/Tests/Server/Services/RestoreDroppedUniqueIndexesMigration.test.ts +386 -0
  113. package/Tests/Server/Services/RestoreServiceLowerNameIndexMigration.test.ts +240 -0
  114. package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -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/UserServiceFirstMasterAdminElection.test.ts +885 -0
  119. package/Tests/Server/Services/WidenHashedStringColumnsForScryptMigration.test.ts +220 -0
  120. package/Tests/Server/Utils/AI/CodeTools.test.ts +47 -1
  121. package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +10 -0
  122. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
  123. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +120 -0
  124. package/Tests/Server/Utils/CodeRepository/GitHubInstallationBinding.test.ts +292 -0
  125. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
  126. package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
  127. package/Tests/Server/Utils/GitHubInstallationOwnershipVerification.test.ts +340 -0
  128. package/Tests/Server/Utils/GitHubWebhookAndTreeCacheIsolation.test.ts +250 -0
  129. package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
  130. package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
  131. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
  132. package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
  133. package/Tests/Server/Utils/PasswordHash.test.ts +555 -0
  134. package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
  135. package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
  136. package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
  137. package/Tests/Types/Database/ColumnLength.test.ts +7 -1
  138. package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
  139. package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
  140. package/Tests/Types/Decimal.test.ts +37 -0
  141. package/Tests/Types/HashedStringPerUserSalt.test.ts +476 -0
  142. package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +293 -0
  143. package/Tests/Types/Monitor/HostAlertTemplates.test.ts +249 -0
  144. package/Tests/Types/Monitor/IotAlertTemplates.test.ts +320 -0
  145. package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +271 -0
  146. package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
  147. package/Tests/Types/Port.test.ts +38 -0
  148. package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +696 -0
  149. package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
  150. package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
  151. package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
  152. package/Tests/UI/Utils/UserProjectsModelAPI.test.ts +714 -0
  153. package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
  154. package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
  155. package/Tests/Utils/TeamMembersByProject.test.ts +655 -0
  156. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  157. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  158. package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
  159. package/Types/Dashboard/DashboardTemplates.ts +397 -0
  160. package/Types/Database/BigIntColumnTransformer.ts +74 -0
  161. package/Types/Database/ColumnLength.ts +9 -1
  162. package/Types/Database/DatabaseProperty.ts +26 -0
  163. package/Types/Database/NumericColumnValue.ts +128 -0
  164. package/Types/Database/TableColumn.ts +11 -0
  165. package/Types/Database/UnsynchronizedIndex.ts +48 -0
  166. package/Types/Decimal.ts +16 -4
  167. package/Types/HashedString.ts +139 -4
  168. package/Types/Permission.ts +48 -0
  169. package/Types/Port.ts +16 -4
  170. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +85 -11
  171. package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
  172. package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
  173. package/UI/Components/Navbar/NavBar.tsx +12 -2
  174. package/UI/Components/Navbar/NavBarMenuModal.tsx +19 -7
  175. package/UI/Utils/ModelAPI/UserProjectsModelAPI.ts +257 -0
  176. package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
  177. package/Utils/Dashboard/Components/Index.ts +7 -0
  178. package/Utils/TeamMembersByProject.ts +237 -0
  179. package/build/dist/Models/DatabaseModels/CephCluster.js +16 -1
  180. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  181. package/build/dist/Models/DatabaseModels/CodeRepository.js +14 -6
  182. package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
  183. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
  184. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  185. package/build/dist/Models/DatabaseModels/DockerHost.js +16 -1
  186. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  187. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +16 -1
  188. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
  189. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +16 -1
  190. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
  191. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  192. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  193. package/build/dist/Models/DatabaseModels/IoTFleet.js +16 -1
  194. package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
  195. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +16 -1
  196. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  197. package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
  198. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  199. package/build/dist/Models/DatabaseModels/NetworkDevice.js +16 -1
  200. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  201. package/build/dist/Models/DatabaseModels/NetworkInterface.js +16 -1
  202. package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
  203. package/build/dist/Models/DatabaseModels/Project.js +16 -2
  204. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  205. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +16 -1
  206. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  207. package/build/dist/Models/DatabaseModels/Service.js +28 -1
  208. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  209. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
  210. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
  211. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +32 -0
  212. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
  213. package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
  214. package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
  215. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
  216. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/User.js +32 -0
  218. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  219. package/build/dist/Server/API/AIAgentDataAPI.js +21 -2
  220. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  221. package/build/dist/Server/API/BaseAPI.js +11 -1
  222. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  223. package/build/dist/Server/API/DashboardAPI.js +343 -10
  224. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  225. package/build/dist/Server/API/GitHubAPI.js +94 -167
  226. package/build/dist/Server/API/GitHubAPI.js.map +1 -1
  227. package/build/dist/Server/API/UserAPI.js +187 -2
  228. package/build/dist/Server/API/UserAPI.js.map +1 -1
  229. package/build/dist/Server/EnvironmentConfig.js +34 -4
  230. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  231. package/build/dist/Server/Infrastructure/GlobalCache.js +120 -0
  232. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  233. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
  234. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
  236. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
  237. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js +14 -0
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js.map +1 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js +59 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js.map +1 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js +93 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js.map +1 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js +101 -0
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js.map +1 -0
  245. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js +66 -0
  246. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js.map +1 -0
  247. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  248. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  249. package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
  250. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  251. package/build/dist/Server/Services/AnalyticsDatabaseService.js +57 -1
  252. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  253. package/build/dist/Server/Services/CephClusterService.js +26 -76
  254. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  255. package/build/dist/Server/Services/CloudResourceService.js +23 -73
  256. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  257. package/build/dist/Server/Services/CodeRepositoryService.js +90 -2
  258. package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -1
  259. package/build/dist/Server/Services/DatabaseService.js +246 -2
  260. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  261. package/build/dist/Server/Services/DockerHostService.js +19 -69
  262. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  263. package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -78
  264. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  265. package/build/dist/Server/Services/HostService.js +58 -102
  266. package/build/dist/Server/Services/HostService.js.map +1 -1
  267. package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
  268. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  269. package/build/dist/Server/Services/Index.js +2 -0
  270. package/build/dist/Server/Services/Index.js.map +1 -1
  271. package/build/dist/Server/Services/IoTFleetService.js +19 -69
  272. package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
  273. package/build/dist/Server/Services/KubernetesClusterService.js +17 -68
  274. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  275. package/build/dist/Server/Services/LabelService.js +42 -7
  276. package/build/dist/Server/Services/LabelService.js.map +1 -1
  277. package/build/dist/Server/Services/MetricTypeService.js +74 -0
  278. package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
  279. package/build/dist/Server/Services/MonitorService.js +81 -9
  280. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  281. package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
  282. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  283. package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
  284. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  285. package/build/dist/Server/Services/OpenTelemetryIngestService.js +155 -25
  286. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  287. package/build/dist/Server/Services/PodmanHostService.js +19 -69
  288. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  289. package/build/dist/Server/Services/ProxmoxClusterService.js +23 -73
  290. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  291. package/build/dist/Server/Services/RumApplicationService.js +19 -70
  292. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  293. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
  294. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  295. package/build/dist/Server/Services/ServerlessFunctionService.js +24 -75
  296. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  297. package/build/dist/Server/Services/ServiceService.js +236 -61
  298. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  299. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
  300. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
  301. package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
  302. package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
  303. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
  304. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
  305. package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
  306. package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
  307. package/build/dist/Server/Services/UserService.js +165 -0
  308. package/build/dist/Server/Services/UserService.js.map +1 -1
  309. package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js +31 -1
  310. package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js.map +1 -1
  311. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +13 -0
  312. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  313. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +126 -4
  314. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  315. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js +136 -0
  316. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js.map +1 -0
  317. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
  318. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  319. package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
  320. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  321. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
  322. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
  323. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
  324. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
  325. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
  326. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
  327. package/build/dist/Server/Utils/PasswordHash.js +237 -0
  328. package/build/dist/Server/Utils/PasswordHash.js.map +1 -0
  329. package/build/dist/Server/Utils/SingleFlight.js +76 -0
  330. package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
  331. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
  332. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
  333. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
  334. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  335. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
  336. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
  337. package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
  338. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  339. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  340. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  341. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  342. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  343. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
  344. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
  345. package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
  346. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  347. package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
  348. package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
  349. package/build/dist/Types/Database/ColumnLength.js +9 -1
  350. package/build/dist/Types/Database/ColumnLength.js.map +1 -1
  351. package/build/dist/Types/Database/DatabaseProperty.js +25 -0
  352. package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
  353. package/build/dist/Types/Database/NumericColumnValue.js +97 -0
  354. package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
  355. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  356. package/build/dist/Types/Database/UnsynchronizedIndex.js +46 -0
  357. package/build/dist/Types/Database/UnsynchronizedIndex.js.map +1 -0
  358. package/build/dist/Types/Decimal.js +14 -3
  359. package/build/dist/Types/Decimal.js.map +1 -1
  360. package/build/dist/Types/HashedString.js +95 -5
  361. package/build/dist/Types/HashedString.js.map +1 -1
  362. package/build/dist/Types/Permission.js +42 -0
  363. package/build/dist/Types/Permission.js.map +1 -1
  364. package/build/dist/Types/Port.js +15 -5
  365. package/build/dist/Types/Port.js.map +1 -1
  366. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +51 -10
  367. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  368. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
  369. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
  370. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
  371. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
  372. package/build/dist/UI/Components/Navbar/NavBar.js +3 -1
  373. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  374. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +19 -7
  375. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  376. package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js +156 -0
  377. package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js.map +1 -0
  378. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
  379. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
  380. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  381. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  382. package/build/dist/Utils/TeamMembersByProject.js +145 -0
  383. package/build/dist/Utils/TeamMembersByProject.js.map +1 -0
  384. package/package.json +1 -1
@@ -0,0 +1,500 @@
1
+ import useLogsHistogram, {
2
+ FetchHistogramBucketsFunction,
3
+ LogsHistogramState,
4
+ } from "../../../UI/Components/LogsViewer/useLogsHistogram";
5
+ import { HistogramBucket } from "../../../UI/Components/LogsViewer/types";
6
+ import { act, render, screen, waitFor } from "@testing-library/react";
7
+ import React, { FunctionComponent, ReactElement, useCallback } from "react";
8
+ import { beforeEach, describe, expect, test } from "@jest/globals";
9
+
10
+ function bucket(time: string, count: number): HistogramBucket {
11
+ return { time, severity: "Error", count };
12
+ }
13
+
14
+ const FIRST_WINDOW: Array<HistogramBucket> = [bucket("11:59", 3)];
15
+ const SECOND_WINDOW: Array<HistogramBucket> = [
16
+ bucket("11:59", 3),
17
+ bucket("12:00", 8),
18
+ ];
19
+
20
+ interface ProbeProps {
21
+ fetchBuckets: FetchHistogramBucketsFunction;
22
+ /** Bumping this hands the hook a new query identity, as a filter change would. */
23
+ queryKey?: string | undefined;
24
+ onReady?: ((state: LogsHistogramState) => void) | undefined;
25
+ }
26
+
27
+ /*
28
+ * Renders the hook's state so assertions read it through a real component
29
+ * lifecycle, and hands the state object back so tests can trigger a refresh
30
+ * the way live mode does.
31
+ */
32
+ const HistogramProbe: FunctionComponent<ProbeProps> = (
33
+ props: ProbeProps,
34
+ ): ReactElement => {
35
+ const { fetchBuckets, queryKey } = props;
36
+
37
+ const fetch: FetchHistogramBucketsFunction = useCallback(() => {
38
+ return fetchBuckets();
39
+ /*
40
+ * queryKey stands in for the filters/time range the real caller closes
41
+ * over: changing it is what makes the hook reload.
42
+ */
43
+ }, [fetchBuckets, queryKey]);
44
+
45
+ const state: LogsHistogramState = useLogsHistogram(fetch);
46
+
47
+ props.onReady?.(state);
48
+
49
+ return (
50
+ <div>
51
+ <span data-testid="counts">
52
+ {state.buckets
53
+ .map((item: HistogramBucket) => {
54
+ return `${item.time}=${item.count}`;
55
+ })
56
+ .join(",")}
57
+ </span>
58
+ <span data-testid="loading">{String(state.isLoading)}</span>
59
+ </div>
60
+ );
61
+ };
62
+
63
+ function counts(): string {
64
+ return screen.getByTestId("counts").textContent || "";
65
+ }
66
+
67
+ function isLoading(): boolean {
68
+ return screen.getByTestId("loading").textContent === "true";
69
+ }
70
+
71
+ describe("useLogsHistogram", () => {
72
+ let latest: LogsHistogramState | null;
73
+ let loadingStates: Array<boolean>;
74
+
75
+ const captureState: (state: LogsHistogramState) => void = (
76
+ state: LogsHistogramState,
77
+ ): void => {
78
+ latest = state;
79
+ loadingStates.push(state.isLoading);
80
+ };
81
+
82
+ async function refresh(silent: boolean): Promise<void> {
83
+ await act(async () => {
84
+ await latest!.refresh(silent ? { silent: true } : {});
85
+ });
86
+ }
87
+
88
+ beforeEach(() => {
89
+ latest = null;
90
+ loadingStates = [];
91
+ });
92
+
93
+ describe("first load", () => {
94
+ test("shows the buckets the query returns", async () => {
95
+ const fetchBuckets: FetchHistogramBucketsFunction = async (): Promise<
96
+ Array<HistogramBucket>
97
+ > => {
98
+ return FIRST_WINDOW;
99
+ };
100
+
101
+ render(<HistogramProbe fetchBuckets={fetchBuckets} />);
102
+
103
+ await waitFor(() => {
104
+ expect(counts()).toBe("11:59=3");
105
+ });
106
+ });
107
+
108
+ test("raises the loading flag while the query runs", async () => {
109
+ const fetchBuckets: FetchHistogramBucketsFunction = async (): Promise<
110
+ Array<HistogramBucket>
111
+ > => {
112
+ return FIRST_WINDOW;
113
+ };
114
+
115
+ render(
116
+ <HistogramProbe fetchBuckets={fetchBuckets} onReady={captureState} />,
117
+ );
118
+
119
+ await waitFor(() => {
120
+ expect(counts()).toBe("11:59=3");
121
+ });
122
+
123
+ expect(loadingStates).toContain(true);
124
+ expect(isLoading()).toBe(false);
125
+ });
126
+
127
+ test("leaves the chart empty when the query fails", async () => {
128
+ const fetchBuckets: FetchHistogramBucketsFunction = async (): Promise<
129
+ Array<HistogramBucket>
130
+ > => {
131
+ throw new Error("clickhouse timeout");
132
+ };
133
+
134
+ render(
135
+ <HistogramProbe fetchBuckets={fetchBuckets} onReady={captureState} />,
136
+ );
137
+
138
+ await waitFor(() => {
139
+ expect(isLoading()).toBe(false);
140
+ });
141
+
142
+ expect(counts()).toBe("");
143
+ });
144
+ });
145
+
146
+ describe("when the query changes", () => {
147
+ test("reloads for the new filters", async () => {
148
+ let window: Array<HistogramBucket> = FIRST_WINDOW;
149
+
150
+ const fetchBuckets: FetchHistogramBucketsFunction = async (): Promise<
151
+ Array<HistogramBucket>
152
+ > => {
153
+ return window;
154
+ };
155
+
156
+ const view: ReturnType<typeof render> = render(
157
+ <HistogramProbe fetchBuckets={fetchBuckets} queryKey="one-hour" />,
158
+ );
159
+
160
+ await waitFor(() => {
161
+ expect(counts()).toBe("11:59=3");
162
+ });
163
+
164
+ window = SECOND_WINDOW;
165
+
166
+ view.rerender(
167
+ <HistogramProbe fetchBuckets={fetchBuckets} queryKey="one-day" />,
168
+ );
169
+
170
+ await waitFor(() => {
171
+ expect(counts()).toBe("11:59=3,12:00=8");
172
+ });
173
+ });
174
+
175
+ test("does not reload when nothing about the query changed", async () => {
176
+ let calls: number = 0;
177
+
178
+ const fetchBuckets: FetchHistogramBucketsFunction = async (): Promise<
179
+ Array<HistogramBucket>
180
+ > => {
181
+ calls++;
182
+ return FIRST_WINDOW;
183
+ };
184
+
185
+ const view: ReturnType<typeof render> = render(
186
+ <HistogramProbe fetchBuckets={fetchBuckets} queryKey="one-hour" />,
187
+ );
188
+
189
+ await waitFor(() => {
190
+ expect(counts()).toBe("11:59=3");
191
+ });
192
+
193
+ view.rerender(
194
+ <HistogramProbe fetchBuckets={fetchBuckets} queryKey="one-hour" />,
195
+ );
196
+
197
+ expect(calls).toBe(1);
198
+ });
199
+
200
+ /*
201
+ * A poll fired against the old time range can easily outlive the switch to
202
+ * a new one. Painting its answer would leave the reader looking at a
203
+ * window they have already moved off.
204
+ */
205
+ test("ignores an answer to a query the reader has already left", async () => {
206
+ const pending: Array<(buckets: Array<HistogramBucket>) => void> = [];
207
+
208
+ const fetchBuckets: FetchHistogramBucketsFunction = (): Promise<
209
+ Array<HistogramBucket>
210
+ > => {
211
+ return new Promise<Array<HistogramBucket>>(
212
+ (resolve: (buckets: Array<HistogramBucket>) => void) => {
213
+ pending.push(resolve);
214
+ },
215
+ );
216
+ };
217
+
218
+ const view: ReturnType<typeof render> = render(
219
+ <HistogramProbe fetchBuckets={fetchBuckets} queryKey="one-hour" />,
220
+ );
221
+
222
+ await waitFor(() => {
223
+ expect(pending.length).toBe(1);
224
+ });
225
+
226
+ view.rerender(
227
+ <HistogramProbe fetchBuckets={fetchBuckets} queryKey="five-minutes" />,
228
+ );
229
+
230
+ await waitFor(() => {
231
+ expect(pending.length).toBe(2);
232
+ });
233
+
234
+ // The new window answers first, then the abandoned one straggles in.
235
+ await act(async () => {
236
+ pending[1]!(SECOND_WINDOW);
237
+ });
238
+ await act(async () => {
239
+ pending[0]!(FIRST_WINDOW);
240
+ });
241
+
242
+ expect(counts()).toBe("11:59=3,12:00=8");
243
+ });
244
+
245
+ test("does not blank the chart when an abandoned query fails", async () => {
246
+ const pending: Array<{
247
+ resolve: (buckets: Array<HistogramBucket>) => void;
248
+ reject: (error: Error) => void;
249
+ }> = [];
250
+
251
+ const fetchBuckets: FetchHistogramBucketsFunction = (): Promise<
252
+ Array<HistogramBucket>
253
+ > => {
254
+ return new Promise<Array<HistogramBucket>>(
255
+ (
256
+ resolve: (buckets: Array<HistogramBucket>) => void,
257
+ reject: (error: Error) => void,
258
+ ) => {
259
+ pending.push({ resolve: resolve, reject: reject });
260
+ },
261
+ );
262
+ };
263
+
264
+ const view: ReturnType<typeof render> = render(
265
+ <HistogramProbe fetchBuckets={fetchBuckets} queryKey="one-hour" />,
266
+ );
267
+
268
+ await waitFor(() => {
269
+ expect(pending.length).toBe(1);
270
+ });
271
+
272
+ view.rerender(
273
+ <HistogramProbe fetchBuckets={fetchBuckets} queryKey="five-minutes" />,
274
+ );
275
+
276
+ await waitFor(() => {
277
+ expect(pending.length).toBe(2);
278
+ });
279
+
280
+ await act(async () => {
281
+ pending[1]!.resolve(SECOND_WINDOW);
282
+ });
283
+ await act(async () => {
284
+ pending[0]!.reject(new Error("clickhouse timeout"));
285
+ });
286
+
287
+ expect(counts()).toBe("11:59=3,12:00=8");
288
+ expect(isLoading()).toBe(false);
289
+ });
290
+ });
291
+
292
+ /*
293
+ * Live mode polls the histogram every few seconds. These are the properties
294
+ * that keep the chart from flashing, blanking or stampeding while it does.
295
+ */
296
+ describe("silent refresh", () => {
297
+ test("moves the chart on to the newer window", async () => {
298
+ let window: Array<HistogramBucket> = FIRST_WINDOW;
299
+
300
+ const fetchBuckets: FetchHistogramBucketsFunction = async (): Promise<
301
+ Array<HistogramBucket>
302
+ > => {
303
+ return window;
304
+ };
305
+
306
+ render(
307
+ <HistogramProbe fetchBuckets={fetchBuckets} onReady={captureState} />,
308
+ );
309
+
310
+ await waitFor(() => {
311
+ expect(counts()).toBe("11:59=3");
312
+ });
313
+
314
+ window = SECOND_WINDOW;
315
+ await refresh(true);
316
+
317
+ expect(counts()).toBe("11:59=3,12:00=8");
318
+ });
319
+
320
+ test("never raises the loading flag", async () => {
321
+ const fetchBuckets: FetchHistogramBucketsFunction = async (): Promise<
322
+ Array<HistogramBucket>
323
+ > => {
324
+ return FIRST_WINDOW;
325
+ };
326
+
327
+ render(
328
+ <HistogramProbe fetchBuckets={fetchBuckets} onReady={captureState} />,
329
+ );
330
+
331
+ await waitFor(() => {
332
+ expect(counts()).toBe("11:59=3");
333
+ });
334
+
335
+ loadingStates = [];
336
+
337
+ await refresh(true);
338
+ await refresh(true);
339
+
340
+ expect(loadingStates).not.toContain(true);
341
+ });
342
+
343
+ test("keeps the chart on screen when a poll fails", async () => {
344
+ let shouldFail: boolean = false;
345
+
346
+ const fetchBuckets: FetchHistogramBucketsFunction = async (): Promise<
347
+ Array<HistogramBucket>
348
+ > => {
349
+ if (shouldFail) {
350
+ throw new Error("clickhouse timeout");
351
+ }
352
+
353
+ return FIRST_WINDOW;
354
+ };
355
+
356
+ render(
357
+ <HistogramProbe fetchBuckets={fetchBuckets} onReady={captureState} />,
358
+ );
359
+
360
+ await waitFor(() => {
361
+ expect(counts()).toBe("11:59=3");
362
+ });
363
+
364
+ shouldFail = true;
365
+ await refresh(true);
366
+
367
+ expect(counts()).toBe("11:59=3");
368
+ });
369
+
370
+ test("recovers on the next poll after a failure", async () => {
371
+ let shouldFail: boolean = true;
372
+ let window: Array<HistogramBucket> = FIRST_WINDOW;
373
+
374
+ const fetchBuckets: FetchHistogramBucketsFunction = async (): Promise<
375
+ Array<HistogramBucket>
376
+ > => {
377
+ if (shouldFail) {
378
+ throw new Error("clickhouse timeout");
379
+ }
380
+
381
+ return window;
382
+ };
383
+
384
+ render(
385
+ <HistogramProbe fetchBuckets={fetchBuckets} onReady={captureState} />,
386
+ );
387
+
388
+ await waitFor(() => {
389
+ expect(isLoading()).toBe(false);
390
+ });
391
+
392
+ shouldFail = false;
393
+ window = SECOND_WINDOW;
394
+ await refresh(true);
395
+
396
+ expect(counts()).toBe("11:59=3,12:00=8");
397
+ });
398
+
399
+ test("drops a poll that lands while the previous one is still running", async () => {
400
+ const pending: Array<(buckets: Array<HistogramBucket>) => void> = [];
401
+
402
+ const fetchBuckets: FetchHistogramBucketsFunction = (): Promise<
403
+ Array<HistogramBucket>
404
+ > => {
405
+ return new Promise<Array<HistogramBucket>>(
406
+ (resolve: (buckets: Array<HistogramBucket>) => void) => {
407
+ pending.push(resolve);
408
+ },
409
+ );
410
+ };
411
+
412
+ render(
413
+ <HistogramProbe fetchBuckets={fetchBuckets} onReady={captureState} />,
414
+ );
415
+
416
+ // Let the first load settle so only the polls are in play.
417
+ await waitFor(() => {
418
+ expect(pending.length).toBe(1);
419
+ });
420
+ await act(async () => {
421
+ pending[0]!(FIRST_WINDOW);
422
+ });
423
+
424
+ // A poll that is still waiting on a slow aggregation...
425
+ let slowPoll: Promise<void> = Promise.resolve();
426
+ await act(async () => {
427
+ slowPoll = latest!.refresh({ silent: true });
428
+ });
429
+ expect(pending.length).toBe(2);
430
+
431
+ // ...swallows the ticks that land behind it.
432
+ await act(async () => {
433
+ await latest!.refresh({ silent: true });
434
+ await latest!.refresh({ silent: true });
435
+ });
436
+ expect(pending.length).toBe(2);
437
+
438
+ await act(async () => {
439
+ pending[1]!(SECOND_WINDOW);
440
+ await slowPoll;
441
+ });
442
+
443
+ expect(counts()).toBe("11:59=3,12:00=8");
444
+
445
+ // The gate lifts once the slow poll comes back.
446
+ await act(async () => {
447
+ void latest!.refresh({ silent: true });
448
+ });
449
+ expect(pending.length).toBe(3);
450
+
451
+ await act(async () => {
452
+ pending[2]!(SECOND_WINDOW);
453
+ });
454
+ });
455
+
456
+ test("does not hold up a full reload triggered by the reader", async () => {
457
+ const pending: Array<(buckets: Array<HistogramBucket>) => void> = [];
458
+
459
+ const fetchBuckets: FetchHistogramBucketsFunction = (): Promise<
460
+ Array<HistogramBucket>
461
+ > => {
462
+ return new Promise<Array<HistogramBucket>>(
463
+ (resolve: (buckets: Array<HistogramBucket>) => void) => {
464
+ pending.push(resolve);
465
+ },
466
+ );
467
+ };
468
+
469
+ render(
470
+ <HistogramProbe fetchBuckets={fetchBuckets} onReady={captureState} />,
471
+ );
472
+
473
+ await waitFor(() => {
474
+ expect(pending.length).toBe(1);
475
+ });
476
+ await act(async () => {
477
+ pending[0]!(FIRST_WINDOW);
478
+ });
479
+
480
+ await act(async () => {
481
+ void latest!.refresh({ silent: true });
482
+ });
483
+ expect(pending.length).toBe(2);
484
+
485
+ // A filter change or a manual reload must not be swallowed by the gate.
486
+ await act(async () => {
487
+ void latest!.refresh();
488
+ });
489
+ expect(pending.length).toBe(3);
490
+ expect(isLoading()).toBe(true);
491
+
492
+ await act(async () => {
493
+ pending[1]!(FIRST_WINDOW);
494
+ pending[2]!(SECOND_WINDOW);
495
+ });
496
+
497
+ expect(isLoading()).toBe(false);
498
+ });
499
+ });
500
+ });