CloudWatch Logs: Add Monaco-based query field editor behind feature flag (#71799)

This commit is contained in:
Kevin Yu 2023-07-24 14:33:45 -07:00 committed by GitHub
parent 142cbc2ec6
commit 4c42632ab8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 124 additions and 5 deletions

View File

@ -3638,9 +3638,6 @@ exports[`better eslint`] = {
"public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"public/app/plugins/datasource/cloudwatch/components/LogsQueryEditor.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],

View File

@ -3,6 +3,7 @@ import { css } from '@emotion/css';
import React, { memo } from 'react';
import { AbsoluteTimeRange, QueryEditorProps } from '@grafana/data';
import { config } from '@grafana/runtime';
import { InlineFormLabel } from '@grafana/ui';
import { CloudWatchDatasource } from '../datasource';
@ -10,6 +11,7 @@ import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery } from '../typ
import { CloudWatchLink } from './CloudWatchLink';
import CloudWatchLogsQueryField from './LogsQueryField';
import CloudWatchLogsQueryFieldMonaco from './LogsQueryField/LogsQueryField';
type Props = QueryEditorProps<CloudWatchDatasource, CloudWatchQuery, CloudWatchJsonData> & {
query: CloudWatchLogsQuery;
@ -37,7 +39,16 @@ export const CloudWatchLogsQueryEditor = memo(function CloudWatchLogsQueryEditor
};
}
return (
return config.featureToggles.cloudWatchLogsMonacoEditor ? (
<CloudWatchLogsQueryFieldMonaco
{...props}
ExtraFieldElement={
<InlineFormLabel className={`gf-form-label--btn ${labelClass}`} width="auto" tooltip="Link to Graph in AWS">
<CloudWatchLink query={query} panelData={data} datasource={datasource} />
</InlineFormLabel>
}
/>
) : (
<CloudWatchLogsQueryField
{...props}
exploreId={exploreId}
@ -45,7 +56,7 @@ export const CloudWatchLogsQueryEditor = memo(function CloudWatchLogsQueryEditor
absoluteRange={absolute}
ExtraFieldElement={
<InlineFormLabel className={`gf-form-label--btn ${labelClass}`} width="auto" tooltip="Link to Graph in AWS">
<CloudWatchLink query={query as CloudWatchLogsQuery} panelData={data} datasource={datasource} />
<CloudWatchLink query={query} panelData={data} datasource={datasource} />
</InlineFormLabel>
}
/>

View File

@ -0,0 +1,108 @@
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
import React, { ReactNode, useCallback } from 'react';
import { QueryEditorProps } from '@grafana/data';
import { CodeEditor, Monaco, Themeable2, withTheme2 } from '@grafana/ui';
import { CloudWatchDatasource } from '../../datasource';
import language from '../../language/logs/definition';
import { TRIGGER_SUGGEST } from '../../language/monarch/commands';
import { registerLanguage } from '../../language/monarch/register';
import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery } from '../../types';
import { getStatsGroups } from '../../utils/query/getStatsGroups';
import { LogGroupsField } from './../LogGroups/LogGroupsField';
export interface CloudWatchLogsQueryFieldProps
extends QueryEditorProps<CloudWatchDatasource, CloudWatchQuery, CloudWatchJsonData>,
Themeable2 {
ExtraFieldElement?: ReactNode;
query: CloudWatchLogsQuery;
}
export const CloudWatchLogsQueryFieldMonaco = (props: CloudWatchLogsQueryFieldProps) => {
const { query, datasource, onChange, ExtraFieldElement, data } = props;
const showError = data?.error?.refId === query.refId;
const onChangeQuery = useCallback(
(value: string) => {
const nextQuery = {
...query,
expression: value,
statsGroups: getStatsGroups(value),
};
onChange(nextQuery);
},
[onChange, query]
);
const onEditorMount = useCallback(
(editor: monacoType.editor.IStandaloneCodeEditor, monaco: Monaco) => {
editor.onDidFocusEditorText(() => editor.trigger(TRIGGER_SUGGEST.id, TRIGGER_SUGGEST.id, {}));
editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, () => {
const text = editor.getValue();
onChangeQuery(text);
});
},
[onChangeQuery]
);
return (
<>
<LogGroupsField
region={query.region}
datasource={datasource}
legacyLogGroupNames={query.logGroupNames}
logGroups={query.logGroups}
onChange={(logGroups) => {
onChange({ ...query, logGroups, logGroupNames: undefined });
}}
/>
<div className="gf-form-inline gf-form-inline--nowrap flex-grow-1">
<div className="gf-form--grow flex-shrink-1">
<CodeEditor
height="150px"
width="100%"
showMiniMap={false}
monacoOptions={{
// without this setting, the auto-resize functionality causes an infinite loop, don't remove it!
scrollBeyondLastLine: false,
// These additional options are style focused and are a subset of those in the query editor in Prometheus
fontSize: 14,
lineNumbers: 'off',
renderLineHighlight: 'none',
scrollbar: {
vertical: 'hidden',
horizontal: 'hidden',
},
suggestFontSize: 12,
wordWrap: 'on',
padding: {
top: 6,
},
}}
language={language.id}
value={query.expression ?? ''}
onBlur={(value) => {
if (value !== query.expression) {
onChangeQuery(value);
}
}}
onBeforeEditorMount={(monaco: Monaco) =>
registerLanguage(monaco, language, datasource.logsCompletionItemProvider)
}
onEditorDidMount={onEditorMount}
/>
</div>
{ExtraFieldElement}
</div>
{showError ? (
<div className="query-row-break">
<div className="prom-query-field-info text-error">{data?.error?.message}</div>
</div>
) : null}
</>
);
};
export default withTheme2(CloudWatchLogsQueryFieldMonaco);

View File

@ -22,6 +22,7 @@ import { DEFAULT_METRICS_QUERY, getDefaultLogsQuery } from './defaultQueries';
import { isCloudWatchAnnotationQuery, isCloudWatchLogsQuery, isCloudWatchMetricsQuery } from './guards';
import { CloudWatchLogsLanguageProvider } from './language/cloudwatch-logs/CloudWatchLogsLanguageProvider';
import { SQLCompletionItemProvider } from './language/cloudwatch-sql/completion/CompletionItemProvider';
import { LogsCompletionItemProvider } from './language/logs/completion/CompletionItemProvider';
import { MetricMathCompletionItemProvider } from './language/metric-math/completion/CompletionItemProvider';
import { CloudWatchAnnotationQueryRunner } from './query-runner/CloudWatchAnnotationQueryRunner';
import { CloudWatchLogsQueryRunner } from './query-runner/CloudWatchLogsQueryRunner';
@ -44,6 +45,7 @@ export class CloudWatchDatasource
languageProvider: CloudWatchLogsLanguageProvider;
sqlCompletionItemProvider: SQLCompletionItemProvider;
metricMathCompletionItemProvider: MetricMathCompletionItemProvider;
logsCompletionItemProvider: LogsCompletionItemProvider;
defaultLogGroups?: string[];
type = 'cloudwatch';
@ -65,6 +67,7 @@ export class CloudWatchDatasource
this.sqlCompletionItemProvider = new SQLCompletionItemProvider(this.resources, this.templateSrv);
this.metricMathCompletionItemProvider = new MetricMathCompletionItemProvider(this.resources, this.templateSrv);
this.metricsQueryRunner = new CloudWatchMetricsQueryRunner(instanceSettings, templateSrv);
this.logsCompletionItemProvider = new LogsCompletionItemProvider(this.resources, this.templateSrv);
this.logsQueryRunner = new CloudWatchLogsQueryRunner(instanceSettings, templateSrv, timeSrv);
this.annotationQueryRunner = new CloudWatchAnnotationQueryRunner(instanceSettings, templateSrv);
this.variables = new CloudWatchVariableSupport(this.resources);