Просмотр исходного кода

add user date to awareness user local state

ryoji-s 2 лет назад
Родитель
Сommit
4791c7d447

+ 5 - 4
apps/app/src/components/PageEditor/PageEditor.tsx

@@ -5,7 +5,7 @@ import React, {
 import type EventEmitter from 'events';
 import nodePath from 'path';
 
-import type { IPageHasId } from '@growi/core';
+import type { IPageHasId, IUser } from '@growi/core';
 import { useGlobalSocket } from '@growi/core/dist/swr';
 import { pathUtils } from '@growi/core/dist/utils';
 import {
@@ -165,7 +165,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     initialValueRef.current = initialValue;
   }, [initialValue]);
 
-
+  const [userList, setUserList] = useState<IUser[]>([]);
   const [markdownToPreview, setMarkdownToPreview] = useState<string>(initialValue);
   const setMarkdownPreviewWithDebounce = useMemo(() => debounce(100, throttle(150, (value: string) => {
     setMarkdownToPreview(value);
@@ -440,7 +440,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   return (
     <div data-testid="page-editor" id="page-editor" className={`flex-expand-vert ${props.visibility ? '' : 'd-none'}`}>
       <div className="px-4 py-2">
-        <PageHeader />
+        <PageHeader userList={userList} />
       </div>
       <div className={`flex-expand-horiz ${props.visibility ? '' : 'd-none'}`}>
         <div className="page-editor-editor-container flex-expand-vert">
@@ -463,10 +463,11 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
             acceptedFileType={acceptedFileType}
             onScroll={scrollEditorHandlerThrottle}
             indentSize={currentIndentSize ?? defaultIndentSize}
-            userName={user?.name}
+            user={user}
             pageId={pageId ?? undefined}
             initialValue={initialValue}
             onOpenEditor={markdown => setMarkdownToPreview(markdown)}
+            onUserList={setUserList}
             editorTheme={editorSettings?.theme}
             editorKeymap={editorSettings?.keymapMode}
           />

+ 6 - 3
packages/editor/src/components/CodeMirrorEditorMain.tsx

@@ -2,6 +2,7 @@ import { useEffect } from 'react';
 
 import { type Extension } from '@codemirror/state';
 import { keymap, scrollPastEnd } from '@codemirror/view';
+import { IUser } from '@growi/core/dist/interfaces';
 
 import { GlobalCodeMirrorEditorKey, AcceptedUploadFileType } from '../consts';
 import { setDataLine } from '../services/extensions/setDataLine';
@@ -23,22 +24,24 @@ type Props = {
   onScroll?: () => void,
   acceptedFileType?: AcceptedUploadFileType,
   indentSize?: number,
-  userName?: string,
+  user?: IUser
   pageId?: string,
   initialValue?: string,
   onOpenEditor?: (markdown: string) => void,
+  onUserList?: (userList: any[]) => void,
   editorTheme?: string,
   editorKeymap?: string,
 }
 
 export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
   const {
-    onSave, onChange, onUpload, onScroll, acceptedFileType, indentSize, userName, pageId, initialValue, onOpenEditor, editorTheme, editorKeymap,
+    onSave, onChange, onUpload, onScroll, acceptedFileType, indentSize,
+    user, pageId, initialValue, onOpenEditor, onUserList, editorTheme, editorKeymap,
   } = props;
 
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
 
-  useCollaborativeEditorMode(userName, pageId, initialValue, onOpenEditor, codeMirrorEditor);
+  useCollaborativeEditorMode(user, pageId, initialValue, onOpenEditor, onUserList, codeMirrorEditor);
 
   const acceptedFileTypeNoOpt = acceptedFileType ?? AcceptedUploadFileType.NONE;
 

+ 31 - 9
packages/editor/src/stores/use-collaborative-editor-mode.ts

@@ -1,6 +1,6 @@
 import { useEffect, useState } from 'react';
 
-import { GlobalSocketEventName } from '@growi/core/dist/interfaces';
+import { GlobalSocketEventName, IUser } from '@growi/core/dist/interfaces';
 import { useGlobalSocket, GLOBAL_SOCKET_NS } from '@growi/core/dist/swr';
 // see: https://github.com/yjs/y-codemirror.next#example
 // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -12,11 +12,19 @@ import * as Y from 'yjs';
 import { userColor } from '../consts';
 import { UseCodeMirrorEditor } from '../services';
 
+type UserLocalState = {
+  name: string;
+  user?: IUser;
+  color: string;
+  colorLight: string;
+}
+
 export const useCollaborativeEditorMode = (
-    userName?: string,
+    user?: IUser,
     pageId?: string,
     initialValue?: string,
     onOpenEditor?: (markdown: string) => void,
+    onUserList?: (userList: IUser[]) => void,
     codeMirrorEditor?: UseCodeMirrorEditor,
 ): void => {
   const [ydoc, setYdoc] = useState<Y.Doc | null>(null);
@@ -34,8 +42,8 @@ export const useCollaborativeEditorMode = (
     ydoc?.destroy();
     setYdoc(null);
 
-    // NOTICE: Destorying the provider leaves awareness in the other user's connection,
-    // so only awareness is destoryed here
+    // NOTICE: Destroying the provider leaves awareness in the other user's connection,
+    // so only awareness is destroyed here
     provider?.awareness.destroy();
 
     // TODO: catch ydoc:sync:error GlobalSocketEventName.YDocSyncError
@@ -50,7 +58,7 @@ export const useCollaborativeEditorMode = (
       return;
     }
 
-    // NOTICE: Old provider destory at the time of ydoc setup,
+    // NOTICE: Old provider destroy at the time of ydoc setup,
     // because the awareness destroying is not sync to other clients
     provider?.destroy();
     setProvider(null);
@@ -71,11 +79,14 @@ export const useCollaborativeEditorMode = (
       { autoConnect: true },
     );
 
-    socketIOProvider.awareness.setLocalStateField('user', {
-      name: userName ? `${userName}` : `Guest User ${Math.floor(Math.random() * 100)}`,
+    const userLocalState: UserLocalState = {
+      name: user?.name ? `${user.name}` : `Guest User ${Math.floor(Math.random() * 100)}`,
+      user,
       color: userColor.color,
       colorLight: userColor.light,
-    });
+    };
+
+    socketIOProvider.awareness.setLocalStateField('user', userLocalState);
 
     socketIOProvider.on('sync', (isSync: boolean) => {
       if (isSync) {
@@ -83,6 +94,17 @@ export const useCollaborativeEditorMode = (
       }
     });
 
+    // update args type see: SocketIOProvider.Awareness.awarenessUpdate
+    socketIOProvider.awareness.on('update', (update: any) => {
+      if (onUserList) {
+        const { added, removed } = update;
+        if (added.length > 0 || removed.length > 0) {
+          const userList: IUser[] = Array.from(socketIOProvider.awareness.states.values(), value => value.user.user && value.user.user);
+          onUserList(userList);
+        }
+      }
+    });
+
     setProvider(socketIOProvider);
   };
 
@@ -115,7 +137,7 @@ export const useCollaborativeEditorMode = (
 
   useEffect(cleanupYDocAndProvider, [cPageId, pageId, provider, socket, ydoc]);
   useEffect(setupYDoc, [provider, ydoc]);
-  useEffect(setupProvider, [initialValue, pageId, provider, socket, userName, ydoc]);
+  useEffect(setupProvider, [initialValue, onUserList, pageId, provider, socket, user, ydoc]);
   useEffect(setupYDocExtensions, [codeMirrorEditor, provider, ydoc]);
   useEffect(initializeEditor, [codeMirrorEditor, isInit, onOpenEditor, ydoc]);
 };