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

Merge pull request #5251 from weseek/imprv/87696-show-duplilcate-modal-when-clicking-page-item-control

Imprv/87696 show PageDuplicateModal when clicking DuplicateMenuItem
cao 4 лет назад
Родитель
Сommit
ffdd8d810d

+ 20 - 3
packages/app/src/components/Common/Dropdown/PageItemControl.tsx

@@ -23,6 +23,7 @@ type CommonProps = {
   isEnableActions?: boolean,
   showBookmarkMenuItem?: boolean,
   onClickBookmarkMenuItem?: (pageId: string, newValue?: boolean) => Promise<void>,
+  onClickDuplicateMenuItem?: () => Promise<void> | void,
   onClickRenameMenuItem?: (pageId: string) => void,
   onClickDeleteMenuItem?: (pageId: string) => void,
 
@@ -41,7 +42,7 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
   const {
     pageId, isLoading,
     pageInfo, isEnableActions, showBookmarkMenuItem,
-    onClickBookmarkMenuItem, onClickRenameMenuItem, onClickDeleteMenuItem,
+    onClickBookmarkMenuItem, onClickDuplicateMenuItem, onClickRenameMenuItem, onClickDeleteMenuItem,
     additionalMenuItemRenderer: AdditionalMenuItems,
   } = props;
 
@@ -54,6 +55,14 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
     await onClickBookmarkMenuItem(pageId, !pageInfo.isBookmarked);
   }, [onClickBookmarkMenuItem, pageId, pageInfo]);
 
+  // eslint-disable-next-line react-hooks/rules-of-hooks
+  const duplicateItemClickedHandler = useCallback(async() => {
+    if (onClickDuplicateMenuItem == null) {
+      return;
+    }
+    await onClickDuplicateMenuItem();
+  }, [onClickDuplicateMenuItem]);
+
   // eslint-disable-next-line react-hooks/rules-of-hooks
   const renameItemClickedHandler = useCallback(async() => {
     if (onClickRenameMenuItem == null) {
@@ -104,7 +113,7 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
 
         {/* Duplicate */}
         { isEnableActions && !pageInfo.isEmpty && (
-          <DropdownItem onClick={() => toastr.warning(t('search_result.currently_not_implemented'))}>
+          <DropdownItem onClick={duplicateItemClickedHandler}>
             <i className="icon-fw icon-docs"></i>
             {t('Duplicate')}
           </DropdownItem>
@@ -158,7 +167,7 @@ export const PageItemControlSubstance = (props: PageItemControlSubstanceProps):
   const {
     pageId, pageInfo: presetPageInfo, fetchOnInit,
     children,
-    onClickBookmarkMenuItem,
+    onClickBookmarkMenuItem, onClickDuplicateMenuItem,
   } = props;
 
   const [isOpen, setIsOpen] = useState(false);
@@ -181,6 +190,13 @@ export const PageItemControlSubstance = (props: PageItemControlSubstanceProps):
 
   const isLoading = shouldFetch && fetchedPageInfo == null;
 
+  const duplicateMenuItemClickHandler = useCallback(async() => {
+    if (onClickDuplicateMenuItem == null) {
+      return;
+    }
+    await onClickDuplicateMenuItem();
+  }, [onClickDuplicateMenuItem]);
+
   return (
     <Dropdown isOpen={isOpen} toggle={() => setIsOpen(!isOpen)}>
 
@@ -195,6 +211,7 @@ export const PageItemControlSubstance = (props: PageItemControlSubstanceProps):
         isLoading={isLoading}
         pageInfo={fetchedPageInfo ?? presetPageInfo}
         onClickBookmarkMenuItem={bookmarkMenuItemClickHandler}
+        onClickDuplicateMenuItem={duplicateMenuItemClickHandler}
       />
     </Dropdown>
   );

+ 1 - 1
packages/app/src/components/PageList/PageList.tsx

@@ -27,7 +27,7 @@ const PageList = (props: Props): JSX.Element => {
   }
 
   const pageList = pages.items.map(page => (
-    <PageListItemL page={page} isEnableActions={isEnableActions} />
+    <PageListItemL key={page.pageData._id} page={page} isEnableActions={isEnableActions} />
   ));
 
   if (pageList.length === 0) {

+ 18 - 1
packages/app/src/components/Sidebar/PageTree/Item.tsx

@@ -25,6 +25,7 @@ interface ItemProps {
   itemNode: ItemNode
   targetPathOrId?: string
   isOpen?: boolean
+  onClickDuplicateMenuItem?(pageId: string, path: string): void
   onClickDeleteByPage?(pageToDelete: IPageForPageDeleteModal | null): void
 }
 
@@ -66,7 +67,7 @@ const ItemCount: FC<ItemCountProps> = (props:ItemCountProps) => {
 const Item: FC<ItemProps> = (props: ItemProps) => {
   const { t } = useTranslation();
   const {
-    itemNode, targetPathOrId, isOpen: _isOpen = false, onClickDeleteByPage, isEnableActions,
+    itemNode, targetPathOrId, isOpen: _isOpen = false, onClickDuplicateMenuItem, onClickDeleteByPage, isEnableActions,
   } = props;
 
   const { page, children } = itemNode;
@@ -125,6 +126,20 @@ const Item: FC<ItemProps> = (props: ItemProps) => {
     setNewPageInputShown(true);
   }, []);
 
+  const duplicateMenuItemClickHandler = useCallback((): void => {
+    if (onClickDuplicateMenuItem == null) {
+      return;
+    }
+
+    const { _id: pageId, path } = page;
+
+    if (pageId == null || path == null) {
+      throw Error('Any of _id and path must not be null.');
+    }
+
+    onClickDuplicateMenuItem(pageId, path);
+  }, [onClickDuplicateMenuItem, page]);
+
   const onClickDeleteButton = useCallback(async(_pageId: string): Promise<void> => {
     if (onClickDeleteByPage == null) {
       return;
@@ -267,6 +282,7 @@ const Item: FC<ItemProps> = (props: ItemProps) => {
             isEnableActions={isEnableActions}
             showBookmarkMenuItem
             onClickBookmarkMenuItem={bookmarkMenuItemClickHandler}
+            onClickDuplicateMenuItem={duplicateMenuItemClickHandler}
             onClickDeleteMenuItem={onClickDeleteButton}
             onClickRenameMenuItem={onClickRenameButton}
           >
@@ -301,6 +317,7 @@ const Item: FC<ItemProps> = (props: ItemProps) => {
               itemNode={node}
               isOpen={false}
               targetPathOrId={targetPathOrId}
+              onClickDuplicateMenuItem={onClickDuplicateMenuItem}
               onClickDeleteByPage={onClickDeleteByPage}
             />
           </div>

+ 15 - 4
packages/app/src/components/Sidebar/PageTree/ItemsTree.tsx

@@ -6,7 +6,7 @@ import Item from './Item';
 import { useSWRxPageAncestorsChildren, useSWRxRootPage } from '../../../stores/page-listing';
 import { TargetAndAncestors } from '~/interfaces/page-listing-results';
 import { toastError } from '~/client/util/apiNotification';
-import { IPageForPageDeleteModal, usePageDeleteModalStatus } from '~/stores/ui';
+import { IPageForPageDeleteModal, usePageDuplicateModalStatus, usePageDeleteModalStatus } from '~/stores/ui';
 
 /*
  * Utility to generate initial node
@@ -55,8 +55,13 @@ type ItemsTreeProps = {
 }
 
 const renderByInitialNode = (
-    initialNode: ItemNode, isEnableActions: boolean, targetPathOrId?: string, onClickDeleteByPage?: (pageToDelete: IPageForPageDeleteModal | null) => void,
+    initialNode: ItemNode,
+    isEnableActions: boolean,
+    targetPathOrId?: string,
+    onClickDuplicateMenuItem?: (pageId: string, path: string) => void,
+    onClickDeleteByPage?: (pageToDelete: IPageForPageDeleteModal | null) => void,
 ): JSX.Element => {
+
   return (
     <ul className="grw-pagetree list-group p-3">
       <Item
@@ -65,6 +70,7 @@ const renderByInitialNode = (
         itemNode={initialNode}
         isOpen
         isEnableActions={isEnableActions}
+        onClickDuplicateMenuItem={onClickDuplicateMenuItem}
         onClickDeleteByPage={onClickDeleteByPage}
       />
     </ul>
@@ -82,8 +88,13 @@ const ItemsTree: FC<ItemsTreeProps> = (props: ItemsTreeProps) => {
 
   const { data: ancestorsChildrenData, error: error1 } = useSWRxPageAncestorsChildren(targetPath);
   const { data: rootPageData, error: error2 } = useSWRxRootPage();
+  const { open: openDuplicateModal } = usePageDuplicateModalStatus();
   const { open: openDeleteModal } = usePageDeleteModalStatus();
 
+  const onClickDuplicateMenuItem = (pageId: string, path: string) => {
+    openDuplicateModal(pageId, path);
+  };
+
   const onClickDeleteByPage = (pageToDelete: IPageForPageDeleteModal) => {
     openDeleteModal([pageToDelete]);
   };
@@ -99,7 +110,7 @@ const ItemsTree: FC<ItemsTreeProps> = (props: ItemsTreeProps) => {
    */
   if (ancestorsChildrenData != null && rootPageData != null) {
     const initialNode = generateInitialNodeAfterResponse(ancestorsChildrenData.ancestorsChildren, new ItemNode(rootPageData.rootPage));
-    return renderByInitialNode(initialNode, isEnableActions, targetPathOrId, onClickDeleteByPage);
+    return renderByInitialNode(initialNode, isEnableActions, targetPathOrId, onClickDuplicateMenuItem, onClickDeleteByPage);
   }
 
   /*
@@ -107,7 +118,7 @@ const ItemsTree: FC<ItemsTreeProps> = (props: ItemsTreeProps) => {
    */
   if (targetAndAncestorsData != null) {
     const initialNode = generateInitialNodeBeforeResponse(targetAndAncestorsData.targetAndAncestors);
-    return renderByInitialNode(initialNode, isEnableActions, targetPathOrId, onClickDeleteByPage);
+    return renderByInitialNode(initialNode, isEnableActions, targetPathOrId, onClickDuplicateMenuItem, onClickDeleteByPage);
   }
 
   return null;