From 469896ac0de6f2ad3ab1ec475b985df31b128fd7 Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Thu, 15 Aug 2024 13:18:04 +0300 Subject: [PATCH 01/11] feat: Improve minimap design and position in new canvas (no-changelog) (#10429) --- .../src/components/canvas/Canvas.vue | 19 ++++++++++++++++++- .../src/styles/plugins/_vueflow.scss | 13 +++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/editor-ui/src/components/canvas/Canvas.vue b/packages/editor-ui/src/components/canvas/Canvas.vue index c5995c5cd6bf8..877bdf0b643bf 100644 --- a/packages/editor-ui/src/components/canvas/Canvas.vue +++ b/packages/editor-ui/src/components/canvas/Canvas.vue @@ -328,6 +328,14 @@ function onContextMenuAction(action: ContextMenuAction, nodeIds: string[]) { } } +/** + * Minimap + */ + +function minimapNodeClassnameFn(node: CanvasNode) { + return `minimap-node-${node.data?.render.type.replace(/\./g, '-') ?? 'default'}`; +} + /** * Lifecycle */ @@ -407,7 +415,16 @@ watch(() => props.readOnly, setReadonly, { - + Date: Thu, 15 Aug 2024 13:18:20 +0300 Subject: [PATCH 02/11] feat(editor): Improve node selection outline in new canvas (no-changelog) (#10430) --- packages/design-system/src/css/_tokens.dark.scss | 1 + packages/design-system/src/css/_tokens.scss | 1 + .../canvas/elements/nodes/render-types/CanvasNodeDefault.vue | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/design-system/src/css/_tokens.dark.scss b/packages/design-system/src/css/_tokens.dark.scss index 6a812552ac5dd..8865fb2e3ec8f 100644 --- a/packages/design-system/src/css/_tokens.dark.scss +++ b/packages/design-system/src/css/_tokens.dark.scss @@ -71,6 +71,7 @@ --color-canvas-dot: var(--prim-gray-670); --color-canvas-read-only-line: var(--prim-gray-800); --color-canvas-selected: var(--prim-gray-0-alpha-025); + --color-canvas-selected-transparent: var(--color-canvas-selected); // Nodes --color-node-background: var(--prim-gray-740); diff --git a/packages/design-system/src/css/_tokens.scss b/packages/design-system/src/css/_tokens.scss index e65856f1922d4..7b1adf0d36433 100644 --- a/packages/design-system/src/css/_tokens.scss +++ b/packages/design-system/src/css/_tokens.scss @@ -79,6 +79,7 @@ --color-canvas-dot: var(--prim-gray-120); --color-canvas-read-only-line: var(--prim-gray-30); --color-canvas-selected: var(--prim-gray-70); + --color-canvas-selected-transparent: hsla(var(--prim-gray-h), 47%, 30%, 0.1); // Nodes --color-node-background: var(--color-background-xlight); diff --git a/packages/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeDefault.vue b/packages/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeDefault.vue index 4a62ee0e186ea..847c5bad2cc8c 100644 --- a/packages/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeDefault.vue +++ b/packages/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeDefault.vue @@ -184,7 +184,7 @@ function openContextMenu(event: MouseEvent) { */ &.selected { - box-shadow: 0 0 0 4px var(--color-canvas-selected); + box-shadow: 0 0 0 8px var(--color-canvas-selected-transparent); } &.success { From 5754fe4ec4c0a7c945ce5a3bbcf800dd8c9aa51c Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Thu, 15 Aug 2024 13:18:37 +0300 Subject: [PATCH 03/11] fix(editor): Remove item count from pinned data status icon in new canvas (no-changelog) (#10431) --- .../nodes/render-types/parts/CanvasNodeStatusIcons.spec.ts | 2 +- .../elements/nodes/render-types/parts/CanvasNodeStatusIcons.vue | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/editor-ui/src/components/canvas/elements/nodes/render-types/parts/CanvasNodeStatusIcons.spec.ts b/packages/editor-ui/src/components/canvas/elements/nodes/render-types/parts/CanvasNodeStatusIcons.spec.ts index 5327d715240ce..1488006841118 100644 --- a/packages/editor-ui/src/components/canvas/elements/nodes/render-types/parts/CanvasNodeStatusIcons.spec.ts +++ b/packages/editor-ui/src/components/canvas/elements/nodes/render-types/parts/CanvasNodeStatusIcons.spec.ts @@ -15,7 +15,7 @@ describe('CanvasNodeStatusIcons', () => { }, }); - expect(getByTestId('canvas-node-status-pinned')).toHaveTextContent('5'); + expect(getByTestId('canvas-node-status-pinned')).toBeInTheDocument(); }); it('should render correctly for a running node', () => { diff --git a/packages/editor-ui/src/components/canvas/elements/nodes/render-types/parts/CanvasNodeStatusIcons.vue b/packages/editor-ui/src/components/canvas/elements/nodes/render-types/parts/CanvasNodeStatusIcons.vue index 6c5136bcdf7b6..e3736e54b7c28 100644 --- a/packages/editor-ui/src/components/canvas/elements/nodes/render-types/parts/CanvasNodeStatusIcons.vue +++ b/packages/editor-ui/src/components/canvas/elements/nodes/render-types/parts/CanvasNodeStatusIcons.vue @@ -7,7 +7,6 @@ import { useCanvasNode } from '@/composables/useCanvasNode'; const nodeHelpers = useNodeHelpers(); const { - pinnedDataCount, hasPinnedData, issues, hasIssues, @@ -51,7 +50,6 @@ const hideNodeIssues = computed(() => false); // @TODO Implement this :class="[$style.status, $style.pinnedData]" > - {{ pinnedDataCount }}
From 0dc3e99b26bec45e747d83f383cfe5169d89e6b7 Mon Sep 17 00:00:00 2001 From: Michael Kret <88898367+michael-radency@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:03:16 +0300 Subject: [PATCH 04/11] fix(n8n Form Trigger Node): Show basic authentication modal on wrong credentials (#10423) --- packages/nodes-base/nodes/Form/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nodes-base/nodes/Form/utils.ts b/packages/nodes-base/nodes/Form/utils.ts index 079ae4278c2d9..35f06496cef4c 100644 --- a/packages/nodes-base/nodes/Form/utils.ts +++ b/packages/nodes-base/nodes/Form/utils.ts @@ -170,8 +170,8 @@ export async function formWebhook( } } catch (error) { if (error instanceof WebhookAuthorizationError) { - res.writeHead(error.responseCode, { 'WWW-Authenticate': 'Basic realm="Webhook"' }); - res.end(error.message); + res.setHeader('WWW-Authenticate', 'Basic realm="Enter credentials"'); + res.status(401).send(); return { noWebhookResponse: true }; } throw error; From 2043daa2570bc04b0b8d41f277901a8cc8a7b98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Thu, 15 Aug 2024 13:58:20 +0200 Subject: [PATCH 05/11] fix(core): Use explicit types in configs to ensure valid decorator metadata (#10433) --- .../@n8n/config/src/configs/cache.config.ts | 8 ++-- .../config/src/configs/credentials.config.ts | 6 +-- .../config/src/configs/database.config.ts | 42 +++++++++--------- .../config/src/configs/endpoints.config.ts | 44 +++++++++---------- .../config/src/configs/event-bus.config.ts | 8 ++-- .../src/configs/external-secrets.config.ts | 4 +- .../src/configs/external-storage.config.ts | 10 ++--- .../@n8n/config/src/configs/nodes.config.ts | 2 +- .../config/src/configs/public-api.config.ts | 6 +-- .../config/src/configs/scaling-mode.config.ts | 34 +++++++------- .../config/src/configs/templates.config.ts | 4 +- .../src/configs/user-management.config.ts | 20 ++++----- .../configs/version-notifications.config.ts | 6 +-- .../config/src/configs/workflows.config.ts | 4 +- packages/@n8n/config/src/decorators.ts | 5 +++ packages/@n8n/config/src/index.ts | 8 ++-- packages/@n8n/config/test/config.test.ts | 1 + 17 files changed, 109 insertions(+), 103 deletions(-) diff --git a/packages/@n8n/config/src/configs/cache.config.ts b/packages/@n8n/config/src/configs/cache.config.ts index 8a24bdc18beff..fa1295d583619 100644 --- a/packages/@n8n/config/src/configs/cache.config.ts +++ b/packages/@n8n/config/src/configs/cache.config.ts @@ -4,22 +4,22 @@ import { Config, Env, Nested } from '../decorators'; class MemoryConfig { /** Max size of memory cache in bytes */ @Env('N8N_CACHE_MEMORY_MAX_SIZE') - maxSize = 3 * 1024 * 1024; // 3 MiB + maxSize: number = 3 * 1024 * 1024; // 3 MiB /** Time to live (in milliseconds) for data cached in memory. */ @Env('N8N_CACHE_MEMORY_TTL') - ttl = 3600 * 1000; // 1 hour + ttl: number = 3600 * 1000; // 1 hour } @Config class RedisConfig { /** Prefix for cache keys in Redis. */ @Env('N8N_CACHE_REDIS_KEY_PREFIX') - prefix = 'redis'; + prefix: string = 'redis'; /** Time to live (in milliseconds) for data cached in Redis. 0 for no TTL. */ @Env('N8N_CACHE_REDIS_TTL') - ttl = 3600 * 1000; // 1 hour + ttl: number = 3600 * 1000; // 1 hour } @Config diff --git a/packages/@n8n/config/src/configs/credentials.config.ts b/packages/@n8n/config/src/configs/credentials.config.ts index ee5f78a681ae6..f40e6b9f154bd 100644 --- a/packages/@n8n/config/src/configs/credentials.config.ts +++ b/packages/@n8n/config/src/configs/credentials.config.ts @@ -7,18 +7,18 @@ class CredentialsOverwrite { * Format: { CREDENTIAL_NAME: { PARAMETER: VALUE }} */ @Env('CREDENTIALS_OVERWRITE_DATA') - data = '{}'; + data: string = '{}'; /** Internal API endpoint to fetch overwritten credential types from. */ @Env('CREDENTIALS_OVERWRITE_ENDPOINT') - endpoint = ''; + endpoint: string = ''; } @Config export class CredentialsConfig { /** Default name for credentials */ @Env('CREDENTIALS_DEFAULT_NAME') - defaultName = 'My credentials'; + defaultName: string = 'My credentials'; @Nested overwrite: CredentialsOverwrite; diff --git a/packages/@n8n/config/src/configs/database.config.ts b/packages/@n8n/config/src/configs/database.config.ts index 06a3f85465929..9da83958e6da0 100644 --- a/packages/@n8n/config/src/configs/database.config.ts +++ b/packages/@n8n/config/src/configs/database.config.ts @@ -4,7 +4,7 @@ import { Config, Env, Nested } from '../decorators'; class LoggingConfig { /** Whether database logging is enabled. */ @Env('DB_LOGGING_ENABLED') - enabled = false; + enabled: boolean = false; /** * Database logging level. Requires `DB_LOGGING_MAX_EXECUTION_TIME` to be higher than `0`. @@ -16,7 +16,7 @@ class LoggingConfig { * Only queries that exceed this time (ms) will be logged. Set `0` to disable. */ @Env('DB_LOGGING_MAX_EXECUTION_TIME') - maxQueryExecutionTime = 0; + maxQueryExecutionTime: number = 0; } @Config @@ -26,38 +26,38 @@ class PostgresSSLConfig { * If `DB_POSTGRESDB_SSL_CA`, `DB_POSTGRESDB_SSL_CERT`, or `DB_POSTGRESDB_SSL_KEY` are defined, `DB_POSTGRESDB_SSL_ENABLED` defaults to `true`. */ @Env('DB_POSTGRESDB_SSL_ENABLED') - enabled = false; + enabled: boolean = false; /** SSL certificate authority */ @Env('DB_POSTGRESDB_SSL_CA') - ca = ''; + ca: string = ''; /** SSL certificate */ @Env('DB_POSTGRESDB_SSL_CERT') - cert = ''; + cert: string = ''; /** SSL key */ @Env('DB_POSTGRESDB_SSL_KEY') - key = ''; + key: string = ''; /** If unauthorized SSL connections should be rejected */ @Env('DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED') - rejectUnauthorized = true; + rejectUnauthorized: boolean = true; } @Config class PostgresConfig { /** Postgres database name */ @Env('DB_POSTGRESDB_DATABASE') - database = 'n8n'; + database: string = 'n8n'; /** Postgres database host */ @Env('DB_POSTGRESDB_HOST') - host = 'localhost'; + host: string = 'localhost'; /** Postgres database password */ @Env('DB_POSTGRESDB_PASSWORD') - password = ''; + password: string = ''; /** Postgres database port */ @Env('DB_POSTGRESDB_PORT') @@ -65,15 +65,15 @@ class PostgresConfig { /** Postgres database user */ @Env('DB_POSTGRESDB_USER') - user = 'postgres'; + user: string = 'postgres'; /** Postgres database schema */ @Env('DB_POSTGRESDB_SCHEMA') - schema = 'public'; + schema: string = 'public'; /** Postgres database pool size */ @Env('DB_POSTGRESDB_POOL_SIZE') - poolSize = 2; + poolSize: number = 2; @Nested ssl: PostgresSSLConfig; @@ -83,15 +83,15 @@ class PostgresConfig { class MysqlConfig { /** @deprecated MySQL database name */ @Env('DB_MYSQLDB_DATABASE') - database = 'n8n'; + database: string = 'n8n'; /** MySQL database host */ @Env('DB_MYSQLDB_HOST') - host = 'localhost'; + host: string = 'localhost'; /** MySQL database password */ @Env('DB_MYSQLDB_PASSWORD') - password = ''; + password: string = ''; /** MySQL database port */ @Env('DB_MYSQLDB_PORT') @@ -99,14 +99,14 @@ class MysqlConfig { /** MySQL database user */ @Env('DB_MYSQLDB_USER') - user = 'root'; + user: string = 'root'; } @Config class SqliteConfig { /** SQLite database file name */ @Env('DB_SQLITE_DATABASE') - database = 'database.sqlite'; + database: string = 'database.sqlite'; /** SQLite database pool size. Set to `0` to disable pooling. */ @Env('DB_SQLITE_POOL_SIZE') @@ -116,7 +116,7 @@ class SqliteConfig { * Enable SQLite WAL mode. */ @Env('DB_SQLITE_ENABLE_WAL') - enableWAL = this.poolSize > 1; + enableWAL: boolean = this.poolSize > 1; /** * Run `VACUUM` on startup to rebuild the database, reducing file size and optimizing indexes. @@ -124,7 +124,7 @@ class SqliteConfig { * @warning Long-running blocking operation that will increase startup time. */ @Env('DB_SQLITE_VACUUM_ON_STARTUP') - executeVacuumOnStartup = false; + executeVacuumOnStartup: boolean = false; } @Config @@ -135,7 +135,7 @@ export class DatabaseConfig { /** Prefix for table names */ @Env('DB_TABLE_PREFIX') - tablePrefix = ''; + tablePrefix: string = ''; @Nested logging: LoggingConfig; diff --git a/packages/@n8n/config/src/configs/endpoints.config.ts b/packages/@n8n/config/src/configs/endpoints.config.ts index 4957c5afa58d6..88efa01d26bb5 100644 --- a/packages/@n8n/config/src/configs/endpoints.config.ts +++ b/packages/@n8n/config/src/configs/endpoints.config.ts @@ -4,51 +4,51 @@ import { Config, Env, Nested } from '../decorators'; class PrometheusMetricsConfig { /** Whether to enable the `/metrics` endpoint to expose Prometheus metrics. */ @Env('N8N_METRICS') - enable = false; + enable: boolean = false; /** Prefix for Prometheus metric names. */ @Env('N8N_METRICS_PREFIX') - prefix = 'n8n_'; + prefix: string = 'n8n_'; /** Whether to expose system and Node.js metrics. See: https://www.npmjs.com/package/prom-client */ @Env('N8N_METRICS_INCLUDE_DEFAULT_METRICS') - includeDefaultMetrics = true; + includeDefaultMetrics: boolean = true; /** Whether to include a label for workflow ID on workflow metrics. */ @Env('N8N_METRICS_INCLUDE_WORKFLOW_ID_LABEL') - includeWorkflowIdLabel = false; + includeWorkflowIdLabel: boolean = false; /** Whether to include a label for node type on node metrics. */ @Env('N8N_METRICS_INCLUDE_NODE_TYPE_LABEL') - includeNodeTypeLabel = false; + includeNodeTypeLabel: boolean = false; /** Whether to include a label for credential type on credential metrics. */ @Env('N8N_METRICS_INCLUDE_CREDENTIAL_TYPE_LABEL') - includeCredentialTypeLabel = false; + includeCredentialTypeLabel: boolean = false; /** Whether to expose metrics for API endpoints. See: https://www.npmjs.com/package/express-prom-bundle */ @Env('N8N_METRICS_INCLUDE_API_ENDPOINTS') - includeApiEndpoints = false; + includeApiEndpoints: boolean = false; /** Whether to include a label for the path of API endpoint calls. */ @Env('N8N_METRICS_INCLUDE_API_PATH_LABEL') - includeApiPathLabel = false; + includeApiPathLabel: boolean = false; /** Whether to include a label for the HTTP method of API endpoint calls. */ @Env('N8N_METRICS_INCLUDE_API_METHOD_LABEL') - includeApiMethodLabel = false; + includeApiMethodLabel: boolean = false; /** Whether to include a label for the status code of API endpoint calls. */ @Env('N8N_METRICS_INCLUDE_API_STATUS_CODE_LABEL') - includeApiStatusCodeLabel = false; + includeApiStatusCodeLabel: boolean = false; /** Whether to include metrics for cache hits and misses. */ @Env('N8N_METRICS_INCLUDE_CACHE_METRICS') - includeCacheMetrics = false; + includeCacheMetrics: boolean = false; /** Whether to include metrics derived from n8n's internal events */ @Env('N8N_METRICS_INCLUDE_MESSAGE_EVENT_BUS_METRICS') - includeMessageEventBusMetrics = false; + includeMessageEventBusMetrics: boolean = false; } @Config @@ -62,41 +62,41 @@ export class EndpointsConfig { /** Path segment for REST API endpoints. */ @Env('N8N_ENDPOINT_REST') - rest = 'rest'; + rest: string = 'rest'; /** Path segment for form endpoints. */ @Env('N8N_ENDPOINT_FORM') - form = 'form'; + form: string = 'form'; /** Path segment for test form endpoints. */ @Env('N8N_ENDPOINT_FORM_TEST') - formTest = 'form-test'; + formTest: string = 'form-test'; /** Path segment for waiting form endpoints. */ @Env('N8N_ENDPOINT_FORM_WAIT') - formWaiting = 'form-waiting'; + formWaiting: string = 'form-waiting'; /** Path segment for webhook endpoints. */ @Env('N8N_ENDPOINT_WEBHOOK') - webhook = 'webhook'; + webhook: string = 'webhook'; /** Path segment for test webhook endpoints. */ @Env('N8N_ENDPOINT_WEBHOOK_TEST') - webhookTest = 'webhook-test'; + webhookTest: string = 'webhook-test'; /** Path segment for waiting webhook endpoints. */ @Env('N8N_ENDPOINT_WEBHOOK_WAIT') - webhookWaiting = 'webhook-waiting'; + webhookWaiting: string = 'webhook-waiting'; /** Whether to disable n8n's UI (frontend). */ @Env('N8N_DISABLE_UI') - disableUi = false; + disableUi: boolean = false; /** Whether to disable production webhooks on the main process, when using webhook-specific processes. */ @Env('N8N_DISABLE_PRODUCTION_MAIN_PROCESS') - disableProductionWebhooksOnMainProcess = false; + disableProductionWebhooksOnMainProcess: boolean = false; /** Colon-delimited list of additional endpoints to not open the UI on. */ @Env('N8N_ADDITIONAL_NON_UI_ROUTES') - additionalNonUIRoutes = ''; + additionalNonUIRoutes: string = ''; } diff --git a/packages/@n8n/config/src/configs/event-bus.config.ts b/packages/@n8n/config/src/configs/event-bus.config.ts index 87db613e63968..b4782555d589f 100644 --- a/packages/@n8n/config/src/configs/event-bus.config.ts +++ b/packages/@n8n/config/src/configs/event-bus.config.ts @@ -4,22 +4,22 @@ import { Config, Env, Nested } from '../decorators'; class LogWriterConfig { /* of event log files to keep */ @Env('N8N_EVENTBUS_LOGWRITER_KEEPLOGCOUNT') - keepLogCount = 3; + keepLogCount: number = 3; /** Max size (in KB) of an event log file before a new one is started */ @Env('N8N_EVENTBUS_LOGWRITER_MAXFILESIZEINKB') - maxFileSizeInKB = 10240; // 10 MB + maxFileSizeInKB: number = 10240; // 10 MB /** Basename of event log file */ @Env('N8N_EVENTBUS_LOGWRITER_LOGBASENAME') - logBaseName = 'n8nEventLog'; + logBaseName: string = 'n8nEventLog'; } @Config export class EventBusConfig { /** How often (in ms) to check for unsent event messages. Can in rare cases cause a message to be sent twice. `0` to disable */ @Env('N8N_EVENTBUS_CHECKUNSENTINTERVAL') - checkUnsentInterval = 0; + checkUnsentInterval: number = 0; /** Endpoint to retrieve n8n version information from */ @Nested diff --git a/packages/@n8n/config/src/configs/external-secrets.config.ts b/packages/@n8n/config/src/configs/external-secrets.config.ts index 2e51be87bc6c0..1195adf66035c 100644 --- a/packages/@n8n/config/src/configs/external-secrets.config.ts +++ b/packages/@n8n/config/src/configs/external-secrets.config.ts @@ -4,9 +4,9 @@ import { Config, Env } from '../decorators'; export class ExternalSecretsConfig { /** How often (in seconds) to check for secret updates */ @Env('N8N_EXTERNAL_SECRETS_UPDATE_INTERVAL') - updateInterval = 300; + updateInterval: number = 300; /** Whether to prefer GET over LIST when fetching secrets from Hashicorp Vault */ @Env('N8N_EXTERNAL_SECRETS_PREFER_GET') - preferGet = false; + preferGet: boolean = false; } diff --git a/packages/@n8n/config/src/configs/external-storage.config.ts b/packages/@n8n/config/src/configs/external-storage.config.ts index 3dd1448b44e38..6e5fbd64d89ad 100644 --- a/packages/@n8n/config/src/configs/external-storage.config.ts +++ b/packages/@n8n/config/src/configs/external-storage.config.ts @@ -4,29 +4,29 @@ import { Config, Env, Nested } from '../decorators'; class S3BucketConfig { /** Name of the n8n bucket in S3-compatible external storage */ @Env('N8N_EXTERNAL_STORAGE_S3_BUCKET_NAME') - name = ''; + name: string = ''; /** Region of the n8n bucket in S3-compatible external storage @example "us-east-1" */ @Env('N8N_EXTERNAL_STORAGE_S3_BUCKET_REGION') - region = ''; + region: string = ''; } @Config class S3CredentialsConfig { /** Access key in S3-compatible external storage */ @Env('N8N_EXTERNAL_STORAGE_S3_ACCESS_KEY') - accessKey = ''; + accessKey: string = ''; /** Access secret in S3-compatible external storage */ @Env('N8N_EXTERNAL_STORAGE_S3_ACCESS_SECRET') - accessSecret = ''; + accessSecret: string = ''; } @Config class S3Config { /** Host of the n8n bucket in S3-compatible external storage @example "s3.us-east-1.amazonaws.com" */ @Env('N8N_EXTERNAL_STORAGE_S3_HOST') - host = ''; + host: string = ''; @Nested bucket: S3BucketConfig; diff --git a/packages/@n8n/config/src/configs/nodes.config.ts b/packages/@n8n/config/src/configs/nodes.config.ts index cf8407762cb17..577c4055ab622 100644 --- a/packages/@n8n/config/src/configs/nodes.config.ts +++ b/packages/@n8n/config/src/configs/nodes.config.ts @@ -47,7 +47,7 @@ export class NodesConfig { /** Node type to use as error trigger */ @Env('NODES_ERROR_TRIGGER_TYPE') - errorTriggerType = 'n8n-nodes-base.errorTrigger'; + errorTriggerType: string = 'n8n-nodes-base.errorTrigger'; @Nested communityPackages: CommunityPackagesConfig; diff --git a/packages/@n8n/config/src/configs/public-api.config.ts b/packages/@n8n/config/src/configs/public-api.config.ts index b62cac68c7834..340c54fbd7918 100644 --- a/packages/@n8n/config/src/configs/public-api.config.ts +++ b/packages/@n8n/config/src/configs/public-api.config.ts @@ -4,13 +4,13 @@ import { Config, Env } from '../decorators'; export class PublicApiConfig { /** Whether to disable the Public API */ @Env('N8N_PUBLIC_API_DISABLED') - disabled = false; + disabled: boolean = false; /** Path segment for the Public API */ @Env('N8N_PUBLIC_API_ENDPOINT') - path = 'api'; + path: string = 'api'; /** Whether to disable the Swagger UI for the Public API */ @Env('N8N_PUBLIC_API_SWAGGERUI_DISABLED') - swaggerUiDisabled = false; + swaggerUiDisabled: boolean = false; } diff --git a/packages/@n8n/config/src/configs/scaling-mode.config.ts b/packages/@n8n/config/src/configs/scaling-mode.config.ts index 6ff331eedd8c2..750de77b07cb7 100644 --- a/packages/@n8n/config/src/configs/scaling-mode.config.ts +++ b/packages/@n8n/config/src/configs/scaling-mode.config.ts @@ -4,83 +4,83 @@ import { Config, Env, Nested } from '../decorators'; class HealthConfig { /** Whether to enable the worker health check endpoint `/healthz`. */ @Env('QUEUE_HEALTH_CHECK_ACTIVE') - active = false; + active: boolean = false; /** Port for worker to respond to health checks requests on, if enabled. */ @Env('QUEUE_HEALTH_CHECK_PORT') - port = 5678; + port: number = 5678; } @Config class RedisConfig { /** Redis database for Bull queue. */ @Env('QUEUE_BULL_REDIS_DB') - db = 0; + db: number = 0; /** Redis host for Bull queue. */ @Env('QUEUE_BULL_REDIS_HOST') - host = 'localhost'; + host: string = 'localhost'; /** Password to authenticate with Redis. */ @Env('QUEUE_BULL_REDIS_PASSWORD') - password = ''; + password: string = ''; /** Port for Redis to listen on. */ @Env('QUEUE_BULL_REDIS_PORT') - port = 6379; + port: number = 6379; /** Max cumulative timeout (in milliseconds) of connection retries before process exit. */ @Env('QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD') - timeoutThreshold = 10_000; + timeoutThreshold: number = 10_000; /** Redis username. Redis 6.0 or higher required. */ @Env('QUEUE_BULL_REDIS_USERNAME') - username = ''; + username: string = ''; /** Redis cluster startup nodes, as comma-separated list of `{host}:{port}` pairs. @example 'redis-1:6379,redis-2:6379' */ @Env('QUEUE_BULL_REDIS_CLUSTER_NODES') - clusterNodes = ''; + clusterNodes: string = ''; /** Whether to enable TLS on Redis connections. */ @Env('QUEUE_BULL_REDIS_TLS') - tls = false; + tls: boolean = false; } @Config class SettingsConfig { /** How long (in milliseconds) is the lease period for a worker processing a job. */ @Env('QUEUE_WORKER_LOCK_DURATION') - lockDuration = 30_000; + lockDuration: number = 30_000; /** How often (in milliseconds) a worker must renew the lease. */ @Env('QUEUE_WORKER_LOCK_RENEW_TIME') - lockRenewTime = 15_000; + lockRenewTime: number = 15_000; /** How often (in milliseconds) Bull must check for stalled jobs. `0` to disable. */ @Env('QUEUE_WORKER_STALLED_INTERVAL') - stalledInterval = 30_000; + stalledInterval: number = 30_000; /** Max number of times a stalled job will be re-processed. See Bull's [documentation](https://docs.bullmq.io/guide/workers/stalled-jobs). */ @Env('QUEUE_WORKER_MAX_STALLED_COUNT') - maxStalledCount = 1; + maxStalledCount: number = 1; } @Config class BullConfig { /** Prefix for Bull keys on Redis. @example 'bull:jobs:23' */ @Env('QUEUE_BULL_PREFIX') - prefix = 'bull'; + prefix: string = 'bull'; @Nested redis: RedisConfig; /** How often (in seconds) to poll the Bull queue to identify executions finished during a Redis crash. `0` to disable. May increase Redis traffic significantly. */ @Env('QUEUE_RECOVERY_INTERVAL') - queueRecoveryInterval = 60; // watchdog interval + queueRecoveryInterval: number = 60; // watchdog interval /** @deprecated How long (in seconds) a worker must wait for active executions to finish before exiting. Use `N8N_GRACEFUL_SHUTDOWN_TIMEOUT` instead */ @Env('QUEUE_WORKER_TIMEOUT') - gracefulShutdownTimeout = 30; + gracefulShutdownTimeout: number = 30; @Nested settings: SettingsConfig; diff --git a/packages/@n8n/config/src/configs/templates.config.ts b/packages/@n8n/config/src/configs/templates.config.ts index 3b05048b36301..0707330b322a3 100644 --- a/packages/@n8n/config/src/configs/templates.config.ts +++ b/packages/@n8n/config/src/configs/templates.config.ts @@ -4,9 +4,9 @@ import { Config, Env } from '../decorators'; export class TemplatesConfig { /** Whether to load workflow templates. */ @Env('N8N_TEMPLATES_ENABLED') - enabled = true; + enabled: boolean = true; /** Host to retrieve workflow templates from endpoints. */ @Env('N8N_TEMPLATES_HOST') - host = 'https://api.n8n.io/api/'; + host: string = 'https://api.n8n.io/api/'; } diff --git a/packages/@n8n/config/src/configs/user-management.config.ts b/packages/@n8n/config/src/configs/user-management.config.ts index 2c603a7148002..956bac2b7545d 100644 --- a/packages/@n8n/config/src/configs/user-management.config.ts +++ b/packages/@n8n/config/src/configs/user-management.config.ts @@ -4,26 +4,26 @@ import { Config, Env, Nested } from '../decorators'; class SmtpAuth { /** SMTP login username */ @Env('N8N_SMTP_USER') - user = ''; + user: string = ''; /** SMTP login password */ @Env('N8N_SMTP_PASS') - pass = ''; + pass: string = ''; /** SMTP OAuth Service Client */ @Env('N8N_SMTP_OAUTH_SERVICE_CLIENT') - serviceClient = ''; + serviceClient: string = ''; /** SMTP OAuth Private Key */ @Env('N8N_SMTP_OAUTH_PRIVATE_KEY') - privateKey = ''; + privateKey: string = ''; } @Config class SmtpConfig { /** SMTP server host */ @Env('N8N_SMTP_HOST') - host = ''; + host: string = ''; /** SMTP server port */ @Env('N8N_SMTP_PORT') @@ -39,7 +39,7 @@ class SmtpConfig { /** How to display sender name */ @Env('N8N_SMTP_SENDER') - sender = ''; + sender: string = ''; @Nested auth: SmtpAuth; @@ -49,19 +49,19 @@ class SmtpConfig { export class TemplateConfig { /** Overrides default HTML template for inviting new people (use full path) */ @Env('N8N_UM_EMAIL_TEMPLATES_INVITE') - invite = ''; + invite: string = ''; /** Overrides default HTML template for resetting password (use full path) */ @Env('N8N_UM_EMAIL_TEMPLATES_PWRESET') - passwordReset = ''; + passwordReset: string = ''; /** Overrides default HTML template for notifying that a workflow was shared (use full path) */ @Env('N8N_UM_EMAIL_TEMPLATES_WORKFLOW_SHARED') - workflowShared = ''; + workflowShared: string = ''; /** Overrides default HTML template for notifying that credentials were shared (use full path) */ @Env('N8N_UM_EMAIL_TEMPLATES_CREDENTIALS_SHARED') - credentialsShared = ''; + credentialsShared: string = ''; } @Config diff --git a/packages/@n8n/config/src/configs/version-notifications.config.ts b/packages/@n8n/config/src/configs/version-notifications.config.ts index 5fe495ed6c02e..313e264a2d6fb 100644 --- a/packages/@n8n/config/src/configs/version-notifications.config.ts +++ b/packages/@n8n/config/src/configs/version-notifications.config.ts @@ -4,13 +4,13 @@ import { Config, Env } from '../decorators'; export class VersionNotificationsConfig { /** Whether to request notifications about new n8n versions */ @Env('N8N_VERSION_NOTIFICATIONS_ENABLED') - enabled = true; + enabled: boolean = true; /** Endpoint to retrieve n8n version information from */ @Env('N8N_VERSION_NOTIFICATIONS_ENDPOINT') - endpoint = 'https://api.n8n.io/api/versions/'; + endpoint: string = 'https://api.n8n.io/api/versions/'; /** URL for versions panel to page instructing user on how to update n8n instance */ @Env('N8N_VERSION_NOTIFICATIONS_INFO_URL') - infoUrl = 'https://docs.n8n.io/hosting/installation/updating/'; + infoUrl: string = 'https://docs.n8n.io/hosting/installation/updating/'; } diff --git a/packages/@n8n/config/src/configs/workflows.config.ts b/packages/@n8n/config/src/configs/workflows.config.ts index 9ca004c886b58..3d6eaad12fc4c 100644 --- a/packages/@n8n/config/src/configs/workflows.config.ts +++ b/packages/@n8n/config/src/configs/workflows.config.ts @@ -4,11 +4,11 @@ import { Config, Env } from '../decorators'; export class WorkflowsConfig { /** Default name for workflow */ @Env('WORKFLOWS_DEFAULT_NAME') - defaultName = 'My workflow'; + defaultName: string = 'My workflow'; /** Show onboarding flow in new workflow */ @Env('N8N_ONBOARDING_FLOW_DISABLED') - onboardingFlowDisabled = false; + onboardingFlowDisabled: boolean = false; /** Default option for which workflows may call the current workflow */ @Env('N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION') diff --git a/packages/@n8n/config/src/decorators.ts b/packages/@n8n/config/src/decorators.ts index fd68d44085508..c5549a674fcc5 100644 --- a/packages/@n8n/config/src/decorators.ts +++ b/packages/@n8n/config/src/decorators.ts @@ -47,6 +47,11 @@ export const Config: ClassDecorator = (ConfigClass: Class) => { } else { value = value === 'true'; } + } else if (type === Object) { + // eslint-disable-next-line n8n-local-rules/no-plain-errors + throw new Error( + `Invalid decorator metadata on key "${key as string}" on ${ConfigClass.name}\n Please use explicit typing on all config fields`, + ); } else if (type !== String && type !== Object) { value = new (type as Constructable)(value as string); } diff --git a/packages/@n8n/config/src/index.ts b/packages/@n8n/config/src/index.ts index a5b970eab4730..fd1dc50c18d05 100644 --- a/packages/@n8n/config/src/index.ts +++ b/packages/@n8n/config/src/index.ts @@ -51,19 +51,19 @@ export class GlobalConfig { /** Path n8n is deployed to */ @Env('N8N_PATH') - path = '/'; + path: string = '/'; /** Host name n8n can be reached */ @Env('N8N_HOST') - host = 'localhost'; + host: string = 'localhost'; /** HTTP port n8n can be reached */ @Env('N8N_PORT') - port = 5678; + port: number = 5678; /** IP address n8n should listen on */ @Env('N8N_LISTEN_ADDRESS') - listen_address = '0.0.0.0'; + listen_address: string = '0.0.0.0'; /** HTTP Protocol via which n8n can be reached */ @Env('N8N_PROTOCOL') diff --git a/packages/@n8n/config/test/config.test.ts b/packages/@n8n/config/test/config.test.ts index b8e89d0ab7f0d..adecff7f9d3ac 100644 --- a/packages/@n8n/config/test/config.test.ts +++ b/packages/@n8n/config/test/config.test.ts @@ -232,6 +232,7 @@ describe('GlobalConfig', () => { DB_POSTGRESDB_USER: 'n8n', DB_TABLE_PREFIX: 'test_', NODES_INCLUDE: '["n8n-nodes-base.hackerNews"]', + DB_LOGGING_MAX_EXECUTION_TIME: '0', }; const config = Container.get(GlobalConfig); expect(config).toEqual({ From 1bf2f4f6171d666391bb3a3a312468bc083446e3 Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Thu, 15 Aug 2024 14:54:54 +0200 Subject: [PATCH 06/11] fix(editor): Truncate long data pill labels in schema view (#10427) --- .../src/components/RunDataSchema.vue | 1 + .../src/components/RunDataSchemaItem.vue | 33 ++++++++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/editor-ui/src/components/RunDataSchema.vue b/packages/editor-ui/src/components/RunDataSchema.vue index c087c39ce0c45..acb9f8a576a38 100644 --- a/packages/editor-ui/src/components/RunDataSchema.vue +++ b/packages/editor-ui/src/components/RunDataSchema.vue @@ -463,6 +463,7 @@ watch( .innerSchema { min-height: 0; + min-width: 0; > div { margin-bottom: var(--spacing-xs); diff --git a/packages/editor-ui/src/components/RunDataSchemaItem.vue b/packages/editor-ui/src/components/RunDataSchemaItem.vue index 34979053f7ad4..18b141932933d 100644 --- a/packages/editor-ui/src/components/RunDataSchemaItem.vue +++ b/packages/editor-ui/src/components/RunDataSchemaItem.vue @@ -198,6 +198,8 @@ const getIconBySchemaType = (type: Schema['type']): string => { display: flex; gap: var(--spacing-2xs); align-items: baseline; + flex-grow: 1; + min-width: 0; } .sub { @@ -212,6 +214,7 @@ const getIconBySchemaType = (type: Schema['type']): string => { display: inline-flex; flex-direction: column; order: -1; + min-width: 0; .innerSub > div:first-child { margin-top: var(--spacing-2xs); @@ -242,21 +245,14 @@ const getIconBySchemaType = (type: Schema['type']): string => { height: 24px; padding: 0 var(--spacing-3xs); border: 1px solid var(--color-foreground-light); - border-radius: 4px; + border-radius: var(--border-radius-base); background-color: var(--color-background-xlight); font-size: var(--font-size-2xs); color: var(--color-text-dark); + max-width: 50%; - span { - display: flex; - height: 100%; - align-items: center; - - svg { - path { - fill: var(--color-text-light); - } - } + path { + fill: var(--color-text-light); } &.mappable { @@ -273,11 +269,26 @@ const getIconBySchemaType = (type: Schema['type']): string => { } .label { + display: flex; + min-width: 0; + align-items: center; + > span { + display: flex; + align-items: center; + margin-left: var(--spacing-3xs); padding-left: var(--spacing-3xs); border-left: 1px solid var(--color-foreground-light); + overflow: hidden; + + span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + &.arrayIndex { border: 0; padding-left: 0; From e7ee10f243663d899d32e61bc6264b4df444e2af Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 15 Aug 2024 14:40:50 +0100 Subject: [PATCH 07/11] feat(Facebook Graph API Node): Update node to support API v18 - v20 (#10419) --- .../nodes/Facebook/FacebookGraphApi.node.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/nodes-base/nodes/Facebook/FacebookGraphApi.node.ts b/packages/nodes-base/nodes/Facebook/FacebookGraphApi.node.ts index 9a88354d2a52f..0a4a4eb7f9b32 100644 --- a/packages/nodes-base/nodes/Facebook/FacebookGraphApi.node.ts +++ b/packages/nodes-base/nodes/Facebook/FacebookGraphApi.node.ts @@ -80,6 +80,18 @@ export class FacebookGraphApi implements INodeType { name: 'Default', value: '', }, + { + name: 'v20.0', + value: 'v20.0', + }, + { + name: 'v19.0', + value: 'v19.0', + }, + { + name: 'v18.0', + value: 'v18.0', + }, { name: 'v17.0', value: 'v17.0', From 6bca879d4ae30c7f9a35e8d6672de42cf93be727 Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Thu, 15 Aug 2024 15:43:25 +0200 Subject: [PATCH 08/11] fix(editor): Highlight matching type in filter component (#10425) --- .../components/FilterConditions/Condition.vue | 10 +++++++ .../FilterConditions/OperatorSelect.vue | 29 ++++++++++++------- .../FilterConditions/__tests__/utils.test.ts | 15 +++++++++- .../src/components/FilterConditions/types.ts | 10 +++++-- .../src/components/FilterConditions/utils.ts | 21 +++++++++++++- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/packages/editor-ui/src/components/FilterConditions/Condition.vue b/packages/editor-ui/src/components/FilterConditions/Condition.vue index 71efc75728223..00d83218c1b3e 100644 --- a/packages/editor-ui/src/components/FilterConditions/Condition.vue +++ b/packages/editor-ui/src/components/FilterConditions/Condition.vue @@ -17,6 +17,7 @@ import { type FilterOperatorId } from './constants'; import { getFilterOperator, handleOperatorChange, + inferOperatorType, isEmptyInput, operatorTypeToNodeProperty, resolveCondition, @@ -70,6 +71,14 @@ const conditionResult = computed(() => resolveCondition({ condition: condition.value, options: props.options }), ); +const suggestedType = computed(() => { + if (conditionResult.value.status !== 'resolve_error') { + return inferOperatorType(conditionResult.value.resolved.leftValue); + } + + return 'any'; +}); + const allIssues = computed(() => { if (conditionResult.value.status === 'validation_error' && !isEmpty.value) { return [conditionResult.value.error]; @@ -176,6 +185,7 @@ const onBlur = (): void => {