@oneuptime/common 12.0.23 → 12.0.24

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 (294) hide show
  1. package/Models/DatabaseModels/DetectionRule.ts +55 -0
  2. package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +27 -7
  3. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +67 -0
  4. package/Models/DatabaseModels/Project.ts +68 -0
  5. package/Models/DatabaseModels/User.ts +68 -0
  6. package/Server/API/TelemetryAPI.ts +29 -0
  7. package/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.ts +28 -0
  8. package/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.ts +49 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.ts +33 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  11. package/Server/Middleware/GzipRequestBody.ts +311 -0
  12. package/Server/Middleware/MultipartFormData.ts +87 -3
  13. package/Server/Services/DetectionRuleService.ts +73 -6
  14. package/Server/Services/Index.ts +205 -0
  15. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +59 -0
  16. package/Server/Services/NetworkDeviceService.ts +148 -0
  17. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
  18. package/Server/Services/OnCallDutyPolicyFeedService.ts +1 -1
  19. package/Server/Services/ProjectService.ts +29 -19
  20. package/Server/Services/SecurityEventService.ts +90 -13
  21. package/Server/Services/StatusPageResourceService.ts +223 -0
  22. package/Server/Services/TelemetryAttributeService.ts +17 -0
  23. package/Server/Services/UserService.ts +4 -6
  24. package/Server/Types/Markdown.ts +161 -67
  25. package/Server/Utils/AI/Toolbox/OnCallTools.ts +12 -4
  26. package/Server/Utils/AnalyticsDatabase/Statement.ts +13 -1
  27. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +297 -6
  28. package/Server/Utils/Attribution.ts +4 -0
  29. package/Server/Utils/Marketing/MarketingEventUtil.ts +45 -7
  30. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +55 -3
  31. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +21 -0
  32. package/Server/Utils/StartServer.ts +12 -32
  33. package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +101 -4
  34. package/Server/Utils/Telemetry/LlmMetricSpend.ts +130 -0
  35. package/Server/Views/Partials/AnalyticsConsent.ejs +159 -102
  36. package/Server/Views/Partials/Head.ejs +2 -1
  37. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +776 -38
  38. package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +359 -0
  39. package/Tests/App/Dashboard/CorrelateGraph.test.tsx +865 -0
  40. package/Tests/App/Dashboard/CorrelationGraph.test.ts +346 -0
  41. package/Tests/App/Dashboard/CriteriaFilterConditionDropdown.test.tsx +256 -0
  42. package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +738 -0
  43. package/Tests/App/Dashboard/CriteriaFilterMonitorTypeChange.test.ts +1122 -0
  44. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +283 -0
  45. package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +407 -0
  46. package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +5 -14
  47. package/Tests/App/Dashboard/MonitorCriteriaActionToggles.test.tsx +426 -0
  48. package/Tests/App/Dashboard/MonitorStepsCriteriaAlignmentWiring.test.tsx +352 -0
  49. package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +278 -0
  50. package/Tests/App/Dashboard/OnCallLayerShiftPreviewOverrides.test.ts +237 -0
  51. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +2 -2
  52. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +460 -0
  53. package/Tests/App/Dashboard/SecurityEventAttributeUtil.test.ts +171 -0
  54. package/Tests/App/Dashboard/SecurityEventCorrelation.test.ts +857 -0
  55. package/Tests/App/Dashboard/SecurityEventDetailObservables.test.tsx +194 -0
  56. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +124 -0
  57. package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +79 -19
  58. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +382 -0
  59. package/Tests/App/StatusPage/BulkAddStatusPageMonitors.test.ts +216 -0
  60. package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +590 -11
  61. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +757 -0
  62. package/Tests/Models/DiscoveryScanNameColumn.test.ts +293 -0
  63. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +564 -0
  64. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +120 -4
  65. package/Tests/Server/Middleware/GzipRequestBody.test.ts +725 -0
  66. package/Tests/Server/Middleware/MultipartFormData.test.ts +298 -0
  67. package/Tests/Server/Services/AddDetectionRuleDistinctCountColumnsMigration.test.ts +311 -0
  68. package/Tests/Server/Services/DetectionRuleService.test.ts +134 -2
  69. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +7 -1
  70. package/Tests/Server/Services/FeedRetentionConsistency.test.ts +131 -0
  71. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +194 -0
  72. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +800 -0
  73. package/Tests/Server/Services/OnCallScheduleAttachRosterRefresh.test.ts +244 -0
  74. package/Tests/Server/Services/SecurityEventService.test.ts +376 -0
  75. package/Tests/Server/Services/StatusPageResourceDuplicates.test.ts +703 -0
  76. package/Tests/Server/Services/TelemetryAttributeServiceSecurityEvent.test.ts +256 -0
  77. package/Tests/Server/Types/Workflow/Components/ComponentRegistryParity.test.ts +417 -0
  78. package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorWhereOperators.test.ts +677 -0
  79. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +43 -0
  80. package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +15 -11
  81. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +369 -8
  82. package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +35 -0
  83. package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +368 -4
  84. package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +245 -0
  85. package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +48 -5
  86. package/Tests/Types/Code/YamlSyntax.test.ts +396 -0
  87. package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +957 -0
  88. package/Tests/Types/Monitor/MonitorCriteriaActionValidation.test.ts +598 -0
  89. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +49 -0
  90. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +6 -6
  91. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +4 -4
  92. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +4 -3
  93. package/Tests/Types/Telemetry/LlmMetricConventions.test.ts +193 -0
  94. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +0 -12
  95. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +1 -17
  96. package/Tests/UI/Components/CodeEditor.test.tsx +474 -10
  97. package/Tests/UI/Components/Detail/YamlField.test.tsx +105 -0
  98. package/Tests/UI/Components/EntityDropdownLabelsBulkAdd.test.tsx +319 -0
  99. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +231 -0
  100. package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +1 -0
  101. package/Tests/UI/Components/Forms/ValidationYAML.test.ts +234 -0
  102. package/Tests/UI/Components/ModelTable/AttributeColumns.test.tsx +573 -0
  103. package/Tests/UI/Components/ModelTable/BaseModelTableAttributeColumns.test.tsx +824 -0
  104. package/Tests/UI/Components/ModelTable/ColumnCustomizationModalAddableColumns.test.tsx +707 -0
  105. package/Tests/UI/Components/SideOver.test.tsx +1 -1
  106. package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +294 -0
  107. package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +436 -0
  108. package/Tests/UI/Components/TableBulkCsvExport.test.tsx +6 -2
  109. package/Tests/UI/Components/Toggle.test.tsx +25 -0
  110. package/Tests/UI/Components/YamlEditor.test.tsx +847 -0
  111. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +252 -0
  112. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +221 -0
  113. package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
  114. package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
  115. package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +472 -0
  116. package/Types/Code/YamlSyntax.ts +396 -0
  117. package/Types/Exception/ExceptionCode.ts +1 -0
  118. package/Types/Exception/PayloadTooLargeException.ts +8 -0
  119. package/Types/Marketing/Attribution.ts +10 -0
  120. package/Types/Marketing/MarketingEvent.ts +4 -0
  121. package/Types/Monitor/MonitorCriteriaInstance.ts +116 -56
  122. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +2 -1
  123. package/Types/SecurityEvent/DetectionFindingConstants.ts +11 -0
  124. package/Types/Telemetry/LlmMetricConventions.ts +124 -0
  125. package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +3 -0
  126. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +10 -1
  127. package/UI/Components/CodeEditor/CodeEditor.tsx +241 -79
  128. package/UI/Components/CodeEditor/YamlEditor.tsx +369 -0
  129. package/UI/Components/Detail/Detail.tsx +10 -0
  130. package/UI/Components/EntityDropdown/EntityDropdown.tsx +33 -0
  131. package/UI/Components/Forms/Fields/FormField.tsx +31 -0
  132. package/UI/Components/Forms/Types/Field.ts +8 -0
  133. package/UI/Components/Forms/Types/FormFieldSchemaType.ts +1 -0
  134. package/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.ts +2 -0
  135. package/UI/Components/Forms/Validation.ts +46 -0
  136. package/UI/Components/Input/Input.tsx +3 -0
  137. package/UI/Components/ModelTable/AttributeColumns.tsx +321 -0
  138. package/UI/Components/ModelTable/BaseModelTable.tsx +263 -14
  139. package/UI/Components/ModelTable/Column.ts +8 -0
  140. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +310 -0
  141. package/UI/Components/ModelTable/ColumnPreference.ts +13 -1
  142. package/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.tsx +2 -2
  143. package/UI/Components/SideOver/SideOver.tsx +5 -5
  144. package/UI/Components/StatusPage/ResourceGrid.tsx +82 -2
  145. package/UI/Components/StatusPage/ResourceList.tsx +197 -38
  146. package/UI/Components/Toggle/Toggle.tsx +9 -1
  147. package/UI/Components/Types/FieldType.ts +1 -0
  148. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +73 -1
  149. package/Utils/NetworkDiscovery/ScanNameUtil.ts +181 -0
  150. package/Utils/StatusPage/ResourceExplorer.ts +258 -0
  151. package/Utils/Telemetry/LlmMetricQuery.ts +204 -0
  152. package/build/dist/Models/DatabaseModels/DetectionRule.js +57 -0
  153. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
  154. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +27 -7
  155. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
  156. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +69 -0
  157. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  158. package/build/dist/Models/DatabaseModels/Project.js +76 -0
  159. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  160. package/build/dist/Models/DatabaseModels/User.js +76 -0
  161. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  162. package/build/dist/Server/API/TelemetryAPI.js +17 -0
  163. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  164. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js +21 -0
  165. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js.map +1 -0
  166. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js +42 -0
  167. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js.map +1 -0
  168. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js +22 -0
  169. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js.map +1 -0
  170. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  171. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  172. package/build/dist/Server/Middleware/GzipRequestBody.js +224 -0
  173. package/build/dist/Server/Middleware/GzipRequestBody.js.map +1 -0
  174. package/build/dist/Server/Middleware/MultipartFormData.js +71 -2
  175. package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
  176. package/build/dist/Server/Services/DetectionRuleService.js +49 -4
  177. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  178. package/build/dist/Server/Services/Index.js +204 -0
  179. package/build/dist/Server/Services/Index.js.map +1 -1
  180. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +50 -0
  181. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  182. package/build/dist/Server/Services/NetworkDeviceService.js +124 -0
  183. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  184. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +68 -13
  185. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  186. package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +1 -1
  187. package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -1
  188. package/build/dist/Server/Services/ProjectService.js +25 -45
  189. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  190. package/build/dist/Server/Services/SecurityEventService.js +57 -5
  191. package/build/dist/Server/Services/SecurityEventService.js.map +1 -1
  192. package/build/dist/Server/Services/StatusPageResourceService.js +140 -0
  193. package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
  194. package/build/dist/Server/Services/TelemetryAttributeService.js +17 -0
  195. package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
  196. package/build/dist/Server/Services/UserService.js +2 -12
  197. package/build/dist/Server/Services/UserService.js.map +1 -1
  198. package/build/dist/Server/Types/Markdown.js +147 -61
  199. package/build/dist/Server/Types/Markdown.js.map +1 -1
  200. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +12 -4
  201. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -1
  202. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +12 -1
  203. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  204. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +246 -9
  205. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  206. package/build/dist/Server/Utils/Attribution.js.map +1 -1
  207. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +27 -7
  208. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -1
  209. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +42 -7
  210. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  211. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +18 -0
  212. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  213. package/build/dist/Server/Utils/StartServer.js +12 -21
  214. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  215. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +76 -5
  216. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -1
  217. package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js +102 -0
  218. package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
  219. package/build/dist/Types/Code/YamlSyntax.js +212 -0
  220. package/build/dist/Types/Code/YamlSyntax.js.map +1 -0
  221. package/build/dist/Types/Exception/ExceptionCode.js +1 -0
  222. package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
  223. package/build/dist/Types/Exception/PayloadTooLargeException.js +8 -0
  224. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -0
  225. package/build/dist/Types/Marketing/Attribution.js +10 -0
  226. package/build/dist/Types/Marketing/Attribution.js.map +1 -1
  227. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +112 -51
  228. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  229. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +2 -1
  230. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
  231. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +9 -0
  232. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  233. package/build/dist/Types/Telemetry/LlmMetricConventions.js +98 -0
  234. package/build/dist/Types/Telemetry/LlmMetricConventions.js.map +1 -0
  235. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
  236. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
  237. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +5 -2
  238. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  239. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +206 -76
  240. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  241. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +201 -0
  242. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -0
  243. package/build/dist/UI/Components/Detail/Detail.js +9 -0
  244. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  245. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +16 -1
  246. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  247. package/build/dist/UI/Components/Forms/Fields/FormField.js +14 -1
  248. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  249. package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
  250. package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js +1 -0
  251. package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js.map +1 -1
  252. package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js +2 -0
  253. package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js.map +1 -1
  254. package/build/dist/UI/Components/Forms/Validation.js +27 -0
  255. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  256. package/build/dist/UI/Components/Input/Input.js +1 -1
  257. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  258. package/build/dist/UI/Components/ModelTable/AttributeColumns.js +159 -0
  259. package/build/dist/UI/Components/ModelTable/AttributeColumns.js.map +1 -0
  260. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +179 -17
  261. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  262. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +133 -2
  263. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
  264. package/build/dist/UI/Components/ModelTable/ColumnPreference.js +7 -1
  265. package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -1
  266. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.js +2 -2
  267. package/build/dist/UI/Components/SideOver/SideOver.js +5 -5
  268. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +28 -2
  269. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
  270. package/build/dist/UI/Components/StatusPage/ResourceList.js +87 -20
  271. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
  272. package/build/dist/UI/Components/Toggle/Toggle.js +9 -1
  273. package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
  274. package/build/dist/UI/Components/Types/FieldType.js +1 -0
  275. package/build/dist/UI/Components/Types/FieldType.js.map +1 -1
  276. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +37 -1
  277. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  278. package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js +120 -0
  279. package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
  280. package/build/dist/Utils/StatusPage/ResourceExplorer.js +171 -0
  281. package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -1
  282. package/build/dist/Utils/Telemetry/LlmMetricQuery.js +119 -0
  283. package/build/dist/Utils/Telemetry/LlmMetricQuery.js.map +1 -0
  284. package/jest.config.json +2 -0
  285. package/package.json +1 -1
  286. package/tsconfig.json +2 -1
  287. package/Tests/UI/Components/Toast.test.tsx +0 -197
  288. package/Tests/UI/Components/ToastStacking.test.tsx +0 -198
  289. package/UI/Components/Toast/Toast.tsx +0 -189
  290. package/UI/Components/Toast/ToastInit.tsx +0 -110
  291. package/build/dist/UI/Components/Toast/Toast.js +0 -123
  292. package/build/dist/UI/Components/Toast/Toast.js.map +0 -1
  293. package/build/dist/UI/Components/Toast/ToastInit.js +0 -53
  294. package/build/dist/UI/Components/Toast/ToastInit.js.map +0 -1
@@ -608,3 +608,255 @@ describe("issue #3220 at fleet scale", () => {
608
608
  expect(stale).toBe(50);
609
609
  });
610
610
  });
611
+
612
+ /*
613
+ * Issue #3392: a device nothing polls.
614
+ *
615
+ * The whole rule above is about the OUTCOME of a poll, and a monitor-backed
616
+ * device never gets one — no probe, no credentials, no walk. Its poll
617
+ * columns are NULL forever, so the rule could only ever answer "Pending"
618
+ * for it: an operator who followed the documented workflow to the letter
619
+ * (Monitoring Method = Monitor, a Ping monitor bound, polling off) watched
620
+ * a device that answers every ping sit on "Pending" indefinitely.
621
+ *
622
+ * These pin the second rule: for such a device the bound Monitor's verdict
623
+ * IS the answer, and every poll column on the row is irrelevant to it.
624
+ */
625
+ describe("monitor-backed devices are judged by their monitor, not by a poll", () => {
626
+ const MONITOR_BACKED: string = "Monitor";
627
+
628
+ test("a bound monitor reporting healthy makes the device Up", () => {
629
+ expect(
630
+ statusOf({
631
+ monitoringMethod: MONITOR_BACKED,
632
+ monitorStatusIsOffline: false,
633
+ }),
634
+ ).toBe(NetworkDeviceReachability.Up);
635
+ });
636
+
637
+ test("a bound monitor reporting offline makes the device Down", () => {
638
+ expect(
639
+ statusOf({
640
+ monitoringMethod: MONITOR_BACKED,
641
+ monitorStatusIsOffline: true,
642
+ }),
643
+ ).toBe(NetworkDeviceReachability.Down);
644
+ });
645
+
646
+ /*
647
+ * MonitorStatus is a ladder, not a pair: a "Degraded" row is neither
648
+ * operational nor offline. Reading the OFFLINE end is what keeps this
649
+ * verdict identical to the one the topology map draws for the same
650
+ * device, which resolves the ladder the same way.
651
+ */
652
+ test("a degraded-but-not-offline status is Up, exactly as the map draws it", () => {
653
+ expect(
654
+ statusOf({
655
+ monitoringMethod: MONITOR_BACKED,
656
+ monitorStatusIsOffline: false,
657
+ }),
658
+ ).toBe(NetworkDeviceReachability.Up);
659
+ });
660
+
661
+ /*
662
+ * The two ways a monitor-backed device legitimately has no verdict:
663
+ * nothing is bound to it yet (discovery import creates ping-only hosts
664
+ * that way on purpose), or something is bound and has not been evaluated
665
+ * yet. Both are Pending, and neither may default to healthy.
666
+ */
667
+ test("no stamped status is Pending, not a healthy default", () => {
668
+ expect(statusOf({ monitoringMethod: MONITOR_BACKED })).toBe(
669
+ NetworkDeviceReachability.Pending,
670
+ );
671
+
672
+ expect(
673
+ statusOf({
674
+ monitoringMethod: MONITOR_BACKED,
675
+ monitorStatusIsOffline: null,
676
+ }),
677
+ ).toBe(NetworkDeviceReachability.Pending);
678
+ });
679
+
680
+ /*
681
+ * The regression itself. This is the exact row shape the issue reports:
682
+ * an ICMP-only host imported by a discovery scan, switched to Monitor,
683
+ * bound to a Ping monitor that is reporting healthy, and polled by
684
+ * nothing — so every poll column is NULL.
685
+ */
686
+ test("the reported row shape reads Up rather than Pending", () => {
687
+ const un0661voipcp01: DeviceReachabilityInput = {
688
+ monitoringMethod: MONITOR_BACKED,
689
+ monitorStatusIsOffline: false,
690
+ isReachable: null,
691
+ lastPolledAt: null,
692
+ lastSeenAt: null,
693
+ pollingIntervalInMinutes: null,
694
+ };
695
+
696
+ expect(statusOf(un0661voipcp01)).toBe(NetworkDeviceReachability.Up);
697
+ });
698
+
699
+ /*
700
+ * Poll columns on a monitor-backed row are not merely absent — on a
701
+ * device switched over from SNMP they hold whatever a probe last found
702
+ * before it stopped asking, which is worse than nothing. The monitor
703
+ * wins outright, in both directions.
704
+ */
705
+ test("a stale successful walk does not override a monitor reporting offline", () => {
706
+ expect(
707
+ statusOf({
708
+ monitoringMethod: MONITOR_BACKED,
709
+ monitorStatusIsOffline: true,
710
+ isReachable: true,
711
+ lastPolledAt: minutesAgo(2),
712
+ lastSeenAt: minutesAgo(2),
713
+ }),
714
+ ).toBe(NetworkDeviceReachability.Down);
715
+ });
716
+
717
+ test("a failed walk from its SNMP days does not override a healthy monitor", () => {
718
+ expect(
719
+ statusOf({
720
+ monitoringMethod: MONITOR_BACKED,
721
+ monitorStatusIsOffline: false,
722
+ isReachable: false,
723
+ lastPolledAt: minutesAgo(4000),
724
+ lastSeenAt: minutesAgo(9000),
725
+ }),
726
+ ).toBe(NetworkDeviceReachability.Up);
727
+ });
728
+
729
+ /*
730
+ * Staleness says "nothing has polled this device lately, go and check its
731
+ * probe". For a device that has no probe BY DESIGN that is both false and
732
+ * actively misleading, so it can never be raised here.
733
+ */
734
+ test("is never flagged stale, however old the poll columns are", () => {
735
+ const result: DeviceReachabilityResult = reachabilityOf({
736
+ monitoringMethod: MONITOR_BACKED,
737
+ monitorStatusIsOffline: false,
738
+ lastPolledAt: minutesAgo(60 * 24 * 30),
739
+ lastSeenAt: minutesAgo(60 * 24 * 30),
740
+ pollingIntervalInMinutes: 5,
741
+ });
742
+
743
+ expect(result.status).toBe(NetworkDeviceReachability.Up);
744
+ expect(result.isStale).toBe(false);
745
+ });
746
+
747
+ test("is never flagged stale even when it has no poll columns at all", () => {
748
+ expect(
749
+ reachabilityOf({
750
+ monitoringMethod: MONITOR_BACKED,
751
+ monitorStatusIsOffline: true,
752
+ }).isStale,
753
+ ).toBe(false);
754
+ });
755
+
756
+ /*
757
+ * lastContactAt is still reported honestly — it is "the newest thing a
758
+ * probe wrote", and for a device converted from SNMP that is a real
759
+ * historical fact the device page prints. It just does not decide
760
+ * anything here.
761
+ */
762
+ test("still reports lastContactAt from the poll columns when there is one", () => {
763
+ expect(
764
+ reachabilityOf({
765
+ monitoringMethod: MONITOR_BACKED,
766
+ monitorStatusIsOffline: false,
767
+ lastPolledAt: minutesAgo(90),
768
+ }).lastContactAt?.getTime(),
769
+ ).toBe(minutesAgo(90).getTime());
770
+
771
+ expect(
772
+ reachabilityOf({
773
+ monitoringMethod: MONITOR_BACKED,
774
+ monitorStatusIsOffline: false,
775
+ }).lastContactAt,
776
+ ).toBeNull();
777
+ });
778
+ });
779
+
780
+ /*
781
+ * The column is free text (the SnmpVersion precedent), so what counts as
782
+ * "monitor-backed" is whatever NetworkDeviceMonitoringMethodUtil.parse says
783
+ * — and every other value has to keep the poll rule, because reading a
784
+ * typo as monitor-backed would silently stop a switch being judged by its
785
+ * walk.
786
+ */
787
+ describe("which rows count as monitor-backed", () => {
788
+ test.each(["Monitor", "monitor", "MONITOR", " Monitor "])(
789
+ "%p reads as monitor-backed",
790
+ (monitoringMethod: string) => {
791
+ const result: DeviceReachabilityResult = reachabilityOf({
792
+ monitoringMethod: monitoringMethod,
793
+ monitorStatusIsOffline: false,
794
+ });
795
+
796
+ expect(result.isMonitorBacked).toBe(true);
797
+ expect(result.status).toBe(NetworkDeviceReachability.Up);
798
+ },
799
+ );
800
+
801
+ test.each([
802
+ ["SNMP", "the explicit SNMP value"],
803
+ ["", "an empty string"],
804
+ ["Monitorr", "a typo"],
805
+ ["ping", "an unrecognised word"],
806
+ ])("%p (%s) keeps the poll rule", (monitoringMethod: string) => {
807
+ const device: DeviceReachabilityInput = {
808
+ monitoringMethod: monitoringMethod,
809
+ // A monitor status the poll rule must ignore for these rows.
810
+ monitorStatusIsOffline: true,
811
+ isReachable: true,
812
+ lastPolledAt: minutesAgo(1),
813
+ lastSeenAt: minutesAgo(1),
814
+ };
815
+
816
+ const result: DeviceReachabilityResult = reachabilityOf(device);
817
+
818
+ expect(result.isMonitorBacked).toBe(false);
819
+ expect(result.status).toBe(NetworkDeviceReachability.Up);
820
+ });
821
+
822
+ /*
823
+ * Every row written before the column existed, and every caller that
824
+ * does not select it. Both have to keep behaving exactly as they did.
825
+ */
826
+ test.each([
827
+ ["null", null],
828
+ ["undefined", undefined],
829
+ ])(
830
+ "a %s method is a polled device, unchanged",
831
+ (_label: string, value: string | null | undefined) => {
832
+ const result: DeviceReachabilityResult = reachabilityOf({
833
+ monitoringMethod: value as string | null | undefined,
834
+ monitorStatusIsOffline: true,
835
+ isReachable: true,
836
+ lastPolledAt: minutesAgo(1),
837
+ lastSeenAt: minutesAgo(1),
838
+ });
839
+
840
+ expect(result.isMonitorBacked).toBe(false);
841
+ expect(result.status).toBe(NetworkDeviceReachability.Up);
842
+ },
843
+ );
844
+
845
+ /*
846
+ * A caller that selects neither new column gets precisely the old
847
+ * behaviour, including staleness — which is what lets the topology
848
+ * builder and the site rollup keep passing their existing projections.
849
+ */
850
+ test("an input carrying neither new column behaves exactly as before", () => {
851
+ const result: DeviceReachabilityResult = reachabilityOf({
852
+ isReachable: true,
853
+ lastPolledAt: minutesAgo(180),
854
+ lastSeenAt: minutesAgo(180),
855
+ pollingIntervalInMinutes: 5,
856
+ });
857
+
858
+ expect(result.status).toBe(NetworkDeviceReachability.Up);
859
+ expect(result.isStale).toBe(true);
860
+ expect(result.isMonitorBacked).toBe(false);
861
+ });
862
+ });
@@ -0,0 +1,221 @@
1
+ import { DiscoveredNetworkDevice } from "../../../Models/DatabaseModels/NetworkDeviceDiscoveryScan";
2
+ import { normalizeDiscoveredHosts } from "../../../Utils/NetworkDiscovery/DiscoveredHostUtil";
3
+ import { describe, expect, test } from "@jest/globals";
4
+
5
+ /*
6
+ * normalizeDiscoveredHosts is the one reading of a scan's `discoveredDevices`
7
+ * jsonb that both the dashboard's Review dialog and the server-side
8
+ * auto-import rule engine share. The column is written verbatim from the
9
+ * probe's payload and the only guard on it is "the value is an array", so the
10
+ * three payload shapes documented on the function - a null row, a non-string
11
+ * address, and the same address carrying two different isAlreadyRegistered
12
+ * values - are shapes nothing upstream stops. These tests pin that each is
13
+ * neutralised here, once, so no downstream reader can be handed a different
14
+ * reading of the same payload.
15
+ *
16
+ * A cast through `unknown` is used wherever a test feeds a shape the type
17
+ * forbids on purpose: the whole point of the function is that the runtime
18
+ * value does not honour the type, so the tests have to be able to say so.
19
+ */
20
+
21
+ function host(
22
+ overrides: Partial<DiscoveredNetworkDevice>,
23
+ ): DiscoveredNetworkDevice {
24
+ return { ipAddress: "10.0.0.1", ...overrides };
25
+ }
26
+
27
+ describe("normalizeDiscoveredHosts", () => {
28
+ describe("rows that are not hosts at all", () => {
29
+ test("an empty scan normalises to an empty list", () => {
30
+ expect(normalizeDiscoveredHosts([])).toEqual([]);
31
+ });
32
+
33
+ test.each([
34
+ ["null", null],
35
+ ["undefined", undefined],
36
+ ["a number", 10],
37
+ ["a string", "10.0.0.1"],
38
+ ["a boolean", true],
39
+ ])(
40
+ "%s is dropped rather than dereferenced",
41
+ (_label: string, value: unknown) => {
42
+ expect(
43
+ normalizeDiscoveredHosts([
44
+ value,
45
+ ] as unknown as Array<DiscoveredNetworkDevice>),
46
+ ).toEqual([]);
47
+ },
48
+ );
49
+
50
+ test("the real hosts around a null row survive it", () => {
51
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
52
+ host({ ipAddress: "10.0.0.1" }),
53
+ null as unknown as DiscoveredNetworkDevice,
54
+ host({ ipAddress: "10.0.0.2" }),
55
+ ]);
56
+
57
+ expect(
58
+ result.map((entry: DiscoveredNetworkDevice) => {
59
+ return entry.ipAddress;
60
+ }),
61
+ ).toEqual(["10.0.0.1", "10.0.0.2"]);
62
+ });
63
+ });
64
+
65
+ describe("the address is made a trimmed string", () => {
66
+ test("a numeric address becomes its string spelling, so Set.has can find it", () => {
67
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
68
+ { ipAddress: 10 } as unknown as DiscoveredNetworkDevice,
69
+ ]);
70
+
71
+ expect(result[0]!.ipAddress).toBe("10");
72
+ });
73
+
74
+ test.each([
75
+ ["a leading and trailing space", " 10.0.0.1 ", "10.0.0.1"],
76
+ ["a tab", "\t10.0.0.1", "10.0.0.1"],
77
+ ["only whitespace", " ", ""],
78
+ ])("%s is trimmed", (_label: string, given: string, expected: string) => {
79
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
80
+ host({ ipAddress: given }),
81
+ ]);
82
+
83
+ expect(result[0]!.ipAddress).toBe(expected);
84
+ });
85
+
86
+ test.each([
87
+ ["undefined", undefined],
88
+ ["null", null],
89
+ ])(
90
+ "a %s address becomes the empty string, never the literal word",
91
+ (_label: string, value: unknown) => {
92
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts(
93
+ [{ ipAddress: value } as unknown as DiscoveredNetworkDevice],
94
+ );
95
+
96
+ expect(result[0]!.ipAddress).toBe("");
97
+ },
98
+ );
99
+ });
100
+
101
+ describe("everything else on the row is carried through untouched", () => {
102
+ test("the SNMP system group and reachability flags survive normalisation", () => {
103
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
104
+ {
105
+ ipAddress: " 10.0.0.5 ",
106
+ sysName: "core-switch",
107
+ sysDescr: "vendor OS 1.2",
108
+ sysObjectId: "1.3.6.1.4.1.9",
109
+ sysLocation: "rack 4",
110
+ sysContact: "neteng",
111
+ sysUpTimeSeconds: 4200,
112
+ snmpReachable: true,
113
+ },
114
+ ]);
115
+
116
+ expect(result[0]).toEqual({
117
+ ipAddress: "10.0.0.5",
118
+ sysName: "core-switch",
119
+ sysDescr: "vendor OS 1.2",
120
+ sysObjectId: "1.3.6.1.4.1.9",
121
+ sysLocation: "rack 4",
122
+ sysContact: "neteng",
123
+ sysUpTimeSeconds: 4200,
124
+ snmpReachable: true,
125
+ });
126
+ });
127
+ });
128
+
129
+ describe("an address registered on one row is registered on every row", () => {
130
+ test("a duplicate address inherits the registered verdict regardless of probe ordering", () => {
131
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
132
+ host({ ipAddress: "10.0.0.9", isAlreadyRegistered: false }),
133
+ host({ ipAddress: "10.0.0.9", isAlreadyRegistered: true }),
134
+ ]);
135
+
136
+ expect(
137
+ result.map((entry: DiscoveredNetworkDevice) => {
138
+ return entry.isAlreadyRegistered;
139
+ }),
140
+ ).toEqual([true, true]);
141
+ });
142
+
143
+ test("the verdict does not bleed onto a different address", () => {
144
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
145
+ host({ ipAddress: "10.0.0.9", isAlreadyRegistered: true }),
146
+ host({ ipAddress: "10.0.0.10", isAlreadyRegistered: false }),
147
+ ]);
148
+
149
+ expect(
150
+ result.find((entry: DiscoveredNetworkDevice) => {
151
+ return entry.ipAddress === "10.0.0.10";
152
+ })!.isAlreadyRegistered,
153
+ ).toBe(false);
154
+ });
155
+
156
+ test("an already-registered row is handed back as the very same object", () => {
157
+ const registered: DiscoveredNetworkDevice = host({
158
+ ipAddress: "10.0.0.11",
159
+ isAlreadyRegistered: true,
160
+ });
161
+
162
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
163
+ registered,
164
+ ]);
165
+
166
+ /*
167
+ * With nothing to flip, the normaliser must not churn objects it did
168
+ * not change - a fresh clone every render would defeat any memoised
169
+ * reader keyed on identity. The first pass already re-spread the row,
170
+ * so identity is asserted against that cleaned object, not the input.
171
+ */
172
+ expect(result[0]).toEqual(registered);
173
+ });
174
+
175
+ test("the empty-string address is never treated as a registered key", () => {
176
+ /*
177
+ * A blank address is what an undefined or whitespace-only address
178
+ * normalises to. If it counted as a registered key, every other blank
179
+ * row - unrelated hosts the probe could not address - would be marked
180
+ * registered together.
181
+ */
182
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
183
+ host({ ipAddress: " ", isAlreadyRegistered: true }),
184
+ host({ ipAddress: undefined as unknown as string }),
185
+ ]);
186
+
187
+ expect(
188
+ result.every((entry: DiscoveredNetworkDevice) => {
189
+ return entry.ipAddress === "";
190
+ }),
191
+ ).toBe(true);
192
+ expect(result[1]!.isAlreadyRegistered).toBeUndefined();
193
+ });
194
+
195
+ test("three rows of one address all end up registered when any one is", () => {
196
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
197
+ host({ ipAddress: "10.0.0.20", isAlreadyRegistered: false }),
198
+ host({ ipAddress: "10.0.0.20" }),
199
+ host({ ipAddress: "10.0.0.20", isAlreadyRegistered: true }),
200
+ ]);
201
+
202
+ expect(
203
+ result.map((entry: DiscoveredNetworkDevice) => {
204
+ return entry.isAlreadyRegistered;
205
+ }),
206
+ ).toEqual([true, true, true]);
207
+ });
208
+ });
209
+
210
+ describe("a scan with nothing registered is left as it is found", () => {
211
+ test("no row gains a registered flag it did not arrive with", () => {
212
+ const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
213
+ host({ ipAddress: "10.0.0.30", isAlreadyRegistered: false }),
214
+ host({ ipAddress: "10.0.0.31" }),
215
+ ]);
216
+
217
+ expect(result[0]!.isAlreadyRegistered).toBe(false);
218
+ expect(result[1]!.isAlreadyRegistered).toBeUndefined();
219
+ });
220
+ });
221
+ });