Переглянути джерело

changed DataPanel from HOC to use render props

Torkel Ödegaard 7 роки тому
батько
коміт
2e1d45a875

+ 1 - 1
public/app/core/components/grafana_app.ts

@@ -9,7 +9,7 @@ import Drop from 'tether-drop';
 import colors from 'app/core/utils/colors';
 import colors from 'app/core/utils/colors';
 import { BackendSrv, setBackendSrv } from 'app/core/services/backend_srv';
 import { BackendSrv, setBackendSrv } from 'app/core/services/backend_srv';
 import { DatasourceSrv } from 'app/features/plugins/datasource_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';
 import { configureStore } from 'app/store/configureStore';
 
 
 export class GrafanaCtrl {
 export class GrafanaCtrl {

+ 0 - 42
public/app/core/services/angular_loader.ts

@@ -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;
-}

+ 1 - 1
public/app/features/dashboard/dashgrid/DashboardPanel.tsx

@@ -2,7 +2,7 @@ import React from 'react';
 import config from 'app/core/config';
 import config from 'app/core/config';
 import { PanelModel } from '../panel_model';
 import { PanelModel } from '../panel_model';
 import { DashboardModel } from '../dashboard_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 { DashboardRow } from './DashboardRow';
 import { AddPanelPanel } from './AddPanelPanel';
 import { AddPanelPanel } from './AddPanelPanel';
 import { importPluginModule } from 'app/features/plugins/plugin_loader';
 import { importPluginModule } from 'app/features/plugins/plugin_loader';

+ 75 - 64
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;
-  queries: any[];
-  isVisible: boolean;
+interface RenderProps {
+  loading: LoadingState;
+  data: any;
 }
 }
 
 
-export interface PanelProps extends OuterProps {
-  data: any[];
+export interface Props {
+  datasource: string | null;
+  queries: any[];
+  children: (r: RenderProps) => JSX.Element;
 }
 }
 
 
-export interface DataPanel extends ComponentClass<OuterProps> {}
-
-interface State {
-  isLoading: boolean;
-  data: any[];
+export interface State {
+  isFirstLoad: boolean;
+  loading: LoadingState;
+  data: any;
 }
 }
 
 
-export const DataPanelWrapper = (ComposedComponent: ComponentClass<PanelProps>) => {
-  class Wrapper extends Component<OuterProps, State> {
-    static defaultProps = {
-      isVisible: true,
-    };
+export enum LoadingState {
+  NotStarted = 'NotStarted',
+  Loading = 'Loading',
+  Done = 'Done',
+  Error = 'Error',
+}
 
 
-    constructor(props: OuterProps) {
-      super(props);
+export interface PanelProps extends RenderProps {}
 
 
-      this.state = {
-        isLoading: false,
-        data: [],
-      };
-    }
+export class DataPanel extends Component<Props, State> {
+  constructor(props: Props) {
+    super(props);
 
 
-    componentDidMount() {
-      console.log('data panel mount');
-      this.issueQueries();
-    }
+    this.state = {
+      loading: LoadingState.NotStarted,
+      data: [],
+      isFirstLoad: true,
+    };
+  }
 
 
-    issueQueries = async () => {
-      const { isVisible } = this.props;
+  componentDidMount() {
+    console.log('DataPanel mount');
+    this.issueQueries();
+  }
 
 
-      if (!isVisible) {
-        return;
-      }
+  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 (
+        <div className="loading">
+          <p>Loading</p>
+        </div>
+      );
+    }
 
 
-      this.setState({ isLoading: true });
+    return (
+      <>
+        {this.loadingSpinner}
+        {this.props.children({
+          data,
+          loading,
+        })}
+      </>
+    );
+  }
 
 
-      await new Promise(resolve => {
-        setTimeout(() => {
-          this.setState({ isLoading: false, data: [{ value: 10 }] });
-        }, 500);
-      });
-    };
+  private get loadingSpinner(): JSX.Element {
+    const { loading } = this.state;
 
 
-    render() {
-      const { data, isLoading } = this.state;
-      console.log('data panel render');
-
-      if (!data.length) {
-        return (
-          <div className="no-data">
-            <p>No Data</p>
-          </div>
-        );
-      }
-
-      if (isLoading) {
-        return (
-          <div className="loading">
-            <p>Loading</p>
-          </div>
-        );
-      }
-
-      return <ComposedComponent {...this.props} data={data} />;
+    if (loading === LoadingState.Loading) {
+      return (
+        <div className="panel__loading">
+          <i className="fa fa-spinner fa-spin" />
+        </div>
+      );
     }
     }
-  }
 
 
-  return Wrapper;
-};
+    return null;
+  }
+}

+ 13 - 11
public/app/features/dashboard/dashgrid/PanelChrome.tsx

@@ -2,7 +2,7 @@ import React, { ComponentClass } from 'react';
 import { PanelModel } from '../panel_model';
 import { PanelModel } from '../panel_model';
 import { DashboardModel } from '../dashboard_model';
 import { DashboardModel } from '../dashboard_model';
 import { PanelHeader } from './PanelHeader';
 import { PanelHeader } from './PanelHeader';
-import { DataPanel, PanelProps, DataPanelWrapper } from './DataPanel';
+import { DataPanel, PanelProps } from './DataPanel';
 
 
 export interface Props {
 export interface Props {
   panel: PanelModel;
   panel: PanelModel;
@@ -12,9 +12,6 @@ export interface Props {
 
 
 interface State {}
 interface State {}
 
 
-// cache DataPanel wrapper components
-const dataPanels: { [s: string]: DataPanel } = {};
-
 export class PanelChrome extends React.Component<Props, State> {
 export class PanelChrome extends React.Component<Props, State> {
   panelComponent: DataPanel;
   panelComponent: DataPanel;
 
 
@@ -23,20 +20,25 @@ export class PanelChrome extends React.Component<Props, State> {
   }
   }
 
 
   render() {
   render() {
-    const { type } = this.props.panel;
-
-    let PanelComponent = dataPanels[type];
+    const { datasource, targets } = this.props.panel;
+    const PanelComponent = this.props.component;
 
 
-    if (!PanelComponent) {
-      PanelComponent = dataPanels[type] = DataPanelWrapper(this.props.component);
-    }
+    // if (!PanelComponent) {
+    //   PanelComponent = dataPanels[type] = DataPanelWrapper(this.props.component);
+    // }
 
 
     console.log('PanelChrome render', PanelComponent);
     console.log('PanelChrome render', PanelComponent);
 
 
     return (
     return (
       <div className="panel-container">
       <div className="panel-container">
         <PanelHeader panel={this.props.panel} dashboard={this.props.dashboard} />
         <PanelHeader panel={this.props.panel} dashboard={this.props.dashboard} />
-        <div className="panel-content">{<PanelComponent type={'test'} queries={[]} isVisible={true} />}</div>
+        <div className="panel-content">
+          <DataPanel datasource={datasource} queries={targets}>
+            {({ loading, data }) => {
+              return <PanelComponent loading={loading} data={data} />;
+            }}
+          </DataPanel>
+        </div>
       </div>
       </div>
     );
     );
   }
   }

+ 1 - 1
public/app/features/dashboard/dashgrid/QueriesTab.tsx

@@ -1,7 +1,7 @@
 import React from 'react';
 import React from 'react';
 import { PanelModel } from '../panel_model';
 import { PanelModel } from '../panel_model';
 import { DashboardModel } from '../dashboard_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 {
 interface Props {
   panel: PanelModel;
   panel: PanelModel;

+ 9 - 1
public/app/plugins/panel/graph2/module.tsx

@@ -1,7 +1,15 @@
 import React, { PureComponent } from 'react';
 import React, { PureComponent } from 'react';
 import { PanelProps } from 'app/features/dashboard/dashgrid/DataPanel';
 import { PanelProps } from 'app/features/dashboard/dashgrid/DataPanel';
 
 
-export class Graph2 extends PureComponent<PanelProps> {
+interface Options {
+  showBars: boolean;
+}
+
+interface Props extends PanelProps {
+  options: Options;
+}
+
+export class Graph2 extends PureComponent<Props> {
   constructor(props) {
   constructor(props) {
     super(props);
     super(props);
   }
   }