mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Transform: Add a limit transform (#49291)
* Add a limit transform * Add a limit transform * Simplify filter code Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
This commit is contained in:
parent
062d255124
commit
7d7890e23c
2
.yarn/sdks/integrations.yml
vendored
2
.yarn/sdks/integrations.yml
vendored
@ -2,5 +2,5 @@
|
|||||||
# Manual changes might be lost!
|
# Manual changes might be lost!
|
||||||
|
|
||||||
integrations:
|
integrations:
|
||||||
- vscode
|
|
||||||
- vim
|
- vim
|
||||||
|
- vscode
|
||||||
|
@ -545,3 +545,26 @@ Here is the result after applying the Series to rows transformation.
|
|||||||
## Sort by
|
## Sort by
|
||||||
|
|
||||||
This transformation will sort each frame by the configured field, When `reverse` is checked, the values will return in the opposite order.
|
This transformation will sort each frame by the configured field, When `reverse` is checked, the values will return in the opposite order.
|
||||||
|
|
||||||
|
## Limit
|
||||||
|
|
||||||
|
Use this transformation to limit the number of rows displayed.
|
||||||
|
|
||||||
|
In the example below, we have the following response from the data source:
|
||||||
|
|
||||||
|
| Time | Metric | Value |
|
||||||
|
| ------------------- | ----------- | ----- |
|
||||||
|
| 2020-07-07 11:34:20 | Temperature | 25 |
|
||||||
|
| 2020-07-07 11:34:20 | Humidity | 22 |
|
||||||
|
| 2020-07-07 10:32:20 | Humidity | 29 |
|
||||||
|
| 2020-07-07 10:31:22 | Temperature | 22 |
|
||||||
|
| 2020-07-07 09:30:57 | Humidity | 33 |
|
||||||
|
| 2020-07-07 09:30:05 | Temperature | 19 |
|
||||||
|
|
||||||
|
Here is the result after adding a Limit transformation with a value of '3':
|
||||||
|
|
||||||
|
| Time | Metric | Value |
|
||||||
|
| ------------------- | ----------- | ----- |
|
||||||
|
| 2020-07-07 11:34:20 | Temperature | 25 |
|
||||||
|
| 2020-07-07 11:34:20 | Humidity | 22 |
|
||||||
|
| 2020-07-07 10:32:20 | Humidity | 29 |
|
||||||
|
@ -10,6 +10,7 @@ import { groupByTransformer } from './transformers/groupBy';
|
|||||||
import { groupingToMatrixTransformer } from './transformers/groupingToMatrix';
|
import { groupingToMatrixTransformer } from './transformers/groupingToMatrix';
|
||||||
import { histogramTransformer } from './transformers/histogram';
|
import { histogramTransformer } from './transformers/histogram';
|
||||||
import { labelsToFieldsTransformer } from './transformers/labelsToFields';
|
import { labelsToFieldsTransformer } from './transformers/labelsToFields';
|
||||||
|
import { limitTransformer } from './transformers/limit';
|
||||||
import { mergeTransformer } from './transformers/merge';
|
import { mergeTransformer } from './transformers/merge';
|
||||||
import { noopTransformer } from './transformers/noop';
|
import { noopTransformer } from './transformers/noop';
|
||||||
import { orderFieldsTransformer } from './transformers/order';
|
import { orderFieldsTransformer } from './transformers/order';
|
||||||
@ -45,4 +46,5 @@ export const standardTransformers = {
|
|||||||
histogramTransformer,
|
histogramTransformer,
|
||||||
convertFieldTypeTransformer,
|
convertFieldTypeTransformer,
|
||||||
groupingToMatrixTransformer,
|
groupingToMatrixTransformer,
|
||||||
|
limitTransformer,
|
||||||
};
|
};
|
||||||
|
@ -33,4 +33,5 @@ export enum DataTransformerID {
|
|||||||
joinByLabels = 'joinByLabels',
|
joinByLabels = 'joinByLabels',
|
||||||
extractFields = 'extractFields',
|
extractFields = 'extractFields',
|
||||||
groupingToMatrix = 'groupingToMatrix',
|
groupingToMatrix = 'groupingToMatrix',
|
||||||
|
limit = 'limit',
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
import { DataTransformerConfig } from '@grafana/data';
|
||||||
|
|
||||||
|
import { toDataFrame } from '../../dataframe/processDataFrame';
|
||||||
|
import { Field, FieldType } from '../../types';
|
||||||
|
import { mockTransformationsRegistry } from '../../utils/tests/mockTransformationsRegistry';
|
||||||
|
import { ArrayVector } from '../../vector';
|
||||||
|
import { transformDataFrame } from '../transformDataFrame';
|
||||||
|
|
||||||
|
import { DataTransformerID } from './ids';
|
||||||
|
import { limitTransformer, LimitTransformerOptions } from './limit';
|
||||||
|
|
||||||
|
describe('Limit transformer', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
mockTransformationsRegistry([limitTransformer]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should limit the number of items', async () => {
|
||||||
|
const testSeries = toDataFrame({
|
||||||
|
name: 'A',
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [3000, 4000, 5000, 6000, 7000, 8000] },
|
||||||
|
{ name: 'message', type: FieldType.string, values: ['one', 'two', 'two', 'three', 'three', 'three'] },
|
||||||
|
{ name: 'values', type: FieldType.number, values: [1, 2, 2, 3, 3, 3] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const cfg: DataTransformerConfig<LimitTransformerOptions> = {
|
||||||
|
id: DataTransformerID.limit,
|
||||||
|
options: {
|
||||||
|
limitField: 3,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await expect(transformDataFrame([cfg], [testSeries])).toEmitValuesWith((received) => {
|
||||||
|
const result = received[0];
|
||||||
|
const expected: Field[] = [
|
||||||
|
{
|
||||||
|
name: 'time',
|
||||||
|
type: FieldType.time,
|
||||||
|
values: new ArrayVector([3000, 4000, 5000]),
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'message',
|
||||||
|
type: FieldType.string,
|
||||||
|
values: new ArrayVector(['one', 'two', 'two']),
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'values',
|
||||||
|
type: FieldType.number,
|
||||||
|
values: new ArrayVector([1, 2, 2]),
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(result[0].fields).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not limit the number of items if limit > number of items', async () => {
|
||||||
|
const testSeries = toDataFrame({
|
||||||
|
name: 'A',
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [3000, 4000, 5000, 6000, 7000, 8000] },
|
||||||
|
{ name: 'message', type: FieldType.string, values: ['one', 'two', 'two', 'three', 'three', 'three'] },
|
||||||
|
{ name: 'values', type: FieldType.number, values: [1, 2, 2, 3, 3, 3] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const cfg: DataTransformerConfig<LimitTransformerOptions> = {
|
||||||
|
id: DataTransformerID.limit,
|
||||||
|
options: {
|
||||||
|
limitField: 7,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await expect(transformDataFrame([cfg], [testSeries])).toEmitValuesWith((received) => {
|
||||||
|
const result = received[0];
|
||||||
|
const expected: Field[] = [
|
||||||
|
{
|
||||||
|
name: 'time',
|
||||||
|
type: FieldType.time,
|
||||||
|
values: new ArrayVector([3000, 4000, 5000, 6000, 7000, 8000]),
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'message',
|
||||||
|
type: FieldType.string,
|
||||||
|
values: new ArrayVector(['one', 'two', 'two', 'three', 'three', 'three']),
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'values',
|
||||||
|
type: FieldType.number,
|
||||||
|
values: new ArrayVector([1, 2, 2, 3, 3, 3]),
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(result[0].fields).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,45 @@
|
|||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { DataTransformerInfo } from '../../types';
|
||||||
|
import { ArrayVector } from '../../vector/ArrayVector';
|
||||||
|
|
||||||
|
import { DataTransformerID } from './ids';
|
||||||
|
|
||||||
|
export interface LimitTransformerOptions {
|
||||||
|
limitField?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_LIMIT_FIELD = 10;
|
||||||
|
|
||||||
|
export const limitTransformer: DataTransformerInfo<LimitTransformerOptions> = {
|
||||||
|
id: DataTransformerID.limit,
|
||||||
|
name: 'Limit',
|
||||||
|
description: 'Limit the number of items to the top N',
|
||||||
|
defaultOptions: {
|
||||||
|
limitField: DEFAULT_LIMIT_FIELD,
|
||||||
|
},
|
||||||
|
|
||||||
|
operator: (options) => (source) =>
|
||||||
|
source.pipe(
|
||||||
|
map((data) => {
|
||||||
|
const limitFieldMatch = options.limitField || DEFAULT_LIMIT_FIELD;
|
||||||
|
return data.map((frame) => {
|
||||||
|
if (frame.length > limitFieldMatch) {
|
||||||
|
return {
|
||||||
|
...frame,
|
||||||
|
fields: frame.fields.map((f) => {
|
||||||
|
const vals = f.values.toArray();
|
||||||
|
return {
|
||||||
|
...f,
|
||||||
|
values: new ArrayVector(vals.slice(0, limitFieldMatch)),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
length: limitFieldMatch,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
),
|
||||||
|
};
|
@ -0,0 +1,44 @@
|
|||||||
|
import React, { FormEvent, useCallback } from 'react';
|
||||||
|
|
||||||
|
import { DataTransformerID, standardTransformers, TransformerRegistryItem, TransformerUIProps } from '@grafana/data';
|
||||||
|
import { LimitTransformerOptions } from '@grafana/data/src/transformations/transformers/limit';
|
||||||
|
import { InlineField, InlineFieldRow, Input } from '@grafana/ui';
|
||||||
|
|
||||||
|
export const LimitTransformerEditor: React.FC<TransformerUIProps<LimitTransformerOptions>> = ({
|
||||||
|
options,
|
||||||
|
onChange,
|
||||||
|
}) => {
|
||||||
|
const onSetLimit = useCallback(
|
||||||
|
(value: FormEvent<HTMLInputElement>) => {
|
||||||
|
onChange({
|
||||||
|
...options,
|
||||||
|
limitField: Number(value.currentTarget.value),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[onChange, options]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<InlineFieldRow>
|
||||||
|
<InlineField label="Limit" labelWidth={8}>
|
||||||
|
<Input
|
||||||
|
placeholder="Limit count"
|
||||||
|
pattern="[0-9]*"
|
||||||
|
value={options.limitField}
|
||||||
|
onChange={onSetLimit}
|
||||||
|
width={25}
|
||||||
|
/>
|
||||||
|
</InlineField>
|
||||||
|
</InlineFieldRow>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const limitTransformRegistryItem: TransformerRegistryItem<LimitTransformerOptions> = {
|
||||||
|
id: DataTransformerID.limit,
|
||||||
|
editor: LimitTransformerEditor,
|
||||||
|
transformation: standardTransformers.limitTransformer,
|
||||||
|
name: 'Limit',
|
||||||
|
description: `Limit the number of items displayed.`,
|
||||||
|
};
|
@ -12,6 +12,7 @@ import { groupByTransformRegistryItem } from './editors/GroupByTransformerEditor
|
|||||||
import { groupingToMatrixTransformRegistryItem } from './editors/GroupingToMatrixTransformerEditor';
|
import { groupingToMatrixTransformRegistryItem } from './editors/GroupingToMatrixTransformerEditor';
|
||||||
import { histogramTransformRegistryItem } from './editors/HistogramTransformerEditor';
|
import { histogramTransformRegistryItem } from './editors/HistogramTransformerEditor';
|
||||||
import { labelsToFieldsTransformerRegistryItem } from './editors/LabelsToFieldsTransformerEditor';
|
import { labelsToFieldsTransformerRegistryItem } from './editors/LabelsToFieldsTransformerEditor';
|
||||||
|
import { limitTransformRegistryItem } from './editors/LimitTransformerEditor';
|
||||||
import { mergeTransformerRegistryItem } from './editors/MergeTransformerEditor';
|
import { mergeTransformerRegistryItem } from './editors/MergeTransformerEditor';
|
||||||
import { organizeFieldsTransformRegistryItem } from './editors/OrganizeFieldsTransformerEditor';
|
import { organizeFieldsTransformRegistryItem } from './editors/OrganizeFieldsTransformerEditor';
|
||||||
import { reduceTransformRegistryItem } from './editors/ReduceTransformerEditor';
|
import { reduceTransformRegistryItem } from './editors/ReduceTransformerEditor';
|
||||||
@ -52,6 +53,7 @@ export const getStandardTransformers = (): Array<TransformerRegistryItem<any>> =
|
|||||||
extractFieldsTransformRegistryItem,
|
extractFieldsTransformRegistryItem,
|
||||||
heatmapTransformRegistryItem,
|
heatmapTransformRegistryItem,
|
||||||
groupingToMatrixTransformRegistryItem,
|
groupingToMatrixTransformRegistryItem,
|
||||||
|
limitTransformRegistryItem,
|
||||||
joinByLabelsTransformRegistryItem,
|
joinByLabelsTransformRegistryItem,
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user