Explorar el Código

Merge pull request #7403 from weseek/feat/gw-7911-fix-links-on-compare-difference

feat: gw 7911 fix links on compare difference
Ryoji Shimizu hace 3 años
padre
commit
760b4bfc6f

+ 29 - 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,17 @@ 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);
+      mutate({ isOpened: true });
+    }
+  }, [mutate]);
+
   const navTabMapping = useMemo(() => {
     const isOpened = status == null ? false : status.isOpened;
     return {
@@ -57,7 +84,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 +114,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">

+ 14 - 3
packages/app/src/components/PageHistory.tsx

@@ -8,15 +8,26 @@ 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;
+
   const { data: currentPageId } = useCurrentPageId();
   const { data: currentPagePath } = useCurrentPagePath();
+
   return (
     <div className="revision-history" data-testid="page-history">
-      { currentPageId && currentPagePath && (
+      {currentPageId && currentPagePath && (
         <PageRevisionTable
+          sourceRevisionId={sourceRevisionId}
+          targetRevisionId={targetRevisionId}
           currentPageId={currentPageId}
-          currentPagePath = {currentPagePath}
+          currentPagePath={currentPagePath}
           onClose={onClose}
         />
       )}

+ 27 - 11
packages/app/src/components/PageHistory/PageRevisionTable.tsx

@@ -14,9 +14,11 @@ import { Revision } from './Revision';
 import styles from './PageRevisionTable.module.scss';
 
 type PageRevisionTableProps = {
+  sourceRevisionId?: string
+  targetRevisionId?: string
+  onClose: () => void,
   currentPageId: string
   currentPagePath: string
-  onClose: () => void
 }
 
 export const PageRevisionTable = (props: PageRevisionTableProps): JSX.Element => {
@@ -25,10 +27,13 @@ export const PageRevisionTable = (props: PageRevisionTableProps): JSX.Element =>
   const REVISIONS_PER_PAGE = 10;
 
   const {
-    onClose, currentPageId, currentPagePath,
+    sourceRevisionId, targetRevisionId, onClose, currentPageId, currentPagePath,
   } = props;
 
-  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,
@@ -41,20 +46,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
@@ -186,7 +202,7 @@ export const PageRevisionTable = (props: PageRevisionTableProps): JSX.Element =>
           </tr>
         </thead>
         <tbody className="overflow-auto d-block" ref={tbodyRef}>
-          { revisions && data != null && data.map(apiResult => apiResult.revisions).flat()
+          {revisions && data != null && data.map(apiResult => apiResult.revisions).flat()
             .map((revision, idx) => {
               const previousRevision = (idx + 1 < revisions?.length) ? revisions[idx + 1] : revision;
 
@@ -201,7 +217,7 @@ export const PageRevisionTable = (props: PageRevisionTableProps): JSX.Element =>
         </tbody>
       </table>
 
-      { sourceRevision && targetRevision && (
+      {sourceRevision && targetRevision && (
         <RevisionComparer
           sourceRevision={sourceRevision}
           targetRevision={targetRevision}

+ 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) => {

+ 1 - 6
packages/app/src/stores/page.tsx

@@ -1,7 +1,7 @@
 import { useEffect, useMemo } from 'react';
 
 import type {
-  IPageInfoForEntity, IPagePopulatedToShowRevision, IRevisionHasPageId, Nullable,
+  IPageInfoForEntity, IPagePopulatedToShowRevision, Nullable, SWRInfinitePageRevisionsResponse,
 } from '@growi/core';
 import { Ref, isClient, pagePathUtils } from '@growi/core';
 import useSWR, { mutate, SWRResponse } from 'swr';
@@ -147,11 +147,6 @@ export const useSWRxPageRevision = (pageId: string, revisionId: Ref<IRevision>):
 /*
  * SWR Infinite for page revision list
  */
-type SWRInfinitePageRevisionsResponse = {
-  revisions: IRevisionHasPageId[],
-  totalCount: number,
-  offset: number,
-}
 
 export const useSWRxInfinitePageRevisions = (
     pageId: string,

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

@@ -32,3 +32,9 @@ export type IRevisionOnConflict = {
 export type HasRevisionShortbody = {
   revisionShortBody?: string,
 }
+
+export type SWRInfinitePageRevisionsResponse = {
+  revisions: IRevisionHasPageId[],
+  totalCount: number,
+  offset: number,
+}