Transformations: Add time filtering to filter by value (#101591)

* WIP - time filtering

* Replace variable test

* Change tests

* Validator is already tested

* Change test to match evaluation

* Add line to docs

* Revert "Add line to docs"

This reverts commit 783f247c33.

* Put transformations docs update in the right place, cannot build without an update, WIP

* Run build

* Use regex test and rewind

* Does this help

* make config optional
pull/100552/merge
Kristina 1 month ago committed by GitHub
parent fc97b0e6b4
commit c00caa2fb2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      docs/sources/panels-visualizations/query-transform-data/transform-data/index.md
  2. 17
      packages/grafana-data/src/transformations/matchers/valueMatchers/rangeMatchers.ts
  3. 2
      public/app/core/config.ts
  4. 2
      public/app/features/expressions/types.ts
  5. 4
      public/app/features/transformers/docs/content.ts
  6. 12
      public/app/features/transformers/utils.test.ts
  7. 6
      public/app/features/transformers/utils.ts

@ -461,13 +461,13 @@ The available conditions for string fields are:
- **Contains substring** - Match if the value contains the specified substring (case insensitive).
- **Does not contain substring** - Match if the value doesn't contain the specified substring (case insensitive).
The available conditions for number fields are:
The available conditions for number and time fields are:
- **Greater** - Match if the value is greater than the specified value.
- **Lower** - Match if the value is lower than the specified value.
- **Greater or equal** - Match if the value is greater or equal.
- **Lower or equal** - Match if the value is lower or equal.
- **Range** - Match a range between a specified minimum and maximum, min and max included.
- **Range** - Match a range between a specified minimum and maximum, min and max included. A time field will pre-populate with variables to filter by selected time.
Consider the following dataset:

@ -14,14 +14,25 @@ const isBetweenValueMatcher: ValueMatcherInfo<RangeValueMatcherOptions> = {
if (isNaN(value)) {
return false;
}
return value > options.from && value < options.to;
// if it is a time, it is interpolated as a string, so convert before comparing
const fromVal = typeof options.from !== 'number' ? parseInt(options.from, 10) : options.from;
const toVal = typeof options.to !== 'number' ? parseInt(options.to, 10) : options.to;
return value > fromVal && value < toVal;
};
},
getOptionsDisplayText: (options) => {
return `Matches all rows where field value is between ${options.from} and ${options.to}.`;
},
isApplicable: (field) => field.type === FieldType.number,
getDefaultOptions: () => ({ from: 0, to: 100 }),
isApplicable: (field) => field.type === FieldType.number || field.type === FieldType.time,
getDefaultOptions: (field) => {
if (field.type === FieldType.time) {
return { from: '$__from', to: '$__to' };
} else {
return { from: 0, to: 100 };
}
},
};
export const getRangeValueMatchers = (): ValueMatcherInfo[] => [isBetweenValueMatcher];

@ -18,4 +18,4 @@ export const updateConfig = (update: Partial<GrafanaBootConfig>) => {
};
// The `enable_alpha` flag is not exposed directly, this is equivalent
export const hasAlphaPanels = Boolean(config.panels?.debug?.state === PluginState.alpha);
export const hasAlphaPanels = Boolean(config?.panels?.debug?.state === PluginState.alpha);

@ -70,7 +70,7 @@ export const expressionTypes: Array<SelectableValue<ExpressionQueryType>> = [
},
].filter((expr) => {
if (expr.value === ExpressionQueryType.sql) {
return config.featureToggles?.sqlExpressions;
return config?.featureToggles?.sqlExpressions;
}
return true;
});

@ -380,13 +380,13 @@ The available conditions for string fields are:
- **Contains substring** - Match if the value contains the specified substring (case insensitive).
- **Does not contain substring** - Match if the value doesn't contain the specified substring (case insensitive).
The available conditions for number fields are:
The available conditions for number and time fields are:
- **Greater** - Match if the value is greater than the specified value.
- **Lower** - Match if the value is lower than the specified value.
- **Greater or equal** - Match if the value is greater or equal.
- **Lower or equal** - Match if the value is lower or equal.
- **Range** - Match a range between a specified minimum and maximum, min and max included.
- **Range** - Match a range between a specified minimum and maximum, min and max included. A time field will pre-populate with variables to filter by selected time.
Consider the following dataset:

@ -27,19 +27,19 @@ describe('validator', () => {
expect(numberOrVariableValidator('1')).toBe(true);
});
it('validats a string that is a negative integer', () => {
it('validates a string that is a negative integer', () => {
expect(numberOrVariableValidator('-1')).toBe(true);
});
it('validats a string that is zero', () => {
it('validates a string that is zero', () => {
expect(numberOrVariableValidator('0')).toBe(true);
});
it('validats a string that is a float', () => {
it('validates a string that is a float', () => {
expect(numberOrVariableValidator('1.2')).toBe(true);
});
it('validats a string that is a negative float', () => {
it('validates a string that is a negative float', () => {
expect(numberOrVariableValidator('-1.2')).toBe(true);
});
@ -51,8 +51,8 @@ describe('validator', () => {
expect(numberOrVariableValidator('$foo')).toBe(true);
});
it('fails a string that has multiple variables', () => {
expect(numberOrVariableValidator('$foo$asd')).toBe(false);
it('validates a string that has multiple variables', () => {
expect(numberOrVariableValidator('$foo$asd')).toBe(true);
});
});

@ -12,6 +12,8 @@ import {
import { t } from '@grafana/i18n';
import { getTemplateSrv } from '@grafana/runtime';
import { variableRegex } from '../variables/utils';
export const getAllFieldNamesFromDataFrames = (frames: DataFrame[], withBaseFieldNames = false) => {
// get full names
let names = frames.flatMap((frame) => frame.fields.map((field) => getFieldDisplayName(field, frame, frames)));
@ -77,7 +79,9 @@ export const numberOrVariableValidator = (value: string | number) => {
if (!Number.isNaN(Number(value))) {
return true;
}
if (/^\$[A-Za-z0-9_]+$/.test(value)) {
const variableFound = variableRegex.test(value);
variableRegex.lastIndex = 0;
if (variableFound) {
return true;
}
return false;

Loading…
Cancel
Save