import { DataSourceInstanceSettings, GrafanaTheme } from '@grafana/data'; import { Icon, InfoBox, useStyles, Button } from '@grafana/ui'; import { SerializedError } from '@reduxjs/toolkit'; import React, { FC, useEffect, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import { AlertingPageWrapper } from './components/AlertingPageWrapper'; import { NoRulesSplash } from './components/rules/NoRulesCTA'; import { SystemOrApplicationRules } from './components/rules/SystemOrApplicationRules'; import { useUnifiedAlertingSelector } from './hooks/useUnifiedAlertingSelector'; import { useFilteredRules } from './hooks/useFilteredRules'; import { fetchAllPromAndRulerRulesAction } from './state/actions'; import { getAllRulesSourceNames, getRulesDataSources, GRAFANA_RULES_SOURCE_NAME, isCloudRulesSource, } from './utils/datasource'; import { css } from '@emotion/css'; import { ThresholdRules } from './components/rules/ThresholdRules'; import { useCombinedRuleNamespaces } from './hooks/useCombinedRuleNamespaces'; import { RULE_LIST_POLL_INTERVAL_MS } from './utils/constants'; import { isRulerNotSupportedResponse } from './utils/rules'; import RulesFilter from './components/rules/RulesFilter'; export const RuleList: FC = () => { const dispatch = useDispatch(); const styles = useStyles(getStyles); const rulesDataSourceNames = useMemo(getAllRulesSourceNames, []); // fetch rules, then poll every RULE_LIST_POLL_INTERVAL_MS useEffect(() => { dispatch(fetchAllPromAndRulerRulesAction()); const interval = setInterval(() => dispatch(fetchAllPromAndRulerRulesAction()), RULE_LIST_POLL_INTERVAL_MS); return () => { clearInterval(interval); }; }, [dispatch]); const promRuleRequests = useUnifiedAlertingSelector((state) => state.promRules); const rulerRuleRequests = useUnifiedAlertingSelector((state) => state.rulerRules); const dispatched = rulesDataSourceNames.some( (name) => promRuleRequests[name]?.dispatched || rulerRuleRequests[name]?.dispatched ); const loading = rulesDataSourceNames.some( (name) => promRuleRequests[name]?.loading || rulerRuleRequests[name]?.loading ); const haveResults = rulesDataSourceNames.some( (name) => (promRuleRequests[name]?.result?.length && !promRuleRequests[name]?.error) || (Object.keys(rulerRuleRequests[name]?.result || {}).length && !rulerRuleRequests[name]?.error) ); const [promReqeustErrors, rulerRequestErrors] = useMemo( () => [promRuleRequests, rulerRuleRequests].map((requests) => getRulesDataSources().reduce>( (result, dataSource) => { const error = requests[dataSource.name]?.error; if (requests[dataSource.name] && error && !isRulerNotSupportedResponse(requests[dataSource.name])) { return [...result, { dataSource, error }]; } return result; }, [] ) ), [promRuleRequests, rulerRuleRequests] ); const grafanaPromError = promRuleRequests[GRAFANA_RULES_SOURCE_NAME]?.error; const grafanaRulerError = rulerRuleRequests[GRAFANA_RULES_SOURCE_NAME]?.error; const showNewAlertSplash = dispatched && !loading && !haveResults; const combinedNamespaces = useCombinedRuleNamespaces(); const filteredNamespaces = useFilteredRules(combinedNamespaces); const [thresholdNamespaces, systemNamespaces] = useMemo(() => { const sorted = filteredNamespaces .map((namespace) => ({ ...namespace, groups: namespace.groups.sort((a, b) => a.name.localeCompare(b.name)), })) .sort((a, b) => a.name.localeCompare(b.name)); return [ sorted.filter((ns) => ns.rulesSource === GRAFANA_RULES_SOURCE_NAME), sorted.filter((ns) => isCloudRulesSource(ns.rulesSource)), ]; }, [filteredNamespaces]); return ( {(promReqeustErrors.length || rulerRequestErrors.length || grafanaPromError) && ( Errors loading rules } severity="error" > {grafanaPromError && (
Failed to load Grafana threshold rules state: {grafanaPromError.message || 'Unknown error.'}
)} {grafanaRulerError && (
Failed to load Grafana threshold rules config: {grafanaRulerError.message || 'Unknown error.'}
)} {promReqeustErrors.map(({ dataSource, error }) => (
Failed to load rules state from {dataSource.name}:{' '} {error.message || 'Unknown error.'}
))} {rulerRequestErrors.map(({ dataSource, error }) => (
Failed to load rules config from {dataSource.name}:{' '} {error.message || 'Unknown error.'}
))}
)} {!showNewAlertSplash && ( <>
)} {showNewAlertSplash && } {haveResults && } {haveResults && } ); }; const getStyles = (theme: GrafanaTheme) => ({ break: css` width: 100%; height: 0; margin-bottom: ${theme.spacing.md}; border-bottom: solid 1px ${theme.colors.border2}; `, iconError: css` color: ${theme.palette.red}; margin-right: ${theme.spacing.md}; `, buttonsContainer: css` margin-bottom: ${theme.spacing.md}; display: flex; justify-content: space-between; `, });