Yuki Takei vor 2 Jahren
Ursprung
Commit
d383cc0e77

+ 8 - 6
packages/remark-lsx/src/components/Lsx.tsx

@@ -1,7 +1,8 @@
 import React, { useCallback, useMemo } from 'react';
 
 
-import { useSWRxNodeTree } from '../stores/lsx';
+import { useSWRxLsx } from '../stores/lsx';
+import { generatePageNodeTree } from '../utils/page-node';
 
 import { LsxListView } from './LsxPageList/LsxListView';
 import { LsxContext } from './lsx-context';
@@ -37,9 +38,8 @@ const LsxSubstance = React.memo(({
     return new LsxContext(prefix, options);
   }, [depth, filter, num, prefix, reverse, sort, except]);
 
-  const { data, error, isLoading: _isLoading } = useSWRxNodeTree(lsxContext, isImmutable);
+  const { data, error, isLoading } = useSWRxLsx(lsxContext, isImmutable);
 
-  const isLoading = _isLoading || data === undefined;
   const hasError = error != null;
   const errorMessage = error?.message;
 
@@ -77,12 +77,14 @@ const LsxSubstance = React.memo(({
   }, [hasError, isLoading, lsxContext]);
 
   const contents = useMemo(() => {
-    if (isLoading) {
+    if (data == null) {
       return <></>;
     }
 
-    return <LsxListView nodeTree={data.nodeTree} lsxContext={lsxContext} basisViewersCount={data.toppageViewersCount} />;
-  }, [data?.nodeTree, data?.toppageViewersCount, isLoading, lsxContext]);
+    const nodeTree = generatePageNodeTree(prefix, data.pages);
+
+    return <LsxListView nodeTree={nodeTree} lsxContext={lsxContext} basisViewersCount={data.toppageViewersCount} />;
+  }, [data, lsxContext, prefix]);
 
   return (
     <div className={`lsx ${styles.lsx}`}>

+ 4 - 1
packages/remark-lsx/src/server/routes/list-pages/index.ts

@@ -111,6 +111,9 @@ export const listPages = async(req: Request & { user: IUser }, res: Response): P
     if (options?.except != null) {
       query = addExceptCondition(query, pagePath, options.except);
     }
+
+    const total = await query.clone().count();
+
     // num
     const optionsNum = options?.num || DEFAULT_PAGES_NUM;
     query = addNumCondition(query, optionsNum);
@@ -118,7 +121,7 @@ export const listPages = async(req: Request & { user: IUser }, res: Response): P
     query = addSortCondition(query, options?.sort, options?.reverse);
 
     const pages = await query.exec();
-    return res.status(200).send({ pages, toppageViewersCount });
+    return res.status(200).send({ pages, total, toppageViewersCount });
   }
   catch (error) {
     if (isHttpError(error)) {

+ 5 - 120
packages/remark-lsx/src/stores/lsx.tsx

@@ -1,103 +1,18 @@
-import * as url from 'url';
-
-import { IPageHasId, pathUtils } from '@growi/core';
+import type { IPageHasId } from '@growi/core';
 import axios from 'axios';
 import useSWR, { SWRResponse } from 'swr';
 
 import { LsxContext } from '../components/lsx-context';
-import type { PageNode } from '../interfaces/page-node';
-
-function isEquals(path1: string, path2: string) {
-  return pathUtils.removeTrailingSlash(path1) === pathUtils.removeTrailingSlash(path2);
-}
-
-function getParentPath(path: string) {
-  return pathUtils.addTrailingSlash(decodeURIComponent(url.resolve(path, '../')));
-}
-
-/**
- * generate PageNode instances for target page and the ancestors
- *
- * @param {any} pathToNodeMap
- * @param {any} rootPagePath
- * @param {any} pagePath
- * @returns
- * @memberof Lsx
- */
-function generatePageNode(pathToNodeMap: Record<string, PageNode>, rootPagePath: string, pagePath: string): PageNode | null {
-  // exclude rootPagePath itself
-  if (isEquals(pagePath, rootPagePath)) {
-    return null;
-  }
-
-  // return when already registered
-  if (pathToNodeMap[pagePath] != null) {
-    return pathToNodeMap[pagePath];
-  }
-
-  // generate node
-  const node = { pagePath, children: [] };
-  pathToNodeMap[pagePath] = node;
-
-  /*
-    * process recursively for ancestors
-    */
-  // get or create parent node
-  const parentPath = getParentPath(pagePath);
-  const parentNode = generatePageNode(pathToNodeMap, rootPagePath, parentPath);
-  // associate to patent
-  if (parentNode != null) {
-    parentNode.children.push(node);
-  }
-
-  return node;
-}
-
-function generatePageNodeTree(rootPagePath: string, pages: IPageHasId[]) {
-  const pathToNodeMap: Record<string, PageNode> = {};
-
-  pages.forEach((page) => {
-    // add slash ensure not to forward match to another page
-    // e.g. '/Java/' not to match to '/JavaScript'
-    const pagePath = pathUtils.addTrailingSlash(page.path);
-
-    const node = generatePageNode(pathToNodeMap, rootPagePath, pagePath); // this will not be null
-
-    // exclude rootPagePath itself
-    if (node == null) {
-      return;
-    }
-
-    // set the Page substance
-    node.page = page;
-  });
-
-  // return root objects
-  const rootNodes: PageNode[] = [];
-  Object.keys(pathToNodeMap).forEach((pagePath) => {
-    // exclude '/'
-    if (pagePath === '/') {
-      return;
-    }
-
-    const parentPath = getParentPath(pagePath);
-
-    // pick up what parent doesn't exist
-    if ((parentPath === '/') || !(parentPath in pathToNodeMap)) {
-      rootNodes.push(pathToNodeMap[pagePath]);
-    }
-  });
-  return rootNodes;
-}
 
 type LsxResponse = {
   pages: IPageHasId[],
+  total: number,
   toppageViewersCount: number,
 }
 
-const useSWRxLsxResponse = (
-    pagePath: string, options?: Record<string, string | undefined>, isImmutable?: boolean,
-): SWRResponse<LsxResponse, Error> => {
+export const useSWRxLsx = (lsxContext: LsxContext, isImmutable?: boolean): SWRResponse<LsxResponse, Error> => {
+  const { pagePath, options } = lsxContext;
+
   return useSWR(
     ['/_api/lsx', pagePath, options, isImmutable],
     async([endpoint, pagePath, options]) => {
@@ -125,33 +40,3 @@ const useSWRxLsxResponse = (
     },
   );
 };
-
-type LsxNodeTree = {
-  nodeTree: PageNode[],
-  toppageViewersCount: number,
-}
-
-export const useSWRxNodeTree = (lsxContext: LsxContext, isImmutable?: boolean): SWRResponse<LsxNodeTree, Error> => {
-  const {
-    data, error, isLoading, isValidating,
-  } = useSWRxLsxResponse(lsxContext.pagePath, lsxContext.options, isImmutable);
-
-  return useSWR(
-    !isLoading && !isValidating ? ['lsxNodeTree', lsxContext.pagePath, lsxContext.options, isImmutable, data, error] : null,
-    ([, pagePath, , , data]) => {
-      if (data === undefined || error != null) {
-        throw error;
-      }
-      return {
-        nodeTree: generatePageNodeTree(pagePath, data?.pages),
-        toppageViewersCount: data.toppageViewersCount,
-      };
-    },
-    {
-      keepPreviousData: true,
-      revalidateIfStale: !isImmutable,
-      revalidateOnFocus: !isImmutable,
-      revalidateOnReconnect: !isImmutable,
-    },
-  );
-};

+ 88 - 0
packages/remark-lsx/src/utils/page-node.ts

@@ -0,0 +1,88 @@
+import * as url from 'url';
+
+import { IPageHasId, pathUtils } from '@growi/core';
+
+import type { PageNode } from '../interfaces/page-node';
+
+function isEquals(path1: string, path2: string) {
+  return pathUtils.removeTrailingSlash(path1) === pathUtils.removeTrailingSlash(path2);
+}
+
+function getParentPath(path: string) {
+  return pathUtils.addTrailingSlash(decodeURIComponent(url.resolve(path, '../')));
+}
+
+/**
+ * generate PageNode instances for target page and the ancestors
+ *
+ * @param {any} pathToNodeMap
+ * @param {any} rootPagePath
+ * @param {any} pagePath
+ * @returns
+ * @memberof Lsx
+ */
+function generatePageNode(pathToNodeMap: Record<string, PageNode>, rootPagePath: string, pagePath: string): PageNode | null {
+  // exclude rootPagePath itself
+  if (isEquals(pagePath, rootPagePath)) {
+    return null;
+  }
+
+  // return when already registered
+  if (pathToNodeMap[pagePath] != null) {
+    return pathToNodeMap[pagePath];
+  }
+
+  // generate node
+  const node = { pagePath, children: [] };
+  pathToNodeMap[pagePath] = node;
+
+  /*
+    * process recursively for ancestors
+    */
+  // get or create parent node
+  const parentPath = getParentPath(pagePath);
+  const parentNode = generatePageNode(pathToNodeMap, rootPagePath, parentPath);
+  // associate to patent
+  if (parentNode != null) {
+    parentNode.children.push(node);
+  }
+
+  return node;
+}
+
+export function generatePageNodeTree(rootPagePath: string, pages: IPageHasId[]): PageNode[] {
+  const pathToNodeMap: Record<string, PageNode> = {};
+
+  pages.forEach((page) => {
+    // add slash ensure not to forward match to another page
+    // e.g. '/Java/' not to match to '/JavaScript'
+    const pagePath = pathUtils.addTrailingSlash(page.path);
+
+    const node = generatePageNode(pathToNodeMap, rootPagePath, pagePath); // this will not be null
+
+    // exclude rootPagePath itself
+    if (node == null) {
+      return;
+    }
+
+    // set the Page substance
+    node.page = page;
+  });
+
+  // return root objects
+  const rootNodes: PageNode[] = [];
+  Object.keys(pathToNodeMap).forEach((pagePath) => {
+    // exclude '/'
+    if (pagePath === '/') {
+      return;
+    }
+
+    const parentPath = getParentPath(pagePath);
+
+    // pick up what parent doesn't exist
+    if ((parentPath === '/') || !(parentPath in pathToNodeMap)) {
+      rootNodes.push(pathToNodeMap[pagePath]);
+    }
+  });
+  return rootNodes;
+}