diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index ca1b6e5..9363cdf 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -1,4 +1,5 @@ -import { DataProcessor } from '../grafana/data_processor'; +import { Options } from '../models/options'; +import { Series } from '../models/series'; import { PanelOptions } from '../types'; @@ -14,40 +15,19 @@ interface Props extends PanelProps {} export function Panel({ options, data, width, height, timeZone, timeRange, onChangeTimeRange }: Props) { console.log('options', options); - console.log('data', data); - const processor = new DataProcessor({}); - const seriesList = processor.getSeriesList({ - dataList: data.series, - range: timeRange, - }); - const chwSeriesList = updateSeriesListWithChartwerkParams(seriesList); - console.log('seriesList', chwSeriesList); - let chartContainer = useRef(null); - // TODO: use models to parse options and series + const series = new Series(data, timeRange, options.gauge.value).getChartwerkSeries(); + console.log('series', series); + const chartwerkOptions = new Options(options).getChartwerkOptions(); - // we request animation frame here because at the moment we need an existing DOM-element at the moment we render the pod + let chartContainer = useRef(null); + // we request animation frame here because we need an existing DOM-element at the moment we render the pod window.requestAnimationFrame(() => { - // TODO: pass datapoints - // TODO: pass options // TODO: switch / case pod type - const pod = new ChartwerkGaugePod((chartContainer as any).current, chwSeriesList, { - maxValue: options.gauge.max, - minValue: options.gauge.min, - valueFormatter: (val) => val.toFixed(2), - defaultColor: 'green', - stops: [ - { - color: 'green', - value: 100, - }, - { - color: 'orange', - value: 140, - }, - ], - // @ts-ignore - icons: [{ src: 'https://cityhost.ua/upload_img/blog5ef308ea5529c_trash2-01.jpg', position: 'middle', size: 30 }], - }); + const pod = new ChartwerkGaugePod( + (chartContainer as any).current, + series, + chartwerkOptions + ); pod.render(); }); return ( @@ -60,14 +40,3 @@ export function Panel({ options, data, width, height, timeZone, timeRange, onCha > ); } - -function updateSeriesListWithChartwerkParams(series: any[]): any[] { - return _.map(series, (serie: any, idx: number) => { - return { - target: serie.alias, - color: serie.color, - datapoints: _.map(serie.datapoints, (row) => _.reverse(row)), - alias: serie.label, - }; - }); -} diff --git a/src/models/options.ts b/src/models/options.ts new file mode 100644 index 0000000..01d32d3 --- /dev/null +++ b/src/models/options.ts @@ -0,0 +1,27 @@ +import { PanelOptions } from 'types'; + +// Convert Grafana options into Chartwerk options +export class Options { + constructor(private grafanaOptions: PanelOptions) {} + + public getChartwerkOptions(): any { + return { + maxValue: this.grafanaOptions.gauge.max.value || 0, + minValue: this.grafanaOptions.gauge.min.value || 0, + valueFormatter: (val: any) => val.toFixed(2), + defaultColor: 'green', + stops: [ + { + color: 'green', + value: 100, + }, + { + color: 'orange', + value: 140, + }, + ], + // @ts-ignore + icons: [{ src: 'https://cityhost.ua/upload_img/blog5ef308ea5529c_trash2-01.jpg', position: 'middle', size: 30 }], + }; + } +} diff --git a/src/models/series.ts b/src/models/series.ts new file mode 100644 index 0000000..1c34f98 --- /dev/null +++ b/src/models/series.ts @@ -0,0 +1,59 @@ +import { PanelData, TimeRange } from '@grafana/data'; +import { DataProcessor } from '../grafana/data_processor'; + +import { ExtremumOptions } from 'types'; + +import * as _ from 'lodash'; + +// Convert Grafana options into Chartwerk options +export class Series { + private processor; + private _seriesList; + private _selectedSerieName; + + constructor(grafanaData: PanelData, timeRange: TimeRange, private gaugeValueOptions: ExtremumOptions) { + if(this._isSerieOneValue()) { + this._seriesList = [{ datapoints: [[0, gaugeValueOptions.value]] }]; + return; + } + if(this.gaugeValueOptions.useMetric && _.isEmpty(this.gaugeValueOptions.metricName)) { + throw new Error(`Value or metric is not selected.`); + } + + this._selectedSerieName = this.gaugeValueOptions.metricName; + this.processor = new DataProcessor({}); + const seriesList = this.processor.getSeriesList({ + dataList: grafanaData.series, + range: timeRange, + }); + + const filteredSeries = _.filter(seriesList, serie => serie.alias === this._selectedSerieName); + if(filteredSeries.length === 0) { + throw new Error(`Can't find metric for ${this._selectedSerieName} name`); + } + if(filteredSeries.length > 1) { + throw new Error(`Get ${filteredSeries.length} metrics for ${this._selectedSerieName} name. Please choose one`); + } + + this._seriesList = this._updateSeriesListWithChartwerkParams(filteredSeries); + } + + public getChartwerkSeries(): any[] { + return this._seriesList; + } + + private _updateSeriesListWithChartwerkParams(series: any[]): any[] { + return _.map(series, (serie: any, idx: number) => { + return { + target: serie.alias, + color: serie.color, + datapoints: _.map(serie.datapoints, (row) => _.reverse(row)), + alias: serie.label, + }; + }); + } + + private _isSerieOneValue(): boolean { + return !this.gaugeValueOptions.useMetric; + } +} diff --git a/src/module.ts b/src/module.ts index 3cefdac..84217f1 100644 --- a/src/module.ts +++ b/src/module.ts @@ -30,38 +30,57 @@ export const plugin = new PanelPlugin(Panel).setPanelOptions((buil }, }) .addNumberInput({ - path: 'gauge.min', + name: 'Value', + path: 'gauge.value.value', + category: ['Extremum'], + showIf: (config) => config.visualizationType === Pod.GAUGE && !config.gauge.value.useMetric, + }) + .addFieldNamePicker({ + name: 'Value', + path: 'gauge.value.metricName', + category: ['Extremum'], + showIf: (config) => config.visualizationType === Pod.GAUGE && config.gauge.value.useMetric, + }) + .addBooleanSwitch({ + path: 'gauge.value.useMetric', + name: 'Use metric', + defaultValue: false, + category: ['Extremum'], + showIf: (config) => config.visualizationType === Pod.GAUGE, + }) + .addNumberInput({ + path: 'gauge.min.value', name: 'Min', category: ['Extremum'], - showIf: (config) => config.visualizationType === Pod.GAUGE && !config.gauge.useMetricForMin, + showIf: (config) => config.visualizationType === Pod.GAUGE && !config.gauge.min.useMetric, }) .addFieldNamePicker({ name: 'Min', - path: 'gauge.minMetricName', + path: 'gauge.min.metricName', category: ['Extremum'], - showIf: (config) => config.visualizationType === Pod.GAUGE && config.gauge.useMetricForMin, + showIf: (config) => config.visualizationType === Pod.GAUGE && config.gauge.min.useMetric, }) .addBooleanSwitch({ - path: 'gauge.useMetricForMin', + path: 'gauge.min.useMetric', name: 'Use metric', defaultValue: false, category: ['Extremum'], showIf: (config) => config.visualizationType === Pod.GAUGE, }) .addNumberInput({ - path: 'gauge.max', + path: 'gauge.max.value', name: 'Max', category: ['Extremum'], - showIf: (config) => config.visualizationType === Pod.GAUGE && !config.gauge.useMetricForMax, + showIf: (config) => config.visualizationType === Pod.GAUGE && !config.gauge.max.useMetric, }) .addFieldNamePicker({ name: 'Max', - path: 'gauge.maxMetricName', + path: 'gauge.max.metricName', category: ['Extremum'], - showIf: (config) => config.visualizationType === Pod.GAUGE && config.gauge.useMetricForMax, + showIf: (config) => config.visualizationType === Pod.GAUGE && config.gauge.max.useMetric, }) .addBooleanSwitch({ - path: 'gauge.useMetricForMax', + path: 'gauge.max.useMetric', name: 'Use metric', defaultValue: false, category: ['Extremum'], diff --git a/src/types.ts b/src/types.ts index 0950057..22e89bb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,15 +1,18 @@ export interface PanelOptions { visualizationType: Pod; gauge: { - min?: number; - useMetricForMin: boolean; - minMetricName: string; - max?: number; - useMetricForMax: boolean; - maxMetricName: string; + min: ExtremumOptions; + max: ExtremumOptions; + value: ExtremumOptions; }; } +export type ExtremumOptions = { + value?: number; + useMetric: false; + metricName: string; +}; + export enum Pod { LINE = 'Line', BAR = 'Bar',