mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Silence drawer being forcefully closed (#96579)
Co-authored-by: Tom Ratcliffe <tom.ratcliffe@grafana.com>
This commit is contained in:
parent
ed31457c00
commit
73ae4a51b2
@ -1,16 +1,18 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { useMeasure } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { Counter, LoadingBar, Pagination, Stack } from '@grafana/ui';
|
||||||
import { Counter, Pagination, Stack, useStyles2 } from '@grafana/ui';
|
|
||||||
import { DEFAULT_PER_PAGE_PAGINATION } from 'app/core/constants';
|
import { DEFAULT_PER_PAGE_PAGINATION } from 'app/core/constants';
|
||||||
import { CombinedRule, CombinedRuleNamespace } from 'app/types/unified-alerting';
|
import { CombinedRule, CombinedRuleNamespace } from 'app/types/unified-alerting';
|
||||||
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
import { usePagination } from '../../hooks/usePagination';
|
import { usePagination } from '../../hooks/usePagination';
|
||||||
|
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
|
||||||
import { AlertRuleListItem } from '../../rule-list/components/AlertRuleListItem';
|
import { AlertRuleListItem } from '../../rule-list/components/AlertRuleListItem';
|
||||||
import { ListSection } from '../../rule-list/components/ListSection';
|
import { ListSection } from '../../rule-list/components/ListSection';
|
||||||
|
import { getRulesDataSources, GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource';
|
||||||
import { createViewLink } from '../../utils/misc';
|
import { createViewLink } from '../../utils/misc';
|
||||||
|
import { isAsyncRequestStatePending } from '../../utils/redux';
|
||||||
import { hashRule } from '../../utils/rule-id';
|
import { hashRule } from '../../utils/rule-id';
|
||||||
import { getRulePluginOrigin, isAlertingRule, isProvisionedRule } from '../../utils/rules';
|
import { getRulePluginOrigin, isAlertingRule, isProvisionedRule } from '../../utils/rules';
|
||||||
import { calculateTotalInstances } from '../rule-viewer/RuleViewer';
|
import { calculateTotalInstances } from '../rule-viewer/RuleViewer';
|
||||||
@ -24,7 +26,9 @@ interface Props {
|
|||||||
type GroupedRules = Map<PromAlertingRuleState, CombinedRule[]>;
|
type GroupedRules = Map<PromAlertingRuleState, CombinedRule[]>;
|
||||||
|
|
||||||
export const RuleListStateView = ({ namespaces }: Props) => {
|
export const RuleListStateView = ({ namespaces }: Props) => {
|
||||||
const styles = useStyles2(getStyles);
|
const [ref, { width }] = useMeasure<HTMLUListElement>();
|
||||||
|
|
||||||
|
const isLoading = useDataSourcesLoadingState();
|
||||||
|
|
||||||
const groupedRules = useMemo(() => {
|
const groupedRules = useMemo(() => {
|
||||||
const result: GroupedRules = new Map([
|
const result: GroupedRules = new Map([
|
||||||
@ -54,10 +58,13 @@ export const RuleListStateView = ({ namespaces }: Props) => {
|
|||||||
const entries = groupedRules.entries();
|
const entries = groupedRules.entries();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className={styles.columnStack} role="tree">
|
<ul role="tree" ref={ref}>
|
||||||
{Array.from(entries).map(([state, rules]) => (
|
{isLoading && <LoadingBar width={width} />}
|
||||||
<RulesByState key={state} state={state} rules={rules} />
|
<Stack direction="column">
|
||||||
))}
|
{Array.from(entries).map(([state, rules]) => (
|
||||||
|
<RulesByState key={state} state={state} rules={rules} />
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -71,7 +78,7 @@ const STATE_TITLES: Record<PromAlertingRuleState, string> = {
|
|||||||
const RulesByState = ({ state, rules }: { state: PromAlertingRuleState; rules: CombinedRule[] }) => {
|
const RulesByState = ({ state, rules }: { state: PromAlertingRuleState; rules: CombinedRule[] }) => {
|
||||||
const { page, pageItems, numberOfPages, onPageChange } = usePagination(rules, 1, DEFAULT_PER_PAGE_PAGINATION);
|
const { page, pageItems, numberOfPages, onPageChange } = usePagination(rules, 1, DEFAULT_PER_PAGE_PAGINATION);
|
||||||
|
|
||||||
const isNotFiringState = state !== PromAlertingRuleState.Firing;
|
const isFiringState = state !== PromAlertingRuleState.Firing;
|
||||||
const hasRulesMatchingState = rules.length > 0;
|
const hasRulesMatchingState = rules.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -82,7 +89,7 @@ const RulesByState = ({ state, rules }: { state: PromAlertingRuleState; rules: C
|
|||||||
<Counter value={rules.length} />
|
<Counter value={rules.length} />
|
||||||
</Stack>
|
</Stack>
|
||||||
}
|
}
|
||||||
collapsed={isNotFiringState || hasRulesMatchingState}
|
collapsed={isFiringState || hasRulesMatchingState}
|
||||||
pagination={
|
pagination={
|
||||||
<Pagination
|
<Pagination
|
||||||
currentPage={page}
|
currentPage={page}
|
||||||
@ -127,10 +134,20 @@ const RulesByState = ({ state, rules }: { state: PromAlertingRuleState; rules: C
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStyles = (theme: GrafanaTheme2) => ({
|
function useDataSourcesLoadingState() {
|
||||||
columnStack: css({
|
const promRules = useUnifiedAlertingSelector((state) => state.promRules);
|
||||||
display: 'flex',
|
const rulesDataSources = useMemo(getRulesDataSources, []);
|
||||||
flexDirection: 'column',
|
|
||||||
gap: theme.spacing(1),
|
const grafanaLoading = useUnifiedAlertingSelector((state) => {
|
||||||
}),
|
const promLoading = isAsyncRequestStatePending(state.promRules[GRAFANA_RULES_SOURCE_NAME]);
|
||||||
});
|
const rulerLoading = isAsyncRequestStatePending(state.rulerRules[GRAFANA_RULES_SOURCE_NAME]);
|
||||||
|
|
||||||
|
return promLoading || rulerLoading;
|
||||||
|
});
|
||||||
|
|
||||||
|
const externalDataSourcesLoading = rulesDataSources.some((ds) => isAsyncRequestStatePending(promRules[ds.name]));
|
||||||
|
|
||||||
|
const loading = grafanaLoading || externalDataSourcesLoading;
|
||||||
|
|
||||||
|
return loading;
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { useEffect, useMemo } from 'react';
|
|||||||
import Skeleton from 'react-loading-skeleton';
|
import Skeleton from 'react-loading-skeleton';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { LoadingPlaceholder, Pagination, Tooltip, useStyles2 } from '@grafana/ui';
|
import { Pagination, Tooltip, useStyles2 } from '@grafana/ui';
|
||||||
import { CombinedRule } from 'app/types/unified-alerting';
|
import { CombinedRule } from 'app/types/unified-alerting';
|
||||||
|
|
||||||
import { DEFAULT_PER_PAGE_PAGINATION } from '../../../../../core/constants';
|
import { DEFAULT_PER_PAGE_PAGINATION } from '../../../../../core/constants';
|
||||||
@ -63,18 +63,9 @@ export const RulesTable = ({
|
|||||||
|
|
||||||
const { pageItems, page, numberOfPages, onPageChange } = usePagination(rules, 1, DEFAULT_PER_PAGE_PAGINATION);
|
const { pageItems, page, numberOfPages, onPageChange } = usePagination(rules, 1, DEFAULT_PER_PAGE_PAGINATION);
|
||||||
|
|
||||||
const [lazyLoadRules, { result: rulesWithRulerDefinitions, status: rulerRulesLoadingStatus }] =
|
const { result: rulesWithRulerDefinitions, status: rulerRulesLoadingStatus } = useLazyLoadRulerRules(pageItems);
|
||||||
useLazyLoadRulerRules(pageItems);
|
|
||||||
const isLoadingRulerGroup = useMemo(
|
|
||||||
() => !rulerRulesLoadingStatus || rulerRulesLoadingStatus === 'loading',
|
|
||||||
[rulerRulesLoadingStatus]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const isLoadingRulerGroup = rulerRulesLoadingStatus === 'loading';
|
||||||
if (pageItems.length > 0) {
|
|
||||||
lazyLoadRules.execute();
|
|
||||||
}
|
|
||||||
}, [lazyLoadRules, pageItems, rulerRulesLoadingStatus]);
|
|
||||||
|
|
||||||
const items = useMemo((): RuleTableItemProps[] => {
|
const items = useMemo((): RuleTableItemProps[] => {
|
||||||
return rulesWithRulerDefinitions.map((rule, ruleIdx) => {
|
return rulesWithRulerDefinitions.map((rule, ruleIdx) => {
|
||||||
@ -91,10 +82,6 @@ export const RulesTable = ({
|
|||||||
return <div className={cx(wrapperClass, styles.emptyMessage)}>{emptyMessage}</div>;
|
return <div className={cx(wrapperClass, styles.emptyMessage)}>{emptyMessage}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoadingRulerGroup) {
|
|
||||||
return <LoadingPlaceholder text="Loading..." />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TableComponent = showGuidelines ? DynamicTableWithGuidelines : DynamicTable;
|
const TableComponent = showGuidelines ? DynamicTableWithGuidelines : DynamicTable;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -127,11 +114,8 @@ function useLazyLoadRulerRules(rules: CombinedRule[]) {
|
|||||||
const [fetchRulerRuleGroup] = useLazyGetRuleGroupForNamespaceQuery();
|
const [fetchRulerRuleGroup] = useLazyGetRuleGroupForNamespaceQuery();
|
||||||
const [fetchDsFeatures] = useLazyDiscoverDsFeaturesQuery();
|
const [fetchDsFeatures] = useLazyDiscoverDsFeaturesQuery();
|
||||||
|
|
||||||
return useAsync(async () => {
|
const [actions, state] = useAsync(async () => {
|
||||||
if (!prometheusRulesPrimary) {
|
const result = Promise.all(
|
||||||
return rules;
|
|
||||||
}
|
|
||||||
return Promise.all(
|
|
||||||
rules.map(async (rule) => {
|
rules.map(async (rule) => {
|
||||||
const dsFeatures = await fetchDsFeatures(
|
const dsFeatures = await fetchDsFeatures(
|
||||||
{ rulesSourceName: getRulesSourceName(rule.namespace.rulesSource) },
|
{ rulesSourceName: getRulesSourceName(rule.namespace.rulesSource) },
|
||||||
@ -156,7 +140,20 @@ function useLazyLoadRulerRules(rules: CombinedRule[]) {
|
|||||||
return rule;
|
return rule;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
return result;
|
||||||
}, rules);
|
}, rules);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (prometheusRulesPrimary) {
|
||||||
|
actions.execute();
|
||||||
|
} else {
|
||||||
|
// We need to reset the actions to update the rules if they changed
|
||||||
|
// Otherwise useAsync acts like a cache and always return the first rules passed to it
|
||||||
|
actions.reset();
|
||||||
|
}
|
||||||
|
}, [rules, actions]);
|
||||||
|
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getStyles = (theme: GrafanaTheme2) => ({
|
export const getStyles = (theme: GrafanaTheme2) => ({
|
||||||
|
Loading…
Reference in New Issue
Block a user