@pranaysahith/decap-cms-core 3.9.1

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 (299) hide show
  1. package/README.md +9 -0
  2. package/dist/@pranaysahith/decap-cms-core.js +52 -0
  3. package/dist/@pranaysahith/decap-cms-core.js.LICENSE.txt +141 -0
  4. package/dist/@pranaysahith/decap-cms-core.js.map +1 -0
  5. package/dist/decap-cms-core.js +47 -0
  6. package/dist/decap-cms-core.js.LICENSE.txt +116 -0
  7. package/dist/decap-cms-core.js.map +1 -0
  8. package/dist/esm/actions/auth.js +97 -0
  9. package/dist/esm/actions/collections.js +15 -0
  10. package/dist/esm/actions/config.js +493 -0
  11. package/dist/esm/actions/deploys.js +79 -0
  12. package/dist/esm/actions/editorialWorkflow.js +480 -0
  13. package/dist/esm/actions/entries.js +865 -0
  14. package/dist/esm/actions/media.js +147 -0
  15. package/dist/esm/actions/mediaLibrary.js +552 -0
  16. package/dist/esm/actions/notifications.js +21 -0
  17. package/dist/esm/actions/search.js +149 -0
  18. package/dist/esm/actions/status.js +74 -0
  19. package/dist/esm/actions/waitUntil.js +32 -0
  20. package/dist/esm/backend.js +1082 -0
  21. package/dist/esm/bootstrap.js +101 -0
  22. package/dist/esm/components/App/App.js +289 -0
  23. package/dist/esm/components/App/Header.js +172 -0
  24. package/dist/esm/components/App/NotFoundPage.js +19 -0
  25. package/dist/esm/components/Collection/Collection.js +198 -0
  26. package/dist/esm/components/Collection/CollectionControls.js +46 -0
  27. package/dist/esm/components/Collection/CollectionSearch.js +222 -0
  28. package/dist/esm/components/Collection/CollectionTop.js +68 -0
  29. package/dist/esm/components/Collection/ControlButton.js +17 -0
  30. package/dist/esm/components/Collection/Entries/Entries.js +73 -0
  31. package/dist/esm/components/Collection/Entries/EntriesCollection.js +241 -0
  32. package/dist/esm/components/Collection/Entries/EntriesSearch.js +113 -0
  33. package/dist/esm/components/Collection/Entries/EntryCard.js +177 -0
  34. package/dist/esm/components/Collection/Entries/EntryListing.js +143 -0
  35. package/dist/esm/components/Collection/FilterControl.js +33 -0
  36. package/dist/esm/components/Collection/FolderRenameControl.js +403 -0
  37. package/dist/esm/components/Collection/GroupControl.js +33 -0
  38. package/dist/esm/components/Collection/NestedCollection.js +308 -0
  39. package/dist/esm/components/Collection/Sidebar.js +91 -0
  40. package/dist/esm/components/Collection/SortControl.js +59 -0
  41. package/dist/esm/components/Collection/ViewStyleControl.js +38 -0
  42. package/dist/esm/components/Editor/Editor.js +466 -0
  43. package/dist/esm/components/Editor/EditorControlPane/EditorControl.js +395 -0
  44. package/dist/esm/components/Editor/EditorControlPane/EditorControlPane.js +254 -0
  45. package/dist/esm/components/Editor/EditorControlPane/Widget.js +374 -0
  46. package/dist/esm/components/Editor/EditorInterface.js +386 -0
  47. package/dist/esm/components/Editor/EditorPreviewPane/EditorPreview.js +47 -0
  48. package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewContent.js +66 -0
  49. package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewPane.js +288 -0
  50. package/dist/esm/components/Editor/EditorPreviewPane/PreviewHOC.js +27 -0
  51. package/dist/esm/components/Editor/EditorToolbar.js +536 -0
  52. package/dist/esm/components/Editor/EntryPathEditor.js +272 -0
  53. package/dist/esm/components/Editor/withWorkflow.js +56 -0
  54. package/dist/esm/components/EditorWidgets/Unknown/UnknownControl.js +18 -0
  55. package/dist/esm/components/EditorWidgets/Unknown/UnknownPreview.js +20 -0
  56. package/dist/esm/components/EditorWidgets/index.js +4 -0
  57. package/dist/esm/components/MediaLibrary/EmptyMessage.js +22 -0
  58. package/dist/esm/components/MediaLibrary/MediaLibrary.js +446 -0
  59. package/dist/esm/components/MediaLibrary/MediaLibraryButtons.js +93 -0
  60. package/dist/esm/components/MediaLibrary/MediaLibraryCard.js +99 -0
  61. package/dist/esm/components/MediaLibrary/MediaLibraryCardGrid.js +198 -0
  62. package/dist/esm/components/MediaLibrary/MediaLibraryHeader.js +32 -0
  63. package/dist/esm/components/MediaLibrary/MediaLibraryModal.js +156 -0
  64. package/dist/esm/components/MediaLibrary/MediaLibrarySearch.js +51 -0
  65. package/dist/esm/components/MediaLibrary/MediaLibraryTop.js +123 -0
  66. package/dist/esm/components/UI/DragDrop.js +67 -0
  67. package/dist/esm/components/UI/ErrorBoundary.js +173 -0
  68. package/dist/esm/components/UI/FileUploadButton.js +27 -0
  69. package/dist/esm/components/UI/Modal.js +104 -0
  70. package/dist/esm/components/UI/Notifications.js +62 -0
  71. package/dist/esm/components/UI/SettingsDropdown.js +107 -0
  72. package/dist/esm/components/UI/index.js +6 -0
  73. package/dist/esm/components/Workflow/Workflow.js +133 -0
  74. package/dist/esm/components/Workflow/WorkflowCard.js +128 -0
  75. package/dist/esm/components/Workflow/WorkflowList.js +204 -0
  76. package/dist/esm/constants/collectionTypes.js +2 -0
  77. package/dist/esm/constants/collectionViews.js +2 -0
  78. package/dist/esm/constants/commitProps.js +2 -0
  79. package/dist/esm/constants/configSchema.js +644 -0
  80. package/dist/esm/constants/fieldInference.js +57 -0
  81. package/dist/esm/constants/publishModes.js +18 -0
  82. package/dist/esm/constants/validationErrorTypes.js +6 -0
  83. package/dist/esm/formats/formats.js +83 -0
  84. package/dist/esm/formats/frontmatter.js +146 -0
  85. package/dist/esm/formats/helpers.js +12 -0
  86. package/dist/esm/formats/json.js +8 -0
  87. package/dist/esm/formats/toml.js +32 -0
  88. package/dist/esm/formats/yaml.js +51 -0
  89. package/dist/esm/index.js +7 -0
  90. package/dist/esm/integrations/index.js +28 -0
  91. package/dist/esm/integrations/providers/algolia/implementation.js +174 -0
  92. package/dist/esm/integrations/providers/assetStore/implementation.js +165 -0
  93. package/dist/esm/lib/consoleError.js +3 -0
  94. package/dist/esm/lib/formatters.js +191 -0
  95. package/dist/esm/lib/i18n.js +367 -0
  96. package/dist/esm/lib/phrases.js +6 -0
  97. package/dist/esm/lib/polyfill.js +8 -0
  98. package/dist/esm/lib/registry.js +329 -0
  99. package/dist/esm/lib/serializeEntryValues.js +67 -0
  100. package/dist/esm/lib/stega.js +142 -0
  101. package/dist/esm/lib/textHelper.js +9 -0
  102. package/dist/esm/lib/urlHelper.js +111 -0
  103. package/dist/esm/mediaLibrary.js +37 -0
  104. package/dist/esm/reducers/auth.js +27 -0
  105. package/dist/esm/reducers/collections.js +428 -0
  106. package/dist/esm/reducers/combinedReducer.js +8 -0
  107. package/dist/esm/reducers/config.js +29 -0
  108. package/dist/esm/reducers/cursors.js +31 -0
  109. package/dist/esm/reducers/deploys.js +45 -0
  110. package/dist/esm/reducers/editorialWorkflow.js +83 -0
  111. package/dist/esm/reducers/entries.js +568 -0
  112. package/dist/esm/reducers/entryDraft.js +212 -0
  113. package/dist/esm/reducers/globalUI.js +25 -0
  114. package/dist/esm/reducers/index.js +66 -0
  115. package/dist/esm/reducers/integrations.js +53 -0
  116. package/dist/esm/reducers/mediaLibrary.js +252 -0
  117. package/dist/esm/reducers/medias.js +68 -0
  118. package/dist/esm/reducers/notifications.js +23 -0
  119. package/dist/esm/reducers/search.js +92 -0
  120. package/dist/esm/reducers/status.js +30 -0
  121. package/dist/esm/redux/index.js +7 -0
  122. package/dist/esm/redux/middleware/waitUntilAction.js +48 -0
  123. package/dist/esm/routing/history.js +12 -0
  124. package/dist/esm/types/diacritics.d.js +0 -0
  125. package/dist/esm/types/global.d.js +1 -0
  126. package/dist/esm/types/immutable.js +7 -0
  127. package/dist/esm/types/redux.js +14 -0
  128. package/dist/esm/types/tomlify-j0.4.d.js +0 -0
  129. package/dist/esm/valueObjects/AssetProxy.js +44 -0
  130. package/dist/esm/valueObjects/EditorComponent.js +34 -0
  131. package/dist/esm/valueObjects/Entry.js +20 -0
  132. package/index.d.ts +618 -0
  133. package/package.json +106 -0
  134. package/src/__tests__/backend.spec.js +1161 -0
  135. package/src/actions/__tests__/config.spec.js +1009 -0
  136. package/src/actions/__tests__/editorialWorkflow.spec.js +216 -0
  137. package/src/actions/__tests__/entries.spec.js +596 -0
  138. package/src/actions/__tests__/media.spec.ts +171 -0
  139. package/src/actions/__tests__/mediaLibrary.spec.js +327 -0
  140. package/src/actions/__tests__/search.spec.js +209 -0
  141. package/src/actions/auth.ts +127 -0
  142. package/src/actions/collections.ts +18 -0
  143. package/src/actions/config.ts +565 -0
  144. package/src/actions/deploys.ts +104 -0
  145. package/src/actions/editorialWorkflow.ts +567 -0
  146. package/src/actions/entries.ts +1055 -0
  147. package/src/actions/media.ts +139 -0
  148. package/src/actions/mediaLibrary.ts +574 -0
  149. package/src/actions/notifications.ts +36 -0
  150. package/src/actions/search.ts +221 -0
  151. package/src/actions/status.ts +99 -0
  152. package/src/actions/waitUntil.ts +49 -0
  153. package/src/backend.ts +1400 -0
  154. package/src/bootstrap.js +104 -0
  155. package/src/components/App/App.js +286 -0
  156. package/src/components/App/Header.js +266 -0
  157. package/src/components/App/NotFoundPage.js +23 -0
  158. package/src/components/Collection/Collection.js +210 -0
  159. package/src/components/Collection/CollectionControls.js +58 -0
  160. package/src/components/Collection/CollectionSearch.js +243 -0
  161. package/src/components/Collection/CollectionTop.js +81 -0
  162. package/src/components/Collection/ControlButton.js +27 -0
  163. package/src/components/Collection/Entries/Entries.js +82 -0
  164. package/src/components/Collection/Entries/EntriesCollection.js +277 -0
  165. package/src/components/Collection/Entries/EntriesSearch.js +102 -0
  166. package/src/components/Collection/Entries/EntryCard.js +246 -0
  167. package/src/components/Collection/Entries/EntryListing.js +151 -0
  168. package/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js +163 -0
  169. package/src/components/Collection/Entries/__tests__/__snapshots__/EntriesCollection.spec.js.snap +46 -0
  170. package/src/components/Collection/FilterControl.js +39 -0
  171. package/src/components/Collection/GroupControl.js +39 -0
  172. package/src/components/Collection/NestedCollection.js +330 -0
  173. package/src/components/Collection/Sidebar.js +136 -0
  174. package/src/components/Collection/SortControl.js +68 -0
  175. package/src/components/Collection/ViewStyleControl.js +50 -0
  176. package/src/components/Collection/__tests__/Collection.spec.js +75 -0
  177. package/src/components/Collection/__tests__/NestedCollection.spec.js +445 -0
  178. package/src/components/Collection/__tests__/Sidebar.spec.js +87 -0
  179. package/src/components/Collection/__tests__/__snapshots__/Collection.spec.js.snap +144 -0
  180. package/src/components/Collection/__tests__/__snapshots__/NestedCollection.spec.js.snap +550 -0
  181. package/src/components/Collection/__tests__/__snapshots__/Sidebar.spec.js.snap +312 -0
  182. package/src/components/Editor/Editor.js +497 -0
  183. package/src/components/Editor/EditorControlPane/EditorControl.js +452 -0
  184. package/src/components/Editor/EditorControlPane/EditorControlPane.js +269 -0
  185. package/src/components/Editor/EditorControlPane/Widget.js +384 -0
  186. package/src/components/Editor/EditorInterface.js +444 -0
  187. package/src/components/Editor/EditorPreviewPane/EditorPreview.js +40 -0
  188. package/src/components/Editor/EditorPreviewPane/EditorPreviewContent.js +74 -0
  189. package/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js +333 -0
  190. package/src/components/Editor/EditorPreviewPane/PreviewHOC.js +33 -0
  191. package/src/components/Editor/EditorToolbar.js +691 -0
  192. package/src/components/Editor/__tests__/Editor.spec.js +221 -0
  193. package/src/components/Editor/__tests__/EditorToolbar.spec.js +120 -0
  194. package/src/components/Editor/__tests__/__snapshots__/Editor.spec.js.snap +45 -0
  195. package/src/components/Editor/__tests__/__snapshots__/EditorToolbar.spec.js.snap +4233 -0
  196. package/src/components/Editor/withWorkflow.js +61 -0
  197. package/src/components/EditorWidgets/Unknown/UnknownControl.js +17 -0
  198. package/src/components/EditorWidgets/Unknown/UnknownPreview.js +19 -0
  199. package/src/components/EditorWidgets/index.js +5 -0
  200. package/src/components/MediaLibrary/EmptyMessage.js +28 -0
  201. package/src/components/MediaLibrary/MediaLibrary.js +411 -0
  202. package/src/components/MediaLibrary/MediaLibraryButtons.js +136 -0
  203. package/src/components/MediaLibrary/MediaLibraryCard.js +128 -0
  204. package/src/components/MediaLibrary/MediaLibraryCardGrid.js +199 -0
  205. package/src/components/MediaLibrary/MediaLibraryHeader.js +48 -0
  206. package/src/components/MediaLibrary/MediaLibraryModal.js +200 -0
  207. package/src/components/MediaLibrary/MediaLibrarySearch.js +61 -0
  208. package/src/components/MediaLibrary/MediaLibraryTop.js +143 -0
  209. package/src/components/MediaLibrary/__tests__/MediaLibraryButtons.spec.js +45 -0
  210. package/src/components/MediaLibrary/__tests__/MediaLibraryCard.spec.js +49 -0
  211. package/src/components/MediaLibrary/__tests__/__snapshots__/MediaLibraryCard.spec.js.snap +264 -0
  212. package/src/components/UI/DragDrop.js +66 -0
  213. package/src/components/UI/ErrorBoundary.js +214 -0
  214. package/src/components/UI/FileUploadButton.js +24 -0
  215. package/src/components/UI/Modal.js +112 -0
  216. package/src/components/UI/Notifications.tsx +83 -0
  217. package/src/components/UI/SettingsDropdown.js +103 -0
  218. package/src/components/UI/__tests__/ErrorBoundary.spec.js +57 -0
  219. package/src/components/UI/index.js +6 -0
  220. package/src/components/Workflow/Workflow.js +169 -0
  221. package/src/components/Workflow/WorkflowCard.js +177 -0
  222. package/src/components/Workflow/WorkflowList.js +272 -0
  223. package/src/constants/__tests__/configSchema.spec.js +611 -0
  224. package/src/constants/collectionTypes.ts +2 -0
  225. package/src/constants/collectionViews.js +2 -0
  226. package/src/constants/commitProps.ts +2 -0
  227. package/src/constants/configSchema.js +441 -0
  228. package/src/constants/fieldInference.tsx +78 -0
  229. package/src/constants/publishModes.ts +22 -0
  230. package/src/constants/validationErrorTypes.js +6 -0
  231. package/src/formats/__tests__/formats.spec.js +87 -0
  232. package/src/formats/__tests__/frontmatter.spec.js +429 -0
  233. package/src/formats/__tests__/toml.spec.js +9 -0
  234. package/src/formats/__tests__/yaml.spec.js +162 -0
  235. package/src/formats/formats.ts +97 -0
  236. package/src/formats/frontmatter.ts +150 -0
  237. package/src/formats/helpers.ts +14 -0
  238. package/src/formats/json.ts +9 -0
  239. package/src/formats/toml.ts +33 -0
  240. package/src/formats/yaml.ts +58 -0
  241. package/src/index.js +8 -0
  242. package/src/integrations/index.js +35 -0
  243. package/src/integrations/providers/algolia/implementation.js +176 -0
  244. package/src/integrations/providers/assetStore/implementation.js +148 -0
  245. package/src/lib/__tests__/formatters.spec.js +751 -0
  246. package/src/lib/__tests__/i18n.spec.js +792 -0
  247. package/src/lib/__tests__/phrases.spec.js +119 -0
  248. package/src/lib/__tests__/registry.spec.js +261 -0
  249. package/src/lib/__tests__/serializeEntryValues.spec.js +22 -0
  250. package/src/lib/__tests__/urlHelper.spec.js +138 -0
  251. package/src/lib/consoleError.js +7 -0
  252. package/src/lib/formatters.ts +286 -0
  253. package/src/lib/i18n.ts +454 -0
  254. package/src/lib/phrases.js +8 -0
  255. package/src/lib/polyfill.js +9 -0
  256. package/src/lib/registry.js +312 -0
  257. package/src/lib/serializeEntryValues.js +75 -0
  258. package/src/lib/stega.ts +145 -0
  259. package/src/lib/textHelper.js +11 -0
  260. package/src/lib/urlHelper.ts +128 -0
  261. package/src/mediaLibrary.ts +51 -0
  262. package/src/reducers/__tests__/auth.spec.ts +38 -0
  263. package/src/reducers/__tests__/collections.spec.js +610 -0
  264. package/src/reducers/__tests__/config.spec.js +38 -0
  265. package/src/reducers/__tests__/entries.spec.js +694 -0
  266. package/src/reducers/__tests__/entryDraft.spec.js +297 -0
  267. package/src/reducers/__tests__/globalUI.js +43 -0
  268. package/src/reducers/__tests__/integrations.spec.ts +76 -0
  269. package/src/reducers/__tests__/mediaLibrary.spec.js +154 -0
  270. package/src/reducers/__tests__/medias.spec.ts +49 -0
  271. package/src/reducers/auth.ts +46 -0
  272. package/src/reducers/collections.ts +535 -0
  273. package/src/reducers/combinedReducer.ts +11 -0
  274. package/src/reducers/config.ts +38 -0
  275. package/src/reducers/cursors.js +36 -0
  276. package/src/reducers/deploys.ts +52 -0
  277. package/src/reducers/editorialWorkflow.ts +163 -0
  278. package/src/reducers/entries.ts +819 -0
  279. package/src/reducers/entryDraft.js +260 -0
  280. package/src/reducers/globalUI.ts +45 -0
  281. package/src/reducers/index.ts +82 -0
  282. package/src/reducers/integrations.ts +59 -0
  283. package/src/reducers/mediaLibrary.ts +296 -0
  284. package/src/reducers/medias.ts +66 -0
  285. package/src/reducers/notifications.ts +52 -0
  286. package/src/reducers/search.ts +111 -0
  287. package/src/reducers/status.ts +40 -0
  288. package/src/redux/index.ts +18 -0
  289. package/src/redux/middleware/waitUntilAction.ts +64 -0
  290. package/src/routing/__tests__/history.spec.ts +49 -0
  291. package/src/routing/history.ts +17 -0
  292. package/src/types/diacritics.d.ts +1 -0
  293. package/src/types/global.d.ts +8 -0
  294. package/src/types/immutable.ts +49 -0
  295. package/src/types/redux.ts +827 -0
  296. package/src/types/tomlify-j0.4.d.ts +13 -0
  297. package/src/valueObjects/AssetProxy.ts +48 -0
  298. package/src/valueObjects/EditorComponent.js +38 -0
  299. package/src/valueObjects/Entry.ts +63 -0
@@ -0,0 +1,428 @@
1
+ import { List, Set, fromJS, OrderedMap } from 'immutable';
2
+ import get from 'lodash/get';
3
+ import escapeRegExp from 'lodash/escapeRegExp';
4
+ import { stringTemplate } from 'decap-cms-lib-widgets';
5
+ import consoleError from '../lib/consoleError';
6
+ import { CONFIG_SUCCESS } from '../actions/config';
7
+ import { FILES, FOLDER } from '../constants/collectionTypes';
8
+ import { COMMIT_DATE, COMMIT_AUTHOR } from '../constants/commitProps';
9
+ import { INFERABLE_FIELDS, IDENTIFIER_FIELDS, SORTABLE_FIELDS } from '../constants/fieldInference';
10
+ import { getFormatExtensions } from '../formats/formats';
11
+ import { selectMediaFolder } from './entries';
12
+ import { summaryFormatter } from '../lib/formatters';
13
+ const {
14
+ keyToPathArray
15
+ } = stringTemplate;
16
+ const defaultState = fromJS({});
17
+ function collections(state = defaultState, action) {
18
+ switch (action.type) {
19
+ case CONFIG_SUCCESS:
20
+ {
21
+ const collections = action.payload.collections;
22
+ let newState = OrderedMap({});
23
+ collections.forEach(collection => {
24
+ newState = newState.set(collection.name, fromJS(collection));
25
+ });
26
+ return newState;
27
+ }
28
+ default:
29
+ return state;
30
+ }
31
+ }
32
+ const selectors = {
33
+ [FOLDER]: {
34
+ entryExtension(collection) {
35
+ const ext = collection.get('extension') || get(getFormatExtensions(), collection.get('format') || 'frontmatter');
36
+ if (!ext) {
37
+ throw new Error(`No extension found for format ${collection.get('format')}`);
38
+ }
39
+ return ext.replace(/^\./, '');
40
+ },
41
+ fields(collection) {
42
+ return collection.get('fields');
43
+ },
44
+ entryPath(collection, slug) {
45
+ const folder = collection.get('folder').replace(/\/$/, '');
46
+ return `${folder}/${slug}.${this.entryExtension(collection)}`;
47
+ },
48
+ entrySlug(collection, path) {
49
+ const folder = collection.get('folder').replace(/\/$/, '');
50
+ const slug = path.split(folder + '/').pop()?.replace(new RegExp(`\\.${escapeRegExp(this.entryExtension(collection))}$`), '');
51
+ return slug;
52
+ },
53
+ allowNewEntries(collection) {
54
+ return collection.get('create');
55
+ },
56
+ allowDeletion(collection) {
57
+ return collection.get('delete', true);
58
+ },
59
+ templateName(collection) {
60
+ return collection.get('name');
61
+ }
62
+ },
63
+ [FILES]: {
64
+ fileForEntry(collection, slug) {
65
+ const files = collection.get('files');
66
+ return files && files.filter(f => f?.get('name') === slug).get(0);
67
+ },
68
+ fields(collection, slug) {
69
+ const file = this.fileForEntry(collection, slug);
70
+ return file && file.get('fields');
71
+ },
72
+ entryPath(collection, slug) {
73
+ const file = this.fileForEntry(collection, slug);
74
+ return file && file.get('file');
75
+ },
76
+ entrySlug(collection, path) {
77
+ const file = collection.get('files').filter(f => f?.get('file') === path).get(0);
78
+ return file && file.get('name');
79
+ },
80
+ entryLabel(collection, slug) {
81
+ const file = this.fileForEntry(collection, slug);
82
+ return file && file.get('label');
83
+ },
84
+ allowNewEntries() {
85
+ return false;
86
+ },
87
+ allowDeletion(collection) {
88
+ return collection.get('delete', false);
89
+ },
90
+ templateName(_collection, slug) {
91
+ return slug;
92
+ }
93
+ }
94
+ };
95
+ function getFieldsWithMediaFolders(fields) {
96
+ const fieldsWithMediaFolders = fields.reduce((acc, f) => {
97
+ if (f.has('media_folder')) {
98
+ acc = [...acc, f];
99
+ }
100
+ if (f.has('fields')) {
101
+ const fields = f.get('fields')?.toArray();
102
+ acc = [...acc, ...getFieldsWithMediaFolders(fields)];
103
+ } else if (f.has('field')) {
104
+ const field = f.get('field');
105
+ acc = [...acc, ...getFieldsWithMediaFolders([field])];
106
+ } else if (f.has('types')) {
107
+ const types = f.get('types')?.toArray();
108
+ acc = [...acc, ...getFieldsWithMediaFolders(types)];
109
+ }
110
+ return acc;
111
+ }, []);
112
+ return fieldsWithMediaFolders;
113
+ }
114
+ export function getFileFromSlug(collection, slug) {
115
+ return collection.get('files')?.toArray().find(f => f.get('name') === slug);
116
+ }
117
+ export function selectFieldsWithMediaFolders(collection, slug) {
118
+ if (collection.has('folder')) {
119
+ const fields = collection.get('fields').toArray();
120
+ return getFieldsWithMediaFolders(fields);
121
+ } else if (collection.has('files')) {
122
+ const fields = getFileFromSlug(collection, slug)?.get('fields').toArray() || [];
123
+ return getFieldsWithMediaFolders(fields);
124
+ }
125
+ return [];
126
+ }
127
+ export function selectMediaFolders(config, collection, entry) {
128
+ const fields = selectFieldsWithMediaFolders(collection, entry.get('slug'));
129
+ const folders = fields.map(f => selectMediaFolder(config, collection, entry, f));
130
+ if (collection.has('files')) {
131
+ const file = getFileFromSlug(collection, entry.get('slug'));
132
+ if (file) {
133
+ folders.unshift(selectMediaFolder(config, collection, entry, undefined));
134
+ }
135
+ }
136
+ if (collection.has('media_folder')) {
137
+ // stop evaluating media folders at collection level
138
+ collection = collection.delete('files');
139
+ folders.unshift(selectMediaFolder(config, collection, entry, undefined));
140
+ }
141
+ return Set(folders).toArray();
142
+ }
143
+ export function selectFields(collection, slug) {
144
+ return selectors[collection.get('type')].fields(collection, slug);
145
+ }
146
+ export function selectFolderEntryExtension(collection) {
147
+ return selectors[FOLDER].entryExtension(collection);
148
+ }
149
+ export function selectFileEntryLabel(collection, slug) {
150
+ return selectors[FILES].entryLabel(collection, slug);
151
+ }
152
+ export function selectEntryPath(collection, slug) {
153
+ return selectors[collection.get('type')].entryPath(collection, slug);
154
+ }
155
+ export function selectEntrySlug(collection, path) {
156
+ return selectors[collection.get('type')].entrySlug(collection, path);
157
+ }
158
+ export function selectAllowNewEntries(collection) {
159
+ return selectors[collection.get('type')].allowNewEntries(collection);
160
+ }
161
+ export function selectAllowDeletion(collection) {
162
+ return selectors[collection.get('type')].allowDeletion(collection);
163
+ }
164
+ export function selectTemplateName(collection, slug) {
165
+ return selectors[collection.get('type')].templateName(collection, slug);
166
+ }
167
+ export function getFieldsNames(fields, prefix = '') {
168
+ let names = fields.map(f => `${prefix}${f.get('name')}`);
169
+ fields.forEach((f, index) => {
170
+ if (f.has('fields')) {
171
+ const fields = f.get('fields')?.toArray();
172
+ names = [...names, ...getFieldsNames(fields, `${names[index]}.`)];
173
+ } else if (f.has('field')) {
174
+ const field = f.get('field');
175
+ names = [...names, ...getFieldsNames([field], `${names[index]}.`)];
176
+ } else if (f.has('types')) {
177
+ const types = f.get('types')?.toArray();
178
+ names = [...names, ...getFieldsNames(types, `${names[index]}.`)];
179
+ }
180
+ });
181
+ return names;
182
+ }
183
+ export function selectField(collection, key) {
184
+ const array = keyToPathArray(key);
185
+ let name;
186
+ let field;
187
+ let fields = collection.get('fields', List()).toArray();
188
+ while ((name = array.shift()) && fields) {
189
+ field = fields.find(f => f.get('name') === name);
190
+ if (field?.has('fields')) {
191
+ fields = field?.get('fields')?.toArray();
192
+ } else if (field?.has('field')) {
193
+ fields = [field?.get('field')];
194
+ } else if (field?.has('types')) {
195
+ fields = field?.get('types')?.toArray();
196
+ }
197
+ }
198
+ return field;
199
+ }
200
+ export function traverseFields(fields, updater, done = () => false) {
201
+ if (done()) {
202
+ return fields;
203
+ }
204
+ fields = fields.map(f => {
205
+ const field = updater(f);
206
+ if (done()) {
207
+ return field;
208
+ } else if (field.has('fields')) {
209
+ return field.set('fields', traverseFields(field.get('fields'), updater, done));
210
+ } else if (field.has('field')) {
211
+ return field.set('field', traverseFields(List([field.get('field')]), updater, done).get(0));
212
+ } else if (field.has('types')) {
213
+ return field.set('types', traverseFields(field.get('types'), updater, done));
214
+ } else {
215
+ return field;
216
+ }
217
+ }).toList();
218
+ return fields;
219
+ }
220
+ export function updateFieldByKey(collection, key, updater) {
221
+ const selected = selectField(collection, key);
222
+ if (!selected) {
223
+ return collection;
224
+ }
225
+ let updated = false;
226
+ function updateAndBreak(f) {
227
+ const field = f;
228
+ if (field === selected) {
229
+ updated = true;
230
+ return updater(field);
231
+ } else {
232
+ return field;
233
+ }
234
+ }
235
+ collection = collection.set('fields', traverseFields(collection.get('fields', List()), updateAndBreak, () => updated));
236
+ return collection;
237
+ }
238
+ export function selectIdentifier(collection) {
239
+ const identifier = collection.get('identifier_field');
240
+ const identifierFields = identifier ? [identifier, ...IDENTIFIER_FIELDS] : [...IDENTIFIER_FIELDS];
241
+ const fieldNames = getFieldsNames(collection.get('fields', List()).toArray());
242
+ return identifierFields.find(id => fieldNames.find(name => name.toLowerCase().trim() === id.toLowerCase().trim()));
243
+ }
244
+ export function selectInferredField(collection, fieldName) {
245
+ if (fieldName === 'title' && collection.get('identifier_field')) {
246
+ return selectIdentifier(collection);
247
+ }
248
+ const inferableField = INFERABLE_FIELDS[fieldName];
249
+ const fields = collection.get('fields');
250
+ let field;
251
+
252
+ // If collection has no fields or fieldName is not defined within inferables list, return null
253
+ if (!fields || !inferableField) return null;
254
+ // Try to return a field of the specified type with one of the synonyms
255
+ const mainTypeFields = fields.filter(f => f?.get('widget', 'string') === inferableField.type).map(f => f?.get('name'));
256
+ field = mainTypeFields.filter(f => inferableField.synonyms.indexOf(f) !== -1);
257
+ if (field && field.size > 0) return field.first();
258
+
259
+ // Try to return a field for each of the specified secondary types
260
+ const secondaryTypeFields = fields.filter(f => inferableField.secondaryTypes.indexOf(f?.get('widget', 'string')) !== -1).map(f => f?.get('name'));
261
+ field = secondaryTypeFields.filter(f => inferableField.synonyms.indexOf(f) !== -1);
262
+ if (field && field.size > 0) return field.first();
263
+
264
+ // Try to return the first field of the specified type
265
+ if (inferableField.fallbackToFirstField && mainTypeFields.size > 0) return mainTypeFields.first();
266
+
267
+ // Coundn't infer the field. Show error and return null.
268
+ if (inferableField.showError) {
269
+ consoleError(`The Field ${fieldName} is missing for the collection “${collection.get('name')}”`, `Decap CMS tries to infer the entry ${fieldName} automatically, but one couldn't be found for entries of the collection “${collection.get('name')}”. Please check your site configuration.`);
270
+ }
271
+ return null;
272
+ }
273
+ export function selectEntryCollectionTitle(collection, entry) {
274
+ // prefer formatted summary over everything else
275
+ const summaryTemplate = collection.get('summary');
276
+ if (summaryTemplate) return summaryFormatter(summaryTemplate, entry, collection);
277
+
278
+ // if the collection is a file collection return the label of the entry
279
+ if (collection.get('type') == FILES) {
280
+ const label = selectFileEntryLabel(collection, entry.get('slug'));
281
+ if (label) return label;
282
+ }
283
+
284
+ // try to infer a title field from the entry data
285
+ const entryData = entry.get('data');
286
+ const titleField = selectInferredField(collection, 'title');
287
+ const result = titleField && entryData.getIn(keyToPathArray(titleField));
288
+
289
+ // if the custom field does not yield a result, fallback to 'title'
290
+ if (!result && titleField !== 'title') {
291
+ return entryData.getIn(keyToPathArray('title'));
292
+ }
293
+ return result;
294
+ }
295
+ export function selectDefaultSortableFields(collection, backend, hasIntegration) {
296
+ let defaultSortable = SORTABLE_FIELDS.map(type => {
297
+ const field = selectInferredField(collection, type);
298
+ if (backend.isGitBackend() && type === 'author' && !field && !hasIntegration) {
299
+ // default to commit author if not author field is found
300
+ return COMMIT_AUTHOR;
301
+ }
302
+ return field;
303
+ }).filter(Boolean);
304
+ if (backend.isGitBackend() && !hasIntegration) {
305
+ // always have commit date by default
306
+ defaultSortable = [COMMIT_DATE, ...defaultSortable];
307
+ }
308
+
309
+ // Return as objects with field property
310
+ return defaultSortable.map(field => ({
311
+ field
312
+ }));
313
+ }
314
+ export function selectSortableFields(collection, t) {
315
+ const fields = collection.get('sortable_fields').toArray().map(sortableField => {
316
+ // Extract the field name and custom label from the sortable field object
317
+ const key = sortableField.get('field');
318
+ const customLabel = sortableField.get('label');
319
+ if (key === COMMIT_DATE) {
320
+ const label = customLabel || t('collection.defaultFields.updatedOn.label');
321
+ return {
322
+ key,
323
+ field: {
324
+ name: key,
325
+ label
326
+ }
327
+ };
328
+ }
329
+ const field = selectField(collection, key);
330
+ if (key === COMMIT_AUTHOR && !field) {
331
+ const label = customLabel || t('collection.defaultFields.author.label');
332
+ return {
333
+ key,
334
+ field: {
335
+ name: key,
336
+ label
337
+ }
338
+ };
339
+ }
340
+ let fieldObj = field?.toJS();
341
+
342
+ // If custom label is provided, override the field's label
343
+ if (fieldObj && customLabel) {
344
+ fieldObj = {
345
+ ...fieldObj,
346
+ label: customLabel
347
+ };
348
+ }
349
+
350
+ // If no label exists at all, use the field name
351
+ if (fieldObj && !fieldObj.label) {
352
+ fieldObj = {
353
+ ...fieldObj,
354
+ label: fieldObj.name || key
355
+ };
356
+ }
357
+ return {
358
+ key,
359
+ field: fieldObj
360
+ };
361
+ }).filter(item => !!item.field).map(item => ({
362
+ ...item.field,
363
+ key: item.key
364
+ }));
365
+ return fields;
366
+ }
367
+ export function selectDefaultSortField(collection) {
368
+ const sortableFields = collection.get('sortable_fields').toArray();
369
+ const defaultField = sortableFields.find(field => field.get('default_sort') !== undefined);
370
+ if (!defaultField) {
371
+ return null;
372
+ }
373
+ const fieldName = defaultField.get('field');
374
+ const defaultSortValue = defaultField.get('default_sort');
375
+
376
+ // Determine direction based on default_sort value
377
+ let direction;
378
+ if (defaultSortValue === true || defaultSortValue === 'asc') {
379
+ direction = 'asc';
380
+ } else if (defaultSortValue === 'desc') {
381
+ direction = 'desc';
382
+ } else {
383
+ direction = 'asc'; // fallback
384
+ }
385
+ return {
386
+ field: fieldName,
387
+ direction
388
+ };
389
+ }
390
+ export function selectSortDataPath(collection, key) {
391
+ if (key === COMMIT_DATE) {
392
+ return 'updatedOn';
393
+ } else if (key === COMMIT_AUTHOR && !selectField(collection, key)) {
394
+ return 'author';
395
+ } else {
396
+ return `data.${key}`;
397
+ }
398
+ }
399
+ export function selectViewFilters(collection) {
400
+ const viewFilters = collection.get('view_filters').toJS();
401
+ return viewFilters;
402
+ }
403
+ export function selectViewGroups(collection) {
404
+ const viewGroups = collection.get('view_groups').toJS();
405
+ return viewGroups;
406
+ }
407
+ export function selectFieldsComments(collection, entryMap) {
408
+ let fields = [];
409
+ if (collection.has('folder')) {
410
+ fields = collection.get('fields').toArray();
411
+ } else if (collection.has('files')) {
412
+ const file = collection.get('files').find(f => f?.get('name') === entryMap.get('slug'));
413
+ fields = file.get('fields').toArray();
414
+ }
415
+ const comments = {};
416
+ const names = getFieldsNames(fields);
417
+ names.forEach(name => {
418
+ const field = selectField(collection, name);
419
+ if (field?.has('comment')) {
420
+ comments[name] = field.get('comment');
421
+ }
422
+ });
423
+ return comments;
424
+ }
425
+ export function selectHasMetaPath(collection) {
426
+ return collection.has('folder') && collection.get('type') === FOLDER && collection.has('meta') && collection.get('meta')?.has('path');
427
+ }
428
+ export default collections;
@@ -0,0 +1,8 @@
1
+ import { combineReducers } from 'redux';
2
+ import reducers from './index';
3
+ function createRootReducer() {
4
+ return combineReducers({
5
+ ...reducers
6
+ });
7
+ }
8
+ export default createRootReducer;
@@ -0,0 +1,29 @@
1
+ import { produce } from 'immer';
2
+ import { CONFIG_REQUEST, CONFIG_SUCCESS, CONFIG_FAILURE } from '../actions/config';
3
+ import { EDITORIAL_WORKFLOW } from '../constants/publishModes';
4
+ const defaultState = {
5
+ isFetching: true
6
+ };
7
+ const config = produce((state, action) => {
8
+ switch (action.type) {
9
+ case CONFIG_REQUEST:
10
+ state.isFetching = true;
11
+ break;
12
+ case CONFIG_SUCCESS:
13
+ return {
14
+ ...action.payload,
15
+ isFetching: false,
16
+ error: undefined
17
+ };
18
+ case CONFIG_FAILURE:
19
+ state.isFetching = false;
20
+ state.error = action.payload.toString();
21
+ }
22
+ }, defaultState);
23
+ export function selectLocale(state) {
24
+ return state.locale || 'en';
25
+ }
26
+ export function selectUseWorkflow(state) {
27
+ return state.publish_mode === EDITORIAL_WORKFLOW;
28
+ }
29
+ export default config;
@@ -0,0 +1,31 @@
1
+ import { fromJS } from 'immutable';
2
+ import { Cursor } from 'decap-cms-lib-util';
3
+ import { ENTRIES_SUCCESS, SORT_ENTRIES_SUCCESS, FILTER_ENTRIES_SUCCESS, GROUP_ENTRIES_SUCCESS } from '../actions/entries';
4
+
5
+ // Since pagination can be used for a variety of views (collections
6
+ // and searches are the most common examples), we namespace cursors by
7
+ // their type before storing them in the state.
8
+ export function selectCollectionEntriesCursor(state, collectionName) {
9
+ return new Cursor(state.getIn(['cursorsByType', 'collectionEntries', collectionName]));
10
+ }
11
+ function cursors(state = fromJS({
12
+ cursorsByType: {
13
+ collectionEntries: {}
14
+ }
15
+ }), action) {
16
+ switch (action.type) {
17
+ case ENTRIES_SUCCESS:
18
+ {
19
+ return state.setIn(['cursorsByType', 'collectionEntries', action.payload.collection], Cursor.create(action.payload.cursor).store);
20
+ }
21
+ case FILTER_ENTRIES_SUCCESS:
22
+ case GROUP_ENTRIES_SUCCESS:
23
+ case SORT_ENTRIES_SUCCESS:
24
+ {
25
+ return state.deleteIn(['cursorsByType', 'collectionEntries', action.payload.collection]);
26
+ }
27
+ default:
28
+ return state;
29
+ }
30
+ }
31
+ export default cursors;
@@ -0,0 +1,45 @@
1
+ import { produce } from 'immer';
2
+ import { DEPLOY_PREVIEW_REQUEST, DEPLOY_PREVIEW_SUCCESS, DEPLOY_PREVIEW_FAILURE } from '../actions/deploys';
3
+ const defaultState = {};
4
+ const deploys = produce((state, action) => {
5
+ switch (action.type) {
6
+ case DEPLOY_PREVIEW_REQUEST:
7
+ {
8
+ const {
9
+ collection,
10
+ slug
11
+ } = action.payload;
12
+ const key = `${collection}.${slug}`;
13
+ state[key] = state[key] || {};
14
+ state[key].isFetching = true;
15
+ break;
16
+ }
17
+ case DEPLOY_PREVIEW_SUCCESS:
18
+ {
19
+ const {
20
+ collection,
21
+ slug,
22
+ url,
23
+ status
24
+ } = action.payload;
25
+ const key = `${collection}.${slug}`;
26
+ state[key].isFetching = false;
27
+ state[key].url = url;
28
+ state[key].status = status;
29
+ break;
30
+ }
31
+ case DEPLOY_PREVIEW_FAILURE:
32
+ {
33
+ const {
34
+ collection,
35
+ slug
36
+ } = action.payload;
37
+ state[`${collection}.${slug}`].isFetching = false;
38
+ break;
39
+ }
40
+ }
41
+ }, defaultState);
42
+ export function selectDeployPreview(state, collection, slug) {
43
+ return state[`${collection}.${slug}`];
44
+ }
45
+ export default deploys;
@@ -0,0 +1,83 @@
1
+ import { Map, List, fromJS } from 'immutable';
2
+ import startsWith from 'lodash/startsWith';
3
+ import { EDITORIAL_WORKFLOW } from '../constants/publishModes';
4
+ import { UNPUBLISHED_ENTRY_REQUEST, UNPUBLISHED_ENTRY_REDIRECT, UNPUBLISHED_ENTRY_SUCCESS, UNPUBLISHED_ENTRIES_REQUEST, UNPUBLISHED_ENTRIES_SUCCESS, UNPUBLISHED_ENTRY_PERSIST_REQUEST, UNPUBLISHED_ENTRY_PERSIST_SUCCESS, UNPUBLISHED_ENTRY_PERSIST_FAILURE, UNPUBLISHED_ENTRY_STATUS_CHANGE_REQUEST, UNPUBLISHED_ENTRY_STATUS_CHANGE_SUCCESS, UNPUBLISHED_ENTRY_STATUS_CHANGE_FAILURE, UNPUBLISHED_ENTRY_PUBLISH_REQUEST, UNPUBLISHED_ENTRY_PUBLISH_SUCCESS, UNPUBLISHED_ENTRY_PUBLISH_FAILURE, UNPUBLISHED_ENTRY_DELETE_SUCCESS } from '../actions/editorialWorkflow';
5
+ import { CONFIG_SUCCESS } from '../actions/config';
6
+ function unpublishedEntries(state = Map(), action) {
7
+ switch (action.type) {
8
+ case CONFIG_SUCCESS:
9
+ {
10
+ const publishMode = action.payload && action.payload.publish_mode;
11
+ if (publishMode === EDITORIAL_WORKFLOW) {
12
+ // Editorial workflow state is explicitly initiated after the config.
13
+ return Map({
14
+ entities: Map(),
15
+ pages: Map()
16
+ });
17
+ }
18
+ return state;
19
+ }
20
+ case UNPUBLISHED_ENTRY_REQUEST:
21
+ return state.setIn(['entities', `${action.payload.collection}.${action.payload.slug}`, 'isFetching'], true);
22
+ case UNPUBLISHED_ENTRY_REDIRECT:
23
+ return state.deleteIn(['entities', `${action.payload.collection}.${action.payload.slug}`]);
24
+ case UNPUBLISHED_ENTRY_SUCCESS:
25
+ return state.setIn(['entities', `${action.payload.collection}.${action.payload.entry.slug}`], fromJS(action.payload.entry));
26
+ case UNPUBLISHED_ENTRIES_REQUEST:
27
+ return state.setIn(['pages', 'isFetching'], true);
28
+ case UNPUBLISHED_ENTRIES_SUCCESS:
29
+ return state.withMutations(map => {
30
+ action.payload.entries.forEach(entry => map.setIn(['entities', `${entry.collection}.${entry.slug}`], fromJS(entry).set('isFetching', false)));
31
+ map.set('pages', Map({
32
+ ...action.payload.pages,
33
+ ids: List(action.payload.entries.map(entry => entry.slug))
34
+ }));
35
+ });
36
+ case UNPUBLISHED_ENTRY_PERSIST_REQUEST:
37
+ {
38
+ return state.setIn(['entities', `${action.payload.collection}.${action.payload.slug}`, 'isPersisting'], true);
39
+ }
40
+ case UNPUBLISHED_ENTRY_PERSIST_SUCCESS:
41
+ // Update Optimistically
42
+ return state.withMutations(map => {
43
+ map.setIn(['entities', `${action.payload.collection}.${action.payload.entry.get('slug')}`], fromJS(action.payload.entry));
44
+ map.deleteIn(['entities', `${action.payload.collection}.${action.payload.entry.get('slug')}`, 'isPersisting']);
45
+ map.updateIn(['pages', 'ids'], List(), list => list.push(action.payload.entry.get('slug')));
46
+ });
47
+ case UNPUBLISHED_ENTRY_PERSIST_FAILURE:
48
+ return state.setIn(['entities', `${action.payload.collection}.${action.payload.slug}`, 'isPersisting'], false);
49
+ case UNPUBLISHED_ENTRY_STATUS_CHANGE_REQUEST:
50
+ // Update Optimistically
51
+ return state.setIn(['entities', `${action.payload.collection}.${action.payload.slug}`, 'isUpdatingStatus'], true);
52
+ case UNPUBLISHED_ENTRY_STATUS_CHANGE_SUCCESS:
53
+ return state.withMutations(map => {
54
+ map.setIn(['entities', `${action.payload.collection}.${action.payload.slug}`, 'status'], action.payload.newStatus);
55
+ map.setIn(['entities', `${action.payload.collection}.${action.payload.slug}`, 'isUpdatingStatus'], false);
56
+ });
57
+ case UNPUBLISHED_ENTRY_STATUS_CHANGE_FAILURE:
58
+ return state.setIn(['entities', `${action.payload.collection}.${action.payload.slug}`, 'isUpdatingStatus'], false);
59
+ case UNPUBLISHED_ENTRY_PUBLISH_REQUEST:
60
+ return state.setIn(['entities', `${action.payload.collection}.${action.payload.slug}`, 'isPublishing'], true);
61
+ case UNPUBLISHED_ENTRY_PUBLISH_SUCCESS:
62
+ return state.deleteIn(['entities', `${action.payload.collection}.${action.payload.slug}`]);
63
+ case UNPUBLISHED_ENTRY_DELETE_SUCCESS:
64
+ return state.deleteIn(['entities', `${action.payload.collection}.${action.payload.slug}`]);
65
+ case UNPUBLISHED_ENTRY_PUBLISH_FAILURE:
66
+ default:
67
+ return state;
68
+ }
69
+ }
70
+ export function selectUnpublishedEntry(state, collection, slug) {
71
+ return state && state.getIn(['entities', `${collection}.${slug}`]);
72
+ }
73
+ export function selectUnpublishedEntriesByStatus(state, status) {
74
+ if (!state) return null;
75
+ const entities = state.get('entities');
76
+ return entities.filter(entry => entry.get('status') === status).valueSeq();
77
+ }
78
+ export function selectUnpublishedSlugs(state, collection) {
79
+ if (!state.get('entities')) return null;
80
+ const entities = state.get('entities');
81
+ return entities.filter((_v, k) => startsWith(k, `${collection}.`)).map(entry => entry.get('slug')).valueSeq();
82
+ }
83
+ export default unpublishedEntries;