12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060 |
- import { each, map } from 'lodash';
- import { expect } from 'test/lib/common';
- import { DataLinkBuiltInVars, MappingType } from '@grafana/data';
- import { setDataSourceSrv } from '@grafana/runtime';
- import { config } from 'app/core/config';
- import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN } from 'app/core/constants';
- import { mockDataSource, MockDataSourceSrv } from 'app/features/alerting/unified/mocks';
- import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
- import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
- import { VariableHide } from '../../variables/types';
- import { DashboardModel } from '../state/DashboardModel';
- import { PanelModel } from '../state/PanelModel';
- jest.mock('app/core/services/context_srv', () => ({}));
- const dataSources = {
- prom: mockDataSource({
- name: 'prom',
- uid: 'prom-uid',
- type: 'prometheus',
- }),
- prom2: mockDataSource({
- name: 'prom2',
- uid: 'prom2-uid',
- type: 'prometheus',
- isDefault: true,
- }),
- notDefault: mockDataSource({
- name: 'prom-not-default',
- uid: 'prom-not-default-uid',
- type: 'prometheus',
- isDefault: false,
- }),
- [MIXED_DATASOURCE_NAME]: mockDataSource({
- name: MIXED_DATASOURCE_NAME,
- type: 'mixed',
- uid: MIXED_DATASOURCE_NAME,
- }),
- };
- setDataSourceSrv(new MockDataSourceSrv(dataSources));
- describe('DashboardModel', () => {
- describe('when creating dashboard with old schema', () => {
- let model: any;
- let graph: any;
- let singlestat: any;
- let table: any;
- let singlestatGauge: any;
- config.panels = {
- stat: getPanelPlugin({ id: 'stat' }).meta,
- gauge: getPanelPlugin({ id: 'gauge' }).meta,
- };
- beforeEach(() => {
- model = new DashboardModel({
- services: {
- filter: { time: { from: 'now-1d', to: 'now' }, list: [{}] },
- },
- pulldowns: [
- { type: 'filtering', enable: true },
- { type: 'annotations', enable: true, annotations: [{ name: 'old' }] },
- ],
- panels: [
- {
- type: 'graph',
- legend: true,
- aliasYAxis: { test: 2 },
- y_formats: ['kbyte', 'ms'],
- grid: {
- min: 1,
- max: 10,
- rightMin: 5,
- rightMax: 15,
- leftLogBase: 1,
- rightLogBase: 2,
- threshold1: 200,
- threshold2: 400,
- threshold1Color: 'yellow',
- threshold2Color: 'red',
- },
- leftYAxisLabel: 'left label',
- targets: [{ refId: 'A' }, {}],
- },
- {
- type: 'singlestat',
- legend: true,
- thresholds: '10,20,30',
- colors: ['#FF0000', 'green', 'orange'],
- aliasYAxis: { test: 2 },
- grid: { min: 1, max: 10 },
- targets: [{ refId: 'A' }, {}],
- },
- {
- type: 'singlestat',
- thresholds: '10,20,30',
- colors: ['#FF0000', 'green', 'orange'],
- gauge: {
- show: true,
- thresholdMarkers: true,
- thresholdLabels: false,
- },
- grid: { min: 1, max: 10 },
- },
- {
- type: 'table',
- legend: true,
- styles: [{ thresholds: ['10', '20', '30'] }, { thresholds: ['100', '200', '300'] }],
- targets: [{ refId: 'A' }, {}],
- },
- ],
- });
- graph = model.panels[0];
- singlestat = model.panels[1];
- singlestatGauge = model.panels[2];
- table = model.panels[3];
- });
- it('should have title', () => {
- expect(model.title).toBe('No Title');
- });
- it('should have panel id', () => {
- expect(graph.id).toBe(1);
- });
- it('should move time and filtering list', () => {
- expect(model.time.from).toBe('now-1d');
- expect(model.templating.list[0].allFormat).toBe('glob');
- });
- it('graphite panel should change name too graph', () => {
- expect(graph.type).toBe('graph');
- });
- it('singlestat panel should be mapped to stat panel', () => {
- expect(singlestat.type).toBe('stat');
- expect(singlestat.fieldConfig.defaults.thresholds.steps[2].value).toBe(30);
- expect(singlestat.fieldConfig.defaults.thresholds.steps[0].color).toBe('#FF0000');
- });
- it('singlestat panel should be mapped to gauge panel', () => {
- expect(singlestatGauge.type).toBe('gauge');
- expect(singlestatGauge.options.showThresholdMarkers).toBe(true);
- expect(singlestatGauge.options.showThresholdLabels).toBe(false);
- });
- it('queries without refId should get it', () => {
- expect(graph.targets[1].refId).toBe('B');
- });
- it('update legend setting', () => {
- expect(graph.legend.show).toBe(true);
- });
- it('move aliasYAxis to series override', () => {
- expect(graph.seriesOverrides[0].alias).toBe('test');
- expect(graph.seriesOverrides[0].yaxis).toBe(2);
- });
- it('should move pulldowns to new schema', () => {
- expect(model.annotations.list[1].name).toBe('old');
- });
- it('table panel should only have two thresholds values', () => {
- expect(table.styles[0].thresholds[0]).toBe('20');
- expect(table.styles[0].thresholds[1]).toBe('30');
- expect(table.styles[1].thresholds[0]).toBe('200');
- expect(table.styles[1].thresholds[1]).toBe('300');
- });
- it('table type should be deprecated', () => {
- expect(table.type).toBe('table-old');
- });
- it('graph grid to yaxes options', () => {
- expect(graph.yaxes[0].min).toBe(1);
- expect(graph.yaxes[0].max).toBe(10);
- expect(graph.yaxes[0].format).toBe('kbyte');
- expect(graph.yaxes[0].label).toBe('left label');
- expect(graph.yaxes[0].logBase).toBe(1);
- expect(graph.yaxes[1].min).toBe(5);
- expect(graph.yaxes[1].max).toBe(15);
- expect(graph.yaxes[1].format).toBe('ms');
- expect(graph.yaxes[1].logBase).toBe(2);
- expect(graph.grid.rightMax).toBe(undefined);
- expect(graph.grid.rightLogBase).toBe(undefined);
- expect(graph.y_formats).toBe(undefined);
- });
- it('dashboard schema version should be set to latest', () => {
- expect(model.schemaVersion).toBe(36);
- });
- it('graph thresholds should be migrated', () => {
- expect(graph.thresholds.length).toBe(2);
- expect(graph.thresholds[0].op).toBe('gt');
- expect(graph.thresholds[0].value).toBe(200);
- expect(graph.thresholds[0].fillColor).toBe('yellow');
- expect(graph.thresholds[1].value).toBe(400);
- expect(graph.thresholds[1].fillColor).toBe('red');
- });
- it('graph thresholds should be migrated onto specified thresholds', () => {
- model = new DashboardModel({
- panels: [
- {
- type: 'graph',
- y_formats: ['kbyte', 'ms'],
- grid: {
- threshold1: 200,
- threshold2: 400,
- },
- thresholds: [{ value: 100 }],
- },
- ],
- });
- graph = model.panels[0];
- expect(graph.thresholds.length).toBe(3);
- expect(graph.thresholds[0].value).toBe(100);
- expect(graph.thresholds[1].value).toBe(200);
- expect(graph.thresholds[2].value).toBe(400);
- });
- });
- describe('when migrating to the grid layout', () => {
- let model: any;
- beforeEach(() => {
- model = {
- rows: [],
- };
- });
- it('should create proper grid', () => {
- model.rows = [createRow({ collapse: false, height: 8 }, [[6], [6]])];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 12, h: 8 },
- { x: 12, y: 0, w: 12, h: 8 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should add special "row" panel if row is collapsed', () => {
- model.rows = [createRow({ collapse: true, height: 8 }, [[6], [6]]), createRow({ height: 8 }, [[12]])];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 24, h: 8 }, // row
- { x: 0, y: 1, w: 24, h: 8 }, // row
- { x: 0, y: 2, w: 24, h: 8 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should add special "row" panel if row has visible title', () => {
- model.rows = [
- createRow({ showTitle: true, title: 'Row', height: 8 }, [[6], [6]]),
- createRow({ height: 8 }, [[12]]),
- ];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 24, h: 8 }, // row
- { x: 0, y: 1, w: 12, h: 8 },
- { x: 12, y: 1, w: 12, h: 8 },
- { x: 0, y: 9, w: 24, h: 8 }, // row
- { x: 0, y: 10, w: 24, h: 8 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should not add "row" panel if row has not visible title or not collapsed', () => {
- model.rows = [
- createRow({ collapse: true, height: 8 }, [[12]]),
- createRow({ height: 8 }, [[12]]),
- createRow({ height: 8 }, [[12], [6], [6]]),
- createRow({ collapse: true, height: 8 }, [[12]]),
- ];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 24, h: 8 }, // row
- { x: 0, y: 1, w: 24, h: 8 }, // row
- { x: 0, y: 2, w: 24, h: 8 },
- { x: 0, y: 10, w: 24, h: 8 }, // row
- { x: 0, y: 11, w: 24, h: 8 },
- { x: 0, y: 19, w: 12, h: 8 },
- { x: 12, y: 19, w: 12, h: 8 },
- { x: 0, y: 27, w: 24, h: 8 }, // row
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should add all rows if even one collapsed or titled row is present', () => {
- model.rows = [createRow({ collapse: true, height: 8 }, [[6], [6]]), createRow({ height: 8 }, [[12]])];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 24, h: 8 }, // row
- { x: 0, y: 1, w: 24, h: 8 }, // row
- { x: 0, y: 2, w: 24, h: 8 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should properly place panels with fixed height', () => {
- model.rows = [
- createRow({ height: 6 }, [[6], [6, 3], [6, 3]]),
- createRow({ height: 6 }, [[4], [4], [4, 3], [4, 3]]),
- ];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 12, h: 6 },
- { x: 12, y: 0, w: 12, h: 3 },
- { x: 12, y: 3, w: 12, h: 3 },
- { x: 0, y: 6, w: 8, h: 6 },
- { x: 8, y: 6, w: 8, h: 6 },
- { x: 16, y: 6, w: 8, h: 3 },
- { x: 16, y: 9, w: 8, h: 3 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should place panel to the right side of panel having bigger height', () => {
- model.rows = [createRow({ height: 6 }, [[4], [2, 3], [4, 6], [2, 3], [2, 3]])];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 8, h: 6 },
- { x: 8, y: 0, w: 4, h: 3 },
- { x: 12, y: 0, w: 8, h: 6 },
- { x: 20, y: 0, w: 4, h: 3 },
- { x: 20, y: 3, w: 4, h: 3 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should fill current row if it possible', () => {
- model.rows = [createRow({ height: 9 }, [[4], [2, 3], [4, 6], [2, 3], [2, 3], [8, 3]])];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 8, h: 9 },
- { x: 8, y: 0, w: 4, h: 3 },
- { x: 12, y: 0, w: 8, h: 6 },
- { x: 20, y: 0, w: 4, h: 3 },
- { x: 20, y: 3, w: 4, h: 3 },
- { x: 8, y: 6, w: 16, h: 3 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should fill current row if it possible (2)', () => {
- model.rows = [createRow({ height: 8 }, [[4], [2, 3], [4, 6], [2, 3], [2, 3], [8, 3]])];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 8, h: 8 },
- { x: 8, y: 0, w: 4, h: 3 },
- { x: 12, y: 0, w: 8, h: 6 },
- { x: 20, y: 0, w: 4, h: 3 },
- { x: 20, y: 3, w: 4, h: 3 },
- { x: 8, y: 6, w: 16, h: 3 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should fill current row if panel height more than row height', () => {
- model.rows = [createRow({ height: 6 }, [[4], [2, 3], [4, 8], [2, 3], [2, 3]])];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 8, h: 6 },
- { x: 8, y: 0, w: 4, h: 3 },
- { x: 12, y: 0, w: 8, h: 8 },
- { x: 20, y: 0, w: 4, h: 3 },
- { x: 20, y: 3, w: 4, h: 3 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should wrap panels to multiple rows', () => {
- model.rows = [createRow({ height: 6 }, [[6], [6], [12], [6], [3], [3]])];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 12, h: 6 },
- { x: 12, y: 0, w: 12, h: 6 },
- { x: 0, y: 6, w: 24, h: 6 },
- { x: 0, y: 12, w: 12, h: 6 },
- { x: 12, y: 12, w: 6, h: 6 },
- { x: 18, y: 12, w: 6, h: 6 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- });
- it('should add repeated row if repeat set', () => {
- model.rows = [
- createRow({ showTitle: true, title: 'Row', height: 8, repeat: 'server' }, [[6]]),
- createRow({ height: 8 }, [[12]]),
- ];
- const dashboard = new DashboardModel(model);
- const panelGridPos = getGridPositions(dashboard);
- const expectedGrid = [
- { x: 0, y: 0, w: 24, h: 8 },
- { x: 0, y: 1, w: 12, h: 8 },
- { x: 0, y: 9, w: 24, h: 8 },
- { x: 0, y: 10, w: 24, h: 8 },
- ];
- expect(panelGridPos).toEqual(expectedGrid);
- expect(dashboard.panels[0].repeat).toBe('server');
- expect(dashboard.panels[1].repeat).toBeUndefined();
- expect(dashboard.panels[2].repeat).toBeUndefined();
- expect(dashboard.panels[3].repeat).toBeUndefined();
- });
- it('should ignore repeated row', () => {
- model.rows = [
- createRow({ showTitle: true, title: 'Row1', height: 8, repeat: 'server' }, [[6]]),
- createRow(
- {
- showTitle: true,
- title: 'Row2',
- height: 8,
- repeatIteration: 12313,
- repeatRowId: 1,
- },
- [[6]]
- ),
- ];
- const dashboard = new DashboardModel(model);
- expect(dashboard.panels[0].repeat).toBe('server');
- expect(dashboard.panels.length).toBe(2);
- });
- it('should assign id', () => {
- model.rows = [createRow({ collapse: true, height: 8 }, [[6], [6]])];
- model.rows[0].panels[0] = {};
- const dashboard = new DashboardModel(model);
- expect(dashboard.panels[0].id).toBe(1);
- });
- });
- describe('when migrating from minSpan to maxPerRow', () => {
- it('maxPerRow should be correct', () => {
- const model = {
- panels: [{ minSpan: 8 }],
- };
- const dashboard = new DashboardModel(model);
- expect(dashboard.panels[0].maxPerRow).toBe(3);
- });
- });
- describe('when migrating panel links', () => {
- let model: any;
- beforeEach(() => {
- model = new DashboardModel({
- panels: [
- {
- links: [
- {
- url: 'http://mylink.com',
- keepTime: true,
- title: 'test',
- },
- {
- url: 'http://mylink.com?existingParam',
- params: 'customParam',
- title: 'test',
- },
- {
- url: 'http://mylink.com?existingParam',
- includeVars: true,
- title: 'test',
- },
- {
- dashboard: 'my other dashboard',
- title: 'test',
- },
- {
- dashUri: '',
- title: 'test',
- },
- {
- type: 'dashboard',
- keepTime: true,
- },
- ],
- },
- ],
- });
- });
- it('should add keepTime as variable', () => {
- expect(model.panels[0].links[0].url).toBe(`http://mylink.com?$${DataLinkBuiltInVars.keepTime}`);
- });
- it('should add params to url', () => {
- expect(model.panels[0].links[1].url).toBe('http://mylink.com?existingParam&customParam');
- });
- it('should add includeVars to url', () => {
- expect(model.panels[0].links[2].url).toBe(`http://mylink.com?existingParam&$${DataLinkBuiltInVars.includeVars}`);
- });
- it('should slugify dashboard name', () => {
- expect(model.panels[0].links[3].url).toBe(`dashboard/db/my-other-dashboard`);
- });
- });
- describe('when migrating variables', () => {
- let model: any;
- beforeEach(() => {
- model = new DashboardModel({
- panels: [
- {
- //graph panel
- options: {
- dataLinks: [
- {
- url: 'http://mylink.com?series=${__series_name}',
- },
- {
- url: 'http://mylink.com?series=${__value_time}',
- },
- ],
- },
- },
- {
- // panel with field options
- options: {
- fieldOptions: {
- defaults: {
- links: [
- {
- url: 'http://mylink.com?series=${__series_name}',
- },
- {
- url: 'http://mylink.com?series=${__value_time}',
- },
- ],
- title: '$__cell_0 * $__field_name * $__series_name',
- },
- },
- },
- },
- ],
- });
- });
- describe('data links', () => {
- it('should replace __series_name variable with __series.name', () => {
- expect(model.panels[0].options.dataLinks[0].url).toBe('http://mylink.com?series=${__series.name}');
- expect(model.panels[1].options.fieldOptions.defaults.links[0].url).toBe(
- 'http://mylink.com?series=${__series.name}'
- );
- });
- it('should replace __value_time variable with __value.time', () => {
- expect(model.panels[0].options.dataLinks[1].url).toBe('http://mylink.com?series=${__value.time}');
- expect(model.panels[1].options.fieldOptions.defaults.links[1].url).toBe(
- 'http://mylink.com?series=${__value.time}'
- );
- });
- });
- describe('field display', () => {
- it('should replace __series_name and __field_name variables with new syntax', () => {
- expect(model.panels[1].options.fieldOptions.defaults.title).toBe(
- '$__cell_0 * ${__field.name} * ${__series.name}'
- );
- });
- });
- });
- describe('when migrating labels from DataFrame to Field', () => {
- let model: any;
- beforeEach(() => {
- model = new DashboardModel({
- panels: [
- {
- //graph panel
- options: {
- dataLinks: [
- {
- url: 'http://mylink.com?series=${__series.labels}&${__series.labels.a}',
- },
- ],
- },
- },
- {
- // panel with field options
- options: {
- fieldOptions: {
- defaults: {
- links: [
- {
- url: 'http://mylink.com?series=${__series.labels}&${__series.labels.x}',
- },
- ],
- },
- },
- },
- },
- ],
- });
- });
- describe('data links', () => {
- it('should replace __series.label variable with __field.label', () => {
- expect(model.panels[0].options.dataLinks[0].url).toBe(
- 'http://mylink.com?series=${__field.labels}&${__field.labels.a}'
- );
- expect(model.panels[1].options.fieldOptions.defaults.links[0].url).toBe(
- 'http://mylink.com?series=${__field.labels}&${__field.labels.x}'
- );
- });
- });
- });
- describe('when migrating variables with multi support', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- templating: {
- list: [
- {
- multi: false,
- current: {
- value: ['value'],
- text: ['text'],
- },
- },
- {
- multi: true,
- current: {
- value: ['value'],
- text: ['text'],
- },
- },
- ],
- },
- });
- });
- it('should have two variables after migration', () => {
- expect(model.templating.list.length).toBe(2);
- });
- it('should be migrated if being out of sync', () => {
- expect(model.templating.list[0].multi).toBe(false);
- expect(model.templating.list[0].current).toEqual({
- text: 'text',
- value: 'value',
- });
- });
- it('should not be migrated if being in sync', () => {
- expect(model.templating.list[1].multi).toBe(true);
- expect(model.templating.list[1].current).toEqual({
- text: ['text'],
- value: ['value'],
- });
- });
- });
- describe('when migrating variables with tags', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- templating: {
- list: [
- {
- type: 'query',
- tags: ['Africa', 'America', 'Asia', 'Europe'],
- tagsQuery: 'select datacenter from x',
- tagValuesQuery: 'select value from x where datacenter = xyz',
- useTags: true,
- },
- {
- type: 'query',
- current: {
- tags: [
- {
- selected: true,
- text: 'America',
- values: ['server-us-east', 'server-us-central', 'server-us-west'],
- valuesText: 'server-us-east + server-us-central + server-us-west',
- },
- {
- selected: true,
- text: 'Europe',
- values: ['server-eu-east', 'server-eu-west'],
- valuesText: 'server-eu-east + server-eu-west',
- },
- ],
- text: 'server-us-east + server-us-central + server-us-west + server-eu-east + server-eu-west',
- value: ['server-us-east', 'server-us-central', 'server-us-west', 'server-eu-east', 'server-eu-west'],
- },
- tags: ['Africa', 'America', 'Asia', 'Europe'],
- tagsQuery: 'select datacenter from x',
- tagValuesQuery: 'select value from x where datacenter = xyz',
- useTags: true,
- },
- {
- type: 'query',
- tags: [
- { text: 'Africa', selected: false },
- { text: 'America', selected: true },
- { text: 'Asia', selected: false },
- { text: 'Europe', selected: false },
- ],
- tagsQuery: 'select datacenter from x',
- tagValuesQuery: 'select value from x where datacenter = xyz',
- useTags: true,
- },
- ],
- },
- });
- });
- it('should have three variables after migration', () => {
- expect(model.templating.list.length).toBe(3);
- });
- it('should have no tags', () => {
- expect(model.templating.list[0].tags).toBeUndefined();
- expect(model.templating.list[1].tags).toBeUndefined();
- expect(model.templating.list[2].tags).toBeUndefined();
- });
- it('should have no tagsQuery property', () => {
- expect(model.templating.list[0].tagsQuery).toBeUndefined();
- expect(model.templating.list[1].tagsQuery).toBeUndefined();
- expect(model.templating.list[2].tagsQuery).toBeUndefined();
- });
- it('should have no tagValuesQuery property', () => {
- expect(model.templating.list[0].tagValuesQuery).toBeUndefined();
- expect(model.templating.list[1].tagValuesQuery).toBeUndefined();
- expect(model.templating.list[2].tagValuesQuery).toBeUndefined();
- });
- it('should have no useTags property', () => {
- expect(model.templating.list[0].useTags).toBeUndefined();
- expect(model.templating.list[1].useTags).toBeUndefined();
- expect(model.templating.list[2].useTags).toBeUndefined();
- });
- });
- describe('when migrating to new Text Panel', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- panels: [
- {
- id: 2,
- type: 'text',
- title: 'Angular Text Panel',
- content:
- '# Angular Text Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n\n',
- mode: 'markdown',
- },
- {
- id: 3,
- type: 'text2',
- title: 'React Text Panel from scratch',
- options: {
- mode: 'markdown',
- content:
- '# React Text Panel from scratch\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text',
- },
- },
- {
- id: 4,
- type: 'text2',
- title: 'React Text Panel from Angular Panel',
- options: {
- mode: 'markdown',
- content:
- '# React Text Panel from Angular Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text',
- angular: {
- content:
- '# React Text Panel from Angular Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n',
- mode: 'markdown',
- options: {},
- },
- },
- },
- ],
- });
- });
- it('should have 3 panels after migration', () => {
- expect(model.panels.length).toBe(3);
- });
- it('should not migrate panel with old Text Panel id', () => {
- const oldAngularPanel: any = model.panels[0];
- expect(oldAngularPanel.id).toEqual(2);
- expect(oldAngularPanel.type).toEqual('text');
- expect(oldAngularPanel.title).toEqual('Angular Text Panel');
- expect(oldAngularPanel.content).toEqual(
- '# Angular Text Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n\n'
- );
- expect(oldAngularPanel.mode).toEqual('markdown');
- });
- it('should migrate panels with new Text Panel id', () => {
- const reactPanel: any = model.panels[1];
- expect(reactPanel.id).toEqual(3);
- expect(reactPanel.type).toEqual('text');
- expect(reactPanel.title).toEqual('React Text Panel from scratch');
- expect(reactPanel.options.content).toEqual(
- '# React Text Panel from scratch\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text'
- );
- expect(reactPanel.options.mode).toEqual('markdown');
- });
- it('should clean up old angular options for panels with new Text Panel id', () => {
- const reactPanel: any = model.panels[2];
- expect(reactPanel.id).toEqual(4);
- expect(reactPanel.type).toEqual('text');
- expect(reactPanel.title).toEqual('React Text Panel from Angular Panel');
- expect(reactPanel.options.content).toEqual(
- '# React Text Panel from Angular Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text'
- );
- expect(reactPanel.options.mode).toEqual('markdown');
- expect(reactPanel.options.angular).toBeUndefined();
- });
- });
- describe('when migrating constant variables so they are always hidden', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- templating: {
- list: [
- {
- type: 'query',
- hide: VariableHide.dontHide,
- datasource: null,
- allFormat: '',
- },
- {
- type: 'query',
- hide: VariableHide.hideLabel,
- datasource: null,
- allFormat: '',
- },
- {
- type: 'query',
- hide: VariableHide.hideVariable,
- datasource: null,
- allFormat: '',
- },
- {
- type: 'constant',
- hide: VariableHide.dontHide,
- query: 'default value',
- current: { selected: true, text: 'A', value: 'B' },
- options: [{ selected: true, text: 'A', value: 'B' }],
- datasource: null,
- allFormat: '',
- },
- {
- type: 'constant',
- hide: VariableHide.hideLabel,
- query: 'default value',
- current: { selected: true, text: 'A', value: 'B' },
- options: [{ selected: true, text: 'A', value: 'B' }],
- datasource: null,
- allFormat: '',
- },
- {
- type: 'constant',
- hide: VariableHide.hideVariable,
- query: 'default value',
- current: { selected: true, text: 'A', value: 'B' },
- options: [{ selected: true, text: 'A', value: 'B' }],
- datasource: null,
- allFormat: '',
- },
- ],
- },
- });
- });
- it('should have six variables after migration', () => {
- expect(model.templating.list.length).toBe(6);
- });
- it('should not touch other variable types', () => {
- expect(model.templating.list[0].hide).toEqual(VariableHide.dontHide);
- expect(model.templating.list[1].hide).toEqual(VariableHide.hideLabel);
- expect(model.templating.list[2].hide).toEqual(VariableHide.hideVariable);
- });
- it('should migrate visible constant variables to textbox variables', () => {
- expect(model.templating.list[3]).toEqual({
- type: 'textbox',
- hide: VariableHide.dontHide,
- query: 'default value',
- current: { selected: true, text: 'default value', value: 'default value' },
- options: [{ selected: true, text: 'default value', value: 'default value' }],
- datasource: null,
- allFormat: '',
- });
- expect(model.templating.list[4]).toEqual({
- type: 'textbox',
- hide: VariableHide.hideLabel,
- query: 'default value',
- current: { selected: true, text: 'default value', value: 'default value' },
- options: [{ selected: true, text: 'default value', value: 'default value' }],
- datasource: null,
- allFormat: '',
- });
- });
- it('should change current and options for hidden constant variables', () => {
- expect(model.templating.list[5]).toEqual({
- type: 'constant',
- hide: VariableHide.hideVariable,
- query: 'default value',
- current: { selected: true, text: 'default value', value: 'default value' },
- options: [{ selected: true, text: 'default value', value: 'default value' }],
- datasource: null,
- allFormat: '',
- });
- });
- });
- describe('when migrating variable refresh to on dashboard load', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- templating: {
- list: [
- {
- type: 'query',
- name: 'variable_with_never_refresh_with_options',
- options: [{ text: 'A', value: 'A' }],
- refresh: 0,
- },
- {
- type: 'query',
- name: 'variable_with_never_refresh_without_options',
- options: [],
- refresh: 0,
- },
- {
- type: 'query',
- name: 'variable_with_dashboard_refresh_with_options',
- options: [{ text: 'A', value: 'A' }],
- refresh: 1,
- },
- {
- type: 'query',
- name: 'variable_with_dashboard_refresh_without_options',
- options: [],
- refresh: 1,
- },
- {
- type: 'query',
- name: 'variable_with_timerange_refresh_with_options',
- options: [{ text: 'A', value: 'A' }],
- refresh: 2,
- },
- {
- type: 'query',
- name: 'variable_with_timerange_refresh_without_options',
- options: [],
- refresh: 2,
- },
- {
- type: 'query',
- name: 'variable_with_no_refresh_with_options',
- options: [{ text: 'A', value: 'A' }],
- },
- {
- type: 'query',
- name: 'variable_with_no_refresh_without_options',
- options: [],
- },
- {
- type: 'query',
- name: 'variable_with_unknown_refresh_with_options',
- options: [{ text: 'A', value: 'A' }],
- refresh: 2001,
- },
- {
- type: 'query',
- name: 'variable_with_unknown_refresh_without_options',
- options: [],
- refresh: 2001,
- },
- {
- type: 'custom',
- name: 'custom',
- options: [{ text: 'custom', value: 'custom' }],
- },
- {
- type: 'textbox',
- name: 'textbox',
- options: [{ text: 'Hello', value: 'World' }],
- },
- {
- type: 'datasource',
- name: 'datasource',
- options: [{ text: 'ds', value: 'ds' }], // fake example doesn't exist
- },
- {
- type: 'interval',
- name: 'interval',
- options: [{ text: '1m', value: '1m' }],
- },
- ],
- },
- });
- });
- it('should have 11 variables after migration', () => {
- expect(model.templating.list.length).toBe(14);
- });
- it('should not affect custom variable types', () => {
- const custom = model.templating.list[10];
- expect(custom.type).toEqual('custom');
- expect(custom.options).toEqual([{ text: 'custom', value: 'custom' }]);
- });
- it('should not affect textbox variable types', () => {
- const textbox = model.templating.list[11];
- expect(textbox.type).toEqual('textbox');
- expect(textbox.options).toEqual([{ text: 'Hello', value: 'World' }]);
- });
- it('should not affect datasource variable types', () => {
- const datasource = model.templating.list[12];
- expect(datasource.type).toEqual('datasource');
- expect(datasource.options).toEqual([{ text: 'ds', value: 'ds' }]);
- });
- it('should not affect interval variable types', () => {
- const interval = model.templating.list[13];
- expect(interval.type).toEqual('interval');
- expect(interval.options).toEqual([{ text: '1m', value: '1m' }]);
- });
- it('should removed options from all query variables', () => {
- const queryVariables = model.templating.list.filter((v) => v.type === 'query');
- expect(queryVariables).toHaveLength(10);
- const noOfOptions = queryVariables.reduce((all, variable) => all + variable.options.length, 0);
- expect(noOfOptions).toBe(0);
- });
- it('should set the refresh prop to on dashboard load for all query variables that have never or unknown', () => {
- expect(model.templating.list[0].refresh).toBe(1);
- expect(model.templating.list[1].refresh).toBe(1);
- expect(model.templating.list[2].refresh).toBe(1);
- expect(model.templating.list[3].refresh).toBe(1);
- expect(model.templating.list[4].refresh).toBe(2);
- expect(model.templating.list[5].refresh).toBe(2);
- expect(model.templating.list[6].refresh).toBe(1);
- expect(model.templating.list[7].refresh).toBe(1);
- expect(model.templating.list[8].refresh).toBe(1);
- expect(model.templating.list[9].refresh).toBe(1);
- expect(model.templating.list[10].refresh).toBeUndefined();
- expect(model.templating.list[11].refresh).toBeUndefined();
- expect(model.templating.list[12].refresh).toBeUndefined();
- expect(model.templating.list[13].refresh).toBeUndefined();
- });
- });
- describe('when migrating old value mapping model', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- panels: [
- {
- id: 1,
- type: 'timeseries',
- fieldConfig: {
- defaults: {
- thresholds: {
- mode: 'absolute',
- steps: [
- {
- color: 'green',
- value: null,
- },
- {
- color: 'red',
- value: 80,
- },
- ],
- },
- mappings: [
- {
- id: 0,
- text: '1',
- type: 1,
- value: 'up',
- },
- {
- id: 1,
- text: 'BAD',
- type: 1,
- value: 'down',
- },
- {
- from: '0',
- id: 2,
- text: 'below 30',
- to: '30',
- type: 2,
- },
- {
- from: '30',
- id: 3,
- text: '100',
- to: '100',
- type: 2,
- },
- {
- type: 1,
- value: 'null',
- text: 'it is null',
- },
- ],
- },
- overrides: [
- {
- matcher: { id: 'byName', options: 'D-series' },
- properties: [
- {
- id: 'mappings',
- value: [
- {
- id: 0,
- text: 'OverrideText',
- type: 1,
- value: 'up',
- },
- ],
- },
- ],
- },
- ],
- },
- },
- ],
- });
- });
- it('should migrate value mapping model', () => {
- expect(model.panels[0].fieldConfig.defaults.mappings).toEqual([
- {
- type: MappingType.ValueToText,
- options: {
- down: { text: 'BAD', color: undefined },
- up: { text: '1', color: 'green' },
- },
- },
- {
- type: MappingType.RangeToText,
- options: {
- from: 0,
- to: 30,
- result: { text: 'below 30' },
- },
- },
- {
- type: MappingType.RangeToText,
- options: {
- from: 30,
- to: 100,
- result: { text: '100', color: 'red' },
- },
- },
- {
- type: MappingType.SpecialValue,
- options: {
- match: 'null',
- result: { text: 'it is null', color: undefined },
- },
- },
- ]);
- expect(model.panels[0].fieldConfig.overrides).toEqual([
- {
- matcher: { id: 'byName', options: 'D-series' },
- properties: [
- {
- id: 'mappings',
- value: [
- {
- type: MappingType.ValueToText,
- options: {
- up: { text: 'OverrideText' },
- },
- },
- ],
- },
- ],
- },
- ]);
- });
- });
- describe('when migrating tooltipOptions to tooltip', () => {
- it('should rename options.tooltipOptions to options.tooltip', () => {
- const model = new DashboardModel({
- panels: [
- {
- type: 'timeseries',
- legend: true,
- options: {
- tooltipOptions: { mode: 'multi' },
- },
- },
- {
- type: 'xychart',
- legend: true,
- options: {
- tooltipOptions: { mode: 'single' },
- },
- },
- ],
- });
- expect(model.panels[0].options).toMatchInlineSnapshot(`
- Object {
- "tooltip": Object {
- "mode": "multi",
- },
- }
- `);
- expect(model.panels[1].options).toMatchInlineSnapshot(`
- Object {
- "tooltip": Object {
- "mode": "single",
- },
- }
- `);
- });
- });
- describe('when migrating singlestat value mappings', () => {
- it('should migrate value mapping', () => {
- const model = new DashboardModel({
- panels: [
- {
- type: 'singlestat',
- legend: true,
- thresholds: '10,20,30',
- colors: ['#FF0000', 'green', 'orange'],
- aliasYAxis: { test: 2 },
- grid: { min: 1, max: 10 },
- targets: [{ refId: 'A' }, {}],
- mappingType: 1,
- mappingTypes: [
- {
- name: 'value to text',
- value: 1,
- },
- ],
- valueMaps: [
- {
- op: '=',
- text: 'test',
- value: '20',
- },
- {
- op: '=',
- text: 'test1',
- value: '30',
- },
- {
- op: '=',
- text: '50',
- value: '40',
- },
- ],
- },
- ],
- });
- expect(model.panels[0].fieldConfig.defaults.mappings).toMatchInlineSnapshot(`
- Array [
- Object {
- "options": Object {
- "20": Object {
- "color": undefined,
- "text": "test",
- },
- "30": Object {
- "color": undefined,
- "text": "test1",
- },
- "40": Object {
- "color": "orange",
- "text": "50",
- },
- },
- "type": "value",
- },
- ]
- `);
- });
- it('should migrate range mapping', () => {
- const model = new DashboardModel({
- panels: [
- {
- type: 'singlestat',
- legend: true,
- thresholds: '10,20,30',
- colors: ['#FF0000', 'green', 'orange'],
- aliasYAxis: { test: 2 },
- grid: { min: 1, max: 10 },
- targets: [{ refId: 'A' }, {}],
- mappingType: 2,
- mappingTypes: [
- {
- name: 'range to text',
- value: 2,
- },
- ],
- rangeMaps: [
- {
- from: '20',
- to: '25',
- text: 'text1',
- },
- {
- from: '1',
- to: '5',
- text: 'text2',
- },
- {
- from: '5',
- to: '10',
- text: '50',
- },
- ],
- },
- ],
- });
- expect(model.panels[0].fieldConfig.defaults.mappings).toMatchInlineSnapshot(`
- Array [
- Object {
- "options": Object {
- "from": 20,
- "result": Object {
- "color": undefined,
- "text": "text1",
- },
- "to": 25,
- },
- "type": "range",
- },
- Object {
- "options": Object {
- "from": 1,
- "result": Object {
- "color": undefined,
- "text": "text2",
- },
- "to": 5,
- },
- "type": "range",
- },
- Object {
- "options": Object {
- "from": 5,
- "result": Object {
- "color": "orange",
- "text": "50",
- },
- "to": 10,
- },
- "type": "range",
- },
- ]
- `);
- });
- });
- describe('when migrating folded panel without fieldConfig.defaults', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- schemaVersion: 29,
- panels: [
- {
- id: 1,
- type: 'timeseries',
- panels: [
- {
- id: 2,
- fieldConfig: {
- overrides: [
- {
- matcher: { id: 'byName', options: 'D-series' },
- properties: [
- {
- id: 'displayName',
- value: 'foobar',
- },
- ],
- },
- ],
- },
- },
- ],
- },
- ],
- });
- });
- it('should ignore fieldConfig.defaults', () => {
- expect(model.panels[0].panels?.[0].fieldConfig.defaults).toEqual(undefined);
- });
- });
- describe('labelsToFields should be split into two transformers', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- schemaVersion: 29,
- panels: [
- {
- id: 1,
- type: 'timeseries',
- transformations: [{ id: 'labelsToFields' }],
- },
- ],
- });
- });
- it('should create two transormatoins', () => {
- const xforms = model.panels[0].transformations;
- expect(xforms).toMatchInlineSnapshot(`
- Array [
- Object {
- "id": "labelsToFields",
- },
- Object {
- "id": "merge",
- "options": Object {},
- },
- ]
- `);
- });
- });
- describe('migrating legacy CloudWatch queries', () => {
- let model: any;
- let panelTargets: any;
- beforeEach(() => {
- model = new DashboardModel({
- annotations: {
- list: [
- {
- actionPrefix: '',
- alarmNamePrefix: '',
- alias: '',
- dimensions: {
- InstanceId: 'i-123',
- },
- enable: true,
- expression: '',
- iconColor: 'red',
- id: '',
- matchExact: true,
- metricName: 'CPUUtilization',
- name: 'test',
- namespace: 'AWS/EC2',
- period: '',
- prefixMatching: false,
- region: 'us-east-2',
- statistics: ['Minimum', 'Sum'],
- },
- ],
- },
- panels: [
- {
- gridPos: {
- h: 8,
- w: 12,
- x: 0,
- y: 0,
- },
- id: 4,
- options: {
- legend: {
- calcs: [],
- displayMode: 'list',
- placement: 'bottom',
- },
- tooltipOptions: {
- mode: 'single',
- },
- },
- targets: [
- {
- alias: '',
- dimensions: {
- InstanceId: 'i-123',
- },
- expression: '',
- id: '',
- matchExact: true,
- metricName: 'CPUUtilization',
- namespace: 'AWS/EC2',
- period: '',
- refId: 'A',
- region: 'default',
- statistics: ['Average', 'Minimum', 'p12.21'],
- },
- {
- alias: '',
- dimensions: {
- InstanceId: 'i-123',
- },
- expression: '',
- hide: false,
- id: '',
- matchExact: true,
- metricName: 'CPUUtilization',
- namespace: 'AWS/EC2',
- period: '',
- refId: 'B',
- region: 'us-east-2',
- statistics: ['Sum'],
- },
- ],
- title: 'Panel Title',
- type: 'timeseries',
- },
- ],
- });
- panelTargets = model.panels[0].targets;
- });
- it('multiple stats query should have been split into three', () => {
- expect(panelTargets.length).toBe(4);
- });
- it('new stats query should get the right statistic', () => {
- expect(panelTargets[0].statistic).toBe('Average');
- expect(panelTargets[1].statistic).toBe('Sum');
- expect(panelTargets[2].statistic).toBe('Minimum');
- expect(panelTargets[3].statistic).toBe('p12.21');
- });
- it('new stats queries should be put in the end of the array', () => {
- expect(panelTargets[0].refId).toBe('A');
- expect(panelTargets[1].refId).toBe('B');
- expect(panelTargets[2].refId).toBe('C');
- expect(panelTargets[3].refId).toBe('D');
- });
- describe('with nested panels', () => {
- let panel1Targets: any;
- let panel2Targets: any;
- let nestedModel: DashboardModel;
- beforeEach(() => {
- nestedModel = new DashboardModel({
- annotations: {
- list: [
- {
- actionPrefix: '',
- alarmNamePrefix: '',
- alias: '',
- dimensions: {
- InstanceId: 'i-123',
- },
- enable: true,
- expression: '',
- iconColor: 'red',
- id: '',
- matchExact: true,
- metricName: 'CPUUtilization',
- name: 'test',
- namespace: 'AWS/EC2',
- period: '',
- prefixMatching: false,
- region: 'us-east-2',
- statistics: ['Minimum', 'Sum'],
- },
- ],
- },
- panels: [
- {
- collapsed: false,
- gridPos: {
- h: 1,
- w: 24,
- x: 0,
- y: 89,
- },
- id: 96,
- title: 'DynamoDB',
- type: 'row',
- panels: [
- {
- gridPos: {
- h: 8,
- w: 12,
- x: 0,
- y: 0,
- },
- id: 4,
- options: {
- legend: {
- calcs: [],
- displayMode: 'list',
- placement: 'bottom',
- },
- tooltipOptions: {
- mode: 'single',
- },
- },
- targets: [
- {
- alias: '',
- dimensions: {
- InstanceId: 'i-123',
- },
- expression: '',
- id: '',
- matchExact: true,
- metricName: 'CPUUtilization',
- namespace: 'AWS/EC2',
- period: '',
- refId: 'C',
- region: 'default',
- statistics: ['Average', 'Minimum', 'p12.21'],
- },
- {
- alias: '',
- dimensions: {
- InstanceId: 'i-123',
- },
- expression: '',
- hide: false,
- id: '',
- matchExact: true,
- metricName: 'CPUUtilization',
- namespace: 'AWS/EC2',
- period: '',
- refId: 'B',
- region: 'us-east-2',
- statistics: ['Sum'],
- },
- ],
- title: 'Panel Title',
- type: 'timeseries',
- },
- {
- gridPos: {
- h: 8,
- w: 12,
- x: 0,
- y: 0,
- },
- id: 4,
- options: {
- legend: {
- calcs: [],
- displayMode: 'list',
- placement: 'bottom',
- },
- tooltipOptions: {
- mode: 'single',
- },
- },
- targets: [
- {
- alias: '',
- dimensions: {
- InstanceId: 'i-123',
- },
- expression: '',
- id: '',
- matchExact: true,
- metricName: 'CPUUtilization',
- namespace: 'AWS/EC2',
- period: '',
- refId: 'A',
- region: 'default',
- statistics: ['Average'],
- },
- {
- alias: '',
- dimensions: {
- InstanceId: 'i-123',
- },
- expression: '',
- hide: false,
- id: '',
- matchExact: true,
- metricName: 'CPUUtilization',
- namespace: 'AWS/EC2',
- period: '',
- refId: 'B',
- region: 'us-east-2',
- statistics: ['Sum', 'Min'],
- },
- ],
- title: 'Panel Title',
- type: 'timeseries',
- },
- ],
- },
- ],
- });
- panel1Targets = nestedModel.panels[0].panels?.[0].targets;
- panel2Targets = nestedModel.panels[0].panels?.[1].targets;
- });
- it('multiple stats query should have been split into one query per stat', () => {
- expect(panel1Targets.length).toBe(4);
- expect(panel2Targets.length).toBe(3);
- });
- it('new stats query should get the right statistic', () => {
- expect(panel1Targets[0].statistic).toBe('Average');
- expect(panel1Targets[1].statistic).toBe('Sum');
- expect(panel1Targets[2].statistic).toBe('Minimum');
- expect(panel1Targets[3].statistic).toBe('p12.21');
- expect(panel2Targets[0].statistic).toBe('Average');
- expect(panel2Targets[1].statistic).toBe('Sum');
- expect(panel2Targets[2].statistic).toBe('Min');
- });
- it('new stats queries should be put in the end of the array', () => {
- expect(panel1Targets[0].refId).toBe('C');
- expect(panel1Targets[1].refId).toBe('B');
- expect(panel1Targets[2].refId).toBe('A');
- expect(panel1Targets[3].refId).toBe('D');
- expect(panel2Targets[0].refId).toBe('A');
- expect(panel2Targets[1].refId).toBe('B');
- expect(panel2Targets[2].refId).toBe('C');
- });
- });
- });
- describe('when migrating datasource to refs', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- templating: {
- list: [
- {
- type: 'query',
- name: 'var',
- options: [{ text: 'A', value: 'A' }],
- refresh: 0,
- datasource: 'prom',
- },
- ],
- },
- panels: [
- {
- id: 1,
- datasource: 'prom',
- },
- {
- id: 2,
- datasource: null,
- },
- {
- id: 3,
- datasource: MIXED_DATASOURCE_NAME,
- targets: [
- {
- datasource: 'prom',
- },
- ],
- },
- {
- type: 'row',
- id: 5,
- panels: [
- {
- id: 6,
- datasource: 'prom',
- },
- ],
- },
- ],
- });
- });
- it('should not update variable datasource props to refs', () => {
- expect(model.templating.list[0].datasource).toEqual('prom');
- });
- it('should update panel datasource props to refs for named data source', () => {
- expect(model.panels[0].datasource).toEqual({ type: 'prometheus', uid: 'prom-uid' });
- });
- it('should update panel datasource props to refs for default data source', () => {
- expect(model.panels[1].datasource).toEqual({ type: 'prometheus', uid: 'prom2-uid' });
- });
- it('should update panel datasource props to refs for mixed data source', () => {
- expect(model.panels[2].datasource).toEqual({ type: 'mixed', uid: MIXED_DATASOURCE_NAME });
- });
- it('should update target datasource props to refs', () => {
- expect(model.panels[2].targets[0].datasource).toEqual({ type: 'prometheus', uid: 'prom-uid' });
- });
- it('should update datasources in panels collapsed rows', () => {
- expect(model.panels[3].panels?.[0].datasource).toEqual({ type: 'prometheus', uid: 'prom-uid' });
- });
- });
- describe('when fixing query and panel data source refs out of sync due to default data source change', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- templating: {
- list: [],
- },
- panels: [
- {
- id: 2,
- datasource: null,
- targets: [
- {
- datasource: 'prom-not-default',
- },
- ],
- },
- ],
- });
- });
- it('should use data source on query level as source of truth', () => {
- expect(model.panels[0].targets[0]?.datasource?.uid).toEqual('prom-not-default-uid');
- expect(model.panels[0].datasource?.uid).toEqual('prom-not-default-uid');
- });
- });
- describe('when migrating time series axis visibility', () => {
- test('preserves x axis visibility', () => {
- const model = new DashboardModel({
- panels: [
- {
- type: 'timeseries',
- fieldConfig: {
- defaults: {
- custom: {
- axisPlacement: 'hidden',
- },
- },
- overrides: [],
- },
- },
- ],
- });
- expect(model.panels[0].fieldConfig.overrides).toMatchInlineSnapshot(`
- Array [
- Object {
- "matcher": Object {
- "id": "byType",
- "options": "time",
- },
- "properties": Array [
- Object {
- "id": "custom.axisPlacement",
- "value": "auto",
- },
- ],
- },
- ]
- `);
- });
- });
- describe('when migrating default (null) datasource', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- templating: {
- list: [
- {
- type: 'query',
- name: 'var',
- options: [{ text: 'A', value: 'A' }],
- refresh: 0,
- datasource: null,
- },
- ],
- },
- annotations: {
- list: [
- {
- datasource: null,
- },
- {
- datasource: 'prom',
- },
- ],
- },
- panels: [
- {
- id: 2,
- datasource: null,
- targets: [
- {
- datasource: null,
- },
- ],
- },
- {
- id: 3,
- targets: [
- {
- refId: 'A',
- },
- ],
- },
- ],
- schemaVersion: 35,
- });
- });
- it('should set data source to current default', () => {
- expect(model.templating.list[0].datasource).toEqual({ type: 'prometheus', uid: 'prom2-uid' });
- });
- it('should migrate annotation null query to default ds', () => {
- expect(model.annotations.list[1].datasource).toEqual({ type: 'prometheus', uid: 'prom2-uid' });
- });
- it('should migrate annotation query to refs', () => {
- expect(model.annotations.list[2].datasource).toEqual({ type: 'prometheus', uid: 'prom-uid' });
- });
- it('should update panel datasource props to refs for named data source', () => {
- expect(model.panels[0].datasource).toEqual({ type: 'prometheus', uid: 'prom2-uid' });
- });
- it('should update panel datasource props even when undefined', () => {
- expect(model.panels[1].datasource).toEqual({ type: 'prometheus', uid: 'prom2-uid' });
- });
- it('should update target datasource props to refs', () => {
- expect(model.panels[0].targets[0].datasource).toEqual({ type: 'prometheus', uid: 'prom2-uid' });
- });
- });
- describe('when migrating default (null) datasource with panel with expressions queries', () => {
- let model: DashboardModel;
- beforeEach(() => {
- model = new DashboardModel({
- panels: [
- {
- id: 2,
- targets: [
- {
- refId: 'A',
- },
- {
- refId: 'B',
- datasource: '__expr__',
- },
- ],
- },
- ],
- schemaVersion: 30,
- });
- });
- it('should update panel datasource props to default datasource', () => {
- expect(model.panels[0].datasource).toEqual({ type: 'prometheus', uid: 'prom2-uid' });
- });
- it('should update target datasource props to default data source', () => {
- expect(model.panels[0].targets[0].datasource).toEqual({ type: 'prometheus', uid: 'prom2-uid' });
- });
- });
- });
- function createRow(options: any, panelDescriptions: any[]) {
- const PANEL_HEIGHT_STEP = GRID_CELL_HEIGHT + GRID_CELL_VMARGIN;
- const { collapse, showTitle, title, repeat, repeatIteration } = options;
- let { height } = options;
- height = height * PANEL_HEIGHT_STEP;
- const panels: any[] = [];
- each(panelDescriptions, (panelDesc) => {
- const panel = { span: panelDesc[0] };
- if (panelDesc.length > 1) {
- //@ts-ignore
- panel['height'] = panelDesc[1] * PANEL_HEIGHT_STEP;
- }
- panels.push(panel);
- });
- const row = {
- collapse,
- height,
- showTitle,
- title,
- panels,
- repeat,
- repeatIteration,
- };
- return row;
- }
- function getGridPositions(dashboard: DashboardModel) {
- return map(dashboard.panels, (panel: PanelModel) => {
- return panel.gridPos;
- });
- }
|