mirror of
https://github.com/docmost/docmost.git
synced 2026-05-18 07:24:04 +08:00
fix collaboration
This commit is contained in:
@@ -4,6 +4,7 @@ import { IndexeddbPersistence } from "y-indexeddb";
|
|||||||
import * as Y from "yjs";
|
import * as Y from "yjs";
|
||||||
import {
|
import {
|
||||||
HocuspocusProvider,
|
HocuspocusProvider,
|
||||||
|
onStatusParameters,
|
||||||
onAuthenticationFailedParameters,
|
onAuthenticationFailedParameters,
|
||||||
WebSocketStatus,
|
WebSocketStatus,
|
||||||
} from "@hocuspocus/provider";
|
} from "@hocuspocus/provider";
|
||||||
@@ -72,7 +73,7 @@ export default function PageEditor({
|
|||||||
ydocRef.current = new Y.Doc();
|
ydocRef.current = new Y.Doc();
|
||||||
}
|
}
|
||||||
const ydoc = ydocRef.current;
|
const ydoc = ydocRef.current;
|
||||||
const [isLocalSynced, setLocalSynced] = useState(false);
|
const [isLocalSynced, setIsLocalSynced] = useState(false);
|
||||||
const [isRemoteSynced, setRemoteSynced] = useState(false);
|
const [isRemoteSynced, setRemoteSynced] = useState(false);
|
||||||
const [yjsConnectionStatus, setYjsConnectionStatus] = useAtom(
|
const [yjsConnectionStatus, setYjsConnectionStatus] = useAtom(
|
||||||
yjsConnectionStatusAtom,
|
yjsConnectionStatusAtom,
|
||||||
@@ -100,29 +101,31 @@ export default function PageEditor({
|
|||||||
|
|
||||||
// Track when collaborative provider is ready and synced
|
// Track when collaborative provider is ready and synced
|
||||||
const [collabReady, setCollabReady] = useState(false);
|
const [collabReady, setCollabReady] = useState(false);
|
||||||
/*
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
remoteProvider?.status === WebSocketStatus.Connected &&
|
remoteProvider?.configuration.websocketProvider.status ===
|
||||||
|
WebSocketStatus.Connected &&
|
||||||
isLocalSynced &&
|
isLocalSynced &&
|
||||||
isRemoteSynced
|
isRemoteSynced
|
||||||
) {
|
) {
|
||||||
setCollabReady(true);
|
setCollabReady(true);
|
||||||
}
|
}
|
||||||
}, [remoteProvider?.status, isLocalSynced, isRemoteSynced]);
|
}, [
|
||||||
*/
|
remoteProvider?.configuration.websocketProvider.status,
|
||||||
|
isLocalSynced,
|
||||||
|
isRemoteSynced,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!providersRef.current) {
|
if (!providersRef.current) {
|
||||||
const local = new IndexeddbPersistence(documentName, ydoc);
|
const local = new IndexeddbPersistence(documentName, ydoc);
|
||||||
local.on("synced", () => setLocalSynced(true));
|
local.on("synced", () => setIsLocalSynced(true));
|
||||||
const remote = new HocuspocusProvider({
|
const remote = new HocuspocusProvider({
|
||||||
name: documentName,
|
name: documentName,
|
||||||
url: collaborationURL,
|
url: collaborationURL,
|
||||||
document: ydoc,
|
document: ydoc,
|
||||||
token: collabQuery?.token,
|
token: collabQuery?.token,
|
||||||
//connect: true,
|
|
||||||
//preserveConnection: false,
|
|
||||||
onAuthenticationFailed: (auth: onAuthenticationFailedParameters) => {
|
onAuthenticationFailed: (auth: onAuthenticationFailedParameters) => {
|
||||||
const payload = jwtDecode(collabQuery?.token);
|
const payload = jwtDecode(collabQuery?.token);
|
||||||
const now = Date.now().valueOf() / 1000;
|
const now = Date.now().valueOf() / 1000;
|
||||||
@@ -130,25 +133,28 @@ export default function PageEditor({
|
|||||||
if (isTokenExpired) {
|
if (isTokenExpired) {
|
||||||
refetchCollabToken().then((result) => {
|
refetchCollabToken().then((result) => {
|
||||||
if (result.data?.token) {
|
if (result.data?.token) {
|
||||||
remote.disconnect();
|
remote.configuration.websocketProvider.disconnect();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
remote.configuration.token = result.data.token;
|
remote.configuration.token = result.data.token;
|
||||||
remote.connect();
|
remote.configuration.websocketProvider.connect();
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
//onStatus: (status) => {
|
|
||||||
// if (status.status === "connected") {
|
|
||||||
// setYjsConnectionStatus(status.status);
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
remote.on("synced", () => setRemoteSynced(true));
|
remote.on("synced", () => setRemoteSynced(true));
|
||||||
remote.on("disconnect", () => {
|
|
||||||
setYjsConnectionStatus(WebSocketStatus.Disconnected);
|
const handleSocketStatus = (status: onStatusParameters) => {
|
||||||
});
|
if (status.status === "connected") {
|
||||||
|
setYjsConnectionStatus(WebSocketStatus.Connected);
|
||||||
|
} else if (status.status === "disconnected") {
|
||||||
|
setYjsConnectionStatus(WebSocketStatus.Disconnected);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
remote.configuration.websocketProvider.on("status", handleSocketStatus);
|
||||||
|
|
||||||
providersRef.current = { local, remote };
|
providersRef.current = { local, remote };
|
||||||
setProvidersReady(true);
|
setProvidersReady(true);
|
||||||
} else {
|
} else {
|
||||||
@@ -178,29 +184,29 @@ export default function PageEditor({
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Only connect/disconnect on tab/idle, not destroy
|
// Only connect/disconnect on tab/idle, not destroy
|
||||||
/*
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!providersReady || !providersRef.current) return;
|
if (!providersReady || !providersRef.current) return;
|
||||||
const remoteProvider = providersRef.current.remote;
|
const remoteProvider = providersRef.current.remote;
|
||||||
if (
|
if (
|
||||||
isIdle &&
|
isIdle &&
|
||||||
documentState === "hidden" &&
|
documentState === "hidden" &&
|
||||||
remoteProvider === WebSocketStatus.Connected
|
remoteProvider.configuration.websocketProvider.status ===
|
||||||
|
WebSocketStatus.Connected
|
||||||
) {
|
) {
|
||||||
remoteProvider.disconnect();
|
remoteProvider.configuration.websocketProvider.disconnect();
|
||||||
setIsCollabReady(false);
|
setIsCollabReady(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
documentState === "visible" &&
|
documentState === "visible" &&
|
||||||
remoteProvider.status === WebSocketStatus.Disconnected
|
remoteProvider.configuration.websocketProvider.status ===
|
||||||
|
WebSocketStatus.Disconnected
|
||||||
) {
|
) {
|
||||||
resetIdle();
|
resetIdle();
|
||||||
remoteProvider.connect();
|
remoteProvider.configuration.websocketProvider.connect();
|
||||||
setTimeout(() => setIsCollabReady(true), 500);
|
setTimeout(() => setIsCollabReady(true), 500);
|
||||||
}
|
}
|
||||||
}, [isIdle, documentState, providersReady, resetIdle]);
|
}, [isIdle, documentState, providersReady, resetIdle]);
|
||||||
*/
|
|
||||||
|
|
||||||
const extensions = useMemo(() => {
|
const extensions = useMemo(() => {
|
||||||
if (!remoteProvider || !currentUser?.user) return mainExtensions;
|
if (!remoteProvider || !currentUser?.user) return mainExtensions;
|
||||||
@@ -316,32 +322,37 @@ export default function PageEditor({
|
|||||||
setAsideState({ tab: "", isAsideOpen: false });
|
setAsideState({ tab: "", isAsideOpen: false });
|
||||||
}, [pageId]);
|
}, [pageId]);
|
||||||
|
|
||||||
/*
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (remoteProvider?.status === WebSocketStatus.Connecting) {
|
if (
|
||||||
|
remoteProvider?.configuration.websocketProvider.status ===
|
||||||
|
WebSocketStatus.Connecting
|
||||||
|
) {
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
setYjsConnectionStatus(WebSocketStatus.Disconnected);
|
setYjsConnectionStatus(WebSocketStatus.Disconnected);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
return () => clearTimeout(timeout);
|
return () => clearTimeout(timeout);
|
||||||
}
|
}
|
||||||
}, [remoteProvider?.status]);
|
}, [remoteProvider?.configuration.websocketProvider.status]);
|
||||||
*/
|
|
||||||
const isSynced = isLocalSynced && isRemoteSynced;
|
const isSynced = isLocalSynced && isRemoteSynced;
|
||||||
|
|
||||||
/*
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const collabReadyTimeout = setTimeout(() => {
|
const collabReadyTimeout = setTimeout(() => {
|
||||||
if (
|
if (
|
||||||
!isCollabReady &&
|
!isCollabReady &&
|
||||||
isSynced &&
|
isSynced &&
|
||||||
remoteProvider?.status === WebSocketStatus.Connected
|
remoteProvider?.configuration.websocketProvider.status ===
|
||||||
|
WebSocketStatus.Connected
|
||||||
) {
|
) {
|
||||||
setIsCollabReady(true);
|
setIsCollabReady(true);
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
return () => clearTimeout(collabReadyTimeout);
|
return () => clearTimeout(collabReadyTimeout);
|
||||||
}, [isRemoteSynced, isLocalSynced, remoteProvider?.status]);
|
}, [
|
||||||
*/
|
isRemoteSynced,
|
||||||
|
isLocalSynced,
|
||||||
|
remoteProvider?.configuration.websocketProvider.status,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Only honor user default page edit mode preference and permissions
|
// Only honor user default page edit mode preference and permissions
|
||||||
@@ -359,18 +370,18 @@ export default function PageEditor({
|
|||||||
}, [userPageEditMode, editor, editable]);
|
}, [userPageEditMode, editor, editable]);
|
||||||
|
|
||||||
const hasConnectedOnceRef = useRef(false);
|
const hasConnectedOnceRef = useRef(false);
|
||||||
const [showStatic, setShowStatic] = useState(false);
|
const [showStatic, setShowStatic] = useState(true);
|
||||||
|
|
||||||
/*
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
!hasConnectedOnceRef.current &&
|
!hasConnectedOnceRef.current &&
|
||||||
remoteProvider?.status === WebSocketStatus.Connected
|
remoteProvider?.configuration.websocketProvider.status ===
|
||||||
|
WebSocketStatus.Connected
|
||||||
) {
|
) {
|
||||||
hasConnectedOnceRef.current = true;
|
hasConnectedOnceRef.current = true;
|
||||||
setShowStatic(false);
|
setShowStatic(false);
|
||||||
}
|
}
|
||||||
}, [remoteProvider?.status]);*/
|
}, [remoteProvider?.configuration.websocketProvider.status]);
|
||||||
|
|
||||||
if (showStatic) {
|
if (showStatic) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -58,7 +58,6 @@
|
|||||||
"@tiptap/suggestion": "^3.0.9",
|
"@tiptap/suggestion": "^3.0.9",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
"bytes": "^3.1.2",
|
"bytes": "^3.1.2",
|
||||||
"core": "link:highlight.js/lib/core",
|
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"dompurify": "^3.2.6",
|
"dompurify": "^3.2.6",
|
||||||
|
|||||||
Generated
+1
-8
@@ -136,9 +136,6 @@ importers:
|
|||||||
bytes:
|
bytes:
|
||||||
specifier: ^3.1.2
|
specifier: ^3.1.2
|
||||||
version: 3.1.2
|
version: 3.1.2
|
||||||
core:
|
|
||||||
specifier: link:highlight.js/lib/core
|
|
||||||
version: link:highlight.js/lib/core
|
|
||||||
cross-env:
|
cross-env:
|
||||||
specifier: ^7.0.3
|
specifier: ^7.0.3
|
||||||
version: 7.0.3
|
version: 7.0.3
|
||||||
@@ -683,11 +680,7 @@ importers:
|
|||||||
specifier: ^8.24.1
|
specifier: ^8.24.1
|
||||||
version: 8.24.1(eslint@9.20.1(jiti@1.21.0))(typescript@5.7.3)
|
version: 8.24.1(eslint@9.20.1(jiti@1.21.0))(typescript@5.7.3)
|
||||||
|
|
||||||
packages/editor-ext:
|
packages/editor-ext: {}
|
||||||
dependencies:
|
|
||||||
'@tiptap/extension-code-block':
|
|
||||||
specifier: ^3.0.9
|
|
||||||
version: 3.0.9(@tiptap/core@3.0.9(@tiptap/pm@3.0.9))(@tiptap/pm@3.0.9)
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user