This commit is contained in:
Rizky 2023-10-21 22:23:22 +07:00
parent 7ba2c91dc0
commit 55a6b2564c
12 changed files with 193 additions and 35 deletions

View File

@ -9,8 +9,11 @@ import { svLocal } from "./edit/action/sv-local";
import { svdiffRemote } from "./edit/action/svdiff-remote";
import { redo, undo } from "./edit/action/undo-redo";
import { eg } from "./edit/edit-global";
import { sendWS } from "./edit/send";import { syncHandler } from "./sync/sync-handler";
import { sendWS } from "./edit/send";
import { syncHandler } from "./sync/sync-handler";
import * as Y from "yjs";
(globalThis as any).Y = Y;
eg.edit = {
site: {},
comp: {},

View File

@ -7,7 +7,7 @@ export const SyncActionDefinition = {
"comp": {
"list": "3",
"group": "4",
"doc": "5"
"load": "5"
},
"page": {
"list": "6",
@ -20,7 +20,7 @@ export const SyncActionPaths = {
"2": "site.load",
"3": "comp.list",
"4": "comp.group",
"5": "comp.doc",
"5": "comp.load",
"6": "page.list",
"7": "page.load"
};

View File

@ -1,5 +1,5 @@
import { component, page } from "dbgen";
import { EPage, ESite } from "../../../web/src/render/ed/logic/ed-global";
import { EComp, EPage, ESite } from "../../../web/src/render/ed/logic/ed-global";
/*
WARNING:
@ -20,7 +20,7 @@ export const SyncActions = {
comp: {
list: () => ({}) as Record<string, Exclude<component, "content_tree">>,
group: () => ({}) as Record<string, string[]>,
doc: (id: string) => ({}) as Uint8Array,
load: async (id: string) => ({}) as EComp | void,
},
page: {
list: (id_site: string) =>

View File

@ -0,0 +1,49 @@
import { syncronize } from "y-pojo";
import { docs } from "../entity/docs";
import { snapshot } from "../entity/snapshot";
import { ActionCtx } from "../type";
export const comp_load = async function (this: ActionCtx, id: string) {
let snap = snapshot.get("comp", id);
let ydoc = docs.comp[id];
if (!snap || !ydoc) {
const comp = await db.component.findFirst({ where: { id } });
if (comp) {
const doc = new Y.Doc();
let root = doc.getMap("map");
syncronize(root, { id, item: comp.content_tree });
const um = new Y.UndoManager(root, { ignoreRemoteMapChanges: true });
docs.comp[id] = {
doc: doc as any,
id,
um,
};
const bin = Y.encodeStateAsUpdate(doc);
snapshot.set({
bin,
id,
type: "comp",
name: comp.name,
url: "",
ts: Date.now(),
});
return {
id: id,
name: comp.name,
snapshot: bin,
};
}
}
if (snap) {
return {
id: snap.id,
name: snap.name,
snapshot: snap.bin,
};
}
};

View File

@ -1,3 +1,4 @@
export * from "./site_load";
export * from "./site_group";
export * from "./page_load";
export * from "./comp_load";

View File

@ -8,10 +8,10 @@ export const page_load: SAction["page"]["load"] = async function (
this: ActionCtx,
id: string
) {
let ss = snapshot.get("page", id);
let snap = snapshot.get("page", id);
let ydoc = docs.page[id];
if (!ss || !ydoc) {
if (!snap || !ydoc) {
const page = await db.page.findFirst({ where: { id } });
if (page) {
const doc = new Y.Doc();
@ -44,12 +44,12 @@ export const page_load: SAction["page"]["load"] = async function (
}
}
if (ss) {
if (snap) {
return {
id: ss.id,
url: ss.url,
name: ss.name,
snapshot: ss.bin,
id: snap.id,
url: snap.url,
name: snap.name,
snapshot: snap.bin,
};
}
};

View File

@ -8,7 +8,7 @@ const emptySnapshot = {
bin: new Uint8Array(),
url: "",
name: "",
ts: Date.now(),
ts: Date.now()
};
export type DocSnapshot = typeof emptySnapshot;

View File

@ -81,7 +81,7 @@ export const syncHandler: WebSocketHandler<WSData> = {
if (actionName) {
const baseAction = (actions as any)[actionName];
if (!baseAction) {
console.log(`app/ws/edit/sync/${actionName}.ts not found}`);
console.log(`app/ws/edit/sync/${actionName}.ts not found`);
}
if (baseAction) {
const action = baseAction.bind({

View File

@ -2,9 +2,8 @@ import { NodeModel } from "@minoru/react-dnd-treeview";
import { clientStartSync } from "../../../utils/sync/client";
import { IContent, MContent } from "../../../utils/types/general";
import { IItem, MItem } from "../../../utils/types/item";
import { DPage, IRoot } from "../../../utils/types/root";
import { DComp, DPage, IRoot } from "../../../utils/types/root";
import { IText, MText } from "../../../utils/types/text";
import { NodeMeta } from "../../editor/logic/global";
const EmptySite = {
id: "",
@ -16,6 +15,7 @@ const EmptySite = {
};
export type ESite = typeof EmptySite;
export type EPage = typeof EmptyPage;
export type EComp = typeof EmptyComp;
const EmptyPage = {
id: "",
@ -24,9 +24,18 @@ const EmptyPage = {
snapshot: null as null | Uint8Array,
};
const EmptyComp = {
id: "",
snapshot: null as null | Uint8Array,
};
export type EdMeta = {
item: IItem | IText;
mitem?: MItem | MText;
parent_comp?: {
ref_ids: Record<string, string>;
mcomp: MItem;
};
};
export const EDGlobal = {
@ -39,12 +48,19 @@ export const EDGlobal = {
sync: null as unknown as Awaited<ReturnType<typeof clientStartSync>>,
site: EmptySite,
page: {
current: EmptyPage,
cur: EmptyPage,
doc: null as null | DPage,
root: null as null | IRoot,
entry: [] as string[],
tree: [] as NodeModel<EdMeta>[],
meta: {} as Record<string, { item: IContent; mitem?: MContent }>,
list: {} as Record<string, EPage>,
},
comp: {
cur: EmptyComp,
doc: null as null | DComp,
item: null as null | IItem,
list: {} as Record<string, { cur: EComp; doc: DComp }>,
},
};

View File

@ -16,7 +16,7 @@ export const edRoute = async (p: PG) => {
p.site = site;
}
if (p.page.current.id !== params.page_id || !p.page.current.snapshot) {
if (p.page.cur.id !== params.page_id || !p.page.cur.snapshot) {
p.status = "loading";
const page = await p.sync.page.load(params.page_id);
@ -26,7 +26,7 @@ export const edRoute = async (p: PG) => {
return;
}
p.page.current = page;
p.page.cur = page;
if (page.snapshot) {
const doc = new Y.Doc();
Y.applyUpdate(doc, page.snapshot);

View File

@ -1,7 +1,8 @@
import { createId } from "@paralleldrive/cuid2";
import { MContent } from "../../../../utils/types/general";
import { IItem, MItem } from "../../../../utils/types/item";
import { MRoot } from "../../../../utils/types/root";
import { DComp } from "../../../../utils/types/root";
import { MSection } from "../../../../utils/types/section";
import { walk } from "../../../editor/logic/tree-logic";
import { EdMeta, PG } from "../ed-global";
export const treeRebuild = async (p: PG) => {
@ -24,13 +25,7 @@ export const treeRebuild = async (p: PG) => {
}
};
const walkMap = async (
p: PG,
arg: { mitem: MItem | MSection; tree_parent_id: string }
) => {
const { mitem, tree_parent_id } = arg;
const item = {} as unknown as IItem;
const mapItem = (mitem: MContent, item: any) => {
mitem.forEach((e, k) => {
if (k !== "childs") {
let val = e;
@ -39,15 +34,104 @@ const walkMap = async (
val = e.toJSON() as any;
}
}
(item as any)[k] = val;
item[k] = val;
} else {
item[k] = [];
}
});
};
const walkMap = async (
p: PG,
arg: {
mitem: MItem | MSection;
tree_parent_id: string;
parent_comp?: EdMeta["parent_comp"];
}
) => {
const { mitem, tree_parent_id, parent_comp } = arg;
const item = {} as unknown as IItem;
mapItem(mitem, item);
// sesuaikan item instance id dengan parent comp
if (parent_comp) {
if (!parent_comp["ref_ids"][item.id]) {
parent_comp["ref_ids"][item.id] = createId();
}
if (parent_comp["ref_ids"][item.id]) {
item.id = parent_comp["ref_ids"][item.id];
}
}
const metaNotFound = () => {
p.page.tree.push({
id: item.id,
parent: tree_parent_id,
text: item.name,
});
};
const item_comp = item.component;
if (item_comp && item_comp.id) {
if (!p.comp.list[item_comp.id]) {
let found = false;
const cur = await p.sync.comp.load(item_comp.id);
if (cur && cur.snapshot) {
const doc = new Y.Doc() as DComp;
if (cur.snapshot) {
Y.applyUpdate(doc as any, cur.snapshot);
p.comp.list[item_comp.id] = { cur, doc };
found = true;
}
}
if (!found) {
metaNotFound();
return;
}
}
const ref_comp = p.comp.list[item_comp.id];
if (ref_comp) {
const mcomp = ref_comp.doc.getMap("map").get("item");
if (mcomp) {
const ref_ids: Record<string, string> = {};
if (parent_comp) {
let old_id = item.id;
mapItem(mcomp, item);
ref_ids[item.id] = old_id;
item.id = old_id;
} else {
mapItem(mcomp, item);
ref_ids[item.id] = createId();
item.id = ref_ids[item.id];
}
await Promise.all(
mcomp.get("childs")?.map(async (e) => {
await walkMap(p, {
mitem: e,
tree_parent_id: item.id,
parent_comp: { ref_ids, mcomp },
});
}) || []
);
return;
}
}
metaNotFound();
return;
}
const meta: EdMeta = {
item,
mitem: mitem as MItem,
parent_comp,
};
p.page.meta[item.id] = meta;
@ -59,10 +143,13 @@ const walkMap = async (
data: meta,
});
await Promise.all(
mitem.get("childs")?.map(async (e, k) => {
item.childs.push(e.get("id"));
await walkMap(p, { mitem: e, tree_parent_id: item.id });
}) || []
);
const mchilds = mitem.get("childs");
if (mchilds) {
await Promise.all(
mchilds.map(async (e, k) => {
item.childs.push(e.get("id"));
await walkMap(p, { mitem: e, tree_parent_id: item.id });
}) || []
);
}
};

View File

@ -1,5 +1,6 @@
import { TypedArray, TypedDoc, TypedMap } from "yjs-types";
import { ISection } from "./section";
import { MItem } from "./item";
export type IRoot = {
id: "root";
@ -14,3 +15,4 @@ export type MRoot = TypedMap<{
}>;
export type DPage = TypedDoc<{ map: TypedMap<{ id: string; root: MRoot }> }>;
export type DComp = TypedDoc<{ map: TypedMap<{ id: string; item: MItem }> }>;