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

use additionalMenuItemOnTopRenderer

ryoji-s 2 лет назад
Родитель
Сommit
1b60e9347d

+ 39 - 3
apps/app/src/components/Bookmarks/BookmarkItem.tsx

@@ -1,17 +1,22 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import React, {
+  useCallback, useEffect, useState, useMemo,
+} from 'react';
 
 import nodePath from 'path';
 
 import { DevidedPagePath, pathUtils } from '@growi/core';
 import { useTranslation } from 'react-i18next';
-import { UncontrolledTooltip, DropdownToggle } from 'reactstrap';
+import {
+  UncontrolledTooltip, DropdownItem, DropdownToggle,
+} from 'reactstrap';
 
 import { unbookmark } from '~/client/services/page-operation';
-import { renamePage } from '~/client/util/bookmark-utils';
+import { addBookmarkToFolder, renamePage } from '~/client/util/bookmark-utils';
 import { ValidationTarget } from '~/client/util/input-validator';
 import { toastError } from '~/client/util/toastr';
 import { BookmarkFolderItems, DragItemDataType, DRAG_ITEM_TYPE } from '~/interfaces/bookmark-info';
 import { IPageHasId, IPageInfoAll, IPageToDeleteWithMeta } from '~/interfaces/page';
+import { useSWRxCurrentUserBookmarks } from '~/stores/bookmark';
 import { useSWRxBookmarkFolderAndChild } from '~/stores/bookmark-folder';
 import { useSWRxPageInfo } from '~/stores/page';
 
@@ -54,6 +59,36 @@ export const BookmarkItem = (props: Props): JSX.Element => {
     mutateBookmarkData();
   }, [mutateBookmarkData]);
 
+  const pageId = bookmarkedPage._id;
+
+  const { data: userBookmarks, mutate: mutateUserBookmarks } = useSWRxCurrentUserBookmarks();
+  const isMoveToRoot = useMemo(() => {
+    return !userBookmarks?.map(userBookmark => userBookmark._id).includes(pageId);
+  }, [pageId, userBookmarks]);
+
+  const moveToRootClickedHandler = useCallback(async() => {
+    try {
+      await addBookmarkToFolder(pageId, null);
+      await mutateUserBookmarks();
+    }
+    catch (err) {
+      toastError(err);
+    }
+  }, [mutateUserBookmarks, pageId]);
+
+  const additionalMenuItemOnTopRenderer = useMemo(() => {
+    return (
+      <DropdownItem
+        onClick={moveToRootClickedHandler}
+        className="grw-page-control-dropdown-item"
+        data-testid="add-remove-bookmark-btn"
+      >
+        <i className="fa fa-fw fa-bookmark-o grw-page-control-dropdown-icon"></i>
+        {t('bookmark_folder.move_to_root')}
+      </DropdownItem>
+    );
+  }, [moveToRootClickedHandler, t]);
+
   const bookmarkMenuItemClickHandler = useCallback(async() => {
     await unbookmark(bookmarkedPage._id);
     onUnbookmarked();
@@ -130,6 +165,7 @@ export const BookmarkItem = (props: Props): JSX.Element => {
             onClickBookmarkMenuItem={bookmarkMenuItemClickHandler}
             onClickRenameMenuItem={renameMenuItemClickHandler}
             onClickDeleteMenuItem={deleteMenuItemClickHandler}
+            additionalMenuItemOnTopRenderer={isMoveToRoot ? (() => additionalMenuItemOnTopRenderer) : undefined}
           >
             <DropdownToggle color="transparent" className="border-0 rounded btn-page-item-control p-0 grw-visible-on-hover mr-1">
               <i className="icon-options fa fa-rotate-90 p-1"></i>

+ 1 - 33
apps/app/src/components/Common/Dropdown/PageItemControl.tsx

@@ -1,5 +1,5 @@
 import React, {
-  useState, useCallback, useEffect, useMemo,
+  useState, useCallback, useEffect,
 } from 'react';
 
 import { useTranslation } from 'next-i18next';
@@ -7,14 +7,11 @@ import {
   Dropdown, DropdownMenu, DropdownToggle, DropdownItem,
 } from 'reactstrap';
 
-import { addBookmarkToFolder } from '~/client/util/bookmark-utils';
-import { toastError } from '~/client/util/toastr';
 import { NotAvailableForGuest } from '~/components/NotAvailableForGuest';
 import {
   IPageInfoAll, isIPageInfoForOperation,
 } from '~/interfaces/page';
 import { IPageOperationProcessData } from '~/interfaces/page-operation';
-import { useSWRxCurrentUserBookmarks } from '~/stores/bookmark';
 import { useSWRxPageInfo } from '~/stores/page';
 import loggerFactory from '~/utils/logger';
 import { shouldRecoverPagePaths } from '~/utils/page-operation';
@@ -24,7 +21,6 @@ const logger = loggerFactory('growi:cli:PageItemControl');
 
 export const MenuItemType = {
   BOOKMARK: 'bookmark',
-  BOOKMARKS_TREE_MOVE_TO_ROOT: 'bookmarks_tree_move_to_root',
   RENAME: 'rename',
   DUPLICATE: 'duplicate',
   DELETE: 'delete',
@@ -66,8 +62,6 @@ type DropdownMenuProps = CommonProps & {
 const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.Element => {
   const { t } = useTranslation('');
 
-  const { data: userBookmarks, mutate: mutateUserBookmarks } = useSWRxCurrentUserBookmarks();
-
   const {
     pageId, isLoading, pageInfo, isEnableActions, forceHideMenuItems, operationProcessData,
     onClickBookmarkMenuItem, onClickRenameMenuItem, onClickDuplicateMenuItem, onClickDeleteMenuItem,
@@ -85,20 +79,6 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
     await onClickBookmarkMenuItem(pageId, !pageInfo.isBookmarked);
   }, [onClickBookmarkMenuItem, pageId, pageInfo]);
 
-  const isMoveToRoot = useMemo(() => {
-    return !userBookmarks?.map(userBookmark => userBookmark._id).includes(pageId);
-  }, [pageId, userBookmarks]);
-
-  const moveToRootClickedHandler = useCallback(async() => {
-    try {
-      await addBookmarkToFolder(pageId, null);
-      await mutateUserBookmarks();
-    }
-    catch (err) {
-      toastError(err);
-    }
-  }, [mutateUserBookmarks, pageId]);
-
   // eslint-disable-next-line react-hooks/rules-of-hooks
   const renameItemClickedHandler = useCallback(async() => {
     if (onClickRenameMenuItem == null) {
@@ -194,18 +174,6 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
           </DropdownItem>
         ) }
 
-        {/* Bookmarks Tree Move to Root */}
-        { !forceHideMenuItems?.includes(MenuItemType.BOOKMARKS_TREE_MOVE_TO_ROOT) && isEnableActions && isMoveToRoot && (
-          <DropdownItem
-            onClick={moveToRootClickedHandler}
-            className="grw-page-control-dropdown-item"
-            data-testid="add-remove-bookmark-btn"
-          >
-            <i className="fa fa-fw fa-bookmark-o grw-page-control-dropdown-icon"></i>
-            {t('bookmark_folder.move_to_root')}
-          </DropdownItem>
-        ) }
-
         {/* Move/Rename */}
         { !forceHideMenuItems?.includes(MenuItemType.RENAME) && isEnableActions && pageInfo.isMovable && (
           <DropdownItem

+ 1 - 2
apps/app/src/components/DescendantsPageListModal.tsx

@@ -11,7 +11,6 @@ import {
 import { useIsSharedUser } from '~/stores/context';
 import { useDescendantsPageListModal } from '~/stores/modal';
 
-import { MenuItemType } from './Common/Dropdown/PageItemControl';
 import { CustomNavTab } from './CustomNavigation/CustomNav';
 import CustomTabContent from './CustomNavigation/CustomTabContent';
 import { DescendantsPageListProps } from './DescendantsPageList';
@@ -52,7 +51,7 @@ export const DescendantsPageListModal = (): JSX.Element => {
           if (status == null || status.path == null || !status.isOpened) {
             return <></>;
           }
-          return <DescendantsPageList path={status.path} forceHideMenuItems={[MenuItemType.BOOKMARKS_TREE_MOVE_TO_ROOT]}/>;
+          return <DescendantsPageList path={status.path} />;
         },
         i18n: t('page_list'),
         isLinkEnabled: () => !isSharedUser,

+ 0 - 2
apps/app/src/components/IdenticalPathPage.tsx

@@ -6,7 +6,6 @@ import { useTranslation } from 'next-i18next';
 import { useCurrentPathname } from '~/stores/context';
 import { useSWRxPageInfoForList, useSWRxPagesByPath } from '~/stores/page-listing';
 
-import { MenuItemType } from './Common/Dropdown/PageItemControl';
 import { PageListItemL } from './PageList/PageListItemL';
 
 
@@ -77,7 +76,6 @@ export const IdenticalPathPage = (): JSX.Element => {
                 isSelected={false}
                 isEnableActions
                 showPageUpdatedTime
-                forceHideMenuItems={[MenuItemType.BOOKMARKS_TREE_MOVE_TO_ROOT]}
               />
             );
           })}

+ 0 - 1
apps/app/src/components/Navbar/SubNavButtons.tsx

@@ -207,7 +207,6 @@ const SubNavButtonsSubstance = (props: SubNavButtonsSubstanceProps): JSX.Element
 
   const forceHideMenuItemsWithBookmark = forceHideMenuItems ?? [];
   forceHideMenuItemsWithBookmark.push(MenuItemType.BOOKMARK);
-  forceHideMenuItemsWithBookmark.push(MenuItemType.BOOKMARKS_TREE_MOVE_TO_ROOT);
 
   return (
     <div className="d-flex" style={{ gap: '2px' }}>

+ 1 - 2
apps/app/src/components/NotFoundPage.tsx

@@ -2,7 +2,6 @@ import React, { useMemo } from 'react';
 
 import { useTranslation } from 'next-i18next';
 
-import { MenuItemType } from './Common/Dropdown/PageItemControl';
 import CustomNavAndContents from './CustomNavigation/CustomNavAndContents';
 import { DescendantsPageList } from './DescendantsPageList';
 import PageListIcon from './Icons/PageListIcon';
@@ -22,7 +21,7 @@ const NotFoundPage = (props: NotFoundPageProps): JSX.Element => {
     return {
       pagelist: {
         Icon: PageListIcon,
-        Content: () => <DescendantsPageList path={path} forceHideMenuItems={[MenuItemType.BOOKMARKS_TREE_MOVE_TO_ROOT]}/>,
+        Content: () => <DescendantsPageList path={path}/>,
         i18n: t('page_list'),
       },
       timeLine: {

+ 35 - 2
apps/app/src/components/PageList/BookmarkList.tsx

@@ -1,4 +1,4 @@
-import React, { useCallback, useState } from 'react';
+import React, { useCallback, useState, useMemo } from 'react';
 
 import nodePath from 'path';
 
@@ -6,13 +6,15 @@ import {
   IPageInfoAll, IPageToDeleteWithMeta, pathUtils,
 } from '@growi/core';
 import { useTranslation } from 'next-i18next';
-import { DropdownToggle } from 'reactstrap';
+import { DropdownItem, DropdownToggle } from 'reactstrap';
 
 import { unbookmark } from '~/client/services/page-operation';
 import { apiv3Put } from '~/client/util/apiv3-client';
+import { addBookmarkToFolder } from '~/client/util/bookmark-utils';
 import { ValidationTarget } from '~/client/util/input-validator';
 import { toastError, toastSuccess } from '~/client/util/toastr';
 import { IPageHasId } from '~/interfaces/page';
+import { useSWRxCurrentUserBookmarks } from '~/stores/bookmark';
 import loggerFactory from '~/utils/logger';
 
 import ClosableTextInput from '../Common/ClosableTextInput';
@@ -35,6 +37,36 @@ export const BookmarkList = (props:Props): JSX.Element => {
   const { t } = useTranslation();
   const [isRenameInputShown, setIsRenameInputShown] = useState(false);
 
+  const pageId = page._id;
+
+  const { data: userBookmarks, mutate: mutateUserBookmarks } = useSWRxCurrentUserBookmarks();
+  const isMoveToRoot = useMemo(() => {
+    return !userBookmarks?.map(userBookmark => userBookmark._id).includes(pageId);
+  }, [pageId, userBookmarks]);
+
+  const moveToRootClickedHandler = useCallback(async() => {
+    try {
+      await addBookmarkToFolder(pageId, null);
+      await mutateUserBookmarks();
+    }
+    catch (err) {
+      toastError(err);
+    }
+  }, [mutateUserBookmarks, pageId]);
+
+  const additionalMenuItemOnTopRenderer = useMemo(() => {
+    return (
+      <DropdownItem
+        onClick={moveToRootClickedHandler}
+        className="grw-page-control-dropdown-item"
+        data-testid="add-remove-bookmark-btn"
+      >
+        <i className="fa fa-fw fa-bookmark-o grw-page-control-dropdown-icon"></i>
+        {t('bookmark_folder.move_to_root')}
+      </DropdownItem>
+    );
+  }, [moveToRootClickedHandler, t]);
+
   const bookmarkMenuItemClickHandler = useCallback(async() => {
     await unbookmark(page._id);
     onUnbookmarked();
@@ -103,6 +135,7 @@ export const BookmarkList = (props:Props): JSX.Element => {
         onClickBookmarkMenuItem={bookmarkMenuItemClickHandler}
         onClickRenameMenuItem={() => setIsRenameInputShown(true)}
         onClickDeleteMenuItem={deleteMenuItemClickHandler}
+        additionalMenuItemOnTopRenderer={isMoveToRoot ? (() => additionalMenuItemOnTopRenderer) : undefined}
       >
         <DropdownToggle color="transparent" className="border-0 rounded btn-page-item-control p-0 grw-visible-on-hover mr-1">
           <i className="icon-options fa fa-rotate-90 p-1"></i>

+ 0 - 1
apps/app/src/components/PrivateLegacyPages.tsx

@@ -438,7 +438,6 @@ const PrivateLegacyPages = (): JSX.Element => {
         onSelectedPagesByCheckboxesChanged={selectedPagesByCheckboxesChangedHandler}
         forceHideMenuItems={[
           MenuItemType.BOOKMARK,
-          MenuItemType.BOOKMARKS_TREE_MOVE_TO_ROOT,
           MenuItemType.RENAME,
           MenuItemType.DUPLICATE,
           MenuItemType.REVERT,

+ 0 - 2
apps/app/src/components/SearchPage.tsx

@@ -12,7 +12,6 @@ import { IFormattedSearchResult } from '~/interfaces/search';
 import { useIsSearchServiceReachable, useShowPageLimitationL } from '~/stores/context';
 import { ISearchConditions, ISearchConfigurations, useSWRxSearch } from '~/stores/search';
 
-import { MenuItemType } from './Common/Dropdown/PageItemControl';
 import { NotAvailableForGuest } from './NotAvailableForGuest';
 import PaginationWrapper from './PaginationWrapper';
 import { OperateAllControl } from './SearchPage/OperateAllControl';
@@ -265,7 +264,6 @@ export const SearchPage = (): JSX.Element => {
       searchControl={searchControl}
       searchResultListHead={searchResultListHead}
       searchPager={searchPager}
-      forceHideMenuItems={[MenuItemType.BOOKMARKS_TREE_MOVE_TO_ROOT]}
     />
   );
 };

+ 0 - 1
apps/app/src/components/Sidebar/PageTree/Item.tsx

@@ -494,7 +494,6 @@ const Item: FC<ItemProps> = (props: ItemProps) => {
               isInstantRename
               // Todo: It is wanted to find a better way to pass operationProcessData to PageItemControl
               operationProcessData={page.processData}
-              forceHideMenuItems={[MenuItemType.BOOKMARKS_TREE_MOVE_TO_ROOT]}
             >
               {/* pass the color property to reactstrap dropdownToggle props. https://6-4-0--reactstrap.netlify.app/components/dropdowns/  */}
               <DropdownToggle color="transparent" className="border-0 rounded btn-page-item-control p-0 grw-visible-on-hover mr-1">

+ 1 - 1
apps/app/src/components/TrashPageList.tsx

@@ -72,7 +72,7 @@ const DescendantsPageListForTrash = (): JSX.Element => {
     <DescendantsPageList
       path="/trash"
       limit={limit}
-      forceHideMenuItems={[MenuItemType.RENAME, MenuItemType.BOOKMARKS_TREE_MOVE_TO_ROOT]}
+      forceHideMenuItems={[MenuItemType.RENAME]}
     />
   );
 };