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

Merge branch 'master' into feat/enable-function-section-in-admin-customize

Yohei Shiina 3 лет назад
Родитель
Сommit
744c1909fc

+ 4 - 0
packages/app/src/components/Layout/SearchResultLayout.module.scss

@@ -67,6 +67,10 @@
       }
       }
 
 
       .search-result-content-body-container {
       .search-result-content-body-container {
+        // correct apply overflow scrolling for react-markdown on Google Chrome
+        // see: https://github.com/weseek/growi/pull/6731
+        position: relative;
+
         overflow-y: auto;
         overflow-y: auto;
 
 
         .wiki {
         .wiki {

+ 5 - 2
packages/app/src/components/Navbar/GrowiSubNavigation.tsx

@@ -54,8 +54,11 @@ export const GrowiSubNavigation = (props: GrowiSubNavigationProps): JSX.Element
   const compactModeClasses = isCompactMode ? 'grw-subnav-compact d-print-none' : '';
   const compactModeClasses = isCompactMode ? 'grw-subnav-compact d-print-none' : '';
 
 
   return (
   return (
-    <div className={`grw-subnav ${styles['grw-subnav']} d-flex align-items-center justify-content-between ${additionalClasses.join(' ')}
-    ${compactModeClasses}`} >
+    <div className={`
+      grw-subnav ${styles['grw-subnav']} d-flex align-items-center justify-content-between
+      ${additionalClasses.join(' ')}
+      ${compactModeClasses}`}
+    >
       {/* Left side */}
       {/* Left side */}
       <div className="d-flex grw-subnav-left-side">
       <div className="d-flex grw-subnav-left-side">
         { (showDrawerToggler && isDrawerMode) && (
         { (showDrawerToggler && isDrawerMode) && (

+ 6 - 2
packages/app/src/components/PageCreateModal.jsx

@@ -13,6 +13,7 @@ import { debounce } from 'throttle-debounce';
 import { toastError } from '~/client/util/apiNotification';
 import { toastError } from '~/client/util/apiNotification';
 import { useCurrentUser, useIsSearchServiceReachable } from '~/stores/context';
 import { useCurrentUser, useIsSearchServiceReachable } from '~/stores/context';
 import { usePageCreateModal } from '~/stores/modal';
 import { usePageCreateModal } from '~/stores/modal';
+import { EditorMode, useEditorMode } from '~/stores/ui';
 
 
 import PagePathAutoComplete from './PagePathAutoComplete';
 import PagePathAutoComplete from './PagePathAutoComplete';
 
 
@@ -36,6 +37,8 @@ const PageCreateModal = () => {
   const pageNameInputInitialValue = isCreatable ? pathUtils.addTrailingSlash(pathname) : '/';
   const pageNameInputInitialValue = isCreatable ? pathUtils.addTrailingSlash(pathname) : '/';
   const now = format(new Date(), 'yyyy/MM/dd');
   const now = format(new Date(), 'yyyy/MM/dd');
 
 
+  const { mutate: mutateEditorMode } = useEditorMode();
+
   const [todayInput1, setTodayInput1] = useState(t('Memo'));
   const [todayInput1, setTodayInput1] = useState(t('Memo'));
   const [todayInput2, setTodayInput2] = useState('');
   const [todayInput2, setTodayInput2] = useState('');
   const [pageNameInput, setPageNameInput] = useState(pageNameInputInitialValue);
   const [pageNameInput, setPageNameInput] = useState(pageNameInputInitialValue);
@@ -99,8 +102,9 @@ const PageCreateModal = () => {
    */
    */
   async function redirectToEditor(...paths) {
   async function redirectToEditor(...paths) {
     try {
     try {
-      const editorPath = await generateEditorPath(...paths);
-      router.push(editorPath);
+      const editorPath = generateEditorPath(...paths);
+      await router.push(editorPath);
+      mutateEditorMode(EditorMode.Editor);
 
 
       // close modal
       // close modal
       closeCreateModal();
       closeCreateModal();

+ 4 - 3
packages/app/src/components/PagePathNav.tsx

@@ -7,6 +7,8 @@ import { useIsNotFound } from '~/stores/context';
 
 
 import LinkedPagePath from '../models/linked-page-path';
 import LinkedPagePath from '../models/linked-page-path';
 
 
+import PagePathHierarchicalLink from './PagePathHierarchicalLink';
+
 const { isTrashPage } = pagePathUtils;
 const { isTrashPage } = pagePathUtils;
 
 
 type Props = {
 type Props = {
@@ -17,7 +19,6 @@ type Props = {
 }
 }
 
 
 const CopyDropdown = dynamic(() => import('./Page/CopyDropdown'), { ssr: false });
 const CopyDropdown = dynamic(() => import('./Page/CopyDropdown'), { ssr: false });
-const PagePathHierarchicalLink = dynamic(() => import('./PagePathHierarchicalLink'), { ssr: false });
 
 
 const PagePathNav: FC<Props> = (props: Props) => {
 const PagePathNav: FC<Props> = (props: Props) => {
   const {
   const {
@@ -51,7 +52,7 @@ const PagePathNav: FC<Props> = (props: Props) => {
   return (
   return (
     <div className="grw-page-path-nav">
     <div className="grw-page-path-nav">
       {formerLink}
       {formerLink}
-      <span className="d-flex align-items-center">
+      <div className="d-flex align-items-center">
         <h1 className="m-0">{latterLink}</h1>
         <h1 className="m-0">{latterLink}</h1>
         { pageId != null && !isNotFound && (
         { pageId != null && !isNotFound && (
           <div className="mx-2">
           <div className="mx-2">
@@ -60,7 +61,7 @@ const PagePathNav: FC<Props> = (props: Props) => {
             </CopyDropdown>
             </CopyDropdown>
           </div>
           </div>
         ) }
         ) }
-      </span>
+      </div>
     </div>
     </div>
   );
   );
 };
 };

+ 4 - 3
packages/app/src/pages/[[...path]].page.tsx

@@ -233,9 +233,6 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
 
 
   const { pageWithMeta, userUISettings } = props;
   const { pageWithMeta, userUISettings } = props;
 
 
-  useSWRxCurrentPage(undefined, pageWithMeta?.data ?? null); // store initial data
-  useEditingMarkdown(pageWithMeta?.data.revision?.body ?? '');
-
   const pageId = pageWithMeta?.data._id;
   const pageId = pageWithMeta?.data._id;
   const pagePath = pageWithMeta?.data.path ?? (!_isPermalink(props.currentPathname) ? props.currentPathname : undefined);
   const pagePath = pageWithMeta?.data.path ?? (!_isPermalink(props.currentPathname) ? props.currentPathname : undefined);
 
 
@@ -245,6 +242,10 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   useCurrentPagePath(pagePath);
   useCurrentPagePath(pagePath);
   useCurrentPathname(props.currentPathname);
   useCurrentPathname(props.currentPathname);
   useIsTrashPage(pagePath != null && _isTrashPage(pagePath));
   useIsTrashPage(pagePath != null && _isTrashPage(pagePath));
+
+  useSWRxCurrentPage(undefined, pageWithMeta?.data ?? null); // store initial data
+  useEditingMarkdown(pageWithMeta?.data.revision?.body ?? '');
+
   const { data: layoutSetting } = useLayoutSetting({ isContainerFluid: props.isContainerFluid });
   const { data: layoutSetting } = useLayoutSetting({ isContainerFluid: props.isContainerFluid });
   const { data: dataPageInfo } = useSWRxPageInfo(pageId);
   const { data: dataPageInfo } = useSWRxPageInfo(pageId);
 
 

+ 28 - 14
packages/app/src/pages/_app.page.tsx

@@ -1,29 +1,40 @@
 import React, { useEffect } from 'react';
 import React, { useEffect } from 'react';
 
 
+import { isServer } from '@growi/core';
 import { appWithTranslation } from 'next-i18next';
 import { appWithTranslation } from 'next-i18next';
 import { AppProps } from 'next/app';
 import { AppProps } from 'next/app';
 import { DndProvider } from 'react-dnd';
 import { DndProvider } from 'react-dnd';
 import { HTML5Backend } from 'react-dnd-html5-backend';
 import { HTML5Backend } from 'react-dnd-html5-backend';
-
-import '~/styles/style-next.scss';
-import '~/styles/style-themes.scss';
-// import InterceptorManager from '~/service/interceptor-manager';
+import { SWRConfig } from 'swr';
 
 
 import * as nextI18nConfig from '^/config/next-i18next.config';
 import * as nextI18nConfig from '^/config/next-i18next.config';
 
 
-import { NextThemesProvider } from '~/stores/use-next-themes';
-
-import { useI18nextHMR } from '../services/i18next-hmr';
+import { useI18nextHMR } from '~/services/i18next-hmr';
 import {
 import {
   useAppTitle, useConfidential, useGrowiTheme, useGrowiVersion, useSiteUrl,
   useAppTitle, useConfidential, useGrowiTheme, useGrowiVersion, useSiteUrl,
-} from '../stores/context';
+} from '~/stores/context';
+import { NextThemesProvider } from '~/stores/use-next-themes';
+import { SWRConfigValue, swrGlobalConfiguration } from '~/utils/swr-utils';
+
 
 
 import { CommonProps } from './utils/commons';
 import { CommonProps } from './utils/commons';
 import { registerTransformerForObjectId } from './utils/objectid-transformer';
 import { registerTransformerForObjectId } from './utils/objectid-transformer';
-// import { useInterceptorManager } from '~/stores/interceptor';
+
+import '~/styles/style-next.scss';
+import '~/styles/style-themes.scss';
+
 
 
 const isDev = process.env.NODE_ENV === 'development';
 const isDev = process.env.NODE_ENV === 'development';
 
 
+const swrConfig: SWRConfigValue = {
+  ...swrGlobalConfiguration,
+  // set the request scoped cache provider in server
+  provider: isServer()
+    ? cache => new Map(cache)
+    : undefined,
+};
+
+
 type GrowiAppProps = AppProps & {
 type GrowiAppProps = AppProps & {
   pageProps: CommonProps;
   pageProps: CommonProps;
 };
 };
@@ -37,6 +48,7 @@ function GrowiApp({ Component, pageProps }: GrowiAppProps): JSX.Element {
     import('bootstrap/dist/js/bootstrap');
     import('bootstrap/dist/js/bootstrap');
   }, []);
   }, []);
 
 
+
   const commonPageProps = pageProps as CommonProps;
   const commonPageProps = pageProps as CommonProps;
   // useInterceptorManager(new InterceptorManager());
   // useInterceptorManager(new InterceptorManager());
   useAppTitle(commonPageProps.appTitle);
   useAppTitle(commonPageProps.appTitle);
@@ -46,11 +58,13 @@ function GrowiApp({ Component, pageProps }: GrowiAppProps): JSX.Element {
   useGrowiVersion(commonPageProps.growiVersion);
   useGrowiVersion(commonPageProps.growiVersion);
 
 
   return (
   return (
-    <NextThemesProvider>
-      <DndProvider backend={HTML5Backend}>
-        <Component {...pageProps} />
-      </DndProvider>
-    </NextThemesProvider>
+    <SWRConfig value={swrConfig}>
+      <NextThemesProvider>
+        <DndProvider backend={HTML5Backend}>
+          <Component {...pageProps} />
+        </DndProvider>
+      </NextThemesProvider>
+    </SWRConfig>
   );
   );
 }
 }
 
 

+ 9 - 5
packages/app/src/stores/use-static-swr.tsx

@@ -1,6 +1,7 @@
 import assert from 'assert';
 import assert from 'assert';
+
 import {
 import {
-  Key, SWRConfiguration, SWRResponse,
+  Key, SWRConfiguration, SWRResponse, useSWRConfig,
 } from 'swr';
 } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 import useSWRImmutable from 'swr/immutable';
 
 
@@ -19,12 +20,15 @@ export function useStaticSWR<Data, Error>(
 
 
   assert.notStrictEqual(configuration?.fetcher, null, 'useStaticSWR does not support \'configuration.fetcher\'');
   assert.notStrictEqual(configuration?.fetcher, null, 'useStaticSWR does not support \'configuration.fetcher\'');
 
 
-  const swrResponse = useSWRImmutable(key, null, configuration);
+  const { cache } = useSWRConfig();
+  const swrResponse = useSWRImmutable(key, null, {
+    ...configuration,
+    fallbackData: configuration?.fallbackData ?? cache.get(key),
+  });
 
 
-  // mutate
+  // write data to cache directly
   if (data !== undefined) {
   if (data !== undefined) {
-    const { mutate } = swrResponse;
-    mutate(data);
+    cache.set(key, data);
   }
   }
 
 
   return swrResponse;
   return swrResponse;

+ 6 - 2
packages/app/src/utils/swr-utils.ts

@@ -1,5 +1,9 @@
-import { SWRConfiguration } from 'swr';
+import { ProviderConfiguration, PublicConfiguration } from 'swr/dist/types';
 
 
-export const swrGlobalConfiguration: SWRConfiguration = {
+export type SWRConfigValue = Partial<PublicConfiguration> & Partial<ProviderConfiguration> & {
+  provider?: (cache) => any | undefined,
+};
+
+export const swrGlobalConfiguration: SWRConfigValue = {
   errorRetryCount: 1,
   errorRetryCount: 1,
 };
 };