Преглед изворни кода

Merge branch 'master' into support/bump-version-to-6.0.0-RC.3

yuken пре 3 година
родитељ
комит
ebf733f866

+ 0 - 5
packages/app/_obsolete/src/client/services/ContextExtractor.tsx

@@ -167,11 +167,6 @@ const ContextExtractorOnce: FC = () => {
   usePreferDrawerModeOnEditByUser();
   useIsDeviceSmallerThanMd();
 
-  // Navigation
-  usePreferDrawerModeByUser();
-  usePreferDrawerModeOnEditByUser();
-  useIsDeviceSmallerThanMd();
-
   // Editor
   // useSelectedGrant(grant);
   // useSelectedGrantGroupId(grantGroupId);

+ 4 - 2
packages/app/src/components/LoginForm.tsx

@@ -9,6 +9,7 @@ import ReactCardFlip from 'react-card-flip';
 import { apiv3Post } from '~/client/util/apiv3-client';
 import { LoginErrorCode } from '~/interfaces/errors/login-error';
 import { IErrorV3 } from '~/interfaces/errors/v3-error';
+import { toArrayIfNot } from '~/utils/array-utils';
 
 type LoginFormProps = {
   username?: string,
@@ -80,10 +81,11 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
     try {
       const res = await apiv3Post('/login', { loginForm });
       const { redirectTo } = res.data;
-      router.push(redirectTo);
+      router.push(redirectTo ?? '/');
     }
     catch (err) {
-      setLoginErrors(err);
+      const errs = toArrayIfNot(err);
+      setLoginErrors(errs);
     }
     return;
 

+ 1 - 0
packages/app/src/components/PrivateLegacyPages.tsx

@@ -455,6 +455,7 @@ const PrivateLegacyPages = (): JSX.Element => {
             toastSuccess(t('private_legacy_pages.by_path_modal.success'));
             setOpenConvertModal(false);
             mutate();
+            advancePt();
           }
           catch (errs) {
             if (errs.length === 1) {

+ 10 - 8
packages/app/src/pages/[[...path]].page.tsx

@@ -26,7 +26,6 @@ import { CurrentPageContentFooter } from '~/components/PageContentFooter';
 import { UsersHomePageFooterProps } from '~/components/UsersHomePageFooter';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
 // import { renderScriptTagByName, renderHighlightJsStyleTag } from '~/service/cdn-resources-loader';
-// import { useIndentSize } from '~/stores/editor';
 // import { useRendererSettings } from '~/stores/renderer';
 // import { EditorMode, useEditorMode, useIsMobile } from '~/stores/ui';
 import type { EditorConfig } from '~/interfaces/editor-settings';
@@ -60,7 +59,7 @@ import {
   useIsForbidden, useIsNotFound, useIsTrashPage, useIsSharedUser,
   useIsEnabledStaleNotification, useIsIdenticalPath,
   useIsSearchServiceConfigured, useIsSearchServiceReachable, useDisableLinkSharing,
-  useDrawioUri, useHackmdUri,
+  useDrawioUri, useHackmdUri, useDefaultIndentSize, useIsIndentSizeForced,
   useIsAclEnabled, useIsUserPage, useIsSearchPage,
   useCsrfToken, useIsSearchScopeChildrenAsDefault, useCurrentPageId, useCurrentPathname,
   useIsSlackConfigured, useRendererConfig, useEditingMarkdown,
@@ -160,8 +159,8 @@ type Props = CommonProps & {
   isEnabledStaleNotification: boolean,
   // isEnabledLinebreaks: boolean,
   // isEnabledLinebreaksInComments: boolean,
-  // adminPreferredIndentSize: number,
-  // isIndentSizeForced: boolean,
+  adminPreferredIndentSize: number,
+  isIndentSizeForced: boolean,
   disableLinkSharing: boolean,
 
   rendererConfig: RendererConfig,
@@ -220,7 +219,8 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   useDrawioUri(props.drawioUri);
   useHackmdUri(props.hackmdUri);
   // useNoCdn(props.noCdn);
-  // useIndentSize(props.adminPreferredIndentSize);
+  useDefaultIndentSize(props.adminPreferredIndentSize);
+  useIsIndentSizeForced(props.isIndentSizeForced);
   useDisableLinkSharing(props.disableLinkSharing);
   useRendererConfig(props.rendererConfig);
   // useRendererSettings(props.rendererSettingsStr != null ? JSON.parse(props.rendererSettingsStr) : undefined);
@@ -305,7 +305,9 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
       <BasicLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')} expandContainer={isContainerFluid}>
         <div className="h-100 d-flex flex-column justify-content-between">
           <header className="py-0 position-relative">
-            <GrowiContextualSubNavigation isLinkSharingDisabled={props.disableLinkSharing} />
+            <div id="grw-subnav-container">
+              <GrowiContextualSubNavigation isLinkSharingDisabled={props.disableLinkSharing} />
+            </div>
           </header>
           <div className="d-edit-none">
             <GrowiSubNavigationSwitcher />
@@ -524,8 +526,8 @@ function injectServerConfigurations(context: GetServerSidePropsContext, props: P
       isUploadableImage: crowi.fileUploadService.getIsUploadable(),
     },
   };
-  // props.adminPreferredIndentSize = configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize');
-  // props.isIndentSizeForced = configManager.getConfig('markdown', 'markdown:isIndentSizeForced');
+  props.adminPreferredIndentSize = configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize');
+  props.isIndentSizeForced = configManager.getConfig('markdown', 'markdown:isIndentSizeForced');
 
   props.rendererConfig = {
     isEnabledLinebreaks: configManager.getConfig('markdown', 'markdown:isEnabledLinebreaks'),

+ 1 - 1
packages/app/src/stores/context.tsx

@@ -196,7 +196,7 @@ export const useHasParent = (initialData?: boolean) : SWRResponse<boolean, Error
 };
 
 export const useIsIndentSizeForced = (initialData?: boolean) : SWRResponse<boolean, Error> => {
-  return useStaticSWR<boolean, Error>('isIndentSizeForced', initialData);
+  return useStaticSWR<boolean, Error>('isIndentSizeForced', initialData, { fallbackData: false });
 };
 
 export const useDefaultIndentSize = (initialData?: number) : SWRResponse<number, Error> => {

+ 4 - 5
packages/app/src/stores/editor.tsx

@@ -1,4 +1,4 @@
-import { Nullable } from '@growi/core';
+import { Nullable, withUtils, SWRResponseWithUtils } from '@growi/core';
 import useSWR, { SWRResponse } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 
@@ -20,7 +20,7 @@ type EditorSettingsOperation = {
   turnOffAskingBeforeDownloadLargeFiles: () => void,
 }
 
-export const useEditorSettings = (): SWRResponse<IEditorSettings, Error> & EditorSettingsOperation => {
+export const useEditorSettings = (): SWRResponseWithUtils<EditorSettingsOperation, IEditorSettings, Error> => {
   const { data: currentUser } = useCurrentUser();
   const { data: isGuestUser } = useIsGuestUser();
 
@@ -30,8 +30,7 @@ export const useEditorSettings = (): SWRResponse<IEditorSettings, Error> & Edito
     { use: [localStorageMiddleware] }, // store to localStorage for initialization fastly
   );
 
-  return {
-    ...swrResult,
+  return withUtils<EditorSettingsOperation, IEditorSettings, Error>(swrResult, {
     update: (updateData) => {
       const { data, mutate } = swrResult;
 
@@ -56,7 +55,7 @@ export const useEditorSettings = (): SWRResponse<IEditorSettings, Error> & Edito
       // revalidate
       mutate();
     },
-  };
+  });
 };
 
 export const useIsTextlintEnabled = (): SWRResponse<boolean, Error> => {

+ 34 - 26
packages/app/src/stores/ui.tsx

@@ -1,10 +1,10 @@
-import { RefObject } from 'react';
+import { RefObject, useEffect } from 'react';
 
 import {
   isClient, isServer, pagePathUtils, Nullable, PageGrant,
 } from '@growi/core';
 import { withUtils, SWRResponseWithUtils } from '@growi/core/src/utils/with-utils';
-import { Breakpoint, addBreakpointListener } from '@growi/ui';
+import { Breakpoint, addBreakpointListener, cleanupBreakpointListener } from '@growi/ui';
 import SimpleBar from 'simplebar-react';
 import {
   useSWRConfig, SWRResponse, Key, Fetcher,
@@ -177,21 +177,25 @@ export const useIsDeviceSmallerThanMd = (): SWRResponse<boolean, Error> => {
 
   const { cache, mutate } = useSWRConfig();
 
-  if (isClient()) {
-    const mdOrAvobeHandler = function(this: MediaQueryList): void {
-      // sm -> md: matches will be true
-      // md -> sm: matches will be false
-      mutate(key, !this.matches);
-    };
-    const mql = addBreakpointListener(Breakpoint.MD, mdOrAvobeHandler);
+  useEffect(() => {
+    if (isClient()) {
+      const mdOrAvobeHandler = function(this: MediaQueryList): void {
+        // sm -> md: matches will be true
+        // md -> sm: matches will be false
+        mutate(key, !this.matches);
+      };
+      const mql = addBreakpointListener(Breakpoint.MD, mdOrAvobeHandler);
 
-    // initialize
-    if (cache.get(key) == null) {
-      document.addEventListener('DOMContentLoaded', () => {
+      // initialize
+      if (cache.get(key) == null) {
         mutate(key, !mql.matches);
-      });
+      }
+
+      return () => {
+        cleanupBreakpointListener(mql, mdOrAvobeHandler);
+      };
     }
-  }
+  }, [cache, key, mutate]);
 
   return useStaticSWR(key);
 };
@@ -201,21 +205,25 @@ export const useIsDeviceSmallerThanLg = (): SWRResponse<boolean, Error> => {
 
   const { cache, mutate } = useSWRConfig();
 
-  if (isClient()) {
-    const lgOrAvobeHandler = function(this: MediaQueryList): void {
-      // md -> lg: matches will be true
-      // lg -> md: matches will be false
-      mutate(key, !this.matches);
-    };
-    const mql = addBreakpointListener(Breakpoint.LG, lgOrAvobeHandler);
+  useEffect(() => {
+    if (isClient()) {
+      const lgOrAvobeHandler = function(this: MediaQueryList): void {
+        // md -> lg: matches will be true
+        // lg -> md: matches will be false
+        mutate(key, !this.matches);
+      };
+      const mql = addBreakpointListener(Breakpoint.LG, lgOrAvobeHandler);
 
-    // initialize
-    if (cache.get(key) == null) {
-      document.addEventListener('DOMContentLoaded', () => {
+      // initialize
+      if (cache.get(key) == null) {
         mutate(key, !mql.matches);
-      });
+      }
+
+      return () => {
+        cleanupBreakpointListener(mql, lgOrAvobeHandler);
+      };
     }
-  }
+  }, [cache, key, mutate]);
 
   return useStaticSWR(key);
 };

+ 10 - 1
packages/ui/src/utils/browser-utils.ts

@@ -1,5 +1,6 @@
 import { Breakpoint } from '../interfaces/breakpoints';
 
+const EVENT_TYPE_CHANGE = 'change';
 
 export const addBreakpointListener = (
     breakpoint: Breakpoint,
@@ -12,7 +13,15 @@ export const addBreakpointListener = (
   const mediaQueryList = window.matchMedia(`(min-width: ${breakpointPixel}px)`);
 
   // add event listener
-  mediaQueryList.addEventListener('change', listener);
+  mediaQueryList.addEventListener(EVENT_TYPE_CHANGE, listener);
 
   return mediaQueryList;
 };
+
+export const cleanupBreakpointListener = (
+    mediaQueryList: MediaQueryList,
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    listener: (this: MediaQueryList, ev: MediaQueryListEvent) => any,
+): void => {
+  mediaQueryList.removeEventListener(EVENT_TYPE_CHANGE, listener);
+};