@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,147 @@
1
+ import { isAbsolutePath } from 'decap-cms-lib-util';
2
+ import { createAssetProxy } from '../valueObjects/AssetProxy';
3
+ import { selectMediaFilePath } from '../reducers/entries';
4
+ import { selectMediaFileByPath } from '../reducers/mediaLibrary';
5
+ import { getMediaFile, waitForMediaLibraryToLoad, getMediaDisplayURL } from './mediaLibrary';
6
+ export const ADD_ASSETS = 'ADD_ASSETS';
7
+ export const ADD_ASSET = 'ADD_ASSET';
8
+ export const REMOVE_ASSET = 'REMOVE_ASSET';
9
+ export const LOAD_ASSET_REQUEST = 'LOAD_ASSET_REQUEST';
10
+ export const LOAD_ASSET_SUCCESS = 'LOAD_ASSET_SUCCESS';
11
+ export const LOAD_ASSET_FAILURE = 'LOAD_ASSET_FAILURE';
12
+ export function addAssets(assets) {
13
+ return {
14
+ type: ADD_ASSETS,
15
+ payload: assets
16
+ };
17
+ }
18
+ export function addAsset(assetProxy) {
19
+ return {
20
+ type: ADD_ASSET,
21
+ payload: assetProxy
22
+ };
23
+ }
24
+ export function removeAsset(path) {
25
+ return {
26
+ type: REMOVE_ASSET,
27
+ payload: path
28
+ };
29
+ }
30
+ export function loadAssetRequest(path) {
31
+ return {
32
+ type: LOAD_ASSET_REQUEST,
33
+ payload: {
34
+ path
35
+ }
36
+ };
37
+ }
38
+ export function loadAssetSuccess(path) {
39
+ return {
40
+ type: LOAD_ASSET_SUCCESS,
41
+ payload: {
42
+ path
43
+ }
44
+ };
45
+ }
46
+ export function loadAssetFailure(path, error) {
47
+ return {
48
+ type: LOAD_ASSET_FAILURE,
49
+ payload: {
50
+ path,
51
+ error
52
+ }
53
+ };
54
+ }
55
+ export function loadAsset(resolvedPath) {
56
+ return async (dispatch, getState) => {
57
+ try {
58
+ dispatch(loadAssetRequest(resolvedPath));
59
+ // load asset url from backend
60
+ await waitForMediaLibraryToLoad(dispatch, getState());
61
+ const file = selectMediaFileByPath(getState(), resolvedPath);
62
+ if (file) {
63
+ const url = await getMediaDisplayURL(dispatch, getState(), file);
64
+ const asset = createAssetProxy({
65
+ path: resolvedPath,
66
+ url: url || resolvedPath
67
+ });
68
+ dispatch(addAsset(asset));
69
+ } else {
70
+ const {
71
+ url
72
+ } = await getMediaFile(getState(), resolvedPath);
73
+ const asset = createAssetProxy({
74
+ path: resolvedPath,
75
+ url
76
+ });
77
+ dispatch(addAsset(asset));
78
+ }
79
+ dispatch(loadAssetSuccess(resolvedPath));
80
+ } catch (e) {
81
+ dispatch(loadAssetFailure(resolvedPath, e));
82
+ }
83
+ };
84
+ }
85
+ const emptyAsset = createAssetProxy({
86
+ path: 'empty.svg',
87
+ file: new File([`<svg xmlns="http://www.w3.org/2000/svg"></svg>`], 'empty.svg', {
88
+ type: 'image/svg+xml'
89
+ })
90
+ });
91
+ export function boundGetAsset(dispatch, collection, entry) {
92
+ function bound(path, field) {
93
+ const asset = dispatch(getAsset({
94
+ collection,
95
+ entry,
96
+ path,
97
+ field
98
+ }));
99
+ return asset;
100
+ }
101
+ return bound;
102
+ }
103
+ export function getAsset({
104
+ collection,
105
+ entry,
106
+ path,
107
+ field
108
+ }) {
109
+ return (dispatch, getState) => {
110
+ if (!path) return emptyAsset;
111
+ const state = getState();
112
+ const resolvedPath = selectMediaFilePath(state.config, collection, entry, path, field);
113
+ let {
114
+ asset,
115
+ isLoading,
116
+ error
117
+ } = state.medias[resolvedPath] || {};
118
+ if (isLoading) {
119
+ return emptyAsset;
120
+ }
121
+ if (asset) {
122
+ // There is already an AssetProxy in memory for this path. Use it.
123
+ return asset;
124
+ }
125
+ if (isAbsolutePath(resolvedPath)) {
126
+ // asset path is a public url so we can just use it as is
127
+ asset = createAssetProxy({
128
+ path: resolvedPath,
129
+ url: path
130
+ });
131
+ dispatch(addAsset(asset));
132
+ } else {
133
+ if (error) {
134
+ // on load error default back to original path
135
+ asset = createAssetProxy({
136
+ path: resolvedPath,
137
+ url: path
138
+ });
139
+ dispatch(addAsset(asset));
140
+ } else {
141
+ dispatch(loadAsset(resolvedPath));
142
+ asset = emptyAsset;
143
+ }
144
+ }
145
+ return asset;
146
+ };
147
+ }
@@ -0,0 +1,552 @@
1
+ import { Map } from 'immutable';
2
+ import { basename, getBlobSHA } from 'decap-cms-lib-util';
3
+ import { currentBackend } from '../backend';
4
+ import { createAssetProxy } from '../valueObjects/AssetProxy';
5
+ import { selectIntegration } from '../reducers';
6
+ import { selectMediaFilePath, selectMediaFilePublicPath, selectEditingDraft } from '../reducers/entries';
7
+ import { selectMediaDisplayURL, selectMediaFiles } from '../reducers/mediaLibrary';
8
+ import { getIntegrationProvider } from '../integrations';
9
+ import { addAsset, removeAsset } from './media';
10
+ import { addDraftEntryMediaFile, removeDraftEntryMediaFile } from './entries';
11
+ import { sanitizeSlug } from '../lib/urlHelper';
12
+ import { waitUntilWithTimeout } from './waitUntil';
13
+ import { addNotification } from './notifications';
14
+ export const MEDIA_LIBRARY_OPEN = 'MEDIA_LIBRARY_OPEN';
15
+ export const MEDIA_LIBRARY_CLOSE = 'MEDIA_LIBRARY_CLOSE';
16
+ export const MEDIA_LIBRARY_CREATE = 'MEDIA_LIBRARY_CREATE';
17
+ export const MEDIA_INSERT = 'MEDIA_INSERT';
18
+ export const MEDIA_REMOVE_INSERTED = 'MEDIA_REMOVE_INSERTED';
19
+ export const MEDIA_LOAD_REQUEST = 'MEDIA_LOAD_REQUEST';
20
+ export const MEDIA_LOAD_SUCCESS = 'MEDIA_LOAD_SUCCESS';
21
+ export const MEDIA_LOAD_FAILURE = 'MEDIA_LOAD_FAILURE';
22
+ export const MEDIA_PERSIST_REQUEST = 'MEDIA_PERSIST_REQUEST';
23
+ export const MEDIA_PERSIST_SUCCESS = 'MEDIA_PERSIST_SUCCESS';
24
+ export const MEDIA_PERSIST_FAILURE = 'MEDIA_PERSIST_FAILURE';
25
+ export const MEDIA_DELETE_REQUEST = 'MEDIA_DELETE_REQUEST';
26
+ export const MEDIA_DELETE_SUCCESS = 'MEDIA_DELETE_SUCCESS';
27
+ export const MEDIA_DELETE_FAILURE = 'MEDIA_DELETE_FAILURE';
28
+ export const MEDIA_DISPLAY_URL_REQUEST = 'MEDIA_DISPLAY_URL_REQUEST';
29
+ export const MEDIA_DISPLAY_URL_SUCCESS = 'MEDIA_DISPLAY_URL_SUCCESS';
30
+ export const MEDIA_DISPLAY_URL_FAILURE = 'MEDIA_DISPLAY_URL_FAILURE';
31
+ export function createMediaLibrary(instance) {
32
+ const api = {
33
+ show: instance.show || (() => undefined),
34
+ hide: instance.hide || (() => undefined),
35
+ onClearControl: instance.onClearControl || (() => undefined),
36
+ onRemoveControl: instance.onRemoveControl || (() => undefined),
37
+ enableStandalone: instance.enableStandalone || (() => undefined)
38
+ };
39
+ return {
40
+ type: MEDIA_LIBRARY_CREATE,
41
+ payload: api
42
+ };
43
+ }
44
+ export function clearMediaControl(id) {
45
+ return (_dispatch, getState) => {
46
+ const state = getState();
47
+ const mediaLibrary = state.mediaLibrary.get('externalLibrary');
48
+ if (mediaLibrary) {
49
+ mediaLibrary.onClearControl({
50
+ id
51
+ });
52
+ }
53
+ };
54
+ }
55
+ export function removeMediaControl(id) {
56
+ return (_dispatch, getState) => {
57
+ const state = getState();
58
+ const mediaLibrary = state.mediaLibrary.get('externalLibrary');
59
+ if (mediaLibrary) {
60
+ mediaLibrary.onRemoveControl({
61
+ id
62
+ });
63
+ }
64
+ };
65
+ }
66
+ export function openMediaLibrary(payload = {}) {
67
+ return (dispatch, getState) => {
68
+ const state = getState();
69
+ const mediaLibrary = state.mediaLibrary.get('externalLibrary');
70
+ if (mediaLibrary) {
71
+ const {
72
+ controlID: id,
73
+ value,
74
+ config = Map(),
75
+ allowMultiple,
76
+ forImage
77
+ } = payload;
78
+ mediaLibrary.show({
79
+ id,
80
+ value,
81
+ config: config.toJS(),
82
+ allowMultiple,
83
+ imagesOnly: forImage
84
+ });
85
+ }
86
+ dispatch(mediaLibraryOpened(payload));
87
+ };
88
+ }
89
+ export function closeMediaLibrary() {
90
+ return (dispatch, getState) => {
91
+ const state = getState();
92
+ const mediaLibrary = state.mediaLibrary.get('externalLibrary');
93
+ if (mediaLibrary) {
94
+ mediaLibrary.hide();
95
+ }
96
+ dispatch(mediaLibraryClosed());
97
+ };
98
+ }
99
+ export function insertMedia(mediaPath, field) {
100
+ return (dispatch, getState) => {
101
+ const state = getState();
102
+ const config = state.config;
103
+ const entry = state.entryDraft.get('entry');
104
+ const collectionName = state.entryDraft.getIn(['entry', 'collection']);
105
+ const collection = state.collections.get(collectionName);
106
+ if (Array.isArray(mediaPath)) {
107
+ mediaPath = mediaPath.map(path => selectMediaFilePublicPath(config, collection, path, entry, field));
108
+ } else {
109
+ mediaPath = selectMediaFilePublicPath(config, collection, mediaPath, entry, field);
110
+ }
111
+ dispatch(mediaInserted(mediaPath));
112
+ };
113
+ }
114
+ export function removeInsertedMedia(controlID) {
115
+ return {
116
+ type: MEDIA_REMOVE_INSERTED,
117
+ payload: {
118
+ controlID
119
+ }
120
+ };
121
+ }
122
+ export function loadMedia(opts = {}) {
123
+ const {
124
+ delay = 0,
125
+ query = '',
126
+ page = 1,
127
+ privateUpload
128
+ } = opts;
129
+ return async (dispatch, getState) => {
130
+ const state = getState();
131
+ const backend = currentBackend(state.config);
132
+ const integration = selectIntegration(state, null, 'assetStore');
133
+ if (integration) {
134
+ const provider = getIntegrationProvider(state.integrations, backend.getToken, integration);
135
+ dispatch(mediaLoading(page));
136
+ try {
137
+ const files = await provider.retrieve(query, page, privateUpload);
138
+ const mediaLoadedOpts = {
139
+ page,
140
+ canPaginate: true,
141
+ dynamicSearch: true,
142
+ dynamicSearchQuery: query,
143
+ privateUpload
144
+ };
145
+ return dispatch(mediaLoaded(files, mediaLoadedOpts));
146
+ } catch (error) {
147
+ return dispatch(mediaLoadFailed({
148
+ privateUpload
149
+ }));
150
+ }
151
+ }
152
+ dispatch(mediaLoading(page));
153
+ function loadFunction() {
154
+ return backend.getMedia().then(files => dispatch(mediaLoaded(files))).catch(error => {
155
+ console.error(error);
156
+ if (error.status === 404) {
157
+ console.log('This 404 was expected and handled appropriately.');
158
+ dispatch(mediaLoaded([]));
159
+ } else {
160
+ dispatch(mediaLoadFailed());
161
+ }
162
+ });
163
+ }
164
+ if (delay > 0) {
165
+ return new Promise(resolve => {
166
+ setTimeout(() => resolve(loadFunction()), delay);
167
+ });
168
+ } else {
169
+ return loadFunction();
170
+ }
171
+ };
172
+ }
173
+ function createMediaFileFromAsset({
174
+ id,
175
+ file,
176
+ assetProxy,
177
+ draft
178
+ }) {
179
+ const mediaFile = {
180
+ id,
181
+ name: basename(assetProxy.path),
182
+ displayURL: assetProxy.url,
183
+ draft,
184
+ file,
185
+ size: file.size,
186
+ url: assetProxy.url,
187
+ path: assetProxy.path,
188
+ field: assetProxy.field
189
+ };
190
+ return mediaFile;
191
+ }
192
+ export function persistMedia(file, opts = {}) {
193
+ const {
194
+ privateUpload,
195
+ field
196
+ } = opts;
197
+ return async (dispatch, getState) => {
198
+ const state = getState();
199
+ const backend = currentBackend(state.config);
200
+ const integration = selectIntegration(state, null, 'assetStore');
201
+ const files = selectMediaFiles(state, field);
202
+ const fileName = sanitizeSlug(file.name.toLowerCase(), state.config.slug);
203
+ const existingFile = files.find(existingFile => existingFile.name.toLowerCase() === fileName);
204
+ const editingDraft = selectEditingDraft(state.entryDraft);
205
+
206
+ /**
207
+ * Check for existing files of the same name before persisting. If no asset
208
+ * store integration is used, files are being stored in Git, so we can
209
+ * expect file names to be unique. If an asset store is in use, file names
210
+ * may not be unique, so we forego this check.
211
+ */
212
+ if (!integration && existingFile) {
213
+ if (!window.confirm(`${existingFile.name} already exists. Do you want to replace it?`)) {
214
+ return;
215
+ } else {
216
+ await dispatch(deleteMedia(existingFile, {
217
+ privateUpload
218
+ }));
219
+ }
220
+ }
221
+ if (integration || !editingDraft) {
222
+ dispatch(mediaPersisting());
223
+ }
224
+ try {
225
+ let assetProxy;
226
+ if (integration) {
227
+ try {
228
+ const provider = getIntegrationProvider(state.integrations, backend.getToken, integration);
229
+ const response = await provider.upload(file, privateUpload);
230
+ assetProxy = createAssetProxy({
231
+ url: response.asset.url,
232
+ path: response.asset.url
233
+ });
234
+ } catch (error) {
235
+ assetProxy = createAssetProxy({
236
+ file,
237
+ path: fileName
238
+ });
239
+ }
240
+ } else if (privateUpload) {
241
+ throw new Error('The Private Upload option is only available for Asset Store Integration');
242
+ } else {
243
+ const entry = state.entryDraft.get('entry');
244
+ const collection = state.collections.get(entry?.get('collection'));
245
+ const path = selectMediaFilePath(state.config, collection, entry, fileName, field);
246
+ assetProxy = createAssetProxy({
247
+ file,
248
+ path,
249
+ field
250
+ });
251
+ }
252
+ dispatch(addAsset(assetProxy));
253
+ let mediaFile;
254
+ if (integration) {
255
+ const id = await getBlobSHA(file);
256
+ // integration assets are persisted immediately, thus draft is false
257
+ mediaFile = createMediaFileFromAsset({
258
+ id,
259
+ file,
260
+ assetProxy,
261
+ draft: false
262
+ });
263
+ } else if (editingDraft) {
264
+ const id = await getBlobSHA(file);
265
+ mediaFile = createMediaFileFromAsset({
266
+ id,
267
+ file,
268
+ assetProxy,
269
+ draft: editingDraft
270
+ });
271
+ return dispatch(addDraftEntryMediaFile(mediaFile));
272
+ } else {
273
+ mediaFile = await backend.persistMedia(state.config, assetProxy);
274
+ }
275
+ return dispatch(mediaPersisted(mediaFile, {
276
+ privateUpload
277
+ }));
278
+ } catch (error) {
279
+ console.error(error);
280
+ dispatch(addNotification({
281
+ message: `Failed to persist media: ${error}`,
282
+ type: 'error',
283
+ dismissAfter: 8000
284
+ }));
285
+ return dispatch(mediaPersistFailed({
286
+ privateUpload
287
+ }));
288
+ }
289
+ };
290
+ }
291
+ export function deleteMedia(file, opts = {}) {
292
+ const {
293
+ privateUpload
294
+ } = opts;
295
+ return async (dispatch, getState) => {
296
+ const state = getState();
297
+ const backend = currentBackend(state.config);
298
+ const integration = selectIntegration(state, null, 'assetStore');
299
+ if (integration) {
300
+ const provider = getIntegrationProvider(state.integrations, backend.getToken, integration);
301
+ dispatch(mediaDeleting());
302
+ try {
303
+ await provider.delete(file.id);
304
+ return dispatch(mediaDeleted(file, {
305
+ privateUpload
306
+ }));
307
+ } catch (error) {
308
+ console.error(error);
309
+ dispatch(addNotification({
310
+ message: `Failed to delete media: ${error.message}`,
311
+ type: 'error',
312
+ dismissAfter: 8000
313
+ }));
314
+ return dispatch(mediaDeleteFailed({
315
+ privateUpload
316
+ }));
317
+ }
318
+ }
319
+ try {
320
+ if (file.draft) {
321
+ dispatch(removeAsset(file.path));
322
+ dispatch(removeDraftEntryMediaFile({
323
+ id: file.id
324
+ }));
325
+ } else {
326
+ const editingDraft = selectEditingDraft(state.entryDraft);
327
+ dispatch(mediaDeleting());
328
+ dispatch(removeAsset(file.path));
329
+ await backend.deleteMedia(state.config, file.path);
330
+ dispatch(mediaDeleted(file));
331
+ if (editingDraft) {
332
+ dispatch(removeDraftEntryMediaFile({
333
+ id: file.id
334
+ }));
335
+ }
336
+ }
337
+ } catch (error) {
338
+ console.error(error);
339
+ dispatch(addNotification({
340
+ message: `Failed to delete media: ${error.message}`,
341
+ type: 'error',
342
+ dismissAfter: 8000
343
+ }));
344
+ return dispatch(mediaDeleteFailed());
345
+ }
346
+ };
347
+ }
348
+ export async function getMediaFile(state, path) {
349
+ const backend = currentBackend(state.config);
350
+ const {
351
+ url
352
+ } = await backend.getMediaFile(path);
353
+ return {
354
+ url
355
+ };
356
+ }
357
+ export function loadMediaDisplayURL(file) {
358
+ return async (dispatch, getState) => {
359
+ const {
360
+ displayURL,
361
+ id
362
+ } = file;
363
+ const state = getState();
364
+ const displayURLState = selectMediaDisplayURL(state, id);
365
+ if (!id || !displayURL || displayURLState.get('url') || displayURLState.get('isFetching') || displayURLState.get('err')) {
366
+ return Promise.resolve();
367
+ }
368
+ if (typeof displayURL === 'string') {
369
+ dispatch(mediaDisplayURLRequest(id));
370
+ dispatch(mediaDisplayURLSuccess(id, displayURL));
371
+ return;
372
+ }
373
+ try {
374
+ const backend = currentBackend(state.config);
375
+ dispatch(mediaDisplayURLRequest(id));
376
+ const newURL = await backend.getMediaDisplayURL(displayURL);
377
+ if (newURL) {
378
+ dispatch(mediaDisplayURLSuccess(id, newURL));
379
+ } else {
380
+ throw new Error('No display URL was returned!');
381
+ }
382
+ } catch (err) {
383
+ console.error(err);
384
+ dispatch(mediaDisplayURLFailure(id, err));
385
+ }
386
+ };
387
+ }
388
+ function mediaLibraryOpened(payload) {
389
+ return {
390
+ type: MEDIA_LIBRARY_OPEN,
391
+ payload
392
+ };
393
+ }
394
+ function mediaLibraryClosed() {
395
+ return {
396
+ type: MEDIA_LIBRARY_CLOSE
397
+ };
398
+ }
399
+ function mediaInserted(mediaPath) {
400
+ return {
401
+ type: MEDIA_INSERT,
402
+ payload: {
403
+ mediaPath
404
+ }
405
+ };
406
+ }
407
+ export function mediaLoading(page) {
408
+ return {
409
+ type: MEDIA_LOAD_REQUEST,
410
+ payload: {
411
+ page
412
+ }
413
+ };
414
+ }
415
+ export function mediaLoaded(files, opts = {}) {
416
+ return {
417
+ type: MEDIA_LOAD_SUCCESS,
418
+ payload: {
419
+ files,
420
+ ...opts
421
+ }
422
+ };
423
+ }
424
+ export function mediaLoadFailed(opts = {}) {
425
+ const {
426
+ privateUpload
427
+ } = opts;
428
+ return {
429
+ type: MEDIA_LOAD_FAILURE,
430
+ payload: {
431
+ privateUpload
432
+ }
433
+ };
434
+ }
435
+ export function mediaPersisting() {
436
+ return {
437
+ type: MEDIA_PERSIST_REQUEST
438
+ };
439
+ }
440
+ export function mediaPersisted(file, opts = {}) {
441
+ const {
442
+ privateUpload
443
+ } = opts;
444
+ return {
445
+ type: MEDIA_PERSIST_SUCCESS,
446
+ payload: {
447
+ file,
448
+ privateUpload
449
+ }
450
+ };
451
+ }
452
+ export function mediaPersistFailed(opts = {}) {
453
+ const {
454
+ privateUpload
455
+ } = opts;
456
+ return {
457
+ type: MEDIA_PERSIST_FAILURE,
458
+ payload: {
459
+ privateUpload
460
+ }
461
+ };
462
+ }
463
+ export function mediaDeleting() {
464
+ return {
465
+ type: MEDIA_DELETE_REQUEST
466
+ };
467
+ }
468
+ export function mediaDeleted(file, opts = {}) {
469
+ const {
470
+ privateUpload
471
+ } = opts;
472
+ return {
473
+ type: MEDIA_DELETE_SUCCESS,
474
+ payload: {
475
+ file,
476
+ privateUpload
477
+ }
478
+ };
479
+ }
480
+ export function mediaDeleteFailed(opts = {}) {
481
+ const {
482
+ privateUpload
483
+ } = opts;
484
+ return {
485
+ type: MEDIA_DELETE_FAILURE,
486
+ payload: {
487
+ privateUpload
488
+ }
489
+ };
490
+ }
491
+ export function mediaDisplayURLRequest(key) {
492
+ return {
493
+ type: MEDIA_DISPLAY_URL_REQUEST,
494
+ payload: {
495
+ key
496
+ }
497
+ };
498
+ }
499
+ export function mediaDisplayURLSuccess(key, url) {
500
+ return {
501
+ type: MEDIA_DISPLAY_URL_SUCCESS,
502
+ payload: {
503
+ key,
504
+ url
505
+ }
506
+ };
507
+ }
508
+ export function mediaDisplayURLFailure(key, err) {
509
+ return {
510
+ type: MEDIA_DISPLAY_URL_FAILURE,
511
+ payload: {
512
+ key,
513
+ err
514
+ }
515
+ };
516
+ }
517
+ export async function waitForMediaLibraryToLoad(dispatch, state) {
518
+ if (state.mediaLibrary.get('isLoading') !== false && !state.mediaLibrary.get('externalLibrary')) {
519
+ await waitUntilWithTimeout(dispatch, resolve => ({
520
+ predicate: ({
521
+ type
522
+ }) => type === MEDIA_LOAD_SUCCESS || type === MEDIA_LOAD_FAILURE,
523
+ run: () => resolve()
524
+ }));
525
+ }
526
+ }
527
+ export async function getMediaDisplayURL(dispatch, state, file) {
528
+ const displayURLState = selectMediaDisplayURL(state, file.id);
529
+ let url;
530
+ if (displayURLState.get('url')) {
531
+ // url was already loaded
532
+ url = displayURLState.get('url');
533
+ } else if (displayURLState.get('err')) {
534
+ // url loading had an error
535
+ url = null;
536
+ } else {
537
+ const key = file.id;
538
+ const promise = waitUntilWithTimeout(dispatch, resolve => ({
539
+ predicate: ({
540
+ type,
541
+ payload
542
+ }) => (type === MEDIA_DISPLAY_URL_SUCCESS || type === MEDIA_DISPLAY_URL_FAILURE) && payload.key === key,
543
+ run: (_dispatch, _getState, action) => resolve(action.payload.url)
544
+ }));
545
+ if (!displayURLState.get('isFetching')) {
546
+ // load display url
547
+ dispatch(loadMediaDisplayURL(file));
548
+ }
549
+ url = (await promise) ?? null;
550
+ }
551
+ return url;
552
+ }
@@ -0,0 +1,21 @@
1
+ export const NOTIFICATION_SEND = 'NOTIFICATION_SEND';
2
+ export const NOTIFICATION_DISMISS = 'NOTIFICATION_DISMISS';
3
+ export const NOTIFICATIONS_CLEAR = 'NOTIFICATION_CLEAR';
4
+ function addNotification(notification) {
5
+ return {
6
+ type: NOTIFICATION_SEND,
7
+ payload: notification
8
+ };
9
+ }
10
+ function dismissNotification(id) {
11
+ return {
12
+ type: NOTIFICATION_DISMISS,
13
+ id
14
+ };
15
+ }
16
+ function clearNotifications() {
17
+ return {
18
+ type: NOTIFICATIONS_CLEAR
19
+ };
20
+ }
21
+ export { addNotification, dismissNotification, clearNotifications };