@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.
- package/Models/AnalyticsModels/Span.ts +14 -0
- package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
- package/Models/DatabaseModels/Index.ts +10 -0
- package/Models/DatabaseModels/Monitor.ts +76 -0
- package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
- package/Models/DatabaseModels/NetworkDevice.ts +176 -1
- package/Models/DatabaseModels/NetworkSite.ts +201 -2
- package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
- package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
- package/Models/DatabaseModels/TelemetryException.ts +119 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
- package/Server/API/EnterpriseLicenseAPI.ts +391 -64
- package/Server/API/LlmProviderAPI.ts +137 -22
- package/Server/EnvironmentConfig.ts +14 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.ts +55 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.ts +124 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.ts +132 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.ts +79 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.ts +191 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Infrastructure/QueueWorker.ts +38 -8
- package/Server/Middleware/BearerTokenAuthorization.ts +12 -0
- package/Server/Middleware/ProjectAuthorization.ts +11 -0
- package/Server/Middleware/SCIMAuthorization.ts +12 -0
- package/Server/Middleware/TelemetryIngest.ts +11 -0
- package/Server/Services/AIBillingService.ts +101 -27
- package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
- package/Server/Services/EnterpriseLicenseService.ts +55 -0
- package/Server/Services/Index.ts +10 -0
- package/Server/Services/MonitorService.ts +143 -21
- package/Server/Services/MonitorStatusTimelineService.ts +150 -8
- package/Server/Services/MonitorTemplateService.ts +217 -1
- package/Server/Services/NetworkAlertPolicyEngineService.ts +2159 -0
- package/Server/Services/NetworkAlertPolicyService.ts +944 -0
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +9 -10
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +60 -15
- package/Server/Services/NetworkDeviceService.ts +1032 -73
- package/Server/Services/NetworkSiteService.ts +1502 -129
- package/Server/Services/NetworkSiteTypeService.ts +1216 -0
- package/Server/Services/NetworkSnmpCredentialProfileService.ts +238 -0
- package/Server/Services/NotificationService.ts +118 -28
- package/Server/Services/ProjectService.ts +105 -48
- package/Server/Services/StatusPagePrivateUserService.ts +103 -3
- package/Server/Services/UserNotificationEmailRollupBatchService.ts +78 -0
- package/Server/Services/UserNotificationEmailRollupItemService.ts +79 -0
- package/Server/Services/UserNotificationEmailRollupSettingService.ts +113 -0
- package/Server/Services/UserNotificationSettingService.ts +62 -25
- package/Server/Services/UserService.ts +95 -0
- package/Server/Types/Database/QueryHelper.ts +2 -2
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +14 -3
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +10 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +10 -0
- package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +62 -1
- package/Server/Utils/AI/Toolbox/AlertTools.ts +15 -1
- package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
- package/Server/Utils/DataSource/HttpFetch.ts +9 -2
- package/Server/Utils/EmailRollup/EmailRollupConstants.ts +98 -0
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +872 -0
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
- package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
- package/Server/Utils/LLM/LLMService.ts +78 -0
- package/Server/Utils/LogRedaction.ts +8 -0
- package/Server/Utils/Logger.ts +79 -1
- package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
- package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +49 -0
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +43 -0
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +499 -19
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +66 -10
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +238 -44
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +146 -39
- package/Server/Utils/NetworkDevice/DeviceHealthAggregation.ts +31 -18
- package/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.ts +213 -0
- package/Server/Utils/OutboundUserAgent.ts +152 -0
- package/Server/Utils/StartServer.ts +51 -19
- package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
- package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
- package/Server/Utils/Telemetry/SpanUtil.ts +33 -0
- package/Server/Utils/Telemetry.ts +198 -51
- package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
- package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +134 -33
- package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
- package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
- package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
- package/Tests/App/Dashboard/DeviceStatusHero.test.tsx +588 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +18 -9
- package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +632 -0
- package/Tests/App/Dashboard/MonitorRecommendationCreateProgress.test.tsx +682 -0
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
- package/Tests/App/Dashboard/NetworkDeviceCreateFormMonitorBinding.test.tsx +676 -0
- package/Tests/App/Dashboard/NetworkDeviceCreateFormPingMonitor.test.tsx +791 -0
- package/Tests/App/Dashboard/NetworkDeviceCreateFormProbeAndSnmp.test.tsx +833 -0
- package/Tests/App/Dashboard/NetworkDeviceCriteriaFilter.test.ts +161 -0
- package/Tests/App/Dashboard/NetworkDeviceSettingsMonitoringSection.test.tsx +458 -0
- package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +41 -5
- package/Tests/App/Dashboard/PingMonitorProvisioning.test.ts +368 -0
- package/Tests/App/Dashboard/RecommendationCard.test.tsx +796 -0
- package/Tests/App/Dashboard/RecommendationToolbar.test.tsx +519 -0
- package/Tests/App/Dashboard/RecommendationsList.test.tsx +661 -0
- package/Tests/App/Dashboard/UseBulkCreatePingMonitors.test.tsx +899 -0
- package/Tests/App/Dashboard/UseBulkSnmpCredentialProfileActions.test.tsx +732 -0
- package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +256 -0
- package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +11 -1
- package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
- package/Tests/Models/NetworkSiteHierarchy.test.ts +41 -4
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
- package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -0
- package/Tests/Server/Infrastructure/Postgres/NetworkSnmpCredentialProfilesAndAlertPoliciesMigration.test.ts +854 -0
- package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +18 -0
- package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -0
- package/Tests/Server/Services/AIChatPrivacyPin.test.ts +560 -0
- package/Tests/Server/Services/BillingRechargeOwnerEmailGuards.test.ts +783 -0
- package/Tests/Server/Services/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
- package/Tests/Server/Services/MonitorServiceDeleteNetworkDeviceCleanup.test.ts +294 -0
- package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +802 -0
- package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +72 -2
- package/Tests/Server/Services/NetworkAlertPolicyEngineHooks.test.ts +752 -0
- package/Tests/Server/Services/NetworkAlertPolicyEngineService.test.ts +1849 -0
- package/Tests/Server/Services/NetworkAlertPolicyModel.test.ts +1793 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +47 -4
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +97 -12
- package/Tests/Server/Services/NetworkDeviceAutoMonitorLifecycle.test.ts +148 -3
- package/Tests/Server/Services/NetworkDeviceMonitorBindingUpdateGuard.test.ts +514 -0
- package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +447 -58
- package/Tests/Server/Services/NetworkDeviceMonitoringMethodTransition.test.ts +739 -0
- package/Tests/Server/Services/NetworkDevicePollingTenancy.test.ts +501 -0
- package/Tests/Server/Services/NetworkDeviceSiteDefaultProbe.test.ts +432 -0
- package/Tests/Server/Services/NetworkSiteMonitoringDefaults.test.ts +498 -0
- package/Tests/Server/Services/NetworkSiteRollupPolicyAndMaintenance.test.ts +337 -55
- package/Tests/Server/Services/NetworkSiteService.test.ts +1868 -131
- package/Tests/Server/Services/NetworkSiteTypeService.test.ts +1109 -0
- package/Tests/Server/Services/NetworkSnmpCredentialProfileModel.test.ts +926 -0
- package/Tests/Server/Services/NetworkSnmpCredentialProfileService.test.ts +796 -0
- package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
- package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -0
- package/Tests/Server/Services/UserEmailChangePasswordResetExpiry.test.ts +472 -0
- package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +569 -0
- package/Tests/Server/Services/UserNotificationEmailRollupSettingModel.test.ts +314 -0
- package/Tests/Server/Services/UserNotificationEmailRollupSettingService.test.ts +409 -0
- package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +856 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +102 -1
- package/Tests/Server/Types/Database/Permissions/DashboardAccessPermission.test.ts +321 -0
- package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +17 -0
- package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +124 -0
- package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +208 -0
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +235 -0
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +253 -0
- package/Tests/Server/Utils/Captcha.test.ts +422 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +96 -2
- package/Tests/Server/Utils/Database/MigrationFailureLog.test.ts +466 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1096 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerClaim.test.ts +466 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +752 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
- package/Tests/Server/Utils/LoggerFaultDemotion.test.ts +346 -0
- package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
- package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +196 -0
- package/Tests/Server/Utils/Monitor/DatabaseMetricWrite.test.ts +367 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +100 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +5 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +512 -31
- package/Tests/Server/Utils/Monitor/NetworkDeviceMetricUtil.test.ts +252 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +479 -42
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +351 -5
- package/Tests/Server/Utils/NetworkDevice/DeviceHealthAggregation.test.ts +136 -12
- package/Tests/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.test.ts +306 -0
- package/Tests/Server/Utils/OutboundUserAgent.test.ts +266 -0
- package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -0
- package/Tests/Server/Utils/Telemetry/ErrorClassResolver.test.ts +298 -0
- package/Tests/Server/Utils/Telemetry.test.ts +456 -66
- package/Tests/Types/Monitor/DatabaseMetricCatalog.test.ts +388 -0
- package/Tests/Types/Monitor/MonitorStepDatabaseMonitor.test.ts +243 -0
- package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +16 -7
- package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +60 -0
- package/Tests/Types/NetworkDevice/NetworkAlertPolicyScope.test.ts +655 -0
- package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +115 -26
- package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +39 -0
- package/Tests/Types/NotificationSetting/NotificationEmailRollupPolicy.test.ts +299 -0
- package/Tests/Types/Telemetry/ErrorClass.test.ts +483 -0
- package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +15 -0
- package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
- package/Tests/UI/Components/SideMenuItem.test.tsx +226 -4
- package/Tests/UI/Components/SideMenuSection.test.tsx +310 -0
- package/Tests/UI/Components/SideOverSubmitState.test.tsx +335 -0
- package/Tests/UI/Utils/PageScrollLock.test.tsx +377 -0
- package/Tests/UI/Utils/PermissionGate.test.ts +78 -0
- package/Tests/UI/Utils/SensitiveUrlToken.test.ts +140 -0
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +69 -0
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +7 -1
- package/Tests/Utils/EnterpriseLicenseUsage.test.ts +433 -2
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +280 -1
- package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +38 -0
- package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +284 -23
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +177 -0
- package/Tests/Utils/NetworkDevice/MonitoringMethodThreadedClassifiers.test.ts +992 -0
- package/Tests/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.test.ts +427 -0
- package/Tests/Utils/NetworkDevice/ReachabilityStampConsistency.test.ts +185 -0
- package/Tests/Utils/NetworkDevice/SnmpCredentialUtil.test.ts +268 -0
- package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +55 -5
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +98 -21
- package/Tests/Utils/NetworkDiscovery/DiscoveryImportEligibility.test.ts +98 -20
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +8 -7
- package/Tests/Utils/NetworkDiscovery/PingMonitorBuilderForAddress.test.ts +274 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +230 -51
- package/Tests/Utils/NetworkSite/TypeHierarchyUtil.test.ts +209 -0
- package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
- package/Types/AI/ExceptionAIClassification.ts +10 -24
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +5 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.ts +13 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.ts +6 -0
- package/Types/Exception/ApiException.ts +10 -0
- package/Types/Exception/BadDataException.ts +11 -0
- package/Types/Exception/BadRequestException.ts +11 -0
- package/Types/Exception/Exception.ts +65 -0
- package/Types/Exception/ForbiddenException.ts +10 -0
- package/Types/Exception/NotAuthenticatedException.ts +10 -0
- package/Types/Exception/NotAuthorizedException.ts +10 -0
- package/Types/Exception/NotFoundException.ts +11 -0
- package/Types/Exception/PayloadTooLargeException.ts +11 -0
- package/Types/Exception/PaymentRequiredException.ts +10 -0
- package/Types/Exception/ServiceUnavailableException.ts +10 -0
- package/Types/Exception/SsoAuthorizationException.ts +10 -0
- package/Types/Exception/TenantNotFoundException.ts +11 -0
- package/Types/Exception/TimeoutException.ts +10 -0
- package/Types/Exception/TooManyRequestsException.ts +10 -0
- package/Types/Exception/UnableToReachServer.ts +10 -0
- package/Types/Exception/WebsiteRequestException.ts +10 -0
- package/Types/Monitor/CriteriaFilter.ts +60 -2
- package/Types/Monitor/DatabaseMetricCatalog.ts +693 -0
- package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +83 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +76 -0
- package/Types/Monitor/MonitorMetricType.ts +71 -0
- package/Types/Monitor/MonitorStep.ts +76 -0
- package/Types/Monitor/MonitorStepDatabaseMonitor.ts +171 -0
- package/Types/Monitor/MonitorStepSqlMonitor.ts +2 -20
- package/Types/Monitor/MonitorType.ts +47 -1
- package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
- package/Types/Monitor/SqlConnectionConfig.ts +31 -0
- package/Types/NetworkDevice/NetworkAlertPolicyScope.ts +343 -0
- package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +42 -22
- package/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.ts +30 -0
- package/Types/NotificationSetting/NotificationEmailRollupCategory.ts +255 -0
- package/Types/NotificationSetting/NotificationEmailRollupPolicy.ts +104 -0
- package/Types/Permission.ts +90 -0
- package/Types/Probe/ProbeMonitorResponse.ts +16 -0
- package/Types/Telemetry/ErrorClass.ts +274 -0
- package/Types/Telemetry/UnitOfWork.ts +59 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +2 -8
- package/UI/Components/EditionLabel/EditionLabel.tsx +4 -0
- package/UI/Components/Modal/Modal.tsx +2 -8
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
- package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
- package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
- package/UI/Components/SideMenu/SideMenu.tsx +123 -5
- package/UI/Components/SideMenu/SideMenuItem.tsx +76 -84
- package/UI/Components/SideMenu/SideMenuSection.tsx +55 -23
- package/UI/Components/SideOver/SideOver.tsx +21 -20
- package/UI/Utils/PageScrollLock.ts +79 -3
- package/UI/Utils/PermissionGate.ts +61 -0
- package/UI/Utils/SensitiveUrlToken.ts +112 -0
- package/UI/Utils/TestLLMProvider.ts +11 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
- package/Utils/Monitor/MonitorMetricType.ts +153 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +23 -3
- package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
- package/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.ts +247 -0
- package/Utils/NetworkDevice/SnmpCredentialUtil.ts +68 -0
- package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +15 -7
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +52 -17
- package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +55 -23
- package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
- package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -0
- package/build/dist/Models/AnalyticsModels/Span.js +14 -0
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +59 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +10 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +75 -0
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js +713 -0
- package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +180 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSite.js +200 -2
- package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js +102 -3
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js +878 -0
- package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js +123 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js +363 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +402 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js +296 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js.map +1 -0
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +273 -60
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +108 -13
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +12 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js +111 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js +77 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js +50 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js +83 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +33 -5
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Middleware/BearerTokenAuthorization.js +12 -0
- package/build/dist/Server/Middleware/BearerTokenAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/ProjectAuthorization.js +11 -0
- package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/SCIMAuthorization.js +12 -0
- package/build/dist/Server/Middleware/SCIMAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +11 -0
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AIBillingService.js +70 -16
- package/build/dist/Server/Services/AIBillingService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js +167 -0
- package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +39 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +10 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +119 -21
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +127 -8
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +162 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js +1683 -0
- package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js.map +1 -0
- package/build/dist/Server/Services/NetworkAlertPolicyService.js +732 -0
- package/build/dist/Server/Services/NetworkAlertPolicyService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +10 -9
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +54 -11
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +841 -70
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +1145 -107
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteTypeService.js +863 -0
- package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js +217 -0
- package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js.map +1 -0
- package/build/dist/Server/Services/NotificationService.js +80 -17
- package/build/dist/Server/Services/NotificationService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +66 -30
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +92 -2
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js +76 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js +77 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js +111 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js +46 -20
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +90 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +14 -3
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +10 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +10 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +54 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +18 -4
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
- package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js +59 -0
- package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js +2 -1
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +91 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +691 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +497 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +257 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -0
- package/build/dist/Server/Utils/LLM/LLMService.js +64 -1
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/LogRedaction.js +8 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
- package/build/dist/Server/Utils/Logger.js +63 -1
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js +141 -0
- package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +51 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +37 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +158 -6
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +32 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +330 -21
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +55 -10
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +178 -49
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +119 -29
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js +30 -17
- package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js.map +1 -1
- package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js +158 -0
- package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js.map +1 -0
- package/build/dist/Server/Utils/OutboundUserAgent.js +123 -0
- package/build/dist/Server/Utils/OutboundUserAgent.js.map +1 -0
- package/build/dist/Server/Utils/StartServer.js +38 -14
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +28 -8
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js +95 -0
- package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js +29 -0
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry.js +162 -46
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Types/AI/ExceptionAIClassification.js +10 -24
- package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js +2 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js.map +1 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js +7 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js.map +1 -0
- package/build/dist/Types/Exception/ApiException.js +9 -0
- package/build/dist/Types/Exception/ApiException.js.map +1 -1
- package/build/dist/Types/Exception/BadDataException.js +10 -0
- package/build/dist/Types/Exception/BadDataException.js.map +1 -1
- package/build/dist/Types/Exception/BadRequestException.js +10 -0
- package/build/dist/Types/Exception/BadRequestException.js.map +1 -1
- package/build/dist/Types/Exception/Exception.js +56 -0
- package/build/dist/Types/Exception/Exception.js.map +1 -1
- package/build/dist/Types/Exception/ForbiddenException.js +9 -0
- package/build/dist/Types/Exception/ForbiddenException.js.map +1 -1
- package/build/dist/Types/Exception/NotAuthenticatedException.js +9 -0
- package/build/dist/Types/Exception/NotAuthenticatedException.js.map +1 -1
- package/build/dist/Types/Exception/NotAuthorizedException.js +9 -0
- package/build/dist/Types/Exception/NotAuthorizedException.js.map +1 -1
- package/build/dist/Types/Exception/NotFoundException.js +10 -0
- package/build/dist/Types/Exception/NotFoundException.js.map +1 -1
- package/build/dist/Types/Exception/PayloadTooLargeException.js +10 -0
- package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -1
- package/build/dist/Types/Exception/PaymentRequiredException.js +9 -0
- package/build/dist/Types/Exception/PaymentRequiredException.js.map +1 -1
- package/build/dist/Types/Exception/ServiceUnavailableException.js +9 -0
- package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -1
- package/build/dist/Types/Exception/SsoAuthorizationException.js +9 -0
- package/build/dist/Types/Exception/SsoAuthorizationException.js.map +1 -1
- package/build/dist/Types/Exception/TenantNotFoundException.js +10 -0
- package/build/dist/Types/Exception/TenantNotFoundException.js.map +1 -1
- package/build/dist/Types/Exception/TimeoutException.js +9 -0
- package/build/dist/Types/Exception/TimeoutException.js.map +1 -1
- package/build/dist/Types/Exception/TooManyRequestsException.js +9 -0
- package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -1
- package/build/dist/Types/Exception/UnableToReachServer.js +9 -0
- package/build/dist/Types/Exception/UnableToReachServer.js.map +1 -1
- package/build/dist/Types/Exception/WebsiteRequestException.js +9 -0
- package/build/dist/Types/Exception/WebsiteRequestException.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +45 -2
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/DatabaseMetricCatalog.js +594 -0
- package/build/dist/Types/Monitor/DatabaseMetricCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js +21 -0
- package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +70 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorMetricType.js +61 -0
- package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +54 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js +122 -0
- package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +45 -1
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +21 -1
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
- package/build/dist/Types/Monitor/SqlConnectionConfig.js +2 -0
- package/build/dist/Types/Monitor/SqlConnectionConfig.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js +172 -0
- package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +40 -22
- package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -1
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js +26 -0
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js +186 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js +87 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js.map +1 -0
- package/build/dist/Types/Permission.js +80 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Telemetry/ErrorClass.js +216 -0
- package/build/dist/Types/Telemetry/ErrorClass.js.map +1 -0
- package/build/dist/Types/Telemetry/UnitOfWork.js +59 -0
- package/build/dist/Types/Telemetry/UnitOfWork.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +2 -7
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +3 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +2 -7
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +39 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Components/ProgressBar/ProgressBar.js +12 -1
- package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +6 -6
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +67 -5
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js +49 -53
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js +25 -7
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +5 -20
- package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
- package/build/dist/UI/Utils/PageScrollLock.js +31 -3
- package/build/dist/UI/Utils/PageScrollLock.js.map +1 -1
- package/build/dist/UI/Utils/PermissionGate.js +42 -1
- package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
- package/build/dist/UI/Utils/SensitiveUrlToken.js +97 -0
- package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -0
- package/build/dist/UI/Utils/TestLLMProvider.js +4 -5
- package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +15 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +111 -9
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +109 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +8 -3
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +27 -7
- package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +7 -5
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js +180 -0
- package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js +12 -0
- package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +15 -5
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +44 -15
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +52 -23
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js +85 -13
- package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +30 -15
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
- package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js +191 -0
- package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,1109 @@
|
|
|
1
|
+
import NetworkSiteService from "../../../Server/Services/NetworkSiteService";
|
|
2
|
+
import NetworkSiteTypeService from "../../../Server/Services/NetworkSiteTypeService";
|
|
3
|
+
import DatabaseService from "../../../Server/Services/DatabaseService";
|
|
4
|
+
import NetworkSiteHierarchyLock, {
|
|
5
|
+
NETWORK_SITE_HIERARCHY_ROOT_SCOPE_ERROR_MESSAGE,
|
|
6
|
+
} from "../../../Server/Utils/NetworkSite/NetworkSiteHierarchyLock";
|
|
7
|
+
import CreateBy from "../../../Server/Types/Database/CreateBy";
|
|
8
|
+
import DeleteBy from "../../../Server/Types/Database/DeleteBy";
|
|
9
|
+
import UpdateBy from "../../../Server/Types/Database/UpdateBy";
|
|
10
|
+
import NetworkSite from "../../../Models/DatabaseModels/NetworkSite";
|
|
11
|
+
import NetworkSiteType from "../../../Models/DatabaseModels/NetworkSiteType";
|
|
12
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
13
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
14
|
+
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
15
|
+
import { afterEach, describe, expect, it } from "@jest/globals";
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* NetworkSiteService imports the complete monitoring/alerting service graph.
|
|
19
|
+
* This suite tests NetworkSiteTypeService at its service boundary, so replace
|
|
20
|
+
* that collaborator before modules load; the individual tests still spy and
|
|
21
|
+
* assert every site read made through the boundary.
|
|
22
|
+
*/
|
|
23
|
+
jest.mock("../../../Server/Services/NetworkSiteService", () => {
|
|
24
|
+
return {
|
|
25
|
+
__esModule: true,
|
|
26
|
+
default: {
|
|
27
|
+
findBy: jest.fn(),
|
|
28
|
+
findOneBy: jest.fn(),
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
34
|
+
"11111111-1111-4111-8111-111111111111",
|
|
35
|
+
);
|
|
36
|
+
const OTHER_PROJECT_ID: ObjectID = new ObjectID(
|
|
37
|
+
"22222222-2222-4222-8222-222222222222",
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
function typeId(index: number): ObjectID {
|
|
41
|
+
return new ObjectID(
|
|
42
|
+
`aaaaaaaa-aaaa-4aaa-8aaa-${index.toString().padStart(12, "0")}`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function siteId(index: number): ObjectID {
|
|
47
|
+
return new ObjectID(
|
|
48
|
+
`bbbbbbbb-bbbb-4bbb-8bbb-${index.toString().padStart(12, "0")}`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function makeType(data: {
|
|
53
|
+
index: number;
|
|
54
|
+
projectId?: ObjectID | undefined;
|
|
55
|
+
parentIndex?: number | undefined;
|
|
56
|
+
isUnitLevel?: boolean | undefined;
|
|
57
|
+
order?: number | null | undefined;
|
|
58
|
+
}): NetworkSiteType {
|
|
59
|
+
const networkSiteType: NetworkSiteType = new NetworkSiteType();
|
|
60
|
+
networkSiteType.id = typeId(data.index);
|
|
61
|
+
networkSiteType.projectId = data.projectId || PROJECT_ID;
|
|
62
|
+
|
|
63
|
+
if (data.isUnitLevel !== undefined) {
|
|
64
|
+
networkSiteType.isUnitLevel = data.isUnitLevel;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (typeof data.order === "number") {
|
|
68
|
+
networkSiteType.order = data.order;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (data.parentIndex !== undefined) {
|
|
72
|
+
networkSiteType.parentNetworkSiteTypeId = typeId(data.parentIndex);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return networkSiteType;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function makeSite(data: {
|
|
79
|
+
index: number;
|
|
80
|
+
typeIndex?: number | undefined;
|
|
81
|
+
parentIndex?: number | undefined;
|
|
82
|
+
}): NetworkSite {
|
|
83
|
+
const site: NetworkSite = new NetworkSite();
|
|
84
|
+
site.id = siteId(data.index);
|
|
85
|
+
|
|
86
|
+
if (data.typeIndex !== undefined) {
|
|
87
|
+
site.networkSiteTypeId = typeId(data.typeIndex);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (data.parentIndex !== undefined) {
|
|
91
|
+
site.parentSiteId = siteId(data.parentIndex);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return site;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function createBy(data: Partial<NetworkSiteType>): CreateBy<NetworkSiteType> {
|
|
98
|
+
const networkSiteType: NetworkSiteType = new NetworkSiteType();
|
|
99
|
+
networkSiteType.projectId = PROJECT_ID;
|
|
100
|
+
networkSiteType.name = "New Type";
|
|
101
|
+
Object.assign(networkSiteType, data);
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
data: networkSiteType,
|
|
105
|
+
props: { isRoot: true },
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function updateBy(
|
|
110
|
+
data: Record<string, unknown>,
|
|
111
|
+
props: Record<string, unknown> = { isRoot: true },
|
|
112
|
+
): UpdateBy<NetworkSiteType> {
|
|
113
|
+
return {
|
|
114
|
+
query: { _id: typeId(2).toString() },
|
|
115
|
+
data,
|
|
116
|
+
limit: new PositiveNumber(1),
|
|
117
|
+
skip: new PositiveNumber(0),
|
|
118
|
+
props,
|
|
119
|
+
} as unknown as UpdateBy<NetworkSiteType>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function deleteBy(
|
|
123
|
+
props: Record<string, unknown> = { isRoot: true },
|
|
124
|
+
): DeleteBy<NetworkSiteType> {
|
|
125
|
+
return {
|
|
126
|
+
query: { _id: typeId(2).toString() },
|
|
127
|
+
limit: new PositiveNumber(1),
|
|
128
|
+
skip: new PositiveNumber(0),
|
|
129
|
+
props,
|
|
130
|
+
} as unknown as DeleteBy<NetworkSiteType>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/*
|
|
134
|
+
* Configure the three type reads made by a parent update: rows matched by the
|
|
135
|
+
* update, all project types for cycle detection, and destination siblings for
|
|
136
|
+
* automatic order assignment.
|
|
137
|
+
*/
|
|
138
|
+
function mockParentUpdate(data: {
|
|
139
|
+
moving?: NetworkSiteType | undefined;
|
|
140
|
+
parent?: NetworkSiteType | null | undefined;
|
|
141
|
+
projectTypes?: Array<NetworkSiteType> | undefined;
|
|
142
|
+
siblings?: Array<NetworkSiteType> | undefined;
|
|
143
|
+
}): void {
|
|
144
|
+
const moving: NetworkSiteType =
|
|
145
|
+
data.moving || makeType({ index: 2, parentIndex: 1 });
|
|
146
|
+
|
|
147
|
+
jest
|
|
148
|
+
.spyOn(NetworkSiteTypeService, "findOneById")
|
|
149
|
+
.mockResolvedValue(
|
|
150
|
+
data.parent === undefined ? makeType({ index: 4 }) : data.parent,
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
jest
|
|
154
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
155
|
+
.mockImplementation(async (findBy: any) => {
|
|
156
|
+
if (findBy.skip > 0) {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (findBy.query?._id) {
|
|
161
|
+
return [moving];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (findBy.query?.parentNetworkSiteTypeId !== undefined) {
|
|
165
|
+
return data.siblings || [];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return data.projectTypes || [moving];
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
afterEach(() => {
|
|
173
|
+
jest.clearAllMocks();
|
|
174
|
+
jest.restoreAllMocks();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe("NetworkSiteTypeService create hierarchy validation", () => {
|
|
178
|
+
it("accepts an ID parent in the same project and appends after the maximum numbered sibling", async () => {
|
|
179
|
+
jest
|
|
180
|
+
.spyOn(NetworkSiteTypeService, "findOneById")
|
|
181
|
+
.mockResolvedValue(makeType({ index: 1 }));
|
|
182
|
+
jest
|
|
183
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
184
|
+
.mockResolvedValue([
|
|
185
|
+
makeType({ index: 3, order: null }),
|
|
186
|
+
makeType({ index: 4, order: 7 }),
|
|
187
|
+
makeType({ index: 5, order: 2 }),
|
|
188
|
+
]);
|
|
189
|
+
const input: CreateBy<NetworkSiteType> = createBy({
|
|
190
|
+
parentNetworkSiteTypeId: typeId(1),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await (NetworkSiteTypeService as any).onBeforeCreate(input);
|
|
194
|
+
|
|
195
|
+
expect(input.data.order).toBe(8);
|
|
196
|
+
expect(NetworkSiteTypeService.findOneById).toHaveBeenCalledWith(
|
|
197
|
+
expect.objectContaining({ id: typeId(1) }),
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("accepts the relation-object spelling used by entity pickers", async () => {
|
|
202
|
+
const parent: NetworkSiteType = makeType({ index: 1 });
|
|
203
|
+
jest.spyOn(NetworkSiteTypeService, "findOneById").mockResolvedValue(parent);
|
|
204
|
+
jest.spyOn(NetworkSiteTypeService, "findBy").mockResolvedValue([]);
|
|
205
|
+
|
|
206
|
+
await expect(
|
|
207
|
+
(NetworkSiteTypeService as any).onBeforeCreate(
|
|
208
|
+
createBy({ parentNetworkSiteType: parent }),
|
|
209
|
+
),
|
|
210
|
+
).resolves.toBeDefined();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("rejects conflicting relation and ID parent values", async () => {
|
|
214
|
+
const parent: NetworkSiteType = makeType({ index: 1 });
|
|
215
|
+
|
|
216
|
+
await expect(
|
|
217
|
+
(NetworkSiteTypeService as any).onBeforeCreate(
|
|
218
|
+
createBy({
|
|
219
|
+
parentNetworkSiteTypeId: typeId(3),
|
|
220
|
+
parentNetworkSiteType: parent,
|
|
221
|
+
}),
|
|
222
|
+
),
|
|
223
|
+
).rejects.toThrow("Conflicting parent Network Site Type references");
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("rejects a non-null relation object that does not carry an ID", async () => {
|
|
227
|
+
await expect(
|
|
228
|
+
(NetworkSiteTypeService as any).onBeforeCreate(
|
|
229
|
+
createBy({
|
|
230
|
+
parentNetworkSiteType: {} as NetworkSiteType,
|
|
231
|
+
}),
|
|
232
|
+
),
|
|
233
|
+
).rejects.toThrow("must contain a valid Network Site Type ID");
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("rejects a raw SQL parent expression", async () => {
|
|
237
|
+
await expect(
|
|
238
|
+
(NetworkSiteTypeService as any).onBeforeCreate(
|
|
239
|
+
createBy({
|
|
240
|
+
parentNetworkSiteTypeId: (() => {
|
|
241
|
+
return "some SQL";
|
|
242
|
+
}) as unknown as ObjectID,
|
|
243
|
+
}),
|
|
244
|
+
),
|
|
245
|
+
).rejects.toThrow("cannot be set to a raw SQL expression");
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("rejects a raw SQL isUnitLevel expression on create", async () => {
|
|
249
|
+
await expect(
|
|
250
|
+
(NetworkSiteTypeService as any).onBeforeCreate(
|
|
251
|
+
createBy({
|
|
252
|
+
isUnitLevel: (() => {
|
|
253
|
+
return true;
|
|
254
|
+
}) as unknown as boolean,
|
|
255
|
+
}),
|
|
256
|
+
),
|
|
257
|
+
).rejects.toThrow("unit-level leaf rules must be validated");
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("rejects a missing parent", async () => {
|
|
261
|
+
jest.spyOn(NetworkSiteTypeService, "findOneById").mockResolvedValue(null);
|
|
262
|
+
|
|
263
|
+
await expect(
|
|
264
|
+
(NetworkSiteTypeService as any).onBeforeCreate(
|
|
265
|
+
createBy({ parentNetworkSiteTypeId: typeId(1) }),
|
|
266
|
+
),
|
|
267
|
+
).rejects.toThrow(
|
|
268
|
+
new BadDataException("Parent Network Site Type not found."),
|
|
269
|
+
);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("rejects a parent from another project", async () => {
|
|
273
|
+
jest
|
|
274
|
+
.spyOn(NetworkSiteTypeService, "findOneById")
|
|
275
|
+
.mockResolvedValue(makeType({ index: 1, projectId: OTHER_PROJECT_ID }));
|
|
276
|
+
|
|
277
|
+
await expect(
|
|
278
|
+
(NetworkSiteTypeService as any).onBeforeCreate(
|
|
279
|
+
createBy({ parentNetworkSiteTypeId: typeId(1) }),
|
|
280
|
+
),
|
|
281
|
+
).rejects.toThrow("must belong to the same project");
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("rejects a unit-level parent", async () => {
|
|
285
|
+
jest
|
|
286
|
+
.spyOn(NetworkSiteTypeService, "findOneById")
|
|
287
|
+
.mockResolvedValue(makeType({ index: 1, isUnitLevel: true }));
|
|
288
|
+
|
|
289
|
+
await expect(
|
|
290
|
+
(NetworkSiteTypeService as any).onBeforeCreate(
|
|
291
|
+
createBy({ parentNetworkSiteTypeId: typeId(1) }),
|
|
292
|
+
),
|
|
293
|
+
).rejects.toThrow("unit-level Network Site Type cannot have child types");
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it("rejects self-parenting when a server-side caller supplies the new ID", async () => {
|
|
297
|
+
await expect(
|
|
298
|
+
(NetworkSiteTypeService as any).onBeforeCreate(
|
|
299
|
+
createBy({ id: typeId(2), parentNetworkSiteTypeId: typeId(2) }),
|
|
300
|
+
),
|
|
301
|
+
).rejects.toThrow("cannot be its own parent");
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("assigns the next root sibling order when no parent is supplied", async () => {
|
|
305
|
+
const findOneByIdSpy: jest.SpyInstance = jest.spyOn(
|
|
306
|
+
NetworkSiteTypeService,
|
|
307
|
+
"findOneById",
|
|
308
|
+
);
|
|
309
|
+
jest
|
|
310
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
311
|
+
.mockResolvedValue([
|
|
312
|
+
makeType({ index: 1, order: 3 }),
|
|
313
|
+
makeType({ index: 3, order: 9 }),
|
|
314
|
+
]);
|
|
315
|
+
const input: CreateBy<NetworkSiteType> = createBy({});
|
|
316
|
+
|
|
317
|
+
await (NetworkSiteTypeService as any).onBeforeCreate(input);
|
|
318
|
+
|
|
319
|
+
expect(input.data.order).toBe(10);
|
|
320
|
+
expect(findOneByIdSpy).not.toHaveBeenCalled();
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it("preserves an explicitly supplied order without reading siblings", async () => {
|
|
324
|
+
const findBySpy: jest.SpyInstance = jest.spyOn(
|
|
325
|
+
NetworkSiteTypeService,
|
|
326
|
+
"findBy",
|
|
327
|
+
);
|
|
328
|
+
const input: CreateBy<NetworkSiteType> = createBy({ order: 42 });
|
|
329
|
+
|
|
330
|
+
await (NetworkSiteTypeService as any).onBeforeCreate(input);
|
|
331
|
+
|
|
332
|
+
expect(input.data.order).toBe(42);
|
|
333
|
+
expect(findBySpy).not.toHaveBeenCalled();
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
describe("NetworkSiteTypeService update hierarchy validation", () => {
|
|
338
|
+
it("rejects moving a type to another project", async () => {
|
|
339
|
+
jest
|
|
340
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
341
|
+
.mockResolvedValue([makeType({ index: 2 })]);
|
|
342
|
+
|
|
343
|
+
await expect(
|
|
344
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
345
|
+
updateBy({ projectId: OTHER_PROJECT_ID }),
|
|
346
|
+
),
|
|
347
|
+
).rejects.toThrow("cannot be moved to another project");
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it("accepts a valid ID parent move and places the type last among its new siblings", async () => {
|
|
351
|
+
mockParentUpdate({
|
|
352
|
+
parent: makeType({ index: 4 }),
|
|
353
|
+
siblings: [
|
|
354
|
+
makeType({ index: 6, order: 2 }),
|
|
355
|
+
makeType({ index: 7, order: 5 }),
|
|
356
|
+
],
|
|
357
|
+
});
|
|
358
|
+
jest.spyOn(NetworkSiteService, "findBy").mockResolvedValue([]);
|
|
359
|
+
const input: UpdateBy<NetworkSiteType> = updateBy({
|
|
360
|
+
parentNetworkSiteTypeId: typeId(4),
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
await (NetworkSiteTypeService as any).onBeforeUpdate(input);
|
|
364
|
+
|
|
365
|
+
expect(input.data.order).toBe(6);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it("accepts the relation-object parent spelling on update", async () => {
|
|
369
|
+
const parent: NetworkSiteType = makeType({ index: 4 });
|
|
370
|
+
mockParentUpdate({ parent });
|
|
371
|
+
jest.spyOn(NetworkSiteService, "findBy").mockResolvedValue([]);
|
|
372
|
+
|
|
373
|
+
await expect(
|
|
374
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
375
|
+
updateBy({ parentNetworkSiteType: parent }),
|
|
376
|
+
),
|
|
377
|
+
).resolves.toBeDefined();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it("rejects conflicting relation and ID values before reading target rows", async () => {
|
|
381
|
+
const findBySpy: jest.SpyInstance = jest.spyOn(
|
|
382
|
+
NetworkSiteTypeService,
|
|
383
|
+
"findBy",
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
await expect(
|
|
387
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
388
|
+
updateBy({
|
|
389
|
+
parentNetworkSiteTypeId: typeId(3),
|
|
390
|
+
parentNetworkSiteType: makeType({ index: 4 }),
|
|
391
|
+
}),
|
|
392
|
+
),
|
|
393
|
+
).rejects.toThrow("Conflicting parent Network Site Type references");
|
|
394
|
+
expect(findBySpy).not.toHaveBeenCalled();
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it("rejects self-parenting", async () => {
|
|
398
|
+
mockParentUpdate({ moving: makeType({ index: 2 }) });
|
|
399
|
+
|
|
400
|
+
await expect(
|
|
401
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
402
|
+
updateBy({ parentNetworkSiteTypeId: typeId(2) }),
|
|
403
|
+
),
|
|
404
|
+
).rejects.toThrow("cannot be its own parent");
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it("rejects moving a type under its direct child", async () => {
|
|
408
|
+
const moving: NetworkSiteType = makeType({ index: 2 });
|
|
409
|
+
const child: NetworkSiteType = makeType({
|
|
410
|
+
index: 3,
|
|
411
|
+
parentIndex: 2,
|
|
412
|
+
});
|
|
413
|
+
mockParentUpdate({
|
|
414
|
+
moving,
|
|
415
|
+
parent: child,
|
|
416
|
+
projectTypes: [moving, child],
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
await expect(
|
|
420
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
421
|
+
updateBy({ parentNetworkSiteTypeId: typeId(3) }),
|
|
422
|
+
),
|
|
423
|
+
).rejects.toThrow("cannot be moved under one of its descendants");
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it("rejects moving a type under a deeper descendant", async () => {
|
|
427
|
+
const moving: NetworkSiteType = makeType({ index: 2 });
|
|
428
|
+
const child: NetworkSiteType = makeType({ index: 3, parentIndex: 2 });
|
|
429
|
+
const grandchild: NetworkSiteType = makeType({
|
|
430
|
+
index: 4,
|
|
431
|
+
parentIndex: 3,
|
|
432
|
+
});
|
|
433
|
+
mockParentUpdate({
|
|
434
|
+
moving,
|
|
435
|
+
parent: grandchild,
|
|
436
|
+
projectTypes: [moving, child, grandchild],
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
await expect(
|
|
440
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
441
|
+
updateBy({ parentNetworkSiteTypeId: typeId(4) }),
|
|
442
|
+
),
|
|
443
|
+
).rejects.toThrow("cannot be moved under one of its descendants");
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it("rejects a missing, cross-project, or unit-level parent", async () => {
|
|
447
|
+
const cases: Array<{ parent: NetworkSiteType | null; message: string }> = [
|
|
448
|
+
{ parent: null, message: "not found" },
|
|
449
|
+
{
|
|
450
|
+
parent: makeType({ index: 4, projectId: OTHER_PROJECT_ID }),
|
|
451
|
+
message: "same project",
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
parent: makeType({ index: 4, isUnitLevel: true }),
|
|
455
|
+
message: "unit-level",
|
|
456
|
+
},
|
|
457
|
+
];
|
|
458
|
+
|
|
459
|
+
for (const testCase of cases) {
|
|
460
|
+
jest.restoreAllMocks();
|
|
461
|
+
mockParentUpdate({ parent: testCase.parent });
|
|
462
|
+
|
|
463
|
+
await expect(
|
|
464
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
465
|
+
updateBy({ parentNetworkSiteTypeId: typeId(4) }),
|
|
466
|
+
),
|
|
467
|
+
).rejects.toThrow(testCase.message);
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
it("allows detaching a type when all existing sites of that type are roots", async () => {
|
|
472
|
+
mockParentUpdate({});
|
|
473
|
+
jest
|
|
474
|
+
.spyOn(NetworkSiteService, "findBy")
|
|
475
|
+
.mockResolvedValue([makeSite({ index: 1, typeIndex: 2 })]);
|
|
476
|
+
|
|
477
|
+
await expect(
|
|
478
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
479
|
+
updateBy({ parentNetworkSiteTypeId: null }),
|
|
480
|
+
),
|
|
481
|
+
).resolves.toBeDefined();
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
it("rejects detaching a type while one of its sites still has a parent", async () => {
|
|
485
|
+
mockParentUpdate({});
|
|
486
|
+
jest
|
|
487
|
+
.spyOn(NetworkSiteService, "findBy")
|
|
488
|
+
.mockResolvedValue([
|
|
489
|
+
makeSite({ index: 1, typeIndex: 2, parentIndex: 10 }),
|
|
490
|
+
]);
|
|
491
|
+
|
|
492
|
+
await expect(
|
|
493
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
494
|
+
updateBy({ parentNetworkSiteTypeId: null }),
|
|
495
|
+
),
|
|
496
|
+
).rejects.toThrow(
|
|
497
|
+
"Create a new site type under the desired parent, then move and reassign the sites to it",
|
|
498
|
+
);
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
it("accepts a new parent type when every site's actual parent has that type", async () => {
|
|
502
|
+
mockParentUpdate({ parent: makeType({ index: 4 }) });
|
|
503
|
+
jest
|
|
504
|
+
.spyOn(NetworkSiteService, "findBy")
|
|
505
|
+
.mockImplementation(async (findBy: any) => {
|
|
506
|
+
if (findBy.query?._id) {
|
|
507
|
+
return [makeSite({ index: 10, typeIndex: 4 })];
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return [
|
|
511
|
+
makeSite({ index: 1, typeIndex: 2, parentIndex: 10 }),
|
|
512
|
+
makeSite({ index: 2, typeIndex: 2, parentIndex: 10 }),
|
|
513
|
+
];
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
await expect(
|
|
517
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
518
|
+
updateBy({ parentNetworkSiteTypeId: typeId(4) }),
|
|
519
|
+
),
|
|
520
|
+
).resolves.toBeDefined();
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
it("rejects a new parent when an existing site is root or its parent has another type", async () => {
|
|
524
|
+
const cases: Array<{
|
|
525
|
+
sites: Array<NetworkSite>;
|
|
526
|
+
parentSites: Array<NetworkSite>;
|
|
527
|
+
}> = [
|
|
528
|
+
{
|
|
529
|
+
sites: [makeSite({ index: 1, typeIndex: 2 })],
|
|
530
|
+
parentSites: [],
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
sites: [makeSite({ index: 1, typeIndex: 2, parentIndex: 10 })],
|
|
534
|
+
parentSites: [makeSite({ index: 10, typeIndex: 9 })],
|
|
535
|
+
},
|
|
536
|
+
];
|
|
537
|
+
|
|
538
|
+
for (const testCase of cases) {
|
|
539
|
+
jest.restoreAllMocks();
|
|
540
|
+
mockParentUpdate({ parent: makeType({ index: 4 }) });
|
|
541
|
+
jest
|
|
542
|
+
.spyOn(NetworkSiteService, "findBy")
|
|
543
|
+
.mockImplementation(async (findBy: any) => {
|
|
544
|
+
return findBy.query?._id ? testCase.parentSites : testCase.sites;
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
await expect(
|
|
548
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
549
|
+
updateBy({ parentNetworkSiteTypeId: typeId(4) }),
|
|
550
|
+
),
|
|
551
|
+
).rejects.toThrow("Create a new site type under the desired parent");
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
it("does not revalidate sites or reorder when the parent did not change", async () => {
|
|
556
|
+
const moving: NetworkSiteType = makeType({ index: 2, parentIndex: 4 });
|
|
557
|
+
mockParentUpdate({ moving, parent: makeType({ index: 4 }) });
|
|
558
|
+
const siteFindSpy: jest.SpyInstance = jest.spyOn(
|
|
559
|
+
NetworkSiteService,
|
|
560
|
+
"findBy",
|
|
561
|
+
);
|
|
562
|
+
const input: UpdateBy<NetworkSiteType> = updateBy({
|
|
563
|
+
parentNetworkSiteTypeId: typeId(4),
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
await (NetworkSiteTypeService as any).onBeforeUpdate(input);
|
|
567
|
+
|
|
568
|
+
expect(siteFindSpy).not.toHaveBeenCalled();
|
|
569
|
+
expect(input.data.order).toBeUndefined();
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
it("does no hierarchy reads for an update that touches neither parent nor unit-level", async () => {
|
|
573
|
+
const findBySpy: jest.SpyInstance = jest.spyOn(
|
|
574
|
+
NetworkSiteTypeService,
|
|
575
|
+
"findBy",
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
await expect(
|
|
579
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
580
|
+
updateBy({ name: "Renamed" }),
|
|
581
|
+
),
|
|
582
|
+
).resolves.toBeDefined();
|
|
583
|
+
expect(findBySpy).not.toHaveBeenCalled();
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
it("rejects a raw SQL isUnitLevel expression before it can bypass leaf validation", async () => {
|
|
587
|
+
const findBySpy: jest.SpyInstance = jest.spyOn(
|
|
588
|
+
NetworkSiteTypeService,
|
|
589
|
+
"findBy",
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
await expect(
|
|
593
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
594
|
+
updateBy({
|
|
595
|
+
isUnitLevel: () => {
|
|
596
|
+
return true;
|
|
597
|
+
},
|
|
598
|
+
}),
|
|
599
|
+
),
|
|
600
|
+
).rejects.toThrow("unit-level leaf rules must be validated");
|
|
601
|
+
expect(findBySpy).not.toHaveBeenCalled();
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it("reapplies the caller tenant before resolving rows matched by an update", async () => {
|
|
605
|
+
const findBySpy: jest.SpyInstance = jest
|
|
606
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
607
|
+
.mockResolvedValue([]);
|
|
608
|
+
|
|
609
|
+
await (NetworkSiteTypeService as any).onBeforeUpdate(
|
|
610
|
+
updateBy(
|
|
611
|
+
{ parentNetworkSiteTypeId: null },
|
|
612
|
+
{ tenantId: PROJECT_ID, isRoot: false },
|
|
613
|
+
),
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
expect(findBySpy.mock.calls[0]![0].query).toEqual(
|
|
617
|
+
expect.objectContaining({ projectId: PROJECT_ID }),
|
|
618
|
+
);
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
it("honors the update limit and skip when selecting rows to validate", async () => {
|
|
622
|
+
const findBySpy: jest.SpyInstance = jest
|
|
623
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
624
|
+
.mockResolvedValue([]);
|
|
625
|
+
const input: UpdateBy<NetworkSiteType> = updateBy({
|
|
626
|
+
parentNetworkSiteTypeId: null,
|
|
627
|
+
});
|
|
628
|
+
input.limit = new PositiveNumber(7);
|
|
629
|
+
input.skip = new PositiveNumber(3);
|
|
630
|
+
|
|
631
|
+
await (NetworkSiteTypeService as any).onBeforeUpdate(input);
|
|
632
|
+
|
|
633
|
+
expect(findBySpy).toHaveBeenCalledWith(
|
|
634
|
+
expect.objectContaining({ limit: 7, skip: 3 }),
|
|
635
|
+
);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
it("rejects making a type unit-level when it has child types", async () => {
|
|
639
|
+
const moving: NetworkSiteType = makeType({
|
|
640
|
+
index: 2,
|
|
641
|
+
isUnitLevel: false,
|
|
642
|
+
});
|
|
643
|
+
jest.spyOn(NetworkSiteTypeService, "findBy").mockResolvedValue([moving]);
|
|
644
|
+
jest
|
|
645
|
+
.spyOn(NetworkSiteTypeService, "findOneBy")
|
|
646
|
+
.mockResolvedValue(makeType({ index: 3, parentIndex: 2 }));
|
|
647
|
+
|
|
648
|
+
await expect(
|
|
649
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
650
|
+
updateBy({ isUnitLevel: true }),
|
|
651
|
+
),
|
|
652
|
+
).rejects.toThrow("with child types cannot be made unit-level");
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
it("rejects making a type unit-level when one of its sites has child sites", async () => {
|
|
656
|
+
const moving: NetworkSiteType = makeType({
|
|
657
|
+
index: 2,
|
|
658
|
+
isUnitLevel: false,
|
|
659
|
+
});
|
|
660
|
+
jest.spyOn(NetworkSiteTypeService, "findBy").mockResolvedValue([moving]);
|
|
661
|
+
jest.spyOn(NetworkSiteTypeService, "findOneBy").mockResolvedValue(null);
|
|
662
|
+
jest
|
|
663
|
+
.spyOn(NetworkSiteService, "findBy")
|
|
664
|
+
.mockResolvedValue([makeSite({ index: 1, typeIndex: 2 })]);
|
|
665
|
+
const childSiteFindSpy: jest.SpyInstance = jest
|
|
666
|
+
.spyOn(NetworkSiteService, "findOneBy")
|
|
667
|
+
.mockResolvedValue(makeSite({ index: 2, parentIndex: 1 }));
|
|
668
|
+
|
|
669
|
+
await expect(
|
|
670
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
671
|
+
updateBy({ isUnitLevel: true }),
|
|
672
|
+
),
|
|
673
|
+
).rejects.toThrow("whose sites have child sites cannot be made unit-level");
|
|
674
|
+
|
|
675
|
+
expect(childSiteFindSpy.mock.calls[0]![0].query.projectId).toBeDefined();
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
it("batches child-site checks when a type is used by more than 1,000 sites", async () => {
|
|
679
|
+
const moving: NetworkSiteType = makeType({
|
|
680
|
+
index: 2,
|
|
681
|
+
isUnitLevel: false,
|
|
682
|
+
});
|
|
683
|
+
jest.spyOn(NetworkSiteTypeService, "findBy").mockResolvedValue([moving]);
|
|
684
|
+
jest.spyOn(NetworkSiteTypeService, "findOneBy").mockResolvedValue(null);
|
|
685
|
+
jest.spyOn(NetworkSiteService, "findBy").mockResolvedValue(
|
|
686
|
+
Array.from({ length: 1001 }, (_value: unknown, index: number) => {
|
|
687
|
+
return makeSite({ index: index + 1, typeIndex: 2 });
|
|
688
|
+
}),
|
|
689
|
+
);
|
|
690
|
+
const childSiteFindSpy: jest.SpyInstance = jest
|
|
691
|
+
.spyOn(NetworkSiteService, "findOneBy")
|
|
692
|
+
.mockResolvedValueOnce(null)
|
|
693
|
+
.mockResolvedValueOnce(makeSite({ index: 2000, parentIndex: 1001 }));
|
|
694
|
+
|
|
695
|
+
await expect(
|
|
696
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
697
|
+
updateBy({ isUnitLevel: true }),
|
|
698
|
+
),
|
|
699
|
+
).rejects.toThrow("whose sites have child sites cannot be made unit-level");
|
|
700
|
+
|
|
701
|
+
expect(childSiteFindSpy).toHaveBeenCalledTimes(2);
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
it("does not rerun transition checks for a type that is already unit-level", async () => {
|
|
705
|
+
jest
|
|
706
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
707
|
+
.mockResolvedValue([makeType({ index: 2, isUnitLevel: true })]);
|
|
708
|
+
const childTypeFindSpy: jest.SpyInstance = jest.spyOn(
|
|
709
|
+
NetworkSiteTypeService,
|
|
710
|
+
"findOneBy",
|
|
711
|
+
);
|
|
712
|
+
const siteFindSpy: jest.SpyInstance = jest.spyOn(
|
|
713
|
+
NetworkSiteService,
|
|
714
|
+
"findBy",
|
|
715
|
+
);
|
|
716
|
+
|
|
717
|
+
await expect(
|
|
718
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
719
|
+
updateBy({ isUnitLevel: true }),
|
|
720
|
+
),
|
|
721
|
+
).resolves.toBeDefined();
|
|
722
|
+
|
|
723
|
+
expect(childTypeFindSpy).not.toHaveBeenCalled();
|
|
724
|
+
expect(siteFindSpy).not.toHaveBeenCalled();
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
it("validates site parent consistency beyond the first 10,000 rows", async () => {
|
|
728
|
+
mockParentUpdate({});
|
|
729
|
+
const rootSite: NetworkSite = makeSite({ index: 1, typeIndex: 2 });
|
|
730
|
+
const mismatch: NetworkSite = makeSite({
|
|
731
|
+
index: 2,
|
|
732
|
+
typeIndex: 2,
|
|
733
|
+
parentIndex: 10,
|
|
734
|
+
});
|
|
735
|
+
jest
|
|
736
|
+
.spyOn(NetworkSiteService, "findBy")
|
|
737
|
+
.mockImplementation(async (findBy: any) => {
|
|
738
|
+
if (findBy.skip === 0) {
|
|
739
|
+
return new Array<NetworkSite>(10_000).fill(rootSite);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return [mismatch];
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
await expect(
|
|
746
|
+
(NetworkSiteTypeService as any).onBeforeUpdate(
|
|
747
|
+
updateBy({ parentNetworkSiteTypeId: null }),
|
|
748
|
+
),
|
|
749
|
+
).rejects.toThrow("Create a new site type under the desired parent");
|
|
750
|
+
|
|
751
|
+
expect(NetworkSiteService.findBy).toHaveBeenCalledWith(
|
|
752
|
+
expect.objectContaining({ skip: 10_000 }),
|
|
753
|
+
);
|
|
754
|
+
});
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
describe("NetworkSiteTypeService deletion guards", () => {
|
|
758
|
+
function mockDeleteTarget(): jest.SpyInstance {
|
|
759
|
+
return jest
|
|
760
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
761
|
+
.mockImplementation(async (findBy: any) => {
|
|
762
|
+
return findBy.query?._id ? [makeType({ index: 2 })] : [];
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
it("rejects deleting a type used as another type's parent", async () => {
|
|
767
|
+
jest
|
|
768
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
769
|
+
.mockImplementation(async (findBy: any) => {
|
|
770
|
+
return findBy.query?._id
|
|
771
|
+
? [makeType({ index: 2 })]
|
|
772
|
+
: [makeType({ index: 3, parentIndex: 2 })];
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
await expect(
|
|
776
|
+
(NetworkSiteTypeService as any).onBeforeDelete(deleteBy()),
|
|
777
|
+
).rejects.toThrow("while child types use it as their parent");
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
it("rejects deleting a type used by a Network Site", async () => {
|
|
781
|
+
mockDeleteTarget();
|
|
782
|
+
jest
|
|
783
|
+
.spyOn(NetworkSiteService, "findOneBy")
|
|
784
|
+
.mockResolvedValue(makeSite({ index: 1, typeIndex: 2 }));
|
|
785
|
+
|
|
786
|
+
await expect(
|
|
787
|
+
(NetworkSiteTypeService as any).onBeforeDelete(deleteBy()),
|
|
788
|
+
).rejects.toThrow("while Network Sites use it");
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
it("allows deleting an unused leaf type", async () => {
|
|
792
|
+
const findBySpy: jest.SpyInstance = mockDeleteTarget();
|
|
793
|
+
jest.spyOn(NetworkSiteService, "findOneBy").mockResolvedValue(null);
|
|
794
|
+
|
|
795
|
+
await expect(
|
|
796
|
+
(NetworkSiteTypeService as any).onBeforeDelete(deleteBy()),
|
|
797
|
+
).resolves.toBeDefined();
|
|
798
|
+
|
|
799
|
+
const childQueryCall: Array<any> = findBySpy.mock.calls.find(
|
|
800
|
+
(call: Array<any>) => {
|
|
801
|
+
return Boolean(call[0].query?.parentNetworkSiteTypeId);
|
|
802
|
+
},
|
|
803
|
+
)!;
|
|
804
|
+
expect(childQueryCall[0].query.projectId).toBeDefined();
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
it("allows a parent and its child type to be deleted together", async () => {
|
|
808
|
+
const parent: NetworkSiteType = makeType({ index: 2 });
|
|
809
|
+
const child: NetworkSiteType = makeType({ index: 3, parentIndex: 2 });
|
|
810
|
+
jest
|
|
811
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
812
|
+
.mockImplementation(async (findBy: any) => {
|
|
813
|
+
return findBy.query?.parentNetworkSiteTypeId
|
|
814
|
+
? [child]
|
|
815
|
+
: [parent, child];
|
|
816
|
+
});
|
|
817
|
+
jest.spyOn(NetworkSiteService, "findOneBy").mockResolvedValue(null);
|
|
818
|
+
const input: DeleteBy<NetworkSiteType> = deleteBy();
|
|
819
|
+
input.query = { projectId: PROJECT_ID };
|
|
820
|
+
input.limit = new PositiveNumber(2);
|
|
821
|
+
|
|
822
|
+
await expect(
|
|
823
|
+
(NetworkSiteTypeService as any).onBeforeDelete(input),
|
|
824
|
+
).resolves.toBeDefined();
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
it("honors the delete limit and skip when determining the deletion set", async () => {
|
|
828
|
+
const findBySpy: jest.SpyInstance = jest
|
|
829
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
830
|
+
.mockImplementation(async (findBy: any) => {
|
|
831
|
+
return findBy.query?._id ? [makeType({ index: 2 })] : [];
|
|
832
|
+
});
|
|
833
|
+
jest.spyOn(NetworkSiteService, "findOneBy").mockResolvedValue(null);
|
|
834
|
+
const input: DeleteBy<NetworkSiteType> = deleteBy();
|
|
835
|
+
input.limit = new PositiveNumber(7);
|
|
836
|
+
input.skip = new PositiveNumber(3);
|
|
837
|
+
|
|
838
|
+
await (NetworkSiteTypeService as any).onBeforeDelete(input);
|
|
839
|
+
|
|
840
|
+
expect(findBySpy.mock.calls[0]![0]).toEqual(
|
|
841
|
+
expect.objectContaining({ limit: 7, skip: 3 }),
|
|
842
|
+
);
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
it("reapplies the caller tenant before resolving rows matched by a delete", async () => {
|
|
846
|
+
const findBySpy: jest.SpyInstance = jest
|
|
847
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
848
|
+
.mockResolvedValue([]);
|
|
849
|
+
|
|
850
|
+
await (NetworkSiteTypeService as any).onBeforeDelete(
|
|
851
|
+
deleteBy({ tenantId: PROJECT_ID, isRoot: false }),
|
|
852
|
+
);
|
|
853
|
+
|
|
854
|
+
expect(findBySpy.mock.calls[0]![0].query).toEqual(
|
|
855
|
+
expect.objectContaining({ projectId: PROJECT_ID }),
|
|
856
|
+
);
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
it("matches root delete preflight scoping when a tenant is supplied", async () => {
|
|
860
|
+
const findBySpy: jest.SpyInstance = jest
|
|
861
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
862
|
+
.mockResolvedValue([]);
|
|
863
|
+
|
|
864
|
+
await (NetworkSiteTypeService as any).onBeforeDelete(
|
|
865
|
+
deleteBy({ tenantId: PROJECT_ID, isRoot: true }),
|
|
866
|
+
);
|
|
867
|
+
|
|
868
|
+
expect(findBySpy.mock.calls[0]![0].query).toEqual(
|
|
869
|
+
expect.objectContaining({ projectId: PROJECT_ID }),
|
|
870
|
+
);
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
it("does not invent a tenant scope for a root multi-tenant delete preflight", async () => {
|
|
874
|
+
const findBySpy: jest.SpyInstance = jest
|
|
875
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
876
|
+
.mockResolvedValue([]);
|
|
877
|
+
|
|
878
|
+
await (NetworkSiteTypeService as any).onBeforeDelete(
|
|
879
|
+
deleteBy({
|
|
880
|
+
tenantId: PROJECT_ID,
|
|
881
|
+
isRoot: true,
|
|
882
|
+
isMultiTenantRequest: true,
|
|
883
|
+
}),
|
|
884
|
+
);
|
|
885
|
+
|
|
886
|
+
expect(findBySpy.mock.calls[0]![0].query.projectId).toBeUndefined();
|
|
887
|
+
});
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
describe("NetworkSiteTypeService hierarchy mutation lock", () => {
|
|
891
|
+
const runThroughLock: (data: {
|
|
892
|
+
operation: () => Promise<unknown>;
|
|
893
|
+
}) => Promise<unknown> = async (data: {
|
|
894
|
+
operation: () => Promise<unknown>;
|
|
895
|
+
}): Promise<unknown> => {
|
|
896
|
+
return await data.operation();
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
it("holds the shared project lock around create", async () => {
|
|
900
|
+
const created: NetworkSiteType = makeType({ index: 9 });
|
|
901
|
+
const runExclusiveSpy: jest.SpyInstance = jest
|
|
902
|
+
.spyOn(NetworkSiteHierarchyLock, "runExclusive")
|
|
903
|
+
.mockImplementation(runThroughLock as never);
|
|
904
|
+
const superCreateSpy: jest.SpyInstance = jest
|
|
905
|
+
.spyOn(DatabaseService.prototype, "create")
|
|
906
|
+
.mockResolvedValue(created);
|
|
907
|
+
|
|
908
|
+
await expect(NetworkSiteTypeService.create(createBy({}))).resolves.toBe(
|
|
909
|
+
created,
|
|
910
|
+
);
|
|
911
|
+
|
|
912
|
+
expect(runExclusiveSpy).toHaveBeenCalledWith(
|
|
913
|
+
expect.objectContaining({ projectIds: [PROJECT_ID] }),
|
|
914
|
+
);
|
|
915
|
+
expect(runExclusiveSpy.mock.invocationCallOrder[0]!).toBeLessThan(
|
|
916
|
+
superCreateSpy.mock.invocationCallOrder[0]!,
|
|
917
|
+
);
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
it.each([
|
|
921
|
+
["updateOneBy", { parentNetworkSiteTypeId: typeId(1) }],
|
|
922
|
+
["updateBy", { isUnitLevel: true }],
|
|
923
|
+
["updateOneBy", { projectId: PROJECT_ID }],
|
|
924
|
+
])(
|
|
925
|
+
"locks a hierarchy-changing %s",
|
|
926
|
+
async (method: string, data: Record<string, unknown>) => {
|
|
927
|
+
const runExclusiveSpy: jest.SpyInstance = jest
|
|
928
|
+
.spyOn(NetworkSiteHierarchyLock, "runExclusive")
|
|
929
|
+
.mockImplementation(runThroughLock as never);
|
|
930
|
+
const findBySpy: jest.SpyInstance = jest
|
|
931
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
932
|
+
.mockResolvedValue([makeType({ index: 2 })]);
|
|
933
|
+
const superMethodSpy: jest.SpyInstance = jest
|
|
934
|
+
.spyOn(DatabaseService.prototype as any, method)
|
|
935
|
+
.mockResolvedValue(1);
|
|
936
|
+
const input: Record<string, unknown> = {
|
|
937
|
+
query: { _id: typeId(2).toString() },
|
|
938
|
+
data,
|
|
939
|
+
props: { isRoot: true },
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
if (method === "updateBy") {
|
|
943
|
+
input["limit"] = new PositiveNumber(1);
|
|
944
|
+
input["skip"] = new PositiveNumber(0);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
await expect(
|
|
948
|
+
(NetworkSiteTypeService as any)[method](input),
|
|
949
|
+
).resolves.toBe(1);
|
|
950
|
+
|
|
951
|
+
expect(findBySpy).toHaveBeenCalledWith(
|
|
952
|
+
expect.objectContaining({ select: { projectId: true } }),
|
|
953
|
+
);
|
|
954
|
+
expect(runExclusiveSpy).toHaveBeenCalledWith(
|
|
955
|
+
expect.objectContaining({ projectIds: [PROJECT_ID] }),
|
|
956
|
+
);
|
|
957
|
+
expect(superMethodSpy).toHaveBeenCalledTimes(1);
|
|
958
|
+
},
|
|
959
|
+
);
|
|
960
|
+
|
|
961
|
+
it.each(["deleteOneBy", "deleteBy", "hardDeleteBy"])(
|
|
962
|
+
"locks %s and resolves all affected projects first",
|
|
963
|
+
async (method: string) => {
|
|
964
|
+
const runExclusiveSpy: jest.SpyInstance = jest
|
|
965
|
+
.spyOn(NetworkSiteHierarchyLock, "runExclusive")
|
|
966
|
+
.mockImplementation(runThroughLock as never);
|
|
967
|
+
jest
|
|
968
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
969
|
+
.mockResolvedValue([
|
|
970
|
+
makeType({ index: 2, projectId: OTHER_PROJECT_ID }),
|
|
971
|
+
makeType({ index: 3, projectId: PROJECT_ID }),
|
|
972
|
+
]);
|
|
973
|
+
const superMethodSpy: jest.SpyInstance = jest
|
|
974
|
+
.spyOn(DatabaseService.prototype as any, method)
|
|
975
|
+
.mockResolvedValue(2);
|
|
976
|
+
const input: Record<string, unknown> = {
|
|
977
|
+
query: { projectId: PROJECT_ID },
|
|
978
|
+
props: { isRoot: true },
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
if (method !== "deleteOneBy") {
|
|
982
|
+
input["limit"] = new PositiveNumber(2);
|
|
983
|
+
input["skip"] = new PositiveNumber(0);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
await expect(
|
|
987
|
+
(NetworkSiteTypeService as any)[method](input),
|
|
988
|
+
).resolves.toBe(2);
|
|
989
|
+
|
|
990
|
+
expect(runExclusiveSpy).toHaveBeenCalledWith(
|
|
991
|
+
expect.objectContaining({
|
|
992
|
+
projectIds: [OTHER_PROJECT_ID, PROJECT_ID],
|
|
993
|
+
}),
|
|
994
|
+
);
|
|
995
|
+
expect(superMethodSpy).toHaveBeenCalledTimes(1);
|
|
996
|
+
},
|
|
997
|
+
);
|
|
998
|
+
|
|
999
|
+
it("bypasses locking for unrelated updates and trusted ignoreHooks writes", async () => {
|
|
1000
|
+
const runExclusiveSpy: jest.SpyInstance = jest.spyOn(
|
|
1001
|
+
NetworkSiteHierarchyLock,
|
|
1002
|
+
"runExclusive",
|
|
1003
|
+
);
|
|
1004
|
+
jest.spyOn(DatabaseService.prototype, "updateOneBy").mockResolvedValue(1);
|
|
1005
|
+
jest
|
|
1006
|
+
.spyOn(DatabaseService.prototype, "create")
|
|
1007
|
+
.mockResolvedValue(makeType({ index: 7 }));
|
|
1008
|
+
|
|
1009
|
+
await NetworkSiteTypeService.updateOneBy({
|
|
1010
|
+
query: { _id: typeId(2).toString() },
|
|
1011
|
+
data: { name: "Renamed" },
|
|
1012
|
+
props: { isRoot: true },
|
|
1013
|
+
});
|
|
1014
|
+
await NetworkSiteTypeService.create({
|
|
1015
|
+
...createBy({}),
|
|
1016
|
+
props: { isRoot: true, ignoreHooks: true },
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
expect(runExclusiveSpy).not.toHaveBeenCalled();
|
|
1020
|
+
});
|
|
1021
|
+
|
|
1022
|
+
it("rejects an unscoped root hierarchy bulk mutation before writing", async () => {
|
|
1023
|
+
const superUpdateSpy: jest.SpyInstance = jest.spyOn(
|
|
1024
|
+
DatabaseService.prototype,
|
|
1025
|
+
"updateBy",
|
|
1026
|
+
);
|
|
1027
|
+
|
|
1028
|
+
await expect(
|
|
1029
|
+
NetworkSiteTypeService.updateBy({
|
|
1030
|
+
query: { name: "Any matching type" },
|
|
1031
|
+
data: { parentNetworkSiteTypeId: null },
|
|
1032
|
+
limit: new PositiveNumber(10),
|
|
1033
|
+
skip: new PositiveNumber(0),
|
|
1034
|
+
props: { isRoot: true },
|
|
1035
|
+
}),
|
|
1036
|
+
).rejects.toThrow(NETWORK_SITE_HIERARCHY_ROOT_SCOPE_ERROR_MESSAGE);
|
|
1037
|
+
|
|
1038
|
+
expect(superUpdateSpy).not.toHaveBeenCalled();
|
|
1039
|
+
});
|
|
1040
|
+
|
|
1041
|
+
it("rejects an open-ended root update even when root supplies tenantId", async () => {
|
|
1042
|
+
const superUpdateSpy: jest.SpyInstance = jest.spyOn(
|
|
1043
|
+
DatabaseService.prototype,
|
|
1044
|
+
"updateBy",
|
|
1045
|
+
);
|
|
1046
|
+
|
|
1047
|
+
await expect(
|
|
1048
|
+
NetworkSiteTypeService.updateBy({
|
|
1049
|
+
query: { name: "Any matching type" },
|
|
1050
|
+
data: { parentNetworkSiteTypeId: null },
|
|
1051
|
+
limit: new PositiveNumber(10),
|
|
1052
|
+
skip: new PositiveNumber(0),
|
|
1053
|
+
props: { isRoot: true, tenantId: PROJECT_ID },
|
|
1054
|
+
}),
|
|
1055
|
+
).rejects.toThrow(NETWORK_SITE_HIERARCHY_ROOT_SCOPE_ERROR_MESSAGE);
|
|
1056
|
+
|
|
1057
|
+
expect(superUpdateSpy).not.toHaveBeenCalled();
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1060
|
+
it("turns the retention cron's open root query into an unused leaf-only ID batch", async () => {
|
|
1061
|
+
const retentionQuery: any = { deletedAt: { olderThanThirtyDays: true } };
|
|
1062
|
+
const parent: NetworkSiteType = makeType({ index: 2 });
|
|
1063
|
+
const leaf: NetworkSiteType = makeType({ index: 3, parentIndex: 2 });
|
|
1064
|
+
const usedLeaf: NetworkSiteType = makeType({ index: 4 });
|
|
1065
|
+
|
|
1066
|
+
jest
|
|
1067
|
+
.spyOn(NetworkSiteTypeService, "findBy")
|
|
1068
|
+
.mockImplementation(async (findBy: any) => {
|
|
1069
|
+
if (findBy.query?.parentNetworkSiteTypeId) {
|
|
1070
|
+
return [leaf];
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
if (findBy.skip > 0) {
|
|
1074
|
+
return [];
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
return [parent, leaf, usedLeaf];
|
|
1078
|
+
});
|
|
1079
|
+
jest
|
|
1080
|
+
.spyOn(NetworkSiteService, "findBy")
|
|
1081
|
+
.mockResolvedValue([makeSite({ index: 1, typeIndex: 4 })]);
|
|
1082
|
+
const runExclusiveSpy: jest.SpyInstance = jest
|
|
1083
|
+
.spyOn(NetworkSiteHierarchyLock, "runExclusive")
|
|
1084
|
+
.mockImplementation(runThroughLock as never);
|
|
1085
|
+
const superHardDeleteSpy: jest.SpyInstance = jest
|
|
1086
|
+
.spyOn(DatabaseService.prototype, "hardDeleteBy")
|
|
1087
|
+
.mockResolvedValue(1);
|
|
1088
|
+
|
|
1089
|
+
await expect(
|
|
1090
|
+
NetworkSiteTypeService.hardDeleteBy({
|
|
1091
|
+
query: retentionQuery,
|
|
1092
|
+
limit: new PositiveNumber(3),
|
|
1093
|
+
skip: new PositiveNumber(0),
|
|
1094
|
+
props: { isRoot: true },
|
|
1095
|
+
} as DeleteBy<NetworkSiteType>),
|
|
1096
|
+
).resolves.toBe(1);
|
|
1097
|
+
|
|
1098
|
+
expect(runExclusiveSpy).toHaveBeenCalledWith(
|
|
1099
|
+
expect.objectContaining({ projectIds: [PROJECT_ID] }),
|
|
1100
|
+
);
|
|
1101
|
+
const closedDelete: any = superHardDeleteSpy.mock.calls[0]![0];
|
|
1102
|
+
expect(closedDelete.query.deletedAt).toBe(retentionQuery.deletedAt);
|
|
1103
|
+
expect(
|
|
1104
|
+
Object.values(closedDelete.query._id.objectLiteralParameters)[0],
|
|
1105
|
+
).toEqual([leaf.id!.toString()]);
|
|
1106
|
+
expect(closedDelete.limit).toBe(1);
|
|
1107
|
+
expect(closedDelete.skip).toBe(0);
|
|
1108
|
+
});
|
|
1109
|
+
});
|