graph legend: refactor, fix another review issues

This commit is contained in:
Alexander Zobnin
2018-10-22 14:17:46 +03:00
parent daa95c2375
commit 4b9462993e
7 changed files with 142 additions and 148 deletions
@@ -1,67 +1,81 @@
import React from 'react';
import { ColorPickerPopover } from './ColorPickerPopover';
import { react2AngularDirective } from 'app/core/utils/react2angular';
import ReactDOM from 'react-dom';
import Drop from 'tether-drop';
import { SeriesColorPickerPopover } from './SeriesColorPickerPopover';
export interface SeriesColorPickerProps {
// series: any;
color: string;
yaxis?: number;
onColorChange: (color: string) => void;
optionalClass?: string;
onColorChange: (newColor: string) => void;
onToggleAxis?: () => void;
}
export class SeriesColorPicker extends React.PureComponent<SeriesColorPickerProps, any> {
render() {
return (
<div className="graph-legend-popover">
{this.props.yaxis && <AxisSelector yaxis={this.props.yaxis} onToggleAxis={this.props.onToggleAxis} />}
<ColorPickerPopover color={this.props.color} onColorSelect={this.props.onColorChange} />
</div>
);
}
}
export class SeriesColorPicker extends React.Component<SeriesColorPickerProps> {
pickerElem: any;
colorPickerDrop: any;
interface AxisSelectorProps {
yaxis: number;
onToggleAxis: () => void;
}
static defaultProps = {
optionalClass: '',
yaxis: undefined,
onToggleAxis: () => {},
};
interface AxisSelectorState {
yaxis: number;
}
export class AxisSelector extends React.PureComponent<AxisSelectorProps, AxisSelectorState> {
constructor(props) {
super(props);
this.state = {
yaxis: this.props.yaxis,
};
this.onToggleAxis = this.onToggleAxis.bind(this);
this.openColorPicker = this.openColorPicker.bind(this);
}
onToggleAxis() {
this.setState({
yaxis: this.state.yaxis === 2 ? 1 : 2,
openColorPicker() {
if (this.colorPickerDrop) {
this.destroyDrop();
}
const { color, yaxis, onColorChange, onToggleAxis } = this.props;
const dropContent = (
<SeriesColorPickerPopover color={color} yaxis={yaxis} onColorChange={onColorChange} onToggleAxis={onToggleAxis} />
);
const dropContentElem = document.createElement('div');
ReactDOM.render(dropContent, dropContentElem);
const drop = new Drop({
target: this.pickerElem,
content: dropContentElem,
position: 'top center',
classes: 'drop-popover',
openOn: 'hover',
hoverCloseDelay: 200,
remove: true,
tetherOptions: {
constraints: [{ to: 'scrollParent', attachment: 'none both' }],
},
});
this.props.onToggleAxis();
drop.on('close', this.closeColorPicker.bind(this));
this.colorPickerDrop = drop;
this.colorPickerDrop.open();
}
closeColorPicker() {
setTimeout(() => {
this.destroyDrop();
}, 100);
}
destroyDrop() {
if (this.colorPickerDrop && this.colorPickerDrop.tether) {
this.colorPickerDrop.destroy();
this.colorPickerDrop = null;
}
}
render() {
const leftButtonClass = this.state.yaxis === 1 ? 'btn-success' : 'btn-inverse';
const rightButtonClass = this.state.yaxis === 2 ? 'btn-success' : 'btn-inverse';
const { optionalClass, children } = this.props;
return (
<div className="p-b-1">
<label className="small p-r-1">Y Axis:</label>
<button onClick={this.onToggleAxis} className={'btn btn-small ' + leftButtonClass}>
Left
</button>
<button onClick={this.onToggleAxis} className={'btn btn-small ' + rightButtonClass}>
Right
</button>
<div className={optionalClass} ref={e => (this.pickerElem = e)} onClick={this.openColorPicker}>
{children}
</div>
);
}
}
react2AngularDirective('seriesColorPicker', SeriesColorPicker, ['series', 'onColorChange', 'onToggleAxis']);
@@ -0,0 +1,70 @@
import React from 'react';
import { ColorPickerPopover } from './ColorPickerPopover';
import { react2AngularDirective } from 'app/core/utils/react2angular';
export interface SeriesColorPickerPopoverProps {
color: string;
yaxis?: number;
onColorChange: (color: string) => void;
onToggleAxis?: () => void;
}
export class SeriesColorPickerPopover extends React.PureComponent<SeriesColorPickerPopoverProps, any> {
render() {
return (
<div className="graph-legend-popover">
{this.props.yaxis && <AxisSelector yaxis={this.props.yaxis} onToggleAxis={this.props.onToggleAxis} />}
<ColorPickerPopover color={this.props.color} onColorSelect={this.props.onColorChange} />
</div>
);
}
}
interface AxisSelectorProps {
yaxis: number;
onToggleAxis: () => void;
}
interface AxisSelectorState {
yaxis: number;
}
export class AxisSelector extends React.PureComponent<AxisSelectorProps, AxisSelectorState> {
constructor(props) {
super(props);
this.state = {
yaxis: this.props.yaxis,
};
this.onToggleAxis = this.onToggleAxis.bind(this);
}
onToggleAxis() {
this.setState({
yaxis: this.state.yaxis === 2 ? 1 : 2,
});
this.props.onToggleAxis();
}
render() {
const leftButtonClass = this.state.yaxis === 1 ? 'btn-success' : 'btn-inverse';
const rightButtonClass = this.state.yaxis === 2 ? 'btn-success' : 'btn-inverse';
return (
<div className="p-b-1">
<label className="small p-r-1">Y Axis:</label>
<button onClick={this.onToggleAxis} className={'btn btn-small ' + leftButtonClass}>
Left
</button>
<button onClick={this.onToggleAxis} className={'btn btn-small ' + rightButtonClass}>
Right
</button>
</div>
);
}
}
react2AngularDirective('seriesColorPickerPopover', SeriesColorPickerPopover, [
'series',
'onColorChange',
'onToggleAxis',
]);
@@ -1,83 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Drop from 'tether-drop';
import { SeriesColorPicker } from './SeriesColorPicker';
export interface WithSeriesColorPickerProps {
color: string;
yaxis?: number;
optionalClass?: string;
onColorChange: (newColor: string) => void;
onToggleAxis?: () => void;
}
export default function withSeriesColorPicker(WrappedComponent) {
return class extends React.Component<WithSeriesColorPickerProps, any> {
pickerElem: any;
colorPickerDrop: any;
static defaultProps = {
optionalClass: '',
yaxis: undefined,
onToggleAxis: () => {},
};
constructor(props) {
super(props);
this.openColorPicker = this.openColorPicker.bind(this);
}
openColorPicker() {
if (this.colorPickerDrop) {
this.destroyDrop();
}
const { color, yaxis, onColorChange, onToggleAxis } = this.props;
const dropContent = (
<SeriesColorPicker color={color} yaxis={yaxis} onColorChange={onColorChange} onToggleAxis={onToggleAxis} />
);
const dropContentElem = document.createElement('div');
ReactDOM.render(dropContent, dropContentElem);
const drop = new Drop({
target: this.pickerElem,
content: dropContentElem,
position: 'top center',
classes: 'drop-popover',
openOn: 'hover',
hoverCloseDelay: 200,
remove: true,
tetherOptions: {
constraints: [{ to: 'scrollParent', attachment: 'none both' }],
},
});
drop.on('close', this.closeColorPicker.bind(this));
this.colorPickerDrop = drop;
this.colorPickerDrop.open();
}
closeColorPicker() {
setTimeout(() => {
this.destroyDrop();
}, 100);
}
destroyDrop() {
if (this.colorPickerDrop && this.colorPickerDrop.tether) {
this.colorPickerDrop.destroy();
this.colorPickerDrop = null;
}
}
render() {
const { optionalClass, onColorChange, ...wrappedComponentProps } = this.props;
return (
<div className={optionalClass} ref={e => (this.pickerElem = e)} onClick={this.openColorPicker}>
<WrappedComponent {...wrappedComponentProps} />
</div>
);
}
};
}
+1 -1
View File
@@ -14,7 +14,7 @@ import './components/jsontree/jsontree';
import './components/code_editor/code_editor';
import './utils/outline';
import './components/colorpicker/ColorPicker';
import './components/colorpicker/SeriesColorPicker';
import './components/colorpicker/SeriesColorPickerPopover';
import './components/colorpicker/spectrum_picker';
import './services/search_srv';
import './services/ng_react';
@@ -87,16 +87,6 @@ export class GraphLegend extends React.PureComponent<GraphLegendProps, LegendSta
};
}
onToggleAxis = series => {
this.props.onToggleAxis(series);
this.forceUpdate();
};
onColorChange = (series, color) => {
this.props.onColorChange(series, color);
this.forceUpdate();
};
sortLegend() {
let seriesList = [...this.props.seriesList] || [];
if (this.props.sort) {
@@ -187,9 +177,9 @@ export class GraphLegend extends React.PureComponent<GraphLegendProps, LegendSta
seriesList: seriesList,
hiddenSeries: hiddenSeries,
onToggleSeries: this.onToggleSeries,
onToggleAxis: this.onToggleAxis,
onToggleAxis: this.props.onToggleAxis,
onToggleSort: this.props.onToggleSort,
onColorChange: this.onColorChange,
onColorChange: this.props.onColorChange,
...seriesValuesProps,
...sortProps,
};
@@ -1,6 +1,6 @@
import React from 'react';
import { TimeSeries } from 'app/core/core';
import withColorPicker from 'app/core/components/colorpicker/withColorPicker';
import { SeriesColorPicker } from 'app/core/components/colorpicker/SeriesColorPicker';
export const LEGEND_STATS = ['min', 'max', 'avg', 'current', 'total'];
@@ -55,6 +55,10 @@ export class LegendItem extends React.PureComponent<LegendItemProps, LegendItemS
onColorChange = color => {
this.props.onColorChange(this.props.series, color);
// Because of PureComponent nature it makes only shallow props comparison and changing of series.color doesn't run
// component re-render. In this case we can't rely on color, selected by user, because it may be overwritten
// by series overrides. So we need to use forceUpdate() to make sure we have proper series color.
this.forceUpdate();
};
render() {
@@ -156,17 +160,16 @@ class LegendSeriesIcon extends React.PureComponent<LegendSeriesIconProps, Legend
};
render() {
const { yaxis } = this.props;
const IconWithColorPicker = withColorPicker(SeriesIcon);
return (
<IconWithColorPicker
<SeriesColorPicker
optionalClass="graph-legend-icon"
yaxis={yaxis}
yaxis={this.props.yaxis}
color={this.state.color}
onColorChange={this.onColorChange}
onToggleAxis={this.props.onToggleAxis}
/>
>
<SeriesIcon color={this.props.color} />
</SeriesColorPicker>
);
}
}
@@ -53,7 +53,7 @@ export function SeriesOverridesCtrl($scope, $element, popoverSrv) {
element: $element.find('.dropdown')[0],
position: 'top center',
openOn: 'click',
template: '<series-color-picker series="series" onColorChange="colorSelected" />',
template: '<series-color-picker-popover series="series" onColorChange="colorSelected" />',
model: {
autoClose: true,
colorSelected: $scope.colorSelected,