This is an automated email from the ASF dual-hosted git repository. voidmatcha pushed a commit to branch pr5339-rebase in repository https://gitbox.apache.org/repos/asf/zeppelin.git
commit 077327bee10ada7145e5c1ffbd8c2bb3c44c9892 Author: YONGJAE LEE <[email protected]> AuthorDate: Sun Aug 2 15:19:54 2026 +0900 Keep Monaco shortcuts scoped to the focused paragraph --- .../keyboard/notebook-keyboard-shortcuts.spec.ts | 16 ++++++++++------ zeppelin-web-angular/src/app/key-binding/key-binder.ts | 16 +++++++++++++--- .../notebook-paragraph-keyboard-event-handler.ts | 4 +--- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts index ee2fa5f481..a6c87814b1 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts @@ -461,18 +461,22 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // ===== UI TOGGLE SHORTCUTS ===== test.describe('ParagraphActions.SwitchEditor: Control+Alt+E', () => { - test('should toggle editor visibility with Control+Alt+E', async () => { - // Given: A paragraph with visible editor - await keyboardPage.tryFocusCodeEditor(); - await keyboardPage.setCodeEditorContent('%python\nprint("Test editor toggle")'); + test('should toggle the focused editor with Control+Alt+E', async () => { + await keyboardPage.tryFocusCodeEditor(0); + await keyboardPage.setCodeEditorContent('%python\nprint("First paragraph")', 0); + await keyboardPage.pressInsertBelow(); + await keyboardPage.waitForParagraphCountChange(2); + await keyboardPage.tryFocusCodeEditor(1); + await keyboardPage.setCodeEditorContent('%python\nprint("Second paragraph")', 1); + await keyboardPage.tryFocusCodeEditor(0); const initialEditorVisibility = await keyboardPage.isEditorVisible(0); + const secondEditorVisibility = await keyboardPage.isEditorVisible(1); - // When: User presses Control+Alt+E await keyboardPage.pressSwitchEditor(); - // Then: editor visibility toggles await expect.poll(() => keyboardPage.isEditorVisible(0), { timeout: 10000 }).toBe(!initialEditorVisibility); + expect(await keyboardPage.isEditorVisible(1)).toBe(secondEditorVisibility); }); }); diff --git a/zeppelin-web-angular/src/app/key-binding/key-binder.ts b/zeppelin-web-angular/src/app/key-binding/key-binder.ts index 5267c78849..cfbec5b50b 100644 --- a/zeppelin-web-angular/src/app/key-binding/key-binder.ts +++ b/zeppelin-web-angular/src/app/key-binding/key-binder.ts @@ -18,14 +18,18 @@ import { map, mergeMap, takeUntil } from 'rxjs/operators'; import { ShortcutService } from '@zeppelin/services'; import { castArray, chain, isNil } from 'lodash'; import { KeyCodeConverter } from './key-code-converter'; +import { MonacoHandledParagraphActions } from './notebook-paragraph-keyboard-event-handler'; import { ParagraphActions } from './paragraph-actions'; import { ShortcutsMap } from './shortcuts-map'; export class KeyBinder { + private static nextMonacoContextId = 0; + private events$ = new Subject<{ action: ParagraphActions; event: KeyboardEvent | null; }>(); + private readonly monacoContext = `zeppelin.paragraphEditor.${KeyBinder.nextMonacoContextId++}`; constructor( private destroySubject: Observable<unknown>, @@ -56,17 +60,23 @@ export class KeyBinder { } initKeyBindingsOnMonaco(editor: MonacoEditor.IStandaloneCodeEditor) { + editor.createContextKey(this.monacoContext, true); chain(ShortcutsMap) .toPairs() + .filter(([action]) => MonacoHandledParagraphActions.some(monacoAction => monacoAction === action)) .flatMap(([action, keys]) => castArray(keys).map(key => ({ action, key }))) .forEach(({ action, key }) => { const keyBinding = KeyCodeConverter.angularToMonacoKeyBinding(key); if (isNil(keyBinding)) { return; } - editor.addCommand(keyBinding, () => { - this.events$.next({ action: action as ParagraphActions, event: null }); - }); + editor.addCommand( + keyBinding, + () => { + this.events$.next({ action: action as ParagraphActions, event: null }); + }, + this.monacoContext + ); }) .value(); } diff --git a/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts b/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts index 3c6e8508c8..95cd4ec80f 100644 --- a/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts +++ b/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts @@ -71,9 +71,7 @@ export const ParagraphActionToHandlerName = { [ParagraphActions.FindInCode]: 'handleFindInCode' } as const satisfies Record<ParagraphActions, keyof NotebookParagraphKeyboardEventHandler>; -// Referenced only via `typeof` below to derive a type; the runtime binding is intentionally unused. -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const MonacoHandledParagraphActions = [ +export const MonacoHandledParagraphActions = [ ParagraphActions.MoveCursorUp, ParagraphActions.MoveCursorDown, ParagraphActions.SwitchEditor,
