wip: react panel options architecture
This commit is contained in:
@@ -21,6 +21,7 @@ export interface Props {
|
|||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
refreshCounter: number;
|
refreshCounter: number;
|
||||||
|
renderCounter: number;
|
||||||
timeRange?: TimeRange;
|
timeRange?: TimeRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,11 +31,13 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
refreshCounter: 0,
|
refreshCounter: 0,
|
||||||
|
renderCounter: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.panel.events.on('refresh', this.onRefresh);
|
this.props.panel.events.on('refresh', this.onRefresh);
|
||||||
|
this.props.panel.events.on('render', this.onRender);
|
||||||
this.props.dashboard.panelInitialized(this.props.panel);
|
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() {
|
get isVisible() {
|
||||||
return !this.props.dashboard.otherPanelInFullscreen(this.props.panel);
|
return !this.props.dashboard.otherPanelInFullscreen(this.props.panel);
|
||||||
}
|
}
|
||||||
@@ -59,9 +69,11 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
render() {
|
render() {
|
||||||
const { panel, dashboard } = this.props;
|
const { panel, dashboard } = this.props;
|
||||||
const { datasource, targets } = panel;
|
const { datasource, targets } = panel;
|
||||||
const { refreshCounter, timeRange } = this.state;
|
const { timeRange, renderCounter, refreshCounter } = this.state;
|
||||||
const PanelComponent = this.props.component;
|
const PanelComponent = this.props.component;
|
||||||
|
|
||||||
|
console.log('Panel chrome render');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="panel-container">
|
<div className="panel-container">
|
||||||
<PanelHeader panel={panel} dashboard={dashboard} />
|
<PanelHeader panel={panel} dashboard={dashboard} />
|
||||||
@@ -74,7 +86,16 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
refreshCounter={refreshCounter}
|
refreshCounter={refreshCounter}
|
||||||
>
|
>
|
||||||
{({ loading, timeSeries }) => {
|
{({ 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>
|
</DataPanel>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import React from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { QueriesTab } from './QueriesTab';
|
||||||
|
import { VizTypePicker } from './VizTypePicker';
|
||||||
|
|
||||||
|
import { store } from 'app/store/configureStore';
|
||||||
|
import { updateLocation } from 'app/core/actions';
|
||||||
|
|
||||||
import { PanelModel } from '../panel_model';
|
import { PanelModel } from '../panel_model';
|
||||||
import { DashboardModel } from '../dashboard_model';
|
import { DashboardModel } from '../dashboard_model';
|
||||||
import { store } from 'app/store/configureStore';
|
|
||||||
import { QueriesTab } from './QueriesTab';
|
|
||||||
import { PanelPlugin, PluginExports } from 'app/types/plugins';
|
import { PanelPlugin, PluginExports } from 'app/types/plugins';
|
||||||
import { VizTypePicker } from './VizTypePicker';
|
|
||||||
import { updateLocation } from 'app/core/actions';
|
|
||||||
|
|
||||||
interface PanelEditorProps {
|
interface PanelEditorProps {
|
||||||
panel: PanelModel;
|
panel: PanelModel;
|
||||||
@@ -22,7 +25,7 @@ interface PanelEditorTab {
|
|||||||
icon: string;
|
icon: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PanelEditor extends React.Component<PanelEditorProps, any> {
|
export class PanelEditor extends PureComponent<PanelEditorProps> {
|
||||||
tabs: PanelEditorTab[];
|
tabs: PanelEditorTab[];
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -39,16 +42,20 @@ export class PanelEditor extends React.Component<PanelEditorProps, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderPanelOptions() {
|
renderPanelOptions() {
|
||||||
const { pluginExports } = this.props;
|
const { pluginExports, panel } = this.props;
|
||||||
|
|
||||||
if (pluginExports.PanelOptions) {
|
if (pluginExports.PanelOptionsComponent) {
|
||||||
const PanelOptions = pluginExports.PanelOptions;
|
const OptionsComponent = pluginExports.PanelOptionsComponent;
|
||||||
return <PanelOptions />;
|
return <OptionsComponent options={panel.getOptions()} onChange={this.onPanelOptionsChanged} />;
|
||||||
} else {
|
} else {
|
||||||
return <p>Visualization has no options</p>;
|
return <p>Visualization has no options</p>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPanelOptionsChanged = (options: any) => {
|
||||||
|
this.props.panel.updateOptions(options);
|
||||||
|
};
|
||||||
|
|
||||||
renderVizTab() {
|
renderVizTab() {
|
||||||
return (
|
return (
|
||||||
<div className="viz-editor">
|
<div className="viz-editor">
|
||||||
@@ -70,6 +77,7 @@ export class PanelEditor extends React.Component<PanelEditorProps, any> {
|
|||||||
partial: true,
|
partial: true,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
this.forceUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -60,6 +60,21 @@ export class PanelModel {
|
|||||||
_.defaultsDeep(this, _.cloneDeep(defaults));
|
_.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() {
|
getSaveModel() {
|
||||||
const model: any = {};
|
const model: any = {};
|
||||||
for (const property in this) {
|
for (const property in this) {
|
||||||
@@ -121,10 +136,6 @@ export class PanelModel {
|
|||||||
this.events.emit('panel-initialized');
|
this.events.emit('panel-initialized');
|
||||||
}
|
}
|
||||||
|
|
||||||
initEditMode() {
|
|
||||||
this.events.emit('panel-init-edit-mode');
|
|
||||||
}
|
|
||||||
|
|
||||||
changeType(pluginId: string) {
|
changeType(pluginId: string) {
|
||||||
this.type = pluginId;
|
this.type = pluginId;
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ export class SettingsCtrl {
|
|||||||
|
|
||||||
this.$scope.$on('$destroy', () => {
|
this.$scope.$on('$destroy', () => {
|
||||||
this.dashboard.updateSubmenuVisibility();
|
this.dashboard.updateSubmenuVisibility();
|
||||||
this.dashboard.startRefresh();
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.$rootScope.appEvent('dash-scroll', { restore: true });
|
this.$rootScope.appEvent('dash-scroll', { restore: true });
|
||||||
|
this.dashboard.startRefresh();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
// Libraries
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
// Components
|
|
||||||
import Graph from 'app/viz/Graph';
|
import Graph from 'app/viz/Graph';
|
||||||
import { getTimeSeriesVMs } from 'app/viz/state/timeSeries';
|
|
||||||
import { Switch } from 'app/core/components/Switch/Switch';
|
import { Switch } from 'app/core/components/Switch/Switch';
|
||||||
|
|
||||||
// Types
|
import { getTimeSeriesVMs } from 'app/viz/state/timeSeries';
|
||||||
import { PanelProps, NullValueMode } from 'app/types';
|
import { PanelProps, NullValueMode } from 'app/types';
|
||||||
|
|
||||||
interface Options {
|
interface Options {
|
||||||
@@ -18,9 +15,7 @@ interface Options {
|
|||||||
onChange: (options: Options) => void;
|
onChange: (options: Options) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props extends PanelProps {
|
interface Props extends PanelProps<Options> {}
|
||||||
options: Options;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Graph2 extends PureComponent<Props> {
|
export class Graph2 extends PureComponent<Props> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -29,17 +24,26 @@ export class Graph2 extends PureComponent<Props> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { timeSeries, timeRange } = this.props;
|
const { timeSeries, timeRange } = this.props;
|
||||||
|
const { showLines, showBars, showPoints } = this.props.options;
|
||||||
|
|
||||||
const vmSeries = getTimeSeriesVMs({
|
const vmSeries = getTimeSeriesVMs({
|
||||||
timeSeries: timeSeries,
|
timeSeries: timeSeries,
|
||||||
nullValueMode: NullValueMode.Ignore,
|
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 = () => {
|
onToggleLines = () => {
|
||||||
const options = this.props as Options;
|
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() {
|
render() {
|
||||||
const { showBars, showPoints, showLines } = this.props;
|
const { showBars, showPoints, showLines } = this.props;
|
||||||
|
|
||||||
@@ -58,11 +71,11 @@ export class TextOptions extends PureComponent<Options> {
|
|||||||
<h5 className="page-heading">Draw Modes</h5>
|
<h5 className="page-heading">Draw Modes</h5>
|
||||||
<Switch label="Lines" labelClass="width-5" checked={showLines} onChange={this.onToggleLines} />
|
<Switch label="Lines" labelClass="width-5" checked={showLines} onChange={this.onToggleLines} />
|
||||||
<Switch label="Bars" labelClass="width-5" checked={showBars} 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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Graph2 as PanelComponent, TextOptions as PanelOptions };
|
export { Graph2 as PanelComponent, GraphOptions as PanelOptionsComponent };
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { LoadingState, TimeSeries, TimeRange } from './series';
|
import { LoadingState, TimeSeries, TimeRange } from './series';
|
||||||
|
|
||||||
export interface PanelProps {
|
export interface PanelProps<T = any> {
|
||||||
timeSeries: TimeSeries[];
|
timeSeries: TimeSeries[];
|
||||||
timeRange: TimeRange;
|
timeRange: TimeRange;
|
||||||
loading: LoadingState;
|
loading: LoadingState;
|
||||||
|
options: T;
|
||||||
|
renderCounter: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PanelOptionProps<T = any> {
|
||||||
|
options: T;
|
||||||
|
onChange: (options: T) => void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
|
import { ComponentClass } from 'react';
|
||||||
|
import { PanelProps, PanelOptionProps } from './panel';
|
||||||
|
|
||||||
export interface PluginExports {
|
export interface PluginExports {
|
||||||
PanelCtrl?;
|
|
||||||
PanelComponent?: any;
|
|
||||||
Datasource?: any;
|
Datasource?: any;
|
||||||
QueryCtrl?: any;
|
QueryCtrl?: any;
|
||||||
ConfigCtrl?: any;
|
ConfigCtrl?: any;
|
||||||
AnnotationsQueryCtrl?: any;
|
AnnotationsQueryCtrl?: any;
|
||||||
PanelOptions?: any;
|
|
||||||
ExploreQueryField?: any;
|
ExploreQueryField?: any;
|
||||||
ExploreStartPage?: any;
|
ExploreStartPage?: any;
|
||||||
|
|
||||||
|
// Panel plugin
|
||||||
|
PanelCtrl?;
|
||||||
|
PanelComponent?: ComponentClass<PanelProps>;
|
||||||
|
PanelOptionsComponent: ComponentClass<PanelOptionProps>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PanelPlugin {
|
export interface PanelPlugin {
|
||||||
|
|||||||
+51
-33
@@ -34,37 +34,22 @@ function time_format(ticks, min, max) {
|
|||||||
return '%H:%M';
|
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 {
|
interface GraphProps {
|
||||||
timeSeries: TimeSeriesVMs;
|
timeSeries: TimeSeriesVMs;
|
||||||
timeRange: TimeRange;
|
timeRange: TimeRange;
|
||||||
|
showLines?: boolean;
|
||||||
|
showPoints?: boolean;
|
||||||
|
showBars?: boolean;
|
||||||
size?: { width: number; height: number };
|
size?: { width: number; height: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Graph extends PureComponent<GraphProps> {
|
export class Graph extends PureComponent<GraphProps> {
|
||||||
|
static defaultProps = {
|
||||||
|
showLines: true,
|
||||||
|
showPoints: false,
|
||||||
|
showBars: false,
|
||||||
|
};
|
||||||
|
|
||||||
element: any;
|
element: any;
|
||||||
|
|
||||||
componentDidUpdate(prevProps: GraphProps) {
|
componentDidUpdate(prevProps: GraphProps) {
|
||||||
@@ -82,7 +67,7 @@ export class Graph extends PureComponent<GraphProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
const { size, timeSeries, timeRange } = this.props;
|
const { size, timeSeries, timeRange, showLines, showBars, showPoints } = this.props;
|
||||||
|
|
||||||
if (!size) {
|
if (!size) {
|
||||||
return;
|
return;
|
||||||
@@ -92,7 +77,31 @@ export class Graph extends PureComponent<GraphProps> {
|
|||||||
const min = timeRange.from.valueOf();
|
const min = timeRange.from.valueOf();
|
||||||
const max = timeRange.to.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: {
|
xaxis: {
|
||||||
mode: 'time',
|
mode: 'time',
|
||||||
min: min,
|
min: min,
|
||||||
@@ -101,15 +110,24 @@ export class Graph extends PureComponent<GraphProps> {
|
|||||||
ticks: ticks,
|
ticks: ticks,
|
||||||
timeformat: time_format(ticks, min, max),
|
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 = {
|
try {
|
||||||
...FLOT_OPTIONS,
|
$.plot(this.element, timeSeries, flotOptions);
|
||||||
...dynamicOptions,
|
} catch (err) {
|
||||||
};
|
console.log('Graph rendering error', err, flotOptions, timeSeries);
|
||||||
|
}
|
||||||
console.log('plot', timeSeries, options);
|
|
||||||
$.plot(this.element, timeSeries, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
Reference in New Issue
Block a user