diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx index 946a7d19841..a6775cfde15 100644 --- a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx +++ b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; import { css, cx } from 'emotion'; -import { GrafanaTheme } from '@grafana/data'; +import { GrafanaTheme, PanelData, LoadingState, DefaultTimeRange, PanelEvents } from '@grafana/data'; import { stylesFactory, Forms } from '@grafana/ui'; import config from 'app/core/config'; @@ -12,6 +12,7 @@ import SplitPane from 'react-split-pane'; import { StoreState } from '../../../../types/store'; import { connect } from 'react-redux'; import { updateLocation } from '../../../../core/reducers/location'; +import { Unsubscribable } from 'rxjs'; const getStyles = stylesFactory((theme: GrafanaTheme) => { const resizer = css` @@ -61,15 +62,63 @@ interface Props { } interface State { + pluginLoadedCounter: number; dirtyPanel?: PanelModel; + data: PanelData; } export class PanelEditor extends PureComponent { + querySubscription: Unsubscribable; + + state: State = { + pluginLoadedCounter: 0, + data: { + state: LoadingState.NotStarted, + series: [], + timeRange: DefaultTimeRange, + }, + }; + constructor(props: Props) { super(props); - const { panel } = props; + + // To ensure visualisation settings are re-rendered when plugin has loaded + // panelInitialised event is emmited from PanelChrome + props.panel.events.on(PanelEvents.panelInitialized, () => { + this.setState(state => ({ + pluginLoadedCounter: state.pluginLoadedCounter + 1, + })); + }); + } + + componentDidMount() { + const { panel } = this.props; const dirtyPanel = panel.getEditClone(); - this.state = { dirtyPanel }; + this.setState({ dirtyPanel }); + + // Get data from any pending + panel + .getQueryRunner() + .getData() + .subscribe({ + next: (data: PanelData) => { + this.setState({ data }); + // TODO, cancel???? + }, + }); + + // Listen for queries on the new panel + const queryRunner = dirtyPanel.getQueryRunner(); + this.querySubscription = queryRunner.getData().subscribe({ + next: (data: PanelData) => this.setState({ data }), + }); + } + + componentWillUnmount() { + if (this.querySubscription) { + this.querySubscription.unsubscribe(); + } + //this.cleanUpAngularOptions(); } onPanelUpdate = () => { diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index 613f6cd78ad..32ed6dabb69 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -85,14 +85,19 @@ export class PanelChrome extends PureComponent { }, isFirstLoad: false, }); - } else if (isInEditMode && this.panelHasLastResult()) { - console.log('Reusing results!'); - const lastResult = panel.getQueryRunner().getLastResult(); - if (lastResult) { - this.onDataUpdate(lastResult); + } else { + if (isInEditMode) { + this.querySubscription = panel + .getQueryRunner() + .getData() + .subscribe({ + next: data => this.onDataUpdate(data), + }); + } + + if (!this.wantsQueryExecution) { + this.setState({ isFirstLoad: false }); } - } else if (!this.wantsQueryExecution) { - this.setState({ isFirstLoad: false }); } } @@ -244,11 +249,7 @@ export class PanelChrome extends PureComponent { }; get wantsQueryExecution() { - return !( - this.props.plugin.meta.skipDataQuery || - this.hasPanelSnapshot || - (this.props.isInEditMode && !this.panelHasLastResult()) - ); + return !(this.props.plugin.meta.skipDataQuery || this.hasPanelSnapshot); } onChangeTimeRange = (timeRange: AbsoluteTimeRange) => { diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index 7c353c3ca11..ecc4fb5a33b 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -18,6 +18,7 @@ import config from 'app/core/config'; import { PanelQueryRunner } from './PanelQueryRunner'; import { eventFactory } from '@grafana/data'; +import { take } from 'rxjs/operators'; export const panelAdded = eventFactory('panel-added'); export const panelRemoved = eventFactory('panel-removed'); @@ -349,7 +350,14 @@ export class PanelModel { getEditClone() { const clone = new PanelModel(this.getSaveModel()); - clone.queryRunner = new PanelQueryRunner(this.queryRunner.getLastResult()); + clone.queryRunner = new PanelQueryRunner(); + + // This will send the last result to the new runner + this.getQueryRunner() + .getData() + .pipe(take(1)) + .subscribe(val => clone.queryRunner.pipeDataToSubject(val)); + clone.isNewEdit = true; return clone; }