Sfoglia il codice sorgente

graph legend: refactor, move behaviour logic into component

Alexander Zobnin 7 anni fa
parent
commit
daa95c2375

+ 88 - 12
public/app/plugins/panel/graph/Legend/Legend.tsx

@@ -7,7 +7,17 @@ import { LegendItem, LEGEND_STATS } from './LegendSeriesItem';
 interface LegendProps {
 interface LegendProps {
   seriesList: TimeSeries[];
   seriesList: TimeSeries[];
   optionalClass?: string;
   optionalClass?: string;
-  onToggleSeries?: (series: TimeSeries, event: Event) => void;
+}
+
+interface LegendEventHandlers {
+  onToggleSeries?: (hiddenSeries) => void;
+  onToggleSort?: (sortBy, sortDesc) => void;
+  onToggleAxis?: (series: TimeSeries) => void;
+  onColorChange?: (series: TimeSeries, color: string) => void;
+}
+
+interface LegendComponentEventHandlers {
+  onToggleSeries?: (series, event) => void;
   onToggleSort?: (sortBy, sortDesc) => void;
   onToggleSort?: (sortBy, sortDesc) => void;
   onToggleAxis?: (series: TimeSeries) => void;
   onToggleAxis?: (series: TimeSeries) => void;
   onColorChange?: (series: TimeSeries, color: string) => void;
   onColorChange?: (series: TimeSeries, color: string) => void;
@@ -36,9 +46,22 @@ interface LegendSortProps {
   sortDesc?: boolean;
   sortDesc?: boolean;
 }
 }
 
 
-export type GraphLegendProps = LegendProps & LegendDisplayProps & LegendValuesProps & LegendSortProps;
+export type GraphLegendProps = LegendProps &
+  LegendDisplayProps &
+  LegendValuesProps &
+  LegendSortProps &
+  LegendEventHandlers;
+export type LegendComponentProps = LegendProps &
+  LegendDisplayProps &
+  LegendValuesProps &
+  LegendSortProps &
+  LegendComponentEventHandlers;
+
+interface LegendState {
+  hiddenSeries: any;
+}
 
 
-export class GraphLegend extends React.PureComponent<GraphLegendProps> {
+export class GraphLegend extends React.PureComponent<GraphLegendProps, LegendState> {
   static defaultProps: Partial<GraphLegendProps> = {
   static defaultProps: Partial<GraphLegendProps> = {
     values: false,
     values: false,
     min: false,
     min: false,
@@ -57,10 +80,12 @@ export class GraphLegend extends React.PureComponent<GraphLegendProps> {
     onColorChange: () => {},
     onColorChange: () => {},
   };
   };
 
 
-  onToggleSeries = (series, event) => {
-    this.props.onToggleSeries(series, event);
-    this.forceUpdate();
-  };
+  constructor(props) {
+    super(props);
+    this.state = {
+      hiddenSeries: this.props.hiddenSeries,
+    };
+  }
 
 
   onToggleAxis = series => {
   onToggleAxis = series => {
     this.props.onToggleAxis(series);
     this.props.onToggleAxis(series);
@@ -73,7 +98,7 @@ export class GraphLegend extends React.PureComponent<GraphLegendProps> {
   };
   };
 
 
   sortLegend() {
   sortLegend() {
-    let seriesList = this.props.seriesList || [];
+    let seriesList = [...this.props.seriesList] || [];
     if (this.props.sort) {
     if (this.props.sort) {
       seriesList = _.sortBy(seriesList, series => {
       seriesList = _.sortBy(seriesList, series => {
         let sort = series.stats[this.props.sort];
         let sort = series.stats[this.props.sort];
@@ -89,10 +114,61 @@ export class GraphLegend extends React.PureComponent<GraphLegendProps> {
     return seriesList;
     return seriesList;
   }
   }
 
 
+  onToggleSeries = (series, event) => {
+    let hiddenSeries = { ...this.state.hiddenSeries };
+    if (event.ctrlKey || event.metaKey || event.shiftKey) {
+      if (hiddenSeries[series.alias]) {
+        delete hiddenSeries[series.alias];
+      } else {
+        hiddenSeries[series.alias] = true;
+      }
+    } else {
+      hiddenSeries = this.toggleSeriesExclusiveMode(series);
+    }
+    this.setState({ hiddenSeries: hiddenSeries });
+    this.props.onToggleSeries(hiddenSeries);
+  };
+
+  toggleSeriesExclusiveMode(series) {
+    const hiddenSeries = { ...this.state.hiddenSeries };
+
+    if (hiddenSeries[series.alias]) {
+      delete hiddenSeries[series.alias];
+    }
+
+    // check if every other series is hidden
+    const alreadyExclusive = _.every(this.props.seriesList, value => {
+      if (value.alias === series.alias) {
+        return true;
+      }
+
+      return hiddenSeries[value.alias];
+    });
+
+    if (alreadyExclusive) {
+      // remove all hidden series
+      _.each(this.props.seriesList, value => {
+        delete hiddenSeries[value.alias];
+      });
+    } else {
+      // hide all but this serie
+      _.each(this.props.seriesList, value => {
+        if (value.alias === series.alias) {
+          return;
+        }
+
+        hiddenSeries[value.alias] = true;
+      });
+    }
+
+    return hiddenSeries;
+  }
+
   render() {
   render() {
-    const { optionalClass, hiddenSeries, rightSide, sideWidth, sort, sortDesc, hideEmpty, hideZero } = this.props;
+    const { optionalClass, rightSide, sideWidth, sort, sortDesc, hideEmpty, hideZero } = this.props;
     const { values, min, max, avg, current, total } = this.props;
     const { values, min, max, avg, current, total } = this.props;
     const seriesValuesProps = { values, min, max, avg, current, total };
     const seriesValuesProps = { values, min, max, avg, current, total };
+    const hiddenSeries = this.state.hiddenSeries;
     const seriesHideProps = { hideEmpty, hideZero };
     const seriesHideProps = { hideEmpty, hideZero };
     const sortProps = { sort, sortDesc };
     const sortProps = { sort, sortDesc };
     const seriesList = _.filter(this.sortLegend(), series => !series.hideFromLegend(seriesHideProps));
     const seriesList = _.filter(this.sortLegend(), series => !series.hideFromLegend(seriesHideProps));
@@ -107,7 +183,7 @@ export class GraphLegend extends React.PureComponent<GraphLegendProps> {
       width: ieWidth,
       width: ieWidth,
     };
     };
 
 
-    const legendProps: GraphLegendProps = {
+    const legendProps: LegendComponentProps = {
       seriesList: seriesList,
       seriesList: seriesList,
       hiddenSeries: hiddenSeries,
       hiddenSeries: hiddenSeries,
       onToggleSeries: this.onToggleSeries,
       onToggleSeries: this.onToggleSeries,
@@ -126,7 +202,7 @@ export class GraphLegend extends React.PureComponent<GraphLegendProps> {
   }
   }
 }
 }
 
 
-class LegendSeriesList extends React.PureComponent<GraphLegendProps> {
+class LegendSeriesList extends React.PureComponent<LegendComponentProps> {
   render() {
   render() {
     const { seriesList, hiddenSeries, values, min, max, avg, current, total } = this.props;
     const { seriesList, hiddenSeries, values, min, max, avg, current, total } = this.props;
     const seriesValuesProps = { values, min, max, avg, current, total };
     const seriesValuesProps = { values, min, max, avg, current, total };
@@ -144,7 +220,7 @@ class LegendSeriesList extends React.PureComponent<GraphLegendProps> {
   }
   }
 }
 }
 
 
-class LegendTable extends React.PureComponent<Partial<GraphLegendProps>> {
+class LegendTable extends React.PureComponent<Partial<LegendComponentProps>> {
   onToggleSort = stat => {
   onToggleSort = stat => {
     let sortDesc = this.props.sortDesc;
     let sortDesc = this.props.sortDesc;
     let sortBy = this.props.sort;
     let sortBy = this.props.sort;

+ 41 - 12
public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx

@@ -24,7 +24,11 @@ export interface LegendValuesProps {
 
 
 type LegendItemProps = LegendLabelProps & LegendValuesProps;
 type LegendItemProps = LegendLabelProps & LegendValuesProps;
 
 
-export class LegendItem extends React.PureComponent<LegendItemProps> {
+interface LegendItemState {
+  yaxis: number;
+}
+
+export class LegendItem extends React.PureComponent<LegendItemProps, LegendItemState> {
   static defaultProps = {
   static defaultProps = {
     asTable: false,
     asTable: false,
     hidden: false,
     hidden: false,
@@ -33,26 +37,35 @@ export class LegendItem extends React.PureComponent<LegendItemProps> {
     onToggleAxis: () => {},
     onToggleAxis: () => {},
   };
   };
 
 
+  constructor(props) {
+    super(props);
+    this.state = {
+      yaxis: this.props.series.yaxis,
+    };
+  }
+
   onLabelClick = e => this.props.onLabelClick(this.props.series, e);
   onLabelClick = e => this.props.onLabelClick(this.props.series, e);
+
   onToggleAxis = () => {
   onToggleAxis = () => {
-    this.props.onToggleAxis(this.props.series);
-    this.forceUpdate();
+    const yaxis = this.state.yaxis === 2 ? 1 : 2;
+    const info = { alias: this.props.series.alias, yaxis: yaxis };
+    this.setState({ yaxis: yaxis });
+    this.props.onToggleAxis(info);
   };
   };
+
   onColorChange = color => {
   onColorChange = color => {
     this.props.onColorChange(this.props.series, color);
     this.props.onColorChange(this.props.series, color);
-    // this.forceUpdate();
   };
   };
 
 
   render() {
   render() {
     const { series, hidden, asTable } = this.props;
     const { series, hidden, asTable } = this.props;
-    const { aliasEscaped, color, yaxis } = this.props.series;
     const seriesOptionClasses = getOptionSeriesCSSClasses(series, hidden);
     const seriesOptionClasses = getOptionSeriesCSSClasses(series, hidden);
     const valueItems = this.props.values ? renderLegendValues(this.props, series, asTable) : [];
     const valueItems = this.props.values ? renderLegendValues(this.props, series, asTable) : [];
     const seriesLabel = (
     const seriesLabel = (
       <LegendSeriesLabel
       <LegendSeriesLabel
-        label={aliasEscaped}
-        color={color}
-        yaxis={yaxis}
+        label={series.aliasEscaped}
+        color={series.color}
+        yaxis={this.state.yaxis}
         onLabelClick={this.onLabelClick}
         onLabelClick={this.onLabelClick}
         onColorChange={this.onColorChange}
         onColorChange={this.onColorChange}
         onToggleAxis={this.onToggleAxis}
         onToggleAxis={this.onToggleAxis}
@@ -115,27 +128,43 @@ interface LegendSeriesIconProps {
   onToggleAxis?: () => void;
   onToggleAxis?: () => void;
 }
 }
 
 
+interface LegendSeriesIconState {
+  color: string;
+}
+
 function SeriesIcon(props) {
 function SeriesIcon(props) {
   return <i className="fa fa-minus pointer" style={{ color: props.color }} />;
   return <i className="fa fa-minus pointer" style={{ color: props.color }} />;
 }
 }
 
 
-class LegendSeriesIcon extends React.PureComponent<LegendSeriesIconProps> {
+class LegendSeriesIcon extends React.PureComponent<LegendSeriesIconProps, LegendSeriesIconState> {
   static defaultProps = {
   static defaultProps = {
     yaxis: undefined,
     yaxis: undefined,
     onColorChange: () => {},
     onColorChange: () => {},
     onToggleAxis: () => {},
     onToggleAxis: () => {},
   };
   };
 
 
+  constructor(props) {
+    super(props);
+    this.state = {
+      color: this.props.color,
+    };
+  }
+
+  onColorChange = color => {
+    this.setState({ color: color });
+    this.props.onColorChange(color);
+  };
+
   render() {
   render() {
-    const { color, yaxis } = this.props;
+    const { yaxis } = this.props;
     const IconWithColorPicker = withColorPicker(SeriesIcon);
     const IconWithColorPicker = withColorPicker(SeriesIcon);
 
 
     return (
     return (
       <IconWithColorPicker
       <IconWithColorPicker
         optionalClass="graph-legend-icon"
         optionalClass="graph-legend-icon"
-        color={color}
         yaxis={yaxis}
         yaxis={yaxis}
-        onColorChange={this.props.onColorChange}
+        color={this.state.color}
+        onColorChange={this.onColorChange}
         onToggleAxis={this.props.onToggleAxis}
         onToggleAxis={this.props.onToggleAxis}
       />
       />
     );
     );

+ 2 - 2
public/app/plugins/panel/graph/graph.ts

@@ -75,7 +75,7 @@ class GraphElement {
     this.ctrl.toggleSeries = this.ctrl.toggleSeries.bind(this.ctrl);
     this.ctrl.toggleSeries = this.ctrl.toggleSeries.bind(this.ctrl);
     this.ctrl.toggleSort = this.ctrl.toggleSort.bind(this.ctrl);
     this.ctrl.toggleSort = this.ctrl.toggleSort.bind(this.ctrl);
     this.ctrl.changeSeriesColor = this.ctrl.changeSeriesColor.bind(this.ctrl);
     this.ctrl.changeSeriesColor = this.ctrl.changeSeriesColor.bind(this.ctrl);
-    this.ctrl.toggleAxis = this.ctrl.toggleAxis.bind(this.ctrl);
+    this.ctrl.setSeriesAxis = this.ctrl.setSeriesAxis.bind(this.ctrl);
   }
   }
 
 
   onRender(renderData) {
   onRender(renderData) {
@@ -100,7 +100,7 @@ class GraphElement {
       onToggleSeries: this.ctrl.toggleSeries,
       onToggleSeries: this.ctrl.toggleSeries,
       onToggleSort: this.ctrl.toggleSort,
       onToggleSort: this.ctrl.toggleSort,
       onColorChange: this.ctrl.changeSeriesColor,
       onColorChange: this.ctrl.changeSeriesColor,
-      onToggleAxis: this.ctrl.toggleAxis,
+      onToggleAxis: this.ctrl.setSeriesAxis,
     };
     };
     const legendReactElem = React.createElement(Legend, legendProps);
     const legendReactElem = React.createElement(Legend, legendProps);
     const legendElem = this.elem.parent().find('.graph-legend');
     const legendElem = this.elem.parent().find('.graph-legend');

+ 4 - 45
public/app/plugins/panel/graph/module.ts

@@ -249,65 +249,24 @@ class GraphCtrl extends MetricsPanelCtrl {
     this.render();
     this.render();
   }
   }
 
 
-  toggleSeries(serie, event) {
-    if (event.ctrlKey || event.metaKey || event.shiftKey) {
-      if (this.hiddenSeries[serie.alias]) {
-        delete this.hiddenSeries[serie.alias];
-      } else {
-        this.hiddenSeries[serie.alias] = true;
-      }
-    } else {
-      this.toggleSeriesExclusiveMode(serie);
-    }
+  toggleSeries(hiddenSeries) {
+    this.hiddenSeries = hiddenSeries;
     this.render();
     this.render();
   }
   }
 
 
-  toggleSeriesExclusiveMode(serie) {
-    const hidden = this.hiddenSeries;
-
-    if (hidden[serie.alias]) {
-      delete hidden[serie.alias];
-    }
-
-    // check if every other series is hidden
-    const alreadyExclusive = _.every(this.seriesList, value => {
-      if (value.alias === serie.alias) {
-        return true;
-      }
-
-      return hidden[value.alias];
-    });
-
-    if (alreadyExclusive) {
-      // remove all hidden series
-      _.each(this.seriesList, value => {
-        delete this.hiddenSeries[value.alias];
-      });
-    } else {
-      // hide all but this serie
-      _.each(this.seriesList, value => {
-        if (value.alias === serie.alias) {
-          return;
-        }
-
-        this.hiddenSeries[value.alias] = true;
-      });
-    }
-  }
-
   toggleSort(sortBy, sortDesc) {
   toggleSort(sortBy, sortDesc) {
     this.panel.legend.sort = sortBy;
     this.panel.legend.sort = sortBy;
     this.panel.legend.sortDesc = sortDesc;
     this.panel.legend.sortDesc = sortDesc;
     this.render();
     this.render();
   }
   }
 
 
-  toggleAxis(info) {
+  setSeriesAxis(info) {
     let override = _.find(this.panel.seriesOverrides, { alias: info.alias });
     let override = _.find(this.panel.seriesOverrides, { alias: info.alias });
     if (!override) {
     if (!override) {
       override = { alias: info.alias };
       override = { alias: info.alias };
       this.panel.seriesOverrides.push(override);
       this.panel.seriesOverrides.push(override);
     }
     }
-    info.yaxis = override.yaxis = info.yaxis === 2 ? 1 : 2;
+    override.yaxis = info.yaxis;
     this.render();
     this.render();
   }
   }