changed DataPanel from HOC to use render props

This commit is contained in:
Torkel Ödegaard 2018-10-14 12:41:09 +02:00
parent 0662b5f962
commit 2e1d45a875
7 changed files with 106 additions and 127 deletions

View File

@ -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 {

View File

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

View File

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

View File

@ -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<OuterProps> {}
interface State {
isLoading: boolean;
data: any[];
export enum LoadingState {
NotStarted = 'NotStarted',
Loading = 'Loading',
Done = 'Done',
Error = 'Error',
}
export const DataPanelWrapper = (ComposedComponent: ComponentClass<PanelProps>) => {
class Wrapper extends Component<OuterProps, State> {
static defaultProps = {
isVisible: true,
export interface PanelProps extends RenderProps {}
export class DataPanel extends Component<Props, State> {
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 (
<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} />;
}
}
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 (
<div className="loading">
<p>Loading</p>
</div>
);
}
return (
<>
{this.loadingSpinner}
{this.props.children({
data,
loading,
})}
</>
);
}
private get loadingSpinner(): JSX.Element {
const { loading } = this.state;
if (loading === LoadingState.Loading) {
return (
<div className="panel__loading">
<i className="fa fa-spinner fa-spin" />
</div>
);
}
return null;
}
}

View File

@ -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<Props, State> {
panelComponent: DataPanel;
@ -23,20 +20,25 @@ export class PanelChrome extends React.Component<Props, State> {
}
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 (
<div className="panel-container">
<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>
);
}

View File

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

View File

@ -1,7 +1,15 @@
import React, { PureComponent } from 'react';
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) {
super(props);
}