@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,535 @@
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
+
6
+ import consoleError from '../lib/consoleError';
7
+ import { CONFIG_SUCCESS } from '../actions/config';
8
+ import { FILES, FOLDER } from '../constants/collectionTypes';
9
+ import { COMMIT_DATE, COMMIT_AUTHOR } from '../constants/commitProps';
10
+ import { INFERABLE_FIELDS, IDENTIFIER_FIELDS, SORTABLE_FIELDS } from '../constants/fieldInference';
11
+ import { getFormatExtensions } from '../formats/formats';
12
+ import { selectMediaFolder } from './entries';
13
+ import { summaryFormatter } from '../lib/formatters';
14
+
15
+ import type {
16
+ Collection,
17
+ Collections,
18
+ CollectionFiles,
19
+ EntryField,
20
+ EntryMap,
21
+ ViewFilter,
22
+ ViewGroup,
23
+ CmsConfig,
24
+ } from '../types/redux';
25
+ import type { ConfigAction } from '../actions/config';
26
+ import type { Backend } from '../backend';
27
+
28
+ const { keyToPathArray } = stringTemplate;
29
+
30
+ const defaultState: Collections = fromJS({});
31
+
32
+ function collections(state = defaultState, action: ConfigAction) {
33
+ switch (action.type) {
34
+ case CONFIG_SUCCESS: {
35
+ const collections = action.payload.collections;
36
+ let newState = OrderedMap({});
37
+ collections.forEach(collection => {
38
+ newState = newState.set(collection.name, fromJS(collection));
39
+ });
40
+ return newState;
41
+ }
42
+ default:
43
+ return state;
44
+ }
45
+ }
46
+
47
+ const selectors = {
48
+ [FOLDER]: {
49
+ entryExtension(collection: Collection) {
50
+ const ext =
51
+ collection.get('extension') ||
52
+ get(getFormatExtensions(), collection.get('format') || 'frontmatter');
53
+ if (!ext) {
54
+ throw new Error(`No extension found for format ${collection.get('format')}`);
55
+ }
56
+
57
+ return ext.replace(/^\./, '');
58
+ },
59
+ fields(collection: Collection) {
60
+ return collection.get('fields');
61
+ },
62
+ entryPath(collection: Collection, slug: string) {
63
+ const folder = (collection.get('folder') as string).replace(/\/$/, '');
64
+ return `${folder}/${slug}.${this.entryExtension(collection)}`;
65
+ },
66
+ entrySlug(collection: Collection, path: string) {
67
+ const folder = (collection.get('folder') as string).replace(/\/$/, '');
68
+ const slug = path
69
+ .split(folder + '/')
70
+ .pop()
71
+ ?.replace(new RegExp(`\\.${escapeRegExp(this.entryExtension(collection))}$`), '');
72
+
73
+ return slug;
74
+ },
75
+ allowNewEntries(collection: Collection) {
76
+ return collection.get('create');
77
+ },
78
+ allowDeletion(collection: Collection) {
79
+ return collection.get('delete', true);
80
+ },
81
+ templateName(collection: Collection) {
82
+ return collection.get('name');
83
+ },
84
+ },
85
+ [FILES]: {
86
+ fileForEntry(collection: Collection, slug: string) {
87
+ const files = collection.get('files');
88
+ return files && files.filter(f => f?.get('name') === slug).get(0);
89
+ },
90
+ fields(collection: Collection, slug: string) {
91
+ const file = this.fileForEntry(collection, slug);
92
+ return file && file.get('fields');
93
+ },
94
+ entryPath(collection: Collection, slug: string) {
95
+ const file = this.fileForEntry(collection, slug);
96
+ return file && file.get('file');
97
+ },
98
+ entrySlug(collection: Collection, path: string) {
99
+ const file = (collection.get('files') as CollectionFiles)
100
+ .filter(f => f?.get('file') === path)
101
+ .get(0);
102
+ return file && file.get('name');
103
+ },
104
+ entryLabel(collection: Collection, slug: string) {
105
+ const file = this.fileForEntry(collection, slug);
106
+ return file && file.get('label');
107
+ },
108
+ allowNewEntries() {
109
+ return false;
110
+ },
111
+ allowDeletion(collection: Collection) {
112
+ return collection.get('delete', false);
113
+ },
114
+ templateName(_collection: Collection, slug: string) {
115
+ return slug;
116
+ },
117
+ },
118
+ };
119
+
120
+ function getFieldsWithMediaFolders(fields: EntryField[]) {
121
+ const fieldsWithMediaFolders = fields.reduce((acc, f) => {
122
+ if (f.has('media_folder')) {
123
+ acc = [...acc, f];
124
+ }
125
+
126
+ if (f.has('fields')) {
127
+ const fields = f.get('fields')?.toArray() as EntryField[];
128
+ acc = [...acc, ...getFieldsWithMediaFolders(fields)];
129
+ } else if (f.has('field')) {
130
+ const field = f.get('field') as EntryField;
131
+ acc = [...acc, ...getFieldsWithMediaFolders([field])];
132
+ } else if (f.has('types')) {
133
+ const types = f.get('types')?.toArray() as EntryField[];
134
+ acc = [...acc, ...getFieldsWithMediaFolders(types)];
135
+ }
136
+
137
+ return acc;
138
+ }, [] as EntryField[]);
139
+
140
+ return fieldsWithMediaFolders;
141
+ }
142
+
143
+ export function getFileFromSlug(collection: Collection, slug: string) {
144
+ return collection
145
+ .get('files')
146
+ ?.toArray()
147
+ .find(f => f.get('name') === slug);
148
+ }
149
+
150
+ export function selectFieldsWithMediaFolders(collection: Collection, slug: string) {
151
+ if (collection.has('folder')) {
152
+ const fields = collection.get('fields').toArray();
153
+ return getFieldsWithMediaFolders(fields);
154
+ } else if (collection.has('files')) {
155
+ const fields = getFileFromSlug(collection, slug)?.get('fields').toArray() || [];
156
+ return getFieldsWithMediaFolders(fields);
157
+ }
158
+
159
+ return [];
160
+ }
161
+
162
+ export function selectMediaFolders(config: CmsConfig, collection: Collection, entry: EntryMap) {
163
+ const fields = selectFieldsWithMediaFolders(collection, entry.get('slug'));
164
+ const folders = fields.map(f => selectMediaFolder(config, collection, entry, f));
165
+ if (collection.has('files')) {
166
+ const file = getFileFromSlug(collection, entry.get('slug'));
167
+ if (file) {
168
+ folders.unshift(selectMediaFolder(config, collection, entry, undefined));
169
+ }
170
+ }
171
+ if (collection.has('media_folder')) {
172
+ // stop evaluating media folders at collection level
173
+ collection = collection.delete('files');
174
+ folders.unshift(selectMediaFolder(config, collection, entry, undefined));
175
+ }
176
+
177
+ return Set(folders).toArray();
178
+ }
179
+
180
+ export function selectFields(collection: Collection, slug: string) {
181
+ return selectors[collection.get('type')].fields(collection, slug);
182
+ }
183
+
184
+ export function selectFolderEntryExtension(collection: Collection) {
185
+ return selectors[FOLDER].entryExtension(collection);
186
+ }
187
+
188
+ export function selectFileEntryLabel(collection: Collection, slug: string) {
189
+ return selectors[FILES].entryLabel(collection, slug);
190
+ }
191
+
192
+ export function selectEntryPath(collection: Collection, slug: string) {
193
+ return selectors[collection.get('type')].entryPath(collection, slug);
194
+ }
195
+
196
+ export function selectEntrySlug(collection: Collection, path: string) {
197
+ return selectors[collection.get('type')].entrySlug(collection, path);
198
+ }
199
+
200
+ export function selectAllowNewEntries(collection: Collection) {
201
+ return selectors[collection.get('type')].allowNewEntries(collection);
202
+ }
203
+
204
+ export function selectAllowDeletion(collection: Collection) {
205
+ return selectors[collection.get('type')].allowDeletion(collection);
206
+ }
207
+
208
+ export function selectTemplateName(collection: Collection, slug: string) {
209
+ return selectors[collection.get('type')].templateName(collection, slug);
210
+ }
211
+
212
+ export function getFieldsNames(fields: EntryField[], prefix = '') {
213
+ let names = fields.map(f => `${prefix}${f.get('name')}`);
214
+
215
+ fields.forEach((f, index) => {
216
+ if (f.has('fields')) {
217
+ const fields = f.get('fields')?.toArray() as EntryField[];
218
+ names = [...names, ...getFieldsNames(fields, `${names[index]}.`)];
219
+ } else if (f.has('field')) {
220
+ const field = f.get('field') as EntryField;
221
+ names = [...names, ...getFieldsNames([field], `${names[index]}.`)];
222
+ } else if (f.has('types')) {
223
+ const types = f.get('types')?.toArray() as EntryField[];
224
+ names = [...names, ...getFieldsNames(types, `${names[index]}.`)];
225
+ }
226
+ });
227
+
228
+ return names;
229
+ }
230
+
231
+ export function selectField(collection: Collection, key: string) {
232
+ const array = keyToPathArray(key);
233
+ let name: string | undefined;
234
+ let field;
235
+ let fields = collection.get('fields', List<EntryField>()).toArray();
236
+ while ((name = array.shift()) && fields) {
237
+ field = fields.find(f => f.get('name') === name);
238
+ if (field?.has('fields')) {
239
+ fields = field?.get('fields')?.toArray() as EntryField[];
240
+ } else if (field?.has('field')) {
241
+ fields = [field?.get('field') as EntryField];
242
+ } else if (field?.has('types')) {
243
+ fields = field?.get('types')?.toArray() as EntryField[];
244
+ }
245
+ }
246
+
247
+ return field;
248
+ }
249
+
250
+ export function traverseFields(
251
+ fields: List<EntryField>,
252
+ updater: (field: EntryField) => EntryField,
253
+ done = () => false,
254
+ ) {
255
+ if (done()) {
256
+ return fields;
257
+ }
258
+
259
+ fields = fields
260
+ .map(f => {
261
+ const field = updater(f as EntryField);
262
+ if (done()) {
263
+ return field;
264
+ } else if (field.has('fields')) {
265
+ return field.set('fields', traverseFields(field.get('fields')!, updater, done));
266
+ } else if (field.has('field')) {
267
+ return field.set(
268
+ 'field',
269
+ traverseFields(List([field.get('field')!]), updater, done).get(0),
270
+ );
271
+ } else if (field.has('types')) {
272
+ return field.set('types', traverseFields(field.get('types')!, updater, done));
273
+ } else {
274
+ return field;
275
+ }
276
+ })
277
+ .toList() as List<EntryField>;
278
+
279
+ return fields;
280
+ }
281
+
282
+ export function updateFieldByKey(
283
+ collection: Collection,
284
+ key: string,
285
+ updater: (field: EntryField) => EntryField,
286
+ ) {
287
+ const selected = selectField(collection, key);
288
+ if (!selected) {
289
+ return collection;
290
+ }
291
+
292
+ let updated = false;
293
+
294
+ function updateAndBreak(f: EntryField) {
295
+ const field = f as EntryField;
296
+ if (field === selected) {
297
+ updated = true;
298
+ return updater(field);
299
+ } else {
300
+ return field;
301
+ }
302
+ }
303
+
304
+ collection = collection.set(
305
+ 'fields',
306
+ traverseFields(collection.get('fields', List<EntryField>()), updateAndBreak, () => updated),
307
+ );
308
+
309
+ return collection;
310
+ }
311
+
312
+ export function selectIdentifier(collection: Collection) {
313
+ const identifier = collection.get('identifier_field');
314
+ const identifierFields = identifier ? [identifier, ...IDENTIFIER_FIELDS] : [...IDENTIFIER_FIELDS];
315
+ const fieldNames = getFieldsNames(collection.get('fields', List()).toArray());
316
+ return identifierFields.find(id =>
317
+ fieldNames.find(name => name.toLowerCase().trim() === id.toLowerCase().trim()),
318
+ );
319
+ }
320
+
321
+ export function selectInferredField(collection: Collection, fieldName: string) {
322
+ if (fieldName === 'title' && collection.get('identifier_field')) {
323
+ return selectIdentifier(collection);
324
+ }
325
+ const inferableField = (
326
+ INFERABLE_FIELDS as Record<
327
+ string,
328
+ {
329
+ type: string;
330
+ synonyms: string[];
331
+ secondaryTypes: string[];
332
+ fallbackToFirstField: boolean;
333
+ showError: boolean;
334
+ }
335
+ >
336
+ )[fieldName];
337
+ const fields = collection.get('fields');
338
+ let field;
339
+
340
+ // If collection has no fields or fieldName is not defined within inferables list, return null
341
+ if (!fields || !inferableField) return null;
342
+ // Try to return a field of the specified type with one of the synonyms
343
+ const mainTypeFields = fields
344
+ .filter(f => f?.get('widget', 'string') === inferableField.type)
345
+ .map(f => f?.get('name'));
346
+ field = mainTypeFields.filter(f => inferableField.synonyms.indexOf(f as string) !== -1);
347
+ if (field && field.size > 0) return field.first();
348
+
349
+ // Try to return a field for each of the specified secondary types
350
+ const secondaryTypeFields = fields
351
+ .filter(f => inferableField.secondaryTypes.indexOf(f?.get('widget', 'string') as string) !== -1)
352
+ .map(f => f?.get('name'));
353
+ field = secondaryTypeFields.filter(f => inferableField.synonyms.indexOf(f as string) !== -1);
354
+ if (field && field.size > 0) return field.first();
355
+
356
+ // Try to return the first field of the specified type
357
+ if (inferableField.fallbackToFirstField && mainTypeFields.size > 0) return mainTypeFields.first();
358
+
359
+ // Coundn't infer the field. Show error and return null.
360
+ if (inferableField.showError) {
361
+ consoleError(
362
+ `The Field ${fieldName} is missing for the collection “${collection.get('name')}”`,
363
+ `Decap CMS tries to infer the entry ${fieldName} automatically, but one couldn't be found for entries of the collection “${collection.get(
364
+ 'name',
365
+ )}”. Please check your site configuration.`,
366
+ );
367
+ }
368
+
369
+ return null;
370
+ }
371
+
372
+ export function selectEntryCollectionTitle(collection: Collection, entry: EntryMap) {
373
+ // prefer formatted summary over everything else
374
+ const summaryTemplate = collection.get('summary');
375
+ if (summaryTemplate) return summaryFormatter(summaryTemplate, entry, collection);
376
+
377
+ // if the collection is a file collection return the label of the entry
378
+ if (collection.get('type') == FILES) {
379
+ const label = selectFileEntryLabel(collection, entry.get('slug'));
380
+ if (label) return label;
381
+ }
382
+
383
+ // try to infer a title field from the entry data
384
+ const entryData = entry.get('data');
385
+ const titleField = selectInferredField(collection, 'title');
386
+ const result = titleField && entryData.getIn(keyToPathArray(titleField));
387
+
388
+ // if the custom field does not yield a result, fallback to 'title'
389
+ if (!result && titleField !== 'title') {
390
+ return entryData.getIn(keyToPathArray('title'));
391
+ }
392
+
393
+ return result;
394
+ }
395
+
396
+ export function selectDefaultSortableFields(
397
+ collection: Collection,
398
+ backend: Backend,
399
+ hasIntegration: boolean,
400
+ ) {
401
+ let defaultSortable = SORTABLE_FIELDS.map((type: string) => {
402
+ const field = selectInferredField(collection, type);
403
+ if (backend.isGitBackend() && type === 'author' && !field && !hasIntegration) {
404
+ // default to commit author if not author field is found
405
+ return COMMIT_AUTHOR;
406
+ }
407
+ return field;
408
+ }).filter(Boolean);
409
+
410
+ if (backend.isGitBackend() && !hasIntegration) {
411
+ // always have commit date by default
412
+ defaultSortable = [COMMIT_DATE, ...defaultSortable];
413
+ }
414
+
415
+ // Return as objects with field property
416
+ return defaultSortable.map(field => ({ field })) as {
417
+ field: string;
418
+ label?: string;
419
+ default_sort?: boolean | 'asc' | 'desc';
420
+ }[];
421
+ }
422
+
423
+ export function selectSortableFields(collection: Collection, t: (key: string) => string) {
424
+ const fields = collection
425
+ .get('sortable_fields')
426
+ .toArray()
427
+ .map(sortableField => {
428
+ // Extract the field name and custom label from the sortable field object
429
+ const key = sortableField.get('field');
430
+ const customLabel = sortableField.get('label');
431
+
432
+ if (key === COMMIT_DATE) {
433
+ const label = customLabel || t('collection.defaultFields.updatedOn.label');
434
+ return { key, field: { name: key, label } };
435
+ }
436
+ const field = selectField(collection, key);
437
+ if (key === COMMIT_AUTHOR && !field) {
438
+ const label = customLabel || t('collection.defaultFields.author.label');
439
+ return { key, field: { name: key, label } };
440
+ }
441
+
442
+ let fieldObj: Record<string, unknown> | undefined = field?.toJS();
443
+
444
+ // If custom label is provided, override the field's label
445
+ if (fieldObj && customLabel) {
446
+ fieldObj = { ...fieldObj, label: customLabel };
447
+ }
448
+
449
+ // If no label exists at all, use the field name
450
+ if (fieldObj && !fieldObj.label) {
451
+ fieldObj = { ...fieldObj, label: (fieldObj.name as string) || key };
452
+ }
453
+
454
+ return { key, field: fieldObj };
455
+ })
456
+ .filter(item => !!item.field)
457
+ .map(item => ({ ...item.field, key: item.key }));
458
+
459
+ return fields;
460
+ }
461
+
462
+ export function selectDefaultSortField(collection: Collection) {
463
+ const sortableFields = collection.get('sortable_fields').toArray();
464
+ const defaultField = sortableFields.find(field => field.get('default_sort') !== undefined);
465
+
466
+ if (!defaultField) {
467
+ return null;
468
+ }
469
+
470
+ const fieldName = defaultField.get('field');
471
+ const defaultSortValue = defaultField.get('default_sort');
472
+
473
+ // Determine direction based on default_sort value
474
+ let direction;
475
+ if (defaultSortValue === true || defaultSortValue === 'asc') {
476
+ direction = 'asc';
477
+ } else if (defaultSortValue === 'desc') {
478
+ direction = 'desc';
479
+ } else {
480
+ direction = 'asc'; // fallback
481
+ }
482
+
483
+ return { field: fieldName, direction };
484
+ }
485
+
486
+ export function selectSortDataPath(collection: Collection, key: string) {
487
+ if (key === COMMIT_DATE) {
488
+ return 'updatedOn';
489
+ } else if (key === COMMIT_AUTHOR && !selectField(collection, key)) {
490
+ return 'author';
491
+ } else {
492
+ return `data.${key}`;
493
+ }
494
+ }
495
+
496
+ export function selectViewFilters(collection: Collection) {
497
+ const viewFilters = collection.get('view_filters').toJS() as ViewFilter[];
498
+ return viewFilters;
499
+ }
500
+
501
+ export function selectViewGroups(collection: Collection) {
502
+ const viewGroups = collection.get('view_groups').toJS() as ViewGroup[];
503
+ return viewGroups;
504
+ }
505
+
506
+ export function selectFieldsComments(collection: Collection, entryMap: EntryMap) {
507
+ let fields: EntryField[] = [];
508
+ if (collection.has('folder')) {
509
+ fields = collection.get('fields').toArray();
510
+ } else if (collection.has('files')) {
511
+ const file = collection.get('files')!.find(f => f?.get('name') === entryMap.get('slug'));
512
+ fields = file.get('fields').toArray();
513
+ }
514
+ const comments: Record<string, string> = {};
515
+ const names = getFieldsNames(fields);
516
+ names.forEach(name => {
517
+ const field = selectField(collection, name);
518
+ if (field?.has('comment')) {
519
+ comments[name] = field.get('comment')!;
520
+ }
521
+ });
522
+
523
+ return comments;
524
+ }
525
+
526
+ export function selectHasMetaPath(collection: Collection) {
527
+ return (
528
+ collection.has('folder') &&
529
+ collection.get('type') === FOLDER &&
530
+ collection.has('meta') &&
531
+ collection.get('meta')?.has('path')
532
+ );
533
+ }
534
+
535
+ export default collections;
@@ -0,0 +1,11 @@
1
+ import { combineReducers } from 'redux';
2
+
3
+ import reducers from './index';
4
+
5
+ function createRootReducer() {
6
+ return combineReducers({
7
+ ...reducers,
8
+ });
9
+ }
10
+
11
+ export default createRootReducer;
@@ -0,0 +1,38 @@
1
+ import { produce } from 'immer';
2
+
3
+ import { CONFIG_REQUEST, CONFIG_SUCCESS, CONFIG_FAILURE } from '../actions/config';
4
+ import { EDITORIAL_WORKFLOW } from '../constants/publishModes';
5
+
6
+ import type { ConfigAction } from '../actions/config';
7
+ import type { CmsConfig } from '../types/redux';
8
+
9
+ const defaultState = {
10
+ isFetching: true,
11
+ };
12
+
13
+ const config = produce((state: CmsConfig, action: ConfigAction) => {
14
+ switch (action.type) {
15
+ case CONFIG_REQUEST:
16
+ state.isFetching = true;
17
+ break;
18
+ case CONFIG_SUCCESS:
19
+ return {
20
+ ...action.payload,
21
+ isFetching: false,
22
+ error: undefined,
23
+ };
24
+ case CONFIG_FAILURE:
25
+ state.isFetching = false;
26
+ state.error = action.payload.toString();
27
+ }
28
+ }, defaultState);
29
+
30
+ export function selectLocale(state: CmsConfig) {
31
+ return state.locale || 'en';
32
+ }
33
+
34
+ export function selectUseWorkflow(state: CmsConfig) {
35
+ return state.publish_mode === EDITORIAL_WORKFLOW;
36
+ }
37
+
38
+ export default config;
@@ -0,0 +1,36 @@
1
+ import { fromJS } from 'immutable';
2
+ import { Cursor } from 'decap-cms-lib-util';
3
+
4
+ import {
5
+ ENTRIES_SUCCESS,
6
+ SORT_ENTRIES_SUCCESS,
7
+ FILTER_ENTRIES_SUCCESS,
8
+ GROUP_ENTRIES_SUCCESS,
9
+ } from '../actions/entries';
10
+
11
+ // Since pagination can be used for a variety of views (collections
12
+ // and searches are the most common examples), we namespace cursors by
13
+ // their type before storing them in the state.
14
+ export function selectCollectionEntriesCursor(state, collectionName) {
15
+ return new Cursor(state.getIn(['cursorsByType', 'collectionEntries', collectionName]));
16
+ }
17
+
18
+ function cursors(state = fromJS({ cursorsByType: { collectionEntries: {} } }), action) {
19
+ switch (action.type) {
20
+ case ENTRIES_SUCCESS: {
21
+ return state.setIn(
22
+ ['cursorsByType', 'collectionEntries', action.payload.collection],
23
+ Cursor.create(action.payload.cursor).store,
24
+ );
25
+ }
26
+ case FILTER_ENTRIES_SUCCESS:
27
+ case GROUP_ENTRIES_SUCCESS:
28
+ case SORT_ENTRIES_SUCCESS: {
29
+ return state.deleteIn(['cursorsByType', 'collectionEntries', action.payload.collection]);
30
+ }
31
+ default:
32
+ return state;
33
+ }
34
+ }
35
+
36
+ export default cursors;
@@ -0,0 +1,52 @@
1
+ import { produce } from 'immer';
2
+
3
+ import {
4
+ DEPLOY_PREVIEW_REQUEST,
5
+ DEPLOY_PREVIEW_SUCCESS,
6
+ DEPLOY_PREVIEW_FAILURE,
7
+ } from '../actions/deploys';
8
+
9
+ import type { DeploysAction } from '../actions/deploys';
10
+
11
+ export type Deploys = {
12
+ [key: string]: {
13
+ isFetching: boolean;
14
+ url?: string;
15
+ status?: string;
16
+ };
17
+ };
18
+
19
+ const defaultState: Deploys = {};
20
+
21
+ const deploys = produce((state: Deploys, action: DeploysAction) => {
22
+ switch (action.type) {
23
+ case DEPLOY_PREVIEW_REQUEST: {
24
+ const { collection, slug } = action.payload;
25
+ const key = `${collection}.${slug}`;
26
+ state[key] = state[key] || {};
27
+ state[key].isFetching = true;
28
+ break;
29
+ }
30
+
31
+ case DEPLOY_PREVIEW_SUCCESS: {
32
+ const { collection, slug, url, status } = action.payload;
33
+ const key = `${collection}.${slug}`;
34
+ state[key].isFetching = false;
35
+ state[key].url = url;
36
+ state[key].status = status;
37
+ break;
38
+ }
39
+
40
+ case DEPLOY_PREVIEW_FAILURE: {
41
+ const { collection, slug } = action.payload;
42
+ state[`${collection}.${slug}`].isFetching = false;
43
+ break;
44
+ }
45
+ }
46
+ }, defaultState);
47
+
48
+ export function selectDeployPreview(state: Deploys, collection: string, slug: string) {
49
+ return state[`${collection}.${slug}`];
50
+ }
51
+
52
+ export default deploys;