@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,61 @@
1
+ import React from 'react';
2
+ import { connect } from 'react-redux';
3
+
4
+ import { EDITORIAL_WORKFLOW } from '../../constants/publishModes';
5
+ import { selectUnpublishedEntry } from '../../reducers';
6
+ import { selectAllowDeletion } from '../../reducers/collections';
7
+ import { loadUnpublishedEntry, persistUnpublishedEntry } from '../../actions/editorialWorkflow';
8
+
9
+ function mapStateToProps(state, ownProps) {
10
+ const { collections } = state;
11
+ const isEditorialWorkflow = state.config.publish_mode === EDITORIAL_WORKFLOW;
12
+ const collection = collections.get(ownProps.match.params.name);
13
+ const returnObj = {
14
+ isEditorialWorkflow,
15
+ showDelete: !ownProps.newEntry && selectAllowDeletion(collection),
16
+ };
17
+ if (isEditorialWorkflow) {
18
+ const slug = ownProps.match.params[0];
19
+ const unpublishedEntry = selectUnpublishedEntry(state, collection.get('name'), slug);
20
+ if (unpublishedEntry) {
21
+ returnObj.unpublishedEntry = true;
22
+ returnObj.entry = unpublishedEntry;
23
+ }
24
+ }
25
+ return returnObj;
26
+ }
27
+
28
+ function mergeProps(stateProps, dispatchProps, ownProps) {
29
+ const { isEditorialWorkflow, unpublishedEntry } = stateProps;
30
+ const { dispatch } = dispatchProps;
31
+ const returnObj = {};
32
+
33
+ if (isEditorialWorkflow) {
34
+ // Overwrite loadEntry to loadUnpublishedEntry
35
+ returnObj.loadEntry = (collection, slug) => dispatch(loadUnpublishedEntry(collection, slug));
36
+
37
+ // Overwrite persistEntry to persistUnpublishedEntry
38
+ returnObj.persistEntry = collection =>
39
+ dispatch(persistUnpublishedEntry(collection, unpublishedEntry));
40
+ }
41
+
42
+ return {
43
+ ...ownProps,
44
+ ...stateProps,
45
+ ...returnObj,
46
+ };
47
+ }
48
+
49
+ export default function withWorkflow(Editor) {
50
+ return connect(
51
+ mapStateToProps,
52
+ null,
53
+ mergeProps,
54
+ )(
55
+ class WorkflowEditor extends React.Component {
56
+ render() {
57
+ return <Editor {...this.props} />;
58
+ }
59
+ },
60
+ );
61
+ }
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { translate } from 'react-polyglot';
3
+ import ImmutablePropTypes from 'react-immutable-proptypes';
4
+ import PropTypes from 'prop-types';
5
+
6
+ function UnknownControl({ field, t }) {
7
+ return (
8
+ <div>{t('editor.editorWidgets.unknownControl.noControl', { widget: field.get('widget') })}</div>
9
+ );
10
+ }
11
+
12
+ UnknownControl.propTypes = {
13
+ field: ImmutablePropTypes.map,
14
+ t: PropTypes.func.isRequired,
15
+ };
16
+
17
+ export default translate()(UnknownControl);
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { translate } from 'react-polyglot';
3
+ import ImmutablePropTypes from 'react-immutable-proptypes';
4
+ import PropTypes from 'prop-types';
5
+
6
+ function UnknownPreview({ field, t }) {
7
+ return (
8
+ <div className="nc-widgetPreview">
9
+ {t('editor.editorWidgets.unknownPreview.noPreview', { widget: field.get('widget') })}
10
+ </div>
11
+ );
12
+ }
13
+
14
+ UnknownPreview.propTypes = {
15
+ field: ImmutablePropTypes.map,
16
+ t: PropTypes.func.isRequired,
17
+ };
18
+
19
+ export default translate()(UnknownPreview);
@@ -0,0 +1,5 @@
1
+ import { registerWidget } from '../../lib/registry';
2
+ import UnknownControl from './Unknown/UnknownControl';
3
+ import UnknownPreview from './Unknown/UnknownPreview';
4
+
5
+ registerWidget('unknown', UnknownControl, UnknownPreview);
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import styled from '@emotion/styled';
4
+ import { colors } from 'decap-cms-ui-default';
5
+
6
+ const EmptyMessageContainer = styled.div`
7
+ height: 100%;
8
+ width: 100%;
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ color: ${props => props.isPrivate && colors.textFieldBorder};
13
+ `;
14
+
15
+ function EmptyMessage({ content, isPrivate }) {
16
+ return (
17
+ <EmptyMessageContainer isPrivate={isPrivate}>
18
+ <h1>{content}</h1>
19
+ </EmptyMessageContainer>
20
+ );
21
+ }
22
+
23
+ EmptyMessage.propTypes = {
24
+ content: PropTypes.string.isRequired,
25
+ isPrivate: PropTypes.bool,
26
+ };
27
+
28
+ export default EmptyMessage;
@@ -0,0 +1,411 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import ImmutablePropTypes from 'react-immutable-proptypes';
4
+ import { connect } from 'react-redux';
5
+ import orderBy from 'lodash/orderBy';
6
+ import map from 'lodash/map';
7
+ import { translate } from 'react-polyglot';
8
+ import fuzzy from 'fuzzy';
9
+ import { fileExtension } from 'decap-cms-lib-util';
10
+
11
+ import {
12
+ loadMedia as loadMediaAction,
13
+ persistMedia as persistMediaAction,
14
+ deleteMedia as deleteMediaAction,
15
+ insertMedia as insertMediaAction,
16
+ loadMediaDisplayURL as loadMediaDisplayURLAction,
17
+ closeMediaLibrary as closeMediaLibraryAction,
18
+ } from '../../actions/mediaLibrary';
19
+ import { selectMediaFiles } from '../../reducers/mediaLibrary';
20
+ import MediaLibraryModal, { fileShape } from './MediaLibraryModal';
21
+
22
+ /**
23
+ * Extensions used to determine which files to show when the media library is
24
+ * accessed from an image insertion field.
25
+ */
26
+ const IMAGE_EXTENSIONS_VIEWABLE = [
27
+ 'jpg',
28
+ 'jpeg',
29
+ 'webp',
30
+ 'gif',
31
+ 'png',
32
+ 'bmp',
33
+ 'tiff',
34
+ 'svg',
35
+ 'avif',
36
+ ];
37
+ const IMAGE_EXTENSIONS = [...IMAGE_EXTENSIONS_VIEWABLE];
38
+
39
+ class MediaLibrary extends React.Component {
40
+ static propTypes = {
41
+ isVisible: PropTypes.bool,
42
+ loadMediaDisplayURL: PropTypes.func,
43
+ displayURLs: ImmutablePropTypes.map,
44
+ canInsert: PropTypes.bool,
45
+ files: PropTypes.arrayOf(PropTypes.shape(fileShape)).isRequired,
46
+ dynamicSearch: PropTypes.bool,
47
+ dynamicSearchActive: PropTypes.bool,
48
+ forImage: PropTypes.bool,
49
+ isLoading: PropTypes.bool,
50
+ isPersisting: PropTypes.bool,
51
+ isDeleting: PropTypes.bool,
52
+ hasNextPage: PropTypes.bool,
53
+ isPaginating: PropTypes.bool,
54
+ privateUpload: PropTypes.bool,
55
+ config: ImmutablePropTypes.map,
56
+ loadMedia: PropTypes.func.isRequired,
57
+ dynamicSearchQuery: PropTypes.string,
58
+ page: PropTypes.number,
59
+ persistMedia: PropTypes.func.isRequired,
60
+ deleteMedia: PropTypes.func.isRequired,
61
+ insertMedia: PropTypes.func.isRequired,
62
+ closeMediaLibrary: PropTypes.func.isRequired,
63
+ t: PropTypes.func.isRequired,
64
+ };
65
+
66
+ static defaultProps = {
67
+ files: [],
68
+ };
69
+
70
+ /**
71
+ * The currently selected file and query are tracked in component state as
72
+ * they do not impact the rest of the application.
73
+ */
74
+ state = {
75
+ selectedFile: {},
76
+ query: '',
77
+ isPersisted: false,
78
+ };
79
+
80
+ componentDidMount() {
81
+ // Manually validate PropTypes - React 19 breaking change
82
+ PropTypes.checkPropTypes(MediaLibrary.propTypes, this.props, 'prop', 'MediaLibrary');
83
+
84
+ this.props.loadMedia();
85
+ }
86
+
87
+ UNSAFE_componentWillReceiveProps(nextProps) {
88
+ /**
89
+ * We clear old state from the media library when it's being re-opened
90
+ * because, when doing so on close, the state is cleared while the media
91
+ * library is still fading away.
92
+ */
93
+ const isOpening = !this.props.isVisible && nextProps.isVisible;
94
+ if (isOpening) {
95
+ this.setState({ selectedFile: {}, query: '' });
96
+ }
97
+
98
+ if (this.state.isPersisted) {
99
+ this.setState({
100
+ selectedFile: nextProps.files[0],
101
+ isPersisted: false,
102
+ });
103
+ }
104
+ }
105
+
106
+ componentDidUpdate(prevProps) {
107
+ const isOpening = !prevProps.isVisible && this.props.isVisible;
108
+
109
+ if (isOpening && prevProps.privateUpload !== this.props.privateUpload) {
110
+ this.props.loadMedia({ privateUpload: this.props.privateUpload });
111
+ }
112
+
113
+ if (this.state.isPersisted) {
114
+ this.setState({
115
+ selectedFile: this.props.files[0],
116
+ isPersisted: false,
117
+ });
118
+ }
119
+ }
120
+
121
+ loadDisplayURL = file => {
122
+ const { loadMediaDisplayURL } = this.props;
123
+ loadMediaDisplayURL(file);
124
+ };
125
+
126
+ /**
127
+ * Filter an array of file data to include only images.
128
+ */
129
+ filterImages = files => {
130
+ return files.filter(file => {
131
+ const ext = fileExtension(file.name).toLowerCase();
132
+ return IMAGE_EXTENSIONS.includes(ext);
133
+ });
134
+ };
135
+
136
+ /**
137
+ * Transform file data for table display.
138
+ */
139
+ toTableData = files => {
140
+ const tableData =
141
+ files &&
142
+ files.map(({ key, name, id, size, path, queryOrder, displayURL, draft }) => {
143
+ const ext = fileExtension(name).toLowerCase();
144
+ return {
145
+ key,
146
+ id,
147
+ name,
148
+ path,
149
+ type: ext.toUpperCase(),
150
+ size,
151
+ queryOrder,
152
+ displayURL,
153
+ draft,
154
+ isImage: IMAGE_EXTENSIONS.includes(ext),
155
+ isViewableImage: IMAGE_EXTENSIONS_VIEWABLE.includes(ext),
156
+ };
157
+ });
158
+
159
+ /**
160
+ * Get the sort order for use with `lodash.orderBy`, and always add the
161
+ * `queryOrder` sort as the lowest priority sort order.
162
+ */
163
+ const { sortFields } = this.state;
164
+ const fieldNames = map(sortFields, 'fieldName').concat('queryOrder');
165
+ const directions = map(sortFields, 'direction').concat('asc');
166
+ return orderBy(tableData, fieldNames, directions);
167
+ };
168
+
169
+ handleClose = () => {
170
+ this.props.closeMediaLibrary();
171
+ };
172
+
173
+ /**
174
+ * Toggle asset selection on click.
175
+ */
176
+ handleAssetClick = asset => {
177
+ const selectedFile = this.state.selectedFile.key === asset.key ? {} : asset;
178
+ this.setState({ selectedFile });
179
+ };
180
+
181
+ /**
182
+ * Upload a file.
183
+ */
184
+ handlePersist = async event => {
185
+ /**
186
+ * Stop the browser from automatically handling the file input click, and
187
+ * get the file for upload, and retain the synthetic event for access after
188
+ * the asynchronous persist operation.
189
+ */
190
+ event.persist();
191
+ event.stopPropagation();
192
+ event.preventDefault();
193
+ const { persistMedia, privateUpload, config, t, field } = this.props;
194
+ const { files: fileList } = event.dataTransfer || event.target;
195
+ const files = [...fileList];
196
+ const file = files[0];
197
+ const maxFileSize = config.get('max_file_size');
198
+
199
+ if (maxFileSize && file.size > maxFileSize) {
200
+ window.alert(
201
+ t('mediaLibrary.mediaLibrary.fileTooLarge', {
202
+ size: Math.floor(maxFileSize / 1000),
203
+ }),
204
+ );
205
+ } else {
206
+ await persistMedia(file, { privateUpload, field });
207
+
208
+ this.setState({ isPersisted: true });
209
+
210
+ this.scrollToTop();
211
+ }
212
+
213
+ event.target.value = null;
214
+ };
215
+
216
+ /**
217
+ * Stores the public path of the file in the application store, where the
218
+ * editor field that launched the media library can retrieve it.
219
+ */
220
+ handleInsert = () => {
221
+ const { selectedFile } = this.state;
222
+ const { path } = selectedFile;
223
+ const { insertMedia, field } = this.props;
224
+ insertMedia(path, field);
225
+ this.handleClose();
226
+ };
227
+
228
+ /**
229
+ * Removes the selected file from the backend.
230
+ */
231
+ handleDelete = () => {
232
+ const { selectedFile } = this.state;
233
+ const { files, deleteMedia, privateUpload, t } = this.props;
234
+ if (!window.confirm(t('mediaLibrary.mediaLibrary.onDelete'))) {
235
+ return;
236
+ }
237
+ const file = files.find(file => selectedFile.key === file.key);
238
+ deleteMedia(file, { privateUpload }).then(() => {
239
+ this.setState({ selectedFile: {} });
240
+ });
241
+ };
242
+
243
+ /**
244
+ * Downloads the selected file.
245
+ */
246
+ handleDownload = () => {
247
+ const { selectedFile } = this.state;
248
+ const { displayURLs } = this.props;
249
+ const url = displayURLs.getIn([selectedFile.id, 'url']) || selectedFile.url;
250
+ if (!url) {
251
+ return;
252
+ }
253
+
254
+ const filename = selectedFile.name;
255
+
256
+ const element = document.createElement('a');
257
+ element.setAttribute('href', url);
258
+ element.setAttribute('download', filename);
259
+
260
+ element.style.display = 'none';
261
+ document.body.appendChild(element);
262
+
263
+ element.click();
264
+
265
+ document.body.removeChild(element);
266
+ this.setState({ selectedFile: {} });
267
+ };
268
+
269
+ /**
270
+ *
271
+ */
272
+
273
+ handleLoadMore = () => {
274
+ const { loadMedia, dynamicSearchQuery, page, privateUpload } = this.props;
275
+ loadMedia({ query: dynamicSearchQuery, page: page + 1, privateUpload });
276
+ };
277
+
278
+ /**
279
+ * Executes media library search for implementations that support dynamic
280
+ * search via request. For these implementations, the Enter key must be
281
+ * pressed to execute search. If assets are being stored directly through
282
+ * the GitHub backend, search is in-memory and occurs as the query is typed,
283
+ * so this handler has no impact.
284
+ */
285
+ handleSearchKeyDown = async event => {
286
+ const { dynamicSearch, loadMedia, privateUpload } = this.props;
287
+ if (event.key === 'Enter' && dynamicSearch) {
288
+ await loadMedia({ query: this.state.query, privateUpload });
289
+ this.scrollToTop();
290
+ }
291
+ };
292
+
293
+ scrollToTop = () => {
294
+ this.scrollContainerRef.scrollTop = 0;
295
+ };
296
+
297
+ /**
298
+ * Updates query state as the user types in the search field.
299
+ */
300
+ handleSearchChange = event => {
301
+ this.setState({ query: event.target.value });
302
+ };
303
+
304
+ /**
305
+ * Filters files that do not match the query. Not used for dynamic search.
306
+ */
307
+ queryFilter = (query, files) => {
308
+ /**
309
+ * Because file names don't have spaces, typing a space eliminates all
310
+ * potential matches, so we strip them all out internally before running the
311
+ * query.
312
+ */
313
+ const strippedQuery = query.replace(/ /g, '');
314
+ const matches = fuzzy.filter(strippedQuery, files, { extract: file => file.name });
315
+ const matchFiles = matches.map((match, queryIndex) => {
316
+ const file = files[match.index];
317
+ return { ...file, queryIndex };
318
+ });
319
+ return matchFiles;
320
+ };
321
+
322
+ render() {
323
+ const {
324
+ isVisible,
325
+ canInsert,
326
+ files,
327
+ dynamicSearch,
328
+ dynamicSearchActive,
329
+ forImage,
330
+ isLoading,
331
+ isPersisting,
332
+ isDeleting,
333
+ hasNextPage,
334
+ isPaginating,
335
+ privateUpload,
336
+ displayURLs,
337
+ t,
338
+ } = this.props;
339
+
340
+ return (
341
+ <MediaLibraryModal
342
+ isVisible={isVisible}
343
+ canInsert={canInsert}
344
+ files={files}
345
+ dynamicSearch={dynamicSearch}
346
+ dynamicSearchActive={dynamicSearchActive}
347
+ forImage={forImage}
348
+ isLoading={isLoading}
349
+ isPersisting={isPersisting}
350
+ isDeleting={isDeleting}
351
+ hasNextPage={hasNextPage}
352
+ isPaginating={isPaginating}
353
+ privateUpload={privateUpload}
354
+ query={this.state.query}
355
+ selectedFile={this.state.selectedFile}
356
+ handleFilter={this.filterImages}
357
+ handleQuery={this.queryFilter}
358
+ toTableData={this.toTableData}
359
+ handleClose={this.handleClose}
360
+ handleSearchChange={this.handleSearchChange}
361
+ handleSearchKeyDown={this.handleSearchKeyDown}
362
+ handlePersist={this.handlePersist}
363
+ handleDelete={this.handleDelete}
364
+ handleInsert={this.handleInsert}
365
+ handleDownload={this.handleDownload}
366
+ setScrollContainerRef={ref => (this.scrollContainerRef = ref)}
367
+ handleAssetClick={this.handleAssetClick}
368
+ handleLoadMore={this.handleLoadMore}
369
+ displayURLs={displayURLs}
370
+ loadDisplayURL={this.loadDisplayURL}
371
+ t={t}
372
+ />
373
+ );
374
+ }
375
+ }
376
+
377
+ function mapStateToProps(state) {
378
+ const { mediaLibrary } = state;
379
+ const field = mediaLibrary.get('field');
380
+ const mediaLibraryProps = {
381
+ isVisible: mediaLibrary.get('isVisible'),
382
+ canInsert: mediaLibrary.get('canInsert'),
383
+ files: selectMediaFiles(state, field),
384
+ displayURLs: mediaLibrary.get('displayURLs'),
385
+ dynamicSearch: mediaLibrary.get('dynamicSearch'),
386
+ dynamicSearchActive: mediaLibrary.get('dynamicSearchActive'),
387
+ dynamicSearchQuery: mediaLibrary.get('dynamicSearchQuery'),
388
+ forImage: mediaLibrary.get('forImage'),
389
+ isLoading: mediaLibrary.get('isLoading'),
390
+ isPersisting: mediaLibrary.get('isPersisting'),
391
+ isDeleting: mediaLibrary.get('isDeleting'),
392
+ privateUpload: mediaLibrary.get('privateUpload'),
393
+ config: mediaLibrary.get('config'),
394
+ page: mediaLibrary.get('page'),
395
+ hasNextPage: mediaLibrary.get('hasNextPage'),
396
+ isPaginating: mediaLibrary.get('isPaginating'),
397
+ field,
398
+ };
399
+ return { ...mediaLibraryProps };
400
+ }
401
+
402
+ const mapDispatchToProps = {
403
+ loadMedia: loadMediaAction,
404
+ persistMedia: persistMediaAction,
405
+ deleteMedia: deleteMediaAction,
406
+ insertMedia: insertMediaAction,
407
+ loadMediaDisplayURL: loadMediaDisplayURLAction,
408
+ closeMediaLibrary: closeMediaLibraryAction,
409
+ };
410
+
411
+ export default connect(mapStateToProps, mapDispatchToProps)(translate()(MediaLibrary));
@@ -0,0 +1,136 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { css } from '@emotion/react';
4
+ import styled from '@emotion/styled';
5
+ import copyToClipboard from 'copy-text-to-clipboard';
6
+ import { isAbsolutePath } from 'decap-cms-lib-util';
7
+ import { buttons, shadows, zIndex } from 'decap-cms-ui-default';
8
+
9
+ import { FileUploadButton } from '../UI';
10
+
11
+ const styles = {
12
+ button: css`
13
+ ${buttons.button};
14
+ ${buttons.default};
15
+ display: inline-block;
16
+ margin-left: 15px;
17
+ margin-right: 2px;
18
+
19
+ &[disabled] {
20
+ ${buttons.disabled};
21
+ cursor: default;
22
+ }
23
+ `,
24
+ };
25
+
26
+ export const UploadButton = styled(FileUploadButton)`
27
+ ${styles.button};
28
+ ${buttons.gray};
29
+ ${shadows.dropMain};
30
+ margin-bottom: 0;
31
+
32
+ span {
33
+ font-size: 14px;
34
+ font-weight: 500;
35
+ display: flex;
36
+ justify-content: center;
37
+ align-items: center;
38
+ }
39
+
40
+ input {
41
+ height: 0.1px;
42
+ width: 0.1px;
43
+ margin: 0;
44
+ padding: 0;
45
+ opacity: 0;
46
+ overflow: hidden;
47
+ position: absolute;
48
+ z-index: ${zIndex.zIndex0};
49
+ outline: none;
50
+ }
51
+ `;
52
+
53
+ export const DeleteButton = styled.button`
54
+ ${styles.button};
55
+ ${buttons.lightRed};
56
+ `;
57
+
58
+ export const InsertButton = styled.button`
59
+ ${styles.button};
60
+ ${buttons.green};
61
+ `;
62
+
63
+ const ActionButton = styled.button`
64
+ ${styles.button};
65
+ ${props =>
66
+ !props.disabled &&
67
+ css`
68
+ ${buttons.gray}
69
+ `}
70
+ `;
71
+
72
+ export const DownloadButton = ActionButton;
73
+
74
+ export class CopyToClipBoardButton extends React.Component {
75
+ mounted = false;
76
+ timeout;
77
+
78
+ state = {
79
+ copied: false,
80
+ };
81
+
82
+ componentDidMount() {
83
+ this.mounted = true;
84
+ }
85
+
86
+ componentWillUnmount() {
87
+ this.mounted = false;
88
+ }
89
+
90
+ handleCopy = () => {
91
+ clearTimeout(this.timeout);
92
+ const { path, draft, name } = this.props;
93
+ copyToClipboard(isAbsolutePath(path) || !draft ? path : name);
94
+ this.setState({ copied: true });
95
+ this.timeout = setTimeout(() => this.mounted && this.setState({ copied: false }), 1500);
96
+ };
97
+
98
+ getTitle = () => {
99
+ const { t, path, draft } = this.props;
100
+ if (this.state.copied) {
101
+ return t('mediaLibrary.mediaLibraryCard.copied');
102
+ }
103
+
104
+ if (!path) {
105
+ return t('mediaLibrary.mediaLibraryCard.copy');
106
+ }
107
+
108
+ if (isAbsolutePath(path)) {
109
+ return t('mediaLibrary.mediaLibraryCard.copyUrl');
110
+ }
111
+
112
+ if (draft) {
113
+ return t('mediaLibrary.mediaLibraryCard.copyName');
114
+ }
115
+
116
+ return t('mediaLibrary.mediaLibraryCard.copyPath');
117
+ };
118
+
119
+ render() {
120
+ const { disabled } = this.props;
121
+
122
+ return (
123
+ <ActionButton disabled={disabled} onClick={this.handleCopy}>
124
+ {this.getTitle()}
125
+ </ActionButton>
126
+ );
127
+ }
128
+ }
129
+
130
+ CopyToClipBoardButton.propTypes = {
131
+ disabled: PropTypes.bool.isRequired,
132
+ draft: PropTypes.bool,
133
+ path: PropTypes.string,
134
+ name: PropTypes.string,
135
+ t: PropTypes.func.isRequired,
136
+ };