import { GrafanaTheme2 } from '@grafana/data'; import { useStyles2 } from '@grafana/ui'; import React, { FC, useMemo } from 'react'; import { css, cx } from '@emotion/css'; import { RuleDetails } from './RuleDetails'; import { isCloudRulesSource } from '../../utils/datasource'; import { useHasRuler } from '../../hooks/useHasRuler'; import { CombinedRule } from 'app/types/unified-alerting'; import { Annotation } from '../../utils/constants'; import { RuleState } from './RuleState'; import { RuleHealth } from './RuleHealth'; import { DynamicTable, DynamicTableColumnProps, DynamicTableItemProps } from '../DynamicTable'; type RuleTableColumnProps = DynamicTableColumnProps; type RuleTableItemProps = DynamicTableItemProps; interface Props { rules: CombinedRule[]; showGuidelines?: boolean; showGroupColumn?: boolean; showSummaryColumn?: boolean; emptyMessage?: string; className?: string; } export const RulesTable: FC = ({ rules, className, showGuidelines = false, emptyMessage = 'No rules found.', showGroupColumn = false, showSummaryColumn = false, }) => { const styles = useStyles2(getStyles); const wrapperClass = cx(styles.wrapper, className, { [styles.wrapperMargin]: showGuidelines }); const items = useMemo((): RuleTableItemProps[] => { const seenKeys: string[] = []; return rules.map((rule, ruleIdx) => { let key = JSON.stringify([rule.promRule?.type, rule.labels, rule.query, rule.name, rule.annotations]); if (seenKeys.includes(key)) { key += `-${ruleIdx}`; } seenKeys.push(key); return { id: key, data: rule, }; }); }, [rules]); const columns = useColumns(showSummaryColumn, showGroupColumn, showGuidelines, items.length); if (!rules.length) { return
{emptyMessage}
; } return (
( <> {!(index === rules.length - 1) && showGuidelines ? (
) : null} )} renderPrefixHeader={ showGuidelines ? () => (
) : undefined } renderPrefixCell={ showGuidelines ? (_, index) => (
{!(index === rules.length - 1) && (
)}
) : undefined } />
); }; export const getStyles = (theme: GrafanaTheme2) => ({ wrapperMargin: css` ${theme.breakpoints.up('md')} { margin-left: 36px; } `, emptyMessage: css` padding: ${theme.spacing(1)}; `, wrapper: css` width: auto; background-color: ${theme.colors.background.secondary}; border-radius: ${theme.shape.borderRadius()}; `, table: css` width: 100%; border-radius: ${theme.shape.borderRadius()}; border: solid 1px ${theme.colors.border.weak}; background-color: ${theme.colors.background.secondary}; th { padding: ${theme.spacing(1)}; } td + td { padding: ${theme.spacing(0, 1)}; } tr { height: 38px; } `, evenRow: css` background-color: ${theme.colors.background.primary}; `, relative: css` position: relative; height: 100%; `, guideline: css` left: -19px; border-left: 1px solid ${theme.colors.border.medium}; position: absolute; ${theme.breakpoints.down('md')} { display: none; } `, ruleTopGuideline: css` width: 18px; border-bottom: 1px solid ${theme.colors.border.medium}; top: 0; bottom: 50%; `, ruleBottomGuideline: css` top: 50%; bottom: 0; `, ruleContentGuideline: css` top: 0; bottom: 0; left: -49px !important; `, headerGuideline: css` top: -24px; bottom: 0; `, state: css` width: 110px; `, }); function useColumns(showSummaryColumn: boolean, showGroupColumn: boolean, showGuidelines: boolean, totalRules: number) { const hasRuler = useHasRuler(); const styles = useStyles2(getStyles); return useMemo((): RuleTableColumnProps[] => { const columns: RuleTableColumnProps[] = [ { id: 'state', label: 'State', // eslint-disable-next-line react/display-name renderCell: ({ data: rule }, ruleIdx) => { const { namespace } = rule; const { rulesSource } = namespace; const { promRule, rulerRule } = rule; const isDeleting = !!(hasRuler(rulesSource) && promRule && !rulerRule); const isCreating = !!(hasRuler(rulesSource) && rulerRule && !promRule); return ( <> {showGuidelines && ( <>
{!(ruleIdx === totalRules - 1) && (
)} )} ); }, size: '165px', }, { id: 'name', label: 'Name', // eslint-disable-next-line react/display-name renderCell: ({ data: rule }) => rule.name, size: 5, }, { id: 'health', label: 'Health', // eslint-disable-next-line react/display-name renderCell: ({ data: { promRule } }) => (promRule ? : null), size: '75px', }, ]; if (showSummaryColumn) { columns.push({ id: 'summary', label: 'Summary', // eslint-disable-next-line react/display-name renderCell: ({ data: rule }) => rule.annotations[Annotation.summary] ?? '', size: 5, }); } if (showGroupColumn) { columns.push({ id: 'group', label: 'Group', // eslint-disable-next-line react/display-name renderCell: ({ data: rule }) => { const { namespace, group } = rule; const { rulesSource } = namespace; return isCloudRulesSource(rulesSource) ? `${namespace.name} > ${group.name}` : namespace.name; }, size: 5, }); } return columns; }, [hasRuler, showSummaryColumn, showGroupColumn, showGuidelines, totalRules, styles]); }