Taichi Masuyama 4 лет назад
Родитель
Сommit
642c43a9d2

+ 9 - 3
packages/app/src/components/Sidebar/PageTree/Item.tsx

@@ -21,6 +21,7 @@ import { bookmark, unbookmark } from '~/client/services/page-operation';
 import ClosableTextInput, { AlertInfo, AlertType } from '../../Common/ClosableTextInput';
 import { PageItemControl } from '../../Common/Dropdown/PageItemControl';
 import { ItemNode } from './ItemNode';
+import { usePageTreeDescCountMap } from '~/stores/ui';
 
 interface ItemProps {
   isEnableActions: boolean
@@ -87,9 +88,14 @@ const Item: FC<ItemProps> = (props: ItemProps) => {
 
   const { data, mutate: mutateChildren } = useSWRxPageChildren(isOpen ? page._id : null);
 
+  // descendantCount
+  const { data: ptDescCountMap } = usePageTreeDescCountMap();
+  const descendantCount = ptDescCountMap?.get(page._id || '') || page.descendantCount || 0;
+
+
   // hasDescendants flag
   const isChildrenLoaded = currentChildren?.length > 0;
-  const hasDescendants = (page.descendantCount != null && page?.descendantCount > 0) || isChildrenLoaded;
+  const hasDescendants = descendantCount > 0 || isChildrenLoaded;
 
   // to re-show hidden item when useDrag end() callback
   const displayDroppedItemByPageId = useCallback((pageId) => {
@@ -391,9 +397,9 @@ const Item: FC<ItemProps> = (props: ItemProps) => {
           <p className={`text-truncate m-auto ${page.isEmpty && 'text-muted'}`}>{nodePath.basename(pageTitle as string) || '/'}</p>
         </a>
         {/* )} */}
-        {(page.descendantCount != null && page.descendantCount > 0) && (
+        {(descendantCount > 0) && (
           <div className="grw-pagetree-count-wrapper">
-            <ItemCount descendantCount={page.descendantCount} />
+            <ItemCount descendantCount={descendantCount} />
           </div>
         )}
         <div className="grw-pagetree-control d-flex">

+ 7 - 2
packages/app/src/components/Sidebar/PageTree/ItemsTree.tsx

@@ -18,6 +18,7 @@ import { useIsEnabledAttachTitleHeader } from '~/stores/context';
 import { useFullTextSearchTermManager } from '~/stores/search';
 import { useDescendantsPageListForCurrentPathTermManager } from '~/stores/page';
 import { useGlobalSocket } from '~/stores/websocket';
+import { usePageTreeDescCountMap } from '~/stores/ui';
 
 /*
  * Utility to generate initial node
@@ -127,6 +128,7 @@ const ItemsTree: FC<ItemsTreeProps> = (props: ItemsTreeProps) => {
   const [isScrolled, setIsScrolled] = useState(false);
 
   const { data: socket } = useGlobalSocket();
+  const { data: ptDescCountMap, mutate: mutatePtDescCountMap } = usePageTreeDescCountMap();
 
 
   // for mutation
@@ -154,9 +156,12 @@ const ItemsTree: FC<ItemsTreeProps> = (props: ItemsTreeProps) => {
     // socket
     socket.on(SocketEventName.UpdateDescCount, (data: UpdateDescCountRawData) => {
       // save to global state
-      const dataToSave: UpdateDescCountData = new Map(Object.entries(data));
+      const newData: UpdateDescCountData = new Map(Object.entries(data));
+      const oldData: UpdateDescCountData = ptDescCountMap || new Map();
+
+      mutatePtDescCountMap(new Map([...oldData, ...newData]));
     });
-  }, [socket]);
+  }, [socket, ptDescCountMap, mutatePtDescCountMap]);
 
   const onClickDuplicateMenuItem = (pageToDuplicate: IPageForPageDuplicateModal) => {
     openDuplicateModal(pageToDuplicate);

+ 1 - 1
packages/app/src/server/models/obsolete-page.js

@@ -330,7 +330,7 @@ export class PageQueryBuilder {
   }
 
   addConditionToMinimizeDataForRendering() {
-    this.query = this.query.select('_id path isEmpty grant revision');
+    this.query = this.query.select('_id path isEmpty grant revision, descendantCount');
 
     return this;
   }

+ 7 - 0
packages/app/src/stores/ui.tsx

@@ -17,6 +17,7 @@ import {
 } from './context';
 import { IFocusable } from '~/client/interfaces/focusable';
 import { Nullable } from '~/interfaces/common';
+import { UpdateDescCountData } from '~/interfaces/websocket';
 
 const { isSharedPage } = pagePathUtils;
 
@@ -333,3 +334,9 @@ export const useIsAbleToShowPageAuthors = (): SWRResponse<boolean, Error> => {
     () => isPageExist && !isUserPage,
   );
 };
+
+export const usePageTreeDescCountMap = (initialData?: UpdateDescCountData): SWRResponse<UpdateDescCountData, Error> => {
+  const key = 'pageTreeDescCountMap';
+
+  return useStaticSWR(key, initialData, { fallbackData: new Map() });
+};