Browse Source

use render props pattern

Erik Sundell 7 years ago
parent
commit
9b1b4c09f5

+ 25 - 15
public/app/plugins/datasource/stackdriver/components/Aggregations.tsx

@@ -11,8 +11,10 @@ import { StackdriverPicker } from './StackdriverPicker';
 export interface Props {
 export interface Props {
   onChange: (metricDescriptor) => void;
   onChange: (metricDescriptor) => void;
   templateSrv: any;
   templateSrv: any;
-  valueType: string;
-  metricKind: string;
+  metricDescriptor: {
+    valueType: string;
+    metricKind: string;
+  };
   aggregation: {
   aggregation: {
     crossSeriesReducer: string;
     crossSeriesReducer: string;
     alignmentPeriod: string;
     alignmentPeriod: string;
@@ -39,26 +41,31 @@ export class Aggregations extends React.Component<Props, State> {
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {
-    this.setAggOptions(this.props);
+    if (this.props.metricDescriptor !== null) {
+      this.setAggOptions(this.props);
+    }
   }
   }
 
 
   componentWillReceiveProps(nextProps: Props) {
   componentWillReceiveProps(nextProps: Props) {
-    const { valueType, metricKind, aggregation } = this.props;
-    if (
-      nextProps.valueType !== valueType ||
-      nextProps.metricKind !== metricKind ||
-      nextProps.aggregation.groupBys !== aggregation.groupBys
-    ) {
+    // const { metricDescriptor, aggregation } = this.props;
+    // if (
+    //   (metricDescriptor !== null && nextProps.metricDescriptor.valueType !== metricDescriptor.valueType) ||
+    //   nextProps.metricDescriptor.metricKind !== metricDescriptor.metricKind ||
+    //   nextProps.aggregation.groupBys !== aggregation.groupBys
+    // ) {
+    if (nextProps.metricDescriptor !== null) {
       this.setAggOptions(nextProps);
       this.setAggOptions(nextProps);
     }
     }
   }
   }
 
 
-  setAggOptions({ valueType, metricKind, aggregation }) {
+  setAggOptions({ metricDescriptor, aggregation }) {
     const { templateSrv } = this.props;
     const { templateSrv } = this.props;
-    let aggregations = getAggregationOptionsByMetric(valueType, metricKind).map(a => ({
-      ...a,
-      label: a.text,
-    }));
+    let aggregations = getAggregationOptionsByMetric(metricDescriptor.valueType, metricDescriptor.metricKind).map(
+      a => ({
+        ...a,
+        label: a.text,
+      })
+    );
 
 
     if (
     if (
       aggregations.length > 0 &&
       aggregations.length > 0 &&
@@ -75,7 +82,10 @@ export class Aggregations extends React.Component<Props, State> {
   }
   }
 
 
   deselectAggregationOption(notValidOptionValue: string) {
   deselectAggregationOption(notValidOptionValue: string) {
-    const aggregations = getAggregationOptionsByMetric(this.props.valueType, this.props.metricKind);
+    const aggregations = getAggregationOptionsByMetric(
+      this.props.metricDescriptor.valueType,
+      this.props.metricDescriptor.metricKind
+    );
     const newValue = aggregations.find(o => o.value !== notValidOptionValue);
     const newValue = aggregations.find(o => o.value !== notValidOptionValue);
     this.handleAggregationChange(newValue ? newValue.value : '');
     this.handleAggregationChange(newValue ? newValue.value : '');
   }
   }

+ 30 - 11
public/app/plugins/datasource/stackdriver/components/Filter.tsx

@@ -1,5 +1,6 @@
 import React from 'react';
 import React from 'react';
 import _ from 'lodash';
 import _ from 'lodash';
+import appEvents from 'app/core/app_events';
 
 
 import { QueryMeta, Target } from '../types';
 import { QueryMeta, Target } from '../types';
 import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
 import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
@@ -8,14 +9,19 @@ import '../query_filter_ctrl';
 export interface Props {
 export interface Props {
   filtersChanged: (filters) => void;
   filtersChanged: (filters) => void;
   groupBysChanged: (groupBys) => void;
   groupBysChanged: (groupBys) => void;
+  metricType: string;
   templateSrv: any;
   templateSrv: any;
-  labelData: QueryMeta;
-  loading: Promise<any>;
   target: Target;
   target: Target;
   uiSegmentSrv: any;
   uiSegmentSrv: any;
+  datasource: any;
 }
 }
 
 
-export class Filter extends React.Component<Props, any> {
+interface State {
+  labelData: QueryMeta;
+  loading: Promise<any>;
+}
+
+export class Filter extends React.Component<Props, State> {
   element: any;
   element: any;
   component: AngularComponent;
   component: AngularComponent;
 
 
@@ -24,13 +30,13 @@ export class Filter extends React.Component<Props, any> {
       return;
       return;
     }
     }
 
 
-    const { loading, labelData, target, filtersChanged, groupBysChanged } = this.props;
+    const { target, filtersChanged, groupBysChanged } = this.props;
     const loader = getAngularLoader();
     const loader = getAngularLoader();
     const template = '<stackdriver-filter> </stackdriver-filter>';
     const template = '<stackdriver-filter> </stackdriver-filter>';
 
 
     const scopeProps = {
     const scopeProps = {
-      loading,
-      labelData,
+      loading: this.loadLabels.bind(this),
+      labelData: null,
       target,
       target,
       filtersChanged,
       filtersChanged,
       groupBysChanged,
       groupBysChanged,
@@ -39,11 +45,11 @@ export class Filter extends React.Component<Props, any> {
     this.component = loader.load(this.element, scopeProps, template);
     this.component = loader.load(this.element, scopeProps, template);
   }
   }
 
 
-  componentDidUpdate() {
-    const scope = this.component.getScope();
-    scope.loading = _.clone(this.props.loading);
-    scope.labelData = _.cloneDeep(this.props.labelData);
-    scope.target = _.cloneDeep(this.props.target);
+  componentDidUpdate(prevProps: Props) {
+    if (prevProps.metricType !== this.props.metricType) {
+      const scope = this.component.getScope();
+      scope.loading = this.loadLabels(scope);
+    }
   }
   }
 
 
   componentWillUnmount() {
   componentWillUnmount() {
@@ -52,6 +58,19 @@ export class Filter extends React.Component<Props, any> {
     }
     }
   }
   }
 
 
+  async loadLabels(scope) {
+    return new Promise(async resolve => {
+      try {
+        const { meta } = await this.props.datasource.getLabels(this.props.target.metricType, this.props.target.refId);
+        scope.labelData = meta;
+        resolve();
+      } catch (error) {
+        appEvents.emit('alert-error', ['Error', 'Error loading metric labels for ' + this.props.target.metricType]);
+        resolve();
+      }
+    });
+  }
+
   render() {
   render() {
     return <div ref={element => (this.element = element)} style={{ width: '100%' }} />;
     return <div ref={element => (this.element = element)} style={{ width: '100%' }} />;
   }
   }

+ 14 - 6
public/app/plugins/datasource/stackdriver/components/Metrics.tsx

@@ -9,6 +9,7 @@ export interface Props {
   datasource: any;
   datasource: any;
   defaultProject: string;
   defaultProject: string;
   metricType: string;
   metricType: string;
+  children?: (renderProps: any) => JSX.Element;
 }
 }
 
 
 interface State {
 interface State {
@@ -17,6 +18,7 @@ interface State {
   services: any[];
   services: any[];
   service: string;
   service: string;
   metric: string;
   metric: string;
+  metricDescriptor: any;
 }
 }
 
 
 export class Metrics extends React.Component<Props, State> {
 export class Metrics extends React.Component<Props, State> {
@@ -26,6 +28,7 @@ export class Metrics extends React.Component<Props, State> {
     services: [],
     services: [],
     service: '',
     service: '',
     metric: '',
     metric: '',
+    metricDescriptor: null,
   };
   };
 
 
   constructor(props) {
   constructor(props) {
@@ -68,13 +71,16 @@ export class Metrics extends React.Component<Props, State> {
     const services = this.getServicesList(metricDescriptors);
     const services = this.getServicesList(metricDescriptors);
     const metrics = this.getMetricsList(metricDescriptors);
     const metrics = this.getMetricsList(metricDescriptors);
     const service = metrics.length > 0 ? metrics[0].service : '';
     const service = metrics.length > 0 ? metrics[0].service : '';
-    this.setState({ metricDescriptors, services, metrics, service: service });
+    const metricDescriptor = this.getSelectedMetricDescriptor(this.props.metricType);
+    this.setState({ metricDescriptors, services, metrics, service: service, metricDescriptor });
+  }
+
+  getSelectedMetricDescriptor(metricType) {
+    return this.state.metricDescriptors.find(md => md.type === this.props.templateSrv.replace(metricType));
   }
   }
 
 
   getMetricsList(metricDescriptors) {
   getMetricsList(metricDescriptors) {
-    const selectedMetricDescriptor = metricDescriptors.find(
-      md => md.type === this.props.templateSrv.replace(this.props.metricType)
-    );
+    const selectedMetricDescriptor = this.getSelectedMetricDescriptor(this.props.metricType);
     const metricsByService = metricDescriptors.filter(m => m.service === selectedMetricDescriptor.service).map(m => ({
     const metricsByService = metricDescriptors.filter(m => m.service === selectedMetricDescriptor.service).map(m => ({
       service: m.service,
       service: m.service,
       value: m.type,
       value: m.type,
@@ -103,8 +109,9 @@ export class Metrics extends React.Component<Props, State> {
   }
   }
 
 
   handleMetricTypeChange(value) {
   handleMetricTypeChange(value) {
-    const selectedMetricDescriptor = this.state.metricDescriptors.find(md => md.type === value);
-    this.props.onChange(selectedMetricDescriptor);
+    const metricDescriptor = this.getSelectedMetricDescriptor(value);
+    this.setState({ metricDescriptor });
+    this.props.onChange(metricDescriptor);
   }
   }
 
 
   getServicesList(metricDescriptors) {
   getServicesList(metricDescriptors) {
@@ -166,6 +173,7 @@ export class Metrics extends React.Component<Props, State> {
             <div className="gf-form-label gf-form-label--grow" />
             <div className="gf-form-label gf-form-label--grow" />
           </div>
           </div>
         </div>
         </div>
+        {this.props.children(this.state.metricDescriptor)}
       </React.Fragment>
       </React.Fragment>
     );
     );
   }
   }

+ 71 - 99
public/app/plugins/datasource/stackdriver/components/QueryEditor.tsx

@@ -1,11 +1,10 @@
 import React from 'react';
 import React from 'react';
 import _ from 'lodash';
 import _ from 'lodash';
-import appEvents from 'app/core/app_events';
 
 
 import { Metrics } from './Metrics';
 import { Metrics } from './Metrics';
 import { Filter } from './Filter';
 import { Filter } from './Filter';
 import { Aggregations } from './Aggregations';
 import { Aggregations } from './Aggregations';
-import { Target, QueryMeta } from '../types';
+import { Target } from '../types';
 
 
 export interface Props {
 export interface Props {
   onQueryChange: (target: Target) => void;
   onQueryChange: (target: Target) => void;
@@ -18,8 +17,6 @@ export interface Props {
 
 
 interface State {
 interface State {
   target: Target;
   target: Target;
-  labelData: QueryMeta;
-  loadLabelsPromise: Promise<any>;
 }
 }
 
 
 const DefaultTarget: Target = {
 const DefaultTarget: Target = {
@@ -41,85 +38,79 @@ const DefaultTarget: Target = {
 };
 };
 
 
 export class QueryEditor extends React.Component<Props, State> {
 export class QueryEditor extends React.Component<Props, State> {
-  state: State = { labelData: null, loadLabelsPromise: new Promise(() => {}), target: DefaultTarget };
+  state: State = { target: DefaultTarget };
 
 
   componentDidMount() {
   componentDidMount() {
-    this.getLabels();
     this.setState({ target: this.props.target });
     this.setState({ target: this.props.target });
   }
   }
 
 
-  async getLabels() {
-    const loadLabelsPromise = new Promise(async resolve => {
-      try {
-        const { meta } = await this.props.datasource.getLabels(this.props.target.metricType, this.props.target.refId);
-        this.setState({ labelData: meta });
-        resolve();
-      } catch (error) {
-        appEvents.emit('alert-error', ['Error', 'Error loading metric labels for ' + this.props.target.metricType]);
-        resolve();
-      }
-    });
-    this.setState({ loadLabelsPromise });
-  }
-
   handleMetricTypeChange({ valueType, metricKind, type, unit }) {
   handleMetricTypeChange({ valueType, metricKind, type, unit }) {
-    this.setState({
-      target: {
-        ...this.state.target,
-        ...{
-          metricType: type,
-          unit,
-          valueType,
-          metricKind,
+    this.setState(
+      {
+        target: {
+          ...this.state.target,
+          ...{
+            metricType: type,
+            unit,
+            valueType,
+            metricKind,
+          },
         },
         },
       },
       },
-    });
-
-    // this.$rootScope.$broadcast('metricTypeChanged');
-    this.getLabels();
-    this.props.onQueryChange(this.state.target);
-    this.props.onExecuteQuery();
+      () => {
+        this.props.onQueryChange(this.state.target);
+        this.props.onExecuteQuery();
+      }
+    );
   }
   }
 
 
   handleFilterChange(value) {
   handleFilterChange(value) {
-    this.setState({
-      target: {
-        ...this.state.target,
-        filters: value,
+    this.setState(
+      {
+        target: {
+          ...this.state.target,
+          filters: value,
+        },
       },
       },
-    });
-    this.props.onQueryChange(this.state.target);
-    this.props.onExecuteQuery();
+      () => {
+        this.props.onQueryChange(this.state.target);
+        this.props.onExecuteQuery();
+      }
+    );
   }
   }
 
 
   handleGroupBysChange(value) {
   handleGroupBysChange(value) {
-    this.setState({
-      target: {
-        ...this.state.target,
-        groupBys: value,
+    this.setState(
+      {
+        target: {
+          ...this.state.target,
+          groupBys: value,
+        },
       },
       },
-    });
-    this.props.onQueryChange(this.state.target);
-    this.props.onExecuteQuery();
+      () => {
+        this.props.onQueryChange(this.state.target);
+        this.props.onExecuteQuery();
+      }
+    );
   }
   }
 
 
   handleAggregationChange(value) {
   handleAggregationChange(value) {
-    this.setState({
-      target: {
-        ...this.state.target,
-        aggregation: {
-          ...this.state.target.aggregation,
-          crossSeriesReducer: value,
-        },
+    const target = {
+      ...this.state.target,
+      aggregation: {
+        ...this.state.target.aggregation,
+        crossSeriesReducer: value,
       },
       },
+    };
+    this.setState({ target }, () => {
+      this.props.onQueryChange(target);
+      this.props.onExecuteQuery();
     });
     });
-    this.props.onQueryChange(this.state.target);
-    this.props.onExecuteQuery();
   }
   }
 
 
   render() {
   render() {
-    const { labelData, loadLabelsPromise, target } = this.state;
-    const { defaultProject, metricType, valueType, metricKind, aggregation } = target;
+    const { target } = this.state;
+    const { defaultProject, metricType, aggregation } = target;
     const { templateSrv, datasource, uiSegmentSrv } = this.props;
     const { templateSrv, datasource, uiSegmentSrv } = this.props;
 
 
     return (
     return (
@@ -130,46 +121,27 @@ export class QueryEditor extends React.Component<Props, State> {
           templateSrv={templateSrv}
           templateSrv={templateSrv}
           datasource={datasource}
           datasource={datasource}
           onChange={value => this.handleMetricTypeChange(value)}
           onChange={value => this.handleMetricTypeChange(value)}
-        />
-        <Filter
-          filtersChanged={value => this.handleFilterChange(value)}
-          groupBysChanged={value => this.handleGroupBysChange(value)}
-          target={target}
-          uiSegmentSrv={uiSegmentSrv}
-          labelData={labelData}
-          templateSrv={templateSrv}
-          loading={loadLabelsPromise}
-        />
-        <Aggregations
-          valueType={valueType}
-          metricKind={metricKind}
-          templateSrv={templateSrv}
-          aggregation={aggregation}
-          onChange={value => this.handleAggregationChange(value)}
-        />
-        {/* target="ctrl.target" refresh="ctrl.refresh()" loading="ctrl.loadLabelsPromise" label-data="ctrl.labelData" */}
-        {/* <stackdriver-filter
-          target="target"
-          refresh="target.refresh()"
-          loading="target.loadLabelsPromise"
-          label-data="target.labelData"
-        />
-        <aggregation-picker
-          value-type="target.target.valueType"
-          metric-kind="target.target.metricKind"
-          aggregation="target.target.aggregation"
-          alignment-period="target.lastQueryMeta.alignmentPeriod"
-          refresh="target.refresh()"
-          template-srv="target.templateSrv"
-          datasource="target.datasource"
-          on-change="target.handleAggregationChange"
-        />
-
-        <stackdriver-aggregation
-          target="target.target"
-          alignment-period="target.lastQueryMeta.alignmentPeriod"
-          refresh="target.refresh()"
-        /> */}
+        >
+          {metric => (
+            <React.Fragment>
+              <Filter
+                filtersChanged={value => this.handleFilterChange(value)}
+                groupBysChanged={value => this.handleGroupBysChange(value)}
+                target={target}
+                uiSegmentSrv={uiSegmentSrv}
+                templateSrv={templateSrv}
+                datasource={datasource}
+                metricType={metric ? metric.type : ''}
+              />
+              <Aggregations
+                metricDescriptor={metric}
+                templateSrv={templateSrv}
+                aggregation={aggregation}
+                onChange={value => this.handleAggregationChange(value)}
+              />
+            </React.Fragment>
+          )}
+        </Metrics>
       </React.Fragment>
       </React.Fragment>
     );
     );
   }
   }