mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus/Loki: Add raw query and syntax highlight in explain mode (#50070)
This commit is contained in:
parent
c63071f519
commit
cc90f9bb69
@ -3,25 +3,38 @@ import React from 'react';
|
||||
import { Stack } from '@grafana/experimental';
|
||||
import { OperationExplainedBox } from 'app/plugins/datasource/prometheus/querybuilder/shared/OperationExplainedBox';
|
||||
import { OperationListExplained } from 'app/plugins/datasource/prometheus/querybuilder/shared/OperationListExplained';
|
||||
import { RawQuery } from 'app/plugins/datasource/prometheus/querybuilder/shared/RawQuery';
|
||||
|
||||
import { lokiGrammar } from '../../syntax';
|
||||
import { lokiQueryModeller } from '../LokiQueryModeller';
|
||||
import { buildVisualQueryFromString } from '../parsing';
|
||||
import { LokiVisualQuery } from '../types';
|
||||
|
||||
export interface Props {
|
||||
query: string;
|
||||
nested?: boolean;
|
||||
}
|
||||
|
||||
export const LokiQueryBuilderExplained = React.memo<Props>(({ query, nested }) => {
|
||||
export const LokiQueryBuilderExplained = React.memo<Props>(({ query }) => {
|
||||
const visQuery = buildVisualQueryFromString(query || '').query;
|
||||
const lang = { grammar: lokiGrammar, name: 'lokiql' };
|
||||
|
||||
return (
|
||||
<Stack gap={0} direction="column">
|
||||
<OperationExplainedBox stepNumber={1} title={`${lokiQueryModeller.renderLabels(visQuery.labels)}`}>
|
||||
<OperationExplainedBox>
|
||||
<RawQuery query={query} lang={lang} />
|
||||
</OperationExplainedBox>
|
||||
<OperationExplainedBox
|
||||
stepNumber={1}
|
||||
title={<RawQuery query={`${lokiQueryModeller.renderLabels(visQuery.labels)}`} lang={lang} />}
|
||||
>
|
||||
Fetch all log lines matching label filters.
|
||||
</OperationExplainedBox>
|
||||
<OperationListExplained<LokiVisualQuery> stepNumber={2} queryModeller={lokiQueryModeller} query={visQuery} />
|
||||
<OperationListExplained<LokiVisualQuery>
|
||||
stepNumber={2}
|
||||
queryModeller={lokiQueryModeller}
|
||||
query={visQuery}
|
||||
lang={lang}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
});
|
||||
|
@ -1,11 +1,8 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import Prism from 'prismjs';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { EditorField, EditorFieldGroup, EditorRow } from '@grafana/experimental';
|
||||
import { useTheme2 } from '@grafana/ui';
|
||||
|
||||
import { RawQuery } from '../../../prometheus/querybuilder/shared/RawQuery';
|
||||
import { lokiGrammar } from '../../syntax';
|
||||
|
||||
export interface Props {
|
||||
@ -13,30 +10,13 @@ export interface Props {
|
||||
}
|
||||
|
||||
export function QueryPreview({ query }: Props) {
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme);
|
||||
const highlighted = Prism.highlight(query, lokiGrammar, 'lokiql');
|
||||
|
||||
return (
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<EditorField label="Raw query">
|
||||
<div
|
||||
className={cx(styles.editorField, 'prism-syntax-highlight')}
|
||||
aria-label="selector"
|
||||
dangerouslySetInnerHTML={{ __html: highlighted }}
|
||||
/>
|
||||
<RawQuery query={query} lang={{ grammar: lokiGrammar, name: 'lokiql' }} />
|
||||
</EditorField>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
editorField: css({
|
||||
fontFamily: theme.typography.fontFamilyMonospace,
|
||||
fontSize: theme.typography.bodySmall.fontSize,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
@ -2,29 +2,39 @@ import React from 'react';
|
||||
|
||||
import { Stack } from '@grafana/experimental';
|
||||
|
||||
import promqlGrammar from '../../promql';
|
||||
import { promQueryModeller } from '../PromQueryModeller';
|
||||
import { buildVisualQueryFromString } from '../parsing';
|
||||
import { OperationExplainedBox } from '../shared/OperationExplainedBox';
|
||||
import { OperationListExplained } from '../shared/OperationListExplained';
|
||||
import { RawQuery } from '../shared/RawQuery';
|
||||
import { PromVisualQuery } from '../types';
|
||||
|
||||
export interface Props {
|
||||
query: string;
|
||||
nested?: boolean;
|
||||
}
|
||||
|
||||
export const PromQueryBuilderExplained = React.memo<Props>(({ query, nested }) => {
|
||||
export const PromQueryBuilderExplained = React.memo<Props>(({ query }) => {
|
||||
const visQuery = buildVisualQueryFromString(query || '').query;
|
||||
const lang = { grammar: promqlGrammar, name: 'promql' };
|
||||
|
||||
return (
|
||||
<Stack gap={0} direction="column">
|
||||
<Stack gap={0.5} direction="column">
|
||||
<OperationExplainedBox>
|
||||
<RawQuery query={query} lang={lang} />
|
||||
</OperationExplainedBox>
|
||||
<OperationExplainedBox
|
||||
stepNumber={1}
|
||||
title={`${visQuery.metric} ${promQueryModeller.renderLabels(visQuery.labels)}`}
|
||||
title={<RawQuery query={`${visQuery.metric} ${promQueryModeller.renderLabels(visQuery.labels)}`} lang={lang} />}
|
||||
>
|
||||
Fetch all series matching metric name and label filters.
|
||||
</OperationExplainedBox>
|
||||
<OperationListExplained<PromVisualQuery> stepNumber={2} queryModeller={promQueryModeller} query={visQuery} />
|
||||
<OperationListExplained<PromVisualQuery>
|
||||
stepNumber={2}
|
||||
queryModeller={promQueryModeller}
|
||||
query={visQuery}
|
||||
lang={lang}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
});
|
||||
|
@ -1,42 +1,22 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import Prism from 'prismjs';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { EditorField, EditorFieldGroup, EditorRow } from '@grafana/experimental';
|
||||
import { useTheme2 } from '@grafana/ui';
|
||||
|
||||
import { promqlGrammar } from '../../promql';
|
||||
import promqlGrammar from '../../promql';
|
||||
import { RawQuery } from '../shared/RawQuery';
|
||||
|
||||
export interface Props {
|
||||
query: string;
|
||||
}
|
||||
|
||||
export function QueryPreview({ query }: Props) {
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme);
|
||||
const highlighted = Prism.highlight(query, promqlGrammar, 'promql');
|
||||
|
||||
return (
|
||||
<EditorRow>
|
||||
<EditorFieldGroup>
|
||||
<EditorField label="Raw query">
|
||||
<div
|
||||
className={cx(styles.editorField, 'prism-syntax-highlight')}
|
||||
aria-label="selector"
|
||||
dangerouslySetInnerHTML={{ __html: highlighted }}
|
||||
/>
|
||||
<RawQuery query={query} lang={{ grammar: promqlGrammar, name: 'promql' }} />
|
||||
</EditorField>
|
||||
</EditorFieldGroup>
|
||||
</EditorRow>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
editorField: css({
|
||||
fontFamily: theme.typography.fontFamilyMonospace,
|
||||
fontSize: theme.typography.bodySmall.fontSize,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
@ -5,10 +5,10 @@ import { GrafanaTheme2, renderMarkdown } from '@grafana/data';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
title?: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
markdown?: string;
|
||||
stepNumber: number;
|
||||
stepNumber?: number;
|
||||
}
|
||||
|
||||
export function OperationExplainedBox({ title, stepNumber, markdown, children }: Props) {
|
||||
@ -16,11 +16,13 @@ export function OperationExplainedBox({ title, stepNumber, markdown, children }:
|
||||
|
||||
return (
|
||||
<div className={styles.box}>
|
||||
<div className={styles.stepNumber}>{stepNumber}</div>
|
||||
{stepNumber !== undefined && <div className={styles.stepNumber}>{stepNumber}</div>}
|
||||
<div className={styles.boxInner}>
|
||||
<div className={styles.header}>
|
||||
<span>{title}</span>
|
||||
</div>
|
||||
{title && (
|
||||
<div className={styles.header}>
|
||||
<span>{title}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.body}>
|
||||
{markdown && <div dangerouslySetInnerHTML={{ __html: renderMarkdown(markdown) }}></div>}
|
||||
{children}
|
||||
@ -37,7 +39,6 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
padding: theme.spacing(1),
|
||||
borderRadius: theme.shape.borderRadius(),
|
||||
position: 'relative',
|
||||
marginBottom: theme.spacing(0.5),
|
||||
}),
|
||||
boxInner: css({
|
||||
marginLeft: theme.spacing(4),
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { Grammar } from 'prismjs';
|
||||
import React from 'react';
|
||||
|
||||
import { OperationExplainedBox } from './OperationExplainedBox';
|
||||
import { RawQuery } from './RawQuery';
|
||||
import { QueryWithOperations, VisualQueryModeller } from './types';
|
||||
|
||||
export interface Props<T extends QueryWithOperations> {
|
||||
@ -8,9 +10,18 @@ export interface Props<T extends QueryWithOperations> {
|
||||
queryModeller: VisualQueryModeller;
|
||||
explainMode?: boolean;
|
||||
stepNumber: number;
|
||||
lang: {
|
||||
grammar: Grammar;
|
||||
name: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function OperationListExplained<T extends QueryWithOperations>({ query, queryModeller, stepNumber }: Props<T>) {
|
||||
export function OperationListExplained<T extends QueryWithOperations>({
|
||||
query,
|
||||
queryModeller,
|
||||
stepNumber,
|
||||
lang,
|
||||
}: Props<T>) {
|
||||
return (
|
||||
<>
|
||||
{query.operations.map((op, index) => {
|
||||
@ -21,7 +32,14 @@ export function OperationListExplained<T extends QueryWithOperations>({ query, q
|
||||
const title = def.renderer(op, def, '<expr>');
|
||||
const body = def.explainHandler ? def.explainHandler(op, def) : def.documentation ?? 'no docs';
|
||||
|
||||
return <OperationExplainedBox stepNumber={index + stepNumber} key={index} title={title} markdown={body} />;
|
||||
return (
|
||||
<OperationExplainedBox
|
||||
stepNumber={index + stepNumber}
|
||||
key={index}
|
||||
title={<RawQuery query={title} lang={lang} />}
|
||||
markdown={body}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
|
@ -0,0 +1,36 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import Prism, { Grammar } from 'prismjs';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data/src';
|
||||
import { useTheme2 } from '@grafana/ui/src';
|
||||
|
||||
export interface Props {
|
||||
query: string;
|
||||
lang: {
|
||||
grammar: Grammar;
|
||||
name: string;
|
||||
};
|
||||
}
|
||||
export function RawQuery({ query, lang }: Props) {
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme);
|
||||
const highlighted = Prism.highlight(query, lang.grammar, lang.name);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(styles.editorField, 'prism-syntax-highlight')}
|
||||
aria-label="selector"
|
||||
dangerouslySetInnerHTML={{ __html: highlighted }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
editorField: css({
|
||||
fontFamily: theme.typography.fontFamilyMonospace,
|
||||
fontSize: theme.typography.bodySmall.fontSize,
|
||||
}),
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user