Files
Laura Benz 24502c4c4a Add tooltip to instances of IconButton (#68880)
* 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
2023-06-08 10:23:28 +02:00

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;