Files
Kristina c00caa2fb2 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 783f247c33e854e00a72a42c5d04eee3aa923a5a.

* 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
2025-06-16 14:27:34 -05:00

115 lines
3.2 KiB
TypeScript

import { useMemo } from 'react';
import {
DataFrame,
getFieldDisplayName,
TransformerCategory,
SelectableValue,
getTimeZones,
VariableOrigin,
VariableSuggestion,
} from '@grafana/data';
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)));
if (withBaseFieldNames) {
// only add base names of fields that have same field.name
let baseNameCounts = new Map<string, number>();
frames.forEach((frame) =>
frame.fields.forEach((field) => {
let count = baseNameCounts.get(field.name) ?? 0;
baseNameCounts.set(field.name, count + 1);
})
);
let baseNames: string[] = [];
baseNameCounts.forEach((count, name) => {
if (count > 1) {
baseNames.push(name);
}
});
// prepend base names + uniquify
names = [...new Set(baseNames.concat(names))];
}
return names;
};
export function useAllFieldNamesFromDataFrames(frames: DataFrame[], withBaseFieldNames = false): string[] {
return useMemo(() => getAllFieldNamesFromDataFrames(frames, withBaseFieldNames), [frames, withBaseFieldNames]);
}
export function getDistinctLabels(input: DataFrame[]): Set<string> {
const distinct = new Set<string>();
for (const frame of input) {
for (const field of frame.fields) {
if (field.labels) {
for (const k of Object.keys(field.labels)) {
distinct.add(k);
}
}
}
}
return distinct;
}
export const categoriesLabels: { [K in TransformerCategory]: string } = {
combine: 'Combine',
calculateNewFields: 'Calculate new fields',
createNewVisualization: 'Create new visualization',
filter: 'Filter',
performSpatialOperations: 'Perform spatial operations',
reformat: 'Reformat',
reorderAndRename: 'Reorder and rename',
};
export const numberOrVariableValidator = (value: string | number) => {
if (typeof value === 'number') {
return true;
}
if (!Number.isNaN(Number(value))) {
return true;
}
const variableFound = variableRegex.test(value);
variableRegex.lastIndex = 0;
if (variableFound) {
return true;
}
return false;
};
export function getTimezoneOptions(includeInternal: boolean) {
const timeZoneOptions: Array<SelectableValue<string>> = [];
// There are currently only two internal timezones
// Browser and UTC. We add the manually to avoid
// funky string manipulation.
if (includeInternal) {
timeZoneOptions.push({ label: t('transformers.get-timezone-options.label.browser', 'Browser'), value: 'browser' });
timeZoneOptions.push({ label: t('transformers.get-timezone-options.label.utc', 'UTC'), value: 'utc' });
}
// Add all other timezones
const tzs = getTimeZones();
for (const tz of tzs) {
timeZoneOptions.push({ label: tz, value: tz });
}
return timeZoneOptions;
}
export function getVariableSuggestions(): VariableSuggestion[] {
return getTemplateSrv()
.getVariables()
.map((v) => ({ value: v.name, label: v.label || v.name, origin: VariableOrigin.Template }));
}