mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
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:
@@ -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>
|
||||
Reference in New Issue
Block a user