refactor: mutate config in normalizeConfig and handleLocalBackend fns (#4846)
This commit is contained in:
committed by
GitHub
parent
319a5381eb
commit
3924cfbce5
@ -10,7 +10,7 @@ import {
|
|||||||
|
|
||||||
jest.spyOn(console, 'log').mockImplementation(() => {});
|
jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||||
jest.mock('coreSrc/backend', () => {
|
jest.mock('../../backend', () => {
|
||||||
return {
|
return {
|
||||||
resolveBackend: jest.fn(() => ({ isGitBackend: jest.fn(() => true) })),
|
resolveBackend: jest.fn(() => ({ isGitBackend: jest.fn(() => true) })),
|
||||||
};
|
};
|
||||||
@ -452,8 +452,8 @@ describe('config', () => {
|
|||||||
test('should convert camel case to snake case', () => {
|
test('should convert camel case to snake case', () => {
|
||||||
expect(
|
expect(
|
||||||
applyDefaults(
|
applyDefaults(
|
||||||
normalizeConfig(
|
fromJS(
|
||||||
fromJS({
|
normalizeConfig({
|
||||||
collections: [
|
collections: [
|
||||||
{
|
{
|
||||||
sortableFields: ['title'],
|
sortableFields: ['title'],
|
||||||
@ -922,7 +922,7 @@ describe('config', () => {
|
|||||||
window.location = { hostname: 'localhost' };
|
window.location = { hostname: 'localhost' };
|
||||||
global.fetch = jest.fn().mockRejectedValue(new Error());
|
global.fetch = jest.fn().mockRejectedValue(new Error());
|
||||||
|
|
||||||
const config = fromJS({ local_backend: true, backend: { name: 'github' } });
|
const config = { local_backend: true, backend: { name: 'github' } };
|
||||||
const actual = await handleLocalBackend(config);
|
const actual = await handleLocalBackend(config);
|
||||||
|
|
||||||
expect(actual).toEqual(config);
|
expect(actual).toEqual(config);
|
||||||
|
@ -2,17 +2,32 @@ import yaml from 'yaml';
|
|||||||
import { Map, fromJS } from 'immutable';
|
import { Map, fromJS } from 'immutable';
|
||||||
import deepmerge from 'deepmerge';
|
import deepmerge from 'deepmerge';
|
||||||
import { trimStart, trim, get, isPlainObject, isEmpty } from 'lodash';
|
import { trimStart, trim, get, isPlainObject, isEmpty } from 'lodash';
|
||||||
import * as publishModes from 'Constants/publishModes';
|
import { SIMPLE as SIMPLE_PUBLISH_MODE } from '../constants/publishModes';
|
||||||
import { validateConfig } from 'Constants/configSchema';
|
import { validateConfig } from '../constants/configSchema';
|
||||||
import { selectDefaultSortableFields, traverseFields } from '../reducers/collections';
|
import { selectDefaultSortableFields, traverseFields } from '../reducers/collections';
|
||||||
import { getIntegrations, selectIntegration } from '../reducers/integrations';
|
import { getIntegrations, selectIntegration } from '../reducers/integrations';
|
||||||
import { resolveBackend } from 'coreSrc/backend';
|
import { resolveBackend } from '../backend';
|
||||||
import { I18N, I18N_FIELD, I18N_STRUCTURE } from '../lib/i18n';
|
import { I18N, I18N_FIELD, I18N_STRUCTURE } from '../lib/i18n';
|
||||||
|
|
||||||
export const CONFIG_REQUEST = 'CONFIG_REQUEST';
|
export const CONFIG_REQUEST = 'CONFIG_REQUEST';
|
||||||
export const CONFIG_SUCCESS = 'CONFIG_SUCCESS';
|
export const CONFIG_SUCCESS = 'CONFIG_SUCCESS';
|
||||||
export const CONFIG_FAILURE = 'CONFIG_FAILURE';
|
export const CONFIG_FAILURE = 'CONFIG_FAILURE';
|
||||||
|
|
||||||
|
const traverseFieldsJS = (fields, updater) => {
|
||||||
|
return fields.map(field => {
|
||||||
|
let newField = updater(field);
|
||||||
|
if (newField.fields) {
|
||||||
|
newField = { ...newField, fields: traverseFieldsJS(newField.fields, updater) };
|
||||||
|
} else if (newField.field) {
|
||||||
|
newField = { ...newField, field: traverseFieldsJS([newField.field], updater)[0] };
|
||||||
|
} else if (newField.types) {
|
||||||
|
newField = { ...newField, types: traverseFieldsJS(newField.types, updater) };
|
||||||
|
}
|
||||||
|
|
||||||
|
return newField;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getConfigUrl = () => {
|
const getConfigUrl = () => {
|
||||||
const validTypes = { 'text/yaml': 'yaml', 'application/x-yaml': 'yaml' };
|
const validTypes = { 'text/yaml': 'yaml', 'application/x-yaml': 'yaml' };
|
||||||
const configLinkEl = document.querySelector('link[rel="cms-config-url"]');
|
const configLinkEl = document.querySelector('link[rel="cms-config-url"]');
|
||||||
@ -32,31 +47,30 @@ const setDefaultPublicFolder = map => {
|
|||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setSnakeCaseConfig = field => {
|
// Mapping between existing camelCase and its snake_case counterpart
|
||||||
// Mapping between existing camelCase and its snake_case counterpart
|
const WIDGET_KEY_MAP = {
|
||||||
const widgetKeyMap = {
|
dateFormat: 'date_format',
|
||||||
dateFormat: 'date_format',
|
timeFormat: 'time_format',
|
||||||
timeFormat: 'time_format',
|
pickerUtc: 'picker_utc',
|
||||||
pickerUtc: 'picker_utc',
|
editorComponents: 'editor_components',
|
||||||
editorComponents: 'editor_components',
|
valueType: 'value_type',
|
||||||
valueType: 'value_type',
|
valueField: 'value_field',
|
||||||
valueField: 'value_field',
|
searchFields: 'search_fields',
|
||||||
searchFields: 'search_fields',
|
displayFields: 'display_fields',
|
||||||
displayFields: 'display_fields',
|
optionsLength: 'options_length',
|
||||||
optionsLength: 'options_length',
|
};
|
||||||
};
|
|
||||||
|
|
||||||
Object.entries(widgetKeyMap).forEach(([camel, snake]) => {
|
const setSnakeCaseConfig = field => {
|
||||||
if (field.has(camel)) {
|
const deprecatedKeys = Object.keys(WIDGET_KEY_MAP).filter(camel => camel in field);
|
||||||
field = field.set(snake, field.get(camel));
|
const snakeValues = deprecatedKeys.map(camel => {
|
||||||
console.warn(
|
const snake = WIDGET_KEY_MAP[camel];
|
||||||
`Field ${field.get(
|
console.warn(
|
||||||
'name',
|
`Field ${field.name} is using a deprecated configuration '${camel}'. Please use '${snake}'`,
|
||||||
)} is using a deprecated configuration '${camel}'. Please use '${snake}'`,
|
);
|
||||||
);
|
return { [snake]: field[camel] };
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return field;
|
|
||||||
|
return Object.assign({}, field, ...snakeValues);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setI18nField = field => {
|
const setI18nField = field => {
|
||||||
@ -141,7 +155,7 @@ const setViewPatternsDefaults = (key, collection) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
publish_mode: publishModes.SIMPLE,
|
publish_mode: SIMPLE_PUBLISH_MODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasIntegration = (config, collection) => {
|
const hasIntegration = (config, collection) => {
|
||||||
@ -151,45 +165,38 @@ const hasIntegration = (config, collection) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function normalizeConfig(config) {
|
export function normalizeConfig(config) {
|
||||||
return Map(config).withMutations(map => {
|
const { collections = [] } = config;
|
||||||
map.set(
|
|
||||||
'collections',
|
|
||||||
map.get('collections').map(collection => {
|
|
||||||
const folder = collection.get('folder');
|
|
||||||
if (folder) {
|
|
||||||
collection = collection.set(
|
|
||||||
'fields',
|
|
||||||
traverseFields(collection.get('fields'), setSnakeCaseConfig),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const files = collection.get('files');
|
const normalizedCollections = collections.map(collection => {
|
||||||
if (files) {
|
const { fields, files } = collection;
|
||||||
collection = collection.set(
|
|
||||||
'files',
|
|
||||||
files.map(file => {
|
|
||||||
file = file.set('fields', traverseFields(file.get('fields'), setSnakeCaseConfig));
|
|
||||||
return file;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collection.has('sortableFields')) {
|
let normalizedCollection = collection;
|
||||||
collection = collection
|
if (fields) {
|
||||||
.set('sortable_fields', collection.get('sortableFields'))
|
const normalizedFields = traverseFieldsJS(fields, setSnakeCaseConfig);
|
||||||
.delete('sortableFields');
|
normalizedCollection = { ...normalizedCollection, fields: normalizedFields };
|
||||||
|
}
|
||||||
|
|
||||||
console.warn(
|
if (files) {
|
||||||
`Collection ${collection.get(
|
const normalizedFiles = files.map(file => {
|
||||||
'name',
|
const normalizedFileFields = traverseFieldsJS(file.fields, setSnakeCaseConfig);
|
||||||
)} is using a deprecated configuration 'sortableFields'. Please use 'sortable_fields'`,
|
return { ...file, fields: normalizedFileFields };
|
||||||
);
|
});
|
||||||
}
|
normalizedCollection = { ...normalizedCollection, files: normalizedFiles };
|
||||||
|
}
|
||||||
|
|
||||||
return collection;
|
if (normalizedCollection.sortableFields) {
|
||||||
}),
|
const { sortableFields, ...rest } = normalizedCollection;
|
||||||
);
|
normalizedCollection = { ...rest, sortable_fields: sortableFields };
|
||||||
|
|
||||||
|
console.warn(
|
||||||
|
`Collection ${collection.name} is using a deprecated configuration 'sortableFields'. Please use 'sortable_fields'`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedCollection;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return { ...config, collections: normalizedCollections };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyDefaults(config) {
|
export function applyDefaults(config) {
|
||||||
@ -383,36 +390,38 @@ export async function detectProxyServer(localBackend) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleLocalBackend(originalConfig) {
|
const getPublishMode = (config, publishModes, backendType) => {
|
||||||
if (!originalConfig.local_backend) {
|
if (config.publish_mode && publishModes && !publishModes.includes(config.publish_mode)) {
|
||||||
return originalConfig;
|
const newPublishMode = publishModes[0];
|
||||||
|
console.log(
|
||||||
|
`'${config.publish_mode}' is not supported by '${backendType}' backend, switching to '${newPublishMode}'`,
|
||||||
|
);
|
||||||
|
return newPublishMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { proxyUrl, publish_modes, type } = await detectProxyServer(originalConfig.local_backend);
|
return config.publish_mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleLocalBackend = async config => {
|
||||||
|
if (!config.local_backend) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { proxyUrl, publish_modes: publishModes, type: backendType } = await detectProxyServer(
|
||||||
|
config.local_backend,
|
||||||
|
);
|
||||||
|
|
||||||
if (!proxyUrl) {
|
if (!proxyUrl) {
|
||||||
return originalConfig;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mergedConfig = deepmerge(originalConfig, {
|
const publishMode = getPublishMode(config, publishModes, backendType);
|
||||||
backend: { name: 'proxy', proxy_url: proxyUrl },
|
return {
|
||||||
});
|
...config,
|
||||||
|
...(publishMode && { publish_mode: publishMode }),
|
||||||
if (
|
backend: { ...config.backend, name: 'proxy', proxy_url: proxyUrl },
|
||||||
mergedConfig.publish_mode &&
|
};
|
||||||
publish_modes &&
|
};
|
||||||
!publish_modes.includes(mergedConfig.publish_mode)
|
|
||||||
) {
|
|
||||||
const newPublishMode = publish_modes[0];
|
|
||||||
mergedConfig = deepmerge(mergedConfig, {
|
|
||||||
publish_mode: newPublishMode,
|
|
||||||
});
|
|
||||||
console.log(
|
|
||||||
`'${mergedConfig.publish_mode}' is not supported by '${type}' backend, switching to '${newPublishMode}'`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return mergedConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loadConfig(manualConfig = {}, onLoad) {
|
export function loadConfig(manualConfig = {}, onLoad) {
|
||||||
if (window.CMS_CONFIG) {
|
if (window.CMS_CONFIG) {
|
||||||
@ -430,13 +439,14 @@ export function loadConfig(manualConfig = {}, onLoad) {
|
|||||||
: await getConfigYaml(configUrl, hasManualConfig);
|
: await getConfigYaml(configUrl, hasManualConfig);
|
||||||
|
|
||||||
// Merge manual config into the config.yml one
|
// Merge manual config into the config.yml one
|
||||||
let mergedConfig = deepmerge(configYaml, manualConfig);
|
const mergedConfig = deepmerge(configYaml, manualConfig);
|
||||||
|
|
||||||
validateConfig(mergedConfig);
|
validateConfig(mergedConfig);
|
||||||
|
|
||||||
mergedConfig = await handleLocalBackend(mergedConfig);
|
const withLocalBackend = await handleLocalBackend(mergedConfig);
|
||||||
|
const normalizedConfig = normalizeConfig(withLocalBackend);
|
||||||
|
|
||||||
const config = applyDefaults(normalizeConfig(fromJS(mergedConfig)));
|
const config = applyDefaults(fromJS(normalizedConfig));
|
||||||
|
|
||||||
dispatch(configLoaded(config));
|
dispatch(configLoaded(config));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user