From cbb2c0a5d8e5172bb8bc0ad2ba6fffa77d990e6d Mon Sep 17 00:00:00 2001 From: Marcus Andersson Date: Tue, 1 Dec 2020 09:38:35 +0100 Subject: [PATCH] Field overrides: added matcher to match all fields within frame/query. (#28872) --- .../src/transformations/matchers/ids.ts | 1 + .../matchers/nameMatcher.test.ts | 28 +++++++++ .../transformations/matchers/nameMatcher.ts | 30 ++++++++- .../MatchersUI/FieldsByFrameRefIdMatcher.tsx | 63 +++++++++++++++++++ .../components/MatchersUI/fieldMatchersUI.ts | 3 +- 5 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.tsx diff --git a/packages/grafana-data/src/transformations/matchers/ids.ts b/packages/grafana-data/src/transformations/matchers/ids.ts index cd3976627a0..cb6f0184a38 100644 --- a/packages/grafana-data/src/transformations/matchers/ids.ts +++ b/packages/grafana-data/src/transformations/matchers/ids.ts @@ -23,6 +23,7 @@ export enum FieldMatcherID { byNames = 'byNames', byRegexp = 'byRegexp', byRegexpOrNames = 'byRegexpOrNames', + byFrameRefID = 'byFrameRefID', // byIndex = 'byIndex', // byLabel = 'byLabel', } diff --git a/packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts b/packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts index fefca6bd406..5459cd5fffc 100644 --- a/packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts +++ b/packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts @@ -306,3 +306,31 @@ describe('Field Regexp or Names Matcher', () => { } }); }); + +describe('Fields returned by query with refId', () => { + it('Match all fields in frame with refId: A', () => { + const data = [ + toDataFrame({ + refId: 'A', + fields: [{ name: 'field_1' }, { name: 'field_2' }], + }), + toDataFrame({ + refId: 'B', + fields: [{ name: 'field_1' }, { name: 'field_2' }], + }), + ]; + + const matcher = getFieldMatcher({ + id: FieldMatcherID.byFrameRefID, + options: 'A', + }); + + const frameA = data[0]; + expect(matcher(frameA.fields[0], frameA, data)).toBe(true); + expect(matcher(frameA.fields[1], frameA, data)).toBe(true); + + const frameB = data[1]; + expect(matcher(frameB.fields[0], frameB, data)).toBe(false); + expect(matcher(frameB.fields[1], frameB, data)).toBe(false); + }); +}); diff --git a/packages/grafana-data/src/transformations/matchers/nameMatcher.ts b/packages/grafana-data/src/transformations/matchers/nameMatcher.ts index 16534ba4638..efaa7d0a4d1 100644 --- a/packages/grafana-data/src/transformations/matchers/nameMatcher.ts +++ b/packages/grafana-data/src/transformations/matchers/nameMatcher.ts @@ -66,6 +66,28 @@ const regexpFieldNameMatcher: FieldMatcherInfo = { }, }; +/** + * Field matcher that will match all fields that exists in a + * data frame with configured refId. + * @public + */ +const fieldsInFrameMatcher: FieldMatcherInfo = { + id: FieldMatcherID.byFrameRefID, + name: 'Fields by frame refId', + description: 'match all fields returned in data frame with refId.', + defaultOptions: '', + + get: (refId: string): FieldMatcher => { + return (field: Field, frame: DataFrame, allFrames: DataFrame[]) => { + return frame.refId === refId; + }; + }, + + getOptionsDisplayText: (refId: string): string => { + return `Math all fields returned by query with reference ID: ${refId}`; + }, +}; + const regexpOrMultipleNamesMatcher: FieldMatcherInfo = { id: FieldMatcherID.byRegexpOrNames, name: 'Field Name by Regexp or Names', @@ -127,7 +149,13 @@ const frameNameMatcher: FrameMatcherInfo = { * Registry Initialization */ export function getFieldNameMatchers(): FieldMatcherInfo[] { - return [fieldNameMatcher, regexpFieldNameMatcher, multipleFieldNamesMatcher, regexpOrMultipleNamesMatcher]; + return [ + fieldNameMatcher, + regexpFieldNameMatcher, + multipleFieldNamesMatcher, + regexpOrMultipleNamesMatcher, + fieldsInFrameMatcher, + ]; } export function getFrameNameMatchers(): FrameMatcherInfo[] { diff --git a/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.tsx b/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.tsx new file mode 100644 index 00000000000..c80c742411c --- /dev/null +++ b/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.tsx @@ -0,0 +1,63 @@ +import React, { memo, useMemo, useCallback } from 'react'; +import { MatcherUIProps, FieldMatcherUIRegistryItem } from './types'; +import { FieldMatcherID, fieldMatchers, SelectableValue, DataFrame } from '@grafana/data'; +import { Select } from '../Select/Select'; + +/** + * UI to configure "fields by frame refId"-matcher. + * @public + */ +export const FieldsByFrameRefIdMatcher = memo>(props => { + const { data, options, onChange: onChangeFromProps } = props; + const referenceIDs = useFrameRefIds(data); + const selectOptions = useSelectOptions(referenceIDs); + + const onChange = useCallback( + (selection: SelectableValue) => { + if (!selection.value || !referenceIDs.has(selection.value)) { + return; + } + return onChangeFromProps(selection.value); + }, + [referenceIDs, onChangeFromProps] + ); + + const selectedOption = selectOptions.find(v => v.value === options); + return