diff --git a/packages/frontend/@n8n/design-system/package.json b/packages/frontend/@n8n/design-system/package.json index afbcb36404f..d068042b72f 100644 --- a/packages/frontend/@n8n/design-system/package.json +++ b/packages/frontend/@n8n/design-system/package.json @@ -23,7 +23,7 @@ "lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache" }, "devDependencies": { - "@iconify/json": "^2.2.349", + "@iconify/json": "^2.2.488", "@n8n/eslint-config": "workspace:*", "@n8n/playwright-janitor": "workspace:*", "@n8n/stylelint-config": "workspace:*", diff --git a/packages/frontend/@n8n/design-system/src/components/N8nIcon/Icon.stories.ts b/packages/frontend/@n8n/design-system/src/components/N8nIcon/Icon.stories.ts index d79506c86bb..9a46bb7b9e7 100644 --- a/packages/frontend/@n8n/design-system/src/components/N8nIcon/Icon.stories.ts +++ b/packages/frontend/@n8n/design-system/src/components/N8nIcon/Icon.stories.ts @@ -202,6 +202,11 @@ export const AllColors: StoryFn = (args, { argTypes }) => ({ `, }); +export const UserRoundKey = Template.bind({}); +UserRoundKey.args = { + icon: 'user-round-key', +}; + export const CommonIcons: StoryFn = (args, { argTypes }) => ({ setup: () => ({ args }), props: Object.keys(argTypes), @@ -258,6 +263,10 @@ export const CommonIcons: StoryFn = (args, { argTypes }) => ({ exclamation-triangle +
+ + user-round-key +
`, }); diff --git a/packages/frontend/@n8n/design-system/src/components/N8nIcon/icons.ts b/packages/frontend/@n8n/design-system/src/components/N8nIcon/icons.ts index 169840cb64e..ae5b264871f 100644 --- a/packages/frontend/@n8n/design-system/src/components/N8nIcon/icons.ts +++ b/packages/frontend/@n8n/design-system/src/components/N8nIcon/icons.ts @@ -260,6 +260,7 @@ import IconLucideUserCheck from '~icons/lucide/user-check'; import IconLucideUserLock from '~icons/lucide/user-lock'; import IconLucideUserPen from '~icons/lucide/user-pen'; import IconLucideUserRound from '~icons/lucide/user-round'; +import IconLucideUserRoundKey from '~icons/lucide/user-round-key'; import IconLucideUsers from '~icons/lucide/users'; import IconLucideVariable from '~icons/lucide/variable'; import IconLucideVault from '~icons/lucide/vault'; @@ -752,6 +753,7 @@ export const updatedIconSet = { 'user-lock': IconLucideUserLock, 'user-pen': IconLucideUserPen, 'user-round': IconLucideUserRound, + 'user-round-key': IconLucideUserRoundKey, users: IconLucideUsers, vault: IconLucideVault, video: IconLucideVideo, diff --git a/packages/frontend/@n8n/i18n/src/locales/en.json b/packages/frontend/@n8n/i18n/src/locales/en.json index c2aae86c497..4131af8408d 100644 --- a/packages/frontend/@n8n/i18n/src/locales/en.json +++ b/packages/frontend/@n8n/i18n/src/locales/en.json @@ -4347,6 +4347,7 @@ "workflows.item.readonly": "Read only", "workflows.item.archived": "Archived", "workflows.item.availableInMCP": "Available in MCP", + "workflows.privateCredential.tooltip": "Set up and run with your own credentials", "workflows.dynamic.tooltip": "This workflow resolves credentials at runtime based on who executes it.", "workflows.dynamic.tooltipTitle": "Private credentials", "workflows.dependencies.tooltip.workflow": "Click to view resources referenced by this workflow", diff --git a/packages/frontend/editor-ui/package.json b/packages/frontend/editor-ui/package.json index 2674a0d1c4b..bc3c72a6842 100644 --- a/packages/frontend/editor-ui/package.json +++ b/packages/frontend/editor-ui/package.json @@ -126,7 +126,7 @@ "devDependencies": { "@codecov/vite-plugin": "^1.9.1", "@faker-js/faker": "^8.0.2", - "@iconify/json": "^2.2.349", + "@iconify/json": "^2.2.488", "@n8n/eslint-config": "workspace:*", "@n8n/playwright-janitor": "workspace:*", "@n8n/stylelint-config": "workspace:*", diff --git a/packages/frontend/editor-ui/src/app/components/WorkflowCard.test.ts b/packages/frontend/editor-ui/src/app/components/WorkflowCard.test.ts index 7f00b27c69e..3858d191872 100644 --- a/packages/frontend/editor-ui/src/app/components/WorkflowCard.test.ts +++ b/packages/frontend/editor-ui/src/app/components/WorkflowCard.test.ts @@ -1094,25 +1094,25 @@ describe('WorkflowCard', () => { expect(queryByTestId('workflow-card-mcp-toggle')).not.toBeInTheDocument(); }); - it('should show dynamic credentials indicator when workflow has resolvable credentials', () => { + it('should show private credential indicator when workflow has resolvable credentials', () => { const data = createWorkflow({ hasResolvableCredentials: true, }); const { getByTestId } = renderComponent({ props: { data } }); - const indicator = getByTestId('workflow-card-dynamic-credentials'); + const indicator = getByTestId('workflow-card-private-credential'); expect(indicator).toBeVisible(); }); - it('should hide dynamic credentials indicator when workflow has no resolvable credentials', () => { + it('should hide private credential indicator when workflow has no resolvable credentials', () => { const data = createWorkflow({ hasResolvableCredentials: false, }); const { queryByTestId } = renderComponent({ props: { data } }); - const indicator = queryByTestId('workflow-card-dynamic-credentials'); + const indicator = queryByTestId('workflow-card-private-credential'); expect(indicator).toBeNull(); }); diff --git a/packages/frontend/editor-ui/src/app/components/WorkflowCard.vue b/packages/frontend/editor-ui/src/app/components/WorkflowCard.vue index 71433c397ee..7d37c90f1c3 100644 --- a/packages/frontend/editor-ui/src/app/components/WorkflowCard.vue +++ b/packages/frontend/editor-ui/src/app/components/WorkflowCard.vue @@ -50,6 +50,7 @@ import { useMcp } from '@/features/ai/mcpAccess/composables/useMcp'; import { useWorkflowActivate } from '@/app/composables/useWorkflowActivate'; import { createEventBus } from '@n8n/utils/event-bus'; import { usePrivateCredentials } from '@/features/resolvers/composables/usePrivateCredentials'; +import PrivateCredentialIcon from '@/features/resolvers/components/PrivateCredentialIcon.vue'; import { useDependencies } from '@/app/composables/useDependencies'; const WORKFLOW_LIST_ITEM_ACTIONS = { @@ -618,24 +619,6 @@ const tags = computed( {{ locale.baseText('workflows.item.readonly') }} - - - - - - {{ locale.baseText('credentials.private.badge') }} - - -
@@ -656,6 +639,17 @@ const tags = computed( + { try { await credentialsStore.fetchCredentialTypes(false); @@ -41,10 +43,20 @@ onMounted(async () => { }); // Exclude purpose built credentials for ChatHub -const selectableCredentialTypes = computed(() => +const allSelectableCredentialTypes = computed(() => credentialsStore.allCredentialTypes.filter((c) => !c.name.startsWith('chatHub')), ); +const selectableCredentialTypes = computed(() => { + if (!searchQuery.value) return allSelectableCredentialTypes.value; + const q = searchQuery.value.toLowerCase(); + return allSelectableCredentialTypes.value.filter((c) => c.displayName.toLowerCase().includes(q)); +}); + +function filterCredentials(query: string) { + searchQuery.value = query; +} + function onSelect(type: string) { selected.value = type; } @@ -106,6 +118,7 @@ function openCredentialType() { :placeholder="i18n.baseText('credentialSelectModal.searchForApp')" size="xlarge" :model-value="selected" + :filter-method="filterCredentials" data-test-id="new-credential-type-select" @update:model-value="onSelect" > diff --git a/packages/frontend/editor-ui/src/features/resolvers/components/PrivateCredentialIcon.test.ts b/packages/frontend/editor-ui/src/features/resolvers/components/PrivateCredentialIcon.test.ts new file mode 100644 index 00000000000..304f5e5076e --- /dev/null +++ b/packages/frontend/editor-ui/src/features/resolvers/components/PrivateCredentialIcon.test.ts @@ -0,0 +1,11 @@ +import { createComponentRenderer } from '@/__tests__/render'; +import PrivateCredentialIcon from './PrivateCredentialIcon.vue'; + +const renderComponent = createComponentRenderer(PrivateCredentialIcon); + +describe('PrivateCredentialIcon', () => { + it('should render the icon', () => { + const { getByTestId } = renderComponent(); + expect(getByTestId('private-credential-icon')).toBeInTheDocument(); + }); +}); diff --git a/packages/frontend/editor-ui/src/features/resolvers/components/PrivateCredentialIcon.vue b/packages/frontend/editor-ui/src/features/resolvers/components/PrivateCredentialIcon.vue new file mode 100644 index 00000000000..2733ad76621 --- /dev/null +++ b/packages/frontend/editor-ui/src/features/resolvers/components/PrivateCredentialIcon.vue @@ -0,0 +1,27 @@ + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d83b0903441..263266e0c73 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4188,8 +4188,8 @@ importers: version: 1.0.15 devDependencies: '@iconify/json': - specifier: ^2.2.349 - version: 2.2.354 + specifier: ^2.2.488 + version: 2.2.488 '@n8n/eslint-config': specifier: workspace:* version: link:../../../@n8n/eslint-config @@ -4853,8 +4853,8 @@ importers: specifier: ^8.0.2 version: 8.4.1 '@iconify/json': - specifier: ^2.2.349 - version: 2.2.354 + specifier: ^2.2.488 + version: 2.2.488 '@n8n/eslint-config': specifier: workspace:* version: link:../../@n8n/eslint-config @@ -7620,8 +7620,8 @@ packages: '@iconify-json/mdi@1.1.63': resolution: {integrity: sha512-b07dRM5LYdwJqd/lm+1+JDNDNSWHvpZ7ujb73oJxx3lmK1J0giDS0BSc4yia0hixNV0Z2q/4GyxAu/A8XqDnbg==} - '@iconify/json@2.2.354': - resolution: {integrity: sha512-I7sYXaLfvGw0msuc5p2VdQJ4nthbsqLW8IF9j1jaekUcs/xwGVgs3SHO5lEiFglv0odlkCu26CMbboZMvwkTcw==} + '@iconify/json@2.2.488': + resolution: {integrity: sha512-W2MfGS0n1GugWhQn7SLgRKNH1JonVsKG/O9vO/htP7j3k1bGt54R1mbN9uaZlQ99uCCu65IR5UgQM66E8Cm+Fw==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -18234,9 +18234,6 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -24875,10 +24872,10 @@ snapshots: dependencies: '@iconify/types': 2.0.0 - '@iconify/json@2.2.354': + '@iconify/json@2.2.488': dependencies: '@iconify/types': 2.0.0 - pathe: 1.1.2 + pathe: 2.0.3 '@iconify/types@2.0.0': {} @@ -37338,8 +37335,6 @@ snapshots: path-type@4.0.0: {} - pathe@1.1.2: {} - pathe@2.0.3: {} pathval@2.0.0: {}