mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
3e66328deb
commit
66177e9463
@ -3,6 +3,7 @@ import AutoSizer from 'react-virtualized-auto-sizer';
|
|||||||
import {
|
import {
|
||||||
applyFieldOverrides,
|
applyFieldOverrides,
|
||||||
applyRawFieldOverrides,
|
applyRawFieldOverrides,
|
||||||
|
CSVConfig,
|
||||||
DataFrame,
|
DataFrame,
|
||||||
DataTransformerID,
|
DataTransformerID,
|
||||||
dateTimeFormat,
|
dateTimeFormat,
|
||||||
@ -10,9 +11,8 @@ import {
|
|||||||
SelectableValue,
|
SelectableValue,
|
||||||
toCSV,
|
toCSV,
|
||||||
transformDataFrame,
|
transformDataFrame,
|
||||||
CSVConfig,
|
|
||||||
} from '@grafana/data';
|
} 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 { selectors } from '@grafana/e2e-selectors';
|
||||||
|
|
||||||
import { getPanelInspectorStyles } from './styles';
|
import { getPanelInspectorStyles } from './styles';
|
||||||
@ -94,7 +94,7 @@ export class InspectDataTab extends PureComponent<Props, State> {
|
|||||||
type: 'text/csv;charset=utf-8',
|
type: 'text/csv;charset=utf-8',
|
||||||
});
|
});
|
||||||
const transformation = transformId !== DataTransformerID.noop ? '-as-' + transformId.toLocaleLowerCase() : '';
|
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);
|
saveAs(blob, fileName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ function setupTestContext(options: Partial<Props>) {
|
|||||||
events: { subscribe: jest.fn() },
|
events: { subscribe: jest.fn() },
|
||||||
getQueryRunner: () => panelQueryRunner,
|
getQueryRunner: () => panelQueryRunner,
|
||||||
getOptions: jest.fn(),
|
getOptions: jest.fn(),
|
||||||
|
getDisplayTitle: jest.fn(),
|
||||||
} as unknown) as PanelModel,
|
} as unknown) as PanelModel,
|
||||||
dashboard: ({
|
dashboard: ({
|
||||||
panelInitialized: jest.fn(),
|
panelInitialized: jest.fn(),
|
||||||
|
@ -28,7 +28,7 @@ export interface Props {
|
|||||||
|
|
||||||
export const PanelHeader: FC<Props> = ({ panel, error, isViewing, isEditing, data, alertState, dashboard }) => {
|
export const PanelHeader: FC<Props> = ({ panel, error, isViewing, isEditing, data, alertState, dashboard }) => {
|
||||||
const onCancelQuery = () => panel.getQueryRunner().cancelQuery();
|
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' : '');
|
const className = cx('panel-header', !(isViewing || isEditing) ? 'grid-drag-handle' : '');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import { PanelModel } from './PanelModel';
|
import { PanelModel } from './PanelModel';
|
||||||
import { getPanelPlugin } from '../../plugins/__mocks__/pluginMocks';
|
import { getPanelPlugin } from '../../plugins/__mocks__/pluginMocks';
|
||||||
import {
|
import {
|
||||||
|
DataLinkBuiltInVars,
|
||||||
FieldConfigProperty,
|
FieldConfigProperty,
|
||||||
|
PanelData,
|
||||||
PanelProps,
|
PanelProps,
|
||||||
standardEditorsRegistry,
|
standardEditorsRegistry,
|
||||||
standardFieldConfigEditorRegistry,
|
standardFieldConfigEditorRegistry,
|
||||||
PanelData,
|
|
||||||
DataLinkBuiltInVars,
|
|
||||||
VariableModel,
|
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { ComponentClass } from 'react';
|
import { ComponentClass } from 'react';
|
||||||
import { PanelQueryRunner } from '../../query/state/PanelQueryRunner';
|
import { PanelQueryRunner } from '../../query/state/PanelQueryRunner';
|
||||||
@ -17,6 +16,7 @@ import { setTemplateSrv } from '@grafana/runtime';
|
|||||||
import { variableAdapters } from '../../variables/adapters';
|
import { variableAdapters } from '../../variables/adapters';
|
||||||
import { createQueryVariableAdapter } from '../../variables/query/adapter';
|
import { createQueryVariableAdapter } from '../../variables/query/adapter';
|
||||||
import { mockStandardFieldConfigOptions } from '../../../../test/helpers/fieldConfig';
|
import { mockStandardFieldConfigOptions } from '../../../../test/helpers/fieldConfig';
|
||||||
|
import { queryBuilder } from 'app/features/variables/shared/testing/builders';
|
||||||
|
|
||||||
standardFieldConfigEditorRegistry.setInit(() => mockStandardFieldConfigOptions());
|
standardFieldConfigEditorRegistry.setInit(() => mockStandardFieldConfigOptions());
|
||||||
standardEditorsRegistry.setInit(() => mockStandardFieldConfigOptions());
|
standardEditorsRegistry.setInit(() => mockStandardFieldConfigOptions());
|
||||||
@ -28,16 +28,15 @@ setTimeSrv({
|
|||||||
}),
|
}),
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
|
const getVariables = () => variablesMock;
|
||||||
|
const getVariableWithName = (name: string) => variablesMock.filter((v) => v.name === name)[0];
|
||||||
|
const getFilteredVariables = jest.fn();
|
||||||
|
|
||||||
setTemplateSrv(
|
setTemplateSrv(
|
||||||
new TemplateSrv({
|
new TemplateSrv({
|
||||||
// @ts-ignore
|
getVariables,
|
||||||
getVariables: () => {
|
getVariableWithName,
|
||||||
return variablesMock;
|
getFilteredVariables,
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
getVariableWithName: (name: string) => {
|
|
||||||
return variablesMock.filter((v) => v.name === name)[0];
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -223,7 +222,7 @@ describe('PanelModel', () => {
|
|||||||
|
|
||||||
it('should interpolate $__all_variables variable', () => {
|
it('should interpolate $__all_variables variable', () => {
|
||||||
const out = model.replaceVariables(`/d/1?$${DataLinkBuiltInVars.includeVars}`);
|
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', () => {
|
it('should prefer the local variable value', () => {
|
||||||
@ -328,7 +327,7 @@ describe('PanelModel', () => {
|
|||||||
expect(model.showColumns).toBe(true);
|
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);
|
model.changePlugin(tablePlugin);
|
||||||
expect(model.fieldConfig.defaults.custom.customProp).toBe(true);
|
expect(model.fieldConfig.defaults.custom.customProp).toBe(true);
|
||||||
});
|
});
|
||||||
@ -438,30 +437,32 @@ describe('PanelModel', () => {
|
|||||||
expect(model.getQueryRunner().getLastResult()).toBeDefined();
|
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 = [
|
const variablesMock = [
|
||||||
{
|
queryBuilder().withId('test1').withName('test1').withCurrent('val1').build(),
|
||||||
type: 'query',
|
queryBuilder().withId('test2').withName('test2').withCurrent('val2').build(),
|
||||||
name: 'test1',
|
queryBuilder().withId('test3').withName('test3').withCurrent('Value 3').build(),
|
||||||
label: 'Test1',
|
queryBuilder().withId('test4').withName('test4').withCurrent(['A', 'B']).build(),
|
||||||
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,
|
|
||||||
];
|
];
|
||||||
|
@ -59,6 +59,7 @@ const notPersistedProperties: { [str: string]: boolean } = {
|
|||||||
replaceVariables: true,
|
replaceVariables: true,
|
||||||
editSourceId: true,
|
editSourceId: true,
|
||||||
hasChanged: true,
|
hasChanged: true,
|
||||||
|
getDisplayTitle: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
// For angular panels we need to clean up properties when changing type
|
// For angular panels we need to clean up properties when changing type
|
||||||
@ -102,6 +103,7 @@ const mustKeepProps: { [str: string]: boolean } = {
|
|||||||
interval: true,
|
interval: true,
|
||||||
replaceVariables: true,
|
replaceVariables: true,
|
||||||
libraryPanel: true,
|
libraryPanel: true,
|
||||||
|
getDisplayTitle: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaults: any = {
|
const defaults: any = {
|
||||||
@ -551,6 +553,14 @@ export class PanelModel implements DataConfigSource {
|
|||||||
getSavedId(): number {
|
getSavedId(): number {
|
||||||
return this.editSourceId ?? this.id;
|
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 {
|
function getPluginVersion(plugin: PanelPlugin): string {
|
||||||
|
Loading…
Reference in New Issue
Block a user