@nascentdigital/funnel-editor-contentful 4.6.7 → 5.0.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.
- package/dist/Editor.d.ts +6 -1
- package/dist/Editor.js +17 -1
- package/dist/EditorApp.js +1 -1
- package/dist/EntryEditor.js +42 -1
- package/dist/EntrySidebar.js +18 -1
- package/dist/collection/controller/LocalCollectionController.d.ts +35 -0
- package/dist/collection/controller/LocalCollectionController.js +200 -0
- package/dist/collection/controller/LocalCollectionControllerContainer.d.ts +8 -0
- package/dist/collection/controller/LocalCollectionControllerContainer.js +36 -0
- package/dist/collection/controller/LocalCollectionControllerContext.d.ts +7 -0
- package/dist/collection/controller/LocalCollectionControllerContext.js +6 -0
- package/dist/collection/controller/index.d.ts +4 -0
- package/dist/collection/controller/index.js +20 -0
- package/dist/collection/controller/useLocalCollectionController.d.ts +2 -0
- package/dist/collection/controller/useLocalCollectionController.js +10 -0
- package/dist/collection/index.d.ts +2 -0
- package/dist/collection/index.js +18 -0
- package/dist/collection/screens/CollectionEditor.d.ts +1 -0
- package/dist/collection/screens/CollectionEditor.js +42 -0
- package/dist/collection/screens/index.d.ts +1 -0
- package/dist/{page/hooks → collection/screens}/index.js +1 -1
- package/dist/core/bridge/AppBridgeContainer.d.ts +9 -0
- package/dist/core/bridge/AppBridgeContainer.js +55 -0
- package/dist/core/bridge/AppBridgeContext.d.ts +8 -0
- package/dist/core/bridge/AppBridgeContext.js +11 -0
- package/dist/core/bridge/AppMessage.d.ts +19 -0
- package/dist/core/bridge/AppMessage.js +19 -0
- package/dist/core/bridge/index.d.ts +4 -0
- package/dist/core/bridge/index.js +20 -0
- package/dist/core/bridge/useAppBridge.d.ts +8 -0
- package/dist/core/bridge/useAppBridge.js +24 -0
- package/dist/core/contentful/Contentful.d.ts +33 -0
- package/dist/core/contentful/Contentful.js +67 -0
- package/dist/core/contentful/ContentfulAsset.d.ts +23 -0
- package/dist/core/contentful/ContentfulAsset.js +88 -0
- package/dist/core/contentful/ContentfulCollection.d.ts +29 -0
- package/dist/core/contentful/ContentfulCollection.js +97 -0
- package/dist/core/contentful/ContentfulPage.d.ts +31 -0
- package/dist/core/contentful/ContentfulPage.js +84 -0
- package/dist/core/contentful/ContentfulRefs.d.ts +16 -0
- package/dist/core/contentful/ContentfulRefs.js +152 -0
- package/dist/core/contentful/index.d.ts +5 -0
- package/dist/core/contentful/index.js +21 -0
- package/dist/core/domain/Collection.d.ts +99 -0
- package/dist/core/domain/Collection.js +311 -0
- package/dist/core/domain/Page.d.ts +58 -8
- package/dist/core/domain/Page.js +329 -16
- package/dist/core/domain/index.d.ts +1 -0
- package/dist/core/domain/index.js +1 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +2 -0
- package/dist/core/repository/AssetRepository.d.ts +10 -0
- package/dist/core/repository/AssetRepository.js +33 -0
- package/dist/core/repository/CollectionSerializer.d.ts +9 -0
- package/dist/core/repository/CollectionSerializer.js +41 -0
- package/dist/core/repository/LocalCollectionRepository.d.ts +27 -0
- package/dist/core/repository/LocalCollectionRepository.js +143 -0
- package/dist/core/repository/LocalPageRepository.d.ts +16 -0
- package/dist/core/repository/LocalPageRepository.js +153 -0
- package/dist/core/repository/PageSerializer.d.ts +2 -2
- package/dist/core/repository/PageSerializer.js +16 -13
- package/dist/core/repository/RemoteCollectionRepository.d.ts +19 -0
- package/dist/core/repository/RemoteCollectionRepository.js +236 -0
- package/dist/core/repository/RemotePageRepository.d.ts +14 -0
- package/dist/core/repository/RemotePageRepository.js +113 -0
- package/dist/core/repository/index.d.ts +5 -1
- package/dist/core/repository/index.js +5 -1
- package/dist/page/{hooks/PageController.d.ts → controller/LocalPageController.d.ts} +11 -6
- package/dist/page/controller/LocalPageController.js +190 -0
- package/dist/page/controller/LocalPageControllerContainer.d.ts +8 -0
- package/dist/page/controller/LocalPageControllerContainer.js +36 -0
- package/dist/page/controller/LocalPageControllerContext.d.ts +7 -0
- package/dist/page/controller/LocalPageControllerContext.js +6 -0
- package/dist/page/controller/index.d.ts +3 -0
- package/dist/page/controller/index.js +19 -0
- package/dist/page/controller/useLocalPageController.d.ts +2 -0
- package/dist/page/controller/useLocalPageController.js +10 -0
- package/dist/page/index.d.ts +1 -0
- package/dist/page/index.js +1 -0
- package/dist/page/screens/PageEditor.js +9 -11
- package/package.json +5 -3
- package/dist/core/repository/PageRepository.d.ts +0 -12
- package/dist/core/repository/PageRepository.js +0 -23
- package/dist/page/hooks/PageController.js +0 -107
- package/dist/page/hooks/index.d.ts +0 -1
package/dist/Editor.d.ts
CHANGED
package/dist/Editor.js
CHANGED
|
@@ -3,8 +3,24 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Editor = Editor;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_apps_toolkit_1 = require("@contentful/react-apps-toolkit");
|
|
6
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
7
|
+
const react_1 = require("react");
|
|
6
8
|
const EditorApp_1 = require("./EditorApp");
|
|
7
9
|
// wrapper around editor app to provide Contentful SDK
|
|
8
|
-
function Editor() {
|
|
10
|
+
function Editor({ fonts }) {
|
|
11
|
+
// bind font to root on mount
|
|
12
|
+
(0, react_1.useEffect)(() => {
|
|
13
|
+
// skip if there are no fonts or HTML root
|
|
14
|
+
const html = funnel_core_1.Browser.getHtml();
|
|
15
|
+
if (fonts.length === 0 || !html) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
// apply fonts (create a copy to unbind
|
|
19
|
+
const fontClasses = fonts.slice();
|
|
20
|
+
html.classList.add(...fontClasses);
|
|
21
|
+
// remove fonts on update
|
|
22
|
+
return () => html.classList.remove(...fontClasses);
|
|
23
|
+
}, [fonts]);
|
|
24
|
+
// render
|
|
9
25
|
return ((0, jsx_runtime_1.jsx)(react_apps_toolkit_1.SDKProvider, { children: (0, jsx_runtime_1.jsx)(EditorApp_1.EditorApp, {}) }));
|
|
10
26
|
}
|
package/dist/EditorApp.js
CHANGED
|
@@ -26,5 +26,5 @@ function EditorApp() {
|
|
|
26
26
|
content = (0, jsx_runtime_1.jsx)("div", { children: "Unsupported location" });
|
|
27
27
|
}
|
|
28
28
|
// render
|
|
29
|
-
return ((0, jsx_runtime_1.jsx)(core_1.
|
|
29
|
+
return ((0, jsx_runtime_1.jsx)(components_1.AppStateContainer, { children: (0, jsx_runtime_1.jsx)(core_1.AppBridgeContainer, { children: (0, jsx_runtime_1.jsx)(core_1.EditorApiContainer, { children: content }) }) }));
|
|
30
30
|
}
|
package/dist/EntryEditor.js
CHANGED
|
@@ -2,8 +2,49 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EntryEditor = EntryEditor;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_apps_toolkit_1 = require("@contentful/react-apps-toolkit");
|
|
6
|
+
const components_1 = require("@nascentdigital/funnel-editor/components");
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
const collection_1 = require("./collection");
|
|
9
|
+
const core_1 = require("./core");
|
|
5
10
|
const page_1 = require("./page");
|
|
6
11
|
// entry editor
|
|
7
12
|
function EntryEditor() {
|
|
8
|
-
|
|
13
|
+
// hooks
|
|
14
|
+
const sdk = (0, react_apps_toolkit_1.useSDK)();
|
|
15
|
+
const appState = (0, components_1.useAppState)();
|
|
16
|
+
// create asset repository
|
|
17
|
+
const assetRepository = (0, react_1.useMemo)(() => {
|
|
18
|
+
return new core_1.AssetRepository(sdk);
|
|
19
|
+
}, [sdk]);
|
|
20
|
+
// create remote collection repository
|
|
21
|
+
const remoteCollectionRepository = (0, react_1.useMemo)(() => {
|
|
22
|
+
return new core_1.RemoteCollectionRepository(sdk);
|
|
23
|
+
}, [sdk]);
|
|
24
|
+
// create remote page repository
|
|
25
|
+
const remotePageRepository = (0, react_1.useMemo)(() => {
|
|
26
|
+
return new core_1.RemotePageRepository(sdk);
|
|
27
|
+
}, [sdk]);
|
|
28
|
+
// create collections context
|
|
29
|
+
const collectionsContext = (0, react_1.useMemo)(() => {
|
|
30
|
+
const collections = new components_1.Collections({ appState, repository: remoteCollectionRepository });
|
|
31
|
+
return { collections };
|
|
32
|
+
}, [appState, remoteCollectionRepository]);
|
|
33
|
+
// create site context
|
|
34
|
+
const siteContext = (0, react_1.useMemo)(() => {
|
|
35
|
+
const site = new components_1.Site({ appState, repository: remotePageRepository, region: 'ca' });
|
|
36
|
+
return { site };
|
|
37
|
+
}, [appState, remotePageRepository]);
|
|
38
|
+
// page editor
|
|
39
|
+
let content;
|
|
40
|
+
const { contentType: { sys: { id } } } = sdk.entry.getSys();
|
|
41
|
+
if (id === core_1.ContentfulPage.contentTypeId) {
|
|
42
|
+
content = ((0, jsx_runtime_1.jsx)(page_1.LocalPageControllerContainer, { remoteRepository: remotePageRepository, children: (0, jsx_runtime_1.jsx)(page_1.PageEditor, {}) }));
|
|
43
|
+
}
|
|
44
|
+
// collection editor
|
|
45
|
+
else if (id === core_1.ContentfulCollection.contentTypeId) {
|
|
46
|
+
content = ((0, jsx_runtime_1.jsx)(collection_1.LocalCollectionControllerContainer, { remoteRepository: remoteCollectionRepository, children: (0, jsx_runtime_1.jsx)(collection_1.CollectionEditor, {}) }));
|
|
47
|
+
}
|
|
48
|
+
// render
|
|
49
|
+
return ((0, jsx_runtime_1.jsx)(components_1.SiteContext.Provider, { value: siteContext, children: (0, jsx_runtime_1.jsx)(components_1.AssetRepositoryContext.Provider, { value: assetRepository, children: (0, jsx_runtime_1.jsx)(components_1.CollectionRepositoryContext.Provider, { value: remoteCollectionRepository, children: (0, jsx_runtime_1.jsx)(components_1.CollectionsContext.Provider, { value: collectionsContext, children: (0, jsx_runtime_1.jsx)(components_1.DialogContainer, { children: (0, jsx_runtime_1.jsx)(components_1.CenterSheetContainer, { children: content }) }) }) }) }) }));
|
|
9
50
|
}
|
package/dist/EntrySidebar.js
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EntrySidebar = EntrySidebar;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const rxjs_1 = require("rxjs");
|
|
7
|
+
const core_1 = require("./core");
|
|
8
|
+
// component
|
|
5
9
|
function EntrySidebar() {
|
|
6
|
-
|
|
10
|
+
// setup hooks
|
|
11
|
+
const bridge = (0, core_1.useAppBridge)();
|
|
12
|
+
const [itemId, setItemId] = (0, react_1.useState)();
|
|
13
|
+
// listen to bridge events
|
|
14
|
+
(0, react_1.useEffect)(() => {
|
|
15
|
+
// subscribe to block nav messages
|
|
16
|
+
const subscription = bridge.messages$
|
|
17
|
+
.pipe((0, rxjs_1.filter)(core_1.AppBlockNavMessage.guard))
|
|
18
|
+
.subscribe(message => setItemId(message.itemId));
|
|
19
|
+
// unsubscribe on unmount
|
|
20
|
+
return () => subscription.unsubscribe();
|
|
21
|
+
});
|
|
22
|
+
// render
|
|
23
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: ["Entry sidebar ", itemId] }));
|
|
7
24
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { CollectionGroup, CollectionTarget, ICollection, ICollectionController } from '@nascentdigital/funnel-editor/components';
|
|
2
|
+
import { type Observable } from 'rxjs';
|
|
3
|
+
import { Collection, LocalCollectionRepository, RemoteCollectionRepository } from '../../core';
|
|
4
|
+
export declare class LocalCollectionController implements ICollectionController {
|
|
5
|
+
readonly localRepository: LocalCollectionRepository;
|
|
6
|
+
readonly remoteRepository: RemoteCollectionRepository;
|
|
7
|
+
private readonly _eventBus;
|
|
8
|
+
private _state;
|
|
9
|
+
private _collectionGroup?;
|
|
10
|
+
private _collection?;
|
|
11
|
+
private _subscription?;
|
|
12
|
+
constructor({ localRepository, remoteRepository }: LocalCollectionController.ConstructorArgs);
|
|
13
|
+
get events$(): Observable<ICollectionController.Event | ICollection.Event>;
|
|
14
|
+
get state(): ICollectionController.State;
|
|
15
|
+
private set state(value);
|
|
16
|
+
get ready(): boolean;
|
|
17
|
+
get languages(): ("id" | "ca" | "en" | "aa" | "ab" | "ae" | "af" | "ak" | "am" | "an" | "ar" | "as" | "av" | "ay" | "az" | "ba" | "be" | "bg" | "bh" | "bi" | "bm" | "bn" | "bo" | "br" | "bs" | "ce" | "ch" | "co" | "cr" | "cs" | "cu" | "cv" | "cy" | "da" | "de" | "dv" | "dz" | "ee" | "el" | "eo" | "es" | "et" | "eu" | "fa" | "ff" | "fi" | "fj" | "fo" | "fr" | "fy" | "ga" | "gd" | "gl" | "gn" | "gu" | "gv" | "ha" | "he" | "hi" | "ho" | "hr" | "ht" | "hu" | "hy" | "hz" | "ia" | "ie" | "ig" | "ii" | "ik" | "io" | "is" | "it" | "iu" | "ja" | "jv" | "ka" | "kg" | "ki" | "kj" | "kk" | "kl" | "km" | "kn" | "ko" | "kr" | "ks" | "ku" | "kv" | "kw" | "ky" | "la" | "lb" | "lg" | "li" | "ln" | "lo" | "lt" | "lu" | "lv" | "mg" | "mh" | "mi" | "mk" | "ml" | "mn" | "mr" | "ms" | "mt" | "my" | "na" | "nb" | "nd" | "ne" | "ng" | "nl" | "nn" | "no" | "nr" | "nv" | "ny" | "oc" | "oj" | "om" | "or" | "os" | "pa" | "pi" | "pl" | "ps" | "pt" | "qu" | "rm" | "rn" | "ro" | "ru" | "rw" | "sa" | "sc" | "sd" | "se" | "sg" | "si" | "sk" | "sl" | "sm" | "sn" | "so" | "sq" | "sr" | "ss" | "st" | "su" | "sv" | "sw" | "ta" | "te" | "tg" | "th" | "ti" | "tk" | "tl" | "tn" | "to" | "tr" | "ts" | "tt" | "tw" | "ty" | "ug" | "uk" | "ur" | "uz" | "ve" | "vi" | "vo" | "wa" | "wo" | "xh" | "yi" | "yo" | "za" | "zh" | "zu")[];
|
|
18
|
+
get collectionGroup(): CollectionGroup | undefined;
|
|
19
|
+
private set collectionGroup(value);
|
|
20
|
+
get collection(): Collection | undefined;
|
|
21
|
+
set collection(collection: Collection | undefined);
|
|
22
|
+
sync(updatedOn: number): Promise<void>;
|
|
23
|
+
load(): Promise<void>;
|
|
24
|
+
createLanguage(target: CollectionTarget): Promise<void>;
|
|
25
|
+
unpublish(): Promise<void>;
|
|
26
|
+
save(collection: Collection): Promise<void>;
|
|
27
|
+
reload(): Promise<void>;
|
|
28
|
+
private raiseEvent;
|
|
29
|
+
}
|
|
30
|
+
export declare namespace LocalCollectionController {
|
|
31
|
+
type ConstructorArgs = {
|
|
32
|
+
localRepository: LocalCollectionRepository;
|
|
33
|
+
remoteRepository: RemoteCollectionRepository;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalCollectionController = void 0;
|
|
4
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
5
|
+
const components_1 = require("@nascentdigital/funnel-editor/components");
|
|
6
|
+
const rxjs_1 = require("rxjs");
|
|
7
|
+
// class
|
|
8
|
+
class LocalCollectionController {
|
|
9
|
+
constructor({ localRepository, remoteRepository }) {
|
|
10
|
+
// initialize instance variables
|
|
11
|
+
this.localRepository = localRepository;
|
|
12
|
+
this.remoteRepository = remoteRepository;
|
|
13
|
+
this._eventBus = new funnel_core_1.EventBus();
|
|
14
|
+
this._state = 'uninitialized';
|
|
15
|
+
}
|
|
16
|
+
get events$() {
|
|
17
|
+
return this._eventBus.events$
|
|
18
|
+
.pipe((0, rxjs_1.filter)(e => components_1.ICollectionController.Event.filter(e) || components_1.ICollection.Event.filter(e)));
|
|
19
|
+
}
|
|
20
|
+
get state() {
|
|
21
|
+
return this._state;
|
|
22
|
+
}
|
|
23
|
+
set state(value) {
|
|
24
|
+
// skip if unchanged
|
|
25
|
+
if (this._state === value) {
|
|
26
|
+
console.debug('[CollectionController/state] skipping redundant update', value);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// or update
|
|
30
|
+
this._state = value;
|
|
31
|
+
console.debug('[CollectionController/state] updated state', value);
|
|
32
|
+
// raise event
|
|
33
|
+
this.raiseEvent('state.changed');
|
|
34
|
+
}
|
|
35
|
+
get ready() {
|
|
36
|
+
const { _state } = this;
|
|
37
|
+
return _state !== 'uninitialized' && _state !== 'initializing';
|
|
38
|
+
}
|
|
39
|
+
get languages() {
|
|
40
|
+
const brand = funnel_core_1.AppConfig.brandConfig();
|
|
41
|
+
return funnel_core_1.RegionsConfig.getLanguages(brand.regionalization);
|
|
42
|
+
}
|
|
43
|
+
get collectionGroup() {
|
|
44
|
+
return this._collectionGroup;
|
|
45
|
+
}
|
|
46
|
+
set collectionGroup(collectionGroup) {
|
|
47
|
+
// skip if group is the same
|
|
48
|
+
if (this._collectionGroup === collectionGroup) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// update group
|
|
52
|
+
this._collectionGroup = collectionGroup;
|
|
53
|
+
// raise event
|
|
54
|
+
this.raiseEvent('collectionGroup.changed');
|
|
55
|
+
}
|
|
56
|
+
get collection() {
|
|
57
|
+
return this._collection;
|
|
58
|
+
}
|
|
59
|
+
set collection(collection) {
|
|
60
|
+
// skip if collection is the same
|
|
61
|
+
if (this._collection === collection) {
|
|
62
|
+
console.debug('[CE][CollectionController] ignoring collection change for', collection);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// unbind previous subscription (if any)
|
|
66
|
+
if (this._subscription) {
|
|
67
|
+
this._subscription.unsubscribe();
|
|
68
|
+
delete this._subscription;
|
|
69
|
+
}
|
|
70
|
+
console.debug('[CE][CollectionController] updating to new collection', collection);
|
|
71
|
+
// update collection
|
|
72
|
+
this._collection = collection;
|
|
73
|
+
// subscribe to collection changes
|
|
74
|
+
if (collection) {
|
|
75
|
+
this._subscription = collection.events$
|
|
76
|
+
.pipe((0, rxjs_1.filter)(e => {
|
|
77
|
+
// handle collection events
|
|
78
|
+
if (components_1.ICollection.Event.filter(e)) {
|
|
79
|
+
return e.type === 'modified';
|
|
80
|
+
}
|
|
81
|
+
// or item/object/list events
|
|
82
|
+
else if (components_1.Item.Event.filter(e)
|
|
83
|
+
|| components_1.Item.Event.filter(e)
|
|
84
|
+
|| funnel_core_1.ObjectField.Event.filter(e)
|
|
85
|
+
|| funnel_core_1.FieldList.Event.filter(e)) {
|
|
86
|
+
return e.type === 'changed';
|
|
87
|
+
}
|
|
88
|
+
// or field
|
|
89
|
+
else {
|
|
90
|
+
return funnel_core_1.Field.Event.filter(e) && (e.type === 'changed' || e.type === 'reset');
|
|
91
|
+
}
|
|
92
|
+
}), (0, rxjs_1.debounce)(e => {
|
|
93
|
+
if ((components_1.ICollection.Event.filter(e) && e.type === 'modified')
|
|
94
|
+
|| components_1.Item.Event.filter(e)
|
|
95
|
+
|| funnel_core_1.FieldList.Event.filter(e)
|
|
96
|
+
|| (funnel_core_1.Field.Event.filter(e) && e.field.isComposite)) {
|
|
97
|
+
return (0, rxjs_1.interval)(0);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
return (0, rxjs_1.interval)(2000);
|
|
101
|
+
}
|
|
102
|
+
}))
|
|
103
|
+
.subscribe(async () => {
|
|
104
|
+
if (collection.modified && this._collection === collection) {
|
|
105
|
+
console.debug('[CE][CollectionController] saving modified collection', collection);
|
|
106
|
+
await this.save(collection);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.debug('[CE][CollectionController] ignoring change for zombie collection', collection);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// raise event
|
|
114
|
+
this.raiseEvent('collection.changed');
|
|
115
|
+
}
|
|
116
|
+
async sync(updatedOn) {
|
|
117
|
+
// get current collection
|
|
118
|
+
const collection = this._collection;
|
|
119
|
+
// bail if no collection
|
|
120
|
+
if (!collection) {
|
|
121
|
+
console.warn('[CE][CollectionController] tried to sync with no collection');
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// skip if page already in sync
|
|
125
|
+
if (collection.updatedOn >= updatedOn) {
|
|
126
|
+
console.debug('[CE][CollectionController] skipping sync, collection already in sync');
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
// skip if saving already
|
|
130
|
+
if (this.state === 'saving') {
|
|
131
|
+
console.debug('[CE][CollectionController] skipping sync while saving');
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// start fresh load
|
|
135
|
+
console.debug('[CE][CollectionController] syncing, page out of date...');
|
|
136
|
+
await this.load();
|
|
137
|
+
}
|
|
138
|
+
async load() {
|
|
139
|
+
// mark as loading (or initialing if loading for first time)
|
|
140
|
+
this.state = this._state === 'uninitialized'
|
|
141
|
+
? 'initializing'
|
|
142
|
+
: 'loading';
|
|
143
|
+
// try to fetch collection
|
|
144
|
+
try {
|
|
145
|
+
// load collection
|
|
146
|
+
const collection = await this.localRepository.load({ eventBus: this._eventBus });
|
|
147
|
+
// get collection references
|
|
148
|
+
if (collection) {
|
|
149
|
+
const references = await this.remoteRepository.getReferences(collection.id);
|
|
150
|
+
collection.hydrateStores(references);
|
|
151
|
+
}
|
|
152
|
+
// set collection
|
|
153
|
+
// TODO: create real collection group
|
|
154
|
+
this._collectionGroup = new components_1.CollectionGroup({ collections: [] });
|
|
155
|
+
this.collection = collection;
|
|
156
|
+
// update state
|
|
157
|
+
this.state = 'ready';
|
|
158
|
+
}
|
|
159
|
+
// handle load error
|
|
160
|
+
catch (e) {
|
|
161
|
+
console.error('[CollectionController] failed to load collection', e);
|
|
162
|
+
// TODO: expose error
|
|
163
|
+
// set error state
|
|
164
|
+
this.state = 'error';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async createLanguage(target) {
|
|
168
|
+
throw new funnel_core_1.NotImplementedError();
|
|
169
|
+
}
|
|
170
|
+
async unpublish() {
|
|
171
|
+
throw new funnel_core_1.NotImplementedError();
|
|
172
|
+
}
|
|
173
|
+
async save(collection) {
|
|
174
|
+
// try to save collection
|
|
175
|
+
try {
|
|
176
|
+
console.debug('[CE][CollectionController/save] starting save');
|
|
177
|
+
// update state
|
|
178
|
+
this.state = 'saving';
|
|
179
|
+
// save page
|
|
180
|
+
const updatedCollection = await this.localRepository.save(collection);
|
|
181
|
+
this.collection = updatedCollection;
|
|
182
|
+
// update state
|
|
183
|
+
this.state = 'ready';
|
|
184
|
+
console.debug('[CE][CollectionController/save] save finished');
|
|
185
|
+
}
|
|
186
|
+
// handle error
|
|
187
|
+
catch (e) {
|
|
188
|
+
console.error('[CE][CollectionController/save] save failed', e);
|
|
189
|
+
// update state
|
|
190
|
+
this.state = 'error';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async reload() {
|
|
194
|
+
throw new funnel_core_1.NotImplementedError();
|
|
195
|
+
}
|
|
196
|
+
raiseEvent(type) {
|
|
197
|
+
this._eventBus.publish(components_1.ICollectionController.Event.create({ type, controller: this }));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
exports.LocalCollectionController = LocalCollectionController;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { RemoteCollectionRepository } from '../../core';
|
|
3
|
+
export declare function LocalCollectionControllerContainer({ children, remoteRepository }: LocalCollectionControllerContainer.Props): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare namespace LocalCollectionControllerContainer {
|
|
5
|
+
type Props = PropsWithChildren & {
|
|
6
|
+
remoteRepository: RemoteCollectionRepository;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalCollectionControllerContainer = LocalCollectionControllerContainer;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_apps_toolkit_1 = require("@contentful/react-apps-toolkit");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const core_1 = require("../../core");
|
|
8
|
+
const LocalCollectionController_1 = require("./LocalCollectionController");
|
|
9
|
+
const LocalCollectionControllerContext_1 = require("./LocalCollectionControllerContext");
|
|
10
|
+
// container
|
|
11
|
+
function LocalCollectionControllerContainer({ children, remoteRepository }) {
|
|
12
|
+
// bind context
|
|
13
|
+
const sdk = (0, react_apps_toolkit_1.useSDK)();
|
|
14
|
+
const context = (0, react_1.useMemo)(() => {
|
|
15
|
+
console.debug('[CE][CollectionControllerContainer] creating collection controller');
|
|
16
|
+
const localRepository = new core_1.LocalCollectionRepository(sdk);
|
|
17
|
+
// return context
|
|
18
|
+
return {
|
|
19
|
+
controller: new LocalCollectionController_1.LocalCollectionController({ localRepository, remoteRepository })
|
|
20
|
+
};
|
|
21
|
+
}, [sdk, remoteRepository]);
|
|
22
|
+
// list to collection changes
|
|
23
|
+
(0, react_1.useEffect)(() => {
|
|
24
|
+
// get controller
|
|
25
|
+
const { controller } = context;
|
|
26
|
+
// sync on change
|
|
27
|
+
sdk.entry.onSysChanged(sys => {
|
|
28
|
+
// get updatedOn in milliseconds
|
|
29
|
+
const updatedOn = new Date(sys.updatedAt).getTime();
|
|
30
|
+
// call sync
|
|
31
|
+
controller.sync(updatedOn).catch(console.error);
|
|
32
|
+
});
|
|
33
|
+
}, [sdk, context]);
|
|
34
|
+
// render
|
|
35
|
+
return ((0, jsx_runtime_1.jsx)(LocalCollectionControllerContext_1.LocalCollectionControllerContext.Provider, { value: context, children: children }));
|
|
36
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { LocalCollectionController } from './LocalCollectionController';
|
|
2
|
+
export declare const LocalCollectionControllerContext: import("react").Context<LocalCollectionControllerContext.Type>;
|
|
3
|
+
export declare namespace LocalCollectionControllerContext {
|
|
4
|
+
type Type = {
|
|
5
|
+
controller: LocalCollectionController;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./LocalCollectionController"), exports);
|
|
18
|
+
__exportStar(require("./LocalCollectionControllerContext"), exports);
|
|
19
|
+
__exportStar(require("./LocalCollectionControllerContainer"), exports);
|
|
20
|
+
__exportStar(require("./useLocalCollectionController"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useLocalCollectionController = useLocalCollectionController;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const LocalCollectionControllerContext_1 = require("./LocalCollectionControllerContext");
|
|
6
|
+
// hook
|
|
7
|
+
function useLocalCollectionController() {
|
|
8
|
+
// bind and return context
|
|
9
|
+
return (0, react_1.useContext)(LocalCollectionControllerContext_1.LocalCollectionControllerContext);
|
|
10
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./screens"), exports);
|
|
18
|
+
__exportStar(require("./controller"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function CollectionEditor(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CollectionEditor = CollectionEditor;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const components_1 = require("@nascentdigital/funnel-editor/components");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const controller_1 = require("../controller");
|
|
8
|
+
// component
|
|
9
|
+
function CollectionEditor() {
|
|
10
|
+
// hooks
|
|
11
|
+
const controllerContext = (0, controller_1.useLocalCollectionController)();
|
|
12
|
+
const { controller } = controllerContext;
|
|
13
|
+
const { collection } = controller;
|
|
14
|
+
const collectionContext = (0, react_1.useMemo)(() => ({ collection }), [collection]);
|
|
15
|
+
// sync with controller
|
|
16
|
+
(0, components_1.useCollectionController)(controller);
|
|
17
|
+
// load
|
|
18
|
+
(0, react_1.useEffect)(() => {
|
|
19
|
+
controller.load().catch(console.error);
|
|
20
|
+
}, [controller]);
|
|
21
|
+
// render
|
|
22
|
+
return ((0, jsx_runtime_1.jsx)(components_1.CollectionControllerContext.Provider, { value: controllerContext, children: (0, jsx_runtime_1.jsx)(components_1.CollectionContext.Provider, { value: collectionContext, children: (0, jsx_runtime_1.jsx)(components_1.AssetStoreContext.Provider, { value: collection, children: (0, jsx_runtime_1.jsx)(components_1.CollectionStoreContext.Provider, { value: collection, children: (0, jsx_runtime_1.jsx)("div", { className: "w-dvw h-dvh flex flex-col bg-background", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex-1", children: (0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 flex", children: (0, jsx_runtime_1.jsx)("section", { className: "flex-1 h-full max-h-full max-w-[1000px] mx-auto", children: renderContent({ controller }) }) }) }) }) }) }) }) }));
|
|
23
|
+
}
|
|
24
|
+
function renderContent({ controller }) {
|
|
25
|
+
// render loader if not ready
|
|
26
|
+
const { ready, collectionGroup, collection } = controller;
|
|
27
|
+
if (!ready) {
|
|
28
|
+
return ((0, jsx_runtime_1.jsx)(components_1.Loader, {}, "loader"));
|
|
29
|
+
}
|
|
30
|
+
// render error if there's no group
|
|
31
|
+
else if (!collectionGroup) {
|
|
32
|
+
return ((0, jsx_runtime_1.jsx)(components_1.EmptyState, { variant: "missing", size: "md", children: "Oops! This page doesn't seem to exist..." }));
|
|
33
|
+
}
|
|
34
|
+
// render create state if there's no group
|
|
35
|
+
else if (!collection) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
// otherwise render editor
|
|
39
|
+
else {
|
|
40
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "flex-1 flex flex-col gap-l10 px-l6 py-l10 overflow-y-scroll scrollbar-thin bg-background", children: (0, jsx_runtime_1.jsx)(components_1.FieldsPanel, { title: "Content", fields: collection.allFields }) }));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CollectionEditor';
|
|
@@ -14,4 +14,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./
|
|
17
|
+
__exportStar(require("./CollectionEditor"), exports);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export declare const CHANNEL_PREFIX = "funnel:channel:";
|
|
3
|
+
export declare function AppBridgeContainer({ children }: AppBridgeContainer.Props): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare namespace AppBridgeContainer {
|
|
5
|
+
type Props = {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export declare function getUniqueId(): string;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CHANNEL_PREFIX = void 0;
|
|
4
|
+
exports.AppBridgeContainer = AppBridgeContainer;
|
|
5
|
+
exports.getUniqueId = getUniqueId;
|
|
6
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
const rxjs_1 = require("rxjs");
|
|
9
|
+
const uuid_1 = require("uuid");
|
|
10
|
+
const AppBridgeContext_1 = require("./AppBridgeContext");
|
|
11
|
+
// constants
|
|
12
|
+
exports.CHANNEL_PREFIX = 'funnel:channel:';
|
|
13
|
+
// container
|
|
14
|
+
function AppBridgeContainer({ children }) {
|
|
15
|
+
// create context
|
|
16
|
+
const context = (0, react_1.useMemo)(() => ({
|
|
17
|
+
id: (0, uuid_1.v4)(),
|
|
18
|
+
eventBus: new rxjs_1.Subject(),
|
|
19
|
+
channel: new BroadcastChannel(exports.CHANNEL_PREFIX + getUniqueId())
|
|
20
|
+
}), []);
|
|
21
|
+
// forward all events to channel
|
|
22
|
+
(0, react_1.useEffect)(() => {
|
|
23
|
+
// create message handler
|
|
24
|
+
const { id, eventBus, channel } = context;
|
|
25
|
+
const onChannelMessage = (event) => {
|
|
26
|
+
console.debug(`[${id}] received event`, event);
|
|
27
|
+
// ignore message if sent from this container
|
|
28
|
+
const message = event.data;
|
|
29
|
+
if (message.source === id) {
|
|
30
|
+
console.debug(`[${id}] ignoring echo`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
console.debug(`[${id}] forwarding message to local bus`);
|
|
34
|
+
eventBus.next(message);
|
|
35
|
+
};
|
|
36
|
+
// listen to messages and forward all to the channel
|
|
37
|
+
channel.addEventListener('message', onChannelMessage);
|
|
38
|
+
// remove listener on unmount
|
|
39
|
+
return () => channel.removeEventListener('message', onChannelMessage);
|
|
40
|
+
}, [context]);
|
|
41
|
+
// render
|
|
42
|
+
return ((0, jsx_runtime_1.jsx)(AppBridgeContext_1.AppBridgeContext.Provider, { value: context, children: children }));
|
|
43
|
+
}
|
|
44
|
+
// helpers
|
|
45
|
+
const UUID_KEY = 'funnel:uuid';
|
|
46
|
+
function getUniqueId() {
|
|
47
|
+
// fetch window id (or create one)
|
|
48
|
+
let value = window.sessionStorage.getItem(UUID_KEY);
|
|
49
|
+
if (!value) {
|
|
50
|
+
value = (0, uuid_1.v4)();
|
|
51
|
+
window.sessionStorage.setItem(UUID_KEY, value);
|
|
52
|
+
}
|
|
53
|
+
// return value
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Subject } from 'rxjs';
|
|
2
|
+
import { AppContextId, TrackedAppMessage } from './AppMessage';
|
|
3
|
+
export type IAppBridgeContext = {
|
|
4
|
+
id: AppContextId;
|
|
5
|
+
eventBus: Subject<TrackedAppMessage>;
|
|
6
|
+
channel: BroadcastChannel;
|
|
7
|
+
};
|
|
8
|
+
export declare const AppBridgeContext: import("react").Context<IAppBridgeContext>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppBridgeContext = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const rxjs_1 = require("rxjs");
|
|
6
|
+
// context
|
|
7
|
+
exports.AppBridgeContext = (0, react_1.createContext)({
|
|
8
|
+
id: '',
|
|
9
|
+
eventBus: new rxjs_1.Subject(),
|
|
10
|
+
channel: {}
|
|
11
|
+
});
|