mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
feat(editor): Make node credential select searchable (#12497)
This commit is contained in:
parent
b1a40a231b
commit
91277c44f1
|
@ -250,7 +250,7 @@ describe('Webhook Trigger node', () => {
|
||||||
});
|
});
|
||||||
// add credentials
|
// add credentials
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
||||||
credentialsModal.actions.fillCredentialsForm();
|
credentialsModal.actions.fillCredentialsForm();
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ describe('Webhook Trigger node', () => {
|
||||||
});
|
});
|
||||||
// add credentials
|
// add credentials
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
||||||
credentialsModal.actions.fillCredentialsForm();
|
credentialsModal.actions.fillCredentialsForm();
|
||||||
|
|
||||||
|
|
|
@ -297,10 +297,9 @@ describe('Credential Usage in Cross Shared Workflows', () => {
|
||||||
workflowsPage.actions.createWorkflowFromCard();
|
workflowsPage.actions.createWorkflowFromCard();
|
||||||
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
||||||
|
|
||||||
// Only the credential in this project (+ the 'Create new' option) should
|
// Only the credential in this project should be in the dropdown
|
||||||
// be in the dropdown
|
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').should('have.length', 2);
|
getVisibleSelect().find('li').should('have.length', 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should only show credentials in their personal project for members', () => {
|
it('should only show credentials in their personal project for members', () => {
|
||||||
|
@ -325,10 +324,9 @@ describe('Credential Usage in Cross Shared Workflows', () => {
|
||||||
workflowsPage.actions.createWorkflowFromCard();
|
workflowsPage.actions.createWorkflowFromCard();
|
||||||
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
||||||
|
|
||||||
// Only the own credential the shared one (+ the 'Create new' option)
|
// Only the own credential the shared one should be in the dropdown
|
||||||
// should be in the dropdown
|
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').should('have.length', 3);
|
getVisibleSelect().find('li').should('have.length', 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should only show credentials in their personal project for members if the workflow was shared with them', () => {
|
it('should only show credentials in their personal project for members if the workflow was shared with them', () => {
|
||||||
|
@ -355,10 +353,9 @@ describe('Credential Usage in Cross Shared Workflows', () => {
|
||||||
workflowsPage.getters.workflowCardContent(workflowName).click();
|
workflowsPage.getters.workflowCardContent(workflowName).click();
|
||||||
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
||||||
|
|
||||||
// Only the own credential the shared one (+ the 'Create new' option)
|
// Only the own credential the shared one should be in the dropdown
|
||||||
// should be in the dropdown
|
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').should('have.length', 2);
|
getVisibleSelect().find('li').should('have.length', 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show all credentials from all personal projects the workflow's been shared into for the global owner", () => {
|
it("should show all credentials from all personal projects the workflow's been shared into for the global owner", () => {
|
||||||
|
@ -400,10 +397,9 @@ describe('Credential Usage in Cross Shared Workflows', () => {
|
||||||
workflowsPage.getters.workflowCardContent(workflowName).click();
|
workflowsPage.getters.workflowCardContent(workflowName).click();
|
||||||
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
||||||
|
|
||||||
// Only the personal credentials of the workflow owner and the global owner
|
// Only the personal credentials of the workflow owner and the global owner should show up.
|
||||||
// should show up.
|
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').should('have.length', 4);
|
getVisibleSelect().find('li').should('have.length', 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show all personal credentials if the global owner owns the workflow', () => {
|
it('should show all personal credentials if the global owner owns the workflow', () => {
|
||||||
|
@ -421,6 +417,6 @@ describe('Credential Usage in Cross Shared Workflows', () => {
|
||||||
|
|
||||||
// Show all personal credentials
|
// Show all personal credentials
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').should('have.have.length', 2);
|
getVisibleSelect().find('li').should('have.have.length', 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,7 +31,7 @@ function createNotionCredential() {
|
||||||
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME);
|
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME);
|
||||||
workflowPage.actions.openNode(NOTION_NODE_NAME);
|
workflowPage.actions.openNode(NOTION_NODE_NAME);
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.actions.fillCredentialsForm();
|
credentialsModal.actions.fillCredentialsForm();
|
||||||
cy.get('body').type('{esc}');
|
cy.get('body').type('{esc}');
|
||||||
workflowPage.actions.deleteNode(NOTION_NODE_NAME);
|
workflowPage.actions.deleteNode(NOTION_NODE_NAME);
|
||||||
|
@ -79,7 +79,7 @@ describe('Credentials', () => {
|
||||||
workflowPage.getters.canvasNodes().last().click();
|
workflowPage.getters.canvasNodes().last().click();
|
||||||
cy.get('body').type('{enter}');
|
cy.get('body').type('{enter}');
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
||||||
credentialsModal.getters.credentialAuthTypeRadioButtons().should('have.length', 2);
|
credentialsModal.getters.credentialAuthTypeRadioButtons().should('have.length', 2);
|
||||||
credentialsModal.getters.credentialAuthTypeRadioButtons().first().click();
|
credentialsModal.getters.credentialAuthTypeRadioButtons().first().click();
|
||||||
|
@ -99,7 +99,7 @@ describe('Credentials', () => {
|
||||||
cy.get('body').type('{enter}');
|
cy.get('body').type('{enter}');
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
// Add oAuth credentials
|
// Add oAuth credentials
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
||||||
credentialsModal.getters.credentialAuthTypeRadioButtons().should('have.length', 2);
|
credentialsModal.getters.credentialAuthTypeRadioButtons().should('have.length', 2);
|
||||||
credentialsModal.getters.credentialAuthTypeRadioButtons().first().click();
|
credentialsModal.getters.credentialAuthTypeRadioButtons().first().click();
|
||||||
|
@ -107,14 +107,13 @@ describe('Credentials', () => {
|
||||||
cy.get('.el-message-box').find('button').contains('Close').click();
|
cy.get('.el-message-box').find('button').contains('Close').click();
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
// Add Service account credentials
|
// Add Service account credentials
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
||||||
credentialsModal.getters.credentialAuthTypeRadioButtons().should('have.length', 2);
|
credentialsModal.getters.credentialAuthTypeRadioButtons().should('have.length', 2);
|
||||||
credentialsModal.getters.credentialAuthTypeRadioButtons().last().click();
|
credentialsModal.getters.credentialAuthTypeRadioButtons().last().click();
|
||||||
credentialsModal.actions.fillCredentialsForm();
|
credentialsModal.actions.fillCredentialsForm();
|
||||||
// Both (+ the 'Create new' option) should be in the dropdown
|
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').should('have.length.greaterThan', 2);
|
getVisibleSelect().find('li').should('have.length', 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly render required and optional credentials', () => {
|
it('should correctly render required and optional credentials', () => {
|
||||||
|
@ -130,13 +129,13 @@ describe('Credentials', () => {
|
||||||
workflowPage.getters.nodeCredentialsSelect().should('have.length', 2);
|
workflowPage.getters.nodeCredentialsSelect().should('have.length', 2);
|
||||||
|
|
||||||
workflowPage.getters.nodeCredentialsSelect().first().click();
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
getVisibleSelect().find('li').contains('Create New Credential').click();
|
workflowPage.getters.nodeCredentialsCreateOption().first().click();
|
||||||
// This one should show auth type selector
|
// This one should show auth type selector
|
||||||
credentialsModal.getters.credentialAuthTypeRadioButtons().should('have.length', 2);
|
credentialsModal.getters.credentialAuthTypeRadioButtons().should('have.length', 2);
|
||||||
cy.get('body').type('{esc}');
|
cy.get('body').type('{esc}');
|
||||||
|
|
||||||
workflowPage.getters.nodeCredentialsSelect().last().click();
|
workflowPage.getters.nodeCredentialsSelect().last().click();
|
||||||
getVisibleSelect().find('li').contains('Create New Credential').click();
|
workflowPage.getters.nodeCredentialsCreateOption().last().click();
|
||||||
// This one should not show auth type selector
|
// This one should not show auth type selector
|
||||||
credentialsModal.getters.credentialsAuthTypeSelector().should('not.exist');
|
credentialsModal.getters.credentialsAuthTypeSelector().should('not.exist');
|
||||||
});
|
});
|
||||||
|
@ -148,7 +147,7 @@ describe('Credentials', () => {
|
||||||
workflowPage.getters.canvasNodes().last().click();
|
workflowPage.getters.canvasNodes().last().click();
|
||||||
cy.get('body').type('{enter}');
|
cy.get('body').type('{enter}');
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.getters.credentialsAuthTypeSelector().should('not.exist');
|
credentialsModal.getters.credentialsAuthTypeSelector().should('not.exist');
|
||||||
credentialsModal.actions.fillCredentialsForm();
|
credentialsModal.actions.fillCredentialsForm();
|
||||||
workflowPage.getters
|
workflowPage.getters
|
||||||
|
@ -164,7 +163,7 @@ describe('Credentials', () => {
|
||||||
workflowPage.getters.canvasNodes().last().click();
|
workflowPage.getters.canvasNodes().last().click();
|
||||||
cy.get('body').type('{enter}');
|
cy.get('body').type('{enter}');
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.actions.fillCredentialsForm();
|
credentialsModal.actions.fillCredentialsForm();
|
||||||
workflowPage.getters
|
workflowPage.getters
|
||||||
.nodeCredentialsSelect()
|
.nodeCredentialsSelect()
|
||||||
|
@ -189,7 +188,7 @@ describe('Credentials', () => {
|
||||||
workflowPage.getters.canvasNodes().last().click();
|
workflowPage.getters.canvasNodes().last().click();
|
||||||
cy.get('body').type('{enter}');
|
cy.get('body').type('{enter}');
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.actions.fillCredentialsForm();
|
credentialsModal.actions.fillCredentialsForm();
|
||||||
workflowPage.getters.nodeCredentialsEditButton().click();
|
workflowPage.getters.nodeCredentialsEditButton().click();
|
||||||
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
||||||
|
@ -232,7 +231,7 @@ describe('Credentials', () => {
|
||||||
cy.getByTestId('credential-select').click();
|
cy.getByTestId('credential-select').click();
|
||||||
cy.contains('Adalo API').click();
|
cy.contains('Adalo API').click();
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.actions.fillCredentialsForm();
|
credentialsModal.actions.fillCredentialsForm();
|
||||||
workflowPage.getters.nodeCredentialsEditButton().click();
|
workflowPage.getters.nodeCredentialsEditButton().click();
|
||||||
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
credentialsModal.getters.credentialsEditModal().should('be.visible');
|
||||||
|
@ -296,7 +295,7 @@ describe('Credentials', () => {
|
||||||
|
|
||||||
workflowPage.getters.nodeCredentialsSelect().should('exist');
|
workflowPage.getters.nodeCredentialsSelect().should('exist');
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.actions.fillCredentialsForm();
|
credentialsModal.actions.fillCredentialsForm();
|
||||||
workflowPage.getters
|
workflowPage.getters
|
||||||
.nodeCredentialsSelect()
|
.nodeCredentialsSelect()
|
||||||
|
@ -325,7 +324,7 @@ describe('Credentials', () => {
|
||||||
workflowPage.actions.addNodeToCanvas('Slack', true, true, 'Get a channel');
|
workflowPage.actions.addNodeToCanvas('Slack', true, true, 'Get a channel');
|
||||||
workflowPage.getters.nodeCredentialsSelect().should('exist');
|
workflowPage.getters.nodeCredentialsSelect().should('exist');
|
||||||
workflowPage.getters.nodeCredentialsSelect().click();
|
workflowPage.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.getters.credentialAuthTypeRadioButtons().first().click();
|
credentialsModal.getters.credentialAuthTypeRadioButtons().first().click();
|
||||||
nodeDetailsView.getters.copyInput().should('not.exist');
|
nodeDetailsView.getters.copyInput().should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
|
@ -89,7 +89,7 @@ describe('Community and custom nodes in canvas', () => {
|
||||||
workflowPage.actions.addNodeToCanvas('Manual');
|
workflowPage.actions.addNodeToCanvas('Manual');
|
||||||
workflowPage.actions.addNodeToCanvas('E2E Node with native n8n credential', true, true);
|
workflowPage.actions.addNodeToCanvas('E2E Node with native n8n credential', true, true);
|
||||||
workflowPage.getters.nodeCredentialsLabel().click();
|
workflowPage.getters.nodeCredentialsLabel().click();
|
||||||
cy.contains('Create New Credential').click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.getters.editCredentialModal().should('be.visible');
|
credentialsModal.getters.editCredentialModal().should('be.visible');
|
||||||
credentialsModal.getters.editCredentialModal().should('contain.text', 'Notion API');
|
credentialsModal.getters.editCredentialModal().should('contain.text', 'Notion API');
|
||||||
});
|
});
|
||||||
|
@ -98,7 +98,7 @@ describe('Community and custom nodes in canvas', () => {
|
||||||
workflowPage.actions.addNodeToCanvas('Manual');
|
workflowPage.actions.addNodeToCanvas('Manual');
|
||||||
workflowPage.actions.addNodeToCanvas('E2E Node with custom credential', true, true);
|
workflowPage.actions.addNodeToCanvas('E2E Node with custom credential', true, true);
|
||||||
workflowPage.getters.nodeCredentialsLabel().click();
|
workflowPage.getters.nodeCredentialsLabel().click();
|
||||||
cy.contains('Create New Credential').click();
|
workflowPage.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.getters.editCredentialModal().should('be.visible');
|
credentialsModal.getters.editCredentialModal().should('be.visible');
|
||||||
credentialsModal.getters.editCredentialModal().should('contain.text', 'Custom E2E Credential');
|
credentialsModal.getters.editCredentialModal().should('contain.text', 'Custom E2E Credential');
|
||||||
});
|
});
|
||||||
|
|
|
@ -367,7 +367,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
|
||||||
workflowPage.getters.nodeCredentialsSelect().first().click();
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
getVisibleSelect()
|
getVisibleSelect()
|
||||||
.find('li')
|
.find('li')
|
||||||
.should('have.length', 2)
|
.should('have.length', 1)
|
||||||
.first()
|
.first()
|
||||||
.should('contain.text', 'Notion account project 1');
|
.should('contain.text', 'Notion account project 1');
|
||||||
ndv.getters.backToCanvas().click();
|
ndv.getters.backToCanvas().click();
|
||||||
|
@ -382,7 +382,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
|
||||||
workflowPage.getters.nodeCredentialsSelect().first().click();
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
getVisibleSelect()
|
getVisibleSelect()
|
||||||
.find('li')
|
.find('li')
|
||||||
.should('have.length', 2)
|
.should('have.length', 1)
|
||||||
.first()
|
.first()
|
||||||
.should('contain.text', 'Notion account project 1');
|
.should('contain.text', 'Notion account project 1');
|
||||||
ndv.getters.backToCanvas().click();
|
ndv.getters.backToCanvas().click();
|
||||||
|
@ -396,7 +396,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
|
||||||
workflowPage.getters.nodeCredentialsSelect().first().click();
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
getVisibleSelect()
|
getVisibleSelect()
|
||||||
.find('li')
|
.find('li')
|
||||||
.should('have.length', 2)
|
.should('have.length', 1)
|
||||||
.first()
|
.first()
|
||||||
.should('contain.text', 'Notion account project 2');
|
.should('contain.text', 'Notion account project 2');
|
||||||
ndv.getters.backToCanvas().click();
|
ndv.getters.backToCanvas().click();
|
||||||
|
@ -407,7 +407,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
|
||||||
workflowPage.getters.nodeCredentialsSelect().first().click();
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
getVisibleSelect()
|
getVisibleSelect()
|
||||||
.find('li')
|
.find('li')
|
||||||
.should('have.length', 2)
|
.should('have.length', 1)
|
||||||
.first()
|
.first()
|
||||||
.should('contain.text', 'Notion account project 2');
|
.should('contain.text', 'Notion account project 2');
|
||||||
ndv.getters.backToCanvas().click();
|
ndv.getters.backToCanvas().click();
|
||||||
|
@ -425,7 +425,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
|
||||||
workflowPage.getters.nodeCredentialsSelect().first().click();
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
getVisibleSelect()
|
getVisibleSelect()
|
||||||
.find('li')
|
.find('li')
|
||||||
.should('have.length', 2)
|
.should('have.length', 1)
|
||||||
.first()
|
.first()
|
||||||
.should('contain.text', 'Notion account personal project');
|
.should('contain.text', 'Notion account personal project');
|
||||||
ndv.getters.backToCanvas().click();
|
ndv.getters.backToCanvas().click();
|
||||||
|
@ -436,7 +436,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
|
||||||
workflowPage.getters.nodeCredentialsSelect().first().click();
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
getVisibleSelect()
|
getVisibleSelect()
|
||||||
.find('li')
|
.find('li')
|
||||||
.should('have.length', 2)
|
.should('have.length', 1)
|
||||||
.first()
|
.first()
|
||||||
.should('contain.text', 'Notion account personal project');
|
.should('contain.text', 'Notion account personal project');
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { GMAIL_NODE_NAME, SCHEDULE_TRIGGER_NODE_NAME } from '../constants';
|
||||||
import { CredentialsModal, CredentialsPage, NDV, WorkflowPage } from '../pages';
|
import { CredentialsModal, CredentialsPage, NDV, WorkflowPage } from '../pages';
|
||||||
import { AIAssistant } from '../pages/features/ai-assistant';
|
import { AIAssistant } from '../pages/features/ai-assistant';
|
||||||
import { NodeCreator } from '../pages/features/node-creator';
|
import { NodeCreator } from '../pages/features/node-creator';
|
||||||
import { getVisibleSelect } from '../utils';
|
|
||||||
|
|
||||||
const wf = new WorkflowPage();
|
const wf = new WorkflowPage();
|
||||||
const ndv = new NDV();
|
const ndv = new NDV();
|
||||||
|
@ -434,7 +433,7 @@ describe('AI Assistant Credential Help', () => {
|
||||||
wf.actions.addNodeToCanvas('Slack', true, true, 'Get a channel');
|
wf.actions.addNodeToCanvas('Slack', true, true, 'Get a channel');
|
||||||
wf.getters.nodeCredentialsSelect().should('exist');
|
wf.getters.nodeCredentialsSelect().should('exist');
|
||||||
wf.getters.nodeCredentialsSelect().click();
|
wf.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
wf.getters.nodeCredentialsCreateOption().click();
|
||||||
credentialsModal.getters.credentialAuthTypeRadioButtons().first().click();
|
credentialsModal.getters.credentialAuthTypeRadioButtons().first().click();
|
||||||
ndv.getters.copyInput().should('not.exist');
|
ndv.getters.copyInput().should('not.exist');
|
||||||
credentialsModal.getters.oauthConnectButton().should('have.length', 1);
|
credentialsModal.getters.oauthConnectButton().should('have.length', 1);
|
||||||
|
@ -467,7 +466,7 @@ describe('AI Assistant Credential Help', () => {
|
||||||
wf.actions.addNodeToCanvas('Microsoft Outlook', true, true, 'Get a calendar');
|
wf.actions.addNodeToCanvas('Microsoft Outlook', true, true, 'Get a calendar');
|
||||||
wf.getters.nodeCredentialsSelect().should('exist');
|
wf.getters.nodeCredentialsSelect().should('exist');
|
||||||
wf.getters.nodeCredentialsSelect().click();
|
wf.getters.nodeCredentialsSelect().click();
|
||||||
getVisibleSelect().find('li').last().click();
|
wf.getters.nodeCredentialsCreateOption().click();
|
||||||
ndv.getters.copyInput().should('not.exist');
|
ndv.getters.copyInput().should('not.exist');
|
||||||
credentialsModal.getters.oauthConnectButton().should('have.length', 1);
|
credentialsModal.getters.oauthConnectButton().should('have.length', 1);
|
||||||
credentialsModal.getters.credentialInputs().should('have.length', 1);
|
credentialsModal.getters.credentialInputs().should('have.length', 1);
|
||||||
|
|
|
@ -136,6 +136,12 @@ defineExpose({
|
||||||
<template v-if="$slots.suffix" #suffix>
|
<template v-if="$slots.suffix" #suffix>
|
||||||
<slot name="suffix" />
|
<slot name="suffix" />
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="$slots.footer" #footer>
|
||||||
|
<slot name="footer" />
|
||||||
|
</template>
|
||||||
|
<template v-if="$slots.empty" #empty>
|
||||||
|
<slot name="empty" />
|
||||||
|
</template>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</ElSelect>
|
</ElSelect>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
// Danger
|
// Danger
|
||||||
--color-danger-shade-1: var(--prim-color-alt-c-shade-100);
|
--color-danger-shade-1: var(--prim-color-alt-c-shade-100);
|
||||||
--color-danger: var(--prim-color-alt-c);
|
--color-danger: var(--prim-color-alt-c);
|
||||||
|
--color-danger-light: var(--prim-color-alt-c-tint-150);
|
||||||
|
--color-danger-light-2: var(--prim-color-alt-c-tint-250);
|
||||||
--color-danger-tint-1: var(--prim-color-alt-c-tint-400);
|
--color-danger-tint-1: var(--prim-color-alt-c-tint-400);
|
||||||
--color-danger-tint-2: var(--prim-color-alt-c-tint-450);
|
--color-danger-tint-2: var(--prim-color-alt-c-tint-450);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { describe, it } from 'vitest';
|
import { describe, it } from 'vitest';
|
||||||
import { fireEvent, screen } from '@testing-library/vue';
|
import { screen } from '@testing-library/vue';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
import { createTestingPinia } from '@pinia/testing';
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
import NodeCredentials from './NodeCredentials.vue';
|
import NodeCredentials from './NodeCredentials.vue';
|
||||||
import type { RenderOptions } from '@/__tests__/render';
|
import type { RenderOptions } from '@/__tests__/render';
|
||||||
|
@ -8,6 +9,7 @@ import { useCredentialsStore } from '@/stores/credentials.store';
|
||||||
import { mockedStore } from '@/__tests__/utils';
|
import { mockedStore } from '@/__tests__/utils';
|
||||||
import type { INodeUi } from '@/Interface';
|
import type { INodeUi } from '@/Interface';
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
|
import { useUIStore } from '../stores/ui.store';
|
||||||
|
|
||||||
const httpNode: INodeUi = {
|
const httpNode: INodeUi = {
|
||||||
parameters: {
|
parameters: {
|
||||||
|
@ -67,6 +69,7 @@ describe('NodeCredentials', () => {
|
||||||
|
|
||||||
const credentialsStore = mockedStore(useCredentialsStore);
|
const credentialsStore = mockedStore(useCredentialsStore);
|
||||||
const ndvStore = mockedStore(useNDVStore);
|
const ndvStore = mockedStore(useNDVStore);
|
||||||
|
const uiStore = mockedStore(useUIStore);
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
credentialsStore.state.credentialTypes = {
|
credentialsStore.state.credentialTypes = {
|
||||||
|
@ -120,7 +123,7 @@ describe('NodeCredentials', () => {
|
||||||
|
|
||||||
const credentialsSelect = screen.getByTestId('node-credentials-select');
|
const credentialsSelect = screen.getByTestId('node-credentials-select');
|
||||||
|
|
||||||
await fireEvent.click(credentialsSelect);
|
await userEvent.click(credentialsSelect);
|
||||||
|
|
||||||
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
|
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
@ -150,7 +153,7 @@ describe('NodeCredentials', () => {
|
||||||
|
|
||||||
const credentialsSelect = screen.getByTestId('node-credentials-select');
|
const credentialsSelect = screen.getByTestId('node-credentials-select');
|
||||||
|
|
||||||
await fireEvent.click(credentialsSelect);
|
await userEvent.click(credentialsSelect);
|
||||||
|
|
||||||
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
|
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('OpenAi account 2')).not.toBeInTheDocument();
|
expect(screen.queryByText('OpenAi account 2')).not.toBeInTheDocument();
|
||||||
|
@ -188,9 +191,69 @@ describe('NodeCredentials', () => {
|
||||||
|
|
||||||
const credentialsSelect = screen.getByTestId('node-credentials-select');
|
const credentialsSelect = screen.getByTestId('node-credentials-select');
|
||||||
|
|
||||||
await fireEvent.click(credentialsSelect);
|
await userEvent.click(credentialsSelect);
|
||||||
|
|
||||||
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
|
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('OpenAi account 2')).toBeInTheDocument();
|
expect(screen.queryByText('OpenAi account 2')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should filter available credentials in the dropdown', async () => {
|
||||||
|
ndvStore.activeNode = httpNode;
|
||||||
|
credentialsStore.state.credentials = {
|
||||||
|
c8vqdPpPClh4TgIO: {
|
||||||
|
id: 'c8vqdPpPClh4TgIO',
|
||||||
|
name: 'OpenAi account',
|
||||||
|
type: 'openAiApi',
|
||||||
|
isManaged: false,
|
||||||
|
createdAt: '',
|
||||||
|
updatedAt: '',
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
id: 'test',
|
||||||
|
name: 'Test OpenAi account',
|
||||||
|
type: 'openAiApi',
|
||||||
|
isManaged: false,
|
||||||
|
createdAt: '',
|
||||||
|
updatedAt: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
renderComponent();
|
||||||
|
|
||||||
|
const credentialsSelect = screen.getByTestId('node-credentials-select');
|
||||||
|
|
||||||
|
await userEvent.click(credentialsSelect);
|
||||||
|
|
||||||
|
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Test OpenAi account')).toBeInTheDocument();
|
||||||
|
|
||||||
|
const credentialSearch = credentialsSelect.querySelector('input') as HTMLElement;
|
||||||
|
await userEvent.type(credentialSearch, 'test');
|
||||||
|
|
||||||
|
expect(screen.queryByText('OpenAi account')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Test OpenAi account')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open the new credential modal when clicked', async () => {
|
||||||
|
ndvStore.activeNode = httpNode;
|
||||||
|
credentialsStore.state.credentials = {
|
||||||
|
c8vqdPpPClh4TgIO: {
|
||||||
|
id: 'c8vqdPpPClh4TgIO',
|
||||||
|
name: 'OpenAi account',
|
||||||
|
type: 'openAiApi',
|
||||||
|
isManaged: false,
|
||||||
|
createdAt: '',
|
||||||
|
updatedAt: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
renderComponent();
|
||||||
|
|
||||||
|
const credentialsSelect = screen.getByTestId('node-credentials-select');
|
||||||
|
|
||||||
|
await userEvent.click(credentialsSelect);
|
||||||
|
await userEvent.click(screen.getByTestId('node-credentials-select-item-new'));
|
||||||
|
|
||||||
|
expect(uiStore.openNewCredential).toHaveBeenCalledWith('openAiApi', true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
import type { ICredentialsResponse, INodeUi, INodeUpdatePropertiesInformation } from '@/Interface';
|
import type { ICredentialsResponse, INodeUi, INodeUpdatePropertiesInformation } from '@/Interface';
|
||||||
import {
|
import {
|
||||||
HTTP_REQUEST_NODE_TYPE,
|
HTTP_REQUEST_NODE_TYPE,
|
||||||
|
type ICredentialType,
|
||||||
type INodeCredentialDescription,
|
type INodeCredentialDescription,
|
||||||
type INodeCredentialsDetails,
|
type INodeCredentialsDetails,
|
||||||
type NodeParameterValueType,
|
type NodeParameterValueType,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
|
@ -31,6 +32,7 @@ import {
|
||||||
updateNodeAuthType,
|
updateNodeAuthType,
|
||||||
} from '@/utils/nodeTypesUtils';
|
} from '@/utils/nodeTypesUtils';
|
||||||
import {
|
import {
|
||||||
|
N8nIcon,
|
||||||
N8nInput,
|
N8nInput,
|
||||||
N8nInputLabel,
|
N8nInputLabel,
|
||||||
N8nOption,
|
N8nOption,
|
||||||
|
@ -67,7 +69,7 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const NEW_CREDENTIALS_TEXT = `- ${i18n.baseText('nodeCredentials.createNew')} -`;
|
const NEW_CREDENTIALS_TEXT = i18n.baseText('nodeCredentials.createNew');
|
||||||
|
|
||||||
const credentialsStore = useCredentialsStore();
|
const credentialsStore = useCredentialsStore();
|
||||||
const nodeTypesStore = useNodeTypesStore();
|
const nodeTypesStore = useNodeTypesStore();
|
||||||
|
@ -79,7 +81,9 @@ const nodeHelpers = useNodeHelpers();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const subscribedToCredentialType = ref('');
|
const subscribedToCredentialType = ref('');
|
||||||
|
const filter = ref('');
|
||||||
const listeningForAuthChange = ref(false);
|
const listeningForAuthChange = ref(false);
|
||||||
|
const selectRefs = ref<Array<InstanceType<typeof N8nSelect>>>([]);
|
||||||
|
|
||||||
const credentialTypesNode = computed(() =>
|
const credentialTypesNode = computed(() =>
|
||||||
credentialTypesNodeDescription.value.map(
|
credentialTypesNodeDescription.value.map(
|
||||||
|
@ -344,9 +348,8 @@ function onCredentialSelected(
|
||||||
credentialId: string | null | undefined,
|
credentialId: string | null | undefined,
|
||||||
showAuthOptions = false,
|
showAuthOptions = false,
|
||||||
) {
|
) {
|
||||||
const newCredentialOptionSelected = credentialId === NEW_CREDENTIALS_TEXT;
|
if (!credentialId) {
|
||||||
if (!credentialId || newCredentialOptionSelected) {
|
createNewCredential(credentialType, false, showAuthOptions);
|
||||||
createNewCredential(credentialType, newCredentialOptionSelected, showAuthOptions);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,6 +504,20 @@ function getCredentialsFieldLabel(credentialType: INodeCredentialDescription): s
|
||||||
}
|
}
|
||||||
return i18n.baseText('nodeCredentials.credentialsLabel');
|
return i18n.baseText('nodeCredentials.credentialsLabel');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setFilter(newFilter = '') {
|
||||||
|
filter.value = newFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
function matches(needle: string, haystack: string) {
|
||||||
|
return haystack.toLocaleLowerCase().includes(needle);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onClickCreateCredential(type: ICredentialType | INodeCredentialDescription) {
|
||||||
|
selectRefs.value.forEach((select) => select.blur());
|
||||||
|
await nextTick();
|
||||||
|
createNewCredential(type.name, true, showMixedCredentials(type));
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -530,16 +547,20 @@ function getCredentialsFieldLabel(credentialType: INodeCredentialDescription): s
|
||||||
data-test-id="node-credentials-select"
|
data-test-id="node-credentials-select"
|
||||||
>
|
>
|
||||||
<N8nSelect
|
<N8nSelect
|
||||||
|
ref="selectRefs"
|
||||||
:model-value="getSelectedId(type.name)"
|
:model-value="getSelectedId(type.name)"
|
||||||
:placeholder="getSelectPlaceholder(type.name, getIssues(type.name))"
|
:placeholder="getSelectPlaceholder(type.name, getIssues(type.name))"
|
||||||
size="small"
|
size="small"
|
||||||
|
filterable
|
||||||
|
:filter-method="setFilter"
|
||||||
|
:popper-class="$style.selectPopper"
|
||||||
@update:model-value="
|
@update:model-value="
|
||||||
(value: string) => onCredentialSelected(type.name, value, showMixedCredentials(type))
|
(value: string) => onCredentialSelected(type.name, value, showMixedCredentials(type))
|
||||||
"
|
"
|
||||||
@blur="emit('blur', 'credentials')"
|
@blur="emit('blur', 'credentials')"
|
||||||
>
|
>
|
||||||
<N8nOption
|
<N8nOption
|
||||||
v-for="item in options"
|
v-for="item in options.filter((o) => matches(filter, o.name))"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:data-test-id="`node-credentials-select-item-${item.id}`"
|
:data-test-id="`node-credentials-select-item-${item.id}`"
|
||||||
:label="item.name"
|
:label="item.name"
|
||||||
|
@ -550,13 +571,17 @@ function getCredentialsFieldLabel(credentialType: INodeCredentialDescription): s
|
||||||
<N8nText size="small">{{ item.typeDisplayName }}</N8nText>
|
<N8nText size="small">{{ item.typeDisplayName }}</N8nText>
|
||||||
</div>
|
</div>
|
||||||
</N8nOption>
|
</N8nOption>
|
||||||
<N8nOption
|
<template #empty> </template>
|
||||||
:key="NEW_CREDENTIALS_TEXT"
|
<template #footer>
|
||||||
data-test-id="node-credentials-select-item-new"
|
<div
|
||||||
:value="NEW_CREDENTIALS_TEXT"
|
data-test-id="node-credentials-select-item-new"
|
||||||
:label="NEW_CREDENTIALS_TEXT"
|
:class="['clickable', $style.newCredential]"
|
||||||
>
|
@click="onClickCreateCredential(type)"
|
||||||
</N8nOption>
|
>
|
||||||
|
<N8nIcon size="xsmall" icon="plus" />
|
||||||
|
<N8nText bold>{{ NEW_CREDENTIALS_TEXT }}</N8nText>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</N8nSelect>
|
</N8nSelect>
|
||||||
|
|
||||||
<div v-if="getIssues(type.name).length && !hideIssues" :class="$style.warning">
|
<div v-if="getIssues(type.name).length && !hideIssues" :class="$style.warning">
|
||||||
|
@ -567,7 +592,7 @@ function getCredentialsFieldLabel(credentialType: INodeCredentialDescription): s
|
||||||
:items="getIssues(type.name)"
|
:items="getIssues(type.name)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<font-awesome-icon icon="exclamation-triangle" />
|
<N8nIcon icon="exclamation-triangle" />
|
||||||
</N8nTooltip>
|
</N8nTooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -576,7 +601,7 @@ function getCredentialsFieldLabel(credentialType: INodeCredentialDescription): s
|
||||||
:class="$style.edit"
|
:class="$style.edit"
|
||||||
data-test-id="credential-edit-button"
|
data-test-id="credential-edit-button"
|
||||||
>
|
>
|
||||||
<font-awesome-icon
|
<N8nIcon
|
||||||
icon="pen"
|
icon="pen"
|
||||||
class="clickable"
|
class="clickable"
|
||||||
:title="i18n.baseText('nodeCredentials.updateCredential')"
|
:title="i18n.baseText('nodeCredentials.updateCredential')"
|
||||||
|
@ -598,10 +623,25 @@ function getCredentialsFieldLabel(credentialType: INodeCredentialDescription): s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selectPopper {
|
||||||
|
:global(.el-select-dropdown__list) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:has(.newCredential:hover) :global(.hover) {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:has(li)) .newCredential {
|
||||||
|
border-top: none;
|
||||||
|
box-shadow: none;
|
||||||
|
border-radius: var(--border-radius-base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.warning {
|
.warning {
|
||||||
min-width: 20px;
|
margin-left: var(--spacing-4xs);
|
||||||
margin-left: 5px;
|
color: var(--color-danger-light);
|
||||||
color: #ff8080;
|
|
||||||
font-size: var(--font-size-s);
|
font-size: var(--font-size-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,8 +650,7 @@ function getCredentialsFieldLabel(credentialType: INodeCredentialDescription): s
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: var(--color-text-base);
|
color: var(--color-text-base);
|
||||||
min-width: 20px;
|
margin-left: var(--spacing-3xs);
|
||||||
margin-left: 5px;
|
|
||||||
font-size: var(--font-size-s);
|
font-size: var(--font-size-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,4 +668,21 @@ function getCredentialsFieldLabel(credentialType: INodeCredentialDescription): s
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.newCredential {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-3xs);
|
||||||
|
align-items: center;
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
padding: var(--spacing-xs) var(--spacing-m);
|
||||||
|
background-color: var(--color-background-light);
|
||||||
|
|
||||||
|
border-top: var(--border-base);
|
||||||
|
box-shadow: var(--box-shadow-light);
|
||||||
|
clip-path: inset(-12px 0 0 0); // Only show box shadow on top
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import TitledList from '@/components/TitledList.vue';
|
import TitledList from '@/components/TitledList.vue';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
|
import { N8nTooltip, N8nIcon } from 'n8n-design-system';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
issues: string[];
|
issues: string[];
|
||||||
|
@ -11,22 +12,21 @@ const i18n = useI18n();
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="issues.length" :class="$style['parameter-issues']" data-test-id="parameter-issues">
|
<div v-if="issues.length" :class="$style['parameter-issues']" data-test-id="parameter-issues">
|
||||||
<n8n-tooltip placement="top">
|
<N8nTooltip placement="top">
|
||||||
<template #content>
|
<template #content>
|
||||||
<TitledList :title="`${i18n.baseText('parameterInput.issues')}:`" :items="issues" />
|
<TitledList :title="`${i18n.baseText('parameterInput.issues')}:`" :items="issues" />
|
||||||
</template>
|
</template>
|
||||||
<font-awesome-icon icon="exclamation-triangle" />
|
<N8nIcon icon="exclamation-triangle" />
|
||||||
</n8n-tooltip>
|
</N8nTooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style module lang="scss">
|
<style module lang="scss">
|
||||||
.parameter-issues {
|
.parameter-issues {
|
||||||
width: 20px;
|
|
||||||
text-align: right;
|
text-align: right;
|
||||||
float: right;
|
float: right;
|
||||||
color: #ff8080;
|
color: var(--color-danger-light);
|
||||||
font-size: var(--font-size-s);
|
font-size: var(--font-size-s);
|
||||||
padding-left: var(--spacing-4xs);
|
padding-left: var(--spacing-3xs);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -597,7 +597,6 @@
|
||||||
"credentialsList.confirmMessage.confirmButtonText": "Yes, delete",
|
"credentialsList.confirmMessage.confirmButtonText": "Yes, delete",
|
||||||
"credentialsList.confirmMessage.headline": "Delete Credential?",
|
"credentialsList.confirmMessage.headline": "Delete Credential?",
|
||||||
"credentialsList.confirmMessage.message": "Are you sure you want to delete {credentialName}?",
|
"credentialsList.confirmMessage.message": "Are you sure you want to delete {credentialName}?",
|
||||||
"credentialsList.createNewCredential": "Create New Credential",
|
|
||||||
"credentialsList.created": "Created",
|
"credentialsList.created": "Created",
|
||||||
"credentialsList.credentials": "Credentials",
|
"credentialsList.credentials": "Credentials",
|
||||||
"credentialsList.deleteCredential": "Delete Credential",
|
"credentialsList.deleteCredential": "Delete Credential",
|
||||||
|
@ -1187,7 +1186,7 @@
|
||||||
"nodeCreator.aiPanel.workflowTriggerDescription": "Runs the flow when called by the Execute Workflow node from a different workflow",
|
"nodeCreator.aiPanel.workflowTriggerDescription": "Runs the flow when called by the Execute Workflow node from a different workflow",
|
||||||
"nodeCreator.nodeItem.triggerIconTitle": "Trigger Node",
|
"nodeCreator.nodeItem.triggerIconTitle": "Trigger Node",
|
||||||
"nodeCreator.nodeItem.aiIconTitle": "LangChain AI Node",
|
"nodeCreator.nodeItem.aiIconTitle": "LangChain AI Node",
|
||||||
"nodeCredentials.createNew": "Create New Credential",
|
"nodeCredentials.createNew": "Create new credential",
|
||||||
"nodeCredentials.credentialFor": "Credential for {credentialType}",
|
"nodeCredentials.credentialFor": "Credential for {credentialType}",
|
||||||
"nodeCredentials.credentialsLabel": "Credential to connect with",
|
"nodeCredentials.credentialsLabel": "Credential to connect with",
|
||||||
"nodeCredentials.issues": "Issues",
|
"nodeCredentials.issues": "Issues",
|
||||||
|
|
Loading…
Reference in a new issue