diff --git a/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx b/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx
index ba84fa6f830..e401eb8bcc6 100644
--- a/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx
+++ b/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx
@@ -1,9 +1,9 @@
// Libraries
import React, { memo } from 'react';
-
// Types
import { LokiQuery } from '../types';
-import { LokiQueryFieldForm } from './LokiQueryFieldForm';
+import { LokiQueryField } from './LokiQueryField';
+import { LokiOptionFields } from './LokiOptionFields';
import LokiDatasource from '../datasource';
interface Props {
@@ -18,7 +18,7 @@ export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEdito
const { expr, maxLines, instant, datasource, onChange } = props;
// Timerange to get existing labels from. Hard coding like this seems to be good enough right now.
- const absolute = {
+ const absoluteRange = {
from: Date.now() - 10000,
to: Date.now(),
};
@@ -31,13 +31,23 @@ export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEdito
};
return (
- {}}
+ onBlur={() => {}}
history={[]}
- absoluteRange={absolute}
+ absoluteRange={absoluteRange}
+ ExtraFieldElement={
+ {}}
+ onChange={onChange}
+ />
+ }
/>
);
diff --git a/public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.tsx b/public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.tsx
index 4ade8c83841..ab8e20098c4 100644
--- a/public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.tsx
@@ -6,11 +6,13 @@ import { ExploreQueryFieldProps } from '@grafana/data';
import { LokiDatasource } from '../datasource';
import { LokiQuery, LokiOptions } from '../types';
import { LokiQueryField } from './LokiQueryField';
+import { LokiOptionFields } from './LokiOptionFields';
type Props = ExploreQueryFieldProps;
export function LokiExploreQueryEditor(props: Props) {
const { range, query, data, datasource, history, onChange, onRunQuery } = props;
+ const absoluteTimeRange = { from: range!.from!.valueOf(), to: range!.to!.valueOf() }; // Range here is never optional
return (
+ }
/>
);
}
diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx
index 67ded1bd8ad..fc1afe27570 100644
--- a/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx
@@ -7,11 +7,13 @@ import { InlineFormLabel } from '@grafana/ui';
import { LokiDatasource } from '../datasource';
import { LokiQuery, LokiOptions } from '../types';
import { LokiQueryField } from './LokiQueryField';
+import { LokiOptionFields } from './LokiOptionFields';
type Props = QueryEditorProps;
export function LokiQueryEditor(props: Props) {
const { range, query, data, datasource, onChange, onRunQuery } = props;
+ const absoluteTimeRange = { from: range!.from!.valueOf(), to: range!.to!.valueOf() }; // Range here is never optional
const onLegendChange = (e: React.SyntheticEvent) => {
const nextQuery = { ...query, legendFormat: e.currentTarget.value };
@@ -49,9 +51,20 @@ export function LokiQueryEditor(props: Props) {
onBlur={onRunQuery}
history={[]}
data={data}
- range={range}
- runOnBlur={true}
- ExtraFieldElement={legendField}
+ absoluteRange={absoluteTimeRange}
+ ExtraFieldElement={
+ <>
+
+ {legendField}
+ >
+ }
/>
);
}
diff --git a/public/app/plugins/datasource/loki/components/LokiQueryField.tsx b/public/app/plugins/datasource/loki/components/LokiQueryField.tsx
index 37946b487ce..bfce16b58d1 100644
--- a/public/app/plugins/datasource/loki/components/LokiQueryField.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiQueryField.tsx
@@ -1,16 +1,185 @@
-import React, { FunctionComponent } from 'react';
-import { LokiQueryFieldForm, LokiQueryFieldFormProps } from './LokiQueryFieldForm';
+// Libraries
+import React, { ReactNode } from 'react';
-type LokiQueryFieldProps = Omit<
- LokiQueryFieldFormProps,
- 'labelsLoaded' | 'onLoadOptions' | 'onLabelsRefresh' | 'absoluteRange'
->;
+import {
+ SlatePrism,
+ TypeaheadOutput,
+ SuggestionsState,
+ QueryField,
+ TypeaheadInput,
+ BracesPlugin,
+ DOMUtil,
+ Icon,
+} from '@grafana/ui';
-export const LokiQueryField: FunctionComponent = (props) => {
- const { datasource, range, ...otherProps } = props;
- const absoluteTimeRange = { from: range!.from!.valueOf(), to: range!.to!.valueOf() }; // Range here is never optional
+// Utils & Services
+// dom also includes Element polyfills
+import { Plugin, Node } from 'slate';
+import { LokiLabelBrowser } from './LokiLabelBrowser';
- return ;
-};
+// Types
+import { ExploreQueryFieldProps, AbsoluteTimeRange } from '@grafana/data';
+import { LokiQuery, LokiOptions } from '../types';
+import { LanguageMap, languages as prismLanguages } from 'prismjs';
+import LokiLanguageProvider, { LokiHistoryItem } from '../language_provider';
+import LokiDatasource from '../datasource';
-export default LokiQueryField;
+function getChooserText(hasSyntax: boolean, hasLogLabels: boolean) {
+ if (!hasSyntax) {
+ return 'Loading labels...';
+ }
+ if (!hasLogLabels) {
+ return '(No logs found)';
+ }
+ return 'Log browser';
+}
+
+function willApplySuggestion(suggestion: string, { typeaheadContext, typeaheadText }: SuggestionsState): string {
+ // Modify suggestion based on context
+ switch (typeaheadContext) {
+ case 'context-labels': {
+ const nextChar = DOMUtil.getNextCharacter();
+ if (!nextChar || nextChar === '}' || nextChar === ',') {
+ suggestion += '=';
+ }
+ break;
+ }
+
+ case 'context-label-values': {
+ // Always add quotes and remove existing ones instead
+ if (!typeaheadText.match(/^(!?=~?"|")/)) {
+ suggestion = `"${suggestion}`;
+ }
+ if (DOMUtil.getNextCharacter() !== '"') {
+ suggestion = `${suggestion}"`;
+ }
+ break;
+ }
+
+ default:
+ }
+ return suggestion;
+}
+
+export interface LokiQueryFieldProps extends ExploreQueryFieldProps {
+ history: LokiHistoryItem[];
+ absoluteRange: AbsoluteTimeRange;
+ ExtraFieldElement?: ReactNode;
+}
+
+interface LokiQueryFieldState {
+ labelsLoaded: boolean;
+ labelBrowserVisible: boolean;
+}
+
+export class LokiQueryField extends React.PureComponent {
+ plugins: Plugin[];
+
+ constructor(props: LokiQueryFieldProps) {
+ super(props);
+
+ this.state = { labelsLoaded: false, labelBrowserVisible: false };
+
+ this.plugins = [
+ BracesPlugin(),
+ SlatePrism(
+ {
+ onlyIn: (node: Node) => node.object === 'block' && node.type === 'code_block',
+ getSyntax: (node: Node) => 'logql',
+ },
+ { ...(prismLanguages as LanguageMap), logql: this.props.datasource.languageProvider.getSyntax() }
+ ),
+ ];
+ }
+
+ async componentDidUpdate() {
+ await this.props.datasource.languageProvider.start();
+ this.setState({ labelsLoaded: true });
+ }
+
+ onChangeLogLabels = (selector: string) => {
+ this.onChangeQuery(selector, true);
+ this.setState({ labelBrowserVisible: false });
+ };
+
+ onChangeQuery = (value: string, override?: boolean) => {
+ // Send text change to parent
+ const { query, onChange, onRunQuery } = this.props;
+ if (onChange) {
+ const nextQuery = { ...query, expr: value };
+ onChange(nextQuery);
+
+ if (override && onRunQuery) {
+ onRunQuery();
+ }
+ }
+ };
+
+ onClickChooserButton = () => {
+ this.setState((state) => ({ labelBrowserVisible: !state.labelBrowserVisible }));
+ };
+
+ onTypeahead = async (typeahead: TypeaheadInput): Promise => {
+ const { datasource } = this.props;
+
+ if (!datasource.languageProvider) {
+ return { suggestions: [] };
+ }
+
+ const lokiLanguageProvider = datasource.languageProvider as LokiLanguageProvider;
+ const { history } = this.props;
+ const { prefix, text, value, wrapperClasses, labelKey } = typeahead;
+
+ const result = await lokiLanguageProvider.provideCompletionItems(
+ { text, value, prefix, wrapperClasses, labelKey },
+ { history }
+ );
+ return result;
+ };
+
+ render() {
+ const { ExtraFieldElement, query, datasource } = this.props;
+ const { labelsLoaded, labelBrowserVisible } = this.state;
+ const lokiLanguageProvider = datasource.languageProvider as LokiLanguageProvider;
+ const cleanText = datasource.languageProvider ? lokiLanguageProvider.cleanText : undefined;
+ const hasLogLabels = lokiLanguageProvider.getLabelKeys().length > 0;
+ const chooserText = getChooserText(labelsLoaded, hasLogLabels);
+ const buttonDisabled = !(labelsLoaded && hasLogLabels);
+
+ return (
+ <>
+
+
+ {chooserText}
+
+
+
+
+
+
+ {labelBrowserVisible && (
+
+
+
+ )}
+
+ {ExtraFieldElement}
+ >
+ );
+ }
+}
diff --git a/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx b/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx
deleted file mode 100644
index 1da18e0e764..00000000000
--- a/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx
+++ /dev/null
@@ -1,194 +0,0 @@
-// Libraries
-import React, { ReactNode } from 'react';
-
-import {
- SlatePrism,
- TypeaheadOutput,
- SuggestionsState,
- QueryField,
- TypeaheadInput,
- BracesPlugin,
- DOMUtil,
- Icon,
-} from '@grafana/ui';
-
-// Utils & Services
-// dom also includes Element polyfills
-import { Plugin, Node } from 'slate';
-import { LokiLabelBrowser } from './LokiLabelBrowser';
-
-// Types
-import { ExploreQueryFieldProps, AbsoluteTimeRange } from '@grafana/data';
-import { LokiQuery, LokiOptions } from '../types';
-import { LanguageMap, languages as prismLanguages } from 'prismjs';
-import LokiLanguageProvider, { LokiHistoryItem } from '../language_provider';
-import LokiDatasource from '../datasource';
-import LokiOptionFields from './LokiOptionFields';
-
-function getChooserText(hasSyntax: boolean, hasLogLabels: boolean) {
- if (!hasSyntax) {
- return 'Loading labels...';
- }
- if (!hasLogLabels) {
- return '(No logs found)';
- }
- return 'Log browser';
-}
-
-function willApplySuggestion(suggestion: string, { typeaheadContext, typeaheadText }: SuggestionsState): string {
- // Modify suggestion based on context
- switch (typeaheadContext) {
- case 'context-labels': {
- const nextChar = DOMUtil.getNextCharacter();
- if (!nextChar || nextChar === '}' || nextChar === ',') {
- suggestion += '=';
- }
- break;
- }
-
- case 'context-label-values': {
- // Always add quotes and remove existing ones instead
- if (!typeaheadText.match(/^(!?=~?"|")/)) {
- suggestion = `"${suggestion}`;
- }
- if (DOMUtil.getNextCharacter() !== '"') {
- suggestion = `${suggestion}"`;
- }
- break;
- }
-
- default:
- }
- return suggestion;
-}
-
-export interface LokiQueryFieldFormProps extends ExploreQueryFieldProps {
- history: LokiHistoryItem[];
- absoluteRange: AbsoluteTimeRange;
- ExtraFieldElement?: ReactNode;
- runOnBlur?: boolean;
-}
-
-interface LokiQueryFieldFormState {
- labelsLoaded: boolean;
- labelBrowserVisible: boolean;
-}
-
-export class LokiQueryFieldForm extends React.PureComponent {
- plugins: Plugin[];
-
- constructor(props: LokiQueryFieldFormProps) {
- super(props);
-
- this.state = { labelsLoaded: false, labelBrowserVisible: false };
-
- this.plugins = [
- BracesPlugin(),
- SlatePrism(
- {
- onlyIn: (node: Node) => node.object === 'block' && node.type === 'code_block',
- getSyntax: (node: Node) => 'logql',
- },
- { ...(prismLanguages as LanguageMap), logql: this.props.datasource.languageProvider.getSyntax() }
- ),
- ];
- }
-
- async componentDidUpdate() {
- await this.props.datasource.languageProvider.start();
- this.setState({ labelsLoaded: true });
- }
-
- onChangeLogLabels = (selector: string) => {
- this.onChangeQuery(selector, true);
- this.setState({ labelBrowserVisible: false });
- };
-
- onChangeQuery = (value: string, override?: boolean) => {
- // Send text change to parent
- const { query, onChange, onRunQuery } = this.props;
- if (onChange) {
- const nextQuery = { ...query, expr: value };
- onChange(nextQuery);
-
- if (override && onRunQuery) {
- onRunQuery();
- }
- }
- };
-
- onClickChooserButton = () => {
- this.setState((state) => ({ labelBrowserVisible: !state.labelBrowserVisible }));
- };
-
- onTypeahead = async (typeahead: TypeaheadInput): Promise => {
- const { datasource } = this.props;
-
- if (!datasource.languageProvider) {
- return { suggestions: [] };
- }
-
- const lokiLanguageProvider = datasource.languageProvider as LokiLanguageProvider;
- const { history } = this.props;
- const { prefix, text, value, wrapperClasses, labelKey } = typeahead;
-
- const result = await lokiLanguageProvider.provideCompletionItems(
- { text, value, prefix, wrapperClasses, labelKey },
- { history }
- );
- return result;
- };
-
- render() {
- const { ExtraFieldElement, query, datasource, runOnBlur } = this.props;
- const { labelsLoaded, labelBrowserVisible } = this.state;
- const lokiLanguageProvider = datasource.languageProvider as LokiLanguageProvider;
- const cleanText = datasource.languageProvider ? lokiLanguageProvider.cleanText : undefined;
- const hasLogLabels = lokiLanguageProvider.getLabelKeys().length > 0;
- const chooserText = getChooserText(labelsLoaded, hasLogLabels);
- const buttonDisabled = !(labelsLoaded && hasLogLabels);
-
- return (
- <>
-
-
- {chooserText}
-
-
-
-
-
-
- {labelBrowserVisible && (
-
-
-
- )}
-
- {ExtraFieldElement}
- >
- );
- }
-}
diff --git a/public/app/plugins/datasource/loki/components/__snapshots__/LokiExploreQueryEditor.test.tsx.snap b/public/app/plugins/datasource/loki/components/__snapshots__/LokiExploreQueryEditor.test.tsx.snap
index 5b3345352fd..4e70de00a8d 100644
--- a/public/app/plugins/datasource/loki/components/__snapshots__/LokiExploreQueryEditor.test.tsx.snap
+++ b/public/app/plugins/datasource/loki/components/__snapshots__/LokiExploreQueryEditor.test.tsx.snap
@@ -2,6 +2,27 @@
exports[`LokiExploreQueryEditor should render component 1`] = `
+ }
+ absoluteRange={
+ Object {
+ "from": 1577836800000,
+ "to": 1577923200000,
+ }
+ }
data={
Object {
"request": Object {
@@ -98,15 +119,5 @@ exports[`LokiExploreQueryEditor should render component 1`] = `
"refId": "A",
}
}
- range={
- Object {
- "from": "2020-01-01T00:00:00.000Z",
- "raw": Object {
- "from": "2020-01-01T00:00:00.000Z",
- "to": "2020-01-02T00:00:00.000Z",
- },
- "to": "2020-01-02T00:00:00.000Z",
- }
- }
/>
`;
diff --git a/public/app/plugins/datasource/loki/components/__snapshots__/LokiQueryEditor.test.tsx.snap b/public/app/plugins/datasource/loki/components/__snapshots__/LokiQueryEditor.test.tsx.snap
index c22188a19bd..a42bb5b248c 100644
--- a/public/app/plugins/datasource/loki/components/__snapshots__/LokiQueryEditor.test.tsx.snap
+++ b/public/app/plugins/datasource/loki/components/__snapshots__/LokiQueryEditor.test.tsx.snap
@@ -3,29 +3,51 @@
exports[`Render LokiQueryEditor with legend should render 1`] = `
+
+
-
- Legend
-
-
+
+ Legend
+
+
+
-
+
+ }
+ absoluteRange={
+ Object {
+ "from": 1577836800000,
+ "to": 1577923200000,
+ }
}
datasource={Object {}}
history={Array []}
@@ -39,42 +61,57 @@ exports[`Render LokiQueryEditor with legend should render 1`] = `
"refId": "A",
}
}
- range={
- Object {
- "from": "2020-01-01T00:00:00.000Z",
- "to": "2020-01-02T00:00:00.000Z",
- }
- }
- runOnBlur={true}
/>
`;
exports[`Render LokiQueryEditor with legend should update timerange 1`] = `
+
+
-
- Legend
-
-
+
+ Legend
+
+
+
-
+
+ }
+ absoluteRange={
+ Object {
+ "from": 1546300800000,
+ "to": 1577923200000,
+ }
}
datasource={Object {}}
history={Array []}
@@ -88,12 +125,5 @@ exports[`Render LokiQueryEditor with legend should update timerange 1`] = `
"refId": "A",
}
}
- range={
- Object {
- "from": "2019-01-01T00:00:00.000Z",
- "to": "2020-01-02T00:00:00.000Z",
- }
- }
- runOnBlur={true}
/>
`;
diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx
index 7fdcaf24dd4..b3ed70825a2 100644
--- a/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx
+++ b/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx
@@ -110,92 +110,91 @@ export class PromQueryEditor extends PureComponent {
const { formatOption, instant, interval, intervalFactorOption, legendFormat, exemplar } = this.state;
return (
-
-
-
-
-
-
+
+
- Legend
-
-
-
-
-
-
- An additional lower limit for the step parameter of the Prometheus query and for the{' '}
- $__interval and $__rate_interval variables. The limit is absolute and not
- modified by the "Resolution" setting.
- >
- }
- >
- Min step
-
-
-
-
-
-
-
-
Format
-
-
-
-
-
+ Legend
+
+
-
-
+
-
-
-
+
+
+ An additional lower limit for the step parameter of the Prometheus query and for the{' '}
+ $__interval and $__rate_interval variables. The limit is absolute and not
+ modified by the "Resolution" setting.
+ >
+ }
+ >
+ Min step
+
+
+
+
+
+
+
+
+
+
+ }
+ />
);
}
}
diff --git a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap
index 4b6beed89eb..a3f1dffa559 100644
--- a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap
+++ b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap
@@ -1,197 +1,197 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render PromQueryEditor with basic options should render 1`] = `
-
-
-
-
-
- An additional lower limit for the step parameter of the Prometheus query and for the
-
-
- $__interval
-
- and
-
- $__rate_interval
-
- variables. The limit is absolute and not modified by the "Resolution" setting.
-
- }
- width={7}
- >
- Min step
-
-
-
-
+
-
-
+
+
-
-
+ isEnabled={true}
+ onChange={[Function]}
+ />
+
+ }
+ datasource={
+ Object {
+ "createQuery": [MockFunction],
+ "getPrometheusTime": [MockFunction],
+ }
+ }
+ history={Array []}
+ onChange={[Function]}
+ onRunQuery={[Function]}
+ query={
+ Object {
+ "expr": "",
+ "refId": "A",
+ }
+ }
+/>
`;