fix(editor): Ready to run v2 save instead of import (no-changelog) (#19821)

This commit is contained in:
Romeo Balta 2025-09-22 09:43:11 +01:00 committed by GitHub
parent 9b96149caf
commit 517b936152
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 40 additions and 61 deletions

View File

@ -6,10 +6,12 @@ import { useCredentialsStore } from '@/stores/credentials.store';
import { usePostHog } from '@/stores/posthog.store';
import { useSettingsStore } from '@/stores/settings.store';
import { useUsersStore } from '@/stores/users.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { useI18n } from '@n8n/i18n';
import { STORES } from '@n8n/stores';
import { useLocalStorage } from '@vueuse/core';
import { OPEN_AI_API_CREDENTIAL_TYPE } from 'n8n-workflow';
import { OPEN_AI_API_CREDENTIAL_TYPE, deepCopy } from 'n8n-workflow';
import type { WorkflowDataCreate } from '@n8n/rest-api-client';
import { defineStore } from 'pinia';
import { computed, ref } from 'vue';
import { useRouter, type RouteLocationNormalized } from 'vue-router';
@ -31,6 +33,7 @@ export const useReadyToRunWorkflowsV2Store = defineStore(
const settingsStore = useSettingsStore();
const posthogStore = usePostHog();
const cloudPlanStore = useCloudPlanStore();
const workflowsStore = useWorkflowsStore();
const isFeatureEnabled = computed(() => {
const variant = posthogStore.getVariant(READY_TO_RUN_V2_EXPERIMENT.name);
@ -109,23 +112,50 @@ export const useReadyToRunWorkflowsV2Store = defineStore(
}
};
const openAiWorkflow = async (source: 'card' | 'button', parentFolderId?: string) => {
const createAndOpenAiWorkflow = async (source: 'card' | 'button', parentFolderId?: string) => {
const variant = getCurrentVariant();
telemetry.track('User opened ready to run AI workflow', {
source,
variant,
});
const workflow =
const workflowTemplate =
variant === READY_TO_RUN_V2_EXPERIMENT.variant2
? READY_TO_RUN_WORKFLOW_V2
: READY_TO_RUN_WORKFLOW_V1;
await router.push({
name: VIEWS.TEMPLATE_IMPORT,
params: { id: workflow.meta?.templateId },
query: { fromJson: 'true', parentFolderId },
});
try {
let workflowToCreate: WorkflowDataCreate = {
...workflowTemplate,
parentFolderId,
};
const credentialId = claimedCredentialIdRef.value;
if (credentialId && workflowToCreate.nodes) {
const clonedWorkflow = deepCopy(workflowToCreate);
const openAiNode = clonedWorkflow.nodes?.find((node) => node.name === 'OpenAI Model');
if (openAiNode) {
openAiNode.credentials ??= {};
openAiNode.credentials[OPEN_AI_API_CREDENTIAL_TYPE] = {
id: credentialId,
name: '',
};
}
workflowToCreate = clonedWorkflow;
}
const createdWorkflow = await workflowsStore.createNewWorkflow(workflowToCreate);
await router.push({
name: VIEWS.WORKFLOW,
params: { name: createdWorkflow.id },
});
return createdWorkflow;
} catch (error) {
toast.showError(error, i18n.baseText('generic.error'));
throw error;
}
};
const claimCreditsAndOpenWorkflow = async (
@ -134,7 +164,7 @@ export const useReadyToRunWorkflowsV2Store = defineStore(
projectId?: string,
) => {
await claimFreeAiCredits(projectId);
await openAiWorkflow(source, parentFolderId);
await createAndOpenAiWorkflow(source, parentFolderId);
};
const getCardVisibility = (
@ -176,7 +206,7 @@ export const useReadyToRunWorkflowsV2Store = defineStore(
claimingCredits,
userCanClaimOpenAiCredits,
claimFreeAiCredits,
openAiWorkflow,
createAndOpenAiWorkflow,
claimCreditsAndOpenWorkflow,
getCardVisibility,
getButtonVisibility,

View File

@ -1,48 +0,0 @@
import { ApplicationError, deepCopy, OPEN_AI_API_CREDENTIAL_TYPE } from 'n8n-workflow';
import type { WorkflowDataWithTemplateId } from '@/Interface';
import { isWorkflowDataWithTemplateId } from '@/utils/templates/typeGuards';
import { READY_TO_RUN_WORKFLOW_V1 } from '../workflows/ai-workflow';
import { READY_TO_RUN_WORKFLOW_V2 } from '../workflows/ai-workflow-v2';
const getWorkflowJson = (json: unknown): WorkflowDataWithTemplateId => {
if (!isWorkflowDataWithTemplateId(json)) {
throw new ApplicationError('Invalid workflow template JSON structure');
}
return json;
};
/**
* Injects OpenAI credentials into workflow template if available in localStorage
*/
const injectOpenAiCredentialIntoWorkflow = (
workflow: WorkflowDataWithTemplateId,
): WorkflowDataWithTemplateId => {
const credentialId = localStorage.getItem('N8N_READY_TO_RUN_V2_OPENAI_CREDENTIAL_ID');
if (!credentialId) {
return workflow;
}
const clonedWorkflow = deepCopy(workflow);
if (clonedWorkflow.nodes) {
const openAiNode = clonedWorkflow.nodes.find((node) => node.name === 'OpenAI Model');
if (openAiNode) {
openAiNode.credentials ??= {};
openAiNode.credentials[OPEN_AI_API_CREDENTIAL_TYPE] = {
id: credentialId,
name: '',
};
}
}
return clonedWorkflow;
};
export const getReadyToRunAIWorkflows = (): WorkflowDataWithTemplateId[] => {
return [
injectOpenAiCredentialIntoWorkflow(getWorkflowJson(READY_TO_RUN_WORKFLOW_V1)),
injectOpenAiCredentialIntoWorkflow(getWorkflowJson(READY_TO_RUN_WORKFLOW_V2)),
];
};

View File

@ -1,8 +1,6 @@
import { ApplicationError, type INodeTypeNameVersion } from 'n8n-workflow';
import type { WorkflowDataWithTemplateId } from '@/Interface';
import { isWorkflowDataWithTemplateId } from '@/utils/templates/typeGuards';
import { getReadyToRunAIWorkflows } from '@/experiments/readyToRunWorkflowsV2/utils/workflowSamples';
/* eslint-disable import-x/extensions */
import easyAiStarterJson from '@/utils/templates/samples/easy_ai_starter.json';
import ragStarterJson from '@/utils/templates/samples/rag_starter.json';
@ -193,7 +191,6 @@ export const getSampleWorkflowByTemplateId = (
const workflows = [
getEasyAiWorkflowJson(),
getRagStarterWorkflowJson(),
...getReadyToRunAIWorkflows(),
...getPrebuiltAgents().map((agent) => agent.template),
...getTutorialTemplates().map((tutorial) => tutorial.template),
];