فهرست منبع

Relocate conflitc.tsx under components/PageEditor

Shun Miyazawa 2 سال پیش
والد
کامیت
4c2c3ac878

+ 1 - 134
apps/app/src/client/services/update-page/conflict.tsx

@@ -1,29 +1,7 @@
-import { useCallback, useEffect } from 'react';
-
-import { Origin } from '@growi/core';
 import type { ErrorV3 } from '@growi/core/dist/models';
-import { useGlobalSocket } from '@growi/core/dist/swr';
-import { GlobalCodeMirrorEditorKey, useCodeMirrorEditorIsolated } from '@growi/editor';
-import { useTranslation } from 'react-i18next';
 
-import { toastSuccess } from '~/client/util/toastr';
-import type { Save, SaveOptions } from '~/components/PageEditor/PageEditor';
 import { PageUpdateErrorCode } from '~/interfaces/apiv3';
-import { SocketEventName } from '~/interfaces/websocket';
-import { usePageStatusAlert } from '~/stores/alert';
-import { useConflictDiffModal } from '~/stores/modal';
-import { useCurrentPageId, useSWRxCurrentPage } from '~/stores/page';
-import { type RemoteRevisionData, useSetRemoteLatestPageData } from '~/stores/remote-latest-page';
-import { EditorMode, useEditorMode } from '~/stores/ui';
-
-import { useUpdateStateAfterSave } from '../page-operation';
-
-export type ConflictHandler = (
-  remoteRevisionData: RemoteRevisionData,
-  requestMarkdown: string,
-  save: Save,
-  saveOptions?: SaveOptions,
-) => void;
+import { type RemoteRevisionData } from '~/stores/remote-latest-page';
 
 export const extractRemoteRevisionDataFromErrorObj = (errors: Array<ErrorV3>): RemoteRevisionData | undefined => {
   for (const error of errors) {
@@ -42,114 +20,3 @@ export const extractRemoteRevisionDataFromErrorObj = (errors: Array<ErrorV3>): R
     }
   }
 };
-
-type GenerateResolveConflicthandler = () => (
-  revisionId: string,
-  save: Save,
-  saveOptions?: SaveOptions,
-  onConflict?: () => void
-) => (newMarkdown: string) => Promise<void>
-
-export const useGenerateResolveConflictHandler: GenerateResolveConflicthandler = () => {
-  const { t } = useTranslation();
-
-  const { data: pageId } = useCurrentPageId();
-  const { close: closePageStatusAlert } = usePageStatusAlert();
-  const { close: closeConflictDiffModal } = useConflictDiffModal();
-  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
-  const updateStateAfterSave = useUpdateStateAfterSave(pageId, { supressEditingMarkdownMutation: true });
-
-  return useCallback((revisionId, save, saveOptions, onConflict) => {
-    return async(newMarkdown) => {
-      const page = await save(revisionId, newMarkdown, saveOptions, onConflict);
-      if (page == null) {
-        return;
-      }
-
-      // Reflect conflict resolution results in CodeMirrorEditor
-      codeMirrorEditor?.initDoc(newMarkdown);
-
-      closePageStatusAlert();
-      closeConflictDiffModal();
-
-      toastSuccess(t('toaster.save_succeeded'));
-      updateStateAfterSave?.();
-    };
-  }, [closeConflictDiffModal, closePageStatusAlert, codeMirrorEditor, t, updateStateAfterSave]);
-};
-
-
-type ConflictResolver = () => ConflictHandler;
-
-export const useConflictResolver: ConflictResolver = () => {
-  const { open: openPageStatusAlert } = usePageStatusAlert();
-  const { open: openConflictDiffModal } = useConflictDiffModal();
-  const { setRemoteLatestPageData } = useSetRemoteLatestPageData();
-  const generateResolveConflictHandler = useGenerateResolveConflictHandler();
-
-  return useCallback((remoteRevidsionData, requestMarkdown, save, saveOptions) => {
-    const conflictHandler = () => {
-      const resolveConflictHandler = generateResolveConflictHandler(remoteRevidsionData.remoteRevisionId, save, saveOptions, conflictHandler);
-      openPageStatusAlert({ onResolveConflict: () => openConflictDiffModal(requestMarkdown, resolveConflictHandler) });
-      setRemoteLatestPageData(remoteRevidsionData);
-    };
-
-    conflictHandler();
-  }, [generateResolveConflictHandler, openConflictDiffModal, openPageStatusAlert, setRemoteLatestPageData]);
-};
-
-export const useConflictEffect = (): void => {
-  const { data: currentPage } = useSWRxCurrentPage();
-  const { close: closePageStatusAlert } = usePageStatusAlert();
-  const { close: closeConflictDiffModal } = useConflictDiffModal();
-  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
-  const { open: openPageStatusAlert } = usePageStatusAlert();
-  const { open: openConflictDiffModal } = useConflictDiffModal();
-  const { data: socket } = useGlobalSocket();
-  const { data: editorMode } = useEditorMode();
-
-  const conflictHandler = useCallback(() => {
-    const onResolveConflict = () => {
-      const resolveConflictHandler = (newMarkdown: string) => {
-        codeMirrorEditor?.initDoc(newMarkdown);
-        closeConflictDiffModal();
-        closePageStatusAlert();
-      };
-
-      const markdown = codeMirrorEditor?.getDoc();
-      openConflictDiffModal(markdown ?? '', resolveConflictHandler);
-    };
-
-    openPageStatusAlert({ onResolveConflict });
-  }, [closeConflictDiffModal, closePageStatusAlert, codeMirrorEditor, openConflictDiffModal, openPageStatusAlert]);
-
-  const updateRemotePageDataHandler = useCallback((data) => {
-    const { s2cMessagePageUpdated } = data;
-
-    const remoteRevisionId = s2cMessagePageUpdated.revisionId;
-    const remoteRevisionOrigin = s2cMessagePageUpdated.revisionOrigin;
-    const currentRevisionId = currentPage?.revision?._id;
-    const isRevisionOutdated = (currentRevisionId != null || remoteRevisionId != null) && currentRevisionId !== remoteRevisionId;
-
-    // !!CAUTION!! Timing of calling openPageStatusAlert may clash with client/services/side-effects/page-updated.ts
-    if (isRevisionOutdated && editorMode === EditorMode.Editor && (remoteRevisionOrigin === Origin.View || remoteRevisionOrigin === undefined)) {
-      conflictHandler();
-    }
-
-    // Clear cache
-    if (!isRevisionOutdated) {
-      closePageStatusAlert();
-    }
-  }, [closePageStatusAlert, currentPage?.revision?._id, editorMode, conflictHandler]);
-
-  useEffect(() => {
-    if (socket == null) { return }
-
-    socket.on(SocketEventName.PageUpdated, updateRemotePageDataHandler);
-
-    return () => {
-      socket.off(SocketEventName.PageUpdated, updateRemotePageDataHandler);
-    };
-
-  }, [socket, updateRemotePageDataHandler]);
-};

+ 2 - 7
apps/app/src/components/PageEditor/PageEditor.tsx

@@ -20,13 +20,7 @@ import { throttle, debounce } from 'throttle-debounce';
 
 import { useShouldExpandContent } from '~/client/services/layout';
 import { useUpdateStateAfterSave } from '~/client/services/page-operation';
-import {
-  updatePage,
-  extractRemoteRevisionDataFromErrorObj,
-  useConflictResolver,
-  useConflictEffect,
-  type ConflictHandler,
-} from '~/client/services/update-page';
+import { updatePage, extractRemoteRevisionDataFromErrorObj } from '~/client/services/update-page';
 import { apiv3Get, apiv3PostForm } from '~/client/util/apiv3-client';
 import { toastError, toastSuccess, toastWarning } from '~/client/util/toastr';
 import {
@@ -58,6 +52,7 @@ import { EditorNavbar } from './EditorNavbar';
 import EditorNavbarBottom from './EditorNavbarBottom';
 import Preview from './Preview';
 import { scrollEditor, scrollPreview } from './ScrollSyncHelper';
+import { useConflictResolver, useConflictEffect, type ConflictHandler } from './conflict';
 
 import '@growi/editor/dist/style.css';
 

+ 135 - 0
apps/app/src/components/PageEditor/conflict.tsx

@@ -0,0 +1,135 @@
+import { useCallback, useEffect } from 'react';
+
+import { Origin } from '@growi/core';
+import { useGlobalSocket } from '@growi/core/dist/swr';
+import { GlobalCodeMirrorEditorKey, useCodeMirrorEditorIsolated } from '@growi/editor';
+import { useTranslation } from 'react-i18next';
+
+import { useUpdateStateAfterSave } from '~/client/services/page-operation';
+import { toastSuccess } from '~/client/util/toastr';
+import type { Save, SaveOptions } from '~/components/PageEditor/PageEditor';
+import { SocketEventName } from '~/interfaces/websocket';
+import { usePageStatusAlert } from '~/stores/alert';
+import { useConflictDiffModal } from '~/stores/modal';
+import { useCurrentPageId, useSWRxCurrentPage } from '~/stores/page';
+import { type RemoteRevisionData, useSetRemoteLatestPageData } from '~/stores/remote-latest-page';
+import { EditorMode, useEditorMode } from '~/stores/ui';
+
+
+export type ConflictHandler = (
+  remoteRevisionData: RemoteRevisionData,
+  requestMarkdown: string,
+  save: Save,
+  saveOptions?: SaveOptions,
+) => void;
+
+type GenerateResolveConflicthandler = () => (
+  revisionId: string,
+  save: Save,
+  saveOptions?: SaveOptions,
+  onConflict?: () => void
+) => (newMarkdown: string) => Promise<void>
+
+const useGenerateResolveConflictHandler: GenerateResolveConflicthandler = () => {
+  const { t } = useTranslation();
+
+  const { data: pageId } = useCurrentPageId();
+  const { close: closePageStatusAlert } = usePageStatusAlert();
+  const { close: closeConflictDiffModal } = useConflictDiffModal();
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
+  const updateStateAfterSave = useUpdateStateAfterSave(pageId, { supressEditingMarkdownMutation: true });
+
+  return useCallback((revisionId, save, saveOptions, onConflict) => {
+    return async(newMarkdown) => {
+      const page = await save(revisionId, newMarkdown, saveOptions, onConflict);
+      if (page == null) {
+        return;
+      }
+
+      // Reflect conflict resolution results in CodeMirrorEditor
+      codeMirrorEditor?.initDoc(newMarkdown);
+
+      closePageStatusAlert();
+      closeConflictDiffModal();
+
+      toastSuccess(t('toaster.save_succeeded'));
+      updateStateAfterSave?.();
+    };
+  }, [closeConflictDiffModal, closePageStatusAlert, codeMirrorEditor, t, updateStateAfterSave]);
+};
+
+
+type ConflictResolver = () => ConflictHandler;
+
+export const useConflictResolver: ConflictResolver = () => {
+  const { open: openPageStatusAlert } = usePageStatusAlert();
+  const { open: openConflictDiffModal } = useConflictDiffModal();
+  const { setRemoteLatestPageData } = useSetRemoteLatestPageData();
+  const generateResolveConflictHandler = useGenerateResolveConflictHandler();
+
+  return useCallback((remoteRevidsionData, requestMarkdown, save, saveOptions) => {
+    const conflictHandler = () => {
+      const resolveConflictHandler = generateResolveConflictHandler(remoteRevidsionData.remoteRevisionId, save, saveOptions, conflictHandler);
+      openPageStatusAlert({ onResolveConflict: () => openConflictDiffModal(requestMarkdown, resolveConflictHandler) });
+      setRemoteLatestPageData(remoteRevidsionData);
+    };
+
+    conflictHandler();
+  }, [generateResolveConflictHandler, openConflictDiffModal, openPageStatusAlert, setRemoteLatestPageData]);
+};
+
+export const useConflictEffect = (): void => {
+  const { data: currentPage } = useSWRxCurrentPage();
+  const { close: closePageStatusAlert } = usePageStatusAlert();
+  const { close: closeConflictDiffModal } = useConflictDiffModal();
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
+  const { open: openPageStatusAlert } = usePageStatusAlert();
+  const { open: openConflictDiffModal } = useConflictDiffModal();
+  const { data: socket } = useGlobalSocket();
+  const { data: editorMode } = useEditorMode();
+
+  const conflictHandler = useCallback(() => {
+    const onResolveConflict = () => {
+      const resolveConflictHandler = (newMarkdown: string) => {
+        codeMirrorEditor?.initDoc(newMarkdown);
+        closeConflictDiffModal();
+        closePageStatusAlert();
+      };
+
+      const markdown = codeMirrorEditor?.getDoc();
+      openConflictDiffModal(markdown ?? '', resolveConflictHandler);
+    };
+
+    openPageStatusAlert({ onResolveConflict });
+  }, [closeConflictDiffModal, closePageStatusAlert, codeMirrorEditor, openConflictDiffModal, openPageStatusAlert]);
+
+  const updateRemotePageDataHandler = useCallback((data) => {
+    const { s2cMessagePageUpdated } = data;
+
+    const remoteRevisionId = s2cMessagePageUpdated.revisionId;
+    const remoteRevisionOrigin = s2cMessagePageUpdated.revisionOrigin;
+    const currentRevisionId = currentPage?.revision?._id;
+    const isRevisionOutdated = (currentRevisionId != null || remoteRevisionId != null) && currentRevisionId !== remoteRevisionId;
+
+    // !!CAUTION!! Timing of calling openPageStatusAlert may clash with client/services/side-effects/page-updated.ts
+    if (isRevisionOutdated && editorMode === EditorMode.Editor && (remoteRevisionOrigin === Origin.View || remoteRevisionOrigin === undefined)) {
+      conflictHandler();
+    }
+
+    // Clear cache
+    if (!isRevisionOutdated) {
+      closePageStatusAlert();
+    }
+  }, [closePageStatusAlert, currentPage?.revision?._id, editorMode, conflictHandler]);
+
+  useEffect(() => {
+    if (socket == null) { return }
+
+    socket.on(SocketEventName.PageUpdated, updateRemotePageDataHandler);
+
+    return () => {
+      socket.off(SocketEventName.PageUpdated, updateRemotePageDataHandler);
+    };
+
+  }, [socket, updateRemotePageDataHandler]);
+};