diff --git a/cypress/e2e/16-form-trigger-node.cy.ts b/cypress/e2e/16-form-trigger-node.cy.ts index 60fbd7c419586..ed901107ea60e 100644 --- a/cypress/e2e/16-form-trigger-node.cy.ts +++ b/cypress/e2e/16-form-trigger-node.cy.ts @@ -44,8 +44,7 @@ describe('n8n Form Trigger', () => { ':nth-child(3) > .border-top-dashed > .parameter-input-list-wrapper > :nth-child(1) > .parameter-item', ) .find('input[placeholder*="e.g. What is your name?"]') - .type('Test Field 3') - .blur(); + .type('Test Field 3'); cy.get( ':nth-child(3) > .border-top-dashed > .parameter-input-list-wrapper > :nth-child(2) > .parameter-item', ).click(); @@ -56,27 +55,24 @@ describe('n8n Form Trigger', () => { ':nth-child(4) > .border-top-dashed > .parameter-input-list-wrapper > :nth-child(1) > .parameter-item', ) .find('input[placeholder*="e.g. What is your name?"]') - .type('Test Field 4') - .blur(); + .type('Test Field 4'); cy.get( ':nth-child(4) > .border-top-dashed > .parameter-input-list-wrapper > :nth-child(2) > .parameter-item', ).click(); getVisibleSelect().contains('Dropdown').click(); - cy.get( - '.border-top-dashed > :nth-child(2) > :nth-child(3) > .multi-parameter > .fixed-collection-parameter > :nth-child(2) > .button', - ).click(); - cy.get( - ':nth-child(4) > :nth-child(1) > :nth-child(2) > :nth-child(3) > .multi-parameter > .fixed-collection-parameter > .fixed-collection-parameter-property > :nth-child(1) > :nth-child(1)', - ) - .find('input') - .type('Option 1') - .blur(); - cy.get( - ':nth-child(4) > :nth-child(1) > :nth-child(2) > :nth-child(3) > .multi-parameter > .fixed-collection-parameter > .fixed-collection-parameter-property > :nth-child(1) > :nth-child(2)', - ) - .find('input') - .type('Option 2') - .blur(); + cy.contains('button', 'Add Field Option').click(); + cy.contains('label', 'Field Options') + .parent() + .nextAll() + .find('[data-test-id="parameter-input-field"]') + .eq(0) + .type('Option 1'); + cy.contains('label', 'Field Options') + .parent() + .nextAll() + .find('[data-test-id="parameter-input-field"]') + .eq(1) + .type('Option 2'); //add optional submitted message cy.get('.param-options').click(); @@ -94,7 +90,6 @@ describe('n8n Form Trigger', () => { .children() .children() .first() - .clear() .type('Your test form was successfully submitted'); ndv.getters.backToCanvas().click(); diff --git a/cypress/e2e/5-ndv.cy.ts b/cypress/e2e/5-ndv.cy.ts index e8215db38f345..8bad4245544c0 100644 --- a/cypress/e2e/5-ndv.cy.ts +++ b/cypress/e2e/5-ndv.cy.ts @@ -65,26 +65,6 @@ describe('NDV', () => { cy.shouldNotHaveConsoleErrors(); }); - it('should disconect Switch outputs if rules order was changed', () => { - cy.createFixtureWorkflow('NDV-test-switch_reorder.json', 'NDV test switch reorder'); - workflowPage.actions.zoomToFit(); - - workflowPage.actions.executeWorkflow(); - workflowPage.actions.openNode('Merge'); - ndv.getters.outputPanel().contains('2 items').should('exist'); - cy.contains('span', 'first').should('exist'); - ndv.getters.backToCanvas().click(); - - workflowPage.actions.openNode('Switch'); - cy.get('.cm-line').realMouseMove(100, 100); - cy.get('.fa-angle-down').first().click(); - ndv.getters.backToCanvas().click(); - workflowPage.actions.executeWorkflow(); - workflowPage.actions.openNode('Merge'); - ndv.getters.outputPanel().contains('2 items').should('exist'); - cy.contains('span', 'zero').should('exist'); - }); - it('should show correct validation state for resource locator params', () => { workflowPage.actions.addNodeToCanvas('Typeform', true, true); ndv.getters.container().should('be.visible'); diff --git a/packages/design-system/src/css/_tokens.dark.scss b/packages/design-system/src/css/_tokens.dark.scss index a3fc653550f1a..4390bc1da81cb 100644 --- a/packages/design-system/src/css/_tokens.dark.scss +++ b/packages/design-system/src/css/_tokens.dark.scss @@ -462,6 +462,9 @@ --color-configurable-node-name: var(--color-text-dark); --color-secondary-link: var(--prim-color-secondary-tint-200); --color-secondary-link-hover: var(--prim-color-secondary-tint-100); + //Params + --color-icon-base: var(--color-text-light); + --color-icon-hover: var(--prim-color-primary); --color-menu-background: var(--prim-gray-740); --color-menu-hover-background: var(--prim-gray-670); diff --git a/packages/design-system/src/css/_tokens.scss b/packages/design-system/src/css/_tokens.scss index b8f3049cf2eaf..944652e43e3bc 100644 --- a/packages/design-system/src/css/_tokens.scss +++ b/packages/design-system/src/css/_tokens.scss @@ -621,6 +621,10 @@ --spacing-3xl: 4rem; --spacing-4xl: 8rem; --spacing-5xl: 16rem; + + //Params + --color-icon-base: var(--color-text-light); + --color-icon-hover: var(--prim-color-primary); } :root { diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 3cf113d98fc0d..68b13e13f492d 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -82,6 +82,7 @@ "vue-router": "catalog:frontend", "vue-virtual-scroller": "2.0.0-beta.8", "vue3-touch-events": "^4.1.3", + "vuedraggable": "4.1.0", "xss": "catalog:" }, "devDependencies": { diff --git a/packages/editor-ui/src/components/AssignmentCollection/Assignment.vue b/packages/editor-ui/src/components/AssignmentCollection/Assignment.vue index 7240dac1e2c11..614ae3f590071 100644 --- a/packages/editor-ui/src/components/AssignmentCollection/Assignment.vue +++ b/packages/editor-ui/src/components/AssignmentCollection/Assignment.vue @@ -152,6 +152,14 @@ const onBlur = (): void => { }" data-test-id="assignment" > + { size="mini" icon="trash" data-test-id="assignment-remove" - :class="$style.remove" + :class="[$style.iconButton, $style.extraTopPadding]" @click="onRemove" > @@ -241,7 +249,7 @@ const onBlur = (): void => { } &:hover { - .remove { + .iconButton { opacity: 1; } } @@ -269,12 +277,19 @@ const onBlur = (): void => { } } -.remove { +.iconButton { position: absolute; left: 0; - top: var(--spacing-l); opacity: 0; transition: opacity 100ms ease-in; + color: var(--icon-base-color); +} +.extraTopPadding { + top: calc(20px + var(--spacing-l)); +} + +.defaultTopPadding { + top: var(--spacing-l); } .status { diff --git a/packages/editor-ui/src/components/AssignmentCollection/AssignmentCollection.vue b/packages/editor-ui/src/components/AssignmentCollection/AssignmentCollection.vue index 24545bd7b9085..0aebc16bb64fe 100644 --- a/packages/editor-ui/src/components/AssignmentCollection/AssignmentCollection.vue +++ b/packages/editor-ui/src/components/AssignmentCollection/AssignmentCollection.vue @@ -15,6 +15,7 @@ import ParameterOptions from '../ParameterOptions.vue'; import Assignment from './Assignment.vue'; import { inputDataToAssignments, typeFromExpression } from './utils'; import { propertyNameFromExpression } from '@/utils/mappingUtils'; +import Draggable from 'vuedraggable'; interface Props { parameter: INodeProperties; @@ -133,19 +134,27 @@ function optionSelected(action: string) {
-
- - -
+ + +
diff --git a/packages/editor-ui/src/components/FilterConditions/Condition.vue b/packages/editor-ui/src/components/FilterConditions/Condition.vue index 316b6827fac93..be4d02224c2e7 100644 --- a/packages/editor-ui/src/components/FilterConditions/Condition.vue +++ b/packages/editor-ui/src/components/FilterConditions/Condition.vue @@ -33,6 +33,7 @@ interface Props { canRemove?: boolean; readOnly?: boolean; index?: number; + canDrag?: boolean; } const props = withDefaults(defineProps(), { @@ -41,6 +42,7 @@ const props = withDefaults(defineProps(), { fixedLeftValue: false, readOnly: false, index: 0, + canDrag: true, }); const emit = defineEmits<{ @@ -152,6 +154,15 @@ const onBlur = (): void => { }" data-test-id="filter-condition" > + { icon="trash" data-test-id="filter-remove-condition" :title="i18n.baseText('filter.removeCondition')" - :class="$style.remove" + :class="[$style.iconButton, $style.extraTopPadding]" @click="onRemove" > @@ -248,7 +259,7 @@ const onBlur = (): void => { } &:hover { - .remove { + .iconButton { opacity: 1; } } @@ -261,13 +272,21 @@ const onBlur = (): void => { .statusIcon { padding-left: var(--spacing-4xs); + padding-right: var(--spacing-4xs); } -.remove { +.iconButton { position: absolute; left: 0; - top: var(--spacing-l); opacity: 0; transition: opacity 100ms ease-in; + color: var(--icon-base-color); +} + +.defaultTopPadding { + top: var(--spacing-m); +} +.extraTopPadding { + top: calc(14px + var(--spacing-m)); } diff --git a/packages/editor-ui/src/components/FilterConditions/FilterConditions.vue b/packages/editor-ui/src/components/FilterConditions/FilterConditions.vue index 6b58fb4290be5..41ef0f7430ce8 100644 --- a/packages/editor-ui/src/components/FilterConditions/FilterConditions.vue +++ b/packages/editor-ui/src/components/FilterConditions/FilterConditions.vue @@ -23,6 +23,7 @@ import Condition from './Condition.vue'; import CombinatorSelect from './CombinatorSelect.vue'; import { resolveParameter } from '@/composables/useWorkflowHelpers'; import { v4 as uuid } from 'uuid'; +import Draggable from 'vuedraggable'; interface Props { parameter: INodeProperties; @@ -161,30 +162,41 @@ function getIssues(index: number): string[] {
-
- - - -
+ + +
.combinator { + display: none; +} diff --git a/packages/editor-ui/src/components/FixedCollectionParameter.vue b/packages/editor-ui/src/components/FixedCollectionParameter.vue index de7359dfddb9a..59eacfdb100e6 100644 --- a/packages/editor-ui/src/components/FixedCollectionParameter.vue +++ b/packages/editor-ui/src/components/FixedCollectionParameter.vue @@ -17,6 +17,7 @@ import { N8nButton, } from 'n8n-design-system'; import ParameterInputList from './ParameterInputList.vue'; +import Draggable from 'vuedraggable'; const locale = useI18n(); @@ -126,42 +127,6 @@ const getOptionProperties = (optionName: string) => { return undefined; }; -const moveOptionDown = (optionName: string, index: number) => { - if (Array.isArray(mutableValues.value[optionName])) { - mutableValues.value[optionName].splice( - index + 1, - 0, - mutableValues.value[optionName].splice(index, 1)[0], - ); - } - - const parameterData: ValueChangedEvent = { - name: getPropertyPath(optionName), - value: mutableValues.value[optionName], - type: 'optionsOrderChanged', - }; - - emit('valueChanged', parameterData); -}; - -const moveOptionUp = (optionName: string, index: number) => { - if (Array.isArray(mutableValues.value[optionName])) { - mutableValues.value?.[optionName].splice( - index - 1, - 0, - mutableValues.value[optionName].splice(index, 1)[0], - ); - } - - const parameterData: ValueChangedEvent = { - name: getPropertyPath(optionName), - value: mutableValues.value[optionName], - type: 'optionsOrderChanged', - }; - - emit('valueChanged', parameterData); -}; - const optionSelected = (optionName: string) => { const option = getOptionProperties(optionName); if (option === undefined) { @@ -219,6 +184,15 @@ const optionSelected = (optionName: string) => { const valueChanged = (parameterData: IUpdateInformation) => { emit('valueChanged', parameterData); }; +const onDragChange = (optionName: string) => { + const parameterData: ValueChangedEvent = { + name: getPropertyPath(optionName), + value: mutableValues.value[optionName], + type: 'optionsOrderChanged', + }; + + emit('valueChanged', parameterData); +};