123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- import { from, of, OperatorFunction } from 'rxjs';
- import { map, mergeMap } from 'rxjs/operators';
- import { FieldType, getFieldDisplayName, isDataFrame, MetricFindValue, PanelData } from '@grafana/data';
- import { getProcessedDataFrames } from 'app/features/query/state/runRequest';
- import { ThunkDispatch } from '../../../types';
- import { validateVariableSelectionState } from '../state/actions';
- import { toKeyedAction } from '../state/keyedVariablesReducer';
- import { QueryVariableModel } from '../types';
- import { getTemplatedRegex, toKeyedVariableIdentifier, toVariablePayload } from '../utils';
- import { updateVariableOptions } from './reducer';
- export function toMetricFindValues(): OperatorFunction<PanelData, MetricFindValue[]> {
- return (source) =>
- source.pipe(
- map((panelData) => {
- const frames = panelData.series;
- if (!frames || !frames.length) {
- return [];
- }
- if (areMetricFindValues(frames)) {
- return frames;
- }
- const processedDataFrames = getProcessedDataFrames(frames);
- const metrics: MetricFindValue[] = [];
- let valueIndex = -1;
- let textIndex = -1;
- let stringIndex = -1;
- let expandableIndex = -1;
- for (const frame of processedDataFrames) {
- for (let index = 0; index < frame.fields.length; index++) {
- const field = frame.fields[index];
- const fieldName = getFieldDisplayName(field, frame, frames).toLowerCase();
- if (field.type === FieldType.string && stringIndex === -1) {
- stringIndex = index;
- }
- if (fieldName === 'text' && field.type === FieldType.string && textIndex === -1) {
- textIndex = index;
- }
- if (fieldName === 'value' && field.type === FieldType.string && valueIndex === -1) {
- valueIndex = index;
- }
- if (
- fieldName === 'expandable' &&
- (field.type === FieldType.boolean || field.type === FieldType.number) &&
- expandableIndex === -1
- ) {
- expandableIndex = index;
- }
- }
- }
- if (stringIndex === -1) {
- throw new Error("Couldn't find any field of type string in the results.");
- }
- for (const frame of frames) {
- for (let index = 0; index < frame.length; index++) {
- const expandable = expandableIndex !== -1 ? frame.fields[expandableIndex].values.get(index) : undefined;
- const string = frame.fields[stringIndex].values.get(index);
- const text = textIndex !== -1 ? frame.fields[textIndex].values.get(index) : null;
- const value = valueIndex !== -1 ? frame.fields[valueIndex].values.get(index) : null;
- if (valueIndex === -1 && textIndex === -1) {
- metrics.push({ text: string, value: string, expandable });
- continue;
- }
- if (valueIndex === -1 && textIndex !== -1) {
- metrics.push({ text, value: text, expandable });
- continue;
- }
- if (valueIndex !== -1 && textIndex === -1) {
- metrics.push({ text: value, value, expandable });
- continue;
- }
- metrics.push({ text, value, expandable });
- }
- }
- return metrics;
- })
- );
- }
- export function updateOptionsState(args: {
- variable: QueryVariableModel;
- dispatch: ThunkDispatch;
- getTemplatedRegexFunc: typeof getTemplatedRegex;
- }): OperatorFunction<MetricFindValue[], void> {
- return (source) =>
- source.pipe(
- map((results) => {
- const { variable, dispatch, getTemplatedRegexFunc } = args;
- if (!variable.rootStateKey) {
- console.error('updateOptionsState: variable.rootStateKey is not defined');
- return;
- }
- const templatedRegex = getTemplatedRegexFunc(variable);
- const payload = toVariablePayload(variable, { results, templatedRegex });
- dispatch(toKeyedAction(variable.rootStateKey, updateVariableOptions(payload)));
- })
- );
- }
- export function validateVariableSelection(args: {
- variable: QueryVariableModel;
- dispatch: ThunkDispatch;
- searchFilter?: string;
- }): OperatorFunction<void, void> {
- return (source) =>
- source.pipe(
- mergeMap(() => {
- const { dispatch, variable, searchFilter } = args;
- // If we are searching options there is no need to validate selection state
- // This condition was added to as validateVariableSelectionState will update the current value of the variable
- // So after search and selection the current value is already update so no setValue, refresh and URL update is performed
- // The if statement below fixes https://github.com/grafana/grafana/issues/25671
- if (!searchFilter) {
- return from(dispatch(validateVariableSelectionState(toKeyedVariableIdentifier(variable))));
- }
- return of<void>();
- })
- );
- }
- export function areMetricFindValues(data: any[]): data is MetricFindValue[] {
- if (!data) {
- return false;
- }
- if (!data.length) {
- return true;
- }
- const firstValue: any = data[0];
- if (isDataFrame(firstValue)) {
- return false;
- }
- for (const firstValueKey in firstValue) {
- if (!firstValue.hasOwnProperty(firstValueKey)) {
- continue;
- }
- if (
- firstValue[firstValueKey] !== null &&
- typeof firstValue[firstValueKey] !== 'string' &&
- typeof firstValue[firstValueKey] !== 'number'
- ) {
- continue;
- }
- const key = firstValueKey.toLowerCase();
- if (key === 'text' || key === 'value') {
- return true;
- }
- }
- return false;
- }
|