99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
import { css } from '@emotion/css';
|
|
import { take, takeRight, uniqueId } from 'lodash';
|
|
import { FC } from 'react';
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data';
|
|
import { Stack, getTagColorsFromName, useStyles2 } from '@grafana/ui';
|
|
import { ObjectMatcher } from 'app/plugins/datasource/alertmanager/types';
|
|
|
|
import { MatcherFormatter, matcherFormatter } from '../../utils/matchers';
|
|
import { PopupCard } from '../HoverCard';
|
|
|
|
type MatchersProps = { matchers: ObjectMatcher[]; formatter?: MatcherFormatter };
|
|
|
|
// renders the first N number of matchers
|
|
const Matchers: FC<MatchersProps> = ({ matchers, formatter = 'default' }) => {
|
|
const styles = useStyles2(getStyles);
|
|
|
|
const NUM_MATCHERS = 5;
|
|
|
|
const firstFew = take(matchers, NUM_MATCHERS);
|
|
const rest = takeRight(matchers, matchers.length - NUM_MATCHERS);
|
|
const hasMoreMatchers = rest.length > 0;
|
|
|
|
return (
|
|
<span data-testid="label-matchers">
|
|
<Stack direction="row" gap={1} alignItems="center" wrap={'wrap'}>
|
|
{firstFew.map((matcher) => (
|
|
<MatcherBadge key={uniqueId()} matcher={matcher} formatter={formatter} />
|
|
))}
|
|
{/* TODO hover state to show all matchers we're not showing */}
|
|
{hasMoreMatchers && (
|
|
<PopupCard
|
|
arrow
|
|
placement="top"
|
|
content={
|
|
<>
|
|
{rest.map((matcher) => (
|
|
<MatcherBadge key={uniqueId()} matcher={matcher} />
|
|
))}
|
|
</>
|
|
}
|
|
>
|
|
<span>
|
|
<div className={styles.metadata}>{`and ${rest.length} more`}</div>
|
|
</span>
|
|
</PopupCard>
|
|
)}
|
|
</Stack>
|
|
</span>
|
|
);
|
|
};
|
|
|
|
interface MatcherBadgeProps {
|
|
matcher: ObjectMatcher;
|
|
formatter?: MatcherFormatter;
|
|
}
|
|
|
|
const MatcherBadge: FC<MatcherBadgeProps> = ({ matcher, formatter = 'default' }) => {
|
|
const styles = useStyles2(getStyles);
|
|
|
|
return (
|
|
<div className={styles.matcher(matcher[0]).wrapper}>
|
|
<Stack direction="row" gap={0} alignItems="baseline">
|
|
{matcherFormatter[formatter](matcher)}
|
|
</Stack>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const getStyles = (theme: GrafanaTheme2) => ({
|
|
matcher: (label: string) => {
|
|
const { color, borderColor } = getTagColorsFromName(label);
|
|
|
|
return {
|
|
wrapper: css({
|
|
color: '#fff',
|
|
background: color,
|
|
padding: `${theme.spacing(0.33)} ${theme.spacing(0.66)}`,
|
|
fontSize: theme.typography.bodySmall.fontSize,
|
|
|
|
border: `solid 1px ${borderColor}`,
|
|
borderRadius: theme.shape.borderRadius(2),
|
|
|
|
// Ensure we preserve whitespace, as otherwise it's not noticeable _at all_
|
|
// when rendering the matcher, and is only noticeable when editing
|
|
whiteSpace: 'pre',
|
|
}),
|
|
};
|
|
},
|
|
metadata: css({
|
|
color: theme.colors.text.secondary,
|
|
|
|
fontSize: theme.typography.bodySmall.fontSize,
|
|
fontWeight: theme.typography.bodySmall.fontWeight,
|
|
}),
|
|
});
|
|
|
|
export { Matchers };
|