@oneuptime/common 12.0.32 → 12.0.33

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 (597) hide show
  1. package/Models/AnalyticsModels/Span.ts +14 -0
  2. package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
  3. package/Models/DatabaseModels/Index.ts +10 -0
  4. package/Models/DatabaseModels/Monitor.ts +76 -0
  5. package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
  6. package/Models/DatabaseModels/NetworkDevice.ts +176 -1
  7. package/Models/DatabaseModels/NetworkSite.ts +201 -2
  8. package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
  9. package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
  10. package/Models/DatabaseModels/TelemetryException.ts +119 -0
  11. package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
  12. package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
  13. package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
  14. package/Server/API/EnterpriseLicenseAPI.ts +391 -64
  15. package/Server/API/LlmProviderAPI.ts +137 -22
  16. package/Server/EnvironmentConfig.ts +14 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.ts +55 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.ts +31 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.ts +124 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.ts +132 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.ts +79 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.ts +191 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  24. package/Server/Infrastructure/QueueWorker.ts +38 -8
  25. package/Server/Middleware/BearerTokenAuthorization.ts +12 -0
  26. package/Server/Middleware/ProjectAuthorization.ts +11 -0
  27. package/Server/Middleware/SCIMAuthorization.ts +12 -0
  28. package/Server/Middleware/TelemetryIngest.ts +11 -0
  29. package/Server/Services/AIBillingService.ts +101 -27
  30. package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
  31. package/Server/Services/EnterpriseLicenseService.ts +55 -0
  32. package/Server/Services/Index.ts +10 -0
  33. package/Server/Services/MonitorService.ts +143 -21
  34. package/Server/Services/MonitorStatusTimelineService.ts +150 -8
  35. package/Server/Services/MonitorTemplateService.ts +217 -1
  36. package/Server/Services/NetworkAlertPolicyEngineService.ts +2159 -0
  37. package/Server/Services/NetworkAlertPolicyService.ts +944 -0
  38. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +9 -10
  39. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +60 -15
  40. package/Server/Services/NetworkDeviceService.ts +1032 -73
  41. package/Server/Services/NetworkSiteService.ts +1502 -129
  42. package/Server/Services/NetworkSiteTypeService.ts +1216 -0
  43. package/Server/Services/NetworkSnmpCredentialProfileService.ts +238 -0
  44. package/Server/Services/NotificationService.ts +118 -28
  45. package/Server/Services/ProjectService.ts +105 -48
  46. package/Server/Services/StatusPagePrivateUserService.ts +103 -3
  47. package/Server/Services/UserNotificationEmailRollupBatchService.ts +78 -0
  48. package/Server/Services/UserNotificationEmailRollupItemService.ts +79 -0
  49. package/Server/Services/UserNotificationEmailRollupSettingService.ts +113 -0
  50. package/Server/Services/UserNotificationSettingService.ts +62 -25
  51. package/Server/Services/UserService.ts +95 -0
  52. package/Server/Types/Database/QueryHelper.ts +2 -2
  53. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +14 -3
  54. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +10 -0
  55. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +10 -0
  56. package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +62 -1
  57. package/Server/Utils/AI/Toolbox/AlertTools.ts +15 -1
  58. package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
  59. package/Server/Utils/DataSource/HttpFetch.ts +9 -2
  60. package/Server/Utils/EmailRollup/EmailRollupConstants.ts +98 -0
  61. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +872 -0
  62. package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
  63. package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
  64. package/Server/Utils/LLM/LLMService.ts +78 -0
  65. package/Server/Utils/LogRedaction.ts +8 -0
  66. package/Server/Utils/Logger.ts +79 -1
  67. package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
  68. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
  69. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
  70. package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
  71. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +49 -0
  72. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
  73. package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
  74. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +43 -0
  75. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +499 -19
  76. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +66 -10
  77. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +238 -44
  78. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +146 -39
  79. package/Server/Utils/NetworkDevice/DeviceHealthAggregation.ts +31 -18
  80. package/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.ts +213 -0
  81. package/Server/Utils/OutboundUserAgent.ts +152 -0
  82. package/Server/Utils/StartServer.ts +51 -19
  83. package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
  84. package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
  85. package/Server/Utils/Telemetry/SpanUtil.ts +33 -0
  86. package/Server/Utils/Telemetry.ts +198 -51
  87. package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
  88. package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +134 -33
  89. package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
  90. package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
  91. package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
  92. package/Tests/App/Dashboard/DeviceStatusHero.test.tsx +588 -0
  93. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +18 -9
  94. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +632 -0
  95. package/Tests/App/Dashboard/MonitorRecommendationCreateProgress.test.tsx +682 -0
  96. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
  97. package/Tests/App/Dashboard/NetworkDeviceCreateFormMonitorBinding.test.tsx +676 -0
  98. package/Tests/App/Dashboard/NetworkDeviceCreateFormPingMonitor.test.tsx +791 -0
  99. package/Tests/App/Dashboard/NetworkDeviceCreateFormProbeAndSnmp.test.tsx +833 -0
  100. package/Tests/App/Dashboard/NetworkDeviceCriteriaFilter.test.ts +161 -0
  101. package/Tests/App/Dashboard/NetworkDeviceSettingsMonitoringSection.test.tsx +458 -0
  102. package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +41 -5
  103. package/Tests/App/Dashboard/PingMonitorProvisioning.test.ts +368 -0
  104. package/Tests/App/Dashboard/RecommendationCard.test.tsx +796 -0
  105. package/Tests/App/Dashboard/RecommendationToolbar.test.tsx +519 -0
  106. package/Tests/App/Dashboard/RecommendationsList.test.tsx +661 -0
  107. package/Tests/App/Dashboard/UseBulkCreatePingMonitors.test.tsx +899 -0
  108. package/Tests/App/Dashboard/UseBulkSnmpCredentialProfileActions.test.tsx +732 -0
  109. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +256 -0
  110. package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +11 -1
  111. package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
  112. package/Tests/Models/NetworkSiteHierarchy.test.ts +41 -4
  113. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
  114. package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -0
  115. package/Tests/Server/Infrastructure/Postgres/NetworkSnmpCredentialProfilesAndAlertPoliciesMigration.test.ts +854 -0
  116. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +18 -0
  117. package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -0
  118. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +560 -0
  119. package/Tests/Server/Services/BillingRechargeOwnerEmailGuards.test.ts +783 -0
  120. package/Tests/Server/Services/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
  121. package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
  122. package/Tests/Server/Services/MonitorServiceDeleteNetworkDeviceCleanup.test.ts +294 -0
  123. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +802 -0
  124. package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +72 -2
  125. package/Tests/Server/Services/NetworkAlertPolicyEngineHooks.test.ts +752 -0
  126. package/Tests/Server/Services/NetworkAlertPolicyEngineService.test.ts +1849 -0
  127. package/Tests/Server/Services/NetworkAlertPolicyModel.test.ts +1793 -0
  128. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +47 -4
  129. package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +97 -12
  130. package/Tests/Server/Services/NetworkDeviceAutoMonitorLifecycle.test.ts +148 -3
  131. package/Tests/Server/Services/NetworkDeviceMonitorBindingUpdateGuard.test.ts +514 -0
  132. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +447 -58
  133. package/Tests/Server/Services/NetworkDeviceMonitoringMethodTransition.test.ts +739 -0
  134. package/Tests/Server/Services/NetworkDevicePollingTenancy.test.ts +501 -0
  135. package/Tests/Server/Services/NetworkDeviceSiteDefaultProbe.test.ts +432 -0
  136. package/Tests/Server/Services/NetworkSiteMonitoringDefaults.test.ts +498 -0
  137. package/Tests/Server/Services/NetworkSiteRollupPolicyAndMaintenance.test.ts +337 -55
  138. package/Tests/Server/Services/NetworkSiteService.test.ts +1868 -131
  139. package/Tests/Server/Services/NetworkSiteTypeService.test.ts +1109 -0
  140. package/Tests/Server/Services/NetworkSnmpCredentialProfileModel.test.ts +926 -0
  141. package/Tests/Server/Services/NetworkSnmpCredentialProfileService.test.ts +796 -0
  142. package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
  143. package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -0
  144. package/Tests/Server/Services/UserEmailChangePasswordResetExpiry.test.ts +472 -0
  145. package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +569 -0
  146. package/Tests/Server/Services/UserNotificationEmailRollupSettingModel.test.ts +314 -0
  147. package/Tests/Server/Services/UserNotificationEmailRollupSettingService.test.ts +409 -0
  148. package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +856 -0
  149. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +102 -1
  150. package/Tests/Server/Types/Database/Permissions/DashboardAccessPermission.test.ts +321 -0
  151. package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +17 -0
  152. package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +124 -0
  153. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +208 -0
  154. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +235 -0
  155. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +253 -0
  156. package/Tests/Server/Utils/Captcha.test.ts +422 -0
  157. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +96 -2
  158. package/Tests/Server/Utils/Database/MigrationFailureLog.test.ts +466 -0
  159. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1096 -0
  160. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerClaim.test.ts +466 -0
  161. package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
  162. package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +752 -0
  163. package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
  164. package/Tests/Server/Utils/LoggerFaultDemotion.test.ts +346 -0
  165. package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
  166. package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +196 -0
  167. package/Tests/Server/Utils/Monitor/DatabaseMetricWrite.test.ts +367 -0
  168. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +100 -0
  169. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +5 -0
  170. package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +512 -31
  171. package/Tests/Server/Utils/Monitor/NetworkDeviceMetricUtil.test.ts +252 -0
  172. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +479 -42
  173. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +351 -5
  174. package/Tests/Server/Utils/NetworkDevice/DeviceHealthAggregation.test.ts +136 -12
  175. package/Tests/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.test.ts +306 -0
  176. package/Tests/Server/Utils/OutboundUserAgent.test.ts +266 -0
  177. package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -0
  178. package/Tests/Server/Utils/Telemetry/ErrorClassResolver.test.ts +298 -0
  179. package/Tests/Server/Utils/Telemetry.test.ts +456 -66
  180. package/Tests/Types/Monitor/DatabaseMetricCatalog.test.ts +388 -0
  181. package/Tests/Types/Monitor/MonitorStepDatabaseMonitor.test.ts +243 -0
  182. package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
  183. package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
  184. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +16 -7
  185. package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +60 -0
  186. package/Tests/Types/NetworkDevice/NetworkAlertPolicyScope.test.ts +655 -0
  187. package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +115 -26
  188. package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +39 -0
  189. package/Tests/Types/NotificationSetting/NotificationEmailRollupPolicy.test.ts +299 -0
  190. package/Tests/Types/Telemetry/ErrorClass.test.ts +483 -0
  191. package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
  192. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +15 -0
  193. package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
  194. package/Tests/UI/Components/SideMenuItem.test.tsx +226 -4
  195. package/Tests/UI/Components/SideMenuSection.test.tsx +310 -0
  196. package/Tests/UI/Components/SideOverSubmitState.test.tsx +335 -0
  197. package/Tests/UI/Utils/PageScrollLock.test.tsx +377 -0
  198. package/Tests/UI/Utils/PermissionGate.test.ts +78 -0
  199. package/Tests/UI/Utils/SensitiveUrlToken.test.ts +140 -0
  200. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +69 -0
  201. package/Tests/Utils/EnterpriseLicenseSync.test.ts +7 -1
  202. package/Tests/Utils/EnterpriseLicenseUsage.test.ts +433 -2
  203. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +280 -1
  204. package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
  205. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +38 -0
  206. package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +284 -23
  207. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +177 -0
  208. package/Tests/Utils/NetworkDevice/MonitoringMethodThreadedClassifiers.test.ts +992 -0
  209. package/Tests/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.test.ts +427 -0
  210. package/Tests/Utils/NetworkDevice/ReachabilityStampConsistency.test.ts +185 -0
  211. package/Tests/Utils/NetworkDevice/SnmpCredentialUtil.test.ts +268 -0
  212. package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +55 -5
  213. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +98 -21
  214. package/Tests/Utils/NetworkDiscovery/DiscoveryImportEligibility.test.ts +98 -20
  215. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +8 -7
  216. package/Tests/Utils/NetworkDiscovery/PingMonitorBuilderForAddress.test.ts +274 -0
  217. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +230 -51
  218. package/Tests/Utils/NetworkSite/TypeHierarchyUtil.test.ts +209 -0
  219. package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
  220. package/Types/AI/ExceptionAIClassification.ts +10 -24
  221. package/Types/Email/EmailTemplateType.ts +2 -0
  222. package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +5 -0
  223. package/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.ts +13 -0
  224. package/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.ts +6 -0
  225. package/Types/Exception/ApiException.ts +10 -0
  226. package/Types/Exception/BadDataException.ts +11 -0
  227. package/Types/Exception/BadRequestException.ts +11 -0
  228. package/Types/Exception/Exception.ts +65 -0
  229. package/Types/Exception/ForbiddenException.ts +10 -0
  230. package/Types/Exception/NotAuthenticatedException.ts +10 -0
  231. package/Types/Exception/NotAuthorizedException.ts +10 -0
  232. package/Types/Exception/NotFoundException.ts +11 -0
  233. package/Types/Exception/PayloadTooLargeException.ts +11 -0
  234. package/Types/Exception/PaymentRequiredException.ts +10 -0
  235. package/Types/Exception/ServiceUnavailableException.ts +10 -0
  236. package/Types/Exception/SsoAuthorizationException.ts +10 -0
  237. package/Types/Exception/TenantNotFoundException.ts +11 -0
  238. package/Types/Exception/TimeoutException.ts +10 -0
  239. package/Types/Exception/TooManyRequestsException.ts +10 -0
  240. package/Types/Exception/UnableToReachServer.ts +10 -0
  241. package/Types/Exception/WebsiteRequestException.ts +10 -0
  242. package/Types/Monitor/CriteriaFilter.ts +60 -2
  243. package/Types/Monitor/DatabaseMetricCatalog.ts +693 -0
  244. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +83 -0
  245. package/Types/Monitor/MonitorCriteriaInstance.ts +76 -0
  246. package/Types/Monitor/MonitorMetricType.ts +71 -0
  247. package/Types/Monitor/MonitorStep.ts +76 -0
  248. package/Types/Monitor/MonitorStepDatabaseMonitor.ts +171 -0
  249. package/Types/Monitor/MonitorStepSqlMonitor.ts +2 -20
  250. package/Types/Monitor/MonitorType.ts +47 -1
  251. package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
  252. package/Types/Monitor/SqlConnectionConfig.ts +31 -0
  253. package/Types/NetworkDevice/NetworkAlertPolicyScope.ts +343 -0
  254. package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +42 -22
  255. package/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.ts +30 -0
  256. package/Types/NotificationSetting/NotificationEmailRollupCategory.ts +255 -0
  257. package/Types/NotificationSetting/NotificationEmailRollupPolicy.ts +104 -0
  258. package/Types/Permission.ts +90 -0
  259. package/Types/Probe/ProbeMonitorResponse.ts +16 -0
  260. package/Types/Telemetry/ErrorClass.ts +274 -0
  261. package/Types/Telemetry/UnitOfWork.ts +59 -0
  262. package/UI/Components/CommandPalette/CommandPalette.tsx +2 -8
  263. package/UI/Components/EditionLabel/EditionLabel.tsx +4 -0
  264. package/UI/Components/Modal/Modal.tsx +2 -8
  265. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
  266. package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
  267. package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
  268. package/UI/Components/SideMenu/SideMenu.tsx +123 -5
  269. package/UI/Components/SideMenu/SideMenuItem.tsx +76 -84
  270. package/UI/Components/SideMenu/SideMenuSection.tsx +55 -23
  271. package/UI/Components/SideOver/SideOver.tsx +21 -20
  272. package/UI/Utils/PageScrollLock.ts +79 -3
  273. package/UI/Utils/PermissionGate.ts +61 -0
  274. package/UI/Utils/SensitiveUrlToken.ts +112 -0
  275. package/UI/Utils/TestLLMProvider.ts +11 -0
  276. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
  277. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
  278. package/Utils/Monitor/MonitorMetricType.ts +153 -1
  279. package/Utils/Monitor/NetworkTopologyUtil.ts +23 -3
  280. package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
  281. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
  282. package/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.ts +247 -0
  283. package/Utils/NetworkDevice/SnmpCredentialUtil.ts +68 -0
  284. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +15 -7
  285. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +52 -17
  286. package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +55 -23
  287. package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
  288. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
  289. package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -0
  290. package/build/dist/Models/AnalyticsModels/Span.js +14 -0
  291. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  292. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +59 -0
  293. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  294. package/build/dist/Models/DatabaseModels/Index.js +10 -0
  295. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  296. package/build/dist/Models/DatabaseModels/Monitor.js +75 -0
  297. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  298. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js +713 -0
  299. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js.map +1 -0
  300. package/build/dist/Models/DatabaseModels/NetworkDevice.js +180 -1
  301. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  302. package/build/dist/Models/DatabaseModels/NetworkSite.js +200 -2
  303. package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
  304. package/build/dist/Models/DatabaseModels/NetworkSiteType.js +102 -3
  305. package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -1
  306. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js +878 -0
  307. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js.map +1 -0
  308. package/build/dist/Models/DatabaseModels/TelemetryException.js +123 -0
  309. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  310. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js +363 -0
  311. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js.map +1 -0
  312. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +402 -0
  313. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -0
  314. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js +296 -0
  315. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js.map +1 -0
  316. package/build/dist/Server/API/EnterpriseLicenseAPI.js +273 -60
  317. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  318. package/build/dist/Server/API/LlmProviderAPI.js +108 -13
  319. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  320. package/build/dist/Server/EnvironmentConfig.js +12 -0
  321. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  322. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js +24 -0
  323. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js.map +1 -0
  324. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js +16 -0
  325. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js.map +1 -0
  326. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js +111 -0
  327. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js.map +1 -0
  328. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js +77 -0
  329. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js.map +1 -0
  330. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js +50 -0
  331. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js.map +1 -0
  332. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js +83 -0
  333. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js.map +1 -0
  334. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  335. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  336. package/build/dist/Server/Infrastructure/QueueWorker.js +33 -5
  337. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  338. package/build/dist/Server/Middleware/BearerTokenAuthorization.js +12 -0
  339. package/build/dist/Server/Middleware/BearerTokenAuthorization.js.map +1 -1
  340. package/build/dist/Server/Middleware/ProjectAuthorization.js +11 -0
  341. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  342. package/build/dist/Server/Middleware/SCIMAuthorization.js +12 -0
  343. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +1 -1
  344. package/build/dist/Server/Middleware/TelemetryIngest.js +11 -0
  345. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  346. package/build/dist/Server/Services/AIBillingService.js +70 -16
  347. package/build/dist/Server/Services/AIBillingService.js.map +1 -1
  348. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js +167 -0
  349. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js.map +1 -1
  350. package/build/dist/Server/Services/EnterpriseLicenseService.js +39 -0
  351. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  352. package/build/dist/Server/Services/Index.js +10 -0
  353. package/build/dist/Server/Services/Index.js.map +1 -1
  354. package/build/dist/Server/Services/MonitorService.js +119 -21
  355. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  356. package/build/dist/Server/Services/MonitorStatusTimelineService.js +127 -8
  357. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  358. package/build/dist/Server/Services/MonitorTemplateService.js +162 -0
  359. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  360. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js +1683 -0
  361. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js.map +1 -0
  362. package/build/dist/Server/Services/NetworkAlertPolicyService.js +732 -0
  363. package/build/dist/Server/Services/NetworkAlertPolicyService.js.map +1 -0
  364. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +10 -9
  365. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  366. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +54 -11
  367. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  368. package/build/dist/Server/Services/NetworkDeviceService.js +841 -70
  369. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  370. package/build/dist/Server/Services/NetworkSiteService.js +1145 -107
  371. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  372. package/build/dist/Server/Services/NetworkSiteTypeService.js +863 -0
  373. package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -1
  374. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js +217 -0
  375. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js.map +1 -0
  376. package/build/dist/Server/Services/NotificationService.js +80 -17
  377. package/build/dist/Server/Services/NotificationService.js.map +1 -1
  378. package/build/dist/Server/Services/ProjectService.js +66 -30
  379. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  380. package/build/dist/Server/Services/StatusPagePrivateUserService.js +92 -2
  381. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  382. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js +76 -0
  383. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js.map +1 -0
  384. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js +77 -0
  385. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js.map +1 -0
  386. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js +111 -0
  387. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js.map +1 -0
  388. package/build/dist/Server/Services/UserNotificationSettingService.js +46 -20
  389. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  390. package/build/dist/Server/Services/UserService.js +90 -0
  391. package/build/dist/Server/Services/UserService.js.map +1 -1
  392. package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
  393. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  394. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +14 -3
  395. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
  396. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +10 -0
  397. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  398. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +10 -0
  399. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  400. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +54 -1
  401. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
  402. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +18 -4
  403. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
  404. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js +59 -0
  405. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js.map +1 -0
  406. package/build/dist/Server/Utils/DataSource/HttpFetch.js +2 -1
  407. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
  408. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +91 -0
  409. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
  410. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +691 -0
  411. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -0
  412. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +497 -0
  413. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -0
  414. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +257 -0
  415. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -0
  416. package/build/dist/Server/Utils/LLM/LLMService.js +64 -1
  417. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  418. package/build/dist/Server/Utils/LogRedaction.js +8 -0
  419. package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
  420. package/build/dist/Server/Utils/Logger.js +63 -1
  421. package/build/dist/Server/Utils/Logger.js.map +1 -1
  422. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js +141 -0
  423. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js.map +1 -0
  424. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  425. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  426. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +51 -1
  427. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  428. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
  429. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
  430. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +37 -0
  431. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  432. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +158 -6
  433. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  434. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  435. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  436. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +32 -0
  437. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  438. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +330 -21
  439. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  440. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +55 -10
  441. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  442. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +178 -49
  443. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  444. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +119 -29
  445. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  446. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js +30 -17
  447. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js.map +1 -1
  448. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js +158 -0
  449. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js.map +1 -0
  450. package/build/dist/Server/Utils/OutboundUserAgent.js +123 -0
  451. package/build/dist/Server/Utils/OutboundUserAgent.js.map +1 -0
  452. package/build/dist/Server/Utils/StartServer.js +38 -14
  453. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  454. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +28 -8
  455. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
  456. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js +95 -0
  457. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js.map +1 -0
  458. package/build/dist/Server/Utils/Telemetry/SpanUtil.js +29 -0
  459. package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
  460. package/build/dist/Server/Utils/Telemetry.js +162 -46
  461. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  462. package/build/dist/Types/AI/ExceptionAIClassification.js +10 -24
  463. package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -1
  464. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  465. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  466. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js +2 -0
  467. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js.map +1 -0
  468. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js +7 -0
  469. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js.map +1 -0
  470. package/build/dist/Types/Exception/ApiException.js +9 -0
  471. package/build/dist/Types/Exception/ApiException.js.map +1 -1
  472. package/build/dist/Types/Exception/BadDataException.js +10 -0
  473. package/build/dist/Types/Exception/BadDataException.js.map +1 -1
  474. package/build/dist/Types/Exception/BadRequestException.js +10 -0
  475. package/build/dist/Types/Exception/BadRequestException.js.map +1 -1
  476. package/build/dist/Types/Exception/Exception.js +56 -0
  477. package/build/dist/Types/Exception/Exception.js.map +1 -1
  478. package/build/dist/Types/Exception/ForbiddenException.js +9 -0
  479. package/build/dist/Types/Exception/ForbiddenException.js.map +1 -1
  480. package/build/dist/Types/Exception/NotAuthenticatedException.js +9 -0
  481. package/build/dist/Types/Exception/NotAuthenticatedException.js.map +1 -1
  482. package/build/dist/Types/Exception/NotAuthorizedException.js +9 -0
  483. package/build/dist/Types/Exception/NotAuthorizedException.js.map +1 -1
  484. package/build/dist/Types/Exception/NotFoundException.js +10 -0
  485. package/build/dist/Types/Exception/NotFoundException.js.map +1 -1
  486. package/build/dist/Types/Exception/PayloadTooLargeException.js +10 -0
  487. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -1
  488. package/build/dist/Types/Exception/PaymentRequiredException.js +9 -0
  489. package/build/dist/Types/Exception/PaymentRequiredException.js.map +1 -1
  490. package/build/dist/Types/Exception/ServiceUnavailableException.js +9 -0
  491. package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -1
  492. package/build/dist/Types/Exception/SsoAuthorizationException.js +9 -0
  493. package/build/dist/Types/Exception/SsoAuthorizationException.js.map +1 -1
  494. package/build/dist/Types/Exception/TenantNotFoundException.js +10 -0
  495. package/build/dist/Types/Exception/TenantNotFoundException.js.map +1 -1
  496. package/build/dist/Types/Exception/TimeoutException.js +9 -0
  497. package/build/dist/Types/Exception/TimeoutException.js.map +1 -1
  498. package/build/dist/Types/Exception/TooManyRequestsException.js +9 -0
  499. package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -1
  500. package/build/dist/Types/Exception/UnableToReachServer.js +9 -0
  501. package/build/dist/Types/Exception/UnableToReachServer.js.map +1 -1
  502. package/build/dist/Types/Exception/WebsiteRequestException.js +9 -0
  503. package/build/dist/Types/Exception/WebsiteRequestException.js.map +1 -1
  504. package/build/dist/Types/Monitor/CriteriaFilter.js +45 -2
  505. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  506. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js +594 -0
  507. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js.map +1 -0
  508. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js +21 -0
  509. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js.map +1 -0
  510. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +70 -0
  511. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  512. package/build/dist/Types/Monitor/MonitorMetricType.js +61 -0
  513. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  514. package/build/dist/Types/Monitor/MonitorStep.js +54 -0
  515. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  516. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js +122 -0
  517. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js.map +1 -0
  518. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
  519. package/build/dist/Types/Monitor/MonitorType.js +45 -1
  520. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  521. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +21 -1
  522. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
  523. package/build/dist/Types/Monitor/SqlConnectionConfig.js +2 -0
  524. package/build/dist/Types/Monitor/SqlConnectionConfig.js.map +1 -0
  525. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js +172 -0
  526. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js.map +1 -0
  527. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +40 -22
  528. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -1
  529. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js +26 -0
  530. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js.map +1 -0
  531. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js +186 -0
  532. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js.map +1 -0
  533. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js +87 -0
  534. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js.map +1 -0
  535. package/build/dist/Types/Permission.js +80 -0
  536. package/build/dist/Types/Permission.js.map +1 -1
  537. package/build/dist/Types/Telemetry/ErrorClass.js +216 -0
  538. package/build/dist/Types/Telemetry/ErrorClass.js.map +1 -0
  539. package/build/dist/Types/Telemetry/UnitOfWork.js +59 -0
  540. package/build/dist/Types/Telemetry/UnitOfWork.js.map +1 -0
  541. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +2 -7
  542. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  543. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +3 -0
  544. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  545. package/build/dist/UI/Components/Modal/Modal.js +2 -7
  546. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  547. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +39 -0
  548. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  549. package/build/dist/UI/Components/ProgressBar/ProgressBar.js +12 -1
  550. package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
  551. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +6 -6
  552. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
  553. package/build/dist/UI/Components/SideMenu/SideMenu.js +67 -5
  554. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  555. package/build/dist/UI/Components/SideMenu/SideMenuItem.js +49 -53
  556. package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
  557. package/build/dist/UI/Components/SideMenu/SideMenuSection.js +25 -7
  558. package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
  559. package/build/dist/UI/Components/SideOver/SideOver.js +5 -20
  560. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  561. package/build/dist/UI/Utils/PageScrollLock.js +31 -3
  562. package/build/dist/UI/Utils/PageScrollLock.js.map +1 -1
  563. package/build/dist/UI/Utils/PermissionGate.js +42 -1
  564. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  565. package/build/dist/UI/Utils/SensitiveUrlToken.js +97 -0
  566. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -0
  567. package/build/dist/UI/Utils/TestLLMProvider.js +4 -5
  568. package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -1
  569. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +15 -0
  570. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -1
  571. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +111 -9
  572. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  573. package/build/dist/Utils/Monitor/MonitorMetricType.js +109 -1
  574. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  575. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +8 -3
  576. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  577. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +27 -7
  578. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -1
  579. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +7 -5
  580. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  581. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js +180 -0
  582. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js.map +1 -0
  583. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js +12 -0
  584. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js.map +1 -0
  585. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +15 -5
  586. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  587. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +44 -15
  588. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  589. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +52 -23
  590. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -1
  591. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js +85 -13
  592. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js.map +1 -1
  593. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +30 -15
  594. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
  595. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js +191 -0
  596. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js.map +1 -0
  597. package/package.json +2 -2
@@ -0,0 +1,833 @@
1
+ import "@testing-library/jest-dom";
2
+ import { cleanup, render, waitFor } from "@testing-library/react";
3
+ import React, { ReactElement } from "react";
4
+ import { MemoryRouter } from "react-router-dom";
5
+ import {
6
+ afterEach,
7
+ beforeEach,
8
+ describe,
9
+ expect,
10
+ jest,
11
+ test,
12
+ } from "@jest/globals";
13
+ import NetworkSite from "../../../Models/DatabaseModels/NetworkSite";
14
+ import NetworkSnmpCredentialProfile from "../../../Models/DatabaseModels/NetworkSnmpCredentialProfile";
15
+ import ObjectID from "../../../Types/ObjectID";
16
+ import FormFieldSchemaType from "../../../UI/Components/Forms/Types/FormFieldSchemaType";
17
+
18
+ /*
19
+ * WHY THIS FILE EXISTS
20
+ *
21
+ * Registering a device asks what the device IS, and the two answers it cannot
22
+ * work without are the address and the PROBE that can reach it. A device with
23
+ * no probe is not polled by anything: it is created, it sits on Pending
24
+ * wearing "No probe", and nobody finds out until somebody wonders why a
25
+ * switch has no interfaces. So the probe is required here — and because
26
+ * requiring a field an operator cannot answer is just a wall, the form
27
+ * answers it for them wherever it honestly can:
28
+ *
29
+ * 1. the selected site's own default probe (the site exists to hold it),
30
+ * 2. otherwise the project's single non-global probe, when there is exactly
31
+ * one — a question with one possible answer is not a question,
32
+ * 3. otherwise empty, and the operator picks.
33
+ *
34
+ * Every property that makes step 1 SAFE is invisible on screen: it is one
35
+ * request per site id and not one per keystroke, it is remembered so that
36
+ * re-opening the form or flipping between two sites costs nothing, a site
37
+ * with no probe is remembered as such, and it never overwrites a probe the
38
+ * operator picked themselves.
39
+ *
40
+ * The SNMP step is the other half. It stays, it is optional, and it now
41
+ * offers the credential PROFILE beside the device's own credentials — the
42
+ * same either/or the Settings page offers, in the same words, because a
43
+ * device created here and a device edited there have to end up describing
44
+ * their credentials the same way.
45
+ *
46
+ * ModelTable is replaced by a prop recorder — the point is what the page
47
+ * hands it, not re-testing the table (the same approach as
48
+ * NetworkDeviceBulkDelete.test.tsx).
49
+ */
50
+
51
+ jest.mock("react-i18next", () => {
52
+ return {
53
+ useTranslation: () => {
54
+ return {
55
+ t: (key: string): string => {
56
+ return key;
57
+ },
58
+ };
59
+ },
60
+ };
61
+ });
62
+
63
+ jest.mock("../../../UI/Utils/Permission", () => {
64
+ return {
65
+ __esModule: true,
66
+ default: {
67
+ getAllPermissions: () => {
68
+ return [];
69
+ },
70
+ getProjectPermissions: () => {
71
+ return [];
72
+ },
73
+ getGlobalPermissions: () => {
74
+ return [];
75
+ },
76
+ },
77
+ };
78
+ });
79
+
80
+ jest.mock("../../../UI/Utils/User", () => {
81
+ return {
82
+ __esModule: true,
83
+ default: {
84
+ isMasterAdmin: () => {
85
+ return false;
86
+ },
87
+ getUserId: () => {
88
+ return null;
89
+ },
90
+ },
91
+ };
92
+ });
93
+
94
+ const SITE_ID: string = "77777777-0000-4000-8000-000000000001";
95
+ const OTHER_SITE_ID: string = "77777777-0000-4000-8000-000000000002";
96
+ const SITE_PROBE_ID: string = "88888888-0000-4000-8000-000000000001";
97
+ const OTHER_PROBE_ID: string = "88888888-0000-4000-8000-000000000002";
98
+
99
+ /*
100
+ * The probe list the page fetches on mount, and the site rows the create form
101
+ * looks up. Both are `let`s with the `mock` prefix so the hoisted factories
102
+ * below may close over them and each test can set what this project owns.
103
+ */
104
+ type ProbeRow = {
105
+ _id: string;
106
+ name: string;
107
+ isGlobalProbe?: boolean | undefined;
108
+ };
109
+
110
+ let mockProbeList: Array<ProbeRow> = [];
111
+
112
+ type GetItemRequest = {
113
+ modelType: unknown;
114
+ id: ObjectID;
115
+ select: Record<string, unknown>;
116
+ };
117
+
118
+ const mockGetItemCalls: Array<GetItemRequest> = [];
119
+
120
+ let mockGetItem: (
121
+ request: GetItemRequest,
122
+ ) => Promise<unknown> = (): Promise<unknown> => {
123
+ return Promise.resolve(null);
124
+ };
125
+
126
+ jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
127
+ return {
128
+ __esModule: true,
129
+ default: {
130
+ getItem: (request: GetItemRequest): Promise<unknown> => {
131
+ mockGetItemCalls.push(request);
132
+ return mockGetItem(request);
133
+ },
134
+ getList: () => {
135
+ return Promise.resolve({ data: [], count: 0 });
136
+ },
137
+ // The unbound-devices banner counts on mount; not what this file is about.
138
+ count: () => {
139
+ return Promise.resolve(0);
140
+ },
141
+ },
142
+ };
143
+ });
144
+
145
+ jest.mock("../../../../App/FeatureSet/Dashboard/src/Utils/Probe", () => {
146
+ return {
147
+ __esModule: true,
148
+ default: {
149
+ getAllProbes: async () => {
150
+ return mockProbeList;
151
+ },
152
+ },
153
+ };
154
+ });
155
+
156
+ /*
157
+ * The facet bar fetches sites, labels and probes on mount and owns the query
158
+ * the table is given. None of that is what these tests are about.
159
+ */
160
+ jest.mock(
161
+ "../../../../App/FeatureSet/Dashboard/src/Components/ResourceOwners/useResourceOwners",
162
+ () => {
163
+ const actual: Record<string, unknown> = jest.requireActual(
164
+ "../../../../App/FeatureSet/Dashboard/src/Components/ResourceOwners/useResourceOwners",
165
+ ) as Record<string, unknown>;
166
+
167
+ return {
168
+ ...actual,
169
+ __esModule: true,
170
+ default: () => {
171
+ return {
172
+ filterBar: null,
173
+ mergeFiltersIntoQuery: (
174
+ base: Record<string, unknown> | undefined,
175
+ ) => {
176
+ return base || {};
177
+ },
178
+ hasActiveFilters: false,
179
+ facetSelections: {},
180
+ facetOperators: {},
181
+ setFacetSelection: () => {
182
+ // no-op
183
+ },
184
+ clearAllFacets: () => {
185
+ // no-op
186
+ },
187
+ facetSaveState: {},
188
+ restoreFacetState: () => {
189
+ // no-op
190
+ },
191
+ getOwnersForResource: () => {
192
+ return [];
193
+ },
194
+ isLoadingOwners: false,
195
+ onResourcesFetched: () => {
196
+ // no-op
197
+ },
198
+ };
199
+ },
200
+ };
201
+ },
202
+ );
203
+
204
+ jest.mock("../../../UI/Components/BulkUpdate/BulkLabelActions", () => {
205
+ return {
206
+ __esModule: true,
207
+ default: () => {
208
+ return { bulkActions: [], modals: null };
209
+ },
210
+ };
211
+ });
212
+
213
+ jest.mock(
214
+ "../../../../App/FeatureSet/Dashboard/src/Components/NetworkDevice/useBulkOidTemplateActions",
215
+ () => {
216
+ return {
217
+ __esModule: true,
218
+ default: () => {
219
+ return { bulkActions: [], modals: null };
220
+ },
221
+ };
222
+ },
223
+ );
224
+
225
+ /*
226
+ * Stubbed to a recognisable button, so "the page mounts the hook" and "the
227
+ * page puts its actions on the table" are one assertion rather than a source
228
+ * grep that a rename would walk straight past.
229
+ */
230
+ jest.mock(
231
+ "../../../../App/FeatureSet/Dashboard/src/Components/NetworkDevice/useBulkSnmpCredentialProfileActions",
232
+ () => {
233
+ return {
234
+ __esModule: true,
235
+ default: () => {
236
+ return {
237
+ bulkActions: [{ title: "Set SNMP Credential Profile" }],
238
+ modals: null,
239
+ };
240
+ },
241
+ };
242
+ },
243
+ );
244
+
245
+ jest.mock(
246
+ "../../../../App/FeatureSet/Dashboard/src/Components/NetworkDevice/DeviceSummaryCards",
247
+ () => {
248
+ return {
249
+ __esModule: true,
250
+ default: () => {
251
+ return null;
252
+ },
253
+ };
254
+ },
255
+ );
256
+
257
+ type FormValuesLike = Record<string, unknown>;
258
+
259
+ type SetFormValuesFunction = (values: FormValuesLike) => void;
260
+
261
+ type CapturedFormField = {
262
+ field?: Record<string, unknown> | undefined;
263
+ overrideFieldKey?: string | undefined;
264
+ title?: string | undefined;
265
+ stepId?: string | undefined;
266
+ description?: string | undefined;
267
+ sectionTitle?: string | undefined;
268
+ sectionDescription?: string | undefined;
269
+ placeholder?: string | undefined;
270
+ fieldType?: FormFieldSchemaType | undefined;
271
+ defaultValue?: unknown;
272
+ dropdownModal?: { type: unknown } | undefined;
273
+ sideLink?: { text: string; url: unknown } | undefined;
274
+ required?: boolean | ((values: FormValuesLike) => boolean) | undefined;
275
+ showIf?: ((values: FormValuesLike) => boolean) | undefined;
276
+ onChange?:
277
+ | ((
278
+ value: unknown,
279
+ currentFormValues: FormValuesLike,
280
+ setNewFormValues: SetFormValuesFunction,
281
+ ) => void)
282
+ | undefined;
283
+ };
284
+
285
+ type CapturedFormStep = {
286
+ id: string;
287
+ title: string;
288
+ showIf?: ((values: FormValuesLike) => boolean) | undefined;
289
+ };
290
+
291
+ type CapturedTableProps = {
292
+ formFields?: Array<CapturedFormField> | undefined;
293
+ formSteps?: Array<CapturedFormStep> | undefined;
294
+ bulkActions?:
295
+ | { buttons?: Array<{ title?: string | undefined }> | undefined }
296
+ | undefined;
297
+ };
298
+
299
+ let capturedTableProps: CapturedTableProps | null = null;
300
+
301
+ jest.mock("../../../UI/Components/ModelTable/ModelTable", () => {
302
+ return {
303
+ __esModule: true,
304
+ default: (props: CapturedTableProps) => {
305
+ capturedTableProps = props;
306
+ return null;
307
+ },
308
+ };
309
+ });
310
+
311
+ import NetworkDevicesPage from "../../../../App/FeatureSet/Dashboard/src/Pages/NetworkDevice/Devices";
312
+ import PageComponentProps from "../../../../App/FeatureSet/Dashboard/src/Pages/PageComponentProps";
313
+ import {
314
+ PROBE_FIELD_DESCRIPTION,
315
+ SNMP_STEP_DESCRIPTION,
316
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/NetworkDevice/MonitoringMethodFormFields";
317
+ import Route from "../../../Types/API/Route";
318
+
319
+ const PAGE_PROPS: PageComponentProps = {
320
+ pageRoute: new Route("/dashboard/network-devices"),
321
+ currentProject: null,
322
+ hasPaymentMethod: true,
323
+ };
324
+
325
+ async function renderDevicesPage(): Promise<CapturedTableProps> {
326
+ const Page: (props: PageComponentProps) => ReactElement =
327
+ NetworkDevicesPage as unknown as (
328
+ props: PageComponentProps,
329
+ ) => ReactElement;
330
+
331
+ render(
332
+ <MemoryRouter>
333
+ <Page {...PAGE_PROPS} />
334
+ </MemoryRouter>,
335
+ );
336
+
337
+ await waitFor(() => {
338
+ expect(capturedTableProps).not.toBeNull();
339
+ });
340
+
341
+ return capturedTableProps!;
342
+ }
343
+
344
+ function fieldFor(props: CapturedTableProps, key: string): CapturedFormField {
345
+ const match: CapturedFormField | undefined = (props.formFields || []).find(
346
+ (field: CapturedFormField): boolean => {
347
+ return Object.keys(field.field || {})[0] === key;
348
+ },
349
+ );
350
+
351
+ expect({ key: key, found: Boolean(match) }).toEqual({
352
+ key: key,
353
+ found: true,
354
+ });
355
+
356
+ return match!;
357
+ }
358
+
359
+ /** `required` the way FormField.tsx reads it: a boolean, or a callback. */
360
+ function isRequired(field: CapturedFormField, values: FormValuesLike): boolean {
361
+ if (typeof field.required === "function") {
362
+ return field.required(values);
363
+ }
364
+
365
+ return field.required === true;
366
+ }
367
+
368
+ function siteRow(probeId: string | undefined): NetworkSite {
369
+ const site: NetworkSite = new NetworkSite();
370
+
371
+ if (probeId) {
372
+ site.probeId = new ObjectID(probeId);
373
+ }
374
+
375
+ return site;
376
+ }
377
+
378
+ /**
379
+ * Pick a site the way the entity dropdown does — value first, then the form's
380
+ * own setFieldValue — and hand back whatever the field wrote afterwards.
381
+ */
382
+ async function selectSite(data: {
383
+ props: CapturedTableProps;
384
+ siteId: string;
385
+ currentFormValues?: FormValuesLike | undefined;
386
+ expectWrite?: boolean | undefined;
387
+ }): Promise<Array<FormValuesLike>> {
388
+ const site: CapturedFormField = fieldFor(data.props, "site");
389
+ const writes: Array<FormValuesLike> = [];
390
+
391
+ expect(site.onChange).toBeDefined();
392
+
393
+ site.onChange!(
394
+ data.siteId,
395
+ data.currentFormValues || { name: "core-switch-01" },
396
+ (values: FormValuesLike): void => {
397
+ writes.push(values);
398
+ },
399
+ );
400
+
401
+ if (data.expectWrite === false) {
402
+ /*
403
+ * Nothing to wait FOR, so drain instead: a timer callback runs only once
404
+ * every queued microtask has, so the lookup and its handler have both
405
+ * finished by the time this resolves. Without it, "it wrote nothing"
406
+ * would pass simply by being asserted first.
407
+ */
408
+ await new Promise<void>((resolve: () => void): void => {
409
+ setTimeout(resolve, 0);
410
+ });
411
+
412
+ return writes;
413
+ }
414
+
415
+ await waitFor(() => {
416
+ expect(writes.length).toBeGreaterThan(0);
417
+ });
418
+
419
+ return writes;
420
+ }
421
+
422
+ describe("the create form's Probe field", () => {
423
+ beforeEach(() => {
424
+ capturedTableProps = null;
425
+ mockGetItemCalls.length = 0;
426
+ mockProbeList = [{ _id: "probe-1", name: "Branch probe" }];
427
+ mockGetItem = (): Promise<unknown> => {
428
+ return Promise.resolve(siteRow(SITE_PROBE_ID));
429
+ };
430
+ window.localStorage.clear();
431
+ });
432
+
433
+ afterEach(() => {
434
+ cleanup();
435
+ jest.clearAllMocks();
436
+ });
437
+
438
+ /*
439
+ * The regression this file exists for. The probe used to be required only
440
+ * for an "SNMP" device and hidden for a monitor-backed one; this form
441
+ * creates neither kind of exception any more, so a device without a probe
442
+ * is simply a device nothing polls.
443
+ */
444
+ test("is required for every device, and shown for every device", async () => {
445
+ const props: CapturedTableProps = await renderDevicesPage();
446
+ const probe: CapturedFormField = fieldFor(props, "probe");
447
+
448
+ expect(isRequired(probe, { name: "core-switch-01" })).toBe(true);
449
+ // No showIf at all: there is no branch left that hides it.
450
+ expect(probe.showIf).toBeUndefined();
451
+ });
452
+
453
+ /*
454
+ * One sentence for the create form, the Settings page and the topology
455
+ * dialog. A private copy here is how "the probe polls this device via SNMP"
456
+ * survived on one surface after ping-first polling made it false.
457
+ */
458
+ test("explains itself with the shared probe description", async () => {
459
+ const props: CapturedTableProps = await renderDevicesPage();
460
+
461
+ expect(fieldFor(props, "probe").description).toBe(PROBE_FIELD_DESCRIPTION);
462
+ });
463
+
464
+ test("defaults to the project's single custom probe", async () => {
465
+ const props: CapturedTableProps = await renderDevicesPage();
466
+
467
+ expect(fieldFor(props, "probe").defaultValue).toBe("probe-1");
468
+ });
469
+
470
+ /*
471
+ * A global probe sits on the public internet and cannot reach an RFC1918
472
+ * address, so pre-selecting one would hand the operator a device guaranteed
473
+ * to read Down — worse than an empty box, because it looks answered.
474
+ */
475
+ test("never defaults to a global probe, even as the only one", async () => {
476
+ mockProbeList = [{ _id: "global-1", name: "US East", isGlobalProbe: true }];
477
+
478
+ const props: CapturedTableProps = await renderDevicesPage();
479
+
480
+ expect(fieldFor(props, "probe").defaultValue).toBe("");
481
+ });
482
+
483
+ // Two custom probes is a real question, and the form must not answer it.
484
+ test("does not guess when the project has more than one custom probe", async () => {
485
+ mockProbeList = [
486
+ { _id: "probe-1", name: "Branch probe" },
487
+ { _id: "probe-2", name: "Datacenter probe" },
488
+ ];
489
+
490
+ const props: CapturedTableProps = await renderDevicesPage();
491
+
492
+ expect(fieldFor(props, "probe").defaultValue).toBe("");
493
+ });
494
+ });
495
+
496
+ describe("picking a site fills in the site's default probe", () => {
497
+ beforeEach(() => {
498
+ capturedTableProps = null;
499
+ mockGetItemCalls.length = 0;
500
+ mockProbeList = [{ _id: "probe-1", name: "Branch probe" }];
501
+ mockGetItem = (): Promise<unknown> => {
502
+ return Promise.resolve(siteRow(SITE_PROBE_ID));
503
+ };
504
+ window.localStorage.clear();
505
+ });
506
+
507
+ afterEach(() => {
508
+ cleanup();
509
+ jest.clearAllMocks();
510
+ });
511
+
512
+ test("reads the chosen site's probe and writes it into the probe box", async () => {
513
+ const props: CapturedTableProps = await renderDevicesPage();
514
+
515
+ const writes: Array<FormValuesLike> = await selectSite({
516
+ props: props,
517
+ siteId: SITE_ID,
518
+ currentFormValues: { name: "core-switch-01", probe: "probe-1" },
519
+ });
520
+
521
+ expect(mockGetItemCalls.length).toBe(1);
522
+ expect(mockGetItemCalls[0]!.modelType).toBe(NetworkSite);
523
+ expect(mockGetItemCalls[0]!.id.toString()).toBe(SITE_ID);
524
+ /*
525
+ * One column. The site row carries credentials-adjacent columns and a
526
+ * whole rollup; this lookup exists to answer one question.
527
+ */
528
+ expect(mockGetItemCalls[0]!.select).toEqual({ probeId: true });
529
+
530
+ /*
531
+ * The site is written back beside the probe: this write lands AFTER the
532
+ * dropdown's own setFieldValue, and the values it spreads were snapshot
533
+ * before it — so a write that carried only the probe would undo the very
534
+ * selection that triggered it.
535
+ */
536
+ expect(writes[writes.length - 1]).toEqual({
537
+ name: "core-switch-01",
538
+ site: SITE_ID,
539
+ probe: SITE_PROBE_ID,
540
+ });
541
+ });
542
+
543
+ /*
544
+ * "One getItem per site id", which is the whole reason the answers are
545
+ * cached: flipping between two sites while deciding, or opening the create
546
+ * form a second time, must not put a request on the wire per click.
547
+ */
548
+ test("asks the server once per site id, however often the site is picked", async () => {
549
+ const props: CapturedTableProps = await renderDevicesPage();
550
+
551
+ await selectSite({ props: props, siteId: SITE_ID });
552
+ expect(mockGetItemCalls.length).toBe(1);
553
+
554
+ await selectSite({
555
+ props: props,
556
+ siteId: SITE_ID,
557
+ currentFormValues: { probe: SITE_PROBE_ID },
558
+ // Same site, same probe already in the box: nothing left to write.
559
+ expectWrite: false,
560
+ });
561
+ expect(mockGetItemCalls.length).toBe(1);
562
+
563
+ mockGetItem = (): Promise<unknown> => {
564
+ return Promise.resolve(siteRow(OTHER_PROBE_ID));
565
+ };
566
+
567
+ const writes: Array<FormValuesLike> = await selectSite({
568
+ props: props,
569
+ siteId: OTHER_SITE_ID,
570
+ currentFormValues: { probe: SITE_PROBE_ID },
571
+ });
572
+
573
+ // A second site is a second question, and gets asked.
574
+ expect(mockGetItemCalls.length).toBe(2);
575
+ expect(writes[writes.length - 1]!["probe"]).toBe(OTHER_PROBE_ID);
576
+ });
577
+
578
+ /*
579
+ * A site with no default probe is an ANSWER, and it is cached as one: the
580
+ * alternative is a lookup on every pick of the sites that have nothing to
581
+ * say.
582
+ */
583
+ test("remembers a site that has no default probe, and leaves the box alone", async () => {
584
+ mockGetItem = (): Promise<unknown> => {
585
+ return Promise.resolve(siteRow(undefined));
586
+ };
587
+
588
+ const props: CapturedTableProps = await renderDevicesPage();
589
+
590
+ const writes: Array<FormValuesLike> = await selectSite({
591
+ props: props,
592
+ siteId: SITE_ID,
593
+ currentFormValues: { probe: "probe-1" },
594
+ expectWrite: false,
595
+ });
596
+
597
+ expect(writes).toEqual([]);
598
+ expect(mockGetItemCalls.length).toBe(1);
599
+
600
+ await selectSite({
601
+ props: props,
602
+ siteId: SITE_ID,
603
+ currentFormValues: { probe: "probe-1" },
604
+ expectWrite: false,
605
+ });
606
+
607
+ expect(mockGetItemCalls.length).toBe(1);
608
+ });
609
+
610
+ /*
611
+ * The site's probe is a DEFAULT, and a default may only replace a default.
612
+ * An operator who picked the one probe that can reach this particular
613
+ * device, and then recorded which site it stands in, must not have that
614
+ * quietly undone.
615
+ */
616
+ test("never overwrites a probe the operator picked themselves", async () => {
617
+ const props: CapturedTableProps = await renderDevicesPage();
618
+
619
+ const writes: Array<FormValuesLike> = await selectSite({
620
+ props: props,
621
+ siteId: SITE_ID,
622
+ // Neither the form's default ("probe-1") nor anything it filled in.
623
+ currentFormValues: { probe: "probe-chosen-by-hand" },
624
+ expectWrite: false,
625
+ });
626
+
627
+ expect(writes).toEqual([]);
628
+ // Not even asked: the answer could not be used.
629
+ expect(mockGetItemCalls.length).toBe(0);
630
+ });
631
+
632
+ test("replaces the probe it filled in for a previously chosen site", async () => {
633
+ const props: CapturedTableProps = await renderDevicesPage();
634
+
635
+ await selectSite({ props: props, siteId: SITE_ID });
636
+
637
+ mockGetItem = (): Promise<unknown> => {
638
+ return Promise.resolve(siteRow(OTHER_PROBE_ID));
639
+ };
640
+
641
+ const writes: Array<FormValuesLike> = await selectSite({
642
+ props: props,
643
+ siteId: OTHER_SITE_ID,
644
+ // What the previous site's lookup put there, not an operator's choice.
645
+ currentFormValues: { probe: SITE_PROBE_ID },
646
+ });
647
+
648
+ expect(writes[writes.length - 1]!["probe"]).toBe(OTHER_PROBE_ID);
649
+ });
650
+
651
+ // Clearing the site says nothing about which probe can reach the device.
652
+ test("clearing the site looks nothing up and changes nothing", async () => {
653
+ const props: CapturedTableProps = await renderDevicesPage();
654
+
655
+ const writes: Array<FormValuesLike> = await selectSite({
656
+ props: props,
657
+ siteId: "",
658
+ currentFormValues: { probe: "probe-1" },
659
+ expectWrite: false,
660
+ });
661
+
662
+ expect(writes).toEqual([]);
663
+ expect(mockGetItemCalls.length).toBe(0);
664
+ });
665
+
666
+ /*
667
+ * A lookup that fails must cost one pick, not the form — and must not be
668
+ * remembered as "this site has no probe", which would make one bad response
669
+ * permanent for the life of the page.
670
+ */
671
+ test("a failed lookup leaves the box alone and is not cached as an answer", async () => {
672
+ /*
673
+ * Rejected from a timer rather than immediately, so the handler is
674
+ * attached before the rejection happens and the run does not log a
675
+ * spurious unhandled-rejection warning for a case that is handled.
676
+ */
677
+ mockGetItem = (): Promise<unknown> => {
678
+ return new Promise<unknown>(
679
+ (_resolve: (value: unknown) => void, reject: (err: Error) => void) => {
680
+ setTimeout(() => {
681
+ reject(new Error("Network error"));
682
+ }, 0);
683
+ },
684
+ );
685
+ };
686
+
687
+ const props: CapturedTableProps = await renderDevicesPage();
688
+
689
+ const writes: Array<FormValuesLike> = await selectSite({
690
+ props: props,
691
+ siteId: SITE_ID,
692
+ currentFormValues: { probe: "probe-1" },
693
+ expectWrite: false,
694
+ });
695
+
696
+ expect(writes).toEqual([]);
697
+
698
+ mockGetItem = (): Promise<unknown> => {
699
+ return Promise.resolve(siteRow(SITE_PROBE_ID));
700
+ };
701
+
702
+ const retried: Array<FormValuesLike> = await selectSite({
703
+ props: props,
704
+ siteId: SITE_ID,
705
+ currentFormValues: { probe: "probe-1" },
706
+ });
707
+
708
+ expect(mockGetItemCalls.length).toBe(2);
709
+ expect(retried[retried.length - 1]!["probe"]).toBe(SITE_PROBE_ID);
710
+ });
711
+ });
712
+
713
+ describe("the create form's SNMP step", () => {
714
+ beforeEach(() => {
715
+ capturedTableProps = null;
716
+ mockGetItemCalls.length = 0;
717
+ mockProbeList = [{ _id: "probe-1", name: "Branch probe" }];
718
+ window.localStorage.clear();
719
+ });
720
+
721
+ afterEach(() => {
722
+ cleanup();
723
+ jest.clearAllMocks();
724
+ });
725
+
726
+ /*
727
+ * The step used to be hidden for a monitor-backed device, which is the only
728
+ * device that is never polled. This form creates no such device, so there
729
+ * is no branch left — and a step every device walks through is a step whose
730
+ * fields must all be skippable.
731
+ */
732
+ test("is shown for every device and gated by nothing", async () => {
733
+ const props: CapturedTableProps = await renderDevicesPage();
734
+
735
+ const snmp: CapturedFormStep | undefined = (props.formSteps || []).find(
736
+ (step: CapturedFormStep): boolean => {
737
+ return step.id === "snmp";
738
+ },
739
+ );
740
+
741
+ expect(snmp).toBeDefined();
742
+ expect(snmp!.showIf).toBeUndefined();
743
+ // The stepper is where an operator learns they may walk past it.
744
+ expect(snmp!.title.toLowerCase()).toContain("optional");
745
+ });
746
+
747
+ test("says what an empty community string means, in the shared words", async () => {
748
+ const props: CapturedTableProps = await renderDevicesPage();
749
+ const profile: CapturedFormField = fieldFor(props, "snmpCredentialProfile");
750
+
751
+ /*
752
+ * The heading rides on the first field of the step, which is how BasicForm
753
+ * renders a section — sectionDescription is dropped unless a sectionTitle
754
+ * is set beside it.
755
+ */
756
+ expect(profile.sectionTitle).toBe("SNMP");
757
+ expect(profile.sectionDescription).toBe(SNMP_STEP_DESCRIPTION);
758
+ });
759
+
760
+ test("credentials are optional: nothing on the step is required but the version", async () => {
761
+ const props: CapturedTableProps = await renderDevicesPage();
762
+
763
+ const onSnmpStep: Array<CapturedFormField> = (
764
+ props.formFields || []
765
+ ).filter((field: CapturedFormField): boolean => {
766
+ return field.stepId === "snmp";
767
+ });
768
+
769
+ expect(onSnmpStep.length).toBeGreaterThan(0);
770
+
771
+ const community: CapturedFormField = fieldFor(props, "snmpCommunityString");
772
+ const profile: CapturedFormField = fieldFor(props, "snmpCredentialProfile");
773
+
774
+ expect(isRequired(community, {})).toBe(false);
775
+ expect(isRequired(profile, {})).toBe(false);
776
+ /*
777
+ * The v3 fields ARE required, but only once V3 is chosen — they are
778
+ * revealed by showIf, so a device left on the defaulted V2c never meets
779
+ * them. The version itself is required and defaulted, which is why it is
780
+ * the one exception.
781
+ */
782
+ expect(isRequired(fieldFor(props, "snmpVersion"), {})).toBe(true);
783
+ expect(fieldFor(props, "snmpVersion").defaultValue).toBe("V2c");
784
+ });
785
+
786
+ /*
787
+ * The either/or has to read the same here and on the Settings page, or a
788
+ * device created with a profile and a device switched to one afterwards are
789
+ * described by two different explanations of the same column.
790
+ */
791
+ test("offers the credential profile beside the device's own credentials", async () => {
792
+ const props: CapturedTableProps = await renderDevicesPage();
793
+ const profile: CapturedFormField = fieldFor(props, "snmpCredentialProfile");
794
+
795
+ expect(profile.stepId).toBe("snmp");
796
+ expect(profile.fieldType).toBe(FormFieldSchemaType.Dropdown);
797
+ expect(profile.dropdownModal?.type).toBe(NetworkSnmpCredentialProfile);
798
+ expect(profile.description).toContain("credentials below win");
799
+ expect(profile.placeholder?.toLowerCase()).toContain("no profile");
800
+ // Somewhere to go when the list is empty, which it is until one is made.
801
+ expect(profile.sideLink?.text).toBe("Manage credential profiles");
802
+ });
803
+ });
804
+
805
+ describe("the device list's bulk actions", () => {
806
+ beforeEach(() => {
807
+ capturedTableProps = null;
808
+ mockProbeList = [{ _id: "probe-1", name: "Branch probe" }];
809
+ window.localStorage.clear();
810
+ });
811
+
812
+ afterEach(() => {
813
+ cleanup();
814
+ jest.clearAllMocks();
815
+ });
816
+
817
+ /*
818
+ * A credential profile is only worth having if an EXISTING fleet can be
819
+ * moved onto it — the ping-only devices that need credentials were imported
820
+ * long before anybody wrote the profile down.
821
+ */
822
+ test("include setting an SNMP credential profile on a selection", async () => {
823
+ const props: CapturedTableProps = await renderDevicesPage();
824
+
825
+ const titles: Array<string> = (props.bulkActions?.buttons || []).map(
826
+ (button: { title?: string | undefined }): string => {
827
+ return button.title || "";
828
+ },
829
+ );
830
+
831
+ expect(titles).toContain("Set SNMP Credential Profile");
832
+ });
833
+ });