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

Modify and implement InfiniteScroll component

https://youtrack.weseek.co.jp/issue/GW-7908
- Move InfiniteScroll component
- Add props isLoadingIndicatorShown and adjust loading indicator
- Move implementation of RevisionComparer to PageRevisionTable
- Adjust PageRevisionTable props
- Modify onChangeSource and  onChangeTarget method
- Adjust props of Revision and REvisionComparer component
- Update dateTime Props type of UserDate
Mudana-Grune 3 лет назад
Родитель
Сommit
f289926d61

+ 13 - 8
packages/app/src/components/Sidebar/InfiniteScroll.tsx → packages/app/src/components/InfiniteScroll.tsx

@@ -1,6 +1,7 @@
 import React, {
   Ref, useEffect, useState,
 } from 'react';
+
 import type { SWRInfiniteResponse } from 'swr/infinite';
 
 type Props<T> = {
@@ -8,8 +9,9 @@ type Props<T> = {
   children: React.ReactChild | ((item: T) => React.ReactNode),
   loadingIndicator?: React.ReactNode
   endingIndicator?: React.ReactNode
-  isReachingEnd?: boolean,
+  isReachingEnd?: boolean
   offset?: number
+  isLoadingIndicatorShown?: boolean
 }
 
 const useIntersection = <E extends HTMLElement>(): [boolean, Ref<E>] => {
@@ -46,6 +48,7 @@ const InfiniteScroll = <E, >(props: Props<E>): React.ReactElement<Props<E>> => {
     endingIndicator,
     isReachingEnd,
     offset = 0,
+    isLoadingIndicatorShown = true,
   } = props;
 
   const [intersecting, ref] = useIntersection<HTMLDivElement>();
@@ -59,13 +62,15 @@ const InfiniteScroll = <E, >(props: Props<E>): React.ReactElement<Props<E>> => {
   return (
     <>
       {typeof children === 'function' ? data?.map(item => children(item)) : children}
-      <div style={{ position: 'relative' }}>
-        <div ref={ref} style={{ position: 'absolute', top: offset }}></div>
-        {isReachingEnd
-          ? endingIndicator
-          : loadingIndicator || <LoadingIndicator />
-        }
-      </div>
+      {isLoadingIndicatorShown && (
+        <div style={{ position: 'relative' }}>
+          <div ref={ref} style={{ position: 'absolute', top: offset }}></div>
+          {isReachingEnd
+            ? endingIndicator
+            : loadingIndicator || <LoadingIndicator />
+          }
+        </div>
+      )}
     </>
   );
 };

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

@@ -7,7 +7,6 @@ import { useCurrentPagePath, useSWRxInfinitePageRevisions } from '~/stores/page'
 import loggerFactory from '~/utils/logger';
 
 import { PageRevisionTable } from './PageHistory/PageRevisionTable';
-import { RevisionComparer } from './RevisionComparer/RevisionComparer';
 
 const logger = loggerFactory('growi:PageHistory');
 
@@ -48,19 +47,6 @@ export const PageHistory: React.FC<{ onClose: () => void }> = ({ onClose }) => {
   return (
     <div className="revision-history" data-testid="page-history">
       <PageRevisionTable
-        sourceRevision={sourceRevision}
-        targetRevision={targetRevision}
-        currentPageId={currentPageId}
-        currentPagePath={currentPagePath}
-        onChangeSourceInvoked={setSourceRevision}
-        onChangeTargetInvoked={setTargetRevision}
-        onClose={onClose}
-      />
-      <RevisionComparer
-        sourceRevision={sourceRevision}
-        targetRevision={targetRevision}
-        currentPageId={currentPageId}
-        currentPagePath={currentPagePath}
         onClose={onClose}
       />
     </div>

+ 72 - 44
packages/app/src/components/PageHistory/PageRevisionTable.tsx

@@ -1,23 +1,21 @@
-import React from 'react';
+import React, {
+  useEffect, useState,
+} from 'react';
 
-import { IRevisionHasId } from '@growi/core';
+import { IRevisionHasId, IRevisionHasPageId } from '@growi/core';
 import { useTranslation } from 'next-i18next';
 
+import { useCurrentPageId } from '~/stores/context';
 import { useSWRxInfinitePageRevisions } from '~/stores/page';
 
-import InfiniteScroll from '../Sidebar/InfiniteScroll';
+import InfiniteScroll from '../InfiniteScroll';
+import { RevisionComparer } from '../RevisionComparer/RevisionComparer';
 
 import { Revision } from './Revision';
 
 import styles from './PageRevisionTable.module.scss';
 
 type PageRevisionTAble = {
-  sourceRevision: IRevisionHasId,
-  targetRevision: IRevisionHasId,
-  currentPageId: string,
-  currentPagePath: string,
-  onChangeSourceInvoked: React.Dispatch<React.SetStateAction<IRevisionHasId | undefined>>,
-  onChangeTargetInvoked: React.Dispatch<React.SetStateAction<IRevisionHasId | undefined>>,
   onClose: () => void,
 }
 
@@ -27,10 +25,11 @@ export const PageRevisionTable = (props: PageRevisionTAble): JSX.Element => {
   const REVISIONS_PER_PAGE = 10;
 
   const {
-    sourceRevision, targetRevision, currentPageId, currentPagePath,
-    onChangeSourceInvoked, onChangeTargetInvoked, onClose,
+    onClose,
   } = props;
 
+
+  const { data: currentPageId } = useCurrentPageId();
   const swrInifiniteResponse = useSWRxInfinitePageRevisions(currentPageId);
 
   const { data: revisionsData } = swrInifiniteResponse;
@@ -42,7 +41,28 @@ export const PageRevisionTable = (props: PageRevisionTAble): JSX.Element => {
   const isReachingEnd = isEmpty
    || (revisionsData && revisionsData[revisionsData.length - 1]?.length < REVISIONS_PER_PAGE);
 
-  const renderRow = (revision: IRevisionHasId, previousRevision: IRevisionHasId, latestRevision: IRevisionHasId,
+
+  const [sourceRevision, setSourceRevision] = useState<IRevisionHasPageId>();
+  const [targetRevision, setTargetRevision] = useState<IRevisionHasPageId>();
+  const latestRevision = revisionsData != null ? revisionsData[0][0] : null;
+
+
+  useEffect(() => {
+    if (latestRevision != null) {
+      setSourceRevision(latestRevision);
+      setTargetRevision(latestRevision);
+    }
+  }, [latestRevision]);
+
+  const onChangeSourceInvoked: React.Dispatch<React.SetStateAction<IRevisionHasId | undefined>> = (revision: IRevisionHasPageId) => {
+    setSourceRevision(revision);
+  };
+  const onChangeTargetInvoked: React.Dispatch<React.SetStateAction<IRevisionHasId | undefined>> = (revision: IRevisionHasPageId) => {
+    setTargetRevision(revision);
+  };
+
+
+  const renderRow = (revision: IRevisionHasPageId, previousRevision: IRevisionHasPageId, latestRevision: IRevisionHasPageId,
       isOldestRevision: boolean, hasDiff: boolean) => {
 
     const revisionId = revision._id;
@@ -63,8 +83,6 @@ export const PageRevisionTable = (props: PageRevisionTAble): JSX.Element => {
           <div className="d-lg-flex">
             <Revision
               revision={revision}
-              currentPageId={currentPageId}
-              currentPagePath={currentPagePath}
               isLatestRevision={revision === latestRevision}
               hasDiff={hasDiff}
               key={`revision-history-rev-${revisionId}`}
@@ -130,36 +148,46 @@ export const PageRevisionTable = (props: PageRevisionTAble): JSX.Element => {
   };
 
   return (
-    <table className={`${styles['revision-history-table']} table revision-history-table`}>
-      <thead>
-        <tr className="d-flex">
-          <th className="col">{t('page_history.revision')}</th>
-          <th className="col-1">{t('page_history.comparing_source')}</th>
-          <th className="col-2">{t('page_history.comparing_target')}</th>
-        </tr>
-      </thead>
-      <tbody className="overflow-auto d-block">
-        {revisions && (
-          <InfiniteScroll
-            swrInifiniteResponse={swrInifiniteResponse}
-            isReachingEnd= {isReachingEnd}
-          >
-            {pageRevisions => pageRevisions.map((revision, idx) => {
-
-              const previousRevision = (idx + 1 < revisions?.length) ? revisions[idx + 1] : revision;
-
-              const isOldestRevision = revision === oldestRevision;
-              const latestRevision = revisions[0];
-
-              // set 'true' if undefined for backward compatibility
-              const hasDiff = revision.hasDiffToPrev !== false;
-              return renderRow(revision, previousRevision, latestRevision, isOldestRevision, hasDiff);
-
-            })}
-          </InfiniteScroll>
-        )}
-      </tbody>
-    </table>
+    <>
+      <table className={`${styles['revision-history-table']} table revision-history-table`}>
+        <thead>
+          <tr className="d-flex">
+            <th className="col">{t('page_history.revision')}</th>
+            <th className="col-1">{t('page_history.comparing_source')}</th>
+            <th className="col-2">{t('page_history.comparing_target')}</th>
+          </tr>
+        </thead>
+        <tbody className="overflow-auto d-block">
+          {revisions && (
+            <InfiniteScroll
+              swrInifiniteResponse={swrInifiniteResponse}
+              isReachingEnd={isReachingEnd}
+              isLoadingIndicatorShown ={false}
+            >
+              {pageRevisions => pageRevisions.map((revision, idx) => {
+
+                const previousRevision = (idx + 1 < revisions?.length) ? revisions[idx + 1] : revision;
+
+                const isOldestRevision = revision === oldestRevision;
+                const latestRevision = revisions[0];
+
+                // set 'true' if undefined for backward compatibility
+                const hasDiff = revision.hasDiffToPrev !== false;
+                return renderRow(revision, previousRevision, latestRevision, isOldestRevision, hasDiff);
+              })}
+            </InfiniteScroll>
+          )}
+        </tbody>
+      </table>
+
+      { sourceRevision && targetRevision && (
+        <RevisionComparer
+          sourceRevision={sourceRevision}
+          targetRevision={targetRevision}
+          onClose={onClose}
+        />)
+      }
+    </>
   );
 
 };

+ 14 - 8
packages/app/src/components/PageHistory/Revision.tsx

@@ -6,6 +6,9 @@ import { useTranslation } from 'next-i18next';
 import Link from 'next/link';
 import urljoin from 'url-join';
 
+import { useCurrentPageId } from '~/stores/context';
+import { useCurrentPagePath } from '~/stores/page';
+
 import UserDate from '../User/UserDate';
 import { Username } from '../User/Username';
 
@@ -13,8 +16,6 @@ import styles from './Revision.module.scss';
 
 type RevisionProps = {
   revision: IRevisionHasId,
-  currentPageId: string,
-  currentPagePath: string,
   isLatestRevision: boolean,
   hasDiff: boolean,
   onClose: () => void,
@@ -24,9 +25,12 @@ export const Revision = (props: RevisionProps): JSX.Element => {
   const { t } = useTranslation();
 
   const {
-    revision, currentPageId, currentPagePath, isLatestRevision, hasDiff, onClose,
+    revision, isLatestRevision, hasDiff, onClose,
   } = props;
 
+  const { data: currentPageId } = useCurrentPageId();
+  const { data: currentPagePath } = useCurrentPagePath();
+
   const { returnPathForURL } = pathUtils;
 
   const renderSimplifiedNodiff = (revision: IRevisionHasId) => {
@@ -69,11 +73,13 @@ export const Revision = (props: RevisionProps): JSX.Element => {
           <div className="mb-1">
             <UserDate dateTime={revision.createdAt} />
             <br className="d-xl-none d-block" />
-            <Link href={urljoin(returnPathForURL(currentPagePath, currentPageId), `?revisionId=${revision._id}`)} prefetch={false}>
-              <a className="ml-xl-3" onClick={onClose}>
-                <i className="icon-login"></i> {t('Go to this version')}
-              </a>
-            </Link>
+            {currentPagePath && currentPageId && (
+              <Link href={urljoin(returnPathForURL(currentPagePath, currentPageId), `?revisionId=${revision._id}`)} prefetch={false}>
+                <a className="ml-xl-3" onClick={onClose}>
+                  <i className="icon-login"></i> {t('Go to this version')}
+                </a>
+              </Link>
+            )}
           </div>
         </div>
       </div>

+ 6 - 3
packages/app/src/components/RevisionComparer/RevisionComparer.tsx

@@ -7,6 +7,9 @@ import {
   Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
 } from 'reactstrap';
 
+import { useCurrentPageId } from '~/stores/context';
+import { useCurrentPagePath } from '~/stores/page';
+
 import { RevisionDiff } from '../PageHistory/RevisionDiff';
 
 import styles from './RevisionComparer.module.scss';
@@ -23,8 +26,6 @@ const DropdownItemContents = ({ title, contents }) => (
 type RevisionComparerProps = {
   sourceRevision: IRevisionHasPageId
   targetRevision: IRevisionHasPageId
-  currentPageId?: string
-  currentPagePath: string
   onClose: () => void
 }
 
@@ -32,10 +33,12 @@ export const RevisionComparer = (props: RevisionComparerProps): JSX.Element => {
   const { t } = useTranslation(['translation', 'commons']);
 
   const {
-    sourceRevision, targetRevision, currentPageId, currentPagePath, onClose,
+    sourceRevision, targetRevision, onClose,
   } = props;
 
   const [dropdownOpen, setDropdownOpen] = useState(false);
+  const { data: currentPageId } = useCurrentPageId();
+  const { data: currentPagePath } = useCurrentPagePath();
 
   const toggleDropdown = () => {
     setDropdownOpen(!dropdownOpen);

+ 1 - 1
packages/app/src/components/Sidebar/RecentChanges.tsx

@@ -14,8 +14,8 @@ import { useSWRInifinitexRecentlyUpdated } from '~/stores/page-listing';
 import loggerFactory from '~/utils/logger';
 
 import FormattedDistanceDate from '../FormattedDistanceDate';
+import InfiniteScroll from '../InfiniteScroll';
 
-import InfiniteScroll from './InfiniteScroll';
 import { SidebarHeaderReloadButton } from './SidebarHeaderReloadButton';
 import RecentChangesContentSkeleton from './Skeleton/RecentChangesContentSkeleton';
 

+ 1 - 1
packages/app/src/components/User/UserDate.jsx

@@ -25,7 +25,7 @@ export default class UserDate extends React.Component {
 }
 
 UserDate.propTypes = {
-  dateTime: PropTypes.string.isRequired,
+  dateTime: PropTypes.instanceOf(Date).isRequired,
   format: PropTypes.string,
   className: PropTypes.string,
 };