mirror of
https://github.com/n8n-io/n8n.git
synced 2024-09-19 22:37:31 -07:00
Compare commits
47 commits
c0e4c4b3c8
...
925e5096af
Author | SHA1 | Date | |
---|---|---|---|
925e5096af | |||
48294e7ec1 | |||
fdef6c9f0d | |||
8fb31e8459 | |||
cee57b6504 | |||
f5474ff791 | |||
b86fd80fc9 | |||
aa6cfa07ef | |||
69c6e0790d | |||
91008b2676 | |||
ee7147c6b3 | |||
0a317b7072 | |||
05ae2aa9c5 | |||
a7d24d9dac | |||
2a084f96f8 | |||
73f89ef101 | |||
d2eb7998bd | |||
4568969e1f | |||
08ebe1e480 | |||
ab83c4b416 | |||
df8b2c0694 | |||
4f0a1a953f | |||
5a1db6db1a | |||
c1d88f3bb3 | |||
44e5fb9b06 | |||
989f69d1f4 | |||
aa283b7554 | |||
c43aef1a26 | |||
430c14ad19 | |||
3c15890a5b | |||
0b5299a248 | |||
d65ade4e92 | |||
a3335e0ecd | |||
aa00d9c2ae | |||
c55df63abc | |||
6a35812f92 | |||
57836cc17a | |||
a63a9b53f0 | |||
d81e72b6c7 | |||
9c95db8282 | |||
acb4194fa1 | |||
5a2c7e00a0 | |||
e0c0ddee59 | |||
c6b2beadf2 | |||
55b99a815b | |||
9d6356b194 | |||
220c590b23 |
|
@ -9,7 +9,7 @@
|
|||
"type=bind,source=${localEnv:HOME}/.n8n,target=/home/node/.n8n,consistency=cached"
|
||||
],
|
||||
"forwardPorts": [8080, 5678],
|
||||
"postCreateCommand": "corepack prepare --activate && pnpm install ",
|
||||
"postCreateCommand": "corepack prepare --activate && pnpm install",
|
||||
"postAttachCommand": "pnpm build",
|
||||
"customizations": {
|
||||
"codespaces": {
|
||||
|
|
3
.github/workflows/ci-pull-requests.yml
vendored
3
.github/workflows/ci-pull-requests.yml
vendored
|
@ -30,6 +30,9 @@ jobs:
|
|||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Run formatcheck
|
||||
run: pnpm format:check
|
||||
|
||||
- name: Run typecheck
|
||||
run: pnpm typecheck
|
||||
|
||||
|
|
|
@ -7,3 +7,11 @@ packages/nodes-base/nodes/**/test
|
|||
packages/cli/templates/form-trigger.handlebars
|
||||
cypress/fixtures
|
||||
CHANGELOG.md
|
||||
.github/pull_request_template.md
|
||||
# Ignored for now
|
||||
**/*.md
|
||||
# Handled by biome
|
||||
**/*.ts
|
||||
**/*.js
|
||||
**/*.json
|
||||
**/*.jsonc
|
||||
|
|
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"biomejs.biome",
|
||||
"streetsidesoftware.code-spell-checker",
|
||||
"dangmai.workspace-default-settings",
|
||||
"dbaeumer.vscode-eslint",
|
||||
|
|
16
.vscode/settings.default.json
vendored
16
.vscode/settings.default.json
vendored
|
@ -1,6 +1,22 @@
|
|||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"quickfix.biome": "explicit",
|
||||
"source.organizeImports.biome": "never"
|
||||
},
|
||||
"search.exclude": {
|
||||
"node_modules": true,
|
||||
"dist": true,
|
||||
|
|
39
CHANGELOG.md
39
CHANGELOG.md
|
@ -1,3 +1,42 @@
|
|||
# [1.60.0](https://github.com/n8n-io/n8n/compare/n8n@1.59.0...n8n@1.60.0) (2024-09-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Azure OpenAI Chat Model Node:** Add response format option ([#10851](https://github.com/n8n-io/n8n/issues/10851)) ([0b5299a](https://github.com/n8n-io/n8n/commit/0b5299a248fdd451ceabb98ff6a2b38e818d02f8))
|
||||
* **Contentful Node:** Add missing additional fields to entry > get ([#10830](https://github.com/n8n-io/n8n/issues/10830)) ([c43aef1](https://github.com/n8n-io/n8n/commit/c43aef1a266cc6ccf8f778c290f8cb8ba2ee28cf))
|
||||
* **core:** Prevent shutdown error in regular mode ([#10844](https://github.com/n8n-io/n8n/issues/10844)) ([acb4194](https://github.com/n8n-io/n8n/commit/acb4194fa1a1d0497dd1f48045f069e1db28c432))
|
||||
* **core:** Restore queue listeners for `webhook` process ([#10781](https://github.com/n8n-io/n8n/issues/10781)) ([86f4877](https://github.com/n8n-io/n8n/commit/86f4877bab978a1ec2f53df23b6c515507cd8f72))
|
||||
* **editor:** Add missing node parameter values to AI Assistant request ([#10788](https://github.com/n8n-io/n8n/issues/10788)) ([d65ade4](https://github.com/n8n-io/n8n/commit/d65ade4e92eed3cfc47854d493fac6885a1a852b))
|
||||
* **editor:** Address edge toolbar rendering glitches ([#10839](https://github.com/n8n-io/n8n/issues/10839)) ([e0c0dde](https://github.com/n8n-io/n8n/commit/e0c0ddee59e889f50dd5033d0a933bad60fb7e3a))
|
||||
* **editor:** Allow custom git repo urls in source control settings ([#10849](https://github.com/n8n-io/n8n/issues/10849)) ([a63a9b5](https://github.com/n8n-io/n8n/commit/a63a9b53f06d3a00e8e76c0ab9f2571604c01922))
|
||||
* **editor:** Fix completion on $input.item. in Code node ([#10800](https://github.com/n8n-io/n8n/issues/10800)) ([45dccf3](https://github.com/n8n-io/n8n/commit/45dccf3d0c8282987833962a8e3f3a77d256ea37))
|
||||
* **editor:** Make expression edit modal read-only in executions view ([#10806](https://github.com/n8n-io/n8n/issues/10806)) ([394ef88](https://github.com/n8n-io/n8n/commit/394ef888433b1d48593531ab9eea93a3c3ae6040))
|
||||
* **editor:** Make schema view search copy more clear ([#10807](https://github.com/n8n-io/n8n/issues/10807)) ([7f1c131](https://github.com/n8n-io/n8n/commit/7f1c131b72ad1b98b4a8c976b8a0ef5d963d5f1f))
|
||||
* **editor:** Minimap Show nodes outside viewport ([#10843](https://github.com/n8n-io/n8n/issues/10843)) ([9c95db8](https://github.com/n8n-io/n8n/commit/9c95db8282c9f3cef5568aa9793ca977d4d8a347))
|
||||
* **editor:** Prevent clipboard XSS injection ([#10805](https://github.com/n8n-io/n8n/issues/10805)) ([db846d3](https://github.com/n8n-io/n8n/commit/db846d3235a360b4b729312b6ffe0d75be08fd45))
|
||||
* **editor:** Render image binary-data using img tags ([#10829](https://github.com/n8n-io/n8n/issues/10829)) ([7c23101](https://github.com/n8n-io/n8n/commit/7c23101ab8c12b735a17deb35637f3f12c00aeb0))
|
||||
* **editor:** Replace v-html with custom directive to sanitize html ([#10804](https://github.com/n8n-io/n8n/issues/10804)) ([44e5fb9](https://github.com/n8n-io/n8n/commit/44e5fb9b06c794033204ef1744b54b3b87160082))
|
||||
* **editor:** Restore V1 keybinding, Space Key to toggle panning ([#10841](https://github.com/n8n-io/n8n/issues/10841)) ([5a1db6d](https://github.com/n8n-io/n8n/commit/5a1db6db1adad43887e839181719818474bc66b0))
|
||||
* Fix telemetry causing console error ([#10828](https://github.com/n8n-io/n8n/issues/10828)) ([3be31e2](https://github.com/n8n-io/n8n/commit/3be31e27edc6e71400bde23f992ba98b2365bcff))
|
||||
* **Google Vertex Chat Model Node:** Clean service account private key ([#10770](https://github.com/n8n-io/n8n/issues/10770)) ([e6d84db](https://github.com/n8n-io/n8n/commit/e6d84db89930afc16f4a08fae87d8af4a059e6d7))
|
||||
* **HTTP Request Tool Node:** Fix subsequent tool calls reusung the same options ([#10808](https://github.com/n8n-io/n8n/issues/10808)) ([d647ef4](https://github.com/n8n-io/n8n/commit/d647ef41acf672177ea5e8ce0e99d78c565e34b2))
|
||||
* **OpenAI Node, Basic LLM Chain Node, Tool Agent Node:** Better OpenAI API rate limit errors ([#10797](https://github.com/n8n-io/n8n/issues/10797)) ([ab83c4b](https://github.com/n8n-io/n8n/commit/ab83c4b4166d5ad5f4ca46a636f83c8802fe3ec0))
|
||||
* Prevent copying workflow when copying outside of canvas ([#10813](https://github.com/n8n-io/n8n/issues/10813)) ([22c1890](https://github.com/n8n-io/n8n/commit/22c1890139c89e74df67b9673a1d0c85d647eb9d))
|
||||
* **RSS Feed Trigger Node:** Handle empty items gracefully ([#10855](https://github.com/n8n-io/n8n/issues/10855)) ([c55df63](https://github.com/n8n-io/n8n/commit/c55df63abc234ace6ac8e54ed094d10797671264))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **core:** Allow customizing max file size in form-data payloads for webhooks ([#10857](https://github.com/n8n-io/n8n/issues/10857)) ([a3335e0](https://github.com/n8n-io/n8n/commit/a3335e0ecd3796c874985d3c6fbbaabc35dc3490))
|
||||
* **core:** Introduce worker metrics ([#10850](https://github.com/n8n-io/n8n/issues/10850)) ([08ebe1e](https://github.com/n8n-io/n8n/commit/08ebe1e4807b3d7b4a4840887cbb30f547a5c89a))
|
||||
* **editor:** Add truncate directive ([#10842](https://github.com/n8n-io/n8n/issues/10842)) ([57836cc](https://github.com/n8n-io/n8n/commit/57836cc17a57c790d2ffb2463abb16a03321eb59))
|
||||
* **editor:** Show Collaboration pane only when there are multiple active users ([#10772](https://github.com/n8n-io/n8n/issues/10772)) ([a0af1d9](https://github.com/n8n-io/n8n/commit/a0af1d9a06c78d29f215dc010332ea7c8f28717d))
|
||||
* **Invoice Ninja Node:** Add actions for bank transactions ([#10389](https://github.com/n8n-io/n8n/issues/10389)) ([5a2c7e0](https://github.com/n8n-io/n8n/commit/5a2c7e00a0ca1a151a7fec56da5f99b086c25b1f))
|
||||
* **OpenAI Node:** Include O1 models in the models select ([#10801](https://github.com/n8n-io/n8n/issues/10801)) ([b2b1abc](https://github.com/n8n-io/n8n/commit/b2b1abc5319bdbf2bc855649ea27359b22aba009))
|
||||
|
||||
|
||||
|
||||
# [1.59.0](https://github.com/n8n-io/n8n/compare/n8n@1.58.0...n8n@1.59.0) (2024-09-11)
|
||||
|
||||
|
||||
|
|
48
biome.jsonc
Normal file
48
biome.jsonc
Normal file
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
||||
"vcs": {
|
||||
"clientKind": "git",
|
||||
"enabled": true,
|
||||
"useIgnoreFile": true
|
||||
},
|
||||
"files": {
|
||||
"ignore": [
|
||||
"**/.turbo",
|
||||
"**/coverage",
|
||||
"**/dist",
|
||||
"**/package.json",
|
||||
"**/pnpm-lock.yaml",
|
||||
"**/CHANGELOG.md"
|
||||
]
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "tab",
|
||||
"indentWidth": 2,
|
||||
"lineEnding": "lf",
|
||||
"lineWidth": 100,
|
||||
"attributePosition": "auto",
|
||||
"ignore": [
|
||||
// Handled by prettier
|
||||
"**/*.vue"
|
||||
]
|
||||
},
|
||||
"organizeImports": { "enabled": false },
|
||||
"linter": {
|
||||
"enabled": false
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"jsxQuoteStyle": "double",
|
||||
"quoteProperties": "asNeeded",
|
||||
"trailingCommas": "all",
|
||||
"semicolons": "always",
|
||||
"arrowParentheses": "always",
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": false,
|
||||
"quoteStyle": "single",
|
||||
"attributePosition": "auto"
|
||||
}
|
||||
}
|
||||
}
|
7
cypress/biome.jsonc
Normal file
7
cypress/biome.jsonc
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "../node_modules/@biomejs/biome/configuration_schema.json",
|
||||
"extends": ["../biome.jsonc"],
|
||||
"formatter": {
|
||||
"ignore": ["fixtures/**"]
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { ROUTES } from '../constants';
|
||||
import { getManualChatModal } from './modals/chat-modal';
|
||||
import { ROUTES } from '../constants';
|
||||
|
||||
/**
|
||||
* Types
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { WorkflowsPage as WorkflowsPageClass } from '../pages/workflows';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
import { WorkflowsPage as WorkflowsPageClass } from '../pages/workflows';
|
||||
import { getUniqueWorkflowName } from '../utils/workflowUtils';
|
||||
|
||||
const WorkflowsPage = new WorkflowsPageClass();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { SettingsLogStreamingPage } from '../pages';
|
||||
import { getVisibleModalOverlay } from '../utils/modal';
|
||||
import { getVisibleDropdown } from '../utils';
|
||||
import { getVisibleModalOverlay } from '../utils/modal';
|
||||
|
||||
const settingsLogStreamingPage = new SettingsLogStreamingPage();
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ import {
|
|||
SET_NODE_NAME,
|
||||
EDIT_FIELDS_SET_NODE_NAME,
|
||||
} from '../constants';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
import { MessageBox as MessageBoxClass } from '../pages/modals/message-box';
|
||||
import { NDV } from '../pages/ndv';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
|
||||
// Suite-specific constants
|
||||
const CODE_NODE_NEW_NAME = 'Something else';
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
import { successToast } from '../pages/notifications';
|
||||
import {
|
||||
MANUAL_TRIGGER_NODE_NAME,
|
||||
MANUAL_TRIGGER_NODE_DISPLAY_NAME,
|
||||
|
@ -9,6 +7,8 @@ import {
|
|||
IF_NODE_NAME,
|
||||
HTTP_REQUEST_NODE_NAME,
|
||||
} from './../constants';
|
||||
import { successToast } from '../pages/notifications';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
|
||||
const WorkflowPage = new WorkflowPageClass();
|
||||
describe('Canvas Actions', () => {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
import { NDV, WorkflowExecutionsTab } from '../pages';
|
||||
import {
|
||||
MANUAL_TRIGGER_NODE_NAME,
|
||||
MANUAL_TRIGGER_NODE_DISPLAY_NAME,
|
||||
|
@ -9,6 +7,8 @@ import {
|
|||
SWITCH_NODE_NAME,
|
||||
MERGE_NODE_NAME,
|
||||
} from './../constants';
|
||||
import { NDV, WorkflowExecutionsTab } from '../pages';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
|
||||
const WorkflowPage = new WorkflowPageClass();
|
||||
const ExecutionsTab = new WorkflowExecutionsTab();
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { WorkflowPage, NDV } from '../pages';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
import {
|
||||
MANUAL_TRIGGER_NODE_NAME,
|
||||
MANUAL_TRIGGER_NODE_DISPLAY_NAME,
|
||||
SCHEDULE_TRIGGER_NODE_NAME,
|
||||
} from './../constants';
|
||||
import { WorkflowPage, NDV } from '../pages';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
|
||||
const workflowPage = new WorkflowPage();
|
||||
const ndv = new NDV();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { nanoid } from 'nanoid';
|
||||
|
||||
import { BACKEND_BASE_URL, EDIT_FIELDS_SET_NODE_NAME } from '../constants';
|
||||
import { WorkflowPage, NDV, CredentialsModal } from '../pages';
|
||||
import { cowBase64 } from '../support/binaryTestFiles';
|
||||
import { BACKEND_BASE_URL, EDIT_FIELDS_SET_NODE_NAME } from '../constants';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
|
||||
const workflowPage = new WorkflowPage();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import * as projects from '../composables/projects';
|
||||
import { INSTANCE_MEMBERS, INSTANCE_OWNER, INSTANCE_ADMIN, NOTION_NODE_NAME } from '../constants';
|
||||
import {
|
||||
CredentialsModal,
|
||||
|
@ -8,7 +9,6 @@ import {
|
|||
WorkflowsPage,
|
||||
} from '../pages';
|
||||
import { getVisibleDropdown, getVisiblePopper, getVisibleSelect } from '../utils';
|
||||
import * as projects from '../composables/projects';
|
||||
|
||||
/**
|
||||
* User U1 - Instance owner
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { INSTANCE_MEMBERS, INSTANCE_OWNER, INSTANCE_ADMIN } from '../constants';
|
||||
import { MainSidebar, SettingsSidebar, SettingsUsersPage } from '../pages';
|
||||
import { errorToast, successToast } from '../pages/notifications';
|
||||
import { PersonalSettingsPage } from '../pages/settings-personal';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
import { errorToast, successToast } from '../pages/notifications';
|
||||
|
||||
/**
|
||||
* User A - Instance owner
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { NDV, WorkflowExecutionsTab, WorkflowPage as WorkflowPageClass } from '../pages';
|
||||
import { SCHEDULE_TRIGGER_NODE_NAME, EDIT_FIELDS_SET_NODE_NAME } from '../constants';
|
||||
import { NDV, WorkflowExecutionsTab, WorkflowPage as WorkflowPageClass } from '../pages';
|
||||
import { clearNotifications, errorToast, successToast } from '../pages/notifications';
|
||||
|
||||
const workflowPage = new WorkflowPageClass();
|
||||
|
@ -503,7 +503,7 @@ describe('Execution', () => {
|
|||
|
||||
workflowPage.getters.clearExecutionDataButton().should('be.visible');
|
||||
|
||||
cy.intercept('POST', '/rest/workflows/**/run').as('workflowRun');
|
||||
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowRun');
|
||||
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('do something with them')
|
||||
|
@ -525,7 +525,7 @@ describe('Execution', () => {
|
|||
|
||||
workflowPage.getters.zoomToFitButton().click();
|
||||
|
||||
cy.intercept('POST', '/rest/workflows/**/run').as('workflowRun');
|
||||
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowRun');
|
||||
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('If')
|
||||
|
@ -547,7 +547,7 @@ describe('Execution', () => {
|
|||
|
||||
workflowPage.getters.clearExecutionDataButton().should('be.visible');
|
||||
|
||||
cy.intercept('POST', '/rest/workflows/**/run').as('workflowRun');
|
||||
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowRun');
|
||||
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('NoOp2')
|
||||
|
@ -576,7 +576,7 @@ describe('Execution', () => {
|
|||
it('should successfully execute partial executions with nodes attached to the second output', () => {
|
||||
cy.createFixtureWorkflow('Test_Workflow_pairedItem_incomplete_manual_bug.json');
|
||||
|
||||
cy.intercept('POST', '/rest/workflows/**/run').as('workflowRun');
|
||||
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowRun');
|
||||
|
||||
workflowPage.getters.zoomToFitButton().click();
|
||||
workflowPage.getters.executeWorkflowButton().click();
|
||||
|
@ -596,7 +596,7 @@ describe('Execution', () => {
|
|||
it('should execute workflow partially up to the node that has issues', () => {
|
||||
cy.createFixtureWorkflow('Test_workflow_partial_execution_with_missing_credentials.json');
|
||||
|
||||
cy.intercept('POST', '/rest/workflows/**/run').as('workflowRun');
|
||||
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowRun');
|
||||
|
||||
workflowPage.getters.zoomToFitButton().click();
|
||||
workflowPage.getters.executeWorkflowButton().click();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { type ICredentialType } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
AGENT_NODE_NAME,
|
||||
AI_TOOL_HTTP_NODE_NAME,
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import type { RouteHandler } from 'cypress/types/net-stubbing';
|
||||
|
||||
import executionOutOfMemoryServerResponse from '../fixtures/responses/execution-out-of-memory-server-response.json';
|
||||
import { WorkflowPage } from '../pages';
|
||||
import { WorkflowExecutionsTab } from '../pages/workflow-executions-tab';
|
||||
import executionOutOfMemoryServerResponse from '../fixtures/responses/execution-out-of-memory-server-response.json';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
|
||||
const workflowPage = new WorkflowPage();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import type { ICredentialType } from 'n8n-workflow';
|
||||
import { NodeCreator } from '../pages/features/node-creator';
|
||||
import CustomNodeFixture from '../fixtures/Custom_node.json';
|
||||
import { CredentialsModal, WorkflowPage } from '../pages';
|
||||
import CustomNodeWithN8nCredentialFixture from '../fixtures/Custom_node_n8n_credential.json';
|
||||
import CustomNodeWithCustomCredentialFixture from '../fixtures/Custom_node_custom_credential.json';
|
||||
|
||||
import CustomCredential from '../fixtures/Custom_credential.json';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
import CustomNodeFixture from '../fixtures/Custom_node.json';
|
||||
import CustomNodeWithCustomCredentialFixture from '../fixtures/Custom_node_custom_credential.json';
|
||||
import CustomNodeWithN8nCredentialFixture from '../fixtures/Custom_node_n8n_credential.json';
|
||||
import { CredentialsModal, WorkflowPage } from '../pages';
|
||||
import { NodeCreator } from '../pages/features/node-creator';
|
||||
import {
|
||||
confirmCommunityNodeUninstall,
|
||||
confirmCommunityNodeUpdate,
|
||||
|
@ -13,6 +13,7 @@ import {
|
|||
installFirstCommunityNode,
|
||||
visitCommunityNodesSettings,
|
||||
} from '../pages/settings-community-nodes';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
|
||||
const credentialsModal = new CredentialsModal();
|
||||
const nodeCreatorFeature = new NodeCreator();
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
import type { ExecutionError } from 'n8n-workflow/src';
|
||||
import { NDV, WorkflowPage as WorkflowPageClass } from '../pages';
|
||||
|
||||
import {
|
||||
closeManualChatModal,
|
||||
getManualChatMessages,
|
||||
getManualChatModalLogs,
|
||||
getManualChatModalLogsEntries,
|
||||
sendManualChatMessage,
|
||||
} from '../composables/modals/chat-modal';
|
||||
import { setCredentialValues } from '../composables/modals/credential-modal';
|
||||
import {
|
||||
clickCreateNewCredential,
|
||||
clickExecuteNode,
|
||||
clickGetBackToCanvas,
|
||||
} from '../composables/ndv';
|
||||
import {
|
||||
addLanguageModelNodeToParent,
|
||||
addMemoryNodeToParent,
|
||||
|
@ -18,19 +31,7 @@ import {
|
|||
MANUAL_TRIGGER_NODE_DISPLAY_NAME,
|
||||
MANUAL_TRIGGER_NODE_NAME,
|
||||
} from '../constants';
|
||||
import {
|
||||
clickCreateNewCredential,
|
||||
clickExecuteNode,
|
||||
clickGetBackToCanvas,
|
||||
} from '../composables/ndv';
|
||||
import { setCredentialValues } from '../composables/modals/credential-modal';
|
||||
import {
|
||||
closeManualChatModal,
|
||||
getManualChatMessages,
|
||||
getManualChatModalLogs,
|
||||
getManualChatModalLogsEntries,
|
||||
sendManualChatMessage,
|
||||
} from '../composables/modals/chat-modal';
|
||||
import { NDV, WorkflowPage as WorkflowPageClass } from '../pages';
|
||||
import { createMockNodeExecutionData, getVisibleSelect, runMockWorkflowExecution } from '../utils';
|
||||
|
||||
const ndv = new NDV();
|
||||
|
|
|
@ -227,7 +227,7 @@ describe('NDV', () => {
|
|||
|
||||
workflowPage.actions.zoomToFit();
|
||||
|
||||
/* prettier-ignore */
|
||||
// biome-ignore format:
|
||||
const PINNED_DATA = [
|
||||
{
|
||||
"id": "abc",
|
||||
|
@ -263,7 +263,6 @@ describe('NDV', () => {
|
|||
]
|
||||
}
|
||||
];
|
||||
/* prettier-ignore */
|
||||
workflowPage.actions.openNode('Get thread details1');
|
||||
ndv.actions.pastePinnedData(PINNED_DATA);
|
||||
ndv.actions.close();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import planData from '../fixtures/Plan_data_opt_in_trial.json';
|
||||
import {
|
||||
BannerStack,
|
||||
MainSidebar,
|
||||
|
@ -5,7 +6,6 @@ import {
|
|||
visitPublicApiPage,
|
||||
getPublicApiUpgradeCTA,
|
||||
} from '../pages';
|
||||
import planData from '../fixtures/Plan_data_opt_in_trial.json';
|
||||
|
||||
const mainSidebar = new MainSidebar();
|
||||
const bannerStack = new BannerStack();
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import generateOTPToken from 'cypress-otp';
|
||||
|
||||
import { MainSidebar } from './../pages/sidebar/main-sidebar';
|
||||
import { INSTANCE_OWNER, INSTANCE_ADMIN, BACKEND_BASE_URL } from '../constants';
|
||||
import { SigninPage } from '../pages';
|
||||
import { PersonalSettingsPage } from '../pages/settings-personal';
|
||||
import { MfaLoginPage } from '../pages/mfa-login';
|
||||
import { MainSidebar } from './../pages/sidebar/main-sidebar';
|
||||
import { PersonalSettingsPage } from '../pages/settings-personal';
|
||||
|
||||
const MFA_SECRET = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD';
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ describe('Debug', () => {
|
|||
it('should be able to debug executions', () => {
|
||||
cy.intercept('GET', '/rest/executions?filter=*').as('getExecutions');
|
||||
cy.intercept('GET', '/rest/executions/*').as('getExecution');
|
||||
cy.intercept('POST', '/rest/workflows/**/run').as('postWorkflowRun');
|
||||
cy.intercept('POST', '/rest/workflows/**/run?**').as('postWorkflowRun');
|
||||
|
||||
cy.signinAsOwner();
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import OnboardingWorkflow from '../fixtures/Onboarding_workflow.json';
|
||||
import WorkflowTemplate from '../fixtures/Workflow_template_write_http_query.json';
|
||||
import { MainSidebar } from '../pages/sidebar/main-sidebar';
|
||||
import { TemplatesPage } from '../pages/templates';
|
||||
import { WorkflowPage } from '../pages/workflow';
|
||||
import { WorkflowsPage } from '../pages/workflows';
|
||||
import { MainSidebar } from '../pages/sidebar/main-sidebar';
|
||||
import OnboardingWorkflow from '../fixtures/Onboarding_workflow.json';
|
||||
import WorkflowTemplate from '../fixtures/Workflow_template_write_http_query.json';
|
||||
|
||||
const templatesPage = new TemplatesPage();
|
||||
const workflowPage = new WorkflowPage();
|
||||
|
|
|
@ -142,7 +142,7 @@ describe('Editor actions should work', () => {
|
|||
it('after switching between Editor and Debug', () => {
|
||||
cy.intercept('GET', '/rest/executions?filter=*').as('getExecutions');
|
||||
cy.intercept('GET', '/rest/executions/*').as('getExecution');
|
||||
cy.intercept('POST', '/rest/workflows/**/run').as('postWorkflowRun');
|
||||
cy.intercept('POST', '/rest/workflows/**/run?**').as('postWorkflowRun');
|
||||
|
||||
editWorkflowAndDeactivate();
|
||||
workflowPage.actions.executeWorkflow();
|
||||
|
|
|
@ -1,4 +1,34 @@
|
|||
import { createMockNodeExecutionData, runMockWorkflowExecution } from '../utils';
|
||||
import {
|
||||
AGENT_NODE_NAME,
|
||||
MANUAL_CHAT_TRIGGER_NODE_NAME,
|
||||
AI_LANGUAGE_MODEL_OPENAI_CHAT_MODEL_NODE_NAME,
|
||||
MANUAL_TRIGGER_NODE_NAME,
|
||||
AI_MEMORY_WINDOW_BUFFER_MEMORY_NODE_NAME,
|
||||
AI_TOOL_CALCULATOR_NODE_NAME,
|
||||
AI_OUTPUT_PARSER_AUTO_FIXING_NODE_NAME,
|
||||
AI_TOOL_CODE_NODE_NAME,
|
||||
AI_TOOL_WIKIPEDIA_NODE_NAME,
|
||||
BASIC_LLM_CHAIN_NODE_NAME,
|
||||
EDIT_FIELDS_SET_NODE_NAME,
|
||||
CHAT_TRIGGER_NODE_DISPLAY_NAME,
|
||||
} from './../constants';
|
||||
import {
|
||||
closeManualChatModal,
|
||||
getManualChatDialog,
|
||||
getManualChatMessages,
|
||||
getManualChatModal,
|
||||
getManualChatModalLogs,
|
||||
getManualChatModalLogsEntries,
|
||||
getManualChatModalLogsTree,
|
||||
sendManualChatMessage,
|
||||
} from '../composables/modals/chat-modal';
|
||||
import { setCredentialValues } from '../composables/modals/credential-modal';
|
||||
import {
|
||||
clickCreateNewCredential,
|
||||
clickExecuteNode,
|
||||
clickGetBackToCanvas,
|
||||
toggleParameterCheckboxInputByName,
|
||||
} from '../composables/ndv';
|
||||
import {
|
||||
addLanguageModelNodeToParent,
|
||||
addMemoryNodeToParent,
|
||||
|
@ -14,37 +44,7 @@ import {
|
|||
openNode,
|
||||
getConnectionBySourceAndTarget,
|
||||
} from '../composables/workflow';
|
||||
import {
|
||||
clickCreateNewCredential,
|
||||
clickExecuteNode,
|
||||
clickGetBackToCanvas,
|
||||
toggleParameterCheckboxInputByName,
|
||||
} from '../composables/ndv';
|
||||
import { setCredentialValues } from '../composables/modals/credential-modal';
|
||||
import {
|
||||
closeManualChatModal,
|
||||
getManualChatDialog,
|
||||
getManualChatMessages,
|
||||
getManualChatModal,
|
||||
getManualChatModalLogs,
|
||||
getManualChatModalLogsEntries,
|
||||
getManualChatModalLogsTree,
|
||||
sendManualChatMessage,
|
||||
} from '../composables/modals/chat-modal';
|
||||
import {
|
||||
AGENT_NODE_NAME,
|
||||
MANUAL_CHAT_TRIGGER_NODE_NAME,
|
||||
AI_LANGUAGE_MODEL_OPENAI_CHAT_MODEL_NODE_NAME,
|
||||
MANUAL_TRIGGER_NODE_NAME,
|
||||
AI_MEMORY_WINDOW_BUFFER_MEMORY_NODE_NAME,
|
||||
AI_TOOL_CALCULATOR_NODE_NAME,
|
||||
AI_OUTPUT_PARSER_AUTO_FIXING_NODE_NAME,
|
||||
AI_TOOL_CODE_NODE_NAME,
|
||||
AI_TOOL_WIKIPEDIA_NODE_NAME,
|
||||
BASIC_LLM_CHAIN_NODE_NAME,
|
||||
EDIT_FIELDS_SET_NODE_NAME,
|
||||
CHAT_TRIGGER_NODE_DISPLAY_NAME,
|
||||
} from './../constants';
|
||||
import { createMockNodeExecutionData, runMockWorkflowExecution } from '../utils';
|
||||
|
||||
describe('Langchain Integration', () => {
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import workflow from '../fixtures/Manual_wait_set.json';
|
||||
import { importWorkflow, visitDemoPage } from '../pages/demo';
|
||||
import { WorkflowPage } from '../pages/workflow';
|
||||
import { errorToast } from '../pages/notifications';
|
||||
import { WorkflowPage } from '../pages/workflow';
|
||||
|
||||
const workflowPage = new WorkflowPage();
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
import * as setupCredsModal from '../composables/modals/workflow-credential-setup-modal';
|
||||
import * as formStep from '../composables/setup-template-form-step';
|
||||
import { getSetupWorkflowCredentialsButton } from '../composables/setup-workflow-credentials-button';
|
||||
import TestTemplate1 from '../fixtures/Test_Template_1.json';
|
||||
import TestTemplate2 from '../fixtures/Test_Template_2.json';
|
||||
import {
|
||||
clickUseWorkflowButtonByTitle,
|
||||
visitTemplateCollectionPage,
|
||||
|
@ -5,11 +10,6 @@ import {
|
|||
} from '../pages/template-collection';
|
||||
import * as templateCredentialsSetupPage from '../pages/template-credential-setup';
|
||||
import { WorkflowPage } from '../pages/workflow';
|
||||
import * as formStep from '../composables/setup-template-form-step';
|
||||
import { getSetupWorkflowCredentialsButton } from '../composables/setup-workflow-credentials-button';
|
||||
import * as setupCredsModal from '../composables/modals/workflow-credential-setup-modal';
|
||||
import TestTemplate1 from '../fixtures/Test_Template_1.json';
|
||||
import TestTemplate2 from '../fixtures/Test_Template_2.json';
|
||||
|
||||
const workflowPage = new WorkflowPage();
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { WorkflowsPage } from '../pages/workflows';
|
||||
import {
|
||||
closeVersionUpdatesPanel,
|
||||
getVersionCard,
|
||||
getVersionUpdatesPanelOpenButton,
|
||||
openVersionUpdatesPanel,
|
||||
} from '../composables/versions';
|
||||
import { WorkflowsPage } from '../pages/workflows';
|
||||
|
||||
const workflowsPage = new WorkflowsPage();
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import * as projects from '../composables/projects';
|
||||
import { INSTANCE_MEMBERS, MANUAL_TRIGGER_NODE_NAME, NOTION_NODE_NAME } from '../constants';
|
||||
import {
|
||||
WorkflowsPage,
|
||||
|
@ -8,7 +9,6 @@ import {
|
|||
NDV,
|
||||
MainSidebar,
|
||||
} from '../pages';
|
||||
import * as projects from '../composables/projects';
|
||||
import { getVisibleDropdown, getVisibleModalOverlay, getVisibleSelect } from '../utils';
|
||||
|
||||
const workflowsPage = new WorkflowsPage();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { NodeCreator } from '../pages/features/node-creator';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
import { NDV } from '../pages/ndv';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
import { IF_NODE_NAME } from '../constants';
|
||||
import { NodeCreator } from '../pages/features/node-creator';
|
||||
import { NDV } from '../pages/ndv';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
|
||||
const nodeCreatorFeature = new NodeCreator();
|
||||
const WorkflowPage = new WorkflowPageClass();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { WorkflowsPage as WorkflowsPageClass } from '../pages/workflows';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
import { EDIT_FIELDS_SET_NODE_NAME } from '../constants';
|
||||
import { getSaveChangesModal } from '../composables/modals/save-changes-modal';
|
||||
import { EDIT_FIELDS_SET_NODE_NAME } from '../constants';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
import { WorkflowsPage as WorkflowsPageClass } from '../pages/workflows';
|
||||
|
||||
const WorkflowsPage = new WorkflowsPageClass();
|
||||
const WorkflowPage = new WorkflowPageClass();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { setCredentialValues } from '../composables/modals/credential-modal';
|
||||
import { clickCreateNewCredential } from '../composables/ndv';
|
||||
import { MANUAL_TRIGGER_NODE_DISPLAY_NAME, NOTION_NODE_NAME } from '../constants';
|
||||
import { NDV, WorkflowPage } from '../pages';
|
||||
import { NodeCreator } from '../pages/features/node-creator';
|
||||
import { clickCreateNewCredential } from '../composables/ndv';
|
||||
import { setCredentialValues } from '../composables/modals/credential-modal';
|
||||
|
||||
const workflowPage = new WorkflowPage();
|
||||
const ndv = new NDV();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { nanoid } from 'nanoid';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
|
||||
import { NDV } from '../pages/ndv';
|
||||
import { successToast } from '../pages/notifications';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
|
||||
const WorkflowPage = new WorkflowPageClass();
|
||||
const ndv = new NDV();
|
||||
|
@ -43,7 +44,9 @@ describe('Code node', () => {
|
|||
const getParameter = () => ndv.getters.parameterInput('jsCode').should('be.visible');
|
||||
const getEditor = () => getParameter().find('.cm-content').should('exist');
|
||||
|
||||
getEditor().type('{selectall}').paste(`$input.itemMatching()
|
||||
getEditor()
|
||||
.type('{selectall}')
|
||||
.paste(`$input.itemMatching()
|
||||
$input.item
|
||||
$('When clicking ‘Test workflow’').item
|
||||
$input.first(1)
|
||||
|
@ -68,7 +71,9 @@ return
|
|||
|
||||
ndv.getters.parameterInput('mode').click();
|
||||
ndv.actions.selectOptionInParameterDropdown('mode', 'Run Once for Each Item');
|
||||
getEditor().type('{selectall}').paste(`$input.itemMatching()
|
||||
getEditor()
|
||||
.type('{selectall}')
|
||||
.paste(`$input.itemMatching()
|
||||
$input.all()
|
||||
$input.first()
|
||||
$input.item()
|
||||
|
|
|
@ -5,11 +5,11 @@ import {
|
|||
EDIT_FIELDS_SET_NODE_NAME,
|
||||
NOTION_NODE_NAME,
|
||||
} from '../constants';
|
||||
import { WorkflowExecutionsTab } from '../pages';
|
||||
import { errorToast, successToast } from '../pages/notifications';
|
||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||
import { WorkflowsPage as WorkflowsPageClass } from '../pages/workflows';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
import { WorkflowExecutionsTab } from '../pages';
|
||||
import { errorToast, successToast } from '../pages/notifications';
|
||||
|
||||
const NEW_WORKFLOW_NAME = 'Something else';
|
||||
const DUPLICATE_WORKFLOW_NAME = 'Duplicated workflow';
|
||||
|
|
|
@ -7,13 +7,15 @@
|
|||
"test:e2e:ui": "scripts/run-e2e.js ui",
|
||||
"test:e2e:dev": "scripts/run-e2e.js dev",
|
||||
"test:e2e:all": "scripts/run-e2e.js all",
|
||||
"format": "prettier --write . --ignore-path ../.prettierignore",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"develop": "cd ..; pnpm dev",
|
||||
"start": "cd ..; pnpm start"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@n8n/api-types": "workspace:*",
|
||||
"@types/lodash": "catalog:",
|
||||
"eslint-plugin-cypress": "^3.3.0",
|
||||
"n8n-workflow": "workspace:*"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { N8N_AUTH_COOKIE } from '../constants';
|
||||
import { BasePage } from './base';
|
||||
import { SigninPage } from './signin';
|
||||
import { WorkflowsPage } from './workflows';
|
||||
import { N8N_AUTH_COOKIE } from '../constants';
|
||||
|
||||
export class MfaLoginPage extends BasePage {
|
||||
url = '/mfa';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BasePage } from '../base';
|
||||
import { getVisibleSelect } from '../../utils';
|
||||
import { BasePage } from '../base';
|
||||
|
||||
export class CredentialsModal extends BasePage {
|
||||
getters = {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { getVisiblePopper, getVisibleSelect } from '../utils';
|
||||
import { BasePage } from './base';
|
||||
import { getVisiblePopper, getVisibleSelect } from '../utils';
|
||||
|
||||
export class NDV extends BasePage {
|
||||
getters = {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { getVisibleSelect } from '../utils';
|
||||
import { BasePage } from './base';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
|
||||
export class SettingsLogStreamingPage extends BasePage {
|
||||
url = '/settings/log-streaming';
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import generateOTPToken from 'cypress-otp';
|
||||
|
||||
import { BasePage } from './base';
|
||||
import { ChangePasswordModal } from './modals/change-password-modal';
|
||||
import { MfaSetupModal } from './modals/mfa-setup-modal';
|
||||
import { BasePage } from './base';
|
||||
|
||||
const changePasswordModal = new ChangePasswordModal();
|
||||
const mfaSetupModal = new MfaSetupModal();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { SettingsSidebar } from './sidebar/settings-sidebar';
|
||||
import { BasePage } from './base';
|
||||
import { MainSidebar } from './sidebar/main-sidebar';
|
||||
import { SettingsSidebar } from './sidebar/settings-sidebar';
|
||||
import { WorkflowPage } from './workflow';
|
||||
import { WorkflowsPage } from './workflows';
|
||||
import { BasePage } from './base';
|
||||
|
||||
const workflowPage = new WorkflowPage();
|
||||
const workflowsPage = new WorkflowsPage();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { N8N_AUTH_COOKIE } from '../constants';
|
||||
import { BasePage } from './base';
|
||||
import { WorkflowsPage } from './workflows';
|
||||
import { N8N_AUTH_COOKIE } from '../constants';
|
||||
|
||||
export class SigninPage extends BasePage {
|
||||
url = '/signin';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as formStep from '../composables/setup-template-form-step';
|
||||
import { overrideFeatureFlag } from '../composables/featureFlags';
|
||||
import { CredentialsModal, MessageBox } from './modals';
|
||||
import { overrideFeatureFlag } from '../composables/featureFlags';
|
||||
import * as formStep from '../composables/setup-template-form-step';
|
||||
|
||||
const credentialsModal = new CredentialsModal();
|
||||
const messageBox = new MessageBox();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { BasePage } from './base';
|
||||
|
||||
import Chainable = Cypress.Chainable;
|
||||
|
||||
export class VariablesPage extends BasePage {
|
||||
|
|
|
@ -35,7 +35,7 @@ export class WorkflowExecutionsTab extends BasePage {
|
|||
},
|
||||
createManualExecutions: (count: number) => {
|
||||
for (let i = 0; i < count; i++) {
|
||||
cy.intercept('POST', '/rest/workflows/**/run').as('workflowExecution');
|
||||
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowExecution');
|
||||
workflowPage.actions.executeWorkflow();
|
||||
cy.wait('@workflowExecution');
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { BasePage } from './base';
|
||||
import { NodeCreator } from './features/node-creator';
|
||||
import { META_KEY } from '../constants';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
import { getUniqueWorkflowName } from '../utils/workflowUtils';
|
||||
import { BasePage } from './base';
|
||||
import { NodeCreator } from './features/node-creator';
|
||||
|
||||
const nodeCreator = new NodeCreator();
|
||||
export class WorkflowPage extends BasePage {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'cypress-real-events';
|
||||
import type { FrontendSettings } from '@n8n/api-types';
|
||||
import FakeTimers from '@sinonjs/fake-timers';
|
||||
import type { IN8nUISettings } from 'n8n-workflow';
|
||||
import { WorkflowPage } from '../pages';
|
||||
|
||||
import {
|
||||
BACKEND_BASE_URL,
|
||||
INSTANCE_ADMIN,
|
||||
|
@ -9,6 +9,7 @@ import {
|
|||
INSTANCE_OWNER,
|
||||
N8N_AUTH_COOKIE,
|
||||
} from '../constants';
|
||||
import { WorkflowPage } from '../pages';
|
||||
import { getUniqueWorkflowName } from '../utils/workflowUtils';
|
||||
|
||||
Cypress.Commands.add('setAppDate', (targetDate: number | Date) => {
|
||||
|
@ -86,8 +87,8 @@ Cypress.Commands.add('signout', () => {
|
|||
cy.getCookie(N8N_AUTH_COOKIE).should('not.exist');
|
||||
});
|
||||
|
||||
export let settings: Partial<IN8nUISettings>;
|
||||
Cypress.Commands.add('overrideSettings', (value: Partial<IN8nUISettings>) => {
|
||||
export let settings: Partial<FrontendSettings>;
|
||||
Cypress.Commands.add('overrideSettings', (value: Partial<FrontendSettings>) => {
|
||||
settings = value;
|
||||
});
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import merge from 'lodash/merge';
|
||||
|
||||
import { settings } from './commands';
|
||||
|
||||
before(() => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Load type definitions that come with Cypress module
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import type { IN8nUISettings } from 'n8n-workflow';
|
||||
import type { FrontendSettings } from '@n8n/api-types';
|
||||
|
||||
Cypress.Keyboard.defaults({
|
||||
keystrokeDelay: 0,
|
||||
|
@ -45,7 +45,7 @@ declare global {
|
|||
*/
|
||||
signinAsMember(index?: number): void;
|
||||
signout(): void;
|
||||
overrideSettings(value: Partial<IN8nUISettings>): void;
|
||||
overrideSettings(value: Partial<FrontendSettings>): void;
|
||||
enableFeature(feature: string): void;
|
||||
disableFeature(feature: string): void;
|
||||
enableQueueMode(): void;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { nanoid } from 'nanoid';
|
||||
import type { IDataObject, IPinData, ITaskData, ITaskDataConnections } from 'n8n-workflow';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
import { clickExecuteWorkflowButton } from '../composables/workflow';
|
||||
|
||||
export function createMockNodeExecutionData(
|
||||
|
@ -88,7 +89,7 @@ export function runMockWorkflowExecution({
|
|||
}) {
|
||||
const executionId = nanoid(8);
|
||||
|
||||
cy.intercept('POST', '/rest/workflows/**/run', {
|
||||
cy.intercept('POST', '/rest/workflows/**/run?**', {
|
||||
statusCode: 201,
|
||||
body: {
|
||||
data: {
|
||||
|
|
|
@ -6,7 +6,7 @@ FROM --platform=linux/amd64 n8nio/base:${NODE_VERSION} AS builder
|
|||
# Build the application from source
|
||||
WORKDIR /src
|
||||
COPY . /src
|
||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store --mount=type=cache,id=pnpm-metadata,target=/root/.cache/pnpm/metadata pnpm install --frozen-lockfile
|
||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store --mount=type=cache,id=pnpm-metadata,target=/root/.cache/pnpm/metadata DOCKER_BUILD=true pnpm install --frozen-lockfile
|
||||
RUN pnpm build
|
||||
|
||||
# Delete all dev dependencies
|
||||
|
@ -18,7 +18,7 @@ RUN find . -type f -name "*.ts" -o -name "*.js.map" -o -name "*.vue" -o -name "t
|
|||
|
||||
# Deploy the `n8n` package into /compiled
|
||||
RUN mkdir /compiled
|
||||
RUN NODE_ENV=production pnpm --filter=n8n --prod --no-optional deploy /compiled
|
||||
RUN NODE_ENV=production DOCKER_BUILD=true pnpm --filter=n8n --prod --no-optional deploy /compiled
|
||||
|
||||
# 2. Start with a new clean image with just the code that is needed to run n8n
|
||||
FROM n8nio/base:${NODE_VERSION}
|
||||
|
|
16
lefthook.yml
Normal file
16
lefthook.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
pre-commit:
|
||||
commands:
|
||||
biome_check:
|
||||
glob: 'packages/**/*.{js,ts,json}'
|
||||
run: ./node_modules/.bin/biome check --write --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files}
|
||||
stage_fixed: true
|
||||
skip:
|
||||
- merge
|
||||
- rebase
|
||||
prettier_check:
|
||||
glob: 'packages/**/*.{vue,yml,md}'
|
||||
run: ./node_modules/.bin/prettier --write --ignore-unknown --no-error-on-unmatched-pattern {staged_files}
|
||||
stage_fixed: true
|
||||
skip:
|
||||
- merge
|
||||
- rebase
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": ".",
|
||||
},
|
||||
],
|
||||
"path": "."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n-monorepo",
|
||||
"version": "1.59.0",
|
||||
"version": "1.60.0",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=20.15",
|
||||
|
@ -8,6 +8,7 @@
|
|||
},
|
||||
"packageManager": "pnpm@9.6.0",
|
||||
"scripts": {
|
||||
"prepare": "node scripts/prepare.mjs",
|
||||
"preinstall": "node scripts/block-npm-install.js",
|
||||
"build": "turbo run build",
|
||||
"build:backend": "turbo run build:backend",
|
||||
|
@ -19,6 +20,7 @@
|
|||
"clean": "turbo run clean --parallel",
|
||||
"reset": "node scripts/ensure-zx.mjs && zx scripts/reset.mjs",
|
||||
"format": "turbo run format && node scripts/format.mjs",
|
||||
"format:check": "turbo run format:check",
|
||||
"lint": "turbo run lint",
|
||||
"lintfix": "turbo run lintfix",
|
||||
"lint:backend": "turbo run lint:backend",
|
||||
|
@ -38,6 +40,7 @@
|
|||
"worker": "./packages/cli/bin/n8n worker"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.0",
|
||||
"@n8n_io/eslint-config": "workspace:*",
|
||||
"@types/jest": "^29.5.3",
|
||||
"@types/supertest": "^6.0.2",
|
||||
|
@ -46,6 +49,7 @@
|
|||
"jest-expect-message": "^1.1.3",
|
||||
"jest-mock": "^29.6.2",
|
||||
"jest-mock-extended": "^3.0.4",
|
||||
"lefthook": "^1.7.15",
|
||||
"nock": "^13.3.2",
|
||||
"nodemon": "^3.0.1",
|
||||
"p-limit": "^3.1.0",
|
||||
|
@ -68,7 +72,6 @@
|
|||
"chokidar": "3.5.2",
|
||||
"esbuild": "^0.20.2",
|
||||
"formidable": "3.5.1",
|
||||
"prettier": "^3.2.5",
|
||||
"pug": "^3.0.3",
|
||||
"semver": "^7.5.4",
|
||||
"tslib": "^2.6.2",
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"name": "@n8n/api-types",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist .turbo",
|
||||
"dev": "pnpm watch",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"format": "prettier --write . --ignore-path ../../../.prettierignore",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint .",
|
||||
"lintfix": "eslint . --fix",
|
||||
"watch": "tsc -p tsconfig.build.json --watch",
|
||||
|
|
172
packages/@n8n/api-types/src/frontend-settings.ts
Normal file
172
packages/@n8n/api-types/src/frontend-settings.ts
Normal file
|
@ -0,0 +1,172 @@
|
|||
import type { ExpressionEvaluatorType, LogLevel, WorkflowSettings } from 'n8n-workflow';
|
||||
|
||||
export interface IVersionNotificationSettings {
|
||||
enabled: boolean;
|
||||
endpoint: string;
|
||||
infoUrl: string;
|
||||
}
|
||||
|
||||
export interface ITelemetryClientConfig {
|
||||
url: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
export interface ITelemetrySettings {
|
||||
enabled: boolean;
|
||||
config?: ITelemetryClientConfig;
|
||||
}
|
||||
|
||||
export type AuthenticationMethod = 'email' | 'ldap' | 'saml';
|
||||
|
||||
export interface IUserManagementSettings {
|
||||
quota: number;
|
||||
showSetupOnFirstLoad?: boolean;
|
||||
smtpSetup: boolean;
|
||||
authenticationMethod: AuthenticationMethod;
|
||||
}
|
||||
|
||||
export interface FrontendSettings {
|
||||
isDocker?: boolean;
|
||||
databaseType: 'sqlite' | 'mariadb' | 'mysqldb' | 'postgresdb';
|
||||
endpointForm: string;
|
||||
endpointFormTest: string;
|
||||
endpointFormWaiting: string;
|
||||
endpointWebhook: string;
|
||||
endpointWebhookTest: string;
|
||||
saveDataErrorExecution: WorkflowSettings.SaveDataExecution;
|
||||
saveDataSuccessExecution: WorkflowSettings.SaveDataExecution;
|
||||
saveManualExecutions: boolean;
|
||||
saveExecutionProgress: boolean;
|
||||
executionTimeout: number;
|
||||
maxExecutionTimeout: number;
|
||||
workflowCallerPolicyDefaultOption: WorkflowSettings.CallerPolicy;
|
||||
oauthCallbackUrls: {
|
||||
oauth1: string;
|
||||
oauth2: string;
|
||||
};
|
||||
timezone: string;
|
||||
urlBaseWebhook: string;
|
||||
urlBaseEditor: string;
|
||||
versionCli: string;
|
||||
nodeJsVersion: string;
|
||||
concurrency: number;
|
||||
authCookie: {
|
||||
secure: boolean;
|
||||
};
|
||||
binaryDataMode: 'default' | 'filesystem' | 's3';
|
||||
releaseChannel: 'stable' | 'beta' | 'nightly' | 'dev';
|
||||
n8nMetadata?: {
|
||||
userId?: string;
|
||||
[key: string]: string | number | undefined;
|
||||
};
|
||||
versionNotifications: IVersionNotificationSettings;
|
||||
instanceId: string;
|
||||
telemetry: ITelemetrySettings;
|
||||
posthog: {
|
||||
enabled: boolean;
|
||||
apiHost: string;
|
||||
apiKey: string;
|
||||
autocapture: boolean;
|
||||
disableSessionRecording: boolean;
|
||||
debug: boolean;
|
||||
};
|
||||
personalizationSurveyEnabled: boolean;
|
||||
defaultLocale: string;
|
||||
userManagement: IUserManagementSettings;
|
||||
sso: {
|
||||
saml: {
|
||||
loginLabel: string;
|
||||
loginEnabled: boolean;
|
||||
};
|
||||
ldap: {
|
||||
loginLabel: string;
|
||||
loginEnabled: boolean;
|
||||
};
|
||||
};
|
||||
publicApi: {
|
||||
enabled: boolean;
|
||||
latestVersion: number;
|
||||
path: string;
|
||||
swaggerUi: {
|
||||
enabled: boolean;
|
||||
};
|
||||
};
|
||||
workflowTagsDisabled: boolean;
|
||||
logLevel: LogLevel;
|
||||
hiringBannerEnabled: boolean;
|
||||
previewMode: boolean;
|
||||
templates: {
|
||||
enabled: boolean;
|
||||
host: string;
|
||||
};
|
||||
missingPackages?: boolean;
|
||||
executionMode: 'regular' | 'queue';
|
||||
pushBackend: 'sse' | 'websocket';
|
||||
communityNodesEnabled: boolean;
|
||||
aiAssistant: {
|
||||
enabled: boolean;
|
||||
};
|
||||
deployment: {
|
||||
type: string;
|
||||
};
|
||||
isNpmAvailable: boolean;
|
||||
allowedModules: {
|
||||
builtIn?: string[];
|
||||
external?: string[];
|
||||
};
|
||||
enterprise: {
|
||||
sharing: boolean;
|
||||
ldap: boolean;
|
||||
saml: boolean;
|
||||
logStreaming: boolean;
|
||||
advancedExecutionFilters: boolean;
|
||||
variables: boolean;
|
||||
sourceControl: boolean;
|
||||
auditLogs: boolean;
|
||||
externalSecrets: boolean;
|
||||
showNonProdBanner: boolean;
|
||||
debugInEditor: boolean;
|
||||
binaryDataS3: boolean;
|
||||
workflowHistory: boolean;
|
||||
workerView: boolean;
|
||||
advancedPermissions: boolean;
|
||||
projects: {
|
||||
team: {
|
||||
limit: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
hideUsagePage: boolean;
|
||||
license: {
|
||||
planName?: string;
|
||||
consumerId: string;
|
||||
environment: 'development' | 'production' | 'staging';
|
||||
};
|
||||
variables: {
|
||||
limit: number;
|
||||
};
|
||||
expressions: {
|
||||
evaluator: ExpressionEvaluatorType;
|
||||
};
|
||||
mfa: {
|
||||
enabled: boolean;
|
||||
};
|
||||
banners: {
|
||||
dismissed: string[];
|
||||
};
|
||||
ai: {
|
||||
enabled: boolean;
|
||||
};
|
||||
workflowHistory: {
|
||||
pruneTime: number;
|
||||
licensePruneTime: number;
|
||||
};
|
||||
pruning: {
|
||||
isEnabled: boolean;
|
||||
maxAge: number;
|
||||
maxCount: number;
|
||||
};
|
||||
security: {
|
||||
blockFileAccessToN8nFiles: boolean;
|
||||
};
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
export type * from './datetime';
|
||||
export type * from './push';
|
||||
export type * from './scaling';
|
||||
export type * from './datetime';
|
||||
export type * from './frontend-settings';
|
||||
export type * from './user';
|
||||
|
||||
export type { Collaborator } from './push/collaboration';
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import type { ExecutionPushMessage } from './execution';
|
||||
import type { WorkflowPushMessage } from './workflow';
|
||||
import type { HotReloadPushMessage } from './hot-reload';
|
||||
import type { WorkerPushMessage } from './worker';
|
||||
import type { WebhookPushMessage } from './webhook';
|
||||
import type { CollaborationPushMessage } from './collaboration';
|
||||
import type { DebugPushMessage } from './debug';
|
||||
import type { ExecutionPushMessage } from './execution';
|
||||
import type { HotReloadPushMessage } from './hot-reload';
|
||||
import type { WebhookPushMessage } from './webhook';
|
||||
import type { WorkerPushMessage } from './worker';
|
||||
import type { WorkflowPushMessage } from './workflow';
|
||||
|
||||
export type PushMessage =
|
||||
| ExecutionPushMessage
|
||||
|
|
|
@ -33,6 +33,7 @@ COPY --chown=node:node ./packages/@n8n/benchmark/package.json /app/packages/@n8n
|
|||
COPY --chown=node:node ./patches /app/patches
|
||||
COPY --chown=node:node ./scripts /app/scripts
|
||||
|
||||
ENV DOCKER_BUILD=true
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# TS config files
|
||||
|
|
7
packages/@n8n/benchmark/biome.jsonc
Normal file
7
packages/@n8n/benchmark/biome.jsonc
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "../node_modules/@biomejs/biome/configuration_schema.json",
|
||||
"extends": ["../../../biome.jsonc"],
|
||||
"files": {
|
||||
"ignore": ["scripts/mock-api/**"]
|
||||
}
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
{
|
||||
"name": "@n8n/n8n-benchmark",
|
||||
"version": "1.3.0",
|
||||
"version": "1.4.0",
|
||||
"description": "Cli for running benchmark tests for n8n",
|
||||
"main": "dist/index",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint .",
|
||||
"lintfix": "eslint . --fix",
|
||||
"start": "./bin/n8n-benchmark",
|
||||
|
|
|
@ -3,8 +3,9 @@ import { check } from 'k6';
|
|||
|
||||
const apiBaseUrl = __ENV.API_BASE_URL;
|
||||
|
||||
const file = open(__ENV.SCRIPT_FILE_PATH, 'b');
|
||||
const filename = String(__ENV.SCRIPT_FILE_PATH).split('/').pop();
|
||||
// This creates a 2MB file (16 * 128 * 1024 = 2 * 1024 * 1024 = 2MB)
|
||||
const file = Array.from({ length: 128 * 1024 }, () => Math.random().toString().slice(2)).join('');
|
||||
const filename = 'test.bin';
|
||||
|
||||
export default function () {
|
||||
const data = {
|
||||
|
|
|
@ -37,6 +37,17 @@ else
|
|||
sudo chown -R "$CURRENT_USER":"$CURRENT_USER" /n8n
|
||||
fi
|
||||
|
||||
### Remove unneeded dependencies
|
||||
# TTY
|
||||
sudo systemctl disable getty@tty1.service
|
||||
sudo systemctl disable serial-getty@ttyS0.service
|
||||
# Snap
|
||||
sudo systemctl disable snapd.service
|
||||
# Unattended upgrades
|
||||
sudo systemctl disable unattended-upgrades.service
|
||||
# Cron
|
||||
sudo systemctl disable cron.service
|
||||
|
||||
# Include nodejs v20 repository
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
|
||||
sudo -E bash nodesource_setup.sh
|
||||
|
|
|
@ -78,6 +78,12 @@ async function runBenchmarksOnVm(config, benchmarkEnv) {
|
|||
const bootstrapScriptPath = path.join(scriptsDir, 'bootstrap.sh');
|
||||
await sshClient.ssh(`chmod a+x ${bootstrapScriptPath} && ${bootstrapScriptPath}`);
|
||||
|
||||
// Benchmarking the VM
|
||||
const vmBenchmarkScriptPath = path.join(scriptsDir, 'vm-benchmark.sh');
|
||||
await sshClient.ssh(`chmod a+x ${vmBenchmarkScriptPath} && ${vmBenchmarkScriptPath}`, {
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
// Give some time for the VM to be ready
|
||||
await sleep(1000);
|
||||
|
||||
|
|
13
packages/@n8n/benchmark/scripts/vm-benchmark.sh
Normal file
13
packages/@n8n/benchmark/scripts/vm-benchmark.sh
Normal file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Install fio
|
||||
DEBIAN_FRONTEND=noninteractive sudo apt-get -y install fio > /dev/null
|
||||
|
||||
# Run the disk benchmark
|
||||
fio --name=rand_rw --ioengine=libaio --rw=randrw --rwmixread=70 --bs=4k --numjobs=4 --size=1G --runtime=30 --directory=/n8n --group_reporting
|
||||
|
||||
# Remove files
|
||||
sudo rm /n8n/rand_rw.*
|
||||
|
||||
# Uninstall fio
|
||||
DEBIAN_FRONTEND=noninteractive sudo apt-get -y remove fio > /dev/null
|
|
@ -1,6 +1,7 @@
|
|||
import { Command } from '@oclif/core';
|
||||
import { ScenarioLoader } from '@/scenario/scenario-loader';
|
||||
|
||||
import { testScenariosPath } from '@/config/common-flags';
|
||||
import { ScenarioLoader } from '@/scenario/scenario-loader';
|
||||
|
||||
export default class ListCommand extends Command {
|
||||
static description = 'List all available scenarios';
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { Command, Flags } from '@oclif/core';
|
||||
import { ScenarioLoader } from '@/scenario/scenario-loader';
|
||||
import { ScenarioRunner } from '@/test-execution/scenario-runner';
|
||||
|
||||
import { testScenariosPath } from '@/config/common-flags';
|
||||
import { N8nApiClient } from '@/n8n-api-client/n8n-api-client';
|
||||
import { ScenarioDataFileLoader } from '@/scenario/scenario-data-loader';
|
||||
import { ScenarioLoader } from '@/scenario/scenario-loader';
|
||||
import type { K6Tag } from '@/test-execution/k6-executor';
|
||||
import { K6Executor } from '@/test-execution/k6-executor';
|
||||
import { testScenariosPath } from '@/config/common-flags';
|
||||
import { ScenarioRunner } from '@/test-execution/scenario-runner';
|
||||
|
||||
export default class RunCommand extends Command {
|
||||
static description = 'Run all (default) or specified test scenarios';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { AxiosRequestConfig } from 'axios';
|
||||
|
||||
import { N8nApiClient } from './n8n-api-client';
|
||||
|
||||
export class AuthenticatedN8nApiClient extends N8nApiClient {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { AuthenticatedN8nApiClient } from './authenticated-n8n-api-client';
|
||||
import type { Workflow } from '@/n8n-api-client/n8n-api-client.types';
|
||||
|
||||
import type { AuthenticatedN8nApiClient } from './authenticated-n8n-api-client';
|
||||
|
||||
export class WorkflowApiClient {
|
||||
constructor(private readonly apiClient: AuthenticatedN8nApiClient) {}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type { Scenario } from '@/types/scenario';
|
||||
|
||||
import type { Workflow } from '@/n8n-api-client/n8n-api-client.types';
|
||||
import type { Scenario } from '@/types/scenario';
|
||||
|
||||
/**
|
||||
* Loads scenario data files from FS
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { createHash } from 'node:crypto';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'path';
|
||||
import { createHash } from 'node:crypto';
|
||||
|
||||
import type { Scenario, ScenarioManifest } from '@/types/scenario';
|
||||
|
||||
export class ScenarioLoader {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import assert from 'node:assert/strict';
|
||||
import path from 'path';
|
||||
import { $, which, tmpfile } from 'zx';
|
||||
import type { Scenario } from '@/types/scenario';
|
||||
|
||||
import { buildTestReport, type K6Tag } from '@/test-execution/test-report';
|
||||
import type { Scenario } from '@/types/scenario';
|
||||
export type { K6Tag };
|
||||
|
||||
export type K6ExecutorOpts = {
|
||||
|
@ -76,7 +77,6 @@ export function handleSummary(data) {
|
|||
env: {
|
||||
API_BASE_URL: this.opts.n8nApiBaseUrl,
|
||||
K6_CLOUD_TOKEN: this.opts.k6ApiToken,
|
||||
SCRIPT_FILE_PATH: augmentedTestScriptPath,
|
||||
},
|
||||
stdio: 'inherit',
|
||||
})`${k6ExecutablePath} run ${flattedFlags} ${augmentedTestScriptPath}`;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import type { K6Executor } from './k6-executor';
|
||||
import type { Scenario } from '@/types/scenario';
|
||||
import { AuthenticatedN8nApiClient } from '@/n8n-api-client/authenticated-n8n-api-client';
|
||||
import type { N8nApiClient } from '@/n8n-api-client/n8n-api-client';
|
||||
import type { ScenarioDataFileLoader } from '@/scenario/scenario-data-loader';
|
||||
import { ScenarioDataImporter } from '@/test-execution/scenario-data-importer';
|
||||
import { AuthenticatedN8nApiClient } from '@/n8n-api-client/authenticated-n8n-api-client';
|
||||
import type { Scenario } from '@/types/scenario';
|
||||
|
||||
import type { K6Executor } from './k6-executor';
|
||||
|
||||
/**
|
||||
* Runs scenarios
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { nanoid } from 'nanoid';
|
||||
|
||||
import type { Scenario } from '@/types/scenario';
|
||||
|
||||
export type K6Tag = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@n8n/chat",
|
||||
"version": "0.25.0",
|
||||
"version": "0.26.0",
|
||||
"scripts": {
|
||||
"dev": "pnpm run storybook",
|
||||
"build": "pnpm build:vite && pnpm build:bundle",
|
||||
|
@ -12,7 +12,8 @@
|
|||
"typecheck": "vue-tsc --noEmit",
|
||||
"lint": "eslint . --ext .js,.ts,.vue --quiet",
|
||||
"lintfix": "eslint . --ext .js,.ts,.vue --fix",
|
||||
"format": "prettier --write src/",
|
||||
"format": "biome format --write src .storybook && prettier --write src/ --ignore-path ../../.prettierignore",
|
||||
"format:check": "biome ci src .storybook && prettier --check src/ --ignore-path ../../.prettierignore",
|
||||
"storybook": "storybook dev -p 6006 --no-open",
|
||||
"build:storybook": "storybook build"
|
||||
},
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed, onMounted } from 'vue';
|
||||
import hljs from 'highlight.js/lib/core';
|
||||
import hljsXML from 'highlight.js/lib/languages/xml';
|
||||
import hljsJavascript from 'highlight.js/lib/languages/javascript';
|
||||
import hljsXML from 'highlight.js/lib/languages/xml';
|
||||
import { computed, onMounted } from 'vue';
|
||||
|
||||
import { Chat, ChatWindow } from '@n8n/chat/components';
|
||||
import { useOptions } from '@n8n/chat/composables';
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import type { StoryObj } from '@storybook/vue3';
|
||||
import { onMounted } from 'vue';
|
||||
import type { ChatOptions } from '@n8n/chat/types';
|
||||
|
||||
import { createChat } from '@n8n/chat/index';
|
||||
import type { ChatOptions } from '@n8n/chat/types';
|
||||
|
||||
const webhookUrl = 'http://localhost:5678/webhook/f406671e-c954-4691-b39a-66c90aa2f103/chat';
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { fireEvent, waitFor } from '@testing-library/vue';
|
||||
|
||||
import {
|
||||
createFetchResponse,
|
||||
createGetLatestMessagesResponse,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { screen } from '@testing-library/vue';
|
||||
|
||||
import { defaultMountingTarget } from '@n8n/chat/constants';
|
||||
|
||||
export function getMountingTarget(target = defaultMountingTarget) {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import Close from 'virtual:icons/mdi/close';
|
||||
import { computed, nextTick, onMounted } from 'vue';
|
||||
import Layout from '@n8n/chat/components/Layout.vue';
|
||||
|
||||
import GetStarted from '@n8n/chat/components/GetStarted.vue';
|
||||
import GetStartedFooter from '@n8n/chat/components/GetStartedFooter.vue';
|
||||
import MessagesList from '@n8n/chat/components/MessagesList.vue';
|
||||
import Input from '@n8n/chat/components/Input.vue';
|
||||
import Layout from '@n8n/chat/components/Layout.vue';
|
||||
import MessagesList from '@n8n/chat/components/MessagesList.vue';
|
||||
import { useI18n, useChat, useOptions } from '@n8n/chat/composables';
|
||||
import { chatEventBus } from '@n8n/chat/event-buses';
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import IconFileText from 'virtual:icons/mdi/fileText';
|
||||
import IconFileMusic from 'virtual:icons/mdi/fileMusic';
|
||||
import IconFileImage from 'virtual:icons/mdi/fileImage';
|
||||
import IconFileVideo from 'virtual:icons/mdi/fileVideo';
|
||||
import IconDelete from 'virtual:icons/mdi/closeThick';
|
||||
import IconFileImage from 'virtual:icons/mdi/fileImage';
|
||||
import IconFileMusic from 'virtual:icons/mdi/fileMusic';
|
||||
import IconFileText from 'virtual:icons/mdi/fileText';
|
||||
import IconFileVideo from 'virtual:icons/mdi/fileVideo';
|
||||
import IconPreview from 'virtual:icons/mdi/openInNew';
|
||||
|
||||
import { computed, type FunctionalComponent } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import IconChat from 'virtual:icons/mdi/chat';
|
||||
import IconChevronDown from 'virtual:icons/mdi/chevron-down';
|
||||
import { nextTick, ref } from 'vue';
|
||||
|
||||
import Chat from '@n8n/chat/components/Chat.vue';
|
||||
import { chatEventBus } from '@n8n/chat/event-buses';
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { useI18n } from '@n8n/chat/composables';
|
||||
import PoweredBy from '@n8n/chat/components/PoweredBy.vue';
|
||||
import { useI18n } from '@n8n/chat/composables';
|
||||
|
||||
const { t, te } = useI18n();
|
||||
</script>
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import IconSend from 'virtual:icons/mdi/send';
|
||||
import IconFilePlus from 'virtual:icons/mdi/filePlus';
|
||||
import { computed, onMounted, onUnmounted, ref, unref } from 'vue';
|
||||
import { useFileDialog } from '@vueuse/core';
|
||||
import ChatFile from './ChatFile.vue';
|
||||
import IconFilePlus from 'virtual:icons/mdi/filePlus';
|
||||
import IconSend from 'virtual:icons/mdi/send';
|
||||
import { computed, onMounted, onUnmounted, ref, unref } from 'vue';
|
||||
|
||||
import { useI18n, useChat, useOptions } from '@n8n/chat/composables';
|
||||
import { chatEventBus } from '@n8n/chat/event-buses';
|
||||
|
||||
import ChatFile from './ChatFile.vue';
|
||||
|
||||
export interface ArrowKeyDownPayload {
|
||||
key: 'ArrowUp' | 'ArrowDown';
|
||||
currentInputValue: string;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
|
||||
import { chatEventBus } from '@n8n/chat/event-buses';
|
||||
|
||||
const chatBodyRef = ref<HTMLElement | null>(null);
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
<script lang="ts" setup>
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import hljs from 'highlight.js/lib/core';
|
||||
import bash from 'highlight.js/lib/languages/bash';
|
||||
import javascript from 'highlight.js/lib/languages/javascript';
|
||||
import python from 'highlight.js/lib/languages/python';
|
||||
import typescript from 'highlight.js/lib/languages/typescript';
|
||||
import xml from 'highlight.js/lib/languages/xml';
|
||||
import type MarkdownIt from 'markdown-it';
|
||||
import markdownLink from 'markdown-it-link-attributes';
|
||||
import { computed, ref, toRefs, onMounted } from 'vue';
|
||||
import VueMarkdown from 'vue-markdown-render';
|
||||
import hljs from 'highlight.js/lib/core';
|
||||
import javascript from 'highlight.js/lib/languages/javascript';
|
||||
import typescript from 'highlight.js/lib/languages/typescript';
|
||||
import python from 'highlight.js/lib/languages/python';
|
||||
import xml from 'highlight.js/lib/languages/xml';
|
||||
import bash from 'highlight.js/lib/languages/bash';
|
||||
import markdownLink from 'markdown-it-link-attributes';
|
||||
import type MarkdownIt from 'markdown-it';
|
||||
import ChatFile from './ChatFile.vue';
|
||||
import type { ChatMessage, ChatMessageText } from '@n8n/chat/types';
|
||||
|
||||
import { useOptions } from '@n8n/chat/composables';
|
||||
import type { ChatMessage, ChatMessageText } from '@n8n/chat/types';
|
||||
|
||||
import ChatFile from './ChatFile.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
message: ChatMessage;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { Message } from './index';
|
||||
|
||||
import type { ChatMessage } from '@n8n/chat/types';
|
||||
|
||||
import { Message } from './index';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
animation?: 'bouncing' | 'scaling';
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import Message from '@n8n/chat/components/Message.vue';
|
||||
import type { ChatMessage } from '@n8n/chat/types';
|
||||
import MessageTyping from '@n8n/chat/components/MessageTyping.vue';
|
||||
import { useChat } from '@n8n/chat/composables';
|
||||
import type { ChatMessage } from '@n8n/chat/types';
|
||||
|
||||
defineProps<{
|
||||
messages: ChatMessage[];
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { inject } from 'vue';
|
||||
|
||||
import { ChatSymbol } from '@n8n/chat/constants';
|
||||
import type { Chat } from '@n8n/chat/types';
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { isRef } from 'vue';
|
||||
|
||||
import { useOptions } from '@n8n/chat/composables/useOptions';
|
||||
|
||||
export function useI18n() {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { inject } from 'vue';
|
||||
|
||||
import { ChatOptionsSymbol } from '@n8n/chat/constants';
|
||||
import type { ChatOptions } from '@n8n/chat/types';
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { InjectionKey } from 'vue';
|
||||
|
||||
import type { Chat, ChatOptions } from '@n8n/chat/types';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// https://github.com/pxlrbt/markdown-css
|
||||
.chat-message-markdown {
|
||||
/*
|
||||
/*
|
||||
universalize.css (v1.0.2) — by Alexander Sandberg (https://alexandersandberg.com)
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
@ -45,8 +45,6 @@
|
|||
vertical-align: inherit; /* 2 */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Remove inconsistent and unnecessary margins
|
||||
*/
|
||||
|
@ -63,7 +61,8 @@
|
|||
button, /* (Safari) 3 lines */
|
||||
input,
|
||||
select,
|
||||
textarea { /* (Firefox, Safari) */
|
||||
textarea {
|
||||
/* (Firefox, Safari) */
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
@ -80,11 +79,13 @@
|
|||
Add correct display
|
||||
*/
|
||||
main, /* (IE11) */
|
||||
details { /* (Edge 18-, IE) */
|
||||
details {
|
||||
/* (Edge 18-, IE) */
|
||||
display: block;
|
||||
}
|
||||
|
||||
summary { /* (all) */
|
||||
summary {
|
||||
/* (all) */
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
|
@ -106,18 +107,19 @@
|
|||
kbd,
|
||||
samp {
|
||||
font-family:
|
||||
/* macOS 10.10+ */ "Menlo",
|
||||
/* Windows 6+ */ "Consolas",
|
||||
/* Android 4+ */ "Roboto Mono",
|
||||
/* Ubuntu 10.10+ */ "Ubuntu Monospace",
|
||||
/* KDE Plasma 5+ */ "Noto Mono",
|
||||
/* KDE Plasma 4+ */ "Oxygen Mono",
|
||||
/* Linux/OpenOffice fallback */ "Liberation Mono",
|
||||
/* macOS 10.10+ */
|
||||
'Menlo',
|
||||
/* Windows 6+ */ 'Consolas',
|
||||
/* Android 4+ */ 'Roboto Mono',
|
||||
/* Ubuntu 10.10+ */ 'Ubuntu Monospace',
|
||||
/* KDE Plasma 5+ */ 'Noto Mono',
|
||||
/* KDE Plasma 4+ */ 'Oxygen Mono',
|
||||
/* Linux/OpenOffice fallback */ 'Liberation Mono',
|
||||
/* fallback */ monospace,
|
||||
/* macOS emoji */ "Apple Color Emoji",
|
||||
/* Windows emoji */ "Segoe UI Emoji",
|
||||
/* Windows emoji */ "Segoe UI Symbol",
|
||||
/* Linux emoji */ "Noto Color Emoji"; /* 1 */
|
||||
/* macOS emoji */ 'Apple Color Emoji',
|
||||
/* Windows emoji */ 'Segoe UI Emoji',
|
||||
/* Windows emoji */ 'Segoe UI Symbol',
|
||||
/* Linux emoji */ 'Noto Color Emoji'; /* 1 */
|
||||
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
@ -130,7 +132,7 @@
|
|||
cursor: help; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -201,9 +203,9 @@
|
|||
Correct inability to style buttons (iOS, Safari)
|
||||
*/
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
[type='button'],
|
||||
[type='reset'],
|
||||
[type='submit'] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
|
@ -249,7 +251,7 @@
|
|||
1. Correct outline style (Safari)
|
||||
2. Correct odd appearance (Chrome, Edge, Safari)
|
||||
*/
|
||||
[type="search"] {
|
||||
[type='search'] {
|
||||
outline-offset: -2px; /* 1 */
|
||||
-webkit-appearance: textfield; /* 2 */
|
||||
}
|
||||
|
@ -311,7 +313,7 @@
|
|||
/*
|
||||
Change cursor on busy elements (all)
|
||||
*/
|
||||
[aria-busy="true"] {
|
||||
[aria-busy='true'] {
|
||||
cursor: progress;
|
||||
}
|
||||
|
||||
|
@ -325,7 +327,7 @@
|
|||
/*
|
||||
Change cursor on disabled, non-editable, or inoperable elements (all)
|
||||
*/
|
||||
[aria-disabled="true"],
|
||||
[aria-disabled='true'],
|
||||
[disabled] {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
@ -333,12 +335,12 @@
|
|||
/*
|
||||
Change display on visually hidden accessible elements (all)
|
||||
*/
|
||||
[aria-hidden="false"][hidden] {
|
||||
[aria-hidden='false'][hidden] {
|
||||
display: inline;
|
||||
display: initial;
|
||||
}
|
||||
|
||||
[aria-hidden="false"][hidden]:not(:focus) {
|
||||
[aria-hidden='false'][hidden]:not(:focus) {
|
||||
clip: rect(0, 0, 0, 0);
|
||||
position: absolute;
|
||||
}
|
||||
|
@ -347,8 +349,8 @@
|
|||
Print out URLs after links (all)
|
||||
*/
|
||||
@media print {
|
||||
a[href^="http"]::after {
|
||||
content: " (" attr(href) ")";
|
||||
a[href^='http']::after {
|
||||
content: ' (' attr(href) ')';
|
||||
}
|
||||
}
|
||||
/* ----- Variables ----- */
|
||||
|
@ -484,8 +486,8 @@
|
|||
*/
|
||||
pre {
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -563,7 +565,7 @@
|
|||
padding: 0.1em 0.25em;
|
||||
border-radius: 0.2rem;
|
||||
-webkit-box-decoration-break: clone;
|
||||
box-decoration-break: clone;
|
||||
box-decoration-break: clone;
|
||||
}
|
||||
|
||||
kbd > kbd {
|
||||
|
@ -573,8 +575,8 @@
|
|||
|
||||
pre {
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
}
|
||||
|
||||
pre code {
|
||||
|
@ -586,7 +588,7 @@
|
|||
/* ----- Forms ----- */
|
||||
/* ----- Misc ----- */
|
||||
|
||||
[tabindex="-1"]:focus {
|
||||
[tabindex='-1']:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import './main.scss';
|
||||
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import type { ChatOptions } from '@n8n/chat/types';
|
||||
|
||||
import { defaultMountingTarget, defaultOptions } from '@n8n/chat/constants';
|
||||
import { createDefaultMountingTarget } from '@n8n/chat/utils';
|
||||
import { ChatPlugin } from '@n8n/chat/plugins';
|
||||
import type { ChatOptions } from '@n8n/chat/types';
|
||||
import { createDefaultMountingTarget } from '@n8n/chat/utils';
|
||||
|
||||
import App from './App.vue';
|
||||
|
||||
export function createChat(options?: Partial<ChatOptions>) {
|
||||
const resolvedOptions: ChatOptions = {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { v4 as uuidv4 } from 'uuid';
|
||||
import type { Plugin } from 'vue';
|
||||
import { computed, nextTick, ref } from 'vue';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import type { ChatMessage, ChatOptions } from '@n8n/chat/types';
|
||||
import { chatEventBus } from '@n8n/chat/event-buses';
|
||||
|
||||
import * as api from '@n8n/chat/api';
|
||||
import { ChatOptionsSymbol, ChatSymbol, localStorageSessionIdKey } from '@n8n/chat/constants';
|
||||
import { chatEventBus } from '@n8n/chat/event-buses';
|
||||
import type { ChatMessage, ChatOptions } from '@n8n/chat/types';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const ChatPlugin: Plugin<ChatOptions> = {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue