Commit 35e62bbb by Torkel Ödegaard

wip: react panel options architecture

parent dd4eab17
......@@ -21,6 +21,7 @@ export interface Props {
export interface State {
refreshCounter: number;
renderCounter: number;
timeRange?: TimeRange;
}
......@@ -30,11 +31,13 @@ export class PanelChrome extends PureComponent<Props, State> {
this.state = {
refreshCounter: 0,
renderCounter: 0,
};
}
componentDidMount() {
this.props.panel.events.on('refresh', this.onRefresh);
this.props.panel.events.on('render', this.onRender);
this.props.dashboard.panelInitialized(this.props.panel);
}
......@@ -52,6 +55,13 @@ export class PanelChrome extends PureComponent<Props, State> {
});
};
onRender = () => {
console.log('onRender');
this.setState({
renderCounter: this.state.renderCounter + 1,
});
};
get isVisible() {
return !this.props.dashboard.otherPanelInFullscreen(this.props.panel);
}
......@@ -59,9 +69,11 @@ export class PanelChrome extends PureComponent<Props, State> {
render() {
const { panel, dashboard } = this.props;
const { datasource, targets } = panel;
const { refreshCounter, timeRange } = this.state;
const { timeRange, renderCounter, refreshCounter } = this.state;
const PanelComponent = this.props.component;
console.log('Panel chrome render');
return (
<div className="panel-container">
<PanelHeader panel={panel} dashboard={dashboard} />
......@@ -74,7 +86,16 @@ export class PanelChrome extends PureComponent<Props, State> {
refreshCounter={refreshCounter}
>
{({ loading, timeSeries }) => {
return <PanelComponent loading={loading} timeSeries={timeSeries} timeRange={timeRange} />;
console.log('panelcrome inner render');
return (
<PanelComponent
loading={loading}
timeSeries={timeSeries}
timeRange={timeRange}
options={panel.getOptions()}
renderCounter={renderCounter}
/>
);
}}
</DataPanel>
</div>
......
import React from 'react';
import React, { PureComponent } from 'react';
import classNames from 'classnames';
import { PanelModel } from '../panel_model';
import { DashboardModel } from '../dashboard_model';
import { store } from 'app/store/configureStore';
import { QueriesTab } from './QueriesTab';
import { PanelPlugin, PluginExports } from 'app/types/plugins';
import { VizTypePicker } from './VizTypePicker';
import { store } from 'app/store/configureStore';
import { updateLocation } from 'app/core/actions';
import { PanelModel } from '../panel_model';
import { DashboardModel } from '../dashboard_model';
import { PanelPlugin, PluginExports } from 'app/types/plugins';
interface PanelEditorProps {
panel: PanelModel;
dashboard: DashboardModel;
......@@ -22,7 +25,7 @@ interface PanelEditorTab {
icon: string;
}
export class PanelEditor extends React.Component<PanelEditorProps, any> {
export class PanelEditor extends PureComponent<PanelEditorProps> {
tabs: PanelEditorTab[];
constructor(props) {
......@@ -39,16 +42,20 @@ export class PanelEditor extends React.Component<PanelEditorProps, any> {
}
renderPanelOptions() {
const { pluginExports } = this.props;
const { pluginExports, panel } = this.props;
if (pluginExports.PanelOptions) {
const PanelOptions = pluginExports.PanelOptions;
return <PanelOptions />;
if (pluginExports.PanelOptionsComponent) {
const OptionsComponent = pluginExports.PanelOptionsComponent;
return <OptionsComponent options={panel.getOptions()} onChange={this.onPanelOptionsChanged} />;
} else {
return <p>Visualization has no options</p>;
}
}
onPanelOptionsChanged = (options: any) => {
this.props.panel.updateOptions(options);
};
renderVizTab() {
return (
<div className="viz-editor">
......@@ -70,6 +77,7 @@ export class PanelEditor extends React.Component<PanelEditorProps, any> {
partial: true,
})
);
this.forceUpdate();
};
render() {
......
......@@ -60,6 +60,21 @@ export class PanelModel {
_.defaultsDeep(this, _.cloneDeep(defaults));
}
getOptions() {
return this[this.getOptionsKey()] || {};
}
updateOptions(options: object) {
const update: any = {};
update[this.getOptionsKey()] = options;
Object.assign(this, update);
this.render();
}
private getOptionsKey() {
return this.type + 'Options';
}
getSaveModel() {
const model: any = {};
for (const property in this) {
......@@ -121,10 +136,6 @@ export class PanelModel {
this.events.emit('panel-initialized');
}
initEditMode() {
this.events.emit('panel-init-edit-mode');
}
changeType(pluginId: string) {
this.type = pluginId;
......
......@@ -32,9 +32,9 @@ export class SettingsCtrl {
this.$scope.$on('$destroy', () => {
this.dashboard.updateSubmenuVisibility();
this.dashboard.startRefresh();
setTimeout(() => {
this.$rootScope.appEvent('dash-scroll', { restore: true });
this.dashboard.startRefresh();
});
});
......
// Libraries
import _ from 'lodash';
import React, { PureComponent } from 'react';
// Components
import Graph from 'app/viz/Graph';
import { getTimeSeriesVMs } from 'app/viz/state/timeSeries';
import { Switch } from 'app/core/components/Switch/Switch';
// Types
import { getTimeSeriesVMs } from 'app/viz/state/timeSeries';
import { PanelProps, NullValueMode } from 'app/types';
interface Options {
......@@ -18,9 +15,7 @@ interface Options {
onChange: (options: Options) => void;
}
interface Props extends PanelProps {
options: Options;
}
interface Props extends PanelProps<Options> {}
export class Graph2 extends PureComponent<Props> {
constructor(props) {
......@@ -29,17 +24,26 @@ export class Graph2 extends PureComponent<Props> {
render() {
const { timeSeries, timeRange } = this.props;
const { showLines, showBars, showPoints } = this.props.options;
const vmSeries = getTimeSeriesVMs({
timeSeries: timeSeries,
nullValueMode: NullValueMode.Ignore,
});
return <Graph timeSeries={vmSeries} timeRange={timeRange} />;
return (
<Graph
timeSeries={vmSeries}
timeRange={timeRange}
showLines={showLines}
showPoints={showPoints}
showBars={showBars}
/>
);
}
}
export class TextOptions extends PureComponent<Options> {
export class GraphOptions extends PureComponent<Options> {
onToggleLines = () => {
const options = this.props as Options;
......@@ -49,6 +53,15 @@ export class TextOptions extends PureComponent<Options> {
});
};
onTogglePoints = () => {
const options = this.props as Options;
this.props.onChange({
...options,
showPoints: !this.props.showPoints,
});
};
render() {
const { showBars, showPoints, showLines } = this.props;
......@@ -58,11 +71,11 @@ export class TextOptions extends PureComponent<Options> {
<h5 className="page-heading">Draw Modes</h5>
<Switch label="Lines" labelClass="width-5" checked={showLines} onChange={this.onToggleLines} />
<Switch label="Bars" labelClass="width-5" checked={showBars} onChange={this.onToggleLines} />
<Switch label="Points" labelClass="width-5" checked={showPoints} onChange={this.onToggleLines} />
<Switch label="Points" labelClass="width-5" checked={showPoints} onChange={this.onTogglePoints} />
</div>
</div>
);
}
}
export { Graph2 as PanelComponent, TextOptions as PanelOptions };
export { Graph2 as PanelComponent, GraphOptions as PanelOptionsComponent };
import { LoadingState, TimeSeries, TimeRange } from './series';
export interface PanelProps {
export interface PanelProps<T = any> {
timeSeries: TimeSeries[];
timeRange: TimeRange;
loading: LoadingState;
options: T;
renderCounter: number;
}
export interface PanelOptionProps<T = any> {
options: T;
onChange: (options: T) => void;
}
import { ComponentClass } from 'react';
import { PanelProps, PanelOptionProps } from './panel';
export interface PluginExports {
PanelCtrl?;
PanelComponent?: any;
Datasource?: any;
QueryCtrl?: any;
ConfigCtrl?: any;
AnnotationsQueryCtrl?: any;
PanelOptions?: any;
ExploreQueryField?: any;
ExploreStartPage?: any;
// Panel plugin
PanelCtrl?;
PanelComponent?: ComponentClass<PanelProps>;
PanelOptionsComponent: ComponentClass<PanelOptionProps>;
}
export interface PanelPlugin {
......
......@@ -34,37 +34,22 @@ function time_format(ticks, min, max) {
return '%H:%M';
}
const FLOT_OPTIONS = {
legend: {
show: false,
},
series: {
lines: {
linewidth: 1,
zero: false,
},
shadowSize: 0,
},
grid: {
minBorderMargin: 0,
markings: [],
backgroundColor: null,
borderWidth: 0,
// hoverable: true,
clickable: true,
color: '#a1a1a1',
margin: { left: 0, right: 0 },
labelMarginX: 0,
},
};
interface GraphProps {
timeSeries: TimeSeriesVMs;
timeRange: TimeRange;
showLines?: boolean;
showPoints?: boolean;
showBars?: boolean;
size?: { width: number; height: number };
}
export class Graph extends PureComponent<GraphProps> {
static defaultProps = {
showLines: true,
showPoints: false,
showBars: false,
};
element: any;
componentDidUpdate(prevProps: GraphProps) {
......@@ -82,7 +67,7 @@ export class Graph extends PureComponent<GraphProps> {
}
draw() {
const { size, timeSeries, timeRange } = this.props;
const { size, timeSeries, timeRange, showLines, showBars, showPoints } = this.props;
if (!size) {
return;
......@@ -92,7 +77,31 @@ export class Graph extends PureComponent<GraphProps> {
const min = timeRange.from.valueOf();
const max = timeRange.to.valueOf();
const dynamicOptions = {
const flotOptions = {
legend: {
show: false,
},
series: {
lines: {
show: showLines,
linewidth: 1,
zero: false,
},
points: {
show: showPoints,
fill: 1,
fillColor: false,
radius: 2,
},
bars: {
show: showBars,
fill: 1,
barWidth: 1,
zero: false,
lineWidth: 0,
},
shadowSize: 0,
},
xaxis: {
mode: 'time',
min: min,
......@@ -101,15 +110,24 @@ export class Graph extends PureComponent<GraphProps> {
ticks: ticks,
timeformat: time_format(ticks, min, max),
},
grid: {
minBorderMargin: 0,
markings: [],
backgroundColor: null,
borderWidth: 0,
// hoverable: true,
clickable: true,
color: '#a1a1a1',
margin: { left: 0, right: 0 },
labelMarginX: 0,
},
};
const options = {
...FLOT_OPTIONS,
...dynamicOptions,
};
console.log('plot', timeSeries, options);
$.plot(this.element, timeSeries, options);
try {
$.plot(this.element, timeSeries, flotOptions);
} catch (err) {
console.log('Graph rendering error', err, flotOptions, timeSeries);
}
}
render() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment