@oneuptime/common 12.0.22 → 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 (345) hide show
  1. package/Models/DatabaseModels/DetectionRule.ts +55 -0
  2. package/Models/DatabaseModels/Index.ts +2 -0
  3. package/Models/DatabaseModels/NetworkDevice.ts +44 -0
  4. package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +584 -0
  5. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +105 -0
  6. package/Models/DatabaseModels/Project.ts +68 -0
  7. package/Models/DatabaseModels/User.ts +68 -0
  8. package/Server/API/TelemetryAPI.ts +29 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.ts +60 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.ts +26 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.ts +26 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.ts +28 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.ts +49 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.ts +33 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  16. package/Server/Middleware/GzipRequestBody.ts +311 -0
  17. package/Server/Middleware/MultipartFormData.ts +87 -3
  18. package/Server/Services/DetectionRuleService.ts +73 -6
  19. package/Server/Services/Index.ts +207 -0
  20. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +917 -0
  21. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +181 -0
  22. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +59 -0
  23. package/Server/Services/NetworkDeviceService.ts +148 -0
  24. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
  25. package/Server/Services/OnCallDutyPolicyFeedService.ts +1 -1
  26. package/Server/Services/ProjectService.ts +29 -19
  27. package/Server/Services/SecurityEventService.ts +90 -13
  28. package/Server/Services/StatusPageResourceService.ts +223 -0
  29. package/Server/Services/TelemetryAttributeService.ts +17 -0
  30. package/Server/Services/UserService.ts +4 -6
  31. package/Server/Types/Markdown.ts +161 -67
  32. package/Server/Utils/AI/Toolbox/OnCallTools.ts +12 -4
  33. package/Server/Utils/AnalyticsDatabase/Statement.ts +13 -1
  34. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +297 -6
  35. package/Server/Utils/Attribution.ts +4 -0
  36. package/Server/Utils/Marketing/MarketingEventUtil.ts +45 -7
  37. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +39 -1
  38. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +55 -3
  39. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +21 -0
  40. package/Server/Utils/StartServer.ts +12 -32
  41. package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +101 -4
  42. package/Server/Utils/Telemetry/LlmMetricSpend.ts +130 -0
  43. package/Server/Views/Partials/AnalyticsConsent.ejs +159 -102
  44. package/Server/Views/Partials/Head.ejs +2 -1
  45. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +776 -38
  46. package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +359 -0
  47. package/Tests/App/Dashboard/CorrelateGraph.test.tsx +865 -0
  48. package/Tests/App/Dashboard/CorrelationGraph.test.ts +346 -0
  49. package/Tests/App/Dashboard/CriteriaFilterConditionDropdown.test.tsx +256 -0
  50. package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +738 -0
  51. package/Tests/App/Dashboard/CriteriaFilterMonitorTypeChange.test.ts +1122 -0
  52. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +283 -0
  53. package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +407 -0
  54. package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +5 -14
  55. package/Tests/App/Dashboard/MonitorCriteriaActionToggles.test.tsx +426 -0
  56. package/Tests/App/Dashboard/MonitorStepsCriteriaAlignmentWiring.test.tsx +352 -0
  57. package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +278 -0
  58. package/Tests/App/Dashboard/OnCallLayerShiftPreviewOverrides.test.ts +237 -0
  59. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +2 -2
  60. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +460 -0
  61. package/Tests/App/Dashboard/SecurityEventAttributeUtil.test.ts +171 -0
  62. package/Tests/App/Dashboard/SecurityEventCorrelation.test.ts +857 -0
  63. package/Tests/App/Dashboard/SecurityEventDetailObservables.test.tsx +194 -0
  64. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +124 -0
  65. package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +79 -19
  66. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +382 -0
  67. package/Tests/App/StatusPage/BulkAddStatusPageMonitors.test.ts +216 -0
  68. package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +590 -11
  69. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +757 -0
  70. package/Tests/Models/DiscoveryScanNameColumn.test.ts +293 -0
  71. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +564 -0
  72. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +120 -4
  73. package/Tests/Server/Middleware/GzipRequestBody.test.ts +725 -0
  74. package/Tests/Server/Middleware/MultipartFormData.test.ts +298 -0
  75. package/Tests/Server/Services/AddDetectionRuleDistinctCountColumnsMigration.test.ts +311 -0
  76. package/Tests/Server/Services/AutoImportScanCredentialSelect.test.ts +205 -0
  77. package/Tests/Server/Services/DetectionRuleService.test.ts +134 -2
  78. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +7 -1
  79. package/Tests/Server/Services/FeedRetentionConsistency.test.ts +131 -0
  80. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +933 -0
  81. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +194 -0
  82. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +800 -0
  83. package/Tests/Server/Services/OnCallScheduleAttachRosterRefresh.test.ts +244 -0
  84. package/Tests/Server/Services/SecurityEventService.test.ts +376 -0
  85. package/Tests/Server/Services/StatusPageResourceDuplicates.test.ts +703 -0
  86. package/Tests/Server/Services/TelemetryAttributeServiceSecurityEvent.test.ts +256 -0
  87. package/Tests/Server/Types/Workflow/Components/ComponentRegistryParity.test.ts +417 -0
  88. package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorWhereOperators.test.ts +677 -0
  89. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +43 -0
  90. package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +15 -11
  91. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +97 -1
  92. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +369 -8
  93. package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +35 -0
  94. package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +368 -4
  95. package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +245 -0
  96. package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +48 -5
  97. package/Tests/Types/Code/YamlSyntax.test.ts +396 -0
  98. package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +957 -0
  99. package/Tests/Types/Monitor/MonitorCriteriaActionValidation.test.ts +598 -0
  100. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +49 -0
  101. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +6 -6
  102. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +4 -4
  103. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +4 -3
  104. package/Tests/Types/Telemetry/LlmMetricConventions.test.ts +193 -0
  105. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +0 -12
  106. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +1 -17
  107. package/Tests/UI/Components/CodeEditor.test.tsx +474 -10
  108. package/Tests/UI/Components/Detail/YamlField.test.tsx +105 -0
  109. package/Tests/UI/Components/EntityDropdownLabelsBulkAdd.test.tsx +319 -0
  110. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +231 -0
  111. package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +1 -0
  112. package/Tests/UI/Components/Forms/ValidationYAML.test.ts +234 -0
  113. package/Tests/UI/Components/ModelTable/AttributeColumns.test.tsx +573 -0
  114. package/Tests/UI/Components/ModelTable/BaseModelTableAttributeColumns.test.tsx +824 -0
  115. package/Tests/UI/Components/ModelTable/ColumnCustomizationModalAddableColumns.test.tsx +707 -0
  116. package/Tests/UI/Components/SideOver.test.tsx +1 -1
  117. package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +294 -0
  118. package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +436 -0
  119. package/Tests/UI/Components/TableBulkCsvExport.test.tsx +6 -2
  120. package/Tests/UI/Components/Toggle.test.tsx +25 -0
  121. package/Tests/UI/Components/YamlEditor.test.tsx +847 -0
  122. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +252 -0
  123. package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +516 -0
  124. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +272 -0
  125. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +221 -0
  126. package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
  127. package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +164 -0
  128. package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
  129. package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +472 -0
  130. package/Types/Code/YamlSyntax.ts +396 -0
  131. package/Types/Exception/ExceptionCode.ts +1 -0
  132. package/Types/Exception/PayloadTooLargeException.ts +8 -0
  133. package/Types/Marketing/Attribution.ts +10 -0
  134. package/Types/Marketing/MarketingEvent.ts +4 -0
  135. package/Types/Monitor/MonitorCriteriaInstance.ts +116 -56
  136. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +2 -1
  137. package/Types/NetworkAutomation/RuleRunResult.ts +84 -0
  138. package/Types/Permission.ts +47 -0
  139. package/Types/SecurityEvent/DetectionFindingConstants.ts +11 -0
  140. package/Types/Telemetry/LlmMetricConventions.ts +124 -0
  141. package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +3 -0
  142. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +10 -1
  143. package/UI/Components/CodeEditor/CodeEditor.tsx +241 -79
  144. package/UI/Components/CodeEditor/YamlEditor.tsx +369 -0
  145. package/UI/Components/Detail/Detail.tsx +10 -0
  146. package/UI/Components/EntityDropdown/EntityDropdown.tsx +33 -0
  147. package/UI/Components/Forms/Fields/FormField.tsx +31 -0
  148. package/UI/Components/Forms/Types/Field.ts +8 -0
  149. package/UI/Components/Forms/Types/FormFieldSchemaType.ts +1 -0
  150. package/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.ts +2 -0
  151. package/UI/Components/Forms/Validation.ts +46 -0
  152. package/UI/Components/Input/Input.tsx +3 -0
  153. package/UI/Components/ModelTable/AttributeColumns.tsx +321 -0
  154. package/UI/Components/ModelTable/BaseModelTable.tsx +263 -14
  155. package/UI/Components/ModelTable/Column.ts +8 -0
  156. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +310 -0
  157. package/UI/Components/ModelTable/ColumnPreference.ts +13 -1
  158. package/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.tsx +2 -2
  159. package/UI/Components/SideOver/SideOver.tsx +5 -5
  160. package/UI/Components/StatusPage/ResourceGrid.tsx +82 -2
  161. package/UI/Components/StatusPage/ResourceList.tsx +197 -38
  162. package/UI/Components/Toggle/Toggle.tsx +9 -1
  163. package/UI/Components/Types/FieldType.ts +1 -0
  164. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +73 -1
  165. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +257 -0
  166. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +183 -0
  167. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +95 -0
  168. package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +66 -0
  169. package/Utils/NetworkDiscovery/ScanNameUtil.ts +181 -0
  170. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +82 -0
  171. package/Utils/StatusPage/ResourceExplorer.ts +258 -0
  172. package/Utils/Telemetry/LlmMetricQuery.ts +204 -0
  173. package/build/dist/Models/DatabaseModels/DetectionRule.js +57 -0
  174. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
  175. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  176. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  177. package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
  178. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  179. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +609 -0
  180. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -0
  181. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +97 -0
  182. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  183. package/build/dist/Models/DatabaseModels/Project.js +76 -0
  184. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  185. package/build/dist/Models/DatabaseModels/User.js +76 -0
  186. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  187. package/build/dist/Server/API/TelemetryAPI.js +17 -0
  188. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  189. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.js +35 -0
  190. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.js.map +1 -0
  191. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.js +19 -0
  192. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.js.map +1 -0
  193. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.js +19 -0
  194. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.js.map +1 -0
  195. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js +21 -0
  196. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js.map +1 -0
  197. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js +42 -0
  198. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js.map +1 -0
  199. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js +22 -0
  200. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js.map +1 -0
  201. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  202. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  203. package/build/dist/Server/Middleware/GzipRequestBody.js +224 -0
  204. package/build/dist/Server/Middleware/GzipRequestBody.js.map +1 -0
  205. package/build/dist/Server/Middleware/MultipartFormData.js +71 -2
  206. package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
  207. package/build/dist/Server/Services/DetectionRuleService.js +49 -4
  208. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  209. package/build/dist/Server/Services/Index.js +206 -0
  210. package/build/dist/Server/Services/Index.js.map +1 -1
  211. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +711 -0
  212. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -0
  213. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +155 -0
  214. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -0
  215. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +50 -0
  216. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  217. package/build/dist/Server/Services/NetworkDeviceService.js +124 -0
  218. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  219. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +68 -13
  220. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  221. package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +1 -1
  222. package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -1
  223. package/build/dist/Server/Services/ProjectService.js +25 -45
  224. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  225. package/build/dist/Server/Services/SecurityEventService.js +57 -5
  226. package/build/dist/Server/Services/SecurityEventService.js.map +1 -1
  227. package/build/dist/Server/Services/StatusPageResourceService.js +140 -0
  228. package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
  229. package/build/dist/Server/Services/TelemetryAttributeService.js +17 -0
  230. package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
  231. package/build/dist/Server/Services/UserService.js +2 -12
  232. package/build/dist/Server/Services/UserService.js.map +1 -1
  233. package/build/dist/Server/Types/Markdown.js +147 -61
  234. package/build/dist/Server/Types/Markdown.js.map +1 -1
  235. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +12 -4
  236. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -1
  237. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +12 -1
  238. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  239. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +246 -9
  240. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  241. package/build/dist/Server/Utils/Attribution.js.map +1 -1
  242. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +27 -7
  243. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -1
  244. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +26 -0
  245. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  246. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +42 -7
  247. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  248. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +18 -0
  249. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  250. package/build/dist/Server/Utils/StartServer.js +12 -21
  251. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  252. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +76 -5
  253. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -1
  254. package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js +102 -0
  255. package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
  256. package/build/dist/Types/Code/YamlSyntax.js +212 -0
  257. package/build/dist/Types/Code/YamlSyntax.js.map +1 -0
  258. package/build/dist/Types/Exception/ExceptionCode.js +1 -0
  259. package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
  260. package/build/dist/Types/Exception/PayloadTooLargeException.js +8 -0
  261. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -0
  262. package/build/dist/Types/Marketing/Attribution.js +10 -0
  263. package/build/dist/Types/Marketing/Attribution.js.map +1 -1
  264. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +112 -51
  265. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  266. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +2 -1
  267. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
  268. package/build/dist/Types/NetworkAutomation/RuleRunResult.js +24 -0
  269. package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -1
  270. package/build/dist/Types/Permission.js +41 -0
  271. package/build/dist/Types/Permission.js.map +1 -1
  272. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +9 -0
  273. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  274. package/build/dist/Types/Telemetry/LlmMetricConventions.js +98 -0
  275. package/build/dist/Types/Telemetry/LlmMetricConventions.js.map +1 -0
  276. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
  277. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
  278. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +5 -2
  279. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  280. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +206 -76
  281. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  282. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +201 -0
  283. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -0
  284. package/build/dist/UI/Components/Detail/Detail.js +9 -0
  285. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  286. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +16 -1
  287. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  288. package/build/dist/UI/Components/Forms/Fields/FormField.js +14 -1
  289. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  290. package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
  291. package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js +1 -0
  292. package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js.map +1 -1
  293. package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js +2 -0
  294. package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js.map +1 -1
  295. package/build/dist/UI/Components/Forms/Validation.js +27 -0
  296. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  297. package/build/dist/UI/Components/Input/Input.js +1 -1
  298. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  299. package/build/dist/UI/Components/ModelTable/AttributeColumns.js +159 -0
  300. package/build/dist/UI/Components/ModelTable/AttributeColumns.js.map +1 -0
  301. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +179 -17
  302. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  303. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +133 -2
  304. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
  305. package/build/dist/UI/Components/ModelTable/ColumnPreference.js +7 -1
  306. package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -1
  307. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.js +2 -2
  308. package/build/dist/UI/Components/SideOver/SideOver.js +5 -5
  309. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +28 -2
  310. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
  311. package/build/dist/UI/Components/StatusPage/ResourceList.js +87 -20
  312. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
  313. package/build/dist/UI/Components/Toggle/Toggle.js +9 -1
  314. package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
  315. package/build/dist/UI/Components/Types/FieldType.js +1 -0
  316. package/build/dist/UI/Components/Types/FieldType.js.map +1 -1
  317. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +37 -1
  318. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  319. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +149 -0
  320. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -0
  321. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +121 -0
  322. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -0
  323. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +75 -0
  324. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -0
  325. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +59 -0
  326. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -0
  327. package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js +120 -0
  328. package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
  329. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +60 -0
  330. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
  331. package/build/dist/Utils/StatusPage/ResourceExplorer.js +171 -0
  332. package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -1
  333. package/build/dist/Utils/Telemetry/LlmMetricQuery.js +119 -0
  334. package/build/dist/Utils/Telemetry/LlmMetricQuery.js.map +1 -0
  335. package/jest.config.json +2 -0
  336. package/package.json +1 -1
  337. package/tsconfig.json +2 -1
  338. package/Tests/UI/Components/Toast.test.tsx +0 -197
  339. package/Tests/UI/Components/ToastStacking.test.tsx +0 -198
  340. package/UI/Components/Toast/Toast.tsx +0 -189
  341. package/UI/Components/Toast/ToastInit.tsx +0 -110
  342. package/build/dist/UI/Components/Toast/Toast.js +0 -123
  343. package/build/dist/UI/Components/Toast/Toast.js.map +0 -1
  344. package/build/dist/UI/Components/Toast/ToastInit.js +0 -53
  345. package/build/dist/UI/Components/Toast/ToastInit.js.map +0 -1
@@ -0,0 +1,738 @@
1
+ import CriteriaFilterUtil from "../../../../App/FeatureSet/Dashboard/src/Utils/Form/Monitor/CriteriaFilter";
2
+ import {
3
+ CheckOn,
4
+ CriteriaFilter,
5
+ EvaluateOverTimeType,
6
+ FilterType,
7
+ } from "../../../Types/Monitor/CriteriaFilter";
8
+ import MonitorCriteriaInstance from "../../../Types/Monitor/MonitorCriteriaInstance";
9
+ import MonitorType, {
10
+ MonitorTypeHelper,
11
+ } from "../../../Types/Monitor/MonitorType";
12
+ import ObjectID from "../../../Types/ObjectID";
13
+ import { DropdownOption } from "../../../UI/Components/Dropdown/Dropdown";
14
+ import { describe, expect, test } from "@jest/globals";
15
+
16
+ /*
17
+ * Reported as #3412: on an External Status Page monitor, the seeded
18
+ * "External Status Page Active Incidents" filter opened with its Filter
19
+ * Condition dropdown showing an empty "Select...", while every other field
20
+ * around it — including the sibling "Is Online" filter's condition and this
21
+ * filter's own value — was already filled in.
22
+ *
23
+ * The criteria was NOT missing a condition. It was seeded with
24
+ * FilterType.EqualTo and value 0 ("no active incidents"), but the dropdown
25
+ * that renders the condition only offered Greater Than / Less Than / Greater
26
+ * Than Or Equal To / Less Than Or Equal To for that check, so it could not
27
+ * find an option matching the stored value and fell back to its placeholder.
28
+ * The rule was fine; the form could not draw it.
29
+ *
30
+ * That is one instance of a class of defect, and this file locks the class
31
+ * shut rather than the instance:
32
+ *
33
+ * 1. Every filter any default criteria seeds must be renderable — its
34
+ * "check on" has to be one the monitor type offers, and its filter type
35
+ * has to be one that check offers. Assertion (1) below sweeps every
36
+ * MonitorType and would have failed on the reported bug.
37
+ * 2. Every filter the form hands the user must arrive with both dropdowns
38
+ * already chosen. Blank is not a neutral starting state: the server's
39
+ * comparators switch on the filter type and treat one they do not
40
+ * recognise as "no match", so a criteria saved with a blank condition
41
+ * silently never fires — and the empty dropdown is easy to walk past
42
+ * when every field around it is filled in.
43
+ *
44
+ * The instance-level regression tests for the External Status Page filter
45
+ * itself live in ExternalStatusPageCriteriaFilter.test.ts. The same invariant
46
+ * was pinned for two monitor types after an earlier instance of this bug, in
47
+ * App/Tests/Dashboard/IncomingMonitorDefaultCriteriaForm.test.ts; this file is
48
+ * that check widened to every monitor type, which is what it took to catch
49
+ * this one.
50
+ */
51
+
52
+ function optionValues(options: Array<DropdownOption>): Array<string> {
53
+ return options.map((option: DropdownOption) => {
54
+ return option.value.toString();
55
+ });
56
+ }
57
+
58
+ function filterTypeOptionsFor(checkOn: CheckOn): Array<string> {
59
+ return optionValues(
60
+ CriteriaFilterUtil.getFilterTypeOptionsByCheckOn(checkOn),
61
+ );
62
+ }
63
+
64
+ function checkOnOptionsFor(monitorType: MonitorType): Array<string> {
65
+ return optionValues(
66
+ CriteriaFilterUtil.getCheckOnOptionsByMonitorType(monitorType),
67
+ );
68
+ }
69
+
70
+ const ALL_MONITOR_TYPES: Array<MonitorType> = Object.values(
71
+ MonitorType,
72
+ ) as Array<MonitorType>;
73
+
74
+ /*
75
+ * Every monitor type the criteria form is ever drawn for. Manual monitors are
76
+ * the one exception: nothing polls them, no evaluator has a branch for them,
77
+ * and the Criteria page renders an empty state in place of the form - so
78
+ * "arrives with both dropdowns already chosen" is not a question that can be
79
+ * asked of them. They get their own assertion below instead.
80
+ */
81
+ const MONITOR_TYPES_WITH_CRITERIA: Array<MonitorType> =
82
+ ALL_MONITOR_TYPES.filter((monitorType: MonitorType) => {
83
+ return MonitorTypeHelper.doesMonitorTypeHaveCriteria(monitorType);
84
+ });
85
+
86
+ /*
87
+ * Monitor types that fall through `getDefaultOfflineMonitorCriteriaInstance`
88
+ * to `new MonitorCriteriaInstance()` - the blank starting criteria, with an
89
+ * empty name and description and the constructor's placeholder "Is Online"
90
+ * filter. `getDefaultOnlineMonitorCriteriaInstance` returns null for them
91
+ * outright.
92
+ *
93
+ * Manual monitors are the only type left here, and for them the blank is not
94
+ * a gap: nothing polls a Manual monitor, MonitorCriteriaEvaluator has no
95
+ * branch for it, and the Criteria page draws an empty state in place of the
96
+ * form. There is no criteria to seed.
97
+ *
98
+ * Eight types used to sit alongside it - Docker, Host, Podman, Docker Swarm,
99
+ * Proxmox, Ceph, IoT Device, and Profiles. That placeholder was nobody's
100
+ * design for any of them: none of their evaluators decides on "Is Online",
101
+ * the metric family and IoT Device going to MetricMonitorCriteria and
102
+ * Profiles to ProfileMonitorCriteria. They now seed real defaults on the one
103
+ * check their evaluator does read, so they have moved to the other list and
104
+ * are held to the same renderability bar as every other type.
105
+ *
106
+ * This list pins the gap from both sides - the assertions below fail if a
107
+ * type here quietly grows a real default, and if a type not here quietly
108
+ * loses one.
109
+ */
110
+ const MONITOR_TYPES_WITHOUT_SEEDED_CRITERIA: Array<MonitorType> = [
111
+ MonitorType.Manual,
112
+ ];
113
+
114
+ const MONITOR_TYPES_WITH_SEEDED_CRITERIA: Array<MonitorType> =
115
+ MONITOR_TYPES_WITH_CRITERIA.filter((monitorType: MonitorType) => {
116
+ return !MONITOR_TYPES_WITHOUT_SEEDED_CRITERIA.includes(monitorType);
117
+ });
118
+
119
+ const ALL_CHECK_ONS: Array<CheckOn> = Object.values(CheckOn) as Array<CheckOn>;
120
+
121
+ const ALL_FILTER_TYPES: Array<FilterType> = Object.values(
122
+ FilterType,
123
+ ) as Array<FilterType>;
124
+
125
+ /*
126
+ * The default criteria a monitor of this type is created with, as the criteria
127
+ * form would receive them. `getDefaultOnlineMonitorCriteriaInstance` returns
128
+ * null for monitor types that only ship an offline criteria.
129
+ */
130
+ function seededCriteriaInstances(
131
+ monitorType: MonitorType,
132
+ ): Array<MonitorCriteriaInstance> {
133
+ const instances: Array<MonitorCriteriaInstance | null> = [
134
+ MonitorCriteriaInstance.getDefaultOfflineMonitorCriteriaInstance({
135
+ monitorType: monitorType,
136
+ monitorStatusId: new ObjectID("aaaaaaaaaaaaaaaaaaaaaaaa"),
137
+ incidentSeverityId: new ObjectID("bbbbbbbbbbbbbbbbbbbbbbbb"),
138
+ alertSeverityId: new ObjectID("cccccccccccccccccccccccc"),
139
+ monitorName: "Acme",
140
+ metricOptions: { metricAliases: ["cpu"] },
141
+ }),
142
+ MonitorCriteriaInstance.getDefaultOnlineMonitorCriteriaInstance({
143
+ monitorType: monitorType,
144
+ monitorStatusId: new ObjectID("dddddddddddddddddddddddd"),
145
+ monitorName: "Acme",
146
+ metricOptions: { metricAliases: ["cpu"] },
147
+ }),
148
+ ];
149
+
150
+ return instances.filter((instance: MonitorCriteriaInstance | null) => {
151
+ return Boolean(instance?.data);
152
+ }) as Array<MonitorCriteriaInstance>;
153
+ }
154
+
155
+ describe("Criteria filter defaults", () => {
156
+ describe("every seeded default criteria is renderable in the criteria form", () => {
157
+ test.each(MONITOR_TYPES_WITH_SEEDED_CRITERIA)(
158
+ "%s: every seeded filter's check is offered by the monitor type",
159
+ (monitorType: MonitorType) => {
160
+ const offeredChecks: Array<string> = checkOnOptionsFor(monitorType);
161
+
162
+ const unrenderable: Array<string> = [];
163
+
164
+ for (const instance of seededCriteriaInstances(monitorType)) {
165
+ for (const filter of instance.data!.filters) {
166
+ if (!offeredChecks.includes(filter.checkOn.toString())) {
167
+ unrenderable.push(
168
+ `"${instance.data!.name}" seeds check "${filter.checkOn}", which ${monitorType} does not offer`,
169
+ );
170
+ }
171
+ }
172
+ }
173
+
174
+ expect(unrenderable).toEqual([]);
175
+ },
176
+ );
177
+
178
+ test.each(MONITOR_TYPES_WITH_SEEDED_CRITERIA)(
179
+ "%s: every seeded filter's condition is offered by its check",
180
+ (monitorType: MonitorType) => {
181
+ const unrenderable: Array<string> = [];
182
+
183
+ for (const instance of seededCriteriaInstances(monitorType)) {
184
+ for (const filter of instance.data!.filters) {
185
+ const offeredConditions: Array<string> = filterTypeOptionsFor(
186
+ filter.checkOn,
187
+ );
188
+
189
+ if (!filter.filterType) {
190
+ unrenderable.push(
191
+ `"${instance.data!.name}" seeds check "${filter.checkOn}" with no condition at all`,
192
+ );
193
+ continue;
194
+ }
195
+
196
+ if (!offeredConditions.includes(filter.filterType.toString())) {
197
+ unrenderable.push(
198
+ `"${instance.data!.name}" seeds check "${filter.checkOn}" with condition "${filter.filterType}", which is not one of [${offeredConditions.join(", ")}]`,
199
+ );
200
+ }
201
+ }
202
+ }
203
+
204
+ expect(unrenderable).toEqual([]);
205
+ },
206
+ );
207
+
208
+ test.each(MONITOR_TYPES_WITH_SEEDED_CRITERIA)(
209
+ "%s seeds at least one criteria somebody designed for it",
210
+ (monitorType: MonitorType) => {
211
+ const designed: Array<MonitorCriteriaInstance> =
212
+ seededCriteriaInstances(monitorType).filter(
213
+ (instance: MonitorCriteriaInstance) => {
214
+ return Boolean(instance.data!.name);
215
+ },
216
+ );
217
+
218
+ expect(designed.length).toBeGreaterThan(0);
219
+ },
220
+ );
221
+
222
+ /*
223
+ * The other side of that list. These types seed only the blank starting
224
+ * criteria - an unnamed instance carrying the constructor's placeholder
225
+ * "Is Online" filter, which none of their evaluators reads. Kept as an
226
+ * assertion rather than a comment so the gap is visible in the run, and
227
+ * so it closes loudly the day one of them gets real defaults.
228
+ */
229
+ test.each(MONITOR_TYPES_WITHOUT_SEEDED_CRITERIA)(
230
+ "%s seeds nothing but the blank starting criteria",
231
+ (monitorType: MonitorType) => {
232
+ for (const instance of seededCriteriaInstances(monitorType)) {
233
+ expect(instance.data!.name).toBe("");
234
+ expect(instance.data!.filters).toEqual([
235
+ {
236
+ checkOn: CheckOn.IsOnline,
237
+ filterType: FilterType.True,
238
+ value: undefined,
239
+ },
240
+ ]);
241
+ }
242
+ },
243
+ );
244
+ });
245
+
246
+ describe("getDefaultFilterTypeByCheckOn", () => {
247
+ test.each(ALL_CHECK_ONS)(
248
+ "%s resolves to a condition the dropdown actually offers",
249
+ (checkOn: CheckOn) => {
250
+ const defaultFilterType: FilterType | undefined =
251
+ CriteriaFilterUtil.getDefaultFilterTypeByCheckOn(checkOn);
252
+
253
+ expect(defaultFilterType).toBeDefined();
254
+ expect(filterTypeOptionsFor(checkOn)).toContain(
255
+ defaultFilterType!.toString(),
256
+ );
257
+ },
258
+ );
259
+
260
+ /*
261
+ * The default is the first option the check offers. Those lists are
262
+ * written in FilterType declaration order and each is already led by the
263
+ * condition that reads as the natural starting point for its kind of
264
+ * check, so spot-check one of each kind rather than restating the table.
265
+ */
266
+ test.each([
267
+ // Booleans start on True, not on "is not".
268
+ [CheckOn.IsOnline, FilterType.True],
269
+ [CheckOn.SqlIsOnline, FilterType.True],
270
+ [CheckOn.ExternalStatusPageIsOnline, FilterType.True],
271
+ [CheckOn.DomainIsExpired, FilterType.True],
272
+ // Measurements start on a ceiling.
273
+ [CheckOn.ResponseTime, FilterType.GreaterThan],
274
+ [CheckOn.CPUUsagePercent, FilterType.GreaterThan],
275
+ [CheckOn.ExpiresInDays, FilterType.GreaterThan],
276
+ [CheckOn.ExternalStatusPageResponseTime, FilterType.GreaterThan],
277
+ // Free text starts on a substring match.
278
+ [CheckOn.ResponseBody, FilterType.Contains],
279
+ [CheckOn.RequestHeaderValue, FilterType.Contains],
280
+ // Counts and enumerated values start on an exact match.
281
+ [CheckOn.ExternalStatusPageActiveIncidents, FilterType.EqualTo],
282
+ [CheckOn.ExceptionCount, FilterType.EqualTo],
283
+ [CheckOn.ProfileCount, FilterType.EqualTo],
284
+ [CheckOn.ExternalStatusPageComponentStatus, FilterType.EqualTo],
285
+ [CheckOn.BrowserType, FilterType.EqualTo],
286
+ [CheckOn.SqlQueryRowCount, FilterType.EqualTo],
287
+ // Single-option and process checks have only one sensible start.
288
+ [CheckOn.JavaScriptExpression, FilterType.EvaluatesToTrue],
289
+ [CheckOn.ServerProcessName, FilterType.IsExecuting],
290
+ [CheckOn.IncomingRequest, FilterType.NotRecievedInMinutes],
291
+ [CheckOn.EmailReceivedAt, FilterType.NotRecievedInMinutes],
292
+ ])("%s defaults to %s", (checkOn: CheckOn, expected: FilterType) => {
293
+ expect(CriteriaFilterUtil.getDefaultFilterTypeByCheckOn(checkOn)).toBe(
294
+ expected,
295
+ );
296
+ });
297
+ });
298
+
299
+ describe("getFilterTypeOptionsByCheckOn", () => {
300
+ /*
301
+ * Offering a condition the server does not decide on is the mirror image
302
+ * of #3412 and just as quiet: the dropdown draws fine, the criteria saves
303
+ * fine, and then the comparator it lands in does not recognise the filter
304
+ * type and returns "no match" forever. So no check may fall through to the
305
+ * whole FilterType enum - each one has to say which conditions it means.
306
+ */
307
+ test.each(ALL_CHECK_ONS)(
308
+ "%s narrows the conditions it offers rather than offering all of them",
309
+ (checkOn: CheckOn) => {
310
+ expect(filterTypeOptionsFor(checkOn).length).toBeLessThan(
311
+ ALL_FILTER_TYPES.length,
312
+ );
313
+ },
314
+ );
315
+
316
+ /*
317
+ * Exception Count and Profile Count used to be two of those fall-throughs.
318
+ * Both are decided by CompareCriteria.compareCriteriaNumbers - via
319
+ * ExceptionMonitorCriteria and ProfileMonitorCriteria - which recognises
320
+ * these six conditions and nothing else.
321
+ */
322
+ test.each([CheckOn.ExceptionCount, CheckOn.ProfileCount])(
323
+ "%s offers exactly the six numeric comparators the server evaluates",
324
+ (checkOn: CheckOn) => {
325
+ expect(filterTypeOptionsFor(checkOn)).toEqual([
326
+ FilterType.EqualTo,
327
+ FilterType.NotEqualTo,
328
+ FilterType.GreaterThan,
329
+ FilterType.LessThan,
330
+ FilterType.GreaterThanOrEqualTo,
331
+ FilterType.LessThanOrEqualTo,
332
+ ]);
333
+ },
334
+ );
335
+
336
+ /*
337
+ * Spelled out because these are the ones the enum-wide list used to offer
338
+ * on a count: conditions for processes, booleans, JavaScript, and free
339
+ * text, none of which compareCriteriaNumbers has a branch for.
340
+ */
341
+ test.each([CheckOn.ExceptionCount, CheckOn.ProfileCount])(
342
+ "%s no longer offers conditions that mean nothing for a count",
343
+ (checkOn: CheckOn) => {
344
+ const offered: Array<string> = filterTypeOptionsFor(checkOn);
345
+
346
+ for (const nonsense of [
347
+ FilterType.IsExecuting,
348
+ FilterType.IsNotExecuting,
349
+ FilterType.EvaluatesToTrue,
350
+ FilterType.True,
351
+ FilterType.False,
352
+ FilterType.IsEmpty,
353
+ FilterType.IsNotEmpty,
354
+ FilterType.Contains,
355
+ FilterType.NotContains,
356
+ FilterType.StartsWith,
357
+ FilterType.EndsWith,
358
+ FilterType.RecievedInMinutes,
359
+ FilterType.NotRecievedInMinutes,
360
+ ]) {
361
+ expect(offered).not.toContain(nonsense.toString());
362
+ }
363
+ },
364
+ );
365
+
366
+ /*
367
+ * Log and span counts get the anomaly conditions because a baseline
368
+ * exists to compare against (LogCountBaseline / SpanCountBaseline).
369
+ * Exceptions and profiles have no such baseline and no anomaly branch in
370
+ * their evaluators, so an anomaly rule saved against them could never
371
+ * fire.
372
+ */
373
+ test.each([CheckOn.ExceptionCount, CheckOn.ProfileCount])(
374
+ "%s offers no anomaly condition, having no baseline behind it",
375
+ (checkOn: CheckOn) => {
376
+ const offered: Array<string> = filterTypeOptionsFor(checkOn);
377
+
378
+ for (const anomaly of [
379
+ FilterType.AnomalouslyHigh,
380
+ FilterType.AnomalouslyLow,
381
+ FilterType.Anomalous,
382
+ ]) {
383
+ expect(offered).not.toContain(anomaly.toString());
384
+ }
385
+ },
386
+ );
387
+
388
+ test("the counts that do have a baseline keep their anomaly conditions", () => {
389
+ for (const checkOn of [CheckOn.LogCount, CheckOn.SpanCount]) {
390
+ expect(filterTypeOptionsFor(checkOn)).toContain(
391
+ FilterType.AnomalouslyHigh.toString(),
392
+ );
393
+ }
394
+ });
395
+ });
396
+
397
+ describe("getCheckOnOptionsByMonitorType", () => {
398
+ /*
399
+ * Same rule one level up: a monitor type that names no checks offers every
400
+ * check in the product, including ones its evaluator has no branch for.
401
+ */
402
+ test.each(MONITOR_TYPES_WITH_CRITERIA)(
403
+ "%s narrows the checks it offers rather than offering all of them",
404
+ (monitorType: MonitorType) => {
405
+ expect(checkOnOptionsFor(monitorType).length).toBeLessThan(
406
+ ALL_CHECK_ONS.length,
407
+ );
408
+ },
409
+ );
410
+
411
+ test.each(MONITOR_TYPES_WITH_CRITERIA)(
412
+ "%s offers at least one check",
413
+ (monitorType: MonitorType) => {
414
+ expect(checkOnOptionsFor(monitorType).length).toBeGreaterThan(0);
415
+ },
416
+ );
417
+
418
+ /*
419
+ * Manual monitors are the one type with nothing to offer. Their status is
420
+ * set by hand, MonitorCriteriaEvaluator has no branch for them, and the
421
+ * Criteria page shows an empty state instead of this form.
422
+ */
423
+ test("Manual monitors offer no checks at all", () => {
424
+ expect(
425
+ MonitorTypeHelper.doesMonitorTypeHaveCriteria(MonitorType.Manual),
426
+ ).toBe(false);
427
+ expect(checkOnOptionsFor(MonitorType.Manual)).toEqual([]);
428
+ });
429
+
430
+ test("Profiles monitors offer the profile count and nothing else", () => {
431
+ expect(checkOnOptionsFor(MonitorType.Profiles)).toEqual([
432
+ CheckOn.ProfileCount,
433
+ ]);
434
+ });
435
+
436
+ /*
437
+ * MonitorCriteriaEvaluator sends all of these down MetricMonitorCriteria,
438
+ * which only ever reads CheckOn.MetricValue. Metrics and Kubernetes were
439
+ * already narrowed; the infrastructure types and IoT Device fell through
440
+ * to the full list even though they alert on exactly the same one thing.
441
+ */
442
+ test.each([
443
+ MonitorType.Metrics,
444
+ MonitorType.Kubernetes,
445
+ MonitorType.Docker,
446
+ MonitorType.Host,
447
+ MonitorType.Podman,
448
+ MonitorType.DockerSwarm,
449
+ MonitorType.Proxmox,
450
+ MonitorType.Ceph,
451
+ MonitorType.IoTDevice,
452
+ ])(
453
+ "%s alerts on an ingested metric, so it offers only the metric value",
454
+ (monitorType: MonitorType) => {
455
+ expect(checkOnOptionsFor(monitorType)).toEqual([CheckOn.MetricValue]);
456
+ },
457
+ );
458
+
459
+ /*
460
+ * IoT Device is routed to MetricMonitorCriteria alongside the metric-only
461
+ * types but is not itself metric-only - the form still draws the full
462
+ * criteria UI for it rather than pinning the check and hiding the
463
+ * dropdown. Narrowing the list is what makes that UI honest, and the
464
+ * derived default lands on the metric value regardless.
465
+ */
466
+ test("IoT Device is not metric-only, yet still defaults to the metric value", () => {
467
+ expect(
468
+ CriteriaFilterUtil.isMetricOnlyMonitorType(MonitorType.IoTDevice),
469
+ ).toBe(false);
470
+ expect(
471
+ CriteriaFilterUtil.getDefaultCheckOnByMonitorType(
472
+ MonitorType.IoTDevice,
473
+ ),
474
+ ).toBe(CheckOn.MetricValue);
475
+ });
476
+
477
+ test.each([
478
+ [MonitorType.Exceptions, CheckOn.ExceptionCount, FilterType.EqualTo],
479
+ [MonitorType.Profiles, CheckOn.ProfileCount, FilterType.EqualTo],
480
+ ])(
481
+ "%s seeds a new filter on %s / %s",
482
+ (monitorType: MonitorType, checkOn: CheckOn, filterType: FilterType) => {
483
+ const criteriaFilter: CriteriaFilter =
484
+ CriteriaFilterUtil.getDefaultCriteriaFilter(monitorType);
485
+
486
+ expect(criteriaFilter.checkOn).toBe(checkOn);
487
+ expect(criteriaFilter.filterType).toBe(filterType);
488
+ },
489
+ );
490
+ });
491
+
492
+ describe("getFilterTypeOrDefault", () => {
493
+ test("keeps a condition that still applies to the new check", () => {
494
+ expect(
495
+ CriteriaFilterUtil.getFilterTypeOrDefault({
496
+ checkOn: CheckOn.MetricValue,
497
+ filterType: FilterType.LessThanOrEqualTo,
498
+ }),
499
+ ).toBe(FilterType.LessThanOrEqualTo);
500
+ });
501
+
502
+ test("replaces a condition the new check cannot use", () => {
503
+ /*
504
+ * A brand new criteria starts life on an "Is Online" / True filter.
505
+ * Switching it to a metric threshold has to drop True, which numeric
506
+ * comparison has no meaning for.
507
+ */
508
+ expect(filterTypeOptionsFor(CheckOn.MetricValue)).not.toContain(
509
+ FilterType.True,
510
+ );
511
+
512
+ expect(
513
+ CriteriaFilterUtil.getFilterTypeOrDefault({
514
+ checkOn: CheckOn.MetricValue,
515
+ filterType: FilterType.True,
516
+ }),
517
+ ).toBe(
518
+ CriteriaFilterUtil.getDefaultFilterTypeByCheckOn(CheckOn.MetricValue),
519
+ );
520
+ });
521
+
522
+ test("fills in a missing condition", () => {
523
+ expect(
524
+ CriteriaFilterUtil.getFilterTypeOrDefault({
525
+ checkOn: CheckOn.IsOnline,
526
+ filterType: undefined,
527
+ }),
528
+ ).toBe(FilterType.True);
529
+ });
530
+
531
+ test.each(ALL_CHECK_ONS)(
532
+ "%s never resolves to a condition it does not offer, whatever it is handed",
533
+ (checkOn: CheckOn) => {
534
+ const handedIn: Array<FilterType | undefined> = [
535
+ undefined,
536
+ FilterType.True,
537
+ FilterType.EvaluatesToTrue,
538
+ FilterType.IsExecuting,
539
+ FilterType.GreaterThan,
540
+ FilterType.Contains,
541
+ "Not A Real Filter Type" as FilterType,
542
+ ];
543
+
544
+ for (const filterType of handedIn) {
545
+ const resolved: FilterType | undefined =
546
+ CriteriaFilterUtil.getFilterTypeOrDefault({
547
+ checkOn: checkOn,
548
+ filterType: filterType,
549
+ });
550
+
551
+ expect(filterTypeOptionsFor(checkOn)).toContain(resolved!.toString());
552
+ }
553
+ },
554
+ );
555
+ });
556
+
557
+ describe("getDefaultCheckOnByMonitorType", () => {
558
+ test.each(MONITOR_TYPES_WITH_CRITERIA)(
559
+ "%s resolves to a check the monitor type actually offers",
560
+ (monitorType: MonitorType) => {
561
+ const defaultCheckOn: CheckOn | undefined =
562
+ CriteriaFilterUtil.getDefaultCheckOnByMonitorType(monitorType);
563
+
564
+ expect(defaultCheckOn).toBeDefined();
565
+ expect(checkOnOptionsFor(monitorType)).toContain(
566
+ defaultCheckOn!.toString(),
567
+ );
568
+ },
569
+ );
570
+
571
+ test.each([
572
+ MonitorType.Website,
573
+ MonitorType.API,
574
+ MonitorType.Ping,
575
+ MonitorType.IP,
576
+ MonitorType.Port,
577
+ MonitorType.Server,
578
+ MonitorType.Domain,
579
+ ])("%s prefers the up/down check", (monitorType: MonitorType) => {
580
+ expect(
581
+ CriteriaFilterUtil.getDefaultCheckOnByMonitorType(monitorType),
582
+ ).toBe(CheckOn.IsOnline);
583
+ });
584
+
585
+ test.each([
586
+ MonitorType.Kubernetes,
587
+ MonitorType.Metrics,
588
+ MonitorType.Docker,
589
+ MonitorType.Host,
590
+ MonitorType.Podman,
591
+ MonitorType.DockerSwarm,
592
+ MonitorType.Proxmox,
593
+ MonitorType.Ceph,
594
+ ])(
595
+ "%s alerts on metrics, so it prefers the metric value check",
596
+ (monitorType: MonitorType) => {
597
+ expect(
598
+ CriteriaFilterUtil.getDefaultCheckOnByMonitorType(monitorType),
599
+ ).toBe(CheckOn.MetricValue);
600
+ },
601
+ );
602
+
603
+ /*
604
+ * The protocol-specific types have no up/down check on offer. Seeding one
605
+ * anyway is what left the Filter Type dropdown blank as well as the
606
+ * condition, on the very monitor type the bug was reported against.
607
+ */
608
+ test.each([
609
+ [MonitorType.ExternalStatusPage, CheckOn.ExternalStatusPageIsOnline],
610
+ [MonitorType.Logs, CheckOn.LogCount],
611
+ [MonitorType.Traces, CheckOn.SpanCount],
612
+ [MonitorType.Exceptions, CheckOn.ExceptionCount],
613
+ [MonitorType.SecurityEvents, CheckOn.SecurityEventCount],
614
+ [MonitorType.IncomingRequest, CheckOn.IncomingRequest],
615
+ ])(
616
+ "%s falls back to a check it does offer (%s)",
617
+ (monitorType: MonitorType, expected: CheckOn) => {
618
+ expect(checkOnOptionsFor(monitorType)).not.toContain(CheckOn.IsOnline);
619
+ expect(
620
+ CriteriaFilterUtil.getDefaultCheckOnByMonitorType(monitorType),
621
+ ).toBe(expected);
622
+ },
623
+ );
624
+ });
625
+
626
+ describe("getDefaultCriteriaFilter", () => {
627
+ test.each(MONITOR_TYPES_WITH_CRITERIA)(
628
+ "%s: a newly added filter arrives with both dropdowns already chosen",
629
+ (monitorType: MonitorType) => {
630
+ const criteriaFilter: CriteriaFilter =
631
+ CriteriaFilterUtil.getDefaultCriteriaFilter(monitorType);
632
+
633
+ expect(criteriaFilter.checkOn).toBeDefined();
634
+ expect(criteriaFilter.filterType).toBeDefined();
635
+
636
+ expect(checkOnOptionsFor(monitorType)).toContain(
637
+ criteriaFilter.checkOn.toString(),
638
+ );
639
+ expect(filterTypeOptionsFor(criteriaFilter.checkOn)).toContain(
640
+ criteriaFilter.filterType!.toString(),
641
+ );
642
+ },
643
+ );
644
+
645
+ test("External Status Page monitors get a status page check, not a bare Is Online", () => {
646
+ const criteriaFilter: CriteriaFilter =
647
+ CriteriaFilterUtil.getDefaultCriteriaFilter(
648
+ MonitorType.ExternalStatusPage,
649
+ );
650
+
651
+ expect(criteriaFilter.checkOn).toBe(CheckOn.ExternalStatusPageIsOnline);
652
+ expect(criteriaFilter.filterType).toBe(FilterType.True);
653
+ });
654
+
655
+ test("Website monitors keep the up/down check they had before", () => {
656
+ const criteriaFilter: CriteriaFilter =
657
+ CriteriaFilterUtil.getDefaultCriteriaFilter(MonitorType.Website);
658
+
659
+ expect(criteriaFilter.checkOn).toBe(CheckOn.IsOnline);
660
+ // Was FilterType.EqualTo, which "Is Online" has never accepted.
661
+ expect(criteriaFilter.filterType).toBe(FilterType.True);
662
+ });
663
+
664
+ test("metric monitors keep their aggregation seeded alongside the threshold", () => {
665
+ const criteriaFilter: CriteriaFilter =
666
+ CriteriaFilterUtil.getDefaultCriteriaFilter(MonitorType.Kubernetes);
667
+
668
+ expect(criteriaFilter.checkOn).toBe(CheckOn.MetricValue);
669
+ expect(criteriaFilter.metricMonitorOptions?.metricAggregationType).toBe(
670
+ EvaluateOverTimeType.AnyValue,
671
+ );
672
+ });
673
+
674
+ test("non-metric monitors do not carry metric aggregation options", () => {
675
+ expect(
676
+ CriteriaFilterUtil.getDefaultCriteriaFilter(MonitorType.Website)
677
+ .metricMonitorOptions,
678
+ ).toBeUndefined();
679
+ });
680
+
681
+ test("returns a fresh object each call so added filters do not share state", () => {
682
+ const first: CriteriaFilter = CriteriaFilterUtil.getDefaultCriteriaFilter(
683
+ MonitorType.Website,
684
+ );
685
+ const second: CriteriaFilter =
686
+ CriteriaFilterUtil.getDefaultCriteriaFilter(MonitorType.Website);
687
+
688
+ expect(first).not.toBe(second);
689
+
690
+ first.value = "changed";
691
+ expect(second.value).toBe("");
692
+ });
693
+ });
694
+
695
+ describe("isMetricOnlyMonitorType", () => {
696
+ test.each([
697
+ MonitorType.Kubernetes,
698
+ MonitorType.Metrics,
699
+ MonitorType.Docker,
700
+ MonitorType.Host,
701
+ MonitorType.Podman,
702
+ MonitorType.DockerSwarm,
703
+ MonitorType.Proxmox,
704
+ MonitorType.Ceph,
705
+ ])("%s is metric-only", (monitorType: MonitorType) => {
706
+ expect(CriteriaFilterUtil.isMetricOnlyMonitorType(monitorType)).toBe(
707
+ true,
708
+ );
709
+ });
710
+
711
+ test.each([
712
+ MonitorType.Website,
713
+ MonitorType.API,
714
+ MonitorType.Ping,
715
+ MonitorType.Server,
716
+ MonitorType.ExternalStatusPage,
717
+ MonitorType.Logs,
718
+ MonitorType.NetworkDevice,
719
+ ])("%s is not metric-only", (monitorType: MonitorType) => {
720
+ expect(CriteriaFilterUtil.isMetricOnlyMonitorType(monitorType)).toBe(
721
+ false,
722
+ );
723
+ });
724
+ });
725
+
726
+ describe("the seed filter on a brand new criteria", () => {
727
+ test("carries a condition, not just a check", () => {
728
+ const instance: MonitorCriteriaInstance = new MonitorCriteriaInstance();
729
+ const filter: CriteriaFilter | undefined = instance.data?.filters[0];
730
+
731
+ expect(filter?.checkOn).toBe(CheckOn.IsOnline);
732
+ expect(filter?.filterType).toBe(FilterType.True);
733
+ expect(filterTypeOptionsFor(filter!.checkOn)).toContain(
734
+ filter!.filterType!.toString(),
735
+ );
736
+ });
737
+ });
738
+ });