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

Fix links on compare difference

https://youtrack.weseek.co.jp/issue/GW-7911
- Implement ShowPageAccessoriesModal to page.tsx
- Get sourceRevisionId & targetRevisionId from query string in PageAccessoriesModal
- Add  sourceRevisionId & targetRevisionId as props to PageHistory
- Add condition for data fetching with swr in PageRevisiontable
- Add condition to set source and revision value
- Modify conditional query options in revisions route
Mudana-Grune 3 лет назад
Родитель
Сommit
f15ecda47f

+ 28 - 2
packages/app/src/components/PageAccessoriesModal.tsx

@@ -27,6 +27,9 @@ const PageAccessoriesModal = (): JSX.Element => {
   const { t } = useTranslation();
 
   const [activeTab, setActiveTab] = useState<PageAccessoriesModalContents>(PageAccessoriesModalContents.PageHistory);
+  const [sourceRevisionId, setSourceRevisionId] = useState<string>();
+  const [targetRevisionId, setTargetRevisionId] = useState<string>();
+
   const [isWindowExpanded, setIsWindowExpanded] = useState(false);
 
   const { data: isSharedUser } = useIsSharedUser();
@@ -35,6 +38,19 @@ const PageAccessoriesModal = (): JSX.Element => {
 
   const { data: status, mutate, close } = usePageAccessoriesModal();
 
+  // Get string from 'compare' query params
+  const getQueryParam = () => {
+    const query: URLSearchParams = new URL(window.location.href).searchParams;
+    return query.get('compare');
+  };
+
+  // check if query string contains 2 strings like objectId separated by '...'
+  const isValidObjectIds = (queryParams) => {
+    // https://regex101.com/r/t3l36H/1
+    const regex = /^[0-9a-fA-F]{24}...[0-9a-fA-F]{24}?$/;
+    return regex.test(queryParams);
+  };
+
   // add event handler when opened
   useEffect(() => {
     if (status == null || status.onOpened != null) {
@@ -48,6 +64,16 @@ const PageAccessoriesModal = (): JSX.Element => {
     }, false);
   }, [mutate, status]);
 
+  // Set sourceRevisionId and targetRevisionId as state with valid object id string
+  useEffect(() => {
+    const queryParams = getQueryParam();
+    if (queryParams != null && isValidObjectIds(queryParams)) {
+      const [sourceRevisionId, targetRevisionId] = queryParams.split('...');
+      setSourceRevisionId(sourceRevisionId);
+      setTargetRevisionId(targetRevisionId);
+    }
+  }, []);
+
   const navTabMapping = useMemo(() => {
     const isOpened = status == null ? false : status.isOpened;
     return {
@@ -57,7 +83,7 @@ const PageAccessoriesModal = (): JSX.Element => {
           if (!isOpened) {
             return <></>;
           }
-          return <PageHistory onClose={close}/>;
+          return <PageHistory onClose={close} sourceRevisionId={sourceRevisionId} targetRevisionId={targetRevisionId}/>;
         },
         i18n: t('History'),
         index: 0,
@@ -87,7 +113,7 @@ const PageAccessoriesModal = (): JSX.Element => {
         isLinkEnabled: () => !isGuestUser && !isSharedUser && !isLinkSharingDisabled,
       },
     };
-  }, [status, t, close, isGuestUser, isSharedUser, isLinkSharingDisabled]);
+  }, [status, t, close, sourceRevisionId, targetRevisionId, isGuestUser, isSharedUser, isLinkSharingDisabled]);
 
   const buttons = useMemo(() => (
     <div className="d-flex flex-nowrap">

+ 9 - 1
packages/app/src/components/PageHistory.tsx

@@ -6,10 +6,18 @@ import { PageRevisionTable } from './PageHistory/PageRevisionTable';
 
 const logger = loggerFactory('growi:PageHistory');
 
-export const PageHistory: React.FC<{ onClose: () => void }> = ({ onClose }) => {
+type PageHistoryProps = {
+  sourceRevisionId?: string,
+  targetRevisionId?: string
+  onClose: () => void
+}
+export const PageHistory: React.FC<PageHistoryProps> = (props: PageHistoryProps) => {
+  const { sourceRevisionId, targetRevisionId, onClose } = props;
   return (
     <div className="revision-history" data-testid="page-history">
       <PageRevisionTable
+        sourceRevisionId={sourceRevisionId}
+        targetRevisionId={targetRevisionId}
         onClose={onClose}
       />
     </div>

+ 24 - 8
packages/app/src/components/PageHistory/PageRevisionTable.tsx

@@ -15,6 +15,8 @@ import { Revision } from './Revision';
 import styles from './PageRevisionTable.module.scss';
 
 type PageRevisionTableProps = {
+  sourceRevisionId?: string
+  targetRevisionId?: string
   onClose: () => void,
 }
 
@@ -24,12 +26,15 @@ export const PageRevisionTable = (props: PageRevisionTableProps): JSX.Element =>
   const REVISIONS_PER_PAGE = 10;
 
   const {
-    onClose,
+    sourceRevisionId, targetRevisionId, onClose,
   } = props;
 
   const { data: currentPageId } = useCurrentPageId();
   const { data: currentPagePath } = useCurrentPagePath();
-  const swrInifiniteResponse = useSWRxInfinitePageRevisions(currentPageId, REVISIONS_PER_PAGE);
+
+  // Load all data if source revision id and target revision id not null
+  const revisionPerPage = (sourceRevisionId != null && targetRevisionId != null) ? 0 : REVISIONS_PER_PAGE;
+  const swrInifiniteResponse = useSWRxInfinitePageRevisions(currentPageId, revisionPerPage);
 
   const {
     data, size, error, setSize, isValidating,
@@ -42,20 +47,31 @@ export const PageRevisionTable = (props: PageRevisionTableProps): JSX.Element =>
   const isLoadingInitialData = !data && !error;
   const isLoadingMore = isLoadingInitialData
     || (isValidating && data && typeof data[size - 1] === 'undefined');
-  const isReachingEnd = !!(data && data[data.length - 1]?.revisions.length < REVISIONS_PER_PAGE);
+  const isReachingEnd = (revisionPerPage === 0) || !!(data && data[data.length - 1]?.revisions.length < REVISIONS_PER_PAGE);
 
   const [sourceRevision, setSourceRevision] = useState<IRevisionHasPageId>();
   const [targetRevision, setTargetRevision] = useState<IRevisionHasPageId>();
-  const latestRevision = data != null ? data[0].revisions[0] : null;
+
   const tbodyRef = useRef<HTMLTableSectionElement>(null);
 
 
   useEffect(() => {
-    if (latestRevision != null) {
-      setSourceRevision(latestRevision);
-      setTargetRevision(latestRevision);
+    if (revisions != null) {
+      if (sourceRevisionId != null && targetRevisionId != null) {
+        const sourceRevision = revisions.filter(revision => revision._id === sourceRevisionId)[0];
+        const targetRevision = revisions.filter(revision => revision._id === targetRevisionId)[0];
+        setSourceRevision(sourceRevision);
+        setTargetRevision(targetRevision);
+      }
+      else {
+        const latestRevision = revisions != null ? revisions[0] : null;
+        if (latestRevision != null) {
+          setSourceRevision(latestRevision);
+          setTargetRevision(latestRevision);
+        }
+      }
     }
-  }, [latestRevision]);
+  }, [revisions, sourceRevisionId, targetRevisionId]);
 
   useEffect(() => {
     // Apply ref to tbody

+ 2 - 0
packages/app/src/pages/[[...path]].page.tsx

@@ -19,6 +19,7 @@ import Head from 'next/head';
 import { useRouter } from 'next/router';
 import superjson from 'superjson';
 
+import ShowPageAccessoriesModal from '~/client/services/ShowPageAccessoriesModal';
 import { useCurrentGrowiLayoutFluidClassName, useEditorModeClassName } from '~/client/services/layout';
 import { PageView } from '~/components/Page/PageView';
 import { DrawioViewerScript } from '~/components/Script/DrawioViewerScript';
@@ -324,6 +325,7 @@ const Page: NextPageWithLayout<Props> = (props: Props) => {
         <PageStatusAlert />
 
         {shouldRenderPutbackPageModal && <PutbackPageModal />}
+        <ShowPageAccessoriesModal />
       </div>
     </>
   );

+ 12 - 6
packages/app/src/server/routes/apiv3/revisions.js

@@ -123,15 +123,21 @@ module.exports = (crowi) => {
 
     try {
       const page = await Page.findOne({ _id: pageId });
+      const queryOpts = {
+        offset,
+        sort: { createdAt: -1 },
+        populate: 'author',
+        pagination: false,
+      };
+
+      if (limit > 0) {
+        queryOpts.limit = limit;
+        queryOpts.pagination = true;
+      }
 
       const paginateResult = await Revision.paginate(
         { pageId: page._id },
-        {
-          offset,
-          limit,
-          sort: { createdAt: -1 },
-          populate: 'author',
-        },
+        queryOpts,
       );
 
       paginateResult.docs.forEach((doc) => {