/usr/share/grafana/public/app/plugins/datasource/loki/querybuilder/components
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, Stack, 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<string[]>([]); const [selectedPatternName, setSelectedPatternName] = useState<string | null>(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 ( <Modal isOpen={isOpen} title="Kick start your query" onDismiss={onClose} className={styles.modal}> <div className={styles.spacing}> Kick start your query by selecting one of these queries. You can then continue to complete your query. </div> {Object.values(LokiQueryPatternType).map((patternType) => { return ( <Collapse key={patternType} label={`${capitalize(patternType)} query starters`} isOpen={openTabs.includes(patternType)} onToggle={() => setOpenTabs((tabs) => // close tab if it's already open, otherwise open it tabs.includes(patternType) ? tabs.filter((t) => t !== patternType) : [...tabs, patternType] ) } > <Stack wrap justifyContent="space-between"> {lokiQueryModeller .getQueryPatterns() .filter((pattern) => pattern.type === patternType) .map((pattern) => ( <QueryPattern key={pattern.name} pattern={pattern} hasNewQueryOption={hasNewQueryOption} hasPreviousQuery={hasPreviousQuery} onPatternSelect={onPatternSelect} selectedPatternName={selectedPatternName} setSelectedPatternName={setSelectedPatternName} /> ))} </Stack> </Collapse> ); })} <Button variant="secondary" onClick={onClose}> Close </Button> </Modal> ); }; const getStyles = (theme: GrafanaTheme2) => { return { spacing: css({ marginBottom: theme.spacing(1), }), modal: css({ width: '85vw', [theme.breakpoints.down('md')]: { width: '100%', }, }), }; };
.
Edit
..
Edit
LabelBrowserModal.test.tsx
Edit
LabelBrowserModal.tsx
Edit
LabelParamEditor.test.tsx
Edit
LabelParamEditor.tsx
Edit
LokiQueryBuilder.test.tsx
Edit
LokiQueryBuilder.tsx
Edit
LokiQueryBuilderContainer.test.tsx
Edit
LokiQueryBuilderContainer.tsx
Edit
LokiQueryBuilderExplained.tsx
Edit
LokiQueryBuilderOptions.test.tsx
Edit
LokiQueryBuilderOptions.tsx
Edit
LokiQueryCodeEditor.test.tsx
Edit
LokiQueryCodeEditor.tsx
Edit
NestedQuery.test.tsx
Edit
NestedQuery.tsx
Edit
NestedQueryList.test.tsx
Edit
NestedQueryList.tsx
Edit
QueryPattern.tsx
Edit
QueryPatternsModal.test.tsx
Edit
QueryPatternsModal.tsx
Edit
QueryPreview.tsx
Edit
UnwrapParamEditor.test.tsx
Edit
UnwrapParamEditor.tsx
Edit