diff --git a/CHANGELOG.md b/CHANGELOG.md index 8da8af2..4d56b16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * FEATURE: add support for the `/select/logsql/stats_query` and `/select/logsql/stats_query_range` API calls. This feature helps to build different panels with statistic data. See [this issue](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/61). +* BUGFIX: fix options sorting in variables for numerical data type. See [this issue](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/97). + ## v0.7.0 * FEATURE: add support to display live logs by querying the tail endpoint in the datasource. See [this issue](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/83) diff --git a/src/language_provider.ts b/src/language_provider.ts index fbfdf85..ad48656 100644 --- a/src/language_provider.ts +++ b/src/language_provider.ts @@ -2,7 +2,7 @@ import { getDefaultTimeRange, LanguageProvider, TimeRange, } from '@grafana/data import { BackendSrvRequest } from '@grafana/runtime'; import { VictoriaLogsDatasource } from './datasource'; -import { FiledHits, FilterFieldType } from "./types"; +import { FieldHits, FilterFieldType } from "./types"; interface FetchFieldsOptions { type: FilterFieldType; @@ -20,18 +20,24 @@ interface FieldsRequestParams { field?: string; } +enum HitsValueType { + NUMBER = 'number', + DATE = 'date', + STRING = 'string' +} + export default class LogsQlLanguageProvider extends LanguageProvider { declare startTask: Promise; datasource: VictoriaLogsDatasource; cacheSize: number; - cacheValues: Map + cacheValues: Map constructor(datasource: VictoriaLogsDatasource, initialValues?: Partial) { super(); this.datasource = datasource; this.cacheSize = 100; - this.cacheValues = new Map(); + this.cacheValues = new Map(); Object.assign(this, initialValues); } @@ -51,7 +57,7 @@ export default class LogsQlLanguageProvider extends LanguageProvider { return Promise.all([]); }; - async getFieldList(options: FetchFieldsOptions): Promise { + async getFieldList(options: FetchFieldsOptions): Promise { if (options.type === FilterFieldType.FieldValue && !options.field) { return []; } @@ -80,9 +86,10 @@ export default class LogsQlLanguageProvider extends LanguageProvider { this.cacheValues.delete(firstKey); } - const result = await this.request(url, [], params, { method: 'POST' }); - this.cacheValues.set(key, result); - return result; + const result = await this.request(url, [], params, { method: 'POST' }) as FieldHits[]; + const sortedResult = sortFieldHits(result); + this.cacheValues.set(key, sortedResult); + return sortedResult; } getTimeRangeParams(timeRange?: TimeRange) { @@ -93,3 +100,34 @@ export default class LogsQlLanguageProvider extends LanguageProvider { } } } + +function determineType(value: string): HitsValueType { + if (!isNaN(Number(value))) { + return HitsValueType.NUMBER; + } + if (!isNaN(Date.parse(value))) { + return HitsValueType.DATE; + } + return HitsValueType.STRING; +} + +function getArrayType(data: FieldHits[]): HitsValueType { + const types = new Set(data.map(item => determineType(item.value))); + return types.size === 1 ? Array.from(types)[0] : HitsValueType.STRING; +} + +function sortFieldHits(data: FieldHits[]): FieldHits[] { + const arrayType = getArrayType(data); + + return data.sort((a, b) => { + switch (arrayType) { + case HitsValueType.NUMBER: + return Number(a.value) - Number(b.value); + case HitsValueType.DATE: + return new Date(a.value).getTime() - new Date(b.value).getTime(); + case HitsValueType.STRING: + default: + return a.value.localeCompare(b.value); + } + }); +} diff --git a/src/types.ts b/src/types.ts index 9daae50..dc75056 100644 --- a/src/types.ts +++ b/src/types.ts @@ -97,7 +97,7 @@ export interface RequestArguments { options?: Partial; } -export interface FiledHits { +export interface FieldHits { value: string; hits: number; }