Răsfoiți Sursa

Merge pull request #7072 from weseek/support/110608-resolve-conflict-by-modal

support: 110608 resolve conflict by modal
yuken 3 ani în urmă
părinte
comite
19e1176419

+ 10 - 10
packages/app/src/components/Page/DisplaySwitcher.tsx

@@ -13,7 +13,7 @@ import {
 import { useDescendantsPageListModal } from '~/stores/modal';
 import { useCurrentPagePath, useSWRxCurrentPage } from '~/stores/page';
 import {
-  useRemoteRevisionBody, useRemoteRevisionId, useRemoteRevisionLastUpdatedAt, useRemoteRevisionLastUpdatUser,
+  useSetRemoteLatestPageData,
 } from '~/stores/remote-latest-page';
 import { EditorMode, useEditorMode } from '~/stores/ui';
 import { useGlobalSocket } from '~/stores/websocket';
@@ -49,10 +49,7 @@ const PageView = React.memo((): JSX.Element => {
   const { data: isNotFound } = useIsNotFound();
   const { data: currentPage } = useSWRxCurrentPage(shareLinkId ?? undefined);
   const { open: openDescendantPageListModal } = useDescendantsPageListModal();
-  const { mutate: mutateRemoteRevisionId } = useRemoteRevisionId();
-  const { mutate: mutateRemoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdatUser();
-  const { mutate: mutateRemoteRevisionBody } = useRemoteRevisionBody();
-  const { mutate: mutateRemoteRevisionLastUpdatedAt } = useRemoteRevisionLastUpdatedAt();
+  const { setRemoteLatestPageData } = useSetRemoteLatestPageData();
 
   const isTopPagePath = isTopPage(currentPagePath ?? '');
   const isUsersHomePagePath = isUsersHomePage(currentPagePath ?? '');
@@ -62,11 +59,14 @@ const PageView = React.memo((): JSX.Element => {
   const setLatestRemotePageData = useCallback((data) => {
     const { s2cMessagePageUpdated } = data;
 
-    mutateRemoteRevisionId(s2cMessagePageUpdated.revisionId);
-    mutateRemoteRevisionBody(s2cMessagePageUpdated.revisionBody);
-    mutateRemoteRevisionLastUpdateUser(s2cMessagePageUpdated.remoteLastUpdateUser);
-    mutateRemoteRevisionLastUpdatedAt(s2cMessagePageUpdated.revisionUpdateAt);
-  }, [mutateRemoteRevisionBody, mutateRemoteRevisionId, mutateRemoteRevisionLastUpdateUser, mutateRemoteRevisionLastUpdatedAt]);
+    const remoteData = {
+      remoteRevisionId: s2cMessagePageUpdated.revisionId,
+      remoteRevisionBody: s2cMessagePageUpdated.revisionBody,
+      remoteRevisionLastUpdateUser: s2cMessagePageUpdated.remoteLastUpdateUser,
+      remoteRevisionLastUpdatedAt: s2cMessagePageUpdated.revisionUpdateAt,
+    };
+    setRemoteLatestPageData(remoteData);
+  }, [setRemoteLatestPageData]);
 
   // listen socket for someone updating this page
   useEffect(() => {

+ 22 - 3
packages/app/src/components/PageEditor.tsx

@@ -30,7 +30,7 @@ import {
   useEditingMarkdown,
 } from '~/stores/editor';
 import { useConflictDiffModal } from '~/stores/modal';
-import { useCurrentPagePath, useSWRxCurrentPage } from '~/stores/page';
+import { useCurrentPagePath, useSWRxCurrentPage, useSWRxTagsInfo } from '~/stores/page';
 import { usePreviewOptions } from '~/stores/renderer';
 import {
   EditorMode,
@@ -73,8 +73,9 @@ const PageEditor = React.memo((): JSX.Element => {
   const { data: currentPathname } = useCurrentPathname();
   const { data: currentPage, mutate: mutateCurrentPage } = useSWRxCurrentPage();
   const { data: grantData, mutate: mutateGrant } = useSelectedGrant();
-  const { data: pageTags } = usePageTagsForEditors(pageId);
-  const { data: editingMarkdown } = useEditingMarkdown();
+  const { data: pageTags, sync: syncTagsInfoForEditor } = usePageTagsForEditors(pageId);
+  const { mutate: mutateTagsInfo } = useSWRxTagsInfo(pageId);
+  const { data: editingMarkdown, mutate: mutateEditingMarkdown } = useEditingMarkdown();
   const { data: isEnabledAttachTitleHeader } = useIsEnabledAttachTitleHeader();
   const { data: templateBodyData } = useTemplateBodyData();
   const { data: isEditable } = useIsEditable();
@@ -414,6 +415,23 @@ const PageEditor = React.memo((): JSX.Element => {
   }, []);
   const scrollEditorByPreviewScrollWithThrottle = useMemo(() => throttle(20, scrollEditorByPreviewScroll), [scrollEditorByPreviewScroll]);
 
+  const afterResolvedHandler = useCallback(async() => {
+    // get page data from db
+    const pageData = await mutateCurrentPage();
+
+    // update tag
+    await mutateTagsInfo(); // get from DB
+    syncTagsInfoForEditor(); // sync global state for client
+
+    // clear isConflict
+    mutateIsConflict(false);
+
+    // set resolved markdown in editing markdown
+    const markdown = pageData?.revision.body ?? '';
+    mutateEditingMarkdown(markdown);
+
+  }, [mutateCurrentPage, mutateEditingMarkdown, mutateIsConflict, mutateTagsInfo, syncTagsInfoForEditor]);
+
 
   // initialize
   useEffect(() => {
@@ -522,6 +540,7 @@ const PageEditor = React.memo((): JSX.Element => {
         onClose={() => closeConflictDiffModal()}
         markdownOnEdit={markdownToPreview}
         optionsToSave={undefined} // replace undefined
+        afterResolvedHandler={afterResolvedHandler}
       />
     </div>
   );

+ 43 - 17
packages/app/src/components/PageEditor/ConflictDiffModal.tsx

@@ -2,7 +2,6 @@ import React, {
   useState, useEffect, useRef, useMemo, useCallback,
 } from 'react';
 
-import type { IUser } from '@growi/core';
 import { UserPicture } from '@growi/ui';
 import CodeMirror from 'codemirror/lib/codemirror';
 import { format } from 'date-fns';
@@ -11,13 +10,14 @@ import {
   Modal, ModalHeader, ModalBody, ModalFooter,
 } from 'reactstrap';
 
+import { useSaveOrUpdate } from '~/client/services/page-operation';
+import { toastError, toastSuccess } from '~/client/util/toastr';
 import { OptionsToSave } from '~/interfaces/page-operation';
-import { useCurrentUser } from '~/stores/context';
-import { useSWRxCurrentPage } from '~/stores/page';
+import { useCurrentPageId, useCurrentPathname, useCurrentUser } from '~/stores/context';
+import { useCurrentPagePath, useSWRxCurrentPage } from '~/stores/page';
 import {
-  useRemoteRevisionBody, useRemoteRevisionId, useRemoteRevisionLastUpdatedAt, useRemoteRevisionLastUpdatUser,
+  useRemoteRevisionBody, useRemoteRevisionId, useRemoteRevisionLastUpdatedAt, useRemoteRevisionLastUpdateUser, useSetRemoteLatestPageData,
 } from '~/stores/remote-latest-page';
-import { useEditorMode } from '~/stores/ui';
 
 import { IRevisionOnConflict } from '../../interfaces/revision';
 import ExpandOrContractButton from '../ExpandOrContractButton';
@@ -35,6 +35,7 @@ type ConflictDiffModalProps = {
   onClose?: (() => void);
   markdownOnEdit: string;
   optionsToSave: OptionsToSave | undefined;
+  afterResolvedHandler: () => void,
 };
 
 type ConflictDiffModalCoreProps = {
@@ -44,6 +45,7 @@ type ConflictDiffModalCoreProps = {
   request: IRevisionOnConflictWithStringDate,
   origin: IRevisionOnConflictWithStringDate,
   latest: IRevisionOnConflictWithStringDate,
+  afterResolvedHandler: () => void,
 };
 
 type IRevisionOnConflictWithStringDate = Omit<IRevisionOnConflict, 'createdAt'> & {
@@ -52,17 +54,23 @@ type IRevisionOnConflictWithStringDate = Omit<IRevisionOnConflict, 'createdAt'>
 
 const ConflictDiffModalCore = (props: ConflictDiffModalCoreProps): JSX.Element => {
   const {
-    onClose, request, origin, latest,
+    onClose, request, origin, latest, optionsToSave, afterResolvedHandler,
   } = props;
 
-  const { data: editorMode } = useEditorMode();
-
   const { t } = useTranslation('');
   const [resolvedRevision, setResolvedRevision] = useState<string>('');
   const [isRevisionselected, setIsRevisionSelected] = useState<boolean>(false);
   const [isModalExpanded, setIsModalExpanded] = useState<boolean>(false);
   const [codeMirrorRef, setCodeMirrorRef] = useState<HTMLDivElement | null>(null);
 
+  const { data: remoteRevisionId } = useRemoteRevisionId();
+  const { setRemoteLatestPageData } = useSetRemoteLatestPageData();
+  const { data: pageId } = useCurrentPageId();
+  const { data: currentPagePath } = useCurrentPagePath();
+  const { data: currentPathname } = useCurrentPathname();
+
+  const saveOrUpdate = useSaveOrUpdate();
+
   const uncontrolledRef = useRef<CodeMirror>(null);
 
   useEffect(() => {
@@ -89,21 +97,36 @@ const ConflictDiffModalCore = (props: ConflictDiffModalCoreProps): JSX.Element =
   }, [onClose]);
 
   const onResolveConflict = useCallback(async() => {
+    if (currentPathname == null) { return }
     // disable button after clicked
     setIsRevisionSelected(false);
 
     const codeMirrorVal = uncontrolledRef.current?.editor.doc.getValue();
 
     try {
-      // await pageContainer.resolveConflict(codeMirrorVal, editorMode, props.optionsToSave);
-      // close();
-      // pageContainer.showSuccessToastr();
+      const { page } = await saveOrUpdate(
+        codeMirrorVal,
+        { pageId, path: currentPagePath || currentPathname, revisionId: remoteRevisionId },
+        optionsToSave,
+      );
+      const remotePageData = {
+        remoteRevisionId: page.revision._id,
+        remoteRevisionBody: page.revision.body,
+        remoteRevisionLastUpdateUser: page.lastUpdateUser,
+        remoteRevisionLastUpdatedAt: page.updatedAt,
+      };
+      setRemoteLatestPageData(remotePageData);
+      afterResolvedHandler();
+
+      close();
+
+      toastSuccess('Saved successfully');
     }
     catch (error) {
-      // pageContainer.showErrorToastr(error);
+      toastError(`Error occured: ${error.message}`);
     }
 
-  }, []);
+  }, [afterResolvedHandler, close, currentPagePath, currentPathname, optionsToSave, pageId, remoteRevisionId, saveOrUpdate, setRemoteLatestPageData]);
 
   const resizeAndCloseButtons = useMemo(() => (
     <div className="d-flex flex-nowrap">
@@ -258,7 +281,9 @@ const ConflictDiffModalCore = (props: ConflictDiffModalCoreProps): JSX.Element =
 
 
 export const ConflictDiffModal = (props: ConflictDiffModalProps): JSX.Element => {
-  const { isOpen, onClose, optionsToSave } = props;
+  const {
+    isOpen, onClose, optionsToSave, afterResolvedHandler,
+  } = props;
   const { data: currentUser } = useCurrentUser();
 
   // state for current page
@@ -267,12 +292,12 @@ export const ConflictDiffModal = (props: ConflictDiffModalProps): JSX.Element =>
   // state for latest page
   const { data: remoteRevisionId } = useRemoteRevisionId();
   const { data: remoteRevisionBody } = useRemoteRevisionBody();
-  const { data: remoteRevisionLastUpdatUser } = useRemoteRevisionLastUpdatUser();
+  const { data: remoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdateUser();
   const { data: remoteRevisionLastUpdatedAt } = useRemoteRevisionLastUpdatedAt();
 
   const currentTime: Date = new Date();
 
-  const isRemotePageDataInappropriate = remoteRevisionId == null || remoteRevisionBody == null || remoteRevisionLastUpdatUser == null;
+  const isRemotePageDataInappropriate = remoteRevisionId == null || remoteRevisionBody == null || remoteRevisionLastUpdateUser == null;
 
   if (!isOpen || currentUser == null || currentPage == null || isRemotePageDataInappropriate) {
     return <></>;
@@ -294,7 +319,7 @@ export const ConflictDiffModal = (props: ConflictDiffModalProps): JSX.Element =>
     revisionId: remoteRevisionId,
     revisionBody: remoteRevisionBody,
     createdAt: format(new Date(remoteRevisionLastUpdatedAt || currentTime.toString()), 'yyyy/MM/dd HH:mm:ss'),
-    user: remoteRevisionLastUpdatUser,
+    user: remoteRevisionLastUpdateUser,
   };
 
   const propsForCore = {
@@ -304,6 +329,7 @@ export const ConflictDiffModal = (props: ConflictDiffModalProps): JSX.Element =>
     request,
     origin,
     latest,
+    afterResolvedHandler,
   };
 
   return <ConflictDiffModalCore {...propsForCore}/>;

+ 2 - 2
packages/app/src/components/PageStatusAlert.tsx

@@ -9,7 +9,7 @@ import {
 } from '~/stores/hackmd';
 import { useConflictDiffModal } from '~/stores/modal';
 import { useSWRxCurrentPage } from '~/stores/page';
-import { useRemoteRevisionId, useRemoteRevisionLastUpdatUser } from '~/stores/remote-latest-page';
+import { useRemoteRevisionId, useRemoteRevisionLastUpdateUser } from '~/stores/remote-latest-page';
 
 import { Username } from './User/Username';
 
@@ -33,7 +33,7 @@ export const PageStatusAlert = (): JSX.Element => {
   // store remote latest page data
   const { data: revisionIdHackmdSynced } = useRevisionIdHackmdSynced();
   const { data: remoteRevisionId } = useRemoteRevisionId();
-  const { data: remoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdatUser();
+  const { data: remoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdateUser();
 
   const { data: pageData, mutate: mutatePageData } = useSWRxCurrentPage();
   const revision = pageData?.revision;

+ 34 - 3
packages/app/src/stores/remote-latest-page.ts

@@ -10,13 +10,44 @@ export const useRemoteRevisionId = (initialData?: string): SWRResponse<string, E
 };
 
 export const useRemoteRevisionBody = (initialData?: string): SWRResponse<string, Error> => {
-  return useStaticSWR<string, Error>('remoteRevisionId', initialData);
+  return useStaticSWR<string, Error>('remoteRevisionBody', initialData);
 };
 
-export const useRemoteRevisionLastUpdatUser = (initialData?: IUser): SWRResponse<IUser, Error> => {
-  return useStaticSWR<IUser, Error>('remoteRevisionLastUpdatUser', initialData);
+export const useRemoteRevisionLastUpdateUser = (initialData?: IUser): SWRResponse<IUser, Error> => {
+  return useStaticSWR<IUser, Error>('remoteRevisionLastUpdateUser', initialData);
 };
 
 export const useRemoteRevisionLastUpdatedAt = (initialData?: Date): SWRResponse<Date, Error> => {
   return useStaticSWR<Date, Error>('remoteRevisionLastUpdatedAt', initialData);
 };
+
+type RemoteRevisionData = {
+  remoteRevisionId: string,
+  remoteRevisionBody: string,
+  remoteRevisionLastUpdateUser: IUser,
+  remoteRevisionLastUpdatedAt: Date
+}
+
+
+// set remote data all at once
+export const useSetRemoteLatestPageData = (): { setRemoteLatestPageData: (pageData: RemoteRevisionData) => void } => {
+  const { mutate: mutateRemoteRevisionId } = useRemoteRevisionId();
+  const { mutate: mutateRemoteRevisionBody } = useRemoteRevisionBody();
+  const { mutate: mutateRemoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdateUser();
+  const { mutate: mutateRemoteRevisionLastUpdatedAt } = useRemoteRevisionLastUpdatedAt();
+
+  const setRemoteLatestPageData = (remoteRevisionData: RemoteRevisionData) => {
+    const {
+      remoteRevisionId, remoteRevisionBody, remoteRevisionLastUpdateUser, remoteRevisionLastUpdatedAt,
+    } = remoteRevisionData;
+    mutateRemoteRevisionId(remoteRevisionId);
+    mutateRemoteRevisionBody(remoteRevisionBody);
+    mutateRemoteRevisionLastUpdateUser(remoteRevisionLastUpdateUser);
+    mutateRemoteRevisionLastUpdatedAt(remoteRevisionLastUpdatedAt);
+  };
+
+  return {
+    setRemoteLatestPageData,
+  };
+
+};