import { trim } from 'lodash'; import { useCallback, useEffect, useMemo, useState } from 'react'; import * as React from 'react'; import { CoreApp, isValidDuration, isValidGrafanaDuration, LogSortOrderChangeEvent, LogsSortOrder, SelectableValue, store, } from '@grafana/data'; import { EditorField, EditorRow, QueryOptionGroup } from '@grafana/plugin-ui'; import { config, getAppEvents, reportInteraction } from '@grafana/runtime'; import { Alert, AutoSizeInput, RadioButtonGroup, Select } from '@grafana/ui'; import { getQueryDirectionLabel, preprocessMaxLines, queryDirections, queryTypeOptions, RESOLUTION_OPTIONS, } from '../../components/LokiOptionFields'; import { getLokiQueryType, isLogsQuery } from '../../queryUtils'; import { LokiQuery, LokiQueryDirection, LokiQueryType, QueryStats } from '../../types'; export interface Props { query: LokiQuery; onChange: (update: LokiQuery) => void; onRunQuery: () => void; maxLines: number; app?: CoreApp; queryStats: QueryStats | null; } export const LokiQueryBuilderOptions = React.memo( ({ app, query, onChange, onRunQuery, maxLines, queryStats }) => { const [splitDurationValid, setSplitDurationValid] = useState(true); useEffect(() => { if (app !== CoreApp.Explore && app !== CoreApp.Dashboard && app !== CoreApp.PanelEditor) { return; } // Initialize the query direction according to the current environment. if (!query.direction) { onChange({ ...query, direction: getDefaultQueryDirection(app) }); } }, [app, onChange, query]); useEffect(() => { if (query.step && !isValidGrafanaDuration(`${query.step}`) && parseInt(query.step, 10)) { onChange({ ...query, step: `${parseInt(query.step, 10)}s`, }); } }, [onChange, query]); const onQueryTypeChange = (value: LokiQueryType) => { onChange({ ...query, queryType: value }); onRunQuery(); }; const onQueryDirectionChange = useCallback( (value: LokiQueryDirection) => { onChange({ ...query, direction: value }); onRunQuery(); }, [onChange, onRunQuery, query] ); const onResolutionChange = (option: SelectableValue) => { reportInteraction('grafana_loki_resolution_clicked', { app, resolution: option.value, }); onChange({ ...query, resolution: option.value }); onRunQuery(); }; const onChunkRangeChange = (evt: React.FormEvent) => { const value = evt.currentTarget.value; if (!isValidDuration(value)) { setSplitDurationValid(false); return; } setSplitDurationValid(true); onChange({ ...query, splitDuration: value }); onRunQuery(); }; const onLegendFormatChanged = (evt: React.FormEvent) => { onChange({ ...query, legendFormat: evt.currentTarget.value }); onRunQuery(); }; function onMaxLinesChange(e: React.SyntheticEvent) { const newMaxLines = preprocessMaxLines(e.currentTarget.value); if (query.maxLines !== newMaxLines) { onChange({ ...query, maxLines: newMaxLines }); onRunQuery(); } } function onStepChange(e: React.SyntheticEvent) { onChange({ ...query, step: trim(e.currentTarget.value) }); onRunQuery(); } useEffect(() => { if (app !== CoreApp.Dashboard && app !== CoreApp.PanelEditor) { return; } const subscription = getAppEvents().subscribe(LogSortOrderChangeEvent, (sortEvent: LogSortOrderChangeEvent) => { if (query.direction === LokiQueryDirection.Scan) { return; } const newDirection = sortEvent.payload.order === LogsSortOrder.Ascending ? LokiQueryDirection.Forward : LokiQueryDirection.Backward; if (newDirection !== query.direction) { onQueryDirectionChange(newDirection); } }); return () => { subscription.unsubscribe(); }; }, [app, onQueryDirectionChange, query.direction]); let queryType = getLokiQueryType(query); const isLogQuery = isLogsQuery(query.expr); const filteredQueryTypeOptions = isLogQuery ? queryTypeOptions.filter((o) => o.value !== LokiQueryType.Instant) : queryTypeOptions; // if the state's queryType is still Instant, trigger a change to range for log queries if (isLogQuery && queryType === LokiQueryType.Instant) { onChange({ ...query, queryType: LokiQueryType.Range }); queryType = LokiQueryType.Range; } const isValidStep = useMemo(() => { if (!query.step) { return true; } return typeof query.step === 'string' && isValidGrafanaDuration(query.step) && !isNaN(parseInt(query.step, 10)); }, [query.step]); return ( {filteredQueryTypeOptions.length > 1 && ( )} {isLogQuery && ( <> )} {!isLogQuery && ( <> {query.resolution !== undefined && query.resolution > 1 && ( <>