mirror of
https://github.com/AppFlowy-IO/AppFlowy-Web.git
synced 2026-03-13 10:00:26 +08:00
chore: integrated collab version into YDoc
This commit is contained in:
@@ -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<VersionedDoc> {
|
||||
export async function openCollabDB(name: string, options: OpenCollabOptions = {}): Promise<YDoc> {
|
||||
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(
|
||||
|
||||
@@ -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<RowId, number[]>;
|
||||
}
|
||||
>(fetcher: Fetcher<T>, 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<RowId, number[]>) {
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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<YDoc> {
|
||||
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<DatabaseCsvImportStatusResponse> {
|
||||
async getDatabaseCsvImportStatus(workspaceId: string, taskId: string): Promise<DatabaseCsvImportStatusResponse> {
|
||||
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<CreateDatabaseViewResponse> {
|
||||
async createDatabaseView(
|
||||
workspaceId: string,
|
||||
viewId: string,
|
||||
payload: CreateDatabaseViewPayload
|
||||
): Promise<CreateDatabaseViewResponse> {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<VersionedDoc>;
|
||||
getPageDoc: (workspaceId: string, viewId: string, errorCallback?: (error: { code: number }) => void) => Promise<YDoc>;
|
||||
createRowDoc: (rowKey: string) => Promise<YDoc>;
|
||||
deleteRowDoc: (rowKey: string) => void;
|
||||
getAppDatabaseViewRelations: (workspaceId: string, databaseStorageId: string) => Promise<DatabaseRelations>;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
Reference in New Issue
Block a user