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:
@@ -1,167 +1,364 @@
|
||||
<template>
|
||||
<div :class="{ [$style.triggerHelperContainer]: true, [$style.isRoot]: isRoot }">
|
||||
<categorized-items
|
||||
ref="categorizedItems"
|
||||
@subcategoryClose="onSubcategoryClose"
|
||||
@onSubcategorySelected="onSubcategorySelected"
|
||||
@nodeTypeSelected="nodeType => $emit('nodeTypeSelected', nodeType)"
|
||||
:expandAllCategories="isActionsActive"
|
||||
:subcategoryOverride="nodeAppSubcategory"
|
||||
:alwaysShowSearch="isActionsActive"
|
||||
:categorizedItems="computedCategorizedItems"
|
||||
:categoriesWithNodes="computedCategoriesWithNodes"
|
||||
:initialActiveIndex="0"
|
||||
:searchItems="searchItems"
|
||||
:firstLevelItems="isRoot ? items : []"
|
||||
:excludedCategories="isRoot ? [] : [CORE_NODES_CATEGORY]"
|
||||
:initialActiveCategories="[COMMUNICATION_CATEGORY]"
|
||||
:withActionsGetter="shouldShowNodeActions"
|
||||
:firstLevelItems="firstLevelItems"
|
||||
:showSubcategoryIcon="isActionsActive"
|
||||
:flatten="!isActionsActive && isAppEventSubcategory"
|
||||
:filterByType="false"
|
||||
:lazyRender="true"
|
||||
:allItems="allNodes"
|
||||
:searchPlaceholder="searchPlaceholder"
|
||||
ref="categorizedItemsRef"
|
||||
@subcategoryClose="onSubcategoryClose"
|
||||
@onSubcategorySelected="onSubcategorySelected"
|
||||
@nodeTypeSelected="onNodeTypeSelected"
|
||||
@actionsOpen="setActiveActionsNodeType"
|
||||
@actionSelected="onActionSelected"
|
||||
>
|
||||
|
||||
<template #noResultsTitle v-if="isActionsActive">
|
||||
<i />
|
||||
</template>
|
||||
<template #noResultsAction v-if="isActionsActive">
|
||||
<p v-if="containsAPIAction" v-html="getCustomAPICallHintLocale('apiCallNoResult')" class="clickable" @click.stop="addHttpNode" />
|
||||
<p v-else v-text="$locale.baseText('nodeCreator.noResults.noMatchingActions')"/>
|
||||
</template>
|
||||
|
||||
<template #header>
|
||||
<slot name="header" />
|
||||
<p v-if="isRoot" v-text="$locale.baseText('nodeCreator.triggerHelperPanel.title')" :class="$style.title" />
|
||||
<p
|
||||
v-if="isRoot"
|
||||
v-text="$locale.baseText('nodeCreator.triggerHelperPanel.title')"
|
||||
:class="$style.title"
|
||||
/>
|
||||
</template>
|
||||
<template #footer v-if="(activeNodeActions && containsAPIAction)">
|
||||
<slot name="footer" />
|
||||
<span v-html="getCustomAPICallHintLocale('apiCall')" class="clickable" @click.stop="addHttpNode" />
|
||||
</template>
|
||||
</categorized-items>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType } from 'vue';
|
||||
import mixins from 'vue-typed-mixins';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { INodeCreateElement } from '@/Interface';
|
||||
import { CORE_NODES_CATEGORY, WEBHOOK_NODE_TYPE, OTHER_TRIGGER_NODES_SUBCATEGORY, EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE, MANUAL_TRIGGER_NODE_TYPE, COMMUNICATION_CATEGORY, SCHEDULE_TRIGGER_NODE_TYPE } from '@/constants';
|
||||
|
||||
import ItemIterator from './ItemIterator.vue';
|
||||
<script setup lang="ts">
|
||||
import { reactive, toRefs, getCurrentInstance, computed, onMounted, ref } from 'vue';
|
||||
import { INodeTypeDescription, INodeActionTypeDescription, INodeTypeNameVersion } from 'n8n-workflow';
|
||||
import { INodeCreateElement, IActionItemProps, SubcategoryCreateElement, IUpdateInformation } from '@/Interface';
|
||||
import { CORE_NODES_CATEGORY, WEBHOOK_NODE_TYPE, OTHER_TRIGGER_NODES_SUBCATEGORY, EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE, MANUAL_TRIGGER_NODE_TYPE, SCHEDULE_TRIGGER_NODE_TYPE, EMAIL_IMAP_NODE_TYPE, CUSTOM_API_CALL_NAME, HTTP_REQUEST_NODE_TYPE, STICKY_NODE_TYPE } from '@/constants';
|
||||
import CategorizedItems from './CategorizedItems.vue';
|
||||
import SearchBar from './SearchBar.vue';
|
||||
import { useNodeCreatorStore } from '@/stores/nodeCreator';
|
||||
import { getCategoriesWithNodes, getCategorizedList } from "@/utils";
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes';
|
||||
import { BaseTextKey } from '@/plugins/i18n';
|
||||
|
||||
export default mixins(externalHooks).extend({
|
||||
name: 'TriggerHelperPanel',
|
||||
components: {
|
||||
ItemIterator,
|
||||
CategorizedItems,
|
||||
SearchBar,
|
||||
},
|
||||
props: {
|
||||
searchItems: {
|
||||
type: Array as PropType<INodeCreateElement[] | null>,
|
||||
const instance = getCurrentInstance();
|
||||
const items: INodeCreateElement[] = [{
|
||||
key: "*",
|
||||
type: "subcategory",
|
||||
title: instance?.proxy.$locale.baseText('nodeCreator.subcategoryNames.appTriggerNodes'),
|
||||
properties: {
|
||||
subcategory: "App Trigger Nodes",
|
||||
description: instance?.proxy.$locale.baseText('nodeCreator.subcategoryDescriptions.appTriggerNodes'),
|
||||
icon: "fa:satellite-dish",
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
CORE_NODES_CATEGORY,
|
||||
COMMUNICATION_CATEGORY,
|
||||
isRoot: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
items() {
|
||||
return [{
|
||||
key: "*",
|
||||
type: "subcategory",
|
||||
title: this.$locale.baseText('nodeCreator.subcategoryNames.appTriggerNodes'),
|
||||
properties: {
|
||||
subcategory: "App Trigger Nodes",
|
||||
description: this.$locale.baseText('nodeCreator.subcategoryDescriptions.appTriggerNodes'),
|
||||
icon: "fa:satellite-dish",
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: SCHEDULE_TRIGGER_NODE_TYPE,
|
||||
type: "node",
|
||||
properties: {
|
||||
nodeType: {
|
||||
{
|
||||
key: SCHEDULE_TRIGGER_NODE_TYPE,
|
||||
type: "node",
|
||||
properties: {
|
||||
nodeType: {
|
||||
|
||||
group: [],
|
||||
name: SCHEDULE_TRIGGER_NODE_TYPE,
|
||||
displayName: this.$locale.baseText('nodeCreator.triggerHelperPanel.scheduleTriggerDisplayName'),
|
||||
description: this.$locale.baseText('nodeCreator.triggerHelperPanel.scheduleTriggerDescription'),
|
||||
icon: "fa:clock",
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
group: [],
|
||||
name: SCHEDULE_TRIGGER_NODE_TYPE,
|
||||
displayName: instance?.proxy.$locale.baseText('nodeCreator.triggerHelperPanel.scheduleTriggerDisplayName'),
|
||||
description: instance?.proxy.$locale.baseText('nodeCreator.triggerHelperPanel.scheduleTriggerDescription'),
|
||||
icon: "fa:clock",
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
{
|
||||
key: WEBHOOK_NODE_TYPE,
|
||||
type: "node",
|
||||
properties: {
|
||||
nodeType: {
|
||||
group: [],
|
||||
name: WEBHOOK_NODE_TYPE,
|
||||
displayName: this.$locale.baseText('nodeCreator.triggerHelperPanel.webhookTriggerDisplayName'),
|
||||
description: this.$locale.baseText('nodeCreator.triggerHelperPanel.webhookTriggerDescription'),
|
||||
iconData: {
|
||||
type: "file",
|
||||
icon: "webhook",
|
||||
fileBuffer: "/static/webhook-icon.svg",
|
||||
},
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: MANUAL_TRIGGER_NODE_TYPE,
|
||||
type: "node",
|
||||
properties: {
|
||||
nodeType: {
|
||||
group: [],
|
||||
name: MANUAL_TRIGGER_NODE_TYPE,
|
||||
displayName: this.$locale.baseText('nodeCreator.triggerHelperPanel.manualTriggerDisplayName'),
|
||||
description: this.$locale.baseText('nodeCreator.triggerHelperPanel.manualTriggerDescription'),
|
||||
icon: "fa:mouse-pointer",
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
||||
type: "node",
|
||||
properties: {
|
||||
nodeType: {
|
||||
group: [],
|
||||
name: EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
||||
displayName: this.$locale.baseText('nodeCreator.triggerHelperPanel.workflowTriggerDisplayName'),
|
||||
description: this.$locale.baseText('nodeCreator.triggerHelperPanel.workflowTriggerDescription'),
|
||||
icon: "fa:sign-out-alt",
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "subcategory",
|
||||
key: OTHER_TRIGGER_NODES_SUBCATEGORY,
|
||||
category: CORE_NODES_CATEGORY,
|
||||
properties: {
|
||||
subcategory: OTHER_TRIGGER_NODES_SUBCATEGORY,
|
||||
description: this.$locale.baseText('nodeCreator.subcategoryDescriptions.otherTriggerNodes'),
|
||||
icon: "fa:folder-open",
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isRootSubcategory(subcategory: INodeCreateElement) {
|
||||
return this.items.find(item => item.key === subcategory.key) !== undefined;
|
||||
},
|
||||
onSubcategorySelected() {
|
||||
this.isRoot = false;
|
||||
},
|
||||
onSubcategoryClose(subcategory: INodeCreateElement) {
|
||||
this.isRoot = this.isRootSubcategory(subcategory);
|
||||
{
|
||||
key: WEBHOOK_NODE_TYPE,
|
||||
type: "node",
|
||||
properties: {
|
||||
nodeType: {
|
||||
group: [],
|
||||
name: WEBHOOK_NODE_TYPE,
|
||||
displayName: instance?.proxy.$locale.baseText('nodeCreator.triggerHelperPanel.webhookTriggerDisplayName'),
|
||||
description: instance?.proxy.$locale.baseText('nodeCreator.triggerHelperPanel.webhookTriggerDescription'),
|
||||
iconData: {
|
||||
type: "file",
|
||||
icon: "webhook",
|
||||
fileBuffer: "/static/webhook-icon.svg",
|
||||
},
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: MANUAL_TRIGGER_NODE_TYPE,
|
||||
type: "node",
|
||||
properties: {
|
||||
nodeType: {
|
||||
group: [],
|
||||
name: MANUAL_TRIGGER_NODE_TYPE,
|
||||
displayName: instance?.proxy.$locale.baseText('nodeCreator.triggerHelperPanel.manualTriggerDisplayName'),
|
||||
description: instance?.proxy.$locale.baseText('nodeCreator.triggerHelperPanel.manualTriggerDescription'),
|
||||
icon: "fa:mouse-pointer",
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
||||
type: "node",
|
||||
properties: {
|
||||
nodeType: {
|
||||
group: [],
|
||||
name: EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
||||
displayName: instance?.proxy.$locale.baseText('nodeCreator.triggerHelperPanel.workflowTriggerDisplayName'),
|
||||
description: instance?.proxy.$locale.baseText('nodeCreator.triggerHelperPanel.workflowTriggerDescription'),
|
||||
icon: "fa:sign-out-alt",
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "subcategory",
|
||||
key: OTHER_TRIGGER_NODES_SUBCATEGORY,
|
||||
category: CORE_NODES_CATEGORY,
|
||||
properties: {
|
||||
subcategory: OTHER_TRIGGER_NODES_SUBCATEGORY,
|
||||
description: instance?.proxy.$locale.baseText('nodeCreator.subcategoryDescriptions.otherTriggerNodes'),
|
||||
icon: "fa:folder-open",
|
||||
defaults: {
|
||||
color: "#7D838F",
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits({
|
||||
"nodeTypeSelected": (nodeTypes: string[]) => true,
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
isRoot: true,
|
||||
selectedSubcategory: '',
|
||||
activeNodeActions: null as INodeTypeDescription | null,
|
||||
latestNodeData: null as INodeTypeDescription | null,
|
||||
});
|
||||
const categorizedItemsRef = ref<InstanceType<typeof CategorizedItems>>();
|
||||
|
||||
const { $externalHooks } = new externalHooks();
|
||||
const {
|
||||
mergedAppNodes,
|
||||
setShowTabs,
|
||||
getActionData,
|
||||
getNodeTypesWithManualTrigger,
|
||||
setAddedNodeActionParameters,
|
||||
} = useNodeCreatorStore();
|
||||
|
||||
const telemetry = instance?.proxy.$telemetry;
|
||||
const { categorizedItems: allNodes, isTriggerNode } = useNodeTypesStore();
|
||||
const containsAPIAction = computed(() => state.latestNodeData?.properties.some((p) => p.options?.find((o) => o.name === CUSTOM_API_CALL_NAME)) === true);
|
||||
|
||||
const computedCategorizedItems = computed(() => getCategorizedList(computedCategoriesWithNodes.value, true));
|
||||
|
||||
const nodeAppSubcategory = computed<(SubcategoryCreateElement | undefined)>(() => {
|
||||
if(!state.activeNodeActions) return undefined;
|
||||
|
||||
return {
|
||||
type: 'subcategory',
|
||||
properties: {
|
||||
subcategory: state.activeNodeActions.displayName,
|
||||
nodeType: {
|
||||
description: '',
|
||||
key: state.activeNodeActions.name,
|
||||
iconUrl: state.activeNodeActions.iconUrl,
|
||||
icon: state.activeNodeActions.icon,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
const searchPlaceholder = computed(() => {
|
||||
const nodeNameTitle = state.activeNodeActions?.displayName?.trim() as string;
|
||||
const actionsSearchPlaceholder = instance?.proxy.$locale.baseText(
|
||||
'nodeCreator.actionsCategory.searchActions',
|
||||
{ interpolate: { nodeNameTitle }},
|
||||
);
|
||||
|
||||
return isActionsActive.value ? actionsSearchPlaceholder : undefined;
|
||||
});
|
||||
|
||||
const filteredMergedAppNodes = computed(() => {
|
||||
const WHITELISTED_APP_CORE_NODES = [
|
||||
EMAIL_IMAP_NODE_TYPE,
|
||||
WEBHOOK_NODE_TYPE,
|
||||
];
|
||||
|
||||
if(isAppEventSubcategory.value) return mergedAppNodes.filter(node => {
|
||||
const isRegularNode = !isTriggerNode(node.name);
|
||||
const isStickyNode = node.name === STICKY_NODE_TYPE;
|
||||
const isCoreNode = node.codex?.categories?.includes(CORE_NODES_CATEGORY) && !WHITELISTED_APP_CORE_NODES.includes(node.name);
|
||||
const hasActions = (node.actions || []).length > 0;
|
||||
|
||||
if(isRegularNode && !hasActions) return false;
|
||||
return !isCoreNode && !isStickyNode;
|
||||
});
|
||||
|
||||
return mergedAppNodes;
|
||||
});
|
||||
|
||||
const computedCategoriesWithNodes = computed(() => {
|
||||
if(!state.activeNodeActions) return getCategoriesWithNodes(filteredMergedAppNodes.value, []);
|
||||
|
||||
return getCategoriesWithNodes(selectedNodeActions.value, [], state.activeNodeActions.displayName) ;
|
||||
});
|
||||
|
||||
const selectedNodeActions = computed<INodeActionTypeDescription[]>(() => state.activeNodeActions?.actions ?? []);
|
||||
const isAppEventSubcategory = computed(() => state.selectedSubcategory === "*");
|
||||
const isActionsActive = computed(() => state.activeNodeActions !== null);
|
||||
const firstLevelItems = computed(() => isRoot.value ? items : []);
|
||||
|
||||
const isSearchActive = computed(() => useNodeCreatorStore().itemsFilter !== '');
|
||||
const searchItems = computed<INodeCreateElement[]>(() => {
|
||||
const sorted = state.activeNodeActions ? [...selectedNodeActions.value] : [...filteredMergedAppNodes.value];
|
||||
sorted.sort((a, b) => {
|
||||
const textA = a.displayName.toLowerCase();
|
||||
const textB = b.displayName.toLowerCase();
|
||||
return textA < textB ? -1 : textA > textB ? 1 : 0;
|
||||
});
|
||||
|
||||
return sorted.map((nodeType) => ({
|
||||
type: 'node',
|
||||
category: '',
|
||||
key: nodeType.name,
|
||||
properties: {
|
||||
nodeType,
|
||||
subcategory: state.activeNodeActions ? state.activeNodeActions.displayName : '',
|
||||
},
|
||||
includedByTrigger: nodeType.group.includes('trigger'),
|
||||
includedByRegular: !nodeType.group.includes('trigger'),
|
||||
}));
|
||||
});
|
||||
|
||||
function onNodeTypeSelected(nodeTypes: string[]) {
|
||||
emit("nodeTypeSelected", nodeTypes.length === 1 ? getNodeTypesWithManualTrigger(nodeTypes[0]) : nodeTypes);
|
||||
}
|
||||
function getCustomAPICallHintLocale(key: string) {
|
||||
if(!state.activeNodeActions) return '';
|
||||
|
||||
const nodeNameTitle = state.activeNodeActions.displayName;
|
||||
return instance?.proxy.$locale.baseText(
|
||||
`nodeCreator.actionsList.${key}` as BaseTextKey,
|
||||
{ interpolate: { nodeNameTitle }},
|
||||
);
|
||||
}
|
||||
// The nodes.json doesn't contain API CALL option so we need to fetch the node detail
|
||||
// to determine if need to render the API CALL hint
|
||||
async function fetchNodeDetails() {
|
||||
if(!state.activeNodeActions) return;
|
||||
|
||||
const { getNodesInformation } = useNodeTypesStore();
|
||||
const { version, name } = state.activeNodeActions;
|
||||
const payload = {
|
||||
name,
|
||||
version: Array.isArray(version) ? version?.slice(-1)[0] : version,
|
||||
} as INodeTypeNameVersion;
|
||||
|
||||
const nodesInfo = await getNodesInformation([payload], false);
|
||||
|
||||
state.latestNodeData = nodesInfo[0];
|
||||
}
|
||||
|
||||
function setActiveActionsNodeType(nodeType: INodeTypeDescription | null) {
|
||||
state.activeNodeActions = nodeType;
|
||||
setShowTabs(false);
|
||||
fetchNodeDetails();
|
||||
|
||||
if(nodeType) trackActionsView();
|
||||
}
|
||||
|
||||
function onActionSelected(actionCreateElement: INodeCreateElement) {
|
||||
const action = (actionCreateElement.properties as IActionItemProps).nodeType;
|
||||
const actionUpdateData = getActionData(action);
|
||||
emit('nodeTypeSelected', getNodeTypesWithManualTrigger(actionUpdateData.key));
|
||||
setAddedNodeActionParameters(actionUpdateData, telemetry);
|
||||
}
|
||||
function addHttpNode() {
|
||||
const updateData = {
|
||||
name: '',
|
||||
key: HTTP_REQUEST_NODE_TYPE,
|
||||
value: {
|
||||
authentication: "predefinedCredentialType",
|
||||
},
|
||||
} as IUpdateInformation;
|
||||
|
||||
emit('nodeTypeSelected', [MANUAL_TRIGGER_NODE_TYPE, HTTP_REQUEST_NODE_TYPE]);
|
||||
setAddedNodeActionParameters(updateData, telemetry, false);
|
||||
|
||||
const app_identifier = state.activeNodeActions?.name;
|
||||
$externalHooks().run('nodeCreateList.onActionsCustmAPIClicked', { app_identifier });
|
||||
telemetry?.trackNodesPanel('nodeCreateList.onActionsCustmAPIClicked', { app_identifier });
|
||||
}
|
||||
|
||||
function onSubcategorySelected(subcategory: INodeCreateElement) {
|
||||
state.isRoot = false;
|
||||
state.selectedSubcategory = subcategory.key;
|
||||
}
|
||||
function onSubcategoryClose(activeSubcategories: INodeCreateElement[]) {
|
||||
if(isActionsActive.value === true) setActiveActionsNodeType(null);
|
||||
|
||||
state.isRoot = activeSubcategories.length === 0;
|
||||
state.selectedSubcategory = activeSubcategories[activeSubcategories.length - 1]?.key ?? '';
|
||||
}
|
||||
|
||||
function shouldShowNodeActions(node: INodeCreateElement) {
|
||||
if(isAppEventSubcategory.value) return true;
|
||||
if(state.isRoot && !isSearchActive.value) return false;
|
||||
// Do not show actions for core category when searching
|
||||
if(node.type === 'node') return !node.properties.nodeType.codex?.categories?.includes(CORE_NODES_CATEGORY);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function trackActionsView() {
|
||||
const trigger_action_count = selectedNodeActions.value
|
||||
.filter((action) => action.name.toLowerCase().includes('trigger')).length;
|
||||
|
||||
const trackingPayload = {
|
||||
app_identifier: state.activeNodeActions?.name,
|
||||
actions: selectedNodeActions.value.map(action => action.displayName),
|
||||
regular_action_count: selectedNodeActions.value.length - trigger_action_count,
|
||||
trigger_action_count,
|
||||
};
|
||||
|
||||
$externalHooks().run('nodeCreateList.onViewActions', trackingPayload);
|
||||
telemetry?.trackNodesPanel('nodeCreateList.onViewActions', trackingPayload);
|
||||
}
|
||||
|
||||
const { isRoot, activeNodeActions } = toRefs(state);
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
||||
Reference in New Issue
Block a user