This commit is contained in:
Rizky 2023-10-24 09:18:22 +07:00
parent 4be4bdc160
commit 8f5c20beeb
16 changed files with 134 additions and 111 deletions

View File

@ -5,38 +5,32 @@ export const SyncActionDefinition = {
"load": "2" "load": "2"
}, },
"comp": { "comp": {
"undo": "3", "list": "3",
"redo": "4", "group": "4",
"list": "5", "load": "5"
"group": "6",
"load": "7"
}, },
"page": { "page": {
"undo": "8", "list": "6",
"redo": "9", "load": "7"
"list": "10",
"load": "11"
}, },
"yjs": { "yjs": {
"sv_local": "12", "um": "8",
"diff_local": "13", "sv_local": "9",
"sv_remote": "14" "diff_local": "10",
"sv_remote": "11"
} }
}; };
export const SyncActionPaths = { export const SyncActionPaths = {
"0": "site.list", "0": "site.list",
"1": "site.group", "1": "site.group",
"2": "site.load", "2": "site.load",
"3": "comp.undo", "3": "comp.list",
"4": "comp.redo", "4": "comp.group",
"5": "comp.list", "5": "comp.load",
"6": "comp.group", "6": "page.list",
"7": "comp.load", "7": "page.load",
"8": "page.undo", "8": "yjs.um",
"9": "page.redo", "9": "yjs.sv_local",
"10": "page.list", "10": "yjs.diff_local",
"11": "page.load", "11": "yjs.sv_remote"
"12": "yjs.sv_local",
"13": "yjs.diff_local",
"14": "yjs.sv_remote"
}; };

View File

@ -22,29 +22,33 @@ export const SyncActions = {
load: async (id: string) => ({}) as ESite | void, load: async (id: string) => ({}) as ESite | void,
}, },
comp: { comp: {
undo: async (id_comp: string) => {},
redo: async (id_comp: string) => {},
list: () => ({}) as Record<string, Exclude<component, "content_tree">>, list: () => ({}) as Record<string, Exclude<component, "content_tree">>,
group: () => ({}) as Record<string, string[]>, group: () => ({}) as Record<string, string[]>,
load: async (id: string) => ({}) as EComp | void, load: async (id: string) => ({}) as EComp | void,
}, },
page: { page: {
undo: async (id_page: string) => {},
redo: async (id_page: string) => {},
list: (id_site: string) => list: (id_site: string) =>
({}) as Record<string, Exclude<page, "content_tree">>, ({}) as Record<string, Exclude<page, "content_tree">>,
load: async (id: string) => ({}) as EPage | void, load: async (id: string) => ({}) as EPage | void,
}, },
yjs: { yjs: {
sv_local: async (mode: "page" | "comp", id: string, bin: Uint8Array) => um: async (
({}) as { diff: Uint8Array; sv: Uint8Array } | void, mode: "page" | "comp" | "site",
action: "undo" | "redo",
id: string
) => {},
sv_local: async (
mode: "page" | "comp" | "site",
id: string,
bin: Uint8Array
) => ({}) as { diff: Uint8Array; sv: Uint8Array } | void,
diff_local: async ( diff_local: async (
mode: "page" | "comp", mode: "page" | "comp" | "site",
id: string, id: string,
bin: Uint8Array bin: Uint8Array
) => {}, ) => {},
sv_remote: async ( sv_remote: async (
mode: "page" | "comp", mode: "page" | "comp" | "site",
id: string, id: string,
sv: Uint8Array, sv: Uint8Array,
diff: Uint8Array diff: Uint8Array

View File

@ -1,3 +0,0 @@
import { SyncConnection } from "../type";
export const comp_redo = async function (this: SyncConnection, id: string) {};

View File

@ -1,3 +0,0 @@
import { SyncConnection } from "../type";
export const comp_undo = async function (this: SyncConnection, id: string) {};

View File

@ -2,10 +2,7 @@ export * from "./site_load";
export * from "./site_group"; export * from "./site_group";
export * from "./page_load"; export * from "./page_load";
export * from "./comp_load"; export * from "./comp_load";
export * from "./page_undo"; export * from "./yjs_um";
export * from "./page_redo";
export * from "./comp_undo";
export * from "./comp_redo";
export * from "./yjs_sv_local"; export * from "./yjs_sv_local";
export * from "./yjs_diff_local"; export * from "./yjs_diff_local";
export * from "./yjs_sv_remote"; export * from "./yjs_sv_remote";

View File

@ -1,12 +1,12 @@
import { syncronize } from "y-pojo"; import { syncronize } from "y-pojo";
import { SAction } from "../actions"; import { SAction } from "../actions";
import { conns } from "../entity/conn";
import { Y, docs } from "../entity/docs"; import { Y, docs } from "../entity/docs";
import { snapshot } from "../entity/snapshot"; import { snapshot } from "../entity/snapshot";
import { user } from "../entity/user"; import { user } from "../entity/user";
import { gzipAsync } from "../entity/zlib"; import { gzipAsync } from "../entity/zlib";
import { SyncConnection, SyncType } from "../type";
import { conns } from "../entity/conn";
import { sendWS } from "../sync-handler"; import { sendWS } from "../sync-handler";
import { SyncConnection, SyncType } from "../type";
export const page_load: SAction["page"]["load"] = async function ( export const page_load: SAction["page"]["load"] = async function (
this: SyncConnection, this: SyncConnection,
@ -17,27 +17,34 @@ export const page_load: SAction["page"]["load"] = async function (
if (this.conf) this.conf.page_id = id; if (this.conf) this.conf.page_id = id;
const createUndoManager = (root: Y.Map<any>) => { const createUndoManager = async (root: Y.Map<any>) => {
const um = new Y.UndoManager(root, { ignoreRemoteMapChanges: false }); const um = new Y.UndoManager(root, {
ignoreRemoteMapChanges: true,
});
return um; return um;
}; };
const attachOnUpdate = (doc: Y.Doc, um: Y.UndoManager) => { const attachOnUpdate = async (doc: Y.Doc, um: Y.UndoManager) => {
snapshot.set("page", id, "id_doc", um.doc.clientID);
doc.on("update", async (update: Uint8Array, origin: any) => { doc.on("update", async (update: Uint8Array, origin: any) => {
if (origin === um) { const bin = Y.encodeStateAsUpdate(doc);
} else { snapshot.set("page", id, "bin", bin);
const sv_local = await gzipAsync(update);
user.active.findAll({ page_id: id }).map((e) => { const sv_local = await gzipAsync(update);
user.active.findAll({ page_id: id }).map((e) => {
if (origin !== um) {
if (e.client_id === origin) return; if (e.client_id === origin) return;
const ws = conns.get(e.client_id)?.ws; }
if (ws) const ws = conns.get(e.client_id)?.ws;
sendWS(ws, { if (ws)
type: SyncType.Event, sendWS(ws, {
event: "remote_svlocal", type: SyncType.Event,
data: { type: "page", sv_local, id }, event: "remote_svlocal",
}); data: { type: "page", sv_local, id },
}); });
} });
}); });
}; };
@ -52,7 +59,7 @@ export const page_load: SAction["page"]["load"] = async function (
let root = doc.getMap("map"); let root = doc.getMap("map");
syncronize(root, { id, root: page.content_tree }); syncronize(root, { id, root: page.content_tree });
const um = createUndoManager(root); const um = await createUndoManager(root);
docs.page[id] = { docs.page[id] = {
doc: doc as any, doc: doc as any,
id, id,
@ -60,7 +67,7 @@ export const page_load: SAction["page"]["load"] = async function (
}; };
const bin = Y.encodeStateAsUpdate(doc); const bin = Y.encodeStateAsUpdate(doc);
attachOnUpdate(doc, um); await attachOnUpdate(doc, um);
snapshot.update({ snapshot.update({
bin, bin,
@ -69,6 +76,7 @@ export const page_load: SAction["page"]["load"] = async function (
name: page.name, name: page.name,
ts: Date.now(), ts: Date.now(),
url: page.url, url: page.url,
id_doc: doc.clientID,
id_site: page.id_site, id_site: page.id_site,
}); });
@ -89,11 +97,12 @@ export const page_load: SAction["page"]["load"] = async function (
} }
} else if (snap && !ydoc) { } else if (snap && !ydoc) {
const doc = new Y.Doc(); const doc = new Y.Doc();
snapshot.set("page", id, "id_doc", doc.clientID);
Y.applyUpdate(doc, snap.bin); Y.applyUpdate(doc, snap.bin);
let root = doc.getMap("map"); let root = doc.getMap("map");
const um = createUndoManager(root); const um = await createUndoManager(root);
attachOnUpdate(doc, um); await attachOnUpdate(doc, um);
docs.page[id] = { docs.page[id] = {
doc: doc as any, doc: doc as any,

View File

@ -1,14 +0,0 @@
import { docs } from "../entity/docs";
import { SyncConnection } from "../type";
export const page_redo = async function (this: SyncConnection, id: string) {
if (!docs.page[id]) {
return;
}
const um = docs.page[id].um;
if (um.canRedo()) {
console.log("redoing");
um.redo();
}
};

View File

@ -1,15 +0,0 @@
import { docs } from "../entity/docs";
import { SyncConnection } from "../type";
export const page_undo = async function (this: SyncConnection, id: string) {
if (!docs.page[id]) {
return;
}
const um = docs.page[id].um;
if (um.canUndo()) {
console.log("undoing");
um.undo();
}
};

View File

@ -19,7 +19,4 @@ export const yjs_diff_local: SAction["yjs"]["diff_local"] = async function (
const um = docs[mode][id].um; const um = docs[mode][id].um;
um.addTrackedOrigin(this.client_id); um.addTrackedOrigin(this.client_id);
Y.applyUpdate(doc, diff, this.client_id); Y.applyUpdate(doc, diff, this.client_id);
const save = Y.encodeStateAsUpdate(doc);
snapshot.set(mode, id, "bin", save);
}; };

View File

@ -0,0 +1,27 @@
import { SAction } from "../actions";
import { docs } from "../entity/docs";
import { SyncConnection } from "../type";
export const yjs_um: SAction["yjs"]["um"] = async function (
this: SyncConnection,
mode,
action,
id
) {
if (!docs[mode][id]) {
return;
}
const um = docs[mode][id].um;
if (action === "redo") {
if (um.canRedo()) {
um.redo();
}
} else {
if (um.undoStack.length > 1) {
if (um.canUndo()) {
um.undo();
}
}
}
};

View File

@ -5,6 +5,14 @@ import { DPage } from "../../../../web/src/utils/types/root";
export * as Y from "yjs"; export * as Y from "yjs";
export const docs = { export const docs = {
site: {} as Record<
string,
{
id: string;
doc: DPage;
um: Y.UndoManager;
}
>,
page: {} as Record< page: {} as Record<
string, string,
{ {

View File

@ -3,9 +3,10 @@ import { RootDatabase, open } from "lmdb";
import { g } from "utils/global"; import { g } from "utils/global";
const emptySnapshot = { const emptySnapshot = {
type: "" as "" | "comp" | "page", type: "" as "" | "comp" | "page" | "site",
id: "", id: "",
bin: new Uint8Array(), bin: new Uint8Array(),
id_doc: 0,
name: "", name: "",
ts: Date.now(), ts: Date.now(),
}; };

View File

@ -1,19 +1,20 @@
import { NodeModel } from "@minoru/react-dnd-treeview"; import { NodeModel } from "@minoru/react-dnd-treeview";
import { ReactElement } from "react";
import { clientStartSync } from "../../../utils/sync/ws-client"; import { clientStartSync } from "../../../utils/sync/ws-client";
import { IContent, MContent } from "../../../utils/types/general";
import { IItem, MItem } from "../../../utils/types/item"; import { IItem, MItem } from "../../../utils/types/item";
import { DComp, DPage, IRoot } from "../../../utils/types/root"; import { DComp, DPage, IRoot } from "../../../utils/types/root";
import { ISection } from "../../../utils/types/section"; import { ISection } from "../../../utils/types/section";
import { IText, MText } from "../../../utils/types/text"; import { IText, MText } from "../../../utils/types/text";
import { ReactElement } from "react";
const EmptySite = { const EmptySite = {
id: "", id: "",
name: "", name: "",
domain: "", domain: "",
js: "",
js_compiled: "",
config: { api_url: "" }, config: { api_url: "" },
snapshot: null as null | Uint8Array,
// js: "",
// js_compiled: "",
}; };
export type ESite = typeof EmptySite; export type ESite = typeof EmptySite;
export type EPage = typeof EmptyPage; export type EPage = typeof EmptyPage;
@ -95,7 +96,14 @@ export const EDGlobal = {
open: {} as Record<string, string[]>, open: {} as Record<string, string[]>,
}, },
popup: { popup: {
comp: null as null | ((comp_id: string) => void | Promise<void>), comp: null as null | true | ((comp_id: string) => void | Promise<void>),
compGroup: null as
| null
| true
| {
event: React.MouseEvent<HTMLElement, MouseEvent>;
pick: (group_id: string) => void | Promise<void>;
},
}, },
}, },
}; };

View File

@ -19,9 +19,9 @@ export const edUndoManager = async (p: PG) => {
!evt.shiftKey !evt.shiftKey
) { ) {
if (p.comp.cur.id) { if (p.comp.cur.id) {
p.sync.comp.redo(p.comp.cur.id); p.sync.yjs.um("comp", "redo", p.comp.cur.id);
} else { } else {
p.sync.page.redo(p.page.cur.id); p.sync.yjs.um("page", "redo", p.page.cur.id);
} }
return; return;
} }
@ -32,11 +32,10 @@ export const edUndoManager = async (p: PG) => {
evt.shiftKey evt.shiftKey
) { ) {
if (p.comp.cur.id) { if (p.comp.cur.id) {
p.sync.comp.redo(p.comp.cur.id); p.sync.yjs.um("comp", "redo", p.comp.cur.id);
} else { } else {
p.sync.page.redo(p.page.cur.id); p.sync.yjs.um("page", "redo", p.page.cur.id);
} }
return; return;
} }
@ -46,9 +45,9 @@ export const edUndoManager = async (p: PG) => {
!evt.shiftKey !evt.shiftKey
) { ) {
if (p.comp.cur.id) { if (p.comp.cur.id) {
p.sync.comp.undo(p.comp.cur.id); p.sync.yjs.um("comp", "undo", p.comp.cur.id);
} else { } else {
p.sync.page.undo(p.page.cur.id); p.sync.yjs.um("page", "undo", p.page.cur.id);
} }
} }

View File

@ -1,8 +1,22 @@
import { IContent } from "../../../../../../../utils/types/general"; import { syncronize } from "y-pojo";
import { IContent, MContent } from "../../../../../../../utils/types/general";
import { fillID } from "../../../../../../editor/tools/fill-id";
import { PG } from "../../../../../logic/ed-global"; import { PG } from "../../../../../logic/ed-global";
import { treeRebuild } from "../../../../../logic/tree/build";
export const edActionClone = (p: PG, item: IContent) => { export const edActionClone = (p: PG, item: IContent) => {
const mitem = p.page.meta[item.id].mitem; const mitem = p.page.meta[item.id].mitem;
if (mitem) { if (mitem) {
mitem.doc?.transact(() => {
mitem.parent.forEach((e: MContent, idx) => {
if (e.get("id") === mitem.get("id")) {
const json = e.toJSON() as IContent;
const map = new Y.Map();
syncronize(map, fillID(json));
mitem.parent.insert(idx, [map]);
}
});
});
treeRebuild(p, { note: "clone" });
} }
}; };

View File

@ -76,7 +76,7 @@ export const EdTreeCtxMenu = ({
onClick={() => edActionDetach(p, item)} onClick={() => edActionDetach(p, item)}
/> />
)} )}
{type === "item" && comp?.id && ( {type === "item" && !comp?.id && (
<MenuItem <MenuItem
label="Create Component" label="Create Component"
onClick={() => edActionNewComp(p, item)} onClick={() => edActionNewComp(p, item)}