mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Decouple from Prometheus operationUtils (#78830)
* Loki: Decouple from Prometheus operationUtils * Update comments
This commit is contained in:
parent
4d375aa5d4
commit
ed86583107
@ -5861,6 +5861,9 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Styles should be written using objects.", "17"],
|
[0, 0, 0, "Styles should be written using objects.", "17"],
|
||||||
[0, 0, 0, "Styles should be written using objects.", "18"]
|
[0, 0, 0, "Styles should be written using objects.", "18"]
|
||||||
],
|
],
|
||||||
|
"public/app/plugins/datasource/prometheus/querybuilder/operationUtils.ts:5381": [
|
||||||
|
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||||
|
],
|
||||||
"public/app/plugins/datasource/prometheus/querybuilder/shared/LabelFilterItem.tsx:5381": [
|
"public/app/plugins/datasource/prometheus/querybuilder/shared/LabelFilterItem.tsx:5381": [
|
||||||
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"],
|
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"],
|
||||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||||
@ -5889,9 +5892,6 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Styles should be written using objects.", "0"],
|
[0, 0, 0, "Styles should be written using objects.", "0"],
|
||||||
[0, 0, 0, "Styles should be written using objects.", "1"]
|
[0, 0, 0, "Styles should be written using objects.", "1"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/prometheus/querybuilder/shared/operationUtils.ts:5381": [
|
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
|
||||||
],
|
|
||||||
"public/app/plugins/datasource/prometheus/querybuilder/shared/parsingUtils.ts:5381": [
|
"public/app/plugins/datasource/prometheus/querybuilder/shared/parsingUtils.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { defaultAddOperationHandler } from '../../prometheus/querybuilder/shared/operationUtils';
|
|
||||||
import {
|
import {
|
||||||
QueryBuilderOperation,
|
QueryBuilderOperation,
|
||||||
QueryBuilderOperationDef,
|
QueryBuilderOperationDef,
|
||||||
QueryBuilderOperationParamDef,
|
QueryBuilderOperationParamDef,
|
||||||
} from '../../prometheus/querybuilder/shared/types';
|
} from '../../prometheus/querybuilder/shared/types';
|
||||||
|
|
||||||
|
import { defaultAddOperationHandler } from './operationUtils';
|
||||||
import { LokiOperationId, LokiVisualQueryOperationCategory } from './types';
|
import { LokiOperationId, LokiVisualQueryOperationCategory } from './types';
|
||||||
|
|
||||||
export const binaryScalarDefs = [
|
export const binaryScalarDefs = [
|
||||||
|
@ -3,13 +3,13 @@ import React, { useState } from 'react';
|
|||||||
import { SelectableValue, getDefaultTimeRange, toOption } from '@grafana/data';
|
import { SelectableValue, getDefaultTimeRange, toOption } from '@grafana/data';
|
||||||
import { Select } from '@grafana/ui';
|
import { Select } from '@grafana/ui';
|
||||||
|
|
||||||
import { getOperationParamId } from '../../../prometheus/querybuilder/shared/operationUtils';
|
|
||||||
import { QueryBuilderOperationParamEditorProps } from '../../../prometheus/querybuilder/shared/types';
|
import { QueryBuilderOperationParamEditorProps } from '../../../prometheus/querybuilder/shared/types';
|
||||||
import { placeHolderScopedVars } from '../../components/monaco-query-field/monaco-completion-provider/validation';
|
import { placeHolderScopedVars } from '../../components/monaco-query-field/monaco-completion-provider/validation';
|
||||||
import { LokiDatasource } from '../../datasource';
|
import { LokiDatasource } from '../../datasource';
|
||||||
import { getLogQueryFromMetricsQuery, isQueryWithError } from '../../queryUtils';
|
import { getLogQueryFromMetricsQuery, isQueryWithError } from '../../queryUtils';
|
||||||
import { extractUnwrapLabelKeysFromDataFrame } from '../../responseUtils';
|
import { extractUnwrapLabelKeysFromDataFrame } from '../../responseUtils';
|
||||||
import { lokiQueryModeller } from '../LokiQueryModeller';
|
import { lokiQueryModeller } from '../LokiQueryModeller';
|
||||||
|
import { getOperationParamId } from '../operationUtils';
|
||||||
import { LokiVisualQuery } from '../types';
|
import { LokiVisualQuery } from '../types';
|
||||||
|
|
||||||
export function UnwrapParamEditor({
|
export function UnwrapParamEditor({
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { QueryBuilderOperation, QueryBuilderOperationDef } from '../../prometheus/querybuilder/shared/types';
|
import { QueryBuilderOperation, QueryBuilderOperationDef } from '../../prometheus/querybuilder/shared/types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
createAggregationOperation,
|
||||||
|
createAggregationOperationWithParam,
|
||||||
createRangeOperation,
|
createRangeOperation,
|
||||||
createRangeOperationWithGrouping,
|
createRangeOperationWithGrouping,
|
||||||
getLineFilterRenderer,
|
getLineFilterRenderer,
|
||||||
@ -322,3 +324,168 @@ describe('pipelineRenderer', () => {
|
|||||||
expect(pipelineRenderer(model, definition!, '{}')).toBe('{} | drop foo, bar, baz');
|
expect(pipelineRenderer(model, definition!, '{}')).toBe('{} | drop foo, bar, baz');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('createAggregationOperation', () => {
|
||||||
|
it('returns correct aggregation definitions with overrides', () => {
|
||||||
|
expect(createAggregationOperation('test_aggregation', { category: 'test_category' })).toMatchObject([
|
||||||
|
{
|
||||||
|
addOperationHandler: {},
|
||||||
|
alternativesKey: 'plain aggregations',
|
||||||
|
category: 'test_category',
|
||||||
|
defaultParams: [],
|
||||||
|
explainHandler: {},
|
||||||
|
id: 'test_aggregation',
|
||||||
|
name: 'Test aggregation',
|
||||||
|
paramChangedHandler: {},
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
name: 'By label',
|
||||||
|
optional: true,
|
||||||
|
restParam: true,
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
renderer: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
alternativesKey: 'aggregations by',
|
||||||
|
category: 'test_category',
|
||||||
|
defaultParams: [''],
|
||||||
|
explainHandler: {},
|
||||||
|
hideFromList: true,
|
||||||
|
id: '__test_aggregation_by',
|
||||||
|
name: 'Test aggregation by',
|
||||||
|
paramChangedHandler: {},
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
editor: {},
|
||||||
|
name: 'Label',
|
||||||
|
optional: true,
|
||||||
|
restParam: true,
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
renderer: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
alternativesKey: 'aggregations by',
|
||||||
|
category: 'test_category',
|
||||||
|
defaultParams: [''],
|
||||||
|
explainHandler: {},
|
||||||
|
hideFromList: true,
|
||||||
|
id: '__test_aggregation_without',
|
||||||
|
name: 'Test aggregation without',
|
||||||
|
paramChangedHandler: {},
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
name: 'Label',
|
||||||
|
optional: true,
|
||||||
|
restParam: true,
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
renderer: {},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createAggregationOperationWithParams', () => {
|
||||||
|
it('returns correct aggregation definitions with overrides and params', () => {
|
||||||
|
expect(
|
||||||
|
createAggregationOperationWithParam(
|
||||||
|
'test_aggregation',
|
||||||
|
{
|
||||||
|
params: [{ name: 'K-value', type: 'number' }],
|
||||||
|
defaultParams: [5],
|
||||||
|
},
|
||||||
|
{ category: 'test_category' }
|
||||||
|
)
|
||||||
|
).toMatchObject([
|
||||||
|
{
|
||||||
|
addOperationHandler: {},
|
||||||
|
alternativesKey: 'plain aggregations',
|
||||||
|
category: 'test_category',
|
||||||
|
defaultParams: [5],
|
||||||
|
explainHandler: {},
|
||||||
|
id: 'test_aggregation',
|
||||||
|
name: 'Test aggregation',
|
||||||
|
paramChangedHandler: {},
|
||||||
|
params: [
|
||||||
|
{ name: 'K-value', type: 'number' },
|
||||||
|
{ name: 'By label', optional: true, restParam: true, type: 'string' },
|
||||||
|
],
|
||||||
|
renderer: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
alternativesKey: 'aggregations by',
|
||||||
|
category: 'test_category',
|
||||||
|
defaultParams: [5, ''],
|
||||||
|
explainHandler: {},
|
||||||
|
hideFromList: true,
|
||||||
|
id: '__test_aggregation_by',
|
||||||
|
name: 'Test aggregation by',
|
||||||
|
paramChangedHandler: {},
|
||||||
|
params: [
|
||||||
|
{ name: 'K-value', type: 'number' },
|
||||||
|
{ editor: {}, name: 'Label', optional: true, restParam: true, type: 'string' },
|
||||||
|
],
|
||||||
|
renderer: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
alternativesKey: 'aggregations by',
|
||||||
|
category: 'test_category',
|
||||||
|
defaultParams: [5, ''],
|
||||||
|
explainHandler: {},
|
||||||
|
hideFromList: true,
|
||||||
|
id: '__test_aggregation_without',
|
||||||
|
name: 'Test aggregation without',
|
||||||
|
paramChangedHandler: {},
|
||||||
|
params: [
|
||||||
|
{ name: 'K-value', type: 'number' },
|
||||||
|
{ name: 'Label', optional: true, restParam: true, type: 'string' },
|
||||||
|
],
|
||||||
|
renderer: {},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('returns correct query string using aggregation definitions with overrides and number type param', () => {
|
||||||
|
const def = createAggregationOperationWithParam(
|
||||||
|
'test_aggregation',
|
||||||
|
{
|
||||||
|
params: [{ name: 'K-value', type: 'number' }],
|
||||||
|
defaultParams: [5],
|
||||||
|
},
|
||||||
|
{ category: 'test_category' }
|
||||||
|
);
|
||||||
|
|
||||||
|
const topKByDefinition = def[1];
|
||||||
|
expect(
|
||||||
|
topKByDefinition.renderer(
|
||||||
|
{ id: '__topk_by', params: ['5', 'source', 'place'] },
|
||||||
|
def[1],
|
||||||
|
'rate({place="luna"} |= `` [5m])'
|
||||||
|
)
|
||||||
|
).toBe('test_aggregation by(source, place) (5, rate({place="luna"} |= `` [5m]))');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct query string using aggregation definitions with overrides and string type param', () => {
|
||||||
|
const def = createAggregationOperationWithParam(
|
||||||
|
'test_aggregation',
|
||||||
|
{
|
||||||
|
params: [{ name: 'Identifier', type: 'string' }],
|
||||||
|
defaultParams: ['count'],
|
||||||
|
},
|
||||||
|
{ category: 'test_category' }
|
||||||
|
);
|
||||||
|
|
||||||
|
const countValueDefinition = def[1];
|
||||||
|
expect(
|
||||||
|
countValueDefinition.renderer(
|
||||||
|
{ id: 'count_values', params: ['5', 'source', 'place'] },
|
||||||
|
def[1],
|
||||||
|
'rate({place="luna"} |= `` [5m])'
|
||||||
|
)
|
||||||
|
).toBe('test_aggregation by(source, place) ("5", rate({place="luna"} |= `` [5m]))');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
|
import { capitalize } from 'lodash';
|
||||||
|
import pluralize from 'pluralize';
|
||||||
|
|
||||||
import { LabelParamEditor } from '../../prometheus/querybuilder/components/LabelParamEditor';
|
import { LabelParamEditor } from '../../prometheus/querybuilder/components/LabelParamEditor';
|
||||||
import {
|
|
||||||
getAggregationExplainer,
|
|
||||||
getLastLabelRemovedHandler,
|
|
||||||
getOnLabelAddedHandler,
|
|
||||||
getPromAndLokiOperationDisplayName,
|
|
||||||
} from '../../prometheus/querybuilder/shared/operationUtils';
|
|
||||||
import {
|
import {
|
||||||
QueryBuilderOperation,
|
QueryBuilderOperation,
|
||||||
QueryBuilderOperationDef,
|
QueryBuilderOperationDef,
|
||||||
QueryBuilderOperationParamDef,
|
QueryBuilderOperationParamDef,
|
||||||
|
QueryBuilderOperationParamValue,
|
||||||
|
QueryWithOperations,
|
||||||
VisualQueryModeller,
|
VisualQueryModeller,
|
||||||
} from '../../prometheus/querybuilder/shared/types';
|
} from '../../prometheus/querybuilder/shared/types';
|
||||||
import { FUNCTIONS } from '../syntax';
|
import { FUNCTIONS } from '../syntax';
|
||||||
@ -41,7 +40,7 @@ export function createRangeOperation(name: string, isRangeOperationWithGrouping?
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
id: name,
|
id: name,
|
||||||
name: getPromAndLokiOperationDisplayName(name),
|
name: getLokiOperationDisplayName(name),
|
||||||
params: params,
|
params: params,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
alternativesKey: 'range function',
|
alternativesKey: 'range function',
|
||||||
@ -70,7 +69,7 @@ export function createRangeOperationWithGrouping(name: string): QueryBuilderOper
|
|||||||
rangeOperation,
|
rangeOperation,
|
||||||
{
|
{
|
||||||
id: `__${name}_by`,
|
id: `__${name}_by`,
|
||||||
name: `${getPromAndLokiOperationDisplayName(name)} by`,
|
name: `${getLokiOperationDisplayName(name)} by`,
|
||||||
params: [
|
params: [
|
||||||
...params,
|
...params,
|
||||||
{
|
{
|
||||||
@ -92,7 +91,7 @@ export function createRangeOperationWithGrouping(name: string): QueryBuilderOper
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: `__${name}_without`,
|
id: `__${name}_without`,
|
||||||
name: `${getPromAndLokiOperationDisplayName(name)} without`,
|
name: `${getLokiOperationDisplayName(name)} without`,
|
||||||
params: [
|
params: [
|
||||||
...params,
|
...params,
|
||||||
{
|
{
|
||||||
@ -309,3 +308,212 @@ function getRangeVectorParamDef(): QueryBuilderOperationParamDef {
|
|||||||
options: ['$__auto', '1m', '5m', '10m', '1h', '24h'],
|
options: ['$__auto', '1m', '5m', '10m', '1h', '24h'],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getOperationParamId(operationId: string, paramIndex: number) {
|
||||||
|
return `operations.${operationId}.param.${paramIndex}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getOnLabelAddedHandler(changeToOperationId: string) {
|
||||||
|
return function onParamChanged(index: number, op: QueryBuilderOperation, def: QueryBuilderOperationDef) {
|
||||||
|
// Check if we actually have the label param. As it's optional the aggregation can have one less, which is the
|
||||||
|
// case of just simple aggregation without label. When user adds the label it now has the same number of params
|
||||||
|
// as its definition, and now we can change it to its `_by` variant.
|
||||||
|
if (op.params.length === def.params.length) {
|
||||||
|
return {
|
||||||
|
...op,
|
||||||
|
id: changeToOperationId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return op;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Very simple poc implementation, needs to be modified to support all aggregation operators
|
||||||
|
*/
|
||||||
|
export function getAggregationExplainer(aggregationName: string, mode: 'by' | 'without' | '') {
|
||||||
|
return function aggregationExplainer(model: QueryBuilderOperation) {
|
||||||
|
const labels = model.params.map((label) => `\`${label}\``).join(' and ');
|
||||||
|
const labelWord = pluralize('label', model.params.length);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 'by':
|
||||||
|
return `Calculates ${aggregationName} over dimensions while preserving ${labelWord} ${labels}.`;
|
||||||
|
case 'without':
|
||||||
|
return `Calculates ${aggregationName} over the dimensions ${labels}. All other labels are preserved.`;
|
||||||
|
default:
|
||||||
|
return `Calculates ${aggregationName} over the dimensions.`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will transform operations without labels to their plan aggregation operation
|
||||||
|
*/
|
||||||
|
export function getLastLabelRemovedHandler(changeToOperationId: string) {
|
||||||
|
return function onParamChanged(index: number, op: QueryBuilderOperation, def: QueryBuilderOperationDef) {
|
||||||
|
// If definition has more params then is defined there are no optional rest params anymore.
|
||||||
|
// We then transform this operation into a different one
|
||||||
|
if (op.params.length < def.params.length) {
|
||||||
|
return {
|
||||||
|
...op,
|
||||||
|
id: changeToOperationId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return op;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLokiOperationDisplayName(funcName: string) {
|
||||||
|
return capitalize(funcName.replace(/_/g, ' '));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function defaultAddOperationHandler<T extends QueryWithOperations>(def: QueryBuilderOperationDef, query: T) {
|
||||||
|
const newOperation: QueryBuilderOperation = {
|
||||||
|
id: def.id,
|
||||||
|
params: def.defaultParams,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...query,
|
||||||
|
operations: [...query.operations, newOperation],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAggregationOperation(
|
||||||
|
name: string,
|
||||||
|
overrides: Partial<QueryBuilderOperationDef> = {}
|
||||||
|
): QueryBuilderOperationDef[] {
|
||||||
|
const operations: QueryBuilderOperationDef[] = [
|
||||||
|
{
|
||||||
|
id: name,
|
||||||
|
name: getLokiOperationDisplayName(name),
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
name: 'By label',
|
||||||
|
type: 'string',
|
||||||
|
restParam: true,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultParams: [],
|
||||||
|
alternativesKey: 'plain aggregations',
|
||||||
|
category: LokiVisualQueryOperationCategory.Aggregations,
|
||||||
|
renderer: functionRendererLeft,
|
||||||
|
paramChangedHandler: getOnLabelAddedHandler(`__${name}_by`),
|
||||||
|
explainHandler: getAggregationExplainer(name, ''),
|
||||||
|
addOperationHandler: defaultAddOperationHandler,
|
||||||
|
...overrides,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: `__${name}_by`,
|
||||||
|
name: `${getLokiOperationDisplayName(name)} by`,
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
name: 'Label',
|
||||||
|
type: 'string',
|
||||||
|
restParam: true,
|
||||||
|
optional: true,
|
||||||
|
editor: LabelParamEditor,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultParams: [''],
|
||||||
|
alternativesKey: 'aggregations by',
|
||||||
|
category: LokiVisualQueryOperationCategory.Aggregations,
|
||||||
|
renderer: getAggregationByRenderer(name),
|
||||||
|
paramChangedHandler: getLastLabelRemovedHandler(name),
|
||||||
|
explainHandler: getAggregationExplainer(name, 'by'),
|
||||||
|
addOperationHandler: defaultAddOperationHandler,
|
||||||
|
hideFromList: true,
|
||||||
|
...overrides,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: `__${name}_without`,
|
||||||
|
name: `${getLokiOperationDisplayName(name)} without`,
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
name: 'Label',
|
||||||
|
type: 'string',
|
||||||
|
restParam: true,
|
||||||
|
optional: true,
|
||||||
|
editor: LabelParamEditor,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultParams: [''],
|
||||||
|
alternativesKey: 'aggregations by',
|
||||||
|
category: LokiVisualQueryOperationCategory.Aggregations,
|
||||||
|
renderer: getAggregationWithoutRenderer(name),
|
||||||
|
paramChangedHandler: getLastLabelRemovedHandler(name),
|
||||||
|
explainHandler: getAggregationExplainer(name, 'without'),
|
||||||
|
addOperationHandler: defaultAddOperationHandler,
|
||||||
|
hideFromList: true,
|
||||||
|
...overrides,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAggregationWithoutRenderer(aggregation: string) {
|
||||||
|
return function aggregationRenderer(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
||||||
|
return `${aggregation} without(${model.params.join(', ')}) (${innerExpr})`;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function functionRendererLeft(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
||||||
|
const params = renderParams(model, def, innerExpr);
|
||||||
|
const str = model.id + '(';
|
||||||
|
|
||||||
|
if (innerExpr) {
|
||||||
|
params.push(innerExpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str + params.join(', ') + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderParams(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
||||||
|
return (model.params ?? []).map((value, index) => {
|
||||||
|
const paramDef = def.params[index];
|
||||||
|
if (paramDef.type === 'string') {
|
||||||
|
return '"' + value + '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAggregationByRenderer(aggregation: string) {
|
||||||
|
return function aggregationRenderer(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
||||||
|
return `${aggregation} by(${model.params.join(', ')}) (${innerExpr})`;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAggregationOperationWithParam(
|
||||||
|
name: string,
|
||||||
|
paramsDef: { params: QueryBuilderOperationParamDef[]; defaultParams: QueryBuilderOperationParamValue[] },
|
||||||
|
overrides: Partial<QueryBuilderOperationDef> = {}
|
||||||
|
): QueryBuilderOperationDef[] {
|
||||||
|
const operations = createAggregationOperation(name, overrides);
|
||||||
|
operations[0].params.unshift(...paramsDef.params);
|
||||||
|
operations[1].params.unshift(...paramsDef.params);
|
||||||
|
operations[2].params.unshift(...paramsDef.params);
|
||||||
|
operations[0].defaultParams = paramsDef.defaultParams;
|
||||||
|
operations[1].defaultParams = [...paramsDef.defaultParams, ''];
|
||||||
|
operations[2].defaultParams = [...paramsDef.defaultParams, ''];
|
||||||
|
operations[1].renderer = getAggregationByRendererWithParameter(name);
|
||||||
|
operations[2].renderer = getAggregationByRendererWithParameter(name);
|
||||||
|
return operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAggregationByRendererWithParameter(aggregation: string) {
|
||||||
|
return function aggregationRenderer(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
||||||
|
const restParamIndex = def.params.findIndex((param) => param.restParam);
|
||||||
|
const params = model.params.slice(0, restParamIndex);
|
||||||
|
const restParams = model.params.slice(restParamIndex);
|
||||||
|
|
||||||
|
return `${aggregation} by(${restParams.join(', ')}) (${params
|
||||||
|
.map((param, idx) => (def.params[idx].type === 'string' ? `\"${param}\"` : param))
|
||||||
|
.join(', ')}, ${innerExpr})`;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
import {
|
|
||||||
createAggregationOperation,
|
|
||||||
createAggregationOperationWithParam,
|
|
||||||
} from '../../prometheus/querybuilder/shared/operationUtils';
|
|
||||||
import { QueryBuilderOperationDef, QueryBuilderOperationParamValue } from '../../prometheus/querybuilder/shared/types';
|
import { QueryBuilderOperationDef, QueryBuilderOperationParamValue } from '../../prometheus/querybuilder/shared/types';
|
||||||
|
|
||||||
import { binaryScalarOperations } from './binaryScalarOperations';
|
import { binaryScalarOperations } from './binaryScalarOperations';
|
||||||
@ -9,6 +5,8 @@ import { UnwrapParamEditor } from './components/UnwrapParamEditor';
|
|||||||
import {
|
import {
|
||||||
addLokiOperation,
|
addLokiOperation,
|
||||||
addNestedQueryHandler,
|
addNestedQueryHandler,
|
||||||
|
createAggregationOperation,
|
||||||
|
createAggregationOperationWithParam,
|
||||||
createRangeOperation,
|
createRangeOperation,
|
||||||
createRangeOperationWithGrouping,
|
createRangeOperationWithGrouping,
|
||||||
getLineFilterRenderer,
|
getLineFilterRenderer,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { addOperationWithRangeVector } from './operations';
|
|
||||||
import {
|
import {
|
||||||
createAggregationOperation,
|
createAggregationOperation,
|
||||||
createAggregationOperationWithParam,
|
createAggregationOperationWithParam,
|
||||||
getPromAndLokiOperationDisplayName,
|
getPromOperationDisplayName,
|
||||||
getRangeVectorParamDef,
|
getRangeVectorParamDef,
|
||||||
} from './shared/operationUtils';
|
} from './operationUtils';
|
||||||
|
import { addOperationWithRangeVector } from './operations';
|
||||||
import { QueryBuilderOperation, QueryBuilderOperationDef } from './shared/types';
|
import { QueryBuilderOperation, QueryBuilderOperationDef } from './shared/types';
|
||||||
import { PromVisualQueryOperationCategory, PromOperationId } from './types';
|
import { PromVisualQueryOperationCategory, PromOperationId } from './types';
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ export function getAggregationOperations(): QueryBuilderOperationDef[] {
|
|||||||
function createAggregationOverTime(name: string): QueryBuilderOperationDef {
|
function createAggregationOverTime(name: string): QueryBuilderOperationDef {
|
||||||
return {
|
return {
|
||||||
id: name,
|
id: name,
|
||||||
name: getPromAndLokiOperationDisplayName(name),
|
name: getPromOperationDisplayName(name),
|
||||||
params: [getRangeVectorParamDef()],
|
params: [getRangeVectorParamDef()],
|
||||||
defaultParams: ['$__interval'],
|
defaultParams: ['$__interval'],
|
||||||
alternativesKey: 'overtime function',
|
alternativesKey: 'overtime function',
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { defaultAddOperationHandler } from './shared/operationUtils';
|
import { defaultAddOperationHandler } from './operationUtils';
|
||||||
import { QueryBuilderOperation, QueryBuilderOperationDef, QueryBuilderOperationParamDef } from './shared/types';
|
import { QueryBuilderOperation, QueryBuilderOperationDef, QueryBuilderOperationParamDef } from './shared/types';
|
||||||
import { PromOperationId, PromVisualQueryOperationCategory } from './types';
|
import { PromOperationId, PromVisualQueryOperationCategory } from './types';
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { DataSourceApi, SelectableValue, toOption } from '@grafana/data';
|
|||||||
import { Select } from '@grafana/ui';
|
import { Select } from '@grafana/ui';
|
||||||
|
|
||||||
import { promQueryModeller } from '../PromQueryModeller';
|
import { promQueryModeller } from '../PromQueryModeller';
|
||||||
import { getOperationParamId } from '../shared/operationUtils';
|
import { getOperationParamId } from '../operationUtils';
|
||||||
import { QueryBuilderLabelFilter, QueryBuilderOperationParamEditorProps } from '../shared/types';
|
import { QueryBuilderLabelFilter, QueryBuilderOperationParamEditorProps } from '../shared/types';
|
||||||
import { PromVisualQuery } from '../types';
|
import { PromVisualQuery } from '../types';
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@ import { PrometheusDatasource } from '../../datasource';
|
|||||||
import PromQlLanguageProvider from '../../language_provider';
|
import PromQlLanguageProvider from '../../language_provider';
|
||||||
import { EmptyLanguageProviderMock } from '../../language_provider.mock';
|
import { EmptyLanguageProviderMock } from '../../language_provider.mock';
|
||||||
import { PromQuery } from '../../types';
|
import { PromQuery } from '../../types';
|
||||||
|
import { getOperationParamId } from '../operationUtils';
|
||||||
import { addOperation } from '../shared/OperationList.testUtils';
|
import { addOperation } from '../shared/OperationList.testUtils';
|
||||||
import { getOperationParamId } from '../shared/operationUtils';
|
|
||||||
|
|
||||||
import { PromQueryBuilderContainer } from './PromQueryBuilderContainer';
|
import { PromQueryBuilderContainer } from './PromQueryBuilderContainer';
|
||||||
|
|
||||||
|
@ -3,9 +3,7 @@ import pluralize from 'pluralize';
|
|||||||
|
|
||||||
import { SelectableValue } from '@grafana/data/src';
|
import { SelectableValue } from '@grafana/data/src';
|
||||||
|
|
||||||
import { LabelParamEditor } from '../components/LabelParamEditor';
|
import { LabelParamEditor } from './components/LabelParamEditor';
|
||||||
import { PromVisualQueryOperationCategory } from '../types';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
QueryBuilderLabelFilter,
|
QueryBuilderLabelFilter,
|
||||||
QueryBuilderOperation,
|
QueryBuilderOperation,
|
||||||
@ -13,7 +11,8 @@ import {
|
|||||||
QueryBuilderOperationParamDef,
|
QueryBuilderOperationParamDef,
|
||||||
QueryBuilderOperationParamValue,
|
QueryBuilderOperationParamValue,
|
||||||
QueryWithOperations,
|
QueryWithOperations,
|
||||||
} from './types';
|
} from './shared/types';
|
||||||
|
import { PromVisualQueryOperationCategory } from './types';
|
||||||
|
|
||||||
export function functionRendererLeft(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
export function functionRendererLeft(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
||||||
const params = renderParams(model, def, innerExpr);
|
const params = renderParams(model, def, innerExpr);
|
||||||
@ -116,7 +115,7 @@ export function defaultAddOperationHandler<T extends QueryWithOperations>(def: Q
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPromAndLokiOperationDisplayName(funcName: string) {
|
export function getPromOperationDisplayName(funcName: string) {
|
||||||
return capitalize(funcName.replace(/_/g, ' '));
|
return capitalize(funcName.replace(/_/g, ' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,17 +152,14 @@ export function getRangeVectorParamDef(withRateInterval = false): QueryBuilderOp
|
|||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export function createAggregationOperation(
|
||||||
* This function is shared between Prometheus and Loki variants
|
|
||||||
*/
|
|
||||||
export function createAggregationOperation<T extends QueryWithOperations>(
|
|
||||||
name: string,
|
name: string,
|
||||||
overrides: Partial<QueryBuilderOperationDef> = {}
|
overrides: Partial<QueryBuilderOperationDef> = {}
|
||||||
): QueryBuilderOperationDef[] {
|
): QueryBuilderOperationDef[] {
|
||||||
const operations: QueryBuilderOperationDef[] = [
|
const operations: QueryBuilderOperationDef[] = [
|
||||||
{
|
{
|
||||||
id: name,
|
id: name,
|
||||||
name: getPromAndLokiOperationDisplayName(name),
|
name: getPromOperationDisplayName(name),
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'By label',
|
name: 'By label',
|
||||||
@ -183,7 +179,7 @@ export function createAggregationOperation<T extends QueryWithOperations>(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: `__${name}_by`,
|
id: `__${name}_by`,
|
||||||
name: `${getPromAndLokiOperationDisplayName(name)} by`,
|
name: `${getPromOperationDisplayName(name)} by`,
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'Label',
|
name: 'Label',
|
||||||
@ -205,7 +201,7 @@ export function createAggregationOperation<T extends QueryWithOperations>(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: `__${name}_without`,
|
id: `__${name}_without`,
|
||||||
name: `${getPromAndLokiOperationDisplayName(name)} without`,
|
name: `${getPromOperationDisplayName(name)} without`,
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'Label',
|
name: 'Label',
|
@ -4,11 +4,11 @@ import {
|
|||||||
defaultAddOperationHandler,
|
defaultAddOperationHandler,
|
||||||
functionRendererLeft,
|
functionRendererLeft,
|
||||||
functionRendererRight,
|
functionRendererRight,
|
||||||
getPromAndLokiOperationDisplayName,
|
getPromOperationDisplayName,
|
||||||
getRangeVectorParamDef,
|
getRangeVectorParamDef,
|
||||||
rangeRendererLeftWithParams,
|
rangeRendererLeftWithParams,
|
||||||
rangeRendererRightWithParams,
|
rangeRendererRightWithParams,
|
||||||
} from './shared/operationUtils';
|
} from './operationUtils';
|
||||||
import {
|
import {
|
||||||
QueryBuilderOperation,
|
QueryBuilderOperation,
|
||||||
QueryBuilderOperationDef,
|
QueryBuilderOperationDef,
|
||||||
@ -265,7 +265,7 @@ export function createFunction(definition: Partial<QueryBuilderOperationDef>): Q
|
|||||||
return {
|
return {
|
||||||
...definition,
|
...definition,
|
||||||
id: definition.id!,
|
id: definition.id!,
|
||||||
name: definition.name ?? getPromAndLokiOperationDisplayName(definition.id!),
|
name: definition.name ?? getPromOperationDisplayName(definition.id!),
|
||||||
params: definition.params ?? [],
|
params: definition.params ?? [],
|
||||||
defaultParams: definition.defaultParams ?? [],
|
defaultParams: definition.defaultParams ?? [],
|
||||||
category: definition.category ?? PromVisualQueryOperationCategory.Functions,
|
category: definition.category ?? PromVisualQueryOperationCategory.Functions,
|
||||||
@ -277,7 +277,7 @@ export function createFunction(definition: Partial<QueryBuilderOperationDef>): Q
|
|||||||
export function createRangeFunction(name: string, withRateInterval = false): QueryBuilderOperationDef {
|
export function createRangeFunction(name: string, withRateInterval = false): QueryBuilderOperationDef {
|
||||||
return {
|
return {
|
||||||
id: name,
|
id: name,
|
||||||
name: getPromAndLokiOperationDisplayName(name),
|
name: getPromOperationDisplayName(name),
|
||||||
params: [getRangeVectorParamDef(withRateInterval)],
|
params: [getRangeVectorParamDef(withRateInterval)],
|
||||||
defaultParams: [withRateInterval ? '$__rate_interval' : '$__interval'],
|
defaultParams: [withRateInterval ? '$__rate_interval' : '$__interval'],
|
||||||
alternativesKey: 'range function',
|
alternativesKey: 'range function',
|
||||||
|
@ -7,7 +7,8 @@ import { AccessoryButton, InputGroup } from '@grafana/experimental';
|
|||||||
import { InlineField, Select } from '@grafana/ui';
|
import { InlineField, Select } from '@grafana/ui';
|
||||||
import { lokiOperators } from 'app/plugins/datasource/loki/querybuilder/types';
|
import { lokiOperators } from 'app/plugins/datasource/loki/querybuilder/types';
|
||||||
|
|
||||||
import { isConflictingSelector } from './operationUtils';
|
import { isConflictingSelector } from '../operationUtils';
|
||||||
|
|
||||||
import { QueryBuilderLabelFilter } from './types';
|
import { QueryBuilderLabelFilter } from './types';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
@ -7,9 +7,10 @@ import { Button, Icon, InlineField, Tooltip, useTheme2, Stack } from '@grafana/u
|
|||||||
import { isConflictingFilter } from 'app/plugins/datasource/loki/querybuilder/operationUtils';
|
import { isConflictingFilter } from 'app/plugins/datasource/loki/querybuilder/operationUtils';
|
||||||
import { LokiOperationId } from 'app/plugins/datasource/loki/querybuilder/types';
|
import { LokiOperationId } from 'app/plugins/datasource/loki/querybuilder/types';
|
||||||
|
|
||||||
|
import { getOperationParamId } from '../operationUtils';
|
||||||
|
|
||||||
import { OperationHeader } from './OperationHeader';
|
import { OperationHeader } from './OperationHeader';
|
||||||
import { getOperationParamEditor } from './OperationParamEditor';
|
import { getOperationParamEditor } from './OperationParamEditor';
|
||||||
import { getOperationParamId } from './operationUtils';
|
|
||||||
import {
|
import {
|
||||||
QueryBuilderOperation,
|
QueryBuilderOperation,
|
||||||
QueryBuilderOperationDef,
|
QueryBuilderOperationDef,
|
||||||
|
@ -4,10 +4,9 @@ import React, { ComponentType } from 'react';
|
|||||||
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
|
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
|
||||||
import { AutoSizeInput, Button, Checkbox, Select, useStyles2, Stack } from '@grafana/ui';
|
import { AutoSizeInput, Button, Checkbox, Select, useStyles2, Stack } from '@grafana/ui';
|
||||||
|
|
||||||
|
import { getOperationParamId } from '../operationUtils';
|
||||||
import { QueryBuilderOperationParamDef, QueryBuilderOperationParamEditorProps } from '../shared/types';
|
import { QueryBuilderOperationParamDef, QueryBuilderOperationParamEditorProps } from '../shared/types';
|
||||||
|
|
||||||
import { getOperationParamId } from './operationUtils';
|
|
||||||
|
|
||||||
export function getOperationParamEditor(
|
export function getOperationParamEditor(
|
||||||
paramDef: QueryBuilderOperationParamDef
|
paramDef: QueryBuilderOperationParamDef
|
||||||
): ComponentType<QueryBuilderOperationParamEditorProps> {
|
): ComponentType<QueryBuilderOperationParamEditorProps> {
|
||||||
|
Loading…
Reference in New Issue
Block a user