diff --git a/packages/frontend/@n8n/i18n/src/locales/en.json b/packages/frontend/@n8n/i18n/src/locales/en.json index 30005c1dfef..01060531988 100644 --- a/packages/frontend/@n8n/i18n/src/locales/en.json +++ b/packages/frontend/@n8n/i18n/src/locales/en.json @@ -6140,6 +6140,7 @@ "agents.builder.addTrigger.slack.hideJson": "Hide JSON", "agents.builder.addTrigger.slack.copyManifest": "Copy manifest", "agents.builder.addTrigger.slack.manifestTitle": "Slack App Manifest", + "agents.builder.addTrigger.slack.docsCalloutLink": "See docs", "agents.builder.addTrigger.telegram.accessMode.label": "Access mode", "agents.builder.addTrigger.telegram.accessMode.private": "Private", "agents.builder.addTrigger.telegram.accessMode.public": "Public", diff --git a/packages/frontend/editor-ui/src/features/agents/__tests__/AgentBuilderView.test.ts b/packages/frontend/editor-ui/src/features/agents/__tests__/AgentBuilderView.test.ts index eac67a6352a..2809a35683d 100644 --- a/packages/frontend/editor-ui/src/features/agents/__tests__/AgentBuilderView.test.ts +++ b/packages/frontend/editor-ui/src/features/agents/__tests__/AgentBuilderView.test.ts @@ -364,12 +364,6 @@ const commonStubs = { props: ['skill', 'disabled', 'errors'], emits: ['update:skill'], }, - AgentIntegrationsPanel: { - name: 'AgentIntegrationsPanel', - template: '
', - props: ['projectId', 'agentId', 'agentName', 'focusType', 'onlyConnected'], - emits: ['update:connected-triggers', 'trigger-added'], - }, AgentSessionsListView: { name: 'AgentSessionsListView', template: '', @@ -884,23 +878,3 @@ describe('AgentBuilderView — three-column shell', () => { ]); }); }); - -/* - * DROPPED SPECS (no UI entry point in PR1): - * - * 1. 'fires User edited agent config with part=name when the agent name is updated' - * — relied on AgentHomeContent emitting 'update:name'. AgentHomeContent is - * removed from the three-column shell; name editing has no new UI entry point - * in PR1. Re-add once a name-edit surface lands in the editor column. - * - * 2. 'fires User edited agent config with part=description when the description is updated' - * — relied on AgentHomeContent emitting 'update:description'. Same reason as above. - * - * 3. 'fires User edited agent config with part=triggers when the connected-triggers list changes' - * — relied on AgentSettingsSidebar emitting 'update:connected-triggers'. The - * integrations panel is deleted in PR1; triggers telemetry has no new entry point. - * Re-add when AgentIntegrationsPanel or equivalent lands. - * - * 4. 'does not fire User edited agent config when the connected-triggers list is unchanged' - * — same as above. - */ diff --git a/packages/frontend/editor-ui/src/features/agents/__tests__/AgentIntegrationCredentialPickers.test.ts b/packages/frontend/editor-ui/src/features/agents/__tests__/AgentIntegrationCredentialPickers.test.ts index 40360c7d997..1c044755d60 100644 --- a/packages/frontend/editor-ui/src/features/agents/__tests__/AgentIntegrationCredentialPickers.test.ts +++ b/packages/frontend/editor-ui/src/features/agents/__tests__/AgentIntegrationCredentialPickers.test.ts @@ -3,7 +3,6 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { mount, flushPromises } from '@vue/test-utils'; import AgentAddTriggerModal from '../components/AgentAddTriggerModal.vue'; -import AgentIntegrationsPanel from '../components/AgentIntegrationsPanel.vue'; import { clearAgentIntegrationStatusCache } from '../composables/useAgentIntegrationStatus'; const { @@ -220,48 +219,22 @@ describe('agent integration credential picker usage', () => { ); }); - it('uses the shared credential picker in the integrations panel', async () => { - const wrapper = mount(AgentIntegrationsPanel, { - props: { - projectId: 'project-1', - agentId: 'agent-1', - agentName: 'Agent', - isPublished: true, - focusType: 'slack', - }, - global: { stubs: globalStubs }, - }); - await flushPromises(); - - const picker = wrapper.find('[data-testid="agent-credential-select-stub"]'); - expect(picker.exists()).toBe(true); - expect(picker.attributes('data-test-id-prop')).toBe('slack-credential-select'); - expect(picker.attributes('data-can-create')).toBe('true'); - - await wrapper.find('[data-testid="stub-create-credential"]').trigger('click'); - - expect(openNewCredential).toHaveBeenCalledWith( - 'slackApi', - false, - false, - 'project-1', - undefined, - undefined, - undefined, - { hideAskAssistant: true }, - ); - }); - it('passes denied credential creation permission to the shared picker', async () => { projectState.currentProject = { id: 'project-1', name: 'Project', scopes: [] }; - const wrapper = mount(AgentIntegrationsPanel, { + const wrapper = mount(AgentAddTriggerModal, { props: { - projectId: 'project-1', - agentId: 'agent-1', - agentName: 'Agent', - isPublished: true, - focusType: 'slack', + modalName: 'agentAddTriggerModal', + data: { + projectId: 'project-1', + agentId: 'agent-1', + agentName: 'Agent', + isPublished: true, + initialTriggerType: 'slack', + connectedTriggers: [], + onConnectedTriggersChange: vi.fn(), + onTriggerAdded: vi.fn(), + }, }, global: { stubs: globalStubs }, }); @@ -273,13 +246,19 @@ describe('agent integration credential picker usage', () => { }); it('defaults Telegram setup to private mode and requires a user ID before connecting', async () => { - const wrapper = mount(AgentIntegrationsPanel, { + const wrapper = mount(AgentAddTriggerModal, { props: { - projectId: 'project-1', - agentId: 'agent-1', - agentName: 'Agent', - isPublished: true, - focusType: 'telegram', + modalName: 'agentAddTriggerModal', + data: { + projectId: 'project-1', + agentId: 'agent-1', + agentName: 'Agent', + isPublished: true, + initialTriggerType: 'telegram', + connectedTriggers: [], + onConnectedTriggersChange: vi.fn(), + onTriggerAdded: vi.fn(), + }, }, global: { stubs: globalStubs }, }); @@ -313,13 +292,19 @@ describe('agent integration credential picker usage', () => { integrations: [{ type: 'telegram', credentialId: 'cred-telegram' }], }); - const wrapper = mount(AgentIntegrationsPanel, { + const wrapper = mount(AgentAddTriggerModal, { props: { - projectId: 'project-1', - agentId: 'agent-1', - agentName: 'Agent', - isPublished: true, - focusType: 'telegram', + modalName: 'agentAddTriggerModal', + data: { + projectId: 'project-1', + agentId: 'agent-1', + agentName: 'Agent', + isPublished: true, + initialTriggerType: 'telegram', + connectedTriggers: [], + onConnectedTriggersChange: vi.fn(), + onTriggerAdded: vi.fn(), + }, }, global: { stubs: globalStubs }, }); @@ -342,13 +327,19 @@ describe('agent integration credential picker usage', () => { ], }); - const wrapper = mount(AgentIntegrationsPanel, { + const wrapper = mount(AgentAddTriggerModal, { props: { - projectId: 'project-1', - agentId: 'agent-1', - agentName: 'Agent', - isPublished: true, - focusType: 'telegram', + modalName: 'agentAddTriggerModal', + data: { + projectId: 'project-1', + agentId: 'agent-1', + agentName: 'Agent', + isPublished: true, + initialTriggerType: 'telegram', + connectedTriggers: [], + onConnectedTriggersChange: vi.fn(), + onTriggerAdded: vi.fn(), + }, }, global: { stubs: globalStubs }, }); @@ -357,6 +348,6 @@ describe('agent integration credential picker usage', () => { const userIds = wrapper.find('[data-testid="telegram-user-ids"]'); expect(userIds.exists()).toBe(true); expect(userIds.find('input').attributes('disabled')).toBeDefined(); - expect(wrapper.find('[data-testid="telegram-telegram-settings-save"]').exists()).toBe(false); + expect(wrapper.find('[data-testid="telegram-disconnect-button"]').exists()).toBe(true); }); }); diff --git a/packages/frontend/editor-ui/src/features/agents/components/AgentAddTriggerModal.vue b/packages/frontend/editor-ui/src/features/agents/components/AgentAddTriggerModal.vue index a9c0519115b..19ba66fd5b1 100644 --- a/packages/frontend/editor-ui/src/features/agents/components/AgentAddTriggerModal.vue +++ b/packages/frontend/editor-ui/src/features/agents/components/AgentAddTriggerModal.vue @@ -87,7 +87,6 @@ const credentialIdsBeforeNew = ref{{ slackAppManifest }}
- , so the button stays put as the user scrolls and never collides with
- the scrollbar groove. The right offset clears typical macOS / overlay
- scrollbars (~14px) plus our normal inner padding. */
-.codeBlockCopy {
- position: absolute;
- top: var(--spacing--2xs);
- right: var(--spacing--lg);
- z-index: 1;
-}
-
-.manifestCode {
- margin: 0;
- padding: var(--spacing--xs);
- padding-right: calc(var(--spacing--2xl) + var(--spacing--lg));
- background-color: var(--color--foreground--tint-2);
- border-radius: var(--radius);
- font-size: var(--font-size--2xs);
- line-height: var(--line-height--xl);
- overflow-x: auto;
- max-height: 240px;
- overflow-y: auto;
- scrollbar-width: thin;
- scrollbar-color: var(--border-color) transparent;
- white-space: pre;
- font-family: monospace;
- color: var(--color--text);
-}
-
.errorText {
color: var(--color--danger);
}
diff --git a/packages/frontend/editor-ui/src/features/agents/components/AgentIntegrationSettingsForm.vue b/packages/frontend/editor-ui/src/features/agents/components/AgentIntegrationSettingsForm.vue
index 9fcafdf0465..f3ef907b699 100644
--- a/packages/frontend/editor-ui/src/features/agents/components/AgentIntegrationSettingsForm.vue
+++ b/packages/frontend/editor-ui/src/features/agents/components/AgentIntegrationSettingsForm.vue
@@ -4,6 +4,7 @@ import type { AgentIntegrationSettings, AgentTelegramIntegrationSettings } from
import { resolveSavedTelegramSettings } from '../utils/telegramAccessSettings';
import AgentTelegramAccessSettingsForm from './AgentTelegramAccessSettingsForm.vue';
+import AgentSlackSettingsForm from './AgentSlackSettingsForm.vue';
const props = withDefaults(
defineProps<{
@@ -11,8 +12,18 @@ const props = withDefaults(
disabled?: boolean;
connected?: boolean;
savedSettings?: AgentIntegrationSettings;
+ agentName?: string;
+ projectId?: string;
+ agentId?: string;
}>(),
- { disabled: false, connected: false, savedSettings: undefined },
+ {
+ disabled: false,
+ connected: false,
+ savedSettings: undefined,
+ agentName: '',
+ projectId: '',
+ agentId: '',
+ },
);
const telegramFormRef = ref>();
@@ -21,8 +32,6 @@ const telegramSavedSettings = computed props.type === 'telegram');
-
const currentSettings = computed(
() => telegramFormRef.value?.currentSettings,
);
@@ -45,9 +54,16 @@ defineExpose({ currentSettings, validationError, isDirty });
+
diff --git a/packages/frontend/editor-ui/src/features/agents/components/AgentIntegrationsPanel.vue b/packages/frontend/editor-ui/src/features/agents/components/AgentIntegrationsPanel.vue
deleted file mode 100644
index 62b9e52e54a..00000000000
--- a/packages/frontend/editor-ui/src/features/agents/components/AgentIntegrationsPanel.vue
+++ /dev/null
@@ -1,701 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- {{ config.label }}
-
- {{ isConnected(config.type) ? 'Connected' : 'Disconnected' }}
-
-
-
-
-
-
-
- {{ config.description }}
-
-
-
-
-
-
-
- {{ linearCopied ? 'Copied' : 'Copy' }}
-
-
-
-
-
-
-
-
-
-
-
- {{ config.noCredentialsMessage }}
-
-
-
-
-
- {{ config.connectedDescription }}
-
-
-
-
-
-
- {{ errorMessages[config.type] }}
- Edit credential
-
-
-
-
-
- Copy the app manifest and paste it into your Slack app's settings to configure events,
- scopes, and interactivity.
- View JSON
-
-
-
- {{ copied ? 'Copied' : 'Copy manifest' }}
-
-
-
-
-
-
- Connect
-
-
-
-
- Disconnect
-
-
-
-
- {{ slackAppManifest }}
-
-
-
-
-
-
-
diff --git a/packages/frontend/editor-ui/src/features/agents/components/AgentSlackSettingsForm.vue b/packages/frontend/editor-ui/src/features/agents/components/AgentSlackSettingsForm.vue
new file mode 100644
index 00000000000..3994d8f7a0d
--- /dev/null
+++ b/packages/frontend/editor-ui/src/features/agents/components/AgentSlackSettingsForm.vue
@@ -0,0 +1,220 @@
+
+
+
+
+
+ {{ i18n.baseText('agents.builder.addTrigger.slack.manifestTitle') }}
+
+
+ {{ i18n.baseText('agents.builder.addTrigger.slack.manifestHint') }}
+
+ {{ i18n.baseText('agents.builder.addTrigger.slack.docsCalloutLink') }}
+
+
+
+
+
+
+
+ {{
+ manifestCopied
+ ? i18n.baseText('agents.builder.addTrigger.copied')
+ : i18n.baseText('agents.builder.addTrigger.copy')
+ }}
+
+ {{ slackAppManifest }}
+
+
+
+
+