Submit
Path:
~
/
/
usr
/
share
/
grafana
/
public
/
app
/
features
/
alerting
/
unified
/
hooks
/
File Content:
useCombinedRule.ts
import { useEffect, useMemo } from 'react'; import { useAsync } from 'react-use'; import { useDispatch } from 'app/types'; import { CombinedRule, RuleIdentifier, RuleNamespace, RulerDataSourceConfig } from 'app/types/unified-alerting'; import { RulerRuleGroupDTO, RulerRulesConfigDTO } from 'app/types/unified-alerting-dto'; import { alertRuleApi } from '../api/alertRuleApi'; import { featureDiscoveryApi } from '../api/featureDiscoveryApi'; import { fetchPromAndRulerRulesAction } from '../state/actions'; import { getDataSourceByName, GRAFANA_RULES_SOURCE_NAME, isGrafanaRulesSource } from '../utils/datasource'; import { AsyncRequestMapSlice, AsyncRequestState, initialAsyncRequestState } from '../utils/redux'; import * as ruleId from '../utils/rule-id'; import { isCloudRuleIdentifier, isGrafanaRuleIdentifier, isPrometheusRuleIdentifier, isRulerNotSupportedResponse, } from '../utils/rules'; import { attachRulerRulesToCombinedRules, combineRulesNamespaces, useCombinedRuleNamespaces, } from './useCombinedRuleNamespaces'; import { useUnifiedAlertingSelector } from './useUnifiedAlertingSelector'; export function useCombinedRulesMatching( ruleName: string | undefined, ruleSourceName: string | undefined ): AsyncRequestState<CombinedRule[]> { const requestState = useCombinedRulesLoader(ruleSourceName); const combinedRules = useCombinedRuleNamespaces(ruleSourceName); const rules = useMemo(() => { if (!ruleName || !ruleSourceName || combinedRules.length === 0) { return []; } const rules: CombinedRule[] = []; for (const namespace of combinedRules) { for (const group of namespace.groups) { for (const rule of group.rules) { if (rule.name === ruleName) { rules.push(rule); } } } } return rules; }, [ruleName, ruleSourceName, combinedRules]); return { ...requestState, result: rules, }; } export function useCloudCombinedRulesMatching( ruleName: string, ruleSourceName: string, filter?: { namespace?: string; groupName?: string } ): { loading: boolean; error?: unknown; rules?: CombinedRule[] } { const dsSettings = getDataSourceByName(ruleSourceName); const { dsFeatures, isLoadingDsFeatures } = useDataSourceFeatures(ruleSourceName); const { currentData: promRuleNs = [], isLoading: isLoadingPromRules, error: promRuleNsError, } = alertRuleApi.endpoints.prometheusRuleNamespaces.useQuery({ ruleSourceName: ruleSourceName, ruleName: ruleName, namespace: filter?.namespace, groupName: filter?.groupName, }); const [fetchRulerRuleGroup] = alertRuleApi.endpoints.rulerRuleGroup.useLazyQuery(); const { loading, error, value } = useAsync(async () => { if (!dsSettings) { throw new Error('Unable to obtain data source settings'); } if (promRuleNsError) { throw new Error('Unable to obtain Prometheus rules'); } const rulerGroups: RulerRuleGroupDTO[] = []; if (dsFeatures?.rulerConfig) { const rulerConfig = dsFeatures.rulerConfig; const nsGroups = promRuleNs .map((namespace) => namespace.groups.map((group) => ({ namespace: namespace, group: group }))) .flat(); // RTK query takes care of deduplication await Promise.allSettled( nsGroups.map(async (nsGroup) => { const rulerGroup = await fetchRulerRuleGroup({ rulerConfig: rulerConfig, namespace: nsGroup.namespace.name, group: nsGroup.group.name, }).unwrap(); rulerGroups.push(rulerGroup); }) ); } // TODO Join with ruler rules const namespaces = promRuleNs.map((ns) => attachRulerRulesToCombinedRules(dsSettings, ns, rulerGroups)); const rules = namespaces.flatMap((ns) => ns.groups.flatMap((group) => group.rules)); return rules; }, [dsSettings, dsFeatures, isLoadingPromRules, promRuleNsError, promRuleNs, fetchRulerRuleGroup]); return { loading: isLoadingDsFeatures || loading, error: error, rules: value }; } function useCombinedRulesLoader( rulesSourceName: string | undefined, identifier?: RuleIdentifier ): AsyncRequestState<void> { const dispatch = useDispatch(); const promRuleRequests = useUnifiedAlertingSelector((state) => state.promRules); const promRuleRequest = getRequestState(rulesSourceName, promRuleRequests); const rulerRuleRequests = useUnifiedAlertingSelector((state) => state.rulerRules); const rulerRuleRequest = getRequestState(rulesSourceName, rulerRuleRequests); const { loading } = useAsync(async () => { if (!rulesSourceName) { return; } await dispatch(fetchPromAndRulerRulesAction({ rulesSourceName, identifier })); }, [dispatch, rulesSourceName]); return { loading, error: promRuleRequest.error ?? isRulerNotSupportedResponse(rulerRuleRequest) ? undefined : rulerRuleRequest.error, dispatched: promRuleRequest.dispatched && rulerRuleRequest.dispatched, }; } function getRequestState( ruleSourceName: string | undefined, slice: AsyncRequestMapSlice<RulerRulesConfigDTO | RuleNamespace[] | null> ): AsyncRequestState<RulerRulesConfigDTO | RuleNamespace[] | null> { if (!ruleSourceName) { return initialAsyncRequestState; } const state = slice[ruleSourceName]; if (!state) { return initialAsyncRequestState; } return state; } export function useCombinedRule({ ruleIdentifier }: { ruleIdentifier: RuleIdentifier }): { loading: boolean; result?: CombinedRule; error?: unknown; } { const { ruleSourceName } = ruleIdentifier; const dsSettings = getDataSourceByName(ruleSourceName); const { dsFeatures, isLoadingDsFeatures } = useDataSourceFeatures(ruleSourceName); const { currentData: promRuleNs, isLoading: isLoadingPromRules, error: promRuleNsError, } = alertRuleApi.endpoints.prometheusRuleNamespaces.useQuery( { // TODO Refactor parameters ruleSourceName: ruleIdentifier.ruleSourceName, namespace: isPrometheusRuleIdentifier(ruleIdentifier) || isCloudRuleIdentifier(ruleIdentifier) ? ruleIdentifier.namespace : undefined, groupName: isPrometheusRuleIdentifier(ruleIdentifier) || isCloudRuleIdentifier(ruleIdentifier) ? ruleIdentifier.groupName : undefined, ruleName: isPrometheusRuleIdentifier(ruleIdentifier) || isCloudRuleIdentifier(ruleIdentifier) ? ruleIdentifier.ruleName : undefined, } // TODO – experiment with enabling these now that we request a single alert rule more efficiently. // Requires a recent version of Prometheus with support for query params on /api/v1/rules // { // refetchOnFocus: true, // refetchOnReconnect: true, // } ); const [ fetchRulerRuleGroup, { currentData: rulerRuleGroup, isLoading: isLoadingRulerGroup, error: rulerRuleGroupError }, ] = alertRuleApi.endpoints.rulerRuleGroup.useLazyQuery(); const [fetchRulerRules, { currentData: rulerRules, isLoading: isLoadingRulerRules, error: rulerRulesError }] = alertRuleApi.endpoints.rulerRules.useLazyQuery(); useEffect(() => { if (!dsFeatures?.rulerConfig) { return; } if (dsFeatures.rulerConfig && isCloudRuleIdentifier(ruleIdentifier)) { fetchRulerRuleGroup({ rulerConfig: dsFeatures.rulerConfig, namespace: ruleIdentifier.namespace, group: ruleIdentifier.groupName, }); } else if (isGrafanaRuleIdentifier(ruleIdentifier)) { // TODO Fetch a single group for Grafana managed rules, we're currently still fetching all rules for Grafana managed fetchRulerRules({ rulerConfig: dsFeatures.rulerConfig }); } }, [dsFeatures, fetchRulerRuleGroup, fetchRulerRules, ruleIdentifier]); const rule = useMemo(() => { if (!promRuleNs) { return; } if (isGrafanaRuleIdentifier(ruleIdentifier)) { const combinedNamespaces = combineRulesNamespaces('grafana', promRuleNs, rulerRules); for (const namespace of combinedNamespaces) { for (const group of namespace.groups) { for (const rule of group.rules) { const id = ruleId.fromCombinedRule(ruleSourceName, rule); if (ruleId.equal(id, ruleIdentifier)) { return rule; } } } } } if (!dsSettings) { return; } if ( promRuleNs.length > 0 && (isCloudRuleIdentifier(ruleIdentifier) || isPrometheusRuleIdentifier(ruleIdentifier)) ) { const namespaces = promRuleNs.map((ns) => attachRulerRulesToCombinedRules(dsSettings, ns, rulerRuleGroup ? [rulerRuleGroup] : []) ); for (const namespace of namespaces) { for (const group of namespace.groups) { for (const rule of group.rules) { const id = ruleId.fromCombinedRule(ruleSourceName, rule); if (ruleId.equal(id, ruleIdentifier)) { return rule; } } } } } return; }, [ruleIdentifier, ruleSourceName, promRuleNs, rulerRuleGroup, rulerRules, dsSettings]); return { loading: isLoadingDsFeatures || isLoadingPromRules || isLoadingRulerGroup || isLoadingRulerRules, error: promRuleNsError ?? rulerRuleGroupError ?? rulerRulesError, result: rule, }; } const grafanaRulerConfig: RulerDataSourceConfig = { dataSourceName: GRAFANA_RULES_SOURCE_NAME, apiVersion: 'legacy', }; const grafanaDsFeatures = { rulerConfig: grafanaRulerConfig, }; export function useDataSourceFeatures(dataSourceName: string) { const isGrafanaDs = isGrafanaRulesSource(dataSourceName); const { currentData: dsFeatures, isLoading: isLoadingDsFeatures } = featureDiscoveryApi.endpoints.discoverDsFeatures.useQuery( { rulesSourceName: dataSourceName, }, { skip: isGrafanaDs } ); if (isGrafanaDs) { return { isLoadingDsFeatures: false, dsFeatures: grafanaDsFeatures }; } return { isLoadingDsFeatures, dsFeatures }; }
Submit
FILE
FOLDER
INFO
Name
Size
Permission
Action
__snapshots__
---
0755
alert-details
---
0755
useAbilities.test.tsx
6404 bytes
0644
useAbilities.ts
13933 bytes
0644
useAlertManagerSources.ts
293 bytes
0644
useAlertQueriesStatus.ts
681 bytes
0644
useAlertmanagerConfig.ts
732 bytes
0644
useCombinedRule.ts
10042 bytes
0644
useCombinedRuleNamespaces.test.ts
1785 bytes
0644
useCombinedRuleNamespaces.ts
15283 bytes
0644
useControlledFieldArray.ts
1841 bytes
0644
useExternalAMSelector.test.tsx
6805 bytes
0644
useExternalAmSelector.ts
4616 bytes
0644
useFilteredAmGroups.ts
1291 bytes
0644
useFilteredRules.test.ts
8782 bytes
0644
useFilteredRules.ts
12938 bytes
0644
useFolder.ts
847 bytes
0644
useGroupedAlerts.ts
3338 bytes
0644
useHasRuler.ts
1062 bytes
0644
useIsRuleEditable.test.tsx
5996 bytes
0644
useIsRuleEditable.ts
2778 bytes
0644
useManagedAlertStateHistory.ts
692 bytes
0644
useMuteTimingOptions.ts
897 bytes
0644
usePagination.test.tsx
2055 bytes
0644
usePagination.ts
1058 bytes
0644
usePanelCombinedRules.ts
2733 bytes
0644
usePluginBridge.ts
847 bytes
0644
useReturnTo.test.tsx
1946 bytes
0644
useReturnTo.ts
1546 bytes
0644
useRuleSourcesWithRuler.ts
812 bytes
0644
useSilenceNavData.test.tsx
1249 bytes
0644
useSilenceNavData.ts
797 bytes
0644
useStateHistoryModal.tsx
2855 bytes
0644
useURLSearchParams.ts
628 bytes
0644
useUnifiedAlertingSelector.ts
531 bytes
0644
useVizHeight.ts
877 bytes
0644
N4ST4R_ID | Naxtarrr