Alerting: Remove useRulesSourcesWithRuler for SmartAlertTypeDetector (#111623)

* remove useRulesSourcesWithRuler for SmartAlertTypeDetector

* use useHasRulerV2

* avoid using rule context

* update translations

* update eslint
This commit is contained in:
Sonia Aguilar 2025-09-29 23:05:15 +02:00 committed by GitHub
parent d0d55b3c68
commit 37b5b1a03d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 19 additions and 86 deletions

View File

@ -1688,11 +1688,6 @@
"count": 1
}
},
"public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx": {
"no-restricted-syntax": {
"count": 2
}
},
"public/app/features/alerting/unified/components/rule-editor/rule-types/RuleType.tsx": {
"no-restricted-syntax": {
"count": 1

View File

@ -4,7 +4,7 @@ import { useCallback, useEffect, useMemo, useReducer, useState } from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { useEffectOnce } from 'react-use';
import { GrafanaTheme2, getDefaultRelativeTimeRange } from '@grafana/data';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Trans, t } from '@grafana/i18n';
import { config, getDataSourceSrv } from '@grafana/runtime';
@ -31,7 +31,6 @@ import {
} from 'app/features/expressions/types';
import { AlertQuery } from 'app/types/unified-alerting-dto';
import { useRulesSourcesWithRuler } from '../../../hooks/useRuleSourcesWithRuler';
import {
areQueriesTransformableToSimpleCondition,
isExpressionQueryInAlert,
@ -100,7 +99,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod
control,
} = useFormContext<RuleFormValues>();
const { queryPreviewData, runQueries, cancelQueries, isPreviewLoading, clearPreviewData } = useAlertQueryRunner();
const { queryPreviewData, runQueries, cancelQueries, isPreviewLoading } = useAlertQueryRunner();
const isSwitchModeEnabled = config.featureToggles.alertingQueryAndExpressionsStepMode ?? false;
const initialState = {
@ -161,8 +160,6 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod
}
}, [simplifiedQueryStep, expressionQueries, isGrafanaAlertingType, setSimpleCondition]);
const { rulesSourcesWithRuler, isLoading: rulerSourcesIsLoading } = useRulesSourcesWithRuler();
const runQueriesPreview = useCallback(
(condition?: string) => {
if (isCloudAlertRuleType) {
@ -303,40 +300,6 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod
[runQueriesPreview, setValue, updateExpressionAndDatasource]
);
// Using dataSourcesWithRuler[0] gives incorrect types - no undefined
// Using at(0) provides a safe type with undefined
const recordingRuleDefaultDatasource = rulesSourcesWithRuler.at(0);
useEffect(() => {
clearPreviewData();
if (type === RuleFormType.cloudRecording) {
const expr = getValues('expression');
if (!recordingRuleDefaultDatasource) {
return;
}
const datasourceUid =
(editingExistingRule && getDataSourceSrv().getInstanceSettings(dataSourceName)?.uid) ||
recordingRuleDefaultDatasource.uid;
const defaultQuery = {
refId: 'A',
datasourceUid,
queryType: '',
relativeTimeRange: getDefaultRelativeTimeRange(),
expr,
instant: true,
model: {
refId: 'A',
hide: false,
expr,
},
};
dispatch(setRecordingRulesQueries({ recordingRuleQueries: [defaultQuery], expression: expr }));
}
}, [type, recordingRuleDefaultDatasource, editingExistingRule, getValues, dataSourceName, clearPreviewData]);
const onDuplicateQuery = useCallback((query: AlertQuery) => {
dispatch(duplicateQuery(query));
}, []);
@ -475,10 +438,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod
}
: undefined;
const canSelectDataSourceManaged =
onlyOneDSInQueries(queries) &&
Boolean(rulesSourcesWithRuler.length) &&
queries.some((query) => rulesSourcesWithRuler.some((source) => source.uid === query.datasourceUid));
const canSelectDataSourceManaged = onlyOneDSInQueries(queries);
return (
<>
@ -508,7 +468,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod
{/* This is the PromQL Editor for recording rules */}
{isRecordingRuleType && dataSourceName && (
<Field error={errors.expression?.message} invalid={!!errors.expression?.message}>
<Field error={errors.expression?.message} invalid={!!errors.expression?.message} noMargin>
<RecordingRuleEditor
dataSourceName={dataSourceName}
queries={queries}
@ -519,16 +479,10 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod
</Field>
)}
{rulerSourcesIsLoading && (
<Text>
<Trans i18nKey="alerting.query-and-expressions-step.loading-data-sources">Loading data sources...</Trans>
</Text>
)}
{/* This is the PromQL Editor for Cloud rules */}
{!rulerSourcesIsLoading && isCloudAlertRuleType && dataSourceName && (
{isCloudAlertRuleType && dataSourceName && (
<Stack direction="column">
<Field error={errors.expression?.message} invalid={!!errors.expression?.message}>
<Field error={errors.expression?.message} invalid={!!errors.expression?.message} noMargin>
<Controller
name="expression"
render={({ field: { ref, ...field } }) => {
@ -559,7 +513,6 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod
<SmartAlertTypeDetector
editingExistingRule={editingExistingRule}
queries={queries}
rulesSourcesWithRuler={rulesSourcesWithRuler}
onClickSwitch={onClickSwitch}
/>
</>
@ -568,7 +521,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod
)}
{/* This is the editor for Grafana managed rules and Grafana managed recording rules */}
{!rulerSourcesIsLoading && isGrafanaManagedRuleByType(type) && (
{isGrafanaManagedRuleByType(type) && (
<Stack direction="column">
{/* Data Queries */}
<QueryEditor
@ -609,7 +562,6 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod
<Divider />
<SmartAlertTypeDetector
editingExistingRule={editingExistingRule}
rulesSourcesWithRuler={rulesSourcesWithRuler}
queries={queries}
onClickSwitch={onClickSwitch}
/>

View File

@ -1,33 +1,25 @@
import { useFormContext } from 'react-hook-form';
import { DataSourceInstanceSettings } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { DataSourceJsonData } from '@grafana/schema';
import { RadioButtonGroup, Stack, Text } from '@grafana/ui';
import { AlertQuery } from 'app/types/unified-alerting-dto';
import { RuleFormType, RuleFormValues } from '../../../types/rule-form';
import { NeedHelpInfo } from '../NeedHelpInfo';
import { getCanSwitch } from './utils';
import { useGetCanSwitch } from './utils';
interface SmartAlertTypeDetectorProps {
editingExistingRule: boolean;
rulesSourcesWithRuler: Array<DataSourceInstanceSettings<DataSourceJsonData>>;
queries: AlertQuery[];
onClickSwitch: () => void;
}
export function SmartAlertTypeDetector({
editingExistingRule,
rulesSourcesWithRuler,
queries,
onClickSwitch,
}: SmartAlertTypeDetectorProps) {
export function SmartAlertTypeDetector({ editingExistingRule, queries, onClickSwitch }: SmartAlertTypeDetectorProps) {
const { getValues } = useFormContext<RuleFormValues>();
const [ruleFormType] = getValues(['type']);
const canSwitch = getCanSwitch({ queries, ruleFormType, rulesSourcesWithRuler });
const canSwitch = useGetCanSwitch({ queries, ruleFormType });
const options = [
{ label: t('alerting.smart-alert-type-detector.grafana-managed', 'Grafana-managed'), value: RuleFormType.grafana },

View File

@ -1,10 +1,9 @@
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/accessControl';
import { AlertQuery } from 'app/types/unified-alerting-dto';
import { useHasRulerV2 } from '../../../hooks/useHasRuler';
import { RuleFormType } from '../../../types/rule-form';
export const onlyOneDSInQueries = (queries: AlertQuery[]) => {
@ -27,12 +26,10 @@ function getAvailableRuleTypes() {
return { enabledRuleTypes, defaultRuleType };
}
export const getCanSwitch = ({
export const useGetCanSwitch = ({
queries,
ruleFormType,
rulesSourcesWithRuler,
}: {
rulesSourcesWithRuler: Array<DataSourceInstanceSettings<DataSourceJsonData>>;
queries: AlertQuery[];
ruleFormType: RuleFormType | undefined;
}) => {
@ -41,14 +38,12 @@ export const getCanSwitch = ({
// 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;
const dataSourceIdFromQueries = queries[0]?.datasourceUid ?? '';
const { hasRuler } = useHasRulerV2(dataSourceIdFromQueries);
//let's check if we switch to cloud type
const canSwitchToCloudRule =
!isRecordingRuleType &&
onlyOneDS &&
rulesSourcesWithRuler.some((dsJsonData) => dsJsonData.uid === dataSourceIdFromQueries);
const canSwitchToCloudRule = !isRecordingRuleType && onlyOneDS && hasRuler;
const canSwitchToGrafanaRule = !isRecordingRuleType;
// check for enabled types

View File

@ -342,7 +342,7 @@ const PrometheusConsistencyCheck = withErrorBoundary(
({ ruleIdentifier }: PrometheusConsistencyCheckProps) => {
const [ref, { width }] = useMeasure<HTMLDivElement>();
const { hasRuler } = useHasRulerV2(ruleIdentifierToRuleSourceIdentifier(ruleIdentifier));
const { hasRuler } = useHasRulerV2(ruleIdentifierToRuleSourceIdentifier(ruleIdentifier).uid);
const { result: ruleLocation } = useRuleLocation(ruleIdentifier);
const { waitForGroupConsistency, groupConsistent } = useRuleGroupConsistencyCheck();

View File

@ -1,4 +1,4 @@
import { RulesSource, RulesSourceIdentifier } from 'app/types/unified-alerting';
import { GrafanaRulesSourceSymbol, RulesSource } from 'app/types/unified-alerting';
import { featureDiscoveryApi } from '../api/featureDiscoveryApi';
import { getRulesSourceName } from '../utils/datasource';
@ -16,8 +16,8 @@ export function useHasRuler(rulesSource: RulesSource) {
return { hasRuler, rulerConfig: dsFeatures?.rulerConfig };
}
export function useHasRulerV2(rulesSource: RulesSourceIdentifier) {
const { currentData: dsFeatures } = useDiscoverDsFeaturesQuery({ uid: rulesSource.uid });
export function useHasRulerV2(ruleUid: string | typeof GrafanaRulesSourceSymbol) {
const { currentData: dsFeatures } = useDiscoverDsFeaturesQuery({ uid: ruleUid });
const hasRuler = Boolean(dsFeatures?.rulerConfig);
return { hasRuler, rulerConfig: dsFeatures?.rulerConfig };

View File

@ -2162,7 +2162,6 @@
"body-queries-expressions-configured": "Create at least one query or expression to be alerted on",
"confirmText-deactivate": "Deactivate",
"expressions": "Expressions",
"loading-data-sources": "Loading data sources...",
"manipulate-returned-queries-other-operations": "Manipulate data returned from queries with math and other operations.",
"message": {
"a-valid-expression-is-required": "A valid expression is required"