mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
refactor(editor): Migrate settings.store to composition API (no-changelog) (#10022)
Co-authored-by: Elias Meire <elias@meire.dev>
This commit is contained in:
parent
062633ec9b
commit
ba27c987dc
|
@ -23,7 +23,7 @@ export const defaultSettings: IN8nUISettings = {
|
|||
logStreaming: false,
|
||||
debugInEditor: false,
|
||||
advancedExecutionFilters: false,
|
||||
variables: true,
|
||||
variables: false,
|
||||
sourceControl: false,
|
||||
auditLogs: false,
|
||||
showNonProdBanner: false,
|
||||
|
|
|
@ -2,9 +2,14 @@ import { createComponentRenderer } from '@/__tests__/render';
|
|||
import { createTestingPinia } from '@pinia/testing';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import Assignment from '../Assignment.vue';
|
||||
import { defaultSettings } from '@/__tests__/defaults';
|
||||
import { STORES } from '@/constants';
|
||||
import { merge } from 'lodash-es';
|
||||
|
||||
const DEFAULT_SETUP = {
|
||||
pinia: createTestingPinia(),
|
||||
pinia: createTestingPinia({
|
||||
initialState: { [STORES.SETTINGS]: { settings: merge({}, defaultSettings) } },
|
||||
}),
|
||||
props: {
|
||||
path: 'parameters.fields.0',
|
||||
modelValue: {
|
||||
|
|
|
@ -5,10 +5,16 @@ import userEvent from '@testing-library/user-event';
|
|||
import { fireEvent, within } from '@testing-library/vue';
|
||||
import * as workflowHelpers from '@/composables/useWorkflowHelpers';
|
||||
import AssignmentCollection from '../AssignmentCollection.vue';
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
import { STORES } from '@/constants';
|
||||
import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
|
||||
|
||||
const DEFAULT_SETUP = {
|
||||
pinia: createTestingPinia(),
|
||||
pinia: createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: SETTINGS_STORE_DEFAULT_STATE,
|
||||
},
|
||||
stubActions: false,
|
||||
}),
|
||||
props: {
|
||||
path: 'parameters.fields',
|
||||
node: {
|
||||
|
@ -97,10 +103,7 @@ describe('AssignmentCollection.vue', () => {
|
|||
});
|
||||
|
||||
it('can add assignments by drag and drop (and infer type)', async () => {
|
||||
const pinia = createPinia();
|
||||
setActivePinia(pinia);
|
||||
|
||||
const { getByTestId, findAllByTestId } = renderComponent({ pinia });
|
||||
const { getByTestId, findAllByTestId } = renderComponent();
|
||||
const dropArea = getByTestId('drop-area');
|
||||
|
||||
await dropAssignment({ key: 'boolKey', value: true, dropArea });
|
||||
|
|
|
@ -780,7 +780,7 @@ async function saveCredential(): Promise<ICredentialsResponse | null> {
|
|||
};
|
||||
|
||||
if (
|
||||
settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing) &&
|
||||
settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing] &&
|
||||
credentialData.value.sharedWithProjects
|
||||
) {
|
||||
credentialDetails.sharedWithProjects = credentialData.value
|
||||
|
@ -817,7 +817,7 @@ async function saveCredential(): Promise<ICredentialsResponse | null> {
|
|||
type: 'success',
|
||||
});
|
||||
} else {
|
||||
if (settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
|
||||
if (settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing]) {
|
||||
credentialDetails.sharedWithProjects = credentialData.value
|
||||
.sharedWithProjects as ProjectSharingData[];
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ export default defineComponent({
|
|||
];
|
||||
},
|
||||
isSharingEnabled(): boolean {
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing);
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing];
|
||||
},
|
||||
credentialOwnerName(): string {
|
||||
return this.credentialsStore.getCredentialOwnerNameById(`${this.credentialId}`);
|
||||
|
|
|
@ -23,7 +23,7 @@ export default defineComponent({
|
|||
...mapStores(useSettingsStore),
|
||||
canAccess(): boolean {
|
||||
return this.features.reduce((acc: boolean, feature) => {
|
||||
return acc && !!this.settingsStore.isEnterpriseFeatureEnabled(feature);
|
||||
return acc && !!this.settingsStore.isEnterpriseFeatureEnabled[feature];
|
||||
}, true);
|
||||
},
|
||||
},
|
||||
|
|
|
@ -190,9 +190,9 @@ export default defineComponent({
|
|||
: [];
|
||||
},
|
||||
isAdvancedPermissionsEnabled(): boolean {
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled(
|
||||
EnterpriseEditionFeature.AdvancedPermissions,
|
||||
);
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled[
|
||||
EnterpriseEditionFeature.AdvancedPermissions
|
||||
];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -208,7 +208,7 @@ const workflowMenuItems = computed<ActionDropdownItem[]>(() => {
|
|||
});
|
||||
|
||||
const isWorkflowHistoryFeatureEnabled = computed(() => {
|
||||
return settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.WorkflowHistory);
|
||||
return settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.WorkflowHistory];
|
||||
});
|
||||
|
||||
const workflowHistoryRoute = computed<{ name: string; params: { workflowId: string } }>(() => {
|
||||
|
|
|
@ -439,7 +439,7 @@ const foreignCredentials = computed(() => {
|
|||
const usedCredentials = workflowsStore.usedCredentials;
|
||||
|
||||
const foreignCredentialsArray: string[] = [];
|
||||
if (credentials && settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
|
||||
if (credentials && settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing]) {
|
||||
Object.values(credentials).forEach((credential) => {
|
||||
if (
|
||||
credential.id &&
|
||||
|
|
|
@ -50,8 +50,8 @@ const valueInputRef = ref<HTMLElement>();
|
|||
|
||||
const usage = ref(`$vars.${props.data.name}`);
|
||||
|
||||
const isFeatureEnabled = computed(() =>
|
||||
settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Variables),
|
||||
const isFeatureEnabled = computed(
|
||||
() => settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Variables],
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -480,7 +480,7 @@ export default defineComponent({
|
|||
return this.usersStore.currentUser;
|
||||
},
|
||||
isSharingEnabled(): boolean {
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing);
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing];
|
||||
},
|
||||
workflowOwnerName(): string {
|
||||
const fallback = this.$locale.baseText(
|
||||
|
|
|
@ -197,7 +197,7 @@ export default defineComponent({
|
|||
useRolesStore,
|
||||
),
|
||||
isSharingEnabled(): boolean {
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing);
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing];
|
||||
},
|
||||
modalTitle(): string {
|
||||
if (this.isHomeTeamProject) {
|
||||
|
|
|
@ -43,8 +43,8 @@ const debouncedEmit = debounce(emit, {
|
|||
});
|
||||
|
||||
const isCustomDataFilterTracked = ref(false);
|
||||
const isAdvancedExecutionFilterEnabled = computed(() =>
|
||||
settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.AdvancedExecutionFilters),
|
||||
const isAdvancedExecutionFilterEnabled = computed(
|
||||
() => settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.AdvancedExecutionFilters],
|
||||
);
|
||||
const showTags = computed(() => false);
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { useRootStore } from '@/stores/root.store';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import type { WorkflowSettings } from 'n8n-workflow';
|
||||
|
||||
|
@ -38,60 +39,62 @@ type DebugInfo = {
|
|||
};
|
||||
|
||||
export function useDebugInfo() {
|
||||
const store = useSettingsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const rootStore = useRootStore();
|
||||
|
||||
const coreInfo = () => {
|
||||
return {
|
||||
n8nVersion: store.versionCli,
|
||||
n8nVersion: rootStore.versionCli,
|
||||
platform:
|
||||
store.isDocker && store.deploymentType === 'cloud'
|
||||
settingsStore.isDocker && settingsStore.deploymentType === 'cloud'
|
||||
? 'docker (cloud)'
|
||||
: store.isDocker
|
||||
: settingsStore.isDocker
|
||||
? 'docker (self-hosted)'
|
||||
: 'npm',
|
||||
nodeJsVersion: store.nodeJsVersion,
|
||||
nodeJsVersion: settingsStore.nodeJsVersion,
|
||||
database:
|
||||
store.databaseType === 'postgresdb'
|
||||
settingsStore.databaseType === 'postgresdb'
|
||||
? 'postgres'
|
||||
: store.databaseType === 'mysqldb'
|
||||
: settingsStore.databaseType === 'mysqldb'
|
||||
? 'mysql'
|
||||
: store.databaseType,
|
||||
executionMode: store.isQueueModeEnabled ? 'scaling' : 'regular',
|
||||
concurrency: store.settings.concurrency,
|
||||
license: store.isCommunityPlan
|
||||
: settingsStore.databaseType,
|
||||
executionMode: settingsStore.isQueueModeEnabled ? 'scaling' : 'regular',
|
||||
concurrency: settingsStore.settings.concurrency,
|
||||
license: settingsStore.isCommunityPlan
|
||||
? 'community'
|
||||
: store.settings.license.environment === 'production'
|
||||
: settingsStore.settings.license.environment === 'production'
|
||||
? 'enterprise (production)'
|
||||
: 'enterprise (sandbox)',
|
||||
consumerId: store.consumerId,
|
||||
consumerId: settingsStore.consumerId,
|
||||
} as const;
|
||||
};
|
||||
|
||||
const storageInfo = (): DebugInfo['storage'] => {
|
||||
return {
|
||||
success: store.saveDataSuccessExecution,
|
||||
error: store.saveDataErrorExecution,
|
||||
progress: store.saveDataProgressExecution,
|
||||
manual: store.saveManualExecutions,
|
||||
binaryMode: store.binaryDataMode === 'default' ? 'memory' : store.binaryDataMode,
|
||||
success: settingsStore.saveDataSuccessExecution,
|
||||
error: settingsStore.saveDataErrorExecution,
|
||||
progress: settingsStore.saveDataProgressExecution,
|
||||
manual: settingsStore.saveManualExecutions,
|
||||
binaryMode:
|
||||
settingsStore.binaryDataMode === 'default' ? 'memory' : settingsStore.binaryDataMode,
|
||||
};
|
||||
};
|
||||
|
||||
const pruningInfo = () => {
|
||||
if (!store.pruning.isEnabled) return { enabled: false } as const;
|
||||
if (!settingsStore.pruning.isEnabled) return { enabled: false } as const;
|
||||
|
||||
return {
|
||||
enabled: true,
|
||||
maxAge: `${store.pruning.maxAge} hours`,
|
||||
maxCount: `${store.pruning.maxCount} executions`,
|
||||
maxAge: `${settingsStore.pruning.maxAge} hours`,
|
||||
maxCount: `${settingsStore.pruning.maxCount} executions`,
|
||||
} as const;
|
||||
};
|
||||
|
||||
const securityInfo = () => {
|
||||
const info: DebugInfo['security'] = {};
|
||||
|
||||
if (!store.security.blockFileAccessToN8nFiles) info.blockFileAccessToN8nFiles = false;
|
||||
if (!store.security.secureCookie) info.secureCookie = false;
|
||||
if (!settingsStore.security.blockFileAccessToN8nFiles) info.blockFileAccessToN8nFiles = false;
|
||||
if (!settingsStore.security.secureCookie) info.secureCookie = false;
|
||||
|
||||
if (Object.keys(info).length === 0) return;
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ export const useExecutionDebugging = () => {
|
|||
const settingsStore = useSettingsStore();
|
||||
const uiStore = useUIStore();
|
||||
|
||||
const isDebugEnabled = computed(() =>
|
||||
settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.DebugInEditor),
|
||||
const isDebugEnabled = computed(
|
||||
() => settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.DebugInEditor],
|
||||
);
|
||||
|
||||
const applyExecutionData = async (executionId: string): Promise<void> => {
|
||||
|
|
|
@ -44,7 +44,7 @@ function setCurrentUser() {
|
|||
}
|
||||
|
||||
function resetStores() {
|
||||
useSettingsStore().$reset();
|
||||
useSettingsStore().reset();
|
||||
useUsersStore().reset();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ import { generateUpgradeLinkUrl, useUIStore } from '@/stores/ui.store';
|
|||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { merge } from 'lodash-es';
|
||||
import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
|
||||
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
||||
import * as cloudPlanApi from '@/api/cloudPlans';
|
||||
import { defaultSettings } from '../../__tests__/defaults';
|
||||
import {
|
||||
getTrialExpiredUserResponse,
|
||||
getTrialingUserResponse,
|
||||
|
@ -34,7 +34,7 @@ function setUser(role: IRole) {
|
|||
function setupOwnerAndCloudDeployment() {
|
||||
setUser(ROLE.Owner);
|
||||
settingsStore.setSettings(
|
||||
merge({}, SETTINGS_STORE_DEFAULT_STATE.settings, {
|
||||
merge({}, defaultSettings, {
|
||||
n8nMetadata: {
|
||||
userId: '1',
|
||||
},
|
||||
|
@ -103,7 +103,7 @@ describe('UI store', () => {
|
|||
setUser(role as IRole);
|
||||
|
||||
settingsStore.setSettings(
|
||||
merge({}, SETTINGS_STORE_DEFAULT_STATE.settings, {
|
||||
merge({}, defaultSettings, {
|
||||
deployment: {
|
||||
type,
|
||||
},
|
||||
|
@ -123,7 +123,7 @@ describe('UI store', () => {
|
|||
|
||||
it('should add non-production license banner to stack based on enterprise settings', () => {
|
||||
settingsStore.setSettings(
|
||||
merge({}, SETTINGS_STORE_DEFAULT_STATE.settings, {
|
||||
merge({}, defaultSettings, {
|
||||
enterprise: {
|
||||
showNonProdBanner: true,
|
||||
},
|
||||
|
@ -134,7 +134,7 @@ describe('UI store', () => {
|
|||
|
||||
it("should add V1 banner to stack if it's not dismissed", () => {
|
||||
settingsStore.setSettings(
|
||||
merge({}, SETTINGS_STORE_DEFAULT_STATE.settings, {
|
||||
merge({}, defaultSettings, {
|
||||
versionCli: '1.0.0',
|
||||
}),
|
||||
);
|
||||
|
@ -143,7 +143,7 @@ describe('UI store', () => {
|
|||
|
||||
it("should not add V1 banner to stack if it's dismissed", () => {
|
||||
settingsStore.setSettings(
|
||||
merge({}, SETTINGS_STORE_DEFAULT_STATE.settings, {
|
||||
merge({}, defaultSettings, {
|
||||
versionCli: '1.0.0',
|
||||
banners: {
|
||||
dismissed: ['V1'],
|
||||
|
|
|
@ -6,8 +6,8 @@ import { useSettingsStore } from '@/stores/settings.store';
|
|||
export const useAuditLogsStore = defineStore('auditLogs', () => {
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const isEnterpriseAuditLogsFeatureEnabled = computed(() =>
|
||||
settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.AuditLogs),
|
||||
const isEnterpriseAuditLogsFeatureEnabled = computed(
|
||||
() => settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.AuditLogs],
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
|
@ -314,7 +314,7 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, () => {
|
|||
projectId,
|
||||
);
|
||||
|
||||
if (settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
|
||||
if (settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing]) {
|
||||
upsertCredential(credential);
|
||||
if (data.sharedWithProjects) {
|
||||
await setCredentialSharedWith({
|
||||
|
@ -389,7 +389,7 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, () => {
|
|||
sharedWithProjects: ProjectSharingData[];
|
||||
credentialId: string;
|
||||
}): Promise<ICredentialsResponse> => {
|
||||
if (useSettingsStore().isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
|
||||
if (useSettingsStore().isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing]) {
|
||||
await credentialsEeApi.setCredentialSharedWith(
|
||||
useRootStore().restApiContext,
|
||||
payload.credentialId,
|
||||
|
|
|
@ -19,8 +19,8 @@ export const useExternalSecretsStore = defineStore('externalSecrets', () => {
|
|||
connectionState: {} as Record<string, ExternalSecretsProvider['state']>,
|
||||
});
|
||||
|
||||
const isEnterpriseExternalSecretsEnabled = computed(() =>
|
||||
settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.ExternalSecrets),
|
||||
const isEnterpriseExternalSecretsEnabled = computed(
|
||||
() => settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.ExternalSecrets],
|
||||
);
|
||||
|
||||
const secrets = computed(() => state.secrets);
|
||||
|
|
|
@ -1,27 +1,15 @@
|
|||
import { createApiKey, deleteApiKey, getApiKey } from '@/api/api-keys';
|
||||
import {
|
||||
getLdapConfig,
|
||||
getLdapSynchronizations,
|
||||
runLdapSync,
|
||||
testLdapConnection,
|
||||
updateLdapConfig,
|
||||
} from '@/api/ldap';
|
||||
import { getSettings, submitContactInfo } from '@/api/settings';
|
||||
import * as publicApiApi from '@/api/api-keys';
|
||||
import * as ldapApi from '@/api/ldap';
|
||||
import * as settingsApi from '@/api/settings';
|
||||
import { testHealthEndpoint } from '@/api/templates';
|
||||
import type {
|
||||
EnterpriseEditionFeatureValue,
|
||||
ILdapConfig,
|
||||
IN8nPromptResponse,
|
||||
ISettingsState,
|
||||
} from '@/Interface';
|
||||
import type { ILdapConfig } from '@/Interface';
|
||||
import { STORES, INSECURE_CONNECTION_WARNING } from '@/constants';
|
||||
import { UserManagementAuthenticationMethod } from '@/Interface';
|
||||
import type {
|
||||
IDataObject,
|
||||
LogLevel,
|
||||
IN8nUISettings,
|
||||
ITelemetrySettings,
|
||||
WorkflowSettings,
|
||||
IUserManagementSettings,
|
||||
} from 'n8n-workflow';
|
||||
import { ExpressionEvaluatorProxy } from 'n8n-workflow';
|
||||
import { defineStore } from 'pinia';
|
||||
|
@ -33,382 +21,422 @@ import { makeRestApiRequest } from '@/utils/apiUtils';
|
|||
import { useTitleChange } from '@/composables/useTitleChange';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { i18n } from '@/plugins/i18n';
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
||||
state: (): ISettingsState => ({
|
||||
initialized: false,
|
||||
settings: {} as IN8nUISettings,
|
||||
userManagement: {
|
||||
quota: -1,
|
||||
showSetupOnFirstLoad: false,
|
||||
smtpSetup: false,
|
||||
authenticationMethod: UserManagementAuthenticationMethod.Email,
|
||||
},
|
||||
templatesEndpointHealthy: false,
|
||||
api: {
|
||||
export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
|
||||
const initialized = ref(false);
|
||||
const settings = ref<IN8nUISettings>({} as IN8nUISettings);
|
||||
const userManagement = ref<IUserManagementSettings>({
|
||||
quota: -1,
|
||||
showSetupOnFirstLoad: false,
|
||||
smtpSetup: false,
|
||||
authenticationMethod: UserManagementAuthenticationMethod.Email,
|
||||
});
|
||||
const templatesEndpointHealthy = ref(false);
|
||||
const api = ref({
|
||||
enabled: false,
|
||||
latestVersion: 0,
|
||||
path: '/',
|
||||
swaggerUi: {
|
||||
enabled: false,
|
||||
latestVersion: 0,
|
||||
path: '/',
|
||||
swaggerUi: {
|
||||
},
|
||||
});
|
||||
const ldap = ref({ loginLabel: '', loginEnabled: false });
|
||||
const saml = ref({ loginLabel: '', loginEnabled: false });
|
||||
const mfa = ref({ enabled: false });
|
||||
const saveDataErrorExecution = ref<WorkflowSettings.SaveDataExecution>('all');
|
||||
const saveDataSuccessExecution = ref<WorkflowSettings.SaveDataExecution>('all');
|
||||
const saveManualExecutions = ref(false);
|
||||
const saveDataProgressExecution = ref(false);
|
||||
|
||||
const isDocker = computed(() => settings.value?.isDocker ?? false);
|
||||
|
||||
const databaseType = computed(() => settings.value?.databaseType);
|
||||
|
||||
const planName = computed(() => settings.value?.license.planName ?? 'Community');
|
||||
|
||||
const consumerId = computed(() => settings.value?.license.consumerId);
|
||||
|
||||
const binaryDataMode = computed(() => settings.value?.binaryDataMode);
|
||||
|
||||
const pruning = computed(() => settings.value?.pruning);
|
||||
|
||||
const security = computed(() => ({
|
||||
blockFileAccessToN8nFiles: settings.value.security.blockFileAccessToN8nFiles,
|
||||
secureCookie: settings.value.authCookie.secure,
|
||||
}));
|
||||
|
||||
const isEnterpriseFeatureEnabled = computed(() => settings.value.enterprise);
|
||||
|
||||
const nodeJsVersion = computed(() => settings.value.nodeJsVersion);
|
||||
|
||||
const concurrency = computed(() => settings.value.concurrency);
|
||||
|
||||
const isPublicApiEnabled = computed(() => api.value.enabled);
|
||||
|
||||
const isSwaggerUIEnabled = computed(() => api.value.swaggerUi.enabled);
|
||||
|
||||
const isPreviewMode = computed(() => settings.value.previewMode);
|
||||
|
||||
const publicApiLatestVersion = computed(() => api.value.latestVersion);
|
||||
|
||||
const publicApiPath = computed(() => api.value.path);
|
||||
|
||||
const isLdapLoginEnabled = computed(() => ldap.value.loginEnabled);
|
||||
|
||||
const ldapLoginLabel = computed(() => ldap.value.loginLabel);
|
||||
|
||||
const isSamlLoginEnabled = computed(() => saml.value.loginEnabled);
|
||||
|
||||
const showSetupPage = computed(() => userManagement.value.showSetupOnFirstLoad);
|
||||
|
||||
const deploymentType = computed(() => settings.value.deployment?.type || 'default');
|
||||
|
||||
const isDesktopDeployment = computed(() =>
|
||||
settings.value.deployment?.type.startsWith('desktop_'),
|
||||
);
|
||||
|
||||
const isCloudDeployment = computed(() => settings.value.deployment?.type === 'cloud');
|
||||
|
||||
const isSmtpSetup = computed(() => userManagement.value.smtpSetup);
|
||||
|
||||
const isPersonalizationSurveyEnabled = computed(
|
||||
() => settings.value.telemetry?.enabled && settings.value.personalizationSurveyEnabled,
|
||||
);
|
||||
|
||||
const telemetry = computed(() => settings.value.telemetry);
|
||||
|
||||
const logLevel = computed(() => settings.value.logLevel);
|
||||
|
||||
const isTelemetryEnabled = computed(
|
||||
() => settings.value.telemetry && settings.value.telemetry.enabled,
|
||||
);
|
||||
|
||||
const isMfaFeatureEnabled = computed(() => mfa.value.enabled);
|
||||
|
||||
const areTagsEnabled = computed(() =>
|
||||
settings.value.workflowTagsDisabled !== undefined ? !settings.value.workflowTagsDisabled : true,
|
||||
);
|
||||
|
||||
const isHiringBannerEnabled = computed(() => settings.value.hiringBannerEnabled);
|
||||
|
||||
const isTemplatesEnabled = computed(() =>
|
||||
Boolean(settings.value.templates && settings.value.templates.enabled),
|
||||
);
|
||||
|
||||
const isTemplatesEndpointReachable = computed(() => templatesEndpointHealthy.value);
|
||||
|
||||
const templatesHost = computed(() => settings.value.templates.host);
|
||||
|
||||
const pushBackend = computed(() => settings.value.pushBackend);
|
||||
|
||||
const isCommunityNodesFeatureEnabled = computed(() => settings.value.communityNodesEnabled);
|
||||
|
||||
const isNpmAvailable = computed(() => settings.value.isNpmAvailable);
|
||||
|
||||
const allowedModules = computed(() => settings.value.allowedModules);
|
||||
|
||||
const isQueueModeEnabled = computed(() => settings.value.executionMode === 'queue');
|
||||
|
||||
const isWorkerViewAvailable = computed(() => !!settings.value.enterprise?.workerView);
|
||||
|
||||
const workflowCallerPolicyDefaultOption = computed(
|
||||
() => settings.value.workflowCallerPolicyDefaultOption,
|
||||
);
|
||||
|
||||
const isDefaultAuthenticationSaml = computed(
|
||||
() => userManagement.value.authenticationMethod === UserManagementAuthenticationMethod.Saml,
|
||||
);
|
||||
|
||||
const permanentlyDismissedBanners = computed(() => settings.value.banners?.dismissed ?? []);
|
||||
|
||||
const isBelowUserQuota = computed(
|
||||
() =>
|
||||
userManagement.value.quota === -1 ||
|
||||
userManagement.value.quota > useUsersStore().allUsers.length,
|
||||
);
|
||||
|
||||
const isCommunityPlan = computed(() => planName.value.toLowerCase() === 'community');
|
||||
|
||||
const isDevRelease = computed(() => settings.value.releaseChannel === 'dev');
|
||||
|
||||
const setSettings = (newSettings: IN8nUISettings) => {
|
||||
settings.value = newSettings;
|
||||
userManagement.value = newSettings.userManagement;
|
||||
if (userManagement.value) {
|
||||
userManagement.value.showSetupOnFirstLoad =
|
||||
!!settings.value.userManagement.showSetupOnFirstLoad;
|
||||
}
|
||||
api.value = settings.value.publicApi;
|
||||
if (settings.value.sso?.ldap) {
|
||||
ldap.value.loginEnabled = settings.value.sso.ldap.loginEnabled;
|
||||
ldap.value.loginLabel = settings.value.sso.ldap.loginLabel;
|
||||
}
|
||||
if (settings.value.sso?.saml) {
|
||||
saml.value.loginEnabled = settings.value.sso.saml.loginEnabled;
|
||||
saml.value.loginLabel = settings.value.sso.saml.loginLabel;
|
||||
}
|
||||
|
||||
mfa.value.enabled = settings.value.mfa?.enabled;
|
||||
|
||||
if (settings.value.enterprise?.showNonProdBanner) {
|
||||
useUIStore().pushBannerToStack('NON_PRODUCTION_LICENSE');
|
||||
}
|
||||
|
||||
if (settings.value.versionCli) {
|
||||
useRootStore().setVersionCli(settings.value.versionCli);
|
||||
}
|
||||
|
||||
if (
|
||||
settings.value.authCookie.secure &&
|
||||
location.protocol === 'http:' &&
|
||||
!['localhost', '127.0.0.1'].includes(location.hostname)
|
||||
) {
|
||||
document.write(INSECURE_CONNECTION_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
const isV1BannerDismissedPermanently = (settings.value.banners?.dismissed || []).includes('V1');
|
||||
if (!isV1BannerDismissedPermanently && settings.value.versionCli.startsWith('1.')) {
|
||||
useUIStore().pushBannerToStack('V1');
|
||||
}
|
||||
};
|
||||
|
||||
const setAllowedModules = (allowedModules: IN8nUISettings['allowedModules']) => {
|
||||
settings.value.allowedModules = allowedModules;
|
||||
};
|
||||
|
||||
const setSaveDataErrorExecution = (newValue: WorkflowSettings.SaveDataExecution) => {
|
||||
saveDataErrorExecution.value = newValue;
|
||||
};
|
||||
|
||||
const setSaveDataSuccessExecution = (newValue: WorkflowSettings.SaveDataExecution) => {
|
||||
saveDataSuccessExecution.value = newValue;
|
||||
};
|
||||
|
||||
const setSaveManualExecutions = (newValue: boolean) => {
|
||||
saveManualExecutions.value = newValue;
|
||||
};
|
||||
|
||||
const setSaveDataProgressExecution = (newValue: boolean) => {
|
||||
saveDataProgressExecution.value = newValue;
|
||||
};
|
||||
|
||||
const getSettings = async () => {
|
||||
const rootStore = useRootStore();
|
||||
const fetchedSettings = await settingsApi.getSettings(rootStore.restApiContext);
|
||||
setSettings(fetchedSettings);
|
||||
settings.value.communityNodesEnabled = fetchedSettings.communityNodesEnabled;
|
||||
setAllowedModules(fetchedSettings.allowedModules);
|
||||
setSaveDataErrorExecution(fetchedSettings.saveDataErrorExecution);
|
||||
setSaveDataSuccessExecution(fetchedSettings.saveDataSuccessExecution);
|
||||
setSaveDataProgressExecution(fetchedSettings.saveExecutionProgress);
|
||||
setSaveManualExecutions(fetchedSettings.saveManualExecutions);
|
||||
|
||||
rootStore.setUrlBaseWebhook(fetchedSettings.urlBaseWebhook);
|
||||
rootStore.setUrlBaseEditor(fetchedSettings.urlBaseEditor);
|
||||
rootStore.setEndpointForm(fetchedSettings.endpointForm);
|
||||
rootStore.setEndpointFormTest(fetchedSettings.endpointFormTest);
|
||||
rootStore.setEndpointFormWaiting(fetchedSettings.endpointFormWaiting);
|
||||
rootStore.setEndpointWebhook(fetchedSettings.endpointWebhook);
|
||||
rootStore.setEndpointWebhookTest(fetchedSettings.endpointWebhookTest);
|
||||
rootStore.setTimezone(fetchedSettings.timezone);
|
||||
rootStore.setExecutionTimeout(fetchedSettings.executionTimeout);
|
||||
rootStore.setMaxExecutionTimeout(fetchedSettings.maxExecutionTimeout);
|
||||
rootStore.setInstanceId(fetchedSettings.instanceId);
|
||||
rootStore.setOauthCallbackUrls(fetchedSettings.oauthCallbackUrls);
|
||||
rootStore.setN8nMetadata(fetchedSettings.n8nMetadata || {});
|
||||
rootStore.setDefaultLocale(fetchedSettings.defaultLocale);
|
||||
rootStore.setIsNpmAvailable(fetchedSettings.isNpmAvailable);
|
||||
rootStore.setBinaryDataMode(fetchedSettings.binaryDataMode);
|
||||
useVersionsStore().setVersionNotificationSettings(fetchedSettings.versionNotifications);
|
||||
};
|
||||
|
||||
const initialize = async () => {
|
||||
if (initialized.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { showToast } = useToast();
|
||||
try {
|
||||
await getSettings();
|
||||
|
||||
ExpressionEvaluatorProxy.setEvaluator(settings.value.expressions.evaluator);
|
||||
|
||||
// Re-compute title since settings are now available
|
||||
useTitleChange().titleReset();
|
||||
|
||||
initialized.value = true;
|
||||
} catch (e) {
|
||||
showToast({
|
||||
title: i18n.baseText('startupError'),
|
||||
message: i18n.baseText('startupError.message'),
|
||||
type: 'error',
|
||||
duration: 0,
|
||||
dangerouslyUseHTMLString: true,
|
||||
});
|
||||
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
const stopShowingSetupPage = () => {
|
||||
userManagement.value.showSetupOnFirstLoad = false;
|
||||
};
|
||||
|
||||
const disableTemplates = () => {
|
||||
settings.value = {
|
||||
...settings.value,
|
||||
templates: {
|
||||
...settings.value.templates,
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
ldap: {
|
||||
loginLabel: '',
|
||||
loginEnabled: false,
|
||||
},
|
||||
saml: {
|
||||
loginLabel: '',
|
||||
loginEnabled: false,
|
||||
},
|
||||
mfa: {
|
||||
enabled: false,
|
||||
},
|
||||
saveDataErrorExecution: 'all',
|
||||
saveDataSuccessExecution: 'all',
|
||||
saveManualExecutions: false,
|
||||
saveDataProgressExecution: false,
|
||||
}),
|
||||
getters: {
|
||||
isDocker(): boolean {
|
||||
return this.settings.isDocker;
|
||||
},
|
||||
databaseType(): 'sqlite' | 'mariadb' | 'mysqldb' | 'postgresdb' {
|
||||
return this.settings.databaseType;
|
||||
},
|
||||
planName(): string {
|
||||
return this.settings.license?.planName ?? 'Community';
|
||||
},
|
||||
isCommunityPlan(): boolean {
|
||||
return this.planName.toLowerCase() === 'community';
|
||||
},
|
||||
consumerId(): string {
|
||||
return this.settings.license?.consumerId ?? 'unknown';
|
||||
},
|
||||
binaryDataMode(): 'default' | 'filesystem' | 's3' {
|
||||
return this.settings.binaryDataMode;
|
||||
},
|
||||
pruning(): { isEnabled: boolean; maxAge: number; maxCount: number } {
|
||||
return this.settings.pruning;
|
||||
},
|
||||
security(): {
|
||||
blockFileAccessToN8nFiles: boolean;
|
||||
secureCookie: boolean;
|
||||
} {
|
||||
return {
|
||||
blockFileAccessToN8nFiles: this.settings.security.blockFileAccessToN8nFiles,
|
||||
secureCookie: this.settings.authCookie.secure,
|
||||
};
|
||||
},
|
||||
isEnterpriseFeatureEnabled() {
|
||||
return (feature: EnterpriseEditionFeatureValue): boolean =>
|
||||
Boolean(this.settings.enterprise?.[feature]);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
versionCli(): string {
|
||||
return this.settings.versionCli;
|
||||
},
|
||||
nodeJsVersion(): string {
|
||||
return this.settings.nodeJsVersion;
|
||||
},
|
||||
concurrency(): number {
|
||||
return this.settings.concurrency;
|
||||
},
|
||||
isPublicApiEnabled(): boolean {
|
||||
return this.api.enabled;
|
||||
},
|
||||
isSwaggerUIEnabled(): boolean {
|
||||
return this.api.swaggerUi.enabled;
|
||||
},
|
||||
isPreviewMode(): boolean {
|
||||
return this.settings.previewMode;
|
||||
},
|
||||
publicApiLatestVersion(): number {
|
||||
return this.api.latestVersion;
|
||||
},
|
||||
publicApiPath(): string {
|
||||
return this.api.path;
|
||||
},
|
||||
isLdapLoginEnabled(): boolean {
|
||||
return this.ldap.loginEnabled;
|
||||
},
|
||||
ldapLoginLabel(): string {
|
||||
return this.ldap.loginLabel;
|
||||
},
|
||||
isSamlLoginEnabled(): boolean {
|
||||
return this.saml.loginEnabled;
|
||||
},
|
||||
samlLoginLabel(): string {
|
||||
return this.saml.loginLabel;
|
||||
},
|
||||
showSetupPage(): boolean {
|
||||
return this.userManagement.showSetupOnFirstLoad === true;
|
||||
},
|
||||
deploymentType(): string {
|
||||
return this.settings.deployment?.type || 'default';
|
||||
},
|
||||
isDesktopDeployment(): boolean {
|
||||
if (!this.settings.deployment) {
|
||||
return false;
|
||||
}
|
||||
return this.settings.deployment?.type.startsWith('desktop_');
|
||||
},
|
||||
isCloudDeployment(): boolean {
|
||||
return this.settings.deployment?.type === 'cloud';
|
||||
},
|
||||
isSmtpSetup(): boolean {
|
||||
return this.userManagement.smtpSetup;
|
||||
},
|
||||
isPersonalizationSurveyEnabled(): boolean {
|
||||
return (
|
||||
this.settings.telemetry &&
|
||||
this.settings.telemetry.enabled &&
|
||||
this.settings.personalizationSurveyEnabled
|
||||
const submitContactInfo = async (email: string) => {
|
||||
try {
|
||||
const usersStore = useUsersStore();
|
||||
return await settingsApi.submitContactInfo(
|
||||
settings.value.instanceId,
|
||||
usersStore.currentUserId || '',
|
||||
email,
|
||||
);
|
||||
},
|
||||
telemetry(): ITelemetrySettings {
|
||||
return this.settings.telemetry;
|
||||
},
|
||||
logLevel(): LogLevel {
|
||||
return this.settings.logLevel;
|
||||
},
|
||||
isTelemetryEnabled(): boolean {
|
||||
return this.settings.telemetry && this.settings.telemetry.enabled;
|
||||
},
|
||||
isMfaFeatureEnabled(): boolean {
|
||||
return this.settings?.mfa?.enabled;
|
||||
},
|
||||
areTagsEnabled(): boolean {
|
||||
return this.settings.workflowTagsDisabled !== undefined
|
||||
? !this.settings.workflowTagsDisabled
|
||||
: true;
|
||||
},
|
||||
isHiringBannerEnabled(): boolean {
|
||||
return this.settings.hiringBannerEnabled;
|
||||
},
|
||||
isTemplatesEnabled(): boolean {
|
||||
return Boolean(this.settings.templates && this.settings.templates.enabled);
|
||||
},
|
||||
isTemplatesEndpointReachable(): boolean {
|
||||
return this.templatesEndpointHealthy;
|
||||
},
|
||||
templatesHost(): string {
|
||||
return this.settings.templates.host;
|
||||
},
|
||||
pushBackend(): IN8nUISettings['pushBackend'] {
|
||||
return this.settings.pushBackend;
|
||||
},
|
||||
isCommunityNodesFeatureEnabled(): boolean {
|
||||
return this.settings.communityNodesEnabled;
|
||||
},
|
||||
isNpmAvailable(): boolean {
|
||||
return this.settings.isNpmAvailable;
|
||||
},
|
||||
allowedModules(): { builtIn?: string[]; external?: string[] } {
|
||||
return this.settings.allowedModules;
|
||||
},
|
||||
isQueueModeEnabled(): boolean {
|
||||
return this.settings.executionMode === 'queue';
|
||||
},
|
||||
isWorkerViewAvailable(): boolean {
|
||||
return !!this.settings.enterprise?.workerView;
|
||||
},
|
||||
workflowCallerPolicyDefaultOption(): WorkflowSettings.CallerPolicy {
|
||||
return this.settings.workflowCallerPolicyDefaultOption;
|
||||
},
|
||||
isDefaultAuthenticationSaml(): boolean {
|
||||
return this.userManagement.authenticationMethod === UserManagementAuthenticationMethod.Saml;
|
||||
},
|
||||
permanentlyDismissedBanners(): string[] {
|
||||
return this.settings.banners?.dismissed ?? [];
|
||||
},
|
||||
isBelowUserQuota(): boolean {
|
||||
const userStore = useUsersStore();
|
||||
return (
|
||||
this.userManagement.quota === -1 || this.userManagement.quota > userStore.allUsers.length
|
||||
);
|
||||
},
|
||||
isDevRelease(): boolean {
|
||||
return this.settings.releaseChannel === 'dev';
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async initialize() {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const { showToast } = useToast();
|
||||
try {
|
||||
await this.getSettings();
|
||||
const testTemplatesEndpoint = async () => {
|
||||
const timeout = new Promise((_, reject) => setTimeout(() => reject(), 2000));
|
||||
await Promise.race([testHealthEndpoint(templatesHost.value), timeout]);
|
||||
templatesEndpointHealthy.value = true;
|
||||
};
|
||||
|
||||
ExpressionEvaluatorProxy.setEvaluator(this.settings.expressions.evaluator);
|
||||
const getApiKey = async () => {
|
||||
const rootStore = useRootStore();
|
||||
const { apiKey } = await publicApiApi.getApiKey(rootStore.restApiContext);
|
||||
return apiKey;
|
||||
};
|
||||
|
||||
// Re-compute title since settings are now available
|
||||
useTitleChange().titleReset();
|
||||
const createApiKey = async () => {
|
||||
const rootStore = useRootStore();
|
||||
const { apiKey } = await publicApiApi.createApiKey(rootStore.restApiContext);
|
||||
return apiKey;
|
||||
};
|
||||
|
||||
this.initialized = true;
|
||||
} catch (e) {
|
||||
showToast({
|
||||
title: i18n.baseText('startupError'),
|
||||
message: i18n.baseText('startupError.message'),
|
||||
type: 'error',
|
||||
duration: 0,
|
||||
dangerouslyUseHTMLString: true,
|
||||
});
|
||||
const deleteApiKey = async () => {
|
||||
const rootStore = useRootStore();
|
||||
await publicApiApi.deleteApiKey(rootStore.restApiContext);
|
||||
};
|
||||
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
setSettings(settings: IN8nUISettings): void {
|
||||
this.settings = settings;
|
||||
this.userManagement = settings.userManagement;
|
||||
if (this.userManagement) {
|
||||
this.userManagement.showSetupOnFirstLoad = !!settings.userManagement.showSetupOnFirstLoad;
|
||||
}
|
||||
this.api = settings.publicApi;
|
||||
if (settings.sso?.ldap) {
|
||||
this.ldap.loginEnabled = settings.sso.ldap.loginEnabled;
|
||||
this.ldap.loginLabel = settings.sso.ldap.loginLabel;
|
||||
}
|
||||
if (settings.sso?.saml) {
|
||||
this.saml.loginEnabled = settings.sso.saml.loginEnabled;
|
||||
this.saml.loginLabel = settings.sso.saml.loginLabel;
|
||||
}
|
||||
if (settings.enterprise?.showNonProdBanner) {
|
||||
useUIStore().pushBannerToStack('NON_PRODUCTION_LICENSE');
|
||||
}
|
||||
if (settings.versionCli) {
|
||||
useRootStore().setVersionCli(settings.versionCli);
|
||||
}
|
||||
const getLdapConfig = async () => {
|
||||
const rootStore = useRootStore();
|
||||
return await ldapApi.getLdapConfig(rootStore.restApiContext);
|
||||
};
|
||||
|
||||
if (
|
||||
settings.authCookie.secure &&
|
||||
location.protocol === 'http:' &&
|
||||
!['localhost', '127.0.0.1'].includes(location.hostname)
|
||||
) {
|
||||
document.write(INSECURE_CONNECTION_WARNING);
|
||||
return;
|
||||
}
|
||||
const getLdapSynchronizations = async (pagination: { page: number }) => {
|
||||
const rootStore = useRootStore();
|
||||
return await ldapApi.getLdapSynchronizations(rootStore.restApiContext, pagination);
|
||||
};
|
||||
|
||||
const isV1BannerDismissedPermanently = (settings.banners?.dismissed || []).includes('V1');
|
||||
if (!isV1BannerDismissedPermanently && useRootStore().versionCli.startsWith('1.')) {
|
||||
useUIStore().pushBannerToStack('V1');
|
||||
}
|
||||
},
|
||||
async getSettings(): Promise<void> {
|
||||
const rootStore = useRootStore();
|
||||
const settings = await getSettings(rootStore.restApiContext);
|
||||
const testLdapConnection = async () => {
|
||||
const rootStore = useRootStore();
|
||||
return await ldapApi.testLdapConnection(rootStore.restApiContext);
|
||||
};
|
||||
|
||||
this.setSettings(settings);
|
||||
this.settings.communityNodesEnabled = settings.communityNodesEnabled;
|
||||
this.setAllowedModules(settings.allowedModules);
|
||||
this.setSaveDataErrorExecution(settings.saveDataErrorExecution);
|
||||
this.setSaveDataSuccessExecution(settings.saveDataSuccessExecution);
|
||||
this.setSaveDataProgressExecution(settings.saveExecutionProgress);
|
||||
this.setSaveManualExecutions(settings.saveManualExecutions);
|
||||
const updateLdapConfig = async (ldapConfig: ILdapConfig) => {
|
||||
const rootStore = useRootStore();
|
||||
return await ldapApi.updateLdapConfig(rootStore.restApiContext, ldapConfig);
|
||||
};
|
||||
|
||||
rootStore.setUrlBaseWebhook(settings.urlBaseWebhook);
|
||||
rootStore.setUrlBaseEditor(settings.urlBaseEditor);
|
||||
rootStore.setEndpointForm(settings.endpointForm);
|
||||
rootStore.setEndpointFormTest(settings.endpointFormTest);
|
||||
rootStore.setEndpointFormWaiting(settings.endpointFormWaiting);
|
||||
rootStore.setEndpointWebhook(settings.endpointWebhook);
|
||||
rootStore.setEndpointWebhookTest(settings.endpointWebhookTest);
|
||||
rootStore.setTimezone(settings.timezone);
|
||||
rootStore.setExecutionTimeout(settings.executionTimeout);
|
||||
rootStore.setMaxExecutionTimeout(settings.maxExecutionTimeout);
|
||||
rootStore.setVersionCli(settings.versionCli);
|
||||
rootStore.setInstanceId(settings.instanceId);
|
||||
rootStore.setOauthCallbackUrls(settings.oauthCallbackUrls);
|
||||
rootStore.setN8nMetadata(settings.n8nMetadata || {});
|
||||
rootStore.setDefaultLocale(settings.defaultLocale);
|
||||
rootStore.setIsNpmAvailable(settings.isNpmAvailable);
|
||||
rootStore.setBinaryDataMode(settings.binaryDataMode);
|
||||
const runLdapSync = async (data: IDataObject) => {
|
||||
const rootStore = useRootStore();
|
||||
return await ldapApi.runLdapSync(rootStore.restApiContext, data);
|
||||
};
|
||||
|
||||
useVersionsStore().setVersionNotificationSettings(settings.versionNotifications);
|
||||
},
|
||||
stopShowingSetupPage(): void {
|
||||
this.userManagement.showSetupOnFirstLoad = false;
|
||||
},
|
||||
disableTemplates(): void {
|
||||
this.settings = {
|
||||
...this.settings,
|
||||
templates: {
|
||||
...this.settings.templates,
|
||||
enabled: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
setAllowedModules(allowedModules: { builtIn?: string[]; external?: string[] }): void {
|
||||
this.settings.allowedModules = allowedModules;
|
||||
},
|
||||
async submitContactInfo(email: string): Promise<IN8nPromptResponse | undefined> {
|
||||
try {
|
||||
const usersStore = useUsersStore();
|
||||
return await submitContactInfo(
|
||||
this.settings.instanceId,
|
||||
usersStore.currentUserId || '',
|
||||
email,
|
||||
);
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
async testTemplatesEndpoint(): Promise<void> {
|
||||
const timeout = new Promise((_, reject) => setTimeout(() => reject(), 2000));
|
||||
await Promise.race([testHealthEndpoint(this.templatesHost), timeout]);
|
||||
this.templatesEndpointHealthy = true;
|
||||
},
|
||||
async getApiKey(): Promise<string | null> {
|
||||
const rootStore = useRootStore();
|
||||
const { apiKey } = await getApiKey(rootStore.restApiContext);
|
||||
return apiKey;
|
||||
},
|
||||
async createApiKey(): Promise<string | null> {
|
||||
const rootStore = useRootStore();
|
||||
const { apiKey } = await createApiKey(rootStore.restApiContext);
|
||||
return apiKey;
|
||||
},
|
||||
async deleteApiKey(): Promise<void> {
|
||||
const rootStore = useRootStore();
|
||||
await deleteApiKey(rootStore.restApiContext);
|
||||
},
|
||||
async getLdapConfig() {
|
||||
const rootStore = useRootStore();
|
||||
return await getLdapConfig(rootStore.restApiContext);
|
||||
},
|
||||
async getLdapSynchronizations(pagination: { page: number }) {
|
||||
const rootStore = useRootStore();
|
||||
return await getLdapSynchronizations(rootStore.restApiContext, pagination);
|
||||
},
|
||||
async testLdapConnection() {
|
||||
const rootStore = useRootStore();
|
||||
return await testLdapConnection(rootStore.restApiContext);
|
||||
},
|
||||
async updateLdapConfig(ldapConfig: ILdapConfig) {
|
||||
const rootStore = useRootStore();
|
||||
return await updateLdapConfig(rootStore.restApiContext, ldapConfig);
|
||||
},
|
||||
async runLdapSync(data: IDataObject) {
|
||||
const rootStore = useRootStore();
|
||||
return await runLdapSync(rootStore.restApiContext, data);
|
||||
},
|
||||
setSaveDataErrorExecution(newValue: WorkflowSettings.SaveDataExecution) {
|
||||
this.saveDataErrorExecution = newValue;
|
||||
},
|
||||
setSaveDataSuccessExecution(newValue: WorkflowSettings.SaveDataExecution) {
|
||||
this.saveDataSuccessExecution = newValue;
|
||||
},
|
||||
setSaveManualExecutions(saveManualExecutions: boolean) {
|
||||
this.saveManualExecutions = saveManualExecutions;
|
||||
},
|
||||
setSaveDataProgressExecution(newValue: boolean) {
|
||||
this.saveDataProgressExecution = newValue;
|
||||
},
|
||||
async getTimezones(): Promise<IDataObject> {
|
||||
const rootStore = useRootStore();
|
||||
return await makeRestApiRequest(rootStore.restApiContext, 'GET', '/options/timezones');
|
||||
},
|
||||
},
|
||||
const getTimezones = async (): Promise<IDataObject> => {
|
||||
const rootStore = useRootStore();
|
||||
return await makeRestApiRequest(rootStore.restApiContext, 'GET', '/options/timezones');
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
settings.value = {} as IN8nUISettings;
|
||||
};
|
||||
|
||||
return {
|
||||
settings,
|
||||
userManagement,
|
||||
templatesEndpointHealthy,
|
||||
api,
|
||||
ldap,
|
||||
saml,
|
||||
mfa,
|
||||
isDocker,
|
||||
isDevRelease,
|
||||
isEnterpriseFeatureEnabled,
|
||||
databaseType,
|
||||
planName,
|
||||
consumerId,
|
||||
binaryDataMode,
|
||||
pruning,
|
||||
security,
|
||||
nodeJsVersion,
|
||||
concurrency,
|
||||
isPublicApiEnabled,
|
||||
isSwaggerUIEnabled,
|
||||
isPreviewMode,
|
||||
publicApiLatestVersion,
|
||||
publicApiPath,
|
||||
isLdapLoginEnabled,
|
||||
ldapLoginLabel,
|
||||
isSamlLoginEnabled,
|
||||
showSetupPage,
|
||||
deploymentType,
|
||||
isDesktopDeployment,
|
||||
isCloudDeployment,
|
||||
isSmtpSetup,
|
||||
isPersonalizationSurveyEnabled,
|
||||
telemetry,
|
||||
logLevel,
|
||||
isTelemetryEnabled,
|
||||
isMfaFeatureEnabled,
|
||||
areTagsEnabled,
|
||||
isHiringBannerEnabled,
|
||||
isTemplatesEnabled,
|
||||
isTemplatesEndpointReachable,
|
||||
templatesHost,
|
||||
pushBackend,
|
||||
isCommunityNodesFeatureEnabled,
|
||||
isNpmAvailable,
|
||||
allowedModules,
|
||||
isQueueModeEnabled,
|
||||
isWorkerViewAvailable,
|
||||
isDefaultAuthenticationSaml,
|
||||
workflowCallerPolicyDefaultOption,
|
||||
permanentlyDismissedBanners,
|
||||
isBelowUserQuota,
|
||||
saveDataErrorExecution,
|
||||
saveDataSuccessExecution,
|
||||
saveManualExecutions,
|
||||
saveDataProgressExecution,
|
||||
isCommunityPlan,
|
||||
reset,
|
||||
testLdapConnection,
|
||||
getLdapConfig,
|
||||
getLdapSynchronizations,
|
||||
updateLdapConfig,
|
||||
runLdapSync,
|
||||
getTimezones,
|
||||
createApiKey,
|
||||
getApiKey,
|
||||
deleteApiKey,
|
||||
testTemplatesEndpoint,
|
||||
submitContactInfo,
|
||||
disableTemplates,
|
||||
stopShowingSetupPage,
|
||||
getSettings,
|
||||
setSettings,
|
||||
initialize,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -11,8 +11,8 @@ export const useSourceControlStore = defineStore('sourceControl', () => {
|
|||
const rootStore = useRootStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const isEnterpriseSourceControlEnabled = computed(() =>
|
||||
settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.SourceControl),
|
||||
const isEnterpriseSourceControlEnabled = computed(
|
||||
() => settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.SourceControl],
|
||||
);
|
||||
|
||||
const sshKeyTypes: SshKeyTypes = ['ed25519', 'rsa'];
|
||||
|
|
|
@ -42,8 +42,8 @@ export const useSSOStore = defineStore('sso', () => {
|
|||
void toggleLoginEnabled(value);
|
||||
},
|
||||
});
|
||||
const isEnterpriseSamlEnabled = computed(() =>
|
||||
settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Saml),
|
||||
const isEnterpriseSamlEnabled = computed(
|
||||
() => settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Saml],
|
||||
);
|
||||
const isDefaultAuthenticationSaml = computed(() => settingsStore.isDefaultAuthenticationSaml);
|
||||
const showSsoLoginButton = computed(
|
||||
|
|
|
@ -289,8 +289,9 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
},
|
||||
async fetchTemplateById(templateId: string): Promise<ITemplatesWorkflowFull> {
|
||||
const settingsStore = useSettingsStore();
|
||||
const rootStore = useRootStore();
|
||||
const apiEndpoint: string = settingsStore.templatesHost;
|
||||
const versionCli: string = settingsStore.versionCli;
|
||||
const versionCli: string = rootStore.versionCli;
|
||||
const response = await getTemplateById(apiEndpoint, templateId, {
|
||||
'n8n-version': versionCli,
|
||||
});
|
||||
|
@ -305,8 +306,9 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
},
|
||||
async fetchCollectionById(collectionId: string): Promise<ITemplatesCollection | null> {
|
||||
const settingsStore = useSettingsStore();
|
||||
const rootStore = useRootStore();
|
||||
const apiEndpoint: string = settingsStore.templatesHost;
|
||||
const versionCli: string = settingsStore.versionCli;
|
||||
const versionCli: string = rootStore.versionCli;
|
||||
const response = await getCollectionById(apiEndpoint, collectionId, {
|
||||
'n8n-version': versionCli,
|
||||
});
|
||||
|
@ -325,8 +327,9 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
return cachedCategories;
|
||||
}
|
||||
const settingsStore = useSettingsStore();
|
||||
const rootStore = useRootStore();
|
||||
const apiEndpoint: string = settingsStore.templatesHost;
|
||||
const versionCli: string = settingsStore.versionCli;
|
||||
const versionCli: string = rootStore.versionCli;
|
||||
const response = await getCategories(apiEndpoint, { 'n8n-version': versionCli });
|
||||
const categories = response.categories;
|
||||
|
||||
|
@ -340,8 +343,9 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
}
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const rootStore = useRootStore();
|
||||
const apiEndpoint: string = settingsStore.templatesHost;
|
||||
const versionCli: string = settingsStore.versionCli;
|
||||
const versionCli: string = rootStore.versionCli;
|
||||
const response = await getCollections(apiEndpoint, query, { 'n8n-version': versionCli });
|
||||
const collections = response.collections;
|
||||
|
||||
|
@ -361,8 +365,9 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
}
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const rootStore = useRootStore();
|
||||
const apiEndpoint: string = settingsStore.templatesHost;
|
||||
const versionCli: string = settingsStore.versionCli;
|
||||
const versionCli: string = rootStore.versionCli;
|
||||
|
||||
const payload = await getWorkflows(
|
||||
apiEndpoint,
|
||||
|
@ -402,8 +407,9 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
},
|
||||
async getWorkflowTemplate(templateId: string): Promise<IWorkflowTemplate> {
|
||||
const settingsStore = useSettingsStore();
|
||||
const rootStore = useRootStore();
|
||||
const apiEndpoint: string = settingsStore.templatesHost;
|
||||
const versionCli: string = settingsStore.versionCli;
|
||||
const versionCli: string = rootStore.versionCli;
|
||||
return await getWorkflowTemplate(apiEndpoint, templateId, { 'n8n-version': versionCli });
|
||||
},
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ export const useWorkflowsEEStore = defineStore(STORES.WORKFLOWS_EE, {
|
|||
const rootStore = useRootStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
if (settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
|
||||
if (settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing]) {
|
||||
await setWorkflowSharedWith(rootStore.restApiContext, payload.workflowId, {
|
||||
shareWithIds: payload.sharedWithProjects.map((p) => p.id),
|
||||
});
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { isEnterpriseFeatureEnabled } from '@/utils/rbac/checks/isEnterpriseFeatureEnabled';
|
||||
import { EnterpriseEditionFeature } from '@/constants';
|
||||
|
||||
vi.mock('@/stores/settings.store', () => ({
|
||||
useSettingsStore: vi.fn(),
|
||||
}));
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
import { defaultSettings } from '@/__tests__/defaults';
|
||||
|
||||
describe('Checks', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia());
|
||||
});
|
||||
|
||||
describe('isEnterpriseFeatureEnabled()', () => {
|
||||
it('should return true if no feature is provided', () => {
|
||||
expect(isEnterpriseFeatureEnabled({})).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if feature is enabled', () => {
|
||||
vi.mocked(useSettingsStore).mockReturnValue({
|
||||
isEnterpriseFeatureEnabled: vi
|
||||
.fn()
|
||||
.mockImplementation((feature) => feature !== EnterpriseEditionFeature.Variables),
|
||||
} as unknown as ReturnType<typeof useSettingsStore>);
|
||||
useSettingsStore().settings.enterprise = {
|
||||
...defaultSettings.enterprise,
|
||||
[EnterpriseEditionFeature.Saml]: true,
|
||||
};
|
||||
|
||||
expect(
|
||||
isEnterpriseFeatureEnabled({
|
||||
|
@ -27,11 +28,11 @@ describe('Checks', () => {
|
|||
});
|
||||
|
||||
it('should return true if all features are enabled in allOf mode', () => {
|
||||
vi.mocked(useSettingsStore).mockReturnValue({
|
||||
isEnterpriseFeatureEnabled: vi
|
||||
.fn()
|
||||
.mockImplementation((feature) => feature !== EnterpriseEditionFeature.Variables),
|
||||
} as unknown as ReturnType<typeof useSettingsStore>);
|
||||
useSettingsStore().settings.enterprise = {
|
||||
...defaultSettings.enterprise,
|
||||
[EnterpriseEditionFeature.Ldap]: true,
|
||||
[EnterpriseEditionFeature.Saml]: true,
|
||||
};
|
||||
|
||||
expect(
|
||||
isEnterpriseFeatureEnabled({
|
||||
|
@ -42,11 +43,11 @@ describe('Checks', () => {
|
|||
});
|
||||
|
||||
it('should return false if any feature is not enabled in allOf mode', () => {
|
||||
vi.mocked(useSettingsStore).mockReturnValue({
|
||||
isEnterpriseFeatureEnabled: vi
|
||||
.fn()
|
||||
.mockImplementation((feature) => feature !== EnterpriseEditionFeature.Saml),
|
||||
} as unknown as ReturnType<typeof useSettingsStore>);
|
||||
useSettingsStore().settings.enterprise = {
|
||||
...defaultSettings.enterprise,
|
||||
[EnterpriseEditionFeature.Ldap]: true,
|
||||
[EnterpriseEditionFeature.Saml]: false,
|
||||
};
|
||||
|
||||
expect(
|
||||
isEnterpriseFeatureEnabled({
|
||||
|
@ -57,11 +58,11 @@ describe('Checks', () => {
|
|||
});
|
||||
|
||||
it('should return true if any feature is enabled in oneOf mode', () => {
|
||||
vi.mocked(useSettingsStore).mockReturnValue({
|
||||
isEnterpriseFeatureEnabled: vi
|
||||
.fn()
|
||||
.mockImplementation((feature) => feature === EnterpriseEditionFeature.Ldap),
|
||||
} as unknown as ReturnType<typeof useSettingsStore>);
|
||||
useSettingsStore().settings.enterprise = {
|
||||
...defaultSettings.enterprise,
|
||||
[EnterpriseEditionFeature.Ldap]: true,
|
||||
[EnterpriseEditionFeature.Saml]: false,
|
||||
};
|
||||
|
||||
expect(
|
||||
isEnterpriseFeatureEnabled({
|
||||
|
@ -72,9 +73,11 @@ describe('Checks', () => {
|
|||
});
|
||||
|
||||
it('should return false if no features are enabled in anyOf mode', () => {
|
||||
vi.mocked(useSettingsStore).mockReturnValue({
|
||||
isEnterpriseFeatureEnabled: vi.fn().mockReturnValue(false),
|
||||
} as unknown as ReturnType<typeof useSettingsStore>);
|
||||
useSettingsStore().settings.enterprise = {
|
||||
...defaultSettings.enterprise,
|
||||
[EnterpriseEditionFeature.Ldap]: false,
|
||||
[EnterpriseEditionFeature.Saml]: false,
|
||||
};
|
||||
|
||||
expect(
|
||||
isEnterpriseFeatureEnabled({
|
||||
|
|
|
@ -12,8 +12,8 @@ export const isEnterpriseFeatureEnabled: RBACPermissionCheck<EnterprisePermissio
|
|||
const settingsStore = useSettingsStore();
|
||||
const mode = options.mode ?? 'allOf';
|
||||
if (mode === 'allOf') {
|
||||
return features.every(settingsStore.isEnterpriseFeatureEnabled);
|
||||
return features.every((feature) => settingsStore.isEnterpriseFeatureEnabled[feature]);
|
||||
} else {
|
||||
return features.some(settingsStore.isEnterpriseFeatureEnabled);
|
||||
return features.some((feature) => settingsStore.isEnterpriseFeatureEnabled[feature]);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,17 +3,21 @@ import { VIEWS, EnterpriseEditionFeature } from '@/constants';
|
|||
import { enterpriseMiddleware } from '@/utils/rbac/middleware/enterprise';
|
||||
import { type RouteLocationNormalized } from 'vue-router';
|
||||
import type { EnterprisePermissionOptions } from '@/types/rbac';
|
||||
|
||||
vi.mock('@/stores/settings.store', () => ({
|
||||
useSettingsStore: vi.fn(),
|
||||
}));
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
import { defaultSettings } from '@/__tests__/defaults';
|
||||
|
||||
describe('Middleware', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia());
|
||||
});
|
||||
|
||||
describe('enterprise', () => {
|
||||
it('should redirect to homepage if none of the required features are enabled in allOf mode', async () => {
|
||||
vi.mocked(useSettingsStore).mockReturnValue({
|
||||
isEnterpriseFeatureEnabled: (_) => false,
|
||||
} as ReturnType<typeof useSettingsStore>);
|
||||
useSettingsStore().settings.enterprise = {
|
||||
...defaultSettings.enterprise,
|
||||
[EnterpriseEditionFeature.Ldap]: false,
|
||||
[EnterpriseEditionFeature.Saml]: false,
|
||||
};
|
||||
|
||||
const nextMock = vi.fn();
|
||||
const options: EnterprisePermissionOptions = {
|
||||
|
@ -32,10 +36,11 @@ describe('Middleware', () => {
|
|||
});
|
||||
|
||||
it('should allow navigation if all of the required features are enabled in allOf mode', async () => {
|
||||
vi.mocked(useSettingsStore).mockReturnValue({
|
||||
isEnterpriseFeatureEnabled: (feature) =>
|
||||
[EnterpriseEditionFeature.Saml, EnterpriseEditionFeature.Ldap].includes(feature),
|
||||
} as ReturnType<typeof useSettingsStore>);
|
||||
useSettingsStore().settings.enterprise = {
|
||||
...defaultSettings.enterprise,
|
||||
[EnterpriseEditionFeature.Ldap]: true,
|
||||
[EnterpriseEditionFeature.Saml]: true,
|
||||
};
|
||||
|
||||
const nextMock = vi.fn();
|
||||
const options: EnterprisePermissionOptions = {
|
||||
|
@ -54,9 +59,10 @@ describe('Middleware', () => {
|
|||
});
|
||||
|
||||
it('should redirect to homepage if none of the required features are enabled in oneOf mode', async () => {
|
||||
vi.mocked(useSettingsStore).mockReturnValue({
|
||||
isEnterpriseFeatureEnabled: (_) => false,
|
||||
} as ReturnType<typeof useSettingsStore>);
|
||||
useSettingsStore().settings.enterprise = {
|
||||
...defaultSettings.enterprise,
|
||||
[EnterpriseEditionFeature.Saml]: false,
|
||||
};
|
||||
|
||||
const nextMock = vi.fn();
|
||||
const options: EnterprisePermissionOptions = {
|
||||
|
@ -75,9 +81,11 @@ describe('Middleware', () => {
|
|||
});
|
||||
|
||||
it('should allow navigation if at least one of the required features is enabled in oneOf mode', async () => {
|
||||
vi.mocked(useSettingsStore).mockReturnValue({
|
||||
isEnterpriseFeatureEnabled: (feature) => feature === EnterpriseEditionFeature.Saml,
|
||||
} as ReturnType<typeof useSettingsStore>);
|
||||
useSettingsStore().settings.enterprise = {
|
||||
...defaultSettings.enterprise,
|
||||
[EnterpriseEditionFeature.Ldap]: true,
|
||||
[EnterpriseEditionFeature.Saml]: false,
|
||||
};
|
||||
|
||||
const nextMock = vi.fn();
|
||||
const options: EnterprisePermissionOptions = {
|
||||
|
|
|
@ -159,9 +159,8 @@ export default defineComponent({
|
|||
},
|
||||
async initialize() {
|
||||
this.loading = true;
|
||||
const isVarsEnabled = useSettingsStore().isEnterpriseFeatureEnabled(
|
||||
EnterpriseEditionFeature.Variables,
|
||||
);
|
||||
const isVarsEnabled =
|
||||
useSettingsStore().isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Variables];
|
||||
|
||||
const loadPromises = [
|
||||
this.credentialsStore.fetchAllCredentials(
|
||||
|
|
|
@ -210,11 +210,11 @@ async function initializeData() {
|
|||
credentialsStore.fetchCredentialTypes(true),
|
||||
];
|
||||
|
||||
if (settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Variables)) {
|
||||
if (settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Variables]) {
|
||||
promises.push(environmentsStore.fetchAllVariables());
|
||||
}
|
||||
|
||||
if (settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.ExternalSecrets)) {
|
||||
if (settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.ExternalSecrets]) {
|
||||
promises.push(externalSecretsStore.fetchAllSecrets());
|
||||
}
|
||||
|
||||
|
|
|
@ -833,10 +833,10 @@ export default defineComponent({
|
|||
const loadPromises = (() => {
|
||||
if (this.settingsStore.isPreviewMode && this.isDemo) return [];
|
||||
const promises = [this.loadActiveWorkflows(), this.loadCredentialTypes()];
|
||||
if (this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Variables)) {
|
||||
if (this.settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Variables]) {
|
||||
promises.push(this.loadVariables());
|
||||
}
|
||||
if (this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.ExternalSecrets)) {
|
||||
if (this.settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.ExternalSecrets]) {
|
||||
promises.push(this.loadSecrets());
|
||||
}
|
||||
return promises;
|
||||
|
@ -4208,7 +4208,7 @@ export default defineComponent({
|
|||
|
||||
if (
|
||||
nodeData.credentials &&
|
||||
this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)
|
||||
this.settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing]
|
||||
) {
|
||||
const usedCredentials = this.workflowsStore.usedCredentials;
|
||||
nodeData.credentials = Object.fromEntries(
|
||||
|
|
|
@ -153,7 +153,7 @@ export default defineComponent({
|
|||
},
|
||||
isLicensed(): boolean {
|
||||
if (this.disableLicense) return false;
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.LogStreaming);
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.LogStreaming];
|
||||
},
|
||||
canManageLogStreaming(): boolean {
|
||||
return hasPermission(['rbac'], { rbac: { scope: 'logStreaming:manage' } });
|
||||
|
|
|
@ -76,7 +76,7 @@ const usersListActions = computed((): IUserListAction[] => {
|
|||
];
|
||||
});
|
||||
const isAdvancedPermissionsEnabled = computed((): boolean => {
|
||||
return settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.AdvancedPermissions);
|
||||
return settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.AdvancedPermissions];
|
||||
});
|
||||
|
||||
const userRoles = computed((): Array<{ value: IRole; label: string; disabled?: boolean }> => {
|
||||
|
|
|
@ -7,7 +7,9 @@ import { useSettingsStore } from '@/stores/settings.store';
|
|||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { useRBACStore } from '@/stores/rbac.store';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
import { EnterpriseEditionFeature } from '@/constants';
|
||||
import { EnterpriseEditionFeature, STORES } from '@/constants';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
|
||||
|
||||
describe('VariablesView', () => {
|
||||
let server: ReturnType<typeof setupServer>;
|
||||
|
@ -16,7 +18,13 @@ describe('VariablesView', () => {
|
|||
let usersStore: ReturnType<typeof useUsersStore>;
|
||||
let rbacStore: ReturnType<typeof useRBACStore>;
|
||||
|
||||
const renderComponent = createComponentRenderer(VariablesView);
|
||||
const renderComponent = createComponentRenderer(VariablesView, {
|
||||
pinia: createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: SETTINGS_STORE_DEFAULT_STATE,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
server = setupServer();
|
||||
|
@ -105,6 +113,7 @@ describe('VariablesView', () => {
|
|||
});
|
||||
|
||||
it('should render variable entries', async () => {
|
||||
settingsStore.settings.enterprise[EnterpriseEditionFeature.Variables] = true;
|
||||
server.createList('variable', 3);
|
||||
|
||||
const wrapper = renderComponent({ pinia });
|
||||
|
|
|
@ -41,8 +41,8 @@ const editMode = ref<Record<string, boolean>>({});
|
|||
const loading = ref(false);
|
||||
const permissions = getVariablesPermissions(usersStore.currentUser);
|
||||
|
||||
const isFeatureEnabled = computed(() =>
|
||||
settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Variables),
|
||||
const isFeatureEnabled = computed(
|
||||
() => settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Variables],
|
||||
);
|
||||
|
||||
const variablesToResources = computed((): IResource[] =>
|
||||
|
|
|
@ -217,7 +217,7 @@ const WorkflowsView = defineComponent({
|
|||
return this.workflowsStore.allWorkflows;
|
||||
},
|
||||
isShareable(): boolean {
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing);
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing];
|
||||
},
|
||||
statusFilterOptions(): Array<{ label: string; value: string | boolean }> {
|
||||
return [
|
||||
|
|
|
@ -11,8 +11,10 @@ import { useUsersStore } from '@/stores/users.store';
|
|||
import { createUser } from '@/__tests__/data/users';
|
||||
import { createProjectListItem } from '@/__tests__/data/projects';
|
||||
import { useRBACStore } from '@/stores/rbac.store';
|
||||
import { DELETE_USER_MODAL_KEY } from '@/constants';
|
||||
import { DELETE_USER_MODAL_KEY, EnterpriseEditionFeature } from '@/constants';
|
||||
import * as usersApi from '@/api/users';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { defaultSettings } from '@/__tests__/defaults';
|
||||
|
||||
const wrapperComponentWithModal = {
|
||||
components: { SettingsUsersView, ModalRoot, DeleteUserModal },
|
||||
|
@ -47,6 +49,11 @@ describe('SettingsUsersView', () => {
|
|||
usersStore = useUsersStore();
|
||||
rbacStore = useRBACStore();
|
||||
|
||||
useSettingsStore().settings.enterprise = {
|
||||
...defaultSettings.enterprise,
|
||||
[EnterpriseEditionFeature.AdvancedExecutionFilters]: true,
|
||||
};
|
||||
|
||||
vi.spyOn(rbacStore, 'hasScope').mockReturnValue(true);
|
||||
vi.spyOn(usersApi, 'getUsers').mockResolvedValue(users);
|
||||
vi.spyOn(usersStore, 'allUsers', 'get').mockReturnValue(users);
|
||||
|
|
|
@ -2596,7 +2596,7 @@ export type ExpressionEvaluatorType = 'tmpl' | 'tournament';
|
|||
export type N8nAIProviderType = 'openai' | 'unknown';
|
||||
|
||||
export interface IN8nUISettings {
|
||||
isDocker: boolean;
|
||||
isDocker?: boolean;
|
||||
databaseType: 'sqlite' | 'mariadb' | 'mysqldb' | 'postgresdb';
|
||||
endpointForm: string;
|
||||
endpointFormTest: string;
|
||||
|
|
Loading…
Reference in a new issue