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

+ 22 - 54
packages/app/src/components/Sidebar/PageTree/ItemsTree.tsx

@@ -3,72 +3,25 @@ import React, { FC } from 'react';
 import { IPage } from '../../../interfaces/page';
 import { ItemNode } from './ItemNode';
 import Item from './Item';
-
-/*
- * Mock data
- */
-const ancestors: (Partial<IPage> & {isTarget?: boolean})[] = [
-  {
-    path: '/',
-    isEmpty: false,
-    grant: 1,
-  },
-  {
-    path: '/A',
-    isEmpty: false,
-    grant: 1,
-  },
-  {
-    path: '/A/B',
-    isEmpty: false,
-    grant: 1,
-  },
-];
-
-/*
- * Mock data
- */
-const targetAndSiblings: (Partial<IPage> & {isTarget?: boolean})[] = [
-  {
-    path: '/A/B/C',
-    isEmpty: false,
-    grant: 1,
-    isTarget: true,
-  },
-  {
-    path: '/A/B/C2',
-    isEmpty: false,
-    grant: 1,
-  },
-  {
-    path: '/A/B/C3',
-    isEmpty: false,
-    grant: 1,
-  },
-  {
-    path: '/A/B/C4',
-    isEmpty: false,
-    grant: 1,
-  },
-];
+import { useSWRxPageSiblings, useSWRxPageAncestors } from '../../../stores/page-listing';
 
 
 /*
  * Utility to generate node tree and return the root node
  */
 const generateInitialTreeFromAncestors = (ancestors: Partial<IPage>[], siblings: Partial<IPage>[]): ItemNode => {
-  const rootPage = ancestors[0];
+  const rootPage = ancestors[ancestors.length - 1];
   if (rootPage?.path !== '/') throw Error('/ not exist in ancestors');
 
-  const ancestorNodes = ancestors.map((page, i, array): ItemNode => {
-    if (i === array.length - 1) {
+  const ancestorNodes = ancestors.map((page, i): ItemNode => {
+    if (i === 0) {
       const siblingNodes = siblings.map(page => new ItemNode(page));
       return new ItemNode(page, siblingNodes);
     }
     return new ItemNode(page, [], true);
   });
 
-  const rootNode = ancestorNodes.reverse().reduce((child, parent) => {
+  const rootNode = ancestorNodes.reduce((child, parent) => {
     parent.children = [child];
     return parent;
   });
@@ -80,8 +33,23 @@ const generateInitialTreeFromAncestors = (ancestors: Partial<IPage>[], siblings:
  * ItemsTree
  */
 const ItemsTree: FC = () => {
-  // TODO: fetch ancestors, siblings using swr
-  if (ancestors == null) return null;
+  // TODO: get from props
+  const path = '/Sandbox/Bootstrap4';
+  const id = '6181188ae38676152e464fc2';
+
+  const { data: ancestorsData, error: error1 } = useSWRxPageAncestors(path, id);
+  const { data: siblingsData, error: error2 } = useSWRxPageSiblings(path);
+
+  if (error1 != null || error2 != null) {
+    return null;
+  }
+
+  if (ancestorsData == null || siblingsData == null) {
+    return null;
+  }
+
+  const { ancestors } = ancestorsData;
+  const { targetAndSiblings } = siblingsData;
 
   // create node tree
   const rootNode = generateInitialTreeFromAncestors(ancestors, targetAndSiblings);

+ 10 - 0
packages/app/src/interfaces/page-listing-results.ts

@@ -0,0 +1,10 @@
+import { IPage } from './page';
+
+export interface SiblingsResult {
+  targetAndSiblings: Partial<IPage>[]
+}
+
+
+export interface AncestorsResult {
+  ancestors: Partial<IPage>[]
+}

+ 14 - 14
packages/app/src/server/routes/apiv3/page-listing.ts

@@ -23,8 +23,7 @@ interface AuthorizedRequest extends Request {
  * Validators
  */
 const validator = {
-  pageIdAndPathRequired: [
-    query('id').isMongoId().withMessage('id is required'),
+  pagePathRequired: [
     query('path').isString().withMessage('path is required'),
   ],
   pageIdOrPathRequired: oneOf([
@@ -46,20 +45,21 @@ export default (crowi: Crowi): Router => {
 
 
   // eslint-disable-next-line max-len
-  router.get('/siblings', accessTokenParser, loginRequiredStrictly, ...validator.pageIdAndPathRequired, apiV3FormValidator, async(req: AuthorizedRequest, res: ApiV3Response): Promise<any> => {
-    const { id, path } = req.query;
+  router.get('/siblings', accessTokenParser, loginRequiredStrictly, ...validator.pagePathRequired, apiV3FormValidator, async(req: AuthorizedRequest, res: ApiV3Response): Promise<any> => {
+    const { path } = req.query;
 
     const Page: PageModel = crowi.model('Page');
 
-    let siblings: PageDocument[];
-    let target: PageDocument;
+    let targetAndSiblings: PageDocument[];
     try {
-      siblings = await Page.findSiblingsByPathAndViewer(path as string, req.user);
-
-      target = siblings.filter(page => page._id.toString() === id)?.[0];
-      if (target == null) {
-        throw Error('Target must exist.');
-      }
+      targetAndSiblings = await Page.findSiblingsByPathAndViewer(path as string, req.user);
+
+      targetAndSiblings = targetAndSiblings.map((page) => {
+        if (page.path === path) {
+          Object.assign(page, { isTarget: true });
+        }
+        return page;
+      });
     }
     catch (err) {
       logger.error('Error occurred while finding pages.', err);
@@ -67,10 +67,10 @@ export default (crowi: Crowi): Router => {
     }
 
     if (isTopPage(path as string)) {
-      siblings = siblings.filter(page => !isTopPage(page.path));
+      targetAndSiblings = targetAndSiblings.filter(page => !isTopPage(page.path));
     }
 
-    return res.apiv3({ target, siblings });
+    return res.apiv3({ targetAndSiblings });
   });
 
   /*

+ 33 - 0
packages/app/src/stores/page-listing.tsx

@@ -0,0 +1,33 @@
+import useSWR, { SWRResponse } from 'swr';
+
+import { apiv3Get } from '../client/util/apiv3-client';
+import { SiblingsResult, AncestorsResult } from '../interfaces/page-listing-results';
+
+
+export const useSWRxPageSiblings = (
+    path: string,
+): SWRResponse<SiblingsResult, Error> => {
+  return useSWR(
+    `/page-listing/siblings?path=${path}`,
+    endpoint => apiv3Get(endpoint).then((response) => {
+      return {
+        targetAndSiblings: response.data.targetAndSiblings,
+      };
+    }),
+  );
+};
+
+
+export const useSWRxPageAncestors = (
+    path: string,
+    id: string,
+): SWRResponse<AncestorsResult, Error> => {
+  return useSWR(
+    `/page-listing/ancestors?path=${path}&id=${id}`,
+    endpoint => apiv3Get(endpoint).then((response) => {
+      return {
+        ancestors: response.data.ancestors,
+      };
+    }),
+  );
+};