Canvas: Improve enter / exit editor UX (#40591)

pull/40580/head
Nathan Marrs 4 years ago committed by GitHub
parent 9c2d70ce0f
commit 7e59b92c8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      public/app/features/canvas/runtime/scene.tsx
  2. 5
      public/app/features/dashboard/containers/DashboardPage.tsx
  3. 14
      public/app/plugins/panel/canvas/CanvasPanel.tsx
  4. 5
      public/app/types/events.ts

@ -43,14 +43,14 @@ export class Scene {
height = 0; height = 0;
style: CSSProperties = {}; style: CSSProperties = {};
data?: PanelData; data?: PanelData;
selecto?: Selecto | null; selecto?: Selecto;
div?: HTMLDivElement;
constructor(cfg: CanvasGroupOptions, public onSave: (cfg: CanvasGroupOptions) => void) { constructor(cfg: CanvasGroupOptions, public onSave: (cfg: CanvasGroupOptions) => void) {
this.root = this.load(cfg); this.root = this.load(cfg);
} }
load(cfg: CanvasGroupOptions) { load(cfg: CanvasGroupOptions) {
console.log('LOAD', cfg, this);
this.root = new RootElement( this.root = new RootElement(
cfg ?? { cfg ?? {
type: 'group', type: 'group',
@ -65,6 +65,11 @@ export class Scene {
this.lookup.set(v.UID, v); this.lookup.set(v.UID, v);
}); });
setTimeout(() => {
if (this.div) {
this.initMoveable();
}
}, 100);
return this.root; return this.root;
} }
@ -85,6 +90,11 @@ export class Scene {
this.height = height; this.height = height;
this.style = { width, height }; this.style = { width, height };
this.root.updateSize(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) { onChange(uid: number, cfg: CanvasElementOptions) {
@ -143,19 +153,27 @@ export class Scene {
return this.root.elements.find((element) => element.div === target); 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[] = []; const targetElements: HTMLDivElement[] = [];
this.root.elements.forEach((element: ElementState) => { this.root.elements.forEach((element: ElementState) => {
targetElements.push(element.div!); targetElements.push(element.div!);
}); });
this.selecto = new Selecto({ this.selecto = new Selecto({
container: sceneContainer, container: this.div,
selectableTargets: targetElements, selectableTargets: targetElements,
selectByClick: true, selectByClick: true,
}); });
const moveable = new Moveable(sceneContainer, { const moveable = new Moveable(this.div!, {
draggable: true, draggable: true,
resizable: true, resizable: true,
}) })
@ -209,7 +227,6 @@ export class Scene {
if (event.isDragStart) { if (event.isDragStart) {
event.inputEvent.preventDefault(); event.inputEvent.preventDefault();
setTimeout(() => { setTimeout(() => {
moveable.dragStart(event.inputEvent); moveable.dragStart(event.inputEvent);
}); });
@ -219,7 +236,7 @@ export class Scene {
render() { render() {
return ( return (
<div key={this.revId} className={this.styles.wrap} style={this.style} ref={this.initMoveable}> <div key={this.revId} className={this.styles.wrap} style={this.style} ref={this.setRef}>
{this.root.render()} {this.root.render()}
</div> </div>
); );

@ -29,7 +29,7 @@ import { DashboardLoading } from '../components/DashboardLoading/DashboardLoadin
import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed'; import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed';
import { DashboardPrompt } from '../components/DashboardPrompt/DashboardPrompt'; import { DashboardPrompt } from '../components/DashboardPrompt/DashboardPrompt';
import classnames from 'classnames'; import classnames from 'classnames';
import { PanelEditExitedEvent } from 'app/types/events'; import { PanelEditEnteredEvent, PanelEditExitedEvent } from 'app/types/events';
import { liveTimer } from '../dashgrid/liveTimer'; import { liveTimer } from '../dashgrid/liveTimer';
export interface DashboardPageRouteParams { export interface DashboardPageRouteParams {
@ -178,6 +178,9 @@ export class UnthemedDashboardPage extends PureComponent<Props, State> {
// entering edit mode // entering edit mode
if (this.state.editPanel && !prevState.editPanel) { if (this.state.editPanel && !prevState.editPanel) {
dashboardWatcher.setEditingState(true); 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 // leaving edit mode

@ -1,8 +1,8 @@
import { Component } from 'react'; import { Component } from 'react';
import { CoreApp, PanelProps } from '@grafana/data'; import { PanelProps } from '@grafana/data';
import { PanelOptions } from './models.gen'; import { PanelOptions } from './models.gen';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { PanelEditExitedEvent } from 'app/types/events'; import { PanelEditEnteredEvent, PanelEditExitedEvent } from 'app/types/events';
import { CanvasGroupOptions } from 'app/features/canvas'; import { CanvasGroupOptions } from 'app/features/canvas';
import { Scene } from 'app/features/canvas/runtime/scene'; import { Scene } from 'app/features/canvas/runtime/scene';
import { PanelContext, PanelContextRoot } from '@grafana/ui'; import { PanelContext, PanelContextRoot } from '@grafana/ui';
@ -41,6 +41,14 @@ export class CanvasPanel extends Component<Props, State> {
this.scene.updateSize(props.width, props.height); this.scene.updateSize(props.width, props.height);
this.scene.updateData(props.data); 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.subs.add(
this.props.eventBus.subscribe(PanelEditExitedEvent, (evt) => { this.props.eventBus.subscribe(PanelEditExitedEvent, (evt) => {
if (this.props.id === evt.payload) { if (this.props.id === evt.payload) {
@ -52,7 +60,7 @@ export class CanvasPanel extends Component<Props, State> {
componentDidMount() { componentDidMount() {
this.panelContext = this.context as PanelContext; this.panelContext = this.context as PanelContext;
if (this.panelContext.onInstanceStateChange && this.panelContext.app === CoreApp.PanelEditor) { if (this.panelContext.onInstanceStateChange) {
this.panelContext.onInstanceStateChange({ this.panelContext.onInstanceStateChange({
scene: this.scene, scene: this.scene,
layer: this.scene.root, layer: this.scene.root,

@ -201,6 +201,11 @@ export class AnnotationQueryFinished extends BusEventWithPayload<AnnotationQuery
export class TimeRangeUpdatedEvent extends BusEventWithPayload<TimeRange> { export class TimeRangeUpdatedEvent extends BusEventWithPayload<TimeRange> {
static type = 'time-range-updated'; static type = 'time-range-updated';
} }
export class PanelEditEnteredEvent extends BusEventWithPayload<number> {
static type = 'panel-edit-started';
}
export class PanelEditExitedEvent extends BusEventWithPayload<number> { export class PanelEditExitedEvent extends BusEventWithPayload<number> {
static type = 'panel-edit-finished'; static type = 'panel-edit-finished';
} }

Loading…
Cancel
Save