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

+ 2 - 1
apps/app/src/client/services/side-effects/page-updated.ts

@@ -1,9 +1,10 @@
 import { useCallback, useEffect } from 'react';
 
+import { useGlobalSocket } from '@growi/core/dist/swr';
+
 import { SocketEventName } from '~/interfaces/websocket';
 import { useCurrentPageId } from '~/stores/page';
 import { useSetRemoteLatestPageData, type RemoteRevisionData } from '~/stores/remote-latest-page';
-import { useGlobalSocket } from '~/stores/websocket';
 
 export const usePageUpdatedEffect = (): void => {
 

+ 1 - 1
apps/app/src/components/ItemsTree/ItemsTree.tsx

@@ -5,6 +5,7 @@ import React, {
 import path from 'path';
 
 import type { Nullable, IPageHasId, IPageToDeleteWithMeta } from '@growi/core';
+import { useGlobalSocket } from '@growi/core/dist/swr';
 import { useTranslation } from 'next-i18next';
 import { useRouter } from 'next/router';
 import { debounce } from 'throttle-debounce';
@@ -22,7 +23,6 @@ import {
 } from '~/stores/page-listing';
 import { mutateSearching } from '~/stores/search';
 import { usePageTreeDescCountMap, useSidebarScrollerRef } from '~/stores/ui';
-import { useGlobalSocket } from '~/stores/websocket';
 import loggerFactory from '~/utils/logger';
 
 import { ItemNode, SimpleItemProps } from '../TreeItem';

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

@@ -6,6 +6,7 @@ import EventEmitter from 'events';
 import nodePath from 'path';
 
 import type { IPageHasId } from '@growi/core';
+import { useGlobalSocket } from '@growi/core/dist/swr';
 import { pathUtils } from '@growi/core/dist/utils';
 import {
   CodeMirrorEditorMain, GlobalCodeMirrorEditorKey, AcceptedUploadFileType,
@@ -50,7 +51,6 @@ import {
   useEditorMode, useSelectedGrant,
 } from '~/stores/ui';
 import { useNextThemes } from '~/stores/use-next-themes';
-import { useGlobalSocket } from '~/stores/websocket';
 import loggerFactory from '~/utils/logger';
 
 
@@ -580,13 +580,12 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
             onChange={markdownChangedHandler}
             onSave={saveWithShortcut}
             onUpload={uploadHandler}
+            acceptedFileType={acceptedFileType}
             indentSize={currentIndentSize ?? defaultIndentSize}
-            pageId={pageId}
             userName={user?.name}
-            socket={socket}
+            pageId={pageId ?? undefined}
             initialValue={initialValue}
-            setMarkdownToPreview={setMarkdownToPreview}
-            acceptedFileType={acceptedFileType}
+            onOpenEditor={markdown => setMarkdownToPreview(markdown)}
           />
         </div>
         <div className="page-editor-preview-container flex-expand-vert d-none d-lg-flex">

+ 1 - 1
apps/app/src/components/PrivateLegacyPages.tsx

@@ -2,6 +2,7 @@ import React, {
   useCallback, useMemo, useRef, useState, useEffect,
 } from 'react';
 
+import { useGlobalSocket } from '@growi/core/dist/swr';
 import { useTranslation } from 'next-i18next';
 import {
   UncontrolledButtonDropdown, DropdownToggle, DropdownMenu, DropdownItem, Modal, ModalHeader, ModalBody, ModalFooter,
@@ -22,7 +23,6 @@ import { mutatePageTree, useSWRxV5MigrationStatus } from '~/stores/page-listing'
 import {
   useSWRxSearch,
 } from '~/stores/search';
-import { useGlobalSocket } from '~/stores/websocket';
 
 import { MenuItemType } from './Common/Dropdown/PageItemControl';
 import PaginationWrapper from './PaginationWrapper';

+ 0 - 4
apps/app/src/interfaces/websocket.ts

@@ -44,10 +44,6 @@ export const SocketEventName = {
   PageCreated: 'page:create',
   PageUpdated: 'page:update',
   PageDeleted: 'page:delete',
-
-  // YDoc
-  YDocSync: 'ydoc:sync',
-  YDocSyncError: 'ydoc:sync:error',
 } as const;
 export type SocketEventName = typeof SocketEventName[keyof typeof SocketEventName];
 

+ 3 - 3
apps/app/src/server/service/socket-io.js

@@ -1,6 +1,6 @@
+import { GlobalSocketEventName } from '@growi/core/dist/interfaces';
 import { Server } from 'socket.io';
 
-import { SocketEventName } from '~/interfaces/websocket';
 import loggerFactory from '~/utils/logger';
 
 import { RoomPrefix, getRoomNameWithId } from '../util/socket-io-helpers';
@@ -161,13 +161,13 @@ class SocketIoService {
 
   setupYjsConnection() {
     this.io.on('connection', (socket) => {
-      socket.on(SocketEventName.YDocSync, async({ pageId, initialValue }) => {
+      socket.on(GlobalSocketEventName.YDocSync, async({ pageId, initialValue }) => {
         try {
           await this.yjsConnectionManager.handleYDocSync(pageId, initialValue);
         }
         catch (error) {
           logger.warn(error.message);
-          socket.emit(SocketEventName.YDocSyncError, 'An error occurred during YDoc synchronization.');
+          socket.emit(GlobalSocketEventName.YDocSyncError, 'An error occurred during YDoc synchronization.');
         }
       });
     });

+ 1 - 7
apps/app/src/stores/websocket.tsx

@@ -1,5 +1,6 @@
 import { useEffect } from 'react';
 
+import { useGlobalSocket, GLOBAL_SOCKET_KEY, GLOBAL_SOCKET_NS } from '@growi/core/dist/swr';
 import type { Socket } from 'socket.io-client';
 import { SWRResponse } from 'swr';
 
@@ -9,9 +10,6 @@ import { useStaticSWR } from './use-static-swr';
 
 const logger = loggerFactory('growi:stores:ui');
 
-export const GLOBAL_SOCKET_NS = '/';
-export const GLOBAL_SOCKET_KEY = 'globalSocket';
-
 export const GLOBAL_ADMIN_SOCKET_NS = '/admin';
 export const GLOBAL_ADMIN_SOCKET_KEY = 'globalAdminSocket';
 
@@ -40,10 +38,6 @@ export const useSetupGlobalSocket = (): void => {
   }, [mutate]);
 };
 
-export const useGlobalSocket = (): SWRResponse<Socket, Error> => {
-  return useStaticSWR(GLOBAL_SOCKET_KEY);
-};
-
 // comment out for porduction build error: https://github.com/weseek/growi/pull/7131
 /*
  * Global Admin Socket

+ 1 - 0
packages/core/src/interfaces/index.ts

@@ -13,3 +13,4 @@ export * from './subscription';
 export * from './tag';
 export * from './user';
 export * from './vite';
+export * from './websocket';

+ 6 - 0
packages/core/src/interfaces/websocket.ts

@@ -0,0 +1,6 @@
+export const GlobalSocketEventName = {
+  // YDoc
+  YDocSync: 'ydoc:sync',
+  YDocSyncError: 'ydoc:sync:error',
+} as const;
+export type GlobalSocketEventName = typeof GlobalSocketEventName[keyof typeof GlobalSocketEventName];

+ 1 - 0
packages/core/src/swr/index.ts

@@ -1,2 +1,3 @@
 export * from './use-swr-static';
 export * from './with-utils';
+export * from './use-global-socket';

+ 11 - 0
packages/core/src/swr/use-global-socket.ts

@@ -0,0 +1,11 @@
+import type { Socket } from 'socket.io-client';
+import type { SWRResponse } from 'swr';
+
+import { useSWRStatic } from './use-swr-static';
+
+export const GLOBAL_SOCKET_NS = '/';
+export const GLOBAL_SOCKET_KEY = 'globalSocket';
+
+export const useGlobalSocket = (): SWRResponse<Socket, Error> => {
+  return useSWRStatic(GLOBAL_SOCKET_KEY);
+};

+ 20 - 28
packages/editor/src/components/CodeMirrorEditorMain.tsx

@@ -2,9 +2,9 @@ import { useEffect, useState } from 'react';
 
 import type { Extension } from '@codemirror/state';
 import { keymap, scrollPastEnd } from '@codemirror/view';
-import type { Nullable } from '@growi/core';
-// TODO: import socket.io-client types wihtout lint error
-// import type { Socket, DefaultEventsMap } from 'socket.io-client';
+import { GlobalSocketEventName } 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
 // @ts-ignore
 import { yCollab } from 'y-codemirror.next';
@@ -16,11 +16,6 @@ import { useCodeMirrorEditorIsolated } from '../stores';
 
 import { CodeMirrorEditor } from '.';
 
-// TODO: use SocketEventName
-// import { SocketEventName } from '~/interfaces/websocket';
-// TODO: import { GLOBAL_SOCKET_NS } from '~/stores/websocket';
-const GLOBAL_SOCKET_NS = '/';
-
 const additionalExtensions: Extension[] = [
   scrollPastEnd(),
 ];
@@ -31,19 +26,20 @@ type Props = {
   onUpload?: (files: File[]) => void,
   acceptedFileType?: AcceptedUploadFileType,
   indentSize?: number,
-  pageId: Nullable<string>,
   userName?: string,
-  socket?: any, // Socket<DefaultEventsMap, DefaultEventsMap>,
-  initialValue: string,
-  setMarkdownToPreview: React.Dispatch<React.SetStateAction<string>>,
+  pageId?: string,
+  initialValue?: string,
+  onOpenEditor?: (markdown: string) => void,
 }
 
 export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
   const {
-    onSave, onChange, onUpload, acceptedFileType, indentSize, pageId, userName, initialValue, socket, setMarkdownToPreview,
+    onSave, onChange, onUpload, acceptedFileType, indentSize, userName, pageId, initialValue, onOpenEditor,
   } = props;
 
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
+  const { data: socket } = useGlobalSocket();
+
   const [ydoc, setYdoc] = useState<Y.Doc | null>(null);
   const [provider, setProvider] = useState<SocketIOProvider | null>(null);
   const [cPageId, setCPageId] = useState(pageId);
@@ -55,7 +51,7 @@ export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
     if (cPageId === pageId) {
       return;
     }
-    if (!provider || !ydoc || socket == null) {
+    if (provider == null || ydoc == null || socket == null) {
       return;
     }
 
@@ -66,9 +62,9 @@ export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
     provider.disconnect();
     setProvider(null);
 
-    // TODO: catch ydoc:sync:error
-    // TODO: use SocketEventName
-    socket.off('ydoc:sync');
+    // TODO: catch ydoc:sync:error GlobalSocketEventName.YDocSyncError
+
+    socket.off(GlobalSocketEventName.YDocSync);
 
     setCPageId(pageId);
   }, [cPageId, pageId, provider, socket, ydoc]);
@@ -81,9 +77,9 @@ export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
 
     const _ydoc = new Y.Doc();
     setYdoc(_ydoc);
-  }, [initialValue, ydoc]);
+  }, [ydoc]);
 
-  // setup socketIOProvider
+  // setup socketIOProvider and sync ydoc
   useEffect(() => {
     if (ydoc == null || provider != null || socket == null) {
       return;
@@ -104,8 +100,7 @@ export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
 
     socketIOProvider.on('sync', (isSync: boolean) => {
       if (isSync) {
-        // TODO: use SocketEventName
-        socket.emit('ydoc:sync', { pageId, initialValue });
+        socket.emit(GlobalSocketEventName.YDocSync, { pageId, initialValue });
       }
     });
 
@@ -131,21 +126,18 @@ export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
     ]);
 
     return cleanup;
-  }, [codeMirrorEditor, provider, setMarkdownToPreview, ydoc]);
-
+  }, [codeMirrorEditor, provider, ydoc]);
 
   // initialize markdown and preview
   useEffect(() => {
-    if (ydoc == null) {
+    if (ydoc == null || onOpenEditor == null) {
       return;
     }
 
     const ytext = ydoc.getText('codemirror');
     codeMirrorEditor?.initDoc(ytext.toString());
-    setMarkdownToPreview(ytext.toString());
-    // TODO: Check the reproduction conditions that made this code necessary and confirm reproduction
-    // mutateIsEnabledUnsavedWarning(false);
-  }, [codeMirrorEditor, initialValue, pageId, setMarkdownToPreview, socket, ydoc]);
+    onOpenEditor(ytext.toString());
+  }, [codeMirrorEditor, onOpenEditor, ydoc]);
 
   // setup additional extensions
   useEffect(() => {