mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
ValueMappings: UX Feedback and fixes (#34011)
* ValueMappings: UX Feedback and fixes * minor update to texts * Update
This commit is contained in:
parent
d1a44044e5
commit
1601f12cf1
@ -154,7 +154,7 @@ export function ValueMappingEditRow({ mapping, index, onChange, onRemove }: Prop
|
|||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<Input type="text" value={result.text ?? ''} onChange={onChangeText} placeholder="Display text" />
|
<Input type="text" value={result.text ?? ''} onChange={onChangeText} placeholder="Optional display text" />
|
||||||
</td>
|
</td>
|
||||||
<td className={styles.textAlignCenter}>
|
<td className={styles.textAlignCenter}>
|
||||||
{result.color && (
|
{result.color && (
|
||||||
|
@ -2,6 +2,8 @@ import React from 'react';
|
|||||||
import { fireEvent, render, screen } from '@testing-library/react';
|
import { fireEvent, render, screen } from '@testing-library/react';
|
||||||
import { ValueMappingsEditorModal, Props } from './ValueMappingsEditorModal';
|
import { ValueMappingsEditorModal, Props } from './ValueMappingsEditorModal';
|
||||||
import { MappingType } from '@grafana/data';
|
import { MappingType } from '@grafana/data';
|
||||||
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
|
import selectEvent from 'react-select-event';
|
||||||
|
|
||||||
const setup = (spy?: any, propOverrides?: object) => {
|
const setup = (spy?: any, propOverrides?: object) => {
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
@ -75,12 +77,14 @@ describe('When adding and updating value mapp', () => {
|
|||||||
const onChangeSpy = jest.fn();
|
const onChangeSpy = jest.fn();
|
||||||
setup(onChangeSpy);
|
setup(onChangeSpy);
|
||||||
|
|
||||||
fireEvent.click(screen.getByTestId('add value map'));
|
fireEvent.click(screen.getByLabelText(selectors.components.ValuePicker.button('Add a new mapping')));
|
||||||
|
const selectComponent = await screen.findByLabelText(selectors.components.ValuePicker.select('Add a new mapping'));
|
||||||
|
await selectEvent.select(selectComponent, 'Value');
|
||||||
|
|
||||||
const input = (await screen.findAllByPlaceholderText('Exact value to match'))[1];
|
const input = (await screen.findAllByPlaceholderText('Exact value to match'))[1];
|
||||||
|
|
||||||
fireEvent.change(input, { target: { value: 'New' } });
|
fireEvent.change(input, { target: { value: 'New' } });
|
||||||
fireEvent.change(screen.getAllByPlaceholderText('Display text')[2], { target: { value: 'display' } });
|
fireEvent.change(screen.getAllByPlaceholderText('Optional display text')[2], { target: { value: 'display' } });
|
||||||
fireEvent.click(screen.getByText('Update'));
|
fireEvent.click(screen.getByText('Update'));
|
||||||
|
|
||||||
expect(onChangeSpy).toBeCalledWith([
|
expect(onChangeSpy).toBeCalledWith([
|
||||||
@ -117,11 +121,13 @@ describe('When adding and updating range map', () => {
|
|||||||
const onChangeSpy = jest.fn();
|
const onChangeSpy = jest.fn();
|
||||||
setup(onChangeSpy, { value: [] });
|
setup(onChangeSpy, { value: [] });
|
||||||
|
|
||||||
fireEvent.click(screen.getByTestId('add range map'));
|
fireEvent.click(screen.getByLabelText(selectors.components.ValuePicker.button('Add a new mapping')));
|
||||||
|
const selectComponent = await screen.findByLabelText(selectors.components.ValuePicker.select('Add a new mapping'));
|
||||||
|
await selectEvent.select(selectComponent, 'Range');
|
||||||
|
|
||||||
fireEvent.change(screen.getByPlaceholderText('Range start'), { target: { value: '10' } });
|
fireEvent.change(screen.getByPlaceholderText('Range start'), { target: { value: '10' } });
|
||||||
fireEvent.change(screen.getByPlaceholderText('Range end'), { target: { value: '20' } });
|
fireEvent.change(screen.getByPlaceholderText('Range end'), { target: { value: '20' } });
|
||||||
fireEvent.change(screen.getByPlaceholderText('Display text'), { target: { value: 'display' } });
|
fireEvent.change(screen.getByPlaceholderText('Optional display text'), { target: { value: 'display' } });
|
||||||
|
|
||||||
fireEvent.click(screen.getByText('Update'));
|
fireEvent.click(screen.getByText('Update'));
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { GrafanaTheme2, MappingType, SpecialValueMatch, ValueMapping } from '@grafana/data';
|
import { GrafanaTheme2, MappingType, SelectableValue, SpecialValueMatch, ValueMapping } from '@grafana/data';
|
||||||
import { Button } from '../Button/Button';
|
import { Button } from '../Button/Button';
|
||||||
import { Modal } from '../Modal/Modal';
|
import { Modal } from '../Modal/Modal';
|
||||||
import { useStyles2 } from '../../themes';
|
import { useStyles2 } from '../../themes';
|
||||||
import { ValueMappingEditRow, ValueMappingEditRowModel } from './ValueMappingEditRow';
|
import { ValueMappingEditRow, ValueMappingEditRowModel } from './ValueMappingEditRow';
|
||||||
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
|
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
|
||||||
import { HorizontalGroup } from '../Layout/Layout';
|
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
import { ValuePicker } from '../ValuePicker/ValuePicker';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
value: ValueMapping[];
|
value: ValueMapping[];
|
||||||
@ -46,39 +46,23 @@ export function ValueMappingsEditorModal({ value, onChange, onClose }: Props) {
|
|||||||
updateRows(newList);
|
updateRows(newList);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onAddValueMap = () => {
|
const mappingTypes: Array<SelectableValue<MappingType>> = [
|
||||||
updateRows([
|
{ label: 'Value', value: MappingType.ValueToText, description: 'Match a specific text value' },
|
||||||
...rows,
|
{ label: 'Range', value: MappingType.RangeToText, description: 'Match a numerical range of values' },
|
||||||
{
|
{ label: 'Special', value: MappingType.SpecialValue, description: 'Match on null, NaN, boolean and empty values' },
|
||||||
type: MappingType.ValueToText,
|
];
|
||||||
isNew: true,
|
|
||||||
result: {},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onAddRangeMap = () => {
|
const onAddValueMapping = (value: SelectableValue<MappingType>) => {
|
||||||
updateRows([
|
updateRows([
|
||||||
...rows,
|
...rows,
|
||||||
{
|
{
|
||||||
type: MappingType.RangeToText,
|
type: value.value!,
|
||||||
isNew: true,
|
isNew: true,
|
||||||
result: {},
|
result: {},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onAddSpecialValueMap = () => {
|
|
||||||
updateRows([
|
|
||||||
...rows,
|
|
||||||
{
|
|
||||||
type: MappingType.SpecialValue,
|
|
||||||
specialMatch: SpecialValueMatch.Null,
|
|
||||||
result: {},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onUpdate = () => {
|
const onUpdate = () => {
|
||||||
onChange(editModelToSaveModel(rows));
|
onChange(editModelToSaveModel(rows));
|
||||||
onClose();
|
onClose();
|
||||||
@ -90,10 +74,11 @@ export function ValueMappingsEditorModal({ value, onChange, onClose }: Props) {
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style={{ width: '1%' }}></th>
|
<th style={{ width: '1%' }}></th>
|
||||||
<th style={{ width: '1%' }}>Type</th>
|
<th style={{ width: '40%', textAlign: 'left' }} colSpan={2}>
|
||||||
<th style={{ width: '40%' }}>Match</th>
|
Condition
|
||||||
<th>Display text</th>
|
</th>
|
||||||
<th>Color</th>
|
<th style={{ textAlign: 'left' }}>Display text</th>
|
||||||
|
<th style={{ width: '10%' }}>Color</th>
|
||||||
<th style={{ width: '1%' }}></th>
|
<th style={{ width: '1%' }}></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -116,17 +101,16 @@ export function ValueMappingsEditorModal({ value, onChange, onClose }: Props) {
|
|||||||
</Droppable>
|
</Droppable>
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
</table>
|
</table>
|
||||||
<HorizontalGroup>
|
<ValuePicker
|
||||||
<Button variant="secondary" icon="plus" onClick={onAddValueMap} data-testid="add value map">
|
label="Add a new mapping"
|
||||||
Value map
|
variant="secondary"
|
||||||
</Button>
|
size="md"
|
||||||
<Button variant="secondary" icon="plus" onClick={onAddRangeMap} data-testid="add range map">
|
icon="plus"
|
||||||
Range map
|
menuPlacement="auto"
|
||||||
</Button>
|
isFullWidth={false}
|
||||||
<Button variant="secondary" icon="plus" onClick={onAddSpecialValueMap} data-testid="add special map">
|
options={mappingTypes}
|
||||||
Special value map
|
onChange={onAddValueMapping}
|
||||||
</Button>
|
/>
|
||||||
</HorizontalGroup>
|
|
||||||
<Modal.ButtonRow>
|
<Modal.ButtonRow>
|
||||||
<Button variant="secondary" fill="outline" onClick={onClose}>
|
<Button variant="secondary" fill="outline" onClick={onClose}>
|
||||||
Cancel
|
Cancel
|
||||||
@ -171,6 +155,11 @@ export function editModelToSaveModel(rows: ValueMappingEditRowModel[]) {
|
|||||||
index,
|
index,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Set empty texts to undefined
|
||||||
|
if (!result.text || result.text.trim().length === 0) {
|
||||||
|
result.text = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case MappingType.ValueToText:
|
case MappingType.ValueToText:
|
||||||
if (item.key != null) {
|
if (item.key != null) {
|
||||||
|
@ -54,10 +54,11 @@ export function ValuePicker<T>({
|
|||||||
{!isPicking && (isFullWidth ? <FullWidthButtonContainer>{buttonEl}</FullWidthButtonContainer> : buttonEl)}
|
{!isPicking && (isFullWidth ? <FullWidthButtonContainer>{buttonEl}</FullWidthButtonContainer> : buttonEl)}
|
||||||
|
|
||||||
{isPicking && (
|
{isPicking && (
|
||||||
<span aria-label={selectors.components.ValuePicker.select(label)}>
|
<span>
|
||||||
<Select
|
<Select
|
||||||
placeholder={label}
|
placeholder={label}
|
||||||
options={options}
|
options={options}
|
||||||
|
aria-label={selectors.components.ValuePicker.select(label)}
|
||||||
isOpen
|
isOpen
|
||||||
onCloseMenu={() => setIsPicking(false)}
|
onCloseMenu={() => setIsPicking(false)}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
|
Loading…
Reference in New Issue
Block a user