From a47a155a8912cb3201a3237b5430144a08a70ca4 Mon Sep 17 00:00:00 2001 From: Tom Ratcliffe Date: Wed, 23 Apr 2025 12:14:27 +0100 Subject: [PATCH] Alerting: Only show DMA button when query datasource supports it (#104158) --- .../QueryAndExpressionsStep.tsx | 8 ++- .../SmartAlertTypeDetector.tsx | 61 +---------------- .../query-and-alert-condition/utils.ts | 65 +++++++++++++++++++ .../unified/components/rules/CloudRules.tsx | 2 +- 4 files changed, 74 insertions(+), 62 deletions(-) create mode 100644 public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/utils.ts diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx index ebb273dc03f..bc07dbb70a9 100644 --- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx @@ -78,6 +78,7 @@ import { } from './reducer'; import { useAdvancedMode } from './useAdvancedMode'; import { useAlertQueryRunner } from './useAlertQueryRunner'; +import { onlyOneDSInQueries } from './utils'; interface Props { editingExistingRule: boolean; @@ -474,7 +475,10 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod } : undefined; - const hasDatasourcesForDataSourceManaged = Boolean(rulesSourcesWithRuler.length); + const canSelectDataSourceManaged = + onlyOneDSInQueries(queries) && + Boolean(rulesSourcesWithRuler.length) && + queries.some((query) => rulesSourcesWithRuler.some((source) => source.uid === query.datasourceUid)); return ( <> @@ -594,7 +598,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod )} {/* We only show Switch for Grafana managed alerts */} - {hasDatasourcesForDataSourceManaged && isGrafanaAlertingType && !simplifiedQueryStep && mode === 'edit' && ( + {canSelectDataSourceManaged && isGrafanaAlertingType && !simplifiedQueryStep && mode === 'edit' && ( <> { - return queries.filter((q) => q.datasourceUid !== ExpressionDatasourceUID).length === 1; -}; -const getCanSwitch = ({ - queries, - ruleFormType, - rulesSourcesWithRuler, -}: { - rulesSourcesWithRuler: Array>; - queries: AlertQuery[]; - ruleFormType: RuleFormType | undefined; -}) => { - // get available rule types - const availableRuleTypes = getAvailableRuleTypes(); - - // check if we have only one query in queries and if it's a cloud datasource - const onlyOneDS = onlyOneDSInQueries(queries); - const dataSourceIdFromQueries = queries[0]?.datasourceUid ?? ''; - const isRecordingRuleType = ruleFormType === RuleFormType.cloudRecording; - - //let's check if we switch to cloud type - const canSwitchToCloudRule = - !isRecordingRuleType && - onlyOneDS && - rulesSourcesWithRuler.some((dsJsonData) => dsJsonData.uid === dataSourceIdFromQueries); - - const canSwitchToGrafanaRule = !isRecordingRuleType; - // check for enabled types - const grafanaTypeEnabled = availableRuleTypes.enabledRuleTypes.includes(RuleFormType.grafana); - const cloudTypeEnabled = availableRuleTypes.enabledRuleTypes.includes(RuleFormType.cloudAlerting); - - // can we switch to the other type? (cloud or grafana) - const canSwitchFromCloudToGrafana = - ruleFormType === RuleFormType.cloudAlerting && grafanaTypeEnabled && canSwitchToGrafanaRule; - const canSwitchFromGrafanaToCloud = - ruleFormType === RuleFormType.grafana && canSwitchToCloudRule && cloudTypeEnabled && canSwitchToCloudRule; - - return canSwitchFromCloudToGrafana || canSwitchFromGrafanaToCloud; -}; - -export interface SmartAlertTypeDetectorProps { +interface SmartAlertTypeDetectorProps { editingExistingRule: boolean; rulesSourcesWithRuler: Array>; queries: AlertQuery[]; diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/utils.ts b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/utils.ts new file mode 100644 index 00000000000..6ad5dac7d73 --- /dev/null +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/utils.ts @@ -0,0 +1,65 @@ +import { DataSourceInstanceSettings } from '@grafana/data'; +import { DataSourceJsonData } from '@grafana/schema/dist/esm/index'; +import { contextSrv } from 'app/core/core'; +import { ExpressionDatasourceUID } from 'app/features/expressions/types'; +import { AccessControlAction } from 'app/types'; +import { AlertQuery } from 'app/types/unified-alerting-dto'; + +import { RuleFormType } from '../../../types/rule-form'; + +export const onlyOneDSInQueries = (queries: AlertQuery[]) => { + return queries.filter((q) => q.datasourceUid !== ExpressionDatasourceUID).length === 1; +}; + +function getAvailableRuleTypes() { + const canCreateGrafanaRules = contextSrv.hasPermission(AccessControlAction.AlertingRuleCreate); + const canCreateCloudRules = contextSrv.hasPermission(AccessControlAction.AlertingRuleExternalWrite); + const defaultRuleType = canCreateGrafanaRules ? RuleFormType.grafana : RuleFormType.cloudAlerting; + + const enabledRuleTypes: RuleFormType[] = []; + if (canCreateGrafanaRules) { + enabledRuleTypes.push(RuleFormType.grafana); + } + if (canCreateCloudRules) { + enabledRuleTypes.push(RuleFormType.cloudAlerting, RuleFormType.cloudRecording); + } + + return { enabledRuleTypes, defaultRuleType }; +} + +export const getCanSwitch = ({ + queries, + ruleFormType, + rulesSourcesWithRuler, +}: { + rulesSourcesWithRuler: Array>; + queries: AlertQuery[]; + ruleFormType: RuleFormType | undefined; +}) => { + // get available rule types + const availableRuleTypes = getAvailableRuleTypes(); + + // check if we have only one query in queries and if it's a cloud datasource + const onlyOneDS = onlyOneDSInQueries(queries); + const dataSourceIdFromQueries = queries[0]?.datasourceUid ?? ''; + const isRecordingRuleType = ruleFormType === RuleFormType.cloudRecording; + + //let's check if we switch to cloud type + const canSwitchToCloudRule = + !isRecordingRuleType && + onlyOneDS && + rulesSourcesWithRuler.some((dsJsonData) => dsJsonData.uid === dataSourceIdFromQueries); + + const canSwitchToGrafanaRule = !isRecordingRuleType; + // check for enabled types + const grafanaTypeEnabled = availableRuleTypes.enabledRuleTypes.includes(RuleFormType.grafana); + const cloudTypeEnabled = availableRuleTypes.enabledRuleTypes.includes(RuleFormType.cloudAlerting); + + // can we switch to the other type? (cloud or grafana) + const canSwitchFromCloudToGrafana = + ruleFormType === RuleFormType.cloudAlerting && grafanaTypeEnabled && canSwitchToGrafanaRule; + const canSwitchFromGrafanaToCloud = + ruleFormType === RuleFormType.grafana && canSwitchToCloudRule && cloudTypeEnabled && canSwitchToCloudRule; + + return canSwitchFromCloudToGrafana || canSwitchFromGrafanaToCloud; +}; diff --git a/public/app/features/alerting/unified/components/rules/CloudRules.tsx b/public/app/features/alerting/unified/components/rules/CloudRules.tsx index 4f39b1dce3d..bb8e5849ea4 100644 --- a/public/app/features/alerting/unified/components/rules/CloudRules.tsx +++ b/public/app/features/alerting/unified/components/rules/CloudRules.tsx @@ -75,7 +75,7 @@ export const CloudRules = ({ namespaces, expandAll }: Props) => {
)} - {canMigrateToGMA && } + {canMigrateToGMA && hasSomeResults && }