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.
Files changed (31) hide show
  1. package/dist/decap-cms-core.js +26 -26
  2. package/dist/decap-cms-core.js.LICENSE.txt +0 -12
  3. package/dist/decap-cms-core.js.map +1 -1
  4. package/dist/esm/bootstrap.js +3 -2
  5. package/dist/esm/components/App/App.js +6 -3
  6. package/dist/esm/components/App/Header.js +38 -14
  7. package/dist/esm/components/Collection/Entries/Entries.js +14 -5
  8. package/dist/esm/components/Collection/Entries/EntriesCollection.js +65 -9
  9. package/dist/esm/components/Collection/Entries/EntryCard.js +84 -28
  10. package/dist/esm/components/Collection/Entries/EntryListing.js +46 -11
  11. package/dist/esm/components/UI/ErrorBoundary.js +2 -2
  12. package/dist/esm/constants/configSchema.js +14 -0
  13. package/dist/esm/formats/toml.js +2 -2
  14. package/dist/esm/lib/i18n.js +16 -0
  15. package/dist/esm/lib/polyfill.js +8 -0
  16. package/index.d.ts +5 -1
  17. package/package.json +8 -2
  18. package/src/bootstrap.js +1 -0
  19. package/src/components/App/App.js +2 -0
  20. package/src/components/App/Header.js +27 -0
  21. package/src/components/Collection/Entries/Entries.js +9 -0
  22. package/src/components/Collection/Entries/EntriesCollection.js +100 -4
  23. package/src/components/Collection/Entries/EntryCard.js +82 -3
  24. package/src/components/Collection/Entries/EntryListing.js +65 -5
  25. package/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js +26 -18
  26. package/src/components/Collection/Entries/__tests__/__snapshots__/EntriesCollection.spec.js.snap +1 -0
  27. package/src/constants/configSchema.js +9 -1
  28. package/src/formats/toml.ts +2 -2
  29. package/src/lib/i18n.ts +21 -0
  30. package/src/lib/polyfill.js +9 -0
  31. 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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL0NvbGxlY3Rpb24vRW50cmllcy9FbnRyeUxpc3RpbmcuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBVTJCIiwiZmlsZSI6Ii4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL0NvbGxlY3Rpb24vRW50cmllcy9FbnRyeUxpc3RpbmcuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUHJvcFR5cGVzIGZyb20gJ3Byb3AtdHlwZXMnO1xuaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0JztcbmltcG9ydCBJbW11dGFibGVQcm9wVHlwZXMgZnJvbSAncmVhY3QtaW1tdXRhYmxlLXByb3B0eXBlcyc7XG5pbXBvcnQgc3R5bGVkIGZyb20gJ0BlbW90aW9uL3N0eWxlZCc7XG5pbXBvcnQgeyBXYXlwb2ludCB9IGZyb20gJ3JlYWN0LXdheXBvaW50JztcbmltcG9ydCB7IE1hcCB9IGZyb20gJ2ltbXV0YWJsZSc7XG5cbmltcG9ydCB7IHNlbGVjdEZpZWxkcywgc2VsZWN0SW5mZXJyZWRGaWVsZCB9IGZyb20gJy4uLy4uLy4uL3JlZHVjZXJzL2NvbGxlY3Rpb25zJztcbmltcG9ydCBFbnRyeUNhcmQgZnJvbSAnLi9FbnRyeUNhcmQnO1xuXG5jb25zdCBDYXJkc0dyaWQgPSBzdHlsZWQudWxgXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZmxvdzogcm93IHdyYXA7XG4gIGxpc3Qtc3R5bGUtdHlwZTogbm9uZTtcbiAgbWFyZ2luLWxlZnQ6IC0xMnB4O1xuICBtYXJnaW4tdG9wOiAxNnB4O1xuICBtYXJnaW4tYm90dG9tOiAxNnB4O1xuYDtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRW50cnlMaXN0aW5nIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgc3RhdGljIHByb3BUeXBlcyA9IHtcbiAgICBjb2xsZWN0aW9uczogSW1tdXRhYmxlUHJvcFR5cGVzLml0ZXJhYmxlLmlzUmVxdWlyZWQsXG4gICAgZW50cmllczogSW1tdXRhYmxlUHJvcFR5cGVzLmxpc3QsXG4gICAgdmlld1N0eWxlOiBQcm9wVHlwZXMuc3RyaW5nLFxuICAgIGN1cnNvcjogUHJvcFR5cGVzLmFueS5pc1JlcXVpcmVkLFxuICAgIGhhbmRsZUN1cnNvckFjdGlvbnM6IFByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgcGFnZTogUHJvcFR5cGVzLm51bWJlcixcbiAgfTtcblxuICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICAvLyBNYW51YWxseSB2YWxpZGF0ZSBQcm9wVHlwZXMgLSBSZWFjdCAxOSBicmVha2luZyBjaGFuZ2VcbiAgICBQcm9wVHlwZXMuY2hlY2tQcm9wVHlwZXMoRW50cnlMaXN0aW5nLnByb3BUeXBlcywgdGhpcy5wcm9wcywgJ3Byb3AnLCAnRW50cnlMaXN0aW5nJyk7XG4gIH1cblxuICBoYXNNb3JlID0gKCkgPT4ge1xuICAgIGNvbnN0IGhhc01vcmUgPSB0aGlzLnByb3BzLmN1cnNvcj8uYWN0aW9ucz8uaGFzKCdhcHBlbmRfbmV4dCcpO1xuICAgIHJldHVybiBoYXNNb3JlO1xuICB9O1xuXG4gIGhhbmRsZUxvYWRNb3JlID0gKCkgPT4ge1xuICAgIGlmICh0aGlzLmhhc01vcmUoKSkge1xuICAgICAgdGhpcy5wcm9wcy5oYW5kbGVDdXJzb3JBY3Rpb25zKCdhcHBlbmRfbmV4dCcpO1xuICAgIH1cbiAgfTtcblxuICBpbmZlckZpZWxkcyA9IGNvbGxlY3Rpb24gPT4ge1xuICAgIGNvbnN0IHRpdGxlRmllbGQgPSBzZWxlY3RJbmZlcnJlZEZpZWxkKGNvbGxlY3Rpb24sICd0aXRsZScpO1xuICAgIGNvbnN0IGRlc2NyaXB0aW9uRmllbGQgPSBzZWxlY3RJbmZlcnJlZEZpZWxkKGNvbGxlY3Rpb24sICdkZXNjcmlwdGlvbicpO1xuICAgIGNvbnN0IGltYWdlRmllbGQgPSBzZWxlY3RJbmZlcnJlZEZpZWxkKGNvbGxlY3Rpb24sICdpbWFnZScpO1xuICAgIGNvbnN0IGZpZWxkcyA9IHNlbGVjdEZpZWxkcyhjb2xsZWN0aW9uKTtcbiAgICBjb25zdCBpbmZlcnJlZEZpZWxkcyA9IFt0aXRsZUZpZWxkLCBkZXNjcmlwdGlvbkZpZWxkLCBpbWFnZUZpZWxkXTtcbiAgICBjb25zdCByZW1haW5pbmdGaWVsZHMgPVxuICAgICAgZmllbGRzICYmIGZpZWxkcy5maWx0ZXIoZiA9PiBpbmZlcnJlZEZpZWxkcy5pbmRleE9mKGYuZ2V0KCduYW1lJykpID09PSAtMSk7XG4gICAgcmV0dXJuIHsgdGl0bGVGaWVsZCwgZGVzY3JpcHRpb25GaWVsZCwgaW1hZ2VGaWVsZCwgcmVtYWluaW5nRmllbGRzIH07XG4gIH07XG5cbiAgcmVuZGVyQ2FyZHNGb3JTaW5nbGVDb2xsZWN0aW9uID0gKCkgPT4ge1xuICAgIGNvbnN0IHsgY29sbGVjdGlvbnMsIGVudHJpZXMsIHZpZXdTdHlsZSB9ID0gdGhpcy5wcm9wcztcbiAgICBjb25zdCBpbmZlcnJlZEZpZWxkcyA9IHRoaXMuaW5mZXJGaWVsZHMoY29sbGVjdGlvbnMpO1xuICAgIGNvbnN0IGVudHJ5Q2FyZFByb3BzID0geyBjb2xsZWN0aW9uOiBjb2xsZWN0aW9ucywgaW5mZXJyZWRGaWVsZHMsIHZpZXdTdHlsZSB9O1xuICAgIHJldHVybiBlbnRyaWVzLm1hcCgoZW50cnksIGlkeCkgPT4gPEVudHJ5Q2FyZCB7Li4uZW50cnlDYXJkUHJvcHN9IGVudHJ5PXtlbnRyeX0ga2V5PXtpZHh9IC8+KTtcbiAgfTtcblxuICByZW5kZXJDYXJkc0Zvck11bHRpcGxlQ29sbGVjdGlvbnMgPSAoKSA9PiB7XG4gICAgY29uc3QgeyBjb2xsZWN0aW9ucywgZW50cmllcyB9ID0gdGhpcy5wcm9wcztcbiAgICBjb25zdCBpc1NpbmdsZUNvbGxlY3Rpb25Jbkxpc3QgPSBjb2xsZWN0aW9ucy5zaXplID09PSAxO1xuICAgIHJldHVybiBlbnRyaWVzLm1hcCgoZW50cnksIGlkeCkgPT4ge1xuICAgICAgY29uc3QgY29sbGVjdGlvbk5hbWUgPSBlbnRyeS5nZXQoJ2NvbGxlY3Rpb24nKTtcbiAgICAgIGNvbnN0IGNvbGxlY3Rpb24gPSBjb2xsZWN0aW9ucy5maW5kKGNvbGwgPT4gY29sbC5nZXQoJ25hbWUnKSA9PT0gY29sbGVjdGlvbk5hbWUpO1xuICAgICAgY29uc3QgY29sbGVjdGlvbkxhYmVsID0gIWlzU2luZ2xlQ29sbGVjdGlvbkluTGlzdCAmJiBjb2xsZWN0aW9uLmdldCgnbGFiZWwnKTtcbiAgICAgIGNvbnN0IGluZmVycmVkRmllbGRzID0gdGhpcy5pbmZlckZpZWxkcyhjb2xsZWN0aW9uKTtcbiAgICAgIGNvbnN0IGVudHJ5Q2FyZFByb3BzID0geyBjb2xsZWN0aW9uLCBlbnRyeSwgaW5mZXJyZWRGaWVsZHMsIGNvbGxlY3Rpb25MYWJlbCB9O1xuICAgICAgcmV0dXJuIDxFbnRyeUNhcmQgey4uLmVudHJ5Q2FyZFByb3BzfSBrZXk9e2lkeH0gLz47XG4gICAgfSk7XG4gIH07XG5cbiAgcmVuZGVyKCkge1xuICAgIGNvbnN0IHsgY29sbGVjdGlvbnMsIHBhZ2UgfSA9IHRoaXMucHJvcHM7XG5cbiAgICByZXR1cm4gKFxuICAgICAgPGRpdj5cbiAgICAgICAgPENhcmRzR3JpZD5cbiAgICAgICAgICB7TWFwLmlzTWFwKGNvbGxlY3Rpb25zKVxuICAgICAgICAgICAgPyB0aGlzLnJlbmRlckNhcmRzRm9yU2luZ2xlQ29sbGVjdGlvbigpXG4gICAgICAgICAgICA6IHRoaXMucmVuZGVyQ2FyZHNGb3JNdWx0aXBsZUNvbGxlY3Rpb25zKCl9XG4gICAgICAgICAge3RoaXMuaGFzTW9yZSgpICYmIDxXYXlwb2ludCBrZXk9e3BhZ2V9IG9uRW50ZXI9e3RoaXMuaGFuZGxlTG9hZE1vcmV9IC8+fVxuICAgICAgICA8L0NhcmRzR3JpZD5cbiAgICAgIDwvZGl2PlxuICAgICk7XG4gIH1cbn1cbiJdfQ== */",
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
- export default class EntryListing extends React.Component {
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 entries.map((entry, idx) => ___EmotionJSX(EntryCard, _extends({}, entryCardProps, {
72
- entry: entry,
73
- key: idx
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.7.0" === 'string') {
48
- version = `decap-cms-app@${"3.7.0"}`;
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
  },
@@ -1,4 +1,4 @@
1
- import toml from '@iarna/toml';
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 toml.parse(content);
24
+ return parseToml(content);
25
25
  },
26
26
  toFile(data, sortedKeys = []) {
27
27
  return tomlify.toToml(data, {
@@ -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);
@@ -0,0 +1,8 @@
1
+ import { Buffer } from 'buffer';
2
+ if (typeof window !== 'undefined') {
3
+ // Polyfill global for packages like @iarna/toml
4
+ window.global = window;
5
+
6
+ // Polyfill Buffer for packages like gray-matter
7
+ window.Buffer = Buffer;
8
+ }
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.7.0",
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
- "gitHead": "ed7e99318007b83f4c57f3237bf92b931676820a"
100
+ "browser": {
101
+ "path": "path-browserify"
102
+ },
103
+ "gitHead": "d3465f53b7f056ad5d872948a07eaa8e4ae63315"
98
104
  }
package/src/bootstrap.js CHANGED
@@ -1,3 +1,4 @@
1
+ import './lib/polyfill';
1
2
  import React from 'react';
2
3
  import { createRoot } from 'react-dom/client';
3
4
  import { Provider, connect } from 'react-redux';
@@ -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 { collection, entriesLoaded, loadEntries } = this.props;
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 { collection, entriesLoaded, loadEntries } = this.props;
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 { collection, entries, groups, isFetching, viewStyle, cursor, page, t } = this.props;
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
- return { collection, page, entries, groups, entriesLoaded, isFetching, viewStyle, cursor };
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);