From 07947db98b4f6f04e075dd0858cc144e5a046393 Mon Sep 17 00:00:00 2001 From: qinluhe <108015703+qinluhe@users.noreply.github.com> Date: Mon, 17 Apr 2023 10:12:04 +0800 Subject: [PATCH] feat: split create document and open document (#2261) * fix: add method * fix: update text block and doc title --- frontend/appflowy_tauri/src-tauri/Cargo.lock | 10 ++-- .../document/DocumentTitle/index.tsx | 16 +++--- .../components/document/Node/index.tsx | 34 +++++------- .../components/document/Root/index.tsx | 1 + .../components/document/TextBlock/index.tsx | 8 +-- .../document/_shared/SubscribeNode.hooks.ts | 3 +- .../document/_shared/TextInput.hooks.ts | 26 +++++---- .../NavigationPanel/FolderItem.hooks.ts | 27 ++++++---- .../src/appflowy_app/interfaces/document.ts | 8 +++ .../effects/document/document_bd_svc.ts | 19 +++---- .../effects/document/document_controller.ts | 53 +++++++++++-------- .../effects/document/document_observer.ts | 7 +-- .../appflowy_app/views/DocumentPage.hooks.ts | 16 +++--- frontend/rust-lib/Cargo.lock | 50 ++++++++--------- .../rust-lib/flowy-document2/src/document.rs | 4 +- .../rust-lib/flowy-document2/src/entities.rs | 25 +++++++++ .../flowy-document2/src/event_handler.rs | 25 ++++++++- .../rust-lib/flowy-document2/src/event_map.rs | 6 ++- .../rust-lib/flowy-document2/src/manager.rs | 37 ++++++++++--- 19 files changed, 238 insertions(+), 137 deletions(-) diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index 64068f46a7..67665df6c6 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -576,7 +576,7 @@ dependencies = [ [[package]] name = "collab" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab#dd49b08fae2ad008844409c7ce6b8c754446955c" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab#986737b4125162ae94dbeb6ece8267714f67b1dd" dependencies = [ "anyhow", "bytes", @@ -594,7 +594,7 @@ dependencies = [ [[package]] name = "collab-derive" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab#dd49b08fae2ad008844409c7ce6b8c754446955c" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab#986737b4125162ae94dbeb6ece8267714f67b1dd" dependencies = [ "proc-macro2", "quote", @@ -606,7 +606,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab#dd49b08fae2ad008844409c7ce6b8c754446955c" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab#986737b4125162ae94dbeb6ece8267714f67b1dd" dependencies = [ "anyhow", "collab", @@ -622,7 +622,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab#dd49b08fae2ad008844409c7ce6b8c754446955c" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab#986737b4125162ae94dbeb6ece8267714f67b1dd" dependencies = [ "anyhow", "collab", @@ -640,7 +640,7 @@ dependencies = [ [[package]] name = "collab-persistence" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab#dd49b08fae2ad008844409c7ce6b8c754446955c" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab#986737b4125162ae94dbeb6ece8267714f67b1dd" dependencies = [ "bincode", "chrono", diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/DocumentTitle/index.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/DocumentTitle/index.tsx index b7abbe4ca3..07e77a5e3b 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/DocumentTitle/index.tsx +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/DocumentTitle/index.tsx @@ -1,20 +1,16 @@ import React from 'react'; import { useDocumentTitle } from './DocumentTitle.hooks'; import TextBlock from '../TextBlock'; +import { NodeContext } from '../_shared/SubscribeNode.hooks'; export default function DocumentTitle({ id }: { id: string }) { const { node } = useDocumentTitle(id); if (!node) return null; return ( -
- - -
+ +
+ +
+
); } diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/Node/index.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/Node/index.tsx index b875a329de..a72e139e4e 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/Node/index.tsx +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/Node/index.tsx @@ -4,7 +4,7 @@ import { withErrorBoundary } from 'react-error-boundary'; import { ErrorBoundaryFallbackComponent } from '../_shared/ErrorBoundaryFallbackComponent'; import { Node } from '@/appflowy_app/stores/reducers/document/slice'; import TextBlock from '../TextBlock'; -import { TextDelta } from '@/appflowy_app/interfaces/document'; +import { NodeContext } from '../_shared/SubscribeNode.hooks'; function NodeComponent({ id, ...props }: { id: string } & React.HTMLAttributes) { const { node, childIds, isSelected, ref } = useNode(id); @@ -13,19 +13,7 @@ function NodeComponent({ id, ...props }: { id: string } & React.HTMLAttributes { switch (_props.node.type) { case 'text': { - const delta = _props.node.data.delta; - if (!delta) return null; - return ( - - ); + return ; } default: break; @@ -35,14 +23,16 @@ function NodeComponent({ id, ...props }: { id: string } & React.HTMLAttributes - {renderBlock({ - node, - childIds, - })} -
- {isSelected ?
: null} -
+ +
+ {renderBlock({ + node, + childIds, + })} +
+ {isSelected ?
: null} +
+ ); } diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/Root/index.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/Root/index.tsx index 4a5b80a7af..4ce3884400 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/Root/index.tsx +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/Root/index.tsx @@ -18,6 +18,7 @@ function Root({ documentData }: { documentData: DocumentData }) { return ; } + return (
diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/TextBlock/index.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/TextBlock/index.tsx index cb6e06d181..5dff8e199d 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/TextBlock/index.tsx +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/TextBlock/index.tsx @@ -4,8 +4,7 @@ import { useTextBlock } from './TextBlock.hooks'; import { Node } from '@/appflowy_app/stores/reducers/document/slice'; import NodeComponent from '../Node'; import HoveringToolbar from '../_shared/HoveringToolbar'; -import React from 'react'; -import { TextDelta } from '@/appflowy_app/interfaces/document'; +import React, { useMemo } from 'react'; function TextBlock({ node, @@ -13,11 +12,12 @@ function TextBlock({ placeholder, ...props }: { - node: Node & { data: { delta: TextDelta[] } }; + node: Node; childIds?: string[]; placeholder?: string; } & React.HTMLAttributes) { - const { editor, value, onChange, onKeyDownCapture, onDOMBeforeInput } = useTextBlock(node.data.delta); + const delta = useMemo(() => node.data.delta || [], [node.data.delta]); + const { editor, value, onChange, onKeyDownCapture, onDOMBeforeInput } = useTextBlock(delta); return (
diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/_shared/SubscribeNode.hooks.ts b/frontend/appflowy_tauri/src/appflowy_app/components/document/_shared/SubscribeNode.hooks.ts index 0848828c66..1381c7aad4 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/_shared/SubscribeNode.hooks.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/_shared/SubscribeNode.hooks.ts @@ -1,6 +1,7 @@ import { Node } from '@/appflowy_app/stores/reducers/document/slice'; import { useAppSelector } from '@/appflowy_app/stores/store'; -import { useMemo } from 'react'; +import { useMemo, createContext } from 'react'; +export const NodeContext = createContext(null); /** * Subscribe to a node and its children diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/_shared/TextInput.hooks.ts b/frontend/appflowy_tauri/src/appflowy_app/components/document/_shared/TextInput.hooks.ts index b8d52f1b0d..b1f393295c 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/_shared/TextInput.hooks.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/_shared/TextInput.hooks.ts @@ -1,12 +1,14 @@ import { useCallback, useContext, useMemo, useRef, useEffect } from 'react'; import { DocumentControllerContext } from '$app/stores/effects/document/document_controller'; -import { TextDelta } from '$app/interfaces/document'; +import { TextDelta, BlockActionType } from '$app/interfaces/document'; import { debounce } from '@/appflowy_app/utils/tool'; import { createEditor } from 'slate'; import { withReact } from 'slate-react'; import * as Y from 'yjs'; import { withYjs, YjsEditor, slateNodesToInsertDelta } from '@slate-yjs/core'; +import { NodeContext } from './SubscribeNode.hooks'; +import { BlockActionTypePB } from '@/services/backend/models/flowy-document2'; export function useTextInput(delta: TextDelta[]) { const { sendDelta } = useTransact(); @@ -19,23 +21,30 @@ export function useTextInput(delta: TextDelta[]) { function useController() { const docController = useContext(DocumentControllerContext); + const node = useContext(NodeContext); const update = useCallback( - (delta: TextDelta[]) => { - docController?.applyActions([ + async (delta: TextDelta[]) => { + if (!docController || !node) return; + await docController.applyActions([ { - type: 'update', + action: BlockActionTypePB.Update, payload: { block: { - data: { + id: node.id, + ty: node.type, + parent_id: node.parent || '', + children_id: node.children, + data: JSON.stringify({ + ...node.data, delta, - }, + }), }, }, }, ]); }, - [docController] + [docController, node] ); return { @@ -48,7 +57,7 @@ function useTransact() { const sendDelta = useCallback( (delta: TextDelta[]) => { - update(delta); + void update(delta); }, [update] ); @@ -99,7 +108,6 @@ function useBindYjs(delta: TextDelta[], update: (_delta: TextDelta[]) => void) { const textEventHandler = (event: Y.YTextEvent) => { const textDelta = event.target.toDelta(); - console.log('delta', textDelta); update(textDelta); }; yText.applyDelta(delta); diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/FolderItem.hooks.ts b/frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/FolderItem.hooks.ts index 5e63373880..18dd6780b3 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/FolderItem.hooks.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/FolderItem.hooks.ts @@ -10,6 +10,8 @@ import { AppObserver } from '../../../stores/effects/folder/app/app_observer'; import { useNavigate } from 'react-router-dom'; import { INITIAL_FOLDER_HEIGHT, PAGE_ITEM_HEIGHT } from '../../_shared/constants'; +import { DocumentController } from '$app/stores/effects/document/document_controller'; + export const useFolderEvents = (folder: IFolder, pages: IPage[]) => { const appDispatch = useAppDispatch(); const workspace = useAppSelector((state) => state.workspace); @@ -115,19 +117,24 @@ export const useFolderEvents = (folder: IFolder, pages: IPage[]) => { name: 'New Document 1', layoutType: ViewLayoutPB.Document, }); + try { + await new DocumentController(newView.id).create(); + appDispatch( + pagesActions.addPage({ + folderId: folder.id, + pageType: ViewLayoutPB.Document, + title: newView.name, + id: newView.id, + }) + ); - appDispatch( - pagesActions.addPage({ - folderId: folder.id, - pageType: ViewLayoutPB.Document, - title: newView.name, - id: newView.id, - }) - ); + setShowPages(true); - setShowPages(true); + navigate(`/page/document/${newView.id}`); + } catch (e) { + console.error(e); + } - navigate(`/page/document/${newView.id}`); }; const onAddNewBoardPage = async () => { diff --git a/frontend/appflowy_tauri/src/appflowy_app/interfaces/document.ts b/frontend/appflowy_tauri/src/appflowy_app/interfaces/document.ts index f4a0f665f7..efd51152fa 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/interfaces/document.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/interfaces/document.ts @@ -41,3 +41,11 @@ export interface DocumentData { childrenMap: Record; }; } + +// eslint-disable-next-line no-shadow +export enum BlockActionType { + Insert = 0, + Update = 1, + Delete = 2, + Move = 3 +} diff --git a/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_bd_svc.ts b/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_bd_svc.ts index 7ec2659139..f6ac575499 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_bd_svc.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_bd_svc.ts @@ -1,29 +1,30 @@ import { - DocumentDataPB, - DocumentVersionPB, - EditPayloadPB, FlowyError, - OpenDocumentPayloadPB, DocumentDataPB2, - ViewIdPB, OpenDocumentPayloadPBV2, + CreateDocumentPayloadPBV2, ApplyActionPayloadPBV2, - BlockActionTypePB, BlockActionPB, CloseDocumentPayloadPBV2, } from '@/services/backend'; -import { DocumentEventApplyEdit, DocumentEventGetDocument } from '@/services/backend/events/flowy-document'; import { Result } from 'ts-results'; -import { FolderEventCloseView } from '@/services/backend/events/flowy-folder2'; import { DocumentEvent2ApplyAction, DocumentEvent2CloseDocument, DocumentEvent2OpenDocument, + DocumentEvent2CreateDocument, } from '@/services/backend/events/flowy-document2'; export class DocumentBackendService { constructor(public readonly viewId: string) {} + create = (): Promise> => { + const payload = CreateDocumentPayloadPBV2.fromObject({ + document_id: this.viewId, + }); + return DocumentEvent2CreateDocument(payload); + }; + open = (): Promise> => { const payload = OpenDocumentPayloadPBV2.fromObject({ document_id: this.viewId, @@ -31,7 +32,7 @@ export class DocumentBackendService { return DocumentEvent2OpenDocument(payload); }; - applyActions = (actions: [BlockActionPB]): Promise> => { + applyActions = (actions: ReturnType[]): Promise> => { const payload = ApplyActionPayloadPBV2.fromObject({ document_id: this.viewId, actions: actions, diff --git a/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_controller.ts b/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_controller.ts index 2d0b169d26..b752bae2b0 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_controller.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_controller.ts @@ -1,7 +1,7 @@ import { DocumentData, BlockType } from '@/appflowy_app/interfaces/document'; import { createContext } from 'react'; import { DocumentBackendService } from './document_bd_svc'; -import { FlowyError } from '@/services/backend'; +import { FlowyError, BlockActionPB } from '@/services/backend'; import { DocumentObserver } from './document_observer'; export const DocumentControllerContext = createContext(null); @@ -15,51 +15,62 @@ export class DocumentController { this.observer = new DocumentObserver(viewId); } - open = async (): Promise => { - // example: + create = async (): Promise => { + const result = await this.backendService.create(); + if (result.ok) { + return; + } + return result.val; + }; + open = async (): Promise => { await this.observer.subscribe({ - didReceiveUpdate: () => { - console.log('didReceiveUpdate'); - }, + didReceiveUpdate: this.updated, }); const document = await this.backendService.open(); if (document.ok) { - console.log(document.val); - const blocks: DocumentData["blocks"] = {}; + const blocks: DocumentData['blocks'] = {}; document.val.blocks.forEach((block) => { + let data = {}; + try { + data = JSON.parse(block.data); + } catch { + console.log('json parse error', block.data); + } + blocks[block.id] = { id: block.id, type: block.ty as BlockType, parent: block.parent_id, children: block.children_id, - data: JSON.parse(block.data), + data, }; }); const childrenMap: Record = {}; - document.val.meta.children_map.forEach((child, key) => { childrenMap[key] = child.children; }); + document.val.meta.children_map.forEach((child, key) => { + childrenMap[key] = child.children; + }); return { rootId: document.val.page_id, blocks, meta: { - childrenMap - } - } + childrenMap, + }, + }; } - return document.val; + return Promise.reject(document.val); }; - applyActions = ( - actions: { - type: string; - payload: any; - }[] - ) => { - // + applyActions = async (actions: ReturnType[]) => { + await this.backendService.applyActions(actions); }; dispose = async () => { await this.backendService.close(); }; + + private updated = (payload: Uint8Array) => { + console.log('didReceiveUpdate', payload); + }; } diff --git a/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_observer.ts b/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_observer.ts index 7c9b2cb002..7ab264ed18 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_observer.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/stores/effects/document/document_observer.ts @@ -4,7 +4,7 @@ import { FolderNotificationObserver } from '../folder/notifications/observer'; import { DocumentNotification } from '@/services/backend'; import { DocumentNotificationObserver } from './notifications/observer'; -export type DidReceiveUpdateCallback = () => void; // todo: add params +export type DidReceiveUpdateCallback = (payload: Uint8Array) => void; // todo: add params export class DocumentObserver { private listener?: DocumentNotificationObserver; @@ -17,8 +17,9 @@ export class DocumentObserver { parserHandler: (notification, result) => { switch (notification) { case DocumentNotification.DidReceiveUpdate: - callbacks.didReceiveUpdate(); - // Fixme: ... + if (!result.ok) break; + callbacks.didReceiveUpdate(result.val); + break; default: break; diff --git a/frontend/appflowy_tauri/src/appflowy_app/views/DocumentPage.hooks.ts b/frontend/appflowy_tauri/src/appflowy_app/views/DocumentPage.hooks.ts index ba2a543838..01a8c78927 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/views/DocumentPage.hooks.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/views/DocumentPage.hooks.ts @@ -20,12 +20,16 @@ export const useDocument = () => { if (!params?.id) return; const c = new DocumentController(params.id); setController(c); - const res = await c.open(); - console.log(res) - if (!res) return; - // setDocumentData(res) - setDocumentId(params.id) - + try { + const res = await c.open(); + console.log(res) + if (!res) return; + setDocumentData(res); + setDocumentId(params.id); + } catch (e) { + console.log(e) + } + })(); return () => { console.log('==== leave ====', params?.id) diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 82a1111913..52d2692b1e 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -113,7 +113,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -124,7 +124,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -817,7 +817,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -834,7 +834,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -1792,7 +1792,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -1916,9 +1916,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" dependencies = [ "bytes", "fnv", @@ -2064,9 +2064,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.25" +version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ "bytes", "futures-channel", @@ -2668,7 +2668,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -2808,7 +2808,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -3027,9 +3027,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", "prost-derive", @@ -3037,9 +3037,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools", @@ -3050,9 +3050,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ "prost", ] @@ -3631,14 +3631,14 @@ checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -3653,7 +3653,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -3846,9 +3846,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.14" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", @@ -3942,7 +3942,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -4039,7 +4039,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] diff --git a/frontend/rust-lib/flowy-document2/src/document.rs b/frontend/rust-lib/flowy-document2/src/document.rs index e30cc4ccfc..46e539b70d 100644 --- a/frontend/rust-lib/flowy-document2/src/document.rs +++ b/frontend/rust-lib/flowy-document2/src/document.rs @@ -20,8 +20,8 @@ use crate::entities::{BlockPB, ChildrenPB, DocumentDataPB2, MetaPB}; pub struct Document(Arc>); impl Document { - pub fn new(collab: Collab, data: DocumentDataWrapper) -> FlowyResult { - let inner = InnerDocument::create(collab, data.0) + pub fn new(collab: Collab) -> FlowyResult { + let inner = InnerDocument::create(collab) .map_err(|_| FlowyError::from(ErrorCode::DocumentDataInvalid))?; Ok(Self(Arc::new(Mutex::new(inner)))) } diff --git a/frontend/rust-lib/flowy-document2/src/entities.rs b/frontend/rust-lib/flowy-document2/src/entities.rs index d93975917d..664587873f 100644 --- a/frontend/rust-lib/flowy-document2/src/entities.rs +++ b/frontend/rust-lib/flowy-document2/src/entities.rs @@ -9,6 +9,13 @@ pub struct OpenDocumentPayloadPBV2 { // Support customize initial data } +#[derive(Default, ProtoBuf)] +pub struct CreateDocumentPayloadPBV2 { + #[pb(index = 1)] + pub document_id: String, + // Support customize initial data +} + #[derive(Default, ProtoBuf)] pub struct CloseDocumentPayloadPBV2 { #[pb(index = 1)] @@ -102,3 +109,21 @@ impl Default for BlockActionTypePB { Self::Insert } } + +#[derive(Default, ProtoBuf)] +pub struct DocEventPB { + #[pb(index = 1)] + pub events: Vec, + + #[pb(index = 2)] + pub is_remote: bool, +} + +#[derive(Default, ProtoBuf)] +pub struct BlockEventPB { + #[pb(index = 1)] + pub path: Vec, + + #[pb(index = 2)] + pub delta: String, +} diff --git a/frontend/rust-lib/flowy-document2/src/event_handler.rs b/frontend/rust-lib/flowy-document2/src/event_handler.rs index 9405992533..0899bcc148 100644 --- a/frontend/rust-lib/flowy-document2/src/event_handler.rs +++ b/frontend/rust-lib/flowy-document2/src/event_handler.rs @@ -4,13 +4,14 @@ use crate::{ document::DocumentDataWrapper, entities::{ ApplyActionPayloadPBV2, BlockActionPB, BlockActionPayloadPB, BlockActionTypePB, - BlockPB, CloseDocumentPayloadPBV2, DocumentDataPB2, OpenDocumentPayloadPBV2, + BlockPB, CloseDocumentPayloadPBV2, DocumentDataPB2, OpenDocumentPayloadPBV2, CreateDocumentPayloadPBV2, + BlockEventPB }, manager::DocumentManager, }; use collab_document::blocks::{ - json_str_to_hashmap, Block, BlockAction, BlockActionPayload, BlockActionType, + json_str_to_hashmap, Block, BlockAction, BlockActionPayload, BlockActionType, BlockEvent }; use flowy_error::{FlowyError, FlowyResult}; use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult}; @@ -27,6 +28,16 @@ pub(crate) async fn open_document_handler( data_result_ok(DocumentDataPB2::from(DocumentDataWrapper(document_data))) } +pub(crate) async fn create_document_handler( + data: AFPluginData, + manager: AFPluginState>, +) -> FlowyResult<()> { + let context = data.into_inner(); + let data = DocumentDataWrapper::default(); + manager.create_document(context.document_id, data)?; + Ok(()) +} + pub(crate) async fn close_document_handler( data: AFPluginData, manager: AFPluginState>, @@ -96,3 +107,13 @@ impl From for Block { } } } + +impl From for BlockEventPB { + fn from(block_event: BlockEvent) -> Self { + let delta = serde_json::to_value(&block_event.delta).unwrap(); + Self { + path: block_event.path.into(), + delta: delta.to_string(), + } + } +} diff --git a/frontend/rust-lib/flowy-document2/src/event_map.rs b/frontend/rust-lib/flowy-document2/src/event_map.rs index d44586d4ab..6c1611bc40 100644 --- a/frontend/rust-lib/flowy-document2/src/event_map.rs +++ b/frontend/rust-lib/flowy-document2/src/event_map.rs @@ -5,7 +5,7 @@ use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; use lib_dispatch::prelude::AFPlugin; use crate::{ - event_handler::{apply_action_handler, close_document_handler, open_document_handler}, + event_handler::{apply_action_handler, close_document_handler, open_document_handler, create_document_handler }, manager::DocumentManager, }; @@ -17,6 +17,7 @@ pub fn init(document_manager: Arc) -> AFPlugin { plugin = plugin.event(DocumentEvent2::OpenDocument, open_document_handler); plugin = plugin.event(DocumentEvent2::CloseDocument, close_document_handler); plugin = plugin.event(DocumentEvent2::ApplyAction, apply_action_handler); + plugin = plugin.event(DocumentEvent2::CreateDocument, create_document_handler); plugin } @@ -32,4 +33,7 @@ pub enum DocumentEvent2 { #[event(input = "ApplyActionPayloadPBV2")] ApplyAction = 2, + + #[event(input = "CreateDocumentPayloadPBV2")] + CreateDocument = 3, } diff --git a/frontend/rust-lib/flowy-document2/src/manager.rs b/frontend/rust-lib/flowy-document2/src/manager.rs index a4b87f2143..d3cc4f0f98 100644 --- a/frontend/rust-lib/flowy-document2/src/manager.rs +++ b/frontend/rust-lib/flowy-document2/src/manager.rs @@ -8,6 +8,7 @@ use parking_lot::RwLock; use crate::{ document::{Document, DocumentDataWrapper}, notification::{send_notification, DocumentNotification}, + entities::{DocEventPB, BlockEventPB}, }; pub trait DocumentUser: Send + Sync { @@ -32,23 +33,45 @@ impl DocumentManager { } } + pub fn create_document(&self, doc_id: String, data: DocumentDataWrapper) -> FlowyResult> { + self.get_document(doc_id, Some(data)) + } + + fn get_document(&self, doc_id: String, data: Option) -> FlowyResult> { + let collab = self.get_collab_for_doc_id(&doc_id)?; + let document = Arc::new(Document::new(collab)?); + self.documents.write().insert(doc_id, document.clone()); + if data.is_some() { + // Here use unwrap() is safe, because we have checked data.is_some() before. + document.lock().create_with_data(data.unwrap().0).map_err(|err| FlowyError::internal().context(err))?; + } + Ok(document) + } + pub fn open_document(&self, doc_id: String) -> FlowyResult> { if let Some(doc) = self.documents.read().get(&doc_id) { return Ok(doc.clone()); } - let collab = self.get_collab_for_doc_id(&doc_id)?; - let data = DocumentDataWrapper::default(); - let document = Arc::new(Document::new(collab, data)?); + let document = self.get_document(doc_id.clone(), None)?; let clone_doc_id = doc_id.clone(); let _document_data = document .lock() - .open(move |_, _| { - // TODO: add payload data. - send_notification(&clone_doc_id, DocumentNotification::DidReceiveUpdate).send(); + .open(move |events, is_remote| { + println!("events: {:?}", events); + println!("is_remote: {:?}", is_remote); + send_notification(&clone_doc_id, DocumentNotification::DidReceiveUpdate) + .payload(DocEventPB { + events: events + .iter() + .map(|event| event.to_owned().into()) + .collect::>(), + is_remote: is_remote.to_owned(), + }) + .send(); + }) .map_err(|err| FlowyError::internal().context(err))?; - self.documents.write().insert(doc_id, document.clone()); Ok(document) }