Просмотр исходного кода

Merge pull request #7880 from weseek/imprv/routing-with-next-link

imprv: Routing with next link
Yuki Takei 2 лет назад
Родитель
Сommit
714316fd52

+ 0 - 166
apps/app/src/components/Admin/Common/AdminNavigation.jsx

@@ -1,166 +0,0 @@
-import React from 'react';
-
-import { pathUtils } from '@growi/core';
-import { useTranslation } from 'next-i18next';
-import Link from 'next/link';
-import PropTypes from 'prop-types';
-import urljoin from 'url-join';
-
-import { useGrowiCloudUri, useGrowiAppIdForGrowiCloud } from '../../../stores/context';
-// import AppContainer from '~/client/services/AppContainer';
-
-// import { withUnstatedContainers } from '../../UnstatedUtils';
-
-const AdminNavigation = (props) => {
-  const { t } = useTranslation(['admin', 'commons']);
-  // const { appContainer } = props;
-  const pathname = window.location.pathname;
-
-  const { data: growiCloudUri } = useGrowiCloudUri();
-  const { data: growiAppIdForGrowiCloud } = useGrowiAppIdForGrowiCloud();
-
-  // eslint-disable-next-line react/prop-types
-  const MenuLabel = ({ menu }) => {
-    switch (menu) {
-      /* eslint-disable no-multi-spaces, max-len */
-      case 'app':                      return <><i className="mr-1 icon-fw icon-settings"></i>{        t('headers.app_settings', { ns: 'commons' }) }</>;
-      case 'security':                 return <><i className="mr-1 icon-fw icon-shield"></i>{          t('security_settings.security_settings') }</>;
-      case 'markdown':                 return <><i className="mr-1 icon-fw icon-note"></i>{            t('markdown_settings.markdown_settings') }</>;
-      case 'customize':                return <><i className="mr-1 icon-fw icon-wrench"></i>{          t('customize_settings.customize_settings') }</>;
-      case 'importer':                 return <><i className="mr-1 icon-fw icon-cloud-upload"></i>{    t('importer_management.import_data') }</>;
-      case 'export':                   return <><i className="mr-1 icon-fw icon-cloud-download"></i>{  t('export_management.export_archive_data') }</>;
-      case 'data-transfer':            return <><i className="mr-1 icon-fw icon-plane"></i>{           t('g2g_data_transfer.data_transfer', { ns: 'commons' })}</>;
-      case 'notification':             return <><i className="mr-1 icon-fw icon-bell"></i>{            t('external_notification.external_notification')}</>;
-      case 'slack-integration':        return <><i className="mr-1 icon-fw icon-shuffle"></i>{         t('slack_integration.slack_integration') }</>;
-      case 'slack-integration-legacy': return <><i className="mr-1 icon-fw icon-shuffle"></i>{         t('slack_integration_legacy.slack_integration_legacy')}</>;
-      case 'users':                    return <><i className="mr-1 icon-fw icon-user"></i>{            t('user_management.user_management') }</>;
-      case 'user-groups':              return <><i className="mr-1 icon-fw icon-people"></i>{          t('user_group_management.user_group_management') }</>;
-      case 'audit-log':                return <><i className="mr-1 icon-fw icon-feed"></i>{            t('audit_log_management.audit_log')}</>;
-      case 'plugins':                  return <><i className="mr-1 icon-fw icon-puzzle"></i>{          t('plugins.plugins')}</>;
-      case 'search':                   return <><i className="mr-1 icon-fw icon-magnifier"></i>{       t('full_text_search_management.full_text_search_management') }</>;
-      case 'cloud':                    return <><i className="mr-1 icon-fw icon-share-alt"></i>{       t('cloud_setting_management.to_cloud_settings')} </>;
-      default:                         return <><i className="mr-1 icon-fw icon-home"></i>{            t('wiki_management_home_page') }</>;
-      /* eslint-enable no-multi-spaces, max-len */
-    }
-  };
-
-  const MenuLink = ({
-    // eslint-disable-next-line react/prop-types
-    menu, isRoot, isListGroupItems, isActive,
-  }) => {
-    const pageTransitionClassName = isListGroupItems
-      ? 'list-group-item list-group-item-action border-0 round-corner'
-      : 'dropdown-item px-3 py-2';
-
-    const href = isRoot ? '/admin' : urljoin('/admin', menu);
-
-    return (
-      <Link
-        href={href}
-        className={`${pageTransitionClassName} ${isActive ? 'active' : ''}`}
-      >
-        <MenuLabel menu={menu} />
-      </Link>
-    );
-  };
-
-  const isActiveMenu = (path) => {
-    const basisPath = pathUtils.normalizePath(urljoin('/admin', path));
-    const basisParentPath = pathUtils.addTrailingSlash(basisPath);
-
-    return (
-      pathname === basisPath
-      || pathname.startsWith(basisParentPath)
-    );
-  };
-
-  const getListGroupItemOrDropdownItemList = (isListGroupItems) => {
-    return (
-      <>
-        {/* eslint-disable no-multi-spaces */}
-        <MenuLink menu="home"         isListGroupItems isActive={pathname === '/admin'} isRoot />
-        <MenuLink menu="app"          isListGroupItems isActive={isActiveMenu('/app')} />
-        <MenuLink menu="security"     isListGroupItems isActive={isActiveMenu('/security')} />
-        <MenuLink menu="markdown"     isListGroupItems isActive={isActiveMenu('/markdown')} />
-        <MenuLink menu="customize"    isListGroupItems isActive={isActiveMenu('/customize')} />
-        <MenuLink menu="importer"     isListGroupItems isActive={isActiveMenu('/importer')} />
-        <MenuLink menu="export"       isListGroupItems isActive={isActiveMenu('/export')} />
-        <MenuLink menu="data-transfer" isListGroupItems isActive={isActiveMenu('/data-transfer')} />
-        <MenuLink menu="notification" isListGroupItems isActive={isActiveMenu('/notification') || isActiveMenu('/global-notification')} />
-        <MenuLink menu="slack-integration" isListGroupItems isActive={isActiveMenu('/slack-integration')} />
-        <MenuLink menu="slack-integration-legacy" isListGroupItems isActive={isActiveMenu('/slack-integration-legacy')} />
-        <MenuLink menu="users"        isListGroupItems isActive={isActiveMenu('/users')} />
-        <MenuLink menu="user-groups"  isListGroupItems isActive={isActiveMenu('/user-groups')} />
-        <MenuLink menu="audit-log"    isListGroupItems isActive={isActiveMenu('/audit-log')} />
-        <MenuLink menu="plugins"      isListGroupItems isActive={isActiveMenu('/plugins')} />
-        <MenuLink menu="search"       isListGroupItems isActive={isActiveMenu('/search')} />
-        {growiCloudUri != null && growiAppIdForGrowiCloud != null
-          && (
-            <a
-              href={`${growiCloudUri}/my/apps/${growiAppIdForGrowiCloud}`}
-              className="list-group-item list-group-item-action border-0 round-corner"
-            >
-              <MenuLabel menu="cloud" />
-            </a>
-          )
-        }
-        {/* eslint-enable no-multi-spaces */}
-      </>
-    );
-  };
-
-  return (
-    <React.Fragment>
-      {/* List group */}
-      <div className="list-group admin-navigation sticky-top d-none d-lg-block">
-        {getListGroupItemOrDropdownItemList(true)}
-      </div>
-
-      {/* Dropdown */}
-      <div className="dropdown d-block d-lg-none mb-5">
-        <button
-          className="btn btn-outline-primary btn-lg dropdown-toggle col-12 text-right"
-          type="button"
-          id="dropdown-admin-navigation"
-          data-display="static"
-          data-toggle="dropdown"
-          aria-haspopup="true"
-          aria-expanded="false"
-        >
-          <span className="float-left">
-            {/* eslint-disable no-multi-spaces */}
-            {pathname === '/admin' &&              <MenuLabel menu="home" />}
-            {isActiveMenu('/app') &&               <MenuLabel menu="app" />}
-            {isActiveMenu('/security') &&          <MenuLabel menu="security" />}
-            {isActiveMenu('/markdown') &&          <MenuLabel menu="markdown" />}
-            {isActiveMenu('/customize') &&         <MenuLabel menu="customize" />}
-            {isActiveMenu('/importer') &&          <MenuLabel menu="importer" />}
-            {isActiveMenu('/export') &&            <MenuLabel menu="export" />}
-            {(isActiveMenu('/notification') || isActiveMenu('/global-notification')) && <MenuLabel menu="notification" />}
-            {isActiveMenu('/slack-integration') && <MenuLabel menu="slack-integration" />}
-            {isActiveMenu('/users') &&             <MenuLabel menu="users" />}
-            {isActiveMenu('/user-groups') &&       <MenuLabel menu="user-groups" />}
-            {isActiveMenu('/search') &&            <MenuLabel menu="search" />}
-            {isActiveMenu('/audit-log') &&         <MenuLabel menu="audit-log" />}
-            {isActiveMenu('/plugins') &&           <MenuLabel menu="plugins" />}
-            {isActiveMenu('/data-transfer') &&     <MenuLabel menu="data-transfer" />}
-            {/* eslint-enable no-multi-spaces */}
-          </span>
-        </button>
-        <div className="dropdown-menu" aria-labelledby="dropdown-admin-navigation">
-          {getListGroupItemOrDropdownItemList(false)}
-        </div>
-      </div>
-
-    </React.Fragment>
-  );
-};
-
-// const AdminNavigationWrapper = withUnstatedContainers(AdminNavigation, [AppContainer]);
-
-AdminNavigation.propTypes = {
-  // appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-};
-
-// export default AdminNavigationWrapper;
-export default AdminNavigation;

+ 167 - 0
apps/app/src/components/Admin/Common/AdminNavigation.tsx

@@ -0,0 +1,167 @@
+import React, { useCallback } from 'react';
+
+import { pathUtils } from '@growi/core';
+import { useTranslation } from 'next-i18next';
+import Link from 'next/link';
+import urljoin from 'url-join';
+
+import { useGrowiCloudUri, useGrowiAppIdForGrowiCloud } from '../../../stores/context';
+
+// eslint-disable-next-line react/prop-types
+const MenuLabel = ({ menu }: { menu: string }) => {
+  const { t } = useTranslation(['admin', 'commons']);
+
+  switch (menu) {
+    /* eslint-disable no-multi-spaces, max-len */
+    case 'app':                      return <><i className="mr-1 icon-fw icon-settings"></i>{        t('headers.app_settings', { ns: 'commons' }) }</>;
+    case 'security':                 return <><i className="mr-1 icon-fw icon-shield"></i>{          t('security_settings.security_settings') }</>;
+    case 'markdown':                 return <><i className="mr-1 icon-fw icon-note"></i>{            t('markdown_settings.markdown_settings') }</>;
+    case 'customize':                return <><i className="mr-1 icon-fw icon-wrench"></i>{          t('customize_settings.customize_settings') }</>;
+    case 'importer':                 return <><i className="mr-1 icon-fw icon-cloud-upload"></i>{    t('importer_management.import_data') }</>;
+    case 'export':                   return <><i className="mr-1 icon-fw icon-cloud-download"></i>{  t('export_management.export_archive_data') }</>;
+    case 'data-transfer':            return <><i className="mr-1 icon-fw icon-plane"></i>{           t('g2g_data_transfer.data_transfer', { ns: 'commons' })}</>;
+    case 'notification':             return <><i className="mr-1 icon-fw icon-bell"></i>{            t('external_notification.external_notification')}</>;
+    case 'slack-integration':        return <><i className="mr-1 icon-fw icon-shuffle"></i>{         t('slack_integration.slack_integration') }</>;
+    case 'slack-integration-legacy': return <><i className="mr-1 icon-fw icon-shuffle"></i>{         t('slack_integration_legacy.slack_integration_legacy')}</>;
+    case 'users':                    return <><i className="mr-1 icon-fw icon-user"></i>{            t('user_management.user_management') }</>;
+    case 'user-groups':              return <><i className="mr-1 icon-fw icon-people"></i>{          t('user_group_management.user_group_management') }</>;
+    case 'audit-log':                return <><i className="mr-1 icon-fw icon-feed"></i>{            t('audit_log_management.audit_log')}</>;
+    case 'plugins':                  return <><i className="mr-1 icon-fw icon-puzzle"></i>{          t('plugins.plugins')}</>;
+    case 'search':                   return <><i className="mr-1 icon-fw icon-magnifier"></i>{       t('full_text_search_management.full_text_search_management') }</>;
+    case 'cloud':                    return <><i className="mr-1 icon-fw icon-share-alt"></i>{       t('cloud_setting_management.to_cloud_settings')} </>;
+    default:                         return <><i className="mr-1 icon-fw icon-home"></i>{            t('wiki_management_home_page') }</>;
+      /* eslint-enable no-multi-spaces, max-len */
+  }
+};
+
+type MenuLinkProps = {
+  menu: string,
+  isListGroupItems: boolean,
+  isRoot?: boolean,
+  isActive?: boolean,
+}
+
+const MenuLink = ({
+  menu, isRoot, isListGroupItems, isActive,
+}: MenuLinkProps) => {
+
+  const pageTransitionClassName = isListGroupItems
+    ? 'list-group-item list-group-item-action border-0 round-corner'
+    : 'dropdown-item px-3 py-2';
+
+  const href = isRoot ? '/admin' : urljoin('/admin', menu);
+
+  return (
+    <Link
+      href={href}
+      className={`${pageTransitionClassName} ${isActive ? 'active' : ''}`}
+    >
+      <MenuLabel menu={menu} />
+    </Link>
+  );
+};
+
+export const AdminNavigation = (): JSX.Element => {
+  const pathname = window.location.pathname;
+
+  const { data: growiCloudUri } = useGrowiCloudUri();
+  const { data: growiAppIdForGrowiCloud } = useGrowiAppIdForGrowiCloud();
+
+  const isActiveMenu = useCallback((path: string | string[]) => {
+    const paths = Array.isArray(path) ? path : [path];
+
+    return paths.some((path) => {
+      const basisPath = pathUtils.normalizePath(urljoin('/admin', path));
+      const basisParentPath = pathUtils.addTrailingSlash(basisPath);
+
+      return (
+        pathname === basisPath
+        || pathname.startsWith(basisParentPath)
+      );
+    });
+
+  }, [pathname]);
+
+  const getListGroupItemOrDropdownItemList = (isListGroupItems: boolean) => {
+    return (
+      <>
+        {/* eslint-disable no-multi-spaces */}
+        <MenuLink menu="home"                       isListGroupItems={isListGroupItems} isActive={pathname === '/admin'} isRoot />
+        <MenuLink menu="app"                        isListGroupItems={isListGroupItems} isActive={isActiveMenu('/app')} />
+        <MenuLink menu="security"                   isListGroupItems={isListGroupItems} isActive={isActiveMenu('/security')} />
+        <MenuLink menu="markdown"                   isListGroupItems={isListGroupItems} isActive={isActiveMenu('/markdown')} />
+        <MenuLink menu="customize"                  isListGroupItems={isListGroupItems} isActive={isActiveMenu('/customize')} />
+        <MenuLink menu="importer"                   isListGroupItems={isListGroupItems} isActive={isActiveMenu('/importer')} />
+        <MenuLink menu="export"                     isListGroupItems={isListGroupItems} isActive={isActiveMenu('/export')} />
+        <MenuLink menu="data-transfer"              isListGroupItems={isListGroupItems} isActive={isActiveMenu('/data-transfer')} />
+        <MenuLink menu="notification"               isListGroupItems={isListGroupItems} isActive={isActiveMenu(['/notification', '/global-notification'])} />
+        <MenuLink menu="slack-integration"          isListGroupItems={isListGroupItems} isActive={isActiveMenu('/slack-integration')} />
+        <MenuLink menu="slack-integration-legacy"   isListGroupItems={isListGroupItems} isActive={isActiveMenu('/slack-integration-legacy')} />
+        <MenuLink menu="users"                      isListGroupItems={isListGroupItems} isActive={isActiveMenu('/users')} />
+        <MenuLink menu="user-groups"                isListGroupItems={isListGroupItems} isActive={isActiveMenu(['/user-groups', 'user-group-detail'])} />
+        <MenuLink menu="audit-log"                  isListGroupItems={isListGroupItems} isActive={isActiveMenu('/audit-log')} />
+        <MenuLink menu="plugins"                    isListGroupItems={isListGroupItems} isActive={isActiveMenu('/plugins')} />
+        <MenuLink menu="search"                     isListGroupItems={isListGroupItems} isActive={isActiveMenu('/search')} />
+        {growiCloudUri != null && growiAppIdForGrowiCloud != null
+          && (
+            <a
+              href={`${growiCloudUri}/my/apps/${growiAppIdForGrowiCloud}`}
+              className="list-group-item list-group-item-action border-0 round-corner"
+            >
+              <MenuLabel menu="cloud" />
+            </a>
+          )
+        }
+        {/* eslint-enable no-multi-spaces */}
+      </>
+    );
+  };
+
+  return (
+    <React.Fragment>
+      {/* List group */}
+      <div className="list-group admin-navigation sticky-top d-none d-lg-block">
+        {getListGroupItemOrDropdownItemList(true)}
+      </div>
+
+      {/* Dropdown */}
+      <div className="dropdown d-block d-lg-none mb-5">
+        <button
+          className="btn btn-outline-primary btn-lg dropdown-toggle col-12 text-right"
+          type="button"
+          id="dropdown-admin-navigation"
+          data-display="static"
+          data-toggle="dropdown"
+          aria-haspopup="true"
+          aria-expanded="false"
+        >
+          <span className="float-left">
+            {/* eslint-disable no-multi-spaces */}
+            {pathname === '/admin'                  && <MenuLabel menu="home" />}
+            {isActiveMenu('/app')                   && <MenuLabel menu="app" />}
+            {isActiveMenu('/security')              && <MenuLabel menu="security" />}
+            {isActiveMenu('/markdown')              && <MenuLabel menu="markdown" />}
+            {isActiveMenu('/customize')             && <MenuLabel menu="customize" />}
+            {isActiveMenu('/importer')              && <MenuLabel menu="importer" />}
+            {isActiveMenu('/export')                && <MenuLabel menu="export" />}
+            {(isActiveMenu(['/notification', '/global-notification']))
+                                                    && <MenuLabel menu="notification" />}
+            {isActiveMenu('/slack-integration')     && <MenuLabel menu="slack-integration" />}
+            {isActiveMenu('/users')                 && <MenuLabel menu="users" />}
+            {isActiveMenu(['/user-groups', 'user-group-detail'])
+                                                    && <MenuLabel menu="user-groups" />}
+            {isActiveMenu('/search')                && <MenuLabel menu="search" />}
+            {isActiveMenu('/audit-log')             && <MenuLabel menu="audit-log" />}
+            {isActiveMenu('/plugins')               && <MenuLabel menu="plugins" />}
+            {isActiveMenu('/data-transfer')         && <MenuLabel menu="data-transfer" />}
+            {/* eslint-enable no-multi-spaces */}
+          </span>
+        </button>
+        <div className="dropdown-menu" aria-labelledby="dropdown-admin-navigation">
+          {getListGroupItemOrDropdownItemList(false)}
+        </div>
+      </div>
+
+    </React.Fragment>
+  );
+};

+ 3 - 2
apps/app/src/components/Admin/Notification/ManageGlobalNotification.tsx

@@ -3,6 +3,7 @@ import React, {
 } from 'react';
 
 import { useTranslation } from 'next-i18next';
+import Link from 'next/link';
 import { useRouter } from 'next/router';
 
 import { NotifyType, TriggerEventType } from '~/client/interfaces/global-notification';
@@ -111,10 +112,10 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
   return (
     <>
       <div className="my-3">
-        <a href="/admin/notification#global-notification" className="btn btn-outline-secondary">
+        <Link href="/admin/notification" className="btn btn-outline-secondary">
           <i className="icon-fw ti ti-arrow-left" aria-hidden="true"></i>
           {t('notification_settings.back_to_list')}
-        </a>
+        </Link>
       </div>
 
 

+ 3 - 2
apps/app/src/components/Admin/UserGroup/UserGroupTable.tsx

@@ -5,6 +5,7 @@ import React, {
 import type { IUserGroupHasId, IUserGroupRelation, IUserHasId } from '@growi/core';
 import dateFnsFormat from 'date-fns/format';
 import { useTranslation } from 'next-i18next';
+import Link from 'next/link';
 
 
 type Props = {
@@ -147,7 +148,7 @@ export const UserGroupTable: FC<Props> = (props: Props) => {
               <tr key={group._id}>
                 {props.isAclEnabled
                   ? (
-                    <td><a href={`/admin/user-group-detail/${group._id}`}>{group.name}</a></td>
+                    <td><Link href={`/admin/user-group-detail/${group._id}`}>{group.name}</Link></td>
                   )
                   : (
                     <td>{group.name}</td>
@@ -168,7 +169,7 @@ export const UserGroupTable: FC<Props> = (props: Props) => {
                         <li key={group._id} className="list-inline-item badge badge-success">
                           {props.isAclEnabled
                             ? (
-                              <a href={`/admin/user-group-detail/${group._id}`}>{group.name}</a>
+                              <Link href={`/admin/user-group-detail/${group._id}`}>{group.name}</Link>
                             )
                             : (
                               <p>{group.name}</p>

+ 2 - 2
apps/app/src/components/Admin/UserGroupDetail/UserGroupDetailPage.tsx

@@ -334,7 +334,7 @@ const UserGroupDetailPage = (props: Props): JSX.Element => {
       <nav aria-label="breadcrumb">
         <ol className="breadcrumb">
           <li className="breadcrumb-item">
-            <Link href="/admin/user-groups" prefetch={false}>
+            <Link href="/admin/user-groups">
               {t('user_group_management.group_list')}
             </Link>
           </li>
@@ -348,7 +348,7 @@ const UserGroupDetailPage = (props: Props): JSX.Element => {
                 { ancestorUserGroup._id === currentUserGroupId ? (
                   <span>{ancestorUserGroup.name}</span>
                 ) : (
-                  <Link href={`/admin/user-group-detail/${ancestorUserGroup._id}`} prefetch={false}>
+                  <Link href={`/admin/user-group-detail/${ancestorUserGroup._id}`}>
                     {ancestorUserGroup.name}
                   </Link>
                 ) }

+ 6 - 2
apps/app/src/components/Admin/UserGroupDetail/UserGroupPageList.tsx

@@ -49,8 +49,12 @@ const UserGroupPageList = (props: Props): JSX.Element => {
 
   return (
     <>
-      <ul className="page-list-ul page-list-ul-flat mb-3">
-        {currentPages.map(page => <li key={page._id}><PageListItemS page={page} /></li>)}
+      <ul className="page-list-ul page-list-ul-flat mt-3 mb-3">
+        { currentPages.map(page => (
+          <li key={page._id} className="mt-2">
+            <PageListItemS page={page} />
+          </li>
+        )) }
       </ul>
       {relatedPages != null && relatedPages.length === 0 ? <p>{t('user_group_management.no_pages')}</p> : (
         <PaginationWrapper

+ 11 - 9
apps/app/src/components/Bookmarks/BookmarkItem.tsx

@@ -151,15 +151,17 @@ export const BookmarkItem = (props: Props): JSX.Element => {
         id={bookmarkItemId}
         style={{ paddingLeft }}
       >
-        {isRenameInputShown ? (
-          <ClosableTextInput
-            value={nodePath.basename(bookmarkedPage.path ?? '')}
-            placeholder={t('Input page name')}
-            onClickOutside={() => { setRenameInputShown(false) }}
-            onPressEnter={pressEnterForRenameHandler}
-            validationTarget={ValidationTarget.PAGE}
-          />
-        ) : <PageListItemS page={bookmarkedPage} pageTitle={pageTitle} />}
+        { isRenameInputShown
+          ? (
+            <ClosableTextInput
+              value={nodePath.basename(bookmarkedPage.path ?? '')}
+              placeholder={t('Input page name')}
+              onClickOutside={() => { setRenameInputShown(false) }}
+              onPressEnter={pressEnterForRenameHandler}
+              validationTarget={ValidationTarget.PAGE}
+            />
+          )
+          : <PageListItemS page={bookmarkedPage} pageTitle={pageTitle} />}
 
         <div className='grw-foldertree-control'>
           <PageItemControl

+ 1 - 1
apps/app/src/components/Layout/AdminLayout.tsx

@@ -2,6 +2,7 @@ import React, { ReactNode } from 'react';
 
 import dynamic from 'next/dynamic';
 
+import { AdminNavigation } from '../Admin/Common/AdminNavigation';
 import { GrowiNavbar } from '../Navbar/GrowiNavbar';
 
 import { RawLayout } from './RawLayout';
@@ -9,7 +10,6 @@ import { RawLayout } from './RawLayout';
 import styles from './Admin.module.scss';
 
 
-const AdminNavigation = dynamic(() => import('~/components/Admin/Common/AdminNavigation'), { ssr: false });
 const PageCreateModal = dynamic(() => import('../PageCreateModal'), { ssr: false });
 const SystemVersion = dynamic(() => import('../SystemVersion'), { ssr: false });
 const HotkeysManager = dynamic(() => import('../Hotkeys/HotkeysManager'), { ssr: false });

+ 6 - 3
apps/app/src/components/PageList/PageListItemS.tsx

@@ -3,6 +3,7 @@ import React from 'react';
 import { PageListMeta } from '@growi/ui/dist/components/PagePath/PageListMeta';
 import { PagePathLabel } from '@growi/ui/dist/components/PagePath/PagePathLabel';
 import { UserPicture } from '@growi/ui/dist/components/User/UserPicture';
+import Link from 'next/link';
 
 import { IPageHasId } from '~/interfaces/page';
 
@@ -10,18 +11,20 @@ import { IPageHasId } from '~/interfaces/page';
 type PageListItemSProps = {
   page: IPageHasId,
   noLink?: boolean,
-  pageTitle?: string
+  pageTitle?: string,
 }
 
 export const PageListItemS = (props: PageListItemSProps): JSX.Element => {
 
-  const { page, noLink = false, pageTitle } = props;
+  const {
+    page, noLink = false, pageTitle,
+  } = props;
 
   const path = pageTitle != null ? pageTitle : page.path;
 
   let pagePathElement = <PagePathLabel path={path} additionalClassNames={['mx-1']} />;
   if (!noLink) {
-    pagePathElement = <a className="text-break" href={page.path}>{pagePathElement}</a>;
+    pagePathElement = <Link href={`/${page._id}`} className="text-break" prefetch={false}>{pagePathElement}</Link>;
   }
 
   return (