PanelInspect: Interpolates variables in CSV file name (#31936)

* PanelInspect: Variables in CSV file name are interpolated

* Chore: fixes failing test
This commit is contained in:
Hugo Häggmark 2021-03-15 08:44:13 +01:00 committed by GitHub
parent 3e66328deb
commit 66177e9463
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 39 deletions

View File

@ -3,6 +3,7 @@ import AutoSizer from 'react-virtualized-auto-sizer';
import {
applyFieldOverrides,
applyRawFieldOverrides,
CSVConfig,
DataFrame,
DataTransformerID,
dateTimeFormat,
@ -10,9 +11,8 @@ import {
SelectableValue,
toCSV,
transformDataFrame,
CSVConfig,
} from '@grafana/data';
import { Button, Container, Field, HorizontalGroup, Spinner, Select, Switch, Table, VerticalGroup } from '@grafana/ui';
import { Button, Container, Field, HorizontalGroup, Select, Spinner, Switch, Table, VerticalGroup } from '@grafana/ui';
import { selectors } from '@grafana/e2e-selectors';
import { getPanelInspectorStyles } from './styles';
@ -94,7 +94,7 @@ export class InspectDataTab extends PureComponent<Props, State> {
type: 'text/csv;charset=utf-8',
});
const transformation = transformId !== DataTransformerID.noop ? '-as-' + transformId.toLocaleLowerCase() : '';
const fileName = `${panel.title}-data${transformation}-${dateTimeFormat(new Date())}.csv`;
const fileName = `${panel.getDisplayTitle()}-data${transformation}-${dateTimeFormat(new Date())}.csv`;
saveAs(blob, fileName);
};

View File

@ -37,6 +37,7 @@ function setupTestContext(options: Partial<Props>) {
events: { subscribe: jest.fn() },
getQueryRunner: () => panelQueryRunner,
getOptions: jest.fn(),
getDisplayTitle: jest.fn(),
} as unknown) as PanelModel,
dashboard: ({
panelInitialized: jest.fn(),

View File

@ -28,7 +28,7 @@ export interface Props {
export const PanelHeader: FC<Props> = ({ panel, error, isViewing, isEditing, data, alertState, dashboard }) => {
const onCancelQuery = () => panel.getQueryRunner().cancelQuery();
const title = panel.replaceVariables(panel.title, {}, 'text');
const title = panel.getDisplayTitle();
const className = cx('panel-header', !(isViewing || isEditing) ? 'grid-drag-handle' : '');
return (

View File

@ -1,13 +1,12 @@
import { PanelModel } from './PanelModel';
import { getPanelPlugin } from '../../plugins/__mocks__/pluginMocks';
import {
DataLinkBuiltInVars,
FieldConfigProperty,
PanelData,
PanelProps,
standardEditorsRegistry,
standardFieldConfigEditorRegistry,
PanelData,
DataLinkBuiltInVars,
VariableModel,
} from '@grafana/data';
import { ComponentClass } from 'react';
import { PanelQueryRunner } from '../../query/state/PanelQueryRunner';
@ -17,6 +16,7 @@ import { setTemplateSrv } from '@grafana/runtime';
import { variableAdapters } from '../../variables/adapters';
import { createQueryVariableAdapter } from '../../variables/query/adapter';
import { mockStandardFieldConfigOptions } from '../../../../test/helpers/fieldConfig';
import { queryBuilder } from 'app/features/variables/shared/testing/builders';
standardFieldConfigEditorRegistry.setInit(() => mockStandardFieldConfigOptions());
standardEditorsRegistry.setInit(() => mockStandardFieldConfigOptions());
@ -28,16 +28,15 @@ setTimeSrv({
}),
} as any);
const getVariables = () => variablesMock;
const getVariableWithName = (name: string) => variablesMock.filter((v) => v.name === name)[0];
const getFilteredVariables = jest.fn();
setTemplateSrv(
new TemplateSrv({
// @ts-ignore
getVariables: () => {
return variablesMock;
},
// @ts-ignore
getVariableWithName: (name: string) => {
return variablesMock.filter((v) => v.name === name)[0];
},
getVariables,
getVariableWithName,
getFilteredVariables,
})
);
@ -223,7 +222,7 @@ describe('PanelModel', () => {
it('should interpolate $__all_variables variable', () => {
const out = model.replaceVariables(`/d/1?$${DataLinkBuiltInVars.includeVars}`);
expect(out).toBe('/d/1?var-test1=val1&var-test2=val2');
expect(out).toBe('/d/1?var-test1=val1&var-test2=val2&var-test3=Value%203&var-test4=A&var-test4=B');
});
it('should prefer the local variable value', () => {
@ -328,7 +327,7 @@ describe('PanelModel', () => {
expect(model.showColumns).toBe(true);
});
it('should restore custom field config to what it was and preseve standard options', () => {
it('should restore custom field config to what it was and preserve standard options', () => {
model.changePlugin(tablePlugin);
expect(model.fieldConfig.defaults.custom.customProp).toBe(true);
});
@ -438,30 +437,32 @@ describe('PanelModel', () => {
expect(model.getQueryRunner().getLastResult()).toBeDefined();
});
});
describe('getDisplayTitle', () => {
it('when called then it should interpolate singe value variables in title', () => {
const model = new PanelModel({
title: 'Single value variable [[test3]] ${test3} ${test3:percentencode}',
});
const title = model.getDisplayTitle();
expect(title).toEqual('Single value variable Value 3 Value 3 Value%203');
});
it('when called then it should interpolate multi value variables in title', () => {
const model = new PanelModel({
title: 'Multi value variable [[test4]] ${test4} ${test4:percentencode}',
});
const title = model.getDisplayTitle();
expect(title).toEqual('Multi value variable A + B A + B %7BA%2CB%7D');
});
});
});
});
const variablesMock = [
{
type: 'query',
name: 'test1',
label: 'Test1',
hide: false,
current: { value: 'val1' },
skipUrlSync: false,
getValueForUrl: function () {
return 'val1';
},
} as VariableModel,
{
type: 'query',
name: 'test2',
label: 'Test2',
hide: false,
current: { value: 'val2' },
skipUrlSync: false,
getValueForUrl: function () {
return 'val2';
},
} as VariableModel,
queryBuilder().withId('test1').withName('test1').withCurrent('val1').build(),
queryBuilder().withId('test2').withName('test2').withCurrent('val2').build(),
queryBuilder().withId('test3').withName('test3').withCurrent('Value 3').build(),
queryBuilder().withId('test4').withName('test4').withCurrent(['A', 'B']).build(),
];

View File

@ -59,6 +59,7 @@ const notPersistedProperties: { [str: string]: boolean } = {
replaceVariables: true,
editSourceId: true,
hasChanged: true,
getDisplayTitle: true,
};
// For angular panels we need to clean up properties when changing type
@ -102,6 +103,7 @@ const mustKeepProps: { [str: string]: boolean } = {
interval: true,
replaceVariables: true,
libraryPanel: true,
getDisplayTitle: true,
};
const defaults: any = {
@ -551,6 +553,14 @@ export class PanelModel implements DataConfigSource {
getSavedId(): number {
return this.editSourceId ?? this.id;
}
/*
* This is the title used when displaying the title in the UI so it will include any interpolated variables.
* If you need the raw title without interpolation use title property instead.
* */
getDisplayTitle(): string {
return this.replaceVariables(this.title, {}, 'text');
}
}
function getPluginVersion(plugin: PanelPlugin): string {