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

Merge pull request #6209 from weseek/imprv/render-tag-index-page-use-nextjs

Feat: Render tags page using Nextjs
Yuki Takei 3 лет назад
Родитель
Сommit
67a948e207

+ 0 - 2
packages/app/_obsolete/src/client/app.jsx

@@ -39,7 +39,6 @@ import { PageTimeline } from '../components/PageTimeline';
 import RecentCreated from '../components/RecentCreated/RecentCreated';
 import { SearchPage } from '../components/SearchPage';
 import Sidebar from '../components/Sidebar';
-import TagPage from '../components/TagPage';
 import TrashPageList from '../components/TrashPageList';
 
 import { appContainer, componentMappings } from './base';
@@ -75,7 +74,6 @@ Object.assign(componentMappings, {
   'identical-path-page': <IdenticalPathPage />,
 
   // 'revision-history': <PageHistory pageId={pageId} />,
-  'tags-page': <TagPage />,
 
   'grw-page-status-alert-container': <PageStatusAlert />,
 

+ 0 - 59
packages/app/src/components/TagPage.tsx

@@ -1,59 +0,0 @@
-import React, { FC, useState, useCallback } from 'react';
-
-import { useTranslation } from 'next-i18next';
-
-import { IDataTagCount } from '~/interfaces/tag';
-import { useSWRxTagsList } from '~/stores/tag';
-
-import TagCloudBox from './TagCloudBox';
-import TagList from './TagList';
-
-const PAGING_LIMIT = 10;
-
-const TagPage: FC = () => {
-  const [activePage, setActivePage] = useState<number>(1);
-  const [offset, setOffset] = useState<number>(0);
-
-  const { data: tagDataList, error } = useSWRxTagsList(PAGING_LIMIT, offset);
-  const tagData: IDataTagCount[] = tagDataList?.data || [];
-  const totalCount: number = tagDataList?.totalCount || 0;
-  const isLoading = tagDataList === undefined && error == null;
-
-  const { t } = useTranslation('');
-
-  const setOffsetByPageNumber = useCallback((selectedPageNumber: number) => {
-    setActivePage(selectedPageNumber);
-    setOffset((selectedPageNumber - 1) * PAGING_LIMIT);
-  }, []);
-
-  // todo: adjust margin and redesign tags page
-  return (
-    <div className="grw-container-convertible mb-5 pb-5">
-      <h2 className="my-3">{`${t('Tags')}(${totalCount})`}</h2>
-      <div className="px-3 mb-5 text-center">
-        <TagCloudBox tags={tagData} minSize={20} />
-      </div>
-      { isLoading
-        ? (
-          <div className="text-muted text-center">
-            <i className="fa fa-2x fa-spinner fa-pulse mt-3"></i>
-          </div>
-        )
-        : (
-          <div data-testid="grw-tags-list">
-            <TagList
-              tagData={tagData}
-              totalTags={totalCount}
-              activePage={activePage}
-              onChangePage={setOffsetByPageNumber}
-              pagingLimit={PAGING_LIMIT}
-            />
-          </div>
-        )
-      }
-    </div>
-  );
-
-};
-
-export default TagPage;

+ 137 - 0
packages/app/src/pages/tags.page.tsx

@@ -0,0 +1,137 @@
+import React, { useState, useCallback } from 'react';
+
+import {
+  IUser, IUserHasId,
+} from '@growi/core';
+import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
+import { useTranslation } from 'next-i18next';
+import Head from 'next/head';
+
+import TagCloudBox from '~/components/TagCloudBox';
+import TagList from '~/components/TagList';
+import { CrowiRequest } from '~/interfaces/crowi-request';
+import { IDataTagCount } from '~/interfaces/tag';
+import { IUserUISettings } from '~/interfaces/user-ui-settings';
+import UserUISettings from '~/server/models/user-ui-settings';
+import { useSWRxTagsList } from '~/stores/tag';
+
+import { BasicLayout } from '../components/Layout/BasicLayout';
+import {
+  useCurrentUser,
+  useIsSearchServiceConfigured, useIsSearchServiceReachable,
+  useIsSearchScopeChildrenAsDefault,
+} from '../stores/context';
+
+import {
+  CommonProps, getServerSideCommonProps, useCustomTitle,
+} from './utils/commons';
+
+const PAGING_LIMIT = 10;
+
+type Props = CommonProps & {
+  currentUser: IUser,
+  isSearchServiceConfigured: boolean,
+  isSearchServiceReachable: boolean,
+  isSearchScopeChildrenAsDefault: boolean,
+  userUISettings?: IUserUISettings
+};
+
+const TagPage: NextPage<CommonProps> = (props: Props) => {
+  const [activePage, setActivePage] = useState<number>(1);
+  const [offset, setOffset] = useState<number>(0);
+
+  useCurrentUser(props.currentUser ?? null);
+  const { data: tagDataList, error } = useSWRxTagsList(PAGING_LIMIT, offset);
+  const { t } = useTranslation('');
+  const setOffsetByPageNumber = useCallback((selectedPageNumber: number) => {
+    setActivePage(selectedPageNumber);
+    setOffset((selectedPageNumber - 1) * PAGING_LIMIT);
+  }, []);
+
+  const tagData: IDataTagCount[] = tagDataList?.data || [];
+  const totalCount: number = tagDataList?.totalCount || 0;
+  const isLoading = tagDataList === undefined && error == null;
+  const classNames: string[] = [];
+
+  useIsSearchServiceConfigured(props.isSearchServiceConfigured);
+  useIsSearchServiceReachable(props.isSearchServiceReachable);
+  useIsSearchScopeChildrenAsDefault(props.isSearchScopeChildrenAsDefault);
+
+  return (
+    <>
+      <Head>
+      </Head>
+      <BasicLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')}>
+        <div className="grw-container-convertible mb-5 pb-5">
+          <h2 className="my-3">{`${t('Tags')}(${totalCount})`}</h2>
+          <div className="px-3 mb-5 text-center">
+            <TagCloudBox tags={tagData} minSize={20} />
+          </div>
+          { isLoading
+            ? (
+              <div className="text-muted text-center">
+                <i className="fa fa-2x fa-spinner fa-pulse mt-3"></i>
+              </div>
+            )
+            : (
+              <div data-testid="grw-tags-list">
+                <TagList
+                  tagData={tagData}
+                  totalTags={totalCount}
+                  activePage={activePage}
+                  onChangePage={setOffsetByPageNumber}
+                  pagingLimit={PAGING_LIMIT}
+                />
+              </div>
+            )
+          }
+        </div>
+      </BasicLayout>
+    </>
+  );
+};
+
+async function injectUserUISettings(context: GetServerSidePropsContext, props: Props): Promise<void> {
+  const req = context.req as CrowiRequest<IUserHasId & any>;
+  const { user } = req;
+  const userUISettings = user == null ? null : await UserUISettings.findOne({ user: user._id }).exec();
+
+  if (userUISettings != null) {
+    props.userUISettings = userUISettings.toObject();
+  }
+}
+
+function injectServerConfigurations(context: GetServerSidePropsContext, props: Props): void {
+  const req: CrowiRequest = context.req as CrowiRequest;
+  const { crowi } = req;
+  const {
+    searchService, configManager,
+  } = crowi;
+
+  props.isSearchServiceConfigured = searchService.isConfigured;
+  props.isSearchServiceReachable = searchService.isReachable;
+  props.isSearchScopeChildrenAsDefault = configManager.getConfig('crowi', 'customize:isSearchScopeChildrenAsDefault');
+}
+
+export const getServerSideProps: GetServerSideProps = async(context: GetServerSidePropsContext) => {
+  const req = context.req as CrowiRequest<IUserHasId & any>;
+  const { user } = req;
+  const result = await getServerSideCommonProps(context);
+
+  if (!('props' in result)) {
+    throw new Error('invalid getSSP result');
+  }
+  const props: Props = result.props as Props;
+
+  if (user != null) {
+    props.currentUser = user.toObject();
+  }
+  await injectUserUISettings(context, props);
+  injectServerConfigurations(context, props);
+
+  return {
+    props,
+  };
+};
+
+export default TagPage;

+ 2 - 1
packages/app/src/server/routes/index.js

@@ -204,7 +204,8 @@ module.exports = function(crowi, app) {
 
   app.use(unavailableWhenMaintenanceMode);
 
-  app.get('/tags'                     , loginRequired, tag.showPage);
+  // app.get('/tags'                     , loginRequired, tag.showPage);
+  app.get('/tags', loginRequired, next.delegateToNext);
 
   app.get('/me'                                 , loginRequiredStrictly, injectUserUISettings, me.index);
   // external-accounts