mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 08:05:43 -06:00
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:
parent
9afe845d5c
commit
7b7b9ff4a7
@ -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>
|
||||
|
@ -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,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user