mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Canvas: Improve enter / exit editor UX (#40591)
This commit is contained in:
parent
9c2d70ce0f
commit
7e59b92c8c
@ -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…
Reference in New Issue
Block a user