diff --git a/.eslintrc b/.eslintrc index ebea4de90..1cff43a21 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,11 +2,10 @@ "extends": "./.config/.eslintrc", "rules": { "array-element-newline": ["error", { - "ArrayExpression": "consistent", "ArrayPattern": { "minItems": 3 } }], "object-curly-newline": ["error", { - "ObjectPattern": { "multiline": true, "minProperties": 3 } + "ObjectPattern": { "multiline": true, "minProperties": 10 } }] } } diff --git a/src/datasource/datasource.ts b/src/datasource/datasource.ts index 656e950fd..01b8a586b 100644 --- a/src/datasource/datasource.ts +++ b/src/datasource/datasource.ts @@ -159,7 +159,6 @@ export const requestOptions = {...options, range: this.options.range} const originalQuery = this.createQuery(requestOptions, query) - let scanner = new Scanner(originalQuery.stmt.replace(/\r\n|\r|\n/g, ' ')); let { select } = scanner.toAST(); @@ -167,21 +166,21 @@ export return `SELECT ${select.join(',')} FROM $table WHERE $timeFilter AND trace_id=${traceId}` } - const generateQueryForTimestampBackward = (inputTimestampColumn, inputTimestampValue) => { + const generateQueryForTimestampBackward = (inputTimestampColumn, inputTimestampValue, contextWindowSize) => { return `SELECT timestamp FROM ( SELECT ${inputTimestampColumn}, - FIRST_VALUE(${inputTimestampColumn}) OVER (ORDER BY ${inputTimestampColumn} ROWS BETWEEN 10 PRECEDING AND CURRENT ROW) AS timestamp + FIRST_VALUE(${inputTimestampColumn}) OVER (ORDER BY ${inputTimestampColumn} ROWS BETWEEN ${contextWindowSize || 10} PRECEDING AND CURRENT ROW) AS timestamp FROM $table ORDER BY ${inputTimestampColumn} ) WHERE ${inputTimestampColumn} = '${inputTimestampValue}'` } - const generateQueryForTimestampForward = (inputTimestampColumn, inputTimestampValue) => { + const generateQueryForTimestampForward = (inputTimestampColumn, inputTimestampValue, contextWindowSize) => { return `SELECT timestamp FROM ( SELECT ${inputTimestampColumn}, - LAST_VALUE(${inputTimestampColumn}) OVER (ORDER BY ${inputTimestampColumn} ROWS BETWEEN CURRENT ROW AND 10 FOLLOWING) AS timestamp + LAST_VALUE(${inputTimestampColumn}) OVER (ORDER BY ${inputTimestampColumn} ROWS BETWEEN CURRENT ROW AND ${contextWindowSize || 10} FOLLOWING) AS timestamp FROM $table ORDER BY ${inputTimestampColumn} ) WHERE ${inputTimestampColumn} = '${inputTimestampValue}'` @@ -219,11 +218,10 @@ export const timestampColumn = query?.dateTimeColDataType const getLogsTimeBoundaries = async () => { - const boundariesRequest = options?.direction === LogRowContextQueryDirection.Backward ? - generateQueryForTimestampBackward(timestampColumn, row.timeUtc): - generateQueryForTimestampForward(timestampColumn, row.timeUtc) + generateQueryForTimestampBackward(timestampColumn, row.timeUtc, query?.contextWindowSize): + generateQueryForTimestampForward(timestampColumn, row.timeUtc, query?.contextWindowSize) const { stmt, diff --git a/src/types/types.ts b/src/types/types.ts index 406723610..7fd949ade 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -42,6 +42,7 @@ export interface CHQuery extends DataQuery { intervalFactor?: number; interval?: string; formattedQuery?: string; + contextWindowSize?: number; } /** diff --git a/src/views/QueryEditor/QueryEditor.tsx b/src/views/QueryEditor/QueryEditor.tsx index 96b5fcb1c..e2c5ffabb 100644 --- a/src/views/QueryEditor/QueryEditor.tsx +++ b/src/views/QueryEditor/QueryEditor.tsx @@ -12,12 +12,7 @@ import { initializeQueryDefaults } from './helpers/initializeQueryDefaults'; import './QueryEditor.css'; export function QueryEditor(props: QueryEditorProps) { - const { - datasource, - query, - onChange, - onRunQuery - } = props; + const { datasource, query, onChange, onRunQuery } = props; const isAnnotationView = !props.app; const initializedQuery = initializeQueryDefaults(query, isAnnotationView, datasource, onChange); @@ -26,12 +21,12 @@ export function QueryEditor(props: QueryEditorProps onChange({ ...initializedQuery, query: sql }); - const onFieldChange = (field: any) => onChange({ ...initializedQuery, [field.fieldName]: field.value }) + const onFieldChange = (field: any) => onChange({ ...initializedQuery, [field.fieldName]: field.value }); const onTriggerQuery = () => onRunQuery(); // @ts-ignore const adHocFilters = datasource.templateSrv.getAdhocFilters(datasource.name); - const areAdHocFiltersAvailable = !!adHocFilters.length + const areAdHocFiltersAvailable = !!adHocFilters.length; if (adHocFilters?.length) { // eslint-disable-next-line diff --git a/src/views/QueryEditor/components/QueryBuilder/components/UniversalSelectComponent.tsx b/src/views/QueryEditor/components/QueryBuilder/components/UniversalSelectComponent.tsx index 0a606897d..581ced6fa 100644 --- a/src/views/QueryEditor/components/QueryBuilder/components/UniversalSelectComponent.tsx +++ b/src/views/QueryEditor/components/QueryBuilder/components/UniversalSelectComponent.tsx @@ -1,5 +1,5 @@ import { InlineField, Select } from '@grafana/ui'; -import React, { useState, useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { SelectableValue } from '@grafana/data'; type UniversalSelectFieldProps = { diff --git a/src/views/QueryEditor/components/QueryTextEditor/QueryTextEditor.tsx b/src/views/QueryEditor/components/QueryTextEditor/QueryTextEditor.tsx index c831a8bf2..29d96921c 100644 --- a/src/views/QueryEditor/components/QueryTextEditor/QueryTextEditor.tsx +++ b/src/views/QueryEditor/components/QueryTextEditor/QueryTextEditor.tsx @@ -69,6 +69,10 @@ export const QueryTextEditor = ({ onFieldChange({ fieldName: 'format', value: value }); }; + const handleContextWindowChange = (value: string | undefined) => { + onFieldChange({ fieldName: 'contextWindowSize', value: value }); + }; + const handleToggleField = (fieldName: string) => { onFieldChange({ fieldName: fieldName, value: !query[fieldName] }); }; @@ -83,24 +87,26 @@ export const QueryTextEditor = ({ onEditorMount={onEditorMount} onRunQuery={onRunQuery} /> - {!areAdHocFiltersAvailable && `${filter.key} ${filter.operator} ${filter.value}`)} - onChange={(tagsList) => { - onFieldChange({ - fieldName: 'adHocFilters', - value: tagsList.map((item: string) => { - const [ - key, - operator, - value - ] = item.split(' '); + {!areAdHocFiltersAvailable && ( + `${filter.key} ${filter.operator} ${filter.value}`)} + onChange={(tagsList) => { + onFieldChange({ + fieldName: 'adHocFilters', + value: tagsList.map((item: string) => { + const [ + key, + operator, + value + ] = item.split(' '); - return { key, operator, value }; - }), - }); - }} - />} + return { key, operator, value }; + }), + }); + }} + /> + )}
)} + {query.format === 'logs' && ( + Context window}> +