From 2e1d45a8756d99c8c5eaaee2f28bb9a22c0b4a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sun, 14 Oct 2018 12:41:09 +0200 Subject: [PATCH] changed DataPanel from HOC to use render props --- public/app/core/components/grafana_app.ts | 2 +- public/app/core/services/angular_loader.ts | 42 ----- .../dashboard/dashgrid/DashboardPanel.tsx | 2 +- .../features/dashboard/dashgrid/DataPanel.tsx | 151 ++++++++++-------- .../dashboard/dashgrid/PanelChrome.tsx | 24 +-- .../dashboard/dashgrid/QueriesTab.tsx | 2 +- public/app/plugins/panel/graph2/module.tsx | 10 +- 7 files changed, 106 insertions(+), 127 deletions(-) delete mode 100644 public/app/core/services/angular_loader.ts diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index b513bed3ef0..a244a5393d1 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -9,7 +9,7 @@ import Drop from 'tether-drop'; import colors from 'app/core/utils/colors'; import { BackendSrv, setBackendSrv } from 'app/core/services/backend_srv'; import { DatasourceSrv } from 'app/features/plugins/datasource_srv'; -import { AngularLoader, setAngularLoader } from 'app/core/services/angular_loader'; +import { AngularLoader, setAngularLoader } from 'app/core/services/AngularLoader'; import { configureStore } from 'app/store/configureStore'; export class GrafanaCtrl { diff --git a/public/app/core/services/angular_loader.ts b/public/app/core/services/angular_loader.ts deleted file mode 100644 index e3a7dec4351..00000000000 --- a/public/app/core/services/angular_loader.ts +++ /dev/null @@ -1,42 +0,0 @@ -import angular from 'angular'; -import coreModule from 'app/core/core_module'; -import _ from 'lodash'; - -export interface AngularComponent { - destroy(); -} - -export class AngularLoader { - /** @ngInject */ - constructor(private $compile, private $rootScope) {} - - load(elem, scopeProps, template): AngularComponent { - const scope = this.$rootScope.$new(); - - _.assign(scope, scopeProps); - - const compiledElem = this.$compile(template)(scope); - const rootNode = angular.element(elem); - rootNode.append(compiledElem); - - return { - destroy: () => { - scope.$destroy(); - compiledElem.remove(); - }, - }; - } -} - -coreModule.service('angularLoader', AngularLoader); - -let angularLoaderInstance: AngularLoader; - -export function setAngularLoader(pl: AngularLoader) { - angularLoaderInstance = pl; -} - -// away to access it from react -export function getAngularLoader(): AngularLoader { - return angularLoaderInstance; -} diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx index 039473a7a30..7dd8a06996d 100644 --- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx @@ -2,7 +2,7 @@ import React from 'react'; import config from 'app/core/config'; import { PanelModel } from '../panel_model'; import { DashboardModel } from '../dashboard_model'; -import { getAngularLoader, AngularComponent } from 'app/core/services/angular_loader'; +import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader'; import { DashboardRow } from './DashboardRow'; import { AddPanelPanel } from './AddPanelPanel'; import { importPluginModule } from 'app/features/plugins/plugin_loader'; diff --git a/public/app/features/dashboard/dashgrid/DataPanel.tsx b/public/app/features/dashboard/dashgrid/DataPanel.tsx index bce4c69bb69..d19d6b10e2e 100644 --- a/public/app/features/dashboard/dashgrid/DataPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DataPanel.tsx @@ -1,81 +1,92 @@ -import React, { Component, ComponentClass } from 'react'; +// Library +import React, { Component } from 'react'; -export interface OuterProps { - type: string; +interface RenderProps { + loading: LoadingState; + data: any; +} + +export interface Props { + datasource: string | null; queries: any[]; - isVisible: boolean; + children: (r: RenderProps) => JSX.Element; } -export interface PanelProps extends OuterProps { - data: any[]; +export interface State { + isFirstLoad: boolean; + loading: LoadingState; + data: any; } -export interface DataPanel extends ComponentClass {} - -interface State { - isLoading: boolean; - data: any[]; +export enum LoadingState { + NotStarted = 'NotStarted', + Loading = 'Loading', + Done = 'Done', + Error = 'Error', } -export const DataPanelWrapper = (ComposedComponent: ComponentClass) => { - class Wrapper extends Component { - static defaultProps = { - isVisible: true, +export interface PanelProps extends RenderProps {} + +export class DataPanel extends Component { + constructor(props: Props) { + super(props); + + this.state = { + loading: LoadingState.NotStarted, + data: [], + isFirstLoad: true, }; - - constructor(props: OuterProps) { - super(props); - - this.state = { - isLoading: false, - data: [], - }; - } - - componentDidMount() { - console.log('data panel mount'); - this.issueQueries(); - } - - issueQueries = async () => { - const { isVisible } = this.props; - - if (!isVisible) { - return; - } - - this.setState({ isLoading: true }); - - await new Promise(resolve => { - setTimeout(() => { - this.setState({ isLoading: false, data: [{ value: 10 }] }); - }, 500); - }); - }; - - render() { - const { data, isLoading } = this.state; - console.log('data panel render'); - - if (!data.length) { - return ( -
-

No Data

-
- ); - } - - if (isLoading) { - return ( -
-

Loading

-
- ); - } - - return ; - } } - return Wrapper; -}; + componentDidMount() { + console.log('DataPanel mount'); + this.issueQueries(); + } + + issueQueries = async () => { + this.setState({ loading: LoadingState.Loading }); + + await new Promise(resolve => { + setTimeout(() => { + this.setState({ loading: LoadingState.Done, data: [{ value: 10 }], isFirstLoad: false }); + }, 500); + }); + }; + + render() { + const { data, loading, isFirstLoad } = this.state; + console.log('data panel render'); + + if (isFirstLoad && loading === LoadingState.Loading) { + return ( +
+

Loading

+
+ ); + } + + return ( + <> + {this.loadingSpinner} + {this.props.children({ + data, + loading, + })} + + ); + } + + private get loadingSpinner(): JSX.Element { + const { loading } = this.state; + + if (loading === LoadingState.Loading) { + return ( +
+ +
+ ); + } + + return null; + } +} diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index 73208c34130..a3e4b4eedc8 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -2,7 +2,7 @@ import React, { ComponentClass } from 'react'; import { PanelModel } from '../panel_model'; import { DashboardModel } from '../dashboard_model'; import { PanelHeader } from './PanelHeader'; -import { DataPanel, PanelProps, DataPanelWrapper } from './DataPanel'; +import { DataPanel, PanelProps } from './DataPanel'; export interface Props { panel: PanelModel; @@ -12,9 +12,6 @@ export interface Props { interface State {} -// cache DataPanel wrapper components -const dataPanels: { [s: string]: DataPanel } = {}; - export class PanelChrome extends React.Component { panelComponent: DataPanel; @@ -23,20 +20,25 @@ export class PanelChrome extends React.Component { } render() { - const { type } = this.props.panel; + const { datasource, targets } = this.props.panel; + const PanelComponent = this.props.component; - let PanelComponent = dataPanels[type]; - - if (!PanelComponent) { - PanelComponent = dataPanels[type] = DataPanelWrapper(this.props.component); - } + // if (!PanelComponent) { + // PanelComponent = dataPanels[type] = DataPanelWrapper(this.props.component); + // } console.log('PanelChrome render', PanelComponent); return (
-
{}
+
+ + {({ loading, data }) => { + return ; + }} + +
); } diff --git a/public/app/features/dashboard/dashgrid/QueriesTab.tsx b/public/app/features/dashboard/dashgrid/QueriesTab.tsx index 21159df00aa..671075b8c47 100644 --- a/public/app/features/dashboard/dashgrid/QueriesTab.tsx +++ b/public/app/features/dashboard/dashgrid/QueriesTab.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { PanelModel } from '../panel_model'; import { DashboardModel } from '../dashboard_model'; -import { getAngularLoader, AngularComponent } from 'app/core/services/angular_loader'; +import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader'; interface Props { panel: PanelModel; diff --git a/public/app/plugins/panel/graph2/module.tsx b/public/app/plugins/panel/graph2/module.tsx index a0df192f9d8..79bf1890bae 100644 --- a/public/app/plugins/panel/graph2/module.tsx +++ b/public/app/plugins/panel/graph2/module.tsx @@ -1,7 +1,15 @@ import React, { PureComponent } from 'react'; import { PanelProps } from 'app/features/dashboard/dashgrid/DataPanel'; -export class Graph2 extends PureComponent { +interface Options { + showBars: boolean; +} + +interface Props extends PanelProps { + options: Options; +} + +export class Graph2 extends PureComponent { constructor(props) { super(props); }