ValueMappings: Make value mapping row focusable (#52337)

* Dimensions: Move drag handle to draggable container

* Accessibility: Added unique ids to preserve focus when dragging items using keyboard
This commit is contained in:
Leo 2022-07-18 16:19:32 +02:00 committed by GitHub
parent 9afe845d5c
commit 7b7b9ff4a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 35 deletions

View File

@ -17,6 +17,7 @@ export interface ValueMappingEditRowModel {
isNew?: boolean;
specialMatch?: SpecialValueMatch;
result: ValueMappingResult;
id: string;
}
interface Props {
@ -29,7 +30,7 @@ interface Props {
}
export function ValueMappingEditRow({ mapping, index, onChange, onRemove, onDuplicate, showIconPicker }: Props) {
const { key, result } = mapping;
const { key, result, id } = mapping;
const styles = useStyles2(getStyles);
const inputRef = useRef<HTMLInputElement | null>(null);
@ -126,11 +127,11 @@ export function ValueMappingEditRow({ mapping, index, onChange, onRemove, onDupl
];
return (
<Draggable draggableId={`mapping-${index}`} index={index}>
<Draggable key={id} draggableId={id} index={index}>
{(provided) => (
<tr ref={provided.innerRef} {...provided.draggableProps}>
<tr ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
<td>
<div {...provided.dragHandleProps} className={styles.dragHandle}>
<div className={styles.dragHandle}>
<Icon name="draggabledots" size="lg" />
</div>
</td>

View File

@ -1,4 +1,5 @@
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
import React, { useEffect, useState } from 'react';
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
@ -54,18 +55,11 @@ export function ValueMappingsEditorModal({ value, onChange, onClose, showIconPic
];
const onAddValueMapping = (value: SelectableValue<MappingType>) => {
updateRows([
...rows,
{
type: value.value!,
isNew: true,
result: {},
},
]);
updateRows([...rows, createRow({ type: value.value!, result: {}, isNew: true })]);
};
const onDuplicateMapping = (index: number) => {
const sourceRow = rows[index];
const sourceRow = duplicateRow(rows[index]);
const copy = [...rows];
copy.splice(index, 0, { ...sourceRow });
@ -111,7 +105,7 @@ export function ValueMappingsEditorModal({ value, onChange, onClose, showIconPic
<tbody ref={provided.innerRef} {...provided.droppableProps}>
{rows.map((row, index) => (
<ValueMappingEditRow
key={index.toString()}
key={row.id}
mapping={row}
index={index}
onChange={onChangeMapping}
@ -178,6 +172,27 @@ export const getStyles = (theme: GrafanaTheme2) => ({
}),
});
function getRowUniqueId(): string {
return uniqueId('mapping-');
}
function createRow(row: Partial<ValueMappingEditRowModel>): ValueMappingEditRowModel {
return {
type: MappingType.ValueToText,
result: {},
id: getRowUniqueId(),
...row,
};
}
function duplicateRow(row: Partial<ValueMappingEditRowModel>): ValueMappingEditRowModel {
return {
...createRow(row),
// provide a new unique id to the duplicated row, to preserve focus when dragging 2 duplicated rows
id: getRowUniqueId(),
};
}
export function editModelToSaveModel(rows: ValueMappingEditRowModel[]) {
const mappings: ValueMapping[] = [];
const valueMaps: ValueMapping = {
@ -250,34 +265,42 @@ export function buildEditRowModels(value: ValueMapping[]) {
switch (mapping.type) {
case MappingType.ValueToText:
for (const key of Object.keys(mapping.options)) {
editRows.push({
type: mapping.type,
result: mapping.options[key],
key,
});
editRows.push(
createRow({
type: mapping.type,
result: mapping.options[key],
key,
})
);
}
break;
case MappingType.RangeToText:
editRows.push({
type: mapping.type,
result: mapping.options.result,
from: mapping.options.from ?? 0,
to: mapping.options.to ?? 0,
});
editRows.push(
createRow({
type: mapping.type,
result: mapping.options.result,
from: mapping.options.from ?? 0,
to: mapping.options.to ?? 0,
})
);
break;
case MappingType.RegexToText:
editRows.push({
type: mapping.type,
result: mapping.options.result,
pattern: mapping.options.pattern,
});
editRows.push(
createRow({
type: mapping.type,
result: mapping.options.result,
pattern: mapping.options.pattern,
})
);
break;
case MappingType.SpecialValue:
editRows.push({
type: mapping.type,
result: mapping.options.result,
specialMatch: mapping.options.match ?? SpecialValueMatch.Null,
});
editRows.push(
createRow({
type: mapping.type,
result: mapping.options.result,
specialMatch: mapping.options.match ?? SpecialValueMatch.Null,
})
);
}
}
}