Commit dbf04709 by Ivana Huckova Committed by GitHub

Chore: Remove unused Loki and Cloudwatch syntax providers (#29686)

* Remove syntax provider in Cloudwatch

* Remove syntax provider and refactor useLokiLabels
parent 854f6229
......@@ -7,8 +7,6 @@ import { InlineFormLabel } from '@grafana/ui';
import { CloudWatchDatasource } from '../datasource';
import { CloudWatchLogsQuery, CloudWatchQuery } from '../types';
import { CloudWatchLogsQueryField } from './LogsQueryField';
import { useCloudWatchSyntax } from '../useCloudwatchSyntax';
import { CloudWatchLanguageProvider } from '../language_provider';
import CloudWatchLink from './CloudWatchLink';
import { css } from 'emotion';
......@@ -36,11 +34,6 @@ export const CloudWatchLogsQueryEditor = memo(function CloudWatchLogsQueryEditor
};
}
const { isSyntaxReady, syntax } = useCloudWatchSyntax(
datasource.languageProvider as CloudWatchLanguageProvider,
absolute
);
return (
<CloudWatchLogsQueryField
exploreId={exploreId}
......@@ -52,8 +45,6 @@ export const CloudWatchLogsQueryEditor = memo(function CloudWatchLogsQueryEditor
history={[]}
data={data}
absoluteRange={absolute}
syntaxLoaded={isSyntaxReady}
syntax={syntax}
allowCustomValue={allowCustomValue}
ExtraFieldElement={
<InlineFormLabel className={`gf-form-label--btn ${labelClass}`} width="auto" tooltip="Link to Graph in AWS">
......
......@@ -17,8 +17,6 @@ describe('CloudWatchLogsQueryField', () => {
<CloudWatchLogsQueryField
history={[]}
absoluteRange={{ from: 1, to: 10 }}
syntaxLoaded={false}
syntax={{} as any}
exploreId={ExploreId.left}
datasource={
{
......@@ -153,8 +151,6 @@ describe('CloudWatchLogsQueryField', () => {
<CloudWatchLogsQueryField
history={[]}
absoluteRange={{ from: 1, to: 10 }}
syntaxLoaded={false}
syntax={{} as any}
exploreId={ExploreId.left}
datasource={
{
......
......@@ -24,7 +24,7 @@ import syntax from '../syntax';
import { ExploreQueryFieldProps, AbsoluteTimeRange, SelectableValue, AppEvents } from '@grafana/data';
import { CloudWatchQuery, CloudWatchLogsQuery } from '../types';
import { CloudWatchDatasource } from '../datasource';
import { Grammar, LanguageMap, languages as prismLanguages } from 'prismjs';
import { LanguageMap, languages as prismLanguages } from 'prismjs';
import { CloudWatchLanguageProvider } from '../language_provider';
import { css } from 'emotion';
import { ExploreId } from 'app/types';
......@@ -36,8 +36,6 @@ export interface CloudWatchLogsQueryFieldProps extends ExploreQueryFieldProps<Cl
absoluteRange: AbsoluteTimeRange;
onLabelsRefresh?: () => void;
ExtraFieldElement?: ReactNode;
syntaxLoaded: boolean;
syntax: Grammar | null;
exploreId: ExploreId;
allowCustomValue?: boolean;
}
......@@ -294,7 +292,7 @@ export class CloudWatchLogsQueryField extends React.PureComponent<CloudWatchLogs
};
render() {
const { ExtraFieldElement, data, query, syntaxLoaded, datasource, allowCustomValue } = this.props;
const { ExtraFieldElement, data, query, datasource, allowCustomValue } = this.props;
const {
selectedLogGroups,
availableLogGroups,
......@@ -375,7 +373,6 @@ export class CloudWatchLogsQueryField extends React.PureComponent<CloudWatchLogs
cleanText={cleanText}
placeholder="Enter a CloudWatch Logs Insights query (run with Shift+Enter)"
portalOrigin="cloudwatch"
syntaxLoaded={syntaxLoaded}
disabled={loadingLogGroups || selectedLogGroups.length === 0}
/>
</div>
......
import { useState, useEffect } from 'react';
import { Grammar } from 'prismjs';
import { AbsoluteTimeRange } from '@grafana/data';
import { useRefMounted } from 'app/core/hooks/useRefMounted';
import { CloudWatchLanguageProvider } from './language_provider';
/**
* Initialise the language provider. Returns a languageProviderInitialized boolean cause there does not seem other way
* to know if the provider is already initialised or not. By the initialisation it modifies the provided
* languageProvider directly.
*/
const useInitLanguageProvider = (languageProvider: CloudWatchLanguageProvider, absoluteRange: AbsoluteTimeRange) => {
const mounted = useRefMounted();
const [languageProviderInitialized, setLanguageProviderInitialized] = useState(false);
// Async
const initializeLanguageProvider = async () => {
languageProvider.initialRange = absoluteRange;
await languageProvider.start();
if (mounted.current) {
setLanguageProviderInitialized(true);
}
};
useEffect(() => {
initializeLanguageProvider();
}, []);
return languageProviderInitialized;
};
/**
* Returns syntax from languageProvider and initialises global Prism syntax. Waits until languageProvider itself is
* initialised (outside of this hook).
*/
const useCloudwatchSyntax = (languageProvider: CloudWatchLanguageProvider, languageProviderInitialized: boolean) => {
// State
const [syntax, setSyntax] = useState<Grammar | null>(null);
// Effects
useEffect(() => {
if (languageProviderInitialized) {
const syntax = languageProvider.getSyntax();
setSyntax(syntax);
}
}, [languageProviderInitialized, languageProvider]);
return {
isSyntaxReady: !!syntax,
syntax,
};
};
/**
* Initializes given language provider, exposes Loki syntax and enables loading label option values
*/
export const useCloudWatchSyntax = (languageProvider: CloudWatchLanguageProvider, absoluteRange: AbsoluteTimeRange) => {
const languageProviderInitialized = useInitLanguageProvider(languageProvider, absoluteRange);
const { isSyntaxReady, syntax } = useCloudwatchSyntax(languageProvider, languageProviderInitialized);
return {
isSyntaxReady,
syntax,
};
};
......@@ -3,7 +3,7 @@ import React, { memo } from 'react';
// Types
import { LokiQuery } from '../types';
import { useLokiSyntaxAndLabels } from './useLokiSyntaxAndLabels';
import { useLokiLabels } from './useLokiLabels';
import { LokiQueryFieldForm } from './LokiQueryFieldForm';
import LokiDatasource from '../datasource';
......@@ -22,7 +22,7 @@ export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEdito
to: Date.now(),
};
const { isSyntaxReady, setActiveOption, refreshLabels, syntax, logLabelOptions } = useLokiSyntaxAndLabels(
const { setActiveOption, refreshLabels, logLabelOptions, labelsLoaded } = useLokiLabels(
datasource.languageProvider,
absolute
);
......@@ -43,8 +43,7 @@ export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEdito
onLoadOptions={setActiveOption}
onLabelsRefresh={refreshLabels}
absoluteRange={absolute}
syntax={syntax}
syntaxLoaded={isSyntaxReady}
labelsLoaded={labelsLoaded}
logLabelOptions={logLabelOptions}
/>
</div>
......
import React, { FunctionComponent } from 'react';
import { LokiQueryFieldForm, LokiQueryFieldFormProps } from './LokiQueryFieldForm';
import { useLokiSyntaxAndLabels } from './useLokiSyntaxAndLabels';
import { useLokiLabels } from './useLokiLabels';
import LokiLanguageProvider from '../language_provider';
type LokiQueryFieldProps = Omit<
LokiQueryFieldFormProps,
'syntax' | 'syntaxLoaded' | 'onLoadOptions' | 'onLabelsRefresh' | 'logLabelOptions' | 'absoluteRange'
'labelsLoaded' | 'onLoadOptions' | 'onLabelsRefresh' | 'logLabelOptions' | 'absoluteRange'
>;
export const LokiQueryField: FunctionComponent<LokiQueryFieldProps> = props => {
const { datasource, range, ...otherProps } = props;
const absoluteTimeRange = { from: range!.from!.valueOf(), to: range!.to!.valueOf() }; // Range here is never optional
const { isSyntaxReady, setActiveOption, refreshLabels, syntax, logLabelOptions } = useLokiSyntaxAndLabels(
const { setActiveOption, refreshLabels, logLabelOptions, labelsLoaded } = useLokiLabels(
datasource.languageProvider as LokiLanguageProvider,
absoluteTimeRange
);
......@@ -29,8 +29,7 @@ export const LokiQueryField: FunctionComponent<LokiQueryFieldProps> = props => {
onLoadOptions={setActiveOption}
onLabelsRefresh={refreshLabels}
absoluteRange={absoluteTimeRange}
syntax={syntax}
syntaxLoaded={isSyntaxReady}
labelsLoaded={labelsLoaded}
logLabelOptions={logLabelOptions}
{...otherProps}
/>
......
......@@ -20,7 +20,7 @@ import { Plugin, Node } from 'slate';
import { DOMUtil } from '@grafana/ui';
import { ExploreQueryFieldProps, AbsoluteTimeRange } from '@grafana/data';
import { LokiQuery, LokiOptions } from '../types';
import { Grammar, LanguageMap, languages as prismLanguages } from 'prismjs';
import { LanguageMap, languages as prismLanguages } from 'prismjs';
import LokiLanguageProvider, { LokiHistoryItem } from '../language_provider';
import LokiDatasource from '../datasource';
import LokiOptionFields from './LokiOptionFields';
......@@ -64,9 +64,8 @@ function willApplySuggestion(suggestion: string, { typeaheadContext, typeaheadTe
export interface LokiQueryFieldFormProps extends ExploreQueryFieldProps<LokiDatasource, LokiQuery, LokiOptions> {
history: LokiHistoryItem[];
syntax: Grammar | null;
logLabelOptions: CascaderOption[];
syntaxLoaded: boolean;
labelsLoaded: boolean;
absoluteRange: AbsoluteTimeRange;
onLoadOptions: (selectedOptions: CascaderOption[]) => void;
onLabelsRefresh?: () => void;
......@@ -140,18 +139,19 @@ export class LokiQueryFieldForm extends React.PureComponent<LokiQueryFieldFormPr
const {
ExtraFieldElement,
query,
syntaxLoaded,
labelsLoaded,
logLabelOptions,
onLoadOptions,
onLabelsRefresh,
datasource,
runOnBlur,
} = this.props;
const lokiLanguageProvider = datasource.languageProvider as LokiLanguageProvider;
const cleanText = datasource.languageProvider ? lokiLanguageProvider.cleanText : undefined;
const hasLogLabels = logLabelOptions && logLabelOptions.length > 0;
const chooserText = getChooserText(syntaxLoaded, hasLogLabels);
const buttonDisabled = !(syntaxLoaded && hasLogLabels);
const chooserText = getChooserText(labelsLoaded, hasLogLabels);
const buttonDisabled = !(labelsLoaded && hasLogLabels);
return (
<>
......@@ -179,7 +179,6 @@ export class LokiQueryFieldForm extends React.PureComponent<LokiQueryFieldFormPr
onRunQuery={this.props.onRunQuery}
placeholder="Enter a Loki query (run with Shift+Enter)"
portalOrigin="loki"
syntaxLoaded={syntaxLoaded}
/>
</div>
</div>
......
import { renderHook, act } from '@testing-library/react-hooks';
import LanguageProvider from 'app/plugins/datasource/loki/language_provider';
import { useLokiLabels } from './useLokiLabels';
import { getLokiLabels, useLokiLabels } from './useLokiLabels';
import { AbsoluteTimeRange } from '@grafana/data';
import { makeMockLokiDatasource } from '../mocks';
import { CascaderOption } from '@grafana/ui';
describe('useLokiLabels hook', () => {
it('should refresh labels', async () => {
const datasource = makeMockLokiDatasource({});
const languageProvider = new LanguageProvider(datasource);
const logLabelOptionsMock = ['Holy mock!'];
const rangeMock: AbsoluteTimeRange = {
// Mocks
const datasource = makeMockLokiDatasource({});
const languageProvider = new LanguageProvider(datasource);
const logLabelOptionsMock = ['Holy mock!'];
const logLabelOptionsMock2 = ['Mock the hell?!'];
const logLabelOptionsMock3 = ['Oh my mock!'];
const rangeMock: AbsoluteTimeRange = {
from: 1560153109000,
to: 1560153109000,
};
};
describe('getLokiLabels hook', () => {
it('should refresh labels', async () => {
languageProvider.logLabelOptions = ['initial'];
languageProvider.refreshLogLabels = () => {
......@@ -21,10 +27,64 @@ describe('useLokiLabels hook', () => {
return Promise.resolve();
};
const { result, waitForNextUpdate } = renderHook(() => useLokiLabels(languageProvider, true, rangeMock));
const { result, waitForNextUpdate } = renderHook(() => getLokiLabels(languageProvider, true, rangeMock));
expect(result.current.logLabelOptions).toEqual(['initial']);
act(() => result.current.refreshLabels());
await waitForNextUpdate();
expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock);
});
});
describe('useLokiLabels hook', () => {
languageProvider.refreshLogLabels = () => {
languageProvider.logLabelOptions = logLabelOptionsMock;
return Promise.resolve();
};
languageProvider.fetchLogLabels = () => {
languageProvider.logLabelOptions = logLabelOptionsMock2;
return Promise.resolve([]);
};
const activeOptionMock: CascaderOption = {
label: '',
value: '',
};
it('should fetch labels on first call', async () => {
const { result, waitForNextUpdate } = renderHook(() => useLokiLabels(languageProvider, rangeMock));
expect(result.current.logLabelOptions).toEqual([]);
await waitForNextUpdate();
expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock2);
});
it('should try to fetch missing options when active option changes', async () => {
const { result, waitForNextUpdate } = renderHook(() => useLokiLabels(languageProvider, rangeMock));
await waitForNextUpdate();
expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock2);
languageProvider.fetchLabelValues = (key: string, absoluteRange: AbsoluteTimeRange) => {
languageProvider.logLabelOptions = logLabelOptionsMock3;
return Promise.resolve([]);
};
act(() => result.current.setActiveOption([activeOptionMock]));
await waitForNextUpdate();
expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock3);
});
it('should refresh labels', async () => {
const { result, waitForNextUpdate } = renderHook(() => useLokiLabels(languageProvider, rangeMock));
expect(result.current.logLabelOptions).toEqual([]);
act(() => result.current.refreshLabels());
await waitForNextUpdate();
expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock);
});
});
......@@ -7,22 +7,49 @@ import LokiLanguageProvider from 'app/plugins/datasource/loki/language_provider'
import { useRefMounted } from 'app/core/hooks/useRefMounted';
/**
* Initialise the language provider. Returns a languageProviderInitialized boolean cause there does not seem other way
* to know if the provider is already initialised or not. By the initialisation it modifies the provided
* languageProvider directly.
*/
const useInitLanguageProvider = (languageProvider: LokiLanguageProvider, absoluteRange: AbsoluteTimeRange) => {
const mounted = useRefMounted();
const [languageProviderInitialized, setLanguageProviderInitialized] = useState(false);
// Async
const initializeLanguageProvider = async () => {
languageProvider.initialRange = absoluteRange;
await languageProvider.start();
if (mounted.current) {
setLanguageProviderInitialized(true);
}
};
useEffect(() => {
initializeLanguageProvider();
}, []);
return languageProviderInitialized;
};
/**
*
* @param languageProvider
* @param languageProviderInitialised
* @param languageProviderInitialized
* @param absoluteRange
*
* @description Fetches missing labels and enables labels refresh
*/
export const useLokiLabels = (
export const getLokiLabels = (
languageProvider: LokiLanguageProvider,
languageProviderInitialised: boolean,
languageProviderInitialized: boolean,
absoluteRange: AbsoluteTimeRange
) => {
const mounted = useRefMounted();
// State
const [logLabelOptions, setLogLabelOptions] = useState<any>([]);
const [labelsLoaded, setLabelsLoaded] = useState(false);
const [shouldTryRefreshLabels, setRefreshLabels] = useState(false);
const [prevAbsoluteRange, setPrevAbsoluteRange] = useState<AbsoluteTimeRange | null>(null);
/**
......@@ -37,6 +64,7 @@ export const useLokiLabels = (
await languageProvider.fetchLabelValues(option, absoluteRange);
if (mounted.current) {
setLogLabelOptions(languageProvider.logLabelOptions);
setLabelsLoaded(true);
}
};
......@@ -56,7 +84,7 @@ export const useLokiLabels = (
// It's a subject of activeOption state change only. This is because of specific behavior or rc-cascader
// https://github.com/react-component/cascader/blob/master/src/Cascader.jsx#L165
useEffect(() => {
if (languageProviderInitialised) {
if (languageProviderInitialized) {
const targetOption = activeOption[activeOption.length - 1];
if (targetOption) {
const nextOptions = logLabelOptions.map((option: any) => {
......@@ -85,14 +113,35 @@ export const useLokiLabels = (
// Initialize labels from the provider after it gets initialized (it's initialisation happens outside of this hook)
useEffect(() => {
if (languageProviderInitialised) {
if (languageProviderInitialized) {
setLogLabelOptions(languageProvider.logLabelOptions);
setLabelsLoaded(true);
}
}, [languageProviderInitialised]);
}, [languageProviderInitialized]);
return {
logLabelOptions,
refreshLabels: () => setRefreshLabels(true),
setActiveOption,
labelsLoaded,
};
};
/**
* Initializes given language provider and enables loading label option values
*/
export const useLokiLabels = (languageProvider: LokiLanguageProvider, absoluteRange: AbsoluteTimeRange) => {
const languageProviderInitialized = useInitLanguageProvider(languageProvider, absoluteRange);
const { logLabelOptions, refreshLabels, setActiveOption, labelsLoaded } = getLokiLabels(
languageProvider,
languageProviderInitialized,
absoluteRange
);
return {
logLabelOptions,
refreshLabels,
setActiveOption,
labelsLoaded,
};
};
import { renderHook, act } from '@testing-library/react-hooks';
import { AbsoluteTimeRange } from '@grafana/data';
import { CascaderOption } from '@grafana/ui';
import LanguageProvider from 'app/plugins/datasource/loki/language_provider';
import { useLokiSyntaxAndLabels } from './useLokiSyntaxAndLabels';
import { makeMockLokiDatasource } from '../mocks';
describe('useLokiSyntax hook', () => {
const datasource = makeMockLokiDatasource({});
const languageProvider = new LanguageProvider(datasource);
const logLabelOptionsMock = ['Holy mock!'];
const logLabelOptionsMock2 = ['Mock the hell?!'];
const logLabelOptionsMock3 = ['Oh my mock!'];
const rangeMock: AbsoluteTimeRange = {
from: 1560153109000,
to: 1560163909000,
};
languageProvider.refreshLogLabels = () => {
languageProvider.logLabelOptions = logLabelOptionsMock;
return Promise.resolve();
};
languageProvider.fetchLogLabels = () => {
languageProvider.logLabelOptions = logLabelOptionsMock2;
return Promise.resolve([]);
};
const activeOptionMock: CascaderOption = {
label: '',
value: '',
};
it('should provide Loki syntax when used', async () => {
const { result, waitForNextUpdate } = renderHook(() => useLokiSyntaxAndLabels(languageProvider, rangeMock));
expect(result.current.syntax).toEqual(null);
await waitForNextUpdate();
expect(result.current.syntax).toEqual(languageProvider.getSyntax());
});
it('should fetch labels on first call', async () => {
const { result, waitForNextUpdate } = renderHook(() => useLokiSyntaxAndLabels(languageProvider, rangeMock));
expect(result.current.isSyntaxReady).toBeFalsy();
expect(result.current.logLabelOptions).toEqual([]);
await waitForNextUpdate();
expect(result.current.isSyntaxReady).toBeTruthy();
expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock2);
});
it('should try to fetch missing options when active option changes', async () => {
const { result, waitForNextUpdate } = renderHook(() => useLokiSyntaxAndLabels(languageProvider, rangeMock));
await waitForNextUpdate();
expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock2);
languageProvider.fetchLabelValues = (key: string, absoluteRange: AbsoluteTimeRange) => {
languageProvider.logLabelOptions = logLabelOptionsMock3;
return Promise.resolve([]);
};
act(() => result.current.setActiveOption([activeOptionMock]));
await waitForNextUpdate();
expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock3);
});
});
import { useState, useEffect } from 'react';
import { Grammar } from 'prismjs';
import { AbsoluteTimeRange } from '@grafana/data';
import LokiLanguageProvider from 'app/plugins/datasource/loki/language_provider';
import { useLokiLabels } from 'app/plugins/datasource/loki/components/useLokiLabels';
import { useRefMounted } from 'app/core/hooks/useRefMounted';
/**
* Initialise the language provider. Returns a languageProviderInitialized boolean cause there does not seem other way
* to know if the provider is already initialised or not. By the initialisation it modifies the provided
* languageProvider directly.
*/
const useInitLanguageProvider = (languageProvider: LokiLanguageProvider, absoluteRange: AbsoluteTimeRange) => {
const mounted = useRefMounted();
const [languageProviderInitialized, setLanguageProviderInitialized] = useState(false);
// Async
const initializeLanguageProvider = async () => {
languageProvider.initialRange = absoluteRange;
await languageProvider.start();
if (mounted.current) {
setLanguageProviderInitialized(true);
}
};
useEffect(() => {
initializeLanguageProvider();
}, []);
return languageProviderInitialized;
};
/**
* Returns syntax from languageProvider and initialises global Prism syntax. Waits until languageProvider itself is
* initialised (outside of this hook).
*/
const useLokiSyntax = (languageProvider: LokiLanguageProvider, languageProviderInitialized: boolean) => {
// State
const [syntax, setSyntax] = useState<Grammar | null>(null);
// Effects
useEffect(() => {
if (languageProviderInitialized) {
const syntax = languageProvider.getSyntax();
setSyntax(syntax);
}
}, [languageProviderInitialized, languageProvider]);
return {
isSyntaxReady: !!syntax,
syntax,
};
};
/**
* Initializes given language provider, exposes Loki syntax and enables loading label option values
*/
export const useLokiSyntaxAndLabels = (languageProvider: LokiLanguageProvider, absoluteRange: AbsoluteTimeRange) => {
const languageProviderInitialized = useInitLanguageProvider(languageProvider, absoluteRange);
const { logLabelOptions, refreshLabels, setActiveOption } = useLokiLabels(
languageProvider,
languageProviderInitialized,
absoluteRange
);
const { isSyntaxReady, syntax } = useLokiSyntax(languageProvider, languageProviderInitialized);
return {
isSyntaxReady,
syntax,
logLabelOptions,
setActiveOption,
refreshLabels,
};
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment