From 4dbf2f4256111985b367030020f1494b8a8b95af Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Mon, 11 Nov 2024 18:14:53 +0100 Subject: [PATCH] fix(editor): Fix hiding SQL query output when trying to select (#11649) --- .../src/components/SQLEditor.test.ts | 20 ++++++++++++ .../src/components/SqlEditor/SqlEditor.vue | 31 ++++++++++++++++--- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/packages/editor-ui/src/components/SQLEditor.test.ts b/packages/editor-ui/src/components/SQLEditor.test.ts index 234a7acc1b..1792669617 100644 --- a/packages/editor-ui/src/components/SQLEditor.test.ts +++ b/packages/editor-ui/src/components/SQLEditor.test.ts @@ -25,6 +25,7 @@ async function focusEditor(container: Element) { await waitFor(() => expect(container.querySelector('.cm-line')).toBeInTheDocument()); await userEvent.click(container.querySelector('.cm-line') as Element); } + const nodes = [ { id: '1', @@ -172,4 +173,23 @@ describe('SqlEditor.vue', () => { getByTestId(EXPRESSION_OUTPUT_TEST_ID).getElementsByClassName('cm-line').length, ); }); + + it('should keep rendered output visible when clicking', async () => { + const { getByTestId, queryByTestId, container, baseElement } = renderComponent(SqlEditor, { + ...DEFAULT_SETUP, + props: { + ...DEFAULT_SETUP.props, + modelValue: 'SELECT * FROM users', + }, + }); + + // Does not hide output when clicking inside the output + await focusEditor(container); + await userEvent.click(getByTestId(EXPRESSION_OUTPUT_TEST_ID)); + await waitFor(() => expect(queryByTestId(EXPRESSION_OUTPUT_TEST_ID)).toBeInTheDocument()); + + // Does hide output when clicking outside the container + await userEvent.click(baseElement); + await waitFor(() => expect(queryByTestId(EXPRESSION_OUTPUT_TEST_ID)).not.toBeInTheDocument()); + }); }); diff --git a/packages/editor-ui/src/components/SqlEditor/SqlEditor.vue b/packages/editor-ui/src/components/SqlEditor/SqlEditor.vue index 5475e04a05..6350ea52aa 100644 --- a/packages/editor-ui/src/components/SqlEditor/SqlEditor.vue +++ b/packages/editor-ui/src/components/SqlEditor/SqlEditor.vue @@ -37,6 +37,7 @@ import { import { computed, onBeforeUnmount, onMounted, ref, toRaw, watch } from 'vue'; import { codeNodeEditorTheme } from '../CodeNodeEditor/theme'; import { dropInExpressionEditor, mappingDropCursor } from '@/plugins/codemirror/dragAndDrop'; +import { onClickOutside } from '@vueuse/core'; const SQL_DIALECTS = { StandardSQL, @@ -68,7 +69,10 @@ const emit = defineEmits<{ 'update:model-value': [value: string]; }>(); -const sqlEditor = ref(); +const container = ref(); +const sqlEditor = ref(); +const isFocused = ref(false); + const extensions = computed(() => { const dialect = SQL_DIALECTS[props.dialect] ?? SQL_DIALECTS.StandardSQL; function sqlWithN8nLanguageSupport() { @@ -122,7 +126,7 @@ const { editor, segments: { all: segments }, readEditorValue, - hasFocus, + hasFocus: editorHasFocus, } = useExpressionEditor({ editorRef: sqlEditor, editorValue, @@ -138,6 +142,12 @@ watch( }, ); +watch(editorHasFocus, (focus) => { + if (focus) { + isFocused.value = true; + } +}); + watch(segments, () => { emit('update:model-value', readEditorValue()); }); @@ -154,6 +164,19 @@ onBeforeUnmount(() => { codeNodeEditorEventBus.off('highlightLine', highlightLine); }); +onClickOutside(container, (event) => onBlur(event)); + +function onBlur(event: FocusEvent | KeyboardEvent) { + if ( + event?.target instanceof Element && + Array.from(event.target.classList).some((_class) => _class.includes('resizer')) + ) { + return; // prevent blur on resizing + } + + isFocused.value = false; +} + function line(lineNumber: number): Line | null { try { return editor.value?.state.doc.line(lineNumber) ?? null; @@ -189,7 +212,7 @@ async function onDrop(value: string, event: MouseEvent) {