Field overrides: added matcher to match all fields within frame/query. (#28872)
This commit is contained in:
@@ -23,6 +23,7 @@ export enum FieldMatcherID {
|
|||||||
byNames = 'byNames',
|
byNames = 'byNames',
|
||||||
byRegexp = 'byRegexp',
|
byRegexp = 'byRegexp',
|
||||||
byRegexpOrNames = 'byRegexpOrNames',
|
byRegexpOrNames = 'byRegexpOrNames',
|
||||||
|
byFrameRefID = 'byFrameRefID',
|
||||||
// byIndex = 'byIndex',
|
// byIndex = 'byIndex',
|
||||||
// byLabel = 'byLabel',
|
// byLabel = 'byLabel',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -66,6 +66,28 @@ const regexpFieldNameMatcher: FieldMatcherInfo<string> = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field matcher that will match all fields that exists in a
|
||||||
|
* data frame with configured refId.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
const fieldsInFrameMatcher: FieldMatcherInfo<string> = {
|
||||||
|
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<RegexpOrNamesMatcherOptions> = {
|
const regexpOrMultipleNamesMatcher: FieldMatcherInfo<RegexpOrNamesMatcherOptions> = {
|
||||||
id: FieldMatcherID.byRegexpOrNames,
|
id: FieldMatcherID.byRegexpOrNames,
|
||||||
name: 'Field Name by Regexp or Names',
|
name: 'Field Name by Regexp or Names',
|
||||||
@@ -127,7 +149,13 @@ const frameNameMatcher: FrameMatcherInfo<string> = {
|
|||||||
* Registry Initialization
|
* Registry Initialization
|
||||||
*/
|
*/
|
||||||
export function getFieldNameMatchers(): FieldMatcherInfo[] {
|
export function getFieldNameMatchers(): FieldMatcherInfo[] {
|
||||||
return [fieldNameMatcher, regexpFieldNameMatcher, multipleFieldNamesMatcher, regexpOrMultipleNamesMatcher];
|
return [
|
||||||
|
fieldNameMatcher,
|
||||||
|
regexpFieldNameMatcher,
|
||||||
|
multipleFieldNamesMatcher,
|
||||||
|
regexpOrMultipleNamesMatcher,
|
||||||
|
fieldsInFrameMatcher,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFrameNameMatchers(): FrameMatcherInfo[] {
|
export function getFrameNameMatchers(): FrameMatcherInfo[] {
|
||||||
|
|||||||
@@ -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<MatcherUIProps<string>>(props => {
|
||||||
|
const { data, options, onChange: onChangeFromProps } = props;
|
||||||
|
const referenceIDs = useFrameRefIds(data);
|
||||||
|
const selectOptions = useSelectOptions(referenceIDs);
|
||||||
|
|
||||||
|
const onChange = useCallback(
|
||||||
|
(selection: SelectableValue<string>) => {
|
||||||
|
if (!selection.value || !referenceIDs.has(selection.value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return onChangeFromProps(selection.value);
|
||||||
|
},
|
||||||
|
[referenceIDs, onChangeFromProps]
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedOption = selectOptions.find(v => v.value === options);
|
||||||
|
return <Select value={selectedOption} options={selectOptions} onChange={onChange} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registry item for UI to configure "fields by frame refId"-matcher.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export const fieldsByFrameRefIdItem: FieldMatcherUIRegistryItem<string> = {
|
||||||
|
id: FieldMatcherID.byFrameRefID,
|
||||||
|
component: FieldsByFrameRefIdMatcher,
|
||||||
|
matcher: fieldMatchers.get(FieldMatcherID.byFrameRefID),
|
||||||
|
name: 'Fields returned by query',
|
||||||
|
description: 'Set properties for fields from a specific query',
|
||||||
|
optionsToLabel: options => options,
|
||||||
|
};
|
||||||
|
|
||||||
|
const useFrameRefIds = (data: DataFrame[]): Set<string> => {
|
||||||
|
return useMemo(() => {
|
||||||
|
const refIds: Set<string> = new Set();
|
||||||
|
|
||||||
|
for (const frame of data) {
|
||||||
|
if (frame.refId) {
|
||||||
|
refIds.add(frame.refId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return refIds;
|
||||||
|
}, [data]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useSelectOptions = (displayNames: Set<string>): Array<SelectableValue<string>> => {
|
||||||
|
return useMemo(() => {
|
||||||
|
return Array.from(displayNames).map(n => ({
|
||||||
|
value: n,
|
||||||
|
label: n,
|
||||||
|
}));
|
||||||
|
}, [displayNames]);
|
||||||
|
};
|
||||||
@@ -3,7 +3,8 @@ import { FieldMatcherUIRegistryItem } from './types';
|
|||||||
import { fieldNameMatcherItem } from './FieldNameMatcherEditor';
|
import { fieldNameMatcherItem } from './FieldNameMatcherEditor';
|
||||||
import { fieldNameByRegexMatcherItem } from './FieldNameByRegexMatcherEditor';
|
import { fieldNameByRegexMatcherItem } from './FieldNameByRegexMatcherEditor';
|
||||||
import { fieldTypeMatcherItem } from './FieldTypeMatcherEditor';
|
import { fieldTypeMatcherItem } from './FieldTypeMatcherEditor';
|
||||||
|
import { fieldsByFrameRefIdItem } from './FieldsByFrameRefIdMatcher';
|
||||||
|
|
||||||
export const fieldMatchersUI = new Registry<FieldMatcherUIRegistryItem<any>>(() => {
|
export const fieldMatchersUI = new Registry<FieldMatcherUIRegistryItem<any>>(() => {
|
||||||
return [fieldNameMatcherItem, fieldNameByRegexMatcherItem, fieldTypeMatcherItem];
|
return [fieldNameMatcherItem, fieldNameByRegexMatcherItem, fieldTypeMatcherItem, fieldsByFrameRefIdItem];
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user