From f6e525365d462bc9de1274f9a87349436a4ce983 Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 3 May 2022 18:23:32 +0300 Subject: [PATCH 1/8] options for value --- src/module.ts | 19 +++++++++++++++++++ src/types.ts | 3 +++ 2 files changed, 22 insertions(+) diff --git a/src/module.ts b/src/module.ts index 3cefdac..c8fef42 100644 --- a/src/module.ts +++ b/src/module.ts @@ -29,6 +29,25 @@ export const plugin = new PanelPlugin(Panel).setPanelOptions((buil ], }, }) + .addNumberInput({ + name: 'Value', + path: 'gauge.value', + category: ['Extremum'], + showIf: (config) => config.visualizationType === Pod.GAUGE && !config.gauge.useMetricForValue, + }) + .addFieldNamePicker({ + name: 'Value', + path: 'gauge.valueMetricName', + category: ['Extremum'], + showIf: (config) => config.visualizationType === Pod.GAUGE && config.gauge.useMetricForValue, + }) + .addBooleanSwitch({ + path: 'gauge.useMetricForValue', + name: 'Use metric', + defaultValue: false, + category: ['Extremum'], + showIf: (config) => config.visualizationType === Pod.GAUGE, + }) .addNumberInput({ path: 'gauge.min', name: 'Min', diff --git a/src/types.ts b/src/types.ts index 0950057..b44a56e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,6 +7,9 @@ export interface PanelOptions { max?: number; useMetricForMax: boolean; maxMetricName: string; + value?: number; + useMetricForValue: boolean; + valueMetricName: string; }; } From 73faf80ccbaa0e2564f08d0e2d6dc9f4c442969d Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 3 May 2022 19:58:34 +0300 Subject: [PATCH 2/8] gauge config --- src/components/Panel.tsx | 4 ++-- src/module.ts | 30 +++++++++++++++--------------- src/types.ts | 24 +++++++++++++++--------- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index ca1b6e5..101c7bf 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -31,8 +31,8 @@ export function Panel({ options, data, width, height, timeZone, timeRange, onCha // 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, + maxValue: options.gauge.max.value || 0, + minValue: options.gauge.min.value || 0, valueFormatter: (val) => val.toFixed(2), defaultColor: 'green', stops: [ diff --git a/src/module.ts b/src/module.ts index c8fef42..84217f1 100644 --- a/src/module.ts +++ b/src/module.ts @@ -31,56 +31,56 @@ export const plugin = new PanelPlugin(Panel).setPanelOptions((buil }) .addNumberInput({ name: 'Value', - path: 'gauge.value', + path: 'gauge.value.value', category: ['Extremum'], - showIf: (config) => config.visualizationType === Pod.GAUGE && !config.gauge.useMetricForValue, + showIf: (config) => config.visualizationType === Pod.GAUGE && !config.gauge.value.useMetric, }) .addFieldNamePicker({ name: 'Value', - path: 'gauge.valueMetricName', + path: 'gauge.value.metricName', category: ['Extremum'], - showIf: (config) => config.visualizationType === Pod.GAUGE && config.gauge.useMetricForValue, + showIf: (config) => config.visualizationType === Pod.GAUGE && config.gauge.value.useMetric, }) .addBooleanSwitch({ - path: 'gauge.useMetricForValue', + path: 'gauge.value.useMetric', name: 'Use metric', defaultValue: false, category: ['Extremum'], showIf: (config) => config.visualizationType === Pod.GAUGE, }) .addNumberInput({ - path: 'gauge.min', + 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 b44a56e..46814a9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,15 +1,21 @@ export interface PanelOptions { visualizationType: Pod; gauge: { - min?: number; - useMetricForMin: boolean; - minMetricName: string; - max?: number; - useMetricForMax: boolean; - maxMetricName: string; - value?: number; - useMetricForValue: boolean; - valueMetricName: string; + min: { + value?: number; + useMetric: false; + metricName: string; + }; + max: { + value?: number; + useMetric: false; + metricName: string; + }; + value: { + value?: number; + useMetric: false; + metricName: string; + }; }; } From a01567f24a7ec64ff8139e42f4e8bea783cf8a15 Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 3 May 2022 20:16:18 +0300 Subject: [PATCH 3/8] add models to parse data and options --- src/components/Panel.tsx | 50 +++++++++------------------------------- src/models/options.ts | 27 ++++++++++++++++++++++ src/models/series.ts | 34 +++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 39 deletions(-) create mode 100644 src/models/options.ts create mode 100644 src/models/series.ts diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index 101c7bf..f796534 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -1,4 +1,6 @@ import { DataProcessor } from '../grafana/data_processor'; +import { Options } from '../models/options'; +import { Series } from '../models/series'; import { PanelOptions } from '../types'; @@ -14,40 +16,21 @@ 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).getChartwerkSeries(); + console.log('series', series); + const chartwerkOptions = new Options(options).getChartwerkOptions(); + let chartContainer = useRef(null); // we request animation frame here because at the moment 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.value || 0, - minValue: options.gauge.min.value || 0, - 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 +43,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..cf83f5f --- /dev/null +++ b/src/models/series.ts @@ -0,0 +1,34 @@ +import { PanelData, TimeRange } from '@grafana/data'; +import { DataProcessor } from '../grafana/data_processor'; + +import * as _ from 'lodash'; + +// Convert Grafana options into Chartwerk options +export class Series { + private processor; + private _seriesList; + + constructor(private grafanaData: PanelData, timeRange: TimeRange) { + this.processor = new DataProcessor({}); + const seriesList = this.processor.getSeriesList({ + dataList: grafanaData.series, + range: timeRange, + }); + this._seriesList = this._updateSeriesListWithChartwerkParams(seriesList); + } + + 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, + }; + }); + } +} From 7359dab6c5dc3150a4019904aba268e6a4c7e189 Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 3 May 2022 20:41:52 +0300 Subject: [PATCH 4/8] serie as one value --- src/components/Panel.tsx | 2 +- src/models/series.ts | 19 +++++++++++++++---- src/types.ts | 24 +++++++++--------------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index f796534..ad96de6 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -16,7 +16,7 @@ interface Props extends PanelProps {} export function Panel({ options, data, width, height, timeZone, timeRange, onChangeTimeRange }: Props) { console.log('options', options); - const series = new Series(data, timeRange).getChartwerkSeries(); + const series = new Series(data, timeRange, options.gauge.value).getChartwerkSeries(); console.log('series', series); const chartwerkOptions = new Options(options).getChartwerkOptions(); diff --git a/src/models/series.ts b/src/models/series.ts index cf83f5f..590c838 100644 --- a/src/models/series.ts +++ b/src/models/series.ts @@ -1,6 +1,8 @@ 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 @@ -8,17 +10,22 @@ export class Series { private processor; private _seriesList; - constructor(private grafanaData: PanelData, timeRange: TimeRange) { + constructor(private grafanaData: PanelData, timeRange: TimeRange, private gaugeValueOptions: ExtremumOptions) { + if(this._isSerieOneValue()) { + this._seriesList = [{ datapoints: [[0, gaugeValueOptions.value]] }]; + return; + } + this.processor = new DataProcessor({}); - const seriesList = this.processor.getSeriesList({ + this._seriesList = this.processor.getSeriesList({ dataList: grafanaData.series, range: timeRange, }); - this._seriesList = this._updateSeriesListWithChartwerkParams(seriesList); + this._seriesList = this._updateSeriesListWithChartwerkParams(this._seriesList); } public getChartwerkSeries(): any[] { - return this._seriesList; + return this._seriesList } private _updateSeriesListWithChartwerkParams(series: any[]): any[] { @@ -31,4 +38,8 @@ export class Series { }; }); } + + private _isSerieOneValue(): boolean { + return _.isNumber(this.gaugeValueOptions.value); + } } diff --git a/src/types.ts b/src/types.ts index 46814a9..22e89bb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,24 +1,18 @@ export interface PanelOptions { visualizationType: Pod; gauge: { - min: { - value?: number; - useMetric: false; - metricName: string; - }; - max: { - value?: number; - useMetric: false; - metricName: string; - }; - value: { - value?: number; - useMetric: false; - metricName: string; - }; + min: ExtremumOptions; + max: ExtremumOptions; + value: ExtremumOptions; }; } +export type ExtremumOptions = { + value?: number; + useMetric: false; + metricName: string; +}; + export enum Pod { LINE = 'Line', BAR = 'Bar', From 302f509425914f4aa2e4b4406ae2783edb8af531 Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 3 May 2022 21:08:56 +0300 Subject: [PATCH 5/8] get series from options --- src/components/Panel.tsx | 1 - src/models/series.ts | 28 +++++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index ad96de6..a49992e 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -1,4 +1,3 @@ -import { DataProcessor } from '../grafana/data_processor'; import { Options } from '../models/options'; import { Series } from '../models/series'; diff --git a/src/models/series.ts b/src/models/series.ts index 590c838..7f5bfe5 100644 --- a/src/models/series.ts +++ b/src/models/series.ts @@ -9,23 +9,37 @@ import * as _ from 'lodash'; export class Series { private processor; private _seriesList; + private _selectedSerieName; - constructor(private grafanaData: PanelData, timeRange: TimeRange, private gaugeValueOptions: ExtremumOptions) { + 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({}); - this._seriesList = this.processor.getSeriesList({ - dataList: grafanaData.series, + const series = grafanaData.series; + const seriesList = this.processor.getSeriesList({ + dataList: series, range: timeRange, }); - this._seriesList = this._updateSeriesListWithChartwerkParams(this._seriesList); + console.log('_seriesList', seriesList); + 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`); + } + console.log('filteredSeries', filteredSeries); + this._seriesList = this._updateSeriesListWithChartwerkParams(filteredSeries); } public getChartwerkSeries(): any[] { - return this._seriesList + return this._seriesList; } private _updateSeriesListWithChartwerkParams(series: any[]): any[] { @@ -40,6 +54,6 @@ export class Series { } private _isSerieOneValue(): boolean { - return _.isNumber(this.gaugeValueOptions.value); + return !this.gaugeValueOptions.useMetric; } } From 1580a501d52c46570131423848d09b85d7599918 Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 3 May 2022 21:14:04 +0300 Subject: [PATCH 6/8] fix --- src/models/series.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/models/series.ts b/src/models/series.ts index 7f5bfe5..1c34f98 100644 --- a/src/models/series.ts +++ b/src/models/series.ts @@ -19,14 +19,14 @@ export class Series { 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 series = grafanaData.series; const seriesList = this.processor.getSeriesList({ - dataList: series, + dataList: grafanaData.series, range: timeRange, }); - console.log('_seriesList', seriesList); + const filteredSeries = _.filter(seriesList, serie => serie.alias === this._selectedSerieName); if(filteredSeries.length === 0) { throw new Error(`Can't find metric for ${this._selectedSerieName} name`); @@ -34,7 +34,7 @@ export class Series { if(filteredSeries.length > 1) { throw new Error(`Get ${filteredSeries.length} metrics for ${this._selectedSerieName} name. Please choose one`); } - console.log('filteredSeries', filteredSeries); + this._seriesList = this._updateSeriesListWithChartwerkParams(filteredSeries); } From b6f447f55df7c2b77b7903604a12cf9fff61575b Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 3 May 2022 21:14:36 +0300 Subject: [PATCH 7/8] remove todo --- src/components/Panel.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index a49992e..9f41129 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -22,8 +22,6 @@ export function Panel({ options, data, width, height, timeZone, timeRange, onCha let chartContainer = useRef(null); // we request animation frame here because at the moment 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, From e26aaddef0efbdd6b6fff81eaaddeba6809588f8 Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 3 May 2022 21:15:59 +0300 Subject: [PATCH 8/8] fix comment --- src/components/Panel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index 9f41129..9363cdf 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -20,7 +20,7 @@ export function Panel({ options, data, width, height, timeZone, timeRange, onCha const chartwerkOptions = new Options(options).getChartwerkOptions(); let chartContainer = useRef(null); - // we request animation frame here because at the moment we need an existing DOM-element at the moment we render the pod + // we request animation frame here because we need an existing DOM-element at the moment we render the pod window.requestAnimationFrame(() => { // TODO: switch / case pod type const pod = new ChartwerkGaugePod(