From 6c9fa75610a2783250e6f2b4164b65039cc95df6 Mon Sep 17 00:00:00 2001 From: Rizky Date: Wed, 22 Nov 2023 23:31:30 +0700 Subject: [PATCH] fix --- app/srv/ws/sync/actions/page_load.ts | 164 +++--------------- app/srv/ws/sync/editor/load-page.ts | 72 ++++++++ app/web/src/nova/ed/logic/ed-global.ts | 17 +- .../nova/ed/logic/tree/sync-walk-utils.tsx | 23 +++ app/web/src/nova/ed/logic/tree/sync-walk.tsx | 21 +-- 5 files changed, 134 insertions(+), 163 deletions(-) create mode 100644 app/srv/ws/sync/editor/load-page.ts create mode 100644 app/web/src/nova/ed/logic/tree/sync-walk-utils.tsx diff --git a/app/srv/ws/sync/actions/page_load.ts b/app/srv/ws/sync/actions/page_load.ts index 7212f71c..3f37e0e2 100644 --- a/app/srv/ws/sync/actions/page_load.ts +++ b/app/srv/ws/sync/actions/page_load.ts @@ -1,15 +1,7 @@ -import { createId } from "@paralleldrive/cuid2"; -import { - EPage, - IScope, - IScopeComp, -} from "../../../../web/src/nova/ed/logic/ed-global"; -import { IContent } from "../../../../web/src/utils/types/general"; -import { IItem } from "../../../../web/src/utils/types/item"; -import { DComp, DPage, IRoot } from "../../../../web/src/utils/types/root"; +import { EdMeta } from "../../../../web/src/nova/ed/logic/ed-global"; +import { DPage } from "../../../../web/src/utils/types/root"; import { SAction } from "../actions"; -import { loadComponent } from "../editor/load-component"; -import { parseJs } from "../editor/parser/parse-js"; +import { serverWalkLoad, serverWalkMap } from "../editor/load-page"; import { activity } from "../entity/activity"; import { conns } from "../entity/conn"; import { docs } from "../entity/docs"; @@ -112,7 +104,7 @@ export const page_load: SAction["page"]["load"] = async function ( page_id: page.id, }); - const { scope, comps } = await scanMeta(docs.page[id].doc, this); + const { scope, scope_comps } = await scanMeta(docs.page[id].doc, this); return { id: id, @@ -120,7 +112,7 @@ export const page_load: SAction["page"]["load"] = async function ( name: page.name, snapshot: await gzipAsync(bin), scope, - comps, + scope_comps, }; } } else if (snap && !ydoc) { @@ -148,7 +140,7 @@ export const page_load: SAction["page"]["load"] = async function ( page_id: snap.id, }); - const { scope, comps } = await scanMeta(docs.page[id].doc, this); + const { scope, scope_comps } = await scanMeta(docs.page[id].doc, this); return { id: id, @@ -156,7 +148,7 @@ export const page_load: SAction["page"]["load"] = async function ( name: snap.name, snapshot: await gzipAsync(snap.bin), scope, - comps, + scope_comps, }; } else if (snap && ydoc) { await setActivityPage(snap.id_site, id); @@ -169,139 +161,39 @@ export const page_load: SAction["page"]["load"] = async function ( page_id: snap.id, }); - const { scope, comps } = await scanMeta(ydoc.doc, this); + const { scope, scope_comps } = await scanMeta(ydoc.doc, this); return { id: snap.id, url: snap.url, name: snap.name, snapshot: await gzipAsync(snap.bin), scope, - comps, + scope_comps, }; } }; -const scanMeta = async ( - doc: DPage | DComp, - sync: SyncConnection, - existing?: { scope: IScope; comps: Record } -) => { - const root = doc.getMap("map").get("root")?.toJSON() as IRoot; +const scanMeta = async (doc: DPage, sync: SyncConnection) => { + const scope = {}; + const scope_comps = {}; + const loaded = new Set(); - const scope = existing ? existing.scope : ({} as IScope); - const comps = existing ? existing.comps : ({} as Record); - - const instantiate = (item: IItem, comp_id: string) => { - const ref = docs.comp[comp_id]; - if (ref) { - const item_comp = assignNewID( - ref.doc.getMap("map").get("root")?.toJSON() as IItem - ); - parseItem(item_comp, scope, item.id, loadComp); - } + const portal = { + in: {} as Record, + out: {} as Record, }; - - const pendingComp = new Set(); - const loadComp = (item: IItem) => { - const comp_id = item.component?.id; - if (comp_id) { - const comp = comps[comp_id]; - if (!comp) { - pendingComp.add(item); - } else { - instantiate(item, comp_id); - } - return false; - } - return true; - }; - if (root) { - for (const c of root.childs) { - parseItem(c, scope, "", loadComp); - } + const childs = doc.getMap("map").get("root")?.get("childs") || []; + if (childs) { + await Promise.all(childs.map((m) => serverWalkLoad(m, sync, loaded))); + await Promise.all( + childs.map((m) => + serverWalkMap( + { sync, scope, scope_comps }, + { isLayout: false, mitem: m, parent_item: { id: "root" }, portal } + ) + ) + ); } - for (const item of pendingComp) { - const comp_id = item.component?.id; - if (comp_id) { - let ref = docs.comp[comp_id]; - if (!ref) { - await loadComponent(comp_id, sync); - ref = docs.comp[comp_id]; - if (ref) { - await scanMeta(ref.doc, sync, { - scope, - comps, - }); - } - } - - if (ref) { - instantiate(item, comp_id); - } - } - } - - Object.entries(comps) - .filter(([k, v]) => !v) - .map(async ([id, v]) => {}); - - return { scope, comps }; -}; - -const assignNewID = (item: IItem) => { - item.id = createId(); - for (const c of item.childs) { - if (c.type !== "text") { - assignNewID(c); - } - } - return item; -}; - -export const parseItem = ( - item: IContent, - result: EPage["scope"], - parent_id: string, - each: (item: IItem) => boolean -) => { - const js = item.adv?.js; - - const parent_ids: string[] = []; - if (!!parent_id) { - if (!!result[parent_id]) { - result[parent_id].p.forEach((e) => parent_ids.push(e)); - } else { - throw new Error( - `Parent item not found: ${JSON.stringify( - parent_id - )} \nitem:\n${JSON.stringify( - { id: item.id, name: item.name, type: item.type }, - null, - 2 - )}` - ); - } - - parent_ids.push(parent_id); - } - - result[item.id] = { p: parent_ids, s: null }; - - if (!!each && !each(item as IItem)) { - return; - } - - if (typeof js === "string") { - const res = parseJs(js); - if (res) { - result[item.id].s = res; - } - } - - if (item.type !== "text") { - for (const c of item.childs) { - parseItem(c, result, item.id, each); - } - } + return { scope, scope_comps }; }; diff --git a/app/srv/ws/sync/editor/load-page.ts b/app/srv/ws/sync/editor/load-page.ts new file mode 100644 index 00000000..64793167 --- /dev/null +++ b/app/srv/ws/sync/editor/load-page.ts @@ -0,0 +1,72 @@ +import { + EdMeta, + IScope, + IScopeComp, +} from "../../../../web/src/nova/ed/logic/ed-global"; +import { ensurePropContent } from "../../../../web/src/nova/ed/logic/tree/sync-walk-utils"; +import { MItem } from "../../../../web/src/utils/types/item"; +import { FNComponent } from "../../../../web/src/utils/types/meta-fn"; +import { docs } from "../entity/docs"; +import { SyncConnection } from "../type"; +import { loadComponent } from "./load-component"; + +export const serverWalkLoad = async ( + mitem: MItem, + sync: SyncConnection, + loaded: Set +) => { + const mcomp = mitem.get("component"); + if (mcomp) { + const id = mcomp.get("id"); + const comp = mcomp.toJSON() as FNComponent; + if (id) { + const isFirstLoaded = !loaded.has(id); + loaded.add(id); + if (!docs.comp[id]) { + await loadComponent(id, sync); + } + + const pcomp = docs.comp[id]; + if (pcomp) { + const pitem = pcomp.doc.getMap("map").get("root"); + if (pitem && isFirstLoaded) { + await serverWalkLoad(pitem, sync, loaded); + } + } + } + + for (const [propName, prop] of Object.entries(comp.props || {})) { + if (prop.meta?.type === "content-element") { + const mprop = mcomp.get("props")?.get(propName); + if (mprop) { + const mcontent = ensurePropContent(mprop, propName); + if (mcontent) { + await serverWalkLoad(mcontent, sync, loaded); + } + } + } + } + } + + for (const e of mitem.get("childs")?.map((e) => e) || []) { + await serverWalkLoad(e, sync, loaded); + } +}; + +export const serverWalkMap = async ( + p: { + sync: SyncConnection; + scope: IScope; + scope_comps: IScopeComp; + }, + arg: { + isLayout: boolean; + mitem: MItem; + portal: { + in: Record; + out: Record; + }; + parent_item: EdMeta["parent_item"]; + parent_mcomp?: EdMeta["parent_mcomp"]; + } +) => {}; diff --git a/app/web/src/nova/ed/logic/ed-global.ts b/app/web/src/nova/ed/logic/ed-global.ts index 5d5357cc..21d864cc 100644 --- a/app/web/src/nova/ed/logic/ed-global.ts +++ b/app/web/src/nova/ed/logic/ed-global.ts @@ -28,19 +28,22 @@ export type IScope = Record< { p: string[]; s: null | Exclude, undefined> } >; -export type IScopeComp = { - id: string; - name: string; - snapshot: Uint8Array; - scope: IScope; -}; +export type IScopeComp = Record< + string, + { + id: string; + name: string; + snapshot: Uint8Array; + scope: IScope; + } +>; const EmptyPage = { id: "", name: "", url: "", snapshot: null as null | Uint8Array, scope: {} as IScope, - comps: {} as Record, + scope_comps: {} as IScopeComp, }; const EmptyComp = { diff --git a/app/web/src/nova/ed/logic/tree/sync-walk-utils.tsx b/app/web/src/nova/ed/logic/tree/sync-walk-utils.tsx new file mode 100644 index 00000000..df88f863 --- /dev/null +++ b/app/web/src/nova/ed/logic/tree/sync-walk-utils.tsx @@ -0,0 +1,23 @@ +import { createId } from "@paralleldrive/cuid2"; +import { MItem } from "../../../../utils/types/item"; +import { FMCompDef } from "../../../../utils/types/meta-fn"; + +export const ensurePropContent = (mprop: FMCompDef, k: string) => { + let mcontent = mprop.get("content"); + if (!mcontent) { + const newcontent = new Y.Map(); + syncronize(newcontent, { + id: createId(), + name: k, + type: "item", + dim: { w: "full", h: "full" }, + childs: [], + adv: { + css: "", + }, + }); + mprop.set("content", newcontent as MItem); + mcontent = mprop.get("content"); + } + return mcontent; +}; diff --git a/app/web/src/nova/ed/logic/tree/sync-walk.tsx b/app/web/src/nova/ed/logic/tree/sync-walk.tsx index 11314a7a..6df1a7ab 100644 --- a/app/web/src/nova/ed/logic/tree/sync-walk.tsx +++ b/app/web/src/nova/ed/logic/tree/sync-walk.tsx @@ -13,6 +13,7 @@ import { import { DComp } from "../../../../utils/types/root"; import { MSection } from "../../../../utils/types/section"; import { EdMeta, PG } from "../ed-global"; +import { ensurePropContent } from "./sync-walk-utils"; export const syncWalkLoad = async ( p: PG, @@ -274,26 +275,6 @@ export const loadComponent = async (p: PG, id_comp: string) => { return false; }; -const ensurePropContent = (mprop: FMCompDef, k: string) => { - let mcontent = mprop.get("content"); - if (!mcontent) { - const newcontent = new Y.Map(); - syncronize(newcontent, { - id: createId(), - name: k, - type: "item", - dim: { w: "full", h: "full" }, - childs: [], - adv: { - css: "", - }, - }); - mprop.set("content", newcontent as MItem); - mcontent = mprop.get("content"); - } - return mcontent; -}; - const ensureMProp = ( mitem_props: TypedMap>, k: string,