From 66b79fb2211e3ac1c200f7a9c8a5170a64827468 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Fri, 11 Jul 2025 11:13:35 +0100 Subject: [PATCH] Internationalisation: Mark up transformations (#107910) * CalculateFieldTransformerEditor * more CalculateFieldTransformer * ConcatenateTransformerEditor * ConfigFromQueryTransformerEditor * mark up other transformations * few things spotted manually --- .betterer.results | 4 - apps/iam/pkg/apis/iam_manifest.go | 2 - .../transformSceneToSaveModel.test.ts | 4 +- .../TransformationPickerNg.tsx | 49 +-- .../FilterByValueTransformerEditor.tsx | 23 +- .../HeatmapTransformerEditor.tsx | 23 +- .../transformers/calculateHeatmap/heatmap.ts | 14 +- .../ConfigFromQueryTransformerEditor.tsx | 26 +- .../configFromQuery/configFromQuery.ts | 12 +- .../CalculateFieldTransformerEditor.tsx | 77 ++-- .../CalculateFieldTransformerEditor/index.ts | 6 - .../editors/ConcatenateTransformerEditor.tsx | 54 ++- .../ConvertFieldTypeTransformerEditor.tsx | 24 +- .../editors/FilterByNameTransformerEditor.tsx | 22 +- .../FilterByRefIdTransformerEditor.tsx | 15 +- .../editors/FormatStringTransformerEditor.tsx | 22 +- .../editors/FormatTimeTransformerEditor.tsx | 22 +- .../editors/GroupByTransformerEditor.tsx | 27 +- .../GroupToNestedTableTransformerEditor.tsx | 49 ++- .../GroupingToMatrixTransformerEditor.tsx | 22 +- .../editors/HistogramTransformerEditor.tsx | 11 +- .../editors/JoinByFieldTransformerEditor.tsx | 58 +-- .../LabelsToFieldsTransformerEditor.tsx | 28 +- .../editors/LimitTransformerEditor.tsx | 11 +- .../editors/MergeTransformerEditor.tsx | 14 +- .../OrganizeFieldsTransformerEditor.tsx | 23 +- .../editors/ReduceTransformerEditor.tsx | 11 +- .../editors/RenameByRegexTransformer.tsx | 22 +- .../editors/SeriesToRowsTransformerEditor.tsx | 24 +- .../editors/SortByTransformerEditor.tsx | 8 +- .../editors/TransposeTransformerEditor.tsx | 17 +- .../ExtractFieldsTransformerEditor.tsx | 11 +- .../JoinByLabelsTransformerEditor.tsx | 25 +- .../transformers/joinByLabels/joinByLabels.ts | 14 +- .../FieldLookupTransformerEditor.tsx | 14 +- .../lookupGazetteer/fieldLookup.ts | 2 +- .../PartitionByValuesEditor.tsx | 26 +- .../partitionByValues.test.ts | 4 +- .../partitionByValues/partitionByValues.ts | 55 +-- .../PrepareTimeSeriesEditor.tsx | 206 ++++++----- .../prepareTimeSeries.test.ts | 4 +- .../prepareTimeSeries/prepareTimeSeries.ts | 14 +- .../regression/regression.test.ts | 4 +- .../transformers/regression/regression.ts | 13 +- .../regression/regressionEditor.tsx | 21 +- .../RowsToFieldsTransformerEditor.tsx | 23 +- .../transformers/rowsToFields/rowsToFields.ts | 12 +- .../spatial/SpatialTransformerEditor.tsx | 23 +- .../spatial/spatialTransformer.ts | 12 +- .../transformers/standardTransformers.ts | 132 +++---- .../TimeSeriesTableTransformEditor.tsx | 24 +- .../timeSeriesTableTransformer.ts | 18 +- public/app/features/transformers/utils.ts | 24 +- public/locales/en-US/grafana.json | 347 +++++++++++++++++- 54 files changed, 1145 insertions(+), 607 deletions(-) delete mode 100644 public/app/features/transformers/editors/CalculateFieldTransformerEditor/index.ts diff --git a/.betterer.results b/.betterer.results index 8a98e82ff57..db0480152ab 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2785,10 +2785,6 @@ exports[`better eslint`] = { "public/app/features/transformers/editors/CalculateFieldTransformerEditor/WindowOptionsEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], - "public/app/features/transformers/editors/CalculateFieldTransformerEditor/index.ts:5381": [ - [0, 0, 0, "Do not re-export imported variable (\`CalculateFieldTransformerEditor\`)", "0"], - [0, 0, 0, "Do not re-export imported variable (\`calculateFieldTransformRegistryItem\`)", "1"] - ], "public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], diff --git a/apps/iam/pkg/apis/iam_manifest.go b/apps/iam/pkg/apis/iam_manifest.go index 8f144c3cd27..667b7a10354 100644 --- a/apps/iam/pkg/apis/iam_manifest.go +++ b/apps/iam/pkg/apis/iam_manifest.go @@ -14,8 +14,6 @@ import ( v0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" ) -var () - var appManifestData = app.ManifestData{ AppName: "iam", Group: "iam.grafana.app", diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts index 9d4fbea9aa2..b543bdeb10b 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts @@ -19,7 +19,7 @@ import { MultiValueVariable, sceneGraph, SceneGridRow, VizPanel } from '@grafana import { Dashboard, LoadingState, Panel, RowPanel, VariableRefresh } from '@grafana/schema'; import { PanelModel } from 'app/features/dashboard/state/PanelModel'; import { getTimeRange } from 'app/features/dashboard/utils/timeRange'; -import { reduceTransformRegistryItem } from 'app/features/transformers/editors/ReduceTransformerEditor'; +import { getReduceTransformRegistryItem } from 'app/features/transformers/editors/ReduceTransformerEditor'; import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/constants'; import { DashboardDataDTO } from 'app/types/dashboard'; @@ -46,7 +46,7 @@ import { trimDashboardForSnapshot, } from './transformSceneToSaveModel'; -standardTransformersRegistry.setInit(() => [reduceTransformRegistryItem]); +standardTransformersRegistry.setInit(() => [getReduceTransformRegistryItem()]); setPluginImportUtils({ importPanelPlugin: (id: string) => Promise.resolve(getPanelPlugin({})), getPanelPluginFromCache: (id: string) => undefined, diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx index 4dab1da8b45..368cfb23e1c 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx @@ -3,7 +3,6 @@ import { FormEventHandler, KeyboardEventHandler, ReactNode, useCallback } from ' import { DataFrame, - DataTransformerID, TransformerRegistryItem, TransformationApplicabilityLevels, GrafanaTheme2, @@ -15,17 +14,11 @@ import { Trans, t } from '@grafana/i18n'; import { Badge, Card, Drawer, FilterPill, IconButton, Input, Switch, useStyles2 } from '@grafana/ui'; import config from 'app/core/config'; import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo'; -import { categoriesLabels } from 'app/features/transformers/utils'; +import { getCategoriesLabels } from 'app/features/transformers/utils'; import { FilterCategory } from './TransformationsEditor'; -const viewAllLabel = 'View all'; const VIEW_ALL_VALUE = 'viewAll'; -const filterCategoriesLabels: Array<[FilterCategory, string]> = [ - [VIEW_ALL_VALUE, viewAllLabel], - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - ...(Object.entries(categoriesLabels) as Array<[FilterCategory, string]>), -]; interface TransformationPickerNgProps { onTransformationAdd: (selectedItem: SelectableValue) => void; @@ -60,6 +53,12 @@ export function TransformationPickerNg(props: TransformationPickerNgProps) { onSelectedFilterChange, } = props; + const filterCategoriesLabels: Array<[FilterCategory, string]> = [ + [VIEW_ALL_VALUE, t('dashboard.transformation-picker-ng.view-all', 'View all')], + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + ...(Object.entries(getCategoriesLabels()) as Array<[FilterCategory, string]>), + ]; + // Use a callback ref to call "click" on the search input // This will focus it when it's opened const searchInputRef = useCallback((input: HTMLInputElement) => { @@ -218,18 +217,13 @@ function TransformationsGrid({ showIllustrations, transformations, onClick, data {transform.tags && transform.tags.size > 0 && (
{Array.from(transform.tags).map((tag) => ( - + ))}
)} - {getTransformationsRedesignDescriptions(transform.id)} + {standardTransformersRegistry.getIfExists(transform.id)?.description} {showIllustrations && ( {transform.name} @@ -319,28 +313,3 @@ const getImagePath = (id: string, disabled: boolean) => { const folder = config.theme2.isDark ? 'dark' : 'light'; return `public/build/img/transformations/${folder}/${id}.svg`; }; - -const TransformationDescriptionOverrides: { [key: string]: string } = { - [DataTransformerID.concatenate]: 'Combine all fields into a single frame.', - [DataTransformerID.configFromData]: 'Set unit, min, max and more.', - [DataTransformerID.fieldLookup]: 'Use a field value to lookup countries, states, or airports.', - [DataTransformerID.filterFieldsByName]: 'Remove parts of the query results using a regex pattern.', - [DataTransformerID.filterByRefId]: 'Remove rows from the data based on origin query', - [DataTransformerID.filterByValue]: 'Remove rows from the query results using user-defined filters.', - [DataTransformerID.groupBy]: 'Group data by a field value and create aggregate data.', - [DataTransformerID.groupingToMatrix]: 'Summarize and reorganize data based on three fields.', - [DataTransformerID.joinByField]: 'Combine rows from 2+ tables, based on a related field.', - [DataTransformerID.labelsToFields]: 'Group series by time and return labels or tags as fields.', - [DataTransformerID.merge]: 'Merge multiple series. Values will be combined into one row.', - [DataTransformerID.organize]: 'Re-order, hide, or rename fields.', - [DataTransformerID.partitionByValues]: 'Split a one-frame dataset into multiple series.', - [DataTransformerID.prepareTimeSeries]: 'Stretch data frames from the wide format into the long format.', - [DataTransformerID.reduce]: 'Reduce all rows or data points to a single value (ex. max, mean).', - [DataTransformerID.renameByRegex]: - 'Rename parts of the query results using a regular expression and replacement pattern.', - [DataTransformerID.seriesToRows]: 'Merge multiple series. Return time, metric and values as a row.', -}; - -const getTransformationsRedesignDescriptions = (id: string): string => { - return TransformationDescriptionOverrides[id] || standardTransformersRegistry.getIfExists(id)?.description || ''; -}; diff --git a/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.tsx b/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.tsx index 13bc7163c88..fb255cbb530 100644 --- a/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.tsx +++ b/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.tsx @@ -148,16 +148,19 @@ export const FilterByValueTransformerEditor = (props: TransformerUIProps = { - id: DataTransformerID.filterByValue, - editor: FilterByValueTransformerEditor, - transformation: standardTransformers.filterByValueTransformer, - name: standardTransformers.filterByValueTransformer.name, - description: - 'Removes rows of the query results using user-defined filters. This is useful if you can not filter your data in the data source.', - categories: new Set([TransformerCategory.Filter]), - help: getTransformationContent(DataTransformerID.filterByValue).helperDocs, -}; +export const getFilterByValueTransformRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.filterByValue, + editor: FilterByValueTransformerEditor, + transformation: standardTransformers.filterByValueTransformer, + name: t('transformers.filter-by-value-transformer-editor.name.filter-data-by-values', 'Filter data by values'), + description: t( + 'transformers.filter-by-value-transformer-editor.description.remove-rows-query-results-user-defined-filters', + 'Remove rows from the query results using user-defined filters.' + ), + categories: new Set([TransformerCategory.Filter]), + help: getTransformationContent(DataTransformerID.filterByValue).helperDocs, + }); const useFieldsInfo = (data: DataFrame[]): DataFrameFieldsInfo => { return useMemo(() => { diff --git a/public/app/features/transformers/calculateHeatmap/HeatmapTransformerEditor.tsx b/public/app/features/transformers/calculateHeatmap/HeatmapTransformerEditor.tsx index a8810d11807..01d3cdd8064 100644 --- a/public/app/features/transformers/calculateHeatmap/HeatmapTransformerEditor.tsx +++ b/public/app/features/transformers/calculateHeatmap/HeatmapTransformerEditor.tsx @@ -13,7 +13,7 @@ import { getTransformationContent } from '../docs/getTransformationContent'; import { getDefaultOptions, getTransformerOptionPane } from '../spatial/optionsHelper'; import { addHeatmapCalculationOptions } from './editor/helper'; -import { HeatmapTransformerOptions, heatmapTransformer } from './heatmap'; +import { HeatmapTransformerOptions, getHeatmapTransformer } from './heatmap'; // Nothing defined in state const supplier = ( @@ -42,13 +42,16 @@ export const HeatmapTransformerEditor = (props: TransformerUIProps = { - id: heatmapTransformer.id, - editor: HeatmapTransformerEditor, - transformation: heatmapTransformer, - name: heatmapTransformer.name, - description: heatmapTransformer.description, - state: PluginState.alpha, - categories: new Set([TransformerCategory.CreateNewVisualization]), - help: getTransformationContent(heatmapTransformer.id).helperDocs, +export const getHeatmapTransformRegistryItem: () => TransformerRegistryItem = () => { + const heatmapTransformer = getHeatmapTransformer(); + return { + id: heatmapTransformer.id, + editor: HeatmapTransformerEditor, + transformation: heatmapTransformer, + name: heatmapTransformer.name, + description: heatmapTransformer.description, + state: PluginState.alpha, + categories: new Set([TransformerCategory.CreateNewVisualization]), + help: getTransformationContent(heatmapTransformer.id).helperDocs, + }; }; diff --git a/public/app/features/transformers/calculateHeatmap/heatmap.ts b/public/app/features/transformers/calculateHeatmap/heatmap.ts index ed37d76651e..7968444302d 100644 --- a/public/app/features/transformers/calculateHeatmap/heatmap.ts +++ b/public/app/features/transformers/calculateHeatmap/heatmap.ts @@ -16,6 +16,7 @@ import { TimeRange, } from '@grafana/data'; import { isLikelyAscendingVector } from '@grafana/data/internal'; +import { t } from '@grafana/i18n'; import { ScaleDistribution, HeatmapCellLayout, @@ -30,10 +31,13 @@ export interface HeatmapTransformerOptions extends HeatmapCalculationOptions { keepOriginalData?: boolean; } -export const heatmapTransformer: SynchronousDataTransformerInfo = { +export const getHeatmapTransformer: () => SynchronousDataTransformerInfo = () => ({ id: DataTransformerID.heatmap, - name: 'Create heatmap', - description: 'Generate heatmap data from source data.', + name: t('transformers.get-heatmap-transformer.name.create-heatmap', 'Create heatmap'), + description: t( + 'transformers.get-heatmap-transformer.description.generate-heatmap-data-from-source', + 'Generate heatmap data from source data.' + ), defaultOptions: {}, isApplicable: (data) => { const { xField, yField, xs, ys } = findHeatmapFields(data); @@ -51,7 +55,7 @@ export const heatmapTransformer: SynchronousDataTransformerInfo (source) => - source.pipe(map((data) => heatmapTransformer.transformer(options, ctx)(data))), + source.pipe(map((data) => getHeatmapTransformer().transformer(options, ctx)(data))), transformer: (options: HeatmapTransformerOptions) => { return (data: DataFrame[]) => { @@ -62,7 +66,7 @@ export const heatmapTransformer: SynchronousDataTransformerInfo {} @@ -98,16 +98,20 @@ export function ConfigFromQueryTransformerEditor({ input, onChange, options }: P ); } -export const configFromQueryTransformRegistryItem: TransformerRegistryItem = { - id: configFromDataTransformer.id, - editor: ConfigFromQueryTransformerEditor, - transformation: configFromDataTransformer, - name: configFromDataTransformer.name, - description: configFromDataTransformer.description, - state: PluginState.beta, - categories: new Set([TransformerCategory.CalculateNewFields]), - help: getTransformationContent(configFromDataTransformer.id).helperDocs, -}; +export const getConfigFromQueryTransformRegistryItem: () => TransformerRegistryItem = + () => { + const configFromDataTransformer = getConfigFromDataTransformer(); + return { + id: configFromDataTransformer.id, + editor: ConfigFromQueryTransformerEditor, + transformation: configFromDataTransformer, + name: configFromDataTransformer.name, + description: configFromDataTransformer.description, + state: PluginState.beta, + categories: new Set([TransformerCategory.CalculateNewFields]), + help: getTransformationContent(configFromDataTransformer.id).helperDocs, + }; + }; const getStyles = (theme: GrafanaTheme2) => ({ matcherOptions: css({ diff --git a/public/app/features/transformers/configFromQuery/configFromQuery.ts b/public/app/features/transformers/configFromQuery/configFromQuery.ts index 44cd15c2117..4e8ae24b311 100644 --- a/public/app/features/transformers/configFromQuery/configFromQuery.ts +++ b/public/app/features/transformers/configFromQuery/configFromQuery.ts @@ -10,6 +10,7 @@ import { MatcherConfig, reduceField, } from '@grafana/data'; +import { t } from '@grafana/i18n'; import { evaluateFieldMappings, @@ -89,10 +90,13 @@ export function extractConfigFromQuery(options: ConfigFromQueryTransformOptions, return output; } -export const configFromDataTransformer: DataTransformerInfo = { +export const getConfigFromDataTransformer: () => DataTransformerInfo = () => ({ id: DataTransformerID.configFromData, - name: 'Config from query results', - description: 'Set unit, min, max and more from data.', + name: t('transformers.get-config-from-data-transformer.name.config-from-query-results', 'Config from query results'), + description: t( + 'transformers.get-config-from-data-transformer.description.set-unit-min-max-and-more', + 'Set unit, min, max and more.' + ), defaultOptions: { configRefId: 'config', mappings: [], @@ -103,4 +107,4 @@ export const configFromDataTransformer: DataTransformerInfo (source) => source.pipe(map((data) => extractConfigFromQuery(options, data))), -}; +}); diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CalculateFieldTransformerEditor.tsx b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CalculateFieldTransformerEditor.tsx index 55566e530a1..28d020d4e44 100644 --- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CalculateFieldTransformerEditor.tsx +++ b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CalculateFieldTransformerEditor.tsx @@ -42,20 +42,6 @@ interface CalculateFieldTransformerEditorState { selected: string[]; } -const calculationModes = [ - { value: CalculateFieldMode.BinaryOperation, label: 'Binary operation' }, - { value: CalculateFieldMode.UnaryOperation, label: 'Unary operation' }, - { value: CalculateFieldMode.ReduceRow, label: 'Reduce row' }, - { value: CalculateFieldMode.Index, label: 'Row index' }, -]; - -if (cfg.featureToggles.addFieldFromCalculationStatFunctions) { - calculationModes.push( - { value: CalculateFieldMode.CumulativeFunctions, label: 'Cumulative functions' }, - { value: CalculateFieldMode.WindowFunctions, label: 'Window functions' } - ); -} - const okTypes = new Set([FieldType.time, FieldType.number, FieldType.string, FieldType.boolean]); export const CalculateFieldTransformerEditor = (props: CalculateFieldTransformerEditorProps) => { @@ -63,6 +49,44 @@ export const CalculateFieldTransformerEditor = (props: CalculateFieldTransformer const configuredOptions = options?.reduce?.include; const [state, setState] = useState({ names: [], selected: [] }); + const calculationModes = [ + { + value: CalculateFieldMode.BinaryOperation, + label: t( + 'transformers.calculate-field-transformer-editor.calculation-modes.label.binary-operation', + 'Binary operation' + ), + }, + { + value: CalculateFieldMode.UnaryOperation, + label: t( + 'transformers.calculate-field-transformer-editor.calculation-modes.label.unary-operation', + 'Unary operation' + ), + }, + { + value: CalculateFieldMode.ReduceRow, + label: t('transformers.calculate-field-transformer-editor.calculation-modes.label.reduce-row', 'Reduce row'), + }, + { + value: CalculateFieldMode.Index, + label: t('transformers.calculate-field-transformer-editor.calculation-modes.label.row-index', 'Row index'), + }, + ]; + + if (cfg.featureToggles.addFieldFromCalculationStatFunctions) { + calculationModes.push( + { + value: CalculateFieldMode.CumulativeFunctions, + label: t('transformers.calculate-field-transformer-editor.label.cumulative-functions', 'Cumulative functions'), + }, + { + value: CalculateFieldMode.WindowFunctions, + label: t('transformers.calculate-field-transformer-editor.label.window-functions', 'Window functions'), + } + ); + } + useEffect(() => { const ctx = { interpolate: (v: string) => v }; const subscription = of(input) @@ -240,12 +264,19 @@ export const CalculateFieldTransformerEditor = (props: CalculateFieldTransformer ); }; -export const calculateFieldTransformRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.calculateField, - editor: CalculateFieldTransformerEditor, - transformation: standardTransformers.calculateFieldTransformer, - name: standardTransformers.calculateFieldTransformer.name, - description: 'Use the row values to calculate a new field.', - categories: new Set([TransformerCategory.CalculateNewFields]), - help: getTransformationContent(DataTransformerID.calculateField).helperDocs, -}; +export const getCalculateFieldTransformRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.calculateField, + editor: CalculateFieldTransformerEditor, + transformation: standardTransformers.calculateFieldTransformer, + name: t( + 'transformers.get-calculate-field-transform-registry-item.name.add-field-from-calculation', + 'Add field from calculation' + ), + description: t( + 'transformers.get-calculate-field-transform-registry-item.description.values-calculate-field', + 'Use the row values to calculate a new field.' + ), + categories: new Set([TransformerCategory.CalculateNewFields]), + help: getTransformationContent(DataTransformerID.calculateField).helperDocs, + }); diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/index.ts b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/index.ts deleted file mode 100644 index 0772bb9cd00..00000000000 --- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - CalculateFieldTransformerEditor, - calculateFieldTransformRegistryItem, -} from './CalculateFieldTransformerEditor'; - -export { CalculateFieldTransformerEditor, calculateFieldTransformRegistryItem }; diff --git a/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx b/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx index d106bbfadeb..1318cf4de8c 100644 --- a/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx +++ b/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx @@ -16,12 +16,6 @@ import { getTransformationContent } from '../docs/getTransformationContent'; interface ConcatenateTransformerEditorProps extends TransformerUIProps {} -const nameModes: Array> = [ - { value: ConcatenateFrameNameMode.FieldName, label: 'Copy frame name to field name' }, - { value: ConcatenateFrameNameMode.Label, label: 'Add a label with the frame name' }, - { value: ConcatenateFrameNameMode.Drop, label: 'Ignore the frame name' }, -]; - export class ConcatenateTransformerEditor extends PureComponent { constructor(props: ConcatenateTransformerEditorProps) { super(props); @@ -50,6 +44,29 @@ export class ConcatenateTransformerEditor extends PureComponent> = [ + { + value: ConcatenateFrameNameMode.FieldName, + label: t( + 'transformers.concatenate-transformer-editor.name-modes.label.copy-frame-name-to-field', + 'Copy frame name to field name' + ), + }, + { + value: ConcatenateFrameNameMode.Label, + label: t( + 'transformers.concatenate-transformer-editor.name-modes.label.label-frame', + 'Add a label with the frame name' + ), + }, + { + value: ConcatenateFrameNameMode.Drop, + label: t( + 'transformers.concatenate-transformer-editor.name-modes.label.ignore-the-frame-name', + 'Ignore the frame name' + ), + }, + ]; const frameNameMode = options.frameNameMode ?? ConcatenateFrameNameMode.FieldName; @@ -82,14 +99,17 @@ export class ConcatenateTransformerEditor extends PureComponent = { - id: DataTransformerID.concatenate, - editor: ConcatenateTransformerEditor, - transformation: standardTransformers.concatenateTransformer, - name: standardTransformers.concatenateTransformer.name, - description: - 'Combine all fields into a single frame. Values will be appended with undefined values if not the same length.', - categories: new Set([TransformerCategory.Combine]), - help: getTransformationContent(DataTransformerID.concatenate).helperDocs, - tags: new Set(['Combine']), -}; +export const getConcatenateTransformRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.concatenate, + editor: ConcatenateTransformerEditor, + transformation: standardTransformers.concatenateTransformer, + name: t('transformers.editors.concatenate-transformer-editor.name.concatenate-fields', 'Concatenate fields'), + description: t( + 'transformers.editors.concatenate-transformer-editor.description.combine-all-fields', + 'Combine all fields into a single frame.' + ), + categories: new Set([TransformerCategory.Combine]), + help: getTransformationContent(DataTransformerID.concatenate).helperDocs, + tags: new Set([t('transformers.editors.concatenate-transformer-editor.tags.combine', 'Combine')]), + }); diff --git a/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx b/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx index 14fddeba815..0a1542f033a 100644 --- a/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx +++ b/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx @@ -267,13 +267,17 @@ export const ConvertFieldTypeTransformerEditor = ({ ); }; -export const convertFieldTypeTransformRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.convertFieldType, - editor: ConvertFieldTypeTransformerEditor, - transformation: standardTransformers.convertFieldTypeTransformer, - name: standardTransformers.convertFieldTypeTransformer.name, - description: standardTransformers.convertFieldTypeTransformer.description, - categories: new Set([TransformerCategory.Reformat]), - help: getTransformationContent(DataTransformerID.convertFieldType).helperDocs, - tags: new Set(['Format field']), -}; +export const getConvertFieldTypeTransformRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.convertFieldType, + editor: ConvertFieldTypeTransformerEditor, + transformation: standardTransformers.convertFieldTypeTransformer, + name: t('transformers.convert-field-type-transformer-editor.name.convert-field-type', 'Convert field type'), + description: t( + 'transformers.convert-field-type-transformer-editor.description.convert-to-specified-field-type', + 'Convert a field to a specified field type.' + ), + categories: new Set([TransformerCategory.Reformat]), + help: getTransformationContent(DataTransformerID.convertFieldType).helperDocs, + tags: new Set([t('transformers.convert-field-type-transformer-editor.tags.format-field', 'Format field')]), + }); diff --git a/public/app/features/transformers/editors/FilterByNameTransformerEditor.tsx b/public/app/features/transformers/editors/FilterByNameTransformerEditor.tsx index c68ac0dbe41..9f7f37f2e59 100644 --- a/public/app/features/transformers/editors/FilterByNameTransformerEditor.tsx +++ b/public/app/features/transformers/editors/FilterByNameTransformerEditor.tsx @@ -253,12 +253,16 @@ export class FilterByNameTransformerEditor extends React.PureComponent< } } -export const filterFieldsByNameTransformRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.filterFieldsByName, - editor: FilterByNameTransformerEditor, - transformation: standardTransformers.filterFieldsByNameTransformer, - name: standardTransformers.filterFieldsByNameTransformer.name, - description: 'Removes part of the query results using a regex pattern. The pattern can be inclusive or exclusive.', - categories: new Set([TransformerCategory.Filter]), - help: getTransformationContent(DataTransformerID.filterFieldsByName).helperDocs, -}; +export const getFilterFieldsByNameTransformRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.filterFieldsByName, + editor: FilterByNameTransformerEditor, + transformation: standardTransformers.filterFieldsByNameTransformer, + name: t('transformers.filter-by-name-transformer-editor.name.filter-fields-by-name', 'Filter fields by name'), + description: t( + 'transformers.filter-by-name-transformer-editor.description.remove-part-query-results-regex-pattern', + 'Remove parts of the query results using a regex pattern.' + ), + categories: new Set([TransformerCategory.Filter]), + help: getTransformationContent(DataTransformerID.filterFieldsByName).helperDocs, + }); diff --git a/public/app/features/transformers/editors/FilterByRefIdTransformerEditor.tsx b/public/app/features/transformers/editors/FilterByRefIdTransformerEditor.tsx index 05b9e196b83..ad679578389 100644 --- a/public/app/features/transformers/editors/FilterByRefIdTransformerEditor.tsx +++ b/public/app/features/transformers/editors/FilterByRefIdTransformerEditor.tsx @@ -7,6 +7,7 @@ import { FrameMatcherID, } from '@grafana/data'; import { FilterFramesByRefIdTransformerOptions } from '@grafana/data/internal'; +import { t } from '@grafana/i18n'; import { FrameMultiSelectionEditor } from 'app/plugins/panel/geomap/editor/FrameSelectionEditor'; import { getTransformationContent } from '../docs/getTransformationContent'; @@ -29,14 +30,16 @@ export const FilterByRefIdTransformerEditor = (props: TransformerUIProps = - { +export const getFilterFramesByRefIdTransformRegistryItem: () => TransformerRegistryItem = + () => ({ id: DataTransformerID.filterByRefId, editor: FilterByRefIdTransformerEditor, transformation: standardTransformers.filterFramesByRefIdTransformer, - name: standardTransformers.filterFramesByRefIdTransformer.name, - description: - 'Filter data by query. This is useful if you are sharing the results from a different panel that has many queries and you want to only visualize a subset of that in this panel.', + name: t('transformers.filter-by-ref-id-transformer-editor.name.filter-data-by-query', 'Filter data by query'), + description: t( + 'transformers.filter-by-ref-id-transformer-editor.description.filter-data-by-query-useful-sharing-results', + 'Remove rows from the data based on origin query' + ), categories: new Set([TransformerCategory.Filter]), help: getTransformationContent(DataTransformerID.filterByRefId).helperDocs, - }; + }); diff --git a/public/app/features/transformers/editors/FormatStringTransformerEditor.tsx b/public/app/features/transformers/editors/FormatStringTransformerEditor.tsx index 4e23322f9ed..e29cc29833e 100644 --- a/public/app/features/transformers/editors/FormatStringTransformerEditor.tsx +++ b/public/app/features/transformers/editors/FormatStringTransformerEditor.tsx @@ -119,12 +119,16 @@ function FormatStringTransfomerEditor({ ); } -export const formatStringTransformerRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.formatString, - editor: FormatStringTransfomerEditor, - transformation: standardTransformers.formatStringTransformer, - name: standardTransformers.formatStringTransformer.name, - state: PluginState.beta, - description: standardTransformers.formatStringTransformer.description, - categories: new Set([TransformerCategory.Reformat]), -}; +export const getFormatStringTransformerRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.formatString, + editor: FormatStringTransfomerEditor, + transformation: standardTransformers.formatStringTransformer, + name: t('transformers.format-string-transformer-editor.name.format-string', 'Format string'), + state: PluginState.beta, + description: t( + 'transformers.format-string-transformer-editor.description.manipulate-string-fields-formatting', + 'Manipulate string fields formatting.' + ), + categories: new Set([TransformerCategory.Reformat]), + }); diff --git a/public/app/features/transformers/editors/FormatTimeTransformerEditor.tsx b/public/app/features/transformers/editors/FormatTimeTransformerEditor.tsx index 82304ce8870..ca749cfa5c0 100644 --- a/public/app/features/transformers/editors/FormatTimeTransformerEditor.tsx +++ b/public/app/features/transformers/editors/FormatTimeTransformerEditor.tsx @@ -117,12 +117,16 @@ export function FormatTimeTransfomerEditor({ ); } -export const formatTimeTransformerRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.formatTime, - editor: FormatTimeTransfomerEditor, - transformation: standardTransformers.formatTimeTransformer, - name: standardTransformers.formatTimeTransformer.name, - state: PluginState.alpha, - description: standardTransformers.formatTimeTransformer.description, - help: getTransformationContent(DataTransformerID.formatTime).helperDocs, -}; +export const getFormatTimeTransformerRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.formatTime, + editor: FormatTimeTransfomerEditor, + transformation: standardTransformers.formatTimeTransformer, + name: t('transformers.format-time-transformer-editor.name.format-time', 'Format time'), + state: PluginState.alpha, + description: t( + 'transformers.format-time-transformer-editor.description.set-based-on-time', + 'Set the output format of a time field' + ), + help: getTransformationContent(DataTransformerID.formatTime).helperDocs, + }); diff --git a/public/app/features/transformers/editors/GroupByTransformerEditor.tsx b/public/app/features/transformers/editors/GroupByTransformerEditor.tsx index 91c01232de2..fcde5f473de 100644 --- a/public/app/features/transformers/editors/GroupByTransformerEditor.tsx +++ b/public/app/features/transformers/editors/GroupByTransformerEditor.tsx @@ -86,11 +86,6 @@ export const GroupByTransformerEditor = ({ ); }; -const options = [ - { label: 'Group by', value: GroupByOperationID.groupBy }, - { label: 'Calculate', value: GroupByOperationID.aggregate }, -]; - export const GroupByFieldConfiguration = ({ fieldName, config, onConfigChange }: FieldProps) => { const theme = useTheme2(); @@ -106,6 +101,17 @@ export const GroupByFieldConfiguration = ({ fieldName, config, onConfigChange }: [config, onConfigChange] ); + const options = [ + { + label: t('transformers.group-by-field-configuration.options.label.group-by', 'Group by'), + value: GroupByOperationID.groupBy, + }, + { + label: t('transformers.group-by-field-configuration.options.label.calculate', 'Calculate'), + value: GroupByOperationID.aggregate, + }, + ]; + return ( @@ -153,16 +159,19 @@ const getStyles = (theme: GrafanaTheme2) => { }; }; -export const groupByTransformRegistryItem: TransformerRegistryItem = { +export const getGroupByTransformRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.groupBy, editor: GroupByTransformerEditor, transformation: standardTransformers.groupByTransformer, - name: standardTransformers.groupByTransformer.name, - description: standardTransformers.groupByTransformer.description, + name: t('transformers.group-by-transformer-editor.name.group-by', 'Group by'), + description: t( + 'transformers.group-by-transformer-editor.description.group-series-by-field-calculate-stats', + 'Group data by a field value and create aggregate data.' + ), categories: new Set([ TransformerCategory.Combine, TransformerCategory.CalculateNewFields, TransformerCategory.Reformat, ]), help: getTransformationContent(DataTransformerID.groupBy).helperDocs, -}; +}); diff --git a/public/app/features/transformers/editors/GroupToNestedTableTransformerEditor.tsx b/public/app/features/transformers/editors/GroupToNestedTableTransformerEditor.tsx index f0c0b01a007..288fd8441e9 100644 --- a/public/app/features/transformers/editors/GroupToNestedTableTransformerEditor.tsx +++ b/public/app/features/transformers/editors/GroupToNestedTableTransformerEditor.tsx @@ -123,11 +123,6 @@ export const GroupToNestedTableTransformerEditor = ({ ); }; -const options = [ - { label: 'Group by', value: GroupByOperationID.groupBy }, - { label: 'Calculate', value: GroupByOperationID.aggregate }, -]; - export const GroupByFieldConfiguration = ({ fieldName, config, onConfigChange }: FieldProps) => { const theme = useTheme2(); const styles = getStyles(theme); @@ -141,6 +136,17 @@ export const GroupByFieldConfiguration = ({ fieldName, config, onConfigChange }: [config, onConfigChange] ); + const options = [ + { + label: t('transformers.group-by-field-configuration.options.label.group-by', 'Group by'), + value: GroupByOperationID.groupBy, + }, + { + label: t('transformers.group-by-field-configuration.options.label.calculate', 'Calculate'), + value: GroupByOperationID.aggregate, + }, + ]; + return ( @@ -187,16 +193,23 @@ const getStyles = (theme: GrafanaTheme2) => { }; }; -export const groupToNestedTableTransformRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.groupToNestedTable, - editor: GroupToNestedTableTransformerEditor, - transformation: standardTransformers.groupToNestedTable, - name: standardTransformers.groupToNestedTable.name, - description: standardTransformers.groupToNestedTable.description, - categories: new Set([ - TransformerCategory.Combine, - TransformerCategory.CalculateNewFields, - TransformerCategory.Reformat, - ]), - state: PluginState.beta, -}; +export const getGroupToNestedTableTransformRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.groupToNestedTable, + editor: GroupToNestedTableTransformerEditor, + transformation: standardTransformers.groupToNestedTable, + name: t( + 'transformers.group-to-nested-table-transformer-editor.name.group-to-nested-tables', + 'Group to nested tables' + ), + description: t( + 'transformers.group-to-nested-table-transformer-editor.description.group-by-field-value', + 'Group data by a field value and create nested tables with the grouped data.' + ), + categories: new Set([ + TransformerCategory.Combine, + TransformerCategory.CalculateNewFields, + TransformerCategory.Reformat, + ]), + state: PluginState.beta, + }); diff --git a/public/app/features/transformers/editors/GroupingToMatrixTransformerEditor.tsx b/public/app/features/transformers/editors/GroupingToMatrixTransformerEditor.tsx index 60cae734a2a..9ab69c466b2 100644 --- a/public/app/features/transformers/editors/GroupingToMatrixTransformerEditor.tsx +++ b/public/app/features/transformers/editors/GroupingToMatrixTransformerEditor.tsx @@ -148,12 +148,16 @@ export const GroupingToMatrixTransformerEditor = ({ ); }; -export const groupingToMatrixTransformRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.groupingToMatrix, - editor: GroupingToMatrixTransformerEditor, - transformation: standardTransformers.groupingToMatrixTransformer, - name: standardTransformers.groupingToMatrixTransformer.name, - description: 'Takes a three fields combination and produces a Matrix.', - categories: new Set([TransformerCategory.Combine, TransformerCategory.Reformat]), - help: getTransformationContent(DataTransformerID.groupingToMatrix).helperDocs, -}; +export const getGroupingToMatrixTransformRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.groupingToMatrix, + editor: GroupingToMatrixTransformerEditor, + transformation: standardTransformers.groupingToMatrixTransformer, + name: t('transformers.grouping-to-matrix-transformer-editor.name.grouping-to-matrix', 'Grouping to matrix'), + description: t( + 'transformers.grouping-to-matrix-transformer-editor.description.summarize-and-reorganize-data', + 'Summarize and reorganize data based on three fields.' + ), + categories: new Set([TransformerCategory.Combine, TransformerCategory.Reformat]), + help: getTransformationContent(DataTransformerID.groupingToMatrix).helperDocs, + }); diff --git a/public/app/features/transformers/editors/HistogramTransformerEditor.tsx b/public/app/features/transformers/editors/HistogramTransformerEditor.tsx index c70c8e9244c..02e79b66e8a 100644 --- a/public/app/features/transformers/editors/HistogramTransformerEditor.tsx +++ b/public/app/features/transformers/editors/HistogramTransformerEditor.tsx @@ -136,12 +136,15 @@ export const HistogramTransformerEditor = ({ ); }; -export const histogramTransformRegistryItem: TransformerRegistryItem = { +export const getHistogramTransformRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.histogram, editor: HistogramTransformerEditor, transformation: standardTransformers.histogramTransformer, - name: standardTransformers.histogramTransformer.name, - description: standardTransformers.histogramTransformer.description, + name: t('transformers.histogram-transformer-editor.name.histogram', 'Histogram'), + description: t( + 'transformers.histogram-transformer-editor.description.calculate-histogram-from-input-data', + 'Calculate a histogram from input data.' + ), categories: new Set([TransformerCategory.CreateNewVisualization]), help: getTransformationContent(DataTransformerID.histogram).helperDocs, -}; +}); diff --git a/public/app/features/transformers/editors/JoinByFieldTransformerEditor.tsx b/public/app/features/transformers/editors/JoinByFieldTransformerEditor.tsx index 244cea37072..8e491297739 100644 --- a/public/app/features/transformers/editors/JoinByFieldTransformerEditor.tsx +++ b/public/app/features/transformers/editors/JoinByFieldTransformerEditor.tsx @@ -16,30 +16,37 @@ import { useFieldDisplayNames, useSelectOptions } from '@grafana/ui/internal'; import { getTransformationContent } from '../docs/getTransformationContent'; -const modes = [ - { - value: JoinMode.outer, - label: 'OUTER (TIME SERIES)', - description: - 'Keep all rows from any table with a value. Join on distinct field values. Performant and best used for time series.', - }, - { - value: JoinMode.outerTabular, - label: 'OUTER (TABULAR)', - description: - 'Join on a field value with duplicated values. Non performant outer join best used for tabular(SQL like) data.', - }, - { - value: JoinMode.inner, - label: 'INNER', - description: 'Combine data from two tables whenever there are matching values in a fields common to both tables.', - }, -]; - export function SeriesToFieldsTransformerEditor({ input, options, onChange }: TransformerUIProps) { const names = useFieldDisplayNames(input); const fieldNames = useSelectOptions(names); + const modes = [ + { + value: JoinMode.outer, + label: t('transformers.series-to-fields-transformer-editor.modes.label.outer-time-series', 'Outer (time series)'), + description: t( + 'transformers.series-to-fields-transformer-editor.modes.description.keep-all-rows', + 'Keep all rows from any table with a value. Join on distinct field values. Performant and best used for time series.' + ), + }, + { + value: JoinMode.outerTabular, + label: t('transformers.series-to-fields-transformer-editor.modes.label.outer-tabular', 'Outer (tabular)'), + description: t( + 'transformers.series-to-fields-transformer-editor.modes.description.join-on-a-field', + 'Join on a field value with duplicated values. Non performant outer join best used for tabular(SQL like) data.' + ), + }, + { + value: JoinMode.inner, + label: t('transformers.series-to-fields-transformer-editor.modes.label.inner', 'Inner'), + description: t( + 'transformers.series-to-fields-transformer-editor.modes.description.combine-data-from-two-tables', + 'Combine data from two tables whenever there are matching values in a fields common to both tables.' + ), + }, + ]; + const variables = getTemplateSrv() .getVariables() .map((v) => { @@ -98,13 +105,16 @@ export function SeriesToFieldsTransformerEditor({ input, options, onChange }: Tr ); } -export const joinByFieldTransformerRegistryItem: TransformerRegistryItem = { +export const getJoinByFieldTransformerRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.joinByField, aliasIds: [DataTransformerID.seriesToColumns], editor: SeriesToFieldsTransformerEditor, transformation: standardTransformers.joinByFieldTransformer, - name: standardTransformers.joinByFieldTransformer.name, - description: standardTransformers.joinByFieldTransformer.description, + name: t('transformers.join-by-field-transformer-editor.name.join-by-field', 'Join by field'), + description: t( + 'transformers.join-by-field-transformer-editor.description.combine-rows-from-2-tables', + 'Combine rows from 2+ tables, based on a related field.' + ), categories: new Set([TransformerCategory.Combine]), help: getTransformationContent(DataTransformerID.joinByField).helperDocs, -}; +}); diff --git a/public/app/features/transformers/editors/LabelsToFieldsTransformerEditor.tsx b/public/app/features/transformers/editors/LabelsToFieldsTransformerEditor.tsx index bf1eb69bf72..939dacd5763 100644 --- a/public/app/features/transformers/editors/LabelsToFieldsTransformerEditor.tsx +++ b/public/app/features/transformers/editors/LabelsToFieldsTransformerEditor.tsx @@ -14,11 +14,6 @@ import { InlineField, InlineFieldRow, RadioButtonGroup, Select, FilterPill, Stac import { getTransformationContent } from '../docs/getTransformationContent'; -const modes: Array> = [ - { value: LabelsToFieldsMode.Columns, label: 'Columns' }, - { value: LabelsToFieldsMode.Rows, label: 'Rows' }, -]; - export const LabelsAsFieldsTransformerEditor = ({ input, options, @@ -26,6 +21,17 @@ export const LabelsAsFieldsTransformerEditor = ({ }: TransformerUIProps) => { const labelWidth = 20; + const modes: Array> = [ + { + value: LabelsToFieldsMode.Columns, + label: t('transformers.labels-as-fields-transformer-editor.modes.label.columns', 'Columns'), + }, + { + value: LabelsToFieldsMode.Rows, + label: t('transformers.labels-as-fields-transformer-editor.modes.label.rows', 'Rows'), + }, + ]; + const { labelNames, selected } = useMemo(() => { let labelNames: Array> = []; let uniqueLabels: Record = {}; @@ -133,13 +139,15 @@ export const LabelsAsFieldsTransformerEditor = ({ ); }; -export const labelsToFieldsTransformerRegistryItem: TransformerRegistryItem = { +export const getLabelsToFieldsTransformerRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.labelsToFields, editor: LabelsAsFieldsTransformerEditor, transformation: standardTransformers.labelsToFieldsTransformer, - name: standardTransformers.labelsToFieldsTransformer.name, - description: `Groups series by time and return labels or tags as fields. - Useful for showing time series with labels in a table where each label key becomes a separate column.`, + name: t('transformers.labels-to-fields-transformer-editor.name.labels-to-fields', 'Labels to fields'), + description: t( + 'transformers.labels-to-fields-transformer-editor.description.groups-series-time-return-labels-tags-fields', + 'Group series by time and return labels or tags as fields.' + ), categories: new Set([TransformerCategory.Reformat]), help: getTransformationContent(DataTransformerID.labelsToFields).helperDocs, -}; +}); diff --git a/public/app/features/transformers/editors/LimitTransformerEditor.tsx b/public/app/features/transformers/editors/LimitTransformerEditor.tsx index 65313152a49..326f02f3c82 100644 --- a/public/app/features/transformers/editors/LimitTransformerEditor.tsx +++ b/public/app/features/transformers/editors/LimitTransformerEditor.tsx @@ -45,12 +45,15 @@ export const LimitTransformerEditor = ({ options, onChange }: TransformerUIProps ); }; -export const limitTransformRegistryItem: TransformerRegistryItem = { +export const getLimitTransformRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.limit, editor: LimitTransformerEditor, transformation: standardTransformers.limitTransformer, - name: standardTransformers.limitTransformer.name, - description: `Limit the number of items displayed.`, + name: t('transformers.limit-transformer-editor.name.limit', 'Limit'), + description: t( + 'transformers.limit-transformer-editor.description.limit-number-items-displayed', + 'Limit the number of items displayed.' + ), categories: new Set([TransformerCategory.Filter]), help: getTransformationContent(DataTransformerID.limit).helperDocs, -}; +}); diff --git a/public/app/features/transformers/editors/MergeTransformerEditor.tsx b/public/app/features/transformers/editors/MergeTransformerEditor.tsx index 99666ad801e..25ba613307a 100644 --- a/public/app/features/transformers/editors/MergeTransformerEditor.tsx +++ b/public/app/features/transformers/editors/MergeTransformerEditor.tsx @@ -6,7 +6,7 @@ import { TransformerCategory, } from '@grafana/data'; import { MergeTransformerOptions } from '@grafana/data/internal'; -import { Trans } from '@grafana/i18n'; +import { Trans, t } from '@grafana/i18n'; import { FieldValidationMessage } from '@grafana/ui'; import { getTransformationContent } from '../docs/getTransformationContent'; @@ -25,13 +25,15 @@ export const MergeTransformerEditor = ({ input, options, onChange }: Transformer return null; }; -export const mergeTransformerRegistryItem: TransformerRegistryItem = { +export const getMergeTransformerRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.merge, editor: MergeTransformerEditor, transformation: standardTransformers.mergeTransformer, - name: standardTransformers.mergeTransformer.name, - description: `Merge many series/tables and return a single table where mergeable values will be combined into the same row. - Useful for showing multiple series, tables or a combination of both visualized in a table.`, + name: t('transformers.merge-transformer-editor.name.merge', 'Merge series/tables'), + description: t( + 'transformers.merge-transformer-editor.description.merge-multiple-series', + 'Merge multiple series. Values will be combined into one row.' + ), categories: new Set([TransformerCategory.Combine]), help: getTransformationContent(DataTransformerID.merge).helperDocs, -}; +}); diff --git a/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx b/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx index 48c18bdc493..7eec24ee6c6 100644 --- a/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx +++ b/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx @@ -495,13 +495,16 @@ const orderFieldNamesByIndex = (fieldNames: string[], indexByName: Record = { - id: DataTransformerID.organize, - editor: OrganizeFieldsTransformerEditor, - transformation: standardTransformers.organizeFieldsTransformer, - name: standardTransformers.organizeFieldsTransformer.name, - description: - "Allows the user to re-order, hide, or rename fields / columns. Useful when data source doesn't allow overrides for visualizing data.", - categories: new Set([TransformerCategory.ReorderAndRename]), - help: getTransformationContent(DataTransformerID.organize).helperDocs, -}; +export const getOrganizeFieldsTransformRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.organize, + editor: OrganizeFieldsTransformerEditor, + transformation: standardTransformers.organizeFieldsTransformer, + name: t('transformers.organize-fields-transformer-editor.name.organize-fields', 'Organize fields by name'), + description: t( + 'transformers.organize-fields-transformer-editor.description.reorder-hide-or-rename-fields', + 'Re-order, hide, or rename fields.' + ), + categories: new Set([TransformerCategory.ReorderAndRename]), + help: getTransformationContent(DataTransformerID.organize).helperDocs, + }); diff --git a/public/app/features/transformers/editors/ReduceTransformerEditor.tsx b/public/app/features/transformers/editors/ReduceTransformerEditor.tsx index fe69d0a474d..3df242e370c 100644 --- a/public/app/features/transformers/editors/ReduceTransformerEditor.tsx +++ b/public/app/features/transformers/editors/ReduceTransformerEditor.tsx @@ -117,12 +117,15 @@ export const ReduceTransformerEditor = ({ options, onChange }: TransformerUIProp ); }; -export const reduceTransformRegistryItem: TransformerRegistryItem = { +export const getReduceTransformRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.reduce, editor: ReduceTransformerEditor, transformation: standardTransformers.reduceTransformer, - name: standardTransformers.reduceTransformer.name, - description: standardTransformers.reduceTransformer.description, + name: t('transformers.reduce-transformer-editor.name.reduce', 'Reduce'), + description: t( + 'transformers.reduce-transformer-editor.description.reduce-to-single-value', + 'Reduce all rows or data points to a single value (ex. max, mean).' + ), categories: new Set([TransformerCategory.CalculateNewFields]), help: getTransformationContent(DataTransformerID.reduce).helperDocs, -}; +}); diff --git a/public/app/features/transformers/editors/RenameByRegexTransformer.tsx b/public/app/features/transformers/editors/RenameByRegexTransformer.tsx index c68bdf998f9..554557e9804 100644 --- a/public/app/features/transformers/editors/RenameByRegexTransformer.tsx +++ b/public/app/features/transformers/editors/RenameByRegexTransformer.tsx @@ -120,12 +120,16 @@ export class RenameByRegexTransformerEditor extends React.PureComponent< } } -export const renameByRegexTransformRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.renameByRegex, - editor: RenameByRegexTransformerEditor, - transformation: standardTransformers.renameByRegexTransformer, - name: standardTransformers.renameByRegexTransformer.name, - description: 'Renames part of the query result by using regular expression with placeholders.', - categories: new Set([TransformerCategory.ReorderAndRename]), - help: getTransformationContent(DataTransformerID.renameByRegex).helperDocs, -}; +export const getRenameByRegexTransformRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.renameByRegex, + editor: RenameByRegexTransformerEditor, + transformation: standardTransformers.renameByRegexTransformer, + name: t('transformers.rename-by-regex-transformer.name.rename-fields-by-regex', 'Rename fields by regex'), + description: t( + 'transformers.rename-by-regex-transformer.description.rename-parts-using-regex', + 'Rename parts of the query results using a regular expression and replacement pattern.' + ), + categories: new Set([TransformerCategory.ReorderAndRename]), + help: getTransformationContent(DataTransformerID.renameByRegex).helperDocs, + }); diff --git a/public/app/features/transformers/editors/SeriesToRowsTransformerEditor.tsx b/public/app/features/transformers/editors/SeriesToRowsTransformerEditor.tsx index 8b3b66e64ed..15ead54a4a3 100644 --- a/public/app/features/transformers/editors/SeriesToRowsTransformerEditor.tsx +++ b/public/app/features/transformers/editors/SeriesToRowsTransformerEditor.tsx @@ -6,6 +6,7 @@ import { TransformerCategory, } from '@grafana/data'; import { SeriesToRowsTransformerOptions } from '@grafana/data/internal'; +import { t } from '@grafana/i18n'; import { getTransformationContent } from '../docs/getTransformationContent'; @@ -17,13 +18,16 @@ export const SeriesToRowsTransformerEditor = ({ return null; }; -export const seriesToRowsTransformerRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.seriesToRows, - editor: SeriesToRowsTransformerEditor, - transformation: standardTransformers.seriesToRowsTransformer, - name: standardTransformers.seriesToRowsTransformer.name, - description: `Merge many series and return a single series with time, metric and value as columns. - Useful for showing multiple time series visualized in a table.`, - categories: new Set([TransformerCategory.Combine, TransformerCategory.Reformat]), - help: getTransformationContent(DataTransformerID.seriesToRows).helperDocs, -}; +export const getSeriesToRowsTransformerRegistryItem: () => TransformerRegistryItem = + () => ({ + id: DataTransformerID.seriesToRows, + editor: SeriesToRowsTransformerEditor, + transformation: standardTransformers.seriesToRowsTransformer, + name: t('transformers.series-to-rows-transformer-editor.name.series-to-rows', 'Series to rows'), + description: t( + 'transformers.series-to-rows-transformer-editor.description.merge-multiple-series', + 'Merge multiple series. Return time, metric and values as a row.' + ), + categories: new Set([TransformerCategory.Combine, TransformerCategory.Reformat]), + help: getTransformationContent(DataTransformerID.seriesToRows).helperDocs, + }); diff --git a/public/app/features/transformers/editors/SortByTransformerEditor.tsx b/public/app/features/transformers/editors/SortByTransformerEditor.tsx index b3cd482e83d..3f76977c92f 100644 --- a/public/app/features/transformers/editors/SortByTransformerEditor.tsx +++ b/public/app/features/transformers/editors/SortByTransformerEditor.tsx @@ -64,12 +64,12 @@ export const SortByTransformerEditor = ({ input, options, onChange }: Transforme ); }; -export const sortByTransformRegistryItem: TransformerRegistryItem = { +export const getSortByTransformRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.sortBy, editor: SortByTransformerEditor, transformation: standardTransformers.sortByTransformer, - name: standardTransformers.sortByTransformer.name, - description: standardTransformers.sortByTransformer.description, + name: t('transformers.sort-by-transformer-editor.name.sort-by', 'Sort by'), + description: t('transformers.sort-by-transformer-editor.description.sort-fields', 'Sort fields in a frame.'), categories: new Set([TransformerCategory.ReorderAndRename]), help: getTransformationContent(DataTransformerID.sortBy).helperDocs, -}; +}); diff --git a/public/app/features/transformers/editors/TransposeTransformerEditor.tsx b/public/app/features/transformers/editors/TransposeTransformerEditor.tsx index fd9b5c332c5..d8902f20beb 100644 --- a/public/app/features/transformers/editors/TransposeTransformerEditor.tsx +++ b/public/app/features/transformers/editors/TransposeTransformerEditor.tsx @@ -43,12 +43,19 @@ export const TransposeTransformerEditor = ({ options, onChange }: TransformerUIP ); }; -export const transposeTransformerRegistryItem: TransformerRegistryItem = { +export const getTransposeTransformerRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.transpose, editor: TransposeTransformerEditor, transformation: standardTransformers.transposeTransformer, - name: standardTransformers.transposeTransformer.name, - description: standardTransformers.transposeTransformer.description, + name: t('transformers.transpose-transformer-editor.name.transpose', 'Transpose'), + description: t( + 'transformers.transpose-transformer-editor.description.transpose-data-frame', + 'Transpose the data frame.' + ), categories: new Set([TransformerCategory.Reformat]), - tags: new Set(['Pivot', 'Translate', 'Transform']), -}; + tags: new Set([ + t('transformers.transpose-transformer-editor.tags.pivot', 'Pivot'), + t('transformers.transpose-transformer-editor.tags.translate', 'Translate'), + t('transformers.transpose-transformer-editor.tags.transform', 'Transform'), + ]), +}); diff --git a/public/app/features/transformers/extractFields/ExtractFieldsTransformerEditor.tsx b/public/app/features/transformers/extractFields/ExtractFieldsTransformerEditor.tsx index e03cfb22c7b..a8b85f39c5c 100644 --- a/public/app/features/transformers/extractFields/ExtractFieldsTransformerEditor.tsx +++ b/public/app/features/transformers/extractFields/ExtractFieldsTransformerEditor.tsx @@ -180,12 +180,15 @@ export const extractFieldsTransformerEditor = ({ ); }; -export const extractFieldsTransformRegistryItem: TransformerRegistryItem = { +export const getExtractFieldsTransformRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.extractFields, editor: extractFieldsTransformerEditor, transformation: extractFieldsTransformer, - name: extractFieldsTransformer.name, - description: `Parse fields from content (JSON, labels, etc).`, + name: t('transformers.extract-fields-transformer-editor.name.extract-fields', 'Extract fields'), + description: t( + 'transformers.extract-fields-transformer-editor.description.parse-fields-from-content', + 'Parse fields from content (JSON, labels, etc).' + ), categories: new Set([TransformerCategory.Reformat]), help: getTransformationContent(DataTransformerID.extractFields).helperDocs, -}; +}); diff --git a/public/app/features/transformers/joinByLabels/JoinByLabelsTransformerEditor.tsx b/public/app/features/transformers/joinByLabels/JoinByLabelsTransformerEditor.tsx index 144f09552fb..a32f09bf478 100644 --- a/public/app/features/transformers/joinByLabels/JoinByLabelsTransformerEditor.tsx +++ b/public/app/features/transformers/joinByLabels/JoinByLabelsTransformerEditor.tsx @@ -14,7 +14,7 @@ import { Alert, HorizontalGroup, InlineField, InlineFieldRow, Select, ValuePicke import { getTransformationContent } from '../docs/getTransformationContent'; import { getDistinctLabels } from '../utils'; -import { joinByLabelsTransformer, JoinByLabelsTransformOptions } from './joinByLabels'; +import { getJoinByLabelsTransformer, JoinByLabelsTransformOptions } from './joinByLabels'; export interface Props extends TransformerUIProps {} @@ -108,7 +108,7 @@ export function JoinByLabelsTransformerEditor({ input, options, onChange }: Prop = { - id: joinByLabelsTransformer.id, - editor: JoinByLabelsTransformerEditor, - transformation: joinByLabelsTransformer, - name: joinByLabelsTransformer.name, - description: joinByLabelsTransformer.description, - state: PluginState.beta, - categories: new Set([TransformerCategory.Combine]), - help: getTransformationContent(joinByLabelsTransformer.id).helperDocs, +export const getJoinByLabelsTransformRegistryItem: () => TransformerRegistryItem = () => { + const joinByLabelsTransformer = getJoinByLabelsTransformer(); + return { + id: joinByLabelsTransformer.id, + editor: JoinByLabelsTransformerEditor, + transformation: joinByLabelsTransformer, + name: joinByLabelsTransformer.name, + description: joinByLabelsTransformer.description, + state: PluginState.beta, + categories: new Set([TransformerCategory.Combine]), + help: getTransformationContent(joinByLabelsTransformer.id).helperDocs, + }; }; diff --git a/public/app/features/transformers/joinByLabels/joinByLabels.ts b/public/app/features/transformers/joinByLabels/joinByLabels.ts index 4133dae20a6..9d6d8c99772 100644 --- a/public/app/features/transformers/joinByLabels/joinByLabels.ts +++ b/public/app/features/transformers/joinByLabels/joinByLabels.ts @@ -1,6 +1,7 @@ import { map } from 'rxjs/operators'; import { DataFrame, DataTransformerID, Field, FieldType, SynchronousDataTransformerInfo } from '@grafana/data'; +import { t } from '@grafana/i18n'; import { getDistinctLabels } from '../utils'; @@ -9,14 +10,17 @@ export interface JoinByLabelsTransformOptions { join?: string[]; } -export const joinByLabelsTransformer: SynchronousDataTransformerInfo = { +export const getJoinByLabelsTransformer: () => SynchronousDataTransformerInfo = () => ({ id: DataTransformerID.joinByLabels, - name: 'Join by labels', - description: 'Flatten labeled results into a table joined by labels.', + name: t('transformers.get-join-by-labels-transformer.name.join-by-labels', 'Join by labels'), + description: t( + 'transformers.get-join-by-labels-transformer.description.flatten-labeled-results-table-joined-labels', + 'Flatten labeled results into a table joined by labels.' + ), defaultOptions: {}, operator: (options, ctx) => (source) => - source.pipe(map((data) => joinByLabelsTransformer.transformer(options, ctx)(data))), + source.pipe(map((data) => getJoinByLabelsTransformer().transformer(options, ctx)(data))), transformer: (options: JoinByLabelsTransformOptions) => { return (data: DataFrame[]) => { @@ -26,7 +30,7 @@ export const joinByLabelsTransformer: SynchronousDataTransformerInfo = { +export const getFieldLookupTransformRegistryItem: () => TransformerRegistryItem = () => ({ id: DataTransformerID.fieldLookup, editor: FieldLookupTransformerEditor, transformation: fieldLookupTransformer, - name: fieldLookupTransformer.name, - description: `Use a field value to lookup additional fields from an external source. This currently supports spatial data, but will eventually support more formats.`, + name: t( + 'transformers.field-lookup-transformer-editor.name.lookup-fields-from-resource', + 'Lookup fields from resource' + ), + description: t( + 'transformers.field-lookup-transformer-editor.description.lookup-additional-fields-external-source', + 'Use a field value to lookup countries, states, or airports.' + ), state: PluginState.alpha, categories: new Set([TransformerCategory.PerformSpatialOperations]), help: getTransformationContent(DataTransformerID.fieldLookup).helperDocs, -}; +}); diff --git a/public/app/features/transformers/lookupGazetteer/fieldLookup.ts b/public/app/features/transformers/lookupGazetteer/fieldLookup.ts index 871d06edf05..33aae7ca869 100644 --- a/public/app/features/transformers/lookupGazetteer/fieldLookup.ts +++ b/public/app/features/transformers/lookupGazetteer/fieldLookup.ts @@ -19,7 +19,7 @@ export interface FieldLookupOptions { export const fieldLookupTransformer: DataTransformerInfo = { id: DataTransformerID.fieldLookup, name: 'Lookup fields from resource', - description: 'Retrieve matching data based on specified field', + description: 'Use a field value to lookup countries, states, or airports.', defaultOptions: {}, operator: (options) => (source) => source.pipe(mergeMap((data) => from(doGazetteerXform(data, options)))), diff --git a/public/app/features/transformers/partitionByValues/PartitionByValuesEditor.tsx b/public/app/features/transformers/partitionByValues/PartitionByValuesEditor.tsx index 8c552199900..b974a7d4025 100644 --- a/public/app/features/transformers/partitionByValues/PartitionByValuesEditor.tsx +++ b/public/app/features/transformers/partitionByValues/PartitionByValuesEditor.tsx @@ -22,7 +22,7 @@ import { useFieldDisplayNames, useSelectOptions } from '@grafana/ui/internal'; import { getTransformationContent } from '../docs/getTransformationContent'; -import { partitionByValuesTransformer, PartitionByValuesTransformerOptions } from './partitionByValues'; +import { getPartitionByValuesTransformer, PartitionByValuesTransformerOptions } from './partitionByValues'; export function PartitionByValuesEditor({ input, @@ -178,13 +178,17 @@ export function PartitionByValuesEditor({ ); } -export const partitionByValuesTransformRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.partitionByValues, - editor: PartitionByValuesEditor, - transformation: partitionByValuesTransformer, - name: partitionByValuesTransformer.name, - description: partitionByValuesTransformer.description, - state: PluginState.alpha, - categories: new Set([TransformerCategory.Reformat]), - help: getTransformationContent(DataTransformerID.partitionByValues).helperDocs, -}; +export const getPartitionByValuesTransformRegistryItem: () => TransformerRegistryItem = + () => { + const partitionByValuesTransformer = getPartitionByValuesTransformer(); + return { + id: DataTransformerID.partitionByValues, + editor: PartitionByValuesEditor, + transformation: partitionByValuesTransformer, + name: partitionByValuesTransformer.name, + description: partitionByValuesTransformer.description, + state: PluginState.alpha, + categories: new Set([TransformerCategory.Reformat]), + help: getTransformationContent(DataTransformerID.partitionByValues).helperDocs, + }; + }; diff --git a/public/app/features/transformers/partitionByValues/partitionByValues.test.ts b/public/app/features/transformers/partitionByValues/partitionByValues.test.ts index 3741ff8ea94..337efd10215 100644 --- a/public/app/features/transformers/partitionByValues/partitionByValues.test.ts +++ b/public/app/features/transformers/partitionByValues/partitionByValues.test.ts @@ -1,12 +1,14 @@ import { toDataFrame, FieldType } from '@grafana/data'; -import { partitionByValuesTransformer, PartitionByValuesTransformerOptions } from './partitionByValues'; +import { getPartitionByValuesTransformer, PartitionByValuesTransformerOptions } from './partitionByValues'; const ctx = { interpolate: (v: string) => v, }; describe('Partition by values transformer', () => { + const partitionByValuesTransformer = getPartitionByValuesTransformer(); + it('should partition by one field', () => { const source = [ toDataFrame({ diff --git a/public/app/features/transformers/partitionByValues/partitionByValues.ts b/public/app/features/transformers/partitionByValues/partitionByValues.ts index 4ab8d360cbe..e0da0630cc0 100644 --- a/public/app/features/transformers/partitionByValues/partitionByValues.ts +++ b/public/app/features/transformers/partitionByValues/partitionByValues.ts @@ -9,6 +9,7 @@ import { FieldMatcher, } from '@grafana/data'; import { getMatcherConfig, noopTransformer } from '@grafana/data/internal'; +import { t } from '@grafana/i18n'; import { partition } from './partition'; @@ -62,35 +63,39 @@ function buildFieldLabels(names: string[], values: unknown[]) { return labels; } -export const partitionByValuesTransformer: SynchronousDataTransformerInfo = { - id: DataTransformerID.partitionByValues, - name: 'Partition by values', - description: `Splits a one-frame dataset into multiple series discriminated by unique/enum values in one or more fields.`, - defaultOptions: { - keepFields: false, - }, +export const getPartitionByValuesTransformer: () => SynchronousDataTransformerInfo = + () => ({ + id: DataTransformerID.partitionByValues, + name: t('transformers.get-partition-by-values-transformer.name.partition-by-values', 'Partition by values'), + description: t( + 'transformers.get-partition-by-values-transformer.description.split-oneframe-dataset-multiple-series', + 'Split a one-frame dataset into multiple series.' + ), + defaultOptions: { + keepFields: false, + }, - operator: (options, ctx) => (source) => - source.pipe(map((data) => partitionByValuesTransformer.transformer(options, ctx)(data))), + operator: (options, ctx) => (source) => + source.pipe(map((data) => getPartitionByValuesTransformer().transformer(options, ctx)(data))), - transformer: (options: PartitionByValuesTransformerOptions, ctx: DataTransformContext) => { - const matcherConfig = getMatcherConfig({ names: options.fields }); + transformer: (options: PartitionByValuesTransformerOptions, ctx: DataTransformContext) => { + const matcherConfig = getMatcherConfig({ names: options.fields }); - if (!matcherConfig) { - return noopTransformer.transformer({}, ctx); - } - - const matcher = getFieldMatcher(matcherConfig); - - return (data: DataFrame[]) => { - if (!data.length) { - return data; + if (!matcherConfig) { + return noopTransformer.transformer({}, ctx); } - // error if > 1 frame? - return partitionByValues(data[0], matcher, options); - }; - }, -}; + + const matcher = getFieldMatcher(matcherConfig); + + return (data: DataFrame[]) => { + if (!data.length) { + return data; + } + // error if > 1 frame? + return partitionByValues(data[0], matcher, options); + }; + }, + }); // Split a single frame dataset into multiple frames based on values in a set of fields export function partitionByValues( diff --git a/public/app/features/transformers/prepareTimeSeries/PrepareTimeSeriesEditor.tsx b/public/app/features/transformers/prepareTimeSeries/PrepareTimeSeriesEditor.tsx index 19399e3e595..d720744a070 100644 --- a/public/app/features/transformers/prepareTimeSeries/PrepareTimeSeriesEditor.tsx +++ b/public/app/features/transformers/prepareTimeSeries/PrepareTimeSeriesEditor.tsx @@ -14,96 +14,110 @@ import { InlineField, InlineFieldRow, Select, useStyles2 } from '@grafana/ui'; import { getTransformationContent } from '../docs/getTransformationContent'; -import { prepareTimeSeriesTransformer, PrepareTimeSeriesOptions, timeSeriesFormat } from './prepareTimeSeries'; - -const wideInfo = { - label: 'Wide time series', - value: timeSeriesFormat.TimeSeriesWide, - description: 'Creates a single frame joined by time', - info: ( -
    -
  • - Single frame -
  • -
  • - 1st field is shared time field -
  • -
  • - Time in ascending order -
  • -
  • - - Multiple value fields of any type - -
  • -
- ), -}; - -const multiInfo = { - label: 'Multi-frame time series', - value: timeSeriesFormat.TimeSeriesMulti, - description: 'Creates a new frame for each time/number pair', - info: ( -
    -
  • - Multiple frames -
  • -
  • - - Each frame has two fields: {'{{field1}}'}, {'{{field2}}'} - -
  • -
  • - Time in ascending order -
  • -
  • - - String values are represented as labels - -
  • -
  • - All values are numeric -
  • -
- ), -}; - -const longInfo = { - label: 'Long time series', - value: timeSeriesFormat.TimeSeriesLong, - description: 'Convert each frame to long format', - info: ( -
    -
  • - Single frame -
  • -
  • - 1st field is time field -
  • -
  • - - Time in ascending order, but may have duplicates - -
  • -
  • - - String values are represented as separate fields rather than as labels - -
  • -
  • - Multiple value fields may exist -
  • -
- ), -}; - -const formats: Array> = [wideInfo, multiInfo, longInfo]; +import { PrepareTimeSeriesOptions, timeSeriesFormat, getPrepareTimeSeriesTransformer } from './prepareTimeSeries'; export function PrepareTimeSeriesEditor(props: TransformerUIProps): React.ReactElement { const { options, onChange } = props; const styles = useStyles2(getStyles); + const wideInfo = { + label: t('transformers.prepare-time-series-editor.wide-info.label.wide-time-series', 'Wide time series'), + value: timeSeriesFormat.TimeSeriesWide, + description: t( + 'transformers.prepare-time-series-editor.wide-info.description.creates-single-frame-joined', + 'Creates a single frame joined by time' + ), + info: ( +
    +
  • + Single frame +
  • +
  • + 1st field is shared time field +
  • +
  • + Time in ascending order +
  • +
  • + + Multiple value fields of any type + +
  • +
+ ), + }; + + const multiInfo = { + label: t( + 'transformers.prepare-time-series-editor.multi-info.label.multiframe-time-series', + 'Multi-frame time series' + ), + value: timeSeriesFormat.TimeSeriesMulti, + description: t( + 'transformers.prepare-time-series-editor.multi-info.description.creates-frame-timenumber', + 'Creates a new frame for each time/number pair' + ), + info: ( +
    +
  • + Multiple frames +
  • +
  • + + Each frame has two fields: {'{{field1}}'}, {'{{field2}}'} + +
  • +
  • + Time in ascending order +
  • +
  • + + String values are represented as labels + +
  • +
  • + All values are numeric +
  • +
+ ), + }; + + const longInfo = { + label: t('transformers.prepare-time-series-editor.long-info.label.long-time-series', 'Long time series'), + value: timeSeriesFormat.TimeSeriesLong, + description: t( + 'transformers.prepare-time-series-editor.long-info.description.convert-each-frame-to-long-format', + 'Convert each frame to long format' + ), + info: ( +
    +
  • + Single frame +
  • +
  • + 1st field is time field +
  • +
  • + + Time in ascending order, but may have duplicates + +
  • +
  • + + String values are represented as separate fields rather than as labels + +
  • +
  • + + Multiple value fields may exist + +
  • +
+ ), + }; + + const formats: Array> = [wideInfo, multiInfo, longInfo]; + const onSelectFormat = useCallback( (value: SelectableValue) => { onChange({ @@ -154,12 +168,16 @@ const getStyles = (theme: GrafanaTheme2) => ({ }), }); -export const prepareTimeseriesTransformerRegistryItem: TransformerRegistryItem = { - id: prepareTimeSeriesTransformer.id, - editor: PrepareTimeSeriesEditor, - transformation: prepareTimeSeriesTransformer, - name: prepareTimeSeriesTransformer.name, - description: prepareTimeSeriesTransformer.description, - categories: new Set([TransformerCategory.Reformat]), - help: getTransformationContent(prepareTimeSeriesTransformer.id).helperDocs, -}; +export const getPrepareTimeseriesTransformerRegistryItem: () => TransformerRegistryItem = + () => { + const prepareTimeSeriesTransformer = getPrepareTimeSeriesTransformer(); + return { + id: prepareTimeSeriesTransformer.id, + editor: PrepareTimeSeriesEditor, + transformation: prepareTimeSeriesTransformer, + name: prepareTimeSeriesTransformer.name, + description: prepareTimeSeriesTransformer.description, + categories: new Set([TransformerCategory.Reformat]), + help: getTransformationContent(prepareTimeSeriesTransformer.id).helperDocs, + }; + }; diff --git a/public/app/features/transformers/prepareTimeSeries/prepareTimeSeries.test.ts b/public/app/features/transformers/prepareTimeSeries/prepareTimeSeries.test.ts index 7184e16ff91..f96dc4946a4 100644 --- a/public/app/features/transformers/prepareTimeSeries/prepareTimeSeries.test.ts +++ b/public/app/features/transformers/prepareTimeSeries/prepareTimeSeries.test.ts @@ -8,13 +8,15 @@ import { getFrameDisplayName, } from '@grafana/data'; -import { prepareTimeSeriesTransformer, PrepareTimeSeriesOptions, timeSeriesFormat } from './prepareTimeSeries'; +import { getPrepareTimeSeriesTransformer, PrepareTimeSeriesOptions, timeSeriesFormat } from './prepareTimeSeries'; const ctx = { interpolate: (v: string) => v, }; describe('Prepare time series transformer', () => { + const prepareTimeSeriesTransformer = getPrepareTimeSeriesTransformer(); + it('should transform wide to multi', () => { const source = [ toDataFrame({ diff --git a/public/app/features/transformers/prepareTimeSeries/prepareTimeSeries.ts b/public/app/features/transformers/prepareTimeSeries/prepareTimeSeries.ts index fc94e308ec7..a5924958bbc 100644 --- a/public/app/features/transformers/prepareTimeSeries/prepareTimeSeries.ts +++ b/public/app/features/transformers/prepareTimeSeries/prepareTimeSeries.ts @@ -12,6 +12,7 @@ import { Field, MutableDataFrame, } from '@grafana/data'; +import { t } from '@grafana/i18n'; import { Labels } from 'app/types/unified-alerting-dto'; import { partitionByValues } from '../partitionByValues/partitionByValues'; @@ -299,14 +300,17 @@ export function longToMultiTimeSeries(frame: DataFrame): DataFrame[] { }); } -export const prepareTimeSeriesTransformer: SynchronousDataTransformerInfo = { +export const getPrepareTimeSeriesTransformer: () => SynchronousDataTransformerInfo = () => ({ id: DataTransformerID.prepareTimeSeries, - name: 'Prepare time series', - description: `Will stretch data frames from the wide format into the long format. This is really helpful to be able to keep backwards compatibility for panels not supporting the new wide format.`, + name: t('transformers.prepare-time-series.name.prepare-time-series', 'Prepare time series'), + description: t( + 'transformers.prepare-time-series.description.stretch-data-frames', + 'Stretch data frames from the wide format into the long format.' + ), defaultOptions: {}, operator: (options, ctx) => (source) => - source.pipe(map((data) => prepareTimeSeriesTransformer.transformer(options, ctx)(data))), + source.pipe(map((data) => getPrepareTimeSeriesTransformer().transformer(options, ctx)(data))), transformer: (options: PrepareTimeSeriesOptions) => { const format = options?.format ?? timeSeriesFormat.TimeSeriesWide; @@ -349,4 +353,4 @@ export const prepareTimeSeriesTransformer: SynchronousDataTransformerInfo { + const RegressionTransformer = getRegressionTransformer(); + it('it should predict a linear regression to exactly fit the data when the data is f(x) = x', () => { const source = [ toDataFrame({ diff --git a/public/app/features/transformers/regression/regression.ts b/public/app/features/transformers/regression/regression.ts index b7d532d381c..cda498b5e9b 100644 --- a/public/app/features/transformers/regression/regression.ts +++ b/public/app/features/transformers/regression/regression.ts @@ -35,12 +35,15 @@ export const DEGREES = [ { label: () => t('transformers.regression-transformer-editor.label.quintic', 'Quintic'), value: 5 }, ]; -export const RegressionTransformer: SynchronousDataTransformerInfo = { +export const getRegressionTransformer: () => SynchronousDataTransformerInfo = () => ({ id: DataTransformerID.regression, - name: 'Regression analysis', - description: 'Create a new data frame containing values predicted by a statistical model.', + name: t('transformers.regression.name.regression-analysis', 'Regression analysis'), + description: t( + 'transformers.regression.description.create-new-data-frame', + 'Create a new data frame containing values predicted by a statistical model.' + ), operator: (options, ctx) => (source) => - source.pipe(map((data) => RegressionTransformer.transformer(options, ctx)(data))), + source.pipe(map((data) => getRegressionTransformer().transformer(options, ctx)(data))), transformer: (options, ctx) => { return (frames: DataFrame[]) => { const { predictionCount, modelType, degree } = { ...DEFAULTS, ...options }; @@ -137,4 +140,4 @@ export const RegressionTransformer: SynchronousDataTransformerInfo = { - id: DataTransformerID.regression, - editor: RegressionTransformerEditor, - transformation: RegressionTransformer, - name: RegressionTransformer.name, - description: RegressionTransformer.description, - categories: new Set([TransformerCategory.CalculateNewFields]), - help: getTransformationContent(DataTransformerID.regression).helperDocs, +export const getRegressionTransformerRegistryItem: () => TransformerRegistryItem = () => { + const regressionTransformer = getRegressionTransformer(); + return { + id: DataTransformerID.regression, + editor: RegressionTransformerEditor, + transformation: regressionTransformer, + name: regressionTransformer.name, + description: regressionTransformer.description, + categories: new Set([TransformerCategory.CalculateNewFields]), + help: getTransformationContent(DataTransformerID.regression).helperDocs, + }; }; diff --git a/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.tsx b/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.tsx index 8e4a0b5faad..0eb8532f840 100644 --- a/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.tsx +++ b/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.tsx @@ -3,7 +3,7 @@ import { PluginState, TransformerRegistryItem, TransformerUIProps, TransformerCa import { getTransformationContent } from '../docs/getTransformationContent'; import { FieldToConfigMappingEditor } from '../fieldToConfigMapping/FieldToConfigMappingEditor'; -import { rowsToFieldsTransformer, RowToFieldsTransformOptions } from './rowsToFields'; +import { getRowsToFieldsTransformer, RowToFieldsTransformOptions } from './rowsToFields'; export interface Props extends TransformerUIProps {} @@ -24,13 +24,16 @@ export function RowsToFieldsTransformerEditor({ input, options, onChange }: Prop ); } -export const rowsToFieldsTransformRegistryItem: TransformerRegistryItem = { - id: rowsToFieldsTransformer.id, - editor: RowsToFieldsTransformerEditor, - transformation: rowsToFieldsTransformer, - name: rowsToFieldsTransformer.name, - description: rowsToFieldsTransformer.description, - state: PluginState.beta, - categories: new Set([TransformerCategory.Reformat]), - help: getTransformationContent(rowsToFieldsTransformer.id).helperDocs, +export const getRowsToFieldsTransformRegistryItem: () => TransformerRegistryItem = () => { + const rowsToFieldsTransformer = getRowsToFieldsTransformer(); + return { + id: rowsToFieldsTransformer.id, + editor: RowsToFieldsTransformerEditor, + transformation: rowsToFieldsTransformer, + name: rowsToFieldsTransformer.name, + description: rowsToFieldsTransformer.description, + state: PluginState.beta, + categories: new Set([TransformerCategory.Reformat]), + help: getTransformationContent(rowsToFieldsTransformer.id).helperDocs, + }; }; diff --git a/public/app/features/transformers/rowsToFields/rowsToFields.ts b/public/app/features/transformers/rowsToFields/rowsToFields.ts index 7bdece8e98b..d7f5173273b 100644 --- a/public/app/features/transformers/rowsToFields/rowsToFields.ts +++ b/public/app/features/transformers/rowsToFields/rowsToFields.ts @@ -1,6 +1,7 @@ import { map } from 'rxjs/operators'; import { DataFrame, DataTransformerID, DataTransformerInfo, Field, getFieldDisplayName, Labels } from '@grafana/data'; +import { t } from '@grafana/i18n'; import { EvaluatedMappingResult, @@ -16,10 +17,13 @@ export interface RowToFieldsTransformOptions { mappings?: FieldToConfigMapping[]; } -export const rowsToFieldsTransformer: DataTransformerInfo = { +export const getRowsToFieldsTransformer: () => DataTransformerInfo = () => ({ id: DataTransformerID.rowsToFields, - name: 'Rows to fields', - description: 'Convert each row into a field with dynamic config.', + name: t('transformers.get-rows-to-fields-transformer.name.rows-to-fields', 'Rows to fields'), + description: t( + 'transformers.get-rows-to-fields-transformer.description.convert-field-dynamic-config', + 'Convert each row into a field with dynamic config.' + ), defaultOptions: {}, /** @@ -32,7 +36,7 @@ export const rowsToFieldsTransformer: DataTransformerInfo rowsToFields(options, frame)); }) ), -}; +}); export function rowsToFields(options: RowToFieldsTransformOptions, data: DataFrame): DataFrame { const mappingResult = evaluateFieldMappings(data, options.mappings ?? [], true); diff --git a/public/app/features/transformers/spatial/SpatialTransformerEditor.tsx b/public/app/features/transformers/spatial/SpatialTransformerEditor.tsx index 71c8d6d7287..dbc94ad0f0e 100644 --- a/public/app/features/transformers/spatial/SpatialTransformerEditor.tsx +++ b/public/app/features/transformers/spatial/SpatialTransformerEditor.tsx @@ -20,7 +20,7 @@ import { getTransformationContent } from '../docs/getTransformationContent'; import { SpatialCalculation, SpatialOperation, SpatialAction, SpatialTransformOptions } from './models.gen'; import { getDefaultOptions, getTransformerOptionPane } from './optionsHelper'; -import { isLineBuilderOption, spatialTransformer } from './spatialTransformer'; +import { isLineBuilderOption, getSpatialTransformer } from './spatialTransformer'; // Nothing defined in state const supplier = ( @@ -173,13 +173,16 @@ const getStyles = (theme: GrafanaTheme2) => { }; }; -export const spatialTransformRegistryItem: TransformerRegistryItem = { - id: DataTransformerID.spatial, - editor: SetGeometryTransformerEditor, - transformation: spatialTransformer, - name: spatialTransformer.name, - description: spatialTransformer.description, - state: PluginState.alpha, - categories: new Set([TransformerCategory.PerformSpatialOperations]), - help: getTransformationContent(DataTransformerID.spatial).helperDocs, +export const getSpatialTransformRegistryItem: () => TransformerRegistryItem = () => { + const spatialTransformer = getSpatialTransformer(); + return { + id: DataTransformerID.spatial, + editor: SetGeometryTransformerEditor, + transformation: spatialTransformer, + name: spatialTransformer.name, + description: spatialTransformer.description, + state: PluginState.alpha, + categories: new Set([TransformerCategory.PerformSpatialOperations]), + help: getTransformationContent(DataTransformerID.spatial).helperDocs, + }; }; diff --git a/public/app/features/transformers/spatial/spatialTransformer.ts b/public/app/features/transformers/spatial/spatialTransformer.ts index 7bf8c2adf3f..19e0f90d50b 100644 --- a/public/app/features/transformers/spatial/spatialTransformer.ts +++ b/public/app/features/transformers/spatial/spatialTransformer.ts @@ -1,20 +1,24 @@ import { mergeMap, from } from 'rxjs'; import { DataFrame, DataTransformerID, DataTransformerInfo, FieldType } from '@grafana/data'; +import { t } from '@grafana/i18n'; import { createGeometryCollection, createLineBetween } from 'app/features/geo/format/utils'; import { getGeometryField, getLocationMatchers } from 'app/features/geo/utils/location'; import { SpatialOperation, SpatialAction, SpatialTransformOptions } from './models.gen'; import { doGeomeryCalculation, toLineString } from './utils'; -export const spatialTransformer: DataTransformerInfo = { +export const getSpatialTransformer: () => DataTransformerInfo = () => ({ id: DataTransformerID.spatial, - name: 'Spatial operations', - description: 'Apply spatial operations to query results.', + name: t('transformers.get-spatial-transformer.name.spatial-operations', 'Spatial operations'), + description: t( + 'transformers.get-spatial-transformer.description.apply-spatial-operations-to-query-results', + 'Apply spatial operations to query results.' + ), defaultOptions: {}, operator: (options) => (source) => source.pipe(mergeMap((data) => from(doSetGeometry(data, options)))), -}; +}); export function isLineBuilderOption(options: SpatialTransformOptions): boolean { return options.action === SpatialAction.Modify && options.modify?.op === SpatialOperation.LineBuilder; diff --git a/public/app/features/transformers/standardTransformers.ts b/public/app/features/transformers/standardTransformers.ts index 4f8a5598c75..3fdd629a6e4 100644 --- a/public/app/features/transformers/standardTransformers.ts +++ b/public/app/features/transformers/standardTransformers.ts @@ -1,74 +1,74 @@ import { TransformerRegistryItem } from '@grafana/data'; import { config } from '@grafana/runtime'; -import { filterByValueTransformRegistryItem } from './FilterByValueTransformer/FilterByValueTransformerEditor'; -import { heatmapTransformRegistryItem } from './calculateHeatmap/HeatmapTransformerEditor'; -import { configFromQueryTransformRegistryItem } from './configFromQuery/ConfigFromQueryTransformerEditor'; -import { calculateFieldTransformRegistryItem } from './editors/CalculateFieldTransformerEditor'; -import { concatenateTransformRegistryItem } from './editors/ConcatenateTransformerEditor'; -import { convertFieldTypeTransformRegistryItem } from './editors/ConvertFieldTypeTransformerEditor'; -import { filterFieldsByNameTransformRegistryItem } from './editors/FilterByNameTransformerEditor'; -import { filterFramesByRefIdTransformRegistryItem } from './editors/FilterByRefIdTransformerEditor'; -import { formatStringTransformerRegistryItem } from './editors/FormatStringTransformerEditor'; -import { formatTimeTransformerRegistryItem } from './editors/FormatTimeTransformerEditor'; -import { groupByTransformRegistryItem } from './editors/GroupByTransformerEditor'; -import { groupToNestedTableTransformRegistryItem } from './editors/GroupToNestedTableTransformerEditor'; -import { groupingToMatrixTransformRegistryItem } from './editors/GroupingToMatrixTransformerEditor'; -import { histogramTransformRegistryItem } from './editors/HistogramTransformerEditor'; -import { joinByFieldTransformerRegistryItem } from './editors/JoinByFieldTransformerEditor'; -import { labelsToFieldsTransformerRegistryItem } from './editors/LabelsToFieldsTransformerEditor'; -import { limitTransformRegistryItem } from './editors/LimitTransformerEditor'; -import { mergeTransformerRegistryItem } from './editors/MergeTransformerEditor'; -import { organizeFieldsTransformRegistryItem } from './editors/OrganizeFieldsTransformerEditor'; -import { reduceTransformRegistryItem } from './editors/ReduceTransformerEditor'; -import { renameByRegexTransformRegistryItem } from './editors/RenameByRegexTransformer'; -import { seriesToRowsTransformerRegistryItem } from './editors/SeriesToRowsTransformerEditor'; -import { sortByTransformRegistryItem } from './editors/SortByTransformerEditor'; -import { transposeTransformerRegistryItem } from './editors/TransposeTransformerEditor'; -import { extractFieldsTransformRegistryItem } from './extractFields/ExtractFieldsTransformerEditor'; -import { joinByLabelsTransformRegistryItem } from './joinByLabels/JoinByLabelsTransformerEditor'; -import { fieldLookupTransformRegistryItem } from './lookupGazetteer/FieldLookupTransformerEditor'; -import { partitionByValuesTransformRegistryItem } from './partitionByValues/PartitionByValuesEditor'; -import { prepareTimeseriesTransformerRegistryItem } from './prepareTimeSeries/PrepareTimeSeriesEditor'; -import { regressionTransformerRegistryItem } from './regression/regressionEditor'; -import { rowsToFieldsTransformRegistryItem } from './rowsToFields/RowsToFieldsTransformerEditor'; -import { spatialTransformRegistryItem } from './spatial/SpatialTransformerEditor'; -import { timeSeriesTableTransformRegistryItem } from './timeSeriesTable/TimeSeriesTableTransformEditor'; +import { getFilterByValueTransformRegistryItem } from './FilterByValueTransformer/FilterByValueTransformerEditor'; +import { getHeatmapTransformRegistryItem } from './calculateHeatmap/HeatmapTransformerEditor'; +import { getConfigFromQueryTransformRegistryItem } from './configFromQuery/ConfigFromQueryTransformerEditor'; +import { getCalculateFieldTransformRegistryItem } from './editors/CalculateFieldTransformerEditor/CalculateFieldTransformerEditor'; +import { getConcatenateTransformRegistryItem } from './editors/ConcatenateTransformerEditor'; +import { getConvertFieldTypeTransformRegistryItem } from './editors/ConvertFieldTypeTransformerEditor'; +import { getFilterFieldsByNameTransformRegistryItem } from './editors/FilterByNameTransformerEditor'; +import { getFilterFramesByRefIdTransformRegistryItem } from './editors/FilterByRefIdTransformerEditor'; +import { getFormatStringTransformerRegistryItem } from './editors/FormatStringTransformerEditor'; +import { getFormatTimeTransformerRegistryItem } from './editors/FormatTimeTransformerEditor'; +import { getGroupByTransformRegistryItem } from './editors/GroupByTransformerEditor'; +import { getGroupToNestedTableTransformRegistryItem } from './editors/GroupToNestedTableTransformerEditor'; +import { getGroupingToMatrixTransformRegistryItem } from './editors/GroupingToMatrixTransformerEditor'; +import { getHistogramTransformRegistryItem } from './editors/HistogramTransformerEditor'; +import { getJoinByFieldTransformerRegistryItem } from './editors/JoinByFieldTransformerEditor'; +import { getLabelsToFieldsTransformerRegistryItem } from './editors/LabelsToFieldsTransformerEditor'; +import { getLimitTransformRegistryItem } from './editors/LimitTransformerEditor'; +import { getMergeTransformerRegistryItem } from './editors/MergeTransformerEditor'; +import { getOrganizeFieldsTransformRegistryItem } from './editors/OrganizeFieldsTransformerEditor'; +import { getReduceTransformRegistryItem } from './editors/ReduceTransformerEditor'; +import { getRenameByRegexTransformRegistryItem } from './editors/RenameByRegexTransformer'; +import { getSeriesToRowsTransformerRegistryItem } from './editors/SeriesToRowsTransformerEditor'; +import { getSortByTransformRegistryItem } from './editors/SortByTransformerEditor'; +import { getTransposeTransformerRegistryItem } from './editors/TransposeTransformerEditor'; +import { getExtractFieldsTransformRegistryItem } from './extractFields/ExtractFieldsTransformerEditor'; +import { getJoinByLabelsTransformRegistryItem } from './joinByLabels/JoinByLabelsTransformerEditor'; +import { getFieldLookupTransformRegistryItem } from './lookupGazetteer/FieldLookupTransformerEditor'; +import { getPartitionByValuesTransformRegistryItem } from './partitionByValues/PartitionByValuesEditor'; +import { getPrepareTimeseriesTransformerRegistryItem } from './prepareTimeSeries/PrepareTimeSeriesEditor'; +import { getRegressionTransformerRegistryItem } from './regression/regressionEditor'; +import { getRowsToFieldsTransformRegistryItem } from './rowsToFields/RowsToFieldsTransformerEditor'; +import { getSpatialTransformRegistryItem } from './spatial/SpatialTransformerEditor'; +import { getTimeSeriesTableTransformRegistryItem } from './timeSeriesTable/TimeSeriesTableTransformEditor'; export const getStandardTransformers = (): TransformerRegistryItem[] => { return [ - reduceTransformRegistryItem, - filterFieldsByNameTransformRegistryItem, - renameByRegexTransformRegistryItem, - filterFramesByRefIdTransformRegistryItem, - filterByValueTransformRegistryItem, - organizeFieldsTransformRegistryItem, - joinByFieldTransformerRegistryItem, - seriesToRowsTransformerRegistryItem, - concatenateTransformRegistryItem, - calculateFieldTransformRegistryItem, - labelsToFieldsTransformerRegistryItem, - groupByTransformRegistryItem, - sortByTransformRegistryItem, - mergeTransformerRegistryItem, - histogramTransformRegistryItem, - rowsToFieldsTransformRegistryItem, - configFromQueryTransformRegistryItem, - prepareTimeseriesTransformerRegistryItem, - convertFieldTypeTransformRegistryItem, - spatialTransformRegistryItem, - fieldLookupTransformRegistryItem, - extractFieldsTransformRegistryItem, - heatmapTransformRegistryItem, - groupingToMatrixTransformRegistryItem, - limitTransformRegistryItem, - joinByLabelsTransformRegistryItem, - regressionTransformerRegistryItem, - partitionByValuesTransformRegistryItem, - ...(config.featureToggles.formatString ? [formatStringTransformerRegistryItem] : []), - ...(config.featureToggles.groupToNestedTableTransformation ? [groupToNestedTableTransformRegistryItem] : []), - formatTimeTransformerRegistryItem, - timeSeriesTableTransformRegistryItem, - transposeTransformerRegistryItem, + getReduceTransformRegistryItem(), + getFilterFieldsByNameTransformRegistryItem(), + getRenameByRegexTransformRegistryItem(), + getFilterFramesByRefIdTransformRegistryItem(), + getFilterByValueTransformRegistryItem(), + getOrganizeFieldsTransformRegistryItem(), + getJoinByFieldTransformerRegistryItem(), + getSeriesToRowsTransformerRegistryItem(), + getConcatenateTransformRegistryItem(), + getCalculateFieldTransformRegistryItem(), + getLabelsToFieldsTransformerRegistryItem(), + getGroupByTransformRegistryItem(), + getSortByTransformRegistryItem(), + getMergeTransformerRegistryItem(), + getHistogramTransformRegistryItem(), + getRowsToFieldsTransformRegistryItem(), + getConfigFromQueryTransformRegistryItem(), + getPrepareTimeseriesTransformerRegistryItem(), + getConvertFieldTypeTransformRegistryItem(), + getSpatialTransformRegistryItem(), + getFieldLookupTransformRegistryItem(), + getExtractFieldsTransformRegistryItem(), + getHeatmapTransformRegistryItem(), + getGroupingToMatrixTransformRegistryItem(), + getLimitTransformRegistryItem(), + getJoinByLabelsTransformRegistryItem(), + getRegressionTransformerRegistryItem(), + getPartitionByValuesTransformRegistryItem(), + ...(config.featureToggles.formatString ? [getFormatStringTransformerRegistryItem()] : []), + ...(config.featureToggles.groupToNestedTableTransformation ? [getGroupToNestedTableTransformRegistryItem()] : []), + getFormatTimeTransformerRegistryItem(), + getTimeSeriesTableTransformRegistryItem(), + getTransposeTransformerRegistryItem(), ]; }; diff --git a/public/app/features/transformers/timeSeriesTable/TimeSeriesTableTransformEditor.tsx b/public/app/features/transformers/timeSeriesTable/TimeSeriesTableTransformEditor.tsx index bc47f4eb04c..d90702f5f35 100644 --- a/public/app/features/transformers/timeSeriesTable/TimeSeriesTableTransformEditor.tsx +++ b/public/app/features/transformers/timeSeriesTable/TimeSeriesTableTransformEditor.tsx @@ -17,7 +17,7 @@ import { InlineFieldRow, InlineField, StatsPicker, Select, InlineLabel } from '@ import { getTransformationContent } from '../docs/getTransformationContent'; import { - timeSeriesTableTransformer, + getTimeSeriesTableTransformer, TimeSeriesTableTransformerOptions, getRefData, } from './timeSeriesTableTransformer'; @@ -123,12 +123,16 @@ export function TimeSeriesTableTransformEditor({ return <>{configRows}; } -export const timeSeriesTableTransformRegistryItem: TransformerRegistryItem = { - id: timeSeriesTableTransformer.id, - editor: TimeSeriesTableTransformEditor, - transformation: timeSeriesTableTransformer, - name: timeSeriesTableTransformer.name, - description: timeSeriesTableTransformer.description, - state: PluginState.beta, - help: getTransformationContent(timeSeriesTableTransformer.id).helperDocs, -}; +export const getTimeSeriesTableTransformRegistryItem: () => TransformerRegistryItem = + () => { + const timeSeriesTableTransformer = getTimeSeriesTableTransformer(); + return { + id: timeSeriesTableTransformer.id, + editor: TimeSeriesTableTransformEditor, + transformation: timeSeriesTableTransformer, + name: timeSeriesTableTransformer.name, + description: timeSeriesTableTransformer.description, + state: PluginState.beta, + help: getTransformationContent(timeSeriesTableTransformer.id).helperDocs, + }; + }; diff --git a/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.ts b/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.ts index fc20a059fde..d3e4073022b 100644 --- a/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.ts +++ b/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.ts @@ -14,6 +14,7 @@ import { TransformationApplicabilityLevels, isTimeSeriesField, } from '@grafana/data'; +import { t } from '@grafana/i18n'; /** * Maps a refId to a Field which can contain @@ -81,10 +82,13 @@ export interface RefIdTransformerOptions { inlineStat?: boolean; } -export const timeSeriesTableTransformer: DataTransformerInfo = { +export const getTimeSeriesTableTransformer: () => DataTransformerInfo = () => ({ id: DataTransformerID.timeSeriesTable, - name: 'Time series to table', - description: 'Convert time series data to table rows so that they can be viewed in tabular or sparkline format.', + name: t('transformers.time-series-table.name.time-series-to-table', 'Time series to table'), + description: t( + 'transformers.time-series-table.description.convert-to-table-rows', + 'Convert time series data to table rows so that they can be viewed in tabular or sparkline format.' + ), defaultOptions: {}, isApplicable: (data) => { for (const frame of data) { @@ -95,15 +99,17 @@ export const timeSeriesTableTransformer: DataTransformerInfo (source) => source.pipe( map((data) => { return timeSeriesToTableTransform(options, data); }) ), -}; +}); /** * Converts time series frames to table frames for use with sparkline chart type. diff --git a/public/app/features/transformers/utils.ts b/public/app/features/transformers/utils.ts index fcb18493e90..7cbf4cd1241 100644 --- a/public/app/features/transformers/utils.ts +++ b/public/app/features/transformers/utils.ts @@ -62,15 +62,21 @@ export function getDistinctLabels(input: DataFrame[]): Set { 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 getCategoriesLabels: () => { [K in TransformerCategory]: string } = () => ({ + combine: t('transformers.utils.get-categories-labels.combine', 'Combine'), + calculateNewFields: t('transformers.utils.get-categories-labels.calculate-new-fields', 'Calculate new fields'), + createNewVisualization: t( + 'transformers.utils.get-categories-labels.create-new-visualization', + 'Create new visualization' + ), + filter: t('transformers.utils.get-categories-labels.filter', 'Filter'), + performSpatialOperations: t( + 'transformers.utils.get-categories-labels.perform-spatial-operations', + 'Perform spatial operations' + ), + reformat: t('transformers.utils.get-categories-labels.reformat', 'Reformat'), + reorderAndRename: t('transformers.utils.get-categories-labels.reorder-and-rename', 'Reorder and rename'), +}); export const numberOrVariableValidator = (value: string | number) => { if (typeof value === 'number') { diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 6daba435bae..ea3d5595fbb 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -5259,7 +5259,8 @@ "transformation-picker-ng": { "placeholder-search-for-transformation": "Search for transformation", "show-images": "Show images", - "title-add-another-transformation": "Add another transformation" + "title-add-another-transformation": "Add another transformation", + "view-all": "View all" }, "un-theme-transformations-editor": { "body-delete-all-transformations": "By deleting all transformations, you will go back to the main selection screen." @@ -12230,6 +12231,18 @@ "placeholder-fields-or-number": "Field(s) or number" }, "calculate-field-transformer-editor": { + "calculation-modes": { + "label": { + "binary-operation": "Binary operation", + "reduce-row": "Reduce row", + "row-index": "Row index", + "unary-operation": "Unary operation" + } + }, + "label": { + "cumulative-functions": "Cumulative functions", + "window-functions": "Window functions" + }, "label-alias": "Alias", "label-mode": "Mode", "label-replace-all-fields": "Replace all fields" @@ -12244,6 +12257,13 @@ "concatenate-transformer-editor": { "label-label": "Label", "label-name": "Name", + "name-modes": { + "label": { + "copy-frame-name-to-field": "Copy frame name to field name", + "ignore-the-frame-name": "Ignore the frame name", + "label-frame": "Add a label with the frame name" + } + }, "placeholder-frame": "Frame" }, "config-from-query-transformer-editor": { @@ -12255,6 +12275,9 @@ "aria-label-add-a-convert-field-type-transformer": "Add a convert field type transformer", "aria-label-remove-convert-field-type-transformer": "Remove convert field type transformer", "convert-field-type": "Convert field type", + "description": { + "convert-to-specified-field-type": "Convert a field to a specified field type." + }, "label": { "browser": "Browser", "utc": "UTC" @@ -12265,7 +12288,13 @@ "label-input-format": "Input format", "label-join-with": "Join with", "label-set-timezone": "Set timezone", + "name": { + "convert-field-type": "Convert field type" + }, "placeholder-type": "Type", + "tags": { + "format-field": "Format field" + }, "tooltip-explicit-separator-joining-array-values": "Use an explicit separator when joining array values", "tooltip-input-format": "Specify the format of the input field so Grafana can parse the date string correctly.", "tooltip-specify-the-output-format": "Specify the output format.", @@ -12287,6 +12316,19 @@ "desc": "DESC", "off": "Off" }, + "editors": { + "concatenate-transformer-editor": { + "description": { + "combine-all-fields": "Combine all fields into a single frame." + }, + "name": { + "concatenate-fields": "Concatenate fields" + }, + "tags": { + "combine": "Combine" + } + } + }, "enum-mapping-editor": { "add-enum-value": "Add enum value", "generate-enum-values-from-data": "Generate enum values from data" @@ -12297,6 +12339,9 @@ "remove-enum-row-tooltip-delete": "Delete" }, "extract-fields-transformer-editor": { + "description": { + "parse-fields-from-content": "Parse fields from content (JSON, labels, etc)." + }, "field-name-picker-settings": { "placeholderText": { "select-field": "Select field" @@ -12307,6 +12352,9 @@ "label-keep-time": "Keep time", "label-replace-all-fields": "Replace all fields", "label-source": "Source", + "name": { + "extract-fields": "Extract fields" + }, "placeholder-auto": "Auto", "placeholder-select-delimiter": "Select delimiter...", "tooltip-regexp": "Example: {{regexExample}}" @@ -12315,6 +12363,9 @@ "aria-label-threshold-color": "Threshold color" }, "field-lookup-transformer-editor": { + "description": { + "lookup-additional-fields-external-source": "Use a field value to lookup countries, states, or airports." + }, "field-name-picker-settings": { "noFieldsMessage": { "no-text-fields-found": "No text fields found" @@ -12324,7 +12375,10 @@ } }, "label-field": "Field", - "label-lookup": "Lookup" + "label-lookup": "Lookup", + "name": { + "lookup-fields-from-resource": "Lookup fields from resource" + } }, "field-to-config-mapping-editor": { "additional-settings": "Additional settings", @@ -12333,12 +12387,26 @@ "use-as": "Use as" }, "filter-by-name-transformer-editor": { + "description": { + "remove-part-query-results-regex-pattern": "Remove parts of the query results using a regex pattern." + }, "label-from-variable": "From variable", "label-identifier": "Identifier", "label-use-variable": "Use variable", "label-variable": "Variable", + "name": { + "filter-fields-by-name": "Filter fields by name" + }, "placeholder-regular-expression-pattern": "Regular expression pattern" }, + "filter-by-ref-id-transformer-editor": { + "description": { + "filter-data-by-query-useful-sharing-results": "Remove rows from the data based on origin query" + }, + "name": { + "filter-data-by-query": "Filter data by query" + } + }, "filter-by-value-filter-editor": { "label-field": "Field", "label-match": "Match", @@ -12348,6 +12416,9 @@ }, "filter-by-value-transformer-editor": { "add-condition": "Add condition", + "description": { + "remove-rows-query-results-user-defined-filters": "Remove rows from the query results using user-defined filters." + }, "filter-match": { "label": { "match-all": "Match all", @@ -12361,7 +12432,10 @@ } }, "label-conditions": "Conditions", - "label-filter-type": "Filter type" + "label-filter-type": "Filter type", + "name": { + "filter-data-by-values": "Filter data by values" + } }, "format-string-transfomer-editor": { "field-name-picker-settings": { @@ -12376,6 +12450,14 @@ "label-format": "Format", "label-substring-range": "Substring range" }, + "format-string-transformer-editor": { + "description": { + "manipulate-string-fields-formatting": "Manipulate string fields formatting." + }, + "name": { + "format-string": "Format string" + } + }, "format-time-transfomer-editor": { "label-format": "Format", "label-set-timezone": "Set timezone", @@ -12383,6 +12465,70 @@ "tooltip-format": "The output format for the field specified as a <2>Moment.js format string.", "tooltip-timezone-manually": "Set the timezone of the date manually" }, + "format-time-transformer-editor": { + "description": { + "set-based-on-time": "Set the output format of a time field" + }, + "name": { + "format-time": "Format time" + } + }, + "get-calculate-field-transform-registry-item": { + "description": { + "values-calculate-field": "Use the row values to calculate a new field." + }, + "name": { + "add-field-from-calculation": "Add field from calculation" + } + }, + "get-config-from-data-transformer": { + "description": { + "set-unit-min-max-and-more": "Set unit, min, max and more." + }, + "name": { + "config-from-query-results": "Config from query results" + } + }, + "get-heatmap-transformer": { + "description": { + "generate-heatmap-data-from-source": "Generate heatmap data from source data." + }, + "name": { + "create-heatmap": "Create heatmap" + } + }, + "get-join-by-labels-transformer": { + "description": { + "flatten-labeled-results-table-joined-labels": "Flatten labeled results into a table joined by labels." + }, + "name": { + "join-by-labels": "Join by labels" + } + }, + "get-partition-by-values-transformer": { + "description": { + "split-oneframe-dataset-multiple-series": "Split a one-frame dataset into multiple series." + }, + "name": { + "partition-by-values": "Partition by values" + } + }, + "get-rows-to-fields-transformer": { + "description": { + "convert-field-dynamic-config": "Convert each row into a field with dynamic config." + }, + "name": { + "rows-to-fields": "Rows to fields" + } + }, + "get-spatial-transformer": { + "description": { + "apply-spatial-operations-to-query-results": "Apply spatial operations to query results." + }, + "name": { + "spatial-operations": "Spatial operations" + } + }, "get-timezone-options": { "label": { "browser": "Browser", @@ -12410,22 +12556,46 @@ } }, "group-by-field-configuration": { + "options": { + "label": { + "calculate": "Calculate", + "group-by": "Group by" + } + }, "placeholder-ignored": "Ignored", "placeholder-select-stats": "Select stats" }, "group-by-transformer-editor": { + "description": { + "group-series-by-field-calculate-stats": "Group data by a field value and create aggregate data." + }, + "name": { + "group-by": "Group by" + }, "title-calc-alert": "Calculations will not have an effect if no fields are being grouped on" }, "group-to-nested-table-transformer-editor": { + "description": { + "group-by-field-value": "Group data by a field value and create nested tables with the grouped data." + }, "description-show-field-names": "If enabled nested tables will show field names as a table header", "label-show-field-names-in-nested-tables": "Show field names in nested tables", + "name": { + "group-to-nested-tables": "Group to nested tables" + }, "title-calc-alert": "Calculations will not have an effect if no fields are being grouped on." }, "grouping-to-matrix-transformer-editor": { + "description": { + "summarize-and-reorganize-data": "Summarize and reorganize data based on three fields." + }, "label-cell-value": "Cell value", "label-column": "Column", "label-empty-value": "Empty value", "label-row": "Row", + "name": { + "grouping-to-matrix": "Grouping to matrix" + }, "special-value-options": { "description": { "boolean-false-value": "Boolean false value", @@ -12444,6 +12614,12 @@ } }, "histogram-transformer-editor": { + "description": { + "calculate-histogram-from-input-data": "Calculate a histogram from input data." + }, + "name": { + "histogram": "Histogram" + }, "placeholder-auto": "Auto", "placeholder-default": "Default: 30", "placeholder-none": "None" @@ -12452,7 +12628,16 @@ "label-as-percentile": "As percentile", "tooltip-transform-index-percentile": "Transform the row index as a percentile." }, + "join-by-field-transformer-editor": { + "description": { + "combine-rows-from-2-tables": "Combine rows from 2+ tables, based on a related field." + }, + "name": { + "join-by-field": "Join by field" + } + }, "join-by-labels-transformer-editor": { + "error-required": "Required", "info": { "input-contain-labels": "The input does not contain any labels", "no-input-or-labels-found": "No input (or labels) found", @@ -12474,10 +12659,30 @@ "label-labels": "Labels", "label-mode": "Mode", "label-value-field-name": "Value field name", + "modes": { + "label": { + "columns": "Columns", + "rows": "Rows" + } + }, "placeholder-optional-select-label": "(Optional) Select label", "tooltip-replace-value-field-label": "Replace the value field name with a label" }, + "labels-to-fields-transformer-editor": { + "description": { + "groups-series-time-return-labels-tags-fields": "Group series by time and return labels or tags as fields." + }, + "name": { + "labels-to-fields": "Labels to fields" + } + }, "limit-transformer-editor": { + "description": { + "limit-number-items-displayed": "Limit the number of items displayed." + }, + "name": { + "limit": "Limit" + }, "placeholder-value-or-variable": "Value or variable" }, "long-info": { @@ -12488,7 +12693,13 @@ "string-values-separate": "String values are represented as separate fields rather than as labels" }, "merge-transformer-editor": { - "merge-effect-applied-single-frame": "Merge has no effect when applied on a single frame." + "description": { + "merge-multiple-series": "Merge multiple series. Values will be combined into one row." + }, + "merge-effect-applied-single-frame": "Merge has no effect when applied on a single frame.", + "name": { + "merge": "Merge series/tables" + } }, "multi-info": { "all-values-are-numeric": "All values are numeric", @@ -12498,10 +12709,16 @@ "time-in-ascending-order": "Time in ascending order" }, "organize-fields-transformer-editor": { + "description": { + "reorder-hide-or-rename-fields": "Re-order, hide, or rename fields." + }, "field-order": "Field order", "field-order-auto": "Auto", "field-order-manual": "Manual", - "first-frame-warning": "Organize fields only works with a single frame. Consider applying a join transformation or filtering the input first." + "first-frame-warning": "Organize fields only works with a single frame. Consider applying a join transformation or filtering the input first.", + "name": { + "organize-fields": "Organize fields by name" + } }, "partion-by-values-editor": { "tooltip-naming": "Sets how the names of the selected fields are displayed. As frame name is usually better for tabular data" @@ -12526,9 +12743,41 @@ "partition-values-works-single-frame": "Partition by values only works with a single frame.", "tooltip-keeps-partition-fields-frames": "Keeps the partition fields in the frames" }, + "prepare-time-series": { + "description": { + "stretch-data-frames": "Stretch data frames from the wide format into the long format." + }, + "name": { + "prepare-time-series": "Prepare time series" + } + }, "prepare-time-series-editor": { "label-format": "Format", - "label-info": "Info" + "label-info": "Info", + "long-info": { + "description": { + "convert-each-frame-to-long-format": "Convert each frame to long format" + }, + "label": { + "long-time-series": "Long time series" + } + }, + "multi-info": { + "description": { + "creates-frame-timenumber": "Creates a new frame for each time/number pair" + }, + "label": { + "multiframe-time-series": "Multi-frame time series" + } + }, + "wide-info": { + "description": { + "creates-single-frame-joined": "Creates a single frame joined by time" + }, + "label": { + "wide-time-series": "Wide time series" + } + } }, "range-matcher-editor": { "and": "and", @@ -12540,6 +12789,9 @@ "label-operation": "Operation" }, "reduce-transformer-editor": { + "description": { + "reduce-to-single-value": "Reduce all rows or data points to a single value (ex. max, mean)." + }, "label-calculations": "Calculations", "label-include-time": "Include time", "label-labels-to-fields": "Labels to fields", @@ -12554,12 +12806,23 @@ "series-to-rows": "Series to rows" } }, + "name": { + "reduce": "Reduce" + }, "placeholder-choose-stat": "Choose stat" }, "regex-matcher-editor": { "placeholder-value-or-variable": "Value or variable", "variable-regex-documentation": "Formats multi-value variable into a regex string" }, + "regression": { + "description": { + "create-new-data-frame": "Create a new data frame containing values predicted by a statistical model." + }, + "name": { + "regression-analysis": "Regression analysis" + } + }, "regression-transformer-editor": { "label": { "cubic": "Cubic", @@ -12581,6 +12844,14 @@ "regression": "regression", "tooltip-number-of-xy-points-to-predict": "Number of X,Y points to predict" }, + "rename-by-regex-transformer": { + "description": { + "rename-parts-using-regex": "Rename parts of the query results using a regular expression and replacement pattern." + }, + "name": { + "rename-fields-by-regex": "Rename fields by regex" + } + }, "rename-by-regex-transformer-editor": { "label-match": "Match", "label-replace": "Replace", @@ -12589,11 +12860,37 @@ }, "series-to-fields-transformer-editor": { "label-field": "Field", - "label-mode": "Mode" + "label-mode": "Mode", + "modes": { + "description": { + "combine-data-from-two-tables": "Combine data from two tables whenever there are matching values in a fields common to both tables.", + "join-on-a-field": "Join on a field value with duplicated values. Non performant outer join best used for tabular(SQL like) data.", + "keep-all-rows": "Keep all rows from any table with a value. Join on distinct field values. Performant and best used for time series." + }, + "label": { + "inner": "Inner", + "outer-tabular": "Outer (tabular)", + "outer-time-series": "Outer (time series)" + } + } + }, + "series-to-rows-transformer-editor": { + "description": { + "merge-multiple-series": "Merge multiple series. Return time, metric and values as a row." + }, + "name": { + "series-to-rows": "Series to rows" + } }, "sort-by-transformer-editor": { + "description": { + "sort-fields": "Sort fields in a frame." + }, "label-field": "Field", "label-reverse": "Reverse", + "name": { + "sort-by": "Sort by" + }, "placeholder-select-field": "Select field" }, "supplier": { @@ -12613,7 +12910,17 @@ "transform": "Transform" } }, - "tag": "{{ tag }}", + "time-series-table": { + "description": { + "convert-to-table-rows": "Convert time series data to table rows so that they can be viewed in tabular or sparkline format." + }, + "is-applicable-description": { + "requires-time-series-frame": "The Time series to table transformation requires at least one time series frame to function. You currently have none." + }, + "name": { + "time-series-to-table": "Time series to table" + } + }, "time-series-table-transform-editor": { "label-stat": "Stat", "label-time-field": "Time field", @@ -12627,10 +12934,34 @@ "placeholder-value": "Value", "tooltip-name-for-value-fields": "Name for value fields" }, + "transpose-transformer-editor": { + "description": { + "transpose-data-frame": "Transpose the data frame." + }, + "name": { + "transpose": "Transpose" + }, + "tags": { + "pivot": "Pivot", + "transform": "Transform", + "translate": "Translate" + } + }, "unary-operation-editor": { "label-operation": "Operation", "placeholder-field": "Field" }, + "utils": { + "get-categories-labels": { + "calculate-new-fields": "Calculate new fields", + "combine": "Combine", + "create-new-visualization": "Create new visualization", + "filter": "Filter", + "perform-spatial-operations": "Perform spatial operations", + "reformat": "Reformat", + "reorder-and-rename": "Reorder and rename" + } + }, "wide-info": { "multiple-value-fields-of-any-type": "Multiple value fields of any type", "single-frame": "Single frame",