mirror of
https://github.com/grafana/grafana.git
synced 2025-09-20 05:53:07 +08:00

* refactor: tooltip is required * refactor: add tooltips * refactor: add tooltips * refactor: add tooltips * refactor: add tooltips * refactor: add tooltips * refactor: add tooltips * refactor: adjust tests * refactor: apply changes from code review * refactor: adjust component for e2e test * refactor: adjust fallback * refactor: apply changes from code review * refactor: apply changes from code review * refactor: set IconButton default as type=button and remove from use cases * refactor: remove aria-labels when duplicated and type=button from use cases * refactor: clean up * refactor: fix tests * refactor: fix type errors * refactor: remove changes in order in order to add them to a separate PR * refactor: set IconButton default as type=button * refactor: remove tooltip * refactor: apply changes requested in review
140 lines
4.6 KiB
TypeScript
140 lines
4.6 KiB
TypeScript
import { css, cx } from '@emotion/css';
|
|
import React from 'react';
|
|
import { useFormContext, useFieldArray } from 'react-hook-form';
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data';
|
|
import { Button, Field, Input, IconButton, InputControl, useStyles2, Select } from '@grafana/ui';
|
|
import { MatcherOperator } from 'app/plugins/datasource/alertmanager/types';
|
|
|
|
import { SilenceFormFields } from '../../types/silence-form';
|
|
import { matcherFieldOptions } from '../../utils/alertmanager';
|
|
|
|
interface Props {
|
|
className?: string;
|
|
}
|
|
|
|
const MatchersField = ({ className }: Props) => {
|
|
const styles = useStyles2(getStyles);
|
|
const formApi = useFormContext<SilenceFormFields>();
|
|
const {
|
|
control,
|
|
register,
|
|
formState: { errors },
|
|
} = formApi;
|
|
|
|
const { fields: matchers = [], append, remove } = useFieldArray<SilenceFormFields>({ name: 'matchers' });
|
|
|
|
return (
|
|
<div className={cx(className, styles.wrapper)}>
|
|
<Field label="Matching labels" required>
|
|
<div>
|
|
<div className={styles.matchers}>
|
|
{matchers.map((matcher, index) => {
|
|
return (
|
|
<div className={styles.row} key={`${matcher.id}`} data-testid="matcher">
|
|
<Field
|
|
label="Label"
|
|
invalid={!!errors?.matchers?.[index]?.name}
|
|
error={errors?.matchers?.[index]?.name?.message}
|
|
>
|
|
<Input
|
|
{...register(`matchers.${index}.name` as const, {
|
|
required: { value: true, message: 'Required.' },
|
|
})}
|
|
defaultValue={matcher.name}
|
|
placeholder="label"
|
|
/>
|
|
</Field>
|
|
<Field label={'Operator'}>
|
|
<InputControl
|
|
control={control}
|
|
render={({ field: { onChange, ref, ...field } }) => (
|
|
<Select
|
|
{...field}
|
|
onChange={(value) => onChange(value.value)}
|
|
className={styles.matcherOptions}
|
|
options={matcherFieldOptions}
|
|
aria-label="operator"
|
|
/>
|
|
)}
|
|
defaultValue={matcher.operator || matcherFieldOptions[0].value}
|
|
name={`matchers.${index}.operator` as const}
|
|
rules={{ required: { value: true, message: 'Required.' } }}
|
|
/>
|
|
</Field>
|
|
<Field
|
|
label="Value"
|
|
invalid={!!errors?.matchers?.[index]?.value}
|
|
error={errors?.matchers?.[index]?.value?.message}
|
|
>
|
|
<Input
|
|
{...register(`matchers.${index}.value` as const, {
|
|
required: { value: true, message: 'Required.' },
|
|
})}
|
|
defaultValue={matcher.value}
|
|
placeholder="value"
|
|
/>
|
|
</Field>
|
|
{matchers.length > 1 && (
|
|
<IconButton
|
|
className={styles.removeButton}
|
|
tooltip="Remove matcher"
|
|
name="trash-alt"
|
|
onClick={() => remove(index)}
|
|
>
|
|
Remove
|
|
</IconButton>
|
|
)}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
<Button
|
|
type="button"
|
|
icon="plus"
|
|
variant="secondary"
|
|
onClick={() => {
|
|
const newMatcher = { name: '', value: '', operator: MatcherOperator.equal };
|
|
append(newMatcher);
|
|
}}
|
|
>
|
|
Add matcher
|
|
</Button>
|
|
</div>
|
|
</Field>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const getStyles = (theme: GrafanaTheme2) => {
|
|
return {
|
|
wrapper: css`
|
|
margin-top: ${theme.spacing(2)};
|
|
`,
|
|
row: css`
|
|
display: flex;
|
|
align-items: flex-start;
|
|
flex-direction: row;
|
|
background-color: ${theme.colors.background.secondary};
|
|
padding: ${theme.spacing(1)} ${theme.spacing(1)} 0 ${theme.spacing(1)};
|
|
& > * + * {
|
|
margin-left: ${theme.spacing(2)};
|
|
}
|
|
`,
|
|
removeButton: css`
|
|
margin-left: ${theme.spacing(1)};
|
|
margin-top: ${theme.spacing(2.5)};
|
|
`,
|
|
matcherOptions: css`
|
|
min-width: 140px;
|
|
`,
|
|
matchers: css`
|
|
max-width: ${theme.breakpoints.values.sm}px;
|
|
margin: ${theme.spacing(1)} 0;
|
|
padding-top: ${theme.spacing(0.5)};
|
|
`,
|
|
};
|
|
};
|
|
|
|
export default MatchersField;
|