Skip to content

Commit

Permalink
Merge branch 'main' into pre-release-changes
Browse files Browse the repository at this point in the history
# Conflicts:
#	CHANGELOG.md
  • Loading branch information
dmitryk-dk committed Oct 16, 2024
2 parents e9b854f + 6ba3ee3 commit 18452a2
Show file tree
Hide file tree
Showing 14 changed files with 281 additions and 54 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

## tip

## v0.5.1
## v0.6.0

* FEATURE: add `limit` param for the `/field_values` request. See [this issue](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/75).

* BUGFIX: fix variable substitution in queries. See [this issue](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/77).
* BUGFIX: fixed health path for case, when url ends with trailing slash.
* BUGFIX: fix the application of filtering in queries. See [this issue](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/81).

## v0.5.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const QueryBuilderFieldFilter = ({ datasource, filter, query, indexPath, timeRan
}

const handleSelect = (type: FilterFieldType) => ({ value: selected }: SelectableValue<string>) => {
const fullFilter = type === FilterFieldType.Name
const fullFilter = type === FilterFieldType.FieldName
? `${selected}: ${fieldValue || ''}`
: `${field || ''}: ${field === '_stream' ? selected : `"${escapeLabelValueInExactSelector(selected || "")}"`} `

Expand All @@ -64,11 +64,12 @@ const QueryBuilderFieldFilter = ({ datasource, filter, query, indexPath, timeRan
}

const handleOpenMenu = (type: FilterFieldType) => async () => {
const setterLoading = type === FilterFieldType.Name ? setIsLoadingFieldNames : setIsLoadingFieldValues
const setterValues = type === FilterFieldType.Name ? setFieldNames : setFieldValues
const setterLoading = type === FilterFieldType.FieldName ? setIsLoadingFieldNames : setIsLoadingFieldValues
const setterValues = type === FilterFieldType.FieldName ? setFieldNames : setFieldValues

setterLoading(true)
const list = await datasource.languageProvider?.getFieldList({ type, timeRange, field, })
const limit = datasource.getQueryBuilderLimits(type)
const list = await datasource.languageProvider?.getFieldList({ type, timeRange, field, limit })
const result = list ? list.map(({ value, hits }) => ({
value,
label: value || " ",
Expand All @@ -91,30 +92,30 @@ const QueryBuilderFieldFilter = ({ datasource, filter, query, indexPath, timeRan
</div>
<div className={styles.content}>
<Select
placeholder="Select field"
placeholder="Select field name"
width="auto"
options={fieldNames.length ? fieldNames : [{ label: field, value: field }]}
value={field}
isLoading={isLoadingFieldNames}
loadingMessage={"Loading fields names..."}
allowCustomValue
onCreateOption={handleCreate(FilterFieldType.Name)}
onChange={handleSelect(FilterFieldType.Name)}
onOpenMenu={handleOpenMenu(FilterFieldType.Name)}
onCreateOption={handleCreate(FilterFieldType.FieldName)}
onChange={handleSelect(FilterFieldType.FieldName)}
onOpenMenu={handleOpenMenu(FilterFieldType.FieldName)}
/>
<span>:</span>
<Select
placeholder="Select value"
placeholder="Select field value"
width="auto"
options={fieldValues.length ? fieldValues : fieldValue ? [{ label: fieldValue, value: fieldValue }] : []}
value={fieldValue}
isLoading={isLoadingFieldValues}
loadingMessage={"Loading fields values..."}
noOptionsMessage={field ? "No values found" : "Select field first"}
noOptionsMessage={field ? "No values found" : "Select field name first"}
allowCustomValue
onCreateOption={handleCreate(FilterFieldType.Value)}
onChange={handleSelect(FilterFieldType.Value)}
onOpenMenu={handleOpenMenu(FilterFieldType.Value)}
onCreateOption={handleCreate(FilterFieldType.FieldValue)}
onChange={handleSelect(FilterFieldType.FieldValue)}
onOpenMenu={handleOpenMenu(FilterFieldType.FieldValue)}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ interface Context {
type ParsedExpression = string | ParsedExpression[];

export const buildVisualQueryFromString = (expr: string): Context => {
// This will be modified in the handleExpression
const visQuery: VisualQuery = {
filters: { operators: [], values: [] },
pipes: []
Expand Down Expand Up @@ -46,6 +45,10 @@ const handleExpression = (expr: string) => {
return { filters, pipes: pipeParts };
}

export const splitExpression = (expr: string): string[] => {
return expr.split('|').map(part => part.trim());
};

const parseStringToFilterVisualQuery = (expression: string): FilterVisualQuery => {
const parsedExpressions = parseExpression(expression)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ const filterVisualQueryToString = (query: FilterVisualQuery): string => {
}

export const parseVisualQueryToString = (query: VisualQuery): string => {
// TODO add parse pipes
return filterVisualQueryToString(query.filters);
const pipesPart = query.pipes?.length ? ` | ${query.pipes.join(' | ')}` : ''
return filterVisualQueryToString(query.filters) + pipesPart;
}
4 changes: 2 additions & 2 deletions src/components/QueryEditor/QueryEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ const QueryEditor = React.memo<VictoriaLogsQueryEditorProps>((props) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
wrapper: css`
display: grid;
align-items: flex-start;
display: flex;
flex-direction: column;
gap: ${theme.spacing(0.5)};
`
};
Expand Down
42 changes: 34 additions & 8 deletions src/components/VariableQueryEditor/VariableQueryEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React, { FormEvent, useEffect, useState } from 'react';
import { usePrevious } from 'react-use';

import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { DEFAULT_FIELD_DISPLAY_VALUES_LIMIT, QueryEditorProps, SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Input, Select } from "@grafana/ui";

import { VictoriaLogsDatasource } from "../../datasource";
import { FilterFieldType, Options, Query, VariableQuery } from '../../types';

const variableOptions = [
{ label: 'Field names', value: FilterFieldType.Name },
{ label: 'Field values', value: FilterFieldType.Value },
{ label: 'Field names', value: FilterFieldType.FieldName },
{ label: 'Field values', value: FilterFieldType.FieldValue },
];

const refId = 'VictoriaLogsVariableQueryEditor-VariableQuery'
Expand All @@ -20,6 +20,7 @@ export const VariableQueryEditor = ({ onChange, query, datasource, range }: Prop
const [type, setType] = useState<FilterFieldType>();
const [queryFilter, setQueryFilter] = useState<string>('');
const [field, setField] = useState<string>('');
const [limit, setLimit] = useState<number>(DEFAULT_FIELD_DISPLAY_VALUES_LIMIT);
const [fieldNames, setFieldNames] = useState<SelectableValue<string>[]>([])

const previousType = usePrevious(type);
Expand All @@ -40,13 +41,18 @@ export const VariableQueryEditor = ({ onChange, query, datasource, range }: Prop
if (!type) {
return;
}
onChange({ refId, type, field, query: queryFilter });
onChange({ refId, type, field, query: queryFilter, limit });
};

const handleQueryFilterChange = (e: FormEvent<HTMLInputElement>) => {
setQueryFilter(e.currentTarget.value);
};

const handleLimitChange = (e: FormEvent<HTMLInputElement>) => {
const value = Number(e.currentTarget.value)
setLimit(isNaN(value) ? DEFAULT_FIELD_DISPLAY_VALUES_LIMIT : value);
};

const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
e.key === 'Enter' && handleBlur()
}
Expand All @@ -59,15 +65,20 @@ export const VariableQueryEditor = ({ onChange, query, datasource, range }: Prop
setType(query.type);
setField(query.field || '');
setQueryFilter(query.query || '');
setLimit(query.limit ?? DEFAULT_FIELD_DISPLAY_VALUES_LIMIT);
}, [query]);

useEffect(() => {
if (type !== FilterFieldType.Value || previousType === type) {
if (type !== FilterFieldType.FieldValue || previousType === type) {
return;
}

const getFiledNames = async () => {
const list = await datasource.languageProvider?.getFieldList({ type: FilterFieldType.Name, timeRange: range })
const list = await datasource.languageProvider?.getFieldList({
type: FilterFieldType.FieldName,
timeRange: range,
limit,
})
const result = list ? list.map(({ value, hits }) => ({
value,
label: value || " ",
Expand All @@ -77,7 +88,7 @@ export const VariableQueryEditor = ({ onChange, query, datasource, range }: Prop
}

getFiledNames().catch(console.error)
}, [datasource, type, range, previousType]);
}, [datasource, type, range, previousType, limit]);

return (
<div>
Expand All @@ -92,7 +103,7 @@ export const VariableQueryEditor = ({ onChange, query, datasource, range }: Prop
width={20}
/>
</InlineField>
{type === FilterFieldType.Value && (
{type === FilterFieldType.FieldValue && (
<InlineField label="Field" labelWidth={20}>
<Select
aria-label="Field value"
Expand All @@ -104,6 +115,21 @@ export const VariableQueryEditor = ({ onChange, query, datasource, range }: Prop
/>
</InlineField>
)}
<InlineField
label="Limit"
labelWidth={20}
tooltip={'Maximum number of values to return. Set to 0 to remove the limit.'}
>
<Input
type="number"
aria-label="Limit"
placeholder="Limit"
value={limit}
onChange={handleLimitChange}
onBlur={handleBlur}
onKeyDown={handleKeyDown}
/>
</InlineField>
</InlineFieldRow>
<InlineFieldRow>
<InlineField
Expand Down
2 changes: 2 additions & 0 deletions src/configuration/ConfigEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Options } from '../types';

import { AlertingSettings } from './AlertingSettings';
import { HelpfulLinks } from "./HelpfulLinks";
import { LimitsSettings } from "./LimitSettings";
import { QuerySettings } from './QuerySettings';

export type Props = DataSourcePluginOptionsEditorProps<Options>;
Expand Down Expand Up @@ -40,6 +41,7 @@ const ConfigEditor = (props: Props) => {
maxLines={options.jsonData.maxLines || ''}
onMaxLinedChange={(value) => onOptionsChange(setMaxLines(options, value))}
/>
<LimitsSettings {...props}/>
</>
);
};
Expand Down
97 changes: 97 additions & 0 deletions src/configuration/LimitSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React, { SyntheticEvent } from 'react';

import {
DataSourcePluginOptionsEditorProps,
SelectableValue,
} from '@grafana/data';
import {
InlineField,
regexValidation,
Input, validate
} from '@grafana/ui';

import { FilterFieldType, Options } from "../types";

const validationRule = regexValidation(
/^$|^\d+$/,
'Value is not valid, you can use number'
)

const limitFields = [
{
label: "Field values",
tooltip: <>In the Query Builder, the <code>/select/logsql/field_values</code> endpoint allows an optional <code>limit=N</code> parameter to restrict the number of returned values to <code>N</code>. For more details, see the documentation <a href="https://docs.victoriametrics.com/victorialogs/querying/#querying-field-values" target="_blank" rel="noreferrer">here</a>.</>,
placeholder: "",
key: FilterFieldType.FieldValue
}
]

type Props = Pick<DataSourcePluginOptionsEditorProps<Options>, 'options' | 'onOptionsChange'>;

export const LimitsSettings = (props: Props) => {
const { options, onOptionsChange } = props;

const [error, setError] = React.useState<string | null>(null)

const handleBlur = (event: SyntheticEvent<HTMLInputElement>) => {
const errors = validate(event.currentTarget.value, [validationRule])
setError(errors?.[0] || null)
}

return (
<>
<h3 className="page-heading">Limits</h3>
<p className="text-help">Leave the field blank or set the value to <code>0</code> to remove the limit</p>
<div className="gf-form-group">
{limitFields.map((field) => (
<div className="gf-form" key={field.key}>
<InlineField
label={field.label}
labelWidth={28}
tooltip={field.tooltip}
interactive={true}
error={error}
invalid={!!error}
>
<Input
className="width-6"
value={`${options.jsonData?.queryBuilderLimits?.[field.key] || ''}`}
onChange={onChangeHandler(field.key, options, onOptionsChange)}
spellCheck={false}
placeholder={field.placeholder}
onBlur={handleBlur}
/>
</InlineField>
</div>
))}
</div>
</>
)
};

const getValueFromEventItem = (eventItem: SyntheticEvent<HTMLInputElement> | SelectableValue<string>) => {
if (!eventItem) {
return '';
}

if (eventItem.hasOwnProperty('currentTarget')) {
return eventItem.currentTarget.value;
}

return (eventItem as SelectableValue<string>).value;
};

const onChangeHandler =
(key: string, options: Props['options'], onOptionsChange: Props['onOptionsChange']) =>
(eventItem: SyntheticEvent<HTMLInputElement> | SelectableValue<string>) => {
onOptionsChange({
...options,
jsonData: {
...options.jsonData,
queryBuilderLimits: {
...options.jsonData.queryBuilderLimits,
[key]: getValueFromEventItem(eventItem),
}
},
});
};
2 changes: 1 addition & 1 deletion src/configuration/QuerySettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type Props = {
export const QuerySettings = (props: Props) => {
const { maxLines, onMaxLinedChange } = props;
return (
<div>
<div className="gf-form-group">
<InlineField
label="Maximum lines"
labelWidth={22}
Expand Down
11 changes: 10 additions & 1 deletion src/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import {
FilterActionType,
RequestArguments,
VariableQuery,
QueryBuilderLimits,
FilterFieldType,
} from './types';
import { VariableSupport } from "./variableSupport/VariableSupport";

Expand All @@ -49,6 +51,7 @@ export class VictoriaLogsDatasource
httpMethod: string;
customQueryParameters: URLSearchParams;
languageProvider?: LogsQlLanguageProvider;
queryBuilderLimits?: QueryBuilderLimits;

constructor(
instanceSettings: DataSourceInstanceSettings<Options>,
Expand All @@ -70,6 +73,7 @@ export class VictoriaLogsDatasource
QueryEditor: QueryEditor,
};
this.variables = new VariableSupport(this);
this.queryBuilderLimits = instanceSettings.jsonData.queryBuilderLimits;
}

query(request: DataQueryRequest<Query>): Observable<DataQueryResponse> {
Expand Down Expand Up @@ -248,8 +252,13 @@ export class VictoriaLogsDatasource
type: query.type,
timeRange,
field: query.field,
query: query.query
query: query.query,
limit: query.limit,
});
return (list ? list.map(({ value }) => ({ text: value })) : [])
}

getQueryBuilderLimits(key: FilterFieldType): number {
return this.queryBuilderLimits?.[key] || 0;
}
}
Loading

0 comments on commit 18452a2

Please sign in to comment.