@evfrenkel/decap-cms-core 3.13.0-image-conversions.0
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.
- package/README.md +9 -0
- package/dist/20.decap-cms-core.js +2 -0
- package/dist/20.decap-cms-core.js.map +1 -0
- package/dist/3802306e7b58a11862fb.wasm +0 -0
- package/dist/@evfrenkel/20.decap-cms-core.js +2 -0
- package/dist/@evfrenkel/20.decap-cms-core.js.map +1 -0
- package/dist/@evfrenkel/decap-cms-core.js +44 -0
- package/dist/@evfrenkel/decap-cms-core.js.LICENSE.txt +126 -0
- package/dist/@evfrenkel/decap-cms-core.js.map +1 -0
- package/dist/decap-cms-core.js +47 -0
- package/dist/decap-cms-core.js.LICENSE.txt +126 -0
- package/dist/decap-cms-core.js.map +1 -0
- package/dist/esm/actions/auth.js +97 -0
- package/dist/esm/actions/collections.js +15 -0
- package/dist/esm/actions/config.js +503 -0
- package/dist/esm/actions/deploys.js +80 -0
- package/dist/esm/actions/editorialWorkflow.js +480 -0
- package/dist/esm/actions/entries.js +876 -0
- package/dist/esm/actions/media.js +147 -0
- package/dist/esm/actions/mediaLibrary.js +599 -0
- package/dist/esm/actions/notifications.js +21 -0
- package/dist/esm/actions/search.js +149 -0
- package/dist/esm/actions/status.js +74 -0
- package/dist/esm/actions/waitUntil.js +32 -0
- package/dist/esm/backend.js +1090 -0
- package/dist/esm/bootstrap.js +101 -0
- package/dist/esm/components/App/App.js +296 -0
- package/dist/esm/components/App/Header.js +172 -0
- package/dist/esm/components/App/NotFoundPage.js +19 -0
- package/dist/esm/components/Collection/Collection.js +198 -0
- package/dist/esm/components/Collection/CollectionControls.js +47 -0
- package/dist/esm/components/Collection/CollectionSearch.js +222 -0
- package/dist/esm/components/Collection/CollectionTop.js +68 -0
- package/dist/esm/components/Collection/ControlButton.js +17 -0
- package/dist/esm/components/Collection/Entries/Entries.js +73 -0
- package/dist/esm/components/Collection/Entries/EntriesCollection.js +241 -0
- package/dist/esm/components/Collection/Entries/EntriesSearch.js +113 -0
- package/dist/esm/components/Collection/Entries/EntryCard.js +192 -0
- package/dist/esm/components/Collection/Entries/EntryListing.js +143 -0
- package/dist/esm/components/Collection/FilterControl.js +33 -0
- package/dist/esm/components/Collection/GroupControl.js +33 -0
- package/dist/esm/components/Collection/NestedCollection.js +308 -0
- package/dist/esm/components/Collection/Sidebar.js +91 -0
- package/dist/esm/components/Collection/SortControl.js +59 -0
- package/dist/esm/components/Collection/ViewStyleControl.js +41 -0
- package/dist/esm/components/Editor/Editor.js +466 -0
- package/dist/esm/components/Editor/EditorControlPane/EditorControl.js +398 -0
- package/dist/esm/components/Editor/EditorControlPane/EditorControlPane.js +254 -0
- package/dist/esm/components/Editor/EditorControlPane/Widget.js +374 -0
- package/dist/esm/components/Editor/EditorInterface.js +386 -0
- package/dist/esm/components/Editor/EditorPreviewPane/EditorPreview.js +47 -0
- package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewContent.js +67 -0
- package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewPane.js +306 -0
- package/dist/esm/components/Editor/EditorPreviewPane/PreviewHOC.js +27 -0
- package/dist/esm/components/Editor/EditorToolbar.js +554 -0
- package/dist/esm/components/Editor/withWorkflow.js +56 -0
- package/dist/esm/components/EditorWidgets/Unknown/UnknownControl.js +18 -0
- package/dist/esm/components/EditorWidgets/Unknown/UnknownPreview.js +20 -0
- package/dist/esm/components/EditorWidgets/index.js +4 -0
- package/dist/esm/components/MediaLibrary/EmptyMessage.js +22 -0
- package/dist/esm/components/MediaLibrary/MediaLibrary.js +446 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryButtons.js +92 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryCard.js +99 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryCardGrid.js +198 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryHeader.js +34 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryModal.js +156 -0
- package/dist/esm/components/MediaLibrary/MediaLibrarySearch.js +51 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryTop.js +124 -0
- package/dist/esm/components/UI/DragDrop.js +67 -0
- package/dist/esm/components/UI/ErrorBoundary.js +170 -0
- package/dist/esm/components/UI/FileUploadButton.js +27 -0
- package/dist/esm/components/UI/Modal.js +104 -0
- package/dist/esm/components/UI/Notifications.js +62 -0
- package/dist/esm/components/UI/SettingsDropdown.js +107 -0
- package/dist/esm/components/UI/index.js +6 -0
- package/dist/esm/components/Workflow/Workflow.js +133 -0
- package/dist/esm/components/Workflow/WorkflowCard.js +128 -0
- package/dist/esm/components/Workflow/WorkflowList.js +204 -0
- package/dist/esm/constants/collectionTypes.js +2 -0
- package/dist/esm/constants/collectionViews.js +2 -0
- package/dist/esm/constants/commitProps.js +2 -0
- package/dist/esm/constants/configSchema.js +695 -0
- package/dist/esm/constants/fieldInference.js +57 -0
- package/dist/esm/constants/publishModes.js +18 -0
- package/dist/esm/constants/validationErrorTypes.js +6 -0
- package/dist/esm/formats/formats.js +83 -0
- package/dist/esm/formats/frontmatter.js +146 -0
- package/dist/esm/formats/helpers.js +12 -0
- package/dist/esm/formats/json.js +8 -0
- package/dist/esm/formats/toml.js +32 -0
- package/dist/esm/formats/yaml.js +60 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/integrations/index.js +28 -0
- package/dist/esm/integrations/providers/algolia/implementation.js +174 -0
- package/dist/esm/integrations/providers/assetStore/implementation.js +165 -0
- package/dist/esm/lib/consoleError.js +3 -0
- package/dist/esm/lib/formatters.js +201 -0
- package/dist/esm/lib/i18n.js +372 -0
- package/dist/esm/lib/imageTransformations.js +143 -0
- package/dist/esm/lib/phrases.js +6 -0
- package/dist/esm/lib/polyfill.js +8 -0
- package/dist/esm/lib/registry.js +332 -0
- package/dist/esm/lib/serializeEntryValues.js +67 -0
- package/dist/esm/lib/stega.js +142 -0
- package/dist/esm/lib/textHelper.js +9 -0
- package/dist/esm/lib/urlHelper.js +129 -0
- package/dist/esm/mediaLibrary.js +37 -0
- package/dist/esm/reducers/auth.js +27 -0
- package/dist/esm/reducers/collections.js +428 -0
- package/dist/esm/reducers/combinedReducer.js +8 -0
- package/dist/esm/reducers/config.js +29 -0
- package/dist/esm/reducers/cursors.js +31 -0
- package/dist/esm/reducers/deploys.js +50 -0
- package/dist/esm/reducers/editorialWorkflow.js +83 -0
- package/dist/esm/reducers/entries.js +568 -0
- package/dist/esm/reducers/entryDraft.js +211 -0
- package/dist/esm/reducers/globalUI.js +25 -0
- package/dist/esm/reducers/index.js +66 -0
- package/dist/esm/reducers/integrations.js +53 -0
- package/dist/esm/reducers/mediaLibrary.js +252 -0
- package/dist/esm/reducers/medias.js +68 -0
- package/dist/esm/reducers/notifications.js +23 -0
- package/dist/esm/reducers/search.js +92 -0
- package/dist/esm/reducers/status.js +30 -0
- package/dist/esm/redux/index.js +7 -0
- package/dist/esm/redux/middleware/waitUntilAction.js +48 -0
- package/dist/esm/routing/history.js +12 -0
- package/dist/esm/types/diacritics.d.js +0 -0
- package/dist/esm/types/global.d.js +1 -0
- package/dist/esm/types/immutable.js +7 -0
- package/dist/esm/types/redux.js +14 -0
- package/dist/esm/types/tomlify-j0.4.d.js +0 -0
- package/dist/esm/valueObjects/AssetProxy.js +44 -0
- package/dist/esm/valueObjects/EditorComponent.js +34 -0
- package/dist/esm/valueObjects/Entry.js +20 -0
- package/index.d.ts +662 -0
- package/package.json +100 -0
- package/src/__tests__/backend.spec.js +1223 -0
- package/src/actions/__tests__/config.spec.js +1023 -0
- package/src/actions/__tests__/editorialWorkflow.spec.js +216 -0
- package/src/actions/__tests__/entries.spec.js +610 -0
- package/src/actions/__tests__/media.spec.ts +171 -0
- package/src/actions/__tests__/mediaLibrary.spec.js +462 -0
- package/src/actions/__tests__/search.spec.js +209 -0
- package/src/actions/auth.ts +127 -0
- package/src/actions/collections.ts +18 -0
- package/src/actions/config.ts +574 -0
- package/src/actions/deploys.ts +105 -0
- package/src/actions/editorialWorkflow.ts +567 -0
- package/src/actions/entries.ts +1070 -0
- package/src/actions/media.ts +139 -0
- package/src/actions/mediaLibrary.ts +639 -0
- package/src/actions/notifications.ts +36 -0
- package/src/actions/search.ts +221 -0
- package/src/actions/status.ts +99 -0
- package/src/actions/waitUntil.ts +49 -0
- package/src/backend.ts +1411 -0
- package/src/bootstrap.js +104 -0
- package/src/components/App/App.js +295 -0
- package/src/components/App/Header.js +291 -0
- package/src/components/App/NotFoundPage.js +23 -0
- package/src/components/Collection/Collection.js +210 -0
- package/src/components/Collection/CollectionControls.js +58 -0
- package/src/components/Collection/CollectionSearch.js +243 -0
- package/src/components/Collection/CollectionTop.js +81 -0
- package/src/components/Collection/ControlButton.js +27 -0
- package/src/components/Collection/Entries/Entries.js +82 -0
- package/src/components/Collection/Entries/EntriesCollection.js +277 -0
- package/src/components/Collection/Entries/EntriesSearch.js +102 -0
- package/src/components/Collection/Entries/EntryCard.js +256 -0
- package/src/components/Collection/Entries/EntryListing.js +151 -0
- package/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js +163 -0
- package/src/components/Collection/Entries/__tests__/__snapshots__/EntriesCollection.spec.js.snap +46 -0
- package/src/components/Collection/FilterControl.js +39 -0
- package/src/components/Collection/GroupControl.js +39 -0
- package/src/components/Collection/NestedCollection.js +330 -0
- package/src/components/Collection/Sidebar.js +136 -0
- package/src/components/Collection/SortControl.js +68 -0
- package/src/components/Collection/ViewStyleControl.js +52 -0
- package/src/components/Collection/__tests__/Collection.spec.js +75 -0
- package/src/components/Collection/__tests__/NestedCollection.spec.js +445 -0
- package/src/components/Collection/__tests__/Sidebar.spec.js +87 -0
- package/src/components/Collection/__tests__/__snapshots__/Collection.spec.js.snap +144 -0
- package/src/components/Collection/__tests__/__snapshots__/NestedCollection.spec.js.snap +550 -0
- package/src/components/Collection/__tests__/__snapshots__/Sidebar.spec.js.snap +312 -0
- package/src/components/Editor/Editor.js +497 -0
- package/src/components/Editor/EditorControlPane/EditorControl.js +453 -0
- package/src/components/Editor/EditorControlPane/EditorControlPane.js +269 -0
- package/src/components/Editor/EditorControlPane/Widget.js +384 -0
- package/src/components/Editor/EditorInterface.js +444 -0
- package/src/components/Editor/EditorPreviewPane/EditorPreview.js +40 -0
- package/src/components/Editor/EditorPreviewPane/EditorPreviewContent.js +75 -0
- package/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js +337 -0
- package/src/components/Editor/EditorPreviewPane/PreviewHOC.js +33 -0
- package/src/components/Editor/EditorToolbar.js +728 -0
- package/src/components/Editor/__tests__/Editor.spec.js +221 -0
- package/src/components/Editor/__tests__/EditorToolbar.spec.js +166 -0
- package/src/components/Editor/__tests__/__snapshots__/Editor.spec.js.snap +45 -0
- package/src/components/Editor/__tests__/__snapshots__/EditorToolbar.spec.js.snap +4265 -0
- package/src/components/Editor/withWorkflow.js +61 -0
- package/src/components/EditorWidgets/Unknown/UnknownControl.js +17 -0
- package/src/components/EditorWidgets/Unknown/UnknownPreview.js +19 -0
- package/src/components/EditorWidgets/index.js +5 -0
- package/src/components/MediaLibrary/EmptyMessage.js +28 -0
- package/src/components/MediaLibrary/MediaLibrary.js +411 -0
- package/src/components/MediaLibrary/MediaLibraryButtons.js +135 -0
- package/src/components/MediaLibrary/MediaLibraryCard.js +128 -0
- package/src/components/MediaLibrary/MediaLibraryCardGrid.js +199 -0
- package/src/components/MediaLibrary/MediaLibraryHeader.js +48 -0
- package/src/components/MediaLibrary/MediaLibraryModal.js +200 -0
- package/src/components/MediaLibrary/MediaLibrarySearch.js +61 -0
- package/src/components/MediaLibrary/MediaLibraryTop.js +144 -0
- package/src/components/MediaLibrary/__tests__/MediaLibraryButtons.spec.js +45 -0
- package/src/components/MediaLibrary/__tests__/MediaLibraryCard.spec.js +49 -0
- package/src/components/MediaLibrary/__tests__/__snapshots__/MediaLibraryCard.spec.js.snap +264 -0
- package/src/components/UI/DragDrop.js +66 -0
- package/src/components/UI/ErrorBoundary.js +213 -0
- package/src/components/UI/FileUploadButton.js +24 -0
- package/src/components/UI/Modal.js +112 -0
- package/src/components/UI/Notifications.tsx +83 -0
- package/src/components/UI/SettingsDropdown.js +130 -0
- package/src/components/UI/__tests__/ErrorBoundary.spec.js +57 -0
- package/src/components/UI/index.js +6 -0
- package/src/components/Workflow/Workflow.js +169 -0
- package/src/components/Workflow/WorkflowCard.js +177 -0
- package/src/components/Workflow/WorkflowList.js +272 -0
- package/src/constants/__tests__/configSchema.spec.js +644 -0
- package/src/constants/collectionTypes.ts +2 -0
- package/src/constants/collectionViews.js +2 -0
- package/src/constants/commitProps.ts +2 -0
- package/src/constants/configSchema.js +489 -0
- package/src/constants/fieldInference.tsx +78 -0
- package/src/constants/publishModes.ts +22 -0
- package/src/constants/validationErrorTypes.js +6 -0
- package/src/formats/__tests__/formats.spec.js +87 -0
- package/src/formats/__tests__/frontmatter.spec.js +450 -0
- package/src/formats/__tests__/toml.spec.js +9 -0
- package/src/formats/__tests__/yaml.spec.js +189 -0
- package/src/formats/formats.ts +97 -0
- package/src/formats/frontmatter.ts +150 -0
- package/src/formats/helpers.ts +14 -0
- package/src/formats/json.ts +9 -0
- package/src/formats/toml.ts +33 -0
- package/src/formats/yaml.ts +73 -0
- package/src/index.js +8 -0
- package/src/integrations/index.js +35 -0
- package/src/integrations/providers/algolia/implementation.js +176 -0
- package/src/integrations/providers/assetStore/implementation.js +148 -0
- package/src/lib/__tests__/formatters.spec.js +844 -0
- package/src/lib/__tests__/i18n.spec.js +792 -0
- package/src/lib/__tests__/imageTransformations.spec.ts +97 -0
- package/src/lib/__tests__/phrases.spec.js +119 -0
- package/src/lib/__tests__/registry.spec.js +261 -0
- package/src/lib/__tests__/serializeEntryValues.spec.js +22 -0
- package/src/lib/__tests__/urlHelper.spec.js +145 -0
- package/src/lib/consoleError.js +7 -0
- package/src/lib/formatters.ts +297 -0
- package/src/lib/i18n.ts +462 -0
- package/src/lib/imageTransformations.ts +212 -0
- package/src/lib/phrases.js +8 -0
- package/src/lib/polyfill.js +9 -0
- package/src/lib/registry.js +315 -0
- package/src/lib/serializeEntryValues.js +75 -0
- package/src/lib/stega.ts +145 -0
- package/src/lib/textHelper.js +11 -0
- package/src/lib/urlHelper.ts +152 -0
- package/src/mediaLibrary.ts +51 -0
- package/src/reducers/__tests__/auth.spec.ts +38 -0
- package/src/reducers/__tests__/collections.spec.js +610 -0
- package/src/reducers/__tests__/config.spec.js +38 -0
- package/src/reducers/__tests__/deploys.spec.ts +111 -0
- package/src/reducers/__tests__/entries.spec.js +694 -0
- package/src/reducers/__tests__/entryDraft.spec.js +315 -0
- package/src/reducers/__tests__/globalUI.js +43 -0
- package/src/reducers/__tests__/integrations.spec.ts +76 -0
- package/src/reducers/__tests__/mediaLibrary.spec.js +154 -0
- package/src/reducers/__tests__/medias.spec.ts +49 -0
- package/src/reducers/auth.ts +46 -0
- package/src/reducers/collections.ts +535 -0
- package/src/reducers/combinedReducer.ts +11 -0
- package/src/reducers/config.ts +38 -0
- package/src/reducers/cursors.js +36 -0
- package/src/reducers/deploys.ts +54 -0
- package/src/reducers/editorialWorkflow.ts +163 -0
- package/src/reducers/entries.ts +819 -0
- package/src/reducers/entryDraft.js +259 -0
- package/src/reducers/globalUI.ts +45 -0
- package/src/reducers/index.ts +82 -0
- package/src/reducers/integrations.ts +59 -0
- package/src/reducers/mediaLibrary.ts +296 -0
- package/src/reducers/medias.ts +66 -0
- package/src/reducers/notifications.ts +52 -0
- package/src/reducers/search.ts +111 -0
- package/src/reducers/status.ts +40 -0
- package/src/redux/index.ts +18 -0
- package/src/redux/middleware/waitUntilAction.ts +64 -0
- package/src/routing/__tests__/history.spec.ts +49 -0
- package/src/routing/history.ts +17 -0
- package/src/types/diacritics.d.ts +1 -0
- package/src/types/global.d.ts +8 -0
- package/src/types/immutable.ts +49 -0
- package/src/types/redux.ts +875 -0
- package/src/types/tomlify-j0.4.d.ts +13 -0
- package/src/valueObjects/AssetProxy.ts +48 -0
- package/src/valueObjects/EditorComponent.js +38 -0
- package/src/valueObjects/Entry.ts +63 -0
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
import yaml from 'yaml';
|
|
2
|
+
import { fromJS } from 'immutable';
|
|
3
|
+
import deepmerge from 'deepmerge';
|
|
4
|
+
import { produce } from 'immer';
|
|
5
|
+
import trimStart from 'lodash/trimStart';
|
|
6
|
+
import trim from 'lodash/trim';
|
|
7
|
+
import isEmpty from 'lodash/isEmpty';
|
|
8
|
+
|
|
9
|
+
import { SIMPLE as SIMPLE_PUBLISH_MODE } from '../constants/publishModes';
|
|
10
|
+
import { validateConfig } from '../constants/configSchema';
|
|
11
|
+
import { selectDefaultSortableFields } from '../reducers/collections';
|
|
12
|
+
import { getIntegrations, selectIntegration } from '../reducers/integrations';
|
|
13
|
+
import { resolveBackend } from '../backend';
|
|
14
|
+
import { I18N, I18N_FIELD, I18N_STRUCTURE } from '../lib/i18n';
|
|
15
|
+
import { FILES, FOLDER } from '../constants/collectionTypes';
|
|
16
|
+
|
|
17
|
+
import type { ThunkDispatch } from 'redux-thunk';
|
|
18
|
+
import type { AnyAction } from 'redux';
|
|
19
|
+
import type {
|
|
20
|
+
CmsCollection,
|
|
21
|
+
CmsConfig,
|
|
22
|
+
CmsField,
|
|
23
|
+
CmsFieldBase,
|
|
24
|
+
CmsFieldObject,
|
|
25
|
+
CmsFieldList,
|
|
26
|
+
CmsI18nConfig,
|
|
27
|
+
CmsPublishMode,
|
|
28
|
+
CmsLocalBackend,
|
|
29
|
+
State,
|
|
30
|
+
} from '../types/redux';
|
|
31
|
+
|
|
32
|
+
export const CONFIG_REQUEST = 'CONFIG_REQUEST';
|
|
33
|
+
export const CONFIG_SUCCESS = 'CONFIG_SUCCESS';
|
|
34
|
+
export const CONFIG_FAILURE = 'CONFIG_FAILURE';
|
|
35
|
+
|
|
36
|
+
function isObjectField(field: CmsField): field is CmsFieldBase & CmsFieldObject {
|
|
37
|
+
return 'fields' in (field as CmsFieldObject);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isFieldList(field: CmsField): field is CmsFieldBase & CmsFieldList {
|
|
41
|
+
return 'types' in (field as CmsFieldList) || 'field' in (field as CmsFieldList);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function traverseFieldsJS<Field extends CmsField>(
|
|
45
|
+
fields: Field[],
|
|
46
|
+
updater: <T extends CmsField>(field: T) => T,
|
|
47
|
+
): Field[] {
|
|
48
|
+
return fields.map(field => {
|
|
49
|
+
const newField = updater(field);
|
|
50
|
+
if (isObjectField(newField)) {
|
|
51
|
+
return { ...newField, fields: traverseFieldsJS(newField.fields, updater) };
|
|
52
|
+
} else if (isFieldList(newField) && newField.field) {
|
|
53
|
+
return { ...newField, field: traverseFieldsJS([newField.field], updater)[0] };
|
|
54
|
+
} else if (isFieldList(newField) && newField.types) {
|
|
55
|
+
return { ...newField, types: traverseFieldsJS(newField.types, updater) };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return newField;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getConfigUrl() {
|
|
63
|
+
const validTypes: { [type: string]: string } = {
|
|
64
|
+
'text/yaml': 'yaml',
|
|
65
|
+
'application/x-yaml': 'yaml',
|
|
66
|
+
};
|
|
67
|
+
const configLinkEl = document.querySelector<HTMLLinkElement>('link[rel="cms-config-url"]');
|
|
68
|
+
if (configLinkEl && validTypes[configLinkEl.type] && configLinkEl.href) {
|
|
69
|
+
console.log(`Using config file path: "${configLinkEl.href}"`);
|
|
70
|
+
return configLinkEl.href;
|
|
71
|
+
}
|
|
72
|
+
return 'config.yml';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function setDefaultPublicFolderForField<T extends CmsField>(field: T) {
|
|
76
|
+
if ('media_folder' in field && !('public_folder' in field)) {
|
|
77
|
+
return { ...field, public_folder: field.media_folder };
|
|
78
|
+
}
|
|
79
|
+
return field;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Mapping between existing camelCase and its snake_case counterpart
|
|
83
|
+
const WIDGET_KEY_MAP = {
|
|
84
|
+
dateFormat: 'date_format',
|
|
85
|
+
timeFormat: 'time_format',
|
|
86
|
+
pickerUtc: 'picker_utc',
|
|
87
|
+
editorComponents: 'editor_components',
|
|
88
|
+
valueType: 'value_type',
|
|
89
|
+
valueField: 'value_field',
|
|
90
|
+
searchFields: 'search_fields',
|
|
91
|
+
displayFields: 'display_fields',
|
|
92
|
+
optionsLength: 'options_length',
|
|
93
|
+
} as const;
|
|
94
|
+
|
|
95
|
+
function setSnakeCaseConfig<T extends CmsField>(field: T) {
|
|
96
|
+
const deprecatedKeys = Object.keys(WIDGET_KEY_MAP).filter(
|
|
97
|
+
camel => camel in field,
|
|
98
|
+
) as ReadonlyArray<keyof typeof WIDGET_KEY_MAP>;
|
|
99
|
+
|
|
100
|
+
const snakeValues = deprecatedKeys.map(camel => {
|
|
101
|
+
const snake = WIDGET_KEY_MAP[camel];
|
|
102
|
+
console.warn(
|
|
103
|
+
`Field ${field.name} is using a deprecated configuration '${camel}'. Please use '${snake}'`,
|
|
104
|
+
);
|
|
105
|
+
return { [snake]: (field as unknown as Record<string, unknown>)[camel] };
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return Object.assign({}, field, ...snakeValues) as T;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function setI18nField<T extends CmsField>(field: T) {
|
|
112
|
+
if (field[I18N] === true) {
|
|
113
|
+
return { ...field, [I18N]: I18N_FIELD.TRANSLATE };
|
|
114
|
+
} else if (field[I18N] === false || !field[I18N]) {
|
|
115
|
+
return { ...field, [I18N]: I18N_FIELD.NONE };
|
|
116
|
+
}
|
|
117
|
+
return field;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function getI18nDefaults(
|
|
121
|
+
collectionOrFileI18n: boolean | CmsI18nConfig,
|
|
122
|
+
defaultI18n: CmsI18nConfig,
|
|
123
|
+
) {
|
|
124
|
+
if (typeof collectionOrFileI18n === 'boolean') {
|
|
125
|
+
return defaultI18n;
|
|
126
|
+
} else {
|
|
127
|
+
const locales = collectionOrFileI18n.locales || defaultI18n.locales;
|
|
128
|
+
const defaultLocale = collectionOrFileI18n.default_locale || locales[0];
|
|
129
|
+
const mergedI18n: CmsI18nConfig = deepmerge(defaultI18n, collectionOrFileI18n);
|
|
130
|
+
mergedI18n.locales = locales;
|
|
131
|
+
mergedI18n.default_locale = defaultLocale;
|
|
132
|
+
throwOnMissingDefaultLocale(mergedI18n);
|
|
133
|
+
return mergedI18n;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function setI18nDefaultsForFields(collectionOrFileFields: CmsField[], hasI18n: boolean) {
|
|
138
|
+
if (hasI18n) {
|
|
139
|
+
return traverseFieldsJS(collectionOrFileFields, setI18nField);
|
|
140
|
+
} else {
|
|
141
|
+
return traverseFieldsJS(collectionOrFileFields, field => {
|
|
142
|
+
const newField = { ...field };
|
|
143
|
+
delete newField[I18N];
|
|
144
|
+
return newField;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function throwOnInvalidFileCollectionStructure(i18n?: CmsI18nConfig) {
|
|
150
|
+
if (i18n && i18n.structure !== I18N_STRUCTURE.SINGLE_FILE) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
`i18n configuration for files collections is limited to ${I18N_STRUCTURE.SINGLE_FILE} structure`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function throwOnMissingDefaultLocale(i18n?: CmsI18nConfig) {
|
|
158
|
+
if (i18n && i18n.default_locale && !i18n.locales.includes(i18n.default_locale)) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`i18n locales '${i18n.locales.join(', ')}' are missing the default locale ${
|
|
161
|
+
i18n.default_locale
|
|
162
|
+
}`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function hasIntegration(config: CmsConfig, collection: CmsCollection) {
|
|
168
|
+
// TODO remove fromJS when Immutable is removed from the integrations state slice
|
|
169
|
+
const integrations = getIntegrations(fromJS(config));
|
|
170
|
+
const integration = selectIntegration(integrations, collection.name, 'listEntries');
|
|
171
|
+
return !!integration;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function normalizeSortableFields(
|
|
175
|
+
sortableFields: (
|
|
176
|
+
| string
|
|
177
|
+
| { field: string; label?: string; default_sort?: boolean | 'asc' | 'desc' }
|
|
178
|
+
)[],
|
|
179
|
+
) {
|
|
180
|
+
return sortableFields.map(field => {
|
|
181
|
+
if (typeof field === 'string') {
|
|
182
|
+
return { field, default_sort: undefined };
|
|
183
|
+
}
|
|
184
|
+
return field;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function normalizeConfig(config: CmsConfig) {
|
|
189
|
+
const { collections = [] } = config;
|
|
190
|
+
|
|
191
|
+
const normalizedCollections = collections.map(collection => {
|
|
192
|
+
const { fields, files } = collection;
|
|
193
|
+
|
|
194
|
+
let normalizedCollection = collection;
|
|
195
|
+
if (fields) {
|
|
196
|
+
const normalizedFields = traverseFieldsJS(fields, setSnakeCaseConfig);
|
|
197
|
+
normalizedCollection = { ...normalizedCollection, fields: normalizedFields };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (files) {
|
|
201
|
+
const normalizedFiles = files.map(file => {
|
|
202
|
+
const normalizedFileFields = traverseFieldsJS(file.fields, setSnakeCaseConfig);
|
|
203
|
+
return { ...file, fields: normalizedFileFields };
|
|
204
|
+
});
|
|
205
|
+
normalizedCollection = { ...normalizedCollection, files: normalizedFiles };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (normalizedCollection.sortableFields) {
|
|
209
|
+
const { sortableFields, ...rest } = normalizedCollection;
|
|
210
|
+
normalizedCollection = { ...rest, sortable_fields: sortableFields };
|
|
211
|
+
|
|
212
|
+
console.warn(
|
|
213
|
+
`Collection ${collection.name} is using a deprecated configuration 'sortableFields'. Please use 'sortable_fields'`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Normalize sortable_fields to consistent object format
|
|
218
|
+
if (normalizedCollection.sortable_fields) {
|
|
219
|
+
normalizedCollection = {
|
|
220
|
+
...normalizedCollection,
|
|
221
|
+
sortable_fields: normalizeSortableFields(normalizedCollection.sortable_fields),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return normalizedCollection;
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
return { ...config, collections: normalizedCollections };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function applyDefaults(originalConfig: CmsConfig) {
|
|
232
|
+
return produce(originalConfig, config => {
|
|
233
|
+
config.publish_mode = config.publish_mode || SIMPLE_PUBLISH_MODE;
|
|
234
|
+
config.slug = config.slug || {};
|
|
235
|
+
config.collections = config.collections || [];
|
|
236
|
+
|
|
237
|
+
// Use `site_url` as default `display_url`.
|
|
238
|
+
if (!config.display_url && config.site_url) {
|
|
239
|
+
config.display_url = config.site_url;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Use media_folder as default public_folder.
|
|
243
|
+
const defaultPublicFolder = `/${trimStart(config.media_folder, '/')}`;
|
|
244
|
+
if (!('public_folder' in config)) {
|
|
245
|
+
config.public_folder = defaultPublicFolder;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// default values for the slug config
|
|
249
|
+
if (!('encoding' in config.slug)) {
|
|
250
|
+
config.slug.encoding = 'unicode';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (!('clean_accents' in config.slug)) {
|
|
254
|
+
config.slug.clean_accents = false;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (!('sanitize_replacement' in config.slug)) {
|
|
258
|
+
config.slug.sanitize_replacement = '-';
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const i18n = config[I18N];
|
|
262
|
+
|
|
263
|
+
if (i18n) {
|
|
264
|
+
i18n.default_locale = i18n.default_locale || i18n.locales[0];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
throwOnMissingDefaultLocale(i18n);
|
|
268
|
+
|
|
269
|
+
const backend = resolveBackend(config);
|
|
270
|
+
|
|
271
|
+
for (const collection of config.collections) {
|
|
272
|
+
if (!('publish' in collection)) {
|
|
273
|
+
collection.publish = true;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
let collectionI18n = collection[I18N];
|
|
277
|
+
|
|
278
|
+
if (i18n && collectionI18n) {
|
|
279
|
+
collectionI18n = getI18nDefaults(collectionI18n, i18n);
|
|
280
|
+
collection[I18N] = collectionI18n;
|
|
281
|
+
} else {
|
|
282
|
+
collectionI18n = undefined;
|
|
283
|
+
delete collection[I18N];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (collection.fields) {
|
|
287
|
+
collection.fields = setI18nDefaultsForFields(collection.fields, Boolean(collectionI18n));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const { folder, files, view_filters, view_groups, meta } = collection;
|
|
291
|
+
|
|
292
|
+
if (folder) {
|
|
293
|
+
collection.type = FOLDER;
|
|
294
|
+
|
|
295
|
+
if (collection.path && !collection.media_folder) {
|
|
296
|
+
// default value for media folder when using the path config
|
|
297
|
+
collection.media_folder = '';
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if ('media_folder' in collection && !('public_folder' in collection)) {
|
|
301
|
+
collection.public_folder = collection.media_folder;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (collection.fields) {
|
|
305
|
+
collection.fields = traverseFieldsJS(collection.fields, setDefaultPublicFolderForField);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
collection.folder = trim(folder, '/');
|
|
309
|
+
|
|
310
|
+
if (meta && meta.path) {
|
|
311
|
+
const metaPath = meta.path;
|
|
312
|
+
const metaField = {
|
|
313
|
+
name: 'path',
|
|
314
|
+
meta: true,
|
|
315
|
+
required: true,
|
|
316
|
+
...metaPath,
|
|
317
|
+
};
|
|
318
|
+
collection.fields = [metaField, ...(collection.fields || [])];
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (files) {
|
|
323
|
+
collection.type = FILES;
|
|
324
|
+
|
|
325
|
+
throwOnInvalidFileCollectionStructure(collectionI18n);
|
|
326
|
+
|
|
327
|
+
delete collection.nested;
|
|
328
|
+
delete collection.meta;
|
|
329
|
+
|
|
330
|
+
for (const file of files) {
|
|
331
|
+
file.file = trimStart(file.file, '/');
|
|
332
|
+
|
|
333
|
+
if ('media_folder' in file && !('public_folder' in file)) {
|
|
334
|
+
file.public_folder = file.media_folder;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (file.fields) {
|
|
338
|
+
file.fields = traverseFieldsJS(file.fields, setDefaultPublicFolderForField);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
let fileI18n = file[I18N];
|
|
342
|
+
|
|
343
|
+
if (fileI18n && collectionI18n) {
|
|
344
|
+
fileI18n = getI18nDefaults(fileI18n, collectionI18n);
|
|
345
|
+
file[I18N] = fileI18n;
|
|
346
|
+
} else {
|
|
347
|
+
fileI18n = undefined;
|
|
348
|
+
delete file[I18N];
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
throwOnInvalidFileCollectionStructure(fileI18n);
|
|
352
|
+
|
|
353
|
+
if (file.fields) {
|
|
354
|
+
file.fields = setI18nDefaultsForFields(file.fields, Boolean(fileI18n));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (!collection.sortable_fields) {
|
|
360
|
+
collection.sortable_fields = selectDefaultSortableFields(
|
|
361
|
+
// TODO remove fromJS when Immutable is removed from the collections state slice
|
|
362
|
+
fromJS(collection),
|
|
363
|
+
backend,
|
|
364
|
+
hasIntegration(config, collection),
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
collection.view_filters = (view_filters || []).map(filter => {
|
|
369
|
+
return {
|
|
370
|
+
...filter,
|
|
371
|
+
id: `${filter.field}__${filter.pattern}`,
|
|
372
|
+
};
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
collection.view_groups = (view_groups || []).map(group => {
|
|
376
|
+
return {
|
|
377
|
+
...group,
|
|
378
|
+
id: `${group.field}__${group.pattern}`,
|
|
379
|
+
};
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
if (config.editor && !collection.editor) {
|
|
383
|
+
collection.editor = { preview: config.editor.preview };
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export function parseConfig(data: string) {
|
|
390
|
+
const config = yaml.parse(data, { maxAliasCount: -1, prettyErrors: true, merge: true });
|
|
391
|
+
if (
|
|
392
|
+
typeof window !== 'undefined' &&
|
|
393
|
+
typeof window.CMS_ENV === 'string' &&
|
|
394
|
+
config[window.CMS_ENV]
|
|
395
|
+
) {
|
|
396
|
+
const configKeys = Object.keys(config[window.CMS_ENV]) as ReadonlyArray<keyof CmsConfig>;
|
|
397
|
+
for (const key of configKeys) {
|
|
398
|
+
config[key] = config[window.CMS_ENV][key] as CmsConfig[keyof CmsConfig];
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return config as Partial<CmsConfig>;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
async function getConfigYaml(file: string, hasManualConfig: boolean) {
|
|
405
|
+
const response = await fetch(file, { credentials: 'same-origin' }).catch(error => error as Error);
|
|
406
|
+
if (response instanceof Error || response.status !== 200) {
|
|
407
|
+
if (hasManualConfig) {
|
|
408
|
+
return {};
|
|
409
|
+
}
|
|
410
|
+
const message = response instanceof Error ? response.message : response.status;
|
|
411
|
+
throw new Error(`Failed to load config.yml (${message})`);
|
|
412
|
+
}
|
|
413
|
+
const contentType = response.headers.get('Content-Type') || 'Not-Found';
|
|
414
|
+
const isYaml = contentType.indexOf('yaml') !== -1;
|
|
415
|
+
if (!isYaml) {
|
|
416
|
+
console.log(`Response for ${file} was not yaml. (Content-Type: ${contentType})`);
|
|
417
|
+
if (hasManualConfig) {
|
|
418
|
+
return {};
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return parseConfig(await response.text());
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export function configLoaded(config: CmsConfig) {
|
|
425
|
+
return {
|
|
426
|
+
type: CONFIG_SUCCESS,
|
|
427
|
+
payload: config,
|
|
428
|
+
} as const;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export function configLoading() {
|
|
432
|
+
return {
|
|
433
|
+
type: CONFIG_REQUEST,
|
|
434
|
+
} as const;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export function configFailed(err: Error) {
|
|
438
|
+
return {
|
|
439
|
+
type: CONFIG_FAILURE,
|
|
440
|
+
error: 'Error loading config',
|
|
441
|
+
payload: err,
|
|
442
|
+
} as const;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export async function detectProxyServer(localBackend?: boolean | CmsLocalBackend) {
|
|
446
|
+
const allowedHosts = [
|
|
447
|
+
'localhost',
|
|
448
|
+
'127.0.0.1',
|
|
449
|
+
...(typeof localBackend === 'boolean' ? [] : localBackend?.allowed_hosts || []),
|
|
450
|
+
];
|
|
451
|
+
|
|
452
|
+
if (!allowedHosts.includes(location.hostname) || !localBackend) {
|
|
453
|
+
return {};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const defaultUrl = 'http://localhost:8081/api/v1';
|
|
457
|
+
const proxyUrl =
|
|
458
|
+
localBackend === true
|
|
459
|
+
? defaultUrl
|
|
460
|
+
: localBackend.url || defaultUrl.replace('localhost', location.hostname);
|
|
461
|
+
|
|
462
|
+
try {
|
|
463
|
+
const { protocol } = new URL(proxyUrl);
|
|
464
|
+
if (protocol !== 'http:' && protocol !== 'https:') {
|
|
465
|
+
console.log(`Decap CMS local_backend url must use http or https, ignoring '${proxyUrl}'`);
|
|
466
|
+
return {};
|
|
467
|
+
}
|
|
468
|
+
} catch {
|
|
469
|
+
console.log(`Decap CMS local_backend url '${proxyUrl}' is not a valid URL`);
|
|
470
|
+
return {};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
try {
|
|
474
|
+
console.log(`Looking for Decap CMS Proxy Server at '${proxyUrl}'`);
|
|
475
|
+
const res = await fetch(`${proxyUrl}`, {
|
|
476
|
+
method: 'POST',
|
|
477
|
+
headers: { 'Content-Type': 'application/json' },
|
|
478
|
+
body: JSON.stringify({ action: 'info' }),
|
|
479
|
+
});
|
|
480
|
+
const { repo, publish_modes, type } = (await res.json()) as {
|
|
481
|
+
repo?: string;
|
|
482
|
+
publish_modes?: CmsPublishMode[];
|
|
483
|
+
type?: string;
|
|
484
|
+
};
|
|
485
|
+
if (typeof repo === 'string' && Array.isArray(publish_modes) && typeof type === 'string') {
|
|
486
|
+
console.log(`Detected Decap CMS Proxy Server at '${proxyUrl}' with repo: '${repo}'`);
|
|
487
|
+
return { proxyUrl, publish_modes, type };
|
|
488
|
+
} else {
|
|
489
|
+
console.log(`Decap CMS Proxy Server not detected at '${proxyUrl}'`);
|
|
490
|
+
return {};
|
|
491
|
+
}
|
|
492
|
+
} catch {
|
|
493
|
+
console.log(`Decap CMS Proxy Server not detected at '${proxyUrl}'`);
|
|
494
|
+
return {};
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function getPublishMode(config: CmsConfig, publishModes?: CmsPublishMode[], backendType?: string) {
|
|
499
|
+
if (config.publish_mode && publishModes && !publishModes.includes(config.publish_mode)) {
|
|
500
|
+
const newPublishMode = publishModes[0];
|
|
501
|
+
console.log(
|
|
502
|
+
`'${config.publish_mode}' is not supported by '${backendType}' backend, switching to '${newPublishMode}'`,
|
|
503
|
+
);
|
|
504
|
+
return newPublishMode;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return config.publish_mode;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export async function handleLocalBackend(originalConfig: CmsConfig) {
|
|
511
|
+
if (!originalConfig.local_backend) {
|
|
512
|
+
return originalConfig;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const {
|
|
516
|
+
proxyUrl,
|
|
517
|
+
publish_modes: publishModes,
|
|
518
|
+
type: backendType,
|
|
519
|
+
} = await detectProxyServer(originalConfig.local_backend);
|
|
520
|
+
|
|
521
|
+
if (!proxyUrl) {
|
|
522
|
+
return originalConfig;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
return produce(originalConfig, config => {
|
|
526
|
+
config.backend.name = 'proxy';
|
|
527
|
+
config.backend.proxy_url = proxyUrl;
|
|
528
|
+
|
|
529
|
+
if (config.publish_mode) {
|
|
530
|
+
config.publish_mode = getPublishMode(config, publishModes, backendType);
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
export function loadConfig(manualConfig: Partial<CmsConfig> = {}, onLoad: () => unknown) {
|
|
536
|
+
if (window.CMS_CONFIG) {
|
|
537
|
+
return configLoaded(window.CMS_CONFIG);
|
|
538
|
+
}
|
|
539
|
+
return async (dispatch: ThunkDispatch<State, {}, AnyAction>) => {
|
|
540
|
+
dispatch(configLoading());
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
const configUrl = getConfigUrl();
|
|
544
|
+
const hasManualConfig = !isEmpty(manualConfig);
|
|
545
|
+
const configYaml =
|
|
546
|
+
manualConfig.load_config_file === false
|
|
547
|
+
? {}
|
|
548
|
+
: await getConfigYaml(configUrl, hasManualConfig);
|
|
549
|
+
|
|
550
|
+
// Merge manual config into the config.yml one
|
|
551
|
+
const mergedConfig = deepmerge(configYaml, manualConfig);
|
|
552
|
+
|
|
553
|
+
validateConfig(mergedConfig);
|
|
554
|
+
|
|
555
|
+
const withLocalBackend = await handleLocalBackend(mergedConfig);
|
|
556
|
+
const normalizedConfig = normalizeConfig(withLocalBackend);
|
|
557
|
+
|
|
558
|
+
const config = applyDefaults(normalizedConfig);
|
|
559
|
+
|
|
560
|
+
dispatch(configLoaded(config));
|
|
561
|
+
|
|
562
|
+
if (typeof onLoad === 'function') {
|
|
563
|
+
onLoad();
|
|
564
|
+
}
|
|
565
|
+
} catch (err) {
|
|
566
|
+
dispatch(configFailed(err));
|
|
567
|
+
throw err;
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
export type ConfigAction = ReturnType<
|
|
573
|
+
typeof configLoading | typeof configLoaded | typeof configFailed
|
|
574
|
+
>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { currentBackend } from '../backend';
|
|
2
|
+
import { selectDeployPreview } from '../reducers';
|
|
3
|
+
import { addNotification } from './notifications';
|
|
4
|
+
|
|
5
|
+
import type { ThunkDispatch } from 'redux-thunk';
|
|
6
|
+
import type { AnyAction } from 'redux';
|
|
7
|
+
import type { Collection, Entry, State } from '../types/redux';
|
|
8
|
+
|
|
9
|
+
export const DEPLOY_PREVIEW_REQUEST = 'DEPLOY_PREVIEW_REQUEST';
|
|
10
|
+
export const DEPLOY_PREVIEW_SUCCESS = 'DEPLOY_PREVIEW_SUCCESS';
|
|
11
|
+
export const DEPLOY_PREVIEW_FAILURE = 'DEPLOY_PREVIEW_FAILURE';
|
|
12
|
+
|
|
13
|
+
function deployPreviewLoading(collection: string, slug: string) {
|
|
14
|
+
return {
|
|
15
|
+
type: DEPLOY_PREVIEW_REQUEST,
|
|
16
|
+
payload: {
|
|
17
|
+
collection,
|
|
18
|
+
slug,
|
|
19
|
+
},
|
|
20
|
+
} as const;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function deployPreviewLoaded(
|
|
24
|
+
collection: string,
|
|
25
|
+
slug: string,
|
|
26
|
+
deploy: { url: string | undefined; status: string },
|
|
27
|
+
) {
|
|
28
|
+
const { url, status } = deploy;
|
|
29
|
+
return {
|
|
30
|
+
type: DEPLOY_PREVIEW_SUCCESS,
|
|
31
|
+
payload: {
|
|
32
|
+
collection,
|
|
33
|
+
slug,
|
|
34
|
+
url,
|
|
35
|
+
status,
|
|
36
|
+
},
|
|
37
|
+
} as const;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function deployPreviewError(collection: string, slug: string) {
|
|
41
|
+
return {
|
|
42
|
+
type: DEPLOY_PREVIEW_FAILURE,
|
|
43
|
+
payload: {
|
|
44
|
+
collection,
|
|
45
|
+
slug,
|
|
46
|
+
},
|
|
47
|
+
} as const;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Requests a deploy preview object from the registered backend.
|
|
52
|
+
*/
|
|
53
|
+
export function loadDeployPreview(
|
|
54
|
+
collection: Collection,
|
|
55
|
+
slug: string,
|
|
56
|
+
entry: Entry,
|
|
57
|
+
published: boolean,
|
|
58
|
+
opts?: { maxAttempts?: number; interval?: number; signal?: AbortSignal },
|
|
59
|
+
) {
|
|
60
|
+
return async (dispatch: ThunkDispatch<State, undefined, AnyAction>, getState: () => State) => {
|
|
61
|
+
const state = getState();
|
|
62
|
+
const backend = currentBackend(state.config);
|
|
63
|
+
const collectionName = collection.get('name');
|
|
64
|
+
|
|
65
|
+
// Exit if currently fetching, unless the caller provides a signal
|
|
66
|
+
// (indicating it manages cancellation of the previous poll externally).
|
|
67
|
+
const deployState = selectDeployPreview(state, collectionName, slug);
|
|
68
|
+
if (deployState && deployState.isFetching && !opts?.signal) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
dispatch(deployPreviewLoading(collectionName, slug));
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
/**
|
|
76
|
+
* `getDeploy` is for published entries, while `getDeployPreview` is for
|
|
77
|
+
* unpublished entries.
|
|
78
|
+
*/
|
|
79
|
+
const deploy = published
|
|
80
|
+
? backend.getDeploy(collection, slug, entry)
|
|
81
|
+
: await backend.getDeployPreview(collection, slug, entry, opts);
|
|
82
|
+
if (deploy) {
|
|
83
|
+
return dispatch(deployPreviewLoaded(collectionName, slug, deploy));
|
|
84
|
+
}
|
|
85
|
+
return dispatch(deployPreviewError(collectionName, slug));
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error(error);
|
|
88
|
+
dispatch(
|
|
89
|
+
addNotification({
|
|
90
|
+
message: {
|
|
91
|
+
details: error.message,
|
|
92
|
+
key: 'ui.toast.onFailToLoadDeployPreview',
|
|
93
|
+
},
|
|
94
|
+
type: 'error',
|
|
95
|
+
dismissAfter: 8000,
|
|
96
|
+
}),
|
|
97
|
+
);
|
|
98
|
+
dispatch(deployPreviewError(collectionName, slug));
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export type DeploysAction = ReturnType<
|
|
104
|
+
typeof deployPreviewLoading | typeof deployPreviewLoaded | typeof deployPreviewError
|
|
105
|
+
>;
|