From 333c858bc6841c5a4cb12ac26e247c2be1eff0a5 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Wed, 25 Oct 2023 16:21:54 +0000 Subject: [PATCH] GrafanaUI: Prevent code editors from 'trapping' scroll (#77125) * GrafanaUI: Prevent CodeEditor from 'trapping' scroll * fix test * fix lint for unused import --- .betterer.results | 3 --- .../grafana-e2e-selectors/src/selectors/components.ts | 2 +- .../grafana-ui/src/components/Monaco/CodeEditor.tsx | 11 +++++++++-- packages/grafana-ui/src/components/Monaco/types.ts | 7 +++++++ .../components/admin/AlertmanagerConfig.test.tsx | 5 +++-- .../monaco-query-field/MonacoQueryField.tsx | 1 + .../monaco-query-field/MonacoQueryField.tsx | 1 + 7 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.betterer.results b/.betterer.results index 619bc5d815e..67f17632003 100644 --- a/.betterer.results +++ b/.betterer.results @@ -853,9 +853,6 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "2"], [0, 0, 0, "Unexpected any. Specify a different type.", "3"] ], - "packages/grafana-ui/src/components/Monaco/CodeEditor.tsx:5381": [ - [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"] - ], "packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx:5381": [ [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"] ], diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index c023ab6cf3f..d8599280e4e 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -387,7 +387,7 @@ export const Components = { singleLink: 'Data link', }, CodeEditor: { - container: 'Code editor container', + container: 'data-testid Code editor container', }, DashboardImportPage: { textarea: 'data-testid-import-dashboard-textarea', diff --git a/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx b/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx index 1efff90007a..d995299ddc3 100644 --- a/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx +++ b/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx @@ -101,6 +101,7 @@ class UnthemedCodeEditor extends PureComponent { if (getSuggestions && this.modelId) { this.completionCancel = registerSuggestions(monaco, language, getSuggestions, this.modelId); } + // Save when pressing Ctrl+S or Cmd+S editor.onKeyDown((e: monacoType.IKeyboardEvent) => { if (e.keyCode === monaco.KeyCode.KeyS && (e.ctrlKey || e.metaKey)) { @@ -122,6 +123,8 @@ class UnthemedCodeEditor extends PureComponent { render() { const { theme, language, width, height, showMiniMap, showLineNumbers, readOnly, monacoOptions } = this.props; + const { alwaysConsumeMouseWheel, ...restMonacoOptions } = monacoOptions ?? {}; + const value = this.props.value ?? ''; const longText = value.length > 100; @@ -147,6 +150,10 @@ class UnthemedCodeEditor extends PureComponent { bottom: 0.5 * theme.spacing.gridSize, }, fixedOverflowWidgets: true, // Ensures suggestions menu is drawn on top + + scrollbar: { + alwaysConsumeMouseWheel: alwaysConsumeMouseWheel ?? false, + }, }; if (!showLineNumbers) { @@ -157,7 +164,7 @@ class UnthemedCodeEditor extends PureComponent { } return ( -
+
{ value={value} options={{ ...options, - ...(monacoOptions ?? {}), + ...(restMonacoOptions ?? {}), }} beforeMount={this.handleBeforeMount} onMount={this.handleOnMount} diff --git a/packages/grafana-ui/src/components/Monaco/types.ts b/packages/grafana-ui/src/components/Monaco/types.ts index 7c1c1e7581f..79a21a394f8 100644 --- a/packages/grafana-ui/src/components/Monaco/types.ts +++ b/packages/grafana-ui/src/components/Monaco/types.ts @@ -147,4 +147,11 @@ export interface MonacoOptionsWithGrafanaDefaults extends monacoType.editor.ISta * Defaults to true. */ automaticLayout?: boolean; + + /** + * Always consume mouse wheel events (always call preventDefault() and stopPropagation() on the browser events). + * Always consuming mouse wheel events will prevent the page from scrolling if the cursor is over the editor. + * Defaults to `false`. + */ + alwaysConsumeMouseWheel?: boolean; } diff --git a/public/app/features/alerting/unified/components/admin/AlertmanagerConfig.test.tsx b/public/app/features/alerting/unified/components/admin/AlertmanagerConfig.test.tsx index 61860be1322..bb9fe55c4a4 100644 --- a/public/app/features/alerting/unified/components/admin/AlertmanagerConfig.test.tsx +++ b/public/app/features/alerting/unified/components/admin/AlertmanagerConfig.test.tsx @@ -2,8 +2,9 @@ import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { TestProvider } from 'test/helpers/TestProvider'; -import { byLabelText, byRole, byTestId } from 'testing-library-selector'; +import { byRole, byTestId } from 'testing-library-selector'; +import { selectors } from '@grafana/e2e-selectors'; import { locationService, setDataSourceSrv } from '@grafana/runtime'; import { contextSrv } from 'app/core/services/context_srv'; import store from 'app/core/store'; @@ -82,7 +83,7 @@ const ui = { confirmButton: byRole('button', { name: /Yes, reset configuration/ }), resetButton: byRole('button', { name: /Reset configuration/ }), saveButton: byRole('button', { name: /Save/ }), - configInput: byLabelText(/Code editor container/), + configInput: byTestId(selectors.components.CodeEditor.container), readOnlyConfig: byTestId('readonly-config'), }; diff --git a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx index 1bd4c2afec5..45cf68b77fc 100644 --- a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx +++ b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx @@ -40,6 +40,7 @@ const options: monacoTypes.editor.IStandaloneEditorConstructionOptions = { verticalScrollbarSize: 8, // used as "padding-right" horizontal: 'hidden', horizontalScrollbarSize: 0, + alwaysConsumeMouseWheel: false, }, scrollBeyondLastLine: false, suggest: getSuggestOptions(), diff --git a/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx b/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx index 364842537ec..d79208b1efb 100644 --- a/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx +++ b/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx @@ -38,6 +38,7 @@ const options: monacoTypes.editor.IStandaloneEditorConstructionOptions = { verticalScrollbarSize: 8, // used as "padding-right" horizontal: 'hidden', horizontalScrollbarSize: 0, + alwaysConsumeMouseWheel: false, }, scrollBeyondLastLine: false, suggest: getSuggestOptions(),