From 2a66f88348aace40912596062629cd067b1cf030 Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Thu, 11 Apr 2024 15:11:09 +0200 Subject: [PATCH 1/5] Skip bracket segments in SQL editor --- packages/editor-ui/src/components/SqlEditor/SqlEditor.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/src/components/SqlEditor/SqlEditor.vue b/packages/editor-ui/src/components/SqlEditor/SqlEditor.vue index c67688b9e2cde..daa2b33cd08f0 100644 --- a/packages/editor-ui/src/components/SqlEditor/SqlEditor.vue +++ b/packages/editor-ui/src/components/SqlEditor/SqlEditor.vue @@ -140,7 +140,7 @@ const { editorRef: sqlEditor, editorValue, extensions, - skipSegments: ['Statement', 'CompositeIdentifier', 'Parens'], + skipSegments: ['Statement', 'CompositeIdentifier', 'Parens', 'Brackets'], isReadOnly: props.isReadOnly, }); const ndvStore = useNDVStore(); From 3d20fd5db64dc15b1e9c13d75301d267e06d90de Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Thu, 11 Apr 2024 15:11:42 +0200 Subject: [PATCH 2/5] Harden ExpressionEditorOutput to handle duplicate segments + test --- .../InlineExpressionEditorOutput.vue | 7 +- .../InlineExpressionEditorOutput.test.ts | 65 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 packages/editor-ui/src/components/InlineExpressionEditor/__tests__/InlineExpressionEditorOutput.test.ts diff --git a/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue b/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue index ba45d6d1bfaa4..846d60d0c973d 100644 --- a/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue +++ b/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue @@ -34,13 +34,18 @@ const i18n = useI18n(); const editor = ref(null); const root = ref(null); +function addSegment(str: string, segment: Segment): string { + const text = segment.kind === 'resolvable' ? String(segment.resolved) : segment.plaintext; + return str.substring(0, segment.from) + text + str.substring(segment.to + 1); +} + const resolvedExpression = computed(() => { if (props.segments.length === 0) { return i18n.baseText('parameterInput.emptyString'); } return props.segments.reduce((acc, segment) => { - acc += segment.kind === 'resolvable' ? (segment.resolved as string) : segment.plaintext; + acc = addSegment(acc, segment); return acc; }, ''); }); diff --git a/packages/editor-ui/src/components/InlineExpressionEditor/__tests__/InlineExpressionEditorOutput.test.ts b/packages/editor-ui/src/components/InlineExpressionEditor/__tests__/InlineExpressionEditorOutput.test.ts new file mode 100644 index 0000000000000..925fb330b5935 --- /dev/null +++ b/packages/editor-ui/src/components/InlineExpressionEditor/__tests__/InlineExpressionEditorOutput.test.ts @@ -0,0 +1,65 @@ +import { renderComponent } from '@/__tests__/render'; +import { createTestingPinia } from '@pinia/testing'; +import InlineExpressionEditorOutput from '../InlineExpressionEditorOutput.vue'; + +describe('InlineExpressionEditorOutput.vue', () => { + test('should render duplicate segments correctly', async () => { + const { getByTestId } = renderComponent(InlineExpressionEditorOutput, { + pinia: createTestingPinia(), + props: { + hoveringItemNumber: 0, + segments: [ + { + from: 0, + to: 6, + plaintext: 'SELECT', + kind: 'plaintext', + }, + { + from: 6, + to: 7, + plaintext: ' ', + kind: 'plaintext', + }, + { + from: 7, + to: 12, + plaintext: '[1,2]', + kind: 'plaintext', + }, + { + from: 7, + to: 8, + plaintext: '[', + kind: 'plaintext', + }, + { + from: 8, + to: 9, + plaintext: '1', + kind: 'plaintext', + }, + { + from: 9, + to: 10, + plaintext: ',', + kind: 'plaintext', + }, + { + from: 10, + to: 11, + plaintext: '2', + kind: 'plaintext', + }, + { + from: 11, + to: 12, + plaintext: ']', + kind: 'plaintext', + }, + ], + }, + }); + expect(getByTestId('inline-expression-editor-output')).toHaveTextContent('SELECT [1,2]'); + }); +}); From f97d8cdf9c3baf496bc47441cbcbed39580e612f Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Thu, 18 Apr 2024 15:30:41 +0200 Subject: [PATCH 3/5] Fix duplicate segments logic --- .../InlineExpressionEditorOutput.vue | 21 +++-- .../InlineExpressionEditorOutput.test.ts | 83 +++++++++++++------ 2 files changed, 71 insertions(+), 33 deletions(-) diff --git a/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue b/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue index 846d60d0c973d..73573e98b2b76 100644 --- a/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue +++ b/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue @@ -34,20 +34,23 @@ const i18n = useI18n(); const editor = ref(null); const root = ref(null); -function addSegment(str: string, segment: Segment): string { - const text = segment.kind === 'resolvable' ? String(segment.resolved) : segment.plaintext; - return str.substring(0, segment.from) + text + str.substring(segment.to + 1); -} - const resolvedExpression = computed(() => { if (props.segments.length === 0) { return i18n.baseText('parameterInput.emptyString'); } - return props.segments.reduce((acc, segment) => { - acc = addSegment(acc, segment); - return acc; - }, ''); + return props.segments.reduce( + (acc, segment) => { + // skip duplicate segments + if (acc.cursor >= segment.to) return acc; + + acc.resolved += segment.kind === 'resolvable' ? String(segment.resolved) : segment.plaintext; + acc.cursor = segment.to; + + return acc; + }, + { resolved: '', cursor: 0 }, + ).resolved; }); const plaintextSegments = computed(() => { diff --git a/packages/editor-ui/src/components/InlineExpressionEditor/__tests__/InlineExpressionEditorOutput.test.ts b/packages/editor-ui/src/components/InlineExpressionEditor/__tests__/InlineExpressionEditorOutput.test.ts index 925fb330b5935..b88a453d20bdd 100644 --- a/packages/editor-ui/src/components/InlineExpressionEditor/__tests__/InlineExpressionEditorOutput.test.ts +++ b/packages/editor-ui/src/components/InlineExpressionEditor/__tests__/InlineExpressionEditorOutput.test.ts @@ -11,55 +11,90 @@ describe('InlineExpressionEditorOutput.vue', () => { segments: [ { from: 0, - to: 6, - plaintext: 'SELECT', - kind: 'plaintext', - }, - { - from: 6, - to: 7, - plaintext: ' ', - kind: 'plaintext', - }, - { - from: 7, - to: 12, + to: 5, plaintext: '[1,2]', kind: 'plaintext', }, { - from: 7, - to: 8, + from: 0, + to: 1, plaintext: '[', kind: 'plaintext', }, { - from: 8, - to: 9, + from: 1, + to: 2, plaintext: '1', kind: 'plaintext', }, { - from: 9, - to: 10, + from: 2, + to: 3, plaintext: ',', kind: 'plaintext', }, { - from: 10, - to: 11, + from: 3, + to: 4, plaintext: '2', kind: 'plaintext', }, { - from: 11, - to: 12, + from: 4, + to: 5, plaintext: ']', kind: 'plaintext', }, ], }, }); - expect(getByTestId('inline-expression-editor-output')).toHaveTextContent('SELECT [1,2]'); + expect(getByTestId('inline-expression-editor-output')).toHaveTextContent('[1,2]'); + }); + + test('should render segments with resolved expressions', () => { + const { getByTestId } = renderComponent(InlineExpressionEditorOutput, { + pinia: createTestingPinia(), + props: { + hoveringItemNumber: 0, + segments: [ + { + kind: 'plaintext', + from: 0, + to: 6, + plaintext: 'before>', + }, + { + kind: 'plaintext', + from: 6, + to: 7, + plaintext: ' ', + }, + { + kind: 'resolvable', + from: 7, + to: 17, + resolvable: '{{ $now }}', + resolved: '[Object: "2024-04-18T09:03:26.651-04:00"]', + state: 'valid', + error: null, + }, + { + kind: 'plaintext', + from: 17, + to: 18, + plaintext: ' ', + }, + { + kind: 'plaintext', + from: 18, + to: 24, + plaintext: ' [Object: "2024-04-18T09:03:26.651-04:00"] Date: Fri, 19 Apr 2024 10:58:53 +0200 Subject: [PATCH 4/5] Extract common logic beteen inline and modal expression output --- .../src/components/ExpressionEdit.vue | 15 ++- .../ExpressionEditorModalOutput.vue | 101 --------------- .../ExpressionOutput.vue | 117 ++++++++++++++++++ .../InlineExpressionEditorOutput.vue | 105 ++-------------- 4 files changed, 134 insertions(+), 204 deletions(-) delete mode 100644 packages/editor-ui/src/components/ExpressionEditorModal/ExpressionEditorModalOutput.vue create mode 100644 packages/editor-ui/src/components/InlineExpressionEditor/ExpressionOutput.vue diff --git a/packages/editor-ui/src/components/ExpressionEdit.vue b/packages/editor-ui/src/components/ExpressionEdit.vue index 7540d020c94bb..7e4deea9a2aac 100644 --- a/packages/editor-ui/src/components/ExpressionEdit.vue +++ b/packages/editor-ui/src/components/ExpressionEdit.vue @@ -65,9 +65,10 @@ {{ $locale.baseText('expressionEdit.resultOfItem1') }}
-
@@ -82,7 +83,6 @@ import { defineComponent } from 'vue'; import { mapStores } from 'pinia'; import ExpressionEditorModalInput from '@/components/ExpressionEditorModal/ExpressionEditorModalInput.vue'; -import ExpressionEditorModalOutput from '@/components/ExpressionEditorModal/ExpressionEditorModalOutput.vue'; import VariableSelector from '@/components/VariableSelector.vue'; import type { IVariableItemSelected } from '@/Interface'; @@ -96,12 +96,14 @@ import { createExpressionTelemetryPayload } from '@/utils/telemetryUtils'; import { useDebounce } from '@/composables/useDebounce'; import type { Segment } from '@/types/expressions'; +import ExpressionOutput from './InlineExpressionEditor/ExpressionOutput.vue'; +import { outputTheme } from './ExpressionEditorModal/theme'; export default defineComponent({ name: 'ExpressionEdit', components: { ExpressionEditorModalInput, - ExpressionEditorModalOutput, + ExpressionOutput, VariableSelector, }, props: { @@ -149,6 +151,7 @@ export default defineComponent({ latestValue: '', segments: [] as Segment[], expressionsDocsUrl: EXPRESSIONS_DOCS_URL, + theme: outputTheme(), }; }, computed: { @@ -160,11 +163,7 @@ export default defineComponent({ this.latestValue = this.modelValue; const resolvedExpressionValue = - ( - this.$refs.expressionResult as { - getValue: () => string; - } - )?.getValue() || ''; + (this.$refs.expressionResult as InstanceType)?.getValue() || ''; void this.externalHooks.run('expressionEdit.dialogVisibleChanged', { dialogVisible: newValue, parameter: this.parameter, diff --git a/packages/editor-ui/src/components/ExpressionEditorModal/ExpressionEditorModalOutput.vue b/packages/editor-ui/src/components/ExpressionEditorModal/ExpressionEditorModalOutput.vue deleted file mode 100644 index 3e1d84524c5ac..0000000000000 --- a/packages/editor-ui/src/components/ExpressionEditorModal/ExpressionEditorModalOutput.vue +++ /dev/null @@ -1,101 +0,0 @@ - - - - - diff --git a/packages/editor-ui/src/components/InlineExpressionEditor/ExpressionOutput.vue b/packages/editor-ui/src/components/InlineExpressionEditor/ExpressionOutput.vue new file mode 100644 index 0000000000000..72926e89fcaf7 --- /dev/null +++ b/packages/editor-ui/src/components/InlineExpressionEditor/ExpressionOutput.vue @@ -0,0 +1,117 @@ + + + diff --git a/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue b/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue index 73573e98b2b76..e43d0f4fcba9f 100644 --- a/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue +++ b/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue @@ -1,13 +1,11 @@