diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index 415c752ffb..3d223149c3 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -817,10 +817,20 @@ export interface ITemplatesWorkflow { }; } +export interface ITemplatesWorkflowInfo { + nodeCount: number; + nodeTypes: { + [key: string]: { + count: number; + }; + }; +} + export interface ITemplatesWorkflowResponse extends ITemplatesWorkflow, IWorkflowTemplate { description: string | null; image: ITemplatesImage[]; categories: ITemplatesCategory[]; + workflowInfo: ITemplatesWorkflowInfo; } /** @@ -1010,6 +1020,7 @@ export interface IVersionNode { } export interface ITemplatesNode extends IVersionNode { + id: number; categories?: ITemplatesCategory[]; } diff --git a/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/setupTemplate.store.test.ts b/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/__tests__/setupTemplate.store.test.ts similarity index 53% rename from packages/editor-ui/src/views/SetupWorkflowFromTemplateView/setupTemplate.store.test.ts rename to packages/editor-ui/src/views/SetupWorkflowFromTemplateView/__tests__/setupTemplate.store.test.ts index 64d33f311d..4f5743085c 100644 --- a/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/setupTemplate.store.test.ts +++ b/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/__tests__/setupTemplate.store.test.ts @@ -1,10 +1,16 @@ +import { useTemplatesStore } from '@/stores/templates.store'; import type { IWorkflowTemplateNodeWithCredentials } from '@/utils/templates/templateTransforms'; import type { CredentialUsages } from '@/views/SetupWorkflowFromTemplateView/setupTemplate.store'; import { getAppCredentials, getAppsRequiringCredentials, groupNodeCredentialsByName, + useSetupTemplateStore, } from '@/views/SetupWorkflowFromTemplateView/setupTemplate.store'; +import { setActivePinia } from 'pinia'; +import * as testData from './setupTemplate.store.testData'; +import { createTestingPinia } from '@pinia/testing'; +import { useCredentialsStore } from '@/stores/credentials.store'; const objToMap = (obj: Record) => { return new Map(Object.entries(obj)); @@ -145,4 +151,111 @@ describe('SetupWorkflowFromTemplateView store', () => { ]); }); }); + + describe('setInitialCredentialsSelection', () => { + beforeEach(() => { + setActivePinia( + createTestingPinia({ + stubActions: false, + }), + ); + }); + + it("selects no credentials when there isn't any available", () => { + // Setup + const credentialsStore = useCredentialsStore(); + credentialsStore.setCredentialTypes([testData.credentialTypeTelegram]); + const templatesStore = useTemplatesStore(); + templatesStore.addWorkflows([testData.fullShopifyTelegramTwitterTemplate]); + + const setupTemplateStore = useSetupTemplateStore(); + setupTemplateStore.setTemplateId(testData.fullShopifyTelegramTwitterTemplate.id.toString()); + + // Execute + setupTemplateStore.setInitialCredentialSelection(); + + expect(setupTemplateStore.selectedCredentialIdByName).toEqual({}); + }); + + it("selects credential when there's only one", () => { + // Setup + const credentialsStore = useCredentialsStore(); + credentialsStore.setCredentialTypes([testData.credentialTypeTelegram]); + credentialsStore.setCredentials([testData.credentialsTelegram1]); + const templatesStore = useTemplatesStore(); + templatesStore.addWorkflows([testData.fullShopifyTelegramTwitterTemplate]); + + const setupTemplateStore = useSetupTemplateStore(); + setupTemplateStore.setTemplateId(testData.fullShopifyTelegramTwitterTemplate.id.toString()); + + // Execute + setupTemplateStore.setInitialCredentialSelection(); + + expect(setupTemplateStore.selectedCredentialIdByName).toEqual({ + telegram_habot: 'YaSKdvEcT1TSFrrr1', + }); + }); + + it('selects no credentials when there are more than 1 available', () => { + // Setup + const credentialsStore = useCredentialsStore(); + credentialsStore.setCredentialTypes([testData.credentialTypeTelegram]); + credentialsStore.setCredentials([ + testData.credentialsTelegram1, + testData.credentialsTelegram2, + ]); + const templatesStore = useTemplatesStore(); + templatesStore.addWorkflows([testData.fullShopifyTelegramTwitterTemplate]); + + const setupTemplateStore = useSetupTemplateStore(); + setupTemplateStore.setTemplateId(testData.fullShopifyTelegramTwitterTemplate.id.toString()); + + // Execute + setupTemplateStore.setInitialCredentialSelection(); + + expect(setupTemplateStore.selectedCredentialIdByName).toEqual({}); + }); + + test.each([ + ['httpBasicAuth'], + ['httpCustomAuth'], + ['httpDigestAuth'], + ['httpHeaderAuth'], + ['oAuth1Api'], + ['oAuth2Api'], + ['httpQueryAuth'], + ])('does not auto-select credentials for %s', (credentialType) => { + // Setup + const credentialsStore = useCredentialsStore(); + credentialsStore.setCredentialTypes([testData.newCredentialType(credentialType)]); + credentialsStore.setCredentials([ + testData.newCredential({ + name: `${credentialType}Credential`, + type: credentialType, + }), + ]); + + const templatesStore = useTemplatesStore(); + const workflow = testData.newFullOneNodeTemplate({ + name: 'Test', + type: 'n8n-nodes-base.httpRequest', + typeVersion: 1, + credentials: { + [credentialType]: 'Test', + }, + parameters: {}, + position: [250, 300], + }); + templatesStore.addWorkflows([workflow]); + + const setupTemplateStore = useSetupTemplateStore(); + setupTemplateStore.setTemplateId(workflow.id.toString()); + + // Execute + setupTemplateStore.setInitialCredentialSelection(); + + expect(setupTemplateStore.credentialUsages.length).toBe(1); + expect(setupTemplateStore.selectedCredentialIdByName).toEqual({}); + }); + }); }); diff --git a/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/__tests__/setupTemplate.store.testData.ts b/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/__tests__/setupTemplate.store.testData.ts new file mode 100644 index 0000000000..b036138969 --- /dev/null +++ b/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/__tests__/setupTemplate.store.testData.ts @@ -0,0 +1,309 @@ +import { faker } from '@faker-js/faker/locale/en'; +import type { + ICredentialsResponse, + ITemplatesWorkflowFull, + IWorkflowTemplateNode, +} from '@/Interface'; +import type { ICredentialType } from 'n8n-workflow'; + +export const newFullOneNodeTemplate = (node: IWorkflowTemplateNode): ITemplatesWorkflowFull => ({ + full: true, + id: faker.number.int(), + name: faker.commerce.productName(), + totalViews: 1, + createdAt: '2021-08-24T10:40:50.007Z', + description: faker.lorem.paragraph(), + workflow: { + nodes: [node], + connections: {}, + }, + nodes: [ + { + defaults: {}, + displayName: faker.commerce.productName(), + icon: 'file:telegram.svg', + iconData: { + fileBuffer: '', + type: 'file', + }, + id: faker.number.int(), + name: node.type, + }, + ], + image: [], + categories: [], + user: { + username: faker.internet.userName(), + }, + workflowInfo: { + nodeCount: 1, + nodeTypes: { + [node.type]: { + count: 1, + }, + }, + }, +}); + +export const fullShopifyTelegramTwitterTemplate: ITemplatesWorkflowFull = { + full: true, + id: 1205, + name: 'Promote new Shopify products on Twitter and Telegram', + totalViews: 485, + createdAt: '2021-08-24T10:40:50.007Z', + description: + 'This workflow automatically promotes your new Shopify products on Twitter and Telegram. This workflow is also featured in the blog post [*6 e-commerce workflows to power up your Shopify store*](https://n8n.io/blog/no-code-ecommerce-workflow-automations/#promote-your-new-products-on-social-media).\n\n## Prerequisites\n\n- A Shopify account and [credentials](https://docs.n8n.io/integrations/credentials/shopify/)\n- A Twitter account and [credentials](https://docs.n8n.io/integrations/credentials/twitter/)\n- A Telegram account and [credentials](https://docs.n8n.io/integrations/credentials/telegram/) for the channel you want to send messages to.\n\n## Nodes\n\n- [Shopify Trigger node](https://docs.n8n.io/integrations/trigger-nodes/n8n-nodes-base.shopifytrigger/) triggers the workflow when you create a new product in Shopify.\n- [Twitter node](https://docs.n8n.io/integrations/nodes/n8n-nodes-base.twitter/) posts a tweet with the text "Hey there, my design is now on a new product! Visit my {shop name} to get this cool {product title} (and check out more {product type})".\n- [Telegram node](https://docs.n8n.io/integrations/nodes/n8n-nodes-base.telegram/) posts a message with the same text as above in a Telegram channel.', + workflow: { + nodes: [ + { + name: 'Twitter', + type: 'n8n-nodes-base.twitter', + position: [720, -220], + parameters: { + text: '=Hey there, my design is now on a new product ✨\nVisit my {{$json["vendor"]}} shop to get this cool{{$json["title"]}} (and check out more {{$json["product_type"]}}) 🛍️', + additionalFields: {}, + }, + credentials: { + twitterOAuth1Api: 'twitter', + }, + typeVersion: 1, + }, + { + name: 'Telegram', + type: 'n8n-nodes-base.telegram', + position: [720, -20], + parameters: { + text: '=Hey there, my design is now on a new product!\nVisit my {{$json["vendor"]}} shop to get this cool{{$json["title"]}} (and check out more {{$json["product_type"]}})', + chatId: '123456', + additionalFields: {}, + }, + credentials: { + telegramApi: 'telegram_habot', + }, + typeVersion: 1, + }, + { + name: 'product created', + type: 'n8n-nodes-base.shopifyTrigger', + position: [540, -110], + webhookId: '2a7e0e50-8f09-4a2b-bf54-a849a6ac4fe0', + parameters: { + topic: 'products/create', + }, + credentials: { + shopifyApi: 'shopify_nodeqa', + }, + typeVersion: 1, + }, + ], + connections: { + 'product created': { + main: [ + [ + { + node: 'Twitter', + type: 'main', + index: 0, + }, + { + node: 'Telegram', + type: 'main', + index: 0, + }, + ], + ], + }, + }, + }, + workflowInfo: { + nodeCount: 3, + nodeTypes: { + 'n8n-nodes-base.twitter': { + count: 1, + }, + 'n8n-nodes-base.telegram': { + count: 1, + }, + 'n8n-nodes-base.shopifyTrigger': { + count: 1, + }, + }, + }, + user: { + username: 'lorenanda', + }, + nodes: [ + { + id: 49, + icon: 'file:telegram.svg', + name: 'n8n-nodes-base.telegram', + defaults: { + name: 'Telegram', + }, + iconData: { + type: 'file', + fileBuffer: + 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNjYgNjYiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI2EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9ImEiIG92ZXJmbG93PSJ2aXNpYmxlIj48ZyBzdHJva2U9Im5vbmUiIGZpbGwtcnVsZT0ibm9uemVybyI+PHBhdGggZD0iTTAgMzJjMCAxNy42NzMgMTQuMzI3IDMyIDMyIDMyczMyLTE0LjMyNyAzMi0zMlM0OS42NzMgMCAzMiAwIDAgMTQuMzI3IDAgMzIiIGZpbGw9IiMzN2FlZTIiLz48cGF0aCBkPSJNMjEuNjYxIDM0LjMzOGwzLjc5NyAxMC41MDhzLjQ3NS45ODMuOTgzLjk4MyA4LjA2OC03Ljg2NCA4LjA2OC03Ljg2NGw4LjQwNy0xNi4yMzctMjEuMTE5IDkuODk4eiIgZmlsbD0iI2M4ZGFlYSIvPjxwYXRoIGQ9Ik0yNi42OTUgMzcuMDM0bC0uNzI5IDcuNzQ2cy0uMzA1IDIuMzczIDIuMDY4IDBsNC42NDQtNC4yMDMiIGZpbGw9IiNhOWM2ZDgiLz48cGF0aCBkPSJNMjEuNzMgMzQuNzEybC03LjgwOS0yLjU0NXMtLjkzMi0uMzc4LS42MzMtMS4yMzdjLjA2Mi0uMTc3LjE4Ni0uMzI4LjU1OS0uNTg4IDEuNzMxLTEuMjA2IDMyLjAyOC0xMi4wOTYgMzIuMDI4LTEyLjA5NnMuODU2LS4yODggMS4zNjEtLjA5N2MuMjMxLjA4OC4zNzguMTg3LjUwMy41NDguMDQ1LjEzMi4wNzEuNDExLjA2OC42ODktLjAwMy4yMDEtLjAyNy4zODYtLjA0NS42NzgtLjE4NCAyLjk3OC01LjcwNiAyNS4xOTgtNS43MDYgMjUuMTk4cy0uMzMgMS4zLTEuNTE0IDEuMzQ1Yy0uNDMyLjAxNi0uOTU2LS4wNzEtMS41ODItLjYxLTIuMzIzLTEuOTk4LTEwLjM1Mi03LjM5NC0xMi4xMjYtOC41OGEuMzQuMzQgMCAwMS0uMTQ2LS4yMzljLS4wMjUtLjEyNS4xMDgtLjI4LjEwOC0uMjhzMTMuOTgtMTIuNDI3IDE0LjM1Mi0xMy43MzFjLjAyOS0uMTAxLS4wNzktLjE1MS0uMjI2LS4xMDctLjkyOS4zNDItMTcuMDI1IDEwLjUwNi0xOC44MDEgMTEuNjI5LS4xMDQuMDY2LS4zOTUuMDIzLS4zOTUuMDIzIi8+PC9nPjwvc3ltYm9sPjwvc3ZnPg==', + }, + categories: [ + { + id: 6, + name: 'Communication', + }, + ], + displayName: 'Telegram', + typeVersion: 1, + }, + { + id: 107, + icon: 'file:shopify.svg', + name: 'n8n-nodes-base.shopifyTrigger', + defaults: { + name: 'Shopify Trigger', + }, + iconData: { + type: 'file', + fileBuffer: + 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNTggNjYiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI2EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9ImEiIG92ZXJmbG93PSJ2aXNpYmxlIj48ZyBzdHJva2U9Im5vbmUiIGZpbGwtcnVsZT0ibm9uemVybyI+PHBhdGggZD0iTTQ5LjI1NSAxMi40ODRhLjYzMy42MzMgMCAwMC0uNTY0LS41MjdjLS4yMjUtLjAzNy01LjE3LS4zNzYtNS4xNy0uMzc2bC0zLjc3LTMuNzdjLS4zNC0uMzc2LTEuMDkyLS4yNjYtMS4zNzYtLjE4OC0uMDM3IDAtLjc1Mi4yMjUtMS45MjIuNjA1LTEuMTM3LTMuMy0zLjE1LTYuMzA2LTYuNjk2LTYuMzA2aC0uMzAzQzI4LjQzOC42MDUgMjcuMTk0IDAgMjYuMTQ0IDBjLTguMjU2LjAzNy0xMi4yIDEwLjMzMy0xMy40MzQgMTUuNTk0bC01Ljc3IDEuNzdjLTEuNzcuNTY0LTEuODM1LjYwNS0yLjA3MyAyLjI5M0wwIDU3LjE3NSAzNi40NjggNjRsMTkuNzYzLTQuMjZjMC0uMDM3LTYuOTQtNDYuODk3LTYuOTc2LTQ3LjI1NXpNMzQuNDMxIDguODZjLS45MTcuMzAzLTEuOTYzLjYwNS0zLjEuOTQ1di0uNjhhMTUuMDMgMTUuMDMgMCAwMC0uNzUyLTQuOTk5YzEuODQ4LjI4NCAzLjEgMi4zNTcgMy44NDMgNC43MzN6bS02LjA2OC00LjI5OGMuNjAzIDEuNzc4Ljg4MyAzLjY1LjgyNiA1LjUyN3YuMzRsLTYuMzc1IDEuOTYzYzEuMjQ4LTQuNjYgMy41NS02Ljk2MiA1LjU1LTcuODN6bS0yLjQ1LTIuMjkzYTEuOTQgMS45NCAwIDAxMS4wNTUuMzM5Yy0yLjY2IDEuMjM4LTUuNDcyIDQuMzY2LTYuNjc4IDEwLjYyN2wtNS4wNDUgMS41NDZDMTYuNjY4IDEwLjAzIDE5Ljk4OCAyLjI2IDI1LjkxIDIuMjZ6IiBmaWxsPSIjOTViZjQ3Ii8+PHBhdGggZD0iTTQ4LjY5MSAxMS45NTdjLS4yMjUtLjAzNy01LjE3LS4zNzYtNS4xNy0uMzc2bC0zLjc3LTMuNzdhLjc1My43NTMgMCAwMC0uNTI3LS4yMjVMMzYuNDcyIDY0bDE5Ljc2My00LjI2LTYuOTgtNDcuMjE4YS42OC42OCAwIDAwLS41NjQtLjU2NHoiIGZpbGw9IiM1ZThlM2UiLz48cGF0aCBkPSJNMjkuNzU4IDIyLjlsLTIuNDU0IDcuMjQyYTExLjM2IDExLjM2IDAgMDAtNC43NTItMS4xMzNjLTMuODQ4IDAtNC4wMzYgMi40MTItNC4wMzYgMy4wMTggMCAzLjI5OCA4LjYzNiA0LjU2NCA4LjYzNiAxMi4zMzMgMCA2LjEtMy44ODUgMTAuMDMtOS4xIDEwLjAzLTYuMjYgMC05LjQ2Ny0zLjg4NS05LjQ2Ny0zLjg4NWwxLjY2NS01LjU1czMuMjggMi44MyA2LjA3MyAyLjgzYTIuNDcgMi40NyAwIDAwMi41NjQtMi40OWMwLTQuMzQtNy4xLTQuNTI3LTcuMS0xMS42MTggMC01Ljk2MiA0LjI5OC0xMS43NyAxMi45MzQtMTEuNzcgMy4zOTQuMDUgNS4wMTggMSA1LjAxOCAxeiIvPjwvZz48L3N5bWJvbD48L3N2Zz4=', + }, + categories: [ + { + id: 2, + name: 'Sales', + }, + ], + displayName: 'Shopify Trigger', + typeVersion: 1, + }, + { + id: 325, + icon: 'file:x.svg', + name: 'n8n-nodes-base.twitter', + defaults: { + name: 'X', + }, + iconData: { + type: 'file', + fileBuffer: + 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE4LjI0NCAyLjI1aDMuMzA4bC03LjIyNyA4LjI2IDguNTAyIDExLjI0SDE2LjE3bC01LjIxNC02LjgxN0w0Ljk5IDIxLjc1SDEuNjhsNy43My04LjgzNUwxLjI1NCAyLjI1SDguMDhsNC43MTMgNi4yMzF6bS0xLjE2MSAxNy41MmgxLjgzM0w3LjA4NCA0LjEyNkg1LjExN3oiPjwvcGF0aD48L3N2Zz4K', + }, + categories: [ + { + id: 1, + name: 'Marketing & Content', + }, + ], + displayName: 'X (Formerly Twitter)', + typeVersion: 2, + }, + ], + categories: [ + { + id: 2, + name: 'Sales', + }, + { + id: 19, + name: 'Marketing & Growth', + }, + ], + image: [ + { + id: 527, + url: 'https://n8niostorageaccount.blob.core.windows.net/n8nio-strapi-blobs-prod/assets/89a078b208fe4c6181902608b1cd1332.png', + }, + ], +}; + +export const newCredentialType = (name: string): ICredentialType => ({ + name, + displayName: name, + documentationUrl: name, + properties: [], +}); + +export const newCredential = ( + opts: Pick & Partial, +): ICredentialsResponse => ({ + createdAt: faker.date.past().toISOString(), + updatedAt: faker.date.past().toISOString(), + id: faker.string.alphanumeric({ length: 16 }), + name: faker.commerce.productName(), + nodesAccess: [], + ...opts, +}); + +export const credentialTypeTelegram: ICredentialType = { + name: 'telegramApi', + displayName: 'Telegram API', + documentationUrl: 'telegram', + properties: [ + { + displayName: 'Access Token', + name: 'accessToken', + type: 'string', + typeOptions: { + password: true, + }, + default: '', + description: + 'Chat with the bot father to obtain the access token', + }, + ], + test: { + request: { + baseURL: '=https://api.telegram.org/bot{{$credentials.accessToken}}', + url: '/getMe', + }, + }, +}; + +export const credentialsTelegram1: ICredentialsResponse = { + createdAt: '2023-11-23T14:26:07.969Z', + updatedAt: '2023-11-23T14:26:07.964Z', + id: 'YaSKdvEcT1TSFrrr1', + name: 'Telegram account', + type: 'telegramApi', + nodesAccess: [ + { + nodeType: 'n8n-nodes-base.telegram', + date: new Date('2023-11-23T14:26:07.962Z'), + }, + { + nodeType: 'n8n-nodes-base.telegramTrigger', + date: new Date('2023-11-23T14:26:07.962Z'), + }, + ], + ownedBy: { + id: '713ef3e7-9e65-4b0a-893c-8a653cbb2c4f', + email: 'user@n8n.io', + firstName: 'Player', + lastName: 'One', + }, + sharedWith: [], +}; + +export const credentialsTelegram2: ICredentialsResponse = { + createdAt: '2023-11-23T14:26:07.969Z', + updatedAt: '2023-11-23T14:26:07.964Z', + id: 'YaSKdvEcT1TSFrrr2', + name: 'Telegram account', + type: 'telegramApi', + nodesAccess: [ + { + nodeType: 'n8n-nodes-base.telegram', + date: new Date('2023-11-23T14:26:07.962Z'), + }, + { + nodeType: 'n8n-nodes-base.telegramTrigger', + date: new Date('2023-11-23T14:26:07.962Z'), + }, + ], + ownedBy: { + id: '713ef3e7-9e65-4b0a-893c-8a653cbb2c4f', + email: 'user@n8n.io', + firstName: 'Player', + lastName: 'One', + }, + sharedWith: [], +}; diff --git a/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/setupTemplate.store.ts b/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/setupTemplate.store.ts index 5ae601048c..15d86700ae 100644 --- a/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/setupTemplate.store.ts +++ b/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/setupTemplate.store.ts @@ -232,6 +232,34 @@ export const useSetupTemplateStore = defineStore('setupTemplate', () => { templateId.value = id; }; + const ignoredAutoFillCredentialTypes = new Set([ + 'httpBasicAuth', + 'httpCustomAuth', + 'httpDigestAuth', + 'httpHeaderAuth', + 'oAuth1Api', + 'oAuth2Api', + 'httpQueryAuth', + ]); + + /** + * Selects initial credentials for the template. Credentials + * need to be loaded before this. + */ + const setInitialCredentialSelection = () => { + for (const credUsage of credentialUsages.value) { + if (ignoredAutoFillCredentialTypes.has(credUsage.credentialType)) { + continue; + } + + const availableCreds = credentialsStore.getCredentialsByType(credUsage.credentialType); + + if (availableCreds.length === 1) { + selectedCredentialIdByName.value[credUsage.credentialName] = availableCreds[0].id; + } + } + }; + /** * Loads the template if it hasn't been loaded yet. */ @@ -241,6 +269,8 @@ export const useSetupTemplateStore = defineStore('setupTemplate', () => { } await templatesStore.fetchTemplateById(templateId.value); + + setInitialCredentialSelection(); }; /** @@ -257,6 +287,8 @@ export const useSetupTemplateStore = defineStore('setupTemplate', () => { nodeTypesStore.loadNodeTypesIfNotLoaded(), loadTemplateIfNeeded(), ]); + + setInitialCredentialSelection(); } finally { isLoading.value = false; } @@ -341,6 +373,7 @@ export const useSetupTemplateStore = defineStore('setupTemplate', () => { skipSetup, init, loadTemplateIfNeeded, + setInitialCredentialSelection, setTemplateId, setSelectedCredentialId, unsetSelectedCredential,