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

+ 48 - 33
packages/app/src/components/Sidebar/PageTree/ItemsTree.tsx

@@ -1,16 +1,19 @@
 import React, { FC, useState } from 'react';
 import React, { FC, useState } from 'react';
+import { pagePathUtils } from '@growi/core';
 
 
 import { IPage } from '../../../interfaces/page';
 import { IPage } from '../../../interfaces/page';
 import { ItemNode } from './ItemNode';
 import { ItemNode } from './ItemNode';
 import Item from './Item';
 import Item from './Item';
 import { useSWRxPageAncestors, useSWRxPageAncestorsChildren } from '../../../stores/page-listing';
 import { useSWRxPageAncestors, useSWRxPageAncestorsChildren } from '../../../stores/page-listing';
 
 
+const { isTopPage } = pagePathUtils;
+
 /*
 /*
  * Utility to generate initial node and return
  * Utility to generate initial node and return
  */
  */
 const generateInitialNode = (targetAndAncestors: Partial<IPage>[]): ItemNode => {
 const generateInitialNode = (targetAndAncestors: Partial<IPage>[]): ItemNode => {
   const rootPage = targetAndAncestors[targetAndAncestors.length - 1]; // the last item is the root
   const rootPage = targetAndAncestors[targetAndAncestors.length - 1]; // the last item is the root
-  if (rootPage?.path !== '/') throw Error('/ not exist in ancestors');
+  if (!isTopPage(rootPage?.path as string)) throw Error('/ not exist in ancestors');
 
 
   const nodes = targetAndAncestors.map((page): ItemNode => {
   const nodes = targetAndAncestors.map((page): ItemNode => {
     return new ItemNode(page, []);
     return new ItemNode(page, []);
@@ -25,64 +28,76 @@ const generateInitialNode = (targetAndAncestors: Partial<IPage>[]): ItemNode =>
   return rootNode;
   return rootNode;
 };
 };
 
 
+const generateInitialNodeWithChildren = (ancestors: Partial<IPage>[], ancestorsChildren: Record<string, Partial<IPage>[]>): ItemNode => {
+  // create nodes
+  const nodes = ancestors.map((page): ItemNode => {
+    const children = ancestorsChildren[page.path as string].map(page => new ItemNode(page, []));
+    return new ItemNode(page, children);
+  });
+
+  // update children for each node
+  const rootNode = nodes.reduce((child, parent) => {
+    parent.children = [child];
+    return parent;
+  });
+
+  return rootNode;
+};
+
+// TODO: get from props
+const path = '/Sandbox/Bootstrap4';
+const id = '6181188ae38676152e464fc2';
+
 /*
 /*
  * ItemsTree
  * ItemsTree
  */
  */
 const ItemsTree: FC = () => {
 const ItemsTree: FC = () => {
-  // TODO: get from props
-  const path = '/Sandbox/Bootstrap4';
-  const id = '6181188ae38676152e464fc2';
-
   const [initialNode, setInitialNode] = useState<ItemNode | null>(null);
   const [initialNode, setInitialNode] = useState<ItemNode | null>(null);
 
 
-  // initial request
-  const { data: ancestorsData, error } = useSWRxPageAncestors(path, id);
-
+  // initial request this is important
+  const { data: ancestorsChildrenData, error } = useSWRxPageAncestorsChildren(path);
   // secondary request
   // secondary request
-  const { data: ancestorsChildrenData, error: error2 } = useSWRxPageAncestorsChildren(ancestorsData != null ? path : null);
+  const { data: ancestorsData, error: error2 } = useSWRxPageAncestors(path, id);
 
 
-  if (error != null || ancestorsData == null) {
+
+  if (error != null || error2 != null) {
     return null;
     return null;
   }
   }
 
 
-  const { targetAndAncestors } = ancestorsData;
-  const newInitialNode = generateInitialNode(targetAndAncestors);
-
-  if (error2 != null) {
+  if (ancestorsData == null) {
     return null;
     return null;
   }
   }
 
 
   /*
   /*
-   * when second SWR resolved
+   * When initial request is taking long
+   */
+  if (ancestorsChildrenData == null) {
+    const { targetAndAncestors } = ancestorsData;
+    const newInitialNode = generateInitialNode(targetAndAncestors);
+    setInitialNode(newInitialNode); // rerender
+  }
+
+  /*
+   * When initial request finishes
    */
    */
   if (ancestorsChildrenData != null) {
   if (ancestorsChildrenData != null) {
     // increment initialNode
     // increment initialNode
+    const { targetAndAncestors } = ancestorsData;
     const { ancestorsChildren } = ancestorsChildrenData;
     const { ancestorsChildren } = ancestorsChildrenData;
+    const ancestors = targetAndAncestors.filter(page => page.path !== path);
 
 
-    // flatten ancestors
-    const partialChildren: ItemNode[] = [];
-    let currentNode = newInitialNode;
-    while (currentNode.hasChildren() && currentNode?.children?.[0] != null) {
-      const child = currentNode.children[0];
-      partialChildren.push(child);
-      currentNode = child;
-    }
-
-    // update children
-    partialChildren.forEach((node) => {
-      const childPages = ancestorsChildren[node.page.path as string];
-      node.children = ItemNode.generateNodesFromPages(childPages);
-    });
+    const newInitialNode = generateInitialNodeWithChildren(ancestors, ancestorsChildren);
+    setInitialNode(newInitialNode); // rerender
   }
   }
 
 
-  setInitialNode(newInitialNode); // rerender
-
-  if (initialNode == null) return null;
+  if (initialNode == null) {
+    return null;
+  }
 
 
   const isOpen = true;
   const isOpen = true;
   return (
   return (
     <>
     <>
-      <Item key={initialNode.page.path} itemNode={initialNode} isOpen={isOpen} />
+      <Item key={(initialNode as ItemNode).page.path} itemNode={(initialNode as ItemNode)} isOpen={isOpen} />
     </>
     </>
   );
   );
 };
 };

+ 7 - 1
packages/app/src/server/models/page.ts

@@ -281,7 +281,13 @@ schema.statics.findAncestorsChildrenByPathAndViewer = async function(path: strin
   // get pages at once
   // get pages at once
   const queryBuilder = new PageQueryBuilder(this.find({ path: { $in: regexps } }));
   const queryBuilder = new PageQueryBuilder(this.find({ path: { $in: regexps } }));
   await addViewerCondition(queryBuilder, user, userGroups);
   await addViewerCondition(queryBuilder, user, userGroups);
-  const pages: PageDocument[] = await queryBuilder.query.lean().exec();
+  const _pages = await queryBuilder.query.lean().exec();
+  const pages = _pages.map((page: PageDocument & {isTarget?: boolean}) => {
+    if (page.path === path) {
+      page.isTarget = true;
+    }
+    return page;
+  });
 
 
   // make map
   // make map
   const pathToChildren: Record<string, PageDocument[]> = {};
   const pathToChildren: Record<string, PageDocument[]> = {};

+ 2 - 2
packages/app/src/stores/page-listing.tsx

@@ -5,10 +5,10 @@ import { TargetAndAncestorsResult, AncestorsChildrenResult } from '../interfaces
 
 
 
 
 export const useSWRxPageAncestorsChildren = (
 export const useSWRxPageAncestorsChildren = (
-    path: string | null,
+    path: string,
 ): SWRResponse<AncestorsChildrenResult, Error> => {
 ): SWRResponse<AncestorsChildrenResult, Error> => {
   return useSWR(
   return useSWR(
-    path ? `/page-listing/ancestors-children?path=${path}` : null,
+    `/page-listing/ancestors-children?path=${path}`,
     endpoint => apiv3Get(endpoint).then((response) => {
     endpoint => apiv3Get(endpoint).then((response) => {
       return {
       return {
         ancestorsChildren: response.data.ancestorsChildren,
         ancestorsChildren: response.data.ancestorsChildren,