mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Canvas: refactor layer editor (#42562)
Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { Button, HorizontalGroup, Icon, IconButton, stylesFactory, ValuePicker } from '@grafana/ui';
|
||||
import { AppEvents, GrafanaTheme, SelectableValue, StandardEditorProps } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd';
|
||||
import { Button, HorizontalGroup } from '@grafana/ui';
|
||||
import { AppEvents, SelectableValue, StandardEditorProps } from '@grafana/data';
|
||||
import { DropResult } from 'react-beautiful-dnd';
|
||||
|
||||
import { PanelOptions } from '../models.gen';
|
||||
import { LayerActionID } from '../types';
|
||||
@@ -15,12 +13,12 @@ import { GroupState } from 'app/features/canvas/runtime/group';
|
||||
import { LayerEditorProps } from './layerEditor';
|
||||
import { SelectionParams } from 'app/features/canvas/runtime/scene';
|
||||
import { ShowConfirmModalEvent } from 'app/types/events';
|
||||
import { LayerDragDropList } from 'app/core/components/Layers/LayerDragDropList';
|
||||
import { AddLayerButton } from 'app/core/components/Layers/AddLayerButton';
|
||||
|
||||
type Props = StandardEditorProps<any, LayerEditorProps, PanelOptions>;
|
||||
|
||||
export class LayerElementListEditor extends PureComponent<Props> {
|
||||
style = getLayerDragStyles(config.theme);
|
||||
|
||||
getScene = () => {
|
||||
const { settings } = this.props.item;
|
||||
if (!settings?.layer) {
|
||||
@@ -86,10 +84,6 @@ export class LayerElementListEditor extends PureComponent<Props> {
|
||||
layer.scene.clearCurrentSelection();
|
||||
};
|
||||
|
||||
getRowStyle = (sel: boolean) => {
|
||||
return sel ? `${this.style.row} ${this.style.sel}` : this.style.row;
|
||||
};
|
||||
|
||||
onDragEnd = (result: DropResult) => {
|
||||
if (!result.destination) {
|
||||
return;
|
||||
@@ -133,7 +127,7 @@ export class LayerElementListEditor extends PureComponent<Props> {
|
||||
const { layer } = settings;
|
||||
|
||||
layer.elements.forEach((element: ElementState) => {
|
||||
layer.parent?.doAction(LayerActionID.Duplicate, element);
|
||||
layer.parent?.doAction(LayerActionID.Duplicate, element, false);
|
||||
});
|
||||
this.deleteGroup();
|
||||
};
|
||||
@@ -201,8 +195,27 @@ export class LayerElementListEditor extends PureComponent<Props> {
|
||||
return <div>Missing layer?</div>;
|
||||
}
|
||||
|
||||
const styles = this.style;
|
||||
const selection: number[] = settings.selected ? settings.selected.map((v) => v.UID) : [];
|
||||
const onDelete = (element: ElementState) => {
|
||||
layer.doAction(LayerActionID.Delete, element);
|
||||
};
|
||||
|
||||
const onDuplicate = (element: ElementState) => {
|
||||
layer.doAction(LayerActionID.Duplicate, element);
|
||||
};
|
||||
|
||||
const getLayerInfo = (element: ElementState) => {
|
||||
return element.options.type;
|
||||
};
|
||||
|
||||
const onNameChange = (element: ElementState, name: string) => {
|
||||
element.onChange({ ...element.options, name });
|
||||
};
|
||||
|
||||
const isGroup = (element: ElementState) => {
|
||||
return element instanceof GroupState;
|
||||
};
|
||||
|
||||
const selection: string[] = settings.selected ? settings.selected.map((v) => v.getName()) : [];
|
||||
return (
|
||||
<>
|
||||
{!layer.isRoot() && (
|
||||
@@ -221,78 +234,24 @@ export class LayerElementListEditor extends PureComponent<Props> {
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<DragDropContext onDragEnd={this.onDragEnd}>
|
||||
<Droppable droppableId="droppable">
|
||||
{(provided, snapshot) => (
|
||||
<div {...provided.droppableProps} ref={provided.innerRef}>
|
||||
{(() => {
|
||||
// reverse order
|
||||
const rows: any = [];
|
||||
for (let i = layer.elements.length - 1; i >= 0; i--) {
|
||||
const element = layer.elements[i];
|
||||
rows.push(
|
||||
<Draggable key={element.UID} draggableId={`${element.UID}`} index={rows.length}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
className={this.getRowStyle(selection.includes(element.UID))}
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
onMouseDown={() => this.onSelect(element)}
|
||||
>
|
||||
<span className={styles.typeWrapper}>{element.item.name}</span>
|
||||
<div className={styles.textWrapper}>
|
||||
{element.UID} ({i})
|
||||
</div>
|
||||
|
||||
{element.item.id !== 'group' && (
|
||||
<>
|
||||
<IconButton
|
||||
name="copy"
|
||||
title={'Duplicate'}
|
||||
className={styles.actionIcon}
|
||||
onClick={() => layer.doAction(LayerActionID.Duplicate, element)}
|
||||
surface="header"
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
name="trash-alt"
|
||||
title={'Remove'}
|
||||
className={cx(styles.actionIcon, styles.dragIcon)}
|
||||
onClick={() => layer.doAction(LayerActionID.Delete, element)}
|
||||
surface="header"
|
||||
/>
|
||||
<Icon
|
||||
title="Drag and drop to reorder"
|
||||
name="draggabledots"
|
||||
size="lg"
|
||||
className={styles.dragIcon}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
}
|
||||
return rows;
|
||||
})()}
|
||||
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
<LayerDragDropList
|
||||
onDragEnd={this.onDragEnd}
|
||||
onSelect={this.onSelect}
|
||||
onDelete={onDelete}
|
||||
onDuplicate={onDuplicate}
|
||||
getLayerInfo={getLayerInfo}
|
||||
onNameChange={onNameChange}
|
||||
isGroup={isGroup}
|
||||
layers={layer.elements}
|
||||
selection={selection}
|
||||
/>
|
||||
<br />
|
||||
|
||||
<HorizontalGroup>
|
||||
<ValuePicker
|
||||
icon="plus"
|
||||
label="Add item"
|
||||
variant="secondary"
|
||||
options={canvasElementRegistry.selectOptions().options}
|
||||
<AddLayerButton
|
||||
onChange={this.onAddItem}
|
||||
isFullWidth={false}
|
||||
options={canvasElementRegistry.selectOptions().options}
|
||||
label={'Add item'}
|
||||
/>
|
||||
{selection.length > 0 && (
|
||||
<Button size="sm" variant="secondary" onClick={this.onClearSelection}>
|
||||
@@ -309,51 +268,3 @@ export class LayerElementListEditor extends PureComponent<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const getLayerDragStyles = stylesFactory((theme: GrafanaTheme) => ({
|
||||
wrapper: css`
|
||||
margin-bottom: ${theme.spacing.md};
|
||||
`,
|
||||
row: css`
|
||||
padding: ${theme.spacing.xs} ${theme.spacing.sm};
|
||||
border-radius: ${theme.border.radius.sm};
|
||||
background: ${theme.colors.bg2};
|
||||
min-height: ${theme.spacing.formInputHeight}px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 3px;
|
||||
cursor: pointer;
|
||||
|
||||
border: 1px solid ${theme.colors.formInputBorder};
|
||||
&:hover {
|
||||
border: 1px solid ${theme.colors.formInputBorderHover};
|
||||
}
|
||||
`,
|
||||
sel: css`
|
||||
border: 1px solid ${theme.colors.formInputBorderActive};
|
||||
&:hover {
|
||||
border: 1px solid ${theme.colors.formInputBorderActive};
|
||||
}
|
||||
`,
|
||||
dragIcon: css`
|
||||
cursor: drag;
|
||||
`,
|
||||
actionIcon: css`
|
||||
color: ${theme.colors.textWeak};
|
||||
&:hover {
|
||||
color: ${theme.colors.text};
|
||||
}
|
||||
`,
|
||||
typeWrapper: css`
|
||||
color: ${theme.colors.textBlue};
|
||||
margin-right: 5px;
|
||||
`,
|
||||
textWrapper: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
margin-right: ${theme.spacing.sm};
|
||||
`,
|
||||
}));
|
||||
|
||||
@@ -68,6 +68,7 @@ export function getElementEditor(opts: CanvasEditorOptions): NestedPanelOptions<
|
||||
currentOptions = {
|
||||
...layer.getNewOptions(options),
|
||||
type: layer.id,
|
||||
name: `Element ${Date.now()}.${Math.floor(Math.random() * 100)}`,
|
||||
};
|
||||
}
|
||||
const ctx = { ...context, options: currentOptions };
|
||||
|
||||
Reference in New Issue
Block a user