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); } }