feat(editor): Node creator actions (#4696)

* WIP: Node Actions List UI

* WIP: Recommended Actions and preseting of fields

* WIP: Resource category

* 🎨 Moved actions categorisation to the server

* 🏷️ Add missing INodeAction type

*  Improve SSR categorisation, fix adding of mixed actions

* ♻️ Refactor CategorizedItems to composition api, style fixes

* WIP: Adding multiple nodes

* ♻️ Refactor rest of the NodeCreator component to composition API, conver globalLinkActions to composable

*  Allow actions dragging, fix search and refactor passing of actions to categorized items

* 💄 Fix node actions title

* Migrate to the pinia store, add posthog feature and various fixes

* 🐛 Fix filtering of trigger actions when not merged

* fix: N8N-5439 — Do not use simple node item when at NodeHelperPanel root

* 🐛 Design review fixes

* 🐛 Fix disabling of merged actions

* Fix trigger root filtering

*  Allow for custom node actions parser, introduce hubspot parser

* 🐛 Fix initial node params validation, fix position of second added node

* 🐛 Introduce operations category, removed canvas node names overrride, fix API actions display and prevent dragging of action nodes

*  Prevent NDV auto-open feature flag

* 🐛 Inject recommened action for trigger nodes without actions

* Refactored NodeCreatorNode to Storybook, change filtering of merged nodes for the trigger helper panel, minor fixes

* Improve rendering of app nodes and animation

* Cleanup, any only enable accordion transition on triggerhelperpanel

* Hide node creator scrollbars in Firefox

* Minor styles fixes

* Do not copy the array in rendering method

* Removed unused props

* Fix memory leak

* Fix categorisation of regular nodes with a single resource

* Implement telemetry calls for node actions

* Move categorization to FE

* Fix client side actions categorisation

* Skip custom action show

* Only load tooltip for NodeIcon if necessary

* Fix lodash startCase import

* Remove lodash.startcase

* Cleanup

* Fix node creator autofocus on "tab"

* Prevent posthog getFeatureFlag from crashing

* Debugging preview env search issues

* Remove logs

* Make sure the pre-filled params are update not overwritten

* Get rid of transition in itemiterator

* WIP: Rough version of NodeActions keyboard navigation, replace nodeCreator composable with Pinia store module

* Rewrite to add support for ActionItem to ItemIterator and make CategorizedItems accept items props

* Fix category item counter & cleanup

* Add APIHint to actions search no-result, clean up NodeCreatorNode

* Improve node actions no results message

* Remove logging, fix filtering of recommended placeholder category

* Remove unused NodeActions component and node merging feature falg

* Do not show regular nodes without actions

* Make sure to add manual trigger when adding http node via actions hint

* Fixed api hint footer line height

* Prevent pointer-events od NodeIcon img and remove "this" from template

* Address PR points

* Fix e2e specs

* Make sure canvas ia loaded

* Make sure canvas ia loaded before opening nodeCreator in e2e spec

* Fix flaky workflows tags e2e getter

* Imrpove node creator click outside UX, add manual node to regular nodes added from trigger panel

* Add manual trigger node if dragging regular from trigger panel
This commit is contained in:
OlegIvaniv
2022-12-09 10:56:36 +01:00
committed by GitHub
parent b7c1359090
commit 79fe57dad8
78 changed files with 2498 additions and 1515 deletions

View File

@@ -0,0 +1,162 @@
<template>
<n8n-node-creator-node
:key="`${action.actionKey}_${action.displayName}`"
@click="onActionClick(action)"
@dragstart="onDragStart"
@dragend="onDragEnd"
draggable
:class="$style.action"
:title="action.displayName"
:isTrigger="isTriggerAction(action)"
>
<template #dragContent>
<div :class="$style.draggableDataTransfer" ref="draggableDataTransfer"/>
<div
:class="$style.draggable"
:style="draggableStyle"
v-show="dragging"
>
<node-icon :nodeType="nodeType" @click.capture.stop :size="40" :shrink="false" />
</div>
</template>
<template #icon>
<node-icon :nodeType="action" />
</template>
</n8n-node-creator-node>
</template>
<script setup lang="ts">
import { reactive, computed, toRefs, getCurrentInstance } from 'vue';
import { INodeTypeDescription, INodeActionTypeDescription } from 'n8n-workflow';
import { getNewNodePosition, NODE_SIZE } from '@/utils/nodeViewUtils';
import { IUpdateInformation } from '@/Interface';
import NodeIcon from '@/components/NodeIcon.vue';
import { useNodeCreatorStore } from '@/stores/nodeCreator';
export interface Props {
nodeType: INodeTypeDescription,
action: INodeActionTypeDescription,
}
const props = defineProps<Props>();
const instance = getCurrentInstance();
const telemetry = instance?.proxy.$telemetry;
const { getActionData, getNodeTypesWithManualTrigger, setAddedNodeActionParameters } = useNodeCreatorStore();
const state = reactive({
dragging: false,
draggablePosition: {
x: -100,
y: -100,
},
storeWatcher: null as Function | null,
draggableDataTransfer: null as Element | null,
});
const emit = defineEmits<{
(event: 'actionSelected', action: IUpdateInformation): void,
(event: 'dragstart', $e: DragEvent): void,
(event: 'dragend', $e: DragEvent): void,
}>();
const draggableStyle = computed<{ top: string; left: string; }>(() => ({
top: `${state.draggablePosition.y}px`,
left: `${state.draggablePosition.x}px`,
}));
const actionData = computed(() => getActionData(props.action));
const isTriggerAction = (action: INodeActionTypeDescription) => action.name?.toLowerCase().includes('trigger');
function onActionClick(actionItem: INodeActionTypeDescription) {
emit('actionSelected', getActionData(actionItem));
}
function onDragStart(event: DragEvent): void {
/**
* Workaround for firefox, that doesn't attach the pageX and pageY coordinates to "ondrag" event.
* All browsers attach the correct page coordinates to the "dragover" event.
* @bug https://bugzilla.mozilla.org/show_bug.cgi?id=505521
*/
document.body.addEventListener("dragover", onDragOver);
const { pageX: x, pageY: y } = event;
if (event.dataTransfer) {
event.dataTransfer.effectAllowed = "copy";
event.dataTransfer.dropEffect = "copy";
event.dataTransfer.setDragImage(state.draggableDataTransfer as Element, 0, 0);
event.dataTransfer.setData('nodeTypeName', getNodeTypesWithManualTrigger(actionData.value?.key).join(','));
state.storeWatcher = setAddedNodeActionParameters(actionData.value, telemetry);
document.body.addEventListener("dragend", onDragEnd);
}
state.dragging = true;
state.draggablePosition = { x, y };
emit('dragstart', event);
}
function onDragOver(event: DragEvent): void {
if (!state.dragging || event.pageX === 0 && event.pageY === 0) {
return;
}
const [x,y] = getNewNodePosition([], [event.pageX - NODE_SIZE / 2, event.pageY - NODE_SIZE / 2]);
state.draggablePosition = { x, y };
}
function onDragEnd(event: DragEvent): void {
if(state.storeWatcher) state.storeWatcher();
document.body.removeEventListener("dragend", onDragEnd);
document.body.removeEventListener("dragover", onDragOver);
emit('dragend', event);
state.dragging = false;
setTimeout(() => {
state.draggablePosition = { x: -100, y: -100 };
}, 300);
}
const { draggableDataTransfer, dragging } = toRefs(state);
</script>
<style lang="scss" module>
.action {
margin-left: 15px;
margin-right: 12px;
--trigger-icon-background-color: #{$trigger-icon-background-color};
--trigger-icon-border-color: #{$trigger-icon-border-color};
}
.nodeIcon {
margin-right: var(--spacing-s);
}
.apiHint {
font-size: var(--font-size-2xs);
color: var(--color-text-base);
padding-top: var(--spacing-s);
line-height: var(--font-line-height-regular);
border-top: 1px solid #DBDFE7;
z-index: 1;
// Prevent double borders when the last category is collapsed
margin-top: -1px;
}
.draggable {
width: 100px;
height: 100px;
position: fixed;
z-index: 1;
opacity: 0.66;
border: 2px solid var(--color-foreground-xdark);
border-radius: var(--border-radius-large);
background-color: var(--color-background-xlight);
display: flex;
justify-content: center;
align-items: center;
}
.draggableDataTransfer {
width: 1px;
height: 1px;
}
</style>