New panel edit: don't query when entering edit mode (#21921)

* First attempt

* Save confirmation with discard option, reusing queriess a little bit differently

* simplify cloning panels and restoring last results in panel query runner

* Remove save button

* Update public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx

* Exit/discard buttons

* Update snaps

* Review comments

* Fix lint
This commit is contained in:
Dominik Prokop
2020-02-07 14:59:04 +01:00
committed by GitHub
parent 4b271f27fb
commit 9b6a843177
11 changed files with 185 additions and 37 deletions

View File

@@ -35,13 +35,23 @@ interface Props {
title: string; title: string;
body: string; body: string;
confirmText: string; confirmText: string;
dismissText?: string;
icon?: IconType; icon?: IconType;
onConfirm(): void; onConfirm(): void;
onDismiss(): void; onDismiss(): void;
} }
export const ConfirmModal: FC<Props> = ({ isOpen, title, body, confirmText, icon, onConfirm, onDismiss }) => { export const ConfirmModal: FC<Props> = ({
isOpen,
title,
body,
confirmText,
dismissText = 'Cancel',
icon,
onConfirm,
onDismiss,
}) => {
const theme = useContext(ThemeContext); const theme = useContext(ThemeContext);
const styles = getStyles(theme); const styles = getStyles(theme);
@@ -54,7 +64,7 @@ export const ConfirmModal: FC<Props> = ({ isOpen, title, body, confirmText, icon
{confirmText} {confirmText}
</Button> </Button>
<Button variant="inverse" onClick={onDismiss}> <Button variant="inverse" onClick={onDismiss}>
Cancel {dismissText}
</Button> </Button>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
import { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
interface Props { interface Props {
@@ -27,6 +27,10 @@ export class Portal extends PureComponent<Props> {
} }
render() { render() {
return ReactDOM.createPortal(this.props.children, this.node); // Default z-index is high to make sure
return ReactDOM.createPortal(
<div style={{ zIndex: 1051, position: 'relative' }}>{this.props.children}</div>,
this.node
);
} }
} }

View File

@@ -1,13 +1,16 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { css } from 'emotion'; import { css } from 'emotion';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
import { stylesFactory } from '@grafana/ui'; import { stylesFactory, Forms } from '@grafana/ui';
import config from 'app/core/config'; import config from 'app/core/config';
import { PanelModel } from '../../state/PanelModel'; import { PanelModel } from '../../state/PanelModel';
import { DashboardModel } from '../../state/DashboardModel'; import { DashboardModel } from '../../state/DashboardModel';
import { DashboardPanel } from '../../dashgrid/DashboardPanel'; import { DashboardPanel } from '../../dashgrid/DashboardPanel';
import { QueriesTab } from '../../panel_editor/QueriesTab'; import { QueriesTab } from '../../panel_editor/QueriesTab';
import { StoreState } from '../../../../types/store';
import { connect } from 'react-redux';
import { updateLocation } from '../../../../core/reducers/location';
const getStyles = stylesFactory((theme: GrafanaTheme) => ({ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
wrapper: css` wrapper: css`
@@ -47,6 +50,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
interface Props { interface Props {
dashboard: DashboardModel; dashboard: DashboardModel;
panel: PanelModel; panel: PanelModel;
updateLocation: typeof updateLocation;
} }
interface State { interface State {
@@ -54,15 +58,35 @@ interface State {
} }
export class PanelEditor extends PureComponent<Props, State> { export class PanelEditor extends PureComponent<Props, State> {
state: State = {}; constructor(props: Props) {
super(props);
componentDidMount() { const { panel } = props;
const { panel } = this.props; const dirtyPanel = panel.getEditClone();
const dirtyPanel = new PanelModel(panel.getSaveModel()); this.state = { dirtyPanel };
this.setState({ dirtyPanel });
} }
onPanelUpdate = () => {
const { dirtyPanel } = this.state;
const { dashboard } = this.props;
dashboard.updatePanel(dirtyPanel);
};
onPanelExit = () => {
const { updateLocation } = this.props;
this.onPanelUpdate();
updateLocation({
query: { editPanel: null },
partial: true,
});
};
onDiscard = () => {
this.props.updateLocation({
query: { editPanel: null },
partial: true,
});
};
render() { render() {
const { dashboard } = this.props; const { dashboard } = this.props;
const { dirtyPanel } = this.state; const { dirtyPanel } = this.state;
@@ -74,23 +98,41 @@ export class PanelEditor extends PureComponent<Props, State> {
} }
return ( return (
<div className={styles.wrapper}> <>
<div className={styles.leftPane}> <div className={styles.wrapper}>
<div className={styles.leftPaneViz}> <div className={styles.leftPane}>
<DashboardPanel <div className={styles.leftPaneViz}>
dashboard={dashboard} <DashboardPanel
panel={dirtyPanel} dashboard={dashboard}
isEditing={false} panel={dirtyPanel}
isFullscreen={false} isEditing={false}
isInView={true} isInEditMode
/> isFullscreen={false}
isInView={true}
/>
</div>
<div className={styles.leftPaneData}>
<QueriesTab panel={dirtyPanel} dashboard={dashboard} />
</div>
</div> </div>
<div className={styles.leftPaneData}> <div className={styles.rightPane}>
<QueriesTab panel={dirtyPanel} dashboard={dashboard} />; <Forms.Button variant="destructive" onClick={this.onDiscard}>
Discard
</Forms.Button>
<Forms.Button onClick={this.onPanelExit}>Exit</Forms.Button>
</div> </div>
</div> </div>
<div className={styles.rightPane}>Visualization settings</div> </>
</div>
); );
} }
} }
const mapStateToProps = (state: StoreState) => ({
location: state.location,
});
const mapDispatchToProps = {
updateLocation,
};
export default connect(mapStateToProps, mapDispatchToProps)(PanelEditor);

View File

@@ -12,8 +12,8 @@ import { DashboardGrid } from '../dashgrid/DashboardGrid';
import { DashNav } from '../components/DashNav'; import { DashNav } from '../components/DashNav';
import { SubMenu } from '../components/SubMenu'; import { SubMenu } from '../components/SubMenu';
import { DashboardSettings } from '../components/DashboardSettings'; import { DashboardSettings } from '../components/DashboardSettings';
import { PanelEditor } from '../components/PanelEditor'; import PanelEditor from '../components/PanelEditor/PanelEditor';
import { CustomScrollbar, Alert } from '@grafana/ui'; import { CustomScrollbar, Alert, Portal } from '@grafana/ui';
// Redux // Redux
import { initDashboard } from '../state/initDashboard'; import { initDashboard } from '../state/initDashboard';
@@ -325,7 +325,11 @@ export class DashboardPage extends PureComponent<Props, State> {
</div> </div>
{inspectPanel && <PanelInspector dashboard={dashboard} panel={inspectPanel} selectedTab={inspectTab} />} {inspectPanel && <PanelInspector dashboard={dashboard} panel={inspectPanel} selectedTab={inspectTab} />}
{editPanel && <PanelEditor dashboard={dashboard} panel={editPanel} />} {editPanel && (
<Portal>
<PanelEditor dashboard={dashboard} panel={editPanel} />
</Portal>
)}
</div> </div>
); );
} }

View File

@@ -66,6 +66,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
"y": 0, "y": 0,
}, },
"id": 1, "id": 1,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -93,6 +94,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }
@@ -179,6 +181,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
"y": 0, "y": 0,
}, },
"id": 1, "id": 1,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -206,6 +209,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }
@@ -271,6 +275,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
"y": 0, "y": 0,
}, },
"id": 1, "id": 1,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -298,6 +303,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }
@@ -395,6 +401,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"y": 0, "y": 0,
}, },
"id": 1, "id": 1,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -422,6 +429,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }
@@ -506,6 +514,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"y": 0, "y": 0,
}, },
"id": 1, "id": 1,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -533,6 +542,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }
@@ -601,6 +611,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"y": 0, "y": 0,
}, },
"id": 1, "id": 1,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -628,6 +639,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }
@@ -693,6 +705,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"y": 0, "y": 0,
}, },
"id": 1, "id": 1,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -720,6 +733,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }

View File

@@ -22,6 +22,7 @@ export interface Props {
panel: PanelModel; panel: PanelModel;
dashboard: DashboardModel; dashboard: DashboardModel;
isEditing: boolean; isEditing: boolean;
isInEditMode?: boolean;
isFullscreen: boolean; isFullscreen: boolean;
isInView: boolean; isInView: boolean;
} }
@@ -130,7 +131,7 @@ export class DashboardPanel extends PureComponent<Props, State> {
}; };
renderPanel() { renderPanel() {
const { dashboard, panel, isFullscreen, isInView } = this.props; const { dashboard, panel, isFullscreen, isInView, isInEditMode } = this.props;
const { plugin } = this.state; const { plugin } = this.state;
if (plugin.angularPanelCtrl) { if (plugin.angularPanelCtrl) {
@@ -151,6 +152,7 @@ export class DashboardPanel extends PureComponent<Props, State> {
dashboard={dashboard} dashboard={dashboard}
isFullscreen={isFullscreen} isFullscreen={isFullscreen}
isInView={isInView} isInView={isInView}
isInEditMode={isInEditMode}
width={width} width={width}
height={height} height={height}
/> />

View File

@@ -35,6 +35,7 @@ export interface Props {
plugin: PanelPlugin; plugin: PanelPlugin;
isFullscreen: boolean; isFullscreen: boolean;
isInView: boolean; isInView: boolean;
isInEditMode?: boolean;
width: number; width: number;
height: number; height: number;
} }
@@ -69,7 +70,7 @@ export class PanelChrome extends PureComponent<Props, State> {
} }
componentDidMount() { componentDidMount() {
const { panel, dashboard } = this.props; const { panel, dashboard, isInEditMode } = this.props;
panel.events.on(PanelEvents.refresh, this.onRefresh); panel.events.on(PanelEvents.refresh, this.onRefresh);
panel.events.on(PanelEvents.render, this.onRender); panel.events.on(PanelEvents.render, this.onRender);
dashboard.panelInitialized(this.props.panel); dashboard.panelInitialized(this.props.panel);
@@ -84,6 +85,12 @@ export class PanelChrome extends PureComponent<Props, State> {
}, },
isFirstLoad: false, isFirstLoad: false,
}); });
} else if (isInEditMode && this.panelHasLastResult()) {
console.log('Reusing results!');
const lastResult = panel.getQueryRunner().getLastResult();
if (lastResult) {
this.onDataUpdate(lastResult);
}
} else if (!this.wantsQueryExecution) { } else if (!this.wantsQueryExecution) {
this.setState({ isFirstLoad: false }); this.setState({ isFirstLoad: false });
} }
@@ -160,8 +167,8 @@ export class PanelChrome extends PureComponent<Props, State> {
} }
onRefresh = () => { onRefresh = () => {
// debugger
const { panel, isInView, width } = this.props; const { panel, isInView, width } = this.props;
if (!isInView) { if (!isInView) {
console.log('Refresh when panel is visible', panel.id); console.log('Refresh when panel is visible', panel.id);
this.setState({ refreshWhenInView: true }); this.setState({ refreshWhenInView: true });
@@ -232,8 +239,16 @@ export class PanelChrome extends PureComponent<Props, State> {
return panel.snapshotData && panel.snapshotData.length; return panel.snapshotData && panel.snapshotData.length;
} }
panelHasLastResult = () => {
return !!this.props.panel.getQueryRunner().getLastResult();
};
get wantsQueryExecution() { get wantsQueryExecution() {
return !(this.props.plugin.meta.skipDataQuery || this.hasPanelSnapshot); return !(
this.props.plugin.meta.skipDataQuery ||
this.hasPanelSnapshot ||
(this.props.isInEditMode && !this.panelHasLastResult())
);
} }
onChangeTimeRange = (timeRange: AbsoluteTimeRange) => { onChangeTimeRange = (timeRange: AbsoluteTimeRange) => {

View File

@@ -142,6 +142,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 1, "id": 1,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -168,6 +169,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 2, "id": 2,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -194,6 +196,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 3, "id": 3,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -220,6 +223,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 4, "id": 4,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -247,6 +251,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }
@@ -269,6 +274,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 1, "id": 1,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -379,6 +385,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 1, "id": 1,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -405,6 +412,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 2, "id": 2,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -431,6 +439,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 3, "id": 3,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -457,6 +466,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 4, "id": 4,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -484,6 +494,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }
@@ -506,6 +517,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 2, "id": 2,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -616,6 +628,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 1, "id": 1,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -642,6 +655,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 2, "id": 2,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -668,6 +682,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 3, "id": 3,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -694,6 +709,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 4, "id": 4,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -721,6 +737,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }
@@ -743,6 +760,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 3, "id": 3,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -853,6 +871,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 1, "id": 1,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -879,6 +898,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 2, "id": 2,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -905,6 +925,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 3, "id": 3,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -931,6 +952,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 4, "id": 4,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",
@@ -958,6 +980,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"timezone": "", "timezone": "",
"title": "My dashboard", "title": "My dashboard",
"uid": null, "uid": null,
"updatePanel": [Function],
"version": 0, "version": 0,
} }
} }
@@ -980,6 +1003,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
"id": 4, "id": 4,
"isInView": false, "isInView": false,
"restoreModel": [Function],
"targets": Array [ "targets": Array [
Object { Object {
"refId": "A", "refId": "A",

View File

@@ -239,7 +239,9 @@ export class DashboardModel {
panelInitialized(panel: PanelModel) { panelInitialized(panel: PanelModel) {
panel.initialized(); panel.initialized();
if (!this.otherPanelInFullscreen(panel)) { // In new panel edit there is no need to trigger refresh as editor retrieves last results from the query runner
// as an initial value
if (!this.otherPanelInFullscreen(panel) && !panel.isNewEdit) {
panel.refresh(); panel.refresh();
} }
} }
@@ -947,4 +949,16 @@ export class DashboardModel {
panel.render(); panel.render();
} }
} }
updatePanel = (panelModel: PanelModel) => {
let index = 0;
for (const panel of this.panels) {
if (panel.id === panelModel.id) {
this.panels[index].restoreModel(panelModel.getSaveModel());
this.panels[index].getQueryRunner().pipeDataToSubject(panelModel.getQueryRunner().getLastResult());
break;
}
index++;
}
};
} }

View File

@@ -40,6 +40,7 @@ const notPersistedProperties: { [str: string]: boolean } = {
cachedPluginOptions: true, cachedPluginOptions: true,
plugin: true, plugin: true,
queryRunner: true, queryRunner: true,
restoreModel: true,
}; };
// For angular panels we need to clean up properties when changing type // For angular panels we need to clean up properties when changing type
@@ -137,11 +138,14 @@ export class PanelModel {
constructor(model: any) { constructor(model: any) {
this.events = new Emitter(); this.events = new Emitter();
// should not be part of defaults as defaults are removed in save model and // should not be part of defaults as defaults are removed in save model and
// this should not be removed in save model as exporter needs to templatize it // this should not be removed in save model as exporter needs to templatize it
this.datasource = null; this.datasource = null;
this.restoreModel(model);
}
/** Given a persistened PanelModel restores property values */
restoreModel = (model: any) => {
// copy properties from persisted model // copy properties from persisted model
for (const property in model) { for (const property in model) {
(this as any)[property] = model[property]; (this as any)[property] = model[property];
@@ -152,7 +156,7 @@ export class PanelModel {
// queries must have refId // queries must have refId
this.ensureQueryIds(); this.ensureQueryIds();
} };
ensureQueryIds() { ensureQueryIds() {
if (this.targets && _.isArray(this.targets)) { if (this.targets && _.isArray(this.targets)) {
@@ -343,6 +347,13 @@ export class PanelModel {
}); });
} }
getEditClone() {
const clone = new PanelModel(this.getSaveModel());
clone.queryRunner = new PanelQueryRunner(this.queryRunner.getLastResult());
clone.isNewEdit = true;
return clone;
}
getQueryRunner(): PanelQueryRunner { getQueryRunner(): PanelQueryRunner {
if (!this.queryRunner) { if (!this.queryRunner) {
this.queryRunner = new PanelQueryRunner(); this.queryRunner = new PanelQueryRunner();

View File

@@ -56,8 +56,11 @@ export class PanelQueryRunner {
private transformations?: DataTransformerConfig[]; private transformations?: DataTransformerConfig[];
private lastResult?: PanelData; private lastResult?: PanelData;
constructor() { constructor(data?: PanelData) {
this.subject = new ReplaySubject(1); this.subject = new ReplaySubject(1);
if (data) {
this.pipeDataToSubject(data);
}
} }
/** /**
@@ -169,6 +172,11 @@ export class PanelQueryRunner {
}); });
} }
pipeDataToSubject = (data: PanelData) => {
this.subject.next(data);
this.lastResult = data;
};
setTransformations(transformations?: DataTransformerConfig[]) { setTransformations(transformations?: DataTransformerConfig[]) {
this.transformations = transformations; this.transformations = transformations;
} }