Field: getFieldTitle as field / series display identity and use it in all field name matchers & field / series name displays (#24024)

* common title handling

* show labels

* update comment

* Update changelog for v7.0.0-beta1 (#24007)

Co-Authored-By: Marcus Efraimsson <marcus.efraimsson@gmail.com>
Co-Authored-By: Andrej Ocenas <mr.ocenas@gmail.com>
Co-Authored-By: Hugo Häggmark <hugo.haggmark@grafana.com>
Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com>

* verify-repo-update: Fix Dockerfile.deb (#24030)

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* CircleCI: Upgrade build pipeline tool (#24021)

* CircleCI: Upgrade build pipeline tool

* Devenv: ignore enterprise (#24037)

* Add header icon to Add data source page (#24033)

* latest.json: Update testing version (#24038)

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix login page redirected from password reset (#24032)

* Storybook: Rewrite stories to CSF (#23989)

* ColorPicker to CSF format

* Convert stories to CSF

* Do not export ClipboardButton

* Update ConfirmButton

* Remove unused imports

* Fix feedback

* changelog enterprise 7.0.0-beta1 (#24039)

* CircleCI: Bump grafana/build-container revision (#24043)

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Changelog: Updates changelog with more feature details (#24040)

* Changelog: Updates changelog with more feature details

* spell fix

* spell fix

* Updates

* Readme update

* Updates

* Select: fixes so component loses focus on selecting value or pressing outside of input. (#24008)

* changed the value container to a class component to get it to work with focus (maybe something with context?).

* added e2e tests to verify that the select focus is working as it should.

* fixed according to feedback.

* updated snapshot.

* Devenv: add remote renderer to grafana (#24050)

* NewPanelEditor: minor UI twekas (#24042)

* Forward ref for tabs, use html props

* Inspect:  add inspect label to drawer title

* Add tooltips to sidebar pane tabs, copy changes

* Remove unused import

* Place tooltips over tabs

* Inspector: dont show transformations select if there is only one data frame

* Review

* Changelog: Add a breaking change (#24051)

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* CircleCI: Unpin grafana/docs-base (#24054)

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Search: close overlay on Esc press (#24003)

* Search: Close on Esc

* Search: Increase bottom padding for the last item in section

* Search: Move closing search to keybindingsSrv

* Search: Fix folder view

* Search: Do not move folders if already in folder

* Docs: Adds deprecation notice to changelog and docs for scripted dashboards (#24060)

* Update CHANGELOG.md (#24047)

Fix typo

Co-authored-by: Daniel Lee <dan.limerick@gmail.com>

* Documentation: Alternative Team Sync Wording (#23960)

* Alternative wording for team sync docs

Signed-off-by: Joe Elliott <number101010@gmail.com>

* Update docs/sources/auth/team-sync.md

Co-Authored-By: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Fix misspell issues (#23905)

* Fix misspell issues

See,
$ golangci-lint run --timeout 10m --disable-all -E misspell ./...

Signed-off-by: Mario Trangoni <mjtrangoni@gmail.com>

* Fix codespell issues

See,
$ codespell -S './.git*' -L 'uint,thru,pres,unknwon,serie,referer,uptodate,durationm'

Signed-off-by: Mario Trangoni <mjtrangoni@gmail.com>

* ci please?

* non-empty commit - ci?

* Trigger build

Co-authored-by: bergquist <carl.bergquist@gmail.com>
Co-authored-by: Kyle Brandt <kyle@grafana.com>

* fix compile error

* better series display

* better display

* now with prometheus and loki

* a few more tests

* Improvements and tests

* thinking

* More advanced and smart default title generation

* Another fix

* Progress but dam this will be hard

* Reverting the time series Value field name change

* revert revert going in circles

* add a field state object

* Use state title when converting back to legacy format

* Improved the join (series to columsn) transformer

* Got tests running again

* Rewrite of seriesToColums that simplifies and fixing tests

* Fixed the tricky problem of multiple time field when not used in join

* Prometheus: Restoring prometheus formatting

* Graphite: Disable Grafana's series naming

* fixed imports

* Fixed tests and made rename transform change title instead

* Fixing more tests

* fix more tests

* fixed import issue

* Fixed more circular dependencies

* Renamed to getFieldTitle

* More rename

* Review feedback

* Fix for showing field title in calculate field transformer

* fieldOverride: Make it clear that state title after applying defaults & overrides

* Fixed ts issue

* Update packages/grafana-ui/src/components/TransformersUI/OrganizeFieldsTransformerEditor.tsx

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
Co-authored-by: Andrej Ocenas <mr.ocenas@gmail.com>
Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com>
Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
Co-authored-by: Leonard Gram <leo@xlson.com>
Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
Co-authored-by: Alexander Zobnin <alexanderzobnin@gmail.com>
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
Co-authored-by: Richard Hartmann <RichiH@users.noreply.github.com>
Co-authored-by: Daniel Lee <dan.limerick@gmail.com>
Co-authored-by: Joe Elliott <joe.elliott@grafana.com>
Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
Co-authored-by: Mario Trangoni <mario@mariotrangoni.de>
Co-authored-by: bergquist <carl.bergquist@gmail.com>
Co-authored-by: Kyle Brandt <kyle@grafana.com>
This commit is contained in:
Ryan McKinley
2020-05-07 01:42:03 -07:00
committed by GitHub
parent 184941eab4
commit 5dca59f720
47 changed files with 912 additions and 368 deletions

View File

@@ -6,6 +6,7 @@ import {
SelectableValue,
toCSV,
transformDataFrame,
getFrameDisplayTitle,
} from '@grafana/data';
import { Button, Field, Icon, Select, Table } from '@grafana/ui';
import { selectors } from '@grafana/e2e-selectors';
@@ -105,7 +106,7 @@ export class InspectDataTab extends PureComponent<Props, State> {
const choices = dataFrames.map((frame, index) => {
return {
value: index,
label: `${frame.name} (${index})`,
label: `${getFrameDisplayTitle(frame)} (${index})`,
};
});

View File

@@ -169,9 +169,9 @@ export function getProcessedDataFrames(results?: DataQueryResponseData[]): DataF
for (const result of results) {
const dataFrame = guessFieldTypes(toDataFrame(result));
// clear out any cached calcs
// clear out the cached info
for (const field of dataFrame.fields) {
field.calcs = null;
field.state = null;
}
dataFrames.push(dataFrame);

View File

@@ -1,7 +1,7 @@
import '../datasource';
import { CloudWatchDatasource } from '../datasource';
import * as redux from 'app/store/store';
import { DataSourceInstanceSettings, dateMath } from '@grafana/data';
import { DataSourceInstanceSettings, dateMath, getFrameDisplayTitle } from '@grafana/data';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { CustomVariable } from 'app/features/templating/all';
import { CloudWatchQuery, CloudWatchMetricsQuery } from '../types';
@@ -233,7 +233,7 @@ describe('CloudWatchDatasource', () => {
it('should return series list', done => {
ctx.ds.query(query).then((result: any) => {
expect(result.data[0].name).toBe(response.results.A.series[0].name);
expect(getFrameDisplayTitle(result.data[0])).toBe(response.results.A.series[0].name);
expect(result.data[0].fields[1].values.buffer[0]).toBe(response.results.A.series[0].points[0][0]);
done();
});
@@ -249,7 +249,7 @@ describe('CloudWatchDatasource', () => {
it('should be built correctly if theres one search expressions returned in meta for a given query row', done => {
response.results['A'].meta.gmdMeta = [{ Expression: `REMOVE_EMPTY(SEARCH('some expression'))`, Period: '300' }];
ctx.ds.query(query).then((result: any) => {
expect(result.data[0].name).toBe(response.results.A.series[0].name);
expect(getFrameDisplayTitle(result.data[0])).toBe(response.results.A.series[0].name);
expect(result.data[0].fields[1].config.links[0].title).toBe('View in CloudWatch console');
expect(decodeURIComponent(result.data[0].fields[1].config.links[0].url)).toContain(
`region=us-east-1#metricsV2:graph={"view":"timeSeries","stacked":false,"title":"A","start":"2016-12-31T15:00:00.000Z","end":"2016-12-31T16:00:00.000Z","region":"us-east-1","metrics":[{"expression":"REMOVE_EMPTY(SEARCH(\'some expression\'))"}]}`
@@ -264,7 +264,7 @@ describe('CloudWatchDatasource', () => {
{ Expression: `REMOVE_EMPTY(SEARCH('second expression'))` },
];
ctx.ds.query(query).then((result: any) => {
expect(result.data[0].name).toBe(response.results.A.series[0].name);
expect(getFrameDisplayTitle(result.data[0])).toBe(response.results.A.series[0].name);
expect(result.data[0].fields[1].config.links[0].title).toBe('View in CloudWatch console');
expect(decodeURIComponent(result.data[0].fields[0].config.links[0].url)).toContain(
`region=us-east-1#metricsV2:graph={"view":"timeSeries","stacked":false,"title":"A","start":"2016-12-31T15:00:00.000Z","end":"2016-12-31T16:00:00.000Z","region":"us-east-1","metrics":[{"expression":"REMOVE_EMPTY(SEARCH(\'first expression\'))"},{"expression":"REMOVE_EMPTY(SEARCH(\'second expression\'))"}]}`
@@ -276,7 +276,7 @@ describe('CloudWatchDatasource', () => {
it('should be built correctly if the query is a metric stat query', done => {
response.results['A'].meta.gmdMeta = [{ Period: '300' }];
ctx.ds.query(query).then((result: any) => {
expect(result.data[0].name).toBe(response.results.A.series[0].name);
expect(getFrameDisplayTitle(result.data[0])).toBe(response.results.A.series[0].name);
expect(result.data[0].fields[1].config.links[0].title).toBe('View in CloudWatch console');
expect(decodeURIComponent(result.data[0].fields[0].config.links[0].url)).toContain(
`region=us-east-1#metricsV2:graph={\"view\":\"timeSeries\",\"stacked\":false,\"title\":\"A\",\"start\":\"2016-12-31T15:00:00.000Z\",\"end\":\"2016-12-31T16:00:00.000Z\",\"region\":\"us-east-1\",\"metrics\":[[\"AWS/EC2\",\"CPUUtilization\",\"InstanceId\",\"i-12345678\",{\"stat\":\"Average\",\"period\":\"300\"}]]}`
@@ -517,7 +517,7 @@ describe('CloudWatchDatasource', () => {
it('should return series list', done => {
ctx.ds.query(query).then((result: any) => {
expect(result.data[0].name).toBe(response.results.A.series[0].name);
expect(getFrameDisplayTitle(result.data[0])).toBe(response.results.A.series[0].name);
expect(result.data[0].fields[1].values.buffer[0]).toBe(response.results.A.series[0].points[0][0]);
done();
});

View File

@@ -929,9 +929,10 @@ describe('ElasticResponse', () => {
const hist: KeyValue<number> = {};
const histogramResults = new MutableDataFrame(result.data[1]);
rows = new DataFrameView(histogramResults);
for (let i = 0; i < rows.length; i++) {
const row = rows.get(i);
hist[row.Time] = row.Count;
hist[row.Time] = row.Value;
}
response.responses[0].aggregations['2'].buckets.forEach((bucket: any) => {

View File

@@ -1,5 +1,5 @@
import Datasource from '../datasource';
import { DataFrame, toUtc } from '@grafana/data';
import { DataFrame, toUtc, getFrameDisplayTitle } from '@grafana/data';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
@@ -175,7 +175,7 @@ describe('AppInsightsDatasource', () => {
return ctx.ds.query(options).then((results: any) => {
expect(results.data.length).toBe(1);
const data = results.data[0] as DataFrame;
expect(data.name).toEqual('PrimaryResult');
expect(getFrameDisplayTitle(data)).toEqual('PrimaryResult');
expect(data.fields[0].values.length).toEqual(1);
expect(data.fields[0].values.get(0)).toEqual(1558278660000);
expect(data.fields[1].values.get(0)).toEqual(2.2075);
@@ -218,7 +218,7 @@ describe('AppInsightsDatasource', () => {
return ctx.ds.query(options).then((results: any) => {
expect(results.data.length).toBe(1);
const data = results.data[0] as DataFrame;
expect(data.name).toEqual('paritionA');
expect(getFrameDisplayTitle(data)).toEqual('paritionA');
expect(data.fields[0].values.length).toEqual(1);
expect(data.fields[0].values.get(0)).toEqual(1558278660000);
expect(data.fields[1].values.get(0)).toEqual(2.2075);
@@ -279,7 +279,7 @@ describe('AppInsightsDatasource', () => {
return ctx.ds.query(options).then((results: any) => {
expect(results.data.length).toBe(1);
const data = results.data[0] as DataFrame;
expect(data.name).toEqual('exceptions/server');
expect(getFrameDisplayTitle(data)).toEqual('exceptions/server');
expect(data.fields[0].values.get(0)).toEqual(1558278660000);
expect(data.fields[1].values.get(0)).toEqual(2.2075);
});
@@ -322,7 +322,7 @@ describe('AppInsightsDatasource', () => {
return ctx.ds.query(options).then((results: any) => {
expect(results.data.length).toBe(1);
const data = results.data[0] as DataFrame;
expect(data.name).toEqual('exceptions/server');
expect(getFrameDisplayTitle(data)).toEqual('exceptions/server');
expect(data.fields[0].values.length).toEqual(2);
expect(data.fields[0].values.get(0)).toEqual(1504108800000);
expect(data.fields[1].values.get(0)).toEqual(3);
@@ -376,14 +376,14 @@ describe('AppInsightsDatasource', () => {
return ctx.ds.query(options).then((results: any) => {
expect(results.data.length).toBe(2);
let data = results.data[0] as DataFrame;
expect(data.name).toEqual('exceptions/server{client/city="Miami"}');
expect(getFrameDisplayTitle(data)).toEqual('exceptions/server{client/city="Miami"}');
expect(data.fields[1].values.length).toEqual(2);
expect(data.fields[0].values.get(0)).toEqual(1504108800000);
expect(data.fields[1].values.get(0)).toEqual(10);
expect(data.fields[0].values.get(1)).toEqual(1504112400000);
expect(data.fields[1].values.get(1)).toEqual(20);
data = results.data[1] as DataFrame;
expect(data.name).toEqual('exceptions/server{client/city="San Antonio"}');
expect(getFrameDisplayTitle(data)).toEqual('exceptions/server{client/city="San Antonio"}');
expect(data.fields[1].values.length).toEqual(2);
expect(data.fields[0].values.get(0)).toEqual(1504108800000);
expect(data.fields[1].values.get(0)).toEqual(1);

View File

@@ -2,7 +2,7 @@ import AzureMonitorDatasource from '../datasource';
import FakeSchemaData from './__mocks__/schema';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { KustoSchema, AzureLogsVariable } from '../types';
import { toUtc } from '@grafana/data';
import { toUtc, getFrameDisplayTitle } from '@grafana/data';
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
jest.mock('@grafana/runtime', () => ({
@@ -183,10 +183,11 @@ describe('AzureLogAnalyticsDatasource', () => {
it('should return a list of datapoints', () => {
return ctx.ds.query(options).then((results: any) => {
expect(results.data.length).toBe(1);
expect(results.data[0].name).toEqual('grafana-vm');
expect(getFrameDisplayTitle(results.data[0])).toEqual('grafana-vm');
expect(results.data[0].fields.length).toBe(2);
expect(results.data[0].name).toBe('grafana-vm');
expect(results.data[0].fields[0].name).toBe('Time');
expect(results.data[0].fields[1].name).toBe('grafana-vm');
expect(results.data[0].fields[1].name).toBe('Value');
expect(results.data[0].fields[0].values.toArray().length).toBe(6);
expect(results.data[0].fields[0].values.get(0)).toEqual(1587633300000);
expect(results.data[0].fields[1].values.get(0)).toEqual(2017.25);

View File

@@ -1,7 +1,7 @@
import AzureMonitorDatasource from '../datasource';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { toUtc, DataFrame } from '@grafana/data';
import { toUtc, DataFrame, getFrameDisplayTitle } from '@grafana/data';
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
jest.mock('@grafana/runtime', () => ({
@@ -137,7 +137,7 @@ describe('AzureMonitorDatasource', () => {
return ctx.ds.query(options).then((results: any) => {
expect(results.data.length).toBe(1);
const data = results.data[0] as DataFrame;
expect(data.name).toEqual('Percentage CPU');
expect(getFrameDisplayTitle(data)).toEqual('Percentage CPU');
expect(data.fields[0].values.get(0)).toEqual(1558278660000);
expect(data.fields[1].values.get(0)).toEqual(2.2075);
expect(data.fields[0].values.get(1)).toEqual(1558278720000);

View File

@@ -123,6 +123,9 @@ export class GraphiteDatasource extends DataSourceApi<GraphiteQuery, GraphiteOpt
for (let i = 0; i < series.length; i++) {
const s = series[i];
// Disables Grafana own series naming
s.title = s.target;
for (let y = 0; y < s.datapoints.length; y++) {
s.datapoints[y][1] *= 1000;
}

View File

@@ -2,7 +2,7 @@ import { GraphiteDatasource } from '../datasource';
import _ from 'lodash';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { dateTime } from '@grafana/data';
import { dateTime, getFrameDisplayTitle } from '@grafana/data';
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
jest.mock('@grafana/runtime', () => ({
@@ -91,8 +91,8 @@ describe('graphiteDatasource', () => {
});
expect(result.data.length).toBe(2);
expect(result.data[0].name).toBe('seriesA');
expect(result.data[1].name).toBe('seriesB');
expect(getFrameDisplayTitle(result.data[0])).toBe('seriesA');
expect(getFrameDisplayTitle(result.data[1])).toBe('seriesB');
expect(result.data[0].length).toBe(2);
expect(result.data[0].meta.notices.length).toBe(1);
expect(result.data[0].meta.notices[0].text).toBe('Data is rolled up, aggregated over 2h using Average function');

View File

@@ -13,6 +13,8 @@ import {
DataSourceInstanceSettings,
dateTime,
LoadingState,
toDataFrame,
getFieldTitle,
} from '@grafana/data';
import { PromOptions, PromQuery } from './types';
import templateSrv from 'app/features/templating/template_srv';
@@ -586,8 +588,9 @@ describe('PrometheusDatasource', () => {
});
it('should return series list', async () => {
const frame = toDataFrame(results.data[0]);
expect(results.data.length).toBe(1);
expect(results.data[0].target).toBe('test{job="testjob"}');
expect(getFieldTitle(frame.fields[1])).toBe('test{job="testjob"}');
});
});
@@ -730,8 +733,10 @@ describe('PrometheusDatasource', () => {
});
it('should return series list', () => {
const frame = toDataFrame(results.data[0]);
expect(results.data.length).toBe(1);
expect(results.data[0].target).toBe('test{job="testjob"}');
expect(frame.name).toBe('test{job="testjob"}');
expect(getFieldTitle(frame.fields[1])).toBe('Value');
});
});
@@ -1634,8 +1639,9 @@ describe('PrometheusDatasource for POST', () => {
});
it('should return series list', () => {
const frame = toDataFrame(results.data[0]);
expect(results.data.length).toBe(1);
expect(results.data[0].target).toBe('test{job="testjob"}');
expect(getFieldTitle(frame.fields[1])).toBe('test{job="testjob"}');
});
});

View File

@@ -162,6 +162,7 @@ describe('Prometheus Result Transformer', () => {
expect(result).toEqual([
{
target: '1',
title: '1',
query: undefined,
datapoints: [
[10, 1445000010000],
@@ -172,6 +173,7 @@ describe('Prometheus Result Transformer', () => {
},
{
target: '2',
title: '2',
query: undefined,
datapoints: [
[10, 1445000010000],
@@ -182,6 +184,7 @@ describe('Prometheus Result Transformer', () => {
},
{
target: '3',
title: '3',
query: undefined,
datapoints: [
[10, 1445000010000],
@@ -285,6 +288,7 @@ describe('Prometheus Result Transformer', () => {
expect(result).toEqual([
{
target: 'test{job="testjob"}',
title: 'test{job="testjob"}',
query: undefined,
datapoints: [
[10, 0],
@@ -324,6 +328,7 @@ describe('Prometheus Result Transformer', () => {
expect(result).toEqual([
{
target: 'test{job="testjob"}',
title: 'test{job="testjob"}',
query: undefined,
datapoints: [
[null, 0],
@@ -335,6 +340,64 @@ describe('Prometheus Result Transformer', () => {
]);
});
it('should use __name__ label as series name', () => {
const response = {
status: 'success',
data: {
resultType: 'matrix',
result: [
{
metric: { __name__: 'test', job: 'testjob' },
values: [
[1, '10'],
[2, '0'],
],
},
],
},
};
const options = {
format: 'timeseries',
step: 1,
start: 0,
end: 2,
};
const result = ctx.resultTransformer.transform({ data: response }, options);
expect(result[0].target).toEqual('test{job="testjob"}');
});
it('should set frame name to undefined if no __name__ label but there are other labels', () => {
const response = {
status: 'success',
data: {
resultType: 'matrix',
result: [
{
metric: { job: 'testjob' },
values: [
[1, '10'],
[2, '0'],
],
},
],
},
};
const options = {
format: 'timeseries',
step: 1,
query: 'Some query',
start: 0,
end: 2,
};
const result = ctx.resultTransformer.transform({ data: response }, options);
expect(result[0].target).toBe('{job="testjob"}');
expect(result[0].tags.job).toEqual('testjob');
});
it('should align null values with step', () => {
const response = {
status: 'success',
@@ -356,13 +419,20 @@ describe('Prometheus Result Transformer', () => {
step: 2,
start: 0,
end: 8,
refId: 'A',
meta: { custom: { hello: '1' } },
};
const result = ctx.resultTransformer.transform({ data: response }, options);
expect(result).toEqual([
{
target: 'test{job="testjob"}',
title: 'test{job="testjob"}',
meta: {
custom: { hello: '1' },
},
query: undefined,
refId: 'A',
datapoints: [
[null, 0],
[null, 2000],

View File

@@ -1,6 +1,6 @@
import _ from 'lodash';
import TableModel from 'app/core/table_model';
import { TimeSeries, FieldType } from '@grafana/data';
import { TimeSeries, FieldType, Labels, formatLabels } from '@grafana/data';
import { TemplateSrv } from 'app/features/templating/template_srv';
export class ResultTransformer {
@@ -42,9 +42,7 @@ export class ResultTransformer {
transformMetricData(metricData: any, options: any, start: number, end: number) {
const dps = [];
let metricLabel = null;
metricLabel = this.createMetricLabel(metricData.metric, options);
const { name, labels, title } = this.createLabelInfo(metricData.metric, options);
const stepMs = parseFloat(options.step) * 1000;
let baseTimestamp = start * 1000;
@@ -76,9 +74,10 @@ export class ResultTransformer {
datapoints: dps,
query: options.query,
refId: options.refId,
target: name,
tags: labels,
title,
meta: options.meta,
target: metricLabel,
tags: metricData.metric,
};
}
@@ -142,23 +141,39 @@ export class ResultTransformer {
transformInstantMetricData(md: any, options: any) {
const dps = [];
let metricLabel = null;
metricLabel = this.createMetricLabel(md.metric, options);
const { name, labels } = this.createLabelInfo(md.metric, options);
dps.push([parseFloat(md.value[1]), md.value[0] * 1000]);
return { target: metricLabel, datapoints: dps, tags: md.metric, refId: options.refId, meta: options.meta };
return { target: name, datapoints: dps, tags: labels, refId: options.refId, meta: options.meta };
}
createMetricLabel(labelData: { [key: string]: string }, options: any) {
let label = '';
if (_.isUndefined(options) || _.isEmpty(options.legendFormat)) {
label = this.getOriginalMetricName(labelData);
} else {
label = this.renderTemplate(this.templateSrv.replace(options.legendFormat), labelData);
createLabelInfo(labels: { [key: string]: string }, options: any): { name?: string; labels: Labels; title?: string } {
if (options?.legendFormat) {
const title = this.renderTemplate(this.templateSrv.replace(options.legendFormat), labels);
return { name: title, title, labels };
}
if (!label || label === '{}') {
label = options.query;
let { __name__, ...labelsWithoutName } = labels;
let title = __name__ || '';
const labelPart = formatLabels(labelsWithoutName);
if (!title && !labelPart) {
title = options.query;
}
return label;
title = `${__name__ ?? ''}${labelPart}`;
return { name: title, title, labels: labelsWithoutName };
}
getOriginalMetricName(labelData: { [key: string]: string }) {
const metricName = labelData.__name__ || '';
delete labelData.__name__;
const labelPart = Object.entries(labelData)
.map(label => `${label[0]}="${label[1]}"`)
.join(',');
return `${metricName}{${labelPart}}`;
}
renderTemplate(aliasPattern: string, aliasData: { [key: string]: string }) {
@@ -171,15 +186,6 @@ export class ResultTransformer {
});
}
getOriginalMetricName(labelData: { [key: string]: string }) {
const metricName = labelData.__name__ || '';
delete labelData.__name__;
const labelPart = _.map(_.toPairs(labelData), label => {
return label[0] + '="' + label[1] + '"';
}).join(',');
return metricName + '{' + labelPart + '}';
}
transformToHistogramOverTime(seriesList: TimeSeries[]) {
/* t1 = timestamp1, t2 = timestamp2 etc.
t1 t2 t3 t1 t2 t3

View File

@@ -8,6 +8,7 @@ import {
DataFrame,
getTimeField,
dateTime,
getFieldTitle,
} from '@grafana/data';
import TimeSeries from 'app/core/time_series2';
import config from 'app/core/config';
@@ -31,27 +32,24 @@ export class DataProcessor {
for (let i = 0; i < dataList.length; i++) {
const series = dataList[i];
const { timeField } = getTimeField(series);
if (!timeField) {
continue;
}
const seriesName = series.name ? series.name : series.refId;
for (let j = 0; j < series.fields.length; j++) {
const field = series.fields[j];
if (field.type !== FieldType.number) {
continue;
}
let name = field.config && field.config.title ? field.config.title : field.name;
if (seriesName && dataList.length > 0 && name !== seriesName) {
name = seriesName + ' ' + name;
}
const name = getFieldTitle(field, series, dataList);
const datapoints = [];
for (let r = 0; r < series.length; r++) {
datapoints.push([field.values.get(r), dateTime(timeField.values.get(r)).valueOf()]);
}
list.push(this.toTimeSeries(field, name, i, j, datapoints, list.length, range));
}
}
@@ -60,9 +58,11 @@ export class DataProcessor {
if (this.panel.xaxis.mode === 'histogram' && !this.panel.stack && list.length > 1) {
const first = list[0];
first.alias = first.aliasEscaped = 'Count';
for (let i = 1; i < list.length; i++) {
first.datapoints = first.datapoints.concat(list[i].datapoints);
}
return [first];
}

View File

@@ -17,6 +17,7 @@ import {
FieldColor,
FieldColorMode,
FieldConfigSource,
getFieldTitle,
} from '@grafana/data';
import { SeriesOptions, GraphOptions, GraphLegendEditorLegendOptions } from './types';
@@ -122,7 +123,7 @@ export const getGraphSeriesModel = (
});
graphs.push({
label: field.name,
label: getFieldTitle(field, series, dataFrames),
data: points,
color: field.config.color?.fixedColor,
info: statsDisplayValues,

View File

@@ -23,6 +23,7 @@ import {
PanelEvents,
formattedValueToString,
locationUtil,
getFieldTitle,
} from '@grafana/data';
import { convertOldAngularValueMapping } from '@grafana/ui';
@@ -156,6 +157,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
onFramesReceived(frames: DataFrame[]) {
const { panel } = this;
this.dataList = frames;
if (frames && frames.length > 1) {
this.data = {
@@ -204,7 +206,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
processField(fieldInfo: FieldInfo) {
const { panel, dashboard } = this;
const name = fieldInfo.field.config.title || fieldInfo.field.name;
const name = getFieldTitle(fieldInfo.field, fieldInfo.frame.frame, this.dataList as DataFrame[]);
let calc = panel.valueName;
let calcField = fieldInfo.field;
let val: any = undefined;

View File

@@ -1,5 +1,5 @@
import { SingleStatCtrl, ShowData } from '../module';
import { dateTime, ReducerID } from '@grafana/data';
import { dateTime, ReducerID, getFieldTitle } from '@grafana/data';
import { LinkSrv } from 'app/features/panel/panellinks/link_srv';
import { LegacyResponseData } from '@grafana/data';
import { DashboardModel } from 'app/features/dashboard/state';
@@ -90,7 +90,8 @@ describe('SingleStatCtrl', () => {
});
it('Should use series avg as default main value', () => {
expect(ctx.data.value).toBe('test.cpu1');
const title = getFieldTitle(ctx.data.field);
expect(title).toBe('test.cpu1');
});
it('should set formatted value', () => {

View File

@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { Table, Select } from '@grafana/ui';
import { FieldMatcherID, PanelProps, DataFrame, SelectableValue } from '@grafana/data';
import { FieldMatcherID, PanelProps, DataFrame, SelectableValue, getFrameDisplayTitle } from '@grafana/data';
import { Options } from './types';
import { css } from 'emotion';
import { config } from 'app/core/config';
@@ -101,7 +101,7 @@ export class TablePanel extends Component<Props> {
const currentIndex = this.getCurrentFrameIndex();
const names = data.series.map((frame, index) => {
return {
label: `${frame.name ?? 'Series'}`,
label: getFrameDisplayTitle(frame),
value: index,
};
});