import { css } from '@emotion/css'; import { capitalize } from 'lodash'; import { useMemo, useState } from 'react'; import { CoreApp, GrafanaTheme2, getNextRefId } from '@grafana/data'; import { reportInteraction } from '@grafana/runtime'; import { DataQuery } from '@grafana/schema'; import { Button, Collapse, Modal, useStyles2 } from '@grafana/ui'; import { LokiQuery } from '../../types'; import { lokiQueryModeller } from '../LokiQueryModeller'; import { operationDefinitions } from '../operations'; import { buildVisualQueryFromString } from '../parsing'; import { LokiOperationId, LokiQueryPattern, LokiQueryPatternType, LokiVisualQueryOperationCategory } from '../types'; import { QueryPattern } from './QueryPattern'; type Props = { isOpen: boolean; query: LokiQuery; queries: DataQuery[] | undefined; app?: CoreApp; onClose: () => void; onChange: (query: LokiQuery) => void; onAddQuery?: (query: LokiQuery) => void; }; const keepOperationCategories: string[] = [ LokiVisualQueryOperationCategory.Formats, LokiVisualQueryOperationCategory.LineFilters, LokiVisualQueryOperationCategory.LabelFilters, ]; const excludeOperationIds: string[] = [LokiOperationId.Unwrap]; const keepOperations = operationDefinitions .filter( (operation) => operation.category && keepOperationCategories.includes(operation.category) && !excludeOperationIds.includes(operation.id) ) .map((operation) => operation.id); export const QueryPatternsModal = (props: Props) => { const { isOpen, onClose, onChange, onAddQuery, query, queries, app } = props; const [openTabs, setOpenTabs] = useState([]); const [selectedPatternName, setSelectedPatternName] = useState(null); const styles = useStyles2(getStyles); const hasNewQueryOption = !!onAddQuery; const hasPreviousQuery = useMemo( () => buildVisualQueryFromString(query.expr).query.operations.length > 0, [query.expr] ); const onPatternSelect = (pattern: LokiQueryPattern, selectAsNewQuery = false) => { const visualQuery = buildVisualQueryFromString(selectAsNewQuery ? '' : query.expr); reportInteraction('grafana_loki_query_patterns_selected', { version: 'v2', app: app ?? '', editorMode: query.editorMode, selectedPattern: pattern.name, preSelectedOperationsCount: visualQuery.query.operations.length, preSelectedLabelsCount: visualQuery.query.labels.length, createNewQuery: hasNewQueryOption && selectAsNewQuery, }); // Filter operations in the original query except those we configured to keep visualQuery.query.operations = visualQuery.query.operations.filter((op) => keepOperations.includes(op.id)); // Filter operations in the pattern that are present in the original query const patternOperations = pattern.operations.filter( (patternOp) => visualQuery.query.operations.findIndex((op) => op.id === patternOp.id) < 0 ); visualQuery.query.operations = [...visualQuery.query.operations, ...patternOperations]; if (hasNewQueryOption && selectAsNewQuery) { onAddQuery({ ...query, refId: getNextRefId(queries ?? [query]), expr: lokiQueryModeller.renderQuery(visualQuery.query), }); } else { onChange({ ...query, expr: lokiQueryModeller.renderQuery(visualQuery.query), }); } setSelectedPatternName(null); onClose(); }; return (
Kick start your query by selecting one of these queries. You can then continue to complete your query.
{Object.values(LokiQueryPatternType).map((patternType) => { return ( setOpenTabs((tabs) => // close tab if it's already open, otherwise open it tabs.includes(patternType) ? tabs.filter((t) => t !== patternType) : [...tabs, patternType] ) } >
{lokiQueryModeller .getQueryPatterns() .filter((pattern) => pattern.type === patternType) .map((pattern) => ( ))}
); })}
); }; const getStyles = (theme: GrafanaTheme2) => { return { cardsContainer: css({ display: 'flex', flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', }), spacing: css({ marginBottom: theme.spacing(1), }), modal: css({ width: '85vw', [theme.breakpoints.down('md')]: { width: '100%', }, }), }; };