mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
refactor(core): Decouple module settings from frontend service (#16324)
Co-authored-by: Danny Martini <danny@n8n.io>
This commit is contained in:
@@ -12,6 +12,7 @@ export * from './orchestration';
|
||||
export * from './prompts';
|
||||
export * from './roles';
|
||||
export * from './settings';
|
||||
export * from './module-settings';
|
||||
export * from './sso';
|
||||
export * from './ui';
|
||||
export * from './versions';
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { FrontendModuleSettings } from '@n8n/api-types';
|
||||
|
||||
import type { IRestApiContext } from '../types';
|
||||
import { makeRestApiRequest } from '../utils';
|
||||
|
||||
export async function getModuleSettings(context: IRestApiContext): Promise<FrontendModuleSettings> {
|
||||
return await makeRestApiRequest(context, 'GET', '/module-settings');
|
||||
}
|
||||
@@ -145,21 +145,8 @@ export const defaultSettings: FrontendSettings = {
|
||||
folders: {
|
||||
enabled: false,
|
||||
},
|
||||
insights: {
|
||||
enabled: false,
|
||||
summary: true,
|
||||
dashboard: false,
|
||||
dateRanges: [
|
||||
{ key: 'day', licensed: true, granularity: 'hour' },
|
||||
{ key: 'week', licensed: true, granularity: 'day' },
|
||||
{ key: '2weeks', licensed: true, granularity: 'day' },
|
||||
{ key: 'month', licensed: false, granularity: 'day' },
|
||||
{ key: 'quarter', licensed: false, granularity: 'week' },
|
||||
{ key: '6months', licensed: false, granularity: 'week' },
|
||||
{ key: 'year', licensed: false, granularity: 'week' },
|
||||
],
|
||||
},
|
||||
evaluation: {
|
||||
quota: 0,
|
||||
},
|
||||
loadedModules: [],
|
||||
};
|
||||
|
||||
@@ -112,7 +112,7 @@ const mainMenuItems = computed(() => [
|
||||
position: 'bottom',
|
||||
route: { to: { name: VIEWS.INSIGHTS } },
|
||||
available:
|
||||
settingsStore.settings.insights.enabled &&
|
||||
settingsStore.settings.loadedModules.includes('insights') &&
|
||||
hasPermission(['rbac'], { rbac: { scope: 'insights:list' } }),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,9 +13,25 @@ const renderComponent = createComponentRenderer(InsightsDashboard, {
|
||||
},
|
||||
});
|
||||
|
||||
const moduleSettings = {
|
||||
insights: {
|
||||
summary: true,
|
||||
dashboard: true,
|
||||
dateRanges: [
|
||||
{
|
||||
key: 'day',
|
||||
licensed: true,
|
||||
granularity: 'hour',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
describe('InsightsDashboard', () => {
|
||||
beforeEach(() => {
|
||||
createTestingPinia({ initialState: { settings: { settings: defaultSettings } } });
|
||||
createTestingPinia({
|
||||
initialState: { settings: { settings: defaultSettings, moduleSettings } },
|
||||
});
|
||||
});
|
||||
|
||||
it('should render without error', () => {
|
||||
|
||||
@@ -18,8 +18,13 @@ export const useInsightsStore = defineStore('insights', () => {
|
||||
() => getResourcePermissions(usersStore.currentUser?.globalScopes).insights,
|
||||
);
|
||||
|
||||
const isInsightsEnabled = computed(() => settingsStore.settings.insights.enabled);
|
||||
const isDashboardEnabled = computed(() => settingsStore.settings.insights.dashboard);
|
||||
const isInsightsEnabled = computed(() =>
|
||||
settingsStore.settings.loadedModules.includes('insights'),
|
||||
);
|
||||
|
||||
const isDashboardEnabled = computed(
|
||||
() => settingsStore.moduleSettings.insights?.dashboard ?? false,
|
||||
);
|
||||
|
||||
const isSummaryEnabled = computed(
|
||||
() => globalInsightsPermissions.value.list && isInsightsEnabled.value,
|
||||
@@ -64,7 +69,7 @@ export const useInsightsStore = defineStore('insights', () => {
|
||||
{ immediate: false, resetOnExecute: false },
|
||||
);
|
||||
|
||||
const dateRanges = computed(() => settingsStore.settings.insights.dateRanges);
|
||||
const dateRanges = computed(() => settingsStore.moduleSettings.insights?.dateRanges ?? []);
|
||||
|
||||
return {
|
||||
globalInsightsPermissions,
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { computed, ref } from 'vue';
|
||||
import Bowser from 'bowser';
|
||||
import type { IUserManagementSettings, FrontendSettings } from '@n8n/api-types';
|
||||
import type {
|
||||
IUserManagementSettings,
|
||||
FrontendSettings,
|
||||
FrontendModuleSettings,
|
||||
} from '@n8n/api-types';
|
||||
|
||||
import * as eventsApi from '@n8n/rest-api-client/api/events';
|
||||
import * as settingsApi from '@n8n/rest-api-client/api/settings';
|
||||
import * as moduleSettingsApi from '@n8n/rest-api-client/api/module-settings';
|
||||
import * as promptsApi from '@n8n/rest-api-client/api/prompts';
|
||||
import { testHealthEndpoint } from '@/api/templates';
|
||||
import {
|
||||
@@ -26,6 +31,7 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
|
||||
const i18n = useI18n();
|
||||
const initialized = ref(false);
|
||||
const settings = ref<FrontendSettings>({} as FrontendSettings);
|
||||
const moduleSettings = ref<FrontendModuleSettings>({});
|
||||
const userManagement = ref<IUserManagementSettings>({
|
||||
quota: -1,
|
||||
showSetupOnFirstLoad: false,
|
||||
@@ -178,6 +184,8 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
|
||||
|
||||
const isDevRelease = computed(() => settings.value.releaseChannel === 'dev');
|
||||
|
||||
const loadedModules = computed(() => settings.value.loadedModules);
|
||||
|
||||
const setSettings = (newSettings: FrontendSettings) => {
|
||||
settings.value = newSettings;
|
||||
userManagement.value = newSettings.userManagement;
|
||||
@@ -325,6 +333,11 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
|
||||
settings.value = {} as FrontendSettings;
|
||||
};
|
||||
|
||||
const getModuleSettings = async () => {
|
||||
const fetched = await moduleSettingsApi.getModuleSettings(useRootStore().restApiContext);
|
||||
moduleSettings.value = fetched;
|
||||
};
|
||||
|
||||
/**
|
||||
* (Experimental) Minimum zoom level of the canvas to render node settings in place of nodes, without opening NDV
|
||||
*/
|
||||
@@ -402,5 +415,8 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
|
||||
getSettings,
|
||||
setSettings,
|
||||
initialize,
|
||||
loadedModules,
|
||||
getModuleSettings,
|
||||
moduleSettings,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -46,6 +46,7 @@ let telemetry: ReturnType<typeof useTelemetry>;
|
||||
describe('SigninView', () => {
|
||||
const signInWithValidUser = async () => {
|
||||
settingsStore.isCloudDeployment = false;
|
||||
settingsStore.loadedModules = [];
|
||||
usersStore.loginWithCreds.mockResolvedValueOnce();
|
||||
|
||||
const { getByRole, queryByTestId, container } = renderComponent();
|
||||
|
||||
@@ -144,6 +144,11 @@ const login = async (form: LoginRequestDto) => {
|
||||
}
|
||||
}
|
||||
await settingsStore.getSettings();
|
||||
|
||||
if (settingsStore.loadedModules.length > 0) {
|
||||
await settingsStore.getModuleSettings();
|
||||
}
|
||||
|
||||
toast.clearAllStickyNotifications();
|
||||
|
||||
telemetry.track('User attempted to login', {
|
||||
|
||||
Reference in New Issue
Block a user