Prometheus/Loki: Add raw query and syntax highlight in explain mode (#50070)

pull/50084/head
Andrej Ocenas 3 years ago committed by GitHub
parent c63071f519
commit cc90f9bb69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderExplained.tsx
  2. 24
      public/app/plugins/datasource/loki/querybuilder/components/QueryPreview.tsx
  3. 20
      public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderExplained.tsx
  4. 26
      public/app/plugins/datasource/prometheus/querybuilder/components/QueryPreview.tsx
  5. 15
      public/app/plugins/datasource/prometheus/querybuilder/shared/OperationExplainedBox.tsx
  6. 22
      public/app/plugins/datasource/prometheus/querybuilder/shared/OperationListExplained.tsx
  7. 36
      public/app/plugins/datasource/prometheus/querybuilder/shared/RawQuery.tsx

@ -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…
Cancel
Save