Canvas: Refactor group to frame (#48671)

This commit is contained in:
Nathan Marrs 2022-05-03 22:58:00 -07:00 committed by GitHub
parent 0d60b1ce0a
commit ff38f24044
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 94 additions and 95 deletions

View File

@ -16,7 +16,7 @@ type LayerDragDropListProps<T extends LayerElement> = {
onSelect: (element: T) => any; onSelect: (element: T) => any;
onDelete: (element: T) => any; onDelete: (element: T) => any;
onDuplicate?: (element: T) => any; onDuplicate?: (element: T) => any;
isGroup?: (element: T) => boolean; isFrame?: (element: T) => boolean;
selection?: string[]; // list of unique ids (names) selection?: string[]; // list of unique ids (names)
excludeBaseLayer?: boolean; excludeBaseLayer?: boolean;
onNameChange: (element: T, newName: string) => any; onNameChange: (element: T, newName: string) => any;
@ -30,7 +30,7 @@ export const LayerDragDropList = <T extends LayerElement>({
onSelect, onSelect,
onDelete, onDelete,
onDuplicate, onDuplicate,
isGroup, isFrame,
selection, selection,
excludeBaseLayer, excludeBaseLayer,
onNameChange, onNameChange,
@ -74,7 +74,7 @@ export const LayerDragDropList = <T extends LayerElement>({
/> />
<div className={style.textWrapper}>&nbsp; {getLayerInfo(element)}</div> <div className={style.textWrapper}>&nbsp; {getLayerInfo(element)}</div>
{!isGroup!(element) && ( {!isFrame!(element) && (
<> <>
{onDuplicate ? ( {onDuplicate ? (
<IconButton <IconButton

View File

@ -0,0 +1,6 @@
import { CanvasElementOptions } from './element';
export interface CanvasFrameOptions extends CanvasElementOptions {
type: 'frame';
elements: CanvasElementOptions[];
}

View File

@ -1,7 +0,0 @@
import { CanvasElementOptions } from './element';
export interface CanvasGroupOptions extends CanvasElementOptions {
type: 'group';
elements: CanvasElementOptions[];
// layout? // absolute, list, grid?
}

View File

@ -1,4 +1,4 @@
export * from './types'; export * from './types';
export * from './element'; export * from './element';
export { CanvasGroupOptions } from './group'; export { CanvasFrameOptions } from './frame';
export * from './registry'; export * from './registry';

View File

@ -13,7 +13,7 @@ import { DimensionContext } from 'app/features/dimensions';
import { HorizontalConstraint, Placement, VerticalConstraint } from '../types'; import { HorizontalConstraint, Placement, VerticalConstraint } from '../types';
import { GroupState } from './group'; import { FrameState } from './frame';
import { RootElement } from './root'; import { RootElement } from './root';
import { Scene } from './scene'; import { Scene } from './scene';
@ -32,7 +32,7 @@ export class ElementState implements LayerElement {
// Calculated // Calculated
data?: any; // depends on the type data?: any; // depends on the type
constructor(public item: CanvasElementItem, public options: CanvasElementOptions, public parent?: GroupState) { constructor(public item: CanvasElementItem, public options: CanvasElementOptions, public parent?: FrameState) {
const fallbackName = `Element ${Date.now()}`; const fallbackName = `Element ${Date.now()}`;
if (!options) { if (!options) {
this.options = { type: item.id, name: fallbackName }; this.options = { type: item.id, name: fallbackName };

View File

@ -1,7 +1,7 @@
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import React from 'react'; import React from 'react';
import { CanvasGroupOptions, canvasElementRegistry } from 'app/features/canvas'; import { CanvasFrameOptions, canvasElementRegistry } from 'app/features/canvas';
import { notFoundItem } from 'app/features/canvas/elements/notFound'; import { notFoundItem } from 'app/features/canvas/elements/notFound';
import { DimensionContext } from 'app/features/dimensions'; import { DimensionContext } from 'app/features/dimensions';
import { LayerActionID } from 'app/plugins/panel/canvas/types'; import { LayerActionID } from 'app/plugins/panel/canvas/types';
@ -13,10 +13,10 @@ import { ElementState } from './element';
import { RootElement } from './root'; import { RootElement } from './root';
import { Scene } from './scene'; import { Scene } from './scene';
export const groupItemDummy: CanvasElementItem = { export const frameItemDummy: CanvasElementItem = {
id: 'group', id: 'frame',
name: 'Group', name: 'Frame',
description: 'Group', description: 'Frame',
getNewOptions: () => ({ getNewOptions: () => ({
config: {}, config: {},
@ -24,16 +24,16 @@ export const groupItemDummy: CanvasElementItem = {
// eslint-disable-next-line react/display-name // eslint-disable-next-line react/display-name
display: () => { display: () => {
return <div>GROUP!</div>; return <div>FRAME!</div>;
}, },
}; };
export class GroupState extends ElementState { export class FrameState extends ElementState {
elements: ElementState[] = []; elements: ElementState[] = [];
scene: Scene; scene: Scene;
constructor(public options: CanvasGroupOptions, scene: Scene, public parent?: GroupState) { constructor(public options: CanvasFrameOptions, scene: Scene, public parent?: FrameState) {
super(groupItemDummy, options, parent); super(frameItemDummy, options, parent);
this.scene = scene; this.scene = scene;
@ -44,8 +44,8 @@ export class GroupState extends ElementState {
} }
for (const c of elements) { for (const c of elements) {
if (c.type === 'group') { if (c.type === 'frame') {
this.elements.push(new GroupState(c as CanvasGroupOptions, scene, this)); this.elements.push(new FrameState(c as CanvasFrameOptions, scene, this));
} else { } else {
const item = canvasElementRegistry.getIfExists(c.type) ?? notFoundItem; const item = canvasElementRegistry.getIfExists(c.type) ?? notFoundItem;
this.elements.push(new ElementState(item, c, this)); this.elements.push(new ElementState(item, c, this));
@ -91,8 +91,8 @@ export class GroupState extends ElementState {
this.reinitializeMoveable(); this.reinitializeMoveable();
break; break;
case LayerActionID.Duplicate: case LayerActionID.Duplicate:
if (element.item.id === 'group') { if (element.item.id === 'frame') {
console.log('Can not duplicate groups (yet)', action, element); console.log('Can not duplicate frames (yet)', action, element);
return; return;
} }
const opts = cloneDeep(element.options); const opts = cloneDeep(element.options);

View File

@ -1,12 +1,12 @@
import React from 'react'; import React from 'react';
import { CanvasGroupOptions, CanvasElementOptions } from 'app/features/canvas'; import { CanvasFrameOptions, CanvasElementOptions } from 'app/features/canvas';
import { GroupState } from './group'; import { FrameState } from './frame';
import { Scene } from './scene'; import { Scene } from './scene';
export class RootElement extends GroupState { export class RootElement extends FrameState {
constructor(public options: CanvasGroupOptions, public scene: Scene, private changeCallback: () => void) { constructor(public options: CanvasFrameOptions, public scene: Scene, private changeCallback: () => void) {
super(options, scene); super(options, scene);
this.sizeStyle = { this.sizeStyle = {
@ -22,11 +22,11 @@ export class RootElement extends GroupState {
// root type can not change // root type can not change
onChange(options: CanvasElementOptions) { onChange(options: CanvasElementOptions) {
this.revId++; this.revId++;
this.options = { ...options } as CanvasGroupOptions; this.options = { ...options } as CanvasFrameOptions;
this.changeCallback(); this.changeCallback();
} }
getSaveModel(): CanvasGroupOptions { getSaveModel(): CanvasFrameOptions {
const { placement, constraint, ...rest } = this.options; const { placement, constraint, ...rest } = this.options;
return { return {

View File

@ -8,7 +8,7 @@ import Selecto from 'selecto';
import { GrafanaTheme2, PanelData } from '@grafana/data'; import { GrafanaTheme2, PanelData } from '@grafana/data';
import { stylesFactory } from '@grafana/ui'; import { stylesFactory } from '@grafana/ui';
import { config } from 'app/core/config'; import { config } from 'app/core/config';
import { CanvasGroupOptions, DEFAULT_CANVAS_ELEMENT_CONFIG } from 'app/features/canvas'; import { CanvasFrameOptions, DEFAULT_CANVAS_ELEMENT_CONFIG } from 'app/features/canvas';
import { import {
ColorDimensionConfig, ColorDimensionConfig,
ResourceDimensionConfig, ResourceDimensionConfig,
@ -29,12 +29,12 @@ import { LayerActionID } from 'app/plugins/panel/canvas/types';
import { Placement } from '../types'; import { Placement } from '../types';
import { ElementState } from './element'; import { ElementState } from './element';
import { GroupState } from './group'; import { FrameState } from './frame';
import { RootElement } from './root'; import { RootElement } from './root';
export interface SelectionParams { export interface SelectionParams {
targets: Array<HTMLElement | SVGElement>; targets: Array<HTMLElement | SVGElement>;
group?: GroupState; frame?: FrameState;
} }
export class Scene { export class Scene {
@ -53,15 +53,15 @@ export class Scene {
selecto?: Selecto; selecto?: Selecto;
moveable?: Moveable; moveable?: Moveable;
div?: HTMLDivElement; div?: HTMLDivElement;
currentLayer?: GroupState; currentLayer?: FrameState;
isEditingEnabled?: boolean; isEditingEnabled?: boolean;
constructor(cfg: CanvasGroupOptions, enableEditing: boolean, public onSave: (cfg: CanvasGroupOptions) => void) { constructor(cfg: CanvasFrameOptions, enableEditing: boolean, public onSave: (cfg: CanvasFrameOptions) => void) {
this.root = this.load(cfg, enableEditing); this.root = this.load(cfg, enableEditing);
} }
getNextElementName = (isGroup = false) => { getNextElementName = (isFrame = false) => {
const label = isGroup ? 'Group' : 'Element'; const label = isFrame ? 'Frame' : 'Element';
let idx = this.byName.size + 1; let idx = this.byName.size + 1;
const max = idx + 100; const max = idx + 100;
@ -79,10 +79,10 @@ export class Scene {
return !this.byName.has(v); return !this.byName.has(v);
}; };
load(cfg: CanvasGroupOptions, enableEditing: boolean) { load(cfg: CanvasFrameOptions, enableEditing: boolean) {
this.root = new RootElement( this.root = new RootElement(
cfg ?? { cfg ?? {
type: 'group', type: 'frame',
elements: [DEFAULT_CANVAS_ELEMENT_CONFIG], elements: [DEFAULT_CANVAS_ELEMENT_CONFIG],
}, },
this, this,
@ -126,13 +126,13 @@ export class Scene {
} }
} }
groupSelection() { frameSelection() {
this.selection.pipe(first()).subscribe((currentSelectedElements) => { this.selection.pipe(first()).subscribe((currentSelectedElements) => {
const currentLayer = currentSelectedElements[0].parent!; const currentLayer = currentSelectedElements[0].parent!;
const newLayer = new GroupState( const newLayer = new FrameState(
{ {
type: 'group', type: 'frame',
name: this.getNextElementName(true), name: this.getNextElementName(true),
elements: [], elements: [],
}, },
@ -140,18 +140,18 @@ export class Scene {
currentSelectedElements[0].parent currentSelectedElements[0].parent
); );
const groupPlacement = this.generateGroupContainer(currentSelectedElements); const framePlacement = this.generateFrameContainer(currentSelectedElements);
newLayer.options.placement = groupPlacement; newLayer.options.placement = framePlacement;
currentSelectedElements.forEach((element: ElementState) => { currentSelectedElements.forEach((element: ElementState) => {
const elementContainer = element.div?.getBoundingClientRect(); const elementContainer = element.div?.getBoundingClientRect();
element.setPlacementFromConstraint(elementContainer, groupPlacement as DOMRect); element.setPlacementFromConstraint(elementContainer, framePlacement as DOMRect);
currentLayer.doAction(LayerActionID.Delete, element); currentLayer.doAction(LayerActionID.Delete, element);
newLayer.doAction(LayerActionID.Duplicate, element, false, false); newLayer.doAction(LayerActionID.Duplicate, element, false, false);
}); });
newLayer.setPlacementFromConstraint(groupPlacement as DOMRect, currentLayer.div?.getBoundingClientRect()); newLayer.setPlacementFromConstraint(framePlacement as DOMRect, currentLayer.div?.getBoundingClientRect());
currentLayer.elements.push(newLayer); currentLayer.elements.push(newLayer);
@ -161,7 +161,7 @@ export class Scene {
}); });
} }
private generateGroupContainer = (elements: ElementState[]): Placement => { private generateFrameContainer = (elements: ElementState[]): Placement => {
let minTop = Infinity; let minTop = Infinity;
let minLeft = Infinity; let minLeft = Infinity;
let maxRight = 0; let maxRight = 0;
@ -204,7 +204,7 @@ export class Scene {
this.selecto?.clickTarget(event, this.div); this.selecto?.clickTarget(event, this.div);
} }
updateCurrentLayer(newLayer: GroupState) { updateCurrentLayer(newLayer: FrameState) {
this.currentLayer = newLayer; this.currentLayer = newLayer;
this.clearCurrentSelection(); this.clearCurrentSelection();
this.save(); this.save();
@ -233,7 +233,7 @@ export class Scene {
return currentElement; return currentElement;
} }
const nestedElements = currentElement instanceof GroupState ? currentElement.elements : []; const nestedElements = currentElement instanceof FrameState ? currentElement.elements : [];
for (const nestedElement of nestedElements) { for (const nestedElement of nestedElements) {
stack.unshift(nestedElement); stack.unshift(nestedElement);
} }
@ -256,8 +256,8 @@ export class Scene {
private updateSelection = (selection: SelectionParams) => { private updateSelection = (selection: SelectionParams) => {
this.moveable!.target = selection.targets; this.moveable!.target = selection.targets;
if (selection.group) { if (selection.frame) {
this.selection.next([selection.group]); this.selection.next([selection.frame]);
} else { } else {
const s = selection.targets.map((t) => this.findElementByTarget(t)!); const s = selection.targets.map((t) => this.findElementByTarget(t)!);
this.selection.next(s); this.selection.next(s);
@ -275,7 +275,7 @@ export class Scene {
targetElements.push(currentElement.div); targetElements.push(currentElement.div);
} }
const nestedElements = currentElement instanceof GroupState ? currentElement.elements : []; const nestedElements = currentElement instanceof FrameState ? currentElement.elements : [];
for (const nestedElement of nestedElements) { for (const nestedElement of nestedElements) {
stack.unshift(nestedElement); stack.unshift(nestedElement);
} }

View File

@ -3,7 +3,7 @@ import { Subscription } from 'rxjs';
import { PanelProps } from '@grafana/data'; import { PanelProps } from '@grafana/data';
import { PanelContext, PanelContextRoot } from '@grafana/ui'; import { PanelContext, PanelContextRoot } from '@grafana/ui';
import { CanvasGroupOptions } from 'app/features/canvas'; import { CanvasFrameOptions } from 'app/features/canvas';
import { ElementState } from 'app/features/canvas/runtime/element'; import { ElementState } from 'app/features/canvas/runtime/element';
import { Scene } from 'app/features/canvas/runtime/scene'; import { Scene } from 'app/features/canvas/runtime/scene';
import { PanelEditEnteredEvent, PanelEditExitedEvent } from 'app/types/events'; import { PanelEditEnteredEvent, PanelEditExitedEvent } from 'app/types/events';
@ -85,7 +85,7 @@ export class CanvasPanel extends Component<Props, State> {
// NOTE, all changes to the scene flow through this function // NOTE, all changes to the scene flow through this function
// even the editor gets current state from the same scene instance! // even the editor gets current state from the same scene instance!
onUpdateScene = (root: CanvasGroupOptions) => { onUpdateScene = (root: CanvasFrameOptions) => {
const { onOptionsChange, options } = this.props; const { onOptionsChange, options } = this.props;
onOptionsChange({ onOptionsChange({
...options, ...options,

View File

@ -9,7 +9,7 @@ import { LayerDragDropList } from 'app/core/components/Layers/LayerDragDropList'
import { CanvasElementOptions, canvasElementRegistry } from 'app/features/canvas'; import { CanvasElementOptions, canvasElementRegistry } from 'app/features/canvas';
import { notFoundItem } from 'app/features/canvas/elements/notFound'; import { notFoundItem } from 'app/features/canvas/elements/notFound';
import { ElementState } from 'app/features/canvas/runtime/element'; import { ElementState } from 'app/features/canvas/runtime/element';
import { GroupState } from 'app/features/canvas/runtime/group'; import { FrameState } from 'app/features/canvas/runtime/frame';
import { SelectionParams } from 'app/features/canvas/runtime/scene'; import { SelectionParams } from 'app/features/canvas/runtime/scene';
import { ShowConfirmModalEvent } from 'app/types/events'; import { ShowConfirmModalEvent } from 'app/types/events';
@ -53,11 +53,11 @@ export class LayerElementListEditor extends PureComponent<Props> {
if (settings?.scene) { if (settings?.scene) {
try { try {
let selection: SelectionParams = { targets: [] }; let selection: SelectionParams = { targets: [] };
if (item instanceof GroupState) { if (item instanceof FrameState) {
const targetElements: HTMLDivElement[] = []; const targetElements: HTMLDivElement[] = [];
targetElements.push(item?.div!); targetElements.push(item?.div!);
selection.targets = targetElements; selection.targets = targetElements;
selection.group = item; selection.frame = item;
settings.scene.select(selection); settings.scene.select(selection);
} else if (item instanceof ElementState) { } else if (item instanceof ElementState) {
const targetElement = [item?.div!]; const targetElement = [item?.div!];
@ -115,7 +115,7 @@ export class LayerElementListEditor extends PureComponent<Props> {
} }
}; };
private decoupleGroup = () => { private decoupleFrame = () => {
const settings = this.props.item.settings; const settings = this.props.item.settings;
if (!settings?.layer) { if (!settings?.layer) {
@ -124,7 +124,7 @@ export class LayerElementListEditor extends PureComponent<Props> {
const { layer } = settings; const { layer } = settings;
this.deleteGroup(); this.deleteFrame();
layer.elements.forEach((element: ElementState) => { layer.elements.forEach((element: ElementState) => {
const elementContainer = element.div?.getBoundingClientRect(); const elementContainer = element.div?.getBoundingClientRect();
element.setPlacementFromConstraint(elementContainer, layer.parent?.div?.getBoundingClientRect()); element.setPlacementFromConstraint(elementContainer, layer.parent?.div?.getBoundingClientRect());
@ -132,22 +132,22 @@ export class LayerElementListEditor extends PureComponent<Props> {
}); });
}; };
private onDecoupleGroup = () => { private onDecoupleFrame = () => {
appEvents.publish( appEvents.publish(
new ShowConfirmModalEvent({ new ShowConfirmModalEvent({
title: 'Decouple group', title: 'Decouple frame',
text: `Are you sure you want to decouple this group?`, text: `Are you sure you want to decouple this frame?`,
text2: 'This will remove the group and push nested elements in the next level up.', text2: 'This will remove the frame and push nested elements in the next level up.',
confirmText: 'Yes', confirmText: 'Yes',
yesText: 'Decouple', yesText: 'Decouple',
onConfirm: async () => { onConfirm: async () => {
this.decoupleGroup(); this.decoupleFrame();
}, },
}) })
); );
}; };
private deleteGroup = () => { private deleteFrame = () => {
const settings = this.props.item.settings; const settings = this.props.item.settings;
if (!settings?.layer) { if (!settings?.layer) {
@ -164,26 +164,26 @@ export class LayerElementListEditor extends PureComponent<Props> {
this.goUpLayer(); this.goUpLayer();
}; };
private onGroupSelection = () => { private onFrameSelection = () => {
const scene = this.getScene(); const scene = this.getScene();
if (scene) { if (scene) {
scene.groupSelection(); scene.frameSelection();
} else { } else {
console.warn('no scene!'); console.warn('no scene!');
} }
}; };
private onDeleteGroup = () => { private onDeleteFrame = () => {
appEvents.publish( appEvents.publish(
new ShowConfirmModalEvent({ new ShowConfirmModalEvent({
title: 'Delete group', title: 'Delete frame',
text: `Are you sure you want to delete this group?`, text: `Are you sure you want to delete this frame?`,
text2: 'This will delete the group and all nested elements.', text2: 'This will delete the frame and all nested elements.',
icon: 'trash-alt', icon: 'trash-alt',
confirmText: 'Delete', confirmText: 'Delete',
yesText: 'Delete', yesText: 'Delete',
onConfirm: async () => { onConfirm: async () => {
this.deleteGroup(); this.deleteFrame();
}, },
}) })
); );
@ -215,8 +215,8 @@ export class LayerElementListEditor extends PureComponent<Props> {
element.onChange({ ...element.options, name }); element.onChange({ ...element.options, name });
}; };
const isGroup = (element: ElementState) => { const isFrame = (element: ElementState) => {
return element instanceof GroupState; return element instanceof FrameState;
}; };
const verifyLayerNameUniqueness = (nameToVerify: string) => { const verifyLayerNameUniqueness = (nameToVerify: string) => {
@ -231,16 +231,16 @@ export class LayerElementListEditor extends PureComponent<Props> {
{!layer.isRoot() && ( {!layer.isRoot() && (
<> <>
<Button icon="angle-up" size="sm" variant="secondary" onClick={this.goUpLayer}> <Button icon="angle-up" size="sm" variant="secondary" onClick={this.goUpLayer}>
Go Up Level Go up level
</Button> </Button>
<Button size="sm" variant="secondary" onClick={() => this.onSelect(layer)}> <Button size="sm" variant="secondary" onClick={() => this.onSelect(layer)}>
Select Group Select frame
</Button> </Button>
<Button size="sm" variant="secondary" onClick={() => this.onDecoupleGroup()}> <Button size="sm" variant="secondary" onClick={() => this.onDecoupleFrame()}>
Decouple Group Decouple frame
</Button> </Button>
<Button size="sm" variant="secondary" onClick={() => this.onDeleteGroup()}> <Button size="sm" variant="secondary" onClick={() => this.onDeleteFrame()}>
Delete Group Delete frame
</Button> </Button>
</> </>
)} )}
@ -252,7 +252,7 @@ export class LayerElementListEditor extends PureComponent<Props> {
getLayerInfo={getLayerInfo} getLayerInfo={getLayerInfo}
onNameChange={onNameChange} onNameChange={onNameChange}
verifyLayerNameUniqueness={verifyLayerNameUniqueness} verifyLayerNameUniqueness={verifyLayerNameUniqueness}
isGroup={isGroup} isFrame={isFrame}
layers={layer.elements} layers={layer.elements}
selection={selection} selection={selection}
/> />
@ -266,12 +266,12 @@ export class LayerElementListEditor extends PureComponent<Props> {
/> />
{selection.length > 0 && ( {selection.length > 0 && (
<Button size="sm" variant="secondary" onClick={this.onClearSelection}> <Button size="sm" variant="secondary" onClick={this.onClearSelection}>
Clear Selection Clear selection
</Button> </Button>
)} )}
{selection.length > 1 && ( {selection.length > 1 && (
<Button size="sm" variant="secondary" onClick={this.onGroupSelection}> <Button size="sm" variant="secondary" onClick={this.onFrameSelection}>
Group items Frame selection
</Button> </Button>
)} )}
</HorizontalGroup> </HorizontalGroup>

View File

@ -2,7 +2,7 @@ import { get as lodashGet } from 'lodash';
import { NestedPanelOptions, NestedValueAccess } from '@grafana/data/src/utils/OptionsUIBuilders'; import { NestedPanelOptions, NestedValueAccess } from '@grafana/data/src/utils/OptionsUIBuilders';
import { ElementState } from 'app/features/canvas/runtime/element'; import { ElementState } from 'app/features/canvas/runtime/element';
import { GroupState } from 'app/features/canvas/runtime/group'; import { FrameState } from 'app/features/canvas/runtime/frame';
import { Scene } from 'app/features/canvas/runtime/scene'; import { Scene } from 'app/features/canvas/runtime/scene';
import { setOptionImmutably } from 'app/features/dashboard/components/PanelEditor/utils'; import { setOptionImmutably } from 'app/features/dashboard/components/PanelEditor/utils';
@ -14,7 +14,7 @@ import { optionBuilder } from './options';
export interface LayerEditorProps { export interface LayerEditorProps {
scene: Scene; scene: Scene;
layer: GroupState; layer: FrameState;
selected: ElementState[]; selected: ElementState[];
} }
@ -22,12 +22,12 @@ export function getLayerEditor(opts: InstanceState): NestedPanelOptions<LayerEdi
const { selected, scene } = opts; const { selected, scene } = opts;
if (!scene.currentLayer) { if (!scene.currentLayer) {
scene.currentLayer = scene.root as GroupState; scene.currentLayer = scene.root as FrameState;
} }
if (selected) { if (selected) {
for (const element of selected) { for (const element of selected) {
if (element instanceof GroupState) { if (element instanceof FrameState) {
scene.currentLayer = element; scene.currentLayer = element;
break; break;
} }

View File

@ -3,13 +3,13 @@
// It is currenty hand written but will serve as the target for cuetsy // It is currenty hand written but will serve as the target for cuetsy
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import { CanvasGroupOptions, DEFAULT_CANVAS_ELEMENT_CONFIG } from 'app/features/canvas'; import { CanvasFrameOptions, DEFAULT_CANVAS_ELEMENT_CONFIG } from 'app/features/canvas';
export const modelVersion = Object.freeze([1, 0]); export const modelVersion = Object.freeze([1, 0]);
export interface PanelOptions { export interface PanelOptions {
inlineEditing: boolean; inlineEditing: boolean;
root: CanvasGroupOptions; root: CanvasFrameOptions;
} }
export const defaultPanelOptions: PanelOptions = { export const defaultPanelOptions: PanelOptions = {
@ -20,5 +20,5 @@ export const defaultPanelOptions: PanelOptions = {
...DEFAULT_CANVAS_ELEMENT_CONFIG, ...DEFAULT_CANVAS_ELEMENT_CONFIG,
}, },
], ],
} as unknown as CanvasGroupOptions, } as unknown as CanvasFrameOptions,
}; };

View File

@ -1,5 +1,5 @@
import { PanelPlugin } from '@grafana/data'; import { PanelPlugin } from '@grafana/data';
import { GroupState } from 'app/features/canvas/runtime/group'; import { FrameState } from 'app/features/canvas/runtime/frame';
import { CanvasPanel, InstanceState } from './CanvasPanel'; import { CanvasPanel, InstanceState } from './CanvasPanel';
import { getElementEditor } from './editor/elementEditor'; import { getElementEditor } from './editor/elementEditor';
@ -25,7 +25,7 @@ export const plugin = new PanelPlugin<PanelOptions>(CanvasPanel)
const selection = state.selected; const selection = state.selected;
if (selection?.length === 1) { if (selection?.length === 1) {
const element = selection[0]; const element = selection[0];
if (!(element instanceof GroupState)) { if (!(element instanceof FrameState)) {
builder.addNestedOptions( builder.addNestedOptions(
getElementEditor({ getElementEditor({
category: [`Selected element (${element.options.name})`], category: [`Selected element (${element.options.name})`],