Commit 2a61d7ff by Ivana Huckova Committed by GitHub

IntelliSense: Fix autocomplete and highlighting for Loki, Prometheus, Cloudwatch (#29381)

* Pass languages directly to SlatePrism plugin

* Update

* Remove unused variables

* Update packages/grafana-ui/src/components/DataLinks/DataLinkInput.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/components/PromQueryField.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/prometheus/components/PromQueryField.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Try Prism import instead of languages

* Update webpack

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
parent 3dcfe54d
......@@ -6,7 +6,7 @@ import { SelectionReference } from './SelectionReference';
import { Portal, getFormStyles } from '../index';
// @ts-ignore
import Prism from 'prismjs';
import Prism, { Grammar, LanguageMap } from 'prismjs';
import { Editor } from '@grafana/slate-react';
import { Value } from 'slate';
import Plain from 'slate-plain-serializer';
......@@ -27,11 +27,20 @@ interface DataLinkInputProps {
placeholder?: string;
}
const datalinksSyntax: Grammar = {
builtInVariable: {
pattern: /(\${\S+?})/,
},
};
const plugins = [
SlatePrism({
SlatePrism(
{
onlyIn: (node: any) => node.type === 'code_block',
getSyntax: () => 'links',
}),
},
{ ...(Prism.languages as LanguageMap), links: datalinksSyntax }
),
];
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
......@@ -56,19 +65,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
`,
}));
export const enableDatalinksPrismSyntax = () => {
Prism.languages['links'] = {
builtInVariable: {
pattern: /(\${\S+?})/,
},
};
};
// This memoised also because rerendering the slate editor grabs focus which created problem in some cases this
// was used and changes to different state were propagated here.
export const DataLinkInput: React.FC<DataLinkInputProps> = memo(
({ value, onChange, suggestions, placeholder = 'http://your-grafana.com/d/000000010/annotations' }) => {
enableDatalinksPrismSyntax();
const editorRef = useRef<Editor>() as RefObject<Editor>;
const theme = useContext(ThemeContext);
const styles = getStyles(theme);
......
import Prism from 'prismjs';
import Prism, { LanguageMap } from 'prismjs';
import { Block, Text, Decoration } from 'slate';
import { Plugin } from '@grafana/slate-react';
import Options, { OptionsFormat } from './options';
......@@ -19,7 +19,7 @@ export interface Token {
/**
* A Slate plugin to highlight code syntax.
*/
export function SlatePrism(optsParam: OptionsFormat = {}): Plugin {
export function SlatePrism(optsParam: OptionsFormat = {}, prismLanguages = Prism.languages as LanguageMap): Plugin {
const opts: Options = new Options(optsParam);
return {
......@@ -30,7 +30,7 @@ export function SlatePrism(optsParam: OptionsFormat = {}): Plugin {
const block = Block.create(node as Block);
const grammarName = opts.getSyntax(block);
const grammar = Prism.languages[grammarName];
const grammar = prismLanguages[grammarName];
if (!grammar) {
// Grammar not loaded
......
......@@ -192,7 +192,7 @@ const CLIQ_EXAMPLES: QueryExample[] = [
];
function renderHighlightedMarkup(code: string, keyPrefix: string) {
const grammar = Prism.languages['cloudwatch'] ?? tokenizer;
const grammar = tokenizer;
const tokens = flattenTokens(Prism.tokenize(code, grammar));
const spans = tokens
.filter(token => typeof token !== 'string')
......
......@@ -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 Prism, { Grammar } from 'prismjs';
import { Grammar, LanguageMap, languages as prismLanguages } from 'prismjs';
import { CloudWatchLanguageProvider } from '../language_provider';
import { css } from 'emotion';
import { ExploreId } from 'app/types';
......@@ -95,13 +95,15 @@ export class CloudWatchLogsQueryField extends React.PureComponent<CloudWatchLogs
constructor(props: CloudWatchLogsQueryFieldProps, context: React.Context<any>) {
super(props, context);
Prism.languages['cloudwatch'] = syntax;
this.plugins = [
BracesPlugin(),
SlatePrism({
SlatePrism(
{
onlyIn: (node: Node) => node.object === 'block' && node.type === 'code_block',
getSyntax: (node: Node) => 'cloudwatch',
}),
},
{ ...(prismLanguages as LanguageMap), cloudwatch: syntax }
),
];
}
......
import { useState, useEffect } from 'react';
import Prism, { Grammar } from 'prismjs';
import { Grammar } from 'prismjs';
import { AbsoluteTimeRange } from '@grafana/data';
import { useRefMounted } from 'app/core/hooks/useRefMounted';
import { CloudWatchLanguageProvider } from './language_provider';
const PRISM_SYNTAX = 'cloudwatch';
/**
* 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
......@@ -44,7 +42,6 @@ const useCloudwatchSyntax = (languageProvider: CloudWatchLanguageProvider, langu
useEffect(() => {
if (languageProviderInitialized) {
const syntax = languageProvider.getSyntax();
Prism.languages[PRISM_SYNTAX] = syntax;
setSyntax(syntax);
}
}, [languageProviderInitialized, languageProvider]);
......
......@@ -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 } from 'prismjs';
import { Grammar, LanguageMap, languages as prismLanguages } from 'prismjs';
import LokiLanguageProvider, { LokiHistoryItem } from '../language_provider';
import LokiDatasource from '../datasource';
import LokiOptionFields from './LokiOptionFields';
......@@ -82,10 +82,13 @@ export class LokiQueryFieldForm extends React.PureComponent<LokiQueryFieldFormPr
this.plugins = [
BracesPlugin(),
SlatePrism({
SlatePrism(
{
onlyIn: (node: Node) => node.object === 'block' && node.type === 'code_block',
getSyntax: (node: Node) => 'promql',
}),
getSyntax: (node: Node) => 'logql',
},
{ ...(prismLanguages as LanguageMap), logql: this.props.datasource.languageProvider.getSyntax() }
),
];
}
......
import { useState, useEffect } from 'react';
import Prism, { Grammar } from 'prismjs';
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';
const PRISM_SYNTAX = 'promql';
/**
* 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
......@@ -45,7 +43,6 @@ const useLokiSyntax = (languageProvider: LokiLanguageProvider, languageProviderI
useEffect(() => {
if (languageProviderInitialized) {
const syntax = languageProvider.getSyntax();
Prism.languages[PRISM_SYNTAX] = syntax;
setSyntax(syntax);
}
}, [languageProviderInitialized, languageProvider]);
......
......@@ -7,7 +7,11 @@ import { PromQuery } from '../types';
import { LoadingState, PanelData, toUtc, TimeRange } from '@grafana/data';
const setup = (renderMethod: any, propOverrides?: object) => {
const datasourceMock: unknown = {};
const datasourceMock: unknown = {
languageProvider: {
syntax: () => {},
},
};
const datasource: PrometheusDatasource = datasourceMock as PrometheusDatasource;
const onRunQuery = jest.fn();
const onChange = jest.fn();
......
......@@ -17,6 +17,7 @@ describe('PromQueryField', () => {
const datasource = ({
languageProvider: {
start: () => Promise.resolve([]),
syntax: () => {},
},
} as unknown) as DataSourceInstanceSettings<PromOptions>;
......@@ -35,10 +36,16 @@ describe('PromQueryField', () => {
});
it('renders a disabled metrics chooser if lookups are disabled in datasource settings', () => {
const datasource = ({
languageProvider: {
start: () => Promise.resolve([]),
syntax: () => {},
},
} as unknown) as DataSourceInstanceSettings<PromOptions>;
const queryField = render(
<PromQueryField
// @ts-ignore
datasource={{ lookupsDisabled: true }}
datasource={{ ...datasource, lookupsDisabled: true }}
query={{ expr: '', refId: '' }}
onRunQuery={() => {}}
onChange={() => {}}
......
......@@ -12,7 +12,7 @@ import {
BracesPlugin,
} from '@grafana/ui';
import Prism from 'prismjs';
import { LanguageMap, languages as prismLanguages } from 'prismjs';
// dom also includes Element polyfills
import { PromQuery, PromOptions, PromMetricsMetadata } from '../types';
......@@ -22,7 +22,6 @@ import { DOMUtil, SuggestionsState } from '@grafana/ui';
import { PrometheusDatasource } from '../datasource';
const HISTOGRAM_GROUP = '__histograms__';
const PRISM_SYNTAX = 'promql';
export const RECORDING_RULES_GROUP = '__recording_rules__';
function getChooserText(metricsLookupDisabled: boolean, hasSyntax: boolean, metrics: string[]) {
......@@ -133,10 +132,13 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
this.plugins = [
BracesPlugin(),
SlatePrism({
SlatePrism(
{
onlyIn: (node: any) => node.type === 'code_block',
getSyntax: (node: any) => 'promql',
}),
},
{ ...(prismLanguages as LanguageMap), promql: this.props.datasource.languageProvider.syntax }
),
];
this.state = {
......@@ -222,7 +224,6 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
datasource: { languageProvider },
} = this.props;
Prism.languages[PRISM_SYNTAX] = languageProvider.syntax;
this.languageProviderInitializationPromise = makePromiseCancelable(languageProvider.start());
try {
......
......@@ -45,7 +45,13 @@ exports[`PromExploreQueryEditor should render component 1`] = `
},
}
}
datasource={Object {}}
datasource={
Object {
"languageProvider": Object {
"syntax": [Function],
},
}
}
history={Array []}
onBlur={[Function]}
onChange={[MockFunction]}
......
import { Grammar } from 'prismjs';
import { CompletionItem } from '@grafana/ui';
export const RATE_RANGES: CompletionItem[] = [
......@@ -376,7 +377,7 @@ export const FUNCTIONS = [
},
];
const tokenizer = {
const tokenizer: Grammar = {
comment: {
pattern: /#.*/,
},
......
......@@ -48,6 +48,9 @@ module.exports = {
// storybook v6 bump caused the app to bundle multiple versions of react breaking hooks
// make sure to resolve only from the project: https://github.com/facebook/react/issues/13991#issuecomment-435587809
react: path.resolve(__dirname, '../../node_modules/react'),
// some of data source pluginis use global Prism object to add the language definition
// we want to have same Prism object in core and in grafana/ui
prismjs: path.resolve(__dirname, '../../node_modules/prismjs'),
},
modules: [
'node_modules',
......
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