Files
n8n-enterprise-unlocked/packages/frontend/editor-ui/src/composables/useCalloutHelpers.ts
2025-08-09 10:28:14 +03:00

196 lines
5.5 KiB
TypeScript

import { computed, nextTick } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useTelemetry } from '@/composables/useTelemetry';
import { useRootStore } from '@n8n/stores/useRootStore';
import { useI18n } from '@n8n/i18n';
import { useUsersStore } from '@/stores/users.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { usePostHog } from '@/stores/posthog.store';
import { useNDVStore } from '@/stores/ndv.store';
import { useNodeCreatorStore } from '@/stores/nodeCreator.store';
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import { useViewStacks } from '@/components/Node/NodeCreator/composables/useViewStacks';
import { updateCurrentUserSettings } from '@n8n/rest-api-client/api/users';
import {
NODE_CREATOR_OPEN_SOURCES,
PRE_BUILT_AGENTS_EXPERIMENT,
REGULAR_NODE_CREATOR_VIEW,
VIEWS,
} from '@/constants';
import {
getPrebuiltAgents,
getRagStarterWorkflowJson,
getSampleWorkflowByTemplateId,
isPrebuiltAgentTemplateId,
SampleTemplates,
} from '@/utils/templates/workflowSamples';
import type { INodeCreateElement, OpenTemplateElement } from '@/Interface';
export function useCalloutHelpers() {
const route = useRoute();
const router = useRouter();
const telemetry = useTelemetry();
const postHog = usePostHog();
const rootStore = useRootStore();
const workflowsStore = useWorkflowsStore();
const usersStore = useUsersStore();
const ndvStore = useNDVStore();
const nodeCreatorStore = useNodeCreatorStore();
const viewStacks = useViewStacks();
const nodeTypesStore = useNodeTypesStore();
const i18n = useI18n();
const isRagStarterCalloutVisible = computed(() => {
const template = getRagStarterWorkflowJson();
const routeTemplateId = route.query.templateId;
const workflowObject = workflowsStore.workflowObject;
const workflow = workflowsStore.getWorkflowById(workflowObject.id);
// Hide the RAG starter callout if we're currently on the RAG starter template
if ((routeTemplateId ?? workflow?.meta?.templateId) === template.meta.templateId) {
return false;
}
return true;
});
const getPreBuiltAgentNodeCreatorItems = (): OpenTemplateElement[] => {
const templates = getPrebuiltAgents();
return templates.map((template) => {
return {
key: template.template.meta.templateId,
type: 'openTemplate',
properties: {
templateId: template.template.meta.templateId,
title: template.name,
description: template.description,
nodes: template.nodes.flatMap((node) => {
const nodeType = nodeTypesStore.getNodeType(node.name, node.version);
if (!nodeType) {
return [];
}
return nodeType;
}),
},
};
});
};
const openPreBuiltAgentsCollection = async (options: {
telemetry: {
source: 'ndv' | 'nodeCreator';
nodeType?: string;
section?: string;
};
resetStacks?: boolean;
}) => {
telemetry.track('User opened pre-built Agents collection', {
source: options.telemetry.source,
node_type: options.telemetry.nodeType ?? null,
section: options.telemetry.section ?? null,
});
const items: INodeCreateElement[] = getPreBuiltAgentNodeCreatorItems();
ndvStore.setActiveNodeName(null);
nodeCreatorStore.setNodeCreatorState({
source: NODE_CREATOR_OPEN_SOURCES.TEMPLATES_CALLOUT,
createNodeActive: true,
nodeCreatorView: undefined,
connectionType: undefined,
});
await nextTick();
viewStacks.pushViewStack(
{
title: i18n.baseText('nodeCreator.preBuiltAgents.title'),
rootView: REGULAR_NODE_CREATOR_VIEW,
activeIndex: 0,
transitionDirection: 'in',
hasSearch: false,
preventBack: false,
items,
baselineItems: items,
mode: 'nodes',
hideActions: false,
},
{ resetStacks: options.resetStacks ?? false },
);
};
const openSampleWorkflowTemplate = (
templateId: string,
options: {
telemetry: {
source: 'ndv' | 'nodeCreator';
nodeType?: string;
section?: string;
};
},
) => {
if (templateId === SampleTemplates.RagStarterTemplate) {
telemetry.track('User clicked on RAG callout', {
node_type: options.telemetry.nodeType ?? null,
});
} else if (isPrebuiltAgentTemplateId(templateId)) {
telemetry.track('User inserted pre-built Agent', {
template: templateId,
source: options.telemetry.source,
node_type: options.telemetry.nodeType ?? null,
section: options.telemetry.section ?? null,
});
}
const template = getSampleWorkflowByTemplateId(templateId);
if (!template) {
return;
}
const { href } = router.resolve({
name: VIEWS.TEMPLATE_IMPORT,
params: { id: template.meta.templateId },
query: { fromJson: 'true', parentFolderId: route.params.folderId },
});
window.open(href, '_blank');
};
const isPreBuiltAgentsExperimentEnabled = computed(() => {
return postHog.isVariantEnabled(
PRE_BUILT_AGENTS_EXPERIMENT.name,
PRE_BUILT_AGENTS_EXPERIMENT.variant,
);
});
const isPreBuiltAgentsCalloutVisible = computed(() => {
return isPreBuiltAgentsExperimentEnabled.value;
});
const isCalloutDismissed = (callout: string) => {
return usersStore.isCalloutDismissed(callout);
};
const dismissCallout = async (callout: string) => {
usersStore.setCalloutDismissed(callout);
await updateCurrentUserSettings(rootStore.restApiContext, {
dismissedCallouts: {
...usersStore.currentUser?.settings?.dismissedCallouts,
[callout]: true,
},
});
};
return {
openSampleWorkflowTemplate,
openPreBuiltAgentsCollection,
getPreBuiltAgentNodeCreatorItems,
isRagStarterCalloutVisible,
isPreBuiltAgentsCalloutVisible,
isCalloutDismissed,
dismissCallout,
};
}