Alerting: Adds support for toggling common labels (#71497)

pull/60117/head^2
Gilles De Mey 2 years ago committed by GitHub
parent 58689f17cc
commit 0be9658064
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      public/app/features/alerting/unified/components/AlertLabels.test.tsx
  2. 45
      public/app/features/alerting/unified/components/AlertLabels.tsx
  3. 24
      public/app/features/alerting/unified/components/rules/AlertInstancesTable.tsx

@ -0,0 +1,25 @@
import { screen, render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { AlertLabels } from './AlertLabels';
describe('AlertLabels', () => {
it('should toggle show / hide common labels', async () => {
const labels = { foo: 'bar', bar: 'baz', baz: 'qux' };
const commonLabels = { foo: 'bar', baz: 'qux' };
render(<AlertLabels labels={labels} commonLabels={commonLabels} />);
expect(screen.getByText('+2 common labels')).toBeInTheDocument();
userEvent.click(screen.getByRole('button'));
await waitFor(() => {
expect(screen.getByText('Hide common labels')).toBeInTheDocument();
});
userEvent.click(screen.getByRole('button'));
await waitFor(() => {
expect(screen.getByText('+2 common labels')).toBeInTheDocument();
});
});
});

@ -1,26 +1,60 @@
import { css } from '@emotion/css';
import { chain } from 'lodash';
import React from 'react';
import pluralize from 'pluralize';
import React, { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { getTagColorsFromName, useStyles2 } from '@grafana/ui';
import { Button, getTagColorsFromName, useStyles2 } from '@grafana/ui';
import { Label, LabelSize } from './Label';
interface Props {
labels: Record<string, string>;
commonLabels?: Record<string, string>;
size?: LabelSize;
}
export const AlertLabels = ({ labels, size }: Props) => {
export const AlertLabels = ({ labels, commonLabels = {}, size }: Props) => {
const styles = useStyles2((theme) => getStyles(theme, size));
const pairs = chain(labels).toPairs().reject(isPrivateKey).value();
const [showCommonLabels, setShowCommonLabels] = useState(false);
const labelsToShow = chain(labels)
.toPairs()
.reject(isPrivateKey)
.reject(([key]) => (showCommonLabels ? false : key in commonLabels))
.value();
const commonLabelsCount = Object.keys(commonLabels).length;
const hasCommonLabels = commonLabelsCount > 0;
return (
<div className={styles.wrapper} role="list" aria-label="Labels">
{pairs.map(([label, value]) => (
{labelsToShow.map(([label, value]) => (
<Label key={label + value} size={size} label={label} value={value} color={getLabelColor(label)} />
))}
{!showCommonLabels && hasCommonLabels && (
<Button
variant="secondary"
fill="text"
onClick={() => setShowCommonLabels(true)}
tooltip="Show common labels"
tooltipPlacement="top"
size="sm"
>
+{commonLabelsCount} common {pluralize('label', commonLabelsCount)}
</Button>
)}
{showCommonLabels && hasCommonLabels && (
<Button
variant="secondary"
fill="text"
onClick={() => setShowCommonLabels(false)}
tooltipPlacement="top"
size="sm"
>
Hide common labels
</Button>
)}
</div>
);
};
@ -35,6 +69,7 @@ const getStyles = (theme: GrafanaTheme2, size?: LabelSize) => ({
wrapper: css`
display: flex;
flex-wrap: wrap;
align-items: center;
gap: ${size === 'md' ? theme.spacing() : theme.spacing(0.5)};
`,

@ -1,6 +1,6 @@
import React, { useMemo } from 'react';
import { dateTime } from '@grafana/data';
import { dateTime, findCommonLabels } from '@grafana/data';
import { Alert, PaginationProps } from 'app/types/unified-alerting';
import { alertInstanceKey } from '../../utils/rules';
@ -16,17 +16,27 @@ interface Props {
footerRow?: JSX.Element;
}
type AlertTableColumnProps = DynamicTableColumnProps<Alert>;
type AlertTableItemProps = DynamicTableItemProps<Alert>;
interface AlertWithCommonLabels extends Alert {
commonLabels?: Record<string, string>;
}
type AlertTableColumnProps = DynamicTableColumnProps<AlertWithCommonLabels>;
type AlertTableItemProps = DynamicTableItemProps<AlertWithCommonLabels>;
export const AlertInstancesTable = ({ instances, pagination, footerRow }: Props) => {
const commonLabels = useMemo(() => {
// only compute the common labels if we have more than 1 instance, if we don't then that single instance
// will have the complete set of common labels and no unique ones
return instances.length > 1 ? findCommonLabels(instances.map((instance) => instance.labels)) : {};
}, [instances]);
const items = useMemo(
(): AlertTableItemProps[] =>
instances.map((instance) => ({
data: instance,
data: { ...instance, commonLabels },
id: alertInstanceKey(instance),
})),
[instances]
[commonLabels, instances]
);
return (
@ -53,7 +63,9 @@ const columns: AlertTableColumnProps[] = [
id: 'labels',
label: 'Labels',
// eslint-disable-next-line react/display-name
renderCell: ({ data: { labels } }) => <AlertLabels labels={labels} size="sm" />,
renderCell: ({ data: { labels, commonLabels } }) => (
<AlertLabels labels={labels} commonLabels={commonLabels} size="sm" />
),
},
{
id: 'created',

Loading…
Cancel
Save