NewPanelEditor: Angular panel options, and angular component state to redux major change (#22448)

* NewPanelEdit: Added angular options to new panel editor and started looking and angular component state

* Moved angular component state to redux

* Close to working 100%

* Think everything is working

* AlertTab: Alert tab now gets angularComponent from redux

* Fixed panel menu access to angular panel component

* Added new tests

* Fixed unit test

* Fixed strict null errors

* Fixed typescript issues

* fixed issues
This commit is contained in:
Torkel Ödegaard
2020-02-28 11:04:40 +01:00
committed by GitHub
parent 60dbf72820
commit c002a39456
27 changed files with 464 additions and 263 deletions

View File

@@ -160,8 +160,13 @@ export class DashboardPanelUnconnected extends PureComponent<Props, State> {
}
const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state, props) => {
const panelState = state.dashboard.panels[props.panel.id];
if (!panelState) {
return { plugin: null };
}
return {
plugin: state.plugins.panels[props.panel.type],
plugin: panelState.plugin,
};
};

View File

@@ -2,16 +2,22 @@
import React, { PureComponent } from 'react';
import classNames from 'classnames';
import { Unsubscribable } from 'rxjs';
import { connect, MapStateToProps, MapDispatchToProps } from 'react-redux';
// Components
import { PanelHeader } from './PanelHeader/PanelHeader';
// Utils & Services
import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
import { getAngularLoader } from '@grafana/runtime';
import { getAngularLoader, AngularComponent } from '@grafana/runtime';
import { setPanelAngularComponent } from '../state/reducers';
// Types
import { DashboardModel, PanelModel } from '../state';
import { StoreState } from 'app/types';
import { LoadingState, DefaultTimeRange, PanelData, PanelPlugin, PanelEvents } from '@grafana/data';
export interface Props {
interface OwnProps {
panel: PanelModel;
dashboard: DashboardModel;
plugin: PanelPlugin;
@@ -21,6 +27,16 @@ export interface Props {
height: number;
}
interface ConnectedProps {
angularComponent: AngularComponent;
}
interface DispatchProps {
setPanelAngularComponent: typeof setPanelAngularComponent;
}
export type Props = OwnProps & ConnectedProps & DispatchProps;
export interface State {
data: PanelData;
errorMessage?: string;
@@ -36,7 +52,7 @@ interface AngularScopeProps {
};
}
export class PanelChromeAngular extends PureComponent<Props, State> {
export class PanelChromeAngularUnconnected extends PureComponent<Props, State> {
element: HTMLElement | null = null;
timeSrv: TimeSrv = getTimeSrv();
scopeProps?: AngularScopeProps;
@@ -127,10 +143,10 @@ export class PanelChromeAngular extends PureComponent<Props, State> {
}
loadAngularPanel() {
const { panel, dashboard, height, width } = this.props;
const { panel, dashboard, height, width, setPanelAngularComponent } = this.props;
// if we have no element or already have loaded the panel return
if (!this.element || panel.angularPanel) {
if (!this.element) {
return;
}
@@ -143,19 +159,23 @@ export class PanelChromeAngular extends PureComponent<Props, State> {
size: { width, height },
};
// compile angular template and get back handle to scope
panel.setAngularPanel(loader.load(this.element, this.scopeProps, template));
setPanelAngularComponent({
panelId: panel.id,
angularComponent: loader.load(this.element, this.scopeProps, template),
});
// need to to this every time we load an angular as all events are unsubscribed when panel is destroyed
this.subscribeToRenderEvent();
}
cleanUpAngularPanel() {
const { panel } = this.props;
const { angularComponent, setPanelAngularComponent, panel } = this.props;
if (panel.angularPanel) {
panel.setAngularPanel(undefined);
if (angularComponent) {
angularComponent.destroy();
}
setPanelAngularComponent({ panelId: panel.id, angularComponent: null });
}
hasOverlayHeader() {
@@ -176,7 +196,7 @@ export class PanelChromeAngular extends PureComponent<Props, State> {
}
render() {
const { dashboard, panel, isFullscreen, plugin } = this.props;
const { dashboard, panel, isFullscreen, plugin, angularComponent } = this.props;
const { errorMessage, data, alertState } = this.state;
const { transparent } = panel;
@@ -203,6 +223,7 @@ export class PanelChromeAngular extends PureComponent<Props, State> {
title={panel.title}
description={panel.description}
scopedVars={panel.scopedVars}
angularComponent={angularComponent}
links={panel.links}
error={errorMessage}
isFullscreen={isFullscreen}
@@ -215,3 +236,13 @@ export class PanelChromeAngular extends PureComponent<Props, State> {
);
}
}
const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state, props) => {
return {
angularComponent: state.dashboard.panels[props.panel.id].angularComponent,
};
};
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = { setPanelAngularComponent };
export const PanelChromeAngular = connect(mapStateToProps, mapDispatchToProps)(PanelChromeAngularUnconnected);

View File

@@ -2,6 +2,7 @@ import React, { Component } from 'react';
import classNames from 'classnames';
import { isEqual } from 'lodash';
import { DataLink, ScopedVars, PanelMenuItem } from '@grafana/data';
import { AngularComponent } from '@grafana/runtime';
import { ClickOutsideWrapper } from '@grafana/ui';
import { e2e } from '@grafana/e2e';
@@ -21,6 +22,7 @@ export interface Props {
title?: string;
description?: string;
scopedVars?: ScopedVars;
angularComponent?: AngularComponent;
links?: DataLink[];
error?: string;
isFullscreen: boolean;
@@ -67,8 +69,8 @@ export class PanelHeader extends Component<Props, State> {
event.stopPropagation();
const { dashboard, panel } = this.props;
const menuItems = getPanelMenu(dashboard, panel);
const { dashboard, panel, angularComponent } = this.props;
const menuItems = getPanelMenu(dashboard, panel, angularComponent);
this.setState({
panelMenuOpen: !this.state.panelMenuOpen,

View File

@@ -143,7 +143,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 1,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -171,7 +170,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 2,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -199,7 +197,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 3,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -227,7 +224,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 4,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -278,7 +274,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 1,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -390,7 +385,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 1,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -418,7 +412,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 2,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -446,7 +439,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 3,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -474,7 +466,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 4,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -525,7 +516,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 2,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -637,7 +627,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 1,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -665,7 +654,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 2,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -693,7 +681,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 3,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -721,7 +708,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 4,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -772,7 +758,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 3,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -884,7 +869,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 1,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -912,7 +896,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 2,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -940,7 +923,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 3,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -968,7 +950,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 4,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",
@@ -1019,7 +1000,6 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"id": 4,
"isInView": false,
"options": Object {},
"restoreModel": [Function],
"targets": Array [
Object {
"refId": "A",