decap-cms-core 2.56.0-beta.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 (290) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +9 -0
  3. package/dist/decap-cms-core.js +47 -0
  4. package/dist/decap-cms-core.js.LICENSE.txt +109 -0
  5. package/dist/decap-cms-core.js.map +1 -0
  6. package/dist/esm/actions/auth.js +118 -0
  7. package/dist/esm/actions/collections.js +23 -0
  8. package/dist/esm/actions/config.js +482 -0
  9. package/dist/esm/actions/deploys.js +89 -0
  10. package/dist/esm/actions/editorialWorkflow.js +511 -0
  11. package/dist/esm/actions/entries.js +940 -0
  12. package/dist/esm/actions/media.js +168 -0
  13. package/dist/esm/actions/mediaLibrary.js +606 -0
  14. package/dist/esm/actions/notifications.js +32 -0
  15. package/dist/esm/actions/search.js +156 -0
  16. package/dist/esm/actions/status.js +93 -0
  17. package/dist/esm/actions/waitUntil.js +39 -0
  18. package/dist/esm/backend.js +1073 -0
  19. package/dist/esm/bootstrap.js +107 -0
  20. package/dist/esm/components/App/App.js +301 -0
  21. package/dist/esm/components/App/Header.js +162 -0
  22. package/dist/esm/components/App/NotFoundPage.js +27 -0
  23. package/dist/esm/components/Collection/Collection.js +210 -0
  24. package/dist/esm/components/Collection/CollectionControls.js +54 -0
  25. package/dist/esm/components/Collection/CollectionSearch.js +235 -0
  26. package/dist/esm/components/Collection/CollectionTop.js +77 -0
  27. package/dist/esm/components/Collection/ControlButton.js +23 -0
  28. package/dist/esm/components/Collection/Entries/Entries.js +74 -0
  29. package/dist/esm/components/Collection/Entries/EntriesCollection.js +193 -0
  30. package/dist/esm/components/Collection/Entries/EntriesSearch.js +117 -0
  31. package/dist/esm/components/Collection/Entries/EntryCard.js +134 -0
  32. package/dist/esm/components/Collection/Entries/EntryListing.js +120 -0
  33. package/dist/esm/components/Collection/FilterControl.js +41 -0
  34. package/dist/esm/components/Collection/GroupControl.js +41 -0
  35. package/dist/esm/components/Collection/NestedCollection.js +311 -0
  36. package/dist/esm/components/Collection/Sidebar.js +102 -0
  37. package/dist/esm/components/Collection/SortControl.js +67 -0
  38. package/dist/esm/components/Collection/ViewStyleControl.js +47 -0
  39. package/dist/esm/components/Editor/Editor.js +479 -0
  40. package/dist/esm/components/Editor/EditorControlPane/EditorControl.js +393 -0
  41. package/dist/esm/components/Editor/EditorControlPane/EditorControlPane.js +259 -0
  42. package/dist/esm/components/Editor/EditorControlPane/Widget.js +355 -0
  43. package/dist/esm/components/Editor/EditorInterface.js +401 -0
  44. package/dist/esm/components/Editor/EditorPreviewPane/EditorPreview.js +56 -0
  45. package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewContent.js +34 -0
  46. package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewPane.js +252 -0
  47. package/dist/esm/components/Editor/EditorPreviewPane/PreviewHOC.js +39 -0
  48. package/dist/esm/components/Editor/EditorToolbar.js +551 -0
  49. package/dist/esm/components/Editor/withWorkflow.js +64 -0
  50. package/dist/esm/components/EditorWidgets/Unknown/UnknownControl.js +26 -0
  51. package/dist/esm/components/EditorWidgets/Unknown/UnknownPreview.js +28 -0
  52. package/dist/esm/components/EditorWidgets/index.js +7 -0
  53. package/dist/esm/components/MediaLibrary/EmptyMessage.js +30 -0
  54. package/dist/esm/components/MediaLibrary/MediaLibrary.js +444 -0
  55. package/dist/esm/components/MediaLibrary/MediaLibraryButtons.js +110 -0
  56. package/dist/esm/components/MediaLibrary/MediaLibraryCard.js +108 -0
  57. package/dist/esm/components/MediaLibrary/MediaLibraryCardGrid.js +211 -0
  58. package/dist/esm/components/MediaLibrary/MediaLibraryHeader.js +40 -0
  59. package/dist/esm/components/MediaLibrary/MediaLibraryModal.js +163 -0
  60. package/dist/esm/components/MediaLibrary/MediaLibrarySearch.js +60 -0
  61. package/dist/esm/components/MediaLibrary/MediaLibraryTop.js +134 -0
  62. package/dist/esm/components/UI/DragDrop.js +84 -0
  63. package/dist/esm/components/UI/ErrorBoundary.js +184 -0
  64. package/dist/esm/components/UI/FileUploadButton.js +34 -0
  65. package/dist/esm/components/UI/Modal.js +113 -0
  66. package/dist/esm/components/UI/Notifications.js +74 -0
  67. package/dist/esm/components/UI/SettingsDropdown.js +118 -0
  68. package/dist/esm/components/UI/index.js +60 -0
  69. package/dist/esm/components/Workflow/Workflow.js +144 -0
  70. package/dist/esm/components/Workflow/WorkflowCard.js +137 -0
  71. package/dist/esm/components/Workflow/WorkflowList.js +219 -0
  72. package/dist/esm/constants/collectionTypes.js +10 -0
  73. package/dist/esm/constants/collectionViews.js +10 -0
  74. package/dist/esm/constants/commitProps.js +10 -0
  75. package/dist/esm/constants/configSchema.js +594 -0
  76. package/dist/esm/constants/fieldInference.js +67 -0
  77. package/dist/esm/constants/publishModes.js +28 -0
  78. package/dist/esm/constants/validationErrorTypes.js +13 -0
  79. package/dist/esm/formats/formats.js +82 -0
  80. package/dist/esm/formats/frontmatter.js +163 -0
  81. package/dist/esm/formats/helpers.js +18 -0
  82. package/dist/esm/formats/json.js +15 -0
  83. package/dist/esm/formats/toml.js +40 -0
  84. package/dist/esm/formats/yaml.js +63 -0
  85. package/dist/esm/index.js +20 -0
  86. package/dist/esm/integrations/index.js +37 -0
  87. package/dist/esm/integrations/providers/algolia/implementation.js +184 -0
  88. package/dist/esm/integrations/providers/assetStore/implementation.js +175 -0
  89. package/dist/esm/lib/consoleError.js +9 -0
  90. package/dist/esm/lib/formatters.js +204 -0
  91. package/dist/esm/lib/i18n.js +381 -0
  92. package/dist/esm/lib/phrases.js +13 -0
  93. package/dist/esm/lib/registry.js +322 -0
  94. package/dist/esm/lib/serializeEntryValues.js +74 -0
  95. package/dist/esm/lib/textHelper.js +15 -0
  96. package/dist/esm/lib/urlHelper.js +128 -0
  97. package/dist/esm/mediaLibrary.js +42 -0
  98. package/dist/esm/reducers/auth.js +35 -0
  99. package/dist/esm/reducers/collections.js +424 -0
  100. package/dist/esm/reducers/combinedReducer.js +19 -0
  101. package/dist/esm/reducers/config.js +42 -0
  102. package/dist/esm/reducers/cursors.js +38 -0
  103. package/dist/esm/reducers/deploys.js +53 -0
  104. package/dist/esm/reducers/editorialWorkflow.js +98 -0
  105. package/dist/esm/reducers/entries.js +591 -0
  106. package/dist/esm/reducers/entryDraft.js +184 -0
  107. package/dist/esm/reducers/globalUI.js +32 -0
  108. package/dist/esm/reducers/index.js +84 -0
  109. package/dist/esm/reducers/integrations.js +68 -0
  110. package/dist/esm/reducers/mediaLibrary.js +265 -0
  111. package/dist/esm/reducers/medias.js +76 -0
  112. package/dist/esm/reducers/notifications.js +36 -0
  113. package/dist/esm/reducers/search.js +89 -0
  114. package/dist/esm/reducers/status.js +37 -0
  115. package/dist/esm/redux/index.js +14 -0
  116. package/dist/esm/redux/middleware/waitUntilAction.js +56 -0
  117. package/dist/esm/routing/history.js +21 -0
  118. package/dist/esm/types/diacritics.d.js +1 -0
  119. package/dist/esm/types/global.d.js +5 -0
  120. package/dist/esm/types/immutable.js +5 -0
  121. package/dist/esm/types/redux.js +16 -0
  122. package/dist/esm/types/tomlify-j0.4.d.js +1 -0
  123. package/dist/esm/valueObjects/AssetProxy.js +60 -0
  124. package/dist/esm/valueObjects/EditorComponent.js +48 -0
  125. package/dist/esm/valueObjects/Entry.js +27 -0
  126. package/index.d.ts +587 -0
  127. package/package.json +102 -0
  128. package/src/__tests__/backend.spec.js +934 -0
  129. package/src/actions/__tests__/config.spec.js +1009 -0
  130. package/src/actions/__tests__/editorialWorkflow.spec.js +216 -0
  131. package/src/actions/__tests__/entries.spec.js +575 -0
  132. package/src/actions/__tests__/media.spec.ts +171 -0
  133. package/src/actions/__tests__/mediaLibrary.spec.js +327 -0
  134. package/src/actions/__tests__/search.spec.js +209 -0
  135. package/src/actions/auth.ts +127 -0
  136. package/src/actions/collections.ts +18 -0
  137. package/src/actions/config.ts +538 -0
  138. package/src/actions/deploys.ts +104 -0
  139. package/src/actions/editorialWorkflow.ts +567 -0
  140. package/src/actions/entries.ts +1041 -0
  141. package/src/actions/media.ts +139 -0
  142. package/src/actions/mediaLibrary.ts +574 -0
  143. package/src/actions/notifications.ts +36 -0
  144. package/src/actions/search.ts +194 -0
  145. package/src/actions/status.ts +99 -0
  146. package/src/actions/waitUntil.ts +49 -0
  147. package/src/backend.ts +1342 -0
  148. package/src/bootstrap.js +102 -0
  149. package/src/components/App/App.js +280 -0
  150. package/src/components/App/Header.js +236 -0
  151. package/src/components/App/NotFoundPage.js +23 -0
  152. package/src/components/Collection/Collection.js +205 -0
  153. package/src/components/Collection/CollectionControls.js +58 -0
  154. package/src/components/Collection/CollectionSearch.js +238 -0
  155. package/src/components/Collection/CollectionTop.js +81 -0
  156. package/src/components/Collection/ControlButton.js +27 -0
  157. package/src/components/Collection/Entries/Entries.js +73 -0
  158. package/src/components/Collection/Entries/EntriesCollection.js +165 -0
  159. package/src/components/Collection/Entries/EntriesSearch.js +91 -0
  160. package/src/components/Collection/Entries/EntryCard.js +167 -0
  161. package/src/components/Collection/Entries/EntryListing.js +86 -0
  162. package/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js +155 -0
  163. package/src/components/Collection/Entries/__tests__/__snapshots__/EntriesCollection.spec.js.snap +49 -0
  164. package/src/components/Collection/FilterControl.js +39 -0
  165. package/src/components/Collection/GroupControl.js +39 -0
  166. package/src/components/Collection/NestedCollection.js +309 -0
  167. package/src/components/Collection/Sidebar.js +130 -0
  168. package/src/components/Collection/SortControl.js +68 -0
  169. package/src/components/Collection/ViewStyleControl.js +50 -0
  170. package/src/components/Collection/__tests__/Collection.spec.js +75 -0
  171. package/src/components/Collection/__tests__/NestedCollection.spec.js +442 -0
  172. package/src/components/Collection/__tests__/Sidebar.spec.js +87 -0
  173. package/src/components/Collection/__tests__/__snapshots__/Collection.spec.js.snap +144 -0
  174. package/src/components/Collection/__tests__/__snapshots__/NestedCollection.spec.js.snap +550 -0
  175. package/src/components/Collection/__tests__/__snapshots__/Sidebar.spec.js.snap +308 -0
  176. package/src/components/Editor/Editor.js +494 -0
  177. package/src/components/Editor/EditorControlPane/EditorControl.js +428 -0
  178. package/src/components/Editor/EditorControlPane/EditorControlPane.js +256 -0
  179. package/src/components/Editor/EditorControlPane/Widget.js +351 -0
  180. package/src/components/Editor/EditorInterface.js +434 -0
  181. package/src/components/Editor/EditorPreviewPane/EditorPreview.js +40 -0
  182. package/src/components/Editor/EditorPreviewPane/EditorPreviewContent.js +34 -0
  183. package/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js +278 -0
  184. package/src/components/Editor/EditorPreviewPane/PreviewHOC.js +33 -0
  185. package/src/components/Editor/EditorToolbar.js +678 -0
  186. package/src/components/Editor/__tests__/Editor.spec.js +219 -0
  187. package/src/components/Editor/__tests__/EditorToolbar.spec.js +120 -0
  188. package/src/components/Editor/__tests__/__snapshots__/Editor.spec.js.snap +45 -0
  189. package/src/components/Editor/__tests__/__snapshots__/EditorToolbar.spec.js.snap +4020 -0
  190. package/src/components/Editor/withWorkflow.js +61 -0
  191. package/src/components/EditorWidgets/Unknown/UnknownControl.js +17 -0
  192. package/src/components/EditorWidgets/Unknown/UnknownPreview.js +19 -0
  193. package/src/components/EditorWidgets/index.js +5 -0
  194. package/src/components/MediaLibrary/EmptyMessage.js +28 -0
  195. package/src/components/MediaLibrary/MediaLibrary.js +407 -0
  196. package/src/components/MediaLibrary/MediaLibraryButtons.js +136 -0
  197. package/src/components/MediaLibrary/MediaLibraryCard.js +128 -0
  198. package/src/components/MediaLibrary/MediaLibraryCardGrid.js +199 -0
  199. package/src/components/MediaLibrary/MediaLibraryHeader.js +48 -0
  200. package/src/components/MediaLibrary/MediaLibraryModal.js +200 -0
  201. package/src/components/MediaLibrary/MediaLibrarySearch.js +61 -0
  202. package/src/components/MediaLibrary/MediaLibraryTop.js +143 -0
  203. package/src/components/MediaLibrary/__tests__/MediaLibraryButtons.spec.js +45 -0
  204. package/src/components/MediaLibrary/__tests__/MediaLibraryCard.spec.js +49 -0
  205. package/src/components/MediaLibrary/__tests__/__snapshots__/MediaLibraryCard.spec.js.snap +216 -0
  206. package/src/components/UI/DragDrop.js +66 -0
  207. package/src/components/UI/ErrorBoundary.js +209 -0
  208. package/src/components/UI/FileUploadButton.js +24 -0
  209. package/src/components/UI/Modal.js +109 -0
  210. package/src/components/UI/Notifications.tsx +83 -0
  211. package/src/components/UI/SettingsDropdown.js +103 -0
  212. package/src/components/UI/__tests__/ErrorBoundary.spec.js +57 -0
  213. package/src/components/UI/index.js +6 -0
  214. package/src/components/Workflow/Workflow.js +166 -0
  215. package/src/components/Workflow/WorkflowCard.js +177 -0
  216. package/src/components/Workflow/WorkflowList.js +269 -0
  217. package/src/constants/__tests__/configSchema.spec.js +511 -0
  218. package/src/constants/collectionTypes.ts +2 -0
  219. package/src/constants/collectionViews.js +2 -0
  220. package/src/constants/commitProps.ts +2 -0
  221. package/src/constants/configSchema.js +399 -0
  222. package/src/constants/fieldInference.tsx +78 -0
  223. package/src/constants/publishModes.ts +22 -0
  224. package/src/constants/validationErrorTypes.js +6 -0
  225. package/src/formats/__tests__/frontmatter.spec.js +429 -0
  226. package/src/formats/__tests__/toml.spec.js +9 -0
  227. package/src/formats/__tests__/yaml.spec.js +162 -0
  228. package/src/formats/formats.ts +86 -0
  229. package/src/formats/frontmatter.ts +150 -0
  230. package/src/formats/helpers.ts +14 -0
  231. package/src/formats/json.ts +9 -0
  232. package/src/formats/toml.ts +33 -0
  233. package/src/formats/yaml.ts +58 -0
  234. package/src/index.js +8 -0
  235. package/src/integrations/index.js +35 -0
  236. package/src/integrations/providers/algolia/implementation.js +176 -0
  237. package/src/integrations/providers/assetStore/implementation.js +147 -0
  238. package/src/lib/__tests__/formatters.spec.js +723 -0
  239. package/src/lib/__tests__/i18n.spec.js +792 -0
  240. package/src/lib/__tests__/phrases.spec.js +119 -0
  241. package/src/lib/__tests__/registry.spec.js +246 -0
  242. package/src/lib/__tests__/serializeEntryValues.spec.js +22 -0
  243. package/src/lib/__tests__/urlHelper.spec.js +138 -0
  244. package/src/lib/consoleError.js +7 -0
  245. package/src/lib/formatters.ts +267 -0
  246. package/src/lib/i18n.ts +427 -0
  247. package/src/lib/phrases.js +8 -0
  248. package/src/lib/registry.js +282 -0
  249. package/src/lib/serializeEntryValues.js +75 -0
  250. package/src/lib/textHelper.js +11 -0
  251. package/src/lib/urlHelper.ts +125 -0
  252. package/src/mediaLibrary.ts +51 -0
  253. package/src/reducers/__tests__/auth.spec.ts +38 -0
  254. package/src/reducers/__tests__/collections.spec.js +571 -0
  255. package/src/reducers/__tests__/config.spec.js +38 -0
  256. package/src/reducers/__tests__/entries.spec.js +694 -0
  257. package/src/reducers/__tests__/entryDraft.spec.js +198 -0
  258. package/src/reducers/__tests__/globalUI.js +43 -0
  259. package/src/reducers/__tests__/integrations.spec.ts +76 -0
  260. package/src/reducers/__tests__/mediaLibrary.spec.js +154 -0
  261. package/src/reducers/__tests__/medias.spec.ts +49 -0
  262. package/src/reducers/auth.ts +46 -0
  263. package/src/reducers/collections.ts +483 -0
  264. package/src/reducers/combinedReducer.ts +11 -0
  265. package/src/reducers/config.ts +38 -0
  266. package/src/reducers/cursors.js +36 -0
  267. package/src/reducers/deploys.ts +52 -0
  268. package/src/reducers/editorialWorkflow.ts +163 -0
  269. package/src/reducers/entries.ts +806 -0
  270. package/src/reducers/entryDraft.js +218 -0
  271. package/src/reducers/globalUI.ts +45 -0
  272. package/src/reducers/index.ts +82 -0
  273. package/src/reducers/integrations.ts +59 -0
  274. package/src/reducers/mediaLibrary.ts +296 -0
  275. package/src/reducers/medias.ts +66 -0
  276. package/src/reducers/notifications.ts +53 -0
  277. package/src/reducers/search.ts +89 -0
  278. package/src/reducers/status.ts +40 -0
  279. package/src/redux/index.ts +18 -0
  280. package/src/redux/middleware/waitUntilAction.ts +64 -0
  281. package/src/routing/__tests__/history.spec.ts +49 -0
  282. package/src/routing/history.ts +17 -0
  283. package/src/types/diacritics.d.ts +1 -0
  284. package/src/types/global.d.ts +8 -0
  285. package/src/types/immutable.ts +39 -0
  286. package/src/types/redux.ts +810 -0
  287. package/src/types/tomlify-j0.4.d.ts +13 -0
  288. package/src/valueObjects/AssetProxy.ts +48 -0
  289. package/src/valueObjects/EditorComponent.js +38 -0
  290. package/src/valueObjects/Entry.ts +63 -0
@@ -0,0 +1,49 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`EntriesCollection should render apply filter term for nested collections 1`] = `
4
+ <DocumentFragment>
5
+ <mock-entries
6
+ collectionname="Pages"
7
+ collections="Map { \\"name\\": \\"pages\\", \\"label\\": \\"Pages\\", \\"folder\\": \\"src/pages\\", \\"nested\\": Map { \\"depth\\": 10 } }"
8
+ cursor="[object Object]"
9
+ entries="List []"
10
+ isfetching="false"
11
+ />
12
+ </DocumentFragment>
13
+ `;
14
+
15
+ exports[`EntriesCollection should render connected component 1`] = `
16
+ <DocumentFragment>
17
+ <mock-entries
18
+ collectionname="Pages"
19
+ collections="Map { \\"name\\": \\"pages\\", \\"label\\": \\"Pages\\", \\"folder\\": \\"src/pages\\" }"
20
+ cursor="[object Object]"
21
+ entries="List [ Map { \\"slug\\": \\"index\\", \\"path\\": \\"src/pages/index.md\\", \\"data\\": Map { \\"title\\": \\"Root\\" } }, Map { \\"slug\\": \\"dir1/index\\", \\"path\\": \\"src/pages/dir1/index.md\\", \\"data\\": Map { \\"title\\": \\"File 1\\" } }, Map { \\"slug\\": \\"dir2/index\\", \\"path\\": \\"src/pages/dir2/index.md\\", \\"data\\": Map { \\"title\\": \\"File 2\\" } } ]"
22
+ isfetching="false"
23
+ />
24
+ </DocumentFragment>
25
+ `;
26
+
27
+ exports[`EntriesCollection should render show only immediate children for nested collection 1`] = `
28
+ <DocumentFragment>
29
+ <mock-entries
30
+ collectionname="Pages"
31
+ collections="Map { \\"name\\": \\"pages\\", \\"label\\": \\"Pages\\", \\"folder\\": \\"src/pages\\", \\"nested\\": Map { \\"depth\\": 10 } }"
32
+ cursor="[object Object]"
33
+ entries="List [ Map { \\"slug\\": \\"index\\", \\"path\\": \\"src/pages/index.md\\", \\"data\\": Map { \\"title\\": \\"Root\\" } }, Map { \\"slug\\": \\"dir1/index\\", \\"path\\": \\"src/pages/dir1/index.md\\", \\"data\\": Map { \\"title\\": \\"File 1\\" } }, Map { \\"slug\\": \\"dir3/index\\", \\"path\\": \\"src/pages/dir3/index.md\\", \\"data\\": Map { \\"title\\": \\"File 3\\" } } ]"
34
+ isfetching="false"
35
+ />
36
+ </DocumentFragment>
37
+ `;
38
+
39
+ exports[`EntriesCollection should render with entries 1`] = `
40
+ <DocumentFragment>
41
+ <mock-entries
42
+ collectionname="Pages"
43
+ collections="Map { \\"name\\": \\"pages\\", \\"label\\": \\"Pages\\", \\"folder\\": \\"src/pages\\" }"
44
+ cursor="[object Object]"
45
+ entries="List [ Map { \\"slug\\": \\"index\\" } ]"
46
+ isfetching="false"
47
+ />
48
+ </DocumentFragment>
49
+ `;
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import { translate } from 'react-polyglot';
3
+ import { Dropdown, DropdownCheckedItem } from 'decap-cms-ui-default';
4
+
5
+ import { ControlButton } from './ControlButton';
6
+
7
+ function FilterControl({ viewFilters, t, onFilterClick, filter }) {
8
+ const hasActiveFilter = filter
9
+ ?.valueSeq()
10
+ .toJS()
11
+ .some(f => f.active === true);
12
+
13
+ return (
14
+ <Dropdown
15
+ renderButton={() => {
16
+ return (
17
+ <ControlButton active={hasActiveFilter} title={t('collection.collectionTop.filterBy')} />
18
+ );
19
+ }}
20
+ closeOnSelection={false}
21
+ dropdownTopOverlap="30px"
22
+ dropdownPosition="left"
23
+ >
24
+ {viewFilters.map(viewFilter => {
25
+ return (
26
+ <DropdownCheckedItem
27
+ key={viewFilter.id}
28
+ label={viewFilter.label}
29
+ id={viewFilter.id}
30
+ checked={filter.getIn([viewFilter.id, 'active'], false)}
31
+ onClick={() => onFilterClick(viewFilter)}
32
+ />
33
+ );
34
+ })}
35
+ </Dropdown>
36
+ );
37
+ }
38
+
39
+ export default translate()(FilterControl);
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import { translate } from 'react-polyglot';
3
+ import { Dropdown, DropdownItem } from 'decap-cms-ui-default';
4
+
5
+ import { ControlButton } from './ControlButton';
6
+
7
+ function GroupControl({ viewGroups, t, onGroupClick, group }) {
8
+ const hasActiveGroup = group
9
+ ?.valueSeq()
10
+ .toJS()
11
+ .some(f => f.active === true);
12
+
13
+ return (
14
+ <Dropdown
15
+ renderButton={() => {
16
+ return (
17
+ <ControlButton active={hasActiveGroup} title={t('collection.collectionTop.groupBy')} />
18
+ );
19
+ }}
20
+ closeOnSelection={false}
21
+ dropdownTopOverlap="30px"
22
+ dropdownWidth="160px"
23
+ dropdownPosition="left"
24
+ >
25
+ {viewGroups.map(viewGroup => {
26
+ return (
27
+ <DropdownItem
28
+ key={viewGroup.id}
29
+ label={viewGroup.label}
30
+ onClick={() => onGroupClick(viewGroup)}
31
+ isActive={group.getIn([viewGroup.id, 'active'], false)}
32
+ />
33
+ );
34
+ })}
35
+ </Dropdown>
36
+ );
37
+ }
38
+
39
+ export default translate()(GroupControl);
@@ -0,0 +1,309 @@
1
+ import React from 'react';
2
+ import { List } from 'immutable';
3
+ import { css } from '@emotion/core';
4
+ import styled from '@emotion/styled';
5
+ import { connect } from 'react-redux';
6
+ import { NavLink } from 'react-router-dom';
7
+ import { dirname, sep } from 'path';
8
+ import { stringTemplate } from 'decap-cms-lib-widgets';
9
+ import { Icon, colors, components } from 'decap-cms-ui-default';
10
+ import PropTypes from 'prop-types';
11
+ import ImmutablePropTypes from 'react-immutable-proptypes';
12
+ import { sortBy } from 'lodash';
13
+
14
+ import { selectEntries } from '../../reducers/entries';
15
+ import { selectEntryCollectionTitle } from '../../reducers/collections';
16
+
17
+ const { addFileTemplateFields } = stringTemplate;
18
+
19
+ const NodeTitleContainer = styled.div`
20
+ display: flex;
21
+ justify-content: center;
22
+ align-items: center;
23
+ `;
24
+
25
+ const NodeTitle = styled.div`
26
+ margin-right: 4px;
27
+ `;
28
+
29
+ const Caret = styled.div`
30
+ position: relative;
31
+ top: 2px;
32
+ `;
33
+
34
+ const CaretDown = styled(Caret)`
35
+ ${components.caretDown};
36
+ color: currentColor;
37
+ `;
38
+
39
+ const CaretRight = styled(Caret)`
40
+ ${components.caretRight};
41
+ color: currentColor;
42
+ left: 2px;
43
+ `;
44
+
45
+ const TreeNavLink = styled(NavLink)`
46
+ display: flex;
47
+ font-size: 14px;
48
+ font-weight: 500;
49
+ align-items: center;
50
+ padding: 8px;
51
+ padding-left: ${props => props.depth * 20 + 12}px;
52
+ border-left: 2px solid #fff;
53
+
54
+ ${Icon} {
55
+ margin-right: 8px;
56
+ flex-shrink: 0;
57
+ }
58
+
59
+ ${props => css`
60
+ &:hover,
61
+ &:active,
62
+ &.${props.activeClassName} {
63
+ color: ${colors.active};
64
+ background-color: ${colors.activeBackground};
65
+ border-left-color: #4863c6;
66
+ }
67
+ `};
68
+ `;
69
+
70
+ function getNodeTitle(node) {
71
+ const title = node.isRoot
72
+ ? node.title
73
+ : node.children.find(c => !c.isDir && c.title)?.title || node.title;
74
+ return title;
75
+ }
76
+
77
+ function TreeNode(props) {
78
+ const { collection, treeData, depth = 0, onToggle } = props;
79
+ const collectionName = collection.get('name');
80
+
81
+ const sortedData = sortBy(treeData, getNodeTitle);
82
+ return sortedData.map(node => {
83
+ const leaf = node.children.length <= 1 && !node.children[0]?.isDir && depth > 0;
84
+ if (leaf) {
85
+ return null;
86
+ }
87
+ let to = `/collections/${collectionName}`;
88
+ if (depth > 0) {
89
+ to = `${to}/filter${node.path}`;
90
+ }
91
+ const title = getNodeTitle(node);
92
+
93
+ const hasChildren = depth === 0 || node.children.some(c => c.children.some(c => c.isDir));
94
+
95
+ return (
96
+ <React.Fragment key={node.path}>
97
+ <TreeNavLink
98
+ exact
99
+ to={to}
100
+ activeClassName="sidebar-active"
101
+ onClick={() => onToggle({ node, expanded: !node.expanded })}
102
+ depth={depth}
103
+ data-testid={node.path}
104
+ >
105
+ <Icon type="write" />
106
+ <NodeTitleContainer>
107
+ <NodeTitle>{title}</NodeTitle>
108
+ {hasChildren && (node.expanded ? <CaretDown /> : <CaretRight />)}
109
+ </NodeTitleContainer>
110
+ </TreeNavLink>
111
+ {node.expanded && (
112
+ <TreeNode
113
+ collection={collection}
114
+ depth={depth + 1}
115
+ treeData={node.children}
116
+ onToggle={onToggle}
117
+ />
118
+ )}
119
+ </React.Fragment>
120
+ );
121
+ });
122
+ }
123
+
124
+ TreeNode.propTypes = {
125
+ collection: ImmutablePropTypes.map.isRequired,
126
+ depth: PropTypes.number,
127
+ treeData: PropTypes.array.isRequired,
128
+ onToggle: PropTypes.func.isRequired,
129
+ };
130
+
131
+ export function walk(treeData, callback) {
132
+ function traverse(children) {
133
+ for (const child of children) {
134
+ callback(child);
135
+ traverse(child.children);
136
+ }
137
+ }
138
+
139
+ return traverse(treeData);
140
+ }
141
+
142
+ export function getTreeData(collection, entries) {
143
+ const collectionFolder = collection.get('folder');
144
+ const rootFolder = '/';
145
+ const entriesObj = entries
146
+ .toJS()
147
+ .map(e => ({ ...e, path: e.path.slice(collectionFolder.length) }));
148
+
149
+ const dirs = entriesObj.reduce((acc, entry) => {
150
+ let dir = dirname(entry.path);
151
+ while (!acc[dir] && dir && dir !== rootFolder) {
152
+ const parts = dir.split(sep);
153
+ acc[dir] = parts.pop();
154
+ dir = parts.length && parts.join(sep);
155
+ }
156
+ return acc;
157
+ }, {});
158
+
159
+ if (collection.getIn(['nested', 'summary'])) {
160
+ collection = collection.set('summary', collection.getIn(['nested', 'summary']));
161
+ } else {
162
+ collection = collection.delete('summary');
163
+ }
164
+
165
+ const flatData = [
166
+ {
167
+ title: collection.get('label'),
168
+ path: rootFolder,
169
+ isDir: true,
170
+ isRoot: true,
171
+ },
172
+ ...Object.entries(dirs).map(([key, value]) => ({
173
+ title: value,
174
+ path: key,
175
+ isDir: true,
176
+ isRoot: false,
177
+ })),
178
+ ...entriesObj.map((e, index) => {
179
+ let entryMap = entries.get(index);
180
+ entryMap = entryMap.set(
181
+ 'data',
182
+ addFileTemplateFields(entryMap.get('path'), entryMap.get('data')),
183
+ );
184
+ const title = selectEntryCollectionTitle(collection, entryMap);
185
+ return {
186
+ ...e,
187
+ title,
188
+ isDir: false,
189
+ isRoot: false,
190
+ };
191
+ }),
192
+ ];
193
+
194
+ const parentsToChildren = flatData.reduce((acc, node) => {
195
+ const parent = node.path === rootFolder ? '' : dirname(node.path);
196
+ if (acc[parent]) {
197
+ acc[parent].push(node);
198
+ } else {
199
+ acc[parent] = [node];
200
+ }
201
+ return acc;
202
+ }, {});
203
+
204
+ function reducer(acc, value) {
205
+ const node = value;
206
+ let children = [];
207
+ if (parentsToChildren[node.path]) {
208
+ children = parentsToChildren[node.path].reduce(reducer, []);
209
+ }
210
+
211
+ acc.push({ ...node, children });
212
+ return acc;
213
+ }
214
+
215
+ const treeData = parentsToChildren[''].reduce(reducer, []);
216
+
217
+ return treeData;
218
+ }
219
+
220
+ export function updateNode(treeData, node, callback) {
221
+ let stop = false;
222
+
223
+ function updater(nodes) {
224
+ if (stop) {
225
+ return nodes;
226
+ }
227
+ for (let i = 0; i < nodes.length; i++) {
228
+ if (nodes[i].path === node.path) {
229
+ nodes[i] = callback(node);
230
+ stop = true;
231
+ return nodes;
232
+ }
233
+ }
234
+ nodes.forEach(node => updater(node.children));
235
+ return nodes;
236
+ }
237
+
238
+ return updater([...treeData]);
239
+ }
240
+
241
+ export class NestedCollection extends React.Component {
242
+ static propTypes = {
243
+ collection: ImmutablePropTypes.map.isRequired,
244
+ entries: ImmutablePropTypes.list.isRequired,
245
+ filterTerm: PropTypes.string,
246
+ };
247
+
248
+ constructor(props) {
249
+ super(props);
250
+ this.state = {
251
+ treeData: getTreeData(this.props.collection, this.props.entries),
252
+ selected: null,
253
+ useFilter: true,
254
+ };
255
+ }
256
+
257
+ componentDidUpdate(prevProps) {
258
+ const { collection, entries, filterTerm } = this.props;
259
+ if (
260
+ collection !== prevProps.collection ||
261
+ entries !== prevProps.entries ||
262
+ filterTerm !== prevProps.filterTerm
263
+ ) {
264
+ const expanded = {};
265
+ walk(this.state.treeData, node => {
266
+ if (node.expanded) {
267
+ expanded[node.path] = true;
268
+ }
269
+ });
270
+ const treeData = getTreeData(collection, entries);
271
+
272
+ const path = `/${filterTerm}`;
273
+ walk(treeData, node => {
274
+ if (expanded[node.path] || (this.state.useFilter && path.startsWith(node.path))) {
275
+ node.expanded = true;
276
+ }
277
+ });
278
+ this.setState({ treeData });
279
+ }
280
+ }
281
+
282
+ onToggle = ({ node, expanded }) => {
283
+ if (!this.state.selected || this.state.selected.path === node.path || expanded) {
284
+ const treeData = updateNode(this.state.treeData, node, node => ({
285
+ ...node,
286
+ expanded,
287
+ }));
288
+ this.setState({ treeData, selected: node, useFilter: false });
289
+ } else {
290
+ // don't collapse non selected nodes when clicked
291
+ this.setState({ selected: node, useFilter: false });
292
+ }
293
+ };
294
+
295
+ render() {
296
+ const { treeData } = this.state;
297
+ const { collection } = this.props;
298
+
299
+ return <TreeNode collection={collection} treeData={treeData} onToggle={this.onToggle} />;
300
+ }
301
+ }
302
+
303
+ function mapStateToProps(state, ownProps) {
304
+ const { collection } = ownProps;
305
+ const entries = selectEntries(state.entries, collection) || List();
306
+ return { entries };
307
+ }
308
+
309
+ export default connect(mapStateToProps, null)(NestedCollection);
@@ -0,0 +1,130 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import ImmutablePropTypes from 'react-immutable-proptypes';
4
+ import styled from '@emotion/styled';
5
+ import { css } from '@emotion/core';
6
+ import { translate } from 'react-polyglot';
7
+ import { NavLink } from 'react-router-dom';
8
+ import { Icon, components, colors } from 'decap-cms-ui-default';
9
+
10
+ import { searchCollections } from '../../actions/collections';
11
+ import CollectionSearch from './CollectionSearch';
12
+ import NestedCollection from './NestedCollection';
13
+
14
+ const styles = {
15
+ sidebarNavLinkActive: css`
16
+ color: ${colors.active};
17
+ background-color: ${colors.activeBackground};
18
+ border-left-color: #4863c6;
19
+ `,
20
+ };
21
+
22
+ const SidebarContainer = styled.aside`
23
+ ${components.card};
24
+ width: 250px;
25
+ padding: 8px 0 12px;
26
+ position: fixed;
27
+ max-height: calc(100vh - 112px);
28
+ display: flex;
29
+ flex-direction: column;
30
+ `;
31
+
32
+ const SidebarHeading = styled.h2`
33
+ font-size: 23px;
34
+ font-weight: 600;
35
+ padding: 0;
36
+ margin: 18px 12px 12px;
37
+ color: ${colors.textLead};
38
+ `;
39
+
40
+ const SidebarNavList = styled.ul`
41
+ margin: 16px 0 0;
42
+ list-style: none;
43
+ overflow: auto;
44
+ `;
45
+
46
+ const SidebarNavLink = styled(NavLink)`
47
+ display: flex;
48
+ font-size: 14px;
49
+ font-weight: 500;
50
+ align-items: center;
51
+ padding: 8px 12px;
52
+ border-left: 2px solid #fff;
53
+ z-index: -1;
54
+
55
+ ${Icon} {
56
+ margin-right: 8px;
57
+ flex-shrink: 0;
58
+ }
59
+
60
+ ${props => css`
61
+ &:hover,
62
+ &:active,
63
+ &.${props.activeClassName} {
64
+ ${styles.sidebarNavLinkActive};
65
+ }
66
+ `};
67
+ `;
68
+
69
+ export class Sidebar extends React.Component {
70
+ static propTypes = {
71
+ collections: ImmutablePropTypes.map.isRequired,
72
+ collection: ImmutablePropTypes.map,
73
+ isSearchEnabled: PropTypes.bool,
74
+ searchTerm: PropTypes.string,
75
+ filterTerm: PropTypes.string,
76
+ t: PropTypes.func.isRequired,
77
+ };
78
+
79
+ renderLink = (collection, filterTerm) => {
80
+ const collectionName = collection.get('name');
81
+ if (collection.has('nested')) {
82
+ return (
83
+ <li key={collectionName}>
84
+ <NestedCollection
85
+ collection={collection}
86
+ filterTerm={filterTerm}
87
+ data-testid={collectionName}
88
+ />
89
+ </li>
90
+ );
91
+ }
92
+ return (
93
+ <li key={collectionName}>
94
+ <SidebarNavLink
95
+ to={`/collections/${collectionName}`}
96
+ activeClassName="sidebar-active"
97
+ data-testid={collectionName}
98
+ >
99
+ <Icon type="write" />
100
+ {collection.get('label')}
101
+ </SidebarNavLink>
102
+ </li>
103
+ );
104
+ };
105
+
106
+ render() {
107
+ const { collections, collection, isSearchEnabled, searchTerm, t, filterTerm } = this.props;
108
+ return (
109
+ <SidebarContainer>
110
+ <SidebarHeading>{t('collection.sidebar.collections')}</SidebarHeading>
111
+ {isSearchEnabled && (
112
+ <CollectionSearch
113
+ searchTerm={searchTerm}
114
+ collections={collections}
115
+ collection={collection}
116
+ onSubmit={(query, collection) => searchCollections(query, collection)}
117
+ />
118
+ )}
119
+ <SidebarNavList>
120
+ {collections
121
+ .toList()
122
+ .filter(collection => collection.get('hide') !== true)
123
+ .map(collection => this.renderLink(collection, filterTerm))}
124
+ </SidebarNavList>
125
+ </SidebarContainer>
126
+ );
127
+ }
128
+ }
129
+
130
+ export default translate()(Sidebar);
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import { translate } from 'react-polyglot';
3
+ import { Dropdown, DropdownItem } from 'decap-cms-ui-default';
4
+
5
+ import { SortDirection } from '../../types/redux';
6
+ import { ControlButton } from './ControlButton';
7
+
8
+ function nextSortDirection(direction) {
9
+ switch (direction) {
10
+ case SortDirection.Ascending:
11
+ return SortDirection.Descending;
12
+ case SortDirection.Descending:
13
+ return SortDirection.None;
14
+ default:
15
+ return SortDirection.Ascending;
16
+ }
17
+ }
18
+
19
+ function sortIconProps(sortDir) {
20
+ return {
21
+ icon: 'chevron',
22
+ iconDirection: sortIconDirections[sortDir],
23
+ iconSmall: true,
24
+ };
25
+ }
26
+
27
+ const sortIconDirections = {
28
+ [SortDirection.Ascending]: 'up',
29
+ [SortDirection.Descending]: 'down',
30
+ };
31
+
32
+ function SortControl({ t, fields, onSortClick, sort }) {
33
+ const hasActiveSort = sort
34
+ ?.valueSeq()
35
+ .toJS()
36
+ .some(s => s.direction !== SortDirection.None);
37
+
38
+ return (
39
+ <Dropdown
40
+ renderButton={() => {
41
+ return (
42
+ <ControlButton active={hasActiveSort} title={t('collection.collectionTop.sortBy')} />
43
+ );
44
+ }}
45
+ closeOnSelection={false}
46
+ dropdownTopOverlap="30px"
47
+ dropdownWidth="160px"
48
+ dropdownPosition="left"
49
+ >
50
+ {fields.map(field => {
51
+ const sortDir = sort?.getIn([field.key, 'direction']);
52
+ const isActive = sortDir && sortDir !== SortDirection.None;
53
+ const nextSortDir = nextSortDirection(sortDir);
54
+ return (
55
+ <DropdownItem
56
+ key={field.key}
57
+ label={field.label}
58
+ onClick={() => onSortClick(field.key, nextSortDir)}
59
+ isActive={isActive}
60
+ {...(isActive && sortIconProps(sortDir))}
61
+ />
62
+ );
63
+ })}
64
+ </Dropdown>
65
+ );
66
+ }
67
+
68
+ export default translate()(SortControl);
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import styled from '@emotion/styled';
3
+ import { Icon, buttons, colors } from 'decap-cms-ui-default';
4
+
5
+ import { VIEW_STYLE_LIST, VIEW_STYLE_GRID } from '../../constants/collectionViews';
6
+
7
+ const ViewControlsSection = styled.div`
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: flex-end;
11
+ max-width: 500px;
12
+ `;
13
+
14
+ const ViewControlsButton = styled.button`
15
+ ${buttons.button};
16
+ color: ${props => (props.isActive ? colors.active : '#b3b9c4')};
17
+ background-color: transparent;
18
+ display: block;
19
+ padding: 0;
20
+ margin: 0 4px;
21
+
22
+ &:last-child {
23
+ margin-right: 0;
24
+ }
25
+
26
+ ${Icon} {
27
+ display: block;
28
+ }
29
+ `;
30
+
31
+ function ViewStyleControl({ viewStyle, onChangeViewStyle }) {
32
+ return (
33
+ <ViewControlsSection>
34
+ <ViewControlsButton
35
+ isActive={viewStyle === VIEW_STYLE_LIST}
36
+ onClick={() => onChangeViewStyle(VIEW_STYLE_LIST)}
37
+ >
38
+ <Icon type="list" />
39
+ </ViewControlsButton>
40
+ <ViewControlsButton
41
+ isActive={viewStyle === VIEW_STYLE_GRID}
42
+ onClick={() => onChangeViewStyle(VIEW_STYLE_GRID)}
43
+ >
44
+ <Icon type="grid" />
45
+ </ViewControlsButton>
46
+ </ViewControlsSection>
47
+ );
48
+ }
49
+
50
+ export default ViewStyleControl;