@oneuptime/common 12.0.34 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/Models/DatabaseModels/GlobalConfig.ts +12 -12
  2. package/Models/DatabaseModels/InventoryItem.ts +44 -1
  3. package/Models/DatabaseModels/NetworkDevice.ts +126 -0
  4. package/Server/EnvironmentConfig.ts +47 -16
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.ts +25 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  7. package/Server/Infrastructure/Redis.ts +8 -8
  8. package/Server/Infrastructure/Status.ts +10 -4
  9. package/Server/Services/DatabaseService.ts +65 -13
  10. package/Server/Services/InventoryItemService.ts +31 -1
  11. package/Server/Services/MonitorTemplateService.ts +140 -19
  12. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +349 -41
  13. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +87 -2
  14. package/Server/Services/NetworkDeviceService.ts +69 -0
  15. package/Server/Services/UserNotificationRuleService.ts +76 -25
  16. package/Server/Types/Database/Permissions/ReadPermission.ts +45 -5
  17. package/Server/Types/Database/QueryUtil.ts +56 -0
  18. package/Server/Types/Markdown.ts +93 -1
  19. package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +82 -17
  20. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +10 -1
  21. package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +2 -2
  22. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +82 -35
  23. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +31 -5
  24. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +202 -37
  25. package/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.ts +82 -9
  26. package/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.ts +16 -7
  27. package/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.ts +29 -17
  28. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +107 -48
  29. package/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.ts +158 -0
  30. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +27 -0
  31. package/Server/Utils/Telemetry/EntityRegistry.ts +11 -1
  32. package/Server/Utils/Telemetry/TelemetryEntity.ts +83 -9
  33. package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +32 -0
  34. package/Tests/App/Dashboard/AdoptedDeviceDrawer.test.tsx +374 -0
  35. package/Tests/App/Dashboard/DashboardLabelVariables.test.tsx +580 -0
  36. package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +438 -0
  37. package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +5 -2
  38. package/Tests/App/Dashboard/DeviceAttachmentCard.test.tsx +273 -0
  39. package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +505 -0
  40. package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +163 -0
  41. package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +401 -0
  42. package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +232 -0
  43. package/Tests/App/Dashboard/InventoryItems.test.tsx +201 -0
  44. package/Tests/App/Dashboard/InventoryTypeAndStatusFacets.test.tsx +798 -0
  45. package/Tests/App/Dashboard/NetworkTopologyLiveView.test.tsx +320 -0
  46. package/Tests/App/Dashboard/NetworkTopologyToolbar.test.tsx +275 -0
  47. package/Tests/App/Dashboard/OnCallCalendarFeedEmptyState.test.tsx +975 -0
  48. package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +63 -0
  49. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +626 -0
  50. package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +348 -0
  51. package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +331 -0
  52. package/Tests/App/Dashboard/UserSettingsEmailPreferences.test.tsx +603 -0
  53. package/Tests/App/Dashboard/UserSettingsNotificationSettings.test.tsx +324 -0
  54. package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +13 -4
  55. package/Tests/App/StatusPage/StatusPageOidcOrigin.test.tsx +223 -0
  56. package/Tests/Models/InventoryItemStatus.test.ts +147 -0
  57. package/Tests/Models/NetworkDeviceMacAddressColumn.test.ts +294 -0
  58. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +129 -0
  59. package/Tests/Server/EnvironmentConfigValkey.test.ts +227 -0
  60. package/Tests/Server/Infrastructure/Postgres/AddMacAddressToNetworkDeviceMigration.test.ts +365 -0
  61. package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +62 -23
  62. package/Tests/Server/Infrastructure/ValkeyDeploymentConfig.test.ts +265 -0
  63. package/Tests/Server/Middleware/HttpMetricsMiddleware.test.ts +382 -0
  64. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +525 -0
  65. package/Tests/Server/Services/DatabaseServiceAggregateBy.test.ts +291 -56
  66. package/Tests/Server/Services/DatabaseServiceSortTiebreaker.test.ts +151 -0
  67. package/Tests/Server/Services/InventoryItemManualCreate.test.ts +105 -0
  68. package/Tests/Server/Services/InventoryItemPromotionGate.test.ts +178 -0
  69. package/Tests/Server/Services/MonitorTemplateServiceCustomFieldSync.test.ts +502 -0
  70. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +1133 -81
  71. package/Tests/Server/Services/NetworkDeviceDiscoveryScanRegistration.test.ts +520 -0
  72. package/Tests/Server/Services/NetworkDeviceMacAddressNormalization.test.ts +572 -0
  73. package/Tests/Server/Types/Database/InventoryStatusPostgres.test.ts +368 -0
  74. package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +261 -14
  75. package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroups.test.ts +169 -0
  76. package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroupsPostgres.test.ts +297 -0
  77. package/Tests/Server/Types/Markdown.test.ts +194 -1
  78. package/Tests/Server/Types/Workflow/Components/IncomingWebhookUtils.test.ts +279 -0
  79. package/Tests/Server/Types/Workflow/Components/TextToJson.test.ts +212 -0
  80. package/Tests/Server/Utils/CustomField/CustomFieldMappingRegistry.test.ts +436 -0
  81. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +214 -0
  82. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1 -1
  83. package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +10 -3
  84. package/Tests/Server/Utils/EventLoop.test.ts +359 -0
  85. package/Tests/Server/Utils/JsonWebToken.test.ts +30 -0
  86. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +242 -0
  87. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +13 -7
  88. package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +29 -0
  89. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +30 -6
  90. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +246 -0
  91. package/Tests/Server/Utils/Monitor/MonitorCriteriaEmailEvalLogAgreement.test.ts +280 -0
  92. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +224 -10
  93. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +570 -0
  94. package/Tests/Server/Utils/Monitor/MonitorCriteriaExpectationBuilderUnits.test.ts +30 -5
  95. package/Tests/Server/Utils/Monitor/MonitorCriteriaMessageBuilderUnits.test.ts +68 -21
  96. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +36 -19
  97. package/Tests/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.test.ts +573 -0
  98. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +317 -0
  99. package/Tests/Server/Utils/Telemetry/ContextSpanProcessor.test.ts +281 -0
  100. package/Tests/Server/Utils/Telemetry/InventoryDuplicateIdentity.test.ts +316 -0
  101. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +111 -8
  102. package/Tests/Types/Database/IncludesAnyOfGroups.test.ts +106 -0
  103. package/Tests/Types/JSONFunctions.test.ts +40 -0
  104. package/Tests/Types/NetworkAutomation/AutoImportRunMerge.test.ts +235 -0
  105. package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +66 -0
  106. package/Tests/Types/NetworkAutomation/RuleRunResultDescribe.test.ts +309 -1
  107. package/Tests/Types/Telemetry/InventoryLiveness.test.ts +99 -0
  108. package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +160 -0
  109. package/Tests/UI/ReactRouterSingletonBuild.test.ts +133 -0
  110. package/Tests/UI/Rum/ReplayHeader.test.tsx +10 -2
  111. package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +514 -0
  112. package/Tests/UI/Rum/ReplayTimeFormat.test.ts +94 -0
  113. package/Tests/UI/Rum/ReplayUi.test.tsx +559 -0
  114. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +5 -0
  115. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +1 -0
  116. package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +11 -1
  117. package/Tests/Utils/Dashboard/LabelVariable.test.ts +257 -0
  118. package/Tests/Utils/Dashboard/VariableUrlState.test.ts +144 -14
  119. package/Tests/Utils/MetricUnitUtil.test.ts +81 -0
  120. package/Tests/Utils/Monitor/DeviceMacLearningUtil.test.ts +497 -0
  121. package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +546 -0
  122. package/Tests/Utils/Monitor/MonitorTemplateCustomFieldUtil.test.ts +218 -0
  123. package/Tests/Utils/Monitor/NetworkTopologyEndpointAdoption.test.ts +1755 -0
  124. package/Tests/Utils/NetworkAutomation/AutoImportRunChain.test.ts +320 -0
  125. package/Types/BaseDatabase/IncludesAnyOfGroups.ts +77 -0
  126. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  127. package/Types/Dashboard/DashboardComponents/DashboardMonitorListComponent.ts +1 -0
  128. package/Types/Dashboard/DashboardVariable.ts +8 -0
  129. package/Types/JSON.ts +4 -0
  130. package/Types/JSONFunctions.ts +16 -0
  131. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
  132. package/Types/NetworkAutomation/RuleRunResult.ts +402 -13
  133. package/Types/SerializableObjectDictionary.ts +4 -0
  134. package/Types/Telemetry/InventoryLiveness.ts +56 -0
  135. package/UI/Components/CSVFileUpload/CSVFileUpload.tsx +9 -2
  136. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +46 -21
  137. package/UI/Components/Dashboard/DashboardVariableControl.tsx +285 -0
  138. package/UI/esbuild-config.js +6 -0
  139. package/Utils/Dashboard/Components/DashboardMonitorListComponent.ts +12 -1
  140. package/Utils/Dashboard/LabelVariable.ts +152 -0
  141. package/Utils/Dashboard/VariableUrlState.ts +27 -5
  142. package/Utils/MetricUnitUtil.ts +34 -0
  143. package/Utils/Monitor/DeviceMacLearningUtil.ts +177 -0
  144. package/Utils/Monitor/MetricValueFormatter.ts +342 -0
  145. package/Utils/Monitor/MonitorTemplateCustomFieldUtil.ts +124 -0
  146. package/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.ts +7 -2
  147. package/Utils/Monitor/NetworkTopologyUtil.ts +693 -0
  148. package/Utils/NetworkAutomation/AutoImportRunChain.ts +138 -0
  149. package/build/dist/Models/DatabaseModels/GlobalConfig.js +12 -12
  150. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  151. package/build/dist/Models/DatabaseModels/InventoryItem.js +34 -1
  152. package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
  153. package/build/dist/Models/DatabaseModels/NetworkDevice.js +128 -0
  154. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  155. package/build/dist/Server/EnvironmentConfig.js +44 -12
  156. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  157. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js +14 -0
  158. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js.map +1 -0
  159. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  160. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  161. package/build/dist/Server/Infrastructure/Redis.js +8 -8
  162. package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
  163. package/build/dist/Server/Infrastructure/Status.js +10 -4
  164. package/build/dist/Server/Infrastructure/Status.js.map +1 -1
  165. package/build/dist/Server/Services/DatabaseService.js +58 -13
  166. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  167. package/build/dist/Server/Services/InventoryItemService.js +28 -1
  168. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  169. package/build/dist/Server/Services/MonitorTemplateService.js +116 -17
  170. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  171. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +270 -37
  172. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  173. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +65 -0
  174. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  175. package/build/dist/Server/Services/NetworkDeviceService.js +54 -0
  176. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  177. package/build/dist/Server/Services/UserNotificationRuleService.js +60 -25
  178. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  179. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +29 -4
  180. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
  181. package/build/dist/Server/Types/Database/QueryUtil.js +36 -0
  182. package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
  183. package/build/dist/Server/Types/Markdown.js +75 -0
  184. package/build/dist/Server/Types/Markdown.js.map +1 -1
  185. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +53 -18
  186. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
  187. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +10 -1
  188. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
  189. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +2 -2
  190. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -1
  191. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +58 -35
  192. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
  193. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +29 -5
  194. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
  195. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +166 -35
  196. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  197. package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js +58 -9
  198. package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js.map +1 -1
  199. package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js +9 -3
  200. package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js.map +1 -1
  201. package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js +26 -12
  202. package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js.map +1 -1
  203. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +74 -33
  204. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  205. package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js +114 -0
  206. package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js.map +1 -0
  207. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +25 -0
  208. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  209. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +9 -1
  210. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  211. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +70 -13
  212. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  213. package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js +54 -0
  214. package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js.map +1 -0
  215. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  216. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  217. package/build/dist/Types/Dashboard/DashboardVariable.js +1 -0
  218. package/build/dist/Types/Dashboard/DashboardVariable.js.map +1 -1
  219. package/build/dist/Types/JSON.js +1 -0
  220. package/build/dist/Types/JSON.js.map +1 -1
  221. package/build/dist/Types/JSONFunctions.js +13 -0
  222. package/build/dist/Types/JSONFunctions.js.map +1 -1
  223. package/build/dist/Types/NetworkAutomation/RuleRunResult.js +291 -6
  224. package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -1
  225. package/build/dist/Types/SerializableObjectDictionary.js +4 -0
  226. package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
  227. package/build/dist/Types/Telemetry/InventoryLiveness.js +37 -0
  228. package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -0
  229. package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js +7 -0
  230. package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js.map +1 -1
  231. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +9 -2
  232. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  233. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +137 -0
  234. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -0
  235. package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js +9 -1
  236. package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js.map +1 -1
  237. package/build/dist/Utils/Dashboard/LabelVariable.js +96 -0
  238. package/build/dist/Utils/Dashboard/LabelVariable.js.map +1 -0
  239. package/build/dist/Utils/Dashboard/VariableUrlState.js +19 -4
  240. package/build/dist/Utils/Dashboard/VariableUrlState.js.map +1 -1
  241. package/build/dist/Utils/MetricUnitUtil.js +26 -0
  242. package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
  243. package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js +112 -0
  244. package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js.map +1 -0
  245. package/build/dist/Utils/Monitor/MetricValueFormatter.js +276 -0
  246. package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -0
  247. package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js +101 -0
  248. package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js.map +1 -0
  249. package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js +7 -2
  250. package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js.map +1 -1
  251. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +484 -0
  252. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  253. package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js +59 -0
  254. package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js.map +1 -0
  255. package/jest.config.json +2 -0
  256. package/package.json +1 -1
  257. package/test-setup.sh +9 -9
  258. package/tsconfig.json +51 -11
  259. package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +0 -399
@@ -117,13 +117,18 @@ function metricResponse(
117
117
  describe("MonitorCriteriaEvaluator - Proxmox root cause breakdown", () => {
118
118
  test("renders the Resource/Type/Node/Value table: zero rows dropped, worst first", () => {
119
119
  const affectedResources: Array<ProxmoxAffectedResource> = [
120
+ /*
121
+ * pve_cpu_usage_ratio is a [0, 1] ratio — the catalog says so and
122
+ * pve-exporter reports it that way — so these are 42% and 97% of a
123
+ * node's CPU, and the table is expected to say exactly that.
124
+ */
120
125
  {
121
126
  resourceId: "qemu/100",
122
127
  resourceName: "web-vm",
123
128
  resourceType: "qemu",
124
129
  scope: "guest",
125
130
  nodeName: "pve1",
126
- metricValue: 42,
131
+ metricValue: 0.42,
127
132
  },
128
133
  {
129
134
  resourceId: "qemu/101",
@@ -131,7 +136,7 @@ describe("MonitorCriteriaEvaluator - Proxmox root cause breakdown", () => {
131
136
  resourceType: "qemu",
132
137
  scope: "guest",
133
138
  nodeName: "pve2",
134
- metricValue: 97,
139
+ metricValue: 0.97,
135
140
  },
136
141
  // Zero-value row — must be dropped from the table.
137
142
  {
@@ -164,16 +169,60 @@ describe("MonitorCriteriaEvaluator - Proxmox root cause breakdown", () => {
164
169
  expect(context).toContain("- Metric: CPU Usage (`pve_cpu_usage_ratio`)");
165
170
 
166
171
  expect(context).toContain("| Resource | Type | Node | Value |");
167
- // Worst (97) sorts above 42; the zero row is gone entirely.
172
+ // Worst (0.97) sorts above 0.42; the zero row is gone entirely.
168
173
  const dbIndex: number = context!.indexOf("`db-vm` (`qemu/101`)");
169
174
  const webIndex: number = context!.indexOf("`web-vm` (`qemu/100`)");
170
175
  expect(dbIndex).toBeGreaterThan(-1);
171
176
  expect(webIndex).toBeGreaterThan(dbIndex);
172
177
  expect(context).not.toContain("idle-vm");
173
178
  expect(context).toContain("**Affected Resources** (2 total)");
179
+
180
+ /*
181
+ * The Value column is rendered in the unit the catalog declares for
182
+ * the metric — a "ratio" on a `_ratio`-suffixed metric is a fraction,
183
+ * so the reader gets "97.00%" rather than the bare "0.97" they would
184
+ * otherwise have to recognise as a percentage themselves.
185
+ */
186
+ expect(context).toContain(
187
+ "| `db-vm` (`qemu/101`) | qemu | `pve2` | **97.00%** |",
188
+ );
189
+ expect(context).toContain(
190
+ "| `web-vm` (`qemu/100`) | qemu | `pve1` | **42.00%** |",
191
+ );
192
+ });
193
+
194
+ test("renders bytes in the Value column at human scale", () => {
195
+ const context: string | null = Evaluator.buildProxmoxRootCauseContext({
196
+ dataToProcess: metricResponse({
197
+ proxmoxResourceBreakdown: {
198
+ clusterName: "prod-cluster",
199
+ metricName: "pve_memory_usage_bytes",
200
+ metricFriendlyName: "Memory Usage",
201
+ affectedResources: [
202
+ {
203
+ resourceId: "qemu/101",
204
+ resourceName: "db-vm",
205
+ resourceType: "qemu",
206
+ scope: "guest",
207
+ nodeName: "pve2",
208
+ metricValue: 8589934592,
209
+ },
210
+ ],
211
+ attributes: {},
212
+ },
213
+ }),
214
+ monitorStep: proxmoxStep(),
215
+ monitor: new Monitor(),
216
+ });
217
+
218
+ /*
219
+ * The whole point of the change: an on-call engineer reading this at
220
+ * 3am should not have to divide by 2^30 in their head.
221
+ */
174
222
  expect(context).toContain(
175
- "| `db-vm` (`qemu/101`) | qemu | `pve2` | **97** |",
223
+ "| `db-vm` (`qemu/101`) | qemu | `pve2` | **8.59 GB** |",
176
224
  );
225
+ expect(context).not.toContain("**8589934592**");
177
226
  });
178
227
 
179
228
  test("caps the table at 10 rows, worst first, with an overflow suffix", () => {
@@ -187,12 +236,18 @@ describe("MonitorCriteriaEvaluator - Proxmox root cause breakdown", () => {
187
236
  });
188
237
  }
189
238
 
239
+ /*
240
+ * A `count` metric, so the rows render as bare integers and this test
241
+ * stays about the cap. It doubles as the backward-compatibility pin
242
+ * for the unitless path: a metric with no dimension to report must
243
+ * still show its exact digits, never an abbreviated "1.2K".
244
+ */
190
245
  const context: string | null = Evaluator.buildProxmoxRootCauseContext({
191
246
  dataToProcess: metricResponse({
192
247
  proxmoxResourceBreakdown: {
193
248
  clusterName: "prod-cluster",
194
- metricName: "pve_cpu_usage_ratio",
195
- metricFriendlyName: "CPU Usage",
249
+ metricName: "pve_replication_failed_syncs",
250
+ metricFriendlyName: "Failed Replication Syncs",
196
251
  affectedResources,
197
252
  attributes: {},
198
253
  },
@@ -290,8 +345,14 @@ describe("MonitorCriteriaEvaluator - Ceph root cause breakdown", () => {
290
345
  );
291
346
 
292
347
  expect(context).toContain("| Daemon | Pool | Host | Value |");
293
- expect(context).toContain("| `osd.3` | - | `ceph-node-1` | **250** |");
294
- expect(context).toContain("| - | `rbd` (`2`) | - | **91** |");
348
+ /*
349
+ * ceph_osd_apply_latency_ms carries the catalog unit "ms", so the
350
+ * Value column names it. 250 ms stays "250 ms" rather than scaling to
351
+ * seconds — the ladder only moves a value when the magnitude asks
352
+ * for it.
353
+ */
354
+ expect(context).toContain("| `osd.3` | - | `ceph-node-1` | **250 ms** |");
355
+ expect(context).toContain("| - | `rbd` (`2`) | - | **91 ms** |");
295
356
  expect(context).not.toContain("osd.5");
296
357
  expect(context).toContain("**Affected Resources** (2 total)");
297
358
 
@@ -302,6 +363,71 @@ describe("MonitorCriteriaEvaluator - Ceph root cause breakdown", () => {
302
363
  expect(poolIndex).toBeGreaterThan(osdIndex);
303
364
  });
304
365
 
366
+ /*
367
+ * BACKWARD COMPATIBILITY for the platform tables.
368
+ *
369
+ * A metric whose catalog unit is "count" or absent has no dimension to
370
+ * report, and its Value column must keep every digit — never a chart's
371
+ * abbreviated "1.2K", and never the noise "250 count". ceph_osd_up is
372
+ * `unit: "count"`; ceph_health_status has no unit at all.
373
+ */
374
+ test("a count metric keeps exact bare digits in the Value column", () => {
375
+ const context: string | null = Evaluator.buildCephRootCauseContext({
376
+ dataToProcess: metricResponse({
377
+ cephResourceBreakdown: {
378
+ clusterName: "prod-cluster",
379
+ metricName: "ceph_osd_up",
380
+ metricFriendlyName: "OSD Up",
381
+ affectedResources: [
382
+ { daemon: "osd.3", hostname: "ceph-node-1", metricValue: 5000 },
383
+ ],
384
+ attributes: {},
385
+ },
386
+ }),
387
+ monitorStep: cephStep(),
388
+ monitor: new Monitor(),
389
+ });
390
+
391
+ expect(context).toContain("| `osd.3` | - | `ceph-node-1` | **5000** |");
392
+ expect(context).not.toContain("5K");
393
+ expect(context).not.toContain("count");
394
+ });
395
+
396
+ /*
397
+ * ORDERING INVARIANT. The table sorts and filters on the RAW numeric
398
+ * metricValue and only formats at render time. If a refactor ever sorted
399
+ * the formatted strings instead, "1.07 GB" would sort below "900 KB" and
400
+ * the worst-first table would silently invert — putting the healthiest
401
+ * daemon at the top of an incident.
402
+ */
403
+ test("rows still sort worst-first on the raw value, not the formatted string", () => {
404
+ const context: string | null = Evaluator.buildCephRootCauseContext({
405
+ dataToProcess: metricResponse({
406
+ cephResourceBreakdown: {
407
+ clusterName: "prod-cluster",
408
+ metricName: "ceph_pool_rd_bytes",
409
+ metricFriendlyName: "Pool Read Throughput",
410
+ affectedResources: [
411
+ { daemon: "osd.smaller", metricValue: 921600 },
412
+ { daemon: "osd.bigger", metricValue: 1073741824 },
413
+ ],
414
+ attributes: {},
415
+ },
416
+ }),
417
+ monitorStep: cephStep(),
418
+ monitor: new Monitor(),
419
+ });
420
+
421
+ expect(context).toContain("| `osd.bigger` | - | - | **1.07 GB** |");
422
+ expect(context).toContain("| `osd.smaller` | - | - | **922 KB** |");
423
+
424
+ // "1.07 GB" < "922 KB" as strings — the raw numbers must drive this.
425
+ const biggerIndex: number = context!.indexOf("`osd.bigger`");
426
+ const smallerIndex: number = context!.indexOf("`osd.smaller`");
427
+ expect(biggerIndex).toBeGreaterThan(-1);
428
+ expect(smallerIndex).toBeGreaterThan(biggerIndex);
429
+ });
430
+
305
431
  test("cluster-wide series (ceph_health_status) render no table", () => {
306
432
  const context: string | null = Evaluator.buildCephRootCauseContext({
307
433
  dataToProcess: metricResponse({
@@ -521,8 +647,8 @@ describe("MonitorCriteriaEvaluator - Ceph affected-resources breach predicate",
521
647
  ],
522
648
  });
523
649
 
524
- expect(context).toContain("| `osd.3` | - | `ceph-node-1` | **250** |");
525
- expect(context).toContain("| - | `rbd` (`2`) | - | **91** |");
650
+ expect(context).toContain("| `osd.3` | - | `ceph-node-1` | **250 ms** |");
651
+ expect(context).toContain("| - | `rbd` (`2`) | - | **91 ms** |");
526
652
  expect(context).not.toContain("osd.5");
527
653
  expect(context).toContain("**Affected Resources** (2 total)");
528
654
 
@@ -756,4 +882,92 @@ describe("MonitorCriteriaEvaluator - Kubernetes root cause analysis scoping", ()
756
882
 
757
883
  expect(analysis).toContain("Pods are stuck in Pending phase");
758
884
  });
885
+
886
+ /*
887
+ * REGRESSION: three of these sentences hardcoded a "%" suffix onto
888
+ * metrics that are not percentages.
889
+ *
890
+ * k8s.node.memory.usage and k8s.node.filesystem.usage are BYTES, so a
891
+ * node holding 8 GiB was reported as "memory usage is at
892
+ * 8589934592.0%". k8s.node.cpu.utilization is the kubeletstats CORES
893
+ * gauge that four other places in this repo warn is misnamed, so 1.4
894
+ * cores in use read as "1.4% CPU utilization" — a number an on-call
895
+ * engineer would read as "the node is idle".
896
+ *
897
+ * Each sentence now takes its unit from the catalog, which is the same
898
+ * lookup the worker already ran to resolve metricFriendlyName.
899
+ */
900
+ describe("unit rendering in the analysis sentences", () => {
901
+ test("node CPU reports cores, not a percentage", () => {
902
+ const analysis: string | null = analyse({
903
+ metricName: "k8s.node.cpu.utilization",
904
+ topResource: { nodeName: "node-1", metricValue: 1.4 },
905
+ });
906
+
907
+ expect(analysis).toContain(
908
+ "Node `node-1` is at **1.4 cores** CPU utilization.",
909
+ );
910
+ expect(analysis).not.toContain("1.4%");
911
+ });
912
+
913
+ test("node memory reports bytes at human scale, not a percentage", () => {
914
+ const analysis: string | null = analyse({
915
+ metricName: "k8s.node.memory.usage",
916
+ topResource: { nodeName: "node-1", metricValue: 8589934592 },
917
+ });
918
+
919
+ expect(analysis).toContain(
920
+ "Node `node-1` memory usage is at **8.59 GB**.",
921
+ );
922
+ expect(analysis).not.toContain("8589934592");
923
+ expect(analysis).not.toContain("%");
924
+ });
925
+
926
+ test("node filesystem reports bytes at human scale, not a percentage", () => {
927
+ const analysis: string | null = analyse({
928
+ metricName: "k8s.node.filesystem.usage",
929
+ topResource: { nodeName: "node-1", metricValue: 1099511627776 },
930
+ });
931
+
932
+ expect(analysis).toContain(
933
+ "Node `node-1` filesystem usage is at **1.1 TB**.",
934
+ );
935
+ expect(analysis).not.toContain("%");
936
+ });
937
+
938
+ /*
939
+ * Counts keep every digit — and stop reporting the raw float an
940
+ * aggregation hands back, which used to produce "has restarted
941
+ * **2.3333333333333335** times".
942
+ */
943
+ test("restart counts are rounded and carry no unit", () => {
944
+ const analysis: string | null = analyse({
945
+ metricName: "k8s.container.restarts",
946
+ topResource: {
947
+ podName: "web-7d9f",
948
+ containerName: "web",
949
+ metricValue: 2.3333333333333335,
950
+ },
951
+ });
952
+
953
+ expect(analysis).toContain("has restarted **2.33** times.");
954
+ expect(analysis).not.toContain("2.3333333333333335");
955
+ expect(analysis).not.toContain("2.33 count");
956
+ });
957
+
958
+ test("unavailable replicas stay a bare count", () => {
959
+ const analysis: string | null = analyse({
960
+ metricName: "k8s.deployment.unavailable_replicas",
961
+ topResource: {
962
+ workloadType: "Deployment",
963
+ workloadName: "web",
964
+ metricValue: 3,
965
+ },
966
+ });
967
+
968
+ expect(analysis).toContain(
969
+ "Deployment `web` has **3** unavailable replica(s).",
970
+ );
971
+ });
972
+ });
759
973
  });