mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Refactor query editor so query field can be used independently (#33276)
* Refactor Loki so LokiQueryField can be used independently * Refactor PromQueryEditor
This commit is contained in:
parent
c809d63065
commit
c32c682f81
@ -1,9 +1,9 @@
|
|||||||
// Libraries
|
// Libraries
|
||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { LokiQuery } from '../types';
|
import { LokiQuery } from '../types';
|
||||||
import { LokiQueryFieldForm } from './LokiQueryFieldForm';
|
import { LokiQueryField } from './LokiQueryField';
|
||||||
|
import { LokiOptionFields } from './LokiOptionFields';
|
||||||
import LokiDatasource from '../datasource';
|
import LokiDatasource from '../datasource';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -18,7 +18,7 @@ export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEdito
|
|||||||
const { expr, maxLines, instant, datasource, onChange } = props;
|
const { expr, maxLines, instant, datasource, onChange } = props;
|
||||||
|
|
||||||
// Timerange to get existing labels from. Hard coding like this seems to be good enough right now.
|
// 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,
|
from: Date.now() - 10000,
|
||||||
to: Date.now(),
|
to: Date.now(),
|
||||||
};
|
};
|
||||||
@ -31,13 +31,23 @@ export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEdito
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="gf-form-group">
|
<div className="gf-form-group">
|
||||||
<LokiQueryFieldForm
|
<LokiQueryField
|
||||||
datasource={datasource}
|
datasource={datasource}
|
||||||
query={queryWithRefId}
|
query={queryWithRefId}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onRunQuery={() => {}}
|
onRunQuery={() => {}}
|
||||||
|
onBlur={() => {}}
|
||||||
history={[]}
|
history={[]}
|
||||||
absoluteRange={absolute}
|
absoluteRange={absoluteRange}
|
||||||
|
ExtraFieldElement={
|
||||||
|
<LokiOptionFields
|
||||||
|
queryType={queryWithRefId.instant ? 'instant' : 'range'}
|
||||||
|
lineLimitValue={queryWithRefId?.maxLines?.toString() || ''}
|
||||||
|
query={queryWithRefId}
|
||||||
|
onRunQuery={() => {}}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -6,11 +6,13 @@ import { ExploreQueryFieldProps } from '@grafana/data';
|
|||||||
import { LokiDatasource } from '../datasource';
|
import { LokiDatasource } from '../datasource';
|
||||||
import { LokiQuery, LokiOptions } from '../types';
|
import { LokiQuery, LokiOptions } from '../types';
|
||||||
import { LokiQueryField } from './LokiQueryField';
|
import { LokiQueryField } from './LokiQueryField';
|
||||||
|
import { LokiOptionFields } from './LokiOptionFields';
|
||||||
|
|
||||||
type Props = ExploreQueryFieldProps<LokiDatasource, LokiQuery, LokiOptions>;
|
type Props = ExploreQueryFieldProps<LokiDatasource, LokiQuery, LokiOptions>;
|
||||||
|
|
||||||
export function LokiExploreQueryEditor(props: Props) {
|
export function LokiExploreQueryEditor(props: Props) {
|
||||||
const { range, query, data, datasource, history, onChange, onRunQuery } = 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 (
|
return (
|
||||||
<LokiQueryField
|
<LokiQueryField
|
||||||
@ -21,7 +23,16 @@ export function LokiExploreQueryEditor(props: Props) {
|
|||||||
onRunQuery={onRunQuery}
|
onRunQuery={onRunQuery}
|
||||||
history={history}
|
history={history}
|
||||||
data={data}
|
data={data}
|
||||||
range={range}
|
absoluteRange={absoluteTimeRange}
|
||||||
|
ExtraFieldElement={
|
||||||
|
<LokiOptionFields
|
||||||
|
queryType={query.instant ? 'instant' : 'range'}
|
||||||
|
lineLimitValue={query?.maxLines?.toString() || ''}
|
||||||
|
query={query}
|
||||||
|
onRunQuery={onRunQuery}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,13 @@ import { InlineFormLabel } from '@grafana/ui';
|
|||||||
import { LokiDatasource } from '../datasource';
|
import { LokiDatasource } from '../datasource';
|
||||||
import { LokiQuery, LokiOptions } from '../types';
|
import { LokiQuery, LokiOptions } from '../types';
|
||||||
import { LokiQueryField } from './LokiQueryField';
|
import { LokiQueryField } from './LokiQueryField';
|
||||||
|
import { LokiOptionFields } from './LokiOptionFields';
|
||||||
|
|
||||||
type Props = QueryEditorProps<LokiDatasource, LokiQuery, LokiOptions>;
|
type Props = QueryEditorProps<LokiDatasource, LokiQuery, LokiOptions>;
|
||||||
|
|
||||||
export function LokiQueryEditor(props: Props) {
|
export function LokiQueryEditor(props: Props) {
|
||||||
const { range, query, data, datasource, onChange, onRunQuery } = 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<HTMLInputElement>) => {
|
const onLegendChange = (e: React.SyntheticEvent<HTMLInputElement>) => {
|
||||||
const nextQuery = { ...query, legendFormat: e.currentTarget.value };
|
const nextQuery = { ...query, legendFormat: e.currentTarget.value };
|
||||||
@ -49,9 +51,20 @@ export function LokiQueryEditor(props: Props) {
|
|||||||
onBlur={onRunQuery}
|
onBlur={onRunQuery}
|
||||||
history={[]}
|
history={[]}
|
||||||
data={data}
|
data={data}
|
||||||
range={range}
|
absoluteRange={absoluteTimeRange}
|
||||||
runOnBlur={true}
|
ExtraFieldElement={
|
||||||
ExtraFieldElement={legendField}
|
<>
|
||||||
|
<LokiOptionFields
|
||||||
|
queryType={query.instant ? 'instant' : 'range'}
|
||||||
|
lineLimitValue={query?.maxLines?.toString() || ''}
|
||||||
|
query={query}
|
||||||
|
onRunQuery={onRunQuery}
|
||||||
|
onChange={onChange}
|
||||||
|
runOnBlur={true}
|
||||||
|
/>
|
||||||
|
{legendField}
|
||||||
|
</>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,185 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
// Libraries
|
||||||
import { LokiQueryFieldForm, LokiQueryFieldFormProps } from './LokiQueryFieldForm';
|
import React, { ReactNode } from 'react';
|
||||||
|
|
||||||
type LokiQueryFieldProps = Omit<
|
import {
|
||||||
LokiQueryFieldFormProps,
|
SlatePrism,
|
||||||
'labelsLoaded' | 'onLoadOptions' | 'onLabelsRefresh' | 'absoluteRange'
|
TypeaheadOutput,
|
||||||
>;
|
SuggestionsState,
|
||||||
|
QueryField,
|
||||||
|
TypeaheadInput,
|
||||||
|
BracesPlugin,
|
||||||
|
DOMUtil,
|
||||||
|
Icon,
|
||||||
|
} from '@grafana/ui';
|
||||||
|
|
||||||
export const LokiQueryField: FunctionComponent<LokiQueryFieldProps> = (props) => {
|
// Utils & Services
|
||||||
const { datasource, range, ...otherProps } = props;
|
// dom also includes Element polyfills
|
||||||
const absoluteTimeRange = { from: range!.from!.valueOf(), to: range!.to!.valueOf() }; // Range here is never optional
|
import { Plugin, Node } from 'slate';
|
||||||
|
import { LokiLabelBrowser } from './LokiLabelBrowser';
|
||||||
|
|
||||||
return <LokiQueryFieldForm datasource={datasource} absoluteRange={absoluteTimeRange} {...otherProps} />;
|
// 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<LokiDatasource, LokiQuery, LokiOptions> {
|
||||||
|
history: LokiHistoryItem[];
|
||||||
|
absoluteRange: AbsoluteTimeRange;
|
||||||
|
ExtraFieldElement?: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LokiQueryFieldState {
|
||||||
|
labelsLoaded: boolean;
|
||||||
|
labelBrowserVisible: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, LokiQueryFieldState> {
|
||||||
|
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<TypeaheadOutput> => {
|
||||||
|
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 (
|
||||||
|
<>
|
||||||
|
<div className="gf-form-inline gf-form-inline--xs-view-flex-column flex-grow-1">
|
||||||
|
<button
|
||||||
|
className="gf-form-label query-keyword pointer"
|
||||||
|
onClick={this.onClickChooserButton}
|
||||||
|
disabled={buttonDisabled}
|
||||||
|
>
|
||||||
|
{chooserText}
|
||||||
|
<Icon name={labelBrowserVisible ? 'angle-down' : 'angle-right'} />
|
||||||
|
</button>
|
||||||
|
<div className="gf-form gf-form--grow flex-shrink-1 min-width-15">
|
||||||
|
<QueryField
|
||||||
|
additionalPlugins={this.plugins}
|
||||||
|
cleanText={cleanText}
|
||||||
|
query={query.expr}
|
||||||
|
onTypeahead={this.onTypeahead}
|
||||||
|
onWillApplySuggestion={willApplySuggestion}
|
||||||
|
onChange={this.onChangeQuery}
|
||||||
|
onBlur={this.props.onBlur}
|
||||||
|
onRunQuery={this.props.onRunQuery}
|
||||||
|
placeholder="Enter a Loki query (run with Shift+Enter)"
|
||||||
|
portalOrigin="loki"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{labelBrowserVisible && (
|
||||||
|
<div className="gf-form">
|
||||||
|
<LokiLabelBrowser languageProvider={lokiLanguageProvider} onChange={this.onChangeLogLabels} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{ExtraFieldElement}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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<LokiDatasource, LokiQuery, LokiOptions> {
|
|
||||||
history: LokiHistoryItem[];
|
|
||||||
absoluteRange: AbsoluteTimeRange;
|
|
||||||
ExtraFieldElement?: ReactNode;
|
|
||||||
runOnBlur?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LokiQueryFieldFormState {
|
|
||||||
labelsLoaded: boolean;
|
|
||||||
labelBrowserVisible: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LokiQueryFieldForm extends React.PureComponent<LokiQueryFieldFormProps, LokiQueryFieldFormState> {
|
|
||||||
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<TypeaheadOutput> => {
|
|
||||||
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 (
|
|
||||||
<>
|
|
||||||
<div className="gf-form-inline gf-form-inline--xs-view-flex-column flex-grow-1">
|
|
||||||
<button
|
|
||||||
className="gf-form-label query-keyword pointer"
|
|
||||||
onClick={this.onClickChooserButton}
|
|
||||||
disabled={buttonDisabled}
|
|
||||||
>
|
|
||||||
{chooserText}
|
|
||||||
<Icon name={labelBrowserVisible ? 'angle-down' : 'angle-right'} />
|
|
||||||
</button>
|
|
||||||
<div className="gf-form gf-form--grow flex-shrink-1 min-width-15">
|
|
||||||
<QueryField
|
|
||||||
additionalPlugins={this.plugins}
|
|
||||||
cleanText={cleanText}
|
|
||||||
query={query.expr}
|
|
||||||
onTypeahead={this.onTypeahead}
|
|
||||||
onWillApplySuggestion={willApplySuggestion}
|
|
||||||
onChange={this.onChangeQuery}
|
|
||||||
onBlur={this.props.onBlur}
|
|
||||||
onRunQuery={this.props.onRunQuery}
|
|
||||||
placeholder="Enter a Loki query (run with Shift+Enter)"
|
|
||||||
portalOrigin="loki"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{labelBrowserVisible && (
|
|
||||||
<div className="gf-form">
|
|
||||||
<LokiLabelBrowser languageProvider={lokiLanguageProvider} onChange={this.onChangeLogLabels} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<LokiOptionFields
|
|
||||||
queryType={query.instant ? 'instant' : 'range'}
|
|
||||||
lineLimitValue={query?.maxLines?.toString() || ''}
|
|
||||||
query={query}
|
|
||||||
onRunQuery={this.props.onRunQuery}
|
|
||||||
onChange={this.props.onChange}
|
|
||||||
runOnBlur={runOnBlur}
|
|
||||||
/>
|
|
||||||
{ExtraFieldElement}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,27 @@
|
|||||||
|
|
||||||
exports[`LokiExploreQueryEditor should render component 1`] = `
|
exports[`LokiExploreQueryEditor should render component 1`] = `
|
||||||
<LokiQueryField
|
<LokiQueryField
|
||||||
|
ExtraFieldElement={
|
||||||
|
<LokiOptionFields
|
||||||
|
lineLimitValue="0"
|
||||||
|
onChange={[MockFunction]}
|
||||||
|
onRunQuery={[MockFunction]}
|
||||||
|
query={
|
||||||
|
Object {
|
||||||
|
"expr": "",
|
||||||
|
"maxLines": 0,
|
||||||
|
"refId": "A",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queryType="range"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
absoluteRange={
|
||||||
|
Object {
|
||||||
|
"from": 1577836800000,
|
||||||
|
"to": 1577923200000,
|
||||||
|
}
|
||||||
|
}
|
||||||
data={
|
data={
|
||||||
Object {
|
Object {
|
||||||
"request": Object {
|
"request": Object {
|
||||||
@ -98,15 +119,5 @@ exports[`LokiExploreQueryEditor should render component 1`] = `
|
|||||||
"refId": "A",
|
"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",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
@ -3,29 +3,51 @@
|
|||||||
exports[`Render LokiQueryEditor with legend should render 1`] = `
|
exports[`Render LokiQueryEditor with legend should render 1`] = `
|
||||||
<LokiQueryField
|
<LokiQueryField
|
||||||
ExtraFieldElement={
|
ExtraFieldElement={
|
||||||
<div
|
<React.Fragment>
|
||||||
className="gf-form-inline"
|
<LokiOptionFields
|
||||||
>
|
lineLimitValue=""
|
||||||
|
onChange={[MockFunction]}
|
||||||
|
onRunQuery={[MockFunction]}
|
||||||
|
query={
|
||||||
|
Object {
|
||||||
|
"expr": "",
|
||||||
|
"legendFormat": "My Legend",
|
||||||
|
"refId": "A",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queryType="range"
|
||||||
|
runOnBlur={true}
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
className="gf-form"
|
className="gf-form-inline"
|
||||||
>
|
>
|
||||||
<FormLabel
|
<div
|
||||||
tooltip="Controls the name of the time series, using name or pattern. For example
|
className="gf-form"
|
||||||
{{hostname}} will be replaced with label value for the label hostname. The legend only applies to metric queries."
|
|
||||||
width={6}
|
|
||||||
>
|
>
|
||||||
Legend
|
<FormLabel
|
||||||
</FormLabel>
|
tooltip="Controls the name of the time series, using name or pattern. For example
|
||||||
<input
|
{{hostname}} will be replaced with label value for the label hostname. The legend only applies to metric queries."
|
||||||
className="gf-form-input"
|
width={6}
|
||||||
onBlur={[MockFunction]}
|
>
|
||||||
onChange={[Function]}
|
Legend
|
||||||
placeholder="legend format"
|
</FormLabel>
|
||||||
type="text"
|
<input
|
||||||
value="My Legend"
|
className="gf-form-input"
|
||||||
/>
|
onBlur={[MockFunction]}
|
||||||
|
onChange={[Function]}
|
||||||
|
placeholder="legend format"
|
||||||
|
type="text"
|
||||||
|
value="My Legend"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</React.Fragment>
|
||||||
|
}
|
||||||
|
absoluteRange={
|
||||||
|
Object {
|
||||||
|
"from": 1577836800000,
|
||||||
|
"to": 1577923200000,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
datasource={Object {}}
|
datasource={Object {}}
|
||||||
history={Array []}
|
history={Array []}
|
||||||
@ -39,42 +61,57 @@ exports[`Render LokiQueryEditor with legend should render 1`] = `
|
|||||||
"refId": "A",
|
"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`] = `
|
exports[`Render LokiQueryEditor with legend should update timerange 1`] = `
|
||||||
<LokiQueryField
|
<LokiQueryField
|
||||||
ExtraFieldElement={
|
ExtraFieldElement={
|
||||||
<div
|
<React.Fragment>
|
||||||
className="gf-form-inline"
|
<LokiOptionFields
|
||||||
>
|
lineLimitValue=""
|
||||||
|
onChange={[MockFunction]}
|
||||||
|
onRunQuery={[MockFunction]}
|
||||||
|
query={
|
||||||
|
Object {
|
||||||
|
"expr": "",
|
||||||
|
"legendFormat": "My Legend",
|
||||||
|
"refId": "A",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queryType="range"
|
||||||
|
runOnBlur={true}
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
className="gf-form"
|
className="gf-form-inline"
|
||||||
>
|
>
|
||||||
<FormLabel
|
<div
|
||||||
tooltip="Controls the name of the time series, using name or pattern. For example
|
className="gf-form"
|
||||||
{{hostname}} will be replaced with label value for the label hostname. The legend only applies to metric queries."
|
|
||||||
width={6}
|
|
||||||
>
|
>
|
||||||
Legend
|
<FormLabel
|
||||||
</FormLabel>
|
tooltip="Controls the name of the time series, using name or pattern. For example
|
||||||
<input
|
{{hostname}} will be replaced with label value for the label hostname. The legend only applies to metric queries."
|
||||||
className="gf-form-input"
|
width={6}
|
||||||
onBlur={[MockFunction]}
|
>
|
||||||
onChange={[Function]}
|
Legend
|
||||||
placeholder="legend format"
|
</FormLabel>
|
||||||
type="text"
|
<input
|
||||||
value="My Legend"
|
className="gf-form-input"
|
||||||
/>
|
onBlur={[MockFunction]}
|
||||||
|
onChange={[Function]}
|
||||||
|
placeholder="legend format"
|
||||||
|
type="text"
|
||||||
|
value="My Legend"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</React.Fragment>
|
||||||
|
}
|
||||||
|
absoluteRange={
|
||||||
|
Object {
|
||||||
|
"from": 1546300800000,
|
||||||
|
"to": 1577923200000,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
datasource={Object {}}
|
datasource={Object {}}
|
||||||
history={Array []}
|
history={Array []}
|
||||||
@ -88,12 +125,5 @@ exports[`Render LokiQueryEditor with legend should update timerange 1`] = `
|
|||||||
"refId": "A",
|
"refId": "A",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
range={
|
|
||||||
Object {
|
|
||||||
"from": "2019-01-01T00:00:00.000Z",
|
|
||||||
"to": "2020-01-02T00:00:00.000Z",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runOnBlur={true}
|
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
@ -110,92 +110,91 @@ export class PromQueryEditor extends PureComponent<Props, State> {
|
|||||||
const { formatOption, instant, interval, intervalFactorOption, legendFormat, exemplar } = this.state;
|
const { formatOption, instant, interval, intervalFactorOption, legendFormat, exemplar } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<PromQueryField
|
||||||
<PromQueryField
|
datasource={datasource}
|
||||||
datasource={datasource}
|
query={query}
|
||||||
query={query}
|
range={range}
|
||||||
range={range}
|
onRunQuery={this.onRunQuery}
|
||||||
onRunQuery={this.onRunQuery}
|
onChange={this.onFieldChange}
|
||||||
onChange={this.onFieldChange}
|
history={[]}
|
||||||
history={[]}
|
data={data}
|
||||||
data={data}
|
ExtraFieldElement={
|
||||||
/>
|
<div className="gf-form-inline">
|
||||||
|
<div className="gf-form">
|
||||||
<div className="gf-form-inline">
|
<InlineFormLabel
|
||||||
<div className="gf-form">
|
width={7}
|
||||||
<InlineFormLabel
|
tooltip="Controls the name of the time series, using name or pattern. For example
|
||||||
width={7}
|
|
||||||
tooltip="Controls the name of the time series, using name or pattern. For example
|
|
||||||
{{hostname}} will be replaced with label value for the label hostname."
|
{{hostname}} will be replaced with label value for the label hostname."
|
||||||
>
|
>
|
||||||
Legend
|
Legend
|
||||||
</InlineFormLabel>
|
</InlineFormLabel>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="gf-form-input"
|
className="gf-form-input"
|
||||||
placeholder="legend format"
|
placeholder="legend format"
|
||||||
value={legendFormat}
|
value={legendFormat}
|
||||||
onChange={this.onLegendChange}
|
onChange={this.onLegendChange}
|
||||||
onBlur={this.onRunQuery}
|
onBlur={this.onRunQuery}
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="gf-form">
|
|
||||||
<InlineFormLabel
|
|
||||||
width={7}
|
|
||||||
tooltip={
|
|
||||||
<>
|
|
||||||
An additional lower limit for the step parameter of the Prometheus query and for the{' '}
|
|
||||||
<code>$__interval</code> and <code>$__rate_interval</code> variables. The limit is absolute and not
|
|
||||||
modified by the "Resolution" setting.
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Min step
|
|
||||||
</InlineFormLabel>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="gf-form-input width-8"
|
|
||||||
placeholder={interval}
|
|
||||||
onChange={this.onIntervalChange}
|
|
||||||
onBlur={this.onRunQuery}
|
|
||||||
value={interval}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="gf-form">
|
|
||||||
<div className="gf-form-label">Resolution</div>
|
|
||||||
<Select
|
|
||||||
isSearchable={false}
|
|
||||||
options={INTERVAL_FACTOR_OPTIONS}
|
|
||||||
onChange={this.onIntervalFactorChange}
|
|
||||||
value={intervalFactorOption}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="gf-form">
|
|
||||||
<div className="gf-form-label width-7">Format</div>
|
|
||||||
<Select
|
|
||||||
width={16}
|
|
||||||
isSearchable={false}
|
|
||||||
options={FORMAT_OPTIONS}
|
|
||||||
onChange={this.onFormatChange}
|
|
||||||
value={formatOption}
|
|
||||||
/>
|
|
||||||
<Switch label="Instant" checked={instant} onChange={this.onInstantChange} />
|
|
||||||
|
|
||||||
<InlineFormLabel width={10} tooltip="Link to Graph in Prometheus">
|
|
||||||
<PromLink
|
|
||||||
datasource={datasource}
|
|
||||||
query={this.query} // Use modified query
|
|
||||||
panelData={data}
|
|
||||||
/>
|
/>
|
||||||
</InlineFormLabel>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<PromExemplarField isEnabled={exemplar} onChange={this.onExemplarChange} datasource={datasource} />
|
<div className="gf-form">
|
||||||
</div>
|
<InlineFormLabel
|
||||||
</div>
|
width={7}
|
||||||
|
tooltip={
|
||||||
|
<>
|
||||||
|
An additional lower limit for the step parameter of the Prometheus query and for the{' '}
|
||||||
|
<code>$__interval</code> and <code>$__rate_interval</code> variables. The limit is absolute and not
|
||||||
|
modified by the "Resolution" setting.
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Min step
|
||||||
|
</InlineFormLabel>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="gf-form-input width-8"
|
||||||
|
placeholder={interval}
|
||||||
|
onChange={this.onIntervalChange}
|
||||||
|
onBlur={this.onRunQuery}
|
||||||
|
value={interval}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="gf-form">
|
||||||
|
<div className="gf-form-label">Resolution</div>
|
||||||
|
<Select
|
||||||
|
isSearchable={false}
|
||||||
|
options={INTERVAL_FACTOR_OPTIONS}
|
||||||
|
onChange={this.onIntervalFactorChange}
|
||||||
|
value={intervalFactorOption}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="gf-form">
|
||||||
|
<div className="gf-form-label width-7">Format</div>
|
||||||
|
<Select
|
||||||
|
width={16}
|
||||||
|
isSearchable={false}
|
||||||
|
options={FORMAT_OPTIONS}
|
||||||
|
onChange={this.onFormatChange}
|
||||||
|
value={formatOption}
|
||||||
|
/>
|
||||||
|
<Switch label="Instant" checked={instant} onChange={this.onInstantChange} />
|
||||||
|
|
||||||
|
<InlineFormLabel width={10} tooltip="Link to Graph in Prometheus">
|
||||||
|
<PromLink
|
||||||
|
datasource={datasource}
|
||||||
|
query={this.query} // Use modified query
|
||||||
|
panelData={data}
|
||||||
|
/>
|
||||||
|
</InlineFormLabel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<PromExemplarField isEnabled={exemplar} onChange={this.onExemplarChange} datasource={datasource} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,197 +1,197 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Render PromQueryEditor with basic options should render 1`] = `
|
exports[`Render PromQueryEditor with basic options should render 1`] = `
|
||||||
<div>
|
<PromQueryField
|
||||||
<PromQueryField
|
ExtraFieldElement={
|
||||||
datasource={
|
|
||||||
Object {
|
|
||||||
"createQuery": [MockFunction],
|
|
||||||
"getPrometheusTime": [MockFunction],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
history={Array []}
|
|
||||||
onChange={[Function]}
|
|
||||||
onRunQuery={[Function]}
|
|
||||||
query={
|
|
||||||
Object {
|
|
||||||
"expr": "",
|
|
||||||
"refId": "A",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className="gf-form-inline"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
className="gf-form"
|
className="gf-form-inline"
|
||||||
>
|
|
||||||
<FormLabel
|
|
||||||
tooltip="Controls the name of the time series, using name or pattern. For example
|
|
||||||
{{hostname}} will be replaced with label value for the label hostname."
|
|
||||||
width={7}
|
|
||||||
>
|
|
||||||
Legend
|
|
||||||
</FormLabel>
|
|
||||||
<input
|
|
||||||
className="gf-form-input"
|
|
||||||
onBlur={[Function]}
|
|
||||||
onChange={[Function]}
|
|
||||||
placeholder="legend format"
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="gf-form"
|
|
||||||
>
|
|
||||||
<FormLabel
|
|
||||||
tooltip={
|
|
||||||
<React.Fragment>
|
|
||||||
An additional lower limit for the step parameter of the Prometheus query and for the
|
|
||||||
|
|
||||||
<code>
|
|
||||||
$__interval
|
|
||||||
</code>
|
|
||||||
and
|
|
||||||
<code>
|
|
||||||
$__rate_interval
|
|
||||||
</code>
|
|
||||||
variables. The limit is absolute and not modified by the "Resolution" setting.
|
|
||||||
</React.Fragment>
|
|
||||||
}
|
|
||||||
width={7}
|
|
||||||
>
|
|
||||||
Min step
|
|
||||||
</FormLabel>
|
|
||||||
<input
|
|
||||||
className="gf-form-input width-8"
|
|
||||||
onBlur={[Function]}
|
|
||||||
onChange={[Function]}
|
|
||||||
placeholder=""
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="gf-form"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="gf-form-label"
|
className="gf-form"
|
||||||
>
|
>
|
||||||
Resolution
|
<FormLabel
|
||||||
|
tooltip="Controls the name of the time series, using name or pattern. For example
|
||||||
|
{{hostname}} will be replaced with label value for the label hostname."
|
||||||
|
width={7}
|
||||||
|
>
|
||||||
|
Legend
|
||||||
|
</FormLabel>
|
||||||
|
<input
|
||||||
|
className="gf-form-input"
|
||||||
|
onBlur={[Function]}
|
||||||
|
onChange={[Function]}
|
||||||
|
placeholder="legend format"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Select
|
<div
|
||||||
isSearchable={false}
|
className="gf-form"
|
||||||
onChange={[Function]}
|
>
|
||||||
options={
|
<FormLabel
|
||||||
Array [
|
tooltip={
|
||||||
|
<React.Fragment>
|
||||||
|
An additional lower limit for the step parameter of the Prometheus query and for the
|
||||||
|
|
||||||
|
<code>
|
||||||
|
$__interval
|
||||||
|
</code>
|
||||||
|
and
|
||||||
|
<code>
|
||||||
|
$__rate_interval
|
||||||
|
</code>
|
||||||
|
variables. The limit is absolute and not modified by the "Resolution" setting.
|
||||||
|
</React.Fragment>
|
||||||
|
}
|
||||||
|
width={7}
|
||||||
|
>
|
||||||
|
Min step
|
||||||
|
</FormLabel>
|
||||||
|
<input
|
||||||
|
className="gf-form-input width-8"
|
||||||
|
onBlur={[Function]}
|
||||||
|
onChange={[Function]}
|
||||||
|
placeholder=""
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="gf-form"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="gf-form-label"
|
||||||
|
>
|
||||||
|
Resolution
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
isSearchable={false}
|
||||||
|
onChange={[Function]}
|
||||||
|
options={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"label": "1/1",
|
||||||
|
"value": 1,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"label": "1/2",
|
||||||
|
"value": 2,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"label": "1/3",
|
||||||
|
"value": 3,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"label": "1/4",
|
||||||
|
"value": 4,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"label": "1/5",
|
||||||
|
"value": 5,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"label": "1/10",
|
||||||
|
"value": 10,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
value={
|
||||||
Object {
|
Object {
|
||||||
"label": "1/1",
|
"label": "1/1",
|
||||||
"value": 1,
|
"value": 1,
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"label": "1/2",
|
|
||||||
"value": 2,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"label": "1/3",
|
|
||||||
"value": 3,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"label": "1/4",
|
|
||||||
"value": 4,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"label": "1/5",
|
|
||||||
"value": 5,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"label": "1/10",
|
|
||||||
"value": 10,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
value={
|
|
||||||
Object {
|
|
||||||
"label": "1/1",
|
|
||||||
"value": 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="gf-form"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="gf-form-label width-7"
|
|
||||||
>
|
|
||||||
Format
|
|
||||||
</div>
|
|
||||||
<Select
|
|
||||||
isSearchable={false}
|
|
||||||
onChange={[Function]}
|
|
||||||
options={
|
|
||||||
Array [
|
|
||||||
Object {
|
|
||||||
"label": "Time series",
|
|
||||||
"value": "time_series",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"label": "Table",
|
|
||||||
"value": "table",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"label": "Heatmap",
|
|
||||||
"value": "heatmap",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
value={
|
|
||||||
Object {
|
|
||||||
"label": "Time series",
|
|
||||||
"value": "time_series",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
width={16}
|
|
||||||
/>
|
|
||||||
<Switch
|
|
||||||
checked={false}
|
|
||||||
label="Instant"
|
|
||||||
onChange={[Function]}
|
|
||||||
/>
|
|
||||||
<FormLabel
|
|
||||||
tooltip="Link to Graph in Prometheus"
|
|
||||||
width={10}
|
|
||||||
>
|
|
||||||
<Memo(PromLink)
|
|
||||||
datasource={
|
|
||||||
Object {
|
|
||||||
"createQuery": [MockFunction],
|
|
||||||
"getPrometheusTime": [MockFunction],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
query={
|
|
||||||
Object {
|
|
||||||
"exemplar": true,
|
|
||||||
"expr": "",
|
|
||||||
"interval": "",
|
|
||||||
"legendFormat": "",
|
|
||||||
"refId": "A",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</FormLabel>
|
</div>
|
||||||
</div>
|
<div
|
||||||
<PromExemplarField
|
className="gf-form"
|
||||||
datasource={
|
>
|
||||||
Object {
|
<div
|
||||||
"createQuery": [MockFunction],
|
className="gf-form-label width-7"
|
||||||
"getPrometheusTime": [MockFunction],
|
>
|
||||||
|
Format
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
isSearchable={false}
|
||||||
|
onChange={[Function]}
|
||||||
|
options={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"label": "Time series",
|
||||||
|
"value": "time_series",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"label": "Table",
|
||||||
|
"value": "table",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"label": "Heatmap",
|
||||||
|
"value": "heatmap",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
Object {
|
||||||
|
"label": "Time series",
|
||||||
|
"value": "time_series",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
width={16}
|
||||||
|
/>
|
||||||
|
<Switch
|
||||||
|
checked={false}
|
||||||
|
label="Instant"
|
||||||
|
onChange={[Function]}
|
||||||
|
/>
|
||||||
|
<FormLabel
|
||||||
|
tooltip="Link to Graph in Prometheus"
|
||||||
|
width={10}
|
||||||
|
>
|
||||||
|
<Memo(PromLink)
|
||||||
|
datasource={
|
||||||
|
Object {
|
||||||
|
"createQuery": [MockFunction],
|
||||||
|
"getPrometheusTime": [MockFunction],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
query={
|
||||||
|
Object {
|
||||||
|
"exemplar": true,
|
||||||
|
"expr": "",
|
||||||
|
"interval": "",
|
||||||
|
"legendFormat": "",
|
||||||
|
"refId": "A",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormLabel>
|
||||||
|
</div>
|
||||||
|
<PromExemplarField
|
||||||
|
datasource={
|
||||||
|
Object {
|
||||||
|
"createQuery": [MockFunction],
|
||||||
|
"getPrometheusTime": [MockFunction],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
isEnabled={true}
|
||||||
isEnabled={true}
|
onChange={[Function]}
|
||||||
onChange={[Function]}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
}
|
||||||
</div>
|
datasource={
|
||||||
|
Object {
|
||||||
|
"createQuery": [MockFunction],
|
||||||
|
"getPrometheusTime": [MockFunction],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
history={Array []}
|
||||||
|
onChange={[Function]}
|
||||||
|
onRunQuery={[Function]}
|
||||||
|
query={
|
||||||
|
Object {
|
||||||
|
"expr": "",
|
||||||
|
"refId": "A",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
`;
|
`;
|
||||||
|
Loading…
Reference in New Issue
Block a user