diff --git a/public/app/features/canvas/runtime/scene.tsx b/public/app/features/canvas/runtime/scene.tsx index ae30613d838..d098ba0b6c3 100644 --- a/public/app/features/canvas/runtime/scene.tsx +++ b/public/app/features/canvas/runtime/scene.tsx @@ -43,14 +43,14 @@ export class Scene { height = 0; style: CSSProperties = {}; data?: PanelData; - selecto?: Selecto | null; + selecto?: Selecto; + div?: HTMLDivElement; constructor(cfg: CanvasGroupOptions, public onSave: (cfg: CanvasGroupOptions) => void) { this.root = this.load(cfg); } load(cfg: CanvasGroupOptions) { - console.log('LOAD', cfg, this); this.root = new RootElement( cfg ?? { type: 'group', @@ -65,6 +65,11 @@ export class Scene { this.lookup.set(v.UID, v); }); + setTimeout(() => { + if (this.div) { + this.initMoveable(); + } + }, 100); return this.root; } @@ -85,6 +90,11 @@ export class Scene { this.height = height; this.style = { width, height }; this.root.updateSize(width, height); + + if (this.selecto?.getSelectedTargets().length) { + let event: MouseEvent = new MouseEvent('click'); + this.selecto.clickTarget(event, this.div); + } } onChange(uid: number, cfg: CanvasElementOptions) { @@ -143,19 +153,27 @@ export class Scene { return this.root.elements.find((element) => element.div === target); }; - initMoveable = (sceneContainer: HTMLDivElement) => { + setRef = (sceneContainer: HTMLDivElement) => { + this.div = sceneContainer; + }; + + initMoveable = () => { + if (this.selecto) { + this.selecto.destroy(); + } + const targetElements: HTMLDivElement[] = []; this.root.elements.forEach((element: ElementState) => { targetElements.push(element.div!); }); this.selecto = new Selecto({ - container: sceneContainer, + container: this.div, selectableTargets: targetElements, selectByClick: true, }); - const moveable = new Moveable(sceneContainer, { + const moveable = new Moveable(this.div!, { draggable: true, resizable: true, }) @@ -209,7 +227,6 @@ export class Scene { if (event.isDragStart) { event.inputEvent.preventDefault(); - setTimeout(() => { moveable.dragStart(event.inputEvent); }); @@ -219,7 +236,7 @@ export class Scene { render() { return ( -
+
{this.root.render()}
); diff --git a/public/app/features/dashboard/containers/DashboardPage.tsx b/public/app/features/dashboard/containers/DashboardPage.tsx index fd43c05b66b..47d9ab6c6d8 100644 --- a/public/app/features/dashboard/containers/DashboardPage.tsx +++ b/public/app/features/dashboard/containers/DashboardPage.tsx @@ -29,7 +29,7 @@ import { DashboardLoading } from '../components/DashboardLoading/DashboardLoadin import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed'; import { DashboardPrompt } from '../components/DashboardPrompt/DashboardPrompt'; import classnames from 'classnames'; -import { PanelEditExitedEvent } from 'app/types/events'; +import { PanelEditEnteredEvent, PanelEditExitedEvent } from 'app/types/events'; import { liveTimer } from '../dashgrid/liveTimer'; export interface DashboardPageRouteParams { @@ -178,6 +178,9 @@ export class UnthemedDashboardPage extends PureComponent { // entering edit mode if (this.state.editPanel && !prevState.editPanel) { dashboardWatcher.setEditingState(true); + + // Some panels need to be notified when entering edit mode + this.props.dashboard?.events.publish(new PanelEditEnteredEvent(this.state.editPanel.id)); } // leaving edit mode diff --git a/public/app/plugins/panel/canvas/CanvasPanel.tsx b/public/app/plugins/panel/canvas/CanvasPanel.tsx index 6b793edcd8a..0aae1c9cd43 100644 --- a/public/app/plugins/panel/canvas/CanvasPanel.tsx +++ b/public/app/plugins/panel/canvas/CanvasPanel.tsx @@ -1,8 +1,8 @@ import { Component } from 'react'; -import { CoreApp, PanelProps } from '@grafana/data'; +import { PanelProps } from '@grafana/data'; import { PanelOptions } from './models.gen'; import { Subscription } from 'rxjs'; -import { PanelEditExitedEvent } from 'app/types/events'; +import { PanelEditEnteredEvent, PanelEditExitedEvent } from 'app/types/events'; import { CanvasGroupOptions } from 'app/features/canvas'; import { Scene } from 'app/features/canvas/runtime/scene'; import { PanelContext, PanelContextRoot } from '@grafana/ui'; @@ -41,6 +41,14 @@ export class CanvasPanel extends Component { this.scene.updateSize(props.width, props.height); this.scene.updateData(props.data); + this.subs.add( + this.props.eventBus.subscribe(PanelEditEnteredEvent, (evt) => { + // Remove current selection when entering edit mode for any panel in dashboard + let event: MouseEvent = new MouseEvent('click'); + this.scene?.selecto?.clickTarget(event, this.scene?.div); + }) + ); + this.subs.add( this.props.eventBus.subscribe(PanelEditExitedEvent, (evt) => { if (this.props.id === evt.payload) { @@ -52,7 +60,7 @@ export class CanvasPanel extends Component { componentDidMount() { this.panelContext = this.context as PanelContext; - if (this.panelContext.onInstanceStateChange && this.panelContext.app === CoreApp.PanelEditor) { + if (this.panelContext.onInstanceStateChange) { this.panelContext.onInstanceStateChange({ scene: this.scene, layer: this.scene.root, diff --git a/public/app/types/events.ts b/public/app/types/events.ts index d914aae48cd..2da73d11ae7 100644 --- a/public/app/types/events.ts +++ b/public/app/types/events.ts @@ -201,6 +201,11 @@ export class AnnotationQueryFinished extends BusEventWithPayload { static type = 'time-range-updated'; } + +export class PanelEditEnteredEvent extends BusEventWithPayload { + static type = 'panel-edit-started'; +} + export class PanelEditExitedEvent extends BusEventWithPayload { static type = 'panel-edit-finished'; }