Files
Andreas Christou a421f55cd5 Azure: Fix time management field (#107993)
* Fix mode setting

* Update selector

* Add tests

* Fix condition
2025-07-22 16:47:52 +01:00

173 lines
6.6 KiB
TypeScript

import React, { useMemo, useState, useCallback } from 'react';
import { SelectableValue, TimeRange } from '@grafana/data';
import { t } from '@grafana/i18n';
import { EditorRows } from '@grafana/plugin-ui';
import { Alert } from '@grafana/ui';
import {
BuilderQueryEditorExpressionType,
BuilderQueryEditorPropertyType,
BuilderQueryEditorReduceExpression,
BuilderQueryEditorWhereExpression,
BuilderQueryEditorGroupByExpression,
BuilderQueryEditorOrderByExpression,
BuilderQueryEditorPropertyExpression,
BuilderQueryExpression,
} from '../../dataquery.gen';
import Datasource from '../../datasource';
import { selectors } from '../../e2e/selectors';
import { AzureLogAnalyticsMetadataTable, AzureLogAnalyticsMetadataColumn } from '../../types/logAnalyticsMetadata';
import { AzureMonitorQuery } from '../../types/query';
import { EngineSchema } from '../../types/types';
import { AggregateSection } from './AggregationSection';
import { AzureMonitorKustoQueryBuilder } from './AzureMonitorKustoQueryBuilder';
import { FilterSection } from './FilterSection';
import { FuzzySearch } from './FuzzySearch';
import { GroupBySection } from './GroupBySection';
import KQLPreview from './KQLPreview';
import { LimitSection } from './LimitSection';
import { OrderBySection } from './OrderBySection';
import { TableSection } from './TableSection';
import { DEFAULT_LOGS_BUILDER_QUERY } from './utils';
interface LogsQueryBuilderProps {
query: AzureMonitorQuery;
basicLogsEnabled: boolean;
onQueryChange: (newQuery: AzureMonitorQuery) => void;
schema: EngineSchema;
templateVariableOptions: SelectableValue<string>;
datasource: Datasource;
timeRange?: TimeRange;
isLoadingSchema: boolean;
}
export const LogsQueryBuilder: React.FC<LogsQueryBuilderProps> = (props) => {
const { query, onQueryChange, schema, datasource, timeRange, isLoadingSchema } = props;
const [isKQLPreviewHidden, setIsKQLPreviewHidden] = useState<boolean>(true);
const tables: AzureLogAnalyticsMetadataTable[] = useMemo(() => {
return schema?.database?.tables || [];
}, [schema?.database]);
const builderQuery: BuilderQueryExpression = query.azureLogAnalytics?.builderQuery || DEFAULT_LOGS_BUILDER_QUERY;
const allColumns: AzureLogAnalyticsMetadataColumn[] = useMemo(() => {
const tableName = builderQuery.from?.property.name;
const selectedTable = tables.find((table) => table.name === tableName);
return selectedTable?.columns || [];
}, [builderQuery, tables]);
const buildAndUpdateQuery = useCallback(
({
limit,
reduce,
where,
fuzzySearch,
groupBy,
orderBy,
columns,
from,
basicLogsQuery,
}: {
limit?: number;
reduce?: BuilderQueryEditorReduceExpression[];
where?: BuilderQueryEditorWhereExpression[];
fuzzySearch?: BuilderQueryEditorWhereExpression[];
groupBy?: BuilderQueryEditorGroupByExpression[];
orderBy?: BuilderQueryEditorOrderByExpression[];
columns?: string[];
from?: BuilderQueryEditorPropertyExpression;
basicLogsQuery?: boolean;
}) => {
const datetimeColumn = allColumns.find((col) => col.type === 'datetime')?.name || 'TimeGenerated';
const timeFilterExpression: BuilderQueryEditorWhereExpression = {
type: BuilderQueryEditorExpressionType.Or,
expressions: [
{
type: BuilderQueryEditorExpressionType.Operator,
operator: { name: '$__timeFilter', value: datetimeColumn },
property: { name: datetimeColumn, type: BuilderQueryEditorPropertyType.Datetime },
},
],
};
const updatedBuilderQuery: BuilderQueryExpression = {
...builderQuery,
...(limit !== undefined ? { limit } : {}),
...(reduce !== undefined
? { reduce: { expressions: reduce, type: BuilderQueryEditorExpressionType.Reduce } }
: {}),
...(where !== undefined ? { where: { expressions: where, type: BuilderQueryEditorExpressionType.And } } : {}),
...(fuzzySearch !== undefined
? { fuzzySearch: { expressions: fuzzySearch, type: BuilderQueryEditorExpressionType.And } }
: {}),
...(groupBy !== undefined
? { groupBy: { expressions: groupBy, type: BuilderQueryEditorExpressionType.Group_by } }
: {}),
...(orderBy !== undefined
? { orderBy: { expressions: orderBy, type: BuilderQueryEditorExpressionType.Order_by } }
: {}),
...(columns !== undefined ? { columns: { columns, type: BuilderQueryEditorExpressionType.Property } } : {}),
...(from !== undefined ? { from } : {}),
timeFilter: { expressions: [timeFilterExpression], type: BuilderQueryEditorExpressionType.And },
};
const updatedQueryString = AzureMonitorKustoQueryBuilder.toQuery(updatedBuilderQuery);
onQueryChange({
...query,
azureLogAnalytics: {
...query.azureLogAnalytics,
builderQuery: updatedBuilderQuery,
query: updatedQueryString,
basicLogsQuery: from ? basicLogsQuery : query.azureLogAnalytics?.basicLogsQuery,
},
});
},
[query, builderQuery, onQueryChange, allColumns]
);
return (
<span data-testid={selectors.components.queryEditor.logsQueryBuilder.container.input}>
<EditorRows>
{schema && tables.length === 0 && (
<Alert
severity="warning"
title={t(
'components.logs-query-builder.title-no-tables',
'Resource loaded successfully but without any tables'
)}
/>
)}
<TableSection
{...props}
tables={tables}
allColumns={allColumns}
buildAndUpdateQuery={buildAndUpdateQuery}
isLoadingSchema={isLoadingSchema}
/>
<FilterSection
{...props}
allColumns={allColumns}
buildAndUpdateQuery={buildAndUpdateQuery}
datasource={datasource}
timeRange={timeRange}
/>
<AggregateSection {...props} allColumns={allColumns} buildAndUpdateQuery={buildAndUpdateQuery} />
<GroupBySection {...props} allColumns={allColumns} buildAndUpdateQuery={buildAndUpdateQuery} />
<OrderBySection {...props} allColumns={allColumns} buildAndUpdateQuery={buildAndUpdateQuery} />
<FuzzySearch {...props} allColumns={allColumns} buildAndUpdateQuery={buildAndUpdateQuery} />
<LimitSection {...props} buildAndUpdateQuery={buildAndUpdateQuery} />
<KQLPreview
query={query.azureLogAnalytics?.query || ''}
hidden={isKQLPreviewHidden}
setHidden={setIsKQLPreviewHidden}
/>
</EditorRows>
</span>
);
};