Files
grafana/public/app/features/dashboard/state/DashboardMigrator.test.ts

662 lines
20 KiB
TypeScript
Raw Normal View History

2017-12-20 12:33:33 +01:00
import _ from 'lodash';
import { DashboardModel } from '../state/DashboardModel';
import { PanelModel } from '../state/PanelModel';
2017-12-20 12:33:33 +01:00
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN } from 'app/core/constants';
import { expect } from 'test/lib/common';
import { DataLinkBuiltInVars } from '@grafana/data';
2017-12-20 12:33:33 +01:00
jest.mock('app/core/services/context_srv', () => ({}));
describe('DashboardModel', () => {
describe('when creating dashboard with old schema', () => {
let model: any;
let graph: any;
let singlestat: any;
let table: any;
beforeEach(() => {
model = new DashboardModel({
services: {
2017-12-20 12:33:33 +01:00
filter: { time: { from: 'now-1d', to: 'now' }, list: [{}] },
},
pulldowns: [
2017-12-20 12:33:33 +01:00
{ type: 'filtering', enable: true },
{ type: 'annotations', enable: true, annotations: [{ name: 'old' }] },
],
panels: [
{
2017-12-20 12:33:33 +01:00
type: 'graph',
legend: true,
aliasYAxis: { test: 2 },
2017-12-20 12:33:33 +01:00
y_formats: ['kbyte', 'ms'],
grid: {
min: 1,
max: 10,
rightMin: 5,
rightMax: 15,
leftLogBase: 1,
rightLogBase: 2,
threshold1: 200,
threshold2: 400,
2017-12-20 12:33:33 +01:00
threshold1Color: 'yellow',
threshold2Color: 'red',
},
2017-12-20 12:33:33 +01:00
leftYAxisLabel: 'left label',
targets: [{ refId: 'A' }, {}],
},
{
2017-12-20 12:33:33 +01:00
type: 'singlestat',
legend: true,
2017-12-20 12:33:33 +01:00
thresholds: '10,20,30',
aliasYAxis: { test: 2 },
grid: { min: 1, max: 10 },
2017-12-20 12:33:33 +01:00
targets: [{ refId: 'A' }, {}],
},
{
2017-12-20 12:33:33 +01:00
type: 'table',
legend: true,
styles: [{ thresholds: ['10', '20', '30'] }, { thresholds: ['100', '200', '300'] }],
2017-12-20 12:33:33 +01:00
targets: [{ refId: 'A' }, {}],
},
],
});
graph = model.panels[0];
singlestat = model.panels[1];
table = model.panels[2];
});
it('should have title', () => {
2017-12-20 12:33:33 +01:00
expect(model.title).toBe('No Title');
});
it('should have panel id', () => {
expect(graph.id).toBe(1);
});
it('should move time and filtering list', () => {
2017-12-20 12:33:33 +01:00
expect(model.time.from).toBe('now-1d');
expect(model.templating.list[0].allFormat).toBe('glob');
});
it('graphite panel should change name too graph', () => {
2017-12-20 12:33:33 +01:00
expect(graph.type).toBe('graph');
});
it('single stat panel should have two thresholds', () => {
2017-12-20 12:33:33 +01:00
expect(singlestat.thresholds).toBe('20,30');
});
it('queries without refId should get it', () => {
2017-12-20 12:33:33 +01:00
expect(graph.targets[1].refId).toBe('B');
});
it('update legend setting', () => {
expect(graph.legend.show).toBe(true);
});
it('move aliasYAxis to series override', () => {
2017-12-20 12:33:33 +01:00
expect(graph.seriesOverrides[0].alias).toBe('test');
expect(graph.seriesOverrides[0].yaxis).toBe(2);
});
it('should move pulldowns to new schema', () => {
2017-12-20 12:33:33 +01:00
expect(model.annotations.list[1].name).toBe('old');
});
it('table panel should only have two thresholds values', () => {
2017-12-20 12:33:33 +01:00
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);
2017-12-20 12:33:33 +01:00
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);
2017-12-20 12:33:33 +01:00
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(24);
});
it('graph thresholds should be migrated', () => {
expect(graph.thresholds.length).toBe(2);
2017-12-20 12:33:33 +01:00
expect(graph.thresholds[0].op).toBe('gt');
expect(graph.thresholds[0].value).toBe(200);
2017-12-20 12:33:33 +01:00
expect(graph.thresholds[0].fillColor).toBe('yellow');
expect(graph.thresholds[1].value).toBe(400);
2017-12-20 12:33:33 +01:00
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 = {
2017-12-20 12:33:33 +01:00
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
2017-12-20 12:33:33 +01:00
{ 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 = [
2017-12-20 12:33:33 +01:00
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
2017-12-20 12:33:33 +01:00
{ 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]]),
2017-12-20 12:33:33 +01:00
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 },
2017-12-20 12:33:33 +01:00
{ 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
2017-12-20 12:33:33 +01:00
{ 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]]),
2017-12-20 12:33:33 +01:00
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 },
2017-12-20 12:33:33 +01:00
{ 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 },
2017-12-20 12:33:33 +01:00
{ 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 },
2017-12-20 12:33:33 +01:00
{ 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 },
2017-12-20 12:33:33 +01:00
{ 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 },
2017-12-20 12:33:33 +01:00
{ 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 },
2017-12-20 12:33:33 +01:00
{ 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]]),
2017-12-20 12:33:33 +01:00
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 },
2017-12-20 12:33:33 +01:00
{ x: 0, y: 10, w: 24, h: 8 },
];
expect(panelGridPos).toEqual(expectedGrid);
2017-12-20 12:33:33 +01:00
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,
2017-12-20 12:33:33 +01:00
title: 'Row2',
height: 8,
repeatIteration: 12313,
2017-12-20 12:33:33 +01:00
repeatRowId: 1,
},
[[6]]
2017-12-20 12:33:33 +01:00
),
];
const dashboard = new DashboardModel(model);
2017-12-20 12:33:33 +01:00
expect(dashboard.panels[0].repeat).toBe('server');
expect(dashboard.panels.length).toBe(2);
});
2018-02-16 17:29:10 +09:00
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);
});
});
Graph: Add data links feature (click on graph) (#17267) * WIP: initial panel links editor * WIP: Added dashboard migration to new panel drilldown link schema * Make link_srv interpolate new variables * Fix failing tests * Drilldown: Add context menu to graph viz (#17284) * Add simple context menu for adding graph annotations and showing drilldown links * Close graph context menu when user start scrolling * Move context menu component to grafana/ui * Make graph context menu appear on click, use cmd/ctrl click for quick annotations * Move graph context menu controller to separate file * Drilldown: datapoint variables interpolation (#17328) * Add simple context menu for adding graph annotations and showing drilldown links * Close graph context menu when user start scrolling * Move context menu component to grafana/ui * Make graph context menu appear on click, use cmd/ctrl click for quick annotations * Add util for absolute time range transformation * Add series name and datapoint timestamp interpolation * Rename drilldown link variables tot snake case, use const values instead of strings in tests * Bring LinkSrv.getPanelLinkAnchorInfo for compatibility reasons and add deprecation warning * Rename seriesLabel to seriesName * Drilldown: use separate editors for panel and series links (#17355) * Use correct target ini context menu links * Rename PanelLinksEditor to DrilldownLinksEditor and mote it to grafana/ui * Expose DrilldownLinksEditor as an angular directive * Enable visualization specifix drilldown links * Props interfaces rename * Drilldown: Add variables suggestion and syntax highlighting for drilldown link editor (#17391) * Add variables suggestion in drilldown link editor * Enable prism * Fix backspace not working * Move slate value helpers to grafana/ui * Add syntax higlighting for links input * Rename drilldown link components to data links * Add template variabe suggestions * Bugfix * Fix regexp not working in Firefox * Display correct links in panel header corner * bugfix * bugfix * Bugfix * Context menu UI tweaks * Use data link terminology instead of drilldown * DataLinks: changed autocomplete syntax * Use singular form for data link * Use the same syntax higlighting for built-in and template variables in data links editor * UI improvements to context menu * UI review tweaks * Tweak layout of data link editor * Fix vertical spacing * Remove data link header in context menu * Remove pointer cursor from series label in context menu * Fix variable selection on click * DataLinks: migrations for old links * Update docs about data links * Use value time instead of time range when interpolating datapoint timestamp * Remove not used util * Update docs * Moved icon a bit more down * Interpolate value ts only when using __value_time variable * Bring href property back to LinkModel * Add any type annotations * Fix TS error on slate's Value type * minor changes
2019-06-25 11:38:51 +02:00
describe('when migrating panel links', () => {
let model: any;
Graph: Add data links feature (click on graph) (#17267) * WIP: initial panel links editor * WIP: Added dashboard migration to new panel drilldown link schema * Make link_srv interpolate new variables * Fix failing tests * Drilldown: Add context menu to graph viz (#17284) * Add simple context menu for adding graph annotations and showing drilldown links * Close graph context menu when user start scrolling * Move context menu component to grafana/ui * Make graph context menu appear on click, use cmd/ctrl click for quick annotations * Move graph context menu controller to separate file * Drilldown: datapoint variables interpolation (#17328) * Add simple context menu for adding graph annotations and showing drilldown links * Close graph context menu when user start scrolling * Move context menu component to grafana/ui * Make graph context menu appear on click, use cmd/ctrl click for quick annotations * Add util for absolute time range transformation * Add series name and datapoint timestamp interpolation * Rename drilldown link variables tot snake case, use const values instead of strings in tests * Bring LinkSrv.getPanelLinkAnchorInfo for compatibility reasons and add deprecation warning * Rename seriesLabel to seriesName * Drilldown: use separate editors for panel and series links (#17355) * Use correct target ini context menu links * Rename PanelLinksEditor to DrilldownLinksEditor and mote it to grafana/ui * Expose DrilldownLinksEditor as an angular directive * Enable visualization specifix drilldown links * Props interfaces rename * Drilldown: Add variables suggestion and syntax highlighting for drilldown link editor (#17391) * Add variables suggestion in drilldown link editor * Enable prism * Fix backspace not working * Move slate value helpers to grafana/ui * Add syntax higlighting for links input * Rename drilldown link components to data links * Add template variabe suggestions * Bugfix * Fix regexp not working in Firefox * Display correct links in panel header corner * bugfix * bugfix * Bugfix * Context menu UI tweaks * Use data link terminology instead of drilldown * DataLinks: changed autocomplete syntax * Use singular form for data link * Use the same syntax higlighting for built-in and template variables in data links editor * UI improvements to context menu * UI review tweaks * Tweak layout of data link editor * Fix vertical spacing * Remove data link header in context menu * Remove pointer cursor from series label in context menu * Fix variable selection on click * DataLinks: migrations for old links * Update docs about data links * Use value time instead of time range when interpolating datapoint timestamp * Remove not used util * Update docs * Moved icon a bit more down * Interpolate value ts only when using __value_time variable * Bring href property back to LinkModel * Add any type annotations * Fix TS error on slate's Value type * minor changes
2019-06-25 11:38:51 +02:00
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,
},
Graph: Add data links feature (click on graph) (#17267) * WIP: initial panel links editor * WIP: Added dashboard migration to new panel drilldown link schema * Make link_srv interpolate new variables * Fix failing tests * Drilldown: Add context menu to graph viz (#17284) * Add simple context menu for adding graph annotations and showing drilldown links * Close graph context menu when user start scrolling * Move context menu component to grafana/ui * Make graph context menu appear on click, use cmd/ctrl click for quick annotations * Move graph context menu controller to separate file * Drilldown: datapoint variables interpolation (#17328) * Add simple context menu for adding graph annotations and showing drilldown links * Close graph context menu when user start scrolling * Move context menu component to grafana/ui * Make graph context menu appear on click, use cmd/ctrl click for quick annotations * Add util for absolute time range transformation * Add series name and datapoint timestamp interpolation * Rename drilldown link variables tot snake case, use const values instead of strings in tests * Bring LinkSrv.getPanelLinkAnchorInfo for compatibility reasons and add deprecation warning * Rename seriesLabel to seriesName * Drilldown: use separate editors for panel and series links (#17355) * Use correct target ini context menu links * Rename PanelLinksEditor to DrilldownLinksEditor and mote it to grafana/ui * Expose DrilldownLinksEditor as an angular directive * Enable visualization specifix drilldown links * Props interfaces rename * Drilldown: Add variables suggestion and syntax highlighting for drilldown link editor (#17391) * Add variables suggestion in drilldown link editor * Enable prism * Fix backspace not working * Move slate value helpers to grafana/ui * Add syntax higlighting for links input * Rename drilldown link components to data links * Add template variabe suggestions * Bugfix * Fix regexp not working in Firefox * Display correct links in panel header corner * bugfix * bugfix * Bugfix * Context menu UI tweaks * Use data link terminology instead of drilldown * DataLinks: changed autocomplete syntax * Use singular form for data link * Use the same syntax higlighting for built-in and template variables in data links editor * UI improvements to context menu * UI review tweaks * Tweak layout of data link editor * Fix vertical spacing * Remove data link header in context menu * Remove pointer cursor from series label in context menu * Fix variable selection on click * DataLinks: migrations for old links * Update docs about data links * Use value time instead of time range when interpolating datapoint timestamp * Remove not used util * Update docs * Moved icon a bit more down * Interpolate value ts only when using __value_time variable * Bring href property back to LinkModel * Add any type annotations * Fix TS error on slate's Value type * minor changes
2019-06-25 11:38:51 +02:00
],
},
],
});
});
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`);
Graph: Add data links feature (click on graph) (#17267) * WIP: initial panel links editor * WIP: Added dashboard migration to new panel drilldown link schema * Make link_srv interpolate new variables * Fix failing tests * Drilldown: Add context menu to graph viz (#17284) * Add simple context menu for adding graph annotations and showing drilldown links * Close graph context menu when user start scrolling * Move context menu component to grafana/ui * Make graph context menu appear on click, use cmd/ctrl click for quick annotations * Move graph context menu controller to separate file * Drilldown: datapoint variables interpolation (#17328) * Add simple context menu for adding graph annotations and showing drilldown links * Close graph context menu when user start scrolling * Move context menu component to grafana/ui * Make graph context menu appear on click, use cmd/ctrl click for quick annotations * Add util for absolute time range transformation * Add series name and datapoint timestamp interpolation * Rename drilldown link variables tot snake case, use const values instead of strings in tests * Bring LinkSrv.getPanelLinkAnchorInfo for compatibility reasons and add deprecation warning * Rename seriesLabel to seriesName * Drilldown: use separate editors for panel and series links (#17355) * Use correct target ini context menu links * Rename PanelLinksEditor to DrilldownLinksEditor and mote it to grafana/ui * Expose DrilldownLinksEditor as an angular directive * Enable visualization specifix drilldown links * Props interfaces rename * Drilldown: Add variables suggestion and syntax highlighting for drilldown link editor (#17391) * Add variables suggestion in drilldown link editor * Enable prism * Fix backspace not working * Move slate value helpers to grafana/ui * Add syntax higlighting for links input * Rename drilldown link components to data links * Add template variabe suggestions * Bugfix * Fix regexp not working in Firefox * Display correct links in panel header corner * bugfix * bugfix * Bugfix * Context menu UI tweaks * Use data link terminology instead of drilldown * DataLinks: changed autocomplete syntax * Use singular form for data link * Use the same syntax higlighting for built-in and template variables in data links editor * UI improvements to context menu * UI review tweaks * Tweak layout of data link editor * Fix vertical spacing * Remove data link header in context menu * Remove pointer cursor from series label in context menu * Fix variable selection on click * DataLinks: migrations for old links * Update docs about data links * Use value time instead of time range when interpolating datapoint timestamp * Remove not used util * Update docs * Moved icon a bit more down * Interpolate value ts only when using __value_time variable * Bring href property back to LinkModel * Add any type annotations * Fix TS error on slate's Value type * minor changes
2019-06-25 11:38:51 +02:00
});
});
DataLinks: enable access to labels & field names (#18918) * POC: trying to see if there is a way to support objects in template interpolations * Added support for nested objects, and arrays * Added accessor cache * fixed unit tests * First take * Use links supplier in graph * Add field's index to cache items * Get field index from field cache * CHange FiledCacheItem to FieldWithIndex * Add refId to TimeSeries class * Make field link supplier work with _series, _field and _value vars * use field link supplier in graph * Fix yaxis settings * Update dashboard schema version and add migration for data links variables * Update snapshots * Update build in data link variables * FieldCache - idx -> index * Add current query results to panel editor * WIP Updated data links dropdown to display new variables * Fix build * Update variables syntac in field display, update migration * Field links supplier: review updates * Add data frame view and field name to TimeSeries for later inspection * Retrieve data frame from TimeSeries when clicking on plot graph * Use data frame's index instead of view * Retrieve data frame by index instead of view on TimeSeries * Update data links prism regex * Fix typecheck * Add value variables to suggestions list * UI update * Rename field to config in DisplayProcessorOptions * Proces single value of a field instead of entire data frame * Updated font size from 10px to 12px for auto complete * Replace fieldName with fieldIndex in TimeSeries * Don't use .entries() for iterating in field cache * Don't use FieldCache when retrieving field for datalinks in graph * Add value calculation variable to data links (#19031) * Add support for labels with dots in the name (#19033) * Docs update * Use field name instead of removed series.fieldName * Add test dashboard * Typos fix * Make visualization tab subscribe to query results * Added tags to dashboard so it shows up in lists * minor docs fix * Update singlestat-ish variables suggestions to contain series variables * Decrease suggestions update debounce * Enable whitespace characters(new line, space) in links and strip them when processing the data link * minor data links UI update * DataLinks: Add __from and __to variables suggestions to data links (#19093) * Add from and to variables suggestions to data links * Update docs * UI update and added info text * Change ESC global bind to bind (doesn't capture ESC on input) * Close datalinks suggestions on ESC * Remove unnecessary fragment
2019-09-13 16:38:21 +02:00
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'],
});
});
});
});
function createRow(options: any, panelDescriptions: any[]) {
const PANEL_HEIGHT_STEP = GRID_CELL_HEIGHT + GRID_CELL_VMARGIN;
2018-08-26 20:19:23 +02:00
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
2017-12-20 12:33:33 +01:00
panel['height'] = panelDesc[1] * PANEL_HEIGHT_STEP;
}
panels.push(panel);
});
const row = {
collapse,
height,
showTitle,
title,
panels,
repeat,
2017-12-20 12:33:33 +01:00
repeatIteration,
};
return row;
}
function getGridPositions(dashboard: DashboardModel) {
return _.map(dashboard.panels, (panel: PanelModel) => {
return panel.gridPos;
});
}