Files
Josh Hunt 3c6e0e8ef8 Chore: ESlint import order (#44959)
* Add and configure eslint-plugin-import

* Fix the lint:ts npm command

* Autofix + prettier all the files

* Manually fix remaining files

* Move jquery code in jest-setup to external file to safely reorder imports

* Resolve issue caused by circular dependencies within Prometheus

* Update .betterer.results

* Fix missing // @ts-ignore

* ignore iconBundle.ts

* Fix missing // @ts-ignore
2022-04-22 14:33:13 +01:00

129 lines
4.1 KiB
TypeScript

import { css } from '@emotion/css';
import React, { useEffect, useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import { useDebounce } from 'react-use';
import { dateTime, GrafanaTheme2 } from '@grafana/data';
import { Badge, useStyles2 } from '@grafana/ui';
import { Alert, AlertingRule } from 'app/types/unified-alerting';
import { useCombinedRuleNamespaces } from '../../hooks/useCombinedRuleNamespaces';
import { fetchAllPromAndRulerRulesAction } from '../../state/actions';
import { MatcherFieldValue, SilenceFormFields } from '../../types/silence-form';
import { findAlertInstancesWithMatchers } from '../../utils/matchers';
import { isAlertingRule } from '../../utils/rules';
import { AlertLabels } from '../AlertLabels';
import { DynamicTable, DynamicTableColumnProps, DynamicTableItemProps } from '../DynamicTable';
import { AlertStateTag } from '../rules/AlertStateTag';
type MatchedRulesTableItemProps = DynamicTableItemProps<{
matchedInstance: Alert;
}>;
type MatchedRulesTableColumnProps = DynamicTableColumnProps<{ matchedInstance: Alert }>;
export const MatchedSilencedRules = () => {
const [matchedAlertRules, setMatchedAlertRules] = useState<MatchedRulesTableItemProps[]>([]);
const formApi = useFormContext<SilenceFormFields>();
const dispatch = useDispatch();
const { watch } = formApi;
const matchers: MatcherFieldValue[] = watch('matchers');
const styles = useStyles2(getStyles);
const columns = useColumns();
useEffect(() => {
dispatch(fetchAllPromAndRulerRulesAction());
}, [dispatch]);
const combinedNamespaces = useCombinedRuleNamespaces();
useDebounce(
() => {
const matchedInstances = combinedNamespaces.flatMap((namespace) => {
return namespace.groups.flatMap((group) => {
return group.rules
.map((combinedRule) => combinedRule.promRule)
.filter((rule): rule is AlertingRule => isAlertingRule(rule))
.flatMap((rule) => findAlertInstancesWithMatchers(rule.alerts ?? [], matchers));
});
});
setMatchedAlertRules(matchedInstances);
},
500,
[combinedNamespaces, matchers]
);
return (
<div>
<h4 className={styles.title}>
Affected alert instances
{matchedAlertRules.length > 0 ? (
<Badge className={styles.badge} color="blue" text={matchedAlertRules.length} />
) : null}
</h4>
<div className={styles.table}>
{matchers.every((matcher) => !matcher.value && !matcher.name) ? (
<span>Add a valid matcher to see affected alerts</span>
) : (
<>
<DynamicTable items={matchedAlertRules.slice(0, 5) ?? []} isExpandable={false} cols={columns} />
{matchedAlertRules.length > 5 && (
<div className={styles.moreMatches}>and {matchedAlertRules.length - 5} more</div>
)}
</>
)}
</div>
</div>
);
};
function useColumns(): MatchedRulesTableColumnProps[] {
return [
{
id: 'state',
label: 'State',
renderCell: function renderStateTag({ data: { matchedInstance } }) {
return <AlertStateTag state={matchedInstance.state} />;
},
size: '160px',
},
{
id: 'labels',
label: 'Labels',
renderCell: function renderName({ data: { matchedInstance } }) {
return <AlertLabels labels={matchedInstance.labels} />;
},
size: '250px',
},
{
id: 'created',
label: 'Created',
renderCell: function renderSummary({ data: { matchedInstance } }) {
return (
<>
{matchedInstance.activeAt.startsWith('0001')
? '-'
: dateTime(matchedInstance.activeAt).format('YYYY-MM-DD HH:mm:ss')}
</>
);
},
size: '400px',
},
];
}
const getStyles = (theme: GrafanaTheme2) => ({
table: css`
max-width: ${theme.breakpoints.values.lg}px;
`,
moreMatches: css`
margin-top: ${theme.spacing(1)};
`,
title: css`
display: flex;
align-items: center;
`,
badge: css`
margin-left: ${theme.spacing(1)};
`,
});