Add label filtering by clicking a tag

This commit is contained in:
Konrad Lalik
2022-02-22 13:37:47 +01:00
parent 13a819d4ea
commit 3cc598f65b
3 changed files with 45 additions and 23 deletions
@@ -3,13 +3,15 @@ import { GrafanaTheme2 } from '@grafana/data';
import { Stack } from '@grafana/experimental';
import { Card, FilterInput, Icon, Pagination, TagList, useStyles2 } from '@grafana/ui';
import { FolderState } from 'app/types';
import { isEqual, uniqWith } from 'lodash';
import React, { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useDebounce } from 'react-use';
import { useCombinedRuleNamespaces } from './hooks/useCombinedRuleNamespaces';
import { usePagination } from './hooks/usePagination';
import { useURLSearchParams } from './hooks/useURLSearchParams';
import { fetchAllPromAndRulerRulesAction, fetchPromRulesAction, fetchRulerRulesAction } from './state/actions';
import { labelsMatchMatchers, parseMatchers } from './utils/alertmanager';
import { fetchPromRulesAction, fetchRulerRulesAction } from './state/actions';
import { labelsMatchMatchers, matchersToString, parseMatcher, parseMatchers } from './utils/alertmanager';
import { GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
import { createViewLink } from './utils/misc';
@@ -42,6 +44,13 @@ export const AlertsFolderView = ({ folder }: Props) => {
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 (
<Stack direction="column" gap={1}>
<Stack direction="row">
@@ -71,6 +80,7 @@ export const AlertsFolderView = ({ folder }: Props) => {
<Card.Heading>{currentRule.name}</Card.Heading>
<Card.Tags>
<TagList
onClick={onTagClick}
tags={Object.keys(currentRule.labels).map((labelKey) => `${labelKey}=${currentRule.labels[labelKey]}`)}
/>
</Card.Tags>
@@ -110,8 +120,8 @@ function useAlertsFolderViewFilters() {
() =>
setSearchParams(
{
[AlertFolderViewFilters.nameFilter]: getNotEmptyStringOrUndefined(nameFilter),
[AlertFolderViewFilters.labelFilter]: getNotEmptyStringOrUndefined(labelFilter),
[AlertFolderViewFilters.nameFilter]: getNonEmptyStringOrUndefined(nameFilter),
[AlertFolderViewFilters.labelFilter]: getNonEmptyStringOrUndefined(labelFilter),
},
true
),
@@ -129,28 +139,10 @@ function useAlertsFolderViewFilters() {
return { nameFilter, labelFilter, setNameFilter, setLabelFilter };
}
function getNotEmptyStringOrUndefined(value: string | undefined | null) {
function getNonEmptyStringOrUndefined(value: string | undefined | null) {
return value || undefined;
}
function usePagination<T>(items: T[], initialPage: number, itemsPerPage: number) {
const [page, setPage] = useState(initialPage);
const numberOfPages = Math.ceil(items.length / itemsPerPage);
const firstItemOnPageIndex = itemsPerPage * (page - 1);
const pageItems = items.slice(firstItemOnPageIndex, firstItemOnPageIndex + itemsPerPage);
const onPageChange = (newPage: number) => {
setPage(newPage);
};
// Reset the current page when number of changes has been changed
useEffect(() => setPage(1), [numberOfPages]);
return { page, onPageChange, numberOfPages, pageItems };
}
export const getStyles = (theme: GrafanaTheme2) => ({
card: css`
grid-template-columns: auto 1fr 2fr;
@@ -0,0 +1,19 @@
import { useEffect, useState } from 'react';
export function usePagination<T>(items: T[], initialPage: number, itemsPerPage: number) {
const [page, setPage] = useState(initialPage);
const numberOfPages = Math.ceil(items.length / itemsPerPage);
const firstItemOnPageIndex = itemsPerPage * (page - 1);
const pageItems = items.slice(firstItemOnPageIndex, firstItemOnPageIndex + itemsPerPage);
const onPageChange = (newPage: number) => {
setPage(newPage);
};
// Reset the current page when number of changes has been changed
useEffect(() => setPage(1), [numberOfPages]);
return { page, onPageChange, numberOfPages, pageItems };
}
@@ -104,6 +104,17 @@ export function matcherFieldToMatcher(field: MatcherFieldValue): Matcher {
};
}
export function matchersToString(matchers: Matcher[]) {
const matcherFields = matchers.map(matcherToMatcherField);
const combinedMatchers = matcherFields.reduce((acc, current) => {
const currentMatcherString = `${current.name}${current.operator}"${current.value}"`;
return acc ? `${acc},${currentMatcherString}"` : currentMatcherString;
}, '');
return `{${combinedMatchers}}`;
}
export const matcherFieldOptions: SelectableValue[] = [
{ label: MatcherOperator.equal, description: 'Equals', value: MatcherOperator.equal },
{ label: MatcherOperator.notEqual, description: 'Does not equal', value: MatcherOperator.notEqual },