Yuki Takei 2 anos atrás
pai
commit
d53eb20d91

+ 2 - 2
apps/app/src/components/ItemsTree/ItemsTree.tsx

@@ -25,7 +25,7 @@ import { usePageTreeDescCountMap, useSidebarScrollerRef } from '~/stores/ui';
 import { useGlobalSocket } from '~/stores/websocket';
 import { useGlobalSocket } from '~/stores/websocket';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
-import { ItemNode, SimpleItemProps } from '../TreeItem';
+import { ItemNode, type TreeItemProps } from '../TreeItem';
 
 
 import ItemsTreeContentSkeleton from './ItemsTreeContentSkeleton';
 import ItemsTreeContentSkeleton from './ItemsTreeContentSkeleton';
 
 
@@ -92,7 +92,7 @@ type ItemsTreeProps = {
   targetPath: string
   targetPath: string
   targetPathOrId?: Nullable<string>
   targetPathOrId?: Nullable<string>
   targetAndAncestorsData?: TargetAndAncestors
   targetAndAncestorsData?: TargetAndAncestors
-  CustomTreeItem: React.FunctionComponent<SimpleItemProps>
+  CustomTreeItem: React.FunctionComponent<TreeItemProps>
 }
 }
 
 
 /*
 /*

+ 5 - 4
apps/app/src/components/PageSelectModal/TreeItemForModal.tsx

@@ -1,11 +1,12 @@
-import React, { FC } from 'react';
+import React, { type FC } from 'react';
 
 
 import {
 import {
-  SimpleItem, SimpleItemProps, SimpleItemTool, useNewPageInput,
+  SimpleItem, SimpleItemTool, useNewPageInput, type TreeItemProps,
 } from '../TreeItem';
 } from '../TreeItem';
 
 
-type Optional = 'itemRef' | 'itemClass' | 'mainClassName';
-type PageTreeItemProps = Omit<SimpleItemProps, Optional> & {key};
+type PageTreeItemProps = TreeItemProps & {
+  key?: React.Key | null,
+};
 
 
 export const TreeItemForModal: FC<PageTreeItemProps> = (props) => {
 export const TreeItemForModal: FC<PageTreeItemProps> = (props) => {
 
 

+ 6 - 7
apps/app/src/components/Sidebar/PageTreeItem/Ellipsis.tsx

@@ -15,27 +15,26 @@ import { apiv3Put } from '~/client/util/apiv3-client';
 import { ValidationTarget } from '~/client/util/input-validator';
 import { ValidationTarget } from '~/client/util/input-validator';
 import { toastError, toastSuccess } from '~/client/util/toastr';
 import { toastError, toastSuccess } from '~/client/util/toastr';
 import { NotAvailableForGuest } from '~/components/NotAvailableForGuest';
 import { NotAvailableForGuest } from '~/components/NotAvailableForGuest';
-import { IPageForItem } from '~/interfaces/page';
 import { useSWRMUTxCurrentUserBookmarks } from '~/stores/bookmark';
 import { useSWRMUTxCurrentUserBookmarks } from '~/stores/bookmark';
 import { useSWRMUTxPageInfo } from '~/stores/page';
 import { useSWRMUTxPageInfo } from '~/stores/page';
 
 
 import ClosableTextInput from '../../Common/ClosableTextInput';
 import ClosableTextInput from '../../Common/ClosableTextInput';
 import { PageItemControl } from '../../Common/Dropdown/PageItemControl';
 import { PageItemControl } from '../../Common/Dropdown/PageItemControl';
 import {
 import {
-  SimpleItemToolProps, NotDraggableForClosableTextInput, SimpleItemTool,
+  type TreeItemToolProps, NotDraggableForClosableTextInput, SimpleItemTool,
 } from '../../TreeItem';
 } from '../../TreeItem';
 
 
-type EllipsisProps = SimpleItemToolProps & {page: IPageForItem};
-
-export const Ellipsis: FC<EllipsisProps> = (props) => {
+export const Ellipsis: FC<TreeItemToolProps> = (props) => {
   const [isRenameInputShown, setRenameInputShown] = useState(false);
   const [isRenameInputShown, setRenameInputShown] = useState(false);
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
   const {
   const {
-    page, onRenamed, onClickDuplicateMenuItem,
+    itemNode, onRenamed, onClickDuplicateMenuItem,
     onClickDeleteMenuItem, isEnableActions, isReadOnlyUser,
     onClickDeleteMenuItem, isEnableActions, isReadOnlyUser,
   } = props;
   } = props;
 
 
+  const { page } = itemNode;
+
   const { trigger: mutateCurrentUserBookmarks } = useSWRMUTxCurrentUserBookmarks();
   const { trigger: mutateCurrentUserBookmarks } = useSWRMUTxCurrentUserBookmarks();
   const { trigger: mutatePageInfo } = useSWRMUTxPageInfo(page._id ?? null);
   const { trigger: mutatePageInfo } = useSWRMUTxPageInfo(page._id ?? null);
 
 
@@ -141,7 +140,7 @@ export const Ellipsis: FC<EllipsisProps> = (props) => {
           </NotDraggableForClosableTextInput>
           </NotDraggableForClosableTextInput>
         </div>
         </div>
       ) : (
       ) : (
-        <SimpleItemTool page={page} isEnableActions={false} isReadOnlyUser={false} />
+        <SimpleItemTool itemNode={itemNode} isEnableActions={false} isReadOnlyUser={false} />
       )}
       )}
       <NotAvailableForGuest>
       <NotAvailableForGuest>
         <div className="grw-pagetree-control d-flex">
         <div className="grw-pagetree-control d-flex">

+ 4 - 6
apps/app/src/components/Sidebar/PageTreeItem/PageTreeItem.tsx

@@ -1,5 +1,6 @@
 import React, {
 import React, {
-  useCallback, useState, FC,
+  useCallback, useState,
+  type FC,
 } from 'react';
 } from 'react';
 
 
 import nodePath from 'path';
 import nodePath from 'path';
@@ -15,17 +16,14 @@ import { mutatePageTree, useSWRxPageChildren } from '~/stores/page-listing';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
 import {
 import {
-  SimpleItem, type SimpleItemProps, useNewPageInput, ItemNode,
+  SimpleItem, useNewPageInput, ItemNode, type TreeItemProps,
 } from '../../TreeItem';
 } from '../../TreeItem';
 
 
 import { Ellipsis } from './Ellipsis';
 import { Ellipsis } from './Ellipsis';
 
 
 const logger = loggerFactory('growi:cli:Item');
 const logger = loggerFactory('growi:cli:Item');
 
 
-type PageTreeItemPropsOptional = 'itemRef' | 'itemClass' | 'mainClassName';
-type PageTreeItemProps = Omit<SimpleItemProps, PageTreeItemPropsOptional>;
-
-export const PageTreeItem: FC<PageTreeItemProps> = (props) => {
+export const PageTreeItem: FC<TreeItemProps> = (props) => {
   const getNewPathAfterMoved = (droppedPagePath: string, newParentPagePath: string): string => {
   const getNewPathAfterMoved = (droppedPagePath: string, newParentPagePath: string): string => {
     const pageTitle = nodePath.basename(droppedPagePath);
     const pageTitle = nodePath.basename(droppedPagePath);
     return nodePath.join(newParentPagePath, pageTitle);
     return nodePath.join(newParentPagePath, pageTitle);

+ 16 - 19
apps/app/src/components/TreeItem/NewPageInput/use-new-page-input.tsx

@@ -4,14 +4,14 @@ import { apiv3Post } from '~/client/util/apiv3-client';
 import { useSWRxPageChildren } from '~/stores/page-listing';
 import { useSWRxPageChildren } from '~/stores/page-listing';
 import { usePageTreeDescCountMap } from '~/stores/ui';
 import { usePageTreeDescCountMap } from '~/stores/ui';
 
 
-import type { SimpleItemContentProps } from '../interfaces';
+import type { TreeItemToolProps } from '../interfaces';
 
 
 import { NewPageCreateButton } from './NewPageCreateButton';
 import { NewPageCreateButton } from './NewPageCreateButton';
 import { NewPageInput } from './NewPageInput';
 import { NewPageInput } from './NewPageInput';
 
 
 type UseNewPageInput = {
 type UseNewPageInput = {
-  Input: FC<SimpleItemContentProps>,
-  CreateButton: FC<SimpleItemContentProps>,
+  Input: FC<TreeItemToolProps>,
+  CreateButton: FC<TreeItemToolProps>,
   isProcessingSubmission: boolean,
   isProcessingSubmission: boolean,
 }
 }
 
 
@@ -22,10 +22,10 @@ export const useNewPageInput = (): UseNewPageInput => {
 
 
   const { getDescCount } = usePageTreeDescCountMap();
   const { getDescCount } = usePageTreeDescCountMap();
 
 
-  const CreateButton: FC<SimpleItemContentProps> = (props) => {
+  const CreateButton: FC<TreeItemToolProps> = (props) => {
 
 
-    const { page, children, stateHandlers } = props;
-    const { setIsOpen } = stateHandlers;
+    const { itemNode, stateHandlers } = props;
+    const { page, children } = itemNode;
 
 
     // descendantCount
     // descendantCount
     const descendantCount = getDescCount(page._id) || page.descendantCount || 0;
     const descendantCount = getDescCount(page._id) || page.descendantCount || 0;
@@ -37,27 +37,24 @@ export const useNewPageInput = (): UseNewPageInput => {
       setShowInput(true);
       setShowInput(true);
 
 
       if (hasDescendants) {
       if (hasDescendants) {
-        setIsOpen(true);
+        stateHandlers?.setIsOpen(true);
       }
       }
-    }, [hasDescendants, setIsOpen]);
+    }, [hasDescendants, stateHandlers]);
 
 
     return (
     return (
       <NewPageCreateButton
       <NewPageCreateButton
-        page={props.page}
+        page={page}
         onClick={onClick}
         onClick={onClick}
       />
       />
     );
     );
   };
   };
 
 
-  const Input: FC<SimpleItemContentProps> = (props) => {
+  const Input: FC<TreeItemToolProps> = (props) => {
 
 
-    const {
-      page, children, stateHandlers,
-    } = props;
+    const { itemNode, stateHandlers } = props;
+    const { page, children } = itemNode;
 
 
-    const { isOpen, setIsOpen } = stateHandlers;
-
-    const { mutate: mutateChildren } = useSWRxPageChildren(isOpen ? page._id : null);
+    const { mutate: mutateChildren } = useSWRxPageChildren(stateHandlers?.isOpen ? page._id : null);
 
 
     const { getDescCount } = usePageTreeDescCountMap();
     const { getDescCount } = usePageTreeDescCountMap();
     const descendantCount = getDescCount(page._id) || page.descendantCount || 0;
     const descendantCount = getDescCount(page._id) || page.descendantCount || 0;
@@ -81,9 +78,9 @@ export const useNewPageInput = (): UseNewPageInput => {
       mutateChildren();
       mutateChildren();
 
 
       if (!hasDescendants) {
       if (!hasDescendants) {
-        setIsOpen(true);
+        stateHandlers?.setIsOpen(true);
       }
       }
-    }, [hasDescendants, mutateChildren, page.grant, page.grantedGroups, setIsOpen]);
+    }, [hasDescendants, mutateChildren, page.grant, page.grantedGroups, stateHandlers]);
 
 
     const submittionFailedHandler = useCallback(() => {
     const submittionFailedHandler = useCallback(() => {
       setProcessingSubmission(false);
       setProcessingSubmission(false);
@@ -92,7 +89,7 @@ export const useNewPageInput = (): UseNewPageInput => {
     return showInput
     return showInput
       ? (
       ? (
         <NewPageInput
         <NewPageInput
-          page={props.page}
+          page={page}
           isEnableActions={props.isEnableActions}
           isEnableActions={props.isEnableActions}
           onSubmit={submitHandler}
           onSubmit={submitHandler}
           onSubmittionFailed={submittionFailedHandler}
           onSubmittionFailed={submittionFailedHandler}

+ 35 - 38
apps/app/src/components/TreeItem/SimpleItem.tsx

@@ -1,5 +1,6 @@
 import React, {
 import React, {
-  useCallback, useState, FC, useEffect,
+  useCallback, useState, useEffect,
+  type FC, type RefObject, type RefCallback,
 } from 'react';
 } from 'react';
 
 
 import nodePath from 'path';
 import nodePath from 'path';
@@ -18,7 +19,7 @@ import CountBadge from '../Common/CountBadge';
 
 
 import { ItemNode } from './ItemNode';
 import { ItemNode } from './ItemNode';
 import { useNewPageInput } from './NewPageInput';
 import { useNewPageInput } from './NewPageInput';
-import type { SimpleItemContentProps, SimpleItemProps, SimpleItemToolProps } from './interfaces';
+import type { TreeItemProps, TreeItemToolProps } from './interfaces';
 
 
 
 
 // Utility to mark target
 // Utility to mark target
@@ -38,28 +39,14 @@ const markTarget = (children: ItemNode[], targetPathOrId?: Nullable<string>): vo
   });
   });
 };
 };
 
 
-/**
- * Return new page path after the droppedPagePath is moved under the newParentPagePath
- * @param droppedPagePath
- * @param newParentPagePath
- * @returns
- */
-
-/**
- * Return whether the fromPage could be moved under the newParentPage
- * @param fromPage
- * @param newParentPage
- * @param printLog
- * @returns
- */
-
-export const SimpleItemTool: FC<SimpleItemToolProps> = (props) => {
+
+export const SimpleItemTool: FC<TreeItemToolProps> = (props) => {
   const { t } = useTranslation();
   const { t } = useTranslation();
   const router = useRouter();
   const router = useRouter();
 
 
   const { getDescCount } = usePageTreeDescCountMap();
   const { getDescCount } = usePageTreeDescCountMap();
 
 
-  const page = props.page;
+  const { page } = props.itemNode;
 
 
   const pageName = nodePath.basename(page.path ?? '') || '/';
   const pageName = nodePath.basename(page.path ?? '') || '/';
 
 
@@ -103,6 +90,10 @@ export const SimpleItemTool: FC<SimpleItemToolProps> = (props) => {
   );
   );
 };
 };
 
 
+type SimpleItemProps = TreeItemProps & {
+  itemRef?: RefObject<any> | RefCallback<any>,
+}
+
 export const SimpleItem: FC<SimpleItemProps> = (props) => {
 export const SimpleItem: FC<SimpleItemProps> = (props) => {
   const {
   const {
     itemNode, targetPathOrId, isOpen: _isOpen = false,
     itemNode, targetPathOrId, isOpen: _isOpen = false,
@@ -168,8 +159,7 @@ export const SimpleItem: FC<SimpleItemProps> = (props) => {
 
 
   const SimpleItemContent = CustomEndComponents ?? [SimpleItemTool];
   const SimpleItemContent = CustomEndComponents ?? [SimpleItemTool];
 
 
-  const simpleItemProps: SimpleItemProps = {
-    itemNode,
+  const baseProps: Omit<TreeItemProps, 'itemNode'> = {
     isEnableActions,
     isEnableActions,
     isReadOnlyUser,
     isReadOnlyUser,
     isOpen: false,
     isOpen: false,
@@ -179,11 +169,9 @@ export const SimpleItem: FC<SimpleItemProps> = (props) => {
     onClickDeleteMenuItem,
     onClickDeleteMenuItem,
   };
   };
 
 
-  const simpleItemContentProps: SimpleItemContentProps = {
-    ...simpleItemProps,
-    page,
-    children,
-    stateHandlers: { isOpen, setIsOpen },
+  const toolProps: TreeItemToolProps = {
+    ...baseProps,
+    itemNode,
   };
   };
 
 
   const CustomNextComponents = props.customNextComponents;
   const CustomNextComponents = props.customNextComponents;
@@ -216,26 +204,35 @@ export const SimpleItem: FC<SimpleItemProps> = (props) => {
         </div>
         </div>
         {SimpleItemContent.map((ItemContent, index) => (
         {SimpleItemContent.map((ItemContent, index) => (
           // eslint-disable-next-line react/no-array-index-key
           // eslint-disable-next-line react/no-array-index-key
-          <ItemContent key={index} {...simpleItemContentProps} />
+          <ItemContent key={index} {...toolProps} />
         ))}
         ))}
       </li>
       </li>
 
 
       {CustomNextComponents?.map((UnderItemContent, index) => (
       {CustomNextComponents?.map((UnderItemContent, index) => (
         // eslint-disable-next-line react/no-array-index-key
         // eslint-disable-next-line react/no-array-index-key
-        <UnderItemContent key={index} {...simpleItemContentProps} />
+        <UnderItemContent key={index} {...toolProps} />
       ))}
       ))}
 
 
       {
       {
-        isOpen && hasChildren() && currentChildren.map((node, index) => (
-          <div key={node.page._id} className="grw-pagetree-item-children">
-            <ItemClassFixed {...simpleItemProps} />
-            {isProcessingSubmission && (currentChildren.length - 1 === index) && (
-              <div className="text-muted text-center">
-                <i className="fa fa-spinner fa-pulse mr-1"></i>
-              </div>
-            )}
-          </div>
-        ))
+        isOpen && hasChildren() && currentChildren.map((node, index) => {
+          const itemProps = {
+            ...baseProps,
+            itemNode: node,
+            itemClass,
+            mainClassName,
+          };
+
+          return (
+            <div key={node.page._id} className="grw-pagetree-item-children">
+              <ItemClassFixed {...itemProps} />
+              {isProcessingSubmission && (currentChildren.length - 1 === index) && (
+                <div className="text-muted text-center">
+                  <i className="fa fa-spinner fa-pulse mr-1"></i>
+                </div>
+              )}
+            </div>
+          );
+        })
       }
       }
     </div>
     </div>
   );
   );

+ 19 - 27
apps/app/src/components/TreeItem/interfaces/index.ts

@@ -1,38 +1,30 @@
 import type { IPageToDeleteWithMeta } from '@growi/core';
 import type { IPageToDeleteWithMeta } from '@growi/core';
 import type { Nullable } from 'vitest';
 import type { Nullable } from 'vitest';
 
 
-import type { IPageForItem } from '~/interfaces/page';
 import type { IPageForPageDuplicateModal } from '~/stores/modal';
 import type { IPageForPageDuplicateModal } from '~/stores/modal';
 
 
 import type { ItemNode } from '../ItemNode';
 import type { ItemNode } from '../ItemNode';
 
 
-type SimpleItemToolPropsOptional = 'itemNode' | 'targetPathOrId' | 'isOpen' | 'itemRef' | 'itemClass' | 'mainClassName';
-
-export type SimpleItemToolProps = Omit<SimpleItemProps, SimpleItemToolPropsOptional> & {
-  page: IPageForItem,
-};
-
-export type SimpleItemProps = {
-  isEnableActions: boolean
-  isReadOnlyUser: boolean
-  itemNode: ItemNode
-  targetPathOrId?: Nullable<string>
-  isOpen?: boolean
-  onRenamed?(fromPath: string | undefined, toPath: string): void
-  onClickDuplicateMenuItem?(pageToDuplicate: IPageForPageDuplicateModal): void
-  onClickDeleteMenuItem?(pageToDelete: IPageToDeleteWithMeta): void
-  itemRef?
-  itemClass?: React.FunctionComponent<SimpleItemProps>
-  mainClassName?: string
-  customEndComponents?: Array<React.FunctionComponent<SimpleItemToolProps>>
-  customNextComponents?: Array<React.FunctionComponent<SimpleItemToolProps>>
-};
-
-export type SimpleItemContentProps = SimpleItemToolProps & {
-  page: IPageForItem,
-  children: ItemNode[],
-  stateHandlers: {
+type TreeItemBaseProps = {
+  itemNode: ItemNode,
+  isEnableActions: boolean,
+  isReadOnlyUser: boolean,
+  onRenamed?(fromPath: string | undefined, toPath: string): void,
+  onClickDuplicateMenuItem?(pageToDuplicate: IPageForPageDuplicateModal): void,
+  onClickDeleteMenuItem?(pageToDelete: IPageToDeleteWithMeta): void,
+  stateHandlers?: {
     isOpen: boolean,
     isOpen: boolean,
     setIsOpen: React.Dispatch<React.SetStateAction<boolean>>,
     setIsOpen: React.Dispatch<React.SetStateAction<boolean>>,
   },
   },
+}
+
+export type TreeItemToolProps = TreeItemBaseProps;
+
+export type TreeItemProps = TreeItemBaseProps & {
+  targetPathOrId?: Nullable<string>,
+  isOpen?: boolean,
+  itemClass?: React.FunctionComponent<TreeItemProps>,
+  mainClassName?: string,
+  customEndComponents?: Array<React.FunctionComponent<TreeItemToolProps>>,
+  customNextComponents?: Array<React.FunctionComponent<TreeItemToolProps>>,
 };
 };