@oneuptime/common 12.0.33 → 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/DatabaseModels/AlertCustomField.ts +77 -3
- package/Models/DatabaseModels/ApiKeyPermission.ts +3 -27
- package/Models/DatabaseModels/IncidentCustomField.ts +77 -3
- package/Models/DatabaseModels/InventoryItemCustomField.ts +77 -3
- package/Models/DatabaseModels/MonitorCustomField.ts +77 -3
- 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/TelemetryIngestionKey.ts +260 -0
- package/Models/DatabaseModels/UserTelegram.ts +0 -4
- package/Scripts/benchmark-fanin-capacity.js +181 -0
- 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 +35 -2
- 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 +8 -0
- package/Server/Infrastructure/QueueWorker.ts +20 -14
- package/Server/Infrastructure/Semaphore.ts +2 -0
- package/Server/Middleware/TelemetryIngest.ts +453 -7
- 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/GlobalConfigService.ts +194 -0
- package/Server/Services/IncidentCustomFieldService.ts +98 -0
- package/Server/Services/IncidentService.ts +35 -0
- package/Server/Services/MetricService.ts +194 -0
- package/Server/Services/MonitorService.ts +32 -0
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +78 -25
- package/Server/Services/ProjectService.ts +22 -0
- 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/TeamMemberService.ts +78 -0
- package/Server/Services/TeamPermissionService.ts +235 -3
- package/Server/Services/TelemetryIngestionKeyService.ts +722 -19
- package/Server/Services/UserNotificationSettingService.ts +34 -6
- package/Server/Services/UserTelegramService.ts +326 -5
- package/Server/Types/Database/QueryHelper.ts +2 -0
- package/Server/Utils/APIKey/AccessPermission.ts +5 -2
- 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/EmailRollup/EmailRollupConstants.ts +38 -5
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +57 -4
- package/Server/Utils/FrontendEnvironment.ts +40 -0
- package/Server/Utils/LogRedaction.ts +20 -0
- package/Server/Utils/Logger.ts +11 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +338 -77
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +30 -4
- package/Server/Utils/Monitor/MonitorAlert.ts +29 -6
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +110 -15
- package/Server/Utils/Monitor/MonitorIncident.ts +22 -6
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +29 -0
- package/Server/Utils/Monitor/SeriesContextEnricher.ts +304 -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 +2 -17
- package/Server/Utils/TelegramVerificationToken.ts +185 -0
- package/Server/Utils/Telemetry/PinServiceName.ts +197 -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/VM/VMAPI.ts +1 -0
- package/Server/Utils/VM/VMRunner.ts +975 -95
- package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +202 -0
- package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +404 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +468 -0
- package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +399 -0
- package/Tests/App/StatusPage/StatusPageLastUpdated.test.tsx +263 -0
- 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/ResponsiveVisibility.test.ts +115 -0
- package/Tests/ResponsiveVisibility.ts +183 -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/SessionReplayRecordEverySessionByDefaultMigration.test.ts +169 -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/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/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/GlobalConfigService.test.ts +414 -1
- package/Tests/Server/Services/MetricRawEntityKeyPrune.test.ts +592 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +226 -1
- package/Tests/Server/Services/RoutineEmailSettingsPostgres.test.ts +329 -0
- package/Tests/Server/Services/RumSessionReplayViewService.test.ts +267 -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/UserNotificationSettingRollupRouting.test.ts +141 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +18 -10
- package/Tests/Server/Services/UserTelegramVerificationSecurity.test.ts +688 -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/CustomField/CustomFieldMappingValidator.test.ts +437 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +300 -11
- package/Tests/Server/Utils/EmailRollup/EmailRollupBurstWindow.test.ts +83 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1 -1
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerPreferences.test.ts +362 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +77 -1
- 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/Monitor/Criteria/CompareCriteriaAggregation.test.ts +584 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestHeaderCriteria.test.ts +236 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +437 -0
- package/Tests/Server/Utils/Monitor/MonitorTemplateUtilSeriesContext.test.ts +176 -0
- package/Tests/Server/Utils/Monitor/SeriesContextEnricher.test.ts +356 -0
- package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +595 -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/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/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/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/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/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/WebsiteRequest.test.ts +285 -3
- 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 +28 -12
- package/Tests/UI/Components/ShortcutDialogGuard.test.tsx +74 -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/Utils/API.test.ts +308 -0
- package/Tests/Utils/HTTPResponseBodyReader.test.ts +323 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryScanStatus.test.ts +117 -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/OriginAllowList.test.ts +633 -0
- package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +461 -0
- package/Tests/Utils/ValueFormatter.test.ts +148 -0
- package/Types/CustomField/CustomFieldMappingCatalog.ts +161 -0
- package/Types/CustomField/CustomFieldMappingSourceResource.ts +19 -0
- package/Types/CustomField/CustomFieldValueMapping.ts +288 -0
- package/Types/Icon/IconProp.ts +1 -0
- package/Types/JSONFunctions.ts +189 -43
- package/Types/Monitor/CephAlertTemplates.ts +157 -195
- 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/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/UptimeHistoryLabels.ts +56 -0
- package/Types/NotificationSetting/RoutineEmailEvents.ts +30 -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/TelemetryIngestSurface.ts +95 -0
- package/Types/Telemetry/TelemetryIngestionKeyPolicy.ts +75 -0
- package/Types/Telemetry/TelemetryIngestionKeyType.ts +29 -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/CustomFields/CustomFieldsDetail.tsx +143 -25
- package/UI/Components/CustomFields/MapFromCustomFieldInput.tsx +216 -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/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 +44 -0
- 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/Telemetry/BrowserTelemetryConfig.ts +28 -0
- package/UI/Utils/Telemetry/Telemetry.ts +10 -8
- package/Utils/API.ts +129 -3
- package/Utils/HTTPResponseBodyReader.ts +221 -0
- package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +77 -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/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/IncidentCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/IncidentCustomField.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/MonitorCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/MonitorCustomField.js.map +1 -1
- 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/TelemetryIngestionKey.js +267 -0
- package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserTelegram.js +0 -4
- package/build/dist/Models/DatabaseModels/UserTelegram.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 +29 -2
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- 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 +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +19 -7
- 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/TelemetryIngest.js +315 -8
- package/build/dist/Server/Middleware/TelemetryIngest.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/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/MetricService.js +163 -0
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +29 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +79 -27
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +22 -0
- 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/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/UserNotificationSettingService.js +26 -6
- package/build/dist/Server/Services/UserNotificationSettingService.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.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/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/EmailRollup/EmailRollupConstants.js +38 -5
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +44 -2
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
- package/build/dist/Server/Utils/FrontendEnvironment.js +33 -0
- package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -0
- package/build/dist/Server/Utils/LogRedaction.js +20 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
- package/build/dist/Server/Utils/Logger.js +10 -0
- 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/IncomingRequestCriteria.js +20 -4
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.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/MonitorCriteriaEvaluator.js +88 -13
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.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/MonitorTemplateUtil.js +22 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.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/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 +3 -14
- 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/PinServiceName.js +163 -0
- package/build/dist/Server/Utils/Telemetry/PinServiceName.js.map +1 -0
- 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/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/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/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/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/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/UptimeHistoryLabels.js +17 -0
- package/build/dist/Types/Monitor/UptimeHistoryLabels.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/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/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/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/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/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/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 +38 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.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/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/Utils/API.js +67 -5
- package/build/dist/Utils/API.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/NetworkDiscovery/DiscoveryScanStatus.js +69 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.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 +1 -1
|
@@ -0,0 +1,850 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test } from "@jest/globals";
|
|
2
|
+
import CustomFieldMappingSourceResource from "../../../Types/CustomField/CustomFieldMappingSourceResource";
|
|
3
|
+
import CustomFieldType from "../../../Types/CustomField/CustomFieldType";
|
|
4
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
5
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
6
|
+
import Alert from "../../../Models/DatabaseModels/Alert";
|
|
7
|
+
import AlertCustomField from "../../../Models/DatabaseModels/AlertCustomField";
|
|
8
|
+
import Incident from "../../../Models/DatabaseModels/Incident";
|
|
9
|
+
import IncidentCustomField from "../../../Models/DatabaseModels/IncidentCustomField";
|
|
10
|
+
import Monitor from "../../../Models/DatabaseModels/Monitor";
|
|
11
|
+
import AlertService from "../../../Server/Services/AlertService";
|
|
12
|
+
import AlertCustomFieldService from "../../../Server/Services/AlertCustomFieldService";
|
|
13
|
+
import IncidentService from "../../../Server/Services/IncidentService";
|
|
14
|
+
import IncidentCustomFieldService from "../../../Server/Services/IncidentCustomFieldService";
|
|
15
|
+
import MonitorService from "../../../Server/Services/MonitorService";
|
|
16
|
+
import ScheduledMaintenanceService from "../../../Server/Services/ScheduledMaintenanceService";
|
|
17
|
+
import ScheduledMaintenanceCustomFieldService from "../../../Server/Services/ScheduledMaintenanceCustomFieldService";
|
|
18
|
+
import CustomFieldMappingService from "../../../Server/Services/CustomFieldMappingService";
|
|
19
|
+
import CreateBy from "../../../Server/Types/Database/CreateBy";
|
|
20
|
+
import UpdateBy from "../../../Server/Types/Database/UpdateBy";
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* The engine behind "copy this custom field's value from the monitor"
|
|
24
|
+
* (OneUptime/oneuptime#3549).
|
|
25
|
+
*
|
|
26
|
+
* Two properties matter more than any individual behaviour and are asserted
|
|
27
|
+
* from several directions below:
|
|
28
|
+
*
|
|
29
|
+
* 1. It never destroys a value. No source record, no source definition and
|
|
30
|
+
* an empty source value all mean "leave the target alone". The scenario
|
|
31
|
+
* this guards is the natural first action after the feature ships —
|
|
32
|
+
* turning a mapping on for a field a project has been typing in by hand,
|
|
33
|
+
* before any monitor has a value for it.
|
|
34
|
+
*
|
|
35
|
+
* 2. It writes derived data as derived data: hook-free, compare-and-set
|
|
36
|
+
* against the bag it resolved from, and without touching `updatedAt`.
|
|
37
|
+
* Otherwise one monitor edit fires a workflow POST, a realtime emit and
|
|
38
|
+
* an audit insert per alert, and restamps `updatedAt` across years of
|
|
39
|
+
* resolved alerts.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
43
|
+
"11111111-1111-4111-8111-111111111111",
|
|
44
|
+
);
|
|
45
|
+
const MONITOR_ID: ObjectID = new ObjectID(
|
|
46
|
+
"22222222-2222-4222-8222-222222222222",
|
|
47
|
+
);
|
|
48
|
+
const OTHER_MONITOR_ID: ObjectID = new ObjectID(
|
|
49
|
+
"33333333-3333-4333-8333-333333333333",
|
|
50
|
+
);
|
|
51
|
+
const ALERT_ID: ObjectID = new ObjectID("44444444-4444-4444-8444-444444444444");
|
|
52
|
+
const INCIDENT_ID: ObjectID = new ObjectID(
|
|
53
|
+
"55555555-5555-4555-8555-555555555555",
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
interface DefinitionFixture {
|
|
57
|
+
name: string;
|
|
58
|
+
customFieldType?: CustomFieldType | undefined;
|
|
59
|
+
mapFromResourceType?: string | undefined;
|
|
60
|
+
mapFromCustomFieldName?: string | undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
type BuildDefinitionsFunction = (
|
|
64
|
+
fixtures: Array<DefinitionFixture>,
|
|
65
|
+
) => Array<AlertCustomField>;
|
|
66
|
+
|
|
67
|
+
const buildDefinitions: BuildDefinitionsFunction = (
|
|
68
|
+
fixtures: Array<DefinitionFixture>,
|
|
69
|
+
): Array<AlertCustomField> => {
|
|
70
|
+
return fixtures.map((fixture: DefinitionFixture): AlertCustomField => {
|
|
71
|
+
/*
|
|
72
|
+
* Assigned through Object.assign because `exactOptionalPropertyTypes`
|
|
73
|
+
* rejects writing an explicit `undefined` into an optional model property,
|
|
74
|
+
* and "this fixture leaves the field unset" is exactly what several cases
|
|
75
|
+
* below are testing.
|
|
76
|
+
*/
|
|
77
|
+
return Object.assign(new AlertCustomField(), fixture);
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
type BuildMonitorFunction = (
|
|
82
|
+
id: ObjectID,
|
|
83
|
+
customFields?: JSONObject | undefined,
|
|
84
|
+
) => Monitor;
|
|
85
|
+
|
|
86
|
+
const buildMonitor: BuildMonitorFunction = (
|
|
87
|
+
id: ObjectID,
|
|
88
|
+
customFields?: JSONObject | undefined,
|
|
89
|
+
): Monitor => {
|
|
90
|
+
const monitor: Monitor = new Monitor();
|
|
91
|
+
monitor._id = id.toString();
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
* Only set when the caller has one. A monitor read WITHOUT its customFields
|
|
95
|
+
* must not look like a monitor whose bag is empty — that distinction is what
|
|
96
|
+
* decides whether the resolver can use the payload or has to query.
|
|
97
|
+
*/
|
|
98
|
+
if (customFields) {
|
|
99
|
+
monitor.customFields = customFields;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return monitor;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const VENDOR_MAPPING: Array<DefinitionFixture> = [
|
|
106
|
+
{
|
|
107
|
+
name: "Vendor",
|
|
108
|
+
customFieldType: CustomFieldType.Text,
|
|
109
|
+
mapFromResourceType: CustomFieldMappingSourceResource.Monitor,
|
|
110
|
+
mapFromCustomFieldName: "Vendor",
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
type StubAlertDefinitionsFunction = (
|
|
115
|
+
fixtures: Array<DefinitionFixture>,
|
|
116
|
+
) => jest.SpyInstance;
|
|
117
|
+
|
|
118
|
+
const stubAlertDefinitions: StubAlertDefinitionsFunction = (
|
|
119
|
+
fixtures: Array<DefinitionFixture>,
|
|
120
|
+
): jest.SpyInstance => {
|
|
121
|
+
return jest
|
|
122
|
+
.spyOn(AlertCustomFieldService, "findBy")
|
|
123
|
+
.mockResolvedValue(buildDefinitions(fixtures) as never);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
type BuildAlertCreateByFunction = (data: Partial<Alert>) => CreateBy<Alert>;
|
|
127
|
+
|
|
128
|
+
const buildAlertCreateBy: BuildAlertCreateByFunction = (
|
|
129
|
+
data: Partial<Alert>,
|
|
130
|
+
): CreateBy<Alert> => {
|
|
131
|
+
const alert: Alert = new Alert();
|
|
132
|
+
Object.assign(alert, data);
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
data: alert,
|
|
136
|
+
props: { isRoot: true, tenantId: PROJECT_ID },
|
|
137
|
+
} as CreateBy<Alert>;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
afterEach(() => {
|
|
141
|
+
jest.restoreAllMocks();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("CustomFieldMappingService.applyMappingsToCreate", () => {
|
|
145
|
+
test("stamps the monitor's value onto a new alert", async () => {
|
|
146
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
147
|
+
jest
|
|
148
|
+
.spyOn(MonitorService, "findBy")
|
|
149
|
+
.mockResolvedValue([
|
|
150
|
+
buildMonitor(MONITOR_ID, { Vendor: "Acme" }),
|
|
151
|
+
] as never);
|
|
152
|
+
|
|
153
|
+
const createBy: CreateBy<Alert> = buildAlertCreateBy({
|
|
154
|
+
monitorId: MONITOR_ID,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
158
|
+
definitionModelType: AlertCustomField,
|
|
159
|
+
createBy: createBy,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
expect(createBy.data.customFields).toEqual({ Vendor: "Acme" });
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
/*
|
|
166
|
+
* The hottest creation path in the product is a monitor criterion opening an
|
|
167
|
+
* alert, and it assigns the whole Monitor — already read with its
|
|
168
|
+
* customFields for metric attributes. Taking the bag from there is what
|
|
169
|
+
* keeps the ingest path free of an extra query per alert.
|
|
170
|
+
*/
|
|
171
|
+
test("uses a monitor already hydrated on the payload instead of querying", async () => {
|
|
172
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
173
|
+
const findMonitors: jest.SpyInstance = jest
|
|
174
|
+
.spyOn(MonitorService, "findBy")
|
|
175
|
+
.mockResolvedValue([] as never);
|
|
176
|
+
|
|
177
|
+
const createBy: CreateBy<Alert> = buildAlertCreateBy({
|
|
178
|
+
monitor: buildMonitor(MONITOR_ID, { Vendor: "Acme" }),
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
182
|
+
definitionModelType: AlertCustomField,
|
|
183
|
+
createBy: createBy,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
expect(createBy.data.customFields).toEqual({ Vendor: "Acme" });
|
|
187
|
+
expect(findMonitors).not.toHaveBeenCalled();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
/*
|
|
191
|
+
* A monitor supplied as a bare id stub carries no bag. Treating its missing
|
|
192
|
+
* customFields as "empty" instead of "unknown" skips the lookup and silently
|
|
193
|
+
* inherits nothing — which is what an earlier `hasOwnProperty` check did,
|
|
194
|
+
* because every model class initialises its columns in the class body and so
|
|
195
|
+
* a bare `new Monitor()` already owns the property.
|
|
196
|
+
*/
|
|
197
|
+
test("looks the monitor up when the payload carries only an id stub", async () => {
|
|
198
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
199
|
+
const findMonitors: jest.SpyInstance = jest
|
|
200
|
+
.spyOn(MonitorService, "findBy")
|
|
201
|
+
.mockResolvedValue([
|
|
202
|
+
buildMonitor(MONITOR_ID, { Vendor: "Acme" }),
|
|
203
|
+
] as never);
|
|
204
|
+
|
|
205
|
+
const stub: Monitor = new Monitor();
|
|
206
|
+
stub._id = MONITOR_ID.toString();
|
|
207
|
+
|
|
208
|
+
const createBy: CreateBy<Alert> = buildAlertCreateBy({ monitor: stub });
|
|
209
|
+
|
|
210
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
211
|
+
definitionModelType: AlertCustomField,
|
|
212
|
+
createBy: createBy,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
expect(findMonitors).toHaveBeenCalled();
|
|
216
|
+
expect(createBy.data.customFields).toEqual({ Vendor: "Acme" });
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
/*
|
|
220
|
+
* The other side of that distinction: a monitor read WITH its customFields
|
|
221
|
+
* whose column is NULL in Postgres arrives with the property set to null.
|
|
222
|
+
* That is a real answer — the monitor has no value — and must not trigger a
|
|
223
|
+
* second lookup that would return the same nothing.
|
|
224
|
+
*/
|
|
225
|
+
test("treats a monitor read with an empty bag as answered, without querying", async () => {
|
|
226
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
227
|
+
const findMonitors: jest.SpyInstance = jest
|
|
228
|
+
.spyOn(MonitorService, "findBy")
|
|
229
|
+
.mockResolvedValue([] as never);
|
|
230
|
+
|
|
231
|
+
const readButEmpty: Monitor = new Monitor();
|
|
232
|
+
readButEmpty._id = MONITOR_ID.toString();
|
|
233
|
+
readButEmpty.customFields = null as unknown as JSONObject;
|
|
234
|
+
|
|
235
|
+
const createBy: CreateBy<Alert> = buildAlertCreateBy({
|
|
236
|
+
monitor: readButEmpty,
|
|
237
|
+
customFields: { Vendor: "Typed by hand" },
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
241
|
+
definitionModelType: AlertCustomField,
|
|
242
|
+
createBy: createBy,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
expect(findMonitors).not.toHaveBeenCalled();
|
|
246
|
+
expect(createBy.data.customFields).toEqual({ Vendor: "Typed by hand" });
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test("leaves the bag alone when the project has no mappings", async () => {
|
|
250
|
+
stubAlertDefinitions([
|
|
251
|
+
{ name: "Vendor", customFieldType: CustomFieldType.Text },
|
|
252
|
+
]);
|
|
253
|
+
const findMonitors: jest.SpyInstance = jest
|
|
254
|
+
.spyOn(MonitorService, "findBy")
|
|
255
|
+
.mockResolvedValue([] as never);
|
|
256
|
+
|
|
257
|
+
const createBy: CreateBy<Alert> = buildAlertCreateBy({
|
|
258
|
+
monitorId: MONITOR_ID,
|
|
259
|
+
customFields: { Vendor: "Typed by hand" },
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
263
|
+
definitionModelType: AlertCustomField,
|
|
264
|
+
createBy: createBy,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
expect(createBy.data.customFields).toEqual({ Vendor: "Typed by hand" });
|
|
268
|
+
expect(findMonitors).not.toHaveBeenCalled();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
/*
|
|
272
|
+
* SLO burn-rate alerts, security-event alerts and network-site rollup alerts
|
|
273
|
+
* are all created with no monitor at all.
|
|
274
|
+
*/
|
|
275
|
+
test("leaves the bag alone when the alert has no monitor", async () => {
|
|
276
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
277
|
+
|
|
278
|
+
const createBy: CreateBy<Alert> = buildAlertCreateBy({
|
|
279
|
+
customFields: { Vendor: "Typed by hand" },
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
283
|
+
definitionModelType: AlertCustomField,
|
|
284
|
+
createBy: createBy,
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
expect(createBy.data.customFields).toEqual({ Vendor: "Typed by hand" });
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("leaves the bag alone when the monitor holds no value for the source field", async () => {
|
|
291
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
292
|
+
jest
|
|
293
|
+
.spyOn(MonitorService, "findBy")
|
|
294
|
+
.mockResolvedValue([buildMonitor(MONITOR_ID, { Other: "x" })] as never);
|
|
295
|
+
|
|
296
|
+
const createBy: CreateBy<Alert> = buildAlertCreateBy({
|
|
297
|
+
monitorId: MONITOR_ID,
|
|
298
|
+
customFields: { Vendor: "Typed by hand" },
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
302
|
+
definitionModelType: AlertCustomField,
|
|
303
|
+
createBy: createBy,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
expect(createBy.data.customFields).toEqual({ Vendor: "Typed by hand" });
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
test("does not touch custom fields the mapping does not own", async () => {
|
|
310
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
311
|
+
jest
|
|
312
|
+
.spyOn(MonitorService, "findBy")
|
|
313
|
+
.mockResolvedValue([
|
|
314
|
+
buildMonitor(MONITOR_ID, { Vendor: "Acme" }),
|
|
315
|
+
] as never);
|
|
316
|
+
|
|
317
|
+
const createBy: CreateBy<Alert> = buildAlertCreateBy({
|
|
318
|
+
monitorId: MONITOR_ID,
|
|
319
|
+
customFields: { Owner: "kate" },
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
323
|
+
definitionModelType: AlertCustomField,
|
|
324
|
+
createBy: createBy,
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
expect(createBy.data.customFields).toEqual({
|
|
328
|
+
Owner: "kate",
|
|
329
|
+
Vendor: "Acme",
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test("a mapping pointing at a field the monitor never defined writes nothing", async () => {
|
|
334
|
+
stubAlertDefinitions([
|
|
335
|
+
{
|
|
336
|
+
name: "Vendor",
|
|
337
|
+
customFieldType: CustomFieldType.Text,
|
|
338
|
+
mapFromResourceType: CustomFieldMappingSourceResource.Monitor,
|
|
339
|
+
mapFromCustomFieldName: "Supplier",
|
|
340
|
+
},
|
|
341
|
+
]);
|
|
342
|
+
jest
|
|
343
|
+
.spyOn(MonitorService, "findBy")
|
|
344
|
+
.mockResolvedValue([
|
|
345
|
+
buildMonitor(MONITOR_ID, { Vendor: "Acme" }),
|
|
346
|
+
] as never);
|
|
347
|
+
|
|
348
|
+
const createBy: CreateBy<Alert> = buildAlertCreateBy({
|
|
349
|
+
monitorId: MONITOR_ID,
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
353
|
+
definitionModelType: AlertCustomField,
|
|
354
|
+
createBy: createBy,
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
expect(createBy.data.customFields).toBeUndefined();
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
/*
|
|
361
|
+
* A failure to inherit a custom field must never stop an alert being opened,
|
|
362
|
+
* so the whole path is written not to throw.
|
|
363
|
+
*/
|
|
364
|
+
test("swallows a failure reading the definitions", async () => {
|
|
365
|
+
jest
|
|
366
|
+
.spyOn(AlertCustomFieldService, "findBy")
|
|
367
|
+
.mockRejectedValue(new Error("database is down") as never);
|
|
368
|
+
|
|
369
|
+
const createBy: CreateBy<Alert> = buildAlertCreateBy({
|
|
370
|
+
monitorId: MONITOR_ID,
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
await expect(
|
|
374
|
+
CustomFieldMappingService.applyMappingsToCreate({
|
|
375
|
+
definitionModelType: AlertCustomField,
|
|
376
|
+
createBy: createBy,
|
|
377
|
+
}),
|
|
378
|
+
).resolves.toBeUndefined();
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
describe("CustomFieldMappingService.applyMappingsToCreate for many-source resources", () => {
|
|
383
|
+
type BuildIncidentCreateByFunction = (
|
|
384
|
+
monitors: Array<Monitor>,
|
|
385
|
+
) => CreateBy<Incident>;
|
|
386
|
+
|
|
387
|
+
const buildIncidentCreateBy: BuildIncidentCreateByFunction = (
|
|
388
|
+
monitors: Array<Monitor>,
|
|
389
|
+
): CreateBy<Incident> => {
|
|
390
|
+
const incident: Incident = new Incident();
|
|
391
|
+
incident.monitors = monitors;
|
|
392
|
+
|
|
393
|
+
return {
|
|
394
|
+
data: incident,
|
|
395
|
+
props: { isRoot: true, tenantId: PROJECT_ID },
|
|
396
|
+
} as CreateBy<Incident>;
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
const INCIDENT_VENDOR_MAPPING: Array<IncidentCustomField> = [
|
|
400
|
+
Object.assign(new IncidentCustomField(), {
|
|
401
|
+
name: "Vendor",
|
|
402
|
+
customFieldType: CustomFieldType.Text,
|
|
403
|
+
mapFromResourceType: CustomFieldMappingSourceResource.Monitor,
|
|
404
|
+
mapFromCustomFieldName: "Vendor",
|
|
405
|
+
}),
|
|
406
|
+
];
|
|
407
|
+
|
|
408
|
+
test("uses the value every attached monitor agrees on", async () => {
|
|
409
|
+
jest
|
|
410
|
+
.spyOn(IncidentCustomFieldService, "findBy")
|
|
411
|
+
.mockResolvedValue(INCIDENT_VENDOR_MAPPING as never);
|
|
412
|
+
jest
|
|
413
|
+
.spyOn(MonitorService, "findBy")
|
|
414
|
+
.mockResolvedValue([
|
|
415
|
+
buildMonitor(MONITOR_ID, { Vendor: "Acme" }),
|
|
416
|
+
buildMonitor(OTHER_MONITOR_ID, { Vendor: "Acme" }),
|
|
417
|
+
] as never);
|
|
418
|
+
|
|
419
|
+
const createBy: CreateBy<Incident> = buildIncidentCreateBy([
|
|
420
|
+
buildMonitor(MONITOR_ID),
|
|
421
|
+
buildMonitor(OTHER_MONITOR_ID),
|
|
422
|
+
]);
|
|
423
|
+
|
|
424
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
425
|
+
definitionModelType: IncidentCustomField,
|
|
426
|
+
createBy: createBy,
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
expect(createBy.data.customFields).toEqual({ Vendor: "Acme" });
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
/*
|
|
433
|
+
* The monitors relation carries no ORDER BY, so "the first one" is not a
|
|
434
|
+
* stable answer — choosing a winner would make the value flip on its own.
|
|
435
|
+
*/
|
|
436
|
+
test("writes nothing when the attached monitors disagree", async () => {
|
|
437
|
+
jest
|
|
438
|
+
.spyOn(IncidentCustomFieldService, "findBy")
|
|
439
|
+
.mockResolvedValue(INCIDENT_VENDOR_MAPPING as never);
|
|
440
|
+
jest
|
|
441
|
+
.spyOn(MonitorService, "findBy")
|
|
442
|
+
.mockResolvedValue([
|
|
443
|
+
buildMonitor(MONITOR_ID, { Vendor: "Acme" }),
|
|
444
|
+
buildMonitor(OTHER_MONITOR_ID, { Vendor: "Globex" }),
|
|
445
|
+
] as never);
|
|
446
|
+
|
|
447
|
+
const createBy: CreateBy<Incident> = buildIncidentCreateBy([
|
|
448
|
+
buildMonitor(MONITOR_ID),
|
|
449
|
+
buildMonitor(OTHER_MONITOR_ID),
|
|
450
|
+
]);
|
|
451
|
+
|
|
452
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
453
|
+
definitionModelType: IncidentCustomField,
|
|
454
|
+
createBy: createBy,
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
expect(createBy.data.customFields).toBeUndefined();
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
test("an incident with no monitors inherits nothing", async () => {
|
|
461
|
+
jest
|
|
462
|
+
.spyOn(IncidentCustomFieldService, "findBy")
|
|
463
|
+
.mockResolvedValue(INCIDENT_VENDOR_MAPPING as never);
|
|
464
|
+
const findMonitors: jest.SpyInstance = jest
|
|
465
|
+
.spyOn(MonitorService, "findBy")
|
|
466
|
+
.mockResolvedValue([] as never);
|
|
467
|
+
|
|
468
|
+
const createBy: CreateBy<Incident> = buildIncidentCreateBy([]);
|
|
469
|
+
|
|
470
|
+
await CustomFieldMappingService.applyMappingsToCreate({
|
|
471
|
+
definitionModelType: IncidentCustomField,
|
|
472
|
+
createBy: createBy,
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
expect(createBy.data.customFields).toBeUndefined();
|
|
476
|
+
expect(findMonitors).not.toHaveBeenCalled();
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
describe("CustomFieldMappingService.applyMappingsToUpdate", () => {
|
|
481
|
+
type BuildAlertUpdateByFunction = (data: JSONObject) => UpdateBy<Alert>;
|
|
482
|
+
|
|
483
|
+
const buildAlertUpdateBy: BuildAlertUpdateByFunction = (
|
|
484
|
+
data: JSONObject,
|
|
485
|
+
): UpdateBy<Alert> => {
|
|
486
|
+
return {
|
|
487
|
+
query: { _id: ALERT_ID.toString() },
|
|
488
|
+
data: data,
|
|
489
|
+
props: { isRoot: true, tenantId: PROJECT_ID },
|
|
490
|
+
limit: 1,
|
|
491
|
+
skip: 0,
|
|
492
|
+
} as unknown as UpdateBy<Alert>;
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
type StubAffectedAlertFunction = (alert: Partial<Alert>) => jest.SpyInstance;
|
|
496
|
+
|
|
497
|
+
const stubAffectedAlert: StubAffectedAlertFunction = (
|
|
498
|
+
alert: Partial<Alert>,
|
|
499
|
+
): jest.SpyInstance => {
|
|
500
|
+
const model: Alert = new Alert();
|
|
501
|
+
model._id = ALERT_ID.toString();
|
|
502
|
+
model.projectId = PROJECT_ID;
|
|
503
|
+
Object.assign(model, alert);
|
|
504
|
+
|
|
505
|
+
return jest
|
|
506
|
+
.spyOn(AlertService, "findBy")
|
|
507
|
+
.mockResolvedValue([model] as never);
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
/*
|
|
511
|
+
* The Custom Fields modal replaces the WHOLE bag — it has no server-side
|
|
512
|
+
* merge — so saving an unrelated field would otherwise drop the mapped one.
|
|
513
|
+
*/
|
|
514
|
+
test("restores a mapped value the caller's payload dropped", async () => {
|
|
515
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
516
|
+
stubAffectedAlert({
|
|
517
|
+
monitorId: MONITOR_ID,
|
|
518
|
+
customFields: { Vendor: "Acme", Owner: "kate" },
|
|
519
|
+
});
|
|
520
|
+
jest
|
|
521
|
+
.spyOn(MonitorService, "findBy")
|
|
522
|
+
.mockResolvedValue([
|
|
523
|
+
buildMonitor(MONITOR_ID, { Vendor: "Acme" }),
|
|
524
|
+
] as never);
|
|
525
|
+
|
|
526
|
+
const updateBy: UpdateBy<Alert> = buildAlertUpdateBy({
|
|
527
|
+
customFields: { Owner: "raj" },
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
await CustomFieldMappingService.applyMappingsToUpdate({
|
|
531
|
+
definitionModelType: AlertCustomField,
|
|
532
|
+
updateBy: updateBy,
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
expect((updateBy.data as JSONObject)["customFields"]).toEqual({
|
|
536
|
+
Owner: "raj",
|
|
537
|
+
Vendor: "Acme",
|
|
538
|
+
});
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
/*
|
|
542
|
+
* Re-pointing an alert at another monitor changes what the mapped field
|
|
543
|
+
* should hold, and the payload — not the stored row — is the new truth.
|
|
544
|
+
*/
|
|
545
|
+
test("recomputes from the new monitor when the alert is repointed", async () => {
|
|
546
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
547
|
+
stubAffectedAlert({
|
|
548
|
+
monitorId: MONITOR_ID,
|
|
549
|
+
customFields: { Vendor: "Acme" },
|
|
550
|
+
});
|
|
551
|
+
jest
|
|
552
|
+
.spyOn(MonitorService, "findBy")
|
|
553
|
+
.mockResolvedValue([
|
|
554
|
+
buildMonitor(OTHER_MONITOR_ID, { Vendor: "Globex" }),
|
|
555
|
+
] as never);
|
|
556
|
+
|
|
557
|
+
const updateBy: UpdateBy<Alert> = buildAlertUpdateBy({
|
|
558
|
+
monitorId: OTHER_MONITOR_ID,
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
await CustomFieldMappingService.applyMappingsToUpdate({
|
|
562
|
+
definitionModelType: AlertCustomField,
|
|
563
|
+
updateBy: updateBy,
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
expect((updateBy.data as JSONObject)["customFields"]).toEqual({
|
|
567
|
+
Vendor: "Globex",
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
test("recognises the relation-object spelling the dashboard posts", async () => {
|
|
572
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
573
|
+
stubAffectedAlert({ monitorId: MONITOR_ID, customFields: {} });
|
|
574
|
+
jest
|
|
575
|
+
.spyOn(MonitorService, "findBy")
|
|
576
|
+
.mockResolvedValue([
|
|
577
|
+
buildMonitor(OTHER_MONITOR_ID, { Vendor: "Globex" }),
|
|
578
|
+
] as never);
|
|
579
|
+
|
|
580
|
+
const updateBy: UpdateBy<Alert> = buildAlertUpdateBy({
|
|
581
|
+
monitor: { _id: OTHER_MONITOR_ID.toString() },
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
await CustomFieldMappingService.applyMappingsToUpdate({
|
|
585
|
+
definitionModelType: AlertCustomField,
|
|
586
|
+
updateBy: updateBy,
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
expect((updateBy.data as JSONObject)["customFields"]).toEqual({
|
|
590
|
+
Vendor: "Globex",
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
test("ignores an update that touches neither the bag nor the relation", async () => {
|
|
595
|
+
const definitions: jest.SpyInstance = stubAlertDefinitions(VENDOR_MAPPING);
|
|
596
|
+
const findAlerts: jest.SpyInstance = jest
|
|
597
|
+
.spyOn(AlertService, "findBy")
|
|
598
|
+
.mockResolvedValue([] as never);
|
|
599
|
+
|
|
600
|
+
const updateBy: UpdateBy<Alert> = buildAlertUpdateBy({ title: "New" });
|
|
601
|
+
|
|
602
|
+
await CustomFieldMappingService.applyMappingsToUpdate({
|
|
603
|
+
definitionModelType: AlertCustomField,
|
|
604
|
+
updateBy: updateBy,
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
expect((updateBy.data as JSONObject)["customFields"]).toBeUndefined();
|
|
608
|
+
expect(findAlerts).not.toHaveBeenCalled();
|
|
609
|
+
expect(definitions).not.toHaveBeenCalled();
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
/*
|
|
613
|
+
* One payload is shared by every row a query-based update matches, and two
|
|
614
|
+
* alerts can have different monitors — so there is no single correct
|
|
615
|
+
* customFields to fold in. Those rows are re-resolved individually instead.
|
|
616
|
+
*/
|
|
617
|
+
test("leaves the payload alone when the update matches more than one row", async () => {
|
|
618
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
619
|
+
|
|
620
|
+
const first: Alert = new Alert();
|
|
621
|
+
first._id = ALERT_ID.toString();
|
|
622
|
+
const second: Alert = new Alert();
|
|
623
|
+
second._id = OTHER_MONITOR_ID.toString();
|
|
624
|
+
|
|
625
|
+
jest
|
|
626
|
+
.spyOn(AlertService, "findBy")
|
|
627
|
+
.mockResolvedValue([first, second] as never);
|
|
628
|
+
|
|
629
|
+
const updateBy: UpdateBy<Alert> = buildAlertUpdateBy({
|
|
630
|
+
customFields: { Owner: "raj" },
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
await CustomFieldMappingService.applyMappingsToUpdate({
|
|
634
|
+
definitionModelType: AlertCustomField,
|
|
635
|
+
updateBy: updateBy,
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
expect((updateBy.data as JSONObject)["customFields"]).toEqual({
|
|
639
|
+
Owner: "raj",
|
|
640
|
+
});
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
test("does not restore a mapped value on an alert with no monitor", async () => {
|
|
644
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
645
|
+
stubAffectedAlert({ customFields: { Vendor: "Typed by hand" } });
|
|
646
|
+
|
|
647
|
+
const updateBy: UpdateBy<Alert> = buildAlertUpdateBy({
|
|
648
|
+
customFields: { Vendor: "Still typed by hand" },
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
await CustomFieldMappingService.applyMappingsToUpdate({
|
|
652
|
+
definitionModelType: AlertCustomField,
|
|
653
|
+
updateBy: updateBy,
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
expect((updateBy.data as JSONObject)["customFields"]).toEqual({
|
|
657
|
+
Vendor: "Still typed by hand",
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
describe("CustomFieldMappingService.propagateFromSourceRecord", () => {
|
|
663
|
+
type StubTargetsFunction = (alerts: Array<Alert>) => void;
|
|
664
|
+
|
|
665
|
+
const stubTargets: StubTargetsFunction = (alerts: Array<Alert>): void => {
|
|
666
|
+
jest.spyOn(AlertService, "findBy").mockResolvedValue(alerts as never);
|
|
667
|
+
jest.spyOn(IncidentService, "findBy").mockResolvedValue([] as never);
|
|
668
|
+
jest
|
|
669
|
+
.spyOn(ScheduledMaintenanceService, "findBy")
|
|
670
|
+
.mockResolvedValue([] as never);
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
/*
|
|
674
|
+
* A monitor change fans out to all three target resources; these tests are
|
|
675
|
+
* about the Alert leg, so the other two are configured with no mappings.
|
|
676
|
+
*/
|
|
677
|
+
type StubOtherTargetsHaveNoMappingsFunction = () => void;
|
|
678
|
+
|
|
679
|
+
const stubOtherTargetsHaveNoMappings: StubOtherTargetsHaveNoMappingsFunction =
|
|
680
|
+
(): void => {
|
|
681
|
+
jest
|
|
682
|
+
.spyOn(IncidentCustomFieldService, "findBy")
|
|
683
|
+
.mockResolvedValue([] as never);
|
|
684
|
+
jest
|
|
685
|
+
.spyOn(ScheduledMaintenanceCustomFieldService, "findBy")
|
|
686
|
+
.mockResolvedValue([] as never);
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
type BuildAlertFunction = (id: ObjectID, customFields: JSONObject) => Alert;
|
|
690
|
+
|
|
691
|
+
const buildAlert: BuildAlertFunction = (
|
|
692
|
+
id: ObjectID,
|
|
693
|
+
customFields: JSONObject,
|
|
694
|
+
): Alert => {
|
|
695
|
+
const alert: Alert = new Alert();
|
|
696
|
+
alert._id = id.toString();
|
|
697
|
+
alert.projectId = PROJECT_ID;
|
|
698
|
+
alert.monitorId = MONITOR_ID;
|
|
699
|
+
alert.customFields = customFields;
|
|
700
|
+
return alert;
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
/*
|
|
704
|
+
* The full update pipeline would fire a workflow POST, a realtime emit and
|
|
705
|
+
* an audit insert for every alert on the monitor. Derived data goes through
|
|
706
|
+
* the hook-free write instead, with a compare-and-set on the bag it was
|
|
707
|
+
* resolved from and without touching `updatedAt`.
|
|
708
|
+
*/
|
|
709
|
+
test("writes through the hook-free path with a compare-and-set and no updatedAt bump", async () => {
|
|
710
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
711
|
+
stubOtherTargetsHaveNoMappings();
|
|
712
|
+
|
|
713
|
+
stubTargets([buildAlert(ALERT_ID, { Vendor: "Old", Owner: "kate" })]);
|
|
714
|
+
jest
|
|
715
|
+
.spyOn(MonitorService, "findBy")
|
|
716
|
+
.mockResolvedValue([
|
|
717
|
+
buildMonitor(MONITOR_ID, { Vendor: "Acme" }),
|
|
718
|
+
] as never);
|
|
719
|
+
|
|
720
|
+
const write: jest.SpyInstance = jest
|
|
721
|
+
.spyOn(AlertService, "updateColumnsByIdWithoutHooks")
|
|
722
|
+
.mockResolvedValue(undefined as never);
|
|
723
|
+
|
|
724
|
+
await CustomFieldMappingService.propagateFromSourceRecord({
|
|
725
|
+
resource: CustomFieldMappingSourceResource.Monitor,
|
|
726
|
+
sourceId: MONITOR_ID,
|
|
727
|
+
projectId: PROJECT_ID,
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
expect(write).toHaveBeenCalledTimes(1);
|
|
731
|
+
|
|
732
|
+
const call: JSONObject = write.mock.calls[0]![0] as JSONObject;
|
|
733
|
+
|
|
734
|
+
expect((call["data"] as JSONObject)["customFields"]).toEqual({
|
|
735
|
+
Vendor: "Acme",
|
|
736
|
+
Owner: "kate",
|
|
737
|
+
});
|
|
738
|
+
expect((call["expectedData"] as JSONObject)["customFields"]).toEqual({
|
|
739
|
+
Vendor: "Old",
|
|
740
|
+
Owner: "kate",
|
|
741
|
+
});
|
|
742
|
+
expect(call["skipUpdateDateColumn"]).toBe(true);
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
test("does not write a row that already holds the right value", async () => {
|
|
746
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
747
|
+
stubOtherTargetsHaveNoMappings();
|
|
748
|
+
|
|
749
|
+
stubTargets([buildAlert(ALERT_ID, { Vendor: "Acme" })]);
|
|
750
|
+
jest
|
|
751
|
+
.spyOn(MonitorService, "findBy")
|
|
752
|
+
.mockResolvedValue([
|
|
753
|
+
buildMonitor(MONITOR_ID, { Vendor: "Acme" }),
|
|
754
|
+
] as never);
|
|
755
|
+
|
|
756
|
+
const write: jest.SpyInstance = jest
|
|
757
|
+
.spyOn(AlertService, "updateColumnsByIdWithoutHooks")
|
|
758
|
+
.mockResolvedValue(undefined as never);
|
|
759
|
+
|
|
760
|
+
await CustomFieldMappingService.propagateFromSourceRecord({
|
|
761
|
+
resource: CustomFieldMappingSourceResource.Monitor,
|
|
762
|
+
sourceId: MONITOR_ID,
|
|
763
|
+
projectId: PROJECT_ID,
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
expect(write).not.toHaveBeenCalled();
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
/*
|
|
770
|
+
* The single most dangerous thing this feature could do. Clearing the
|
|
771
|
+
* monitor's Vendor must not clear it on every alert that ever inherited it.
|
|
772
|
+
*/
|
|
773
|
+
test("clearing the source does not clear the copies", async () => {
|
|
774
|
+
stubAlertDefinitions(VENDOR_MAPPING);
|
|
775
|
+
stubOtherTargetsHaveNoMappings();
|
|
776
|
+
|
|
777
|
+
stubTargets([buildAlert(ALERT_ID, { Vendor: "Acme" })]);
|
|
778
|
+
jest
|
|
779
|
+
.spyOn(MonitorService, "findBy")
|
|
780
|
+
.mockResolvedValue([buildMonitor(MONITOR_ID, {})] as never);
|
|
781
|
+
|
|
782
|
+
const write: jest.SpyInstance = jest
|
|
783
|
+
.spyOn(AlertService, "updateColumnsByIdWithoutHooks")
|
|
784
|
+
.mockResolvedValue(undefined as never);
|
|
785
|
+
|
|
786
|
+
await CustomFieldMappingService.propagateFromSourceRecord({
|
|
787
|
+
resource: CustomFieldMappingSourceResource.Monitor,
|
|
788
|
+
sourceId: MONITOR_ID,
|
|
789
|
+
projectId: PROJECT_ID,
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
expect(write).not.toHaveBeenCalled();
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
test("a propagation failure for one resource does not stop the others", async () => {
|
|
796
|
+
jest
|
|
797
|
+
.spyOn(AlertCustomFieldService, "findBy")
|
|
798
|
+
.mockRejectedValue(new Error("boom") as never);
|
|
799
|
+
const incidentDefinitions: jest.SpyInstance = jest
|
|
800
|
+
.spyOn(IncidentCustomFieldService, "findBy")
|
|
801
|
+
.mockResolvedValue([] as never);
|
|
802
|
+
jest
|
|
803
|
+
.spyOn(ScheduledMaintenanceCustomFieldService, "findBy")
|
|
804
|
+
.mockResolvedValue([] as never);
|
|
805
|
+
|
|
806
|
+
await expect(
|
|
807
|
+
CustomFieldMappingService.propagateFromSourceRecord({
|
|
808
|
+
resource: CustomFieldMappingSourceResource.Monitor,
|
|
809
|
+
sourceId: MONITOR_ID,
|
|
810
|
+
projectId: PROJECT_ID,
|
|
811
|
+
}),
|
|
812
|
+
).resolves.toBeUndefined();
|
|
813
|
+
|
|
814
|
+
expect(incidentDefinitions).toHaveBeenCalled();
|
|
815
|
+
});
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
describe("CustomFieldMappingService.restampAfterMultiRowUpdate", () => {
|
|
819
|
+
test("does nothing for a single-row update, which the before-hook already handled", () => {
|
|
820
|
+
const definitions: jest.SpyInstance = stubAlertDefinitions(VENDOR_MAPPING);
|
|
821
|
+
|
|
822
|
+
CustomFieldMappingService.restampAfterMultiRowUpdate({
|
|
823
|
+
definitionModelType: AlertCustomField,
|
|
824
|
+
updateBy: {
|
|
825
|
+
query: {},
|
|
826
|
+
data: { customFields: {} },
|
|
827
|
+
props: { isRoot: true, tenantId: PROJECT_ID },
|
|
828
|
+
} as unknown as UpdateBy<Alert>,
|
|
829
|
+
updatedItemIds: [ALERT_ID],
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
expect(definitions).not.toHaveBeenCalled();
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
test("does nothing when the update cannot have changed a mapped value", () => {
|
|
836
|
+
const definitions: jest.SpyInstance = stubAlertDefinitions(VENDOR_MAPPING);
|
|
837
|
+
|
|
838
|
+
CustomFieldMappingService.restampAfterMultiRowUpdate({
|
|
839
|
+
definitionModelType: AlertCustomField,
|
|
840
|
+
updateBy: {
|
|
841
|
+
query: {},
|
|
842
|
+
data: { title: "New" },
|
|
843
|
+
props: { isRoot: true, tenantId: PROJECT_ID },
|
|
844
|
+
} as unknown as UpdateBy<Alert>,
|
|
845
|
+
updatedItemIds: [ALERT_ID, INCIDENT_ID],
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
expect(definitions).not.toHaveBeenCalled();
|
|
849
|
+
});
|
|
850
|
+
});
|