Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(editor): Node creator actions #4696

Merged
merged 72 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
d1ea5fd
WIP: Node Actions List UI
OlegIvaniv Oct 20, 2022
8fd435c
WIP: Recommended Actions and preseting of fields
OlegIvaniv Oct 25, 2022
7ac428e
WIP: Resource category
OlegIvaniv Oct 26, 2022
9671c4e
:art: Moved actions categorisation to the server
OlegIvaniv Oct 26, 2022
a4e3354
:label: Add missing INodeAction type
OlegIvaniv Oct 27, 2022
9c63b56
:sparkles: Improve SSR categorisation, fix adding of mixed actions
OlegIvaniv Oct 27, 2022
ee82bd9
Merge branch 'master' into n8n-5032-node-actions-list
OlegIvaniv Oct 27, 2022
71ef041
:recycle: Refactor CategorizedItems to composition api, style fixes
OlegIvaniv Oct 31, 2022
1a49a1e
WIP: Adding multiple nodes
OlegIvaniv Nov 1, 2022
5223718
:recycle: Refactor rest of the NodeCreator component to composition A…
OlegIvaniv Nov 2, 2022
7176caa
:sparkles: Allow actions dragging, fix search and refactor passing of…
OlegIvaniv Nov 2, 2022
5194d09
:lipstick: Fix node actions title
OlegIvaniv Nov 3, 2022
b4bc1b0
Merge branch 'master' into n8n-5032-node-actions-list
OlegIvaniv Nov 7, 2022
09ebaf5
Migrate to the pinia store, add posthog feature and various fixes
OlegIvaniv Nov 7, 2022
08f6112
Merge branch 'master' into n8n-5032-node-actions-list
OlegIvaniv Nov 7, 2022
5e92e34
:bug: Fix filtering of trigger actions when not merged
OlegIvaniv Nov 8, 2022
86ed189
fix: N8N-5439 — Do not use simple node item when at NodeHelperPanel root
OlegIvaniv Nov 9, 2022
126731c
:bug: Design review fixes
OlegIvaniv Nov 9, 2022
391729a
:bug: Fix disabling of merged actions
OlegIvaniv Nov 9, 2022
f665933
Fix trigger root filtering
OlegIvaniv Nov 9, 2022
0cdbec0
:sparkles: Allow for custom node actions parser, introduce hubspot pa…
OlegIvaniv Nov 9, 2022
355562c
Merge branch 'master' into n8n-5032-node-actions-list
OlegIvaniv Nov 10, 2022
29773ff
:bug: Fix initial node params validation, fix position of second adde…
OlegIvaniv Nov 15, 2022
787139d
:bug: Introduce operations category, removed canvas node names overrr…
OlegIvaniv Nov 17, 2022
c5a5a59
:sparkles: Prevent NDV auto-open feature flag
OlegIvaniv Nov 21, 2022
78ec92d
:bug: Inject recommened action for trigger nodes without actions
OlegIvaniv Nov 21, 2022
df46ddf
Refactored NodeCreatorNode to Storybook, change filtering of merged n…
OlegIvaniv Nov 22, 2022
947aeab
Improve rendering of app nodes and animation
OlegIvaniv Nov 22, 2022
03bf768
Cleanup, any only enable accordion transition on triggerhelperpanel
OlegIvaniv Nov 22, 2022
719e799
Hide node creator scrollbars in Firefox
OlegIvaniv Nov 23, 2022
b743d2f
Minor styles fixes
OlegIvaniv Nov 23, 2022
8c2d6f6
Do not copy the array in rendering method
OlegIvaniv Nov 23, 2022
3b30414
Removed unused props
OlegIvaniv Nov 23, 2022
ca24c25
Fix memory leak
OlegIvaniv Nov 23, 2022
aef1a16
Fix categorisation of regular nodes with a single resource
OlegIvaniv Nov 28, 2022
bdfa50f
Implement telemetry calls for node actions
OlegIvaniv Nov 29, 2022
b1caae8
Merge branch 'master' into n8n-5032-node-actions-list
OlegIvaniv Nov 29, 2022
10977b8
Move categorization to FE
OlegIvaniv Nov 29, 2022
6d650f9
Fix client side actions categorisation
OlegIvaniv Nov 30, 2022
4c7bbbc
Skip custom action show
OlegIvaniv Nov 30, 2022
23747b4
Only load tooltip for NodeIcon if necessary
OlegIvaniv Nov 30, 2022
adfe034
Fix lodash startCase import
OlegIvaniv Nov 30, 2022
18c18ba
Remove lodash.startcase
OlegIvaniv Nov 30, 2022
09164da
Cleanup
OlegIvaniv Nov 30, 2022
65f674e
Fix node creator autofocus on "tab"
OlegIvaniv Nov 30, 2022
2f2befc
Prevent posthog getFeatureFlag from crashing
OlegIvaniv Nov 30, 2022
07193f9
Debugging preview env search issues
OlegIvaniv Nov 30, 2022
a9c257a
Remove logs
OlegIvaniv Nov 30, 2022
1793783
Merge branch 'master' into n8n-5032-node-actions-list
OlegIvaniv Nov 30, 2022
35646d4
Make sure the pre-filled params are update not overwritten
OlegIvaniv Dec 1, 2022
04c250c
Merge branch 'master' into n8n-5032-node-actions-list
OlegIvaniv Dec 1, 2022
79920ff
Get rid of transition in itemiterator
OlegIvaniv Dec 1, 2022
9a75d2b
WIP: Rough version of NodeActions keyboard navigation, replace nodeCr…
OlegIvaniv Dec 5, 2022
eeb1006
Rewrite to add support for ActionItem to ItemIterator and make Catego…
OlegIvaniv Dec 6, 2022
d4753df
Merge branch 'master' into n8n-5032-node-actions-list
OlegIvaniv Dec 6, 2022
81c66af
Fix category item counter & cleanup
OlegIvaniv Dec 6, 2022
b3138c6
Add APIHint to actions search no-result, clean up NodeCreatorNode
OlegIvaniv Dec 6, 2022
f764bca
Improve node actions no results message
OlegIvaniv Dec 6, 2022
e800237
Remove logging, fix filtering of recommended placeholder category
OlegIvaniv Dec 7, 2022
7260b6b
Remove unused NodeActions component and node merging feature falg
OlegIvaniv Dec 8, 2022
094505b
Do not show regular nodes without actions
OlegIvaniv Dec 8, 2022
17f2fcc
Make sure to add manual trigger when adding http node via actions hint
OlegIvaniv Dec 8, 2022
72fb706
Fixed api hint footer line height
OlegIvaniv Dec 8, 2022
a50747d
Prevent pointer-events od NodeIcon img and remove "this" from template
OlegIvaniv Dec 8, 2022
84e9739
Address PR points
OlegIvaniv Dec 8, 2022
11fab8b
Merge branch 'master' into n8n-5032-node-actions-list
OlegIvaniv Dec 8, 2022
b4fada2
Fix e2e specs
OlegIvaniv Dec 8, 2022
6fb0eae
Make sure canvas ia loaded
OlegIvaniv Dec 8, 2022
12f21cc
Make sure canvas ia loaded before opening nodeCreator in e2e spec
OlegIvaniv Dec 8, 2022
2f45c36
Fix flaky workflows tags e2e getter
OlegIvaniv Dec 8, 2022
dfb9217
Imrpove node creator click outside UX, add manual node to regular nod…
OlegIvaniv Dec 8, 2022
7435c24
Add manual trigger node if dragging regular from trigger panel
OlegIvaniv Dec 8, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions cypress/e2e/4-node-creator.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,20 @@ describe('Node Creator', () => {
.should('exist')
.should('contain.text', 'We didn\'t make that... yet');

nodeCreatorFeature.getters.searchBar().find('input').clear().type('edit image');
nodeCreatorFeature.getters.creatorItem().should('have.length', 1);

nodeCreatorFeature.getters.searchBar().find('input').clear().type('this node totally does not exist');
nodeCreatorFeature.getters.creatorItem().should('have.length', 0);

nodeCreatorFeature.getters.searchBar().find('input').clear()
nodeCreatorFeature.getters.getCreatorItem('On App Event').click();

nodeCreatorFeature.getters.searchBar().find('input').clear().type('edit image');
nodeCreatorFeature.getters.creatorItem().should('have.length', 0);
nodeCreatorFeature.getters.noResults()
.should('exist')
.should('contain.text', 'To see results, click here');
.should('contain.text', 'To see all results, click here');

nodeCreatorFeature.getters.noResults().contains('click here').click();
nodeCreatorFeature.getters.nodeCreatorTabs().should('exist');
Expand All @@ -85,6 +94,7 @@ describe('Node Creator', () => {
})

it('should add manual trigger node', () => {
cy.get('.el-loading-mask').should('not.exist');
nodeCreatorFeature.getters.canvasAddButton().click();
nodeCreatorFeature.getters.getCreatorItem('Manually').click();

Expand All @@ -95,7 +105,7 @@ describe('Node Creator', () => {
nodeCreatorFeature.getters.nodeCreator().should('not.exist');

// TODO: Replace once we have canvas feature utils
cy.get('div').contains("On clicking 'execute'").should('exist');
cy.get('div').contains("Add first step").should('exist');
})
it('check if non-core nodes are rendered', () => {
cy.wait('@nodesIntercept').then((interception) => {
Expand Down Expand Up @@ -144,7 +154,7 @@ describe('Node Creator', () => {
nodeCreatorFeature.getters.getCreatorItem(customCategory).should('exist');

nodeCreatorFeature.actions.toggleCategory(customCategory);
nodeCreatorFeature.getters.getCreatorItem(customNode).findChildByTestId('node-item-community-tooltip').should('exist');
nodeCreatorFeature.getters.getCreatorItem(customNode).findChildByTestId('node-creator-item-tooltip').should('exist');
nodeCreatorFeature.getters.getCreatorItem(customNode).contains(customNodeDescription).should('exist');
nodeCreatorFeature.actions.selectNode(customNode);

Expand Down
6 changes: 3 additions & 3 deletions cypress/e2e/7-workflow-actions.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,15 @@ describe('Workflow Actions', () => {
it('should add more tags', () => {
WorkflowPage.getters.newTagLink().click();
WorkflowPage.actions.addTags(TEST_WF_TAGS);
WorkflowPage.getters.workflowTagElements().first().click();
WorkflowPage.getters.firstWorkflowTagElement().click();
WorkflowPage.actions.addTags(['Another one']);
WorkflowPage.getters.workflowTagElements().should('have.length', TEST_WF_TAGS.length + 1);
});

it('should remove tags by clicking X in tag', () => {
WorkflowPage.getters.newTagLink().click();
WorkflowPage.actions.addTags(TEST_WF_TAGS);
WorkflowPage.getters.workflowTagElements().first().click();
WorkflowPage.getters.firstWorkflowTagElement().click();
WorkflowPage.getters.workflowTagsContainer().find('.el-tag__close').first().click();
cy.get('body').type('{enter}');
WorkflowPage.getters.workflowTagElements().should('have.length', TEST_WF_TAGS.length - 1);
Expand All @@ -83,7 +83,7 @@ describe('Workflow Actions', () => {
it('should remove tags from dropdown', () => {
WorkflowPage.getters.newTagLink().click();
WorkflowPage.actions.addTags(TEST_WF_TAGS);
WorkflowPage.getters.workflowTagElements().first().click();
WorkflowPage.getters.firstWorkflowTagElement().click();
WorkflowPage.getters.workflowTagsDropdown().find('li').first().click();
cy.get('body').type('{enter}');
WorkflowPage.getters.workflowTagElements().should('have.length', TEST_WF_TAGS.length - 1);
Expand Down
3 changes: 2 additions & 1 deletion cypress/pages/features/node-creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ export class NodeCreator extends BasePage {
creatorItem: () => cy.getByTestId('item-iterator-item'),
communityNodeTooltip: () => cy.getByTestId('node-item-community-tooltip'),
noResults: () => cy.getByTestId('categorized-no-results'),
nodeItemName: () => cy.getByTestId('node-item-name'),
nodeItemName: () => cy.getByTestId('node-creator-item-name'),
activeSubcategory: () => cy.getByTestId('categorized-items-subcategory'),
expandedCategories: () => this.getters.creatorItem().find('>div').filter('.active').invoke('text'),
};
actions = {
openNodeCreator: () => {
cy.get('.el-loading-mask').should('not.exist');
this.getters.plusButton().click();
this.getters.nodeCreator().should('be.visible')
},
Expand Down
7 changes: 5 additions & 2 deletions cypress/pages/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export class WorkflowPage extends BasePage {
workflowTagsContainer: () => cy.getByTestId('workflow-tags-container'),
workflowTagsInput: () => this.getters.workflowTagsContainer().then(($el) => cy.wrap($el.find('input').first())),
workflowTagElements: () => cy.get('[data-test-id="workflow-tags-container"] span.tags > span'),
firstWorkflowTagElement: () => cy.get('[data-test-id="workflow-tags-container"] span.tags > span:nth-child(1)'),
workflowTagsDropdown: () => cy.getByTestId('workflow-tags-dropdown'),
newTagLink: () => cy.getByTestId('new-tag-link'),
saveButton: () => cy.getByTestId('workflow-save-button'),
Expand Down Expand Up @@ -43,12 +44,14 @@ export class WorkflowPage extends BasePage {
addInitialNodeToCanvas: (nodeDisplayName: string) => {
this.getters.canvasPlusButton().click();
this.getters.nodeCreatorSearchBar().type(nodeDisplayName);
this.getters.nodeCreatorSearchBar().type('{enter}{esc}');
this.getters.nodeCreatorSearchBar().type('{enter}');
cy.get('body').type('{esc}');
},
addNodeToCanvas: (nodeDisplayName: string) => {
this.getters.nodeCreatorPlusButton().click();
this.getters.nodeCreatorSearchBar().type(nodeDisplayName);
this.getters.nodeCreatorSearchBar().type('{enter}{esc}');
this.getters.nodeCreatorSearchBar().type('{enter}');
cy.get('body').type('{esc}');
},
openNodeNdv: (nodeTypeName: string) => {
this.getters.canvasNodeByName(nodeTypeName).dblclick();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* tslint:disable:variable-name */
import N8nNodeCreatorNode from './NodeCreatorNode.vue';
import { StoryFn } from '@storybook/vue';

export default {
title: 'Modules/Node Creator Node',
component: N8nNodeCreatorNode,
};

const DefaultTemplate: StoryFn = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: {
N8nNodeCreatorNode,
},
template: `
<n8n-node-creator-node v-bind="$props">
<template v-slot:icon>
<img src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/cartman.svg" />
</template>
</n8n-node-creator-node>
`,
});

export const WithTitle = DefaultTemplate.bind({});
WithTitle.args = {
title: 'Node with title',
tooltipHtml: '<b>Bold</b> tooltip',
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean et vehicula ipsum, eu facilisis lacus. Aliquam commodo vel elit eget mollis. Quisque ac elit non purus iaculis placerat. Quisque fringilla ultrices nisi sed porta.',
};

const PanelTemplate: StoryFn = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: {
N8nNodeCreatorNode,
},
data() {
return {
isPanelActive: false,
};
},
template: `
<n8n-node-creator-node v-bind="$props" :isPanelActive="isPanelActive" @click.capture="isPanelActive = true">
<template v-slot:icon>
<img src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/cartman.svg" />
</template>
<template v-slot:panel>
<p style="width: 100%; height: 300px; background: white">Lorem ipsum dolor sit amet</p>
<button @click="isPanelActive = false">Close</button>
</template>
</n8n-node-creator-node>
`,
});
export const WithPanel = PanelTemplate.bind({});
WithPanel.args = {
title: 'Node with panel',
isTrigger: true,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<template>
<div
:class="{
[$style.creatorNode]: true,
[$style.hasAction]: !showActionArrow,
}"
v-on="$listeners"
v-bind="$attrs"
>
<div :class="$style.nodeIcon">
<slot name="icon" />
</div>
<div>
<div :class="$style.details">
<span :class="$style.name" v-text="title" data-test-id="node-creator-item-name" />
<trigger-icon v-if="isTrigger" :class="$style.triggerIcon" />
<n8n-tooltip
v-if="!!$slots.tooltip"
placement="top"
data-test-id="node-creator-item-tooltip"
>
<template #content>
<slot name="tooltip" />
</template>
<n8n-icon :class="$style.tooltipIcon" icon="cube" />
</n8n-tooltip>
</div>
<p :class="$style.description" v-if="description" v-text="description" />
</div>
<slot name="dragContent" />
<button :class="$style.panelIcon" v-if="showActionArrow">
<font-awesome-icon :class="$style.panelArrow" icon="arrow-right" />
</button>
</div>
</template>

<script setup lang="ts">
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import TriggerIcon from './TriggerIcon.vue';
import N8nTooltip from '../N8nTooltip';

export interface Props {
active?: boolean;
isTrigger?: boolean;
description?: string;
title: string;
showActionArrow?: boolean;
}

defineProps<Props>();

defineEmits<{
(event: 'tooltipClick', $e: MouseEvent): void;
}>();
</script>

<style lang="scss" module>
.creatorNode {
display: flex;
align-items: center;
cursor: pointer;
z-index: 1;
padding: 11px 8px 11px 0;

&.hasAction {
user-select: none;
}
}
.creatorNode:hover .panelIcon {
color: var(--color-text-light);
}

.panelIcon {
flex-grow: 1;
display: flex;
justify-content: flex-end;
align-items: center;
margin-left: var(--spacing-2xs);
color: var(--color-text-lighter);
cursor: pointer;
background: transparent;
border: none;
}
.tooltipIcon {
margin-left: var(--spacing-3xs);
}
.panelArrow {
font-size: var(--font-size-2xs);
width: 12px;
}
.details {
align-items: center;
}
.nodeIcon {
display: flex;
margin-right: var(--spacing-s);

& > :global(*) {
min-width: 25px;
max-width: 25px;
}
}
.name {
font-weight: var(--font-weight-bold);
font-size: var(--font-size-s);
line-height: 1.115rem;
}
.description {
margin-top: var(--spacing-5xs);
font-size: var(--font-size-2xs);
line-height: 1rem;
font-weight: 400;
color: var(--node-creator-description-colo, var(--color-text-base));
}

.triggerIcon {
margin-left: var(--spacing-2xs);
}
</style>

<style lang="scss" scoped>
.el-tooltip svg {
color: var(--color-foreground-xdark);
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<template>
<span :class="$style.trigger">
<svg
width="36px"
height="36px"
viewBox="0 0 36 36"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<title>Trigger node</title>
<g
id="/integrations-(V1-feature)"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<g
id="Individual-node-view"
transform="translate(-304.000000, -137.000000)"
fill-rule="nonzero"
>
<g id="left-column" transform="translate(120.000000, 131.000000)">
<g id="trigger-badge" transform="translate(178.000000, 0.000000)">
<g id="trigger-icon" transform="translate(6.857143, 6.857143)">
<g id="Icon" transform="translate(8.571429, 0.000000)" fill="#FF6150">
<polygon
id="Icon-Path"
points="7.14285714 21.4285714 0 21.4285714 10 1.42857143 10 12.8571429 17.1428571 12.8571429 7.14285714 32.8571429"
></polygon>
</g>
<rect id="ViewBox" x="0" y="0" width="34.2857143" height="34.2857143"></rect>
</g>
</g>
</g>
</g>
</g>
</svg>
</span>
</template>

<script lang="ts">
export default {
name: 'TriggerIcon',
};
</script>

<style lang="scss" module>
.trigger {
background-color: var(--trigger-icon-background-color, var(--color-background-xlight));
border: 1px solid var(--trigger-icon-border-color, var(--color-background-xlight));
border-radius: 4px;
height: 16px;
width: 16px;
display: inline-block;
vertical-align: middle;
line-height: 16px;

> svg {
width: 100%;
height: 100%;
}
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import NodeCreatorNode from './NodeCreatorNode.vue';

export default NodeCreatorNode;
Loading