@oneuptime/common 14.0.2 → 14.0.5
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/DatabaseModels/Alert.ts +55 -0
- package/Models/DatabaseModels/AlertFeed.ts +2 -0
- package/Models/DatabaseModels/DatabaseServer.ts +1650 -0
- package/Models/DatabaseModels/DatabaseServerEndpoint.ts +540 -0
- package/Models/DatabaseModels/DatabaseServerFeed.ts +625 -0
- package/Models/DatabaseModels/DatabaseServerLabelRule.ts +514 -0
- package/Models/DatabaseModels/DatabaseServerOwnerRule.ts +596 -0
- package/Models/DatabaseModels/DatabaseServerOwnerTeam.ts +491 -0
- package/Models/DatabaseModels/DatabaseServerOwnerUser.ts +490 -0
- package/Models/DatabaseModels/Incident.ts +55 -0
- package/Models/DatabaseModels/IncidentAlert.ts +540 -0
- package/Models/DatabaseModels/IncidentFeed.ts +2 -0
- package/Models/DatabaseModels/Index.ts +18 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +26 -0
- package/Models/DatabaseModels/Project.ts +60 -0
- package/Models/DatabaseModels/RumApplication.ts +52 -1
- package/Models/DatabaseModels/ScheduledMaintenance.ts +55 -0
- package/Models/DatabaseModels/TelemetryException.ts +2 -0
- package/Models/DatabaseModels/UserProjectSsoConsent.ts +146 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.ts +89 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.ts +673 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Middleware/MultipartFormData.ts +1 -1
- package/Server/Middleware/TelemetryIngest.ts +15 -8
- package/Server/Services/AlertReminderRuleService.ts +100 -24
- package/Server/Services/DatabaseServerEndpointService.ts +895 -0
- package/Server/Services/DatabaseServerFeedService.ts +128 -0
- package/Server/Services/DatabaseServerLabelRuleEngineService.ts +340 -0
- package/Server/Services/DatabaseServerLabelRuleService.ts +14 -0
- package/Server/Services/DatabaseServerOwnerRuleEngineService.ts +425 -0
- package/Server/Services/DatabaseServerOwnerRuleService.ts +14 -0
- package/Server/Services/DatabaseServerOwnerTeamService.ts +180 -0
- package/Server/Services/DatabaseServerOwnerUserService.ts +173 -0
- package/Server/Services/DatabaseServerService.ts +4546 -0
- package/Server/Services/DatabaseService.ts +14 -8
- package/Server/Services/DockerResourceService.ts +43 -2
- package/Server/Services/IncidentAlertService.ts +1811 -0
- package/Server/Services/IncidentReminderRuleService.ts +103 -23
- package/Server/Services/IncidentService.ts +210 -10
- package/Server/Services/IncidentStateTimelineService.ts +24 -0
- package/Server/Services/Index.ts +18 -0
- package/Server/Services/InventoryItemService.ts +113 -5
- package/Server/Services/IoTDeviceService.ts +145 -37
- package/Server/Services/OpenTelemetryIngestService.ts +19 -0
- package/Server/Services/PodmanResourceService.ts +43 -2
- package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +107 -23
- package/Server/Services/ServiceService.ts +1 -1
- package/Server/Services/TelemetryUsageBillingService.ts +29 -2
- package/Server/Services/UserProjectSsoConsentService.ts +74 -0
- package/Server/Services/UserService.ts +14 -1
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +18 -0
- package/Server/Types/Database/QueryHelper.ts +30 -1
- package/Server/Utils/AI/Toolbox/ResourceTools.ts +69 -1
- package/Server/Utils/Database/AffectedResourceRelations.ts +6 -0
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +188 -6
- package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +2262 -755
- package/Server/Utils/Monitor/MonitorIncident.ts +28 -1
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +268 -6
- package/Server/Utils/Monitor/MonitorResource.ts +47 -11
- package/Server/Utils/Monitor/MonitorResourceContext.ts +1 -0
- package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +239 -21
- package/Server/Utils/Monitor/PerSeriesResolutionRootCause.ts +43 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +291 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +111 -12
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
- package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +24 -2
- package/Server/Utils/StartServer.ts +26 -6
- package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
- package/Server/Utils/Telemetry/DatabaseEndpointDiscovery.ts +688 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +5 -1
- package/Server/Utils/Telemetry/LogExceptionExtractor.ts +18 -1
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +175 -12
- package/Server/Utils/Telemetry/ResourceFacetResolver.ts +12 -0
- package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +606 -36
- package/Server/Utils/Telemetry/Telemetry.ts +16 -0
- package/Server/Utils/Telemetry/TelemetryEntity.ts +22 -22
- package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +16 -10
- package/Tests/App/Accounts/SignedInRedirect.test.tsx +241 -0
- package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +221 -4
- package/Tests/App/Dashboard/AIInsightsResourcePageContext.test.ts +42 -0
- package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +100 -0
- package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +86 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +2 -0
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +19 -0
- package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +14 -0
- package/Tests/App/Dashboard/BulkIncidentLinkActions.test.tsx +869 -0
- package/Tests/App/Dashboard/CephMetricTooltips.test.tsx +1777 -0
- package/Tests/App/Dashboard/CloudFleetSummary.test.ts +8 -0
- package/Tests/App/Dashboard/CloudMetricTooltips.test.tsx +887 -0
- package/Tests/App/Dashboard/ContainerHostMetricTooltips.test.tsx +1309 -0
- package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +26 -1
- package/Tests/App/Dashboard/DashboardAppSsoError.test.tsx +501 -0
- package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +64 -1
- package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +178 -18
- package/Tests/App/Dashboard/DashboardMasterPageSsoRedirect.test.tsx +444 -0
- package/Tests/App/Dashboard/DashboardNavBarForeignHiddenRule.test.tsx +573 -0
- package/Tests/App/Dashboard/DatabaseChartAxes.test.tsx +431 -0
- package/Tests/App/Dashboard/DatabaseContainerDetailBadge.test.tsx +249 -0
- package/Tests/App/Dashboard/DatabaseDashboardE2EFixes.test.ts +681 -0
- package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +1801 -0
- package/Tests/App/Dashboard/DatabaseFleetSummaryRefresh.test.tsx +280 -0
- package/Tests/App/Dashboard/DatabaseFormHelpers.test.tsx +321 -0
- package/Tests/App/Dashboard/DatabaseMetricMonitorLink.test.tsx +795 -0
- package/Tests/App/Dashboard/DatabaseOverviewHeader.test.tsx +580 -0
- package/Tests/App/Dashboard/DatabaseRecommendationsEngineMetrics.test.ts +270 -0
- package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +1486 -0
- package/Tests/App/Dashboard/DatabaseServerEngineMetricsFilter.test.ts +223 -0
- package/Tests/App/Dashboard/DatabaseServerPresentation.test.ts +435 -0
- package/Tests/App/Dashboard/DatabaseServerSummary.test.ts +186 -0
- package/Tests/App/Dashboard/DatabaseServerTelemetryQueries.test.ts +1553 -0
- package/Tests/App/Dashboard/DatabaseTableTruncation.test.tsx +326 -0
- package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +512 -0
- package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +774 -0
- package/Tests/App/Dashboard/DatabaseViewLayout.test.tsx +233 -0
- package/Tests/App/Dashboard/DatabaseWorkloadBadge.test.tsx +972 -0
- package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +5 -0
- package/Tests/App/Dashboard/DiscoveryReviewUnnamedHostHint.test.tsx +1061 -0
- package/Tests/App/Dashboard/DiscoveryScanLivePage.test.tsx +39 -0
- package/Tests/App/Dashboard/DockerSwarmClustersListTooltips.test.tsx +414 -0
- package/Tests/App/Dashboard/DockerSwarmMetricTooltips.test.ts +796 -0
- package/Tests/App/Dashboard/DockerSwarmOverviewTooltips.test.tsx +747 -0
- package/Tests/App/Dashboard/EventOverlayScope.test.ts +147 -0
- package/Tests/App/Dashboard/EventOverlayScopeHook.test.tsx +1 -0
- package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +38 -18
- package/Tests/App/Dashboard/HostDetailViewTooltips.test.tsx +725 -0
- package/Tests/App/Dashboard/HostListColumnTooltips.test.tsx +472 -0
- package/Tests/App/Dashboard/HostMetricTooltips.test.ts +709 -0
- package/Tests/App/Dashboard/HostOverviewTooltips.test.tsx +698 -0
- package/Tests/App/Dashboard/HostTooltipHarness.ts +124 -0
- package/Tests/App/Dashboard/HostsListTooltips.test.tsx +395 -0
- package/Tests/App/Dashboard/IncidentAlertLinkDialog.test.tsx +691 -0
- package/Tests/App/Dashboard/IncidentAlertLinkHelpers.test.ts +458 -0
- package/Tests/App/Dashboard/IncidentAlertLinkPages.test.tsx +828 -0
- package/Tests/App/Dashboard/IncidentAlertLinkSideMenus.test.tsx +231 -0
- package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +689 -0
- package/Tests/App/Dashboard/IoTMetricTooltips.test.tsx +1123 -0
- package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +837 -0
- package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +699 -0
- package/Tests/App/Dashboard/KubernetesContainersTabTooltips.test.tsx +320 -0
- package/Tests/App/Dashboard/KubernetesCostTooltips.test.tsx +502 -0
- package/Tests/App/Dashboard/KubernetesInsightsTooltips.test.tsx +222 -0
- package/Tests/App/Dashboard/KubernetesResourceMetricTooltips.test.ts +561 -0
- package/Tests/App/Dashboard/KubernetesResourcePagesTooltips.test.tsx +1168 -0
- package/Tests/App/Dashboard/LinkIncidentAlertModal.test.tsx +154 -0
- package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +1 -0
- package/Tests/App/Dashboard/MetricDescriptionRules.ts +170 -0
- package/Tests/App/Dashboard/MetricDescriptionsCatalog.test.ts +206 -0
- package/Tests/App/Dashboard/MetricDescriptionsConsistency.test.ts +275 -0
- package/Tests/App/Dashboard/MetricsViewerDrillDown.test.tsx +310 -0
- package/Tests/App/Dashboard/MetricsViewerEntityScopedRows.test.tsx +495 -0
- package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +132 -1
- package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +5 -0
- package/Tests/App/Dashboard/NetworkDeviceTooltips.test.tsx +852 -0
- package/Tests/App/Dashboard/NetworkDiagnosticsTooltips.test.tsx +556 -0
- package/Tests/App/Dashboard/NetworkMetricTooltips.test.ts +1348 -0
- package/Tests/App/Dashboard/NetworkSiteTooltips.test.tsx +679 -0
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +4 -3
- package/Tests/App/Dashboard/ProxmoxMetricTooltips.test.ts +592 -0
- package/Tests/App/Dashboard/ProxmoxOverviewTooltips.test.tsx +1002 -0
- package/Tests/App/Dashboard/ProxmoxResourcePageTooltips.test.tsx +923 -0
- package/Tests/App/Dashboard/RecommendationsLoadedContext.test.tsx +349 -0
- package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +62 -0
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
- package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +14 -0
- package/Tests/App/Dashboard/ResourceOverviewTileTooltips.test.tsx +1066 -0
- package/Tests/App/Dashboard/RumOverviewPage.test.tsx +1195 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +2 -0
- package/Tests/App/Dashboard/ServerlessMetricTooltips.test.tsx +474 -0
- package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +1085 -0
- package/Tests/App/Dashboard/ServiceMetricTooltips.test.tsx +772 -0
- package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +56 -1
- package/Tests/App/Dashboard/TelemetryMetricsSignals.test.ts +1207 -0
- package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +10 -0
- package/Tests/App/Dashboard/TelemetryResourceTabTooltips.test.tsx +437 -0
- package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +2 -1
- package/Tests/App/Dashboard/VMwareMetricTooltips.test.ts +801 -0
- package/Tests/App/Dashboard/VMwareOverviewTooltips.test.tsx +601 -0
- package/Tests/App/Dashboard/VMwareResourcePagesTooltips.test.tsx +646 -0
- package/Tests/App/Dashboard/VMwareTooltipHarness.ts +145 -0
- package/Tests/App/StatusPage/StatusPageHeaderForeignHiddenRule.test.tsx +284 -0
- package/Tests/ClassStrings.ts +178 -0
- package/Tests/Fixtures/MobilePasskeyUser.json +1 -2
- package/Tests/ForeignHiddenRuleGuard.ts +2152 -0
- package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +2250 -0
- package/Tests/Models/DatabaseModels/IncidentAlertModel.test.ts +554 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +24 -5
- package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +117 -0
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/RenderedMarkup.ts +518 -0
- package/Tests/ResponsiveVisibility.test.ts +490 -4
- package/Tests/ResponsiveVisibility.ts +505 -52
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +541 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentAlertMigration.test.ts +341 -0
- package/Tests/Server/Infrastructure/Postgres/AddSessionReplaySameOriginTracePropagationMigration.test.ts +247 -0
- package/Tests/Server/Infrastructure/Postgres/AddUserProjectSsoConsentMigration.test.ts +234 -0
- package/Tests/Server/Services/ContainerSnapshotUpsertPostgres.test.ts +319 -0
- package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +13 -0
- package/Tests/Server/Services/DatabaseServerEndpointService.test.ts +2033 -0
- package/Tests/Server/Services/DatabaseServerFeedAndOwnerServices.test.ts +529 -0
- package/Tests/Server/Services/DatabaseServerLifecycle.test.ts +3302 -0
- package/Tests/Server/Services/DatabaseServerRegistries.test.ts +603 -0
- package/Tests/Server/Services/DatabaseServerRuleEngines.test.ts +754 -0
- package/Tests/Server/Services/DatabaseServerService.test.ts +3558 -0
- package/Tests/Server/Services/DatabaseServerSqlPostgres.test.ts +2045 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedPostgres.test.ts +362 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedReply.test.ts +210 -0
- package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +18 -0
- package/Tests/Server/Services/IncidentAlertPostgres.test.ts +903 -0
- package/Tests/Server/Services/IncidentAlertRegistration.test.ts +96 -0
- package/Tests/Server/Services/IncidentAlertService.test.ts +2225 -0
- package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +2 -0
- package/Tests/Server/Services/IncidentAlertStateCascade.test.ts +970 -0
- package/Tests/Server/Services/IncidentCreateFromAlerts.test.ts +1284 -0
- package/Tests/Server/Services/IncomingCallPolicyEscalationRuleTarget.test.ts +225 -0
- package/Tests/Server/Services/InventoryItemDisplayName.test.ts +280 -2
- package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +8 -2
- package/Tests/Server/Services/IoTDeviceLatestMetricsPostgres.test.ts +689 -0
- package/Tests/Server/Services/IoTDeviceService.test.ts +379 -0
- package/Tests/Server/Services/LatestMetricsValuesShape.test.ts +360 -0
- package/Tests/Server/Services/LlmModelPriceService.test.ts +402 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +7 -1
- package/Tests/Server/Services/OwnerRowUniqueness.test.ts +61 -9
- package/Tests/Server/Services/ReminderRuleLookupPostgres.test.ts +2250 -0
- package/Tests/Server/Services/ReminderRuleRefreshOpenSubjectsPaging.test.ts +653 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +68 -20
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
- package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +9 -0
- package/Tests/Server/Services/UserProjectSsoConsentPostgres.test.ts +153 -0
- package/Tests/Server/Services/UserProjectSsoConsentService.test.ts +192 -0
- package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +71 -0
- package/Tests/Server/Services/UserSignupIdTakeoverPostgres.test.ts +238 -0
- package/Tests/Server/Services/WorkspaceNotificationSummaryHelpers.test.ts +592 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredAuthorization.test.ts +3 -0
- package/Tests/Server/Types/Database/EventOverlayScopePostgres.test.ts +1 -0
- package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +11 -0
- package/Tests/Server/Types/Database/Permissions/InfrastructureOwnershipScope.test.ts +8 -0
- package/Tests/Server/Types/Database/QueryHelperBooleanForCriteriaBackedRule.test.ts +1094 -0
- package/Tests/Server/Utils/AI/ResourceTools.test.ts +134 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +41 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +279 -9
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaDisplayContext.test.ts +933 -0
- package/Tests/Server/Utils/Monitor/DatabaseMaintenanceSuppression.test.ts +582 -0
- package/Tests/Server/Utils/Monitor/DatabaseServerMonitorLinking.test.ts +753 -0
- package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +119 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +60 -25
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorAffectedResourceEdgeCases.test.ts +1719 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesAffectedResources.test.ts +1447 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesRatioEmail.test.ts +352 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformMetricUnits.test.ts +717 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformRawScan.test.ts +2125 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformSeriesAffectedResources.test.ts +1288 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +88 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +205 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +62 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceDatabaseMaintenance.test.ts +803 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +133 -3
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/PerSeriesRecoveryResolution.test.ts +472 -1
- package/Tests/Server/Utils/Monitor/PerSeriesSecondEntityAlerting.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +236 -2
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +70 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +103 -0
- package/Tests/Server/Utils/StartServerProtobufContentType.test.ts +54 -0
- package/Tests/Server/Utils/Telemetry/DatabaseEndpointDiscovery.test.ts +1895 -0
- package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +7 -0
- package/Tests/Server/Utils/Telemetry/LogExceptionExtractorSeverityGate.test.ts +90 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +570 -0
- package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +97 -2
- package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +1337 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +295 -0
- package/Tests/Types/AI/AIResourceContext.test.ts +30 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerClassifier.test.ts +3644 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommand.test.ts +340 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommandCorpus.ts +826 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommandPostgres.test.ts +150 -0
- package/Tests/Types/DatabaseServer/DatabaseEndpoint.test.ts +2657 -0
- package/Tests/Types/DatabaseServer/DatabaseServerDiscoverySource.test.ts +64 -0
- package/Tests/Types/DatabaseServer/DatabaseServerEntityKeys.test.ts +952 -0
- package/Tests/Types/DatabaseServer/DatabaseServerMetricCatalog.test.ts +1161 -0
- package/Tests/Types/DatabaseServer/DatabaseSystem.test.ts +1514 -0
- package/Tests/Types/DatabaseServer/DatabaseTelemetryResolver.test.ts +1558 -0
- package/Tests/Types/Monitor/CephAlertTemplates.test.ts +255 -6
- package/Tests/Types/Monitor/DatabaseAlertTemplates.test.ts +2254 -0
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +298 -0
- package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +271 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +253 -9
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +13 -5
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +4 -2
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +111 -2
- package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +61 -0
- package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +114 -0
- package/Tests/Types/Monitor/Utils/KubernetesAgentEmittedMetrics.ts +181 -0
- package/Tests/Types/NetworkDevice/DiscoveredHostNamingStatus.test.ts +401 -0
- package/Tests/Types/Rum/WebVitals.test.ts +173 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +4 -1
- package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +24 -2
- package/Tests/UI/Components/Card.test.tsx +93 -2
- package/Tests/UI/Components/FeedOptions.test.ts +6 -0
- package/Tests/UI/Components/FeedOptionsButton.test.tsx +8 -1
- package/Tests/UI/Components/FieldLabelInfoCardTooltip.test.tsx +413 -0
- package/Tests/UI/Components/ForeignHiddenRuleResilience.test.tsx +1147 -0
- package/Tests/UI/Components/HeaderRightRail.test.tsx +41 -1
- package/Tests/UI/Components/InfoTooltip.test.tsx +242 -0
- package/Tests/UI/Components/LogsEntityNames.test.ts +16 -1
- package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +7 -3
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +207 -3
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkDeleteVerb.test.tsx +367 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableCreateButtonTitle.test.tsx +275 -0
- package/Tests/UI/Components/ResourceFacetConfigs.test.ts +2 -1
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/SrOnlyForeignRule.test.tsx +994 -0
- package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +34 -1
- package/Tests/UI/Components/TableHeaderTooltip.test.tsx +662 -0
- package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +4 -1
- package/Tests/UI/ForeignHiddenRuleGuard.test.ts +1951 -0
- package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +166 -9
- package/Tests/UI/Rum/RecordingHealthTooltips.test.tsx +447 -0
- package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +164 -0
- package/Tests/UI/Rum/ReplayFrameCapture.test.ts +6750 -0
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +19 -1
- package/Tests/UI/Rum/ReplayRail.test.tsx +723 -12
- package/Tests/UI/Rum/ReplayRailDetail.test.tsx +86 -0
- package/Tests/UI/Rum/ReplayScreenshot.test.ts +2124 -0
- package/Tests/UI/Rum/ReplayScreenshotActions.test.tsx +3288 -0
- package/Tests/UI/Rum/ReplayStage.test.tsx +62 -0
- package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +983 -2
- package/Tests/UI/Rum/ReplayTabSwitcher.test.tsx +19 -1
- package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +149 -0
- package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +107 -6
- package/Tests/UI/Rum/SessionReplayUsersTableTooltips.test.tsx +330 -0
- package/Tests/UI/Rum/UserFlowTooltips.test.tsx +886 -0
- package/Tests/UI/TailwindPlayCdnForeignHiddenRule.test.ts +1005 -0
- package/Tests/UI/ThemeGroupHoverReveal.test.ts +847 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +80 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +23 -0
- package/Tests/UI/Utils/ModelAPISsoRedirect.test.ts +127 -0
- package/Tests/UI/Utils/Navigation.test.ts +102 -0
- package/Tests/UI/Utils/PermissionGate.test.ts +76 -0
- package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +23 -0
- package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +696 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
- package/Tests/Utils/MetricUnitUtil.test.ts +227 -2
- package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +288 -2
- package/Tests/Utils/Monitor/PlatformResourceIdentityAndUnits.test.ts +1559 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.test.ts +2546 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +315 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +336 -1
- package/Tests/Utils/NetworkDiscovery/NetbiosNameUtil.test.ts +244 -0
- package/Tests/Utils/Rum/SessionTraceState.test.ts +239 -0
- package/Tests/Utils/ValueFormatter.test.ts +50 -0
- package/Tests/tsconfig.json +16 -0
- package/Types/AI/AIResourceContext.ts +7 -0
- package/Types/Dashboard/DashboardTemplates.ts +2 -1
- package/Types/DatabaseServer/DatabaseConnectionSpan.ts +77 -0
- package/Types/DatabaseServer/DatabaseContainerClassifier.ts +2068 -0
- package/Types/DatabaseServer/DatabaseContainerCommand.ts +801 -0
- package/Types/DatabaseServer/DatabaseEndpoint.ts +1943 -0
- package/Types/DatabaseServer/DatabaseServerDiscoverySource.ts +68 -0
- package/Types/DatabaseServer/DatabaseServerMetricCatalog.ts +966 -0
- package/Types/DatabaseServer/DatabaseSystem.ts +2124 -0
- package/Types/DatabaseServer/DatabaseTelemetryResolver.ts +555 -0
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/Incident/IncidentAlertLink.ts +38 -0
- package/Types/Monitor/CephAlertTemplates.ts +18 -0
- package/Types/Monitor/DatabaseAlertTemplates.ts +2020 -0
- package/Types/Monitor/KubernetesAlertTemplates.ts +64 -24
- package/Types/Monitor/KubernetesMetricCatalog.ts +118 -19
- package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +14 -0
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +93 -10
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +109 -8
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +36 -7
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +43 -2
- package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +41 -6
- package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +26 -0
- package/Types/NetworkDevice/DiscoveredHostNamingStatus.ts +147 -0
- package/Types/Permission.ts +315 -0
- package/Types/Probe/ProbeApiIngestResponse.ts +8 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +10 -0
- package/Types/Rules/RuleRun.ts +12 -0
- package/Types/Rum/SessionReplay.ts +25 -6
- package/Types/Rum/WebVitals.ts +52 -0
- package/Types/Telemetry/EntityType.ts +23 -0
- package/Types/Telemetry/ResourceFacetCatalog.ts +14 -0
- package/Types/Telemetry/ServiceType.ts +8 -0
- package/UI/Components/Banner/Banner.tsx +1 -1
- package/UI/Components/Card/Card.tsx +1 -1
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +2 -2
- package/UI/Components/Charts/Line/LineChart.tsx +7 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +1 -1
- package/UI/Components/Date/StartAndEndDate.tsx +5 -5
- package/UI/Components/Detail/FieldLabel.tsx +8 -0
- package/UI/Components/Diagram/HorizontalStepChain.tsx +1 -1
- package/UI/Components/Feed/FeedOptionsButton.tsx +1 -1
- package/UI/Components/Forms/BasicForm.tsx +1 -1
- package/UI/Components/Header/Header.tsx +1 -1
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -1
- package/UI/Components/HeaderAlert/HeaderAlert.tsx +1 -1
- package/UI/Components/InfoCard/InfoCard.tsx +47 -1
- package/UI/Components/LogsViewer/components/FacetValueRow.tsx +1 -1
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +1 -1
- package/UI/Components/Modal/ModalFooter.tsx +1 -1
- package/UI/Components/ModelDetail/CardModelDetail.tsx +2 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +99 -21
- package/UI/Components/ModelTable/Column.ts +5 -0
- package/UI/Components/Navbar/NavBar.tsx +9 -2
- package/UI/Components/Navbar/NavBarMenuModal.tsx +2 -2
- package/UI/Components/Page/Page.tsx +1 -1
- package/UI/Components/Pagination/Pagination.tsx +3 -3
- package/UI/Components/ProgressButtons/ProgressButtonItem.tsx +1 -1
- package/UI/Components/SideMenu/SideMenu.tsx +4 -1
- package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +4 -2
- package/UI/Components/StatusPage/ResourceList.tsx +6 -6
- package/UI/Components/Table/TableHeader.tsx +47 -2
- package/UI/Components/Table/Types/Column.ts +7 -0
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +1 -1
- package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +1 -1
- package/UI/Components/Tooltip/InfoTooltip.tsx +78 -0
- package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +1 -1
- package/UI/Components/Workflow/ComponentsModal.tsx +2 -2
- package/UI/Components/Workflow/StepTraceViewer.tsx +1 -1
- package/UI/Styles/Theme.css +8 -1
- package/UI/Utils/Navigation.ts +89 -42
- package/UI/Utils/PermissionGate.ts +11 -2
- package/UI/Utils/Telemetry/TelemetryEntityNames.ts +7 -0
- package/UI/Utils/TelemetryService.ts +4 -3
- package/Utils/Incident/IncidentFromAlerts.ts +516 -0
- package/Utils/LabelRuleImportExport.ts +2 -0
- package/Utils/MetricUnitUtil.ts +103 -11
- package/Utils/Monitor/MetricValueFormatter.ts +66 -13
- package/Utils/Monitor/PlatformMetricUnitUtil.ts +215 -0
- package/Utils/Monitor/PlatformResourceIdentity.ts +514 -0
- package/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.ts +425 -0
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +32 -0
- package/Utils/NetworkDiscovery/NetbiosNameUtil.ts +73 -0
- package/Utils/Rum/SessionTraceState.ts +212 -0
- package/Utils/Telemetry/DatabaseServerEntityKeys.ts +275 -0
- package/Utils/Telemetry/EntityKey.ts +176 -0
- package/Utils/ValueFormatter.ts +16 -0
- package/build/dist/Models/DatabaseModels/Alert.js +54 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseServer.js +1683 -0
- package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js +559 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js +648 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js +506 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js +505 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Incident.js +54 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentAlert.js +553 -0
- package/build/dist/Models/DatabaseModels/IncidentAlert.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +18 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +62 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js +53 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +54 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +2 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js +162 -0
- package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js +42 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js +240 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.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/Middleware/MultipartFormData.js +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +15 -8
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js +72 -23
- package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseServerEndpointService.js +694 -0
- package/build/dist/Server/Services/DatabaseServerEndpointService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerFeedService.js +110 -0
- package/build/dist/Server/Services/DatabaseServerFeedService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js +272 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleService.js +13 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js +340 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js +160 -0
- package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerUserService.js +153 -0
- package/build/dist/Server/Services/DatabaseServerOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerService.js +3272 -0
- package/build/dist/Server/Services/DatabaseServerService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseService.js +8 -4
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerResourceService.js +30 -3
- package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
- package/build/dist/Server/Services/IncidentAlertService.js +1370 -0
- package/build/dist/Server/Services/IncidentAlertService.js.map +1 -0
- package/build/dist/Server/Services/IncidentReminderRuleService.js +73 -23
- package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +164 -12
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +21 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +18 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +88 -5
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/IoTDeviceService.js +111 -24
- package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +24 -9
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PodmanResourceService.js +30 -3
- package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +75 -23
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +1 -1
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +23 -2
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/UserProjectSsoConsentService.js +79 -0
- package/build/dist/Server/Services/UserProjectSsoConsentService.js.map +1 -0
- package/build/dist/Server/Services/UserService.js +13 -1
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +18 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +26 -1
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +46 -0
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
- package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +6 -0
- package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +134 -13
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -6
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1489 -524
- 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/MonitorMaintenanceSuppression.js +196 -6
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +36 -9
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +175 -17
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js +29 -0
- package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +211 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +82 -10
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +8 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +20 -4
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js +442 -0
- package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +5 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +15 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +121 -5
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +12 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +438 -36
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +12 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -18
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +16 -10
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -1
- package/build/dist/Types/AI/AIResourceContext.js +7 -0
- package/build/dist/Types/AI/AIResourceContext.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js +2 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js +71 -0
- package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js +1462 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js +691 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js +1407 -0
- package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js +60 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js +804 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseSystem.js +1860 -0
- package/build/dist/Types/DatabaseServer/DatabaseSystem.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js +406 -0
- package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.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/Incident/IncidentAlertLink.js +34 -0
- package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -0
- package/build/dist/Types/Monitor/CephAlertTemplates.js +18 -0
- package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/DatabaseAlertTemplates.js +1518 -0
- package/build/dist/Types/Monitor/DatabaseAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +57 -24
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +104 -18
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +80 -3
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +10 -3
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +29 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +21 -6
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -1
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +25 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
- package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js +136 -0
- package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js.map +1 -0
- package/build/dist/Types/Permission.js +276 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +10 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rules/RuleRun.js +4 -0
- package/build/dist/Types/Rules/RuleRun.js.map +1 -1
- package/build/dist/Types/Rum/WebVitals.js +25 -0
- package/build/dist/Types/Rum/WebVitals.js.map +1 -1
- package/build/dist/Types/Telemetry/EntityType.js +23 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +14 -0
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -1
- package/build/dist/Types/Telemetry/ServiceType.js +8 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/Banner/Banner.js +1 -1
- package/build/dist/UI/Components/Banner/Banner.js.map +1 -1
- package/build/dist/UI/Components/Card/Card.js +1 -1
- package/build/dist/UI/Components/Card/Card.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +2 -2
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +1 -1
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
- package/build/dist/UI/Components/Date/StartAndEndDate.js +5 -5
- package/build/dist/UI/Components/Date/StartAndEndDate.js.map +1 -1
- package/build/dist/UI/Components/Detail/FieldLabel.js +2 -0
- package/build/dist/UI/Components/Detail/FieldLabel.js.map +1 -1
- package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +1 -1
- package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js +1 -1
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
- package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js +1 -1
- package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js.map +1 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js +22 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +2 -2
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +70 -18
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js +9 -2
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Components/Page/Page.js +1 -1
- package/build/dist/UI/Components/Page/Page.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +3 -3
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js +1 -1
- package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +4 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +3 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceList.js +6 -6
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +18 -2
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/InfoTooltip.js +28 -0
- package/build/dist/UI/Components/Tooltip/InfoTooltip.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentsModal.js +2 -2
- package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js +1 -1
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +66 -33
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/PermissionGate.js +4 -2
- package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +7 -0
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +3 -2
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
- package/build/dist/Utils/Incident/IncidentFromAlerts.js +306 -0
- package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -0
- package/build/dist/Utils/LabelRuleImportExport.js +2 -0
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/MetricUnitUtil.js +77 -13
- package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +58 -13
- package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -1
- package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js +161 -0
- package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/PlatformResourceIdentity.js +323 -0
- package/build/dist/Utils/Monitor/PlatformResourceIdentity.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js +270 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +23 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js +61 -0
- package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js.map +1 -1
- package/build/dist/Utils/Rum/SessionTraceState.js +154 -0
- package/build/dist/Utils/Rum/SessionTraceState.js.map +1 -0
- package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js +178 -0
- package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityKey.js +133 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/build/dist/Utils/ValueFormatter.js +15 -0
- package/build/dist/Utils/ValueFormatter.js.map +1 -1
- package/package.json +1 -1
- package/tsconfig.tests.json +7 -5
|
@@ -0,0 +1,1370 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import QueryHelper from "../Types/Database/QueryHelper";
|
|
11
|
+
import ModelPermission from "../Types/Database/Permissions/Index";
|
|
12
|
+
import DatabaseService from "./DatabaseService";
|
|
13
|
+
import AlertFeedService from "./AlertFeedService";
|
|
14
|
+
import AlertOwnerTeamService from "./AlertOwnerTeamService";
|
|
15
|
+
import AlertOwnerUserService from "./AlertOwnerUserService";
|
|
16
|
+
import AlertService from "./AlertService";
|
|
17
|
+
import AlertStateService from "./AlertStateService";
|
|
18
|
+
import IncidentFeedService from "./IncidentFeedService";
|
|
19
|
+
import IncidentService from "./IncidentService";
|
|
20
|
+
import IncidentStateService from "./IncidentStateService";
|
|
21
|
+
import ProjectService from "./ProjectService";
|
|
22
|
+
import { IsBillingEnabled } from "../EnvironmentConfig";
|
|
23
|
+
import { applyAlertRelatedRecordPrivacyFilter } from "../Utils/Alert/AlertPrivacyFilter";
|
|
24
|
+
import { applyIncidentRelatedRecordPrivacyFilter } from "../Utils/Incident/IncidentPrivacyFilter";
|
|
25
|
+
import PostgresErrorTranslator from "../Utils/Database/PostgresErrorTranslator";
|
|
26
|
+
import ProjectScopedReferenceValidator from "../Utils/Database/ProjectScopedReferenceValidator";
|
|
27
|
+
import RelationIdUtil from "../Utils/Database/RelationIdUtil";
|
|
28
|
+
import logger from "../Utils/Logger";
|
|
29
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
30
|
+
import Model from "../../Models/DatabaseModels/IncidentAlert";
|
|
31
|
+
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
|
32
|
+
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
|
33
|
+
import { Gray500, Yellow500 } from "../../Types/BrandColors";
|
|
34
|
+
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
35
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
36
|
+
import ForbiddenException from "../../Types/Exception/ForbiddenException";
|
|
37
|
+
import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException";
|
|
38
|
+
import NotFoundException from "../../Types/Exception/NotFoundException";
|
|
39
|
+
import { INCIDENT_ALERT_ALREADY_LINKED_MESSAGE, INCIDENT_ALERT_IDS_TO_LINK_KEY, MAX_ALERTS_PER_INCIDENT_LINK_ACTION, } from "../../Types/Incident/IncidentAlertLink";
|
|
40
|
+
import ObjectID from "../../Types/ObjectID";
|
|
41
|
+
/*
|
|
42
|
+
* The decision half of the linked-alert state sync, shared by the cascade
|
|
43
|
+
* (an incident changes state) and the link-time sync (an alert is linked to
|
|
44
|
+
* an incident that is already acknowledged or resolved).
|
|
45
|
+
*
|
|
46
|
+
* States are compared by `order`, never by the isAcknowledgedState /
|
|
47
|
+
* isResolvedState flags: projects add custom states (say "Monitoring") between
|
|
48
|
+
* Acknowledged and Resolved, and an incident sitting in one of those has
|
|
49
|
+
* still been acknowledged. An incident project without an Acknowledged (or
|
|
50
|
+
* Resolved) state simply never triggers that half.
|
|
51
|
+
*/
|
|
52
|
+
export function getLinkedAlertStateTargets(data) {
|
|
53
|
+
const reachedAcknowledged = data.acknowledgedIncidentStateOrder !== undefined &&
|
|
54
|
+
data.incidentStateOrder >= data.acknowledgedIncidentStateOrder;
|
|
55
|
+
const reachedResolved = data.resolvedIncidentStateOrder !== undefined &&
|
|
56
|
+
data.incidentStateOrder >= data.resolvedIncidentStateOrder;
|
|
57
|
+
return {
|
|
58
|
+
acknowledge: data.acknowledgeSwitch && reachedAcknowledged,
|
|
59
|
+
resolve: data.resolveSwitch && reachedResolved,
|
|
60
|
+
incidentReachedResolved: reachedResolved,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/*
|
|
64
|
+
* The alert state one linked alert should move to, or null to leave it alone.
|
|
65
|
+
*
|
|
66
|
+
* Resolve wins when it applies and the alert is not held back by another
|
|
67
|
+
* linked incident that is still open; acknowledge is the fallback, so an
|
|
68
|
+
* alert that cannot be resolved yet is at least acknowledged (which is what
|
|
69
|
+
* stops its paging). An alert is never moved backwards and never "moved" to
|
|
70
|
+
* where it already is: anything at or past the target is left untouched.
|
|
71
|
+
*/
|
|
72
|
+
export function chooseLinkedAlertTargetState(data) {
|
|
73
|
+
var _a, _b;
|
|
74
|
+
const resolvedOrder = (_a = data.resolvedAlertState) === null || _a === void 0 ? void 0 : _a.order;
|
|
75
|
+
if (data.resolvedAlertState &&
|
|
76
|
+
resolvedOrder !== undefined &&
|
|
77
|
+
!data.isBlockedFromResolve &&
|
|
78
|
+
data.alertStateOrder < resolvedOrder) {
|
|
79
|
+
return data.resolvedAlertState;
|
|
80
|
+
}
|
|
81
|
+
const acknowledgedOrder = (_b = data.acknowledgedAlertState) === null || _b === void 0 ? void 0 : _b.order;
|
|
82
|
+
if (data.acknowledgedAlertState &&
|
|
83
|
+
acknowledgedOrder !== undefined &&
|
|
84
|
+
data.alertStateOrder < acknowledgedOrder) {
|
|
85
|
+
return data.acknowledgedAlertState;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
/*
|
|
90
|
+
* miscDataProps key on an IncidentAlert create: the link is one of the links
|
|
91
|
+
* written while an incident is being declared from alerts. The incident then
|
|
92
|
+
* gets one "Declared from N alerts" entry (see
|
|
93
|
+
* createDeclaredFromAlertsFeedItem) instead of an "Alert Linked" entry - and
|
|
94
|
+
* a Slack / Microsoft Teams post - per alert. Honoured for root callers only:
|
|
95
|
+
* miscDataProps is part of the public create API, and an API client must not
|
|
96
|
+
* be able to link an alert without the incident's audit entry.
|
|
97
|
+
*/
|
|
98
|
+
export const INCIDENT_ALERT_DECLARED_WITH_INCIDENT_KEY = "declaredWithIncident";
|
|
99
|
+
/*
|
|
100
|
+
* "**[Alert #3](link)**: <title>", or "**[Alert #3](link)** (private alert)"
|
|
101
|
+
* for a private alert: its number and link are kept so the entry still says
|
|
102
|
+
* what happened, but its title is never written where people who cannot see
|
|
103
|
+
* the alert read it (the incident's feed and Slack / Microsoft Teams posts).
|
|
104
|
+
*/
|
|
105
|
+
function describeLinkedRecord(data) {
|
|
106
|
+
const subject = `**[${data.label}](${data.link})**`;
|
|
107
|
+
if (data.isPrivate) {
|
|
108
|
+
return {
|
|
109
|
+
subject: `${subject} (private ${data.privateNoun})`,
|
|
110
|
+
titleSuffix: "",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return { subject: subject, titleSuffix: `: ${data.title || "No title"}` };
|
|
114
|
+
}
|
|
115
|
+
/*
|
|
116
|
+
* The one incident feed entry for an incident declared from alerts, listing
|
|
117
|
+
* the alerts in the order given. Private alerts are listed without their
|
|
118
|
+
* titles.
|
|
119
|
+
*/
|
|
120
|
+
export function getDeclaredFromAlertsMarkdown(alerts) {
|
|
121
|
+
const lines = alerts.map((alert) => {
|
|
122
|
+
const described = describeLinkedRecord({
|
|
123
|
+
label: alert.label,
|
|
124
|
+
link: alert.link,
|
|
125
|
+
title: alert.title,
|
|
126
|
+
isPrivate: alert.isPrivate,
|
|
127
|
+
privateNoun: "alert",
|
|
128
|
+
});
|
|
129
|
+
return `- ${described.subject}${described.titleSuffix}`;
|
|
130
|
+
});
|
|
131
|
+
const noun = alerts.length === 1 ? "alert" : "alerts";
|
|
132
|
+
return `🔗 Declared from ${alerts.length} ${noun}:\n\n${lines.join("\n")}`;
|
|
133
|
+
}
|
|
134
|
+
function normalizeId(id) {
|
|
135
|
+
return id.toString().trim().toLowerCase();
|
|
136
|
+
}
|
|
137
|
+
// Distinct ids, in order, with the missing ones left out.
|
|
138
|
+
function uniqueIds(ids) {
|
|
139
|
+
const seen = new Set();
|
|
140
|
+
const result = [];
|
|
141
|
+
for (const id of ids) {
|
|
142
|
+
if (!id) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const key = normalizeId(id);
|
|
146
|
+
if (!key || seen.has(key)) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
seen.add(key);
|
|
150
|
+
result.push(new ObjectID(key));
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
function formatNumber(numberWithPrefix, number) {
|
|
155
|
+
if (numberWithPrefix) {
|
|
156
|
+
return numberWithPrefix;
|
|
157
|
+
}
|
|
158
|
+
if (number !== undefined && number !== null) {
|
|
159
|
+
return `#${number}`;
|
|
160
|
+
}
|
|
161
|
+
return "";
|
|
162
|
+
}
|
|
163
|
+
function withNumber(label, number) {
|
|
164
|
+
return number ? `${label} ${number}` : label;
|
|
165
|
+
}
|
|
166
|
+
const NOT_VISIBLE_ALERTS_MESSAGE = "One or more of the selected alerts do not exist in this project, or you do not have access to them.";
|
|
167
|
+
export class Service extends DatabaseService {
|
|
168
|
+
constructor() {
|
|
169
|
+
super(Model);
|
|
170
|
+
if (IsBillingEnabled) {
|
|
171
|
+
this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365); // 3 years
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/*
|
|
175
|
+
* A link row reveals both of its ends, so it is only visible to a user who
|
|
176
|
+
* can see the private incident AND the private alert. The two filters write
|
|
177
|
+
* different keys (incidentId / alertId) and compose. Relation joins
|
|
178
|
+
* (`select: { alert: { title } }`) do not run AlertService.onBeforeFind,
|
|
179
|
+
* so these are the only thing keeping a private alert's title out of an
|
|
180
|
+
* incident's "Linked Alerts" list, and the other way round.
|
|
181
|
+
*/
|
|
182
|
+
applyPrivacyFilters(query, props) {
|
|
183
|
+
return applyAlertRelatedRecordPrivacyFilter(applyIncidentRelatedRecordPrivacyFilter(query, props), props);
|
|
184
|
+
}
|
|
185
|
+
async onBeforeFind(findBy) {
|
|
186
|
+
findBy.query = this.applyPrivacyFilters(findBy.query, findBy.props);
|
|
187
|
+
return { findBy, carryForward: null };
|
|
188
|
+
}
|
|
189
|
+
/*
|
|
190
|
+
* A pair that is already linked answers with the same message however the
|
|
191
|
+
* duplicate is caught. @UniqueColumnsTogether catches it before the insert
|
|
192
|
+
* with INCIDENT_ALERT_ALREADY_LINKED_MESSAGE; when two requests race past
|
|
193
|
+
* that check, the unique index rejects the second insert, and the generic
|
|
194
|
+
* translation ("A Incident Alert with the same Incident Id, Alert Id,
|
|
195
|
+
* Project Id already exists...") would reach the dashboard, which counts a
|
|
196
|
+
* link as done only by this message. The exception stays tagged as a unique
|
|
197
|
+
* violation, so linkAlertsToIncident still counts it as already linked.
|
|
198
|
+
*
|
|
199
|
+
* IncidentAlert has no other unique index. A unique violation reported
|
|
200
|
+
* against another table (nothing on the create path writes one today) keeps
|
|
201
|
+
* the generic translation. Synchronous and `never`-returning, like the
|
|
202
|
+
* method it overrides.
|
|
203
|
+
*/
|
|
204
|
+
getException(error) {
|
|
205
|
+
if (PostgresErrorTranslator.isUniqueViolation(error) &&
|
|
206
|
+
this.isOwnTableOrUnknown(error)) {
|
|
207
|
+
throw PostgresErrorTranslator.createUniqueViolationException(INCIDENT_ALERT_ALREADY_LINKED_MESSAGE);
|
|
208
|
+
}
|
|
209
|
+
return super.getException(error);
|
|
210
|
+
}
|
|
211
|
+
/*
|
|
212
|
+
* True when a Postgres error names this table, or names none (an exception
|
|
213
|
+
* that was already translated carries no driver details).
|
|
214
|
+
*/
|
|
215
|
+
isOwnTableOrUnknown(error) {
|
|
216
|
+
const direct = error;
|
|
217
|
+
const driverError = error.driverError;
|
|
218
|
+
const table = typeof direct.table === "string" ? direct.table : driverError === null || driverError === void 0 ? void 0 : driverError.table;
|
|
219
|
+
if (typeof table !== "string" || table.length === 0) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
return table === this.getModel().tableName;
|
|
223
|
+
}
|
|
224
|
+
async countBy(countBy) {
|
|
225
|
+
countBy.query = this.applyPrivacyFilters(countBy.query, countBy.props);
|
|
226
|
+
return super.countBy(countBy);
|
|
227
|
+
}
|
|
228
|
+
async onBeforeUpdate(updateBy) {
|
|
229
|
+
updateBy.query = this.applyPrivacyFilters(updateBy.query, updateBy.props);
|
|
230
|
+
return { updateBy, carryForward: null };
|
|
231
|
+
}
|
|
232
|
+
/*
|
|
233
|
+
* Both ends must exist in the link's project, and a user may only link what
|
|
234
|
+
* they can see. The foreign keys only require the rows to exist somewhere,
|
|
235
|
+
* and @CanAccessIfCanReadOn is not applied on create, so without this a
|
|
236
|
+
* member could link another project's alert, or a private incident they
|
|
237
|
+
* cannot open. The duplicate check is left to @UniqueColumnsTogether and the
|
|
238
|
+
* unique index, which are race free.
|
|
239
|
+
*
|
|
240
|
+
* This hook runs before DatabaseService checks the caller's create
|
|
241
|
+
* permission, so every refusal is worded so it reveals nothing about
|
|
242
|
+
* records the caller cannot see.
|
|
243
|
+
*/
|
|
244
|
+
async onBeforeCreate(createBy) {
|
|
245
|
+
const data = createBy.data;
|
|
246
|
+
// A reference arrives as `incidentId` or as `incident: { _id }`.
|
|
247
|
+
const incidentId = RelationIdUtil.readConsistent(data, ["incidentId", "incident"], "incident");
|
|
248
|
+
const alertId = RelationIdUtil.readConsistent(data, ["alertId", "alert"], "alert");
|
|
249
|
+
if (!incidentId) {
|
|
250
|
+
throw new BadDataException("Please select the incident to link the alert to.");
|
|
251
|
+
}
|
|
252
|
+
if (!alertId) {
|
|
253
|
+
throw new BadDataException("Please select the alert to link.");
|
|
254
|
+
}
|
|
255
|
+
const projectId = createBy.props.tenantId ||
|
|
256
|
+
RelationIdUtil.readConsistent(data, ["projectId", "project"], "project");
|
|
257
|
+
if (!projectId) {
|
|
258
|
+
throw new BadDataException("projectId is required to link an alert to an incident.");
|
|
259
|
+
}
|
|
260
|
+
createBy.data.projectId = projectId;
|
|
261
|
+
createBy.data.incidentId = incidentId;
|
|
262
|
+
createBy.data.alertId = alertId;
|
|
263
|
+
if (!createBy.props.isRoot) {
|
|
264
|
+
/*
|
|
265
|
+
* Read both ends as the caller, so privacy, label and owner scoping
|
|
266
|
+
* apply exactly as they do on the incident and alert pages. A caller
|
|
267
|
+
* without read access at all gets the same answer as one asking for
|
|
268
|
+
* a record that does not exist.
|
|
269
|
+
*/
|
|
270
|
+
const incident = await this.findVisible(() => {
|
|
271
|
+
return IncidentService.findOneById({
|
|
272
|
+
id: incidentId,
|
|
273
|
+
select: { _id: true, projectId: true },
|
|
274
|
+
props: createBy.props,
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
if (!incident ||
|
|
278
|
+
normalizeId(incident.projectId || "") !== normalizeId(projectId)) {
|
|
279
|
+
throw new BadDataException("The incident to link does not exist in this project, or you do not have access to it.");
|
|
280
|
+
}
|
|
281
|
+
const alert = await this.findVisible(() => {
|
|
282
|
+
return AlertService.findOneById({
|
|
283
|
+
id: alertId,
|
|
284
|
+
select: { _id: true, projectId: true },
|
|
285
|
+
props: createBy.props,
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
if (!alert ||
|
|
289
|
+
normalizeId(alert.projectId || "") !== normalizeId(projectId)) {
|
|
290
|
+
throw new BadDataException("The alert to link does not exist in this project, or you do not have access to it.");
|
|
291
|
+
}
|
|
292
|
+
/*
|
|
293
|
+
* "Linked by" is whoever made the request. sanitizeCreateOrUpdate
|
|
294
|
+
* stamps it for a user; an API key has no user, and must not be able
|
|
295
|
+
* to name somebody else as the one who linked the alert.
|
|
296
|
+
*/
|
|
297
|
+
if (createBy.props.userId) {
|
|
298
|
+
createBy.data.createdByUserId = createBy.props.userId;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
delete createBy.data.createdByUserId;
|
|
302
|
+
}
|
|
303
|
+
delete createBy.data.createdByUser;
|
|
304
|
+
}
|
|
305
|
+
await ProjectScopedReferenceValidator.validateReferencesBelongToProject({
|
|
306
|
+
projectId: projectId,
|
|
307
|
+
subject: "incident alert link",
|
|
308
|
+
references: [
|
|
309
|
+
{
|
|
310
|
+
modelName: "Incident",
|
|
311
|
+
id: incidentId,
|
|
312
|
+
service: IncidentService,
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
modelName: "Alert",
|
|
316
|
+
id: alertId,
|
|
317
|
+
service: AlertService,
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
});
|
|
321
|
+
return { createBy, carryForward: null };
|
|
322
|
+
}
|
|
323
|
+
/*
|
|
324
|
+
* Runs a read made with the caller's props. A refusal from the permission
|
|
325
|
+
* layer (no read access to the table, a label the caller cannot see) is
|
|
326
|
+
* reported exactly like a record that does not exist, so the answer never
|
|
327
|
+
* reveals which it was. Anything else - a lapsed session, an unpaid
|
|
328
|
+
* project, the database being unavailable - is not about the record and is
|
|
329
|
+
* passed on as it is.
|
|
330
|
+
*/
|
|
331
|
+
async findVisible(read) {
|
|
332
|
+
try {
|
|
333
|
+
return await read();
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
if (error instanceof NotAuthorizedException ||
|
|
337
|
+
error instanceof ForbiddenException ||
|
|
338
|
+
error instanceof NotFoundException ||
|
|
339
|
+
error instanceof BadDataException) {
|
|
340
|
+
logger.debug(`IncidentAlertService: a record to link is not readable by the caller: ${error.message}`);
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
async onCreateSuccess(onCreate, createdItem) {
|
|
347
|
+
var _a, _b;
|
|
348
|
+
const projectId = createdItem.projectId;
|
|
349
|
+
const incidentId = createdItem.incidentId;
|
|
350
|
+
const alertId = createdItem.alertId;
|
|
351
|
+
if (!projectId || !incidentId || !alertId) {
|
|
352
|
+
return createdItem;
|
|
353
|
+
}
|
|
354
|
+
const actorUserId = createdItem.createdByUserId || onCreate.createBy.props.userId;
|
|
355
|
+
/*
|
|
356
|
+
* A link written while its incident is being declared from alerts leaves
|
|
357
|
+
* the incident's side to that incident's single "Declared from N alerts"
|
|
358
|
+
* entry. Root only - see INCIDENT_ALERT_DECLARED_WITH_INCIDENT_KEY.
|
|
359
|
+
*/
|
|
360
|
+
const isDeclaredWithIncident = onCreate.createBy.props.isRoot === true &&
|
|
361
|
+
((_a = onCreate.createBy.miscDataProps) === null || _a === void 0 ? void 0 : _a[INCIDENT_ALERT_DECLARED_WITH_INCIDENT_KEY]) === true;
|
|
362
|
+
try {
|
|
363
|
+
await this.createLinkFeedItems({
|
|
364
|
+
link: {
|
|
365
|
+
id: ((_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString()) || "",
|
|
366
|
+
projectId: projectId,
|
|
367
|
+
incidentId: incidentId,
|
|
368
|
+
alertId: alertId,
|
|
369
|
+
},
|
|
370
|
+
isLinked: true,
|
|
371
|
+
actorUserId: actorUserId,
|
|
372
|
+
writeIncidentEntry: !isDeclaredWithIncident,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
logger.error(`IncidentAlertService.onCreateSuccess could not write the link feed items: ${error}`, {
|
|
377
|
+
projectId: projectId.toString(),
|
|
378
|
+
incidentId: incidentId.toString(),
|
|
379
|
+
alertId: alertId.toString(),
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
/*
|
|
383
|
+
* Linking an alert to an incident that is already acknowledged or
|
|
384
|
+
* resolved brings the alert along, when the project asks for it.
|
|
385
|
+
* Fire-and-forget: it never fails, or slows down, the link.
|
|
386
|
+
*/
|
|
387
|
+
this.syncAlertWithLinkedIncidentState({
|
|
388
|
+
projectId: projectId,
|
|
389
|
+
incidentId: incidentId,
|
|
390
|
+
alertId: alertId,
|
|
391
|
+
}).catch((error) => {
|
|
392
|
+
logger.error(`IncidentAlertService could not sync a newly linked alert with its incident: ${error}`, {
|
|
393
|
+
projectId: projectId.toString(),
|
|
394
|
+
incidentId: incidentId.toString(),
|
|
395
|
+
alertId: alertId.toString(),
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
return createdItem;
|
|
399
|
+
}
|
|
400
|
+
/*
|
|
401
|
+
* Carries the rows about to be deleted to onDeleteSuccess, which reports
|
|
402
|
+
* only the ones that were actually deleted: the permission check that runs
|
|
403
|
+
* after this hook can still narrow the delete. The read is not capped at
|
|
404
|
+
* the delete's own limit because that limit applies to the narrowed query,
|
|
405
|
+
* whose rows need not be among the first rows of this one.
|
|
406
|
+
*/
|
|
407
|
+
async onBeforeDelete(deleteBy) {
|
|
408
|
+
deleteBy.query = this.applyPrivacyFilters(deleteBy.query, deleteBy.props);
|
|
409
|
+
const carriedQuery = Object.assign({}, deleteBy.query);
|
|
410
|
+
if (deleteBy.props.tenantId && !carriedQuery.projectId) {
|
|
411
|
+
carriedQuery.projectId = deleteBy.props.tenantId;
|
|
412
|
+
}
|
|
413
|
+
const linksToDelete = await this.findBy({
|
|
414
|
+
query: carriedQuery,
|
|
415
|
+
select: {
|
|
416
|
+
_id: true,
|
|
417
|
+
incidentId: true,
|
|
418
|
+
alertId: true,
|
|
419
|
+
projectId: true,
|
|
420
|
+
},
|
|
421
|
+
limit: LIMIT_PER_PROJECT,
|
|
422
|
+
skip: 0,
|
|
423
|
+
props: {
|
|
424
|
+
isRoot: true,
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
const carried = [];
|
|
428
|
+
for (const link of linksToDelete) {
|
|
429
|
+
if (!link._id || !link.incidentId || !link.alertId || !link.projectId) {
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
carried.push({
|
|
433
|
+
id: link._id.toString(),
|
|
434
|
+
incidentId: link.incidentId,
|
|
435
|
+
alertId: link.alertId,
|
|
436
|
+
projectId: link.projectId,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
return { deleteBy, carryForward: carried };
|
|
440
|
+
}
|
|
441
|
+
async onDeleteSuccess(onDelete, itemIdsBeforeDelete) {
|
|
442
|
+
var _a;
|
|
443
|
+
const carried = Array.isArray(onDelete.carryForward)
|
|
444
|
+
? onDelete.carryForward
|
|
445
|
+
: [];
|
|
446
|
+
const deletedIds = new Set((itemIdsBeforeDelete || []).map((id) => {
|
|
447
|
+
return normalizeId(id);
|
|
448
|
+
}));
|
|
449
|
+
const actorUserId = ((_a = onDelete.deleteBy.deletedByUser) === null || _a === void 0 ? void 0 : _a.id) || onDelete.deleteBy.props.userId;
|
|
450
|
+
for (const link of carried) {
|
|
451
|
+
if (!deletedIds.has(normalizeId(link.id))) {
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
await this.createLinkFeedItems({
|
|
456
|
+
link: link,
|
|
457
|
+
isLinked: false,
|
|
458
|
+
actorUserId: actorUserId,
|
|
459
|
+
writeIncidentEntry: true,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
logger.error(`IncidentAlertService.onDeleteSuccess could not write the unlink feed items: ${error}`, {
|
|
464
|
+
projectId: link.projectId.toString(),
|
|
465
|
+
incidentId: link.incidentId.toString(),
|
|
466
|
+
alertId: link.alertId.toString(),
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return onDelete;
|
|
471
|
+
}
|
|
472
|
+
/*
|
|
473
|
+
* One entry on each side. Only the incident's entry is posted to Slack /
|
|
474
|
+
* Microsoft Teams: the incident's channels are where responders follow the
|
|
475
|
+
* incident, and posting the alert's entry as well would announce every link
|
|
476
|
+
* twice.
|
|
477
|
+
*
|
|
478
|
+
* Each entry is read by its own side's audience: the incident's feed and
|
|
479
|
+
* channels by whoever can see the incident, the alert's feed by whoever
|
|
480
|
+
* can see the alert. So a private end's title never goes into the other
|
|
481
|
+
* side's entry - not even when both ends are private, because two private
|
|
482
|
+
* records can have different owners. Its number and link are kept (opening
|
|
483
|
+
* the link is subject to the record's own privacy), which is what
|
|
484
|
+
* applyPrivacyFilters promises for the link rows themselves.
|
|
485
|
+
*/
|
|
486
|
+
async createLinkFeedItems(data) {
|
|
487
|
+
const { link, isLinked, actorUserId } = data;
|
|
488
|
+
const incident = await IncidentService.findOneById({
|
|
489
|
+
id: link.incidentId,
|
|
490
|
+
select: {
|
|
491
|
+
incidentNumber: true,
|
|
492
|
+
incidentNumberWithPrefix: true,
|
|
493
|
+
title: true,
|
|
494
|
+
isPrivate: true,
|
|
495
|
+
},
|
|
496
|
+
props: {
|
|
497
|
+
isRoot: true,
|
|
498
|
+
},
|
|
499
|
+
});
|
|
500
|
+
const alert = await AlertService.findOneById({
|
|
501
|
+
id: link.alertId,
|
|
502
|
+
select: {
|
|
503
|
+
alertNumber: true,
|
|
504
|
+
alertNumberWithPrefix: true,
|
|
505
|
+
title: true,
|
|
506
|
+
isPrivate: true,
|
|
507
|
+
},
|
|
508
|
+
props: {
|
|
509
|
+
isRoot: true,
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
const incidentLabel = withNumber("Incident", formatNumber(incident === null || incident === void 0 ? void 0 : incident.incidentNumberWithPrefix, incident === null || incident === void 0 ? void 0 : incident.incidentNumber));
|
|
513
|
+
const alertLabel = withNumber("Alert", formatNumber(alert === null || alert === void 0 ? void 0 : alert.alertNumberWithPrefix, alert === null || alert === void 0 ? void 0 : alert.alertNumber));
|
|
514
|
+
const incidentLink = (await IncidentService.getIncidentLinkInDashboard(link.projectId, link.incidentId)).toString();
|
|
515
|
+
const alertLink = (await AlertService.getAlertLinkInDashboard(link.projectId, link.alertId)).toString();
|
|
516
|
+
const alertMention = describeLinkedRecord({
|
|
517
|
+
label: alertLabel,
|
|
518
|
+
link: alertLink,
|
|
519
|
+
title: alert === null || alert === void 0 ? void 0 : alert.title,
|
|
520
|
+
isPrivate: (alert === null || alert === void 0 ? void 0 : alert.isPrivate) === true,
|
|
521
|
+
privateNoun: "alert",
|
|
522
|
+
});
|
|
523
|
+
const incidentMention = describeLinkedRecord({
|
|
524
|
+
label: incidentLabel,
|
|
525
|
+
link: incidentLink,
|
|
526
|
+
title: incident === null || incident === void 0 ? void 0 : incident.title,
|
|
527
|
+
isPrivate: (incident === null || incident === void 0 ? void 0 : incident.isPrivate) === true,
|
|
528
|
+
privateNoun: "incident",
|
|
529
|
+
});
|
|
530
|
+
const incidentSubject = `**[${incidentLabel}](${incidentLink})**`;
|
|
531
|
+
if (data.writeIncidentEntry) {
|
|
532
|
+
await IncidentFeedService.createIncidentFeedItem({
|
|
533
|
+
incidentId: link.incidentId,
|
|
534
|
+
projectId: link.projectId,
|
|
535
|
+
incidentFeedEventType: isLinked
|
|
536
|
+
? IncidentFeedEventType.AlertLinked
|
|
537
|
+
: IncidentFeedEventType.AlertUnlinked,
|
|
538
|
+
displayColor: isLinked ? Yellow500 : Gray500,
|
|
539
|
+
feedInfoInMarkdown: isLinked
|
|
540
|
+
? `🔗 Linked ${alertMention.subject} to ${incidentSubject}${alertMention.titleSuffix}`
|
|
541
|
+
: `Unlinked ${alertMention.subject} from ${incidentSubject}${alertMention.titleSuffix}`,
|
|
542
|
+
userId: actorUserId,
|
|
543
|
+
workspaceNotification: {
|
|
544
|
+
sendWorkspaceNotification: true,
|
|
545
|
+
notifyUserId: actorUserId,
|
|
546
|
+
},
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
await AlertFeedService.createAlertFeedItem({
|
|
550
|
+
alertId: link.alertId,
|
|
551
|
+
projectId: link.projectId,
|
|
552
|
+
alertFeedEventType: isLinked
|
|
553
|
+
? AlertFeedEventType.LinkedToIncident
|
|
554
|
+
: AlertFeedEventType.UnlinkedFromIncident,
|
|
555
|
+
displayColor: isLinked ? Yellow500 : Gray500,
|
|
556
|
+
feedInfoInMarkdown: isLinked
|
|
557
|
+
? `🔗 Linked to ${incidentMention.subject}${incidentMention.titleSuffix}`
|
|
558
|
+
: `Unlinked from ${incidentMention.subject}${incidentMention.titleSuffix}`,
|
|
559
|
+
userId: actorUserId,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
/*
|
|
563
|
+
* The single incident feed entry for an incident declared from alerts,
|
|
564
|
+
* posted to its Slack / Microsoft Teams channels. The links themselves are
|
|
565
|
+
* written without incident-side entries (INCIDENT_ALERT_DECLARED_WITH_
|
|
566
|
+
* INCIDENT_KEY), so the incident's channels get one message instead of one
|
|
567
|
+
* per alert. IncidentService calls this from its create chain once the
|
|
568
|
+
* "Incident Created" entry is out, which is also when the incident's own
|
|
569
|
+
* channels exist. Nothing is written when none of the alerts can be found.
|
|
570
|
+
*/
|
|
571
|
+
async createDeclaredFromAlertsFeedItem(data) {
|
|
572
|
+
const markdown = await this.buildDeclaredFromAlertsMarkdown({
|
|
573
|
+
projectId: data.projectId,
|
|
574
|
+
alertIds: data.alertIds,
|
|
575
|
+
});
|
|
576
|
+
if (!markdown) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
await IncidentFeedService.createIncidentFeedItem({
|
|
580
|
+
incidentId: data.incidentId,
|
|
581
|
+
projectId: data.projectId,
|
|
582
|
+
incidentFeedEventType: IncidentFeedEventType.AlertLinked,
|
|
583
|
+
displayColor: Yellow500,
|
|
584
|
+
feedInfoInMarkdown: markdown,
|
|
585
|
+
userId: data.actorUserId,
|
|
586
|
+
workspaceNotification: {
|
|
587
|
+
sendWorkspaceNotification: true,
|
|
588
|
+
notifyUserId: data.actorUserId,
|
|
589
|
+
},
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
/*
|
|
593
|
+
* The markdown for createDeclaredFromAlertsFeedItem: the project's alerts
|
|
594
|
+
* among `alertIds`, in that order, each with its number and dashboard
|
|
595
|
+
* link, and its title unless it is private. Read as root; null when none of
|
|
596
|
+
* the alerts exists (any more).
|
|
597
|
+
*/
|
|
598
|
+
async buildDeclaredFromAlertsMarkdown(data) {
|
|
599
|
+
if (data.alertIds.length === 0) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
const alerts = await AlertService.findBy({
|
|
603
|
+
query: {
|
|
604
|
+
_id: QueryHelper.any(data.alertIds),
|
|
605
|
+
projectId: data.projectId,
|
|
606
|
+
},
|
|
607
|
+
select: {
|
|
608
|
+
_id: true,
|
|
609
|
+
alertNumber: true,
|
|
610
|
+
alertNumberWithPrefix: true,
|
|
611
|
+
title: true,
|
|
612
|
+
isPrivate: true,
|
|
613
|
+
},
|
|
614
|
+
limit: LIMIT_PER_PROJECT,
|
|
615
|
+
skip: 0,
|
|
616
|
+
props: {
|
|
617
|
+
isRoot: true,
|
|
618
|
+
},
|
|
619
|
+
});
|
|
620
|
+
const alertById = new Map();
|
|
621
|
+
for (const alert of alerts) {
|
|
622
|
+
if (alert._id) {
|
|
623
|
+
alertById.set(normalizeId(alert._id), alert);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
const mentions = [];
|
|
627
|
+
const seen = new Set();
|
|
628
|
+
for (const alertId of data.alertIds) {
|
|
629
|
+
const key = normalizeId(alertId);
|
|
630
|
+
const alert = alertById.get(key);
|
|
631
|
+
if (!alert || seen.has(key)) {
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
seen.add(key);
|
|
635
|
+
mentions.push({
|
|
636
|
+
label: withNumber("Alert", formatNumber(alert.alertNumberWithPrefix, alert.alertNumber)),
|
|
637
|
+
link: (await AlertService.getAlertLinkInDashboard(data.projectId, new ObjectID(key))).toString(),
|
|
638
|
+
title: alert.title,
|
|
639
|
+
isPrivate: alert.isPrivate === true,
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
if (mentions.length === 0) {
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
645
|
+
return getDeclaredFromAlertsMarkdown(mentions);
|
|
646
|
+
}
|
|
647
|
+
/*
|
|
648
|
+
* Declaring a PRIVATE incident from alerts: the people who work those
|
|
649
|
+
* alerts become its owners too. A private incident is visible only to its
|
|
650
|
+
* owners (and project admins), and a private alert only to its owners, so
|
|
651
|
+
* without this the owners of the private alert an incident was declared
|
|
652
|
+
* from - the only non-admins who could see that alert - could not see the
|
|
653
|
+
* incident. The declaring user is already made an owner by
|
|
654
|
+
* DatabaseService.autoOwnerOnCreate. Owners are added as root, without
|
|
655
|
+
* notifying them (they were notified about their alerts), and owners the
|
|
656
|
+
* incident already has are skipped.
|
|
657
|
+
*/
|
|
658
|
+
async copyAlertOwnersToIncident(data) {
|
|
659
|
+
if (data.alertIds.length === 0) {
|
|
660
|
+
return { userIds: [], teamIds: [] };
|
|
661
|
+
}
|
|
662
|
+
const ownerUsers = await AlertOwnerUserService.findBy({
|
|
663
|
+
query: {
|
|
664
|
+
alertId: QueryHelper.any(data.alertIds),
|
|
665
|
+
projectId: data.projectId,
|
|
666
|
+
},
|
|
667
|
+
select: {
|
|
668
|
+
userId: true,
|
|
669
|
+
},
|
|
670
|
+
limit: LIMIT_PER_PROJECT,
|
|
671
|
+
skip: 0,
|
|
672
|
+
props: {
|
|
673
|
+
isRoot: true,
|
|
674
|
+
},
|
|
675
|
+
});
|
|
676
|
+
const ownerTeams = await AlertOwnerTeamService.findBy({
|
|
677
|
+
query: {
|
|
678
|
+
alertId: QueryHelper.any(data.alertIds),
|
|
679
|
+
projectId: data.projectId,
|
|
680
|
+
},
|
|
681
|
+
select: {
|
|
682
|
+
teamId: true,
|
|
683
|
+
},
|
|
684
|
+
limit: LIMIT_PER_PROJECT,
|
|
685
|
+
skip: 0,
|
|
686
|
+
props: {
|
|
687
|
+
isRoot: true,
|
|
688
|
+
},
|
|
689
|
+
});
|
|
690
|
+
const userIds = uniqueIds(ownerUsers.map((owner) => {
|
|
691
|
+
return owner.userId;
|
|
692
|
+
}));
|
|
693
|
+
const teamIds = uniqueIds(ownerTeams.map((owner) => {
|
|
694
|
+
return owner.teamId;
|
|
695
|
+
}));
|
|
696
|
+
if (userIds.length === 0 && teamIds.length === 0) {
|
|
697
|
+
return { userIds, teamIds };
|
|
698
|
+
}
|
|
699
|
+
await IncidentService.addOwners(data.projectId, data.incidentId, userIds, teamIds, false, {
|
|
700
|
+
isRoot: true,
|
|
701
|
+
});
|
|
702
|
+
return { userIds, teamIds };
|
|
703
|
+
}
|
|
704
|
+
/*
|
|
705
|
+
* Declaring an incident from alerts (miscDataProps.alertIdsToLink on an
|
|
706
|
+
* Incident create). Runs in IncidentService.onBeforeCreate, BEFORE the
|
|
707
|
+
* incident number is taken and before anything is written, so a bad id
|
|
708
|
+
* neither burns an incident number nor leaves an incident behind with
|
|
709
|
+
* half of its alerts. Returns the ids deduplicated and normalised, ready
|
|
710
|
+
* for linkAlertsToIncident once the incident exists.
|
|
711
|
+
*/
|
|
712
|
+
async validateAlertIdsForNewIncident(data) {
|
|
713
|
+
if (!Array.isArray(data.alertIds)) {
|
|
714
|
+
throw new BadDataException(`${INCIDENT_ALERT_IDS_TO_LINK_KEY} must be an array of alert ids.`);
|
|
715
|
+
}
|
|
716
|
+
const alertIds = [];
|
|
717
|
+
const seen = new Set();
|
|
718
|
+
for (const value of data.alertIds) {
|
|
719
|
+
let id = null;
|
|
720
|
+
if (typeof value === "string") {
|
|
721
|
+
id = value.trim();
|
|
722
|
+
}
|
|
723
|
+
else if (value instanceof ObjectID) {
|
|
724
|
+
id = value.toString().trim();
|
|
725
|
+
}
|
|
726
|
+
if (!id || !ObjectID.isValidUUID(id)) {
|
|
727
|
+
throw new BadDataException(`${INCIDENT_ALERT_IDS_TO_LINK_KEY} must only contain alert ids.`);
|
|
728
|
+
}
|
|
729
|
+
const key = normalizeId(id);
|
|
730
|
+
if (seen.has(key)) {
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
seen.add(key);
|
|
734
|
+
alertIds.push(new ObjectID(key));
|
|
735
|
+
}
|
|
736
|
+
if (alertIds.length === 0) {
|
|
737
|
+
throw new BadDataException("Please select at least one alert to link to the incident.");
|
|
738
|
+
}
|
|
739
|
+
if (alertIds.length > MAX_ALERTS_PER_INCIDENT_LINK_ACTION) {
|
|
740
|
+
throw new BadDataException(`You can link at most ${MAX_ALERTS_PER_INCIDENT_LINK_ACTION} alerts to an incident at a time. ${alertIds.length} were selected.`);
|
|
741
|
+
}
|
|
742
|
+
if (!data.projectId) {
|
|
743
|
+
throw new BadDataException("projectId is required to link alerts to an incident.");
|
|
744
|
+
}
|
|
745
|
+
const projectId = data.projectId;
|
|
746
|
+
if (!data.props.isRoot) {
|
|
747
|
+
/*
|
|
748
|
+
* The links are written as root once the incident exists (see
|
|
749
|
+
* IncidentService.onCreateSuccess), so this is where the caller's own
|
|
750
|
+
* right to link alerts is checked.
|
|
751
|
+
*/
|
|
752
|
+
const probe = new Model();
|
|
753
|
+
probe.projectId = projectId;
|
|
754
|
+
probe.incidentId = ObjectID.generate();
|
|
755
|
+
probe.alertId = alertIds[0];
|
|
756
|
+
try {
|
|
757
|
+
ModelPermission.checkCreatePermissions(Model, probe, data.props);
|
|
758
|
+
}
|
|
759
|
+
catch (error) {
|
|
760
|
+
// A lapsed session or an unpaid project keeps its own answer.
|
|
761
|
+
if (error instanceof NotAuthorizedException ||
|
|
762
|
+
error instanceof BadDataException) {
|
|
763
|
+
throw new BadDataException("You do not have permission to link alerts to incidents in this project.");
|
|
764
|
+
}
|
|
765
|
+
throw error;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
/*
|
|
769
|
+
* A user reads the alerts as themselves, so an alert they cannot open
|
|
770
|
+
* (a private alert, a label they are not allowed to see) cannot be
|
|
771
|
+
* pulled into their incident.
|
|
772
|
+
*/
|
|
773
|
+
const alerts = await this.findVisible(() => {
|
|
774
|
+
return AlertService.findBy({
|
|
775
|
+
query: {
|
|
776
|
+
_id: QueryHelper.any(alertIds),
|
|
777
|
+
projectId: projectId,
|
|
778
|
+
},
|
|
779
|
+
select: {
|
|
780
|
+
_id: true,
|
|
781
|
+
},
|
|
782
|
+
limit: LIMIT_PER_PROJECT,
|
|
783
|
+
skip: 0,
|
|
784
|
+
props: data.props.isRoot ? { isRoot: true } : data.props,
|
|
785
|
+
});
|
|
786
|
+
});
|
|
787
|
+
const foundIds = new Set((alerts || []).map((alert) => {
|
|
788
|
+
return normalizeId(alert._id || "");
|
|
789
|
+
}));
|
|
790
|
+
const missing = alertIds.filter((id) => {
|
|
791
|
+
return !foundIds.has(normalizeId(id));
|
|
792
|
+
});
|
|
793
|
+
if (missing.length > 0) {
|
|
794
|
+
throw new BadDataException(NOT_VISIBLE_ALERTS_MESSAGE);
|
|
795
|
+
}
|
|
796
|
+
return alertIds;
|
|
797
|
+
}
|
|
798
|
+
/*
|
|
799
|
+
* Links each alert to the incident, one at a time. An alert that is already
|
|
800
|
+
* linked counts as done, not as a failure; any other failure is reported per
|
|
801
|
+
* alert and never stops the rest.
|
|
802
|
+
*
|
|
803
|
+
* `declaredWithIncident` marks links written while the incident is being
|
|
804
|
+
* declared from these alerts: they get no incident-side feed entry of their
|
|
805
|
+
* own (see INCIDENT_ALERT_DECLARED_WITH_INCIDENT_KEY, root callers only).
|
|
806
|
+
*/
|
|
807
|
+
async linkAlertsToIncident(data) {
|
|
808
|
+
const result = {
|
|
809
|
+
linkedAlertIds: [],
|
|
810
|
+
alreadyLinkedAlertIds: [],
|
|
811
|
+
failed: [],
|
|
812
|
+
};
|
|
813
|
+
for (const alertId of data.alertIds) {
|
|
814
|
+
const link = new Model();
|
|
815
|
+
link.projectId = data.projectId;
|
|
816
|
+
link.incidentId = data.incidentId;
|
|
817
|
+
link.alertId = alertId;
|
|
818
|
+
if (data.createdByUserId) {
|
|
819
|
+
link.createdByUserId = data.createdByUserId;
|
|
820
|
+
}
|
|
821
|
+
try {
|
|
822
|
+
await this.create(Object.assign({ data: link, props: data.props }, (data.declaredWithIncident
|
|
823
|
+
? {
|
|
824
|
+
miscDataProps: {
|
|
825
|
+
[INCIDENT_ALERT_DECLARED_WITH_INCIDENT_KEY]: true,
|
|
826
|
+
},
|
|
827
|
+
}
|
|
828
|
+
: {})));
|
|
829
|
+
result.linkedAlertIds.push(alertId);
|
|
830
|
+
}
|
|
831
|
+
catch (error) {
|
|
832
|
+
if (PostgresErrorTranslator.isUniqueViolation(error)) {
|
|
833
|
+
result.alreadyLinkedAlertIds.push(alertId);
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
837
|
+
result.failed.push({ alertId: alertId, message: message });
|
|
838
|
+
logger.error(`IncidentAlertService could not link alert ${alertId.toString()} to incident ${data.incidentId.toString()}: ${message}`, {
|
|
839
|
+
projectId: data.projectId.toString(),
|
|
840
|
+
incidentId: data.incidentId.toString(),
|
|
841
|
+
alertId: alertId.toString(),
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return result;
|
|
846
|
+
}
|
|
847
|
+
/*
|
|
848
|
+
* An incident changed state: bring its linked alerts along, when the
|
|
849
|
+
* project has opted in. Called fire-and-forget from
|
|
850
|
+
* IncidentStateTimelineService.onCreateSuccess for the incident's CURRENT
|
|
851
|
+
* state only. Never throws; every failure is logged, and one alert failing
|
|
852
|
+
* does not stop the others.
|
|
853
|
+
*/
|
|
854
|
+
async cascadeIncidentStateToLinkedAlerts(data) {
|
|
855
|
+
try {
|
|
856
|
+
const switches = await this.getLinkedAlertSwitches(data.projectId);
|
|
857
|
+
if (!switches) {
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
const plan = await this.buildLinkedAlertStatePlan({
|
|
861
|
+
projectId: data.projectId,
|
|
862
|
+
incidentStateId: data.incidentStateId,
|
|
863
|
+
switches: switches,
|
|
864
|
+
});
|
|
865
|
+
if (!plan) {
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
const links = await this.findBy({
|
|
869
|
+
query: {
|
|
870
|
+
incidentId: data.incidentId,
|
|
871
|
+
projectId: data.projectId,
|
|
872
|
+
},
|
|
873
|
+
select: {
|
|
874
|
+
alertId: true,
|
|
875
|
+
},
|
|
876
|
+
limit: LIMIT_PER_PROJECT,
|
|
877
|
+
skip: 0,
|
|
878
|
+
props: {
|
|
879
|
+
isRoot: true,
|
|
880
|
+
},
|
|
881
|
+
});
|
|
882
|
+
const alertIds = [];
|
|
883
|
+
for (const link of links) {
|
|
884
|
+
if (link.alertId) {
|
|
885
|
+
alertIds.push(link.alertId);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (alertIds.length === 0) {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
const incident = await IncidentService.findOneById({
|
|
892
|
+
id: data.incidentId,
|
|
893
|
+
select: {
|
|
894
|
+
incidentNumber: true,
|
|
895
|
+
incidentNumberWithPrefix: true,
|
|
896
|
+
},
|
|
897
|
+
props: {
|
|
898
|
+
isRoot: true,
|
|
899
|
+
},
|
|
900
|
+
});
|
|
901
|
+
if (!incident) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
await this.applyLinkedAlertStatePlan({
|
|
905
|
+
plan: plan,
|
|
906
|
+
projectId: data.projectId,
|
|
907
|
+
incidentId: data.incidentId,
|
|
908
|
+
incidentNumber: formatNumber(incident.incidentNumberWithPrefix, incident.incidentNumber),
|
|
909
|
+
alertIds: alertIds,
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
catch (error) {
|
|
913
|
+
logger.error(`IncidentAlertService could not carry an incident state change over to its linked alerts: ${error}`, {
|
|
914
|
+
projectId: data.projectId.toString(),
|
|
915
|
+
incidentId: data.incidentId.toString(),
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
/*
|
|
920
|
+
* The link-time half: an alert was just linked to an incident that may
|
|
921
|
+
* already be acknowledged or resolved. Same rules as the cascade, applied to
|
|
922
|
+
* the one alert. A newly declared incident is in its created state, so
|
|
923
|
+
* this is a no-op for "declare incident from alerts". Never throws.
|
|
924
|
+
*/
|
|
925
|
+
async syncAlertWithLinkedIncidentState(data) {
|
|
926
|
+
try {
|
|
927
|
+
const switches = await this.getLinkedAlertSwitches(data.projectId);
|
|
928
|
+
if (!switches) {
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
const incident = await IncidentService.findOneById({
|
|
932
|
+
id: data.incidentId,
|
|
933
|
+
select: {
|
|
934
|
+
currentIncidentStateId: true,
|
|
935
|
+
incidentNumber: true,
|
|
936
|
+
incidentNumberWithPrefix: true,
|
|
937
|
+
},
|
|
938
|
+
props: {
|
|
939
|
+
isRoot: true,
|
|
940
|
+
},
|
|
941
|
+
});
|
|
942
|
+
if (!incident || !incident.currentIncidentStateId) {
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
const plan = await this.buildLinkedAlertStatePlan({
|
|
946
|
+
projectId: data.projectId,
|
|
947
|
+
incidentStateId: incident.currentIncidentStateId,
|
|
948
|
+
switches: switches,
|
|
949
|
+
});
|
|
950
|
+
if (!plan) {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
await this.applyLinkedAlertStatePlan({
|
|
954
|
+
plan: plan,
|
|
955
|
+
projectId: data.projectId,
|
|
956
|
+
incidentId: data.incidentId,
|
|
957
|
+
incidentNumber: formatNumber(incident.incidentNumberWithPrefix, incident.incidentNumber),
|
|
958
|
+
alertIds: [data.alertId],
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
catch (error) {
|
|
962
|
+
logger.error(`IncidentAlertService could not sync a linked alert with its incident's state: ${error}`, {
|
|
963
|
+
projectId: data.projectId.toString(),
|
|
964
|
+
incidentId: data.incidentId.toString(),
|
|
965
|
+
alertId: data.alertId.toString(),
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
// Null when both project switches are off (the default).
|
|
970
|
+
async getLinkedAlertSwitches(projectId) {
|
|
971
|
+
const project = await ProjectService.findOneById({
|
|
972
|
+
id: projectId,
|
|
973
|
+
select: {
|
|
974
|
+
acknowledgeLinkedAlertsWhenIncidentAcknowledged: true,
|
|
975
|
+
resolveLinkedAlertsWhenIncidentResolved: true,
|
|
976
|
+
},
|
|
977
|
+
props: {
|
|
978
|
+
isRoot: true,
|
|
979
|
+
},
|
|
980
|
+
});
|
|
981
|
+
const switches = {
|
|
982
|
+
acknowledge: (project === null || project === void 0 ? void 0 : project.acknowledgeLinkedAlertsWhenIncidentAcknowledged) === true,
|
|
983
|
+
resolve: (project === null || project === void 0 ? void 0 : project.resolveLinkedAlertsWhenIncidentResolved) === true,
|
|
984
|
+
};
|
|
985
|
+
if (!switches.acknowledge && !switches.resolve) {
|
|
986
|
+
return null;
|
|
987
|
+
}
|
|
988
|
+
return switches;
|
|
989
|
+
}
|
|
990
|
+
// Null when the incident's state calls for nothing.
|
|
991
|
+
async buildLinkedAlertStatePlan(data) {
|
|
992
|
+
const logAttributes = {
|
|
993
|
+
projectId: data.projectId.toString(),
|
|
994
|
+
};
|
|
995
|
+
const incidentStates = await IncidentStateService.getAllIncidentStates({
|
|
996
|
+
projectId: data.projectId,
|
|
997
|
+
props: {
|
|
998
|
+
isRoot: true,
|
|
999
|
+
},
|
|
1000
|
+
});
|
|
1001
|
+
const incidentStateOrderById = new Map();
|
|
1002
|
+
for (const state of incidentStates) {
|
|
1003
|
+
if (state._id && state.order !== undefined && state.order !== null) {
|
|
1004
|
+
incidentStateOrderById.set(normalizeId(state._id), state.order);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
const incidentStateOrder = incidentStateOrderById.get(normalizeId(data.incidentStateId));
|
|
1008
|
+
if (incidentStateOrder === undefined) {
|
|
1009
|
+
logger.error(`IncidentAlertService: incident state ${data.incidentStateId.toString()} was not found in its project, linked alerts were left as they are.`, logAttributes);
|
|
1010
|
+
return null;
|
|
1011
|
+
}
|
|
1012
|
+
const acknowledgedIncidentState = incidentStates.find((state) => {
|
|
1013
|
+
return state.isAcknowledgedState;
|
|
1014
|
+
});
|
|
1015
|
+
const resolvedIncidentState = incidentStates.find((state) => {
|
|
1016
|
+
return state.isResolvedState;
|
|
1017
|
+
});
|
|
1018
|
+
const targets = getLinkedAlertStateTargets({
|
|
1019
|
+
incidentStateOrder: incidentStateOrder,
|
|
1020
|
+
acknowledgedIncidentStateOrder: acknowledgedIncidentState === null || acknowledgedIncidentState === void 0 ? void 0 : acknowledgedIncidentState.order,
|
|
1021
|
+
resolvedIncidentStateOrder: resolvedIncidentState === null || resolvedIncidentState === void 0 ? void 0 : resolvedIncidentState.order,
|
|
1022
|
+
acknowledgeSwitch: data.switches.acknowledge,
|
|
1023
|
+
resolveSwitch: data.switches.resolve,
|
|
1024
|
+
});
|
|
1025
|
+
if (!targets.acknowledge && !targets.resolve) {
|
|
1026
|
+
return null;
|
|
1027
|
+
}
|
|
1028
|
+
const alertStates = await AlertStateService.getAllAlertStates({
|
|
1029
|
+
projectId: data.projectId,
|
|
1030
|
+
props: {
|
|
1031
|
+
isRoot: true,
|
|
1032
|
+
},
|
|
1033
|
+
});
|
|
1034
|
+
const alertStateOrderById = new Map();
|
|
1035
|
+
for (const state of alertStates) {
|
|
1036
|
+
if (state._id && state.order !== undefined && state.order !== null) {
|
|
1037
|
+
alertStateOrderById.set(normalizeId(state._id), state.order);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
let acknowledgedAlertState = undefined;
|
|
1041
|
+
let resolvedAlertState = undefined;
|
|
1042
|
+
if (targets.acknowledge) {
|
|
1043
|
+
acknowledgedAlertState = alertStates.find((state) => {
|
|
1044
|
+
return state.isAcknowledgedState;
|
|
1045
|
+
});
|
|
1046
|
+
if (!acknowledgedAlertState) {
|
|
1047
|
+
logger.error("IncidentAlertService: the project has no Acknowledged alert state, so linked alerts could not be acknowledged.", logAttributes);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
if (targets.resolve) {
|
|
1051
|
+
resolvedAlertState = alertStates.find((state) => {
|
|
1052
|
+
return state.isResolvedState;
|
|
1053
|
+
});
|
|
1054
|
+
if (!resolvedAlertState) {
|
|
1055
|
+
logger.error("IncidentAlertService: the project has no Resolved alert state, so linked alerts could not be resolved.", logAttributes);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
if (!acknowledgedAlertState && !resolvedAlertState) {
|
|
1059
|
+
return null;
|
|
1060
|
+
}
|
|
1061
|
+
return {
|
|
1062
|
+
acknowledgedAlertState: acknowledgedAlertState,
|
|
1063
|
+
resolvedAlertState: resolvedAlertState,
|
|
1064
|
+
incidentReachedResolved: targets.incidentReachedResolved,
|
|
1065
|
+
resolvedIncidentStateOrder: resolvedIncidentState === null || resolvedIncidentState === void 0 ? void 0 : resolvedIncidentState.order,
|
|
1066
|
+
alertStateOrderById: alertStateOrderById,
|
|
1067
|
+
incidentStateOrderById: incidentStateOrderById,
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
async applyLinkedAlertStatePlan(data) {
|
|
1071
|
+
var _a;
|
|
1072
|
+
const { plan, projectId, incidentId } = data;
|
|
1073
|
+
const alerts = await AlertService.findBy({
|
|
1074
|
+
query: {
|
|
1075
|
+
_id: QueryHelper.any(data.alertIds),
|
|
1076
|
+
projectId: projectId,
|
|
1077
|
+
},
|
|
1078
|
+
select: {
|
|
1079
|
+
_id: true,
|
|
1080
|
+
currentAlertStateId: true,
|
|
1081
|
+
},
|
|
1082
|
+
limit: LIMIT_PER_PROJECT,
|
|
1083
|
+
skip: 0,
|
|
1084
|
+
props: {
|
|
1085
|
+
isRoot: true,
|
|
1086
|
+
},
|
|
1087
|
+
});
|
|
1088
|
+
const blockedFromResolve = plan.resolvedAlertState
|
|
1089
|
+
? await this.getAlertsHeldOpenByAnotherIncident({
|
|
1090
|
+
plan: plan,
|
|
1091
|
+
projectId: projectId,
|
|
1092
|
+
incidentId: incidentId,
|
|
1093
|
+
alerts: alerts,
|
|
1094
|
+
})
|
|
1095
|
+
: new Set();
|
|
1096
|
+
const incidentLabel = withNumber("Incident", data.incidentNumber);
|
|
1097
|
+
for (const alert of alerts) {
|
|
1098
|
+
const alertId = ((_a = alert._id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
|
|
1099
|
+
const alertStateOrder = alert.currentAlertStateId
|
|
1100
|
+
? plan.alertStateOrderById.get(normalizeId(alert.currentAlertStateId))
|
|
1101
|
+
: undefined;
|
|
1102
|
+
if (!alertId || alertStateOrder === undefined) {
|
|
1103
|
+
logger.error(`IncidentAlertService: the current state of linked alert ${alertId} is unknown, so it was left as it is.`, {
|
|
1104
|
+
projectId: projectId.toString(),
|
|
1105
|
+
incidentId: incidentId.toString(),
|
|
1106
|
+
alertId: alertId,
|
|
1107
|
+
});
|
|
1108
|
+
continue;
|
|
1109
|
+
}
|
|
1110
|
+
const target = chooseLinkedAlertTargetState({
|
|
1111
|
+
alertStateOrder: alertStateOrder,
|
|
1112
|
+
acknowledgedAlertState: plan.acknowledgedAlertState,
|
|
1113
|
+
resolvedAlertState: plan.resolvedAlertState,
|
|
1114
|
+
isBlockedFromResolve: blockedFromResolve.has(normalizeId(alertId)),
|
|
1115
|
+
});
|
|
1116
|
+
if (!target || !target._id) {
|
|
1117
|
+
continue;
|
|
1118
|
+
}
|
|
1119
|
+
const isResolving = target === plan.resolvedAlertState;
|
|
1120
|
+
const rootCause = isResolving
|
|
1121
|
+
? `Resolved because linked ${incidentLabel} was resolved.`
|
|
1122
|
+
: `Acknowledged because linked ${incidentLabel} was ${plan.incidentReachedResolved ? "resolved" : "acknowledged"}.`;
|
|
1123
|
+
try {
|
|
1124
|
+
await AlertService.changeAlertState({
|
|
1125
|
+
projectId: projectId,
|
|
1126
|
+
alertId: new ObjectID(alertId),
|
|
1127
|
+
alertStateId: new ObjectID(target._id.toString()),
|
|
1128
|
+
notifyOwners: false,
|
|
1129
|
+
rootCause: rootCause,
|
|
1130
|
+
stateChangeLog: undefined,
|
|
1131
|
+
props: {
|
|
1132
|
+
isRoot: true,
|
|
1133
|
+
},
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
catch (error) {
|
|
1137
|
+
logger.error(`IncidentAlertService could not change the state of linked alert ${alertId}: ${error}`, {
|
|
1138
|
+
projectId: projectId.toString(),
|
|
1139
|
+
incidentId: incidentId.toString(),
|
|
1140
|
+
alertId: alertId,
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
/*
|
|
1146
|
+
* An alert linked to several incidents is resolved only once none of them
|
|
1147
|
+
* is still open: resolving one incident must not close an alert another
|
|
1148
|
+
* open incident is still tracking. Only alerts that would otherwise be
|
|
1149
|
+
* resolved are looked up.
|
|
1150
|
+
*/
|
|
1151
|
+
async getAlertsHeldOpenByAnotherIncident(data) {
|
|
1152
|
+
var _a;
|
|
1153
|
+
const held = new Set();
|
|
1154
|
+
const resolvedAlertStateOrder = (_a = data.plan.resolvedAlertState) === null || _a === void 0 ? void 0 : _a.order;
|
|
1155
|
+
if (resolvedAlertStateOrder === undefined) {
|
|
1156
|
+
return held;
|
|
1157
|
+
}
|
|
1158
|
+
const candidateIds = [];
|
|
1159
|
+
for (const alert of data.alerts) {
|
|
1160
|
+
const order = alert.currentAlertStateId
|
|
1161
|
+
? data.plan.alertStateOrderById.get(normalizeId(alert.currentAlertStateId))
|
|
1162
|
+
: undefined;
|
|
1163
|
+
if (alert._id && order !== undefined && order < resolvedAlertStateOrder) {
|
|
1164
|
+
candidateIds.push(normalizeId(alert._id));
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
if (candidateIds.length === 0) {
|
|
1168
|
+
return held;
|
|
1169
|
+
}
|
|
1170
|
+
const otherLinks = await this.findBy({
|
|
1171
|
+
query: {
|
|
1172
|
+
alertId: QueryHelper.any(candidateIds),
|
|
1173
|
+
projectId: data.projectId,
|
|
1174
|
+
},
|
|
1175
|
+
select: {
|
|
1176
|
+
alertId: true,
|
|
1177
|
+
incidentId: true,
|
|
1178
|
+
},
|
|
1179
|
+
limit: LIMIT_PER_PROJECT,
|
|
1180
|
+
skip: 0,
|
|
1181
|
+
props: {
|
|
1182
|
+
isRoot: true,
|
|
1183
|
+
},
|
|
1184
|
+
});
|
|
1185
|
+
const thisIncidentId = normalizeId(data.incidentId);
|
|
1186
|
+
const otherIncidentIdsByAlert = new Map();
|
|
1187
|
+
const otherIncidentIds = new Set();
|
|
1188
|
+
for (const link of otherLinks) {
|
|
1189
|
+
if (!link.alertId || !link.incidentId) {
|
|
1190
|
+
continue;
|
|
1191
|
+
}
|
|
1192
|
+
const incidentId = normalizeId(link.incidentId);
|
|
1193
|
+
if (incidentId === thisIncidentId) {
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
const alertId = normalizeId(link.alertId);
|
|
1197
|
+
const incidentIds = otherIncidentIdsByAlert.get(alertId) || [];
|
|
1198
|
+
incidentIds.push(incidentId);
|
|
1199
|
+
otherIncidentIdsByAlert.set(alertId, incidentIds);
|
|
1200
|
+
otherIncidentIds.add(incidentId);
|
|
1201
|
+
}
|
|
1202
|
+
if (otherIncidentIds.size === 0) {
|
|
1203
|
+
return held;
|
|
1204
|
+
}
|
|
1205
|
+
const otherIncidents = await IncidentService.findBy({
|
|
1206
|
+
query: {
|
|
1207
|
+
_id: QueryHelper.any(Array.from(otherIncidentIds)),
|
|
1208
|
+
projectId: data.projectId,
|
|
1209
|
+
},
|
|
1210
|
+
select: {
|
|
1211
|
+
_id: true,
|
|
1212
|
+
currentIncidentStateId: true,
|
|
1213
|
+
},
|
|
1214
|
+
limit: LIMIT_PER_PROJECT,
|
|
1215
|
+
skip: 0,
|
|
1216
|
+
props: {
|
|
1217
|
+
isRoot: true,
|
|
1218
|
+
},
|
|
1219
|
+
});
|
|
1220
|
+
const openIncidentIds = new Set();
|
|
1221
|
+
for (const incident of otherIncidents) {
|
|
1222
|
+
if (!incident._id) {
|
|
1223
|
+
continue;
|
|
1224
|
+
}
|
|
1225
|
+
const order = incident.currentIncidentStateId
|
|
1226
|
+
? data.plan.incidentStateOrderById.get(normalizeId(incident.currentIncidentStateId))
|
|
1227
|
+
: undefined;
|
|
1228
|
+
/*
|
|
1229
|
+
* An incident whose state cannot be placed is treated as open: leaving
|
|
1230
|
+
* an alert unresolved is recoverable, resolving it too early is not.
|
|
1231
|
+
*/
|
|
1232
|
+
const isResolved = order !== undefined &&
|
|
1233
|
+
data.plan.resolvedIncidentStateOrder !== undefined &&
|
|
1234
|
+
order >= data.plan.resolvedIncidentStateOrder;
|
|
1235
|
+
if (!isResolved) {
|
|
1236
|
+
openIncidentIds.add(normalizeId(incident._id));
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
for (const [alertId, incidentIds] of otherIncidentIdsByAlert) {
|
|
1240
|
+
if (incidentIds.some((incidentId) => {
|
|
1241
|
+
return openIncidentIds.has(incidentId);
|
|
1242
|
+
})) {
|
|
1243
|
+
held.add(alertId);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
return held;
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
__decorate([
|
|
1250
|
+
CaptureSpan(),
|
|
1251
|
+
__metadata("design:type", Function),
|
|
1252
|
+
__metadata("design:paramtypes", [Object]),
|
|
1253
|
+
__metadata("design:returntype", Promise)
|
|
1254
|
+
], Service.prototype, "onBeforeFind", null);
|
|
1255
|
+
__decorate([
|
|
1256
|
+
CaptureSpan(),
|
|
1257
|
+
__metadata("design:type", Function),
|
|
1258
|
+
__metadata("design:paramtypes", [Object]),
|
|
1259
|
+
__metadata("design:returntype", Promise)
|
|
1260
|
+
], Service.prototype, "countBy", null);
|
|
1261
|
+
__decorate([
|
|
1262
|
+
CaptureSpan(),
|
|
1263
|
+
__metadata("design:type", Function),
|
|
1264
|
+
__metadata("design:paramtypes", [Object]),
|
|
1265
|
+
__metadata("design:returntype", Promise)
|
|
1266
|
+
], Service.prototype, "onBeforeUpdate", null);
|
|
1267
|
+
__decorate([
|
|
1268
|
+
CaptureSpan(),
|
|
1269
|
+
__metadata("design:type", Function),
|
|
1270
|
+
__metadata("design:paramtypes", [Object]),
|
|
1271
|
+
__metadata("design:returntype", Promise)
|
|
1272
|
+
], Service.prototype, "onBeforeCreate", null);
|
|
1273
|
+
__decorate([
|
|
1274
|
+
CaptureSpan(),
|
|
1275
|
+
__metadata("design:type", Function),
|
|
1276
|
+
__metadata("design:paramtypes", [Function]),
|
|
1277
|
+
__metadata("design:returntype", Promise)
|
|
1278
|
+
], Service.prototype, "findVisible", null);
|
|
1279
|
+
__decorate([
|
|
1280
|
+
CaptureSpan(),
|
|
1281
|
+
__metadata("design:type", Function),
|
|
1282
|
+
__metadata("design:paramtypes", [Object, Model]),
|
|
1283
|
+
__metadata("design:returntype", Promise)
|
|
1284
|
+
], Service.prototype, "onCreateSuccess", null);
|
|
1285
|
+
__decorate([
|
|
1286
|
+
CaptureSpan(),
|
|
1287
|
+
__metadata("design:type", Function),
|
|
1288
|
+
__metadata("design:paramtypes", [Object]),
|
|
1289
|
+
__metadata("design:returntype", Promise)
|
|
1290
|
+
], Service.prototype, "onBeforeDelete", null);
|
|
1291
|
+
__decorate([
|
|
1292
|
+
CaptureSpan(),
|
|
1293
|
+
__metadata("design:type", Function),
|
|
1294
|
+
__metadata("design:paramtypes", [Object, Array]),
|
|
1295
|
+
__metadata("design:returntype", Promise)
|
|
1296
|
+
], Service.prototype, "onDeleteSuccess", null);
|
|
1297
|
+
__decorate([
|
|
1298
|
+
CaptureSpan(),
|
|
1299
|
+
__metadata("design:type", Function),
|
|
1300
|
+
__metadata("design:paramtypes", [Object]),
|
|
1301
|
+
__metadata("design:returntype", Promise)
|
|
1302
|
+
], Service.prototype, "createLinkFeedItems", null);
|
|
1303
|
+
__decorate([
|
|
1304
|
+
CaptureSpan(),
|
|
1305
|
+
__metadata("design:type", Function),
|
|
1306
|
+
__metadata("design:paramtypes", [Object]),
|
|
1307
|
+
__metadata("design:returntype", Promise)
|
|
1308
|
+
], Service.prototype, "createDeclaredFromAlertsFeedItem", null);
|
|
1309
|
+
__decorate([
|
|
1310
|
+
CaptureSpan(),
|
|
1311
|
+
__metadata("design:type", Function),
|
|
1312
|
+
__metadata("design:paramtypes", [Object]),
|
|
1313
|
+
__metadata("design:returntype", Promise)
|
|
1314
|
+
], Service.prototype, "buildDeclaredFromAlertsMarkdown", null);
|
|
1315
|
+
__decorate([
|
|
1316
|
+
CaptureSpan(),
|
|
1317
|
+
__metadata("design:type", Function),
|
|
1318
|
+
__metadata("design:paramtypes", [Object]),
|
|
1319
|
+
__metadata("design:returntype", Promise)
|
|
1320
|
+
], Service.prototype, "copyAlertOwnersToIncident", null);
|
|
1321
|
+
__decorate([
|
|
1322
|
+
CaptureSpan(),
|
|
1323
|
+
__metadata("design:type", Function),
|
|
1324
|
+
__metadata("design:paramtypes", [Object]),
|
|
1325
|
+
__metadata("design:returntype", Promise)
|
|
1326
|
+
], Service.prototype, "validateAlertIdsForNewIncident", null);
|
|
1327
|
+
__decorate([
|
|
1328
|
+
CaptureSpan(),
|
|
1329
|
+
__metadata("design:type", Function),
|
|
1330
|
+
__metadata("design:paramtypes", [Object]),
|
|
1331
|
+
__metadata("design:returntype", Promise)
|
|
1332
|
+
], Service.prototype, "linkAlertsToIncident", null);
|
|
1333
|
+
__decorate([
|
|
1334
|
+
CaptureSpan(),
|
|
1335
|
+
__metadata("design:type", Function),
|
|
1336
|
+
__metadata("design:paramtypes", [Object]),
|
|
1337
|
+
__metadata("design:returntype", Promise)
|
|
1338
|
+
], Service.prototype, "cascadeIncidentStateToLinkedAlerts", null);
|
|
1339
|
+
__decorate([
|
|
1340
|
+
CaptureSpan(),
|
|
1341
|
+
__metadata("design:type", Function),
|
|
1342
|
+
__metadata("design:paramtypes", [Object]),
|
|
1343
|
+
__metadata("design:returntype", Promise)
|
|
1344
|
+
], Service.prototype, "syncAlertWithLinkedIncidentState", null);
|
|
1345
|
+
__decorate([
|
|
1346
|
+
CaptureSpan(),
|
|
1347
|
+
__metadata("design:type", Function),
|
|
1348
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
1349
|
+
__metadata("design:returntype", Promise)
|
|
1350
|
+
], Service.prototype, "getLinkedAlertSwitches", null);
|
|
1351
|
+
__decorate([
|
|
1352
|
+
CaptureSpan(),
|
|
1353
|
+
__metadata("design:type", Function),
|
|
1354
|
+
__metadata("design:paramtypes", [Object]),
|
|
1355
|
+
__metadata("design:returntype", Promise)
|
|
1356
|
+
], Service.prototype, "buildLinkedAlertStatePlan", null);
|
|
1357
|
+
__decorate([
|
|
1358
|
+
CaptureSpan(),
|
|
1359
|
+
__metadata("design:type", Function),
|
|
1360
|
+
__metadata("design:paramtypes", [Object]),
|
|
1361
|
+
__metadata("design:returntype", Promise)
|
|
1362
|
+
], Service.prototype, "applyLinkedAlertStatePlan", null);
|
|
1363
|
+
__decorate([
|
|
1364
|
+
CaptureSpan(),
|
|
1365
|
+
__metadata("design:type", Function),
|
|
1366
|
+
__metadata("design:paramtypes", [Object]),
|
|
1367
|
+
__metadata("design:returntype", Promise)
|
|
1368
|
+
], Service.prototype, "getAlertsHeldOpenByAnotherIncident", null);
|
|
1369
|
+
export default new Service();
|
|
1370
|
+
//# sourceMappingURL=IncidentAlertService.js.map
|