From 3c87f43e00a03347601a66a90f8a9960593924e0 Mon Sep 17 00:00:00 2001 From: Konrad Lalik Date: Tue, 22 Feb 2022 15:09:35 +0100 Subject: [PATCH] Add sorting, improve styles --- .../alerting/unified/AlertsFolderView.tsx | 143 +++++++++++------- 1 file changed, 86 insertions(+), 57 deletions(-) diff --git a/public/app/features/alerting/unified/AlertsFolderView.tsx b/public/app/features/alerting/unified/AlertsFolderView.tsx index 51a5a78937f..248e91b04dd 100644 --- a/public/app/features/alerting/unified/AlertsFolderView.tsx +++ b/public/app/features/alerting/unified/AlertsFolderView.tsx @@ -2,8 +2,10 @@ import { css } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; import { Stack } from '@grafana/experimental'; import { Card, FilterInput, Icon, Pagination, TagList, useStyles2 } from '@grafana/ui'; +import { SortPicker } from 'app/core/components/Select/SortPicker'; import { FolderState } from 'app/types'; -import { isEqual, uniqWith } from 'lodash'; +import { CombinedRule } from 'app/types/unified-alerting'; +import { isEqual, orderBy, uniqWith } from 'lodash'; import React, { useEffect, useState } from 'react'; import { useDispatch } from 'react-redux'; import { useDebounce } from 'react-use'; @@ -15,15 +17,25 @@ import { labelsMatchMatchers, matchersToString, parseMatcher, parseMatchers } fr import { GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; import { createViewLink } from './utils/misc'; +const ITEMS_PER_PAGE = 6; interface Props { folder: FolderState; } -const ITEMS_PER_PAGE = 20; +type SortOrder = 'alpha-asc' | 'alpha-desc'; export const AlertsFolderView = ({ folder }: Props) => { const styles = useStyles2(getStyles); const dispatch = useDispatch(); + const [sortOrder, setSortOrder] = useState('alpha-asc'); + + const onTagClick = (tagName: string) => { + const matchers = parseMatchers(labelFilter); + const tagMatcherField = parseMatcher(tagName); + const uniqueMatchers = uniqWith([...matchers, tagMatcherField], isEqual); + const matchersString = matchersToString(uniqueMatchers); + setLabelFilter(matchersString); + }; useEffect(() => { dispatch(fetchPromRulesAction({ rulesSourceName: GRAFANA_RULES_SOURCE_NAME })); @@ -36,72 +48,71 @@ export const AlertsFolderView = ({ folder }: Props) => { const matchingNamespace = combinedNamespaces.find((namespace) => namespace.name === folder.title); const alertRules = matchingNamespace?.groups[0]?.rules ?? []; - const matchers = parseMatchers(labelFilter); - const filteredRules = alertRules.filter( - (rule) => rule.name.toLowerCase().includes(nameFilter.toLowerCase()) && labelsMatchMatchers(rule.labels, matchers) - ); + const filteredRules = filterAndSortRules(alertRules, nameFilter, labelFilter, sortOrder); const showNoResultsText = alertRules.length === 0 || filteredRules.length === 0; const { page, numberOfPages, onPageChange, pageItems } = usePagination(filteredRules, 1, ITEMS_PER_PAGE); - const onTagClick = (tagName: string) => { - const tagMatcherField = parseMatcher(tagName); - const uniqueMatchers = uniqWith([...matchers, tagMatcherField], isEqual); - const matchersString = matchersToString(uniqueMatchers); - setLabelFilter(matchersString); - }; - return ( - - +
+ - + + setSortOrder(value)} + filter={['alpha-asc', 'alpha-desc']} + /> + + + + + {pageItems.map((currentRule) => ( + + {currentRule.name} + + `${labelKey}=${currentRule.labels[labelKey]}` + )} + /> + + +
+ {folder.title} +
+
+
+ ))} +
+ {showNoResultsText &&
No alert rules found
} +
+ +
-
- {pageItems.map((currentRule) => ( - - {currentRule.name} - - `${labelKey}=${currentRule.labels[labelKey]}`)} - /> - - -
- {folder.title} -
-
-
- ))} -
- {showNoResultsText &&
No alert rules found
} -
- -
- +
); }; @@ -139,18 +150,36 @@ function useAlertsFolderViewFilters() { return { nameFilter, labelFilter, setNameFilter, setLabelFilter }; } +function filterAndSortRules( + originalRules: CombinedRule[], + nameFilter: string, + labelFilter: string, + sortOrder: SortOrder +) { + const matchers = parseMatchers(labelFilter); + let rules = originalRules.filter( + (rule) => rule.name.toLowerCase().includes(nameFilter.toLowerCase()) && labelsMatchMatchers(rule.labels, matchers) + ); + + return orderBy(rules, (x) => x.name, [sortOrder === 'alpha-asc' ? 'asc' : 'desc']); +} + function getNonEmptyStringOrUndefined(value: string | undefined | null) { return value || undefined; } export const getStyles = (theme: GrafanaTheme2) => ({ + container: css` + padding: ${theme.spacing(1)}; + `, card: css` grid-template-columns: auto 1fr 2fr; + margin: 0; `, pagination: css` align-self: center; `, - filterInput: css` + filterLabelsInput: css` flex: 1; width: auto; min-width: 240px;