diff --git a/cypress/e2e/14-mapping.cy.ts b/cypress/e2e/14-mapping.cy.ts index 365efbd0d3..9845d61db9 100644 --- a/cypress/e2e/14-mapping.cy.ts +++ b/cypress/e2e/14-mapping.cy.ts @@ -174,16 +174,22 @@ describe('Data mapping', () => { workflowPage.actions.zoomToFit(); workflowPage.actions.openNode('Set1'); - ndv.actions.selectInputNode(SCHEDULE_TRIGGER_NODE_NAME); - - ndv.getters.inputDataContainer().find('span').contains('count').realMouseDown(); + ndv.actions.executePrevious(); + ndv.actions.expandSchemaViewNode(SCHEDULE_TRIGGER_NODE_NAME); + const dataPill = ndv.getters + .inputDataContainer() + .findChildByTestId('run-data-schema-item') + .contains('count') + .should('be.visible'); + dataPill.realMouseDown(); ndv.actions.mapToParameter('value'); ndv.getters .inlineExpressionEditorInput() .should('have.text', `{{ $('${SCHEDULE_TRIGGER_NODE_NAME}').item.json.input[0].count }}`); ndv.actions.switchInputMode('Table'); + ndv.actions.selectInputNode(SCHEDULE_TRIGGER_NODE_NAME); ndv.actions.mapDataFromHeader(1, 'value'); ndv.getters .inlineExpressionEditorInput() @@ -194,7 +200,6 @@ describe('Data mapping', () => { ndv.actions.selectInputNode('Set'); - ndv.actions.executePrevious(); ndv.getters.executingLoader().should('not.exist'); ndv.getters.inputDataContainer().should('exist'); ndv.actions.validateExpressionPreview('value', '0 [object Object]'); @@ -291,14 +296,8 @@ describe('Data mapping', () => { ndv.actions.executePrevious(); ndv.getters.executingLoader().should('not.exist'); ndv.getters.inputDataContainer().should('exist'); - ndv.getters - .inputDataContainer() - .should('exist') - .find('span') - .contains('test_name') - .realMouseDown(); - ndv.actions.mapToParameter('value'); - + ndv.actions.switchInputMode('Table'); + ndv.actions.mapDataFromHeader(1, 'value'); ndv.actions.validateExpressionPreview('value', 'test_value'); ndv.actions.selectInputNode(SCHEDULE_TRIGGER_NODE_NAME); ndv.actions.validateExpressionPreview('value', 'test_value'); diff --git a/cypress/e2e/24-ndv-paired-item.cy.ts b/cypress/e2e/24-ndv-paired-item.cy.ts index 2def4173d3..5dad8cc174 100644 --- a/cypress/e2e/24-ndv-paired-item.cy.ts +++ b/cypress/e2e/24-ndv-paired-item.cy.ts @@ -112,6 +112,9 @@ describe('NDV', () => { workflowPage.actions.executeWorkflow(); workflowPage.actions.openNode('Set3'); + ndv.actions.switchInputMode('Table'); + ndv.actions.switchOutputMode('Table'); + ndv.getters .inputRunSelector() .should('exist') @@ -123,9 +126,6 @@ describe('NDV', () => { .find('input') .should('include.value', '2 of 2 (6 items)'); - ndv.actions.switchInputMode('Table'); - ndv.actions.switchOutputMode('Table'); - ndv.actions.changeOutputRunSelector('1 of 2 (6 items)'); ndv.getters.inputRunSelector().find('input').should('include.value', '1 of 2 (6 items)'); ndv.getters.outputRunSelector().find('input').should('include.value', '1 of 2 (6 items)'); diff --git a/cypress/e2e/32-node-io-filter.cy.ts b/cypress/e2e/32-node-io-filter.cy.ts index bc39c1b611..6613fa1ff2 100644 --- a/cypress/e2e/32-node-io-filter.cy.ts +++ b/cypress/e2e/32-node-io-filter.cy.ts @@ -15,13 +15,13 @@ describe('Node IO Filter', () => { workflowPage.getters.canvasNodes().first().dblclick(); ndv.actions.close(); workflowPage.getters.canvasNodes().first().dblclick(); - cy.wait(500); ndv.getters.outputDataContainer().should('be.visible'); + ndv.getters.outputPanel().findChildByTestId('ndv-search').should('exist'); cy.document().trigger('keyup', { key: '/' }); const searchInput = ndv.getters.searchInput(); - searchInput.filter(':focus').should('exist'); + searchInput.should('have.focus'); ndv.getters.pagination().find('li').should('have.length', 3); ndv.getters.outputDataContainer().find('mark').should('not.exist'); @@ -36,19 +36,18 @@ describe('Node IO Filter', () => { it('should filter input/output data separately', () => { workflowPage.getters.canvasNodes().eq(1).dblclick(); - cy.wait(500); ndv.getters.outputDataContainer().should('be.visible'); ndv.getters.inputDataContainer().should('be.visible'); ndv.actions.switchInputMode('Table'); + ndv.getters.outputPanel().findChildByTestId('ndv-search').should('exist'); cy.document().trigger('keyup', { key: '/' }); - ndv.getters.outputPanel().findChildByTestId('ndv-search').filter(':focus').should('not.exist'); + ndv.getters.outputPanel().findChildByTestId('ndv-search').should('not.have.focus'); let focusedInput = ndv.getters .inputPanel() .findChildByTestId('ndv-search') - .filter(':focus') - .should('exist'); + .should('have.focus'); const getInputPagination = () => ndv.getters.inputPanel().findChildByTestId('ndv-data-pagination'); @@ -82,13 +81,9 @@ describe('Node IO Filter', () => { ndv.getters.outputDataContainer().trigger('mouseover'); cy.document().trigger('keyup', { key: '/' }); - ndv.getters.inputPanel().findChildByTestId('ndv-search').filter(':focus').should('not.exist'); + ndv.getters.inputPanel().findChildByTestId('ndv-search').should('not.have.focus'); - focusedInput = ndv.getters - .outputPanel() - .findChildByTestId('ndv-search') - .filter(':focus') - .should('exist'); + focusedInput = ndv.getters.outputPanel().findChildByTestId('ndv-search').should('have.focus'); getInputPagination().find('li').should('have.length', 3); getInputCounter().contains('21 items').should('exist'); diff --git a/cypress/e2e/5-ndv.cy.ts b/cypress/e2e/5-ndv.cy.ts index 71febd1807..ebb624d898 100644 --- a/cypress/e2e/5-ndv.cy.ts +++ b/cypress/e2e/5-ndv.cy.ts @@ -57,9 +57,10 @@ describe('NDV', () => { cy.createFixtureWorkflow('NDV-test-select-input.json', 'NDV test select input'); workflowPage.actions.zoomToFit(); workflowPage.getters.canvasNodes().last().dblclick(); + ndv.actions.switchInputMode('Table'); ndv.getters.inputSelect().click(); ndv.getters.inputOption().last().click(); - ndv.getters.inputDataContainer().find('[class*=schema_]').should('exist'); + ndv.getters.inputDataContainer().should('be.visible'); ndv.getters.inputDataContainer().should('contain', 'start'); ndv.getters.backToCanvas().click(); ndv.getters.container().should('not.be.visible'); @@ -252,6 +253,9 @@ describe('NDV', () => { workflowPage.actions.executeWorkflow(); workflowPage.actions.openNode('Set3'); + ndv.actions.switchInputMode('Table'); + ndv.actions.switchOutputMode('Table'); + ndv.getters .inputRunSelector() .should('exist') @@ -263,9 +267,6 @@ describe('NDV', () => { .find('input') .should('include.value', '2 of 2 (6 items)'); - ndv.actions.switchInputMode('Table'); - ndv.actions.switchOutputMode('Table'); - ndv.actions.changeOutputRunSelector('1 of 2 (6 items)'); ndv.getters.inputRunSelector().find('input').should('include.value', '1 of 2 (6 items)'); ndv.getters.inputTbodyCell(1, 0).should('have.text', '1111'); diff --git a/cypress/pages/ndv.ts b/cypress/pages/ndv.ts index 6e051a564d..c654dc3c2c 100644 --- a/cypress/pages/ndv.ts +++ b/cypress/pages/ndv.ts @@ -131,6 +131,8 @@ export class NDV extends BasePage { nodeRunErrorIndicator: () => cy.getByTestId('node-run-info-danger'), nodeRunErrorMessage: () => cy.getByTestId('node-error-message'), nodeRunErrorDescription: () => cy.getByTestId('node-error-description'), + schemaViewNode: () => cy.getByTestId('run-data-schema-node'), + schemaViewNodeName: () => cy.getByTestId('run-data-schema-node-name'), }; actions = { @@ -212,6 +214,9 @@ export class NDV extends BasePage { this.getters.inputSelect().find('.el-select').click(); this.getters.inputOption().contains(nodeName).click(); }, + expandSchemaViewNode: (nodeName: string) => { + this.getters.schemaViewNodeName().contains(nodeName).click(); + }, addDefaultPinnedData: () => { this.actions.editPinnedData(); this.actions.savePinnedData(); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index e58f92c308..a7fa994289 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -42,13 +42,9 @@ Cypress.Commands.add( }, ); -Cypress.Commands.add( - 'findChildByTestId', - { prevSubject: true }, - (subject: Cypress.Chainable>, childTestId) => { - return subject.find(`[data-test-id="${childTestId}"]`); - }, -); +Cypress.Commands.addQuery('findChildByTestId', function (testId: string) { + return (subject: Cypress.Chainable) => subject.find(`[data-test-id="${testId}"]`); +}); Cypress.Commands.add('waitForLoad', (waitForIntercepts = true) => { // These aliases are set-up before each test in cypress/support/e2e.ts diff --git a/packages/design-system/src/css/_tokens.dark.scss b/packages/design-system/src/css/_tokens.dark.scss index 732416956a..7d13e53982 100644 --- a/packages/design-system/src/css/_tokens.dark.scss +++ b/packages/design-system/src/css/_tokens.dark.scss @@ -240,6 +240,9 @@ --color-mfa-recovery-code-color: var(--color-text-dark); --color-mfa-lose-access-text-color: var(--color-danger); + // Text highlight + --color-text-highlight-background: var(--prim-color-alt-d-shade-600); + // AI --node-type-background-l: 20%; --node-type-supplemental-label-color-h: 235; diff --git a/packages/design-system/src/css/_tokens.scss b/packages/design-system/src/css/_tokens.scss index e7314f46b5..230f9802b0 100644 --- a/packages/design-system/src/css/_tokens.scss +++ b/packages/design-system/src/css/_tokens.scss @@ -305,6 +305,9 @@ --color-mfa-recovery-code-color: var(--prim-gray-490); --color-mfa-lose-access-text-color: var(--color-danger); + // Text highlight + --color-text-highlight-background: var(--prim-color-alt-d-shade-150); + // AI --node-type-background-l: 95%; --node-type-supplemental-label-color-h: 235; diff --git a/packages/design-system/src/css/reset.scss b/packages/design-system/src/css/reset.scss index 84efa3cfd1..ccaaf5b329 100644 --- a/packages/design-system/src/css/reset.scss +++ b/packages/design-system/src/css/reset.scss @@ -207,7 +207,7 @@ ins { } mark { - background-color: var(--color-warning); + background-color: var(--color-text-highlight-background); color: var(--color-text-dark); font-style: italic; font-weight: bold; diff --git a/packages/editor-ui/src/components/InputNodeSelect.vue b/packages/editor-ui/src/components/InputNodeSelect.vue index d8a38b830b..36f74ec380 100644 --- a/packages/editor-ui/src/components/InputNodeSelect.vue +++ b/packages/editor-ui/src/components/InputNodeSelect.vue @@ -157,7 +157,8 @@ function onInputNodeChange(value: string) { + + diff --git a/packages/editor-ui/src/components/RunDataSchemaItem.vue b/packages/editor-ui/src/components/RunDataSchemaItem.vue index 2732ead59c..a63a7bd9f2 100644 --- a/packages/editor-ui/src/components/RunDataSchemaItem.vue +++ b/packages/editor-ui/src/components/RunDataSchemaItem.vue @@ -14,7 +14,7 @@ type Props = { paneType: 'input' | 'output'; mappingEnabled: boolean; draggingPath: string; - distanceFromActive: number; + distanceFromActive?: number; node: INodeUi | null; search: string; }; @@ -26,12 +26,7 @@ const schemaArray = computed( () => (isSchemaValueArray.value ? props.schema.value : []) as Schema[], ); const isSchemaParentTypeArray = computed(() => props.parent?.type === 'array'); -const isFlat = computed( - () => - props.level === 0 && - Array.isArray(props.schema.value) && - props.schema.value.every((v) => !Array.isArray(v.value)), -); + const key = computed((): string | undefined => { return isSchemaParentTypeArray.value ? `[${props.schema.key}]` : props.schema.key; }); @@ -48,12 +43,10 @@ const dragged = computed(() => props.draggingPath === props.schema.path); const getJsonParameterPath = (path: string): string => getMappedExpression({ nodeName: props.node!.name, - distanceFromActive: props.distanceFromActive, + distanceFromActive: props.distanceFromActive ?? 1, path, }); -const transitionDelay = (i: number) => `${i * 0.033}s`; - const getIconBySchemaType = (type: Schema['type']): string => { switch (type) { case 'object': @@ -115,31 +108,35 @@ const getIconBySchemaType = (type: Schema['type']): string => { /> + - + -
- + +
+
+ +
@@ -148,69 +145,67 @@ const getIconBySchemaType = (type: Schema['type']): string => { @import '@/styles/variables'; .item { - display: block; + display: flex; + flex-wrap: wrap; + align-items: center; + line-height: var(--font-line-height-loose); position: relative; - transition: all 0.3s $ease-out-expo; + column-gap: var(--spacing-2xs); + + + .item { + margin-top: var(--spacing-2xs); + } .item { - padding-top: var(--spacing-2xs); padding-left: var(--spacing-l); } input { - position: absolute; - left: -100%; + display: none; ~ .sub { - height: 0; + transition: + grid-template-rows 0.2s $ease-out-expo, + opacity 0.2s $ease-out-expo, + transform 0.2s $ease-out-expo; + transform: translateX(-8px); + opacity: 0; + margin-bottom: 0; - > .item { - transform: translateX(-100%); + .innerSub { + min-height: 0; } } &:checked { ~ .toggle svg { - transform: rotate(180deg); + transform: rotate(90deg); } ~ .sub { - height: auto; - - > .item { - transform: translateX(0); - } + transform: translateX(0); + opacity: 1; + grid-template-rows: 1fr; } } } - - &::after { - content: ''; - display: block; - clear: both; - } } .sub { - display: block; + display: grid; + grid-template-rows: 0fr; overflow: hidden; - transition: all 0.2s $ease-out-expo; - clear: both; + flex-basis: 100%; + scroll-margin: 64px; +} - &.flat { - > .item { - padding-left: 0; - } - } +.innerSub { + display: inline-flex; + flex-direction: column; + order: -1; - &:nth-of-type(1) { - > .item:nth-of-type(1) { - padding-top: 0; - - .toggle { - top: -2px; - } - } + .innerSub > div:first-child { + margin-top: var(--spacing-2xs); } } @@ -234,7 +229,6 @@ const getIconBySchemaType = (type: Schema['type']): string => { } .pill { - float: left; display: inline-flex; height: 24px; padding: 0 var(--spacing-3xs); @@ -285,8 +279,6 @@ const getIconBySchemaType = (type: Schema['type']): string => { .text { display: block; - padding-top: var(--spacing-4xs); - padding-left: var(--spacing-2xs); font-weight: var(--font-weight-normal); font-size: var(--font-size-2xs); overflow: hidden; @@ -302,9 +294,9 @@ const getIconBySchemaType = (type: Schema['type']): string => { .toggle { display: flex; position: absolute; - padding: var(--spacing-2xs); + padding: var(--spacing-4xs) var(--spacing-2xs); left: 0; - top: 5px; + top: 0; justify-content: center; align-items: center; cursor: pointer; @@ -314,7 +306,7 @@ const getIconBySchemaType = (type: Schema['type']): string => { overflow: hidden; svg { - transition: all 0.3s $ease-out-expo; + transition: transform 0.2s $ease-out-expo; } } diff --git a/packages/editor-ui/src/components/RunDataSearch.vue b/packages/editor-ui/src/components/RunDataSearch.vue index 03a8433451..85de524551 100644 --- a/packages/editor-ui/src/components/RunDataSearch.vue +++ b/packages/editor-ui/src/components/RunDataSearch.vue @@ -1,16 +1,18 @@