diff --git a/src/application/db/index.ts b/src/application/db/index.ts index 32a62089..27e45c73 100644 --- a/src/application/db/index.ts +++ b/src/application/db/index.ts @@ -11,7 +11,7 @@ import { workspaceMemberProfileSchema, WorkspaceMemberProfileTable, } from '@/application/db/tables/workspace_member_profiles'; -import { VersionedDoc, YDoc } from '@/application/types'; +import { YDoc } from '@/application/types'; import { Log } from '@/utils/log'; type DexieTables = ViewMetasTable & UserTable & rowTable & WorkspaceMemberProfileTable & VersionsTable; @@ -130,10 +130,10 @@ export interface OpenCollabOptions { /** * Open the collaboration database, and return a function to close it */ -export async function openCollabDB(name: string, options: OpenCollabOptions = {}): Promise { +export async function openCollabDB(name: string, options: OpenCollabOptions = {}): Promise { const doc = new Y.Doc({ guid: name, - }); + }) as YDoc; await ensureYjsStores(name); @@ -148,6 +148,7 @@ export async function openCollabDB(name: string, options: OpenCollabOptions = {} } version = options.expectedVersion; + doc.version = version; provider.on('synced', () => { if (!openedSet.has(name)) { @@ -157,7 +158,7 @@ export async function openCollabDB(name: string, options: OpenCollabOptions = {} await provider.whenSynced; - return { doc, version }; + return doc; } export async function openCollabDBWithProvider( diff --git a/src/application/services/js-services/cache/index.ts b/src/application/services/js-services/cache/index.ts index 225d1292..7b2c2337 100644 --- a/src/application/services/js-services/cache/index.ts +++ b/src/application/services/js-services/cache/index.ts @@ -194,7 +194,7 @@ export async function getPublishView< ) { const name = `${namespace}_${publishName}`; - const { doc } = await openCollabDB(name); + const doc = await openCollabDB(name); const exist = (await hasViewMetaCache(name)) && hasCollabCache(doc); let didRevalidate = false; @@ -251,7 +251,7 @@ export async function getPageDoc< rows?: Record; } >(fetcher: Fetcher, name: string, strategy: StrategyType = StrategyType.CACHE_AND_NETWORK) { - const { doc, version } = await openCollabDB(name); + const doc = await openCollabDB(name); const exist = hasCollabCache(doc); let didRevalidate = false; @@ -295,7 +295,7 @@ export async function getPageDoc< }); } - return { doc, version }; + return doc; } async function updateRows(collab: YDoc, rows: Record) { @@ -399,7 +399,7 @@ export async function revalidatePublishView< if (subDocuments) { for (const [key, value] of Object.entries(subDocuments)) { - const { doc } = await openCollabDB(key); + const doc = await openCollabDB(key); applyYDoc(doc, new Uint8Array(value)); } diff --git a/src/application/services/js-services/http/http_api.ts b/src/application/services/js-services/http/http_api.ts index e2589687..74ba2aff 100644 --- a/src/application/services/js-services/http/http_api.ts +++ b/src/application/services/js-services/http/http_api.ts @@ -897,7 +897,7 @@ export async function databaseBlobDiff( return database_blob.DatabaseBlobDiffResponse.decode(bytes); } -export async function getCollabVersions(workspaceId: string, objectId: string, since: Date | undefined) { +export async function getCollabVersions(workspaceId: string, objectId: string, since?: Date) { const url = `/api/workspace/${workspaceId}/collab/${objectId}/history`; const from = since?.getTime() || null; const response = await axiosInstance?.get<{ @@ -908,7 +908,8 @@ export async function getCollabVersions(workspaceId: string, objectId: string, s name: string | null, created_at: string, created_by: number | null, - is_deleted: boolean + is_deleted: boolean, + editors: number[], }[]; message: string; }>(url, { @@ -927,7 +928,8 @@ export async function getCollabVersions(workspaceId: string, objectId: string, s parentId: data.parent, name: data.name, createdAt: new Date(data.created_at), - isDeleted: data.is_deleted + isDeleted: data.is_deleted, + editors: data.editors, }; }); } diff --git a/src/application/services/js-services/index.ts b/src/application/services/js-services/index.ts index 9a825c53..ba9e07e7 100644 --- a/src/application/services/js-services/index.ts +++ b/src/application/services/js-services/index.ts @@ -60,7 +60,8 @@ import { UploadPublishNamespacePayload, ViewIconType, WorkspaceMember, - YjsEditorKey + YDoc, + YjsEditorKey, } from '@/application/types'; import { applyYDoc } from '@/application/ydoc/apply'; import { RepeatedChatMessage } from '@/components/chat'; @@ -86,6 +87,14 @@ export class AFClientService implements AFService { APIService.initAPIService(config.cloudConfig); } + async createRowDoc(rowKey: string): Promise { + throw new Error('Not implemented'); + } + + deleteRowDoc(rowKey: string){ + throw new Error('Not implemented'); + } + getAxiosInstance() { return APIService.getAxiosInstance(); } @@ -193,7 +202,7 @@ export class AFClientService implements AFService { } async getPublishRowDocument(viewId: string) { - const { doc } = await openCollabDB(viewId); + const doc = await openCollabDB(viewId); if (hasCollabCache(doc)) { return doc; @@ -536,7 +545,7 @@ export class AFClientService implements AFService { const isLoaded = this.viewLoaded.has(name); - const { doc, version } = await getPageDoc( + const doc = await getPageDoc( async () => { try { return await fetchPageCollab(workspaceId, viewId); @@ -561,7 +570,7 @@ export class AFClientService implements AFService { this.viewLoaded.add(name); } - return { doc, version }; + return doc; } async getInvitation(invitationId: string) { @@ -625,10 +634,7 @@ export class AFClientService implements AFService { return APIService.uploadDatabaseCsvImportFile(presignedUrl, file, onProgress); } - async getDatabaseCsvImportStatus( - workspaceId: string, - taskId: string - ): Promise { + async getDatabaseCsvImportStatus(workspaceId: string, taskId: string): Promise { return APIService.getDatabaseCsvImportStatus(workspaceId, taskId); } @@ -648,7 +654,11 @@ export class AFClientService implements AFService { return APIService.addAppPage(workspaceId, parentViewId, payload); } - async createDatabaseView(workspaceId: string, viewId: string, payload: CreateDatabaseViewPayload): Promise { + async createDatabaseView( + workspaceId: string, + viewId: string, + payload: CreateDatabaseViewPayload + ): Promise { return APIService.createDatabaseView(workspaceId, viewId, payload); } @@ -774,16 +784,20 @@ export class AFClientService implements AFService { return APIService.getMentionableUsers(workspaceId); } - async updatePageMention(workspaceId: string, viewId: string, data: { - person_id: string; - block_id?: string | null; - row_id?: string | null; - require_notification: boolean; - view_name: string; - ancestors?: string[] | null; - view_layout?: number | null; - is_row_document?: boolean; - }) { + async updatePageMention( + workspaceId: string, + viewId: string, + data: { + person_id: string; + block_id?: string | null; + row_id?: string | null; + require_notification: boolean; + view_name: string; + ancestors?: string[] | null; + view_layout?: number | null; + is_row_document?: boolean; + } + ) { return APIService.updatePageMention(workspaceId, viewId, data); } diff --git a/src/application/services/services.type.ts b/src/application/services/services.type.ts index 19eac8ed..7e6e2ea9 100644 --- a/src/application/services/services.type.ts +++ b/src/application/services/services.type.ts @@ -51,7 +51,6 @@ import { UploadPublishNamespacePayload, User, UserWorkspaceInfo, - VersionedDoc, View, ViewIconType, Workspace, @@ -123,7 +122,7 @@ export interface WorkspaceService { } export interface AppService { - getPageDoc: (workspaceId: string, viewId: string, errorCallback?: (error: { code: number }) => void) => Promise; + getPageDoc: (workspaceId: string, viewId: string, errorCallback?: (error: { code: number }) => void) => Promise; createRowDoc: (rowKey: string) => Promise; deleteRowDoc: (rowKey: string) => void; getAppDatabaseViewRelations: (workspaceId: string, databaseStorageId: string) => Promise; diff --git a/src/application/types.ts b/src/application/types.ts index f28aaf74..6f4ae05f 100644 --- a/src/application/types.ts +++ b/src/application/types.ts @@ -428,6 +428,11 @@ export interface YDoc extends Y.Doc { */ object_id?: string; + /** + * Collab version for this document. + */ + version?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any getMap(key: YjsEditorKey.data_section): YSharedRoot | any; } @@ -1069,11 +1074,6 @@ export interface View { access_level?: AccessLevel; } -export interface VersionedDoc { - doc: Y.Doc; - version: string | null; -} - export interface UpdatePublishConfigPayload { comments_enabled?: boolean; duplicate_enabled?: boolean; diff --git a/src/components/app/hooks/useViewOperations.ts b/src/components/app/hooks/useViewOperations.ts index aaaf7f5c..0358e56b 100644 --- a/src/components/app/hooks/useViewOperations.ts +++ b/src/components/app/hooks/useViewOperations.ts @@ -57,10 +57,10 @@ export function useViewOperations() { // Register workspace database document for sync const registerWorkspaceDatabaseDoc = useCallback( async (workspaceId: string, databaseStorageId: string) => { - const { doc, version } = await openCollabDB(databaseStorageId); + const doc = await openCollabDB(databaseStorageId); doc.guid = databaseStorageId; - const { doc: workspaceDatabaseDoc } = registerSyncContext({ doc, collabType: Types.WorkspaceDatabase, version }); + const { doc: workspaceDatabaseDoc } = registerSyncContext({ doc, collabType: Types.WorkspaceDatabase }); workspaceDatabaseDocMapRef.current.clear(); workspaceDatabaseDocMapRef.current.set(workspaceId, workspaceDatabaseDoc); @@ -393,7 +393,7 @@ export function useViewOperations() { hasAwareness: !!awareness, }); - const syncContext = registerSyncContext({ doc, collabType, awareness, version }); + const syncContext = registerSyncContext({ doc, collabType, awareness }); docWithMeta._syncBound = true; @@ -436,8 +436,7 @@ export function useViewOperations() { }); const syncContext = registerSyncContext({ doc, - collabType: Types.DatabaseRow, - version: null, // atm. versions are not used for database rows + collabType: Types.DatabaseRow }); createdRowKeys.current.push(rowKey); diff --git a/src/components/ws/useSync.ts b/src/components/ws/useSync.ts index 5604d853..1d7e474c 100644 --- a/src/components/ws/useSync.ts +++ b/src/components/ws/useSync.ts @@ -11,7 +11,7 @@ import { openCollabDB } from '@/application/db'; import * as http from '@/application/services/js-services/http/http_api'; import { collabFullSyncBatch } from '@/application/services/js-services/http/http_api'; import { handleMessage, initSync, SyncContext } from '@/application/services/js-services/sync-protocol'; -import { Types, User } from '@/application/types'; +import { Types, User, YDoc } from '@/application/types'; import { useCurrentUser } from '@/components/main/app.hooks'; import { AppflowyWebSocketType } from '@/components/ws/useAppflowyWebSocket'; import { BroadcastChannelType } from '@/components/ws/useBroadcastChannel'; @@ -25,10 +25,9 @@ export interface RegisterSyncContext { * The Y.Doc instance to be used for collaboration. * It must have a valid guid (UUID v4). */ - doc: Y.Doc; + doc: YDoc; awareness?: awarenessProtocol.Awareness; collabType: Types; - version: string | null; emit?: (reply: messages.IMessage) => void; } @@ -396,14 +395,13 @@ export const useSync = (ws: AppflowyWebSocketType, bc: BroadcastChannelType, eve // remove stale persisted data for older version and reinitialize it await deleteDB(context.doc.guid); - const { doc } = await openCollabDB(context.doc.guid, { expectedVersion: newVersion, currentUser: user?.uid }); + const doc = await openCollabDB(context.doc.guid, { expectedVersion: newVersion, currentUser: user?.uid }); const awareness = new awarenessProtocol.Awareness(doc); context = registerSyncContext({ doc: awareness.doc, awareness, - collabType: context.collabType, - version: newVersion || null, + collabType: context.collabType }); } @@ -459,16 +457,15 @@ export const useSync = (ws: AppflowyWebSocketType, bc: BroadcastChannelType, eve context.doc.emit('reset', [context, version]) context.doc.destroy(); - const { doc } = await openCollabDB(context.doc.guid, { expectedVersion: version, currentUser: currentUser.uid }); + const doc = await openCollabDB(context.doc.guid, { expectedVersion: version, currentUser: currentUser.uid }); Y.applyUpdate(doc, docState); const awareness = new awarenessProtocol.Awareness(doc); registerSyncContext({ - doc: awareness.doc, + doc, awareness, - collabType: context.collabType, - version, + collabType: context.collabType }); } }, [registeredContexts, currentUser, registerSyncContext]);