@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,781 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_ROWS_IN_ROLLUP,
|
|
3
|
+
ROLLUP_PROJECT_NAME_MAX,
|
|
4
|
+
ROLLUP_SUBJECT_LEAD_TITLE_MAX,
|
|
5
|
+
ROLLUP_SUBJECT_MAX_CATEGORIES,
|
|
6
|
+
} from "./EmailRollupConstants";
|
|
7
|
+
import UserNotificationEmailRollupItem from "../../../Models/DatabaseModels/UserNotificationEmailRollupItem";
|
|
8
|
+
import Dictionary from "../../../Types/Dictionary";
|
|
9
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
10
|
+
import RollupCategory, {
|
|
11
|
+
ROLLUP_CATEGORY_LABEL,
|
|
12
|
+
ROLLUP_CATEGORY_ORDER,
|
|
13
|
+
} from "../../../Types/NotificationSetting/NotificationEmailRollupCategory";
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* Why this file exists: everything that turns a pile of deferred owner
|
|
17
|
+
* notifications into one readable email lives here, and nothing else does.
|
|
18
|
+
* It is pure and synchronous - no database, no awaits, no clock - so the
|
|
19
|
+
* flush runner can be tested for its claim/stamp/send ordering without
|
|
20
|
+
* caring about copy, and the copy can be tested without a database.
|
|
21
|
+
*
|
|
22
|
+
* THE ESCAPING CONTRACT, WHICH THE VARIABLE NAMES ENCODE.
|
|
23
|
+
*
|
|
24
|
+
* A variable whose name ends in `Html` is ALREADY ESCAPED here in TypeScript
|
|
25
|
+
* and is rendered by a triple-stache partial. Every other variable is RAW and
|
|
26
|
+
* is escaped by Handlebars at render time. Get this backwards in either
|
|
27
|
+
* direction and the failure is silent: a raw value in a triple stache is an
|
|
28
|
+
* XSS hole in somebody's mail client, and a pre-escaped value in a double
|
|
29
|
+
* stache shows the recipient a literal `<`.
|
|
30
|
+
*
|
|
31
|
+
* The mapping, verified against the partials themselves:
|
|
32
|
+
*
|
|
33
|
+
* rollupTitle raw {{> EmailTitle title=...}} -> {{title}}
|
|
34
|
+
* rollupIntroHtml pre-escaped {{> InfoBlock info=...}} -> {{{info}}}
|
|
35
|
+
* summaryCount raw our own summary card
|
|
36
|
+
* summaryWindow raw our own summary card
|
|
37
|
+
* categoryCounts raw our own summary card
|
|
38
|
+
* rows[].title raw our own table, {{this.title}}
|
|
39
|
+
* rows[].link raw our own table, href="{{this.link}}"
|
|
40
|
+
* rows[].hasLink raw {{#ifCond this.hasLink "true"}}
|
|
41
|
+
* rows[].metaLabel raw our own table, {{this.metaLabel}}
|
|
42
|
+
* rows[].isSectionStart raw {{#ifCond this.isSectionStart "true"}}
|
|
43
|
+
* rows[].sectionLabel raw our own section heading
|
|
44
|
+
* rows[].sectionCount raw our own section heading
|
|
45
|
+
* rows[].rowBackground raw our own table, style attribute
|
|
46
|
+
* hasMore raw {{#ifCond hasMore "true"}}
|
|
47
|
+
* moreTextHtml pre-escaped {{> InfoBlock info=...}} -> {{{info}}}
|
|
48
|
+
* projectHomeLink raw {{> ButtonBlock buttonUrl=...}}
|
|
49
|
+
* preferencesHtml pre-escaped {{> InfoBlock info=...}} -> {{{info}}}
|
|
50
|
+
* preferencesLink raw our own <a href="{{preferencesLink}}">
|
|
51
|
+
*
|
|
52
|
+
* The summary card and the section headings are OUR OWN markup rather than
|
|
53
|
+
* partials, so their text is rendered through double staches and stays RAW
|
|
54
|
+
* here. That is why categoryCounts lost its `Html` suffix in this revision:
|
|
55
|
+
* the name is the contract, and a pre-escaped value in the double stache it
|
|
56
|
+
* now reaches would show the recipient a literal `&amp;`.
|
|
57
|
+
*
|
|
58
|
+
* The pre-escaped variables carry PLAIN TEXT only - no markup of our own -
|
|
59
|
+
* so "contains no raw `<`" is a property a test can assert on all of them at
|
|
60
|
+
* once. Every visual decision lives in the template, where a designer can
|
|
61
|
+
* change it without reasoning about escaping.
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/*
|
|
65
|
+
* One folded resource: everything that happened to one incident, one monitor
|
|
66
|
+
* or one probe during the burst, as a single line the reader can act on.
|
|
67
|
+
*
|
|
68
|
+
* The times are milliseconds rather than formatted strings because the format
|
|
69
|
+
* is a decision about the WHOLE email - a rollup that spans two UTC days has
|
|
70
|
+
* to print the date on every row or on none - and a row cannot see the whole
|
|
71
|
+
* email. buildRollupEmail formats them once it can.
|
|
72
|
+
*/
|
|
73
|
+
export interface RollupRow {
|
|
74
|
+
title: string;
|
|
75
|
+
link: string;
|
|
76
|
+
hasLink: string;
|
|
77
|
+
itemCount: number;
|
|
78
|
+
category: RollupCategory;
|
|
79
|
+
firstAtMs: number;
|
|
80
|
+
latestAtMs: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface RollupEmailInput {
|
|
84
|
+
projectName: string;
|
|
85
|
+
projectHomeLink: string;
|
|
86
|
+
preferencesLink: string;
|
|
87
|
+
/*
|
|
88
|
+
* Sorted createdAt ASCENDING, the way the flush runner reads them back.
|
|
89
|
+
* Folding does not depend on that ordering - it compares createdAt - but
|
|
90
|
+
* the subject's lead title does, and so does the "last one wins" rule when
|
|
91
|
+
* two items in a group share a timestamp.
|
|
92
|
+
*/
|
|
93
|
+
items: Array<UserNotificationEmailRollupItem>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface RollupEmail {
|
|
97
|
+
subject: string;
|
|
98
|
+
vars: Dictionary<string | JSONObject>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type FoldItemsFunction = (
|
|
102
|
+
items: Array<UserNotificationEmailRollupItem>,
|
|
103
|
+
) => Array<RollupRow>;
|
|
104
|
+
|
|
105
|
+
export type BuildRollupEmailFunction = (input: RollupEmailInput) => RollupEmail;
|
|
106
|
+
|
|
107
|
+
type EscapeHtmlFunction = (value: string) => string;
|
|
108
|
+
|
|
109
|
+
/*
|
|
110
|
+
* Deliberately a local copy, matching the convention the identical function
|
|
111
|
+
* in WeeklyReadinessDigest.ts already establishes: an escape routine is small
|
|
112
|
+
* enough that duplicating it costs less than the coupling of exporting one,
|
|
113
|
+
* and a shared one invites a caller to escape twice.
|
|
114
|
+
*/
|
|
115
|
+
const escapeHtml: EscapeHtmlFunction = (value: string): string => {
|
|
116
|
+
return value
|
|
117
|
+
.replace(/&/g, "&")
|
|
118
|
+
.replace(/</g, "<")
|
|
119
|
+
.replace(/>/g, ">")
|
|
120
|
+
.replace(/"/g, """)
|
|
121
|
+
.replace(/'/g, "'");
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
type StripHandlebarsBracesFunction = (value: string) => string;
|
|
125
|
+
|
|
126
|
+
/*
|
|
127
|
+
* MailService compiles the SUBJECT through Handlebars as well as the body, so
|
|
128
|
+
* an incident titled "{{projectName}} is down" would otherwise be substituted
|
|
129
|
+
* away to nothing on its journey to the inbox. Stripping the braces is the
|
|
130
|
+
* cheapest fix that cannot itself break anything: the characters are removed,
|
|
131
|
+
* never interpreted.
|
|
132
|
+
*/
|
|
133
|
+
const stripHandlebarsBraces: StripHandlebarsBracesFunction = (
|
|
134
|
+
value: string,
|
|
135
|
+
): string => {
|
|
136
|
+
return value.replace(/\{\{/g, "").replace(/\}\}/g, "");
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
type TruncateFunction = (value: string, maxLength: number) => string;
|
|
140
|
+
|
|
141
|
+
/*
|
|
142
|
+
* The ellipsis replaces the last kept character rather than being appended,
|
|
143
|
+
* so the result is never longer than maxLength. Callers use this to stay
|
|
144
|
+
* under a column length or a sane subject length, and a truncation that
|
|
145
|
+
* overshoots its own limit by one character is exactly the kind of bug those
|
|
146
|
+
* limits exist to prevent.
|
|
147
|
+
*/
|
|
148
|
+
const truncate: TruncateFunction = (
|
|
149
|
+
value: string,
|
|
150
|
+
maxLength: number,
|
|
151
|
+
): string => {
|
|
152
|
+
if (value.length <= maxLength) {
|
|
153
|
+
return value;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (maxLength <= 1) {
|
|
157
|
+
return value.slice(0, Math.max(maxLength, 0));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return `${value.slice(0, maxLength - 1)}…`;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
type PluraliseFunction = (
|
|
164
|
+
count: number,
|
|
165
|
+
singular: string,
|
|
166
|
+
plural: string,
|
|
167
|
+
) => string;
|
|
168
|
+
|
|
169
|
+
const pluralise: PluraliseFunction = (
|
|
170
|
+
count: number,
|
|
171
|
+
singular: string,
|
|
172
|
+
plural: string,
|
|
173
|
+
): string => {
|
|
174
|
+
return count === 1 ? singular : plural;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
type NormaliseCategoryFunction = (value: string | undefined) => RollupCategory;
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* rollupCategory is a plain string column, so a row written by a newer build
|
|
181
|
+
* - or by a build that had a category this one has since removed - can carry
|
|
182
|
+
* a code this process has never heard of. Such a row still belongs in the
|
|
183
|
+
* counts; it just counts as Other rather than crashing the render of an email
|
|
184
|
+
* that is standing in for a hundred others.
|
|
185
|
+
*/
|
|
186
|
+
const normaliseCategory: NormaliseCategoryFunction = (
|
|
187
|
+
value: string | undefined,
|
|
188
|
+
): RollupCategory => {
|
|
189
|
+
if (
|
|
190
|
+
value !== undefined &&
|
|
191
|
+
Object.prototype.hasOwnProperty.call(ROLLUP_CATEGORY_LABEL, value)
|
|
192
|
+
) {
|
|
193
|
+
return value as RollupCategory;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return RollupCategory.Other;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
interface RollupGroup {
|
|
200
|
+
latestAt: number;
|
|
201
|
+
firstAt: number;
|
|
202
|
+
title: string;
|
|
203
|
+
link: string;
|
|
204
|
+
category: RollupCategory;
|
|
205
|
+
itemCount: number;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
interface CategoryCount {
|
|
209
|
+
label: string;
|
|
210
|
+
count: number;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/*
|
|
214
|
+
* Collapse the raw notification list into the rows a human reads.
|
|
215
|
+
*
|
|
216
|
+
* The fold key is the deep link ALONE when there is one, not the event type
|
|
217
|
+
* plus the link. That is the whole point: an incident's created,
|
|
218
|
+
* acknowledged and resolved emails all point at the same incident, so they
|
|
219
|
+
* become ONE row carrying the LATEST subject. A storm of 120 emails becomes
|
|
220
|
+
* roughly 40 rows, and each row is more accurate than any of the individual
|
|
221
|
+
* emails it replaces - every one of those was a stale snapshot by the time it
|
|
222
|
+
* was read, and the row is not.
|
|
223
|
+
*
|
|
224
|
+
* Items with no link have nothing to fold on but their own words, so they
|
|
225
|
+
* fold on event type plus subject. Two identical probe-flip notices collapse;
|
|
226
|
+
* two different ones stay apart.
|
|
227
|
+
*/
|
|
228
|
+
export const foldItems: FoldItemsFunction = (
|
|
229
|
+
items: Array<UserNotificationEmailRollupItem>,
|
|
230
|
+
): Array<RollupRow> => {
|
|
231
|
+
const groups: Map<string, RollupGroup> = new Map<string, RollupGroup>();
|
|
232
|
+
|
|
233
|
+
for (const item of items) {
|
|
234
|
+
const link: string = typeof item.viewLink === "string" ? item.viewLink : "";
|
|
235
|
+
const key: string =
|
|
236
|
+
link === "" ? `E:${item.eventType ?? ""}|${item.subject ?? ""}` : link;
|
|
237
|
+
const createdAtMs: number =
|
|
238
|
+
item.createdAt instanceof Date ? item.createdAt.getTime() : 0;
|
|
239
|
+
const existing: RollupGroup | undefined = groups.get(key);
|
|
240
|
+
|
|
241
|
+
if (!existing) {
|
|
242
|
+
groups.set(key, {
|
|
243
|
+
latestAt: createdAtMs,
|
|
244
|
+
firstAt: createdAtMs,
|
|
245
|
+
title: item.subject ?? "",
|
|
246
|
+
link: link,
|
|
247
|
+
category: normaliseCategory(item.rollupCategory),
|
|
248
|
+
itemCount: 1,
|
|
249
|
+
});
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
existing.itemCount = existing.itemCount + 1;
|
|
254
|
+
|
|
255
|
+
/*
|
|
256
|
+
* Tracked rather than assumed from input order. The flush runner reads its
|
|
257
|
+
* items back sorted ascending, so firstAt is almost always the first item
|
|
258
|
+
* seen - but "almost always" is not a property a row's own timestamp
|
|
259
|
+
* should depend on, and a Math.min costs nothing.
|
|
260
|
+
*/
|
|
261
|
+
if (createdAtMs < existing.firstAt) {
|
|
262
|
+
existing.firstAt = createdAtMs;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/*
|
|
266
|
+
* >= rather than > so that when a group's items share a timestamp the
|
|
267
|
+
* LAST one in input order wins, which is what "input is sorted ascending"
|
|
268
|
+
* is supposed to buy the reader.
|
|
269
|
+
*/
|
|
270
|
+
if (createdAtMs >= existing.latestAt) {
|
|
271
|
+
existing.latestAt = createdAtMs;
|
|
272
|
+
existing.title = item.subject ?? "";
|
|
273
|
+
existing.link = link;
|
|
274
|
+
/*
|
|
275
|
+
* The category follows the LATEST item too. A group is keyed on its deep
|
|
276
|
+
* link, and two events about one resource can in principle be filed
|
|
277
|
+
* under different categories - a monitor status change and the incident
|
|
278
|
+
* it declared both linking to the incident, say - so the section this
|
|
279
|
+
* row lands in is the one its newest event says, not the one its oldest
|
|
280
|
+
* happened to say.
|
|
281
|
+
*/
|
|
282
|
+
existing.category = normaliseCategory(item.rollupCategory);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const groupList: Array<RollupGroup> = Array.from(groups.values());
|
|
287
|
+
|
|
288
|
+
// Newest state first: the reader's eye lands on what is true right now.
|
|
289
|
+
groupList.sort((a: RollupGroup, b: RollupGroup): number => {
|
|
290
|
+
return b.latestAt - a.latestAt;
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
return groupList.map((group: RollupGroup): RollupRow => {
|
|
294
|
+
return {
|
|
295
|
+
title: group.title,
|
|
296
|
+
link: group.link,
|
|
297
|
+
hasLink: group.link === "" ? "false" : "true",
|
|
298
|
+
itemCount: group.itemCount,
|
|
299
|
+
category: group.category,
|
|
300
|
+
firstAtMs: group.firstAt,
|
|
301
|
+
latestAtMs: group.latestAt,
|
|
302
|
+
};
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const MONTH_NAMES: ReadonlyArray<string> = [
|
|
307
|
+
"Jan",
|
|
308
|
+
"Feb",
|
|
309
|
+
"Mar",
|
|
310
|
+
"Apr",
|
|
311
|
+
"May",
|
|
312
|
+
"Jun",
|
|
313
|
+
"Jul",
|
|
314
|
+
"Aug",
|
|
315
|
+
"Sep",
|
|
316
|
+
"Oct",
|
|
317
|
+
"Nov",
|
|
318
|
+
"Dec",
|
|
319
|
+
];
|
|
320
|
+
|
|
321
|
+
type PadFunction = (value: number) => string;
|
|
322
|
+
|
|
323
|
+
const pad: PadFunction = (value: number): string => {
|
|
324
|
+
return value < 10 ? `0${value}` : `${value}`;
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
type FormatTimeFunction = (ms: number, withDate: boolean) => string;
|
|
328
|
+
|
|
329
|
+
/*
|
|
330
|
+
* UTC, spelled out, and never the server's local time.
|
|
331
|
+
*
|
|
332
|
+
* The times in this email are the one piece of information the individual
|
|
333
|
+
* emails it replaces did not carry - each of those WAS its own timestamp,
|
|
334
|
+
* because it arrived when it happened, and a rollup that arrives minutes
|
|
335
|
+
* later owes the reader the difference. Getting the zone wrong turns that
|
|
336
|
+
* into a lie, and there are two ways to get it wrong: this process's TZ is a
|
|
337
|
+
* deployment detail that says nothing about where the recipient is, and the
|
|
338
|
+
* recipient's own timezone is not a thing this pure function is allowed to
|
|
339
|
+
* go and look up. An explicit "UTC" suffix is the honest answer, is the same
|
|
340
|
+
* for every recipient of the same storm - so two colleagues comparing inboxes
|
|
341
|
+
* see the same numbers - and is deterministic in a test.
|
|
342
|
+
*
|
|
343
|
+
* Intl is deliberately not used: it would pull the format from an ICU build
|
|
344
|
+
* that differs between the App image and a developer's laptop, and a rollup
|
|
345
|
+
* email is not the place to discover that.
|
|
346
|
+
*/
|
|
347
|
+
const formatTime: FormatTimeFunction = (
|
|
348
|
+
ms: number,
|
|
349
|
+
withDate: boolean,
|
|
350
|
+
): string => {
|
|
351
|
+
const date: Date = new Date(ms);
|
|
352
|
+
const clock: string = `${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}`;
|
|
353
|
+
|
|
354
|
+
if (!withDate) {
|
|
355
|
+
return `${clock} UTC`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return `${MONTH_NAMES[date.getUTCMonth()]} ${date.getUTCDate()}, ${clock} UTC`;
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
type SpansMultipleDaysFunction = (
|
|
362
|
+
earliestMs: number,
|
|
363
|
+
latestMs: number,
|
|
364
|
+
) => boolean;
|
|
365
|
+
|
|
366
|
+
/*
|
|
367
|
+
* True when the window crosses a UTC date boundary, in which case EVERY time
|
|
368
|
+
* in the email prints its date.
|
|
369
|
+
*
|
|
370
|
+
* A rollup normally covers ten minutes, so the date is noise. But a backlog
|
|
371
|
+
* that drained slowly, or a bucket that sat behind a wedged send, can carry
|
|
372
|
+
* items hours or days apart - and "14:22" against "09:03" with no date is
|
|
373
|
+
* actively misleading about which came first. The decision is made once, for
|
|
374
|
+
* the whole email, because a table where some rows carry a date and others do
|
|
375
|
+
* not is harder to read than either consistent choice.
|
|
376
|
+
*/
|
|
377
|
+
const spansMultipleDays: SpansMultipleDaysFunction = (
|
|
378
|
+
earliestMs: number,
|
|
379
|
+
latestMs: number,
|
|
380
|
+
): boolean => {
|
|
381
|
+
const earliest: Date = new Date(earliestMs);
|
|
382
|
+
const latest: Date = new Date(latestMs);
|
|
383
|
+
|
|
384
|
+
return (
|
|
385
|
+
earliest.getUTCFullYear() !== latest.getUTCFullYear() ||
|
|
386
|
+
earliest.getUTCMonth() !== latest.getUTCMonth() ||
|
|
387
|
+
earliest.getUTCDate() !== latest.getUTCDate()
|
|
388
|
+
);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
interface RollupSection {
|
|
392
|
+
category: RollupCategory;
|
|
393
|
+
label: string;
|
|
394
|
+
rows: Array<RollupRow>;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
type GroupRowsIntoSectionsFunction = (
|
|
398
|
+
rows: Array<RollupRow>,
|
|
399
|
+
) => Array<RollupSection>;
|
|
400
|
+
|
|
401
|
+
/*
|
|
402
|
+
* Split the rendered rows into the sections the email lists them under.
|
|
403
|
+
*
|
|
404
|
+
* Sections follow ROLLUP_CATEGORY_ORDER - fixed, urgency-first - and rows
|
|
405
|
+
* inside a section keep the newest-first order foldItems gave them. A
|
|
406
|
+
* category with no rows produces no section at all, so an email about one
|
|
407
|
+
* flapping probe is one heading, not eleven empty ones.
|
|
408
|
+
*/
|
|
409
|
+
const groupRowsIntoSections: GroupRowsIntoSectionsFunction = (
|
|
410
|
+
rows: Array<RollupRow>,
|
|
411
|
+
): Array<RollupSection> => {
|
|
412
|
+
const byCategory: Map<RollupCategory, Array<RollupRow>> = new Map<
|
|
413
|
+
RollupCategory,
|
|
414
|
+
Array<RollupRow>
|
|
415
|
+
>();
|
|
416
|
+
|
|
417
|
+
for (const row of rows) {
|
|
418
|
+
const existing: Array<RollupRow> | undefined = byCategory.get(row.category);
|
|
419
|
+
|
|
420
|
+
if (existing) {
|
|
421
|
+
existing.push(row);
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
byCategory.set(row.category, [row]);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const sections: Array<RollupSection> = [];
|
|
429
|
+
|
|
430
|
+
for (const category of ROLLUP_CATEGORY_ORDER) {
|
|
431
|
+
const sectionRows: Array<RollupRow> | undefined = byCategory.get(category);
|
|
432
|
+
|
|
433
|
+
if (!sectionRows || sectionRows.length === 0) {
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
sections.push({
|
|
438
|
+
category: category,
|
|
439
|
+
label: ROLLUP_CATEGORY_LABEL[category],
|
|
440
|
+
rows: sectionRows,
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
byCategory.delete(category);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/*
|
|
447
|
+
* ANYTHING ROLLUP_CATEGORY_ORDER FORGOT STILL GETS RENDERED, at the end.
|
|
448
|
+
*
|
|
449
|
+
* A category missing from that array is a bug, and the ratchet test exists
|
|
450
|
+
* to catch it - but the failure mode if one ever slips through must not be
|
|
451
|
+
* that a recipient's incidents quietly do not appear in an email whose one
|
|
452
|
+
* promise is that nothing was suppressed. Sorted by label so the output
|
|
453
|
+
* stays deterministic instead of depending on Map insertion order.
|
|
454
|
+
*/
|
|
455
|
+
const leftovers: Array<RollupSection> = Array.from(byCategory.entries()).map(
|
|
456
|
+
(entry: [RollupCategory, Array<RollupRow>]): RollupSection => {
|
|
457
|
+
return {
|
|
458
|
+
category: entry[0],
|
|
459
|
+
label:
|
|
460
|
+
ROLLUP_CATEGORY_LABEL[entry[0]] ??
|
|
461
|
+
ROLLUP_CATEGORY_LABEL[RollupCategory.Other],
|
|
462
|
+
rows: entry[1],
|
|
463
|
+
};
|
|
464
|
+
},
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
leftovers.sort((a: RollupSection, b: RollupSection): number => {
|
|
468
|
+
if (a.label === b.label) {
|
|
469
|
+
return 0;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return a.label < b.label ? -1 : 1;
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
return sections.concat(leftovers);
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
/*
|
|
479
|
+
* Build the subject and the complete Handlebars variable set for one rollup
|
|
480
|
+
* email. Every string the recipient sees is composed HERE, in TypeScript,
|
|
481
|
+
* because the `concat` helper the templates register takes exactly two
|
|
482
|
+
* arguments and silently drops the rest - a trap two shipped templates are
|
|
483
|
+
* standing in today. NotificationRollup.hbs therefore contains no `concat`
|
|
484
|
+
* call at all, and a test pins that.
|
|
485
|
+
*/
|
|
486
|
+
export const buildRollupEmail: BuildRollupEmailFunction = (
|
|
487
|
+
input: RollupEmailInput,
|
|
488
|
+
): RollupEmail => {
|
|
489
|
+
const items: Array<UserNotificationEmailRollupItem> = input.items;
|
|
490
|
+
const allRows: Array<RollupRow> = foldItems(items);
|
|
491
|
+
const rows: Array<RollupRow> = allRows.slice(0, MAX_ROWS_IN_ROLLUP);
|
|
492
|
+
const hiddenRowList: Array<RollupRow> = allRows.slice(rows.length);
|
|
493
|
+
const hiddenRows: number = hiddenRowList.length;
|
|
494
|
+
|
|
495
|
+
let hiddenItems: number = 0;
|
|
496
|
+
|
|
497
|
+
for (const row of hiddenRowList) {
|
|
498
|
+
hiddenItems = hiddenItems + row.itemCount;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/*
|
|
502
|
+
* Counted over ALL items, never over the rendered slice. A 300-item rollup
|
|
503
|
+
* that can only show 100 rows still tells the reader there were 300 things,
|
|
504
|
+
* because the whole promise of this email is that nothing was suppressed.
|
|
505
|
+
*/
|
|
506
|
+
const countsByCategory: Map<RollupCategory, number> = new Map<
|
|
507
|
+
RollupCategory,
|
|
508
|
+
number
|
|
509
|
+
>();
|
|
510
|
+
|
|
511
|
+
for (const item of items) {
|
|
512
|
+
const category: RollupCategory = normaliseCategory(item.rollupCategory);
|
|
513
|
+
|
|
514
|
+
countsByCategory.set(category, (countsByCategory.get(category) ?? 0) + 1);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const categoryCountList: Array<CategoryCount> = Array.from(
|
|
518
|
+
countsByCategory.entries(),
|
|
519
|
+
).map((entry: [RollupCategory, number]): CategoryCount => {
|
|
520
|
+
return {
|
|
521
|
+
label: ROLLUP_CATEGORY_LABEL[entry[0]],
|
|
522
|
+
count: entry[1],
|
|
523
|
+
};
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
categoryCountList.sort((a: CategoryCount, b: CategoryCount): number => {
|
|
527
|
+
if (a.count !== b.count) {
|
|
528
|
+
return b.count - a.count;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (a.label === b.label) {
|
|
532
|
+
return 0;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return a.label < b.label ? -1 : 1;
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
const categoryCounts: string = categoryCountList
|
|
539
|
+
.map((entry: CategoryCount): string => {
|
|
540
|
+
return `${entry.count} ${entry.label}`;
|
|
541
|
+
})
|
|
542
|
+
.join(" · ");
|
|
543
|
+
|
|
544
|
+
const projectName: string = truncate(
|
|
545
|
+
stripHandlebarsBraces(input.projectName || "your project"),
|
|
546
|
+
ROLLUP_PROJECT_NAME_MAX,
|
|
547
|
+
);
|
|
548
|
+
const notificationCount: number = items.length;
|
|
549
|
+
const notificationWord: string = pluralise(
|
|
550
|
+
notificationCount,
|
|
551
|
+
"notification",
|
|
552
|
+
"notifications",
|
|
553
|
+
);
|
|
554
|
+
|
|
555
|
+
const rollupTitle: string = `${notificationCount} ${notificationWord} from ${projectName}`;
|
|
556
|
+
|
|
557
|
+
/*
|
|
558
|
+
* THE TIME WINDOW, WHICH IS THE ONE THING THE INDIVIDUAL EMAILS ALREADY
|
|
559
|
+
* TOLD THE READER AND THIS EMAIL OTHERWISE WOULD NOT.
|
|
560
|
+
*
|
|
561
|
+
* Each of the forty emails this replaces arrived when its event happened,
|
|
562
|
+
* so its arrival time WAS its timestamp. One email that lands five minutes
|
|
563
|
+
* later has to say what period it covers, or a reader cannot tell a storm
|
|
564
|
+
* that ended twenty minutes ago from one still in progress.
|
|
565
|
+
*
|
|
566
|
+
* Empty items produce an empty window rather than a formatted epoch zero.
|
|
567
|
+
* buildRollupEmail is never called with none - the flush runner returns
|
|
568
|
+
* Empty before it gets here - but "1 Jan 1970" is a bad way to find that
|
|
569
|
+
* out, and the test suite calls it directly.
|
|
570
|
+
*/
|
|
571
|
+
const timestamps: Array<number> = allRows
|
|
572
|
+
.flatMap((row: RollupRow): Array<number> => {
|
|
573
|
+
return [row.firstAtMs, row.latestAtMs];
|
|
574
|
+
})
|
|
575
|
+
.filter((value: number): boolean => {
|
|
576
|
+
return value > 0;
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
const earliestMs: number =
|
|
580
|
+
timestamps.length === 0 ? 0 : Math.min(...timestamps);
|
|
581
|
+
const latestMs: number =
|
|
582
|
+
timestamps.length === 0 ? 0 : Math.max(...timestamps);
|
|
583
|
+
const withDate: boolean =
|
|
584
|
+
timestamps.length > 0 && spansMultipleDays(earliestMs, latestMs);
|
|
585
|
+
|
|
586
|
+
let summaryWindow: string = "";
|
|
587
|
+
|
|
588
|
+
if (timestamps.length > 0) {
|
|
589
|
+
const earliestLabel: string = formatTime(earliestMs, withDate);
|
|
590
|
+
const latestLabel: string = formatTime(latestMs, withDate);
|
|
591
|
+
|
|
592
|
+
summaryWindow =
|
|
593
|
+
earliestLabel === latestLabel
|
|
594
|
+
? earliestLabel
|
|
595
|
+
: `${earliestLabel} to ${latestLabel}`;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const summaryCount: string = `${notificationCount} ${notificationWord}`;
|
|
599
|
+
|
|
600
|
+
/*
|
|
601
|
+
* The intro says WHY this email exists; the summary card beside it says
|
|
602
|
+
* what is in it. Splitting the two that way is what keeps the count, the
|
|
603
|
+
* window and the category breakdown out of the prose, where they read as a
|
|
604
|
+
* paragraph nobody finishes, and in the card, where they are three lines
|
|
605
|
+
* the eye takes in at once.
|
|
606
|
+
*/
|
|
607
|
+
const rollupIntro: string =
|
|
608
|
+
notificationCount === 1
|
|
609
|
+
? `OneUptime grouped this notification from ${projectName} into a single email. Nothing was suppressed.`
|
|
610
|
+
: `OneUptime grouped these ${notificationCount} notifications from ${projectName} into a single email ` +
|
|
611
|
+
`instead of sending ${notificationCount} separate messages. Nothing was suppressed.`;
|
|
612
|
+
|
|
613
|
+
const moreText: string =
|
|
614
|
+
hiddenRows === 0
|
|
615
|
+
? ""
|
|
616
|
+
: `Showing the ${rows.length} most recent. ${hiddenRows} more ${pluralise(hiddenRows, "update", "updates")} ` +
|
|
617
|
+
`(covering ${hiddenItems} ${pluralise(hiddenItems, "notification", "notifications")}) ` +
|
|
618
|
+
`${pluralise(hiddenRows, "is", "are")} not listed here. Open the project to see everything.`;
|
|
619
|
+
|
|
620
|
+
/*
|
|
621
|
+
* The reader of this email did not ask for it, so the footer owes them the
|
|
622
|
+
* way out and not just an explanation. Rollup ships on with no preference,
|
|
623
|
+
* which means somebody who wants an email per event has no idea a switch
|
|
624
|
+
* exists unless this paragraph says so - and it is a per-project switch, so
|
|
625
|
+
* "for this project" is load-bearing rather than padding. It sits under the
|
|
626
|
+
* template's own heading, "Why did I get one email instead of several?",
|
|
627
|
+
* and ends in a colon because the preferencesLink is rendered immediately
|
|
628
|
+
* below it as the sentence's object.
|
|
629
|
+
*/
|
|
630
|
+
const preferencesText: string =
|
|
631
|
+
"OneUptime groups owner notifications into a single email when several arrive at once for the same project. " +
|
|
632
|
+
"To go back to one email per notification, sent the moment it happens, turn off email rollup for this project in your notification settings. " +
|
|
633
|
+
"The same page is where you choose which notifications you receive, or turn email off entirely:";
|
|
634
|
+
|
|
635
|
+
/*
|
|
636
|
+
* ONE FLAT ARRAY, WITH THE SECTION HEADING CARRIED ON ITS FIRST ROW.
|
|
637
|
+
*
|
|
638
|
+
* The alternative - nesting rows inside a sections array and using two
|
|
639
|
+
* {{#each}} blocks - reads better as data and worse as everything else. It
|
|
640
|
+
* needs a second `this.`-scope in the template, which the test that pins
|
|
641
|
+
* "the template reads no field the builder does not set" cannot then tell
|
|
642
|
+
* apart from the row scope; and a heading in its own <table> breaks the
|
|
643
|
+
* shared borders that make the list look like one list in Outlook. A flag
|
|
644
|
+
* on the first row of each section keeps the template to one loop and one
|
|
645
|
+
* scope, and keeps the whole list inside one <table>.
|
|
646
|
+
*/
|
|
647
|
+
const sections: Array<RollupSection> = groupRowsIntoSections(rows);
|
|
648
|
+
const rowsForTemplate: Array<JSONObject> = [];
|
|
649
|
+
|
|
650
|
+
for (const section of sections) {
|
|
651
|
+
/*
|
|
652
|
+
* THE HEADING COUNTS NOTIFICATIONS, NOT ROWS, so the numbers in this
|
|
653
|
+
* email reconcile instead of contradicting each other.
|
|
654
|
+
*
|
|
655
|
+
* A section of two incidents can carry five notifications - created,
|
|
656
|
+
* acknowledged and resolved for one, created and a note for the other -
|
|
657
|
+
* and a heading that said "2" beside a summary card saying "5 Incidents"
|
|
658
|
+
* would read as a bug in the email. Counting updates makes the heading
|
|
659
|
+
* the sum of its rows' own "3 updates" labels AND the matching entry in
|
|
660
|
+
* the card, which is the only version a reader can check.
|
|
661
|
+
*/
|
|
662
|
+
let sectionItemCount: number = 0;
|
|
663
|
+
|
|
664
|
+
for (const row of section.rows) {
|
|
665
|
+
sectionItemCount = sectionItemCount + row.itemCount;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
const sectionCount: string = `${sectionItemCount} ${pluralise(
|
|
669
|
+
sectionItemCount,
|
|
670
|
+
"update",
|
|
671
|
+
"updates",
|
|
672
|
+
)}`;
|
|
673
|
+
|
|
674
|
+
section.rows.forEach((row: RollupRow, index: number): void => {
|
|
675
|
+
/*
|
|
676
|
+
* The row's own timestamp, and the count of what folded into it. A
|
|
677
|
+
* single-update row says only when it happened; a folded one says how
|
|
678
|
+
* many updates there were and when the LATEST of them was, because the
|
|
679
|
+
* title it carries is that latest update's words.
|
|
680
|
+
*/
|
|
681
|
+
const timeLabel: string = formatTime(row.latestAtMs, withDate);
|
|
682
|
+
const metaLabel: string =
|
|
683
|
+
row.itemCount === 1
|
|
684
|
+
? timeLabel
|
|
685
|
+
: `${row.itemCount} updates · latest ${timeLabel}`;
|
|
686
|
+
|
|
687
|
+
rowsForTemplate.push({
|
|
688
|
+
title: row.title,
|
|
689
|
+
link: row.link,
|
|
690
|
+
hasLink: row.hasLink,
|
|
691
|
+
metaLabel: metaLabel,
|
|
692
|
+
/*
|
|
693
|
+
* The heading is emitted by the first row of the section rather than
|
|
694
|
+
* by an entry of its own, so every element of this array is a real
|
|
695
|
+
* row with a real title - an array with two shapes in it is how a
|
|
696
|
+
* heading ends up rendering an empty href.
|
|
697
|
+
*/
|
|
698
|
+
isSectionStart: index === 0 ? "true" : "false",
|
|
699
|
+
sectionLabel: section.label,
|
|
700
|
+
sectionCount: sectionCount,
|
|
701
|
+
/*
|
|
702
|
+
* The zebra stripe is decided here, not in the template. Handlebars
|
|
703
|
+
* has @index, @first, @last and @key but NOT @odd or @even, and an
|
|
704
|
+
* unknown @-variable resolves to undefined rather than erroring - so
|
|
705
|
+
* `{{#if @odd}}` is silently always false and every row comes out the
|
|
706
|
+
* same colour. Emitting the colour as a plain string cannot rot that
|
|
707
|
+
* way, and it keeps the arithmetic in the language that has some.
|
|
708
|
+
*
|
|
709
|
+
* The index is the row's position WITHIN ITS SECTION, so every
|
|
710
|
+
* section starts on white and the stripe reads as part of the section
|
|
711
|
+
* rather than as a pattern running underneath the headings.
|
|
712
|
+
*/
|
|
713
|
+
rowBackground: index % 2 === 1 ? "#f7f9fc" : "#ffffff",
|
|
714
|
+
});
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
const vars: Dictionary<string | JSONObject> = {
|
|
719
|
+
rollupTitle: rollupTitle,
|
|
720
|
+
rollupIntroHtml: escapeHtml(rollupIntro),
|
|
721
|
+
summaryCount: summaryCount,
|
|
722
|
+
summaryWindow: summaryWindow,
|
|
723
|
+
categoryCounts: categoryCounts,
|
|
724
|
+
/*
|
|
725
|
+
* Dictionary<string | JSONObject> does not accept a bare array, and every
|
|
726
|
+
* other template in the codebase that renders a table launders its rows
|
|
727
|
+
* through this same double cast.
|
|
728
|
+
*/
|
|
729
|
+
rows: rowsForTemplate as unknown as JSONObject,
|
|
730
|
+
hasMore: hiddenRows === 0 ? "false" : "true",
|
|
731
|
+
moreTextHtml: escapeHtml(moreText),
|
|
732
|
+
projectHomeLink: input.projectHomeLink,
|
|
733
|
+
preferencesHtml: escapeHtml(preferencesText),
|
|
734
|
+
preferencesLink: input.preferencesLink,
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
const leadTitle: string = truncate(
|
|
738
|
+
stripHandlebarsBraces(allRows[0]?.title ?? ""),
|
|
739
|
+
ROLLUP_SUBJECT_LEAD_TITLE_MAX,
|
|
740
|
+
);
|
|
741
|
+
|
|
742
|
+
/*
|
|
743
|
+
* THE SUBJECT SAYS WHAT KIND OF STORM THIS IS, not just how big it was.
|
|
744
|
+
*
|
|
745
|
+
* "[Acme] 15 notifications" is what a reader sees in a list of forty other
|
|
746
|
+
* subjects, and it does not distinguish a probe that flapped fifteen times
|
|
747
|
+
* - which can wait until after lunch - from three incidents and a monitor
|
|
748
|
+
* outage, which cannot. The categories are already counted for the summary
|
|
749
|
+
* card; spending them on the subject line costs nothing and is the only
|
|
750
|
+
* part of this email that gets read before it is opened.
|
|
751
|
+
*
|
|
752
|
+
* Sorted by count, so the biggest thing leads; capped, because a client
|
|
753
|
+
* truncates the tail at a width this code cannot see, and a truncation this
|
|
754
|
+
* code performs can at least say how much it left out.
|
|
755
|
+
*/
|
|
756
|
+
const namedCategories: Array<CategoryCount> = categoryCountList.slice(
|
|
757
|
+
0,
|
|
758
|
+
ROLLUP_SUBJECT_MAX_CATEGORIES,
|
|
759
|
+
);
|
|
760
|
+
const unnamedCategories: number =
|
|
761
|
+
categoryCountList.length - namedCategories.length;
|
|
762
|
+
const categorySummary: string = namedCategories
|
|
763
|
+
.map((entry: CategoryCount): string => {
|
|
764
|
+
return `${entry.count} ${entry.label}`;
|
|
765
|
+
})
|
|
766
|
+
.join(", ");
|
|
767
|
+
const subjectTail: string =
|
|
768
|
+
unnamedCategories === 0
|
|
769
|
+
? categorySummary
|
|
770
|
+
: `${categorySummary} +${unnamedCategories} more`;
|
|
771
|
+
|
|
772
|
+
const subject: string =
|
|
773
|
+
notificationCount === 1
|
|
774
|
+
? `[${projectName}] 1 notification: ${leadTitle}`
|
|
775
|
+
: `[${projectName}] ${notificationCount} notifications: ${subjectTail}`;
|
|
776
|
+
|
|
777
|
+
return {
|
|
778
|
+
subject: subject,
|
|
779
|
+
vars: vars,
|
|
780
|
+
};
|
|
781
|
+
};
|