mirror of
https://github.com/grafana/grafana.git
synced 2024-11-21 16:38:03 -06:00
Chore: Fix noImplicitAny issues (#17636)
* noImplicitAny: TableRenderer * noImplicitAny and add types * HeatmapData interface * Heatmap rendering * Fix optional type * Remove use of lodash
This commit is contained in:
parent
7eb820081d
commit
17826796da
@ -189,6 +189,7 @@
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "7.2.5",
|
||||
"@torkelo/react-select": "2.4.1",
|
||||
"@types/angular-route": "1.7.0",
|
||||
"@types/react-redux": "^7.0.8",
|
||||
"@types/reselect": "2.2.0",
|
||||
"angular": "1.6.6",
|
||||
|
@ -1,24 +1,16 @@
|
||||
import _ from 'lodash';
|
||||
import { TimeSeries } from 'app/core/core';
|
||||
import { Bucket, HeatmapCard, HeatmapCardStats, YBucket, XBucket } from './types';
|
||||
|
||||
const VALUE_INDEX = 0;
|
||||
const TIME_INDEX = 1;
|
||||
|
||||
interface XBucket {
|
||||
x: number;
|
||||
buckets: any;
|
||||
}
|
||||
|
||||
interface YBucket {
|
||||
y: number;
|
||||
values: number[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert histogram represented by the list of series to heatmap object.
|
||||
* @param seriesList List of time series
|
||||
*/
|
||||
function histogramToHeatmap(seriesList) {
|
||||
const heatmap = {};
|
||||
function histogramToHeatmap(seriesList: TimeSeries[]) {
|
||||
const heatmap: any = {};
|
||||
|
||||
for (let i = 0; i < seriesList.length; i++) {
|
||||
const series = seriesList[i];
|
||||
@ -59,7 +51,7 @@ function histogramToHeatmap(seriesList) {
|
||||
/**
|
||||
* Sort series representing histogram by label value.
|
||||
*/
|
||||
function sortSeriesByLabel(s1, s2) {
|
||||
function sortSeriesByLabel(s1: { label: string }, s2: { label: string }) {
|
||||
let label1, label2;
|
||||
|
||||
try {
|
||||
@ -93,22 +85,6 @@ function parseHistogramLabel(label: string): number {
|
||||
return value;
|
||||
}
|
||||
|
||||
interface HeatmapCard {
|
||||
x: number;
|
||||
y: number;
|
||||
yBounds: {
|
||||
top: number | null;
|
||||
bottom: number | null;
|
||||
};
|
||||
values: number[];
|
||||
count: number;
|
||||
}
|
||||
|
||||
interface HeatmapCardStats {
|
||||
min: number;
|
||||
max: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert buckets into linear array of "cards" - objects, represented heatmap elements.
|
||||
* @param {Object} buckets
|
||||
@ -162,11 +138,11 @@ function convertToCards(buckets: any, hideZero = false): { cards: HeatmapCard[];
|
||||
* @param {Number} minValue Minimum series value
|
||||
* @return {Object} Transformed buckets
|
||||
*/
|
||||
function mergeZeroBuckets(buckets, minValue) {
|
||||
function mergeZeroBuckets(buckets: any, minValue: number) {
|
||||
_.forEach(buckets, xBucket => {
|
||||
const yBuckets = xBucket.buckets;
|
||||
|
||||
const emptyBucket = {
|
||||
const emptyBucket: any = {
|
||||
bounds: { bottom: 0, top: 0 },
|
||||
values: [],
|
||||
points: [],
|
||||
@ -176,7 +152,7 @@ function mergeZeroBuckets(buckets, minValue) {
|
||||
const nullBucket = yBuckets[0] || emptyBucket;
|
||||
const minBucket = yBuckets[minValue] || emptyBucket;
|
||||
|
||||
const newBucket = {
|
||||
const newBucket: any = {
|
||||
y: 0,
|
||||
bounds: { bottom: minValue, top: minBucket.bounds.top || minValue },
|
||||
values: [],
|
||||
@ -228,7 +204,7 @@ function mergeZeroBuckets(buckets, minValue) {
|
||||
* xBucketBound_N: {}
|
||||
* }
|
||||
*/
|
||||
function convertToHeatMap(seriesList, yBucketSize, xBucketSize, logBase = 1) {
|
||||
function convertToHeatMap(seriesList: TimeSeries[], yBucketSize: number, xBucketSize: number, logBase = 1) {
|
||||
const heatmap = {};
|
||||
|
||||
for (const series of seriesList) {
|
||||
@ -264,7 +240,7 @@ function convertToHeatMap(seriesList, yBucketSize, xBucketSize, logBase = 1) {
|
||||
return heatmap;
|
||||
}
|
||||
|
||||
function pushToXBuckets(buckets, point, bucketNum, seriesName) {
|
||||
function pushToXBuckets(buckets: any, point: any[], bucketNum: number, seriesName: string) {
|
||||
const value = point[VALUE_INDEX];
|
||||
if (value === null || value === undefined || isNaN(value)) {
|
||||
return;
|
||||
@ -285,7 +261,13 @@ function pushToXBuckets(buckets, point, bucketNum, seriesName) {
|
||||
}
|
||||
}
|
||||
|
||||
function pushToYBuckets(buckets, bucketNum, value, point, bounds) {
|
||||
function pushToYBuckets(
|
||||
buckets: Bucket,
|
||||
bucketNum: number,
|
||||
value: any,
|
||||
point: string[],
|
||||
bounds: { bottom: number; top: number }
|
||||
) {
|
||||
let count = 1;
|
||||
// Use the 3rd argument as scale/count
|
||||
if (point.length > 3) {
|
||||
@ -306,7 +288,7 @@ function pushToYBuckets(buckets, bucketNum, value, point, bounds) {
|
||||
}
|
||||
}
|
||||
|
||||
function getValueBucketBound(value, yBucketSize, logBase) {
|
||||
function getValueBucketBound(value: any, yBucketSize: number, logBase: number) {
|
||||
if (logBase === 1) {
|
||||
return getBucketBound(value, yBucketSize);
|
||||
} else {
|
||||
@ -317,7 +299,7 @@ function getValueBucketBound(value, yBucketSize, logBase) {
|
||||
/**
|
||||
* Find bucket for given value (for linear scale)
|
||||
*/
|
||||
function getBucketBounds(value, bucketSize) {
|
||||
function getBucketBounds(value: number, bucketSize: number) {
|
||||
let bottom, top;
|
||||
bottom = Math.floor(value / bucketSize) * bucketSize;
|
||||
top = (Math.floor(value / bucketSize) + 1) * bucketSize;
|
||||
@ -325,12 +307,12 @@ function getBucketBounds(value, bucketSize) {
|
||||
return { bottom, top };
|
||||
}
|
||||
|
||||
function getBucketBound(value, bucketSize) {
|
||||
function getBucketBound(value: number, bucketSize: number) {
|
||||
const bounds = getBucketBounds(value, bucketSize);
|
||||
return bounds.bottom;
|
||||
}
|
||||
|
||||
function convertToValueBuckets(xBucket, bucketSize) {
|
||||
function convertToValueBuckets(xBucket: { values: any; points: any }, bucketSize: number) {
|
||||
const values = xBucket.values;
|
||||
const points = xBucket.points;
|
||||
const buckets = {};
|
||||
@ -347,7 +329,7 @@ function convertToValueBuckets(xBucket, bucketSize) {
|
||||
/**
|
||||
* Find bucket for given value (for log scales)
|
||||
*/
|
||||
function getLogScaleBucketBounds(value, yBucketSplitFactor, logBase) {
|
||||
function getLogScaleBucketBounds(value: number, yBucketSplitFactor: number, logBase: number) {
|
||||
let top, bottom;
|
||||
if (value === 0) {
|
||||
return { bottom: 0, top: 0 };
|
||||
@ -371,12 +353,16 @@ function getLogScaleBucketBounds(value, yBucketSplitFactor, logBase) {
|
||||
return { bottom, top };
|
||||
}
|
||||
|
||||
function getLogScaleBucketBound(value, yBucketSplitFactor, logBase) {
|
||||
function getLogScaleBucketBound(value: number, yBucketSplitFactor: number, logBase: number) {
|
||||
const bounds = getLogScaleBucketBounds(value, yBucketSplitFactor, logBase);
|
||||
return bounds.bottom;
|
||||
}
|
||||
|
||||
function convertToLogScaleValueBuckets(xBucket, yBucketSplitFactor, logBase) {
|
||||
function convertToLogScaleValueBuckets(
|
||||
xBucket: { values: any; points: any },
|
||||
yBucketSplitFactor: number,
|
||||
logBase: number
|
||||
) {
|
||||
const values = xBucket.values;
|
||||
const points = xBucket.points;
|
||||
|
||||
@ -395,7 +381,7 @@ function convertToLogScaleValueBuckets(xBucket, yBucketSplitFactor, logBase) {
|
||||
* @param value
|
||||
* @param base logarithm base
|
||||
*/
|
||||
function logp(value, base) {
|
||||
function logp(value: number, base: number) {
|
||||
return Math.log(value) / Math.log(base);
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ const MIN_CARD_SIZE = 1,
|
||||
Y_AXIS_TICK_PADDING = 5,
|
||||
MIN_SELECTION_WIDTH = 2;
|
||||
|
||||
export default function rendering(scope, elem, attrs, ctrl) {
|
||||
export default function rendering(scope: any, elem: any, attrs: any, ctrl: any) {
|
||||
return new HeatmapRenderer(scope, elem, attrs, ctrl);
|
||||
}
|
||||
export class HeatmapRenderer {
|
||||
@ -51,7 +51,7 @@ export class HeatmapRenderer {
|
||||
padding: any;
|
||||
margin: any;
|
||||
dataRangeWidingFactor: number;
|
||||
constructor(private scope, private elem, attrs, private ctrl) {
|
||||
constructor(private scope: any, private elem: any, attrs: any, private ctrl: any) {
|
||||
// $heatmap is JQuery object, but heatmap is D3
|
||||
this.$heatmap = this.elem.find('.heatmap-panel');
|
||||
this.tooltip = new HeatmapTooltip(this.$heatmap, this.scope);
|
||||
@ -89,7 +89,7 @@ export class HeatmapRenderer {
|
||||
this.clearCrosshair();
|
||||
}
|
||||
|
||||
onGraphHover(event) {
|
||||
onGraphHover(event: { pos: any }) {
|
||||
this.drawSharedCrosshair(event.pos);
|
||||
}
|
||||
|
||||
@ -116,7 +116,7 @@ export class HeatmapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
getYAxisWidth(elem) {
|
||||
getYAxisWidth(elem: any) {
|
||||
const axisText = elem.selectAll('.axis-y text').nodes();
|
||||
const maxTextWidth = _.max(
|
||||
_.map(axisText, text => {
|
||||
@ -128,7 +128,7 @@ export class HeatmapRenderer {
|
||||
return maxTextWidth;
|
||||
}
|
||||
|
||||
getXAxisHeight(elem) {
|
||||
getXAxisHeight(elem: any) {
|
||||
const axisLine = elem.select('.axis-x line');
|
||||
if (!axisLine.empty()) {
|
||||
const axisLinePosition = parseFloat(elem.select('.axis-x line').attr('y2'));
|
||||
@ -244,7 +244,7 @@ export class HeatmapRenderer {
|
||||
}
|
||||
|
||||
// Wide Y values range and anjust to bucket size
|
||||
wideYAxisRange(min, max, tickInterval) {
|
||||
wideYAxisRange(min: number, max: number, tickInterval: number) {
|
||||
const yWiding = (max * (this.dataRangeWidingFactor - 1) - min * (this.dataRangeWidingFactor - 1)) / 2;
|
||||
let yMin, yMax;
|
||||
|
||||
@ -349,7 +349,7 @@ export class HeatmapRenderer {
|
||||
this.ctrl.decimals = decimals;
|
||||
|
||||
const tickValueFormatter = this.tickValueFormatter.bind(this);
|
||||
function tickFormatter(valIndex) {
|
||||
function tickFormatter(valIndex: string) {
|
||||
let valueFormatted = tsBuckets[valIndex];
|
||||
if (!_.isNaN(_.toNumber(valueFormatted)) && valueFormatted !== '') {
|
||||
// Try to format numeric tick labels
|
||||
@ -393,7 +393,7 @@ export class HeatmapRenderer {
|
||||
}
|
||||
|
||||
// Adjust data range to log base
|
||||
adjustLogRange(min, max, logBase) {
|
||||
adjustLogRange(min: number, max: number, logBase: number) {
|
||||
let yMin = this.data.heatmapStats.minLog;
|
||||
if (this.data.heatmapStats.minLog > 1 || !this.data.heatmapStats.minLog) {
|
||||
yMin = 1;
|
||||
@ -407,15 +407,15 @@ export class HeatmapRenderer {
|
||||
return { yMin, yMax };
|
||||
}
|
||||
|
||||
adjustLogMax(max, base) {
|
||||
adjustLogMax(max: number, base: number) {
|
||||
return Math.pow(base, Math.ceil(ticksUtils.logp(max, base)));
|
||||
}
|
||||
|
||||
adjustLogMin(min, base) {
|
||||
adjustLogMin(min: number, base: number) {
|
||||
return Math.pow(base, Math.floor(ticksUtils.logp(min, base)));
|
||||
}
|
||||
|
||||
logScaleTickValues(domain, base) {
|
||||
logScaleTickValues(domain: any[], base: number) {
|
||||
const domainMin = domain[0];
|
||||
const domainMax = domain[1];
|
||||
const tickValues = [];
|
||||
@ -437,9 +437,9 @@ export class HeatmapRenderer {
|
||||
return tickValues;
|
||||
}
|
||||
|
||||
tickValueFormatter(decimals, scaledDecimals = null) {
|
||||
tickValueFormatter(decimals: number, scaledDecimals: any = null) {
|
||||
const format = this.panel.yAxis.format;
|
||||
return value => {
|
||||
return (value: any) => {
|
||||
try {
|
||||
return format !== 'none' ? getValueFormat(format)(value, decimals, scaledDecimals) : value;
|
||||
} catch (err) {
|
||||
@ -555,17 +555,17 @@ export class HeatmapRenderer {
|
||||
|
||||
const $cards = this.$heatmap.find('.heatmap-card');
|
||||
$cards
|
||||
.on('mouseenter', event => {
|
||||
.on('mouseenter', (event: any) => {
|
||||
this.tooltip.mouseOverBucket = true;
|
||||
this.highlightCard(event);
|
||||
})
|
||||
.on('mouseleave', event => {
|
||||
.on('mouseleave', (event: any) => {
|
||||
this.tooltip.mouseOverBucket = false;
|
||||
this.resetCardHighLight(event);
|
||||
});
|
||||
}
|
||||
|
||||
highlightCard(event) {
|
||||
highlightCard(event: any) {
|
||||
const color = d3.select(event.target).style('fill');
|
||||
const highlightColor = d3.color(color).darker(2);
|
||||
const strokeColor = d3.color(color).brighter(4);
|
||||
@ -577,7 +577,7 @@ export class HeatmapRenderer {
|
||||
.style('stroke-width', 1);
|
||||
}
|
||||
|
||||
resetCardHighLight(event) {
|
||||
resetCardHighLight(event: any) {
|
||||
d3.select(event.target)
|
||||
.style('fill', this.tooltip.originalFillColor)
|
||||
.style('stroke', this.tooltip.originalFillColor)
|
||||
@ -599,7 +599,7 @@ export class HeatmapRenderer {
|
||||
this.cardHeight = yGridSize ? yGridSize - this.cardPadding * 2 : 0;
|
||||
}
|
||||
|
||||
getCardX(d) {
|
||||
getCardX(d: { x: any }) {
|
||||
let x;
|
||||
if (this.xScale(d.x) < 0) {
|
||||
// Cut card left to prevent overlay
|
||||
@ -611,7 +611,7 @@ export class HeatmapRenderer {
|
||||
return x;
|
||||
}
|
||||
|
||||
getCardWidth(d) {
|
||||
getCardWidth(d: { x: any }) {
|
||||
let w = this.cardWidth;
|
||||
if (this.xScale(d.x) < 0) {
|
||||
// Cut card left to prevent overlay
|
||||
@ -626,7 +626,7 @@ export class HeatmapRenderer {
|
||||
return w;
|
||||
}
|
||||
|
||||
getCardY(d) {
|
||||
getCardY(d: { y: number }) {
|
||||
let y = this.yScale(d.y) + this.chartTop - this.cardHeight - this.cardPadding;
|
||||
if (this.panel.yAxis.logBase !== 1 && d.y === 0) {
|
||||
y = this.chartBottom - this.cardHeight - this.cardPadding;
|
||||
@ -639,7 +639,7 @@ export class HeatmapRenderer {
|
||||
return y;
|
||||
}
|
||||
|
||||
getCardHeight(d) {
|
||||
getCardHeight(d: { y: number }) {
|
||||
const y = this.yScale(d.y) + this.chartTop - this.cardHeight - this.cardPadding;
|
||||
let h = this.cardHeight;
|
||||
|
||||
@ -664,7 +664,7 @@ export class HeatmapRenderer {
|
||||
return h;
|
||||
}
|
||||
|
||||
getCardColor(d) {
|
||||
getCardColor(d: { count: any }) {
|
||||
if (this.panel.color.mode === 'opacity') {
|
||||
return getColorFromHexRgbOrName(
|
||||
this.panel.color.cardColor,
|
||||
@ -675,7 +675,7 @@ export class HeatmapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
getCardOpacity(d) {
|
||||
getCardOpacity(d: { count: any }) {
|
||||
if (this.panel.color.mode === 'opacity') {
|
||||
return this.opacityScale(d.count);
|
||||
} else {
|
||||
@ -683,14 +683,14 @@ export class HeatmapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
getEventOffset(event) {
|
||||
getEventOffset(event: any) {
|
||||
const elemOffset = this.$heatmap.offset();
|
||||
const x = Math.floor(event.clientX - elemOffset.left);
|
||||
const y = Math.floor(event.clientY - elemOffset.top);
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
onMouseDown(event) {
|
||||
onMouseDown(event: any) {
|
||||
const offset = this.getEventOffset(event);
|
||||
this.selection.active = true;
|
||||
this.selection.x1 = offset.x;
|
||||
@ -726,7 +726,7 @@ export class HeatmapRenderer {
|
||||
this.clearCrosshair();
|
||||
}
|
||||
|
||||
onMouseMove(event) {
|
||||
onMouseMove(event: any) {
|
||||
if (!this.heatmap) {
|
||||
return;
|
||||
}
|
||||
@ -747,10 +747,10 @@ export class HeatmapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
getEventPos(event, offset) {
|
||||
getEventPos(event: { pageX: any; pageY: any }, offset: { x: any; y: any }) {
|
||||
const x = this.xScale.invert(offset.x - this.yAxisWidth).valueOf();
|
||||
const y = this.yScale.invert(offset.y - this.chartTop);
|
||||
const pos = {
|
||||
const pos: any = {
|
||||
pageX: event.pageX,
|
||||
pageY: event.pageY,
|
||||
x: x,
|
||||
@ -764,20 +764,20 @@ export class HeatmapRenderer {
|
||||
return pos;
|
||||
}
|
||||
|
||||
emitGraphHoverEvent(pos) {
|
||||
emitGraphHoverEvent(pos: { panelRelY: number; offset: { y: number } }) {
|
||||
// Set minimum offset to prevent showing legend from another panel
|
||||
pos.panelRelY = Math.max(pos.offset.y / this.height, 0.001);
|
||||
// broadcast to other graph panels that we are hovering
|
||||
appEvents.emit('graph-hover', { pos: pos, panel: this.panel });
|
||||
}
|
||||
|
||||
limitSelection(x2) {
|
||||
limitSelection(x2: number) {
|
||||
x2 = Math.max(x2, this.yAxisWidth);
|
||||
x2 = Math.min(x2, this.chartWidth + this.yAxisWidth);
|
||||
return x2;
|
||||
}
|
||||
|
||||
drawSelection(posX1, posX2) {
|
||||
drawSelection(posX1: number, posX2: number) {
|
||||
if (this.heatmap) {
|
||||
this.heatmap.selectAll('.heatmap-selection').remove();
|
||||
const selectionX = Math.min(posX1, posX2);
|
||||
@ -804,7 +804,7 @@ export class HeatmapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
drawCrosshair(position) {
|
||||
drawCrosshair(position: number) {
|
||||
if (this.heatmap) {
|
||||
this.heatmap.selectAll('.heatmap-crosshair').remove();
|
||||
|
||||
@ -825,7 +825,7 @@ export class HeatmapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
drawSharedCrosshair(pos) {
|
||||
drawSharedCrosshair(pos: { x: any }) {
|
||||
if (this.heatmap && this.ctrl.dashboard.graphTooltip !== 0) {
|
||||
const posX = this.xScale(pos.x) + this.yAxisWidth;
|
||||
this.drawCrosshair(posX);
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
calculateBucketSize,
|
||||
isHeatmapDataEqual,
|
||||
} from '../heatmap_data_converter';
|
||||
import { HeatmapData } from '../types';
|
||||
|
||||
describe('isHeatmapDataEqual', () => {
|
||||
const ctx: any = {};
|
||||
@ -248,7 +249,7 @@ describe('Histogram converter', () => {
|
||||
beforeEach(() => {});
|
||||
|
||||
it('should build proper heatmap data', () => {
|
||||
const expectedHeatmap = {
|
||||
const expectedHeatmap: HeatmapData = {
|
||||
'1422774000000': {
|
||||
x: 1422774000000,
|
||||
buckets: {
|
||||
@ -322,7 +323,7 @@ describe('Histogram converter', () => {
|
||||
});
|
||||
|
||||
describe('convertToCards', () => {
|
||||
let buckets = {};
|
||||
let buckets: HeatmapData = {};
|
||||
|
||||
beforeEach(() => {
|
||||
buckets = {
|
||||
|
42
public/app/plugins/panel/heatmap/types.ts
Normal file
42
public/app/plugins/panel/heatmap/types.ts
Normal file
@ -0,0 +1,42 @@
|
||||
export interface Bucket {
|
||||
[x: string]: {
|
||||
y: any;
|
||||
bounds: any;
|
||||
values: any[];
|
||||
points?: any[];
|
||||
count: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface XBucket {
|
||||
x: number;
|
||||
buckets: any;
|
||||
}
|
||||
|
||||
export interface YBucket {
|
||||
y: number;
|
||||
values: number[];
|
||||
}
|
||||
|
||||
export interface HeatmapCard {
|
||||
x: number;
|
||||
y: number;
|
||||
yBounds: {
|
||||
top: number | null;
|
||||
bottom: number | null;
|
||||
};
|
||||
values: number[];
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface HeatmapCardStats {
|
||||
min: number;
|
||||
max: number;
|
||||
}
|
||||
|
||||
export interface HeatmapData {
|
||||
[key: string]: {
|
||||
x: number;
|
||||
buckets: Bucket;
|
||||
};
|
||||
}
|
@ -1,25 +1,27 @@
|
||||
import _ from 'lodash';
|
||||
import { getValueFormat, getColorFromHexRgbOrName, GrafanaThemeType } from '@grafana/ui';
|
||||
import { getValueFormat, getColorFromHexRgbOrName, GrafanaThemeType, ScopedVars } from '@grafana/ui';
|
||||
import { stringToJsRegex } from '@grafana/data';
|
||||
import { ColumnStyle } from '@grafana/ui/src/components/Table/TableCellBuilder';
|
||||
import { dateTime } from '@grafana/ui/src/utils/moment_wrapper';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { TableRenderModel, ColumnRender } from './types';
|
||||
|
||||
export class TableRenderer {
|
||||
formatters: any[];
|
||||
colorState: any;
|
||||
|
||||
constructor(
|
||||
private panel,
|
||||
private table,
|
||||
private isUtc,
|
||||
private sanitize,
|
||||
private templateSrv,
|
||||
private panel: { styles: ColumnStyle[]; pageSize: number },
|
||||
private table: TableRenderModel,
|
||||
private isUtc: boolean,
|
||||
private sanitize: (v: any) => any,
|
||||
private templateSrv: TemplateSrv,
|
||||
private theme?: GrafanaThemeType
|
||||
) {
|
||||
this.initColumns();
|
||||
}
|
||||
|
||||
setTable(table) {
|
||||
setTable(table: TableRenderModel) {
|
||||
this.table = table;
|
||||
|
||||
this.initColumns();
|
||||
@ -52,7 +54,7 @@ export class TableRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
getColorForValue(value, style: ColumnStyle) {
|
||||
getColorForValue(value: number, style: ColumnStyle) {
|
||||
if (!style.thresholds) {
|
||||
return null;
|
||||
}
|
||||
@ -64,7 +66,7 @@ export class TableRenderer {
|
||||
return getColorFromHexRgbOrName(_.first(style.colors), this.theme);
|
||||
}
|
||||
|
||||
defaultCellFormatter(v, style: ColumnStyle) {
|
||||
defaultCellFormatter(v: any, style: ColumnStyle) {
|
||||
if (v === null || v === void 0 || v === undefined) {
|
||||
return '';
|
||||
}
|
||||
@ -80,19 +82,17 @@ export class TableRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
createColumnFormatter(column) {
|
||||
createColumnFormatter(column: ColumnRender) {
|
||||
if (!column.style) {
|
||||
return this.defaultCellFormatter;
|
||||
}
|
||||
|
||||
if (column.style.type === 'hidden') {
|
||||
return v => {
|
||||
return undefined;
|
||||
};
|
||||
return (v: any): undefined => undefined;
|
||||
}
|
||||
|
||||
if (column.style.type === 'date') {
|
||||
return v => {
|
||||
return (v: any) => {
|
||||
if (v === undefined || v === null) {
|
||||
return '-';
|
||||
}
|
||||
@ -117,7 +117,7 @@ export class TableRenderer {
|
||||
}
|
||||
|
||||
if (column.style.type === 'string') {
|
||||
return v => {
|
||||
return (v: any): any => {
|
||||
if (_.isArray(v)) {
|
||||
v = v.join(', ');
|
||||
}
|
||||
@ -173,7 +173,7 @@ export class TableRenderer {
|
||||
if (column.style.type === 'number') {
|
||||
const valueFormatter = getValueFormat(column.unit || column.style.unit);
|
||||
|
||||
return v => {
|
||||
return (v: any): any => {
|
||||
if (v === null || v === void 0) {
|
||||
return '-';
|
||||
}
|
||||
@ -187,12 +187,12 @@ export class TableRenderer {
|
||||
};
|
||||
}
|
||||
|
||||
return value => {
|
||||
return (value: any) => {
|
||||
return this.defaultCellFormatter(value, column.style);
|
||||
};
|
||||
}
|
||||
|
||||
setColorState(value, style: ColumnStyle) {
|
||||
setColorState(value: any, style: ColumnStyle) {
|
||||
if (!style.colorMode) {
|
||||
return;
|
||||
}
|
||||
@ -209,22 +209,22 @@ export class TableRenderer {
|
||||
this.colorState[style.colorMode] = this.getColorForValue(numericValue, style);
|
||||
}
|
||||
|
||||
renderRowVariables(rowIndex) {
|
||||
const scopedVars = {};
|
||||
renderRowVariables(rowIndex: number) {
|
||||
const scopedVars: ScopedVars = {};
|
||||
let cellVariable;
|
||||
const row = this.table.rows[rowIndex];
|
||||
for (let i = 0; i < row.length; i++) {
|
||||
cellVariable = `__cell_${i}`;
|
||||
scopedVars[cellVariable] = { value: row[i] };
|
||||
scopedVars[cellVariable] = { value: row[i], text: row[i] ? row[i].toString() : '' };
|
||||
}
|
||||
return scopedVars;
|
||||
}
|
||||
|
||||
formatColumnValue(colIndex, value) {
|
||||
formatColumnValue(colIndex: number, value: any) {
|
||||
return this.formatters[colIndex] ? this.formatters[colIndex](value) : value;
|
||||
}
|
||||
|
||||
renderCell(columnIndex, rowIndex, value, addWidthHack = false) {
|
||||
renderCell(columnIndex: number, rowIndex: number, value: any, addWidthHack = false) {
|
||||
value = this.formatColumnValue(columnIndex, value);
|
||||
|
||||
const column = this.table.columns[columnIndex];
|
||||
@ -267,7 +267,7 @@ export class TableRenderer {
|
||||
if (column.style && column.style.link) {
|
||||
// Render cell as link
|
||||
const scopedVars = this.renderRowVariables(rowIndex);
|
||||
scopedVars['__cell'] = { value: value };
|
||||
scopedVars['__cell'] = { value: value, text: value ? value.toString() : '' };
|
||||
|
||||
const cellLink = this.templateSrv.replace(column.style.linkUrl, scopedVars, encodeURIComponent);
|
||||
const cellLinkTooltip = this.templateSrv.replace(column.style.linkTooltip, scopedVars);
|
||||
@ -305,7 +305,7 @@ export class TableRenderer {
|
||||
return columnHtml;
|
||||
}
|
||||
|
||||
render(page) {
|
||||
render(page: number) {
|
||||
const pageSize = this.panel.pageSize || 100;
|
||||
const startPos = page * pageSize;
|
||||
const endPos = Math.min(startPos + pageSize, this.table.rows.length);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import TableModel from 'app/core/table_model';
|
||||
import { TableRenderer } from '../renderer';
|
||||
import { getColorDefinitionByName } from '@grafana/ui';
|
||||
import { getColorDefinitionByName, ScopedVars } from '@grafana/ui';
|
||||
|
||||
describe('when rendering table', () => {
|
||||
const SemiDarkOrange = getColorDefinitionByName('semi-dark-orange');
|
||||
@ -166,12 +166,12 @@ describe('when rendering table', () => {
|
||||
],
|
||||
};
|
||||
|
||||
const sanitize = value => {
|
||||
const sanitize = (value: any): string => {
|
||||
return 'sanitized';
|
||||
};
|
||||
|
||||
const templateSrv = {
|
||||
replace: (value, scopedVars) => {
|
||||
replace: (value: any, scopedVars: ScopedVars) => {
|
||||
if (scopedVars) {
|
||||
// For testing variables replacement in link
|
||||
_.each(scopedVars, (val, key) => {
|
||||
@ -182,6 +182,7 @@ describe('when rendering table', () => {
|
||||
},
|
||||
};
|
||||
|
||||
//@ts-ignore
|
||||
const renderer = new TableRenderer(panel, table, 'utc', sanitize, templateSrv);
|
||||
|
||||
it('time column should be formated', () => {
|
||||
@ -386,6 +387,6 @@ describe('when rendering table', () => {
|
||||
});
|
||||
});
|
||||
|
||||
function normalize(str) {
|
||||
function normalize(str: string) {
|
||||
return str.replace(/\s+/gm, ' ').trim();
|
||||
}
|
||||
|
@ -1,7 +1,20 @@
|
||||
import TableModel from 'app/core/table_model';
|
||||
import { Column } from '@grafana/ui';
|
||||
import { ColumnStyle } from '@grafana/ui/src/components/Table/TableCellBuilder';
|
||||
|
||||
export interface TableTransform {
|
||||
description: string;
|
||||
getColumns(data?: any): any[];
|
||||
transform(data: any, panel: any, model: TableModel): void;
|
||||
}
|
||||
|
||||
export interface ColumnRender extends Column {
|
||||
title: string;
|
||||
style: ColumnStyle;
|
||||
hidden: boolean;
|
||||
}
|
||||
|
||||
export interface TableRenderModel {
|
||||
columns: ColumnRender[];
|
||||
rows: any[][];
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ export class TablePanelEditor extends PureComponent<PanelEditorProps<Options>> {
|
||||
this.props.onOptionsChange({ ...this.props.options, rotate: !this.props.options.rotate });
|
||||
};
|
||||
|
||||
onFixedColumnsChange = ({ target }) => {
|
||||
onFixedColumnsChange = ({ target }: any) => {
|
||||
this.props.onOptionsChange({ ...this.props.options, fixedColumns: target.value });
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,7 @@ interface State {
|
||||
export class TextPanel extends PureComponent<Props, State> {
|
||||
remarkable: Remarkable;
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
|
@ -25,17 +25,19 @@ import DashboardPage from '../features/dashboard/containers/DashboardPage';
|
||||
import PluginPage from '../features/plugins/PluginPage';
|
||||
import AppRootPage from 'app/features/plugins/AppRootPage';
|
||||
import config from 'app/core/config';
|
||||
import { route, ILocationProvider } from 'angular';
|
||||
|
||||
// Types
|
||||
import { DashboardRouteInfo } from 'app/types';
|
||||
|
||||
/** @ngInject */
|
||||
export function setupAngularRoutes($routeProvider, $locationProvider) {
|
||||
export function setupAngularRoutes($routeProvider: route.IRouteProvider, $locationProvider: ILocationProvider) {
|
||||
$locationProvider.html5Mode(true);
|
||||
|
||||
$routeProvider
|
||||
.when('/', {
|
||||
template: '<react-container />',
|
||||
//@ts-ignore
|
||||
pageClass: 'page-dashboard',
|
||||
routeInfo: DashboardRouteInfo.Home,
|
||||
reloadOnSearch: false,
|
||||
|
@ -1664,7 +1664,14 @@
|
||||
react-input-autosize "^2.2.1"
|
||||
react-transition-group "^2.2.1"
|
||||
|
||||
"@types/angular@1.6.54":
|
||||
"@types/angular-route@1.7.0":
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/angular-route/-/angular-route-1.7.0.tgz#ba12d09df1aac3c88e3684500001daedfc97fb69"
|
||||
integrity sha512-gctkSXUY7hDwFeW8il7f3+sdMmds0JaMnHvrZmqX79DHXf2D72+SHxJHIt5i6+0BrhoqdWdpgziSxuKnkAUAQw==
|
||||
dependencies:
|
||||
"@types/angular" "*"
|
||||
|
||||
"@types/angular@*", "@types/angular@1.6.54":
|
||||
version "1.6.54"
|
||||
resolved "https://registry.yarnpkg.com/@types/angular/-/angular-1.6.54.tgz#f9d5a03e4da7b021a6dabe5d63e899ed4567a5bd"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user