@oneuptime/common 12.0.32 → 12.0.34
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/RumSession.ts +117 -1
- package/Models/AnalyticsModels/RumSessionChunk.ts +13 -0
- package/Models/AnalyticsModels/Span.ts +14 -0
- package/Models/DatabaseModels/AlertCustomField.ts +77 -3
- package/Models/DatabaseModels/ApiKeyPermission.ts +3 -27
- package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
- package/Models/DatabaseModels/IncidentCustomField.ts +77 -3
- package/Models/DatabaseModels/Index.ts +10 -0
- package/Models/DatabaseModels/InventoryItemCustomField.ts +77 -3
- package/Models/DatabaseModels/Monitor.ts +76 -0
- package/Models/DatabaseModels/MonitorCustomField.ts +77 -3
- 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/OnCallDutyPolicyCustomField.ts +77 -3
- package/Models/DatabaseModels/RumApplication.ts +6 -6
- package/Models/DatabaseModels/ScheduledMaintenanceCustomField.ts +77 -3
- package/Models/DatabaseModels/StatusPageCustomField.ts +77 -3
- package/Models/DatabaseModels/TeamCustomField.ts +77 -3
- package/Models/DatabaseModels/TeamMember.ts +0 -9
- package/Models/DatabaseModels/TeamMemberCustomField.ts +77 -3
- package/Models/DatabaseModels/TeamPermission.ts +3 -24
- package/Models/DatabaseModels/TelemetryException.ts +119 -0
- package/Models/DatabaseModels/TelemetryIngestionKey.ts +260 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
- package/Models/DatabaseModels/UserTelegram.ts +0 -4
- package/Scripts/benchmark-fanin-capacity.js +181 -0
- package/Server/API/EnterpriseLicenseAPI.ts +391 -64
- package/Server/API/LlmProviderAPI.ts +137 -22
- package/Server/API/TelemetryAPI.ts +1284 -164
- package/Server/API/UserNotificationSettingAPI.ts +55 -0
- package/Server/API/UserTelegramAPI.ts +48 -4
- package/Server/EnvironmentConfig.ts +49 -2
- 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/1791300000000-AddTelemetryIngestionKeyType.ts +91 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.ts +67 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.ts +139 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.ts +121 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +20 -0
- package/Server/Infrastructure/QueueWorker.ts +59 -23
- package/Server/Infrastructure/Semaphore.ts +2 -0
- 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 +464 -7
- package/Server/Services/AIBillingService.ts +101 -27
- package/Server/Services/AccessTokenService.ts +1 -0
- package/Server/Services/AlertCustomFieldService.ts +98 -0
- package/Server/Services/AlertService.ts +37 -0
- package/Server/Services/ApiKeyPermissionService.ts +461 -29
- package/Server/Services/CustomFieldMappingService.ts +879 -0
- package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
- package/Server/Services/EnterpriseLicenseService.ts +55 -0
- package/Server/Services/GlobalConfigService.ts +194 -0
- package/Server/Services/IncidentCustomFieldService.ts +98 -0
- package/Server/Services/IncidentService.ts +35 -0
- package/Server/Services/Index.ts +10 -0
- package/Server/Services/MetricService.ts +194 -0
- package/Server/Services/MonitorService.ts +175 -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 +87 -35
- 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 +127 -48
- package/Server/Services/RoutineEmailSettingsService.ts +73 -0
- package/Server/Services/RumSessionReplayViewService.ts +104 -24
- package/Server/Services/ScheduledMaintenanceCustomFieldService.ts +98 -0
- package/Server/Services/ScheduledMaintenanceService.ts +32 -0
- package/Server/Services/StatusPagePrivateUserService.ts +103 -3
- package/Server/Services/TeamMemberService.ts +78 -0
- package/Server/Services/TeamPermissionService.ts +235 -3
- package/Server/Services/TelemetryIngestionKeyService.ts +722 -19
- 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 +90 -25
- package/Server/Services/UserService.ts +95 -0
- package/Server/Services/UserTelegramService.ts +326 -5
- package/Server/Types/Database/QueryHelper.ts +4 -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/APIKey/AccessPermission.ts +5 -2
- package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
- package/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.ts +54 -0
- package/Server/Utils/CustomField/CustomFieldMappingRegistry.ts +415 -0
- package/Server/Utils/CustomField/CustomFieldMappingValidator.ts +335 -0
- package/Server/Utils/DataSource/EgressGuard.ts +177 -8
- package/Server/Utils/DataSource/HttpFetch.ts +9 -2
- package/Server/Utils/EmailRollup/EmailRollupConstants.ts +131 -0
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +925 -0
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
- package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
- package/Server/Utils/FrontendEnvironment.ts +40 -0
- package/Server/Utils/LLM/LLMService.ts +78 -0
- package/Server/Utils/LogRedaction.ts +28 -0
- package/Server/Utils/Logger.ts +90 -1
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +338 -77
- package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +30 -4
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
- package/Server/Utils/Monitor/MonitorAlert.ts +29 -6
- package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +159 -15
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
- package/Server/Utils/Monitor/MonitorIncident.ts +22 -6
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +72 -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/Monitor/SeriesContextEnricher.ts +304 -0
- 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/SSRFProtection.ts +217 -10
- package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +239 -138
- package/Server/Utils/SessionReplay/SessionReplayHealthCounters.ts +305 -0
- package/Server/Utils/SessionReplay/SessionReplayReadService.ts +1430 -289
- package/Server/Utils/StartServer.ts +53 -36
- package/Server/Utils/TelegramVerificationToken.ts +185 -0
- package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
- package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
- package/Server/Utils/Telemetry/PinServiceName.ts +197 -0
- package/Server/Utils/Telemetry/SpanUtil.ts +33 -0
- package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +38 -16
- package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +92 -0
- package/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.ts +217 -0
- package/Server/Utils/Telemetry.ts +198 -51
- package/Server/Utils/VM/VMAPI.ts +1 -0
- package/Server/Utils/VM/VMRunner.ts +975 -95
- package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
- package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +202 -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/DashboardHeaderSmallScreens.test.tsx +404 -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 +486 -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/NotificationEmailPreferences.test.tsx +399 -0
- 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/StatusPageLastUpdated.test.tsx +263 -0
- package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
- package/Tests/App/StatusPage/StatusPageOverviewLiveAndSearch.test.tsx +753 -0
- package/Tests/App/StatusPage/StatusPageResourceSearchBox.test.tsx +224 -0
- package/Tests/Models/AnalyticsModels/RumSessionReplayColumns.test.ts +262 -0
- package/Tests/Models/CustomFieldMappingColumns.test.ts +166 -0
- package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +20 -6
- package/Tests/Models/NetworkSiteHierarchy.test.ts +41 -4
- package/Tests/ResponsiveVisibility.test.ts +115 -0
- package/Tests/ResponsiveVisibility.ts +183 -0
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
- package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -0
- package/Tests/Server/API/SessionReplayAPI.test.ts +1940 -216
- package/Tests/Server/API/UserNotificationSettingAPI.test.ts +186 -0
- package/Tests/Server/API/UserTelegramAPISecurity.test.ts +231 -0
- package/Tests/Server/EnvironmentConfigFrontendSecurity.test.ts +234 -0
- package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +202 -0
- package/Tests/Server/Infrastructure/Postgres/InventoryItemArchiveMigration.test.ts +41 -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/SessionReplayRecordEverySessionByDefaultMigration.test.ts +169 -0
- package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -0
- package/Tests/Server/Infrastructure/QueueWorkerTimeout.test.ts +210 -0
- package/Tests/Server/Infrastructure/TelemetryExporterDeploymentConfig.test.ts +130 -0
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +4 -1
- package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +1163 -0
- package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +5 -3
- package/Tests/Server/Services/AIChatPrivacyPin.test.ts +560 -0
- package/Tests/Server/Services/AddTelemetryIngestionKeyTypeMigration.test.ts +555 -0
- package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +678 -0
- package/Tests/Server/Services/ApiKeyPermissionService.test.ts +276 -28
- package/Tests/Server/Services/BillingRechargeOwnerEmailGuards.test.ts +783 -0
- package/Tests/Server/Services/CustomFieldDropdownOptionsColumnWidth.test.ts +431 -0
- package/Tests/Server/Services/CustomFieldMappingService.test.ts +850 -0
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +32 -0
- package/Tests/Server/Services/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
- package/Tests/Server/Services/GlobalConfigService.test.ts +414 -1
- package/Tests/Server/Services/MetricRawEntityKeyPrune.test.ts +592 -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 +273 -5
- 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/RoutineEmailSettingsPostgres.test.ts +329 -0
- package/Tests/Server/Services/RumSessionReplayViewService.test.ts +267 -0
- package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +9 -0
- package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +9 -0
- package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +834 -0
- package/Tests/Server/Services/TelemetryIngestionKeyPolicyResolution.test.ts +814 -0
- package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +998 -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 +997 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +110 -1
- package/Tests/Server/Services/UserTelegramVerificationSecurity.test.ts +688 -0
- 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/AI/SRE/Insights/FixRouting.test.ts +497 -0
- package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +383 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +7 -3
- package/Tests/Server/Utils/AnalyticsDatabase/ClusterConfig.test.ts +315 -0
- package/Tests/Server/Utils/Captcha.test.ts +422 -0
- package/Tests/Server/Utils/CustomField/CustomFieldMappingValidator.test.ts +437 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +300 -11
- 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/EmailRollupBurstWindow.test.ts +83 -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/EmailRollupFlushRunnerPreferences.test.ts +362 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +828 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
- package/Tests/Server/Utils/FrontendEnvironment.test.ts +190 -0
- package/Tests/Server/Utils/LogRedaction.test.ts +26 -0
- package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +23 -9
- package/Tests/Server/Utils/LoggerFaultDemotion.test.ts +346 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +584 -0
- package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestHeaderCriteria.test.ts +236 -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/MonitorCriteriaEvaluator.test.ts +437 -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/MonitorTemplateUtilSeriesContext.test.ts +176 -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/Monitor/SeriesContextEnricher.test.ts +356 -0
- 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/SSRFProtectionCloudServiceAddresses.test.ts +595 -0
- package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +198 -1
- package/Tests/Server/Utils/SessionReplay/SessionReplayHealthCounters.test.ts +453 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1378 -0
- package/Tests/Server/Utils/SessionReplayOriginAllowListRefactor.test.ts +420 -0
- package/Tests/Server/Utils/TelegramVerificationToken.test.ts +253 -0
- package/Tests/Server/Utils/Telemetry/ErrorClassResolver.test.ts +298 -0
- package/Tests/Server/Utils/Telemetry/PinServiceName.test.ts +666 -0
- package/Tests/Server/Utils/Telemetry/TelemetryFanInWriterCapacity.test.ts +458 -0
- package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +424 -0
- package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.test.ts +528 -0
- package/Tests/Server/Utils/Telemetry.test.ts +456 -66
- package/Tests/Server/Utils/TelemetryExporterEnvironment.test.ts +56 -0
- package/Tests/Server/Utils/VM/VMRunnerHostBridgeLatency.test.ts +74 -0
- package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +100 -7
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +1176 -6
- package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +220 -0
- package/Tests/Types/CustomField/CustomFieldValueMapping.test.ts +348 -0
- package/Tests/Types/JSONFunctions.test.ts +260 -0
- package/Tests/Types/Monitor/CephAlertTemplates.test.ts +422 -53
- package/Tests/Types/Monitor/DatabaseMetricCatalog.test.ts +388 -0
- package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +495 -15
- package/Tests/Types/Monitor/DockerSwarmAlertTemplates.test.ts +191 -45
- package/Tests/Types/Monitor/HostAlertTemplates.test.ts +370 -42
- package/Tests/Types/Monitor/IotAlertTemplates.test.ts +375 -20
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +636 -42
- package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +189 -0
- package/Tests/Types/Monitor/KubernetesTemplateGroupByKeys.test.ts +95 -14
- 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/Monitor/PodmanAlertTemplates.test.ts +190 -21
- package/Tests/Types/Monitor/ProxmoxAlertTemplates.test.ts +352 -22
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationAlertDebuggability.test.ts +363 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +93 -18
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +259 -0
- package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +476 -0
- package/Tests/Types/Monitor/RumAlertTemplates.test.ts +136 -0
- package/Tests/Types/Monitor/SeriesContext/SeriesDebugHints.test.ts +661 -0
- package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +507 -0
- package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +270 -0
- package/Tests/Types/Monitor/TemplateGroupByKeys.test.ts +38 -10
- package/Tests/Types/Monitor/Utils/RecommendationCriteriaAssertions.ts +102 -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/NotificationSetting/RoutineEmailEvents.test.ts +47 -0
- package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +608 -0
- package/Tests/Types/Rum/SessionReplayCustomEvents.test.ts +434 -0
- package/Tests/Types/Telemetry/ErrorClass.test.ts +483 -0
- package/Tests/Types/WebsiteRequest.test.ts +285 -3
- package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
- package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +16 -3
- package/Tests/UI/Components/Charts/ChartTrailingBucketGap.test.ts +691 -0
- package/Tests/UI/Components/ComponentsModal.test.tsx +12 -4
- package/Tests/UI/Components/ComponentsModalUsability.test.tsx +518 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetailMapping.test.tsx +324 -0
- package/Tests/UI/Components/CustomFields/MapFromCustomFieldInput.test.tsx +176 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +484 -0
- package/Tests/UI/Components/HeaderRightRail.test.tsx +157 -0
- package/Tests/UI/Components/IconDropdownItem.test.tsx +102 -0
- package/Tests/UI/Components/JSONTablePrototypePollution.test.tsx +117 -0
- package/Tests/UI/Components/KeyboardShortcutsModal.test.tsx +214 -0
- package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +561 -0
- package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +302 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +43 -12
- package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
- package/Tests/UI/Components/ShortcutDialogGuard.test.tsx +74 -0
- 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/Components/StatusPage/ResourceGroupSectionAutoExpand.test.tsx +248 -0
- package/Tests/UI/Components/TableCellWrapping.test.tsx +625 -0
- package/Tests/UI/Components/TableLoadingStates.test.tsx +205 -0
- package/Tests/UI/Components/Workflow/NodePlacement.test.ts +148 -0
- package/Tests/UI/Components/Workflow/Workflow.test.tsx +981 -0
- package/Tests/UI/ConfigBrowserTelemetry.test.ts +70 -0
- package/Tests/UI/Rum/ChunkLoader.test.ts +1036 -2
- package/Tests/UI/Rum/FidelityNotices.test.ts +187 -0
- package/Tests/UI/Rum/InactivityMap.test.ts +341 -0
- package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +259 -0
- package/Tests/UI/Rum/RecordingHealthCard.test.tsx +855 -0
- package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +594 -0
- package/Tests/UI/Rum/ReplayCard.test.tsx +451 -0
- package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +536 -0
- package/Tests/UI/Rum/ReplayEngine.test.ts +2503 -0
- package/Tests/UI/Rum/ReplayEngineTypes.test.ts +171 -0
- package/Tests/UI/Rum/ReplayHeader.test.tsx +711 -0
- package/Tests/UI/Rum/ReplayLink.test.tsx +119 -0
- package/Tests/UI/Rum/ReplayPinControl.test.tsx +408 -0
- package/Tests/UI/Rum/ReplayPlaybackIntent.test.ts +152 -0
- package/Tests/UI/Rum/ReplayRail.test.tsx +1296 -0
- package/Tests/UI/Rum/ReplayRailDetail.test.tsx +900 -0
- package/Tests/UI/Rum/ReplayScrubber.test.tsx +763 -147
- package/Tests/UI/Rum/ReplaySignalTypes.test.ts +189 -0
- package/Tests/UI/Rum/ReplaySignals.test.ts +1579 -0
- package/Tests/UI/Rum/ReplayStage.test.tsx +396 -473
- package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +918 -0
- package/Tests/UI/Rum/ReplayTimeline.test.tsx +696 -0
- package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +499 -0
- package/Tests/UI/Rum/SessionReplaySearchBar.test.tsx +346 -0
- package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +545 -0
- package/Tests/UI/Rum/SessionReplayTable.test.tsx +991 -0
- package/Tests/UI/Rum/TargetedCapturePanel.test.tsx +254 -0
- package/Tests/UI/Telemetry/BrowserExporterIsolation.test.ts +71 -0
- package/Tests/UI/Utils/GlobalKeyboardShortcut.test.ts +344 -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/API.test.ts +308 -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/HTTPResponseBodyReader.test.ts +323 -0
- 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/DiscoveryScanStatus.test.ts +117 -0
- 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/Rum/ChunkMath.test.ts +83 -0
- package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +993 -0
- package/Tests/Utils/Rum/SessionReplayStringMap.test.ts +245 -0
- package/Tests/Utils/StatusPage/ResourceSearch.test.ts +631 -0
- package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
- package/Tests/Utils/Telemetry/OriginAllowList.test.ts +633 -0
- package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +461 -0
- package/Tests/Utils/ValueFormatter.test.ts +148 -0
- package/Types/AI/ExceptionAIClassification.ts +10 -24
- package/Types/CustomField/CustomFieldMappingCatalog.ts +161 -0
- package/Types/CustomField/CustomFieldMappingSourceResource.ts +19 -0
- package/Types/CustomField/CustomFieldValueMapping.ts +288 -0
- 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/Icon/IconProp.ts +1 -0
- package/Types/JSONFunctions.ts +189 -43
- package/Types/Monitor/CephAlertTemplates.ts +157 -195
- 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/DockerAlertTemplates.ts +338 -128
- package/Types/Monitor/DockerSwarmAlertTemplates.ts +95 -112
- package/Types/Monitor/HostAlertTemplates.ts +302 -130
- package/Types/Monitor/IotAlertTemplates.ts +112 -104
- package/Types/Monitor/KubernetesAlertTemplates.ts +415 -224
- package/Types/Monitor/KubernetesMetricCatalog.ts +23 -19
- 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/PodmanAlertTemplates.ts +116 -163
- package/Types/Monitor/ProxmoxAlertTemplates.ts +217 -99
- package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +98 -6
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +44 -7
- package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +383 -0
- package/Types/Monitor/RumAlertTemplates.ts +46 -7
- package/Types/Monitor/SeriesContext/SeriesDebugHints.ts +596 -0
- package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +554 -0
- package/Types/Monitor/ServiceAlertTemplates.ts +98 -11
- package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
- package/Types/Monitor/SqlConnectionConfig.ts +31 -0
- package/Types/Monitor/UptimeHistoryLabels.ts +56 -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/NotificationSetting/RoutineEmailEvents.ts +30 -0
- package/Types/Permission.ts +90 -0
- package/Types/Probe/ProbeMonitorResponse.ts +16 -0
- package/Types/Rum/SessionReplay.ts +209 -0
- package/Types/Rum/SessionReplayApi.ts +722 -0
- package/Types/Rum/SessionReplayCaptureTrigger.ts +21 -12
- package/Types/Rum/SessionReplayConsentMode.ts +11 -7
- package/Types/Rum/SessionReplayCustomEvents.ts +549 -0
- package/Types/Rum/SessionReplayHealth.ts +238 -0
- package/Types/Telemetry/ErrorClass.ts +274 -0
- package/Types/Telemetry/TelemetryIngestSurface.ts +95 -0
- package/Types/Telemetry/TelemetryIngestionKeyPolicy.ts +75 -0
- package/Types/Telemetry/TelemetryIngestionKeyType.ts +29 -0
- package/Types/Telemetry/UnitOfWork.ts +59 -0
- package/Types/WebsiteRequest.ts +85 -3
- package/UI/Components/Charts/Area/AreaChart.tsx +13 -2
- package/UI/Components/Charts/Bar/BarChart.tsx +6 -2
- package/UI/Components/Charts/Line/LineChart.tsx +13 -2
- package/UI/Components/Charts/Types/XAxis/XAxis.ts +29 -0
- package/UI/Components/Charts/Utils/DataPoint.ts +22 -3
- package/UI/Components/Charts/Utils/TimeAnnotation.ts +76 -9
- package/UI/Components/Charts/Utils/XAxis.ts +217 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +2 -8
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +143 -25
- package/UI/Components/CustomFields/MapFromCustomFieldInput.tsx +216 -0
- package/UI/Components/EditionLabel/EditionLabel.tsx +4 -0
- package/UI/Components/Graphs/DayUptimeGraph.tsx +173 -8
- package/UI/Components/Graphs/UptimeBarTooltip.tsx +22 -278
- package/UI/Components/Graphs/UptimeDaySummary.tsx +327 -0
- package/UI/Components/Header/Header.tsx +25 -9
- package/UI/Components/Header/IconDropdown/IconDropdownItem.tsx +10 -1
- package/UI/Components/Header/IconDropdown/IconDropdownMenu.tsx +6 -1
- package/UI/Components/Header/ProjectPicker/ProjectPicker.tsx +6 -1
- package/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.tsx +6 -1
- package/UI/Components/Icon/Icon.tsx +11 -0
- package/UI/Components/JSONTable/JSONTable.tsx +2 -2
- package/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.tsx +125 -0
- package/UI/Components/KeyboardShortcut/Screenshots/README.md +19 -0
- package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-command-palette.png +0 -0
- package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog-dark.png +0 -0
- package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog.png +0 -0
- package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-help-menu.png +0 -0
- package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-narrow.png +0 -0
- package/UI/Components/Modal/Modal.tsx +2 -8
- package/UI/Components/ModelTable/Column.ts +15 -0
- package/UI/Components/Monitor/SeriesDebugCommandsViewer.tsx +64 -0
- package/UI/Components/Monitor/SeriesLabelsViewer.tsx +93 -0
- package/UI/Components/MonitorGraphs/Uptime.tsx +14 -2
- package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +63 -10
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +88 -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/Components/StatusPage/ResourceGroupSection.tsx +40 -0
- package/UI/Components/Table/CellClassName.ts +81 -0
- package/UI/Components/Table/TableRow.tsx +20 -14
- package/UI/Components/Table/TableSkeletonRows.tsx +9 -9
- package/UI/Components/Table/Types/Column.ts +36 -0
- package/UI/Components/Tooltip/Tooltip.tsx +11 -1
- package/UI/Components/Workflow/ComponentsModal.tsx +60 -39
- package/UI/Components/Workflow/NodePlacement.ts +57 -0
- package/UI/Components/Workflow/Workflow.tsx +47 -18
- package/UI/Config.ts +15 -33
- package/UI/Utils/GlobalKeyboardShortcut.ts +208 -0
- package/UI/Utils/PageScrollLock.ts +79 -3
- package/UI/Utils/PermissionGate.ts +61 -0
- package/UI/Utils/SensitiveUrlToken.ts +112 -0
- package/UI/Utils/Telemetry/BrowserTelemetryConfig.ts +28 -0
- package/UI/Utils/Telemetry/Telemetry.ts +10 -8
- package/UI/Utils/TestLLMProvider.ts +11 -0
- package/Utils/API.ts +129 -3
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
- package/Utils/HTTPResponseBodyReader.ts +221 -0
- 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/DiscoveryScanStatus.ts +77 -0
- package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
- package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -0
- package/Utils/Rum/ChunkMath.ts +106 -0
- package/Utils/Rum/SessionReplayHealth.ts +732 -0
- package/Utils/Rum/SessionReplayStringMap.ts +226 -0
- package/Utils/Schema/ModelSchema.ts +1 -0
- package/Utils/StatusPage/ResourceSearch.ts +290 -0
- package/Utils/Telemetry/OriginAllowList.ts +355 -0
- package/Utils/Uptime/DayUptimeGraphUtil.ts +205 -0
- package/Utils/ValueFormatter.ts +35 -1
- package/build/dist/Models/AnalyticsModels/RumSession.js +102 -19
- package/build/dist/Models/AnalyticsModels/RumSession.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/RumSessionChunk.js +11 -9
- package/build/dist/Models/AnalyticsModels/RumSessionChunk.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Span.js +14 -0
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/AlertCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ApiKeyPermission.js +3 -27
- package/build/dist/Models/DatabaseModels/ApiKeyPermission.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/IncidentCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/IncidentCustomField.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/InventoryItemCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/InventoryItemCustomField.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/MonitorCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/MonitorCustomField.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/OnCallDutyPolicyCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js +6 -6
- package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/StatusPageCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/TeamCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamMember.js +0 -9
- package/build/dist/Models/DatabaseModels/TeamMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamPermission.js +3 -24
- package/build/dist/Models/DatabaseModels/TeamPermission.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +123 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +267 -0
- package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.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/Models/DatabaseModels/UserTelegram.js +0 -4
- package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
- 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/API/TelemetryAPI.js +769 -109
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/API/UserNotificationSettingAPI.js +35 -0
- package/build/dist/Server/API/UserNotificationSettingAPI.js.map +1 -0
- package/build/dist/Server/API/UserTelegramAPI.js +28 -6
- package/build/dist/Server/API/UserTelegramAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +41 -2
- 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/1791300000000-AddTelemetryIngestionKeyType.js +60 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js +53 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js +82 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js +46 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +52 -12
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +1 -0
- package/build/dist/Server/Infrastructure/Semaphore.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 +326 -8
- 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/AccessTokenService.js +1 -0
- package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
- package/build/dist/Server/Services/AlertCustomFieldService.js +93 -0
- package/build/dist/Server/Services/AlertCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +34 -0
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js +331 -28
- package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
- package/build/dist/Server/Services/CustomFieldMappingService.js +614 -0
- package/build/dist/Server/Services/CustomFieldMappingService.js.map +1 -0
- 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/GlobalConfigService.js +133 -0
- package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
- package/build/dist/Server/Services/IncidentCustomFieldService.js +93 -0
- package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +32 -0
- package/build/dist/Server/Services/IncidentService.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/MetricService.js +163 -0
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +148 -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 +89 -36
- 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 +88 -30
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RoutineEmailSettingsService.js +69 -0
- package/build/dist/Server/Services/RoutineEmailSettingsService.js.map +1 -0
- package/build/dist/Server/Services/RumSessionReplayViewService.js +86 -24
- package/build/dist/Server/Services/RumSessionReplayViewService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js +93 -0
- package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +29 -0
- package/build/dist/Server/Services/ScheduledMaintenanceService.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/TeamMemberService.js +62 -2
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamPermissionService.js +166 -3
- package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js +562 -18
- package/build/dist/Server/Services/TelemetryIngestionKeyService.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 +66 -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/Services/UserTelegramService.js +257 -4
- package/build/dist/Server/Services/UserTelegramService.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/APIKey/AccessPermission.js +2 -2
- package/build/dist/Server/Utils/APIKey/AccessPermission.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/CustomField/CustomFieldDefinitionMappingHooks.js +27 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js.map +1 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js +226 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js.map +1 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js +189 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +121 -7
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- 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 +124 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +733 -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/FrontendEnvironment.js +33 -0
- package/build/dist/Server/Utils/FrontendEnvironment.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 +28 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
- package/build/dist/Server/Utils/Logger.js +73 -1
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +287 -68
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.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/IncomingRequestCriteria.js +20 -4
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.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/MonitorAlert.js +29 -6
- package/build/dist/Server/Utils/Monitor/MonitorAlert.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 +125 -13
- 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/MonitorIncident.js +22 -6
- package/build/dist/Server/Utils/Monitor/MonitorIncident.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 +54 -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/Monitor/SeriesContextEnricher.js +237 -0
- package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js.map +1 -0
- 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/SSRFProtection.js +136 -9
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +174 -89
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js +223 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +945 -164
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +41 -28
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/TelegramVerificationToken.js +129 -0
- package/build/dist/Server/Utils/TelegramVerificationToken.js.map +1 -0
- 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/PinServiceName.js +163 -0
- package/build/dist/Server/Utils/Telemetry/PinServiceName.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/TelemetryFanInWriter.js +28 -15
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +64 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js +171 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry.js +162 -46
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +780 -69
- package/build/dist/Server/Utils/VM/VMRunner.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/CustomField/CustomFieldMappingCatalog.js +60 -0
- package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js +20 -0
- package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldValueMapping.js +141 -0
- package/build/dist/Types/CustomField/CustomFieldValueMapping.js.map +1 -0
- 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/Icon/IconProp.js +1 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +118 -37
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/Monitor/CephAlertTemplates.js +130 -171
- package/build/dist/Types/Monitor/CephAlertTemplates.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/DockerAlertTemplates.js +286 -121
- package/build/dist/Types/Monitor/DockerAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js +84 -105
- package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/HostAlertTemplates.js +250 -122
- package/build/dist/Types/Monitor/HostAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/IotAlertTemplates.js +81 -81
- package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +375 -215
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +19 -19
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
- 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/PodmanAlertTemplates.js +104 -153
- package/build/dist/Types/Monitor/PodmanAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +156 -91
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +67 -6
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +38 -7
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +261 -0
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -0
- package/build/dist/Types/Monitor/RumAlertTemplates.js +46 -7
- package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js +422 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js.map +1 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +441 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -0
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js +79 -15
- package/build/dist/Types/Monitor/ServiceAlertTemplates.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/Monitor/UptimeHistoryLabels.js +17 -0
- package/build/dist/Types/Monitor/UptimeHistoryLabels.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/NotificationSetting/RoutineEmailEvents.js +29 -0
- package/build/dist/Types/NotificationSetting/RoutineEmailEvents.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/Rum/SessionReplay.js +117 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayApi.js +181 -0
- package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js +21 -12
- package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayConsentMode.js +11 -7
- package/build/dist/Types/Rum/SessionReplayConsentMode.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayCustomEvents.js +172 -0
- package/build/dist/Types/Rum/SessionReplayCustomEvents.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayHealth.js +37 -0
- package/build/dist/Types/Rum/SessionReplayHealth.js.map +1 -0
- package/build/dist/Types/Telemetry/ErrorClass.js +216 -0
- package/build/dist/Types/Telemetry/ErrorClass.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +85 -0
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js +15 -0
- package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js +30 -0
- package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.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/Types/WebsiteRequest.js +55 -3
- package/build/dist/Types/WebsiteRequest.js.map +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +13 -2
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +6 -2
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +13 -2
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Types/XAxis/XAxis.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -3
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +40 -9
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/XAxis.js +186 -0
- package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
- 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/CustomFields/CustomFieldsDetail.js +80 -6
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js +118 -0
- package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js.map +1 -0
- 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/Graphs/DayUptimeGraph.js +112 -7
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -162
- package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
- package/build/dist/UI/Components/Graphs/UptimeDaySummary.js +181 -0
- package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -0
- package/build/dist/UI/Components/Header/Header.js +2 -3
- package/build/dist/UI/Components/Header/Header.js.map +1 -1
- package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js +2 -1
- package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js.map +1 -1
- package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js +7 -1
- package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js.map +1 -1
- package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js +7 -1
- package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js.map +1 -1
- package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js +7 -1
- package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +5 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/JSONTable/JSONTable.js +2 -2
- package/build/dist/UI/Components/JSONTable/JSONTable.js.map +1 -1
- package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js +35 -0
- package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js.map +1 -0
- 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/Monitor/SeriesDebugCommandsViewer.js +34 -0
- package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js.map +1 -0
- package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js +49 -0
- package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js.map +1 -0
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +32 -6
- package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +77 -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/Components/StatusPage/ResourceGroupSection.js +22 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -1
- package/build/dist/UI/Components/Table/CellClassName.js +55 -0
- package/build/dist/UI/Components/Table/CellClassName.js.map +1 -0
- package/build/dist/UI/Components/Table/TableRow.js +16 -13
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/Table/TableSkeletonRows.js +9 -8
- package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js +25 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentsModal.js +47 -30
- package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/NodePlacement.js +37 -0
- package/build/dist/UI/Components/Workflow/NodePlacement.js.map +1 -0
- package/build/dist/UI/Components/Workflow/Workflow.js +35 -18
- package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
- package/build/dist/UI/Config.js +10 -20
- package/build/dist/UI/Config.js.map +1 -1
- package/build/dist/UI/Utils/GlobalKeyboardShortcut.js +138 -0
- package/build/dist/UI/Utils/GlobalKeyboardShortcut.js.map +1 -0
- 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/Telemetry/BrowserTelemetryConfig.js +14 -0
- package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js.map +1 -0
- package/build/dist/UI/Utils/Telemetry/Telemetry.js +7 -5
- package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/UI/Utils/TestLLMProvider.js +4 -5
- package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -1
- package/build/dist/Utils/API.js +67 -5
- package/build/dist/Utils/API.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/HTTPResponseBodyReader.js +157 -0
- package/build/dist/Utils/HTTPResponseBodyReader.js.map +1 -0
- 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/DiscoveryScanStatus.js +69 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -0
- 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/build/dist/Utils/Rum/ChunkMath.js +76 -0
- package/build/dist/Utils/Rum/ChunkMath.js.map +1 -1
- package/build/dist/Utils/Rum/SessionReplayHealth.js +534 -0
- package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -0
- package/build/dist/Utils/Rum/SessionReplayStringMap.js +165 -0
- package/build/dist/Utils/Rum/SessionReplayStringMap.js.map +1 -0
- package/build/dist/Utils/Schema/ModelSchema.js +1 -0
- package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
- package/build/dist/Utils/StatusPage/ResourceSearch.js +200 -0
- package/build/dist/Utils/StatusPage/ResourceSearch.js.map +1 -0
- package/build/dist/Utils/Telemetry/OriginAllowList.js +299 -0
- package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -0
- package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +147 -0
- package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -0
- package/build/dist/Utils/ValueFormatter.js +32 -1
- package/build/dist/Utils/ValueFormatter.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,1428 @@
|
|
|
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 "../../../../Server/Utils/EmailRollup/EmailRollupConstants";
|
|
7
|
+
import {
|
|
8
|
+
RollupEmail,
|
|
9
|
+
RollupRow,
|
|
10
|
+
buildRollupEmail,
|
|
11
|
+
foldItems,
|
|
12
|
+
} from "../../../../Server/Utils/EmailRollup/EmailRollupRenderer";
|
|
13
|
+
import UserNotificationEmailRollupItem from "../../../../Models/DatabaseModels/UserNotificationEmailRollupItem";
|
|
14
|
+
import { JSONObject, JSONValue } from "../../../../Types/JSON";
|
|
15
|
+
import RollupCategory, {
|
|
16
|
+
ROLLUP_CATEGORY_LABEL,
|
|
17
|
+
ROLLUP_CATEGORY_ORDER,
|
|
18
|
+
} from "../../../../Types/NotificationSetting/NotificationEmailRollupCategory";
|
|
19
|
+
import NotificationSettingEventType from "../../../../Types/NotificationSetting/NotificationSettingEventType";
|
|
20
|
+
import { describe, expect, test } from "@jest/globals";
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* The rollup email is the ONLY thing a flooded recipient sees instead of the
|
|
24
|
+
* forty individual emails it replaces, so everything that can quietly ruin it
|
|
25
|
+
* is pinned here.
|
|
26
|
+
*
|
|
27
|
+
* What breaks in production if this regresses:
|
|
28
|
+
*
|
|
29
|
+
* - Fold on the wrong key and one incident's created / acknowledged /
|
|
30
|
+
* resolved emails stay three rows carrying three contradictory states,
|
|
31
|
+
* which is worse than the three separate emails were.
|
|
32
|
+
* - Count categories over the rendered slice instead of over every item and
|
|
33
|
+
* the email claims a 300-notification storm was 100 notifications, which
|
|
34
|
+
* breaks the one promise this feature makes: nothing was suppressed.
|
|
35
|
+
* - Get the escaping contract backwards and a resource title containing
|
|
36
|
+
* markup is either an XSS hole in a mail client or a wall of visible
|
|
37
|
+
* `<`. Both have already shipped in this repo's templates.
|
|
38
|
+
* - Leave the Handlebars braces in the subject and MailService, which
|
|
39
|
+
* compiles the subject as a template, substitutes an incident title away
|
|
40
|
+
* to an empty string on its way to the inbox.
|
|
41
|
+
* - Drop the opt-out from the footer copy and rollup becomes a thing that
|
|
42
|
+
* happens TO people: it is on by default with no preference, so this email
|
|
43
|
+
* is the only place a recipient who wants one email per event finds out
|
|
44
|
+
* they can have that back.
|
|
45
|
+
* - Stop alternating rowBackground and a hundred-row table is one flat wall
|
|
46
|
+
* of white, which is how it actually shipped: the template asked for
|
|
47
|
+
* {{#if @odd}}, a data variable Handlebars does not define.
|
|
48
|
+
*
|
|
49
|
+
* Pure and synchronous: no database, no clock, no mocks.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
const BASE_TIME_MS: number = Date.UTC(2026, 8, 3, 12, 0, 0);
|
|
53
|
+
|
|
54
|
+
type AtFunction = (offsetSeconds: number) => Date;
|
|
55
|
+
|
|
56
|
+
const at: AtFunction = (offsetSeconds: number): Date => {
|
|
57
|
+
return new Date(BASE_TIME_MS + offsetSeconds * 1000);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
interface ItemInput {
|
|
61
|
+
createdAt: Date;
|
|
62
|
+
subject: string;
|
|
63
|
+
eventType?: NotificationSettingEventType | undefined;
|
|
64
|
+
viewLink?: string | undefined;
|
|
65
|
+
rollupCategory?: RollupCategory | undefined;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type MakeItemFunction = (input: ItemInput) => UserNotificationEmailRollupItem;
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
* exactOptionalPropertyTypes is on, so an optional property is assigned only
|
|
72
|
+
* when there is something to assign - `item.viewLink = undefined` does not
|
|
73
|
+
* compile, and a linkless item is exactly the case the fold has to handle.
|
|
74
|
+
*/
|
|
75
|
+
const makeItem: MakeItemFunction = (
|
|
76
|
+
input: ItemInput,
|
|
77
|
+
): UserNotificationEmailRollupItem => {
|
|
78
|
+
const item: UserNotificationEmailRollupItem =
|
|
79
|
+
new UserNotificationEmailRollupItem();
|
|
80
|
+
|
|
81
|
+
item.createdAt = input.createdAt;
|
|
82
|
+
item.subject = input.subject;
|
|
83
|
+
item.eventType =
|
|
84
|
+
input.eventType ??
|
|
85
|
+
NotificationSettingEventType.SEND_INCIDENT_CREATED_OWNER_NOTIFICATION;
|
|
86
|
+
item.rollupCategory = input.rollupCategory ?? RollupCategory.Incidents;
|
|
87
|
+
|
|
88
|
+
if (input.viewLink !== undefined) {
|
|
89
|
+
item.viewLink = input.viewLink;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return item;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
type SortAscendingFunction = (
|
|
96
|
+
items: Array<UserNotificationEmailRollupItem>,
|
|
97
|
+
) => Array<UserNotificationEmailRollupItem>;
|
|
98
|
+
|
|
99
|
+
const sortAscending: SortAscendingFunction = (
|
|
100
|
+
items: Array<UserNotificationEmailRollupItem>,
|
|
101
|
+
): Array<UserNotificationEmailRollupItem> => {
|
|
102
|
+
return items
|
|
103
|
+
.slice()
|
|
104
|
+
.sort(
|
|
105
|
+
(
|
|
106
|
+
a: UserNotificationEmailRollupItem,
|
|
107
|
+
b: UserNotificationEmailRollupItem,
|
|
108
|
+
): number => {
|
|
109
|
+
return (a.createdAt?.getTime() ?? 0) - (b.createdAt?.getTime() ?? 0);
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
type BuildFunction = (
|
|
115
|
+
items: Array<UserNotificationEmailRollupItem>,
|
|
116
|
+
projectName?: string,
|
|
117
|
+
) => RollupEmail;
|
|
118
|
+
|
|
119
|
+
const build: BuildFunction = (
|
|
120
|
+
items: Array<UserNotificationEmailRollupItem>,
|
|
121
|
+
projectName: string = "Acme",
|
|
122
|
+
): RollupEmail => {
|
|
123
|
+
return buildRollupEmail({
|
|
124
|
+
projectName: projectName,
|
|
125
|
+
projectHomeLink: "https://oneuptime.example.com/dashboard/p1/home",
|
|
126
|
+
preferencesLink:
|
|
127
|
+
"https://oneuptime.example.com/dashboard/p1/user-settings/notification-settings",
|
|
128
|
+
items: sortAscending(items),
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
type VarStringFunction = (email: RollupEmail, name: string) => string;
|
|
133
|
+
|
|
134
|
+
/*
|
|
135
|
+
* Throws rather than stringifying, so a renamed variable fails the assertion
|
|
136
|
+
* that reads it instead of quietly comparing against "undefined".
|
|
137
|
+
*/
|
|
138
|
+
const varString: VarStringFunction = (
|
|
139
|
+
email: RollupEmail,
|
|
140
|
+
name: string,
|
|
141
|
+
): string => {
|
|
142
|
+
const value: string | JSONObject | undefined = email.vars[name];
|
|
143
|
+
|
|
144
|
+
if (typeof value !== "string") {
|
|
145
|
+
throw new Error(`Template var "${name}" is not a string`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return value;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
type VarRowsFunction = (email: RollupEmail) => Array<JSONObject>;
|
|
152
|
+
|
|
153
|
+
const varRows: VarRowsFunction = (email: RollupEmail): Array<JSONObject> => {
|
|
154
|
+
return email.vars["rows"] as unknown as Array<JSONObject>;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
type RowFieldFunction = (row: JSONObject, name: string) => string;
|
|
158
|
+
|
|
159
|
+
const rowField: RowFieldFunction = (row: JSONObject, name: string): string => {
|
|
160
|
+
const value: JSONValue | undefined = row[name];
|
|
161
|
+
|
|
162
|
+
if (typeof value !== "string") {
|
|
163
|
+
throw new Error(`Row field "${name}" is not a string`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return value;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/*
|
|
170
|
+
* The vars the template hands to a TRIPLE stache. These carry plain text that
|
|
171
|
+
* this builder has already escaped.
|
|
172
|
+
*/
|
|
173
|
+
const HTML_VAR_NAMES: Array<string> = [
|
|
174
|
+
"rollupIntroHtml",
|
|
175
|
+
"moreTextHtml",
|
|
176
|
+
"preferencesHtml",
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* The vars the template renders through a DOUBLE stache, where Handlebars
|
|
181
|
+
* escapes them. These must arrive RAW - pre-escaping one would show the
|
|
182
|
+
* recipient a literal "&amp;".
|
|
183
|
+
*
|
|
184
|
+
* categoryCounts is the one that moved between the two lists when the summary
|
|
185
|
+
* card replaced the TitleBlock the counts used to be rendered through, which
|
|
186
|
+
* is exactly the kind of change that ships a wall of "&quot;" to
|
|
187
|
+
* everybody, so both lists are pinned rather than only the escaped one.
|
|
188
|
+
*/
|
|
189
|
+
const RAW_VAR_NAMES: Array<string> = [
|
|
190
|
+
"rollupTitle",
|
|
191
|
+
"summaryCount",
|
|
192
|
+
"summaryWindow",
|
|
193
|
+
"categoryCounts",
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
describe("foldItems", () => {
|
|
197
|
+
test("four items sharing one view link fold to one row carrying the latest subject", () => {
|
|
198
|
+
const link: string =
|
|
199
|
+
"https://oneuptime.example.com/dashboard/p1/incidents/i1";
|
|
200
|
+
|
|
201
|
+
const rows: Array<RollupRow> = foldItems(
|
|
202
|
+
sortAscending([
|
|
203
|
+
makeItem({
|
|
204
|
+
createdAt: at(0),
|
|
205
|
+
subject: "Checkout is down",
|
|
206
|
+
viewLink: link,
|
|
207
|
+
}),
|
|
208
|
+
makeItem({
|
|
209
|
+
createdAt: at(60),
|
|
210
|
+
subject: "Checkout is down - acknowledged",
|
|
211
|
+
viewLink: link,
|
|
212
|
+
}),
|
|
213
|
+
makeItem({
|
|
214
|
+
createdAt: at(120),
|
|
215
|
+
subject: "Checkout is down - investigating",
|
|
216
|
+
viewLink: link,
|
|
217
|
+
}),
|
|
218
|
+
makeItem({
|
|
219
|
+
createdAt: at(180),
|
|
220
|
+
subject: "Checkout is down - resolved",
|
|
221
|
+
viewLink: link,
|
|
222
|
+
}),
|
|
223
|
+
]),
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
expect(rows).toHaveLength(1);
|
|
227
|
+
expect(rows[0]!.title).toBe("Checkout is down - resolved");
|
|
228
|
+
expect(rows[0]!.itemCount).toBe(4);
|
|
229
|
+
expect(rows[0]!.itemCount).toBe(4);
|
|
230
|
+
expect(rows[0]!.link).toBe(link);
|
|
231
|
+
expect(rows[0]!.hasLink).toBe("true");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test("the fold key is the link ALONE, so a different event type on the same resource still folds", () => {
|
|
235
|
+
const link: string =
|
|
236
|
+
"https://oneuptime.example.com/dashboard/p1/incidents/i1";
|
|
237
|
+
|
|
238
|
+
const rows: Array<RollupRow> = foldItems(
|
|
239
|
+
sortAscending([
|
|
240
|
+
makeItem({
|
|
241
|
+
createdAt: at(0),
|
|
242
|
+
subject: "Incident created",
|
|
243
|
+
viewLink: link,
|
|
244
|
+
eventType:
|
|
245
|
+
NotificationSettingEventType.SEND_INCIDENT_CREATED_OWNER_NOTIFICATION,
|
|
246
|
+
}),
|
|
247
|
+
makeItem({
|
|
248
|
+
createdAt: at(60),
|
|
249
|
+
subject: "Incident state changed",
|
|
250
|
+
viewLink: link,
|
|
251
|
+
eventType:
|
|
252
|
+
NotificationSettingEventType.SEND_INCIDENT_STATE_CHANGED_OWNER_NOTIFICATION,
|
|
253
|
+
}),
|
|
254
|
+
]),
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
expect(rows).toHaveLength(1);
|
|
258
|
+
expect(rows[0]!.title).toBe("Incident state changed");
|
|
259
|
+
expect(rows[0]!.itemCount).toBe(2);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test("two different links produce two rows, newest group first", () => {
|
|
263
|
+
const older: string =
|
|
264
|
+
"https://oneuptime.example.com/dashboard/p1/alerts/a1";
|
|
265
|
+
const newer: string =
|
|
266
|
+
"https://oneuptime.example.com/dashboard/p1/incidents/i9";
|
|
267
|
+
|
|
268
|
+
const rows: Array<RollupRow> = foldItems(
|
|
269
|
+
sortAscending([
|
|
270
|
+
makeItem({ createdAt: at(0), subject: "Old alert", viewLink: older }),
|
|
271
|
+
makeItem({
|
|
272
|
+
createdAt: at(30),
|
|
273
|
+
subject: "Old alert again",
|
|
274
|
+
viewLink: older,
|
|
275
|
+
}),
|
|
276
|
+
makeItem({
|
|
277
|
+
createdAt: at(600),
|
|
278
|
+
subject: "Fresh incident",
|
|
279
|
+
viewLink: newer,
|
|
280
|
+
}),
|
|
281
|
+
]),
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
expect(rows).toHaveLength(2);
|
|
285
|
+
expect(rows[0]!.title).toBe("Fresh incident");
|
|
286
|
+
expect(rows[0]!.itemCount).toBe(1);
|
|
287
|
+
expect(rows[1]!.title).toBe("Old alert again");
|
|
288
|
+
expect(rows[1]!.itemCount).toBe(2);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test("items with no view link fold on event type plus subject", () => {
|
|
292
|
+
const rows: Array<RollupRow> = foldItems(
|
|
293
|
+
sortAscending([
|
|
294
|
+
makeItem({
|
|
295
|
+
createdAt: at(0),
|
|
296
|
+
subject: "Probe eu-west is disconnected",
|
|
297
|
+
eventType:
|
|
298
|
+
NotificationSettingEventType.SEND_PROBE_STATUS_CHANGED_OWNER_NOTIFICATION,
|
|
299
|
+
rollupCategory: RollupCategory.Probes,
|
|
300
|
+
}),
|
|
301
|
+
makeItem({
|
|
302
|
+
createdAt: at(60),
|
|
303
|
+
subject: "Probe eu-west is disconnected",
|
|
304
|
+
eventType:
|
|
305
|
+
NotificationSettingEventType.SEND_PROBE_STATUS_CHANGED_OWNER_NOTIFICATION,
|
|
306
|
+
rollupCategory: RollupCategory.Probes,
|
|
307
|
+
}),
|
|
308
|
+
makeItem({
|
|
309
|
+
createdAt: at(120),
|
|
310
|
+
subject: "Probe us-east is disconnected",
|
|
311
|
+
eventType:
|
|
312
|
+
NotificationSettingEventType.SEND_PROBE_STATUS_CHANGED_OWNER_NOTIFICATION,
|
|
313
|
+
rollupCategory: RollupCategory.Probes,
|
|
314
|
+
}),
|
|
315
|
+
/*
|
|
316
|
+
* Same words, different event: these are two genuinely different
|
|
317
|
+
* notices and must not be collapsed into one line.
|
|
318
|
+
*/
|
|
319
|
+
makeItem({
|
|
320
|
+
createdAt: at(180),
|
|
321
|
+
subject: "Probe us-east is disconnected",
|
|
322
|
+
eventType:
|
|
323
|
+
NotificationSettingEventType.SEND_PROBE_OWNER_ADDED_NOTIFICATION,
|
|
324
|
+
rollupCategory: RollupCategory.Probes,
|
|
325
|
+
}),
|
|
326
|
+
]),
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
const counts: Array<number> = rows.map((row: RollupRow): number => {
|
|
330
|
+
return row.itemCount;
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
expect(rows).toHaveLength(3);
|
|
334
|
+
expect(counts).toEqual([1, 1, 2]);
|
|
335
|
+
expect(
|
|
336
|
+
rows.every((row: RollupRow): boolean => {
|
|
337
|
+
return row.hasLink === "false" && row.link === "";
|
|
338
|
+
}),
|
|
339
|
+
).toBe(true);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test("an empty list folds to no rows", () => {
|
|
343
|
+
expect(foldItems([])).toEqual([]);
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
describe("buildRollupEmail category counts", () => {
|
|
348
|
+
test("counts every item, not the rendered slice: 300 items, 100 rows, 300 counted", () => {
|
|
349
|
+
const items: Array<UserNotificationEmailRollupItem> = [];
|
|
350
|
+
|
|
351
|
+
for (let index: number = 0; index < 300; index++) {
|
|
352
|
+
items.push(
|
|
353
|
+
makeItem({
|
|
354
|
+
createdAt: at(index),
|
|
355
|
+
subject: `Event ${index}`,
|
|
356
|
+
viewLink: `https://oneuptime.example.com/dashboard/p1/r/${index}`,
|
|
357
|
+
rollupCategory:
|
|
358
|
+
index < 200 ? RollupCategory.Monitors : RollupCategory.Incidents,
|
|
359
|
+
}),
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const email: RollupEmail = build(items);
|
|
364
|
+
|
|
365
|
+
expect(varRows(email)).toHaveLength(MAX_ROWS_IN_ROLLUP);
|
|
366
|
+
|
|
367
|
+
const counts: string = varString(email, "categoryCounts");
|
|
368
|
+
|
|
369
|
+
expect(counts).toBe("200 Monitors · 100 Incidents");
|
|
370
|
+
|
|
371
|
+
let total: number = 0;
|
|
372
|
+
|
|
373
|
+
for (const part of counts.split(" · ")) {
|
|
374
|
+
total = total + Number(part.split(" ")[0]!);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
expect(total).toBe(300);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test("counts are ordered by size descending, then by label ascending", () => {
|
|
381
|
+
const items: Array<UserNotificationEmailRollupItem> = [
|
|
382
|
+
makeItem({
|
|
383
|
+
createdAt: at(1),
|
|
384
|
+
subject: "s",
|
|
385
|
+
rollupCategory: RollupCategory.StatusPages,
|
|
386
|
+
}),
|
|
387
|
+
makeItem({
|
|
388
|
+
createdAt: at(2),
|
|
389
|
+
subject: "a",
|
|
390
|
+
rollupCategory: RollupCategory.Alerts,
|
|
391
|
+
}),
|
|
392
|
+
makeItem({
|
|
393
|
+
createdAt: at(3),
|
|
394
|
+
subject: "m1",
|
|
395
|
+
rollupCategory: RollupCategory.Monitors,
|
|
396
|
+
}),
|
|
397
|
+
makeItem({
|
|
398
|
+
createdAt: at(4),
|
|
399
|
+
subject: "m2",
|
|
400
|
+
rollupCategory: RollupCategory.Monitors,
|
|
401
|
+
}),
|
|
402
|
+
];
|
|
403
|
+
|
|
404
|
+
expect(varString(build(items), "categoryCounts")).toBe(
|
|
405
|
+
"2 Monitors · 1 Alerts · 1 Status Pages",
|
|
406
|
+
);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
test("a category code the build has never heard of counts as Other rather than crashing", () => {
|
|
410
|
+
const item: UserNotificationEmailRollupItem = makeItem({
|
|
411
|
+
createdAt: at(0),
|
|
412
|
+
subject: "From a newer build",
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
item.rollupCategory = "quantum-widgets" as RollupCategory;
|
|
416
|
+
|
|
417
|
+
expect(varString(build([item]), "categoryCounts")).toBe("1 Other");
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
describe("buildRollupEmail row cap", () => {
|
|
422
|
+
/*
|
|
423
|
+
* 150 groups, of which the oldest 50 carry two items each. The hidden ROW
|
|
424
|
+
* count and the hidden ITEM count are deliberately different numbers so a
|
|
425
|
+
* copy bug that reports one where it means the other cannot pass.
|
|
426
|
+
*/
|
|
427
|
+
type BuildOversizedFunction = () => Array<UserNotificationEmailRollupItem>;
|
|
428
|
+
|
|
429
|
+
const buildOversized: BuildOversizedFunction =
|
|
430
|
+
(): Array<UserNotificationEmailRollupItem> => {
|
|
431
|
+
const items: Array<UserNotificationEmailRollupItem> = [];
|
|
432
|
+
|
|
433
|
+
for (let group: number = 0; group < 150; group++) {
|
|
434
|
+
const link: string = `https://oneuptime.example.com/dashboard/p1/r/${group}`;
|
|
435
|
+
|
|
436
|
+
items.push(
|
|
437
|
+
makeItem({
|
|
438
|
+
createdAt: at(group * 60),
|
|
439
|
+
subject: `Group ${group}`,
|
|
440
|
+
viewLink: link,
|
|
441
|
+
}),
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
if (group < 50) {
|
|
445
|
+
items.push(
|
|
446
|
+
makeItem({
|
|
447
|
+
createdAt: at(group * 60 + 1),
|
|
448
|
+
subject: `Group ${group} update`,
|
|
449
|
+
viewLink: link,
|
|
450
|
+
}),
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return items;
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
test("renders at most MAX_ROWS_IN_ROLLUP rows and flags the rest", () => {
|
|
459
|
+
const email: RollupEmail = build(buildOversized());
|
|
460
|
+
|
|
461
|
+
expect(varRows(email)).toHaveLength(100);
|
|
462
|
+
expect(varString(email, "hasMore")).toBe("true");
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
test("the tail names the true hidden row count and hidden item count", () => {
|
|
466
|
+
const email: RollupEmail = build(buildOversized());
|
|
467
|
+
const moreText: string = varString(email, "moreTextHtml");
|
|
468
|
+
|
|
469
|
+
expect(moreText).toContain("50 more updates");
|
|
470
|
+
expect(moreText).toContain("covering 100 notifications");
|
|
471
|
+
expect(moreText).toContain("are not listed here");
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
test("nothing hidden means no tail at all", () => {
|
|
475
|
+
const email: RollupEmail = build([
|
|
476
|
+
makeItem({ createdAt: at(0), subject: "One thing" }),
|
|
477
|
+
makeItem({ createdAt: at(1), subject: "Another thing" }),
|
|
478
|
+
]);
|
|
479
|
+
|
|
480
|
+
expect(varString(email, "hasMore")).toBe("false");
|
|
481
|
+
expect(varString(email, "moreTextHtml")).toBe("");
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
describe("buildRollupEmail subject grammar", () => {
|
|
486
|
+
test("more than one notification reads [project] N notifications", () => {
|
|
487
|
+
const items: Array<UserNotificationEmailRollupItem> = [];
|
|
488
|
+
|
|
489
|
+
for (let index: number = 0; index < 12; index++) {
|
|
490
|
+
items.push(makeItem({ createdAt: at(index), subject: `Event ${index}` }));
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
expect(build(items).subject).toBe("[Acme] 12 notifications: 12 Incidents");
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
test("exactly one notification leads with its title", () => {
|
|
497
|
+
expect(
|
|
498
|
+
build([makeItem({ createdAt: at(0), subject: "Checkout is down" })])
|
|
499
|
+
.subject,
|
|
500
|
+
).toBe("[Acme] 1 notification: Checkout is down");
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
test("the lead title is truncated to ROLLUP_SUBJECT_LEAD_TITLE_MAX", () => {
|
|
504
|
+
const longTitle: string = "T".repeat(200);
|
|
505
|
+
const subject: string = build([
|
|
506
|
+
makeItem({ createdAt: at(0), subject: longTitle }),
|
|
507
|
+
]).subject;
|
|
508
|
+
|
|
509
|
+
const lead: string = subject.replace("[Acme] 1 notification: ", "");
|
|
510
|
+
|
|
511
|
+
expect(lead).toHaveLength(ROLLUP_SUBJECT_LEAD_TITLE_MAX);
|
|
512
|
+
expect(lead).toBe(`${"T".repeat(79)}…`);
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
test("the project name is truncated to ROLLUP_PROJECT_NAME_MAX", () => {
|
|
516
|
+
const subject: string = build(
|
|
517
|
+
[
|
|
518
|
+
makeItem({ createdAt: at(0), subject: "a" }),
|
|
519
|
+
makeItem({ createdAt: at(1), subject: "b" }),
|
|
520
|
+
],
|
|
521
|
+
"P".repeat(200),
|
|
522
|
+
).subject;
|
|
523
|
+
|
|
524
|
+
expect(subject).toBe(`[${"P".repeat(59)}…] 2 notifications: 2 Incidents`);
|
|
525
|
+
expect(subject.indexOf("]") - 1).toBe(ROLLUP_PROJECT_NAME_MAX);
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
test("handlebars braces are stripped, because MailService compiles the subject", () => {
|
|
529
|
+
const subject: string = build(
|
|
530
|
+
[
|
|
531
|
+
makeItem({ createdAt: at(0), subject: "a" }),
|
|
532
|
+
makeItem({ createdAt: at(1), subject: "b" }),
|
|
533
|
+
],
|
|
534
|
+
"{{constructor}}",
|
|
535
|
+
).subject;
|
|
536
|
+
|
|
537
|
+
expect(subject).toBe("[constructor] 2 notifications: 2 Incidents");
|
|
538
|
+
expect(subject).not.toContain("{{");
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
test("braces are stripped from the lead title too", () => {
|
|
542
|
+
expect(
|
|
543
|
+
build([
|
|
544
|
+
makeItem({ createdAt: at(0), subject: "{{projectName}} is down" }),
|
|
545
|
+
]).subject,
|
|
546
|
+
).toBe("[Acme] 1 notification: projectName is down");
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
test("an unnamed project falls back to prose rather than an empty bracket", () => {
|
|
550
|
+
expect(
|
|
551
|
+
build(
|
|
552
|
+
[
|
|
553
|
+
makeItem({ createdAt: at(0), subject: "a" }),
|
|
554
|
+
makeItem({ createdAt: at(1), subject: "b" }),
|
|
555
|
+
],
|
|
556
|
+
"",
|
|
557
|
+
).subject,
|
|
558
|
+
).toBe("[your project] 2 notifications: 2 Incidents");
|
|
559
|
+
});
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
describe("buildRollupEmail escaping contract", () => {
|
|
563
|
+
/*
|
|
564
|
+
* The fixture carries EVERY character escapeHtml touches - & < > " and ' -
|
|
565
|
+
* on purpose. A fixture built only from <script>alert(1)</script> exercises
|
|
566
|
+
* two of the five, and, worse, a fixture with no escapable character at all
|
|
567
|
+
* makes the whole contract untestable: raw and pre-escaped are then the
|
|
568
|
+
* same bytes, so a test written against it passes whichever way round the
|
|
569
|
+
* two are wired. Both halves of the contract are asserted here, because
|
|
570
|
+
* both halves fail silently in production:
|
|
571
|
+
*
|
|
572
|
+
* raw value in a triple stache -> live markup in a mail client
|
|
573
|
+
* pre-escaped value in a double -> the recipient reads "&lt;"
|
|
574
|
+
*
|
|
575
|
+
* `&` in a project name is the common case (Marks & Spencer), and `"` in a
|
|
576
|
+
* title is the common case for a monitor named after a quoted hostname.
|
|
577
|
+
*/
|
|
578
|
+
const hostileProject: string = "A&B <\"Corp\"> 'Ltd'";
|
|
579
|
+
const hostileSubject: string =
|
|
580
|
+
"Disk \"sda1\" > 90% & <b>hot</b> at 'eu-west'";
|
|
581
|
+
|
|
582
|
+
/* What escapeHtml makes of hostileProject. Escaped once, never twice. */
|
|
583
|
+
const projectEscapedOnce: string =
|
|
584
|
+
"A&B <"Corp"> 'Ltd'";
|
|
585
|
+
|
|
586
|
+
/*
|
|
587
|
+
* An `&` that does not open one of the five entities escapeHtml produces.
|
|
588
|
+
* A pre-escaped var containing one was escaped too few times - which is
|
|
589
|
+
* exactly what dropping the `&` replace from escapeHtml would do, while
|
|
590
|
+
* leaving every angle bracket looking correct.
|
|
591
|
+
*/
|
|
592
|
+
const unescapedAmpersand: RegExp = /&(?!(?:amp|lt|gt|quot|#39);)/;
|
|
593
|
+
|
|
594
|
+
type HostileEmailFunction = () => RollupEmail;
|
|
595
|
+
|
|
596
|
+
const hostileEmail: HostileEmailFunction = (): RollupEmail => {
|
|
597
|
+
return build(
|
|
598
|
+
[
|
|
599
|
+
makeItem({
|
|
600
|
+
createdAt: at(0),
|
|
601
|
+
subject: hostileSubject,
|
|
602
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/incidents/i1",
|
|
603
|
+
}),
|
|
604
|
+
makeItem({ createdAt: at(1), subject: "Something ordinary" }),
|
|
605
|
+
],
|
|
606
|
+
hostileProject,
|
|
607
|
+
);
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
test("a var the template feeds to a DOUBLE stache arrives RAW, byte for byte", () => {
|
|
611
|
+
const email: RollupEmail = hostileEmail();
|
|
612
|
+
const rows: Array<JSONObject> = varRows(email);
|
|
613
|
+
|
|
614
|
+
/* rollupTitle -> {{> EmailTitle title=... }} -> {{title}} */
|
|
615
|
+
expect(varString(email, "rollupTitle")).toBe(
|
|
616
|
+
`2 notifications from ${hostileProject}`,
|
|
617
|
+
);
|
|
618
|
+
|
|
619
|
+
/* rows[].title -> {{this.title}} in this template's own table. */
|
|
620
|
+
expect(rowField(rows[1]!, "title")).toBe(hostileSubject);
|
|
621
|
+
|
|
622
|
+
/*
|
|
623
|
+
* Not one of the five has become an entity yet: Handlebars has not run,
|
|
624
|
+
* and when it does it must be the FIRST and only pass over these bytes.
|
|
625
|
+
*/
|
|
626
|
+
expect(varString(email, "rollupTitle")).not.toContain("&");
|
|
627
|
+
expect(varString(email, "rollupTitle")).not.toContain("<");
|
|
628
|
+
expect(rowField(rows[1]!, "title")).not.toContain(""");
|
|
629
|
+
expect(rowField(rows[1]!, "title")).not.toContain("'");
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
test("a var the template feeds to a TRIPLE stache arrives PRE-ESCAPED, exactly once", () => {
|
|
633
|
+
const email: RollupEmail = hostileEmail();
|
|
634
|
+
|
|
635
|
+
/* rollupIntroHtml -> {{> InfoBlock info=... }} -> {{{info}}} */
|
|
636
|
+
expect(varString(email, "rollupIntroHtml")).toContain(projectEscapedOnce);
|
|
637
|
+
|
|
638
|
+
for (const name of HTML_VAR_NAMES) {
|
|
639
|
+
const value: string = varString(email, name);
|
|
640
|
+
|
|
641
|
+
/* Escaped at least once: nothing a triple stache would render live. */
|
|
642
|
+
expect(value).not.toContain("<");
|
|
643
|
+
expect(value).not.toContain(">");
|
|
644
|
+
expect(value).not.toContain('"');
|
|
645
|
+
expect(value).not.toContain("'");
|
|
646
|
+
expect(value).not.toMatch(unescapedAmpersand);
|
|
647
|
+
|
|
648
|
+
/* And at most once: escaped twice reads as literal "&lt;". */
|
|
649
|
+
expect(value).not.toContain("&amp;");
|
|
650
|
+
expect(value).not.toContain("&lt;");
|
|
651
|
+
expect(value).not.toContain("&gt;");
|
|
652
|
+
expect(value).not.toContain("&quot;");
|
|
653
|
+
expect(value).not.toContain("&#39;");
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
test("the raw links are passed through untouched for their href attributes", () => {
|
|
658
|
+
const email: RollupEmail = hostileEmail();
|
|
659
|
+
|
|
660
|
+
expect(varString(email, "projectHomeLink")).toBe(
|
|
661
|
+
"https://oneuptime.example.com/dashboard/p1/home",
|
|
662
|
+
);
|
|
663
|
+
expect(varString(email, "preferencesLink")).toBe(
|
|
664
|
+
"https://oneuptime.example.com/dashboard/p1/user-settings/notification-settings",
|
|
665
|
+
);
|
|
666
|
+
});
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
describe("buildRollupEmail zebra striping", () => {
|
|
670
|
+
/*
|
|
671
|
+
* The template used to decide the stripe itself, with {{#if @odd}}.
|
|
672
|
+
* Handlebars defines @index, @first, @last, @key, @root and @level - and
|
|
673
|
+
* NOT @odd - and an unknown @-variable resolves to undefined instead of
|
|
674
|
+
* erroring, so that condition was false on every single row and the table
|
|
675
|
+
* rendered flat white. Nothing failed, nothing logged, and no test noticed.
|
|
676
|
+
*
|
|
677
|
+
* The colour is a builder field now, and these are the assertions that
|
|
678
|
+
* would have caught it: the sequence itself, pinned per index.
|
|
679
|
+
*/
|
|
680
|
+
type StripedEmailFunction = (rowCount: number) => RollupEmail;
|
|
681
|
+
|
|
682
|
+
const stripedEmail: StripedEmailFunction = (
|
|
683
|
+
rowCount: number,
|
|
684
|
+
): RollupEmail => {
|
|
685
|
+
const items: Array<UserNotificationEmailRollupItem> = [];
|
|
686
|
+
|
|
687
|
+
for (let index: number = 0; index < rowCount; index++) {
|
|
688
|
+
items.push(
|
|
689
|
+
makeItem({
|
|
690
|
+
createdAt: at(index * 60),
|
|
691
|
+
subject: `Event ${index}`,
|
|
692
|
+
viewLink: `https://oneuptime.example.com/dashboard/p1/r/${index}`,
|
|
693
|
+
}),
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return build(items);
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
type BackgroundsFunction = (email: RollupEmail) => Array<string>;
|
|
701
|
+
|
|
702
|
+
const backgrounds: BackgroundsFunction = (
|
|
703
|
+
email: RollupEmail,
|
|
704
|
+
): Array<string> => {
|
|
705
|
+
return varRows(email).map((row: JSONObject): string => {
|
|
706
|
+
return rowField(row, "rowBackground");
|
|
707
|
+
});
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
test("row backgrounds alternate, starting white on the first row", () => {
|
|
711
|
+
expect(backgrounds(stripedEmail(5))).toEqual([
|
|
712
|
+
"#ffffff",
|
|
713
|
+
"#f7f9fc",
|
|
714
|
+
"#ffffff",
|
|
715
|
+
"#f7f9fc",
|
|
716
|
+
"#ffffff",
|
|
717
|
+
]);
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
test("a one-row rollup is white, never the stripe colour", () => {
|
|
721
|
+
expect(backgrounds(stripedEmail(1))).toEqual(["#ffffff"]);
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
test("every rendered row carries a colour and no two neighbours share one", () => {
|
|
725
|
+
const colours: Array<string> = backgrounds(
|
|
726
|
+
stripedEmail(MAX_ROWS_IN_ROLLUP + 20),
|
|
727
|
+
);
|
|
728
|
+
|
|
729
|
+
expect(colours).toHaveLength(MAX_ROWS_IN_ROLLUP);
|
|
730
|
+
|
|
731
|
+
for (let index: number = 1; index < colours.length; index++) {
|
|
732
|
+
expect(colours[index]!).not.toBe(colours[index - 1]!);
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
describe("buildRollupEmail singular and plural copy", () => {
|
|
738
|
+
test("one item reads in the singular throughout", () => {
|
|
739
|
+
const email: RollupEmail = build([
|
|
740
|
+
makeItem({ createdAt: at(0), subject: "Checkout is down" }),
|
|
741
|
+
]);
|
|
742
|
+
|
|
743
|
+
expect(varString(email, "rollupTitle")).toBe("1 notification from Acme");
|
|
744
|
+
expect(varString(email, "summaryCount")).toBe("1 notification");
|
|
745
|
+
expect(varString(email, "rollupIntroHtml")).toBe(
|
|
746
|
+
"OneUptime grouped this notification from Acme into a single email. Nothing was suppressed.",
|
|
747
|
+
);
|
|
748
|
+
expect(varRows(email)).toHaveLength(1);
|
|
749
|
+
|
|
750
|
+
/*
|
|
751
|
+
* A single-update row says WHEN and nothing else. "1 update" would be
|
|
752
|
+
* noise on every row of the common case - most rows in a real rollup are
|
|
753
|
+
* one event about one resource.
|
|
754
|
+
*/
|
|
755
|
+
expect(rowField(varRows(email)[0]!, "metaLabel")).toBe("12:00 UTC");
|
|
756
|
+
expect(rowField(varRows(email)[0]!, "sectionCount")).toBe("1 update");
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
test("many items read in the plural throughout", () => {
|
|
760
|
+
const email: RollupEmail = build([
|
|
761
|
+
makeItem({ createdAt: at(0), subject: "a" }),
|
|
762
|
+
makeItem({ createdAt: at(1), subject: "b" }),
|
|
763
|
+
]);
|
|
764
|
+
|
|
765
|
+
expect(varString(email, "rollupTitle")).toBe("2 notifications from Acme");
|
|
766
|
+
expect(varString(email, "summaryCount")).toBe("2 notifications");
|
|
767
|
+
expect(varString(email, "rollupIntroHtml")).toBe(
|
|
768
|
+
"OneUptime grouped these 2 notifications from Acme into a single email " +
|
|
769
|
+
"instead of sending 2 separate messages. Nothing was suppressed.",
|
|
770
|
+
);
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
test("exactly one hidden row and one hidden item read in the singular", () => {
|
|
774
|
+
const items: Array<UserNotificationEmailRollupItem> = [];
|
|
775
|
+
|
|
776
|
+
for (let index: number = 0; index < MAX_ROWS_IN_ROLLUP + 1; index++) {
|
|
777
|
+
items.push(
|
|
778
|
+
makeItem({
|
|
779
|
+
createdAt: at(index * 60),
|
|
780
|
+
subject: `Event ${index}`,
|
|
781
|
+
viewLink: `https://oneuptime.example.com/dashboard/p1/r/${index}`,
|
|
782
|
+
}),
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const moreText: string = varString(build(items), "moreTextHtml");
|
|
787
|
+
|
|
788
|
+
expect(moreText).toContain("1 more update ");
|
|
789
|
+
expect(moreText).toContain("covering 1 notification)");
|
|
790
|
+
expect(moreText).toContain("is not listed here");
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
describe("buildRollupEmail variable set", () => {
|
|
795
|
+
test("every variable the template needs is present, and rows carry exactly eight fields", () => {
|
|
796
|
+
const email: RollupEmail = build([
|
|
797
|
+
makeItem({
|
|
798
|
+
createdAt: at(0),
|
|
799
|
+
subject: "Checkout is down",
|
|
800
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/incidents/i1",
|
|
801
|
+
}),
|
|
802
|
+
]);
|
|
803
|
+
|
|
804
|
+
expect(Object.keys(email.vars).sort()).toEqual(
|
|
805
|
+
[
|
|
806
|
+
"categoryCounts",
|
|
807
|
+
"hasMore",
|
|
808
|
+
"moreTextHtml",
|
|
809
|
+
"preferencesHtml",
|
|
810
|
+
"preferencesLink",
|
|
811
|
+
"projectHomeLink",
|
|
812
|
+
"rollupIntroHtml",
|
|
813
|
+
"rollupTitle",
|
|
814
|
+
"rows",
|
|
815
|
+
"summaryCount",
|
|
816
|
+
"summaryWindow",
|
|
817
|
+
].sort(),
|
|
818
|
+
);
|
|
819
|
+
|
|
820
|
+
/*
|
|
821
|
+
* Exactly these, no more: a row field the template reads and the builder
|
|
822
|
+
* does not set renders as the empty string, and rowBackground lives
|
|
823
|
+
* inside a style attribute, where empty means `background-color: ;` and a
|
|
824
|
+
* mail client throws the whole declaration away.
|
|
825
|
+
*/
|
|
826
|
+
expect(Object.keys(varRows(email)[0]!).sort()).toEqual(
|
|
827
|
+
[
|
|
828
|
+
"hasLink",
|
|
829
|
+
"isSectionStart",
|
|
830
|
+
"link",
|
|
831
|
+
"metaLabel",
|
|
832
|
+
"rowBackground",
|
|
833
|
+
"sectionCount",
|
|
834
|
+
"sectionLabel",
|
|
835
|
+
"title",
|
|
836
|
+
].sort(),
|
|
837
|
+
);
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
test("the preferences copy explains the batching AND names the way out of it", () => {
|
|
841
|
+
const email: RollupEmail = build([
|
|
842
|
+
makeItem({ createdAt: at(0), subject: "a" }),
|
|
843
|
+
]);
|
|
844
|
+
|
|
845
|
+
const preferences: string = varString(email, "preferencesHtml");
|
|
846
|
+
|
|
847
|
+
/* Why an email the recipient did not recognise arrived at all. */
|
|
848
|
+
expect(preferences).toContain(
|
|
849
|
+
"groups owner notifications into a single email",
|
|
850
|
+
);
|
|
851
|
+
|
|
852
|
+
/*
|
|
853
|
+
* And the escape hatch, which is the half that regresses silently.
|
|
854
|
+
* Rollup is on for everyone with no preference and no announcement, so
|
|
855
|
+
* this paragraph is the only place a recipient learns the opt-out exists
|
|
856
|
+
* - copy that merely says "choose which notifications you receive" sends
|
|
857
|
+
* them to a page whose most useful switch it never mentioned, and they
|
|
858
|
+
* conclude batching is mandatory.
|
|
859
|
+
*/
|
|
860
|
+
expect(preferences).toContain("turn off email rollup for this project");
|
|
861
|
+
expect(preferences).toContain("notification settings");
|
|
862
|
+
|
|
863
|
+
/*
|
|
864
|
+
* The template renders preferencesLink as a bare URL on the line below
|
|
865
|
+
* this text, so the text has to hand off to it. End on a full stop and
|
|
866
|
+
* the reader gets a naked link with nothing claiming it.
|
|
867
|
+
*/
|
|
868
|
+
expect(preferences.endsWith(":")).toBe(true);
|
|
869
|
+
});
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
/*
|
|
873
|
+
* The rest of this file pins the SHAPE of the rollup email: which section a
|
|
874
|
+
* row lands in, what order the sections come in, what each row says about
|
|
875
|
+
* when it happened, and whether the numbers in the three places this email
|
|
876
|
+
* counts things agree with each other.
|
|
877
|
+
*
|
|
878
|
+
* All of it is behaviour a reader notices immediately and no type checks:
|
|
879
|
+
* every field below is a string in a Dictionary, and every one of them
|
|
880
|
+
* renders as the empty string when it is wrong.
|
|
881
|
+
*/
|
|
882
|
+
|
|
883
|
+
type SectionSummary = {
|
|
884
|
+
label: string;
|
|
885
|
+
count: string;
|
|
886
|
+
titles: Array<string>;
|
|
887
|
+
};
|
|
888
|
+
|
|
889
|
+
type SectionsOfFunction = (email: RollupEmail) => Array<SectionSummary>;
|
|
890
|
+
|
|
891
|
+
/*
|
|
892
|
+
* Rebuild the sections from the flat rows the way the TEMPLATE does - by
|
|
893
|
+
* starting a new one every time isSectionStart is "true" - rather than by
|
|
894
|
+
* reading the builder's internals. A section boundary that the builder knows
|
|
895
|
+
* about and the flag does not express is invisible in the email, so it has to
|
|
896
|
+
* be invisible here too.
|
|
897
|
+
*/
|
|
898
|
+
const sectionsOf: SectionsOfFunction = (
|
|
899
|
+
email: RollupEmail,
|
|
900
|
+
): Array<SectionSummary> => {
|
|
901
|
+
const sections: Array<SectionSummary> = [];
|
|
902
|
+
|
|
903
|
+
for (const row of varRows(email)) {
|
|
904
|
+
const title: string = rowField(row, "title");
|
|
905
|
+
|
|
906
|
+
if (rowField(row, "isSectionStart") === "true") {
|
|
907
|
+
sections.push({
|
|
908
|
+
label: rowField(row, "sectionLabel"),
|
|
909
|
+
count: rowField(row, "sectionCount"),
|
|
910
|
+
titles: [title],
|
|
911
|
+
});
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
const current: SectionSummary | undefined = sections[sections.length - 1];
|
|
916
|
+
|
|
917
|
+
if (!current) {
|
|
918
|
+
throw new Error("A row appeared before any section started");
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
current.titles.push(title);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
return sections;
|
|
925
|
+
};
|
|
926
|
+
|
|
927
|
+
describe("buildRollupEmail sections", () => {
|
|
928
|
+
type MixedItemsFunction = () => Array<UserNotificationEmailRollupItem>;
|
|
929
|
+
|
|
930
|
+
/*
|
|
931
|
+
* Deliberately seeded OUT of the order the sections must come out in, and
|
|
932
|
+
* with the biggest category last: a builder that grouped by first
|
|
933
|
+
* appearance, or that sorted sections by size the way the summary card
|
|
934
|
+
* sorts its counts, passes neither of the next two tests.
|
|
935
|
+
*/
|
|
936
|
+
const mixedItems: MixedItemsFunction =
|
|
937
|
+
(): Array<UserNotificationEmailRollupItem> => {
|
|
938
|
+
return [
|
|
939
|
+
makeItem({
|
|
940
|
+
createdAt: at(0),
|
|
941
|
+
subject: "Probe eu-west is disconnected",
|
|
942
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/probes/p1",
|
|
943
|
+
rollupCategory: RollupCategory.Probes,
|
|
944
|
+
}),
|
|
945
|
+
makeItem({
|
|
946
|
+
createdAt: at(60),
|
|
947
|
+
subject: "api.acme.com is offline",
|
|
948
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/monitors/m1",
|
|
949
|
+
rollupCategory: RollupCategory.Monitors,
|
|
950
|
+
}),
|
|
951
|
+
makeItem({
|
|
952
|
+
createdAt: at(120),
|
|
953
|
+
subject: "Checkout is down",
|
|
954
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/incidents/i1",
|
|
955
|
+
rollupCategory: RollupCategory.Incidents,
|
|
956
|
+
}),
|
|
957
|
+
makeItem({
|
|
958
|
+
createdAt: at(180),
|
|
959
|
+
subject: "Checkout is down - acknowledged",
|
|
960
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/incidents/i1",
|
|
961
|
+
rollupCategory: RollupCategory.Incidents,
|
|
962
|
+
}),
|
|
963
|
+
makeItem({
|
|
964
|
+
createdAt: at(240),
|
|
965
|
+
subject: "Error rate above 5%",
|
|
966
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/alerts/a1",
|
|
967
|
+
rollupCategory: RollupCategory.Alerts,
|
|
968
|
+
}),
|
|
969
|
+
];
|
|
970
|
+
};
|
|
971
|
+
|
|
972
|
+
test("rows are grouped into one section per category", () => {
|
|
973
|
+
const sections: Array<SectionSummary> = sectionsOf(build(mixedItems()));
|
|
974
|
+
|
|
975
|
+
expect(
|
|
976
|
+
sections.map((section: SectionSummary): string => {
|
|
977
|
+
return section.label;
|
|
978
|
+
}),
|
|
979
|
+
).toEqual(["Incidents", "Alerts", "Monitors", "Probes"]);
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
test("sections follow ROLLUP_CATEGORY_ORDER, not size and not arrival order", () => {
|
|
983
|
+
const sections: Array<SectionSummary> = sectionsOf(build(mixedItems()));
|
|
984
|
+
|
|
985
|
+
const orderedLabels: Array<string> = ROLLUP_CATEGORY_ORDER.filter(
|
|
986
|
+
(category: RollupCategory): boolean => {
|
|
987
|
+
return [
|
|
988
|
+
RollupCategory.Incidents,
|
|
989
|
+
RollupCategory.Alerts,
|
|
990
|
+
RollupCategory.Monitors,
|
|
991
|
+
RollupCategory.Probes,
|
|
992
|
+
].includes(category);
|
|
993
|
+
},
|
|
994
|
+
).map((category: RollupCategory): string => {
|
|
995
|
+
return ROLLUP_CATEGORY_LABEL[category];
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
expect(
|
|
999
|
+
sections.map((section: SectionSummary): string => {
|
|
1000
|
+
return section.label;
|
|
1001
|
+
}),
|
|
1002
|
+
).toEqual(orderedLabels);
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
test("exactly one row per section is flagged as its start", () => {
|
|
1006
|
+
const email: RollupEmail = build(mixedItems());
|
|
1007
|
+
|
|
1008
|
+
const starts: number = varRows(email).filter((row: JSONObject): boolean => {
|
|
1009
|
+
return rowField(row, "isSectionStart") === "true";
|
|
1010
|
+
}).length;
|
|
1011
|
+
|
|
1012
|
+
expect(starts).toBe(4);
|
|
1013
|
+
expect(rowField(varRows(email)[0]!, "isSectionStart")).toBe("true");
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
test("every row carries its own section's label and count, not only the first", () => {
|
|
1017
|
+
const email: RollupEmail = build(mixedItems());
|
|
1018
|
+
|
|
1019
|
+
for (const row of varRows(email)) {
|
|
1020
|
+
expect(rowField(row, "sectionLabel").length).toBeGreaterThan(0);
|
|
1021
|
+
expect(rowField(row, "sectionCount")).toMatch(/^\d+ updates?$/);
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
test("rows inside a section stay newest first", () => {
|
|
1026
|
+
const link: string = "https://oneuptime.example.com/dashboard/p1/i";
|
|
1027
|
+
|
|
1028
|
+
const email: RollupEmail = build([
|
|
1029
|
+
makeItem({
|
|
1030
|
+
createdAt: at(0),
|
|
1031
|
+
subject: "Oldest",
|
|
1032
|
+
viewLink: `${link}/1`,
|
|
1033
|
+
}),
|
|
1034
|
+
makeItem({
|
|
1035
|
+
createdAt: at(60),
|
|
1036
|
+
subject: "Middle",
|
|
1037
|
+
viewLink: `${link}/2`,
|
|
1038
|
+
}),
|
|
1039
|
+
makeItem({
|
|
1040
|
+
createdAt: at(120),
|
|
1041
|
+
subject: "Newest",
|
|
1042
|
+
viewLink: `${link}/3`,
|
|
1043
|
+
}),
|
|
1044
|
+
]);
|
|
1045
|
+
|
|
1046
|
+
expect(sectionsOf(email)[0]!.titles).toEqual([
|
|
1047
|
+
"Newest",
|
|
1048
|
+
"Middle",
|
|
1049
|
+
"Oldest",
|
|
1050
|
+
]);
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
test("the section count is UPDATES, so it equals the summary card's count for that category", () => {
|
|
1054
|
+
const sections: Array<SectionSummary> = sectionsOf(build(mixedItems()));
|
|
1055
|
+
|
|
1056
|
+
/* Two notifications about ONE incident: one row, and a heading saying 2. */
|
|
1057
|
+
expect(sections[0]!.label).toBe("Incidents");
|
|
1058
|
+
expect(sections[0]!.titles).toHaveLength(1);
|
|
1059
|
+
expect(sections[0]!.count).toBe("2 updates");
|
|
1060
|
+
|
|
1061
|
+
const counts: string = varString(build(mixedItems()), "categoryCounts");
|
|
1062
|
+
|
|
1063
|
+
expect(counts).toContain("2 Incidents");
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
test("the section counts add up to the summary count, every category", () => {
|
|
1067
|
+
const email: RollupEmail = build(mixedItems());
|
|
1068
|
+
|
|
1069
|
+
let total: number = 0;
|
|
1070
|
+
|
|
1071
|
+
for (const section of sectionsOf(email)) {
|
|
1072
|
+
total = total + Number(section.count.split(" ")[0]!);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
expect(varString(email, "summaryCount")).toBe(`${total} notifications`);
|
|
1076
|
+
expect(total).toBe(5);
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
test("one update reads in the singular in a section heading", () => {
|
|
1080
|
+
const sections: Array<SectionSummary> = sectionsOf(build(mixedItems()));
|
|
1081
|
+
|
|
1082
|
+
expect(sections[1]!.label).toBe("Alerts");
|
|
1083
|
+
expect(sections[1]!.count).toBe("1 update");
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
test("a category the build has never heard of renders under Other rather than vanishing", () => {
|
|
1087
|
+
const item: UserNotificationEmailRollupItem = makeItem({
|
|
1088
|
+
createdAt: at(0),
|
|
1089
|
+
subject: "From a newer build",
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
item.rollupCategory = "quantum-widgets" as RollupCategory;
|
|
1093
|
+
|
|
1094
|
+
const sections: Array<SectionSummary> = sectionsOf(build([item]));
|
|
1095
|
+
|
|
1096
|
+
expect(sections).toHaveLength(1);
|
|
1097
|
+
expect(sections[0]!.label).toBe("Other");
|
|
1098
|
+
expect(sections[0]!.titles).toEqual(["From a newer build"]);
|
|
1099
|
+
});
|
|
1100
|
+
|
|
1101
|
+
test("EVERY row survives grouping - a section is a heading, never a filter", () => {
|
|
1102
|
+
const items: Array<UserNotificationEmailRollupItem> = [];
|
|
1103
|
+
|
|
1104
|
+
for (const category of ROLLUP_CATEGORY_ORDER) {
|
|
1105
|
+
items.push(
|
|
1106
|
+
makeItem({
|
|
1107
|
+
createdAt: at(items.length * 60),
|
|
1108
|
+
subject: `Something in ${category}`,
|
|
1109
|
+
viewLink: `https://oneuptime.example.com/dashboard/p1/r/${category}`,
|
|
1110
|
+
rollupCategory: category,
|
|
1111
|
+
}),
|
|
1112
|
+
);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
const email: RollupEmail = build(items);
|
|
1116
|
+
|
|
1117
|
+
expect(varRows(email)).toHaveLength(ROLLUP_CATEGORY_ORDER.length);
|
|
1118
|
+
expect(sectionsOf(email)).toHaveLength(ROLLUP_CATEGORY_ORDER.length);
|
|
1119
|
+
expect(
|
|
1120
|
+
sectionsOf(email).map((section: SectionSummary): string => {
|
|
1121
|
+
return section.label;
|
|
1122
|
+
}),
|
|
1123
|
+
).toEqual(
|
|
1124
|
+
ROLLUP_CATEGORY_ORDER.map((category: RollupCategory): string => {
|
|
1125
|
+
return ROLLUP_CATEGORY_LABEL[category];
|
|
1126
|
+
}),
|
|
1127
|
+
);
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
test("the zebra stripe restarts at white in every section", () => {
|
|
1131
|
+
const items: Array<UserNotificationEmailRollupItem> = [];
|
|
1132
|
+
|
|
1133
|
+
/* Two incidents, then two monitors: without a restart the third row is striped. */
|
|
1134
|
+
for (let index: number = 0; index < 2; index++) {
|
|
1135
|
+
items.push(
|
|
1136
|
+
makeItem({
|
|
1137
|
+
createdAt: at(index * 60),
|
|
1138
|
+
subject: `Incident ${index}`,
|
|
1139
|
+
viewLink: `https://oneuptime.example.com/dashboard/p1/incidents/${index}`,
|
|
1140
|
+
rollupCategory: RollupCategory.Incidents,
|
|
1141
|
+
}),
|
|
1142
|
+
);
|
|
1143
|
+
items.push(
|
|
1144
|
+
makeItem({
|
|
1145
|
+
createdAt: at(index * 60 + 1),
|
|
1146
|
+
subject: `Monitor ${index}`,
|
|
1147
|
+
viewLink: `https://oneuptime.example.com/dashboard/p1/monitors/${index}`,
|
|
1148
|
+
rollupCategory: RollupCategory.Monitors,
|
|
1149
|
+
}),
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
const colours: Array<string> = varRows(build(items)).map(
|
|
1154
|
+
(row: JSONObject): string => {
|
|
1155
|
+
return rowField(row, "rowBackground");
|
|
1156
|
+
},
|
|
1157
|
+
);
|
|
1158
|
+
|
|
1159
|
+
expect(colours).toEqual(["#ffffff", "#f7f9fc", "#ffffff", "#f7f9fc"]);
|
|
1160
|
+
});
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
describe("buildRollupEmail times", () => {
|
|
1164
|
+
test("a single-update row carries only its timestamp", () => {
|
|
1165
|
+
const email: RollupEmail = build([
|
|
1166
|
+
makeItem({ createdAt: at(0), subject: "Checkout is down" }),
|
|
1167
|
+
]);
|
|
1168
|
+
|
|
1169
|
+
expect(rowField(varRows(email)[0]!, "metaLabel")).toBe("12:00 UTC");
|
|
1170
|
+
});
|
|
1171
|
+
|
|
1172
|
+
test("a folded row carries its update count and the time of the LATEST of them", () => {
|
|
1173
|
+
const link: string = "https://oneuptime.example.com/dashboard/p1/i1";
|
|
1174
|
+
|
|
1175
|
+
const email: RollupEmail = build([
|
|
1176
|
+
makeItem({ createdAt: at(0), subject: "Down", viewLink: link }),
|
|
1177
|
+
makeItem({ createdAt: at(9 * 60), subject: "Acked", viewLink: link }),
|
|
1178
|
+
makeItem({ createdAt: at(21 * 60), subject: "Resolved", viewLink: link }),
|
|
1179
|
+
]);
|
|
1180
|
+
|
|
1181
|
+
expect(rowField(varRows(email)[0]!, "metaLabel")).toBe(
|
|
1182
|
+
"3 updates · latest 12:21 UTC",
|
|
1183
|
+
);
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
test("times are UTC and zero padded, whatever the process timezone is", () => {
|
|
1187
|
+
const email: RollupEmail = build([
|
|
1188
|
+
makeItem({
|
|
1189
|
+
createdAt: new Date(Date.UTC(2026, 8, 3, 4, 5, 0)),
|
|
1190
|
+
subject: "Early",
|
|
1191
|
+
}),
|
|
1192
|
+
]);
|
|
1193
|
+
|
|
1194
|
+
expect(rowField(varRows(email)[0]!, "metaLabel")).toBe("04:05 UTC");
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
test("the summary window spans the earliest and latest notification", () => {
|
|
1198
|
+
const email: RollupEmail = build([
|
|
1199
|
+
makeItem({ createdAt: at(0), subject: "First" }),
|
|
1200
|
+
makeItem({ createdAt: at(26 * 60), subject: "Last" }),
|
|
1201
|
+
]);
|
|
1202
|
+
|
|
1203
|
+
expect(varString(email, "summaryWindow")).toBe("12:00 UTC to 12:26 UTC");
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
test("a window that starts and ends in the same minute is printed once, not as a range", () => {
|
|
1207
|
+
const email: RollupEmail = build([
|
|
1208
|
+
makeItem({ createdAt: at(0), subject: "a" }),
|
|
1209
|
+
makeItem({ createdAt: at(30), subject: "b" }),
|
|
1210
|
+
]);
|
|
1211
|
+
|
|
1212
|
+
expect(varString(email, "summaryWindow")).toBe("12:00 UTC");
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
test("a rollup that spans two UTC days prints the date on EVERY time", () => {
|
|
1216
|
+
const email: RollupEmail = build([
|
|
1217
|
+
makeItem({
|
|
1218
|
+
createdAt: new Date(Date.UTC(2026, 8, 3, 23, 50, 0)),
|
|
1219
|
+
subject: "Late on the third",
|
|
1220
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/r/1",
|
|
1221
|
+
}),
|
|
1222
|
+
makeItem({
|
|
1223
|
+
createdAt: new Date(Date.UTC(2026, 8, 4, 0, 10, 0)),
|
|
1224
|
+
subject: "Early on the fourth",
|
|
1225
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/r/2",
|
|
1226
|
+
}),
|
|
1227
|
+
]);
|
|
1228
|
+
|
|
1229
|
+
expect(varString(email, "summaryWindow")).toBe(
|
|
1230
|
+
"Sep 3, 23:50 UTC to Sep 4, 00:10 UTC",
|
|
1231
|
+
);
|
|
1232
|
+
|
|
1233
|
+
/*
|
|
1234
|
+
* BOTH rows, not only the one on the later day: a table where some times
|
|
1235
|
+
* carry a date and others do not is read as though they are all on the
|
|
1236
|
+
* same day, which is the misreading the date exists to prevent.
|
|
1237
|
+
*/
|
|
1238
|
+
expect(rowField(varRows(email)[0]!, "metaLabel")).toBe("Sep 4, 00:10 UTC");
|
|
1239
|
+
expect(rowField(varRows(email)[1]!, "metaLabel")).toBe("Sep 3, 23:50 UTC");
|
|
1240
|
+
});
|
|
1241
|
+
|
|
1242
|
+
test("a rollup inside one UTC day prints no date at all", () => {
|
|
1243
|
+
const email: RollupEmail = build([
|
|
1244
|
+
makeItem({
|
|
1245
|
+
createdAt: new Date(Date.UTC(2026, 8, 3, 0, 1, 0)),
|
|
1246
|
+
subject: "Just after midnight",
|
|
1247
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/r/1",
|
|
1248
|
+
}),
|
|
1249
|
+
makeItem({
|
|
1250
|
+
createdAt: new Date(Date.UTC(2026, 8, 3, 23, 59, 0)),
|
|
1251
|
+
subject: "Just before the next one",
|
|
1252
|
+
viewLink: "https://oneuptime.example.com/dashboard/p1/r/2",
|
|
1253
|
+
}),
|
|
1254
|
+
]);
|
|
1255
|
+
|
|
1256
|
+
expect(varString(email, "summaryWindow")).toBe("00:01 UTC to 23:59 UTC");
|
|
1257
|
+
expect(rowField(varRows(email)[0]!, "metaLabel")).toBe("23:59 UTC");
|
|
1258
|
+
});
|
|
1259
|
+
|
|
1260
|
+
test("the window covers items the row cap hid, because the card counts them too", () => {
|
|
1261
|
+
const items: Array<UserNotificationEmailRollupItem> = [];
|
|
1262
|
+
|
|
1263
|
+
for (let index: number = 0; index < MAX_ROWS_IN_ROLLUP + 10; index++) {
|
|
1264
|
+
items.push(
|
|
1265
|
+
makeItem({
|
|
1266
|
+
createdAt: at(index * 60),
|
|
1267
|
+
subject: `Event ${index}`,
|
|
1268
|
+
viewLink: `https://oneuptime.example.com/dashboard/p1/r/${index}`,
|
|
1269
|
+
}),
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/* The oldest ten rows are not rendered; the window still starts at 12:00. */
|
|
1274
|
+
expect(varString(build(items), "summaryWindow")).toBe(
|
|
1275
|
+
"12:00 UTC to 13:49 UTC",
|
|
1276
|
+
);
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
test("an item with no createdAt at all leaves the window empty rather than printing 1970", () => {
|
|
1280
|
+
const item: UserNotificationEmailRollupItem = makeItem({
|
|
1281
|
+
createdAt: at(0),
|
|
1282
|
+
subject: "No timestamp",
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1285
|
+
delete (item as unknown as { createdAt?: Date }).createdAt;
|
|
1286
|
+
|
|
1287
|
+
const email: RollupEmail = build([item]);
|
|
1288
|
+
|
|
1289
|
+
expect(varString(email, "summaryWindow")).toBe("");
|
|
1290
|
+
expect(rowField(varRows(email)[0]!, "metaLabel")).not.toContain("1970");
|
|
1291
|
+
});
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
describe("buildRollupEmail subject category summary", () => {
|
|
1295
|
+
type SpreadFunction = (
|
|
1296
|
+
counts: Array<[RollupCategory, number]>,
|
|
1297
|
+
) => Array<UserNotificationEmailRollupItem>;
|
|
1298
|
+
|
|
1299
|
+
const spread: SpreadFunction = (
|
|
1300
|
+
counts: Array<[RollupCategory, number]>,
|
|
1301
|
+
): Array<UserNotificationEmailRollupItem> => {
|
|
1302
|
+
const items: Array<UserNotificationEmailRollupItem> = [];
|
|
1303
|
+
|
|
1304
|
+
for (const [category, count] of counts) {
|
|
1305
|
+
for (let index: number = 0; index < count; index++) {
|
|
1306
|
+
items.push(
|
|
1307
|
+
makeItem({
|
|
1308
|
+
createdAt: at(items.length * 60),
|
|
1309
|
+
subject: `${category} ${index}`,
|
|
1310
|
+
viewLink: `https://oneuptime.example.com/dashboard/p1/r/${category}/${index}`,
|
|
1311
|
+
rollupCategory: category,
|
|
1312
|
+
}),
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
return items;
|
|
1318
|
+
};
|
|
1319
|
+
|
|
1320
|
+
test("the subject names what kind of storm this is, biggest category first", () => {
|
|
1321
|
+
const subject: string = build(
|
|
1322
|
+
spread([
|
|
1323
|
+
[RollupCategory.Monitors, 2],
|
|
1324
|
+
[RollupCategory.Incidents, 5],
|
|
1325
|
+
]),
|
|
1326
|
+
).subject;
|
|
1327
|
+
|
|
1328
|
+
expect(subject).toBe("[Acme] 7 notifications: 5 Incidents, 2 Monitors");
|
|
1329
|
+
});
|
|
1330
|
+
|
|
1331
|
+
test("at most ROLLUP_SUBJECT_MAX_CATEGORIES are named, and the rest are counted", () => {
|
|
1332
|
+
const subject: string = build(
|
|
1333
|
+
spread([
|
|
1334
|
+
[RollupCategory.Incidents, 5],
|
|
1335
|
+
[RollupCategory.Monitors, 4],
|
|
1336
|
+
[RollupCategory.Alerts, 3],
|
|
1337
|
+
[RollupCategory.Probes, 2],
|
|
1338
|
+
[RollupCategory.StatusPages, 1],
|
|
1339
|
+
]),
|
|
1340
|
+
).subject;
|
|
1341
|
+
|
|
1342
|
+
expect(subject).toBe(
|
|
1343
|
+
"[Acme] 15 notifications: 5 Incidents, 4 Monitors, 3 Alerts +2 more",
|
|
1344
|
+
);
|
|
1345
|
+
expect(subject.split(", ")).toHaveLength(ROLLUP_SUBJECT_MAX_CATEGORIES);
|
|
1346
|
+
});
|
|
1347
|
+
|
|
1348
|
+
test("exactly ROLLUP_SUBJECT_MAX_CATEGORIES categories claims nothing is left over", () => {
|
|
1349
|
+
const subject: string = build(
|
|
1350
|
+
spread([
|
|
1351
|
+
[RollupCategory.Incidents, 3],
|
|
1352
|
+
[RollupCategory.Monitors, 2],
|
|
1353
|
+
[RollupCategory.Alerts, 1],
|
|
1354
|
+
]),
|
|
1355
|
+
).subject;
|
|
1356
|
+
|
|
1357
|
+
expect(subject).toBe(
|
|
1358
|
+
"[Acme] 6 notifications: 3 Incidents, 2 Monitors, 1 Alerts",
|
|
1359
|
+
);
|
|
1360
|
+
expect(subject).not.toContain("+");
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
test("the subject's counts are the summary card's counts", () => {
|
|
1364
|
+
const items: Array<UserNotificationEmailRollupItem> = spread([
|
|
1365
|
+
[RollupCategory.Incidents, 5],
|
|
1366
|
+
[RollupCategory.Monitors, 2],
|
|
1367
|
+
]);
|
|
1368
|
+
|
|
1369
|
+
const email: RollupEmail = build(items);
|
|
1370
|
+
|
|
1371
|
+
expect(email.subject).toContain("5 Incidents, 2 Monitors");
|
|
1372
|
+
expect(varString(email, "categoryCounts")).toBe("5 Incidents · 2 Monitors");
|
|
1373
|
+
});
|
|
1374
|
+
|
|
1375
|
+
test("a one-notification rollup still leads with the title, not with a category", () => {
|
|
1376
|
+
expect(
|
|
1377
|
+
build([makeItem({ createdAt: at(0), subject: "Checkout is down" })])
|
|
1378
|
+
.subject,
|
|
1379
|
+
).toBe("[Acme] 1 notification: Checkout is down");
|
|
1380
|
+
});
|
|
1381
|
+
});
|
|
1382
|
+
|
|
1383
|
+
describe("buildRollupEmail raw and pre-escaped vars stay on their own side", () => {
|
|
1384
|
+
test("every RAW var is free of the entities a double stache would escape twice", () => {
|
|
1385
|
+
const email: RollupEmail = build(
|
|
1386
|
+
[
|
|
1387
|
+
makeItem({ createdAt: at(0), subject: "a" }),
|
|
1388
|
+
makeItem({ createdAt: at(60), subject: "b" }),
|
|
1389
|
+
],
|
|
1390
|
+
'A&B <"Corp">',
|
|
1391
|
+
);
|
|
1392
|
+
|
|
1393
|
+
for (const name of RAW_VAR_NAMES) {
|
|
1394
|
+
const value: string = varString(email, name);
|
|
1395
|
+
|
|
1396
|
+
expect(value).not.toContain("&");
|
|
1397
|
+
expect(value).not.toContain("<");
|
|
1398
|
+
expect(value).not.toContain(""");
|
|
1399
|
+
expect(value).not.toContain("'");
|
|
1400
|
+
}
|
|
1401
|
+
});
|
|
1402
|
+
|
|
1403
|
+
test("the raw and pre-escaped lists together cover every string var the builder sets", () => {
|
|
1404
|
+
const email: RollupEmail = build([
|
|
1405
|
+
makeItem({ createdAt: at(0), subject: "a" }),
|
|
1406
|
+
]);
|
|
1407
|
+
|
|
1408
|
+
const stringVars: Array<string> = Object.keys(email.vars).filter(
|
|
1409
|
+
(name: string): boolean => {
|
|
1410
|
+
return typeof email.vars[name] === "string";
|
|
1411
|
+
},
|
|
1412
|
+
);
|
|
1413
|
+
|
|
1414
|
+
const classified: Array<string> = [
|
|
1415
|
+
...RAW_VAR_NAMES,
|
|
1416
|
+
...HTML_VAR_NAMES,
|
|
1417
|
+
/* Links, which are neither: they go in an href and are never prose. */
|
|
1418
|
+
"projectHomeLink",
|
|
1419
|
+
"preferencesLink",
|
|
1420
|
+
/* A flag the template compares against a literal. */
|
|
1421
|
+
"hasMore",
|
|
1422
|
+
];
|
|
1423
|
+
|
|
1424
|
+
for (const name of stringVars) {
|
|
1425
|
+
expect(classified).toContain(name);
|
|
1426
|
+
}
|
|
1427
|
+
});
|
|
1428
|
+
});
|