diff --git a/cypress/e2e/29-templates.cy.ts b/cypress/e2e/29-templates.cy.ts index bd46f90fe7080..3eab7d0d8f8b0 100644 --- a/cypress/e2e/29-templates.cy.ts +++ b/cypress/e2e/29-templates.cy.ts @@ -29,12 +29,35 @@ describe('Templates', () => { cy.url().then(($url) => { expect($url).to.include('/workflow/new?templateId=1234'); }); - + workflowPage.getters.canvasNodes().should('have.length', 4); workflowPage.getters.stickies().should('have.length', 1); workflowPage.actions.shouldHaveWorkflowName(OnboardingWorkflow.name); }); + it('should save template id with the workflow', () => { + cy.visit(templatesPage.url); + templatesPage.getters.firstTemplateCard().click(); + cy.url().should('include', '/templates/'); + + cy.url().then(($url) => { + const templateId = $url.split('/').pop(); + + templatesPage.getters.useTemplateButton().click(); + cy.url().should('include', '/workflow/new'); + workflowPage.actions.saveWorkflowOnButtonClick(); + + workflowPage.actions.selectAll(); + workflowPage.actions.hitCopy(); + + cy.grantBrowserPermissions('clipboardReadWrite', 'clipboardSanitizedWrite'); + // Check workflow JSON by copying it to clipboard + cy.readClipboard().then((workflowJSON) => { + expect(workflowJSON).to.contain(`"templateId": "${templateId}"`); + }); + }); + }); + it('can open template with images and hides workflow screenshots', () => { templateWorkflowPage.actions.openTemplate(WorkflowTemplate); diff --git a/cypress/pages/templates.ts b/cypress/pages/templates.ts index d3a3c95420a5c..7b2ff91e794d7 100644 --- a/cypress/pages/templates.ts +++ b/cypress/pages/templates.ts @@ -4,7 +4,9 @@ export class TemplatesPage extends BasePage { url = '/templates'; getters = { - useTemplateButton: () => cy.get('[data-testid="use-template-button"]'), + useTemplateButton: () => cy.getByTestId('use-template-button'), + templateCards: () => cy.getByTestId('template-card'), + firstTemplateCard: () => this.getters.templateCards().first(), }; actions = { diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index d2a9b8fa4250f..4efc1fa19be65 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -227,6 +227,7 @@ export interface IWorkflowData { tags?: string[]; pinData?: IPinData; versionId?: string; + meta?: WorkflowMetadata; } export interface IWorkflowDataUpdate { @@ -243,9 +244,7 @@ export interface IWorkflowDataUpdate { } export interface IWorkflowToShare extends IWorkflowDataUpdate { - meta?: { - instanceId: string; - }; + meta?: WorkflowMetadata; } export interface IWorkflowTemplateNode @@ -273,6 +272,8 @@ export interface INewWorkflowData { export interface WorkflowMetadata { onboardingId?: string; + templateId?: string; + instanceId?: string; } // Almost identical to cli.Interfaces.ts diff --git a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue index c4f164cec1a99..e8474e37bc6f7 100644 --- a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue +++ b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue @@ -537,6 +537,7 @@ export default defineComponent({ const exportData: IWorkflowToShare = { ...data, meta: { + ...(this.workflowsStore.workflow.meta || {}), instanceId: this.rootStore.instanceId, }, tags: (tags || []).map((tagId) => { diff --git a/packages/editor-ui/src/mixins/workflowHelpers.ts b/packages/editor-ui/src/mixins/workflowHelpers.ts index 00030720beb19..4bda2bfe68e13 100644 --- a/packages/editor-ui/src/mixins/workflowHelpers.ts +++ b/packages/editor-ui/src/mixins/workflowHelpers.ts @@ -656,6 +656,7 @@ export const workflowHelpers = defineComponent({ settings: this.workflowsStore.workflow.settings, tags: this.workflowsStore.workflowTags, versionId: this.workflowsStore.workflow.versionId, + meta: this.workflowsStore.workflow.meta, }; const workflowId = this.workflowsStore.workflowId; diff --git a/packages/editor-ui/src/stores/workflows.store.ts b/packages/editor-ui/src/stores/workflows.store.ts index a217641863410..088263d3f2875 100644 --- a/packages/editor-ui/src/stores/workflows.store.ts +++ b/packages/editor-ui/src/stores/workflows.store.ts @@ -32,6 +32,7 @@ import type { IWorkflowsMap, WorkflowsState, NodeMetadataMap, + WorkflowMetadata, } from '@/Interface'; import { defineStore } from 'pinia'; import type { @@ -652,6 +653,17 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, { }; }, + setWorkflowMetadata(metadata: WorkflowMetadata | undefined): void { + this.workflow.meta = metadata; + }, + + addToWorkflowMetadata(data: Partial): void { + this.workflow.meta = { + ...this.workflow.meta, + ...data, + }; + }, + setWorkflow(workflow: IWorkflowDb): void { this.workflow = workflow; this.workflow = { diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index 86838b5f54aed..14259b90b50ce 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -1064,6 +1064,7 @@ export default defineComponent({ await this.addNodes(data.workflow.nodes, data.workflow.connections); this.workflowData = (await this.workflowsStore.getNewWorkflowData(data.name)) || {}; + this.workflowsStore.addToWorkflowMetadata({ templateId }); await this.$nextTick(); this.canvasStore.zoomToFit(); this.uiStore.stateIsDirty = true; @@ -1089,6 +1090,7 @@ export default defineComponent({ this.workflowsStore.setWorkflowSettings(workflow.settings || {}); this.workflowsStore.setWorkflowPinData(workflow.pinData || {}); this.workflowsStore.setWorkflowVersionId(workflow.versionId); + this.workflowsStore.setWorkflowMetadata(workflow.meta); if (workflow.ownedBy) { this.workflowsEEStore.setWorkflowOwnedBy({ @@ -1585,6 +1587,7 @@ export default defineComponent({ void this.getNodesToSave(nodes).then((data) => { const workflowToCopy: IWorkflowToShare = { meta: { + ...(this.workflowsStore.workflow.meta ?? {}), instanceId: this.rootStore.instanceId, }, ...data,