mirror of
https://github.com/grafana/grafana.git
synced 2025-09-22 07:02:28 +08:00
Elasticsearch: Fix script fields in query editor (#31681)
* Elasticsearch: Fix script fields in query editor * properly name bucke_script deries
This commit is contained in:
@ -23,12 +23,16 @@ interface Props {
|
|||||||
value?: string;
|
value?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MetricPicker: FunctionComponent<Props> = ({ options, onChange, className, value }) => (
|
export const MetricPicker: FunctionComponent<Props> = ({ options, onChange, className, value }) => {
|
||||||
<Segment
|
const selectedOption = options.find((option) => option.id === value);
|
||||||
className={cx(className, noWrap)}
|
|
||||||
options={toOptions(options)}
|
return (
|
||||||
onChange={onChange}
|
<Segment
|
||||||
placeholder="Select Metric"
|
className={cx(className, noWrap)}
|
||||||
value={!!value ? toOption(options.find((option) => option.id === value)!) : null}
|
options={toOptions(options)}
|
||||||
/>
|
onChange={onChange}
|
||||||
);
|
placeholder="Select Metric"
|
||||||
|
value={!!selectedOption ? toOption(selectedOption) : null}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -4,8 +4,9 @@ import { useDispatch } from '../../../../hooks/useStatelessReducer';
|
|||||||
import { changeMetricSetting } from '../state/actions';
|
import { changeMetricSetting } from '../state/actions';
|
||||||
import { ChangeMetricSettingAction } from '../state/types';
|
import { ChangeMetricSettingAction } from '../state/types';
|
||||||
import { SettingKeyOf } from '../../../types';
|
import { SettingKeyOf } from '../../../types';
|
||||||
import { MetricAggregationWithSettings } from '../aggregations';
|
import { MetricAggregationWithInlineScript, MetricAggregationWithSettings } from '../aggregations';
|
||||||
import { uniqueId } from 'lodash';
|
import { uniqueId } from 'lodash';
|
||||||
|
import { getScriptValue } from 'app/plugins/datasource/elasticsearch/utils';
|
||||||
|
|
||||||
interface Props<T extends MetricAggregationWithSettings, K extends SettingKeyOf<T>> {
|
interface Props<T extends MetricAggregationWithSettings, K extends SettingKeyOf<T>> {
|
||||||
label: string;
|
label: string;
|
||||||
@ -26,13 +27,19 @@ export function SettingField<T extends MetricAggregationWithSettings, K extends
|
|||||||
const [id] = useState(uniqueId(`es-field-id-`));
|
const [id] = useState(uniqueId(`es-field-id-`));
|
||||||
const settings = metric.settings;
|
const settings = metric.settings;
|
||||||
|
|
||||||
|
let defaultValue = settings?.[settingName as keyof typeof settings] || '';
|
||||||
|
|
||||||
|
if (settingName === 'script') {
|
||||||
|
defaultValue = getScriptValue(metric as MetricAggregationWithInlineScript);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InlineField label={label} labelWidth={16} tooltip={tooltip}>
|
<InlineField label={label} labelWidth={16} tooltip={tooltip}>
|
||||||
<Input
|
<Input
|
||||||
id={id}
|
id={id}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onBlur={(e) => dispatch(changeMetricSetting(metric, settingName, e.target.value as any))}
|
onBlur={(e) => dispatch(changeMetricSetting(metric, settingName, e.target.value as any))}
|
||||||
defaultValue={settings?.[settingName as keyof typeof settings]}
|
defaultValue={defaultValue}
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
);
|
);
|
||||||
|
@ -43,9 +43,10 @@ export interface MetricAggregationWithMissingSupport extends BaseMetricAggregati
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InlineScript = string | { inline?: string };
|
||||||
export interface MetricAggregationWithInlineScript extends BaseMetricAggregation {
|
export interface MetricAggregationWithInlineScript extends BaseMetricAggregation {
|
||||||
settings?: {
|
settings?: {
|
||||||
script?: string;
|
script?: InlineScript;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ export interface Average
|
|||||||
MetricAggregationWithInlineScript {
|
MetricAggregationWithInlineScript {
|
||||||
type: 'avg';
|
type: 'avg';
|
||||||
settings?: {
|
settings?: {
|
||||||
script?: string;
|
script?: InlineScript;
|
||||||
missing?: string;
|
missing?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -67,7 +68,7 @@ export interface Average
|
|||||||
export interface Sum extends MetricAggregationWithField, MetricAggregationWithInlineScript {
|
export interface Sum extends MetricAggregationWithField, MetricAggregationWithInlineScript {
|
||||||
type: 'sum';
|
type: 'sum';
|
||||||
settings?: {
|
settings?: {
|
||||||
script?: string;
|
script?: InlineScript;
|
||||||
missing?: string;
|
missing?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -75,7 +76,7 @@ export interface Sum extends MetricAggregationWithField, MetricAggregationWithIn
|
|||||||
export interface Max extends MetricAggregationWithField, MetricAggregationWithInlineScript {
|
export interface Max extends MetricAggregationWithField, MetricAggregationWithInlineScript {
|
||||||
type: 'max';
|
type: 'max';
|
||||||
settings?: {
|
settings?: {
|
||||||
script?: string;
|
script?: InlineScript;
|
||||||
missing?: string;
|
missing?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -83,7 +84,7 @@ export interface Max extends MetricAggregationWithField, MetricAggregationWithIn
|
|||||||
export interface Min extends MetricAggregationWithField, MetricAggregationWithInlineScript {
|
export interface Min extends MetricAggregationWithField, MetricAggregationWithInlineScript {
|
||||||
type: 'min';
|
type: 'min';
|
||||||
settings?: {
|
settings?: {
|
||||||
script?: string;
|
script?: InlineScript;
|
||||||
missing?: string;
|
missing?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -105,7 +106,7 @@ export interface ExtendedStat {
|
|||||||
export interface ExtendedStats extends MetricAggregationWithField, MetricAggregationWithInlineScript {
|
export interface ExtendedStats extends MetricAggregationWithField, MetricAggregationWithInlineScript {
|
||||||
type: 'extended_stats';
|
type: 'extended_stats';
|
||||||
settings?: {
|
settings?: {
|
||||||
script?: string;
|
script?: InlineScript;
|
||||||
missing?: string;
|
missing?: string;
|
||||||
sigma?: string;
|
sigma?: string;
|
||||||
};
|
};
|
||||||
@ -118,7 +119,7 @@ export interface Percentiles extends MetricAggregationWithField, MetricAggregati
|
|||||||
type: 'percentiles';
|
type: 'percentiles';
|
||||||
settings?: {
|
settings?: {
|
||||||
percents?: string[];
|
percents?: string[];
|
||||||
script?: string;
|
script?: InlineScript;
|
||||||
missing?: string;
|
missing?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -238,7 +239,7 @@ export interface MovingFunction extends BasePipelineMetricAggregation {
|
|||||||
type: 'moving_fn';
|
type: 'moving_fn';
|
||||||
settings?: {
|
settings?: {
|
||||||
window?: string;
|
window?: string;
|
||||||
script?: string;
|
script?: InlineScript;
|
||||||
shift?: string;
|
shift?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -267,7 +268,7 @@ export interface CumulativeSum extends BasePipelineMetricAggregation {
|
|||||||
export interface BucketScript extends PipelineMetricAggregationWithMultipleBucketPaths {
|
export interface BucketScript extends PipelineMetricAggregationWithMultipleBucketPaths {
|
||||||
type: 'bucket_script';
|
type: 'bucket_script';
|
||||||
settings?: {
|
settings?: {
|
||||||
script?: string;
|
script?: InlineScript;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ import { bucketAggregationConfig } from './components/QueryEditor/BucketAggregat
|
|||||||
import { isBucketAggregationWithField } from './components/QueryEditor/BucketAggregationsEditor/aggregations';
|
import { isBucketAggregationWithField } from './components/QueryEditor/BucketAggregationsEditor/aggregations';
|
||||||
import { generate, Observable, of, throwError } from 'rxjs';
|
import { generate, Observable, of, throwError } from 'rxjs';
|
||||||
import { catchError, first, map, mergeMap, skipWhile, throwIfEmpty } from 'rxjs/operators';
|
import { catchError, first, map, mergeMap, skipWhile, throwIfEmpty } from 'rxjs/operators';
|
||||||
|
import { getScriptValue } from './utils';
|
||||||
|
|
||||||
// Those are metadata fields as defined in https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-fields.html#_identity_metadata_fields.
|
// Those are metadata fields as defined in https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-fields.html#_identity_metadata_fields.
|
||||||
// custom fields can start with underscores, therefore is not safe to exclude anything that starts with one.
|
// custom fields can start with underscores, therefore is not safe to exclude anything that starts with one.
|
||||||
@ -425,7 +426,7 @@ export class ElasticDatasource extends DataSourceApi<ElasticsearchQuery, Elastic
|
|||||||
text += metric.field;
|
text += metric.field;
|
||||||
}
|
}
|
||||||
if (isPipelineAggregationWithMultipleBucketPaths(metric)) {
|
if (isPipelineAggregationWithMultipleBucketPaths(metric)) {
|
||||||
text += metric.settings?.script?.replace(new RegExp('params.', 'g'), '');
|
text += getScriptValue(metric).replace(new RegExp('params.', 'g'), '');
|
||||||
}
|
}
|
||||||
text += '), ';
|
text += '), ';
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import {
|
|||||||
ExtendedStatMetaType,
|
ExtendedStatMetaType,
|
||||||
isMetricAggregationWithField,
|
isMetricAggregationWithField,
|
||||||
} from './components/QueryEditor/MetricAggregationsEditor/aggregations';
|
} from './components/QueryEditor/MetricAggregationsEditor/aggregations';
|
||||||
import { describeMetric } from './utils';
|
import { describeMetric, getScriptValue } from './utils';
|
||||||
import { metricAggregationConfig } from './components/QueryEditor/MetricAggregationsEditor/utils';
|
import { metricAggregationConfig } from './components/QueryEditor/MetricAggregationsEditor/utils';
|
||||||
|
|
||||||
const HIGHLIGHT_TAGS_EXP = `${queryDef.highlightTags.pre}([^@]+)${queryDef.highlightTags.post}`;
|
const HIGHLIGHT_TAGS_EXP = `${queryDef.highlightTags.pre}([^@]+)${queryDef.highlightTags.post}`;
|
||||||
@ -207,7 +207,7 @@ export class ElasticResponse {
|
|||||||
|
|
||||||
if (metric.type === 'bucket_script') {
|
if (metric.type === 'bucket_script') {
|
||||||
//Use the formula in the column name
|
//Use the formula in the column name
|
||||||
metricName = metric.settings?.script || '';
|
metricName = getScriptValue(metric);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,7 +306,7 @@ export class ElasticResponse {
|
|||||||
if (series.metric && queryDef.isPipelineAggWithMultipleBucketPaths(series.metric)) {
|
if (series.metric && queryDef.isPipelineAggWithMultipleBucketPaths(series.metric)) {
|
||||||
const agg: any = _.find(target.metrics, { id: series.metricId });
|
const agg: any = _.find(target.metrics, { id: series.metricId });
|
||||||
if (agg && agg.settings.script) {
|
if (agg && agg.settings.script) {
|
||||||
metricName = agg.settings.script;
|
metricName = getScriptValue(agg);
|
||||||
|
|
||||||
for (const pv of agg.pipelineVariables) {
|
for (const pv of agg.pipelineVariables) {
|
||||||
const appliedAgg: any = _.find(target.metrics, { id: pv.pipelineAgg });
|
const appliedAgg: any = _.find(target.metrics, { id: pv.pipelineAgg });
|
||||||
|
@ -9,10 +9,12 @@ import {
|
|||||||
isMetricAggregationWithSettings,
|
isMetricAggregationWithSettings,
|
||||||
isPipelineAggregation,
|
isPipelineAggregation,
|
||||||
isPipelineAggregationWithMultipleBucketPaths,
|
isPipelineAggregationWithMultipleBucketPaths,
|
||||||
|
MetricAggregation,
|
||||||
|
MetricAggregationWithInlineScript,
|
||||||
} from './components/QueryEditor/MetricAggregationsEditor/aggregations';
|
} from './components/QueryEditor/MetricAggregationsEditor/aggregations';
|
||||||
import { defaultBucketAgg, defaultMetricAgg, findMetricById, highlightTags } from './query_def';
|
import { defaultBucketAgg, defaultMetricAgg, findMetricById, highlightTags } from './query_def';
|
||||||
import { ElasticsearchQuery } from './types';
|
import { ElasticsearchQuery } from './types';
|
||||||
import { convertOrderByToMetricId } from './utils';
|
import { convertOrderByToMetricId, getScriptValue } from './utils';
|
||||||
|
|
||||||
export class ElasticQueryBuilder {
|
export class ElasticQueryBuilder {
|
||||||
timeField: string;
|
timeField: string;
|
||||||
@ -204,8 +206,9 @@ export class ElasticQueryBuilder {
|
|||||||
target.metrics = target.metrics || [defaultMetricAgg()];
|
target.metrics = target.metrics || [defaultMetricAgg()];
|
||||||
target.bucketAggs = target.bucketAggs || [defaultBucketAgg()];
|
target.bucketAggs = target.bucketAggs || [defaultBucketAgg()];
|
||||||
target.timeField = this.timeField;
|
target.timeField = this.timeField;
|
||||||
|
let metric: MetricAggregation;
|
||||||
|
|
||||||
let i, j, pv, nestedAggs, metric;
|
let i, j, pv, nestedAggs;
|
||||||
const query = {
|
const query = {
|
||||||
size: 0,
|
size: 0,
|
||||||
query: {
|
query: {
|
||||||
@ -340,7 +343,9 @@ export class ElasticQueryBuilder {
|
|||||||
if (isMetricAggregationWithSettings(metric)) {
|
if (isMetricAggregationWithSettings(metric)) {
|
||||||
Object.entries(metric.settings || {})
|
Object.entries(metric.settings || {})
|
||||||
.filter(([_, v]) => v !== null)
|
.filter(([_, v]) => v !== null)
|
||||||
.forEach(([k, v]) => (metricAgg[k] = v));
|
.forEach(([k, v]) => {
|
||||||
|
metricAgg[k] = k === 'script' ? getScriptValue(metric as MetricAggregationWithInlineScript) : v;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
aggField[metric.type] = metricAgg;
|
aggField[metric.type] = metricAgg;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
isMetricAggregationWithField,
|
isMetricAggregationWithField,
|
||||||
MetricAggregation,
|
MetricAggregation,
|
||||||
|
MetricAggregationWithInlineScript,
|
||||||
} from './components/QueryEditor/MetricAggregationsEditor/aggregations';
|
} from './components/QueryEditor/MetricAggregationsEditor/aggregations';
|
||||||
import { metricAggregationConfig } from './components/QueryEditor/MetricAggregationsEditor/utils';
|
import { metricAggregationConfig } from './components/QueryEditor/MetricAggregationsEditor/utils';
|
||||||
|
|
||||||
@ -62,3 +63,31 @@ export const convertOrderByToMetricId = (orderBy: string): string | undefined =>
|
|||||||
const metricIdMatches = orderBy.match(/^(\d+)/);
|
const metricIdMatches = orderBy.match(/^(\d+)/);
|
||||||
return metricIdMatches ? metricIdMatches[1] : void 0;
|
return metricIdMatches ? metricIdMatches[1] : void 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Gets the actual script value for metrics that support inline scripts.
|
||||||
|
*
|
||||||
|
* This is needed because the `script` is a bit polymorphic.
|
||||||
|
* when creating a query with Grafana < 7.4 it was stored as:
|
||||||
|
* ```json
|
||||||
|
* {
|
||||||
|
* "settings": {
|
||||||
|
* "script": {
|
||||||
|
* "inline": "value"
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* while from 7.4 it's stored as
|
||||||
|
* ```json
|
||||||
|
* {
|
||||||
|
* "settings": {
|
||||||
|
* "script": "value"
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This allows us to access both formats and support both queries created before 7.4 and after.
|
||||||
|
*/
|
||||||
|
export const getScriptValue = (metric: MetricAggregationWithInlineScript) =>
|
||||||
|
(typeof metric.settings?.script === 'object' ? metric.settings?.script?.inline : metric.settings?.script) || '';
|
||||||
|
Reference in New Issue
Block a user