diff --git a/packages/@n8n/api-types/package.json b/packages/@n8n/api-types/package.json index 0c4440eb6b..b3d28f18cc 100644 --- a/packages/@n8n/api-types/package.json +++ b/packages/@n8n/api-types/package.json @@ -21,6 +21,7 @@ "dist/**/*" ], "devDependencies": { + "@n8n/config": "workspace:*", "n8n-workflow": "workspace:*" }, "dependencies": { diff --git a/packages/@n8n/api-types/src/frontend-settings.ts b/packages/@n8n/api-types/src/frontend-settings.ts index 5084344aeb..6b2f3231d3 100644 --- a/packages/@n8n/api-types/src/frontend-settings.ts +++ b/packages/@n8n/api-types/src/frontend-settings.ts @@ -1,3 +1,4 @@ +import type { FrontendBetaFeatures } from '@n8n/config'; import type { ExpressionEvaluatorType, LogLevel, WorkflowSettings } from 'n8n-workflow'; export interface IVersionNotificationSettings { @@ -169,4 +170,5 @@ export interface FrontendSettings { security: { blockFileAccessToN8nFiles: boolean; }; + betaFeatures: FrontendBetaFeatures[]; } diff --git a/packages/@n8n/config/src/configs/frontend.config.ts b/packages/@n8n/config/src/configs/frontend.config.ts new file mode 100644 index 0000000000..63f812952f --- /dev/null +++ b/packages/@n8n/config/src/configs/frontend.config.ts @@ -0,0 +1,11 @@ +import { Config, Env } from '../decorators'; +import { StringArray } from '../utils'; + +export type FrontendBetaFeatures = 'canvas_v2'; + +@Config +export class FrontendConfig { + /** Which UI experiments to enable. Separate multiple values with a comma `,` */ + @Env('N8N_UI_BETA_FEATURES') + betaFeatures: StringArray = []; +} diff --git a/packages/@n8n/config/src/index.ts b/packages/@n8n/config/src/index.ts index 1a2a3127ad..c056a1090c 100644 --- a/packages/@n8n/config/src/index.ts +++ b/packages/@n8n/config/src/index.ts @@ -24,6 +24,7 @@ import { Config, Env, Nested } from './decorators'; export { Config, Env, Nested } from './decorators'; export { TaskRunnersConfig } from './configs/runners.config'; export { SecurityConfig } from './configs/security.config'; +export { FrontendBetaFeatures, FrontendConfig } from './configs/frontend.config'; export { LOG_SCOPES } from './configs/logging.config'; export type { LogScope } from './configs/logging.config'; diff --git a/packages/cli/src/services/frontend.service.ts b/packages/cli/src/services/frontend.service.ts index 2916f191f3..6cad4a4f24 100644 --- a/packages/cli/src/services/frontend.service.ts +++ b/packages/cli/src/services/frontend.service.ts @@ -1,5 +1,5 @@ import type { FrontendSettings, ITelemetrySettings } from '@n8n/api-types'; -import { GlobalConfig, SecurityConfig } from '@n8n/config'; +import { GlobalConfig, FrontendConfig, SecurityConfig } from '@n8n/config'; import { createWriteStream } from 'fs'; import { mkdir } from 'fs/promises'; import uniq from 'lodash/uniq'; @@ -47,6 +47,7 @@ export class FrontendService { private readonly instanceSettings: InstanceSettings, private readonly urlService: UrlService, private readonly securityConfig: SecurityConfig, + private readonly frontendConfig: FrontendConfig, ) { loadNodesAndCredentials.addPostProcessor(async () => await this.generateTypes()); void this.generateTypes(); @@ -228,6 +229,7 @@ export class FrontendService { security: { blockFileAccessToN8nFiles: this.securityConfig.blockFileAccessToN8nFiles, }, + betaFeatures: this.frontendConfig.betaFeatures, }; } diff --git a/packages/editor-ui/src/__tests__/defaults.ts b/packages/editor-ui/src/__tests__/defaults.ts index dd4fbed9d5..d16678b17c 100644 --- a/packages/editor-ui/src/__tests__/defaults.ts +++ b/packages/editor-ui/src/__tests__/defaults.ts @@ -124,4 +124,5 @@ export const defaultSettings: FrontendSettings = { aiAssistant: { enabled: false, }, + betaFeatures: [], }; diff --git a/packages/editor-ui/src/composables/useNodeViewVersionSwitcher.ts b/packages/editor-ui/src/composables/useNodeViewVersionSwitcher.ts index 336bf388b6..c91da5dcc2 100644 --- a/packages/editor-ui/src/composables/useNodeViewVersionSwitcher.ts +++ b/packages/editor-ui/src/composables/useNodeViewVersionSwitcher.ts @@ -16,7 +16,7 @@ export function useNodeViewVersionSwitcher() { const nodeViewVersion = useLocalStorage( 'NodeView.version', - settingsStore.deploymentType === 'n8n-internal' ? '2' : '1', + settingsStore.isCanvasV2Enabled ? '2' : '1', ); function setNodeViewSwitcherDropdownOpened(visible: boolean) { diff --git a/packages/editor-ui/src/stores/settings.store.ts b/packages/editor-ui/src/stores/settings.store.ts index b7325e4ec5..119fc20ac1 100644 --- a/packages/editor-ui/src/stores/settings.store.ts +++ b/packages/editor-ui/src/stores/settings.store.ts @@ -156,6 +156,10 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => { const isDevRelease = computed(() => settings.value.releaseChannel === 'dev'); + const isCanvasV2Enabled = computed(() => + (settings.value.betaFeatures ?? []).includes('canvas_v2'), + ); + const setSettings = (newSettings: FrontendSettings) => { settings.value = newSettings; userManagement.value = newSettings.userManagement; @@ -418,6 +422,7 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => { saveDataProgressExecution, isCommunityPlan, isAskAiEnabled, + isCanvasV2Enabled, reset, testLdapConnection, getLdapConfig, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9341fbaf3a..fe5ba1e4f7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -254,6 +254,9 @@ importers: specifier: 0.0.15 version: 0.0.15(zod@3.23.8) devDependencies: + '@n8n/config': + specifier: workspace:* + version: link:../config n8n-workflow: specifier: workspace:* version: link:../../workflow @@ -12104,6 +12107,9 @@ packages: vue-component-type-helpers@2.1.6: resolution: {integrity: sha512-ng11B8B/ZADUMMOsRbqv0arc442q7lifSubD0v8oDXIFoMg/mXwAPUunrroIDkY+mcD0dHKccdaznSVp8EoX3w==} + vue-component-type-helpers@2.1.8: + resolution: {integrity: sha512-ii36gDzrYAfOQIkOlo44yceDdT5269gKmNGxf07Qx6seH2U50+tQ2ol02XLhYPmxrh6YabAsOdte8WDrpaO6Tw==} + vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} engines: {node: '>=12'} @@ -16272,7 +16278,7 @@ snapshots: ts-dedent: 2.2.0 type-fest: 2.19.0 vue: 3.5.11(typescript@5.6.2) - vue-component-type-helpers: 2.1.6 + vue-component-type-helpers: 2.1.8 '@supabase/auth-js@2.65.0': dependencies: @@ -25465,6 +25471,8 @@ snapshots: vue-component-type-helpers@2.1.6: {} + vue-component-type-helpers@2.1.8: {} + vue-demi@0.14.10(vue@3.5.11(typescript@5.6.2)): dependencies: vue: 3.5.11(typescript@5.6.2)