mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(editor): Easy AI workflow improvements (#12400)
This commit is contained in:
parent
f56ad8cf49
commit
8dc691dc62
|
@ -1304,6 +1304,7 @@
|
||||||
"nodeView.confirmMessage.debug.headline": "Unpin workflow data",
|
"nodeView.confirmMessage.debug.headline": "Unpin workflow data",
|
||||||
"nodeView.confirmMessage.debug.message": "Loading this execution will unpin the data currently pinned in these nodes",
|
"nodeView.confirmMessage.debug.message": "Loading this execution will unpin the data currently pinned in these nodes",
|
||||||
"nodeView.couldntImportWorkflow": "Could not import workflow",
|
"nodeView.couldntImportWorkflow": "Could not import workflow",
|
||||||
|
"nodeView.couldntLoadWorkflow.invalidWorkflowObject": "Invalid workflow object",
|
||||||
"nodeView.deletesTheCurrentExecutionData": "Deletes the current execution data",
|
"nodeView.deletesTheCurrentExecutionData": "Deletes the current execution data",
|
||||||
"nodeView.itLooksLikeYouHaveBeenEditingSomething": "It looks like you made some edits. If you leave before saving, your changes will be lost.",
|
"nodeView.itLooksLikeYouHaveBeenEditingSomething": "It looks like you made some edits. If you leave before saving, your changes will be lost.",
|
||||||
"nodeView.loadingTemplate": "Loading template",
|
"nodeView.loadingTemplate": "Loading template",
|
||||||
|
|
|
@ -32,6 +32,7 @@ import type {
|
||||||
IWorkflowTemplate,
|
IWorkflowTemplate,
|
||||||
NodeCreatorOpenSource,
|
NodeCreatorOpenSource,
|
||||||
ToggleNodeCreatorOptions,
|
ToggleNodeCreatorOptions,
|
||||||
|
WorkflowDataWithTemplateId,
|
||||||
XYPosition,
|
XYPosition,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
import type {
|
import type {
|
||||||
|
@ -107,6 +108,7 @@ import { getResourcePermissions } from '@/permissions';
|
||||||
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
|
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
|
||||||
import { createCanvasConnectionHandleString } from '@/utils/canvasUtilsV2';
|
import { createCanvasConnectionHandleString } from '@/utils/canvasUtilsV2';
|
||||||
import { isValidNodeConnectionType } from '@/utils/typeGuards';
|
import { isValidNodeConnectionType } from '@/utils/typeGuards';
|
||||||
|
import { EASY_AI_WORKFLOW_JSON } from '@/constants.workflows';
|
||||||
|
|
||||||
const LazyNodeCreation = defineAsyncComponent(
|
const LazyNodeCreation = defineAsyncComponent(
|
||||||
async () => await import('@/components/Node/NodeCreation.vue'),
|
async () => await import('@/components/Node/NodeCreation.vue'),
|
||||||
|
@ -315,7 +317,13 @@ async function initializeRoute(force = false) {
|
||||||
isBlankRedirect.value = false;
|
isBlankRedirect.value = false;
|
||||||
} else if (route.name === VIEWS.TEMPLATE_IMPORT) {
|
} else if (route.name === VIEWS.TEMPLATE_IMPORT) {
|
||||||
const templateId = route.params.id;
|
const templateId = route.params.id;
|
||||||
await openWorkflowTemplate(templateId.toString());
|
const loadWorkflowFromJSON = route.query.fromJson === 'true';
|
||||||
|
|
||||||
|
if (loadWorkflowFromJSON) {
|
||||||
|
await openTemplateFromWorkflowJSON(EASY_AI_WORKFLOW_JSON);
|
||||||
|
} else {
|
||||||
|
await openWorkflowTemplate(templateId.toString());
|
||||||
|
}
|
||||||
} else if (isWorkflowRoute.value) {
|
} else if (isWorkflowRoute.value) {
|
||||||
if (!isAlreadyInitialized) {
|
if (!isAlreadyInitialized) {
|
||||||
historyStore.reset();
|
historyStore.reset();
|
||||||
|
@ -423,6 +431,42 @@ function trackOpenWorkflowFromOnboardingTemplate() {
|
||||||
* Templates
|
* Templates
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
async function openTemplateFromWorkflowJSON(workflow: WorkflowDataWithTemplateId) {
|
||||||
|
if (!workflow.nodes || !workflow.connections) {
|
||||||
|
toast.showError(
|
||||||
|
new Error(i18n.baseText('nodeView.couldntLoadWorkflow.invalidWorkflowObject')),
|
||||||
|
i18n.baseText('nodeView.couldntImportWorkflow'),
|
||||||
|
);
|
||||||
|
await router.replace({ name: VIEWS.NEW_WORKFLOW });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resetWorkspace();
|
||||||
|
|
||||||
|
canvasStore.startLoading();
|
||||||
|
canvasStore.setLoadingText(i18n.baseText('nodeView.loadingTemplate'));
|
||||||
|
|
||||||
|
workflowsStore.currentWorkflowExecutions = [];
|
||||||
|
executionsStore.activeExecution = null;
|
||||||
|
|
||||||
|
isBlankRedirect.value = true;
|
||||||
|
await router.replace({
|
||||||
|
name: VIEWS.NEW_WORKFLOW,
|
||||||
|
query: { templateId: workflow.meta.templateId },
|
||||||
|
});
|
||||||
|
|
||||||
|
const convertedNodes = workflow.nodes.map(workflowsStore.convertTemplateNodeToNodeUi);
|
||||||
|
|
||||||
|
workflowsStore.setConnections(workflow.connections);
|
||||||
|
await addNodes(convertedNodes);
|
||||||
|
await workflowsStore.getNewWorkflowData(workflow.name, projectsStore.currentProjectId);
|
||||||
|
|
||||||
|
uiStore.stateIsDirty = true;
|
||||||
|
|
||||||
|
canvasStore.stopLoading();
|
||||||
|
|
||||||
|
fitView();
|
||||||
|
}
|
||||||
|
|
||||||
async function openWorkflowTemplate(templateId: string) {
|
async function openWorkflowTemplate(templateId: string) {
|
||||||
resetWorkspace();
|
resetWorkspace();
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,7 @@ import type {
|
||||||
AddedNodesAndConnections,
|
AddedNodesAndConnections,
|
||||||
ToggleNodeCreatorOptions,
|
ToggleNodeCreatorOptions,
|
||||||
NodeFilterType,
|
NodeFilterType,
|
||||||
|
WorkflowDataWithTemplateId,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
|
|
||||||
import { type RouteLocation, useRoute, useRouter } from 'vue-router';
|
import { type RouteLocation, useRoute, useRouter } from 'vue-router';
|
||||||
|
@ -180,6 +181,7 @@ import { useNpsSurveyStore } from '@/stores/npsSurvey.store';
|
||||||
import { getResourcePermissions } from '@/permissions';
|
import { getResourcePermissions } from '@/permissions';
|
||||||
import { useBeforeUnload } from '@/composables/useBeforeUnload';
|
import { useBeforeUnload } from '@/composables/useBeforeUnload';
|
||||||
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
|
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
|
||||||
|
import { EASY_AI_WORKFLOW_JSON } from '@/constants.workflows';
|
||||||
|
|
||||||
interface AddNodeOptions {
|
interface AddNodeOptions {
|
||||||
position?: XYPosition;
|
position?: XYPosition;
|
||||||
|
@ -1090,6 +1092,42 @@ export default defineComponent({
|
||||||
await this.$nextTick();
|
await this.$nextTick();
|
||||||
this.canvasStore.zoomToFit();
|
this.canvasStore.zoomToFit();
|
||||||
},
|
},
|
||||||
|
async openWorkflowTemplateFromJson(data: { workflow: WorkflowDataWithTemplateId }) {
|
||||||
|
if (!data.workflow.nodes || !data.workflow.connections) {
|
||||||
|
this.showError(
|
||||||
|
new Error(this.i18n.baseText('nodeView.couldntLoadWorkflow.invalidWorkflowObject')),
|
||||||
|
this.i18n.baseText('nodeView.couldntImportWorkflow'),
|
||||||
|
);
|
||||||
|
await this.$router.replace({ name: VIEWS.NEW_WORKFLOW });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.canvasStore.startLoading();
|
||||||
|
this.canvasStore.setLoadingText(this.i18n.baseText('nodeView.loadingTemplate'));
|
||||||
|
this.resetWorkspace();
|
||||||
|
|
||||||
|
this.workflowsStore.currentWorkflowExecutions = [];
|
||||||
|
this.executionsStore.activeExecution = null;
|
||||||
|
|
||||||
|
this.blankRedirect = true;
|
||||||
|
await this.$router.replace({
|
||||||
|
name: VIEWS.NEW_WORKFLOW,
|
||||||
|
query: { templateId: data.workflow.meta.templateId },
|
||||||
|
});
|
||||||
|
|
||||||
|
const convertedNodes = data.workflow.nodes.map(
|
||||||
|
this.workflowsStore.convertTemplateNodeToNodeUi,
|
||||||
|
);
|
||||||
|
await this.nodeHelpers.addNodes(convertedNodes, data.workflow.connections);
|
||||||
|
this.workflowData =
|
||||||
|
(await this.workflowsStore.getNewWorkflowData(
|
||||||
|
data.workflow.name,
|
||||||
|
this.projectsStore.currentProjectId,
|
||||||
|
)) || {};
|
||||||
|
await this.$nextTick();
|
||||||
|
this.canvasStore.zoomToFit();
|
||||||
|
this.uiStore.stateIsDirty = true;
|
||||||
|
this.canvasStore.stopLoading();
|
||||||
|
},
|
||||||
async openWorkflowTemplate(templateId: string) {
|
async openWorkflowTemplate(templateId: string) {
|
||||||
this.canvasStore.startLoading();
|
this.canvasStore.startLoading();
|
||||||
this.canvasStore.setLoadingText(this.i18n.baseText('nodeView.loadingTemplate'));
|
this.canvasStore.setLoadingText(this.i18n.baseText('nodeView.loadingTemplate'));
|
||||||
|
@ -3361,7 +3399,12 @@ export default defineComponent({
|
||||||
this.blankRedirect = false;
|
this.blankRedirect = false;
|
||||||
} else if (this.$route.name === VIEWS.TEMPLATE_IMPORT) {
|
} else if (this.$route.name === VIEWS.TEMPLATE_IMPORT) {
|
||||||
const templateId = this.$route.params.id;
|
const templateId = this.$route.params.id;
|
||||||
await this.openWorkflowTemplate(templateId.toString());
|
const loadWorkflowFromJSON = this.$route.query.fromJson === 'true';
|
||||||
|
if (loadWorkflowFromJSON) {
|
||||||
|
await this.openWorkflowTemplateFromJson({ workflow: EASY_AI_WORKFLOW_JSON });
|
||||||
|
} else {
|
||||||
|
await this.openWorkflowTemplate(templateId.toString());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
this.uiStore.stateIsDirty &&
|
this.uiStore.stateIsDirty &&
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import type { IWorkflowDataCreate } from '@/Interface';
|
import type { IWorkflowDataCreate } from '@/Interface';
|
||||||
import { EASY_AI_WORKFLOW_JSON, SAMPLE_SUBWORKFLOW_WORKFLOW } from '@/constants.workflows';
|
import { SAMPLE_SUBWORKFLOW_WORKFLOW } from '@/constants.workflows';
|
||||||
|
|
||||||
const loadingService = useLoadingService();
|
const loadingService = useLoadingService();
|
||||||
const templateStore = useTemplatesStore();
|
const templateStore = useTemplatesStore();
|
||||||
|
@ -21,11 +21,6 @@ const openWorkflowTemplate = async (templateId: string) => {
|
||||||
await openSampleSubworkflow();
|
await openSampleSubworkflow();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (templateId === EASY_AI_WORKFLOW_JSON.meta.templateId) {
|
|
||||||
await openEasyAIWorkflow();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loadingService.startLoading();
|
loadingService.startLoading();
|
||||||
const template = await templateStore.getFixedWorkflowTemplate(templateId);
|
const template = await templateStore.getFixedWorkflowTemplate(templateId);
|
||||||
|
@ -63,21 +58,6 @@ const openWorkflowTemplate = async (templateId: string) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const openEasyAIWorkflow = async () => {
|
|
||||||
try {
|
|
||||||
loadingService.startLoading();
|
|
||||||
const newWorkflow = await workflowsStore.createNewWorkflow(EASY_AI_WORKFLOW_JSON);
|
|
||||||
await router.replace({
|
|
||||||
name: VIEWS.WORKFLOW,
|
|
||||||
params: { name: newWorkflow.id },
|
|
||||||
});
|
|
||||||
loadingService.stopLoading();
|
|
||||||
} catch (e) {
|
|
||||||
await router.replace({ name: VIEWS.NEW_WORKFLOW });
|
|
||||||
loadingService.stopLoading();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const openSampleSubworkflow = async () => {
|
const openSampleSubworkflow = async () => {
|
||||||
try {
|
try {
|
||||||
loadingService.startLoading();
|
loadingService.startLoading();
|
||||||
|
|
|
@ -270,8 +270,9 @@ const openAIWorkflow = async (source: string) => {
|
||||||
{ withPostHog: true },
|
{ withPostHog: true },
|
||||||
);
|
);
|
||||||
await router.push({
|
await router.push({
|
||||||
name: VIEWS.WORKFLOW_ONBOARDING,
|
name: VIEWS.TEMPLATE_IMPORT,
|
||||||
params: { id: EASY_AI_WORKFLOW_JSON.meta.templateId },
|
params: { id: EASY_AI_WORKFLOW_JSON.meta.templateId },
|
||||||
|
query: { fromJson: 'true' },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue