@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
package/Types/Date.ts CHANGED
@@ -9,6 +9,12 @@ import Zod, { ZodSchema } from "../Utils/Schema/Zod";
9
9
 
10
10
  export const Moment: typeof moment = moment;
11
11
 
12
+ /*
13
+ * The units a calendar (rather than a fixed-length) interval can be measured in.
14
+ * See getStartOfCalendarUnit / addRemoveCalendarUnits below.
15
+ */
16
+ export type CalendarUnit = "hour" | "day" | "week" | "month" | "year";
17
+
12
18
  export default class OneUptimeDate {
13
19
  // get date time from unix timestamp
14
20
 
@@ -363,6 +369,27 @@ export default class OneUptimeDate {
363
369
  ).trim();
364
370
  }
365
371
 
372
+ /*
373
+ * Format an instant with an explicit moment format string, resolved in an
374
+ * IANA timezone. The formatted-string helpers above each bake in a layout;
375
+ * this one is for callers that need a specific shape ("MMMM YYYY" for the
376
+ * month a status page report covers) and know exactly which zone it must be
377
+ * read in. Falls back to the viewer's / process's zone without one.
378
+ */
379
+ public static getDateAsCustomFormattedStringInTimezone(data: {
380
+ date: Date | string;
381
+ format: string;
382
+ timezone?: string | undefined;
383
+ }): string {
384
+ const date: Date = this.fromString(data.date);
385
+
386
+ if (!data.timezone) {
387
+ return this.inCurrentTimezone(date).format(data.format);
388
+ }
389
+
390
+ return moment(date).tz(data.timezone).format(data.format);
391
+ }
392
+
366
393
  /**
367
394
  * Reinterpret the wall-clock components of `date` — read in the CURRENT
368
395
  * timezone, i.e. the one the pickers render in — as the SAME wall-clock in
@@ -1213,6 +1240,91 @@ export default class OneUptimeDate {
1213
1240
  return moment(date).endOf("day").toDate();
1214
1241
  }
1215
1242
 
1243
+ /*
1244
+ * Calendar arithmetic - "the previous calendar month", "add 3 calendar
1245
+ * months" - as opposed to the fixed-length arithmetic the rest of this class
1246
+ * does. A calendar month is 28-31 days long and a calendar day is 23-25 hours
1247
+ * long across a DST transition, so anything that has to line up with a wall
1248
+ * clock (a status page report that must read "Jul 1 - Jul 31", a schedule that
1249
+ * must keep firing at 09:00 local) cannot be expressed by adding milliseconds.
1250
+ *
1251
+ * Every helper below takes an optional IANA timezone. Without one the
1252
+ * boundaries land in the process's local zone, which on a server is UTC.
1253
+ */
1254
+ private static toMomentCalendarUnit(
1255
+ unit: CalendarUnit,
1256
+ forStartOf: boolean,
1257
+ ): moment.unitOfTime.StartOf & moment.unitOfTime.DurationConstructor {
1258
+ /*
1259
+ * moment's "week" starts on the locale's first day, which differs between
1260
+ * environments and would make a weekly report cover Sun-Sat on one host and
1261
+ * Mon-Sun on another. ISO weeks are always Monday-Sunday, so the boundary is
1262
+ * the same everywhere. Durations have no such ambiguity - a week is 7 days -
1263
+ * and moment has no "isoWeek" duration, so only startOf is remapped.
1264
+ */
1265
+ if (unit === "week" && forStartOf) {
1266
+ return "isoWeek" as moment.unitOfTime.StartOf &
1267
+ moment.unitOfTime.DurationConstructor;
1268
+ }
1269
+
1270
+ return unit as moment.unitOfTime.StartOf &
1271
+ moment.unitOfTime.DurationConstructor;
1272
+ }
1273
+
1274
+ private static inTimezone(
1275
+ date: Date,
1276
+ timezone?: string | undefined,
1277
+ ): moment.Moment {
1278
+ return timezone ? moment.tz(date, timezone) : moment(date);
1279
+ }
1280
+
1281
+ /*
1282
+ * The instant the calendar unit containing `date` began - e.g. the first
1283
+ * millisecond of that month, in `timezone`.
1284
+ */
1285
+ public static getStartOfCalendarUnit(
1286
+ date: Date,
1287
+ unit: CalendarUnit,
1288
+ timezone?: string | undefined,
1289
+ ): Date {
1290
+ return this.inTimezone(this.fromString(date), timezone)
1291
+ .startOf(this.toMomentCalendarUnit(unit, true))
1292
+ .toDate();
1293
+ }
1294
+
1295
+ /*
1296
+ * Move `date` by whole calendar units, keeping the wall clock in `timezone`.
1297
+ * Adding one month to Jan 31 lands on Feb 28/29 (moment clamps), and adding a
1298
+ * day across a DST boundary still lands at the same local time.
1299
+ */
1300
+ public static addRemoveCalendarUnits(
1301
+ date: Date,
1302
+ unit: CalendarUnit,
1303
+ count: number,
1304
+ timezone?: string | undefined,
1305
+ ): Date {
1306
+ return this.inTimezone(this.fromString(date), timezone)
1307
+ .add(count, this.toMomentCalendarUnit(unit, false))
1308
+ .toDate();
1309
+ }
1310
+
1311
+ /*
1312
+ * How many whole calendar units fit between the two instants, measured in
1313
+ * `timezone`. Used to jump a recurrence forward to "now" in one step instead
1314
+ * of looping one interval at a time.
1315
+ */
1316
+ public static getCalendarUnitsBetween(
1317
+ startDate: Date,
1318
+ endDate: Date,
1319
+ unit: CalendarUnit,
1320
+ timezone?: string | undefined,
1321
+ ): number {
1322
+ return this.inTimezone(this.fromString(endDate), timezone).diff(
1323
+ this.inTimezone(this.fromString(startDate), timezone),
1324
+ this.toMomentCalendarUnit(unit, false),
1325
+ );
1326
+ }
1327
+
1216
1328
  public static isBetween(date: Date, startDate: Date, endDate: Date): boolean {
1217
1329
  date = this.fromString(date);
1218
1330
  startDate = this.fromString(startDate);
package/Types/Decimal.ts CHANGED
@@ -35,14 +35,26 @@ export default class Decimal extends DatabaseProperty {
35
35
  return this.value.toString();
36
36
  }
37
37
 
38
+ /*
39
+ * A decimal column is declared `TableColumnType.Number`, so what reaches
40
+ * the transformer may be a Decimal, a string, or a plain number depending
41
+ * on how far the request body got through deserialization.
42
+ *
43
+ * Both raw forms are handled before the truthiness check, because `0` is a
44
+ * perfectly good decimal and the old `if (value)` sent it to `null` — on a
45
+ * NOT NULL column that is a constraint violation for a value the caller
46
+ * supplied.
47
+ */
38
48
  protected static override toDatabase(
39
49
  value: Decimal | FindOperator<Decimal>,
40
50
  ): string | null {
41
- if (value) {
42
- if (typeof value === "string") {
43
- value = new Decimal(value);
44
- }
51
+ const rawValue: unknown = value;
52
+
53
+ if (typeof rawValue === "string" || typeof rawValue === "number") {
54
+ return new Decimal(rawValue).toString();
55
+ }
45
56
 
57
+ if (value) {
46
58
  return value.toString();
47
59
  }
48
60
 
@@ -1,5 +1,5 @@
1
1
  import DatabaseProperty from "../Database/DatabaseProperty";
2
- import OneUptimeDate from "../Date";
2
+ import OneUptimeDate, { CalendarUnit } from "../Date";
3
3
  import BadDataException from "../Exception/BadDataException";
4
4
  import { JSONArray, JSONObject, ObjectType } from "../JSON";
5
5
  import JSONFunctions from "../JSONFunctions";
@@ -109,6 +109,104 @@ export default class Recurring extends DatabaseProperty {
109
109
  return nextDate;
110
110
  }
111
111
 
112
+ /*
113
+ * The calendar unit this interval is expressed in, for the date helpers that
114
+ * do calendar (rather than fixed-millisecond) arithmetic.
115
+ */
116
+ public static toCalendarUnit(intervalType: EventInterval): CalendarUnit {
117
+ switch (intervalType) {
118
+ case EventInterval.Hour:
119
+ return "hour";
120
+ case EventInterval.Day:
121
+ return "day";
122
+ case EventInterval.Week:
123
+ return "week";
124
+ case EventInterval.Month:
125
+ return "month";
126
+ case EventInterval.Year:
127
+ return "year";
128
+ default:
129
+ throw new BadDataException("Invalid Interval Type: " + intervalType);
130
+ }
131
+ }
132
+
133
+ /**
134
+ * The first occurrence of `recurring` (anchored at `startDate`) strictly after
135
+ * `afterDate`, stepping in whole CALENDAR units in `timezone`.
136
+ *
137
+ * getNextDate() approximates a month as 30.4375 days and a year as 365.25
138
+ * days, which is fine for hours/days/weeks but makes a monthly recurrence
139
+ * walk backwards through the calendar: anchored on 1 Jul it fires on 31 Jul,
140
+ * then 30 Aug, and eventually skips a month entirely. This steps 1 Jul ->
141
+ * 1 Aug -> 1 Sep instead, and holds the local time of day across DST.
142
+ *
143
+ * A start date already after `afterDate` is returned unchanged - the first
144
+ * occurrence has not happened yet.
145
+ */
146
+ public static getNextDateAfter(data: {
147
+ startDate: Date;
148
+ recurring: Recurring;
149
+ afterDate: Date;
150
+ timezone?: string | undefined;
151
+ }): Date {
152
+ const startDate: Date = OneUptimeDate.fromString(data.startDate);
153
+ const recurring: Recurring = Recurring.fromJSON(data.recurring);
154
+ const unit: CalendarUnit = Recurring.toCalendarUnit(recurring.intervalType);
155
+
156
+ const intervalCount: number = Math.max(
157
+ 1,
158
+ Math.floor(recurring.intervalCount.toNumber()),
159
+ );
160
+
161
+ if (startDate.getTime() > data.afterDate.getTime()) {
162
+ return startDate;
163
+ }
164
+
165
+ /*
166
+ * Jump most of the way in one step so a status page left disabled for a year
167
+ * does not loop 365 times, then walk the remainder. The estimate can only be
168
+ * off by a single interval either way (calendar units are not uniform), so
169
+ * the two loops below run a handful of times at most.
170
+ */
171
+ const elapsedUnits: number = OneUptimeDate.getCalendarUnitsBetween(
172
+ startDate,
173
+ data.afterDate,
174
+ unit,
175
+ data.timezone,
176
+ );
177
+
178
+ let intervals: number = Math.max(
179
+ 0,
180
+ Math.floor(elapsedUnits / intervalCount),
181
+ );
182
+
183
+ type OccurrenceFunction = (intervalsToAdd: number) => Date;
184
+
185
+ const occurrence: OccurrenceFunction = (intervalsToAdd: number): Date => {
186
+ return OneUptimeDate.addRemoveCalendarUnits(
187
+ startDate,
188
+ unit,
189
+ intervalsToAdd * intervalCount,
190
+ data.timezone,
191
+ );
192
+ };
193
+
194
+ // Overshot - come back until we are at or before the cutoff.
195
+ while (
196
+ intervals > 0 &&
197
+ occurrence(intervals - 1).getTime() > data.afterDate.getTime()
198
+ ) {
199
+ intervals--;
200
+ }
201
+
202
+ // Undershot - advance until we are strictly after it.
203
+ while (occurrence(intervals).getTime() <= data.afterDate.getTime()) {
204
+ intervals++;
205
+ }
206
+
207
+ return occurrence(intervals);
208
+ }
209
+
112
210
  private data: RecurringData = Recurring.getDefaultRotationData();
113
211
 
114
212
  public get intervalType(): EventInterval {
@@ -484,6 +484,12 @@ enum Permission {
484
484
  EditStatusPageLabelRule = "EditStatusPageLabelRule",
485
485
  ReadStatusPageLabelRule = "ReadStatusPageLabelRule",
486
486
 
487
+ // Status Page Monitor Rule Permissions
488
+ CreateStatusPageMonitorRule = "CreateStatusPageMonitorRule",
489
+ DeleteStatusPageMonitorRule = "DeleteStatusPageMonitorRule",
490
+ EditStatusPageMonitorRule = "EditStatusPageMonitorRule",
491
+ ReadStatusPageMonitorRule = "ReadStatusPageMonitorRule",
492
+
487
493
  // Host Owner Rule Permissions
488
494
  CreateHostOwnerRule = "CreateHostOwnerRule",
489
495
  DeleteHostOwnerRule = "DeleteHostOwnerRule",
@@ -11104,6 +11110,48 @@ export class PermissionHelper {
11104
11110
  group: PermissionGroup.StatusPage,
11105
11111
  },
11106
11112
 
11113
+ // Status Page Monitor Rule Permissions
11114
+ {
11115
+ permission: Permission.CreateStatusPageMonitorRule,
11116
+ title: "Create Status Page Monitor Rule",
11117
+ description:
11118
+ "This permission can create Status Page Monitor Rules in this project.",
11119
+ isAssignableToTenant: true,
11120
+ isAccessControlPermission: false,
11121
+ isRolePermission: false,
11122
+ group: PermissionGroup.StatusPage,
11123
+ },
11124
+ {
11125
+ permission: Permission.DeleteStatusPageMonitorRule,
11126
+ title: "Delete Status Page Monitor Rule",
11127
+ description:
11128
+ "This permission can delete Status Page Monitor Rules of this project.",
11129
+ isAssignableToTenant: true,
11130
+ isAccessControlPermission: false,
11131
+ isRolePermission: false,
11132
+ group: PermissionGroup.StatusPage,
11133
+ },
11134
+ {
11135
+ permission: Permission.EditStatusPageMonitorRule,
11136
+ title: "Edit Status Page Monitor Rule",
11137
+ description:
11138
+ "This permission can edit Status Page Monitor Rules of this project.",
11139
+ isAssignableToTenant: true,
11140
+ isAccessControlPermission: false,
11141
+ isRolePermission: false,
11142
+ group: PermissionGroup.StatusPage,
11143
+ },
11144
+ {
11145
+ permission: Permission.ReadStatusPageMonitorRule,
11146
+ title: "Read Status Page Monitor Rule",
11147
+ description:
11148
+ "This permission can read Status Page Monitor Rules of this project.",
11149
+ isAssignableToTenant: true,
11150
+ isAccessControlPermission: false,
11151
+ isRolePermission: false,
11152
+ group: PermissionGroup.StatusPage,
11153
+ },
11154
+
11107
11155
  // Host Owner Rule Permissions
11108
11156
  {
11109
11157
  permission: Permission.CreateHostOwnerRule,
package/Types/Port.ts CHANGED
@@ -59,17 +59,29 @@ export default class Port extends DatabaseProperty {
59
59
  this.port = new PositiveNumber(port);
60
60
  }
61
61
 
62
+ /*
63
+ * A port column is declared `TableColumnType.Number`, so a raw number is
64
+ * as legitimate an incoming value as a raw string — the SMTP forms send
65
+ * one or the other depending on how far the value got through
66
+ * deserialization. Dropping a number on the floor here wrote NULL over a
67
+ * port the user had just typed, with no error anywhere.
68
+ */
62
69
  public static override toDatabase(
63
70
  value: Port | FindOperator<Port>,
64
71
  ): number | null {
65
- if (typeof value === "string") {
66
- value = new Port(value);
72
+ /*
73
+ * The declared parameter type stays Port-shaped so this still overrides
74
+ * DatabaseProperty.toDatabase, but a raw string or number genuinely
75
+ * arrives here — see the note above — so widen at the check instead.
76
+ */
77
+ const rawValue: unknown = value;
78
+
79
+ if (typeof rawValue === "string" || typeof rawValue === "number") {
80
+ value = new Port(rawValue);
67
81
  }
68
82
 
69
83
  if (value instanceof Port) {
70
84
  return value.toNumber();
71
- } else if (typeof value === "string") {
72
- return parseInt(value);
73
85
  }
74
86
 
75
87
  return null;
@@ -85,6 +85,17 @@ export interface StatusPageReportRow {
85
85
 
86
86
  export interface StatusPageReport {
87
87
  reportDates: string; // start date and end date in string. e.g. "01 July 2021 - 14 July 2021"
88
+ /*
89
+ * How a sentence refers to the period this report covers - "the last 30
90
+ * days", "July 2026", "the week of Jul 27, 2026". `reportDates` is the raw
91
+ * range; this is the phrase that goes after "your status summary for ...".
92
+ */
93
+ reportPeriodName: string;
94
+ // The two ends of the window on their own, for templates that lay them out.
95
+ reportStartDate: string;
96
+ reportEndDate: string;
97
+ // The IANA zone every date above was resolved in, e.g. "America/New_York".
98
+ reportTimezone: string;
88
99
  totalResources: number;
89
100
  totalIncidents: number;
90
101
  averageUptimePercent: string;
@@ -0,0 +1,21 @@
1
+ /*
2
+ * What stretch of time a scheduled status page report covers.
3
+ *
4
+ * The report used to only ever cover "the last N days counted back from the
5
+ * moment the email went out", which can never line up with a calendar month -
6
+ * a monthly report sent on 1 Aug covered 2 Jul - 1 Aug rather than the July
7
+ * everyone reading it expects, and consecutive reports silently overlapped or
8
+ * left gaps whenever the day count did not match the send frequency.
9
+ */
10
+ enum StatusPageReportPeriodType {
11
+ // The window ends when the email is sent and runs back `reportDataInDays`.
12
+ Rolling = "Rolling",
13
+ /*
14
+ * The last whole calendar period before the email is sent, sized by the send
15
+ * frequency: a report sent monthly covers 1 Jul 00:00 - 31 Jul 23:59:59.999
16
+ * in the status page's report timezone.
17
+ */
18
+ PreviousCalendarPeriod = "Previous Calendar Period",
19
+ }
20
+
21
+ export default StatusPageReportPeriodType;
@@ -0,0 +1,86 @@
1
+ import React, { useEffect, useRef } from "react";
2
+
3
+ export interface LiveLogsRefreshOptions {
4
+ /** Whether the user has switched live mode on. */
5
+ isLive: boolean;
6
+ /**
7
+ * Whether the current view can be refreshed in place. Live tailing only
8
+ * makes sense on the first page sorted newest-first — on page 3, or sorted
9
+ * by severity, "the newest logs" is not what the viewer is showing.
10
+ */
11
+ isEligible: boolean;
12
+ /** How often to poll while live mode is on. */
13
+ intervalInMs: number;
14
+ /** Pull the newest page of logs. */
15
+ refreshLogs: () => void;
16
+ /**
17
+ * Re-run the histogram query. The chart is driven by its own aggregation
18
+ * request rather than by the rows in the table, so it goes stale unless it
19
+ * is refreshed on the same beat as the list.
20
+ */
21
+ refreshHistogram: () => void;
22
+ }
23
+
24
+ export type UseLiveLogsRefreshFunction = (
25
+ options: LiveLogsRefreshOptions,
26
+ ) => void;
27
+
28
+ /**
29
+ * Drives the polling loop behind the log viewer's live mode.
30
+ *
31
+ * Every tick refreshes the log list *and* the histogram together. That
32
+ * pairing is the point of this hook: the two come from different endpoints,
33
+ * and refreshing only the list leaves a chart that stops moving while rows
34
+ * keep arriving underneath it.
35
+ *
36
+ * The callbacks are read through refs, so a parent that re-renders (which it
37
+ * does on every poll, as results land) does not tear down and re-arm the
38
+ * timer — that would reset the cadence and fire an extra immediate poll each
39
+ * time. Only the gating flags and the interval restart the loop.
40
+ */
41
+ const useLiveLogsRefresh: UseLiveLogsRefreshFunction = (
42
+ options: LiveLogsRefreshOptions,
43
+ ): void => {
44
+ const { isLive, isEligible, intervalInMs } = options;
45
+
46
+ const refreshLogsRef: React.MutableRefObject<() => void> = useRef<() => void>(
47
+ options.refreshLogs,
48
+ );
49
+ const refreshHistogramRef: React.MutableRefObject<() => void> = useRef<
50
+ () => void
51
+ >(options.refreshHistogram);
52
+
53
+ /*
54
+ * Declared before the polling effect so the refs are already current by the
55
+ * time that effect (re-)runs — effects fire in declaration order.
56
+ */
57
+ useEffect(() => {
58
+ refreshLogsRef.current = options.refreshLogs;
59
+ refreshHistogramRef.current = options.refreshHistogram;
60
+ });
61
+
62
+ useEffect(() => {
63
+ if (!isLive || !isEligible) {
64
+ return;
65
+ }
66
+
67
+ const poll: () => void = (): void => {
68
+ refreshLogsRef.current();
69
+ refreshHistogramRef.current();
70
+ };
71
+
72
+ // Switching live mode on should show fresh data immediately, not one tick later.
73
+ poll();
74
+
75
+ const intervalId: ReturnType<typeof setInterval> = setInterval(
76
+ poll,
77
+ intervalInMs,
78
+ );
79
+
80
+ return () => {
81
+ clearInterval(intervalId);
82
+ };
83
+ }, [isLive, isEligible, intervalInMs]);
84
+ };
85
+
86
+ export default useLiveLogsRefresh;
@@ -0,0 +1,113 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
+ import { HistogramBucket } from "./types";
3
+
4
+ export interface LogsHistogramRefreshOptions {
5
+ /**
6
+ * A background refresh: no loader, no blanking on failure, and no stacking
7
+ * if the previous one has not come back yet. This is what live mode uses.
8
+ */
9
+ silent?: boolean | undefined;
10
+ }
11
+
12
+ export interface LogsHistogramState {
13
+ buckets: Array<HistogramBucket>;
14
+ isLoading: boolean;
15
+ refresh: (options?: LogsHistogramRefreshOptions) => Promise<void>;
16
+ }
17
+
18
+ export type FetchHistogramBucketsFunction = () => Promise<
19
+ Array<HistogramBucket>
20
+ >;
21
+
22
+ export type UseLogsHistogramFunction = (
23
+ fetchBuckets: FetchHistogramBucketsFunction,
24
+ ) => LogsHistogramState;
25
+
26
+ /**
27
+ * Owns the log histogram's data, loading flag and refresh loop.
28
+ *
29
+ * The chart is fed by its own aggregation query rather than by the rows in
30
+ * the table, so it needs refreshing in its own right — including on every
31
+ * live-mode tick. A poll is a *silent* refresh, which is what keeps live mode
32
+ * from looking broken:
33
+ *
34
+ * - it does not raise the loading flag, so the chart does not flash a loader
35
+ * every few seconds;
36
+ * - it keeps the buckets already on screen if the request fails, so one bad
37
+ * response does not blank the chart;
38
+ * - it is dropped while an earlier poll is still running, so a slow
39
+ * aggregation cannot pile requests up behind it.
40
+ *
41
+ * `fetchBuckets` doubles as the query identity: hand over a new callback (a
42
+ * new time range, filter or scope) and the histogram reloads.
43
+ */
44
+ const useLogsHistogram: UseLogsHistogramFunction = (
45
+ fetchBuckets: FetchHistogramBucketsFunction,
46
+ ): LogsHistogramState => {
47
+ const [buckets, setBuckets] = useState<Array<HistogramBucket>>([]);
48
+ const [isLoading, setIsLoading] = useState<boolean>(false);
49
+
50
+ const silentRequestInFlight: React.MutableRefObject<boolean> =
51
+ useRef<boolean>(false);
52
+
53
+ /*
54
+ * The query the viewer is on right now. A request that comes back after the
55
+ * reader has moved to another time range or filter is dropped rather than
56
+ * painted over the window they are actually looking at.
57
+ */
58
+ const currentQuery: React.MutableRefObject<FetchHistogramBucketsFunction> =
59
+ useRef<FetchHistogramBucketsFunction>(fetchBuckets);
60
+
61
+ useEffect(() => {
62
+ currentQuery.current = fetchBuckets;
63
+ }, [fetchBuckets]);
64
+
65
+ const refresh: (options?: LogsHistogramRefreshOptions) => Promise<void> =
66
+ useCallback(
67
+ async (options: LogsHistogramRefreshOptions = {}): Promise<void> => {
68
+ const isSilent: boolean = options.silent === true;
69
+
70
+ if (isSilent) {
71
+ if (silentRequestInFlight.current) {
72
+ return;
73
+ }
74
+
75
+ silentRequestInFlight.current = true;
76
+ } else {
77
+ setIsLoading(true);
78
+ }
79
+
80
+ try {
81
+ const nextBuckets: Array<HistogramBucket> = await fetchBuckets();
82
+
83
+ if (currentQuery.current === fetchBuckets) {
84
+ setBuckets(nextBuckets);
85
+ }
86
+ } catch {
87
+ // The histogram is non-critical; degrade rather than fail the page.
88
+ if (!isSilent && currentQuery.current === fetchBuckets) {
89
+ setBuckets([]);
90
+ }
91
+ } finally {
92
+ if (isSilent) {
93
+ silentRequestInFlight.current = false;
94
+ } else if (currentQuery.current === fetchBuckets) {
95
+ setIsLoading(false);
96
+ }
97
+ }
98
+ },
99
+ [fetchBuckets],
100
+ );
101
+
102
+ useEffect(() => {
103
+ void refresh();
104
+ }, [refresh]);
105
+
106
+ return {
107
+ buckets: buckets,
108
+ isLoading: isLoading,
109
+ refresh: refresh,
110
+ };
111
+ };
112
+
113
+ export default useLogsHistogram;
@@ -5,6 +5,7 @@ import DropdownValueBadge from "../Dropdown/DropdownValueBadge";
5
5
  import AnalyticsBaseModel from "../../../Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel";
6
6
  import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
7
7
  import CustomFieldType from "../../../Types/CustomField/CustomFieldType";
8
+ import { CustomFieldDefinition } from "../../../Types/CustomField/CustomFieldDefinition";
8
9
  import {
9
10
  CustomFieldDropdownOption,
10
11
  parseCustomFieldDropdownOptions,
@@ -45,12 +46,7 @@ import React, { ReactElement } from "react";
45
46
  * fall-through text branch understands a dotted key.
46
47
  */
47
48
 
48
- export interface CustomFieldDefinition {
49
- name: string;
50
- description?: string | undefined;
51
- customFieldType?: CustomFieldType | undefined;
52
- dropdownOptions?: string | undefined;
53
- }
49
+ export type { CustomFieldDefinition } from "../../../Types/CustomField/CustomFieldDefinition";
54
50
 
55
51
  export const CustomFieldsColumnKey: string = "customFields";
56
52
 
@@ -55,18 +55,37 @@ const useCustomFieldColumns: UseCustomFieldColumnsFunction = <
55
55
  const [definitions, setDefinitions] = useState<Array<CustomFieldDefinition>>(
56
56
  [],
57
57
  );
58
- const [isLoading, setIsLoading] = useState<boolean>(false);
59
- const [error, setError] = useState<string>("");
60
58
 
61
59
  const projectId: ObjectID | null =
62
60
  data.projectId ?? ProjectUtil.getCurrentProjectId();
63
61
 
62
+ /*
63
+ * Starts true whenever a request is actually going to happen, rather than
64
+ * false-until-the-effect-runs.
65
+ *
66
+ * Columns did not care — they only ever appear — but a caller that has to
67
+ * distinguish "no custom fields" from "not yet" does. The facet bar is one:
68
+ * on the first render it must know that a chip restored from a shared link
69
+ * may still be on its way, or it drops the link's filter before the request
70
+ * has even been sent.
71
+ */
72
+ const [isLoading, setIsLoading] = useState<boolean>(
73
+ Boolean(data.customFieldsModelType && projectId),
74
+ );
75
+ const [error, setError] = useState<string>("");
76
+
64
77
  const projectIdString: string = projectId?.toString() || "";
65
78
  const modelName: string = customFieldsModelType?.name || "";
66
79
 
67
80
  useEffect(() => {
68
81
  if (!customFieldsModelType || !projectId) {
69
82
  setDefinitions([]);
83
+ /*
84
+ * Nothing to wait for. Said explicitly because the initial state is now
85
+ * "loading" whenever a request is expected, and a model type that goes
86
+ * away between renders would otherwise leave it stuck there.
87
+ */
88
+ setIsLoading(false);
70
89
  return;
71
90
  }
72
91