Merge branch 'react-panel-options' into bar-gauge-poc

This commit is contained in:
Torkel Ödegaard 2019-02-16 16:02:31 +01:00
commit 42d90fdb7a
24 changed files with 231 additions and 136 deletions

View File

@ -1,3 +1,4 @@
import { ComponentClass } from 'react';
import { TimeSeries, LoadingState, TableData } from './data'; import { TimeSeries, LoadingState, TableData } from './data';
import { TimeRange } from './time'; import { TimeRange } from './time';
@ -19,11 +20,29 @@ export interface PanelData {
tableData?: TableData; tableData?: TableData;
} }
export interface PanelOptionsProps<T = any> { export interface PanelEditorProps<T = any> {
options: T; options: T;
onChange: (options: T) => void; onChange: (options: T) => void;
} }
export class ReactPanelPlugin<TOptions = any> {
panel: ComponentClass<PanelProps<TOptions>>;
editor?: ComponentClass<PanelEditorProps<TOptions>>;
defaults?: TOptions;
constructor(panel: ComponentClass<PanelProps<TOptions>>) {
this.panel = panel;
}
setEditor(editor: ComponentClass<PanelEditorProps<TOptions>>) {
this.editor = editor;
}
setDefaults(defaults: TOptions) {
this.defaults = defaults;
}
}
export interface PanelSize { export interface PanelSize {
width: number; width: number;
height: number; height: number;

View File

@ -1,5 +1,5 @@
import { ComponentClass } from 'react'; import { ComponentClass } from 'react';
import { PanelProps, PanelOptionsProps } from './panel'; import { ReactPanelPlugin } from './panel';
import { DataQueryOptions, DataQuery, DataQueryResponse, QueryHint, QueryFixAction } from './datasource'; import { DataQueryOptions, DataQuery, DataQueryResponse, QueryHint, QueryFixAction } from './datasource';
export interface DataSourceApi<TQuery extends DataQuery = DataQuery> { export interface DataSourceApi<TQuery extends DataQuery = DataQuery> {
@ -81,9 +81,7 @@ export interface PluginExports {
// Panel plugin // Panel plugin
PanelCtrl?: any; PanelCtrl?: any;
Panel?: ComponentClass<PanelProps>; reactPanel: ReactPanelPlugin;
PanelOptions?: ComponentClass<PanelOptionsProps>;
PanelDefaults?: any;
} }
export interface PluginMeta { export interface PluginMeta {

View File

@ -14,4 +14,3 @@ export const DASHBOARD_TOP_PADDING = 20;
export const PANEL_HEADER_HEIGHT = 27; export const PANEL_HEADER_HEIGHT = 27;
export const PANEL_BORDER = 2; export const PANEL_BORDER = 2;
export const PANEL_OPTIONS_KEY_PREFIX = 'options-';

View File

@ -173,7 +173,7 @@ export class DashboardPanel extends PureComponent<Props, State> {
onMouseLeave={this.onMouseLeave} onMouseLeave={this.onMouseLeave}
style={styles} style={styles}
> >
{plugin.exports.Panel && this.renderReactPanel()} {plugin.exports.reactPanel && this.renderReactPanel()}
{plugin.exports.PanelCtrl && this.renderAngularPanel()} {plugin.exports.PanelCtrl && this.renderAngularPanel()}
</div> </div>
)} )}

View File

@ -139,7 +139,7 @@ export class PanelChrome extends PureComponent<Props, State> {
renderPanelPlugin(loading: LoadingState, panelData: PanelData, width: number, height: number): JSX.Element { renderPanelPlugin(loading: LoadingState, panelData: PanelData, width: number, height: number): JSX.Element {
const { panel, plugin } = this.props; const { panel, plugin } = this.props;
const { timeRange, renderCounter } = this.state; const { timeRange, renderCounter } = this.state;
const PanelComponent = plugin.exports.Panel; const PanelComponent = plugin.exports.reactPanel.panel;
// This is only done to increase a counter that is used by backend // This is only done to increase a counter that is used by backend
// image rendering (phantomjs/headless chrome) to know when to capture image // image rendering (phantomjs/headless chrome) to know when to capture image
@ -153,7 +153,7 @@ export class PanelChrome extends PureComponent<Props, State> {
loading={loading} loading={loading}
panelData={panelData} panelData={panelData}
timeRange={timeRange} timeRange={timeRange}
options={panel.getOptions(plugin.exports.PanelDefaults)} options={panel.getOptions(plugin.exports.reactPanel.defaults)}
width={width - 2 * variables.panelhorizontalpadding} width={width - 2 * variables.panelhorizontalpadding}
height={height - PANEL_HEADER_HEIGHT - variables.panelverticalpadding} height={height - PANEL_HEADER_HEIGHT - variables.panelverticalpadding}
renderCounter={renderCounter} renderCounter={renderCounter}

View File

@ -6,8 +6,8 @@ import React, { PureComponent } from 'react';
import { AlertBox } from 'app/core/components/AlertBox/AlertBox'; import { AlertBox } from 'app/core/components/AlertBox/AlertBox';
// Types // Types
import { PanelProps } from '@grafana/ui';
import { PanelPlugin, AppNotificationSeverity } from 'app/types'; import { PanelPlugin, AppNotificationSeverity } from 'app/types';
import { PanelProps, ReactPanelPlugin } from '@grafana/ui';
interface Props { interface Props {
pluginId: string; pluginId: string;
@ -64,7 +64,7 @@ export function getPanelPluginNotFound(id: string): PanelPlugin {
}, },
exports: { exports: {
Panel: NotFound, reactPanel: new ReactPanelPlugin(NotFound),
}, },
}; };
} }

View File

@ -50,33 +50,27 @@ export class VisualizationTab extends PureComponent<Props, State> {
}; };
} }
getPanelDefaultOptions = () => { getReactPanelOptions = () => {
const { panel, plugin } = this.props; const { panel, plugin } = this.props;
return panel.getOptions(plugin.exports.reactPanel.defaults);
if (plugin.exports.PanelDefaults) {
return panel.getOptions(plugin.exports.PanelDefaults);
}
return panel.getOptions({});
}; };
renderPanelOptions() { renderPanelOptions() {
const { plugin, angularPanel } = this.props; const { plugin, angularPanel } = this.props;
const { PanelOptions } = plugin.exports;
if (angularPanel) { if (angularPanel) {
return <div ref={element => (this.element = element)} />; return <div ref={element => (this.element = element)} />;
} }
return ( if (plugin.exports.reactPanel) {
<> const PanelEditor = plugin.exports.reactPanel.editor;
{PanelOptions ? (
<PanelOptions options={this.getPanelDefaultOptions()} onChange={this.onPanelOptionsChanged} /> if (PanelEditor) {
) : ( return <PanelEditor options={this.getReactPanelOptions()} onChange={this.onPanelOptionsChanged} />;
<p>Visualization has no options</p> }
)} }
</>
); return <p>Visualization has no options</p>;
} }
componentDidMount() { componentDidMount() {

View File

@ -22,7 +22,7 @@ export class DashboardMigrator {
let i, j, k, n; let i, j, k, n;
const oldVersion = this.dashboard.schemaVersion; const oldVersion = this.dashboard.schemaVersion;
const panelUpgrades = []; const panelUpgrades = [];
this.dashboard.schemaVersion = 17; this.dashboard.schemaVersion = 18;
if (oldVersion === this.dashboard.schemaVersion) { if (oldVersion === this.dashboard.schemaVersion) {
return; return;
@ -387,6 +387,30 @@ export class DashboardMigrator {
}); });
} }
if (oldVersion < 18) {
// migrate change to gauge options
panelUpgrades.push(panel => {
if (panel['options-gauge']) {
panel.options = panel['options-gauge'];
panel.options.valueOptions = {
unit: panel.options.unit,
stat: panel.options.stat,
decimals: panel.options.decimals,
prefix: panel.options.prefix,
suffix: panel.options.suffix,
};
// this options prop was due to a bug
delete panel.options.options;
delete panel.options.unit;
delete panel.options.stat;
delete panel.options.decimals;
delete panel.options.prefix;
delete panel.options.suffix;
delete panel['options-gauge'];
}
});
}
if (panelUpgrades.length === 0) { if (panelUpgrades.length === 0) {
return; return;
} }

View File

@ -55,5 +55,19 @@ describe('PanelModel', () => {
expect(model.alert).toBe(undefined); expect(model.alert).toBe(undefined);
}); });
}); });
describe('get panel options', () => {
it('should apply defaults', () => {
model.options = { existingProp: 10 };
const options = model.getOptions({
defaultProp: true,
existingProp: 0,
});
expect(options.defaultProp).toBe(true);
expect(options.existingProp).toBe(10);
expect(model.options).toBe(options);
});
});
}); });
}); });

View File

@ -3,7 +3,6 @@ import _ from 'lodash';
// Types // Types
import { Emitter } from 'app/core/utils/emitter'; import { Emitter } from 'app/core/utils/emitter';
import { PANEL_OPTIONS_KEY_PREFIX } from 'app/core/constants';
import { DataQuery, TimeSeries } from '@grafana/ui'; import { DataQuery, TimeSeries } from '@grafana/ui';
import { TableData } from '@grafana/ui/src'; import { TableData } from '@grafana/ui/src';
@ -92,6 +91,7 @@ export class PanelModel {
timeFrom?: any; timeFrom?: any;
timeShift?: any; timeShift?: any;
hideTimeOverride?: any; hideTimeOverride?: any;
options: object;
maxDataPoints?: number; maxDataPoints?: number;
interval?: string; interval?: string;
@ -105,8 +105,6 @@ export class PanelModel {
hasRefreshed: boolean; hasRefreshed: boolean;
events: Emitter; events: Emitter;
cacheTimeout?: any; cacheTimeout?: any;
// cache props between plugins
cachedPluginOptions?: any; cachedPluginOptions?: any;
constructor(model) { constructor(model) {
@ -134,20 +132,14 @@ export class PanelModel {
} }
getOptions(panelDefaults) { getOptions(panelDefaults) {
return _.defaultsDeep(this[this.getOptionsKey()] || {}, panelDefaults); return _.defaultsDeep(this.options || {}, panelDefaults);
} }
updateOptions(options: object) { updateOptions(options: object) {
const update: any = {}; this.options = options;
update[this.getOptionsKey()] = options;
Object.assign(this, update);
this.render(); this.render();
} }
private getOptionsKey() {
return PANEL_OPTIONS_KEY_PREFIX + this.type;
}
getSaveModel() { getSaveModel() {
const model: any = {}; const model: any = {};
for (const property in this) { for (const property in this) {

View File

@ -16,9 +16,10 @@ interface Props extends PanelProps<BarGaugeOptions> {}
export class BarGaugePanel extends PureComponent<Props> { export class BarGaugePanel extends PureComponent<Props> {
render() { render() {
const { panelData, width, height, onInterpolate, options } = this.props; const { panelData, width, height, onInterpolate, options } = this.props;
const { valueOptions } = options;
const prefix = onInterpolate(options.prefix); const prefix = onInterpolate(valueOptions.prefix);
const suffix = onInterpolate(options.suffix); const suffix = onInterpolate(valueOptions.suffix);
let value: TimeSeriesValue; let value: TimeSeriesValue;
@ -29,7 +30,7 @@ export class BarGaugePanel extends PureComponent<Props> {
}); });
if (vmSeries[0]) { if (vmSeries[0]) {
value = vmSeries[0].stats[options.stat]; value = vmSeries[0].stats[valueOptions.stat];
} else { } else {
value = null; value = null;
} }
@ -42,11 +43,14 @@ export class BarGaugePanel extends PureComponent<Props> {
{theme => ( {theme => (
<BarGauge <BarGauge
value={value} value={value}
{...this.props.options}
width={width} width={width}
height={height} height={height}
prefix={prefix} prefix={prefix}
suffix={suffix} suffix={suffix}
unit={valueOptions.unit}
decimals={valueOptions.decimals}
thresholds={options.thresholds}
valueMappings={options.valueMappings}
theme={theme} theme={theme}
/> />
)} )}

View File

@ -2,14 +2,15 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
// Components // Components
import { ValueOptions } from 'app/plugins/panel/gauge/ValueOptions'; import { SingleStatValueEditor } from 'app/plugins/panel/gauge/SingleStatValueEditor';
import { ThresholdsEditor, ValueMappingsEditor, PanelOptionsGrid, PanelOptionsGroup, FormField } from '@grafana/ui'; import { ThresholdsEditor, ValueMappingsEditor, PanelOptionsGrid, PanelOptionsGroup, FormField } from '@grafana/ui';
// Types // Types
import { PanelOptionsProps, Threshold, ValueMapping } from '@grafana/ui'; import { PanelEditorProps, Threshold, ValueMapping } from '@grafana/ui';
import { BarGaugeOptions } from './types'; import { BarGaugeOptions } from './types';
import { SingleStatValueOptions } from '../gauge/types';
export class BarGaugePanelOptions extends PureComponent<PanelOptionsProps<BarGaugeOptions>> { export class BarGaugePanelEditor extends PureComponent<PanelEditorProps<BarGaugeOptions>> {
onThresholdsChanged = (thresholds: Threshold[]) => onThresholdsChanged = (thresholds: Threshold[]) =>
this.props.onChange({ this.props.onChange({
...this.props.options, ...this.props.options,
@ -22,16 +23,22 @@ export class BarGaugePanelOptions extends PureComponent<PanelOptionsProps<BarGau
valueMappings, valueMappings,
}); });
onValueOptionsChanged = (valueOptions: SingleStatValueOptions) =>
this.props.onChange({
...this.props.options,
valueOptions,
});
onMinValueChange = ({ target }) => this.props.onChange({ ...this.props.options, minValue: target.value }); onMinValueChange = ({ target }) => this.props.onChange({ ...this.props.options, minValue: target.value });
onMaxValueChange = ({ target }) => this.props.onChange({ ...this.props.options, maxValue: target.value }); onMaxValueChange = ({ target }) => this.props.onChange({ ...this.props.options, maxValue: target.value });
render() { render() {
const { onChange, options } = this.props; const { options } = this.props;
return ( return (
<> <>
<PanelOptionsGrid> <PanelOptionsGrid>
<ValueOptions onChange={onChange} options={options} /> <SingleStatValueEditor onChange={this.onValueOptionsChanged} options={options.valueOptions} />
<PanelOptionsGroup title="Gauge"> <PanelOptionsGroup title="Gauge">
<FormField label="Min value" labelWidth={8} onChange={this.onMinValueChange} value={options.minValue} /> <FormField label="Min value" labelWidth={8} onChange={this.onMinValueChange} value={options.minValue} />
<FormField label="Max value" labelWidth={8} onChange={this.onMaxValueChange} value={options.maxValue} /> <FormField label="Max value" labelWidth={8} onChange={this.onMaxValueChange} value={options.maxValue} />

View File

@ -1,5 +1,10 @@
import { BarGaugePanel } from './BarGaugePanel'; import { ReactPanelPlugin } from '@grafana/ui';
import { BarGaugePanelOptions } from './BarGaugePanelOptions';
import { PanelDefaults } from './types';
export { BarGaugePanel as Panel, BarGaugePanelOptions as PanelOptions, PanelDefaults }; import { BarGaugePanel } from './BarGaugePanel';
import { BarGaugePanelEditor } from './BarGaugePanelEditor';
import { BarGaugeOptions, defaults } from './types';
export const reactPanel = new ReactPanelPlugin<BarGaugeOptions>(BarGaugePanel);
reactPanel.setEditor(BarGaugePanelEditor);
reactPanel.setDefaults(defaults);

View File

@ -1,23 +1,24 @@
import { Threshold, ValueMapping } from '@grafana/ui'; import { Threshold, ValueMapping } from '@grafana/ui';
import { SingleStatValueOptions } from '../gauge/types';
export interface BarGaugeOptions { export interface BarGaugeOptions {
minValue: number; minValue: number;
maxValue: number; maxValue: number;
prefix: string; valueOptions: SingleStatValueOptions;
stat: string;
suffix: string;
unit: string;
valueMappings: ValueMapping[]; valueMappings: ValueMapping[];
thresholds: Threshold[]; thresholds: Threshold[];
} }
export const PanelDefaults: BarGaugeOptions = { export const defaults: BarGaugeOptions = {
minValue: 0, minValue: 0,
maxValue: 100, maxValue: 100,
prefix: '', valueOptions: {
suffix: '', unit: 'none',
stat: 'avg', stat: 'avg',
unit: 'none', prefix: '',
suffix: '',
decimals: null,
},
thresholds: [{ index: 2, value: 80, color: 'red' }, { index: 0, value: -Infinity, color: 'green' }], thresholds: [{ index: 2, value: 80, color: 'red' }, { index: 0, value: -Infinity, color: 'green' }],
valueMappings: [], valueMappings: [],
}; };

View File

@ -1,8 +1,14 @@
// Libraries
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { FormField, PanelOptionsProps, PanelOptionsGroup, Switch } from '@grafana/ui';
// Components
import { Switch, PanelOptionsGroup } from '@grafana/ui';
// Types
import { FormField, PanelEditorProps } from '@grafana/ui';
import { GaugeOptions } from './types'; import { GaugeOptions } from './types';
export class GaugeOptionsEditor extends PureComponent<PanelOptionsProps<GaugeOptions>> { export class GaugeOptionsBox extends PureComponent<PanelEditorProps<GaugeOptions>> {
onToggleThresholdLabels = () => onToggleThresholdLabels = () =>
this.props.onChange({ ...this.props.options, showThresholdLabels: !this.props.options.showThresholdLabels }); this.props.onChange({ ...this.props.options, showThresholdLabels: !this.props.options.showThresholdLabels });

View File

@ -16,9 +16,10 @@ interface Props extends PanelProps<GaugeOptions> {}
export class GaugePanel extends PureComponent<Props> { export class GaugePanel extends PureComponent<Props> {
render() { render() {
const { panelData, width, height, onInterpolate, options } = this.props; const { panelData, width, height, onInterpolate, options } = this.props;
const { valueOptions } = options;
const prefix = onInterpolate(options.prefix); const prefix = onInterpolate(valueOptions.prefix);
const suffix = onInterpolate(options.suffix); const suffix = onInterpolate(valueOptions.suffix);
let value: TimeSeriesValue; let value: TimeSeriesValue;
if (panelData.timeSeries) { if (panelData.timeSeries) {
@ -28,7 +29,7 @@ export class GaugePanel extends PureComponent<Props> {
}); });
if (vmSeries[0]) { if (vmSeries[0]) {
value = vmSeries[0].stats[options.stat]; value = vmSeries[0].stats[valueOptions.stat];
} else { } else {
value = null; value = null;
} }
@ -41,11 +42,14 @@ export class GaugePanel extends PureComponent<Props> {
{theme => ( {theme => (
<Gauge <Gauge
value={value} value={value}
{...this.props.options}
width={width} width={width}
height={height} height={height}
prefix={prefix} prefix={prefix}
suffix={suffix} suffix={suffix}
unit={valueOptions.unit}
decimals={valueOptions.decimals}
thresholds={options.thresholds}
valueMappings={options.valueMappings}
theme={theme} theme={theme}
/> />
)} )}

View File

@ -0,0 +1,50 @@
// Libraries
import React, { PureComponent } from 'react';
import {
PanelEditorProps,
ThresholdsEditor,
Threshold,
PanelOptionsGrid,
ValueMappingsEditor,
ValueMapping,
} from '@grafana/ui';
import { SingleStatValueEditor } from 'app/plugins/panel/gauge/SingleStatValueEditor';
import { GaugeOptionsBox } from './GaugeOptionsBox';
import { GaugeOptions, SingleStatValueOptions } from './types';
export class GaugePanelEditor extends PureComponent<PanelEditorProps<GaugeOptions>> {
onThresholdsChanged = (thresholds: Threshold[]) =>
this.props.onChange({
...this.props.options,
thresholds,
});
onValueMappingsChanged = (valueMappings: ValueMapping[]) =>
this.props.onChange({
...this.props.options,
valueMappings,
});
onValueOptionsChanged = (valueOptions: SingleStatValueOptions) =>
this.props.onChange({
...this.props.options,
valueOptions,
});
render() {
const { onChange, options } = this.props;
return (
<>
<PanelOptionsGrid>
<SingleStatValueEditor onChange={this.onValueOptionsChanged} options={options.valueOptions} />
<GaugeOptionsBox onChange={onChange} options={options} />
<ThresholdsEditor onChange={this.onThresholdsChanged} thresholds={options.thresholds} />
</PanelOptionsGrid>
<ValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={options.valueMappings} />
</>
);
}
}

View File

@ -1,41 +0,0 @@
// Libraries
import React, { PureComponent } from 'react';
// Components
import { ValueOptions } from 'app/plugins/panel/gauge/ValueOptions';
import { GaugeOptionsEditor } from './GaugeOptionsEditor';
import { ThresholdsEditor, ValueMappingsEditor } from '@grafana/ui';
// Types
import { PanelOptionsProps, Threshold, PanelOptionsGrid, ValueMapping } from '@grafana/ui';
import { GaugeOptions } from './types';
export class GaugePanelOptions extends PureComponent<PanelOptionsProps<GaugeOptions>> {
onThresholdsChanged = (thresholds: Threshold[]) =>
this.props.onChange({
...this.props.options,
thresholds,
});
onValueMappingsChanged = (valueMappings: ValueMapping[]) =>
this.props.onChange({
...this.props.options,
valueMappings,
});
render() {
const { onChange, options } = this.props;
return (
<>
<PanelOptionsGrid>
<ValueOptions onChange={onChange} options={options} />
<GaugeOptionsEditor onChange={onChange} options={options} />
<ThresholdsEditor onChange={this.onThresholdsChanged} thresholds={options.thresholds} />
</PanelOptionsGrid>
<ValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={options.valueMappings} />
</>
);
}
}

View File

@ -1,7 +1,12 @@
// Libraries
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { FormField, FormLabel, PanelOptionsProps, PanelOptionsGroup, Select } from '@grafana/ui';
// Components
import UnitPicker from 'app/core/components/Select/UnitPicker'; import UnitPicker from 'app/core/components/Select/UnitPicker';
import { GaugeOptions } from './types'; import { FormField, FormLabel, PanelOptionsGroup, Select } from '@grafana/ui';
// Types
import { SingleStatValueOptions } from './types';
const statOptions = [ const statOptions = [
{ value: 'min', label: 'Min' }, { value: 'min', label: 'Min' },
@ -19,9 +24,13 @@ const statOptions = [
const labelWidth = 6; const labelWidth = 6;
export class ValueOptions extends PureComponent<PanelOptionsProps<GaugeOptions>> { export interface Props {
onUnitChange = unit => this.props.onChange({ ...this.props.options, unit: unit.value }); options: SingleStatValueOptions;
onChange: (valueOptions: SingleStatValueOptions) => void;
}
export class SingleStatValueEditor extends PureComponent<Props> {
onUnitChange = unit => this.props.onChange({ ...this.props.options, unit: unit.value });
onStatChange = stat => this.props.onChange({ ...this.props.options, stat: stat.value }); onStatChange = stat => this.props.onChange({ ...this.props.options, stat: stat.value });
onDecimalChange = event => { onDecimalChange = event => {
@ -31,7 +40,6 @@ export class ValueOptions extends PureComponent<PanelOptionsProps<GaugeOptions>>
}; };
onPrefixChange = event => this.props.onChange({ ...this.props.options, prefix: event.target.value }); onPrefixChange = event => this.props.onChange({ ...this.props.options, prefix: event.target.value });
onSuffixChange = event => this.props.onChange({ ...this.props.options, suffix: event.target.value }); onSuffixChange = event => this.props.onChange({ ...this.props.options, suffix: event.target.value });
render() { render() {

View File

@ -1,5 +1,10 @@
import { GaugePanelOptions } from './GaugePanelOptions'; import { ReactPanelPlugin } from '@grafana/ui';
import { GaugePanel } from './GaugePanel';
import { PanelDefaults } from './types';
export { GaugePanel as Panel, GaugePanelOptions as PanelOptions, PanelDefaults }; import { GaugePanelEditor } from './GaugePanelEditor';
import { GaugePanel } from './GaugePanel';
import { GaugeOptions, defaults } from './types';
export const reactPanel = new ReactPanelPlugin<GaugeOptions>(GaugePanel);
reactPanel.setEditor(GaugePanelEditor);
reactPanel.setDefaults(defaults);

View File

@ -1,29 +1,35 @@
import { Threshold, ValueMapping } from '@grafana/ui'; import { Threshold, ValueMapping } from '@grafana/ui';
export interface GaugeOptions { export interface GaugeOptions {
decimals: number;
valueMappings: ValueMapping[]; valueMappings: ValueMapping[];
maxValue: number; maxValue: number;
minValue: number; minValue: number;
prefix: string;
showThresholdLabels: boolean; showThresholdLabels: boolean;
showThresholdMarkers: boolean; showThresholdMarkers: boolean;
stat: string;
suffix: string;
thresholds: Threshold[]; thresholds: Threshold[];
unit: string; valueOptions: SingleStatValueOptions;
} }
export const PanelDefaults: GaugeOptions = { export interface SingleStatValueOptions {
unit: string;
suffix: string;
stat: string;
prefix: string;
decimals: number;
}
export const defaults: GaugeOptions = {
minValue: 0, minValue: 0,
maxValue: 100, maxValue: 100,
prefix: '',
showThresholdMarkers: true, showThresholdMarkers: true,
showThresholdLabels: false, showThresholdLabels: false,
suffix: '', valueOptions: {
decimals: 0, prefix: '',
stat: 'avg', suffix: '',
unit: 'none', decimals: 0,
stat: 'avg',
unit: 'none',
},
valueMappings: [], valueMappings: [],
thresholds: [{ index: 1, value: 80, color: 'red' }, { index: 0, value: -Infinity, color: 'green' }], thresholds: [],
}; };

View File

@ -3,10 +3,10 @@ import _ from 'lodash';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
// Types // Types
import { PanelOptionsProps, Switch } from '@grafana/ui'; import { PanelEditorProps, Switch } from '@grafana/ui';
import { Options } from './types'; import { Options } from './types';
export class GraphPanelOptions extends PureComponent<PanelOptionsProps<Options>> { export class GraphPanelEditor extends PureComponent<PanelEditorProps<Options>> {
onToggleLines = () => { onToggleLines = () => {
this.props.onChange({ ...this.props.options, showLines: !this.props.options.showLines }); this.props.onChange({ ...this.props.options, showLines: !this.props.options.showLines });
}; };

View File

@ -1,4 +1,4 @@
import { GraphPanel } from './GraphPanel'; import { GraphPanel } from './GraphPanel';
import { GraphPanelOptions } from './GraphPanelOptions'; import { GraphPanelEditor } from './GraphPanelEditor';
export { GraphPanel as Panel, GraphPanelOptions as PanelOptions }; export { GraphPanel as Panel, GraphPanelEditor as PanelOptions };

View File

@ -1,5 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { PanelProps } from '@grafana/ui'; import { PanelProps, ReactPanelPlugin } from '@grafana/ui';
export class Text2 extends PureComponent<PanelProps> { export class Text2 extends PureComponent<PanelProps> {
constructor(props: PanelProps) { constructor(props: PanelProps) {
@ -11,4 +11,4 @@ export class Text2 extends PureComponent<PanelProps> {
} }
} }
export { Text2 as Panel }; export const reactPanel = new ReactPanelPlugin(Text2);