Skip to content

Commit

Permalink
feat(editor): Add schema view to expression modal (n8n-io#9976)
Browse files Browse the repository at this point in the history
  • Loading branch information
elsmr authored Aug 12, 2024
1 parent 9d7caac commit 71b6c67
Show file tree
Hide file tree
Showing 29 changed files with 923 additions and 1,789 deletions.
43 changes: 33 additions & 10 deletions cypress/e2e/14-mapping.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('Data mapping', () => {
ndv.actions.mapDataFromHeader(2, 'value');
ndv.getters
.inlineExpressionEditorInput()
.should('have.text', "{{ $json.timestamp }} {{ $json['Readable date'] }}");
.should('have.text', "{{ $json['Readable date'] }}{{ $json.timestamp }}");
});

it('maps expressions from table json, and resolves value based on hover', () => {
Expand Down Expand Up @@ -145,8 +145,8 @@ describe('Data mapping', () => {
ndv.actions.mapToParameter('value');
ndv.getters
.inlineExpressionEditorInput()
.should('have.text', '{{ $json.input[0].count }} {{ $json.input }}');
ndv.actions.validateExpressionPreview('value', '0 [object Object]');
.should('have.text', '{{ $json.input }}{{ $json.input[0].count }}');
ndv.actions.validateExpressionPreview('value', '[object Object]0');
});

it('maps expressions from schema view', () => {
Expand All @@ -170,8 +170,8 @@ describe('Data mapping', () => {
ndv.actions.mapToParameter('value');
ndv.getters
.inlineExpressionEditorInput()
.should('have.text', '{{ $json.input[0].count }} {{ $json.input }}');
ndv.actions.validateExpressionPreview('value', '0 [object Object]');
.should('have.text', '{{ $json.input }}{{ $json.input[0].count }}');
ndv.actions.validateExpressionPreview('value', '[object Object]0');
});

it('maps expressions from previous nodes', () => {
Expand Down Expand Up @@ -200,17 +200,17 @@ describe('Data mapping', () => {
.inlineExpressionEditorInput()
.should(
'have.text',
`{{ $('${SCHEDULE_TRIGGER_NODE_NAME}').item.json.input[0].count }} {{ $('${SCHEDULE_TRIGGER_NODE_NAME}').item.json.input }}`,
`{{ $('${SCHEDULE_TRIGGER_NODE_NAME}').item.json.input }}{{ $('${SCHEDULE_TRIGGER_NODE_NAME}').item.json.input[0].count }}`,
);

ndv.actions.selectInputNode('Set');

ndv.getters.executingLoader().should('not.exist');
ndv.getters.inputDataContainer().should('exist');
ndv.actions.validateExpressionPreview('value', '0 [object Object]');
ndv.actions.validateExpressionPreview('value', '[object Object]0');

ndv.getters.inputTbodyCell(2, 0).realHover();
ndv.actions.validateExpressionPreview('value', '1 [object Object]');
ndv.actions.validateExpressionPreview('value', '[object Object]1');
});

it('maps keys to path', () => {
Expand Down Expand Up @@ -284,8 +284,8 @@ describe('Data mapping', () => {
ndv.actions.mapToParameter('value');
ndv.getters
.inlineExpressionEditorInput()
.should('have.text', '{{ $json.input[0].count }} {{ $json.input }}');
ndv.actions.validateExpressionPreview('value', '0 [object Object]');
.should('have.text', '{{ $json.input }}{{ $json.input[0].count }}');
ndv.actions.validateExpressionPreview('value', '[object Object]0');
});

it('renders expression preview when a previous node is selected', () => {
Expand Down Expand Up @@ -342,4 +342,27 @@ describe('Data mapping', () => {
.invoke('css', 'border')
.should('include', 'dashed rgb(90, 76, 194)');
});

it('maps expressions to a specific location in the editor', () => {
cy.fixture('Test_workflow_3.json').then((data) => {
cy.get('body').paste(JSON.stringify(data));
});
workflowPage.actions.zoomToFit();

workflowPage.actions.openNode('Set');
ndv.actions.clearParameterInput('value');
ndv.actions.typeIntoParameterInput('value', '=');
ndv.actions.typeIntoParameterInput('value', 'hello world{enter}{enter}newline');

ndv.getters.inputDataContainer().should('exist').find('span').contains('count').realMouseDown();

ndv.actions.mapToParameter('value');

ndv.getters.inputDataContainer().find('span').contains('input').realMouseDown();
ndv.actions.mapToParameter('value', 'bottom');

ndv.getters
.inlineExpressionEditorInput()
.should('have.text', '{{ $json.input[0].count }}hello worldnewline{{ $json.input }}');
});
});
4 changes: 2 additions & 2 deletions cypress/pages/ndv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ export class NDV extends BasePage {
const droppable = `[data-test-id="parameter-input-${parameterName}"]`;
cy.draganddrop(draggable, droppable);
},
mapToParameter: (parameterName: string) => {
mapToParameter: (parameterName: string, position?: 'top' | 'center' | 'bottom') => {
const droppable = `[data-test-id="parameter-input-${parameterName}"]`;
cy.draganddrop('', droppable);
cy.draganddrop('', droppable, { position });
},
switchInputMode: (type: 'Schema' | 'Table' | 'JSON' | 'Binary') => {
this.getters.inputDisplayMode().find('label').contains(type).click({ force: true });
Expand Down
4 changes: 2 additions & 2 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ Cypress.Commands.add('drag', (selector, pos, options) => {
});
});

Cypress.Commands.add('draganddrop', (draggableSelector, droppableSelector) => {
Cypress.Commands.add('draganddrop', (draggableSelector, droppableSelector, options) => {
if (draggableSelector) {
cy.get(draggableSelector).should('exist');
}
Expand All @@ -197,7 +197,7 @@ Cypress.Commands.add('draganddrop', (draggableSelector, droppableSelector) => {
cy.get(droppableSelector).realMouseMove(0, 0);
cy.get(droppableSelector).realMouseMove(pageX, pageY);
cy.get(droppableSelector).realHover();
cy.get(droppableSelector).realMouseUp();
cy.get(droppableSelector).realMouseUp({ position: options?.position ?? 'top' });
if (draggableSelector) {
cy.get(draggableSelector).realMouseUp();
}
Expand Down
10 changes: 9 additions & 1 deletion cypress/support/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ interface SigninPayload {
password: string;
}

interface DragAndDropOptions {
position: 'top' | 'center' | 'bottom';
}

declare global {
namespace Cypress {
interface SuiteConfigOverrides {
Expand Down Expand Up @@ -56,7 +60,11 @@ declare global {
target: [number, number],
options?: { abs?: boolean; index?: number; realMouse?: boolean; clickToFinish?: boolean },
): void;
draganddrop(draggableSelector: string, droppableSelector: string): void;
draganddrop(
draggableSelector: string,
droppableSelector: string,
options?: Partial<DragAndDropOptions>,
): void;
push(type: string, data: unknown): void;
shouldNotHaveConsoleErrors(): void;
window(): Chainable<
Expand Down
1 change: 1 addition & 0 deletions packages/design-system/src/css/_tokens.dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
--color-pending-resolvable-foreground: var(--color-text-base);
--color-pending-resolvable-background: var(--prim-gray-70-alpha-01);
--color-expression-editor-background: var(--prim-gray-800);
--color-expression-editor-modal-background: var(--prim-gray-800);
--color-expression-syntax-example: var(--prim-gray-670);
--color-autocomplete-item-selected: var(--prim-color-secondary-tint-200);
--color-autocomplete-section-header-border: var(--prim-gray-540);
Expand Down
1 change: 1 addition & 0 deletions packages/design-system/src/css/_tokens.scss
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
--color-pending-resolvable-foreground: var(--color-text-base);
--color-pending-resolvable-background: var(--prim-gray-40);
--color-expression-editor-background: var(--prim-gray-0);
--color-expression-editor-modal-background: var(--color-background-base);
--color-expression-syntax-example: var(--prim-gray-40);
--color-autocomplete-item-selected: var(--color-secondary);
--color-autocomplete-section-header-border: var(--color-foreground-light);
Expand Down
13 changes: 0 additions & 13 deletions packages/editor-ui/src/Interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,19 +207,6 @@ export interface ITableData {
hasJson: { [key: string]: boolean };
}

export interface IVariableItemSelected {
variable: string;
}

export interface IVariableSelectorOption {
name: string;
key?: string;
value?: string;
options?: IVariableSelectorOption[] | null;
allowParentSelect?: boolean;
dataType?: string;
}

// Simple version of n8n-workflow.Workflow
export interface IWorkflowData {
id?: string;
Expand Down
6 changes: 3 additions & 3 deletions packages/editor-ui/src/components/DraggableTarget.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const props = withDefaults(defineProps<Props>(), {
});
const emit = defineEmits<{
drop: [value: string];
drop: [value: string, event: MouseEvent];
}>();
const hovering = ref(false);
Expand Down Expand Up @@ -60,10 +60,10 @@ function onMouseLeave() {
hovering.value = false;
}
function onMouseUp() {
function onMouseUp(event: MouseEvent) {
if (activeDrop.value) {
const data = ndvStore.draggableData;
emit('drop', data);
emit('drop', data, event);
}
}
Expand Down
Loading

0 comments on commit 71b6c67

Please sign in to comment.