From 54eb1b030cfdad958ea5373f67ea0fb7888e0e24 Mon Sep 17 00:00:00 2001 From: Mutasem Aldmour Date: Thu, 21 Dec 2023 15:52:01 +0100 Subject: [PATCH 1/8] fix: fix json mode santizing content for search --- .../editor-ui/src/components/RunDataJson.vue | 28 ++++++------ .../src/components/TextWithHighlights.vue | 44 +++++++++++++++++++ 2 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 packages/editor-ui/src/components/TextWithHighlights.vue diff --git a/packages/editor-ui/src/components/RunDataJson.vue b/packages/editor-ui/src/components/RunDataJson.vue index b46e95fae61a1..671555f7b382c 100644 --- a/packages/editor-ui/src/components/RunDataJson.vue +++ b/packages/editor-ui/src/components/RunDataJson.vue @@ -33,7 +33,9 @@ @update:selectedValue="selectedJsonPath = $event" > @@ -76,7 +78,6 @@ import type { IDataObject, INodeExecutionData } from 'n8n-workflow'; import Draggable from '@/components/Draggable.vue'; import { executionDataToJson } from '@/utils/nodeTypesUtils'; import { isString } from '@/utils/typeGuards'; -import { highlightText, sanitizeHtml } from '@/utils/htmlUtils'; import { shorten } from '@/utils/typesUtils'; import type { INodeUi } from '@/Interface'; import { mapStores } from 'pinia'; @@ -86,6 +87,7 @@ import { getMappedExpression } from '@/utils/mappingUtils'; import { useWorkflowsStore } from '@/stores/workflows.store'; import { nonExistingJsonPath } from '@/constants'; import { useExternalHooks } from '@/composables/useExternalHooks'; +import TextWithHighlights from './TextWithHighlights.vue'; const RunDataJsonActions = defineAsyncComponent( async () => import('@/components/RunDataJsonActions.vue'), @@ -94,11 +96,12 @@ const RunDataJsonActions = defineAsyncComponent( export default defineComponent({ name: 'run-data-json', components: { - VueJsonPretty, - Draggable, - RunDataJsonActions, - MappingPill, - }, + VueJsonPretty, + Draggable, + RunDataJsonActions, + MappingPill, + TextWithHighlights +}, props: { editMode: { type: Object as () => { enabled?: boolean; value?: string }, @@ -202,9 +205,6 @@ export default defineComponent({ getListItemName(path: string): string { return path.replace(/^(\["?\d"?]\.?)/g, ''); }, - highlightSearchTerm(value: string): string { - return sanitizeHtml(highlightText(this.getContent(value), this.search)); - }, }, }); diff --git a/packages/editor-ui/src/components/TextWithHighlights.vue b/packages/editor-ui/src/components/TextWithHighlights.vue new file mode 100644 index 0000000000000..d86b6dab6cabf --- /dev/null +++ b/packages/editor-ui/src/components/TextWithHighlights.vue @@ -0,0 +1,44 @@ + + + From 53328b3efc0376bc9fe180ed7e73981afc4115c3 Mon Sep 17 00:00:00 2001 From: Mutasem Aldmour Date: Thu, 21 Dec 2023 16:13:36 +0100 Subject: [PATCH 2/8] fix: fix other views --- .../src/components/RunDataSchemaItem.vue | 12 ++---- .../editor-ui/src/components/RunDataTable.vue | 19 ++++----- .../src/utils/__tests__/htmlUtils.test.ts | 41 ------------------- packages/editor-ui/src/utils/htmlUtils.ts | 6 --- 4 files changed, 13 insertions(+), 65 deletions(-) delete mode 100644 packages/editor-ui/src/utils/__tests__/htmlUtils.test.ts diff --git a/packages/editor-ui/src/components/RunDataSchemaItem.vue b/packages/editor-ui/src/components/RunDataSchemaItem.vue index a4a496bd07299..caa30b0f3a318 100644 --- a/packages/editor-ui/src/components/RunDataSchemaItem.vue +++ b/packages/editor-ui/src/components/RunDataSchemaItem.vue @@ -1,10 +1,10 @@ diff --git a/packages/editor-ui/src/components/__tests__/TextWithHIghlights.test.ts b/packages/editor-ui/src/components/__tests__/TextWithHIghlights.test.ts index 101b38c336c61..24d038a0f1bd2 100644 --- a/packages/editor-ui/src/components/__tests__/TextWithHIghlights.test.ts +++ b/packages/editor-ui/src/components/__tests__/TextWithHIghlights.test.ts @@ -1,73 +1,74 @@ - import { shallowMount } from '@vue/test-utils'; import TextWithHighlights from '@/components/TextWithHighlights.vue'; describe('TextWithHighlights', () => { - it('highlights the search text in the content', () => { - const wrapper = shallowMount(TextWithHighlights, { - props: { - content: 'Test content', - search: 'Test', - }, - }); + it('highlights the search text in the content', () => { + const wrapper = shallowMount(TextWithHighlights, { + props: { + content: 'Test content', + search: 'Test', + }, + }); - expect(wrapper.html()).toContain('Test'); - expect(wrapper.html()).toContain(' content'); - }); + expect(wrapper.html()).toContain('Test'); + expect(wrapper.html()).toContain(' content'); + }); - it('renders correctly when search is not set', () => { - const wrapper = shallowMount(TextWithHighlights, { - props: { - content: 'Test content', - }, - }); + it('renders correctly when search is not set', () => { + const wrapper = shallowMount(TextWithHighlights, { + props: { + content: 'Test content', + }, + }); - expect(wrapper.html()).toEqual('Test content'); - expect(wrapper.html()).not.toContain(''); - }); + expect(wrapper.html()).toEqual('Test content'); + expect(wrapper.html()).not.toContain(''); + }); - it('renders correctly numbers when search is not set', () => { - const wrapper = shallowMount(TextWithHighlights, { - props: { - content: 1, - }, - }); + it('renders correctly numbers when search is not set', () => { + const wrapper = shallowMount(TextWithHighlights, { + props: { + content: 1, + }, + }); - expect(wrapper.html()).toEqual('1'); - expect(wrapper.html()).not.toContain(''); - }); + expect(wrapper.html()).toEqual('1'); + expect(wrapper.html()).not.toContain(''); + }); - it('renders correctly objects when search is not set', () => { - const wrapper = shallowMount(TextWithHighlights, { - props: { - content: { hello: 'world' }, - }, - }); + it('renders correctly objects when search is not set', () => { + const wrapper = shallowMount(TextWithHighlights, { + props: { + content: { hello: 'world' }, + }, + }); - expect(wrapper.html()).toEqual('{\n "hello": "world"\n}'); - expect(wrapper.html()).not.toContain(''); - }); + expect(wrapper.html()).toEqual('{\n "hello": "world"\n}'); + expect(wrapper.html()).not.toContain(''); + }); - it('renders correctly objects ignoring search', () => { - const wrapper = shallowMount(TextWithHighlights, { - props: { - content: { hello: 'world' }, - search: 'yo', - }, - }); + it('renders correctly objects ignoring search', () => { + const wrapper = shallowMount(TextWithHighlights, { + props: { + content: { hello: 'world' }, + search: 'yo', + }, + }); - expect(wrapper.html()).toEqual('{\n "hello": "world"\n}'); - expect(wrapper.html()).not.toContain(''); - }); + expect(wrapper.html()).toEqual('{\n "hello": "world"\n}'); + expect(wrapper.html()).not.toContain(''); + }); - it('highlights the search text in middle of the content', () => { - const wrapper = shallowMount(TextWithHighlights, { - props: { - content: 'Test content hello world', - search: 'con', - }, - }); + it('highlights the search text in middle of the content', () => { + const wrapper = shallowMount(TextWithHighlights, { + props: { + content: 'Test content hello world', + search: 'con', + }, + }); - expect(wrapper.html()).toEqual('Test content hello world'); - }); + expect(wrapper.html()).toEqual( + 'Test content hello world', + ); + }); }); From 01cb40d9329ae8c7171811ba75a9add43e6aa445 Mon Sep 17 00:00:00 2001 From: Mutasem Aldmour Date: Thu, 21 Dec 2023 17:31:19 +0100 Subject: [PATCH 5/8] test: add e2e tests --- cypress/e2e/5-ndv.cy.ts | 27 ++++++++++ .../fixtures/Test_workflow_xml_output.json | 53 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 cypress/fixtures/Test_workflow_xml_output.json diff --git a/cypress/e2e/5-ndv.cy.ts b/cypress/e2e/5-ndv.cy.ts index b7711b36e81d5..6d62da4ff0310 100644 --- a/cypress/e2e/5-ndv.cy.ts +++ b/cypress/e2e/5-ndv.cy.ts @@ -490,4 +490,31 @@ describe('NDV', () => { ndv.getters.nodeVersion().should('have.text', 'Function node version 1 (Deprecated)'); ndv.actions.close(); }); + + it('Should render xml and html tags as strings and can search', () => { + cy.createFixtureWorkflow('Test_workflow_xml_output.json', `test`); + + workflowPage.actions.executeWorkflow(); + + workflowPage.actions.openNode('Edit Fields'); + + ndv.getters.outputDisplayMode().find('[class*=active]').should('contain', 'Table'); + + ndv.getters.outputTableRow(1).should('include.text', ' '); + + cy.document().trigger('keyup', { key: '/' }); + ndv.getters.searchInput().filter(':focus').type(' Introduction to XML John Doe 2020 1234567890 Data Science Basics Jane Smith 2019 0987654321 Programming in Python Bob Johnson 2021 5432109876 "}]'); + ndv.getters.outputDataContainer().find('mark').should('have.text', ' span').should('include.text', ''); + }); }); diff --git a/cypress/fixtures/Test_workflow_xml_output.json b/cypress/fixtures/Test_workflow_xml_output.json new file mode 100644 index 0000000000000..b8422c101e7c7 --- /dev/null +++ b/cypress/fixtures/Test_workflow_xml_output.json @@ -0,0 +1,53 @@ +{ + "meta": { + "instanceId": "2d1cf27f75b18bb9e146336f791c37884f4fc7ddb97c2def27c0444d106778bf" + }, + "nodes": [ + { + "parameters": {}, + "id": "8108d313-8b03-4aa4-963d-cd1c0fe8f85c", + "name": "When clicking \"Execute Workflow\"", + "type": "n8n-nodes-base.manualTrigger", + "typeVersion": 1, + "position": [ + 420, + 220 + ] + }, + { + "parameters": { + "fields": { + "values": [ + { + "name": "body", + "stringValue": " Introduction to XML John Doe 2020 1234567890 Data Science Basics Jane Smith 2019 0987654321 Programming in Python Bob Johnson 2021 5432109876 " + } + ] + }, + "options": {} + }, + "id": "45888152-7c5f-4d88-9039-660c594da084", + "name": "Edit Fields", + "type": "n8n-nodes-base.set", + "typeVersion": 3.2, + "position": [ + 640, + 220 + ] + } + ], + "connections": { + "When clicking \"Execute Workflow\"": { + "main": [ + [ + { + "node": "Edit Fields", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "pinData": {} + } \ No newline at end of file From 9eb7109fd00763a0cabe28b2f564732e24dee196 Mon Sep 17 00:00:00 2001 From: Mutasem Aldmour Date: Fri, 22 Dec 2023 14:06:38 +0100 Subject: [PATCH 6/8] fix: address feedback --- .../src/components/TextWithHighlights.vue | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/editor-ui/src/components/TextWithHighlights.vue b/packages/editor-ui/src/components/TextWithHighlights.vue index 4efcde4ad5c65..15863a16bf413 100644 --- a/packages/editor-ui/src/components/TextWithHighlights.vue +++ b/packages/editor-ui/src/components/TextWithHighlights.vue @@ -1,6 +1,7 @@