From cde7a9dbd985ae9e83de2d39dccc508a41d9a676 Mon Sep 17 00:00:00 2001 From: Theodore Nastos <15264814+theonastos@users.noreply.github.com> Date: Fri, 9 Oct 2026 12:59:23 +0000 Subject: [PATCH] feat(editor): Disable restricted model providers in the agent model selector (#40658) --- .../AiModelSelectorDropdown.test.ts | 47 +++++++++++ .../AiModelSelectorDropdown.types.ts | 2 + .../AiModelSelectorDropdown.vue | 36 ++++++++- .../frontend/@n8n/i18n/src/locales/en.json | 1 + .../AgentBuilderEditorColumn.spec.ts | 7 ++ .../__tests__/AgentModelSelector.spec.ts | 79 +++++++++++++++++++ .../components/AgentBuilderEditorColumn.vue | 12 ++- .../agents/components/AgentModelSelector.vue | 50 ++++++++++-- .../frontend/src/index.ts | 1 + 9 files changed, 224 insertions(+), 11 deletions(-) diff --git a/packages/frontend/@n8n/design-system/src/components/N8nAiModelSelectorDropdown/AiModelSelectorDropdown.test.ts b/packages/frontend/@n8n/design-system/src/components/N8nAiModelSelectorDropdown/AiModelSelectorDropdown.test.ts index 8d9f74380ab..a4b4a08c36b 100644 --- a/packages/frontend/@n8n/design-system/src/components/N8nAiModelSelectorDropdown/AiModelSelectorDropdown.test.ts +++ b/packages/frontend/@n8n/design-system/src/components/N8nAiModelSelectorDropdown/AiModelSelectorDropdown.test.ts @@ -121,6 +121,53 @@ describe('N8nAiModelSelectorDropdown', () => { expect(getByText('Connected')).toBeVisible(); }); + it('shows the restricted badge in the trigger instead of the credential name', () => { + const { getByTestId, queryByTestId } = render(N8nAiModelSelectorDropdown, { + props: { + ...defaultProps, + selectedCredentialName: 'Production OpenAI credential', + restrictedLabel: 'Restricted', + }, + }); + + expect(getByTestId('ai-model-selector-restricted-badge')).toHaveTextContent('Restricted'); + expect(queryByTestId('ai-model-selector-credential')).not.toBeInTheDocument(); + }); + + it('hides the restricted badge while loading', () => { + const { queryByTestId } = render(N8nAiModelSelectorDropdown, { + props: { ...defaultProps, restrictedLabel: 'Restricted', isLoading: true }, + }); + + expect(queryByTestId('ai-model-selector-restricted-badge')).not.toBeInTheDocument(); + }); + + it('renders the scope line and lock on a restricted item', async () => { + const { getByTestId } = render(N8nAiModelSelectorDropdown, { + props: { + ...defaultProps, + items: [ + ...baseItems, + { + id: 'anthropic', + label: 'Anthropic', + disabled: true, + data: { restrictedLabel: 'Restricted on this instance' }, + }, + ], + }, + }); + + await userEvent.click(getByTestId('ai-model-selector')); + + await waitFor(() => + expect(getByTestId('ai-model-selector-restriction')).toHaveTextContent( + 'Restricted on this instance', + ), + ); + expect(getByTestId('ai-model-selector-restricted-icon')).toBeInTheDocument(); + }); + it('emits select and search events', async () => { const { getByTestId, getByText, emitted } = render(N8nAiModelSelectorDropdown, { props: { diff --git a/packages/frontend/@n8n/design-system/src/components/N8nAiModelSelectorDropdown/AiModelSelectorDropdown.types.ts b/packages/frontend/@n8n/design-system/src/components/N8nAiModelSelectorDropdown/AiModelSelectorDropdown.types.ts index a4c9954d0e2..a106035097a 100644 --- a/packages/frontend/@n8n/design-system/src/components/N8nAiModelSelectorDropdown/AiModelSelectorDropdown.types.ts +++ b/packages/frontend/@n8n/design-system/src/components/N8nAiModelSelectorDropdown/AiModelSelectorDropdown.types.ts @@ -16,6 +16,8 @@ export interface AiModelSelectorMenuItemData { loading?: boolean; /** Trailing "✓