mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 18:34:52 -06:00
135 lines
4.0 KiB
TypeScript
135 lines
4.0 KiB
TypeScript
import { Component } from 'react';
|
|
import { PanelProps } from '@grafana/data';
|
|
import { PanelOptions } from './models.gen';
|
|
import { Subscription } from 'rxjs';
|
|
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';
|
|
import { ElementState } from 'app/features/canvas/runtime/element';
|
|
import { GroupState } from 'app/features/canvas/runtime/group';
|
|
|
|
interface Props extends PanelProps<PanelOptions> {}
|
|
|
|
interface State {
|
|
refresh: number;
|
|
}
|
|
|
|
export interface InstanceState {
|
|
scene: Scene;
|
|
selected: ElementState[];
|
|
layer: GroupState;
|
|
}
|
|
|
|
export class CanvasPanel extends Component<Props, State> {
|
|
static contextType = PanelContextRoot;
|
|
panelContext: PanelContext = {} as PanelContext;
|
|
|
|
readonly scene: Scene;
|
|
private subs = new Subscription();
|
|
needsReload = false;
|
|
|
|
constructor(props: Props) {
|
|
super(props);
|
|
this.state = {
|
|
refresh: 0,
|
|
};
|
|
|
|
// Only the initial options are ever used.
|
|
// later changes are all controlled by the scene
|
|
this.scene = new Scene(this.props.options.root, this.props.options.inlineEditing, this.onUpdateScene);
|
|
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) {
|
|
this.needsReload = true;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.panelContext = this.context as PanelContext;
|
|
if (this.panelContext.onInstanceStateChange) {
|
|
this.panelContext.onInstanceStateChange({
|
|
scene: this.scene,
|
|
layer: this.scene.root,
|
|
});
|
|
|
|
this.subs.add(
|
|
this.scene.selection.subscribe({
|
|
next: (v) => {
|
|
this.panelContext.onInstanceStateChange!({
|
|
scene: this.scene,
|
|
selected: v,
|
|
layer: this.scene.root,
|
|
});
|
|
},
|
|
})
|
|
);
|
|
}
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this.subs.unsubscribe();
|
|
}
|
|
|
|
// NOTE, all changes to the scene flow through this function
|
|
// even the editor gets current state from the same scene instance!
|
|
onUpdateScene = (root: CanvasGroupOptions) => {
|
|
const { onOptionsChange, options } = this.props;
|
|
onOptionsChange({
|
|
...options,
|
|
root,
|
|
});
|
|
this.setState({ refresh: this.state.refresh + 1 });
|
|
// console.log('send changes', root);
|
|
};
|
|
|
|
shouldComponentUpdate(nextProps: Props) {
|
|
const { width, height, data } = this.props;
|
|
let changed = false;
|
|
|
|
if (width !== nextProps.width || height !== nextProps.height) {
|
|
this.scene.updateSize(nextProps.width, nextProps.height);
|
|
changed = true;
|
|
}
|
|
if (data !== nextProps.data) {
|
|
this.scene.updateData(nextProps.data);
|
|
changed = true;
|
|
}
|
|
|
|
// After editing, the options are valid, but the scene was in a different panel or inline editing mode has changed
|
|
const shouldUpdateSceneAndPanel =
|
|
(this.needsReload && this.props.options !== nextProps.options) ||
|
|
this.props.options.inlineEditing !== nextProps.options.inlineEditing;
|
|
if (shouldUpdateSceneAndPanel) {
|
|
this.needsReload = false;
|
|
this.scene.load(nextProps.options.root, nextProps.options.inlineEditing);
|
|
this.scene.updateSize(nextProps.width, nextProps.height);
|
|
this.scene.updateData(nextProps.data);
|
|
changed = true;
|
|
|
|
if (this.props.options.inlineEditing) {
|
|
this.scene.selecto?.destroy();
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
render() {
|
|
return this.scene.render();
|
|
}
|
|
}
|