decap-cms-core 3.7.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/decap-cms-core.js +26 -26
- package/dist/decap-cms-core.js.LICENSE.txt +0 -12
- package/dist/decap-cms-core.js.map +1 -1
- package/dist/esm/bootstrap.js +3 -2
- package/dist/esm/components/App/App.js +6 -3
- package/dist/esm/components/App/Header.js +38 -14
- package/dist/esm/components/Collection/Entries/Entries.js +14 -5
- package/dist/esm/components/Collection/Entries/EntriesCollection.js +65 -9
- package/dist/esm/components/Collection/Entries/EntryCard.js +84 -28
- package/dist/esm/components/Collection/Entries/EntryListing.js +46 -11
- package/dist/esm/components/UI/ErrorBoundary.js +2 -2
- package/dist/esm/constants/configSchema.js +14 -0
- package/dist/esm/formats/toml.js +2 -2
- package/dist/esm/lib/i18n.js +16 -0
- package/dist/esm/lib/polyfill.js +8 -0
- package/index.d.ts +5 -1
- package/package.json +8 -2
- package/src/bootstrap.js +1 -0
- package/src/components/App/App.js +2 -0
- package/src/components/App/Header.js +27 -0
- package/src/components/Collection/Entries/Entries.js +9 -0
- package/src/components/Collection/Entries/EntriesCollection.js +100 -4
- package/src/components/Collection/Entries/EntryCard.js +82 -3
- package/src/components/Collection/Entries/EntryListing.js +65 -5
- package/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js +26 -18
- package/src/components/Collection/Entries/__tests__/__snapshots__/EntriesCollection.spec.js.snap +1 -0
- package/src/constants/configSchema.js +9 -1
- package/src/formats/toml.ts +2 -2
- package/src/lib/i18n.ts +21 -0
- package/src/lib/polyfill.js +9 -0
- package/src/types/redux.ts +5 -1
|
@@ -5,8 +5,9 @@ import PropTypes from 'prop-types';
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
7
7
|
import { Waypoint } from 'react-waypoint';
|
|
8
|
-
import { Map } from 'immutable';
|
|
8
|
+
import { Map, List } from 'immutable';
|
|
9
9
|
import { selectFields, selectInferredField } from '../../../reducers/collections';
|
|
10
|
+
import { filterNestedEntries } from './EntriesCollection';
|
|
10
11
|
import EntryCard from './EntryCard';
|
|
11
12
|
import { jsx as ___EmotionJSX } from "@emotion/react";
|
|
12
13
|
const CardsGrid = /*#__PURE__*/_styled("ul", {
|
|
@@ -17,17 +18,20 @@ const CardsGrid = /*#__PURE__*/_styled("ul", {
|
|
|
17
18
|
styles: "display:flex;flex-flow:row wrap;list-style-type:none;margin-left:-12px;margin-top:16px;margin-bottom:16px"
|
|
18
19
|
} : {
|
|
19
20
|
name: "1dbthoi",
|
|
20
|
-
styles: "display:flex;flex-flow:row wrap;list-style-type:none;margin-left:-12px;margin-top:16px;margin-bottom:16px/*# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
21
|
+
styles: "display:flex;flex-flow:row wrap;list-style-type:none;margin-left:-12px;margin-top:16px;margin-bottom:16px/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL0NvbGxlY3Rpb24vRW50cmllcy9FbnRyeUxpc3RpbmcuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBVzJCIiwiZmlsZSI6Ii4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL0NvbGxlY3Rpb24vRW50cmllcy9FbnRyeUxpc3RpbmcuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUHJvcFR5cGVzIGZyb20gJ3Byb3AtdHlwZXMnO1xuaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0JztcbmltcG9ydCBJbW11dGFibGVQcm9wVHlwZXMgZnJvbSAncmVhY3QtaW1tdXRhYmxlLXByb3B0eXBlcyc7XG5pbXBvcnQgc3R5bGVkIGZyb20gJ0BlbW90aW9uL3N0eWxlZCc7XG5pbXBvcnQgeyBXYXlwb2ludCB9IGZyb20gJ3JlYWN0LXdheXBvaW50JztcbmltcG9ydCB7IE1hcCwgTGlzdCB9IGZyb20gJ2ltbXV0YWJsZSc7XG5cbmltcG9ydCB7IHNlbGVjdEZpZWxkcywgc2VsZWN0SW5mZXJyZWRGaWVsZCB9IGZyb20gJy4uLy4uLy4uL3JlZHVjZXJzL2NvbGxlY3Rpb25zJztcbmltcG9ydCB7IGZpbHRlck5lc3RlZEVudHJpZXMgfSBmcm9tICcuL0VudHJpZXNDb2xsZWN0aW9uJztcbmltcG9ydCBFbnRyeUNhcmQgZnJvbSAnLi9FbnRyeUNhcmQnO1xuXG5jb25zdCBDYXJkc0dyaWQgPSBzdHlsZWQudWxgXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZmxvdzogcm93IHdyYXA7XG4gIGxpc3Qtc3R5bGUtdHlwZTogbm9uZTtcbiAgbWFyZ2luLWxlZnQ6IC0xMnB4O1xuICBtYXJnaW4tdG9wOiAxNnB4O1xuICBtYXJnaW4tYm90dG9tOiAxNnB4O1xuYDtcblxuY2xhc3MgRW50cnlMaXN0aW5nIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgc3RhdGljIHByb3BUeXBlcyA9IHtcbiAgICBjb2xsZWN0aW9uczogSW1tdXRhYmxlUHJvcFR5cGVzLml0ZXJhYmxlLmlzUmVxdWlyZWQsXG4gICAgZW50cmllczogSW1tdXRhYmxlUHJvcFR5cGVzLmxpc3QsXG4gICAgdmlld1N0eWxlOiBQcm9wVHlwZXMuc3RyaW5nLFxuICAgIGN1cnNvcjogUHJvcFR5cGVzLmFueS5pc1JlcXVpcmVkLFxuICAgIGhhbmRsZUN1cnNvckFjdGlvbnM6IFByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgcGFnZTogUHJvcFR5cGVzLm51bWJlcixcbiAgICBnZXRVbnB1Ymxpc2hlZEVudHJpZXM6IFByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgZ2V0V29ya2Zsb3dTdGF0dXM6IFByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgZmlsdGVyVGVybTogUHJvcFR5cGVzLnN0cmluZyxcbiAgfTtcblxuICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICAvLyBNYW51YWxseSB2YWxpZGF0ZSBQcm9wVHlwZXMgLSBSZWFjdCAxOSBicmVha2luZyBjaGFuZ2VcbiAgICBQcm9wVHlwZXMuY2hlY2tQcm9wVHlwZXMoRW50cnlMaXN0aW5nLnByb3BUeXBlcywgdGhpcy5wcm9wcywgJ3Byb3AnLCAnRW50cnlMaXN0aW5nJyk7XG4gIH1cblxuICBoYXNNb3JlID0gKCkgPT4ge1xuICAgIGNvbnN0IGhhc01vcmUgPSB0aGlzLnByb3BzLmN1cnNvcj8uYWN0aW9ucz8uaGFzKCdhcHBlbmRfbmV4dCcpO1xuICAgIHJldHVybiBoYXNNb3JlO1xuICB9O1xuXG4gIGhhbmRsZUxvYWRNb3JlID0gKCkgPT4ge1xuICAgIGlmICh0aGlzLmhhc01vcmUoKSkge1xuICAgICAgdGhpcy5wcm9wcy5oYW5kbGVDdXJzb3JBY3Rpb25zKCdhcHBlbmRfbmV4dCcpO1xuICAgIH1cbiAgfTtcblxuICBpbmZlckZpZWxkcyA9IGNvbGxlY3Rpb24gPT4ge1xuICAgIGNvbnN0IHRpdGxlRmllbGQgPSBzZWxlY3RJbmZlcnJlZEZpZWxkKGNvbGxlY3Rpb24sICd0aXRsZScpO1xuICAgIGNvbnN0IGRlc2NyaXB0aW9uRmllbGQgPSBzZWxlY3RJbmZlcnJlZEZpZWxkKGNvbGxlY3Rpb24sICdkZXNjcmlwdGlvbicpO1xuICAgIGNvbnN0IGltYWdlRmllbGQgPSBzZWxlY3RJbmZlcnJlZEZpZWxkKGNvbGxlY3Rpb24sICdpbWFnZScpO1xuICAgIGNvbnN0IGZpZWxkcyA9IHNlbGVjdEZpZWxkcyhjb2xsZWN0aW9uKTtcbiAgICBjb25zdCBpbmZlcnJlZEZpZWxkcyA9IFt0aXRsZUZpZWxkLCBkZXNjcmlwdGlvbkZpZWxkLCBpbWFnZUZpZWxkXTtcbiAgICBjb25zdCByZW1haW5pbmdGaWVsZHMgPVxuICAgICAgZmllbGRzICYmIGZpZWxkcy5maWx0ZXIoZiA9PiBpbmZlcnJlZEZpZWxkcy5pbmRleE9mKGYuZ2V0KCduYW1lJykpID09PSAtMSk7XG4gICAgcmV0dXJuIHsgdGl0bGVGaWVsZCwgZGVzY3JpcHRpb25GaWVsZCwgaW1hZ2VGaWVsZCwgcmVtYWluaW5nRmllbGRzIH07XG4gIH07XG5cbiAgZ2V0QWxsRW50cmllcyA9ICgpID0+IHtcbiAgICBjb25zdCB7IGVudHJpZXMsIGNvbGxlY3Rpb25zLCBmaWx0ZXJUZXJtIH0gPSB0aGlzLnByb3BzO1xuICAgIGNvbnN0IGNvbGxlY3Rpb25OYW1lID0gTWFwLmlzTWFwKGNvbGxlY3Rpb25zKSA/IGNvbGxlY3Rpb25zLmdldCgnbmFtZScpIDogbnVsbDtcblxuICAgIGlmICghY29sbGVjdGlvbk5hbWUpIHtcbiAgICAgIHJldHVybiBlbnRyaWVzO1xuICAgIH1cblxuICAgIGNvbnN0IHVucHVibGlzaGVkRW50cmllcyA9IHRoaXMucHJvcHMuZ2V0VW5wdWJsaXNoZWRFbnRyaWVzKGNvbGxlY3Rpb25OYW1lKTtcblxuICAgIGlmICghdW5wdWJsaXNoZWRFbnRyaWVzIHx8IHVucHVibGlzaGVkRW50cmllcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBlbnRyaWVzO1xuICAgIH1cblxuICAgIGxldCB1bnB1Ymxpc2hlZExpc3QgPSBMaXN0KHVucHVibGlzaGVkRW50cmllcy5tYXAoZW50cnkgPT4gZW50cnkpKTtcblxuICAgIGlmIChjb2xsZWN0aW9ucy5oYXMoJ25lc3RlZCcpICYmIGZpbHRlclRlcm0pIHtcbiAgICAgIGNvbnN0IGNvbGxlY3Rpb25Gb2xkZXIgPSBjb2xsZWN0aW9ucy5nZXQoJ2ZvbGRlcicpO1xuICAgICAgY29uc3Qgc3ViZm9sZGVycyA9IGNvbGxlY3Rpb25zLmdldCgnbmVzdGVkJykuZ2V0KCdzdWJmb2xkZXJzJykgIT09IGZhbHNlO1xuXG4gICAgICB1bnB1Ymxpc2hlZExpc3QgPSBmaWx0ZXJOZXN0ZWRFbnRyaWVzKFxuICAgICAgICBmaWx0ZXJUZXJtLFxuICAgICAgICBjb2xsZWN0aW9uRm9sZGVyLFxuICAgICAgICB1bnB1Ymxpc2hlZExpc3QsXG4gICAgICAgIHN1YmZvbGRlcnMsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHB1Ymxpc2hlZFNsdWdzID0gZW50cmllcy5tYXAoZW50cnkgPT4gZW50cnkuZ2V0KCdzbHVnJykpLnRvU2V0KCk7XG4gICAgY29uc3QgdW5pcXVlVW5wdWJsaXNoZWQgPSB1bnB1Ymxpc2hlZExpc3QuZmlsdGVyTm90KGVudHJ5ID0+XG4gICAgICBwdWJsaXNoZWRTbHVncy5oYXMoZW50cnkuZ2V0KCdzbHVnJykpLFxuICAgICk7XG5cbiAgICByZXR1cm4gZW50cmllcy5jb25jYXQodW5pcXVlVW5wdWJsaXNoZWQpO1xuICB9O1xuXG4gIHJlbmRlckNhcmRzRm9yU2luZ2xlQ29sbGVjdGlvbiA9ICgpID0+IHtcbiAgICBjb25zdCB7IGNvbGxlY3Rpb25zLCB2aWV3U3R5bGUgfSA9IHRoaXMucHJvcHM7XG4gICAgY29uc3QgYWxsRW50cmllcyA9IHRoaXMuZ2V0QWxsRW50cmllcygpO1xuICAgIGNvbnN0IGluZmVycmVkRmllbGRzID0gdGhpcy5pbmZlckZpZWxkcyhjb2xsZWN0aW9ucyk7XG4gICAgY29uc3QgZW50cnlDYXJkUHJvcHMgPSB7IGNvbGxlY3Rpb246IGNvbGxlY3Rpb25zLCBpbmZlcnJlZEZpZWxkcywgdmlld1N0eWxlIH07XG5cbiAgICByZXR1cm4gYWxsRW50cmllcy5tYXAoKGVudHJ5LCBpZHgpID0+IHtcbiAgICAgIGNvbnN0IHdvcmtmbG93U3RhdHVzID0gdGhpcy5wcm9wcy5nZXRXb3JrZmxvd1N0YXR1cyhcbiAgICAgICAgY29sbGVjdGlvbnMuZ2V0KCduYW1lJyksXG4gICAgICAgIGVudHJ5LmdldCgnc2x1ZycpLFxuICAgICAgKTtcblxuICAgICAgcmV0dXJuIChcbiAgICAgICAgPEVudHJ5Q2FyZCB7Li4uZW50cnlDYXJkUHJvcHN9IGVudHJ5PXtlbnRyeX0gd29ya2Zsb3dTdGF0dXM9e3dvcmtmbG93U3RhdHVzfSBrZXk9e2lkeH0gLz5cbiAgICAgICk7XG4gICAgfSk7XG4gIH07XG5cbiAgcmVuZGVyQ2FyZHNGb3JNdWx0aXBsZUNvbGxlY3Rpb25zID0gKCkgPT4ge1xuICAgIGNvbnN0IHsgY29sbGVjdGlvbnMsIGVudHJpZXMgfSA9IHRoaXMucHJvcHM7XG4gICAgY29uc3QgaXNTaW5nbGVDb2xsZWN0aW9uSW5MaXN0ID0gY29sbGVjdGlvbnMuc2l6ZSA9PT0gMTtcbiAgICByZXR1cm4gZW50cmllcy5tYXAoKGVudHJ5LCBpZHgpID0+IHtcbiAgICAgIGNvbnN0IGNvbGxlY3Rpb25OYW1lID0gZW50cnkuZ2V0KCdjb2xsZWN0aW9uJyk7XG4gICAgICBjb25zdCBjb2xsZWN0aW9uID0gY29sbGVjdGlvbnMuZmluZChjb2xsID0+IGNvbGwuZ2V0KCduYW1lJykgPT09IGNvbGxlY3Rpb25OYW1lKTtcbiAgICAgIGNvbnN0IGNvbGxlY3Rpb25MYWJlbCA9ICFpc1NpbmdsZUNvbGxlY3Rpb25Jbkxpc3QgJiYgY29sbGVjdGlvbi5nZXQoJ2xhYmVsJyk7XG4gICAgICBjb25zdCBpbmZlcnJlZEZpZWxkcyA9IHRoaXMuaW5mZXJGaWVsZHMoY29sbGVjdGlvbik7XG4gICAgICBjb25zdCB3b3JrZmxvd1N0YXR1cyA9IHRoaXMucHJvcHMuZ2V0V29ya2Zsb3dTdGF0dXMoY29sbGVjdGlvbk5hbWUsIGVudHJ5LmdldCgnc2x1ZycpKTtcbiAgICAgIGNvbnN0IGVudHJ5Q2FyZFByb3BzID0ge1xuICAgICAgICBjb2xsZWN0aW9uLFxuICAgICAgICBlbnRyeSxcbiAgICAgICAgaW5mZXJyZWRGaWVsZHMsXG4gICAgICAgIGNvbGxlY3Rpb25MYWJlbCxcbiAgICAgICAgd29ya2Zsb3dTdGF0dXMsXG4gICAgICB9O1xuICAgICAgcmV0dXJuIDxFbnRyeUNhcmQgey4uLmVudHJ5Q2FyZFByb3BzfSBrZXk9e2lkeH0gLz47XG4gICAgfSk7XG4gIH07XG5cbiAgcmVuZGVyKCkge1xuICAgIGNvbnN0IHsgY29sbGVjdGlvbnMsIHBhZ2UgfSA9IHRoaXMucHJvcHM7XG5cbiAgICByZXR1cm4gKFxuICAgICAgPGRpdj5cbiAgICAgICAgPENhcmRzR3JpZD5cbiAgICAgICAgICB7TWFwLmlzTWFwKGNvbGxlY3Rpb25zKVxuICAgICAgICAgICAgPyB0aGlzLnJlbmRlckNhcmRzRm9yU2luZ2xlQ29sbGVjdGlvbigpXG4gICAgICAgICAgICA6IHRoaXMucmVuZGVyQ2FyZHNGb3JNdWx0aXBsZUNvbGxlY3Rpb25zKCl9XG4gICAgICAgICAge3RoaXMuaGFzTW9yZSgpICYmIDxXYXlwb2ludCBrZXk9e3BhZ2V9IG9uRW50ZXI9e3RoaXMuaGFuZGxlTG9hZE1vcmV9IC8+fVxuICAgICAgICA8L0NhcmRzR3JpZD5cbiAgICAgIDwvZGl2PlxuICAgICk7XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgRW50cnlMaXN0aW5nO1xuIl19 */",
|
|
21
22
|
toString: _EMOTION_STRINGIFIED_CSS_ERROR__
|
|
22
23
|
});
|
|
23
|
-
|
|
24
|
+
class EntryListing extends React.Component {
|
|
24
25
|
static propTypes = {
|
|
25
26
|
collections: ImmutablePropTypes.iterable.isRequired,
|
|
26
27
|
entries: ImmutablePropTypes.list,
|
|
27
28
|
viewStyle: PropTypes.string,
|
|
28
29
|
cursor: PropTypes.any.isRequired,
|
|
29
30
|
handleCursorActions: PropTypes.func.isRequired,
|
|
30
|
-
page: PropTypes.number
|
|
31
|
+
page: PropTypes.number,
|
|
32
|
+
getUnpublishedEntries: PropTypes.func.isRequired,
|
|
33
|
+
getWorkflowStatus: PropTypes.func.isRequired,
|
|
34
|
+
filterTerm: PropTypes.string
|
|
31
35
|
};
|
|
32
36
|
componentDidMount() {
|
|
33
37
|
// Manually validate PropTypes - React 19 breaking change
|
|
@@ -56,22 +60,50 @@ export default class EntryListing extends React.Component {
|
|
|
56
60
|
remainingFields
|
|
57
61
|
};
|
|
58
62
|
};
|
|
63
|
+
getAllEntries = () => {
|
|
64
|
+
const {
|
|
65
|
+
entries,
|
|
66
|
+
collections,
|
|
67
|
+
filterTerm
|
|
68
|
+
} = this.props;
|
|
69
|
+
const collectionName = Map.isMap(collections) ? collections.get('name') : null;
|
|
70
|
+
if (!collectionName) {
|
|
71
|
+
return entries;
|
|
72
|
+
}
|
|
73
|
+
const unpublishedEntries = this.props.getUnpublishedEntries(collectionName);
|
|
74
|
+
if (!unpublishedEntries || unpublishedEntries.length === 0) {
|
|
75
|
+
return entries;
|
|
76
|
+
}
|
|
77
|
+
let unpublishedList = List(unpublishedEntries.map(entry => entry));
|
|
78
|
+
if (collections.has('nested') && filterTerm) {
|
|
79
|
+
const collectionFolder = collections.get('folder');
|
|
80
|
+
const subfolders = collections.get('nested').get('subfolders') !== false;
|
|
81
|
+
unpublishedList = filterNestedEntries(filterTerm, collectionFolder, unpublishedList, subfolders);
|
|
82
|
+
}
|
|
83
|
+
const publishedSlugs = entries.map(entry => entry.get('slug')).toSet();
|
|
84
|
+
const uniqueUnpublished = unpublishedList.filterNot(entry => publishedSlugs.has(entry.get('slug')));
|
|
85
|
+
return entries.concat(uniqueUnpublished);
|
|
86
|
+
};
|
|
59
87
|
renderCardsForSingleCollection = () => {
|
|
60
88
|
const {
|
|
61
89
|
collections,
|
|
62
|
-
entries,
|
|
63
90
|
viewStyle
|
|
64
91
|
} = this.props;
|
|
92
|
+
const allEntries = this.getAllEntries();
|
|
65
93
|
const inferredFields = this.inferFields(collections);
|
|
66
94
|
const entryCardProps = {
|
|
67
95
|
collection: collections,
|
|
68
96
|
inferredFields,
|
|
69
97
|
viewStyle
|
|
70
98
|
};
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
99
|
+
return allEntries.map((entry, idx) => {
|
|
100
|
+
const workflowStatus = this.props.getWorkflowStatus(collections.get('name'), entry.get('slug'));
|
|
101
|
+
return ___EmotionJSX(EntryCard, _extends({}, entryCardProps, {
|
|
102
|
+
entry: entry,
|
|
103
|
+
workflowStatus: workflowStatus,
|
|
104
|
+
key: idx
|
|
105
|
+
}));
|
|
106
|
+
});
|
|
75
107
|
};
|
|
76
108
|
renderCardsForMultipleCollections = () => {
|
|
77
109
|
const {
|
|
@@ -84,11 +116,13 @@ export default class EntryListing extends React.Component {
|
|
|
84
116
|
const collection = collections.find(coll => coll.get('name') === collectionName);
|
|
85
117
|
const collectionLabel = !isSingleCollectionInList && collection.get('label');
|
|
86
118
|
const inferredFields = this.inferFields(collection);
|
|
119
|
+
const workflowStatus = this.props.getWorkflowStatus(collectionName, entry.get('slug'));
|
|
87
120
|
const entryCardProps = {
|
|
88
121
|
collection,
|
|
89
122
|
entry,
|
|
90
123
|
inferredFields,
|
|
91
|
-
collectionLabel
|
|
124
|
+
collectionLabel,
|
|
125
|
+
workflowStatus
|
|
92
126
|
};
|
|
93
127
|
return ___EmotionJSX(EntryCard, _extends({}, entryCardProps, {
|
|
94
128
|
key: idx
|
|
@@ -105,4 +139,5 @@ export default class EntryListing extends React.Component {
|
|
|
105
139
|
onEnter: this.handleLoadMore
|
|
106
140
|
})));
|
|
107
141
|
}
|
|
108
|
-
}
|
|
142
|
+
}
|
|
143
|
+
export default EntryListing;
|
|
@@ -44,8 +44,8 @@ function buildIssueTemplate({
|
|
|
44
44
|
let version = '';
|
|
45
45
|
if (typeof DECAP_CMS_VERSION === 'string') {
|
|
46
46
|
version = `decap-cms@${DECAP_CMS_VERSION}`;
|
|
47
|
-
} else if (typeof "3.
|
|
48
|
-
version = `decap-cms-app@${"3.
|
|
47
|
+
} else if (typeof "3.8.0" === 'string') {
|
|
48
|
+
version = `decap-cms-app@${"3.8.0"}`;
|
|
49
49
|
}
|
|
50
50
|
const template = getIssueTemplate({
|
|
51
51
|
version,
|
|
@@ -244,6 +244,20 @@ function getConfigSchema() {
|
|
|
244
244
|
type: 'string',
|
|
245
245
|
examples: ['https://example.com/images/logo.svg']
|
|
246
246
|
},
|
|
247
|
+
// Deprecated, replaced by `logo.src`
|
|
248
|
+
logo: {
|
|
249
|
+
type: 'object',
|
|
250
|
+
properties: {
|
|
251
|
+
src: {
|
|
252
|
+
type: 'string',
|
|
253
|
+
examples: ['https://example.com/images/logo.svg']
|
|
254
|
+
},
|
|
255
|
+
show_in_header: {
|
|
256
|
+
type: 'boolean'
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
required: ['src']
|
|
260
|
+
},
|
|
247
261
|
show_preview_links: {
|
|
248
262
|
type: 'boolean'
|
|
249
263
|
},
|
package/dist/esm/formats/toml.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import parseToml from '@iarna/toml/parse-string';
|
|
2
2
|
import tomlify from 'tomlify-j0.4';
|
|
3
3
|
import dayjs from 'dayjs';
|
|
4
4
|
import AssetProxy from '../valueObjects/AssetProxy';
|
|
@@ -21,7 +21,7 @@ function outputReplacer(_key, value) {
|
|
|
21
21
|
}
|
|
22
22
|
export default {
|
|
23
23
|
fromFile(content) {
|
|
24
|
-
return
|
|
24
|
+
return parseToml(content);
|
|
25
25
|
},
|
|
26
26
|
toFile(data, sortedKeys = []) {
|
|
27
27
|
return tomlify.toToml(data, {
|
package/dist/esm/lib/i18n.js
CHANGED
|
@@ -185,6 +185,19 @@ export function formatI18nBackup(i18nBackup, formatRawData) {
|
|
|
185
185
|
}, {});
|
|
186
186
|
return i18n;
|
|
187
187
|
}
|
|
188
|
+
function applyDefaultI18nValues(collection, value, defaultLocaleValue) {
|
|
189
|
+
if (collection.get('fields') === undefined) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
collection.get('fields').forEach(field => {
|
|
193
|
+
if (field && field.get(I18N) === I18N_FIELD.DUPLICATE) {
|
|
194
|
+
const data = value.data[field.get('name')];
|
|
195
|
+
if (!data) {
|
|
196
|
+
value.data[field.get('name')] = defaultLocaleValue.data[field.get('name')];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
188
201
|
function mergeValues(collection, structure, defaultLocale, values) {
|
|
189
202
|
let defaultEntry = values.find(e => e.locale === defaultLocale);
|
|
190
203
|
if (!defaultEntry) {
|
|
@@ -196,6 +209,9 @@ function mergeValues(collection, structure, defaultLocale, values) {
|
|
|
196
209
|
value
|
|
197
210
|
}) => {
|
|
198
211
|
const dataPath = getLocaleDataPath(locale);
|
|
212
|
+
if (defaultEntry) {
|
|
213
|
+
applyDefaultI18nValues(collection, value, defaultEntry.value);
|
|
214
|
+
}
|
|
199
215
|
return set(acc, dataPath, value.data);
|
|
200
216
|
}, {});
|
|
201
217
|
const path = normalizeFilePath(structure, defaultEntry.value.path, defaultLocale);
|
package/index.d.ts
CHANGED
|
@@ -384,7 +384,11 @@ declare module 'decap-cms-core' {
|
|
|
384
384
|
locale?: string;
|
|
385
385
|
site_url?: string;
|
|
386
386
|
display_url?: string;
|
|
387
|
-
logo_url?: string;
|
|
387
|
+
logo_url?: string; // Deprecated, replaced by `logo.src`
|
|
388
|
+
logo?: {
|
|
389
|
+
src: string;
|
|
390
|
+
show_in_header?: boolean;
|
|
391
|
+
};
|
|
388
392
|
show_preview_links?: boolean;
|
|
389
393
|
media_folder?: string;
|
|
390
394
|
public_folder?: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "decap-cms-core",
|
|
3
3
|
"description": "Decap CMS core application, see decap-cms package for the main distribution.",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.8.0",
|
|
5
5
|
"repository": "https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-core",
|
|
6
6
|
"bugs": "https://github.com/decaporg/decap-cms/issues",
|
|
7
7
|
"module": "dist/esm/index.js",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"@iarna/toml": "2.2.5",
|
|
28
28
|
"@reduxjs/toolkit": "^1.9.1",
|
|
29
29
|
"@vercel/stega": "^0.1.2",
|
|
30
|
+
"buffer": "^6.0.3",
|
|
30
31
|
"clean-stack": "^5.2.0",
|
|
31
32
|
"copy-text-to-clipboard": "^3.0.0",
|
|
32
33
|
"dayjs": "^1.11.10",
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"js-base64": "^3.0.0",
|
|
41
42
|
"jwt-decode": "^3.0.0",
|
|
42
43
|
"node-polyglot": "^2.3.0",
|
|
44
|
+
"path-browserify": "^1.0.1",
|
|
43
45
|
"prop-types": "^15.7.2",
|
|
44
46
|
"react": "^19.1.0",
|
|
45
47
|
"react-dnd": "^14.0.0",
|
|
@@ -90,9 +92,13 @@
|
|
|
90
92
|
},
|
|
91
93
|
"devDependencies": {
|
|
92
94
|
"@types/history": "^4.7.8",
|
|
95
|
+
"@types/iarna__toml": "^2.0.5",
|
|
93
96
|
"@types/redux-mock-store": "^1.0.2",
|
|
94
97
|
"@types/url-join": "^4.0.0",
|
|
95
98
|
"redux-mock-store": "^1.5.3"
|
|
96
99
|
},
|
|
97
|
-
"
|
|
100
|
+
"browser": {
|
|
101
|
+
"path": "path-browserify"
|
|
102
|
+
},
|
|
103
|
+
"gitHead": "d3465f53b7f056ad5d872948a07eaa8e4ae63315"
|
|
98
104
|
}
|
package/src/bootstrap.js
CHANGED
|
@@ -188,6 +188,8 @@ class App extends React.Component {
|
|
|
188
188
|
openMediaLibrary={openMediaLibrary}
|
|
189
189
|
hasWorkflow={hasWorkflow}
|
|
190
190
|
displayUrl={config.display_url}
|
|
191
|
+
logoUrl={config.logo_url} // Deprecated, replaced by `logo.src`
|
|
192
|
+
logo={config.logo}
|
|
191
193
|
isTestRepo={config.backend.name === 'test-repo'}
|
|
192
194
|
showMediaButton={showMediaButton}
|
|
193
195
|
/>
|
|
@@ -114,6 +114,19 @@ const AppHeaderNavList = styled.ul`
|
|
|
114
114
|
list-style: none;
|
|
115
115
|
`;
|
|
116
116
|
|
|
117
|
+
const AppHeaderLogo = styled.li`
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
|
|
121
|
+
img {
|
|
122
|
+
padding: 12px 20px;
|
|
123
|
+
max-height: 56px;
|
|
124
|
+
max-width: 300px;
|
|
125
|
+
object-fit: contain;
|
|
126
|
+
object-position: center;
|
|
127
|
+
}
|
|
128
|
+
`;
|
|
129
|
+
|
|
117
130
|
class Header extends React.Component {
|
|
118
131
|
static propTypes = {
|
|
119
132
|
user: PropTypes.object.isRequired,
|
|
@@ -123,6 +136,11 @@ class Header extends React.Component {
|
|
|
123
136
|
openMediaLibrary: PropTypes.func.isRequired,
|
|
124
137
|
hasWorkflow: PropTypes.bool.isRequired,
|
|
125
138
|
displayUrl: PropTypes.string,
|
|
139
|
+
logoUrl: PropTypes.string, // Deprecated, replaced by `logo.src`
|
|
140
|
+
logo: PropTypes.shape({
|
|
141
|
+
src: PropTypes.string.isRequired,
|
|
142
|
+
show_in_header: PropTypes.bool,
|
|
143
|
+
}),
|
|
126
144
|
isTestRepo: PropTypes.bool,
|
|
127
145
|
t: PropTypes.func.isRequired,
|
|
128
146
|
checkBackendStatus: PropTypes.func.isRequired,
|
|
@@ -158,6 +176,8 @@ class Header extends React.Component {
|
|
|
158
176
|
openMediaLibrary,
|
|
159
177
|
hasWorkflow,
|
|
160
178
|
displayUrl,
|
|
179
|
+
logoUrl, // Deprecated, replaced by `logo.src`
|
|
180
|
+
logo,
|
|
161
181
|
isTestRepo,
|
|
162
182
|
t,
|
|
163
183
|
showMediaButton,
|
|
@@ -167,11 +187,18 @@ class Header extends React.Component {
|
|
|
167
187
|
.filter(collection => collection.get('create'))
|
|
168
188
|
.toList();
|
|
169
189
|
|
|
190
|
+
const shouldShowLogo = logo?.show_in_header && logo?.src;
|
|
191
|
+
|
|
170
192
|
return (
|
|
171
193
|
<AppHeader>
|
|
172
194
|
<AppHeaderContent>
|
|
173
195
|
<nav>
|
|
174
196
|
<AppHeaderNavList>
|
|
197
|
+
{shouldShowLogo && (
|
|
198
|
+
<AppHeaderLogo>
|
|
199
|
+
<img src={logo?.src || logoUrl} alt="Logo" />
|
|
200
|
+
</AppHeaderLogo>
|
|
201
|
+
)}
|
|
175
202
|
<li>
|
|
176
203
|
<AppHeaderNavLink
|
|
177
204
|
to="/"
|
|
@@ -26,6 +26,9 @@ function Entries({
|
|
|
26
26
|
handleCursorActions,
|
|
27
27
|
t,
|
|
28
28
|
page,
|
|
29
|
+
getWorkflowStatus,
|
|
30
|
+
getUnpublishedEntries,
|
|
31
|
+
filterTerm,
|
|
29
32
|
}) {
|
|
30
33
|
const loadingMessages = [
|
|
31
34
|
t('collection.entries.loadingEntries'),
|
|
@@ -48,6 +51,9 @@ function Entries({
|
|
|
48
51
|
cursor={cursor}
|
|
49
52
|
handleCursorActions={handleCursorActions}
|
|
50
53
|
page={page}
|
|
54
|
+
getWorkflowStatus={getWorkflowStatus}
|
|
55
|
+
getUnpublishedEntries={getUnpublishedEntries}
|
|
56
|
+
filterTerm={filterTerm}
|
|
51
57
|
/>
|
|
52
58
|
{isFetching && page !== undefined && entries.size > 0 ? (
|
|
53
59
|
<PaginationMessage>{t('collection.entries.loadingEntries')}</PaginationMessage>
|
|
@@ -68,6 +74,9 @@ Entries.propTypes = {
|
|
|
68
74
|
cursor: PropTypes.any.isRequired,
|
|
69
75
|
handleCursorActions: PropTypes.func.isRequired,
|
|
70
76
|
t: PropTypes.func.isRequired,
|
|
77
|
+
getWorkflowStatus: PropTypes.func,
|
|
78
|
+
getUnpublishedEntries: PropTypes.func,
|
|
79
|
+
filterTerm: PropTypes.string,
|
|
71
80
|
};
|
|
72
81
|
|
|
73
82
|
export default translate()(Entries);
|
|
@@ -12,12 +12,14 @@ import {
|
|
|
12
12
|
loadEntries as actionLoadEntries,
|
|
13
13
|
traverseCollectionCursor as actionTraverseCollectionCursor,
|
|
14
14
|
} from '../../../actions/entries';
|
|
15
|
+
import { loadUnpublishedEntries } from '../../../actions/editorialWorkflow';
|
|
15
16
|
import {
|
|
16
17
|
selectEntries,
|
|
17
18
|
selectEntriesLoaded,
|
|
18
19
|
selectIsFetching,
|
|
19
20
|
selectGroups,
|
|
20
21
|
} from '../../../reducers/entries';
|
|
22
|
+
import { selectUnpublishedEntry, selectUnpublishedEntriesByStatus } from '../../../reducers';
|
|
21
23
|
import { selectCollectionEntriesCursor } from '../../../reducers/cursors';
|
|
22
24
|
import Entries from './Entries';
|
|
23
25
|
|
|
@@ -61,6 +63,7 @@ function withGroups(groups, entries, EntriesToRender, t) {
|
|
|
61
63
|
export class EntriesCollection extends React.Component {
|
|
62
64
|
static propTypes = {
|
|
63
65
|
collection: ImmutablePropTypes.map.isRequired,
|
|
66
|
+
collections: ImmutablePropTypes.iterable,
|
|
64
67
|
page: PropTypes.number,
|
|
65
68
|
entries: ImmutablePropTypes.list,
|
|
66
69
|
groups: PropTypes.array,
|
|
@@ -70,23 +73,57 @@ export class EntriesCollection extends React.Component {
|
|
|
70
73
|
loadEntries: PropTypes.func.isRequired,
|
|
71
74
|
traverseCollectionCursor: PropTypes.func.isRequired,
|
|
72
75
|
entriesLoaded: PropTypes.bool,
|
|
76
|
+
loadUnpublishedEntries: PropTypes.func.isRequired,
|
|
77
|
+
unpublishedEntriesLoaded: PropTypes.bool,
|
|
78
|
+
isEditorialWorkflowEnabled: PropTypes.bool,
|
|
79
|
+
getWorkflowStatus: PropTypes.func.isRequired,
|
|
80
|
+
getUnpublishedEntries: PropTypes.func.isRequired,
|
|
73
81
|
};
|
|
74
82
|
|
|
75
83
|
componentDidMount() {
|
|
76
84
|
// Manually validate PropTypes - React 19 breaking change
|
|
77
85
|
PropTypes.checkPropTypes(EntriesCollection.propTypes, this.props, 'prop', 'EntriesCollection');
|
|
78
86
|
|
|
79
|
-
const {
|
|
87
|
+
const {
|
|
88
|
+
collection,
|
|
89
|
+
collections,
|
|
90
|
+
entriesLoaded,
|
|
91
|
+
loadEntries,
|
|
92
|
+
unpublishedEntriesLoaded,
|
|
93
|
+
loadUnpublishedEntries,
|
|
94
|
+
isEditorialWorkflowEnabled,
|
|
95
|
+
} = this.props;
|
|
96
|
+
|
|
80
97
|
if (collection && !entriesLoaded) {
|
|
81
98
|
loadEntries(collection);
|
|
82
99
|
}
|
|
100
|
+
|
|
101
|
+
if (isEditorialWorkflowEnabled && !unpublishedEntriesLoaded) {
|
|
102
|
+
loadUnpublishedEntries(collections);
|
|
103
|
+
}
|
|
83
104
|
}
|
|
84
105
|
|
|
85
106
|
componentDidUpdate(prevProps) {
|
|
86
|
-
const {
|
|
107
|
+
const {
|
|
108
|
+
collection,
|
|
109
|
+
collections,
|
|
110
|
+
entriesLoaded,
|
|
111
|
+
loadEntries,
|
|
112
|
+
unpublishedEntriesLoaded,
|
|
113
|
+
loadUnpublishedEntries,
|
|
114
|
+
isEditorialWorkflowEnabled,
|
|
115
|
+
} = this.props;
|
|
116
|
+
|
|
87
117
|
if (collection !== prevProps.collection && !entriesLoaded) {
|
|
88
118
|
loadEntries(collection);
|
|
89
119
|
}
|
|
120
|
+
|
|
121
|
+
if (
|
|
122
|
+
isEditorialWorkflowEnabled &&
|
|
123
|
+
(!unpublishedEntriesLoaded || collection !== prevProps.collection)
|
|
124
|
+
) {
|
|
125
|
+
loadUnpublishedEntries(collections);
|
|
126
|
+
}
|
|
90
127
|
}
|
|
91
128
|
|
|
92
129
|
handleCursorActions = (cursor, action) => {
|
|
@@ -95,7 +132,19 @@ export class EntriesCollection extends React.Component {
|
|
|
95
132
|
};
|
|
96
133
|
|
|
97
134
|
render() {
|
|
98
|
-
const {
|
|
135
|
+
const {
|
|
136
|
+
collection,
|
|
137
|
+
entries,
|
|
138
|
+
groups,
|
|
139
|
+
isFetching,
|
|
140
|
+
viewStyle,
|
|
141
|
+
cursor,
|
|
142
|
+
page,
|
|
143
|
+
t,
|
|
144
|
+
getWorkflowStatus,
|
|
145
|
+
getUnpublishedEntries,
|
|
146
|
+
filterTerm,
|
|
147
|
+
} = this.props;
|
|
99
148
|
|
|
100
149
|
const EntriesToRender = ({ entries }) => {
|
|
101
150
|
return (
|
|
@@ -108,6 +157,9 @@ export class EntriesCollection extends React.Component {
|
|
|
108
157
|
cursor={cursor}
|
|
109
158
|
handleCursorActions={partial(this.handleCursorActions, cursor)}
|
|
110
159
|
page={page}
|
|
160
|
+
getWorkflowStatus={getWorkflowStatus}
|
|
161
|
+
getUnpublishedEntries={getUnpublishedEntries}
|
|
162
|
+
filterTerm={filterTerm}
|
|
111
163
|
/>
|
|
112
164
|
);
|
|
113
165
|
};
|
|
@@ -150,6 +202,8 @@ function mapStateToProps(state, ownProps) {
|
|
|
150
202
|
const { collection, viewStyle, filterTerm } = ownProps;
|
|
151
203
|
const page = state.entries.getIn(['pages', collection.get('name'), 'page']);
|
|
152
204
|
|
|
205
|
+
const collections = state.collections;
|
|
206
|
+
|
|
153
207
|
let entries = selectEntries(state.entries, collection);
|
|
154
208
|
const groups = selectGroups(state.entries, collection);
|
|
155
209
|
|
|
@@ -168,12 +222,54 @@ function mapStateToProps(state, ownProps) {
|
|
|
168
222
|
const rawCursor = selectCollectionEntriesCursor(state.cursors, collection.get('name'));
|
|
169
223
|
const cursor = Cursor.create(rawCursor).clearData();
|
|
170
224
|
|
|
171
|
-
|
|
225
|
+
const isEditorialWorkflowEnabled = state.config?.publish_mode === 'editorial_workflow';
|
|
226
|
+
const unpublishedEntriesLoaded = isEditorialWorkflowEnabled
|
|
227
|
+
? !!state.editorialWorkflow?.getIn(['pages', 'ids'], false)
|
|
228
|
+
: true;
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
collection,
|
|
232
|
+
collections,
|
|
233
|
+
page,
|
|
234
|
+
entries,
|
|
235
|
+
groups,
|
|
236
|
+
entriesLoaded,
|
|
237
|
+
isFetching,
|
|
238
|
+
viewStyle,
|
|
239
|
+
cursor,
|
|
240
|
+
unpublishedEntriesLoaded,
|
|
241
|
+
isEditorialWorkflowEnabled,
|
|
242
|
+
getWorkflowStatus: (collectionName, slug) => {
|
|
243
|
+
const unpublishedEntry = selectUnpublishedEntry(state, collectionName, slug);
|
|
244
|
+
return unpublishedEntry ? unpublishedEntry.get('status') : null;
|
|
245
|
+
},
|
|
246
|
+
getUnpublishedEntries: collectionName => {
|
|
247
|
+
if (!isEditorialWorkflowEnabled) return [];
|
|
248
|
+
|
|
249
|
+
const allStatuses = ['draft', 'pending_review', 'pending_publish'];
|
|
250
|
+
const unpublishedEntries = [];
|
|
251
|
+
|
|
252
|
+
allStatuses.forEach(statusKey => {
|
|
253
|
+
const entriesForStatus = selectUnpublishedEntriesByStatus(state, statusKey);
|
|
254
|
+
if (entriesForStatus) {
|
|
255
|
+
entriesForStatus.forEach(entry => {
|
|
256
|
+
if (entry.get('collection') === collectionName) {
|
|
257
|
+
const entryWithCollection = entry.set('collection', collectionName);
|
|
258
|
+
unpublishedEntries.push(entryWithCollection);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
return unpublishedEntries;
|
|
265
|
+
},
|
|
266
|
+
};
|
|
172
267
|
}
|
|
173
268
|
|
|
174
269
|
const mapDispatchToProps = {
|
|
175
270
|
loadEntries: actionLoadEntries,
|
|
176
271
|
traverseCollectionCursor: actionTraverseCollectionCursor,
|
|
272
|
+
loadUnpublishedEntries: collections => loadUnpublishedEntries(collections),
|
|
177
273
|
};
|
|
178
274
|
|
|
179
275
|
const ConnectedEntriesCollection = connect(mapStateToProps, mapDispatchToProps)(EntriesCollection);
|