Browse Source

Merge branch 'bar-pod-vis' into 'main'

WIP: Bar pod init

See merge request chartwerk/grafana-chartwerk-panel!8
merge-requests/8/merge
Alexander Velikiy 2 years ago
parent
commit
8d33d85e5a
  1. 5
      package.json
  2. 31
      src/components/Panel.tsx
  3. 25
      src/models/barSeries.ts
  4. 155
      src/models/options/barOptions.ts
  5. 4
      src/models/options/gaugeOptions.ts
  6. 66
      yarn.lock

5
package.json

@ -1,6 +1,6 @@
{
"name": "grafana-chartwerk-panel",
"version": "0.4.0",
"version": "0.4.1",
"description": "Chartwerk Panel",
"scripts": {
"build": "grafana-toolkit plugin:build",
@ -14,7 +14,8 @@
"author": "CorpGlory Inc.",
"license": "GPL V3",
"devDependencies": {
"@chartwerk/gauge-pod": "0.4.1",
"@chartwerk/gauge-pod": "0.5.0",
"@chartwerk/bar-pod": "0.5.0",
"@grafana/data": "latest",
"@grafana/toolkit": "latest",
"@grafana/ui": "latest",

31
src/components/Panel.tsx

@ -1,11 +1,14 @@
import { Options } from '../models/options';
import { GaugeOptions } from '../models/options/gaugeOptions';
import { BarOptions } from '../models/options/barOptions';
import { Series } from '../models/series';
import { BarSeries } from '../models/barSeries';
import { PanelOptions } from '../types';
import { PanelOptions, Pod } from '../types';
import { DataProcessor } from '../grafana/data_processor';
import { ChartwerkGaugePod } from '@chartwerk/gauge-pod';
import { ChartwerkBarPod } from '@chartwerk/bar-pod';
import { PanelData, TimeRange, PanelProps } from '@grafana/data';
@ -16,17 +19,29 @@ import * as _ from 'lodash';
interface Props extends PanelProps<PanelOptions> {}
export function Panel({ options, data, width, height, timeZone, timeRange, onChangeTimeRange }: Props) {
console.log('options', options);
console.log('panelOptions', options);
const grafanaSeriesList = getGrafanaSeriesList(data, timeRange);
const series = new Series(grafanaSeriesList, options.gauge.value).getChartwerkSeries();
console.log('series', series);
const chartwerkOptions = new Options(grafanaSeriesList, options).getChartwerkOptions();
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: switch / case pod type
const pod = new ChartwerkGaugePod((chartContainer as any).current, series, chartwerkOptions);
console.log('pod', options.visualizationType);
let pod;
switch (options.visualizationType) {
case Pod.GAUGE:
const series = new Series(grafanaSeriesList, options.gauge.value).getChartwerkSeries();
const chartwerkGaugeOptions = new GaugeOptions(grafanaSeriesList, options).getChartwerkOptions();
pod = new ChartwerkGaugePod((chartContainer as any).current, series, chartwerkGaugeOptions);
break;
case Pod.BAR:
const barSeries = new BarSeries(grafanaSeriesList).getChartwerkSeries();
const chartwerkBarOptions = new BarOptions(grafanaSeriesList, options).getChartwerkOptions();
console.log('data', barSeries, chartwerkBarOptions);
pod = new ChartwerkBarPod((chartContainer as any).current, barSeries, chartwerkBarOptions);
break;
default:
throw new Error(`Unknown visualization type: ${options.visualizationType}`);
}
pod.render();
});

25
src/models/barSeries.ts

@ -0,0 +1,25 @@
import * as _ from 'lodash';
// Convert Grafana series into Chartwerk series
export class BarSeries {
private _seriesList;
constructor(grafanaSeriesList: any) {
this._seriesList = this._updateSeriesListWithChartwerkParams(grafanaSeriesList);
}
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(_.clone(row))),
alias: serie.label,
};
});
}
}

155
src/models/options/barOptions.ts

@ -0,0 +1,155 @@
import { PanelOptions, Aggregation, Threshold, Icon, IconPosition, Condition } from 'types';
import { filterMetricListByAlias, getAggregatedValueFromSerie } from '../../utils';
import _ from 'lodash';
// Convert Grafana options into Chartwerk Bar options
export class BarOptions {
private thresholds: Array<{ value: number; color: string }> = [];
private icons: Array<{ src: string; position: string; size: number }> = [];
constructor(private grafanaSeriesList: any[], private grafanaOptions: PanelOptions) {
this._setThresholds();
this._setIcons();
}
private _setThresholds(): void {
if (_.isEmpty(this.grafanaOptions.gauge.thresholds.thresholds)) {
return;
}
for (let [idx, threshold] of this.grafanaOptions.gauge.thresholds.thresholds.entries()) {
this._setThreshold(threshold, idx);
}
}
private _setThreshold(threshold: Threshold, idx: number): void {
const value = threshold.useMetric
? this.getLastValueFromMetrics(threshold.metricName, `Threshold ${idx + 1}`)
: threshold.value;
if (value === null || value === undefined) {
// TODO: may be throw an error
return;
}
this.thresholds.push({
value,
color: threshold.color,
});
}
private _setIcons(): void {
if (_.isEmpty(this.grafanaOptions.gauge.icons)) {
return;
}
for (let [idx, icon] of this.grafanaOptions.gauge.icons.entries()) {
this._setIcon(icon, idx);
}
}
private _setIcon(icon: Icon, idx: number): void {
if (!this._areIconConditionsFulfilled(icon, idx)) {
return;
}
this.icons.push({
src: icon.url,
size: icon.size,
position: this._getChartwerkIconPosition(icon.position),
});
}
private _areIconConditionsFulfilled(icon: Icon, iconIdx: number): boolean {
if (_.isEmpty(icon.metrics)) {
return true;
}
// check each condition and return false if something goes wrong
for (let [conditionIdx, metric] of icon.metrics.entries()) {
const value = this.getLastValueFromMetrics(metric, `Icon ${iconIdx + 1}, Condition ${conditionIdx + 1}`);
if (value === null || value === undefined) {
// TODO: may be throw an error
return false;
}
if (!this.checkIconCondition(value, icon.values[conditionIdx], icon.conditions[conditionIdx])) {
return false;
}
}
return true;
}
private checkIconCondition(metricValue: number, inputValue: number, condition: Condition): boolean {
if (inputValue === undefined || inputValue === null) {
return true;
}
switch (condition) {
case Condition.EQUAL:
return metricValue === inputValue;
case Condition.GREATER:
return metricValue > inputValue;
case Condition.GREATER_OR_EQUAL:
return metricValue >= inputValue;
case Condition.LESS:
return metricValue < inputValue;
case Condition.LESS_OR_EQUAL:
return metricValue <= inputValue;
default:
throw new Error(`Unknown condition: ${condition}`);
}
}
private _getChartwerkIconPosition(position: IconPosition): string {
// TODO: use chartwerk types
switch (position) {
case IconPosition.MIDDLE:
return 'middle';
case IconPosition.UPPER_LEFT:
return 'left';
case IconPosition.UPPER_RIGHT:
return 'right';
default:
throw new Error(`Unknown Icon Position ${position}`);
}
}
getChartwerkOptions(): any {
return {
axis: {
x: {
format: 'custom',
valueFormatter: (value: any) => {
return 'L' + value;
},
},
y: {
format: 'custom',
range: [-100, 100],
valueFormatter: (value: any) => {
return value + '%';
},
},
},
stacked: false,
matching: false,
zoomEvents: {
scroll: { zoom: { isActive: false }, pan: { isActive: false } },
},
annotations: [
{ key: 'm-1', color: 'red' },
{ key: 'm-2', color: 'green' },
],
eventsCallbacks: {
zoomIn: (range: any) => {
console.log('range', range);
},
},
};
}
getLastValueFromMetrics(metricName: string | undefined, optionName: string): number | null {
// optionName -> helper in Error, mb use option path instead
const filteredSeries = filterMetricListByAlias(this.grafanaSeriesList, metricName, optionName);
const serie = filteredSeries[0];
// Last value for now
return getAggregatedValueFromSerie(serie, Aggregation.LAST);
}
}

4
src/models/options.ts → src/models/options/gaugeOptions.ts

@ -1,13 +1,13 @@
import { PanelOptions, Aggregation, Threshold, Icon, IconPosition, Condition } from 'types';
import { filterMetricListByAlias, getAggregatedValueFromSerie } from '../utils';
import { filterMetricListByAlias, getAggregatedValueFromSerie } from '../../utils';
import { getValueFormat } from '@grafana/data';
import _ from 'lodash';
// Convert Grafana options into Chartwerk Gauge options
export class Options {
export class GaugeOptions {
private minValue: number | undefined;
private maxValue: number | undefined;
private thresholds: Array<{ value: number; color: string }> = [];

66
yarn.lock

@ -902,16 +902,27 @@
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.0.tgz#fe364f025ba74f6de6c837a84ef44bdb1d61e68f"
integrity sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==
"@chartwerk/core@github:chartwerk/core#a30ca83842247c79969deaaacfc7fb444a60cefb":
version "0.1.0"
resolved "https://codeload.github.com/chartwerk/core/tar.gz/a30ca83842247c79969deaaacfc7fb444a60cefb"
"@chartwerk/bar-pod@0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@chartwerk/bar-pod/-/bar-pod-0.5.0.tgz#8550800fa33f2ea49285a3a3a36c04a802d14d9b"
integrity sha512-qZIq0Eq5VDhtcrKusL/gKRRNr4g1tDIRQ0uZd6hGG8LYeT8s5AUG1tYZNNrROutMTKvvaSg56XoQKBY9xvZZaA==
dependencies:
"@chartwerk/core" "^0.5.0"
"@chartwerk/gauge-pod@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@chartwerk/gauge-pod/-/gauge-pod-0.4.1.tgz#ac346d777f72ec855e51f5f7c8c01e12a1e1cb5c"
integrity sha512-Ik6Dr4AJP/L+7YjZVJ9W19ujXXB5/b5A3Qxboi491hrXYlqMrfAx/LoyfDAtSEmGNhK5qpT8XLluzuHVcgTY4g==
"@chartwerk/core@^0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@chartwerk/core/-/core-0.5.0.tgz#7d641a5ee3ec9ca588f5b06a0504659113745636"
integrity sha512-YFqBJ8WFb83yZO2VR+XVRSMX3+ErGcGcdHy5aLeLzOqBW09gO7NENdzlCWXQLsGSx+f9RK2GcSTM4z0Q7OEDfA==
dependencies:
"@chartwerk/core" "github:chartwerk/core#a30ca83842247c79969deaaacfc7fb444a60cefb"
d3 "^5.7.2"
lodash "^4.14.149"
"@chartwerk/gauge-pod@0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@chartwerk/gauge-pod/-/gauge-pod-0.5.0.tgz#4bf1022b5ae3b9536ef3a5bcb0f872fbd9c685d4"
integrity sha512-x+MK737RB8h3c42GJUZoGDKfOcdtwCP58KLdxctzVzH9b0oHdnEGO+BE5M/EwPuoSq1H5F4DqBg8NCLfIVTlvw==
dependencies:
"@chartwerk/core" "^0.5.0"
"@cnakazawa/watch@^1.0.3":
version "1.0.4"
@ -4811,6 +4822,43 @@ d3@5.15.0:
d3-voronoi "1"
d3-zoom "1"
d3@^5.7.2:
version "5.16.0"
resolved "https://registry.yarnpkg.com/d3/-/d3-5.16.0.tgz#9c5e8d3b56403c79d4ed42fbd62f6113f199c877"
integrity sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==
dependencies:
d3-array "1"
d3-axis "1"
d3-brush "1"
d3-chord "1"
d3-collection "1"
d3-color "1"
d3-contour "1"
d3-dispatch "1"
d3-drag "1"
d3-dsv "1"
d3-ease "1"
d3-fetch "1"
d3-force "1"
d3-format "1"
d3-geo "1"
d3-hierarchy "1"
d3-interpolate "1"
d3-path "1"
d3-polygon "1"
d3-quadtree "1"
d3-random "1"
d3-scale "2"
d3-scale-chromatic "1"
d3-selection "1"
d3-shape "1"
d3-time "1"
d3-time-format "2"
d3-timer "1"
d3-transition "1"
d3-voronoi "1"
d3-zoom "1"
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@ -8030,7 +8078,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@4.17.21, lodash@^4.1.1, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.7.0:
lodash@4.17.21, lodash@^4.1.1, lodash@^4.14.149, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.7.0:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==

Loading…
Cancel
Save