decap-cms-core
Version:
Decap CMS core application, see decap-cms package for the main distribution.
590 lines (587 loc) • 23.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.selectEditingDraft = selectEditingDraft;
exports.selectEntries = selectEntries;
exports.selectEntriesFilter = selectEntriesFilter;
exports.selectEntriesFilterFields = selectEntriesFilterFields;
exports.selectEntriesGroup = selectEntriesGroup;
exports.selectEntriesGroupField = selectEntriesGroupField;
exports.selectEntriesLoaded = selectEntriesLoaded;
exports.selectEntriesSort = selectEntriesSort;
exports.selectEntriesSortFields = selectEntriesSortFields;
exports.selectEntry = selectEntry;
exports.selectEntryByPath = selectEntryByPath;
exports.selectGroups = selectGroups;
exports.selectIsFetching = selectIsFetching;
exports.selectMediaFilePath = selectMediaFilePath;
exports.selectMediaFilePublicPath = selectMediaFilePublicPath;
exports.selectMediaFolder = selectMediaFolder;
exports.selectPublishedSlugs = selectPublishedSlugs;
exports.selectViewStyle = selectViewStyle;
var _groupBy2 = _interopRequireDefault(require("lodash/groupBy"));
var _orderBy2 = _interopRequireDefault(require("lodash/orderBy"));
var _set2 = _interopRequireDefault(require("lodash/set"));
var _sortBy2 = _interopRequireDefault(require("lodash/sortBy"));
var _once2 = _interopRequireDefault(require("lodash/once"));
var _trim2 = _interopRequireDefault(require("lodash/trim"));
var _immutable = require("immutable");
var _path = require("path");
var _decapCmsLibUtil = require("decap-cms-lib-util");
var _decapCmsLibWidgets = require("decap-cms-lib-widgets");
var _redux = require("../types/redux");
var _formatters = require("../lib/formatters");
var _collections = require("./collections");
var _search = require("../actions/search");
var _entries = require("../actions/entries");
var _collectionViews = require("../constants/collectionViews");
var _urlHelper = require("../lib/urlHelper");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
const {
keyToPathArray
} = _decapCmsLibWidgets.stringTemplate;
let collection;
let loadedEntries;
let append;
let page;
let slug;
const storageSortKey = 'decap-cms.entries.sort';
const viewStyleKey = 'decap-cms.entries.viewStyle';
const loadSort = (0, _once2.default)(() => {
const sortString = localStorage.getItem(storageSortKey);
if (sortString) {
try {
const sort = JSON.parse(sortString);
let map = (0, _immutable.Map)();
Object.entries(sort).forEach(([collection, sort]) => {
let orderedMap = (0, _immutable.OrderedMap)();
(0, _sortBy2.default)(Object.values(sort), ['index']).forEach(value => {
const {
key,
direction
} = value;
orderedMap = orderedMap.set(key, (0, _immutable.fromJS)({
key,
direction
}));
});
map = map.set(collection, orderedMap);
});
return map;
} catch (e) {
return (0, _immutable.Map)();
}
}
return (0, _immutable.Map)();
});
function clearSort() {
localStorage.removeItem(storageSortKey);
}
function persistSort(sort) {
if (sort) {
const storageSort = {};
sort.keySeq().forEach(key => {
const collection = key;
const sortObjects = sort.get(collection).valueSeq().toJS().map((value, index) => _objectSpread(_objectSpread({}, value), {}, {
index
}));
sortObjects.forEach(value => {
(0, _set2.default)(storageSort, [collection, value.key], value);
});
});
localStorage.setItem(storageSortKey, JSON.stringify(storageSort));
} else {
clearSort();
}
}
const loadViewStyle = (0, _once2.default)(() => {
const viewStyle = localStorage.getItem(viewStyleKey);
if (viewStyle) {
return viewStyle;
}
localStorage.setItem(viewStyleKey, _collectionViews.VIEW_STYLE_LIST);
return _collectionViews.VIEW_STYLE_LIST;
});
function clearViewStyle() {
localStorage.removeItem(viewStyleKey);
}
function persistViewStyle(viewStyle) {
if (viewStyle) {
localStorage.setItem(viewStyleKey, viewStyle);
} else {
clearViewStyle();
}
}
function entries(state = (0, _immutable.Map)({
entities: (0, _immutable.Map)(),
pages: (0, _immutable.Map)(),
sort: loadSort(),
viewStyle: loadViewStyle()
}), action) {
switch (action.type) {
case _entries.ENTRY_REQUEST:
{
const payload = action.payload;
return state.setIn(['entities', `${payload.collection}.${payload.slug}`, 'isFetching'], true);
}
case _entries.ENTRY_SUCCESS:
{
const payload = action.payload;
collection = payload.collection;
slug = payload.entry.slug;
return state.withMutations(map => {
map.setIn(['entities', `${collection}.${slug}`], (0, _immutable.fromJS)(payload.entry));
const ids = map.getIn(['pages', collection, 'ids'], (0, _immutable.List)());
if (!ids.includes(slug)) {
map.setIn(['pages', collection, 'ids'], ids.unshift(slug));
}
});
}
case _entries.ENTRIES_REQUEST:
{
const payload = action.payload;
const newState = state.withMutations(map => {
map.setIn(['pages', payload.collection, 'isFetching'], true);
});
return newState;
}
case _entries.ENTRIES_SUCCESS:
{
const payload = action.payload;
collection = payload.collection;
loadedEntries = payload.entries;
append = payload.append;
page = payload.page;
return state.withMutations(map => {
loadedEntries.forEach(entry => map.setIn(['entities', `${collection}.${entry.slug}`], (0, _immutable.fromJS)(entry).set('isFetching', false)));
const ids = (0, _immutable.List)(loadedEntries.map(entry => entry.slug));
map.setIn(['pages', collection], (0, _immutable.Map)({
page,
ids: append ? map.getIn(['pages', collection, 'ids'], (0, _immutable.List)()).concat(ids) : ids
}));
});
}
case _entries.ENTRIES_FAILURE:
return state.setIn(['pages', action.meta.collection, 'isFetching'], false);
case _entries.ENTRY_FAILURE:
{
const payload = action.payload;
return state.withMutations(map => {
map.setIn(['entities', `${payload.collection}.${payload.slug}`, 'isFetching'], false);
map.setIn(['entities', `${payload.collection}.${payload.slug}`, 'error'], payload.error.message);
});
}
case _search.SEARCH_ENTRIES_SUCCESS:
{
const payload = action.payload;
loadedEntries = payload.entries;
return state.withMutations(map => {
loadedEntries.forEach(entry => map.setIn(['entities', `${entry.collection}.${entry.slug}`], (0, _immutable.fromJS)(entry).set('isFetching', false)));
});
}
case _entries.ENTRY_DELETE_SUCCESS:
{
const payload = action.payload;
return state.withMutations(map => {
map.deleteIn(['entities', `${payload.collectionName}.${payload.entrySlug}`]);
map.updateIn(['pages', payload.collectionName, 'ids'], ids => ids.filter(id => id !== payload.entrySlug));
});
}
case _entries.SORT_ENTRIES_REQUEST:
{
const payload = action.payload;
const {
collection,
key,
direction
} = payload;
const newState = state.withMutations(map => {
const sort = (0, _immutable.OrderedMap)({
[key]: (0, _immutable.Map)({
key,
direction
})
});
map.setIn(['sort', collection], sort);
map.setIn(['pages', collection, 'isFetching'], true);
map.deleteIn(['pages', collection, 'page']);
});
persistSort(newState.get('sort'));
return newState;
}
case _entries.GROUP_ENTRIES_SUCCESS:
case _entries.FILTER_ENTRIES_SUCCESS:
case _entries.SORT_ENTRIES_SUCCESS:
{
const payload = action.payload;
const {
collection,
entries
} = payload;
loadedEntries = entries;
const newState = state.withMutations(map => {
loadedEntries.forEach(entry => map.setIn(['entities', `${entry.collection}.${entry.slug}`], (0, _immutable.fromJS)(entry).set('isFetching', false)));
map.setIn(['pages', collection, 'isFetching'], false);
const ids = (0, _immutable.List)(loadedEntries.map(entry => entry.slug));
map.setIn(['pages', collection], (0, _immutable.Map)({
page: 1,
ids
}));
});
return newState;
}
case _entries.SORT_ENTRIES_FAILURE:
{
const payload = action.payload;
const {
collection,
key
} = payload;
const newState = state.withMutations(map => {
map.deleteIn(['sort', collection, key]);
map.setIn(['pages', collection, 'isFetching'], false);
});
persistSort(newState.get('sort'));
return newState;
}
case _entries.FILTER_ENTRIES_REQUEST:
{
const payload = action.payload;
const {
collection,
filter
} = payload;
const newState = state.withMutations(map => {
const current = map.getIn(['filter', collection, filter.id], (0, _immutable.fromJS)(filter));
map.setIn(['filter', collection, current.get('id')], current.set('active', !current.get('active')));
});
return newState;
}
case _entries.FILTER_ENTRIES_FAILURE:
{
const payload = action.payload;
const {
collection,
filter
} = payload;
const newState = state.withMutations(map => {
map.deleteIn(['filter', collection, filter.id]);
map.setIn(['pages', collection, 'isFetching'], false);
});
return newState;
}
case _entries.GROUP_ENTRIES_REQUEST:
{
const payload = action.payload;
const {
collection,
group
} = payload;
const newState = state.withMutations(map => {
const current = map.getIn(['group', collection, group.id], (0, _immutable.fromJS)(group));
map.deleteIn(['group', collection]);
map.setIn(['group', collection, current.get('id')], current.set('active', !current.get('active')));
});
return newState;
}
case _entries.GROUP_ENTRIES_FAILURE:
{
const payload = action.payload;
const {
collection,
group
} = payload;
const newState = state.withMutations(map => {
map.deleteIn(['group', collection, group.id]);
map.setIn(['pages', collection, 'isFetching'], false);
});
return newState;
}
case _entries.CHANGE_VIEW_STYLE:
{
const payload = action.payload;
const {
style
} = payload;
const newState = state.withMutations(map => {
map.setIn(['viewStyle'], style);
});
persistViewStyle(newState.get('viewStyle'));
return newState;
}
default:
return state;
}
}
function selectEntriesSort(entries, collection) {
const sort = entries.get('sort');
return sort === null || sort === void 0 ? void 0 : sort.get(collection);
}
function selectEntriesFilter(entries, collection) {
const filter = entries.get('filter');
return (filter === null || filter === void 0 ? void 0 : filter.get(collection)) || (0, _immutable.Map)();
}
function selectEntriesGroup(entries, collection) {
const group = entries.get('group');
return (group === null || group === void 0 ? void 0 : group.get(collection)) || (0, _immutable.Map)();
}
function selectEntriesGroupField(entries, collection) {
const groups = selectEntriesGroup(entries, collection);
const value = groups === null || groups === void 0 ? void 0 : groups.valueSeq().find(v => (v === null || v === void 0 ? void 0 : v.get('active')) === true);
return value;
}
function selectEntriesSortFields(entries, collection) {
const sort = selectEntriesSort(entries, collection);
const values = (sort === null || sort === void 0 ? void 0 : sort.valueSeq().filter(v => (v === null || v === void 0 ? void 0 : v.get('direction')) !== _redux.SortDirection.None).toArray()) || [];
return values;
}
function selectEntriesFilterFields(entries, collection) {
const filter = selectEntriesFilter(entries, collection);
const values = (filter === null || filter === void 0 ? void 0 : filter.valueSeq().filter(v => (v === null || v === void 0 ? void 0 : v.get('active')) === true).toArray()) || [];
return values;
}
function selectViewStyle(entries) {
return entries.get('viewStyle');
}
function selectEntry(state, collection, slug) {
return state.getIn(['entities', `${collection}.${slug}`]);
}
function selectPublishedSlugs(state, collection) {
return state.getIn(['pages', collection, 'ids'], (0, _immutable.List)());
}
function getPublishedEntries(state, collectionName) {
const slugs = selectPublishedSlugs(state, collectionName);
const entries = slugs && slugs.map(slug => selectEntry(state, collectionName, slug));
return entries;
}
function selectEntries(state, collection) {
const collectionName = collection.get('name');
let entries = getPublishedEntries(state, collectionName);
const sortFields = selectEntriesSortFields(state, collectionName);
if (sortFields && sortFields.length > 0) {
const keys = sortFields.map(v => (0, _collections.selectSortDataPath)(collection, v.get('key')));
const orders = sortFields.map(v => v.get('direction') === _redux.SortDirection.Ascending ? 'asc' : 'desc');
entries = (0, _immutable.fromJS)((0, _orderBy2.default)(entries.toJS(), keys, orders));
}
const filters = selectEntriesFilterFields(state, collectionName);
if (filters && filters.length > 0) {
entries = entries.filter(e => {
const allMatched = filters.every(f => {
const pattern = f.get('pattern');
const field = f.get('field');
const data = e.get('data') || (0, _immutable.Map)();
const toMatch = data.getIn(keyToPathArray(field));
const matched = toMatch !== undefined && new RegExp(String(pattern)).test(String(toMatch));
return matched;
});
return allMatched;
}).toList();
}
return entries;
}
function getGroup(entry, selectedGroup) {
const label = selectedGroup.get('label');
const field = selectedGroup.get('field');
const fieldData = entry.getIn(['data', ...keyToPathArray(field)]);
if (fieldData === undefined) {
return {
id: 'missing_value',
label,
value: fieldData
};
}
const dataAsString = String(fieldData);
if (selectedGroup.has('pattern')) {
const pattern = selectedGroup.get('pattern');
let value = '';
try {
const regex = new RegExp(pattern);
const matched = dataAsString.match(regex);
if (matched) {
value = matched[0];
}
} catch (e) {
console.warn(`Invalid view group pattern '${pattern}' for field '${field}'`, e);
}
return {
id: `${label}${value}`,
label,
value
};
}
return {
id: `${label}${fieldData}`,
label,
value: typeof fieldData === 'boolean' ? fieldData : dataAsString
};
}
function selectGroups(state, collection) {
const collectionName = collection.get('name');
const entries = getPublishedEntries(state, collectionName);
const selectedGroup = selectEntriesGroupField(state, collectionName);
if (selectedGroup === undefined) {
return [];
}
let groups = {};
const groupedEntries = (0, _groupBy2.default)(entries.toArray(), entry => {
const group = getGroup(entry, selectedGroup);
groups = _objectSpread(_objectSpread({}, groups), {}, {
[group.id]: group
});
return group.id;
});
const groupsArray = Object.entries(groupedEntries).map(([id, entries]) => {
return _objectSpread(_objectSpread({}, groups[id]), {}, {
paths: (0, _immutable.Set)(entries.map(entry => entry.get('path')))
});
});
return groupsArray;
}
function selectEntryByPath(state, collection, path) {
const slugs = selectPublishedSlugs(state, collection);
const entries = slugs && slugs.map(slug => selectEntry(state, collection, slug));
return entries && entries.find(e => (e === null || e === void 0 ? void 0 : e.get('path')) === path);
}
function selectEntriesLoaded(state, collection) {
return !!state.getIn(['pages', collection]);
}
function selectIsFetching(state, collection) {
return state.getIn(['pages', collection, 'isFetching'], false);
}
const DRAFT_MEDIA_FILES = 'DRAFT_MEDIA_FILES';
function getFileField(collectionFiles, slug) {
const file = collectionFiles.find(f => (f === null || f === void 0 ? void 0 : f.get('name')) === slug);
return file;
}
function hasCustomFolder(folderKey, collection, slug, field) {
if (!collection) {
return false;
}
if (field && field.has(folderKey)) {
return true;
}
if (collection.has('files')) {
const file = getFileField(collection.get('files'), slug);
if (file && file.has(folderKey)) {
return true;
}
}
if (collection.has(folderKey)) {
return true;
}
return false;
}
function traverseFields(folderKey, config, collection, entryMap, field, fields, currentFolder) {
const matchedField = fields.filter(f => f === field)[0];
if (matchedField) {
return (0, _formatters.folderFormatter)(matchedField.has(folderKey) ? matchedField.get(folderKey) : `{{${folderKey}}}`, entryMap, collection, currentFolder, folderKey, config.slug);
}
for (let f of fields) {
if (!f.has(folderKey)) {
// add identity template if doesn't exist
f = f.set(folderKey, `{{${folderKey}}}`);
}
const folder = (0, _formatters.folderFormatter)(f.get(folderKey), entryMap, collection, currentFolder, folderKey, config.slug);
let fieldFolder = null;
if (f.has('fields')) {
fieldFolder = traverseFields(folderKey, config, collection, entryMap, field, f.get('fields').toArray(), folder);
} else if (f.has('field')) {
fieldFolder = traverseFields(folderKey, config, collection, entryMap, field, [f.get('field')], folder);
} else if (f.has('types')) {
fieldFolder = traverseFields(folderKey, config, collection, entryMap, field, f.get('types').toArray(), folder);
}
if (fieldFolder != null) {
return fieldFolder;
}
}
return null;
}
function evaluateFolder(folderKey, config, collection, entryMap, field) {
let currentFolder = config[folderKey];
// add identity template if doesn't exist
if (!collection.has(folderKey)) {
collection = collection.set(folderKey, `{{${folderKey}}}`);
}
if (collection.has('files')) {
// files collection evaluate the collection template
// then move on to the specific file configuration denoted by the slug
currentFolder = (0, _formatters.folderFormatter)(collection.get(folderKey), entryMap, collection, currentFolder, folderKey, config.slug);
let file = getFileField(collection.get('files'), entryMap === null || entryMap === void 0 ? void 0 : entryMap.get('slug'));
if (file) {
if (!file.has(folderKey)) {
// add identity template if doesn't exist
file = file.set(folderKey, `{{${folderKey}}}`);
}
// evaluate the file template and keep evaluating until we match our field
currentFolder = (0, _formatters.folderFormatter)(file.get(folderKey), entryMap, collection, currentFolder, folderKey, config.slug);
if (field) {
const fieldFolder = traverseFields(folderKey, config, collection, entryMap, field, file.get('fields').toArray(), currentFolder);
if (fieldFolder !== null) {
currentFolder = fieldFolder;
}
}
}
} else {
// folder collection, evaluate the collection template
// and keep evaluating until we match our field
currentFolder = (0, _formatters.folderFormatter)(collection.get(folderKey), entryMap, collection, currentFolder, folderKey, config.slug);
if (field) {
const fieldFolder = traverseFields(folderKey, config, collection, entryMap, field, collection.get('fields').toArray(), currentFolder);
if (fieldFolder !== null) {
currentFolder = fieldFolder;
}
}
}
return currentFolder;
}
function selectMediaFolder(config, collection, entryMap, field) {
const name = 'media_folder';
let mediaFolder = config[name];
const customFolder = hasCustomFolder(name, collection, entryMap === null || entryMap === void 0 ? void 0 : entryMap.get('slug'), field);
if (customFolder) {
const folder = evaluateFolder(name, config, collection, entryMap, field);
if (folder.startsWith('/')) {
// return absolute paths as is
mediaFolder = (0, _path.join)(folder);
} else {
const entryPath = entryMap === null || entryMap === void 0 ? void 0 : entryMap.get('path');
mediaFolder = entryPath ? (0, _path.join)((0, _path.dirname)(entryPath), folder) : (0, _path.join)(collection.get('folder'), DRAFT_MEDIA_FILES);
}
}
return (0, _trim2.default)(mediaFolder, '/');
}
function selectMediaFilePath(config, collection, entryMap, mediaPath, field) {
if ((0, _decapCmsLibUtil.isAbsolutePath)(mediaPath)) {
return mediaPath;
}
const mediaFolder = selectMediaFolder(config, collection, entryMap, field);
return (0, _path.join)(mediaFolder, (0, _decapCmsLibUtil.basename)(mediaPath));
}
function selectMediaFilePublicPath(config, collection, mediaPath, entryMap, field) {
if ((0, _decapCmsLibUtil.isAbsolutePath)(mediaPath)) {
return mediaPath;
}
const name = 'public_folder';
let publicFolder = config[name];
const customFolder = hasCustomFolder(name, collection, entryMap === null || entryMap === void 0 ? void 0 : entryMap.get('slug'), field);
if (customFolder) {
publicFolder = evaluateFolder(name, config, collection, entryMap, field);
}
if ((0, _decapCmsLibUtil.isAbsolutePath)(publicFolder)) {
return (0, _urlHelper.joinUrlPath)(publicFolder, (0, _decapCmsLibUtil.basename)(mediaPath));
}
return (0, _path.join)(publicFolder, (0, _decapCmsLibUtil.basename)(mediaPath));
}
function selectEditingDraft(state) {
const entry = state.get('entry');
const workflowDraft = entry && !entry.isEmpty();
return workflowDraft;
}
var _default = exports.default = entries;