فهرست منبع

Merge branch 'master' into fix/change-language-installer

Haku Mizuki 3 سال پیش
والد
کامیت
7d382855c6

+ 43 - 30
packages/app/src/components/Me/EditorSettings.tsx

@@ -1,12 +1,13 @@
 import React, {
 import React, {
-  Dispatch,
+  Dispatch, memo,
   FC, SetStateAction, useCallback, useEffect, useState,
   FC, SetStateAction, useCallback, useEffect, useState,
+  useMemo,
 } from 'react';
 } from 'react';
 
 
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 
 
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
-import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
+import { useEditorSettings } from '~/stores/editor';
 
 
 
 
 type EditorSettingsBodyProps = Record<string, never>;
 type EditorSettingsBodyProps = Record<string, never>;
@@ -194,51 +195,62 @@ const RuleListGroup: FC<RuleListGroupProps> = ({
   );
   );
 };
 };
 
 
+const createRulesFromDefaultList = (rule: { name: string }) => (
+  {
+    name: rule.name,
+    isEnabled: true,
+  }
+);
+
 
 
-export const EditorSettings: FC<EditorSettingsBodyProps> = () => {
+export const EditorSettings = memo((): JSX.Element => {
   const { t } = useTranslation();
   const { t } = useTranslation();
   const [textlintRules, setTextlintRules] = useState<LintRule[]>([]);
   const [textlintRules, setTextlintRules] = useState<LintRule[]>([]);
 
 
-  const initializeEditorSettings = useCallback(async() => {
-    const { data } = await apiv3Get('/personal-setting/editor-settings');
-    const retrievedRules: LintRule[] = data?.textlintSettings?.textlintRules;
+  const { data: dataEditorSettings, update: updateEditorSettings } = useEditorSettings();
 
 
-    // If database is empty, add default rules to state
-    if (retrievedRules != null && retrievedRules.length > 0) {
-      setTextlintRules(retrievedRules);
-    }
-    else {
-      const createRulesFromDefaultList = (rule: { name: string }) => (
-        {
-          name: rule.name,
-          isEnabled: true,
-        }
-      );
+  const defaultRules = useMemo(() => {
+    const defaultCommonRules = commonRulesMenuItems.map(rule => createRulesFromDefaultList(rule));
+    const defaultJapaneseRules = japaneseRulesMenuItems.map(rule => createRulesFromDefaultList(rule));
+
+    return [...defaultCommonRules, ...defaultJapaneseRules];
+  }, []);
 
 
-      const defaultCommonRules = commonRulesMenuItems.map(rule => createRulesFromDefaultList(rule));
-      const defaultJapaneseRules = japaneseRulesMenuItems.map(rule => createRulesFromDefaultList(rule));
-      setTextlintRules([...defaultCommonRules, ...defaultJapaneseRules]);
+  const initializeEditorSettings = useCallback(() => {
+    if (dataEditorSettings == null) {
+      return;
     }
     }
 
 
-  }, []);
+    const retrievedRules: LintRule[] | undefined = dataEditorSettings?.textlintSettings?.textlintRules;
 
 
-  useEffect(() => {
-    initializeEditorSettings();
-  }, [initializeEditorSettings]);
+    // If database is empty, add default rules to state
+    if (retrievedRules != null && retrievedRules.length > 0) {
+      setTextlintRules(retrievedRules);
+      return;
+    }
+    setTextlintRules(defaultRules);
+  }, [dataEditorSettings, defaultRules]);
 
 
-  const updateRulesHandler = async() => {
+  const updateRulesHandler = useCallback(async() => {
     try {
     try {
-      const { data } = await apiv3Put('/personal-setting/editor-settings', { textlintSettings: { textlintRules: [...textlintRules] } });
-      setTextlintRules(data.textlintSettings.textlintRules);
+      await updateEditorSettings({ textlintSettings: { textlintRules } });
       toastSuccess(t('toaster.update_successed', { target: 'Updated Textlint Settings' }));
       toastSuccess(t('toaster.update_successed', { target: 'Updated Textlint Settings' }));
     }
     }
     catch (err) {
     catch (err) {
       toastError(err);
       toastError(err);
     }
     }
-  };
+  }, [t, textlintRules, updateEditorSettings]);
+
+  useEffect(() => {
+    initializeEditorSettings();
+  }, [initializeEditorSettings]);
 
 
   if (textlintRules == null) {
   if (textlintRules == null) {
-    return <></>;
+    return (
+      <div className="text-muted text-center">
+        <i className="fa fa-2x fa-spinner fa-pulse"></i>
+      </div>
+    );
   }
   }
 
 
   return (
   return (
@@ -270,4 +282,5 @@ export const EditorSettings: FC<EditorSettingsBodyProps> = () => {
       </div>
       </div>
     </div>
     </div>
   );
   );
-};
+});
+EditorSettings.displayName = 'EditorSettings';

+ 42 - 42
packages/app/src/components/Theme/utils/ThemeProvider.tsx

@@ -7,21 +7,21 @@ import { GrowiThemes } from '~/interfaces/theme';
 import { Themes } from '~/stores/use-next-themes';
 import { Themes } from '~/stores/use-next-themes';
 
 
 
 
-const ThemeAntarctic = dynamic(() => import('../ThemeAntarctic'));
-const ThemeBlackboard = dynamic(() => import('../ThemeBlackboard'));
-const ThemeChristmas = dynamic(() => import('../ThemeChristmas'));
+// const ThemeAntarctic = dynamic(() => import('../ThemeAntarctic'));
+// const ThemeBlackboard = dynamic(() => import('../ThemeBlackboard'));
+// const ThemeChristmas = dynamic(() => import('../ThemeChristmas'));
 const ThemeDefault = dynamic(() => import('../ThemeDefault'));
 const ThemeDefault = dynamic(() => import('../ThemeDefault'));
-const ThemeFireRed = dynamic(() => import('../ThemeFireRed'));
-const ThemeFuture = dynamic(() => import('../ThemeFuture'));
-const ThemeHalloween = dynamic(() => import('../ThemeHalloween'));
-const ThemeHufflepuff = dynamic(() => import('../ThemeHufflepuff'));
-const ThemeIsland = dynamic(() => import('../ThemeIsland'));
-const ThemeJadeGreen = dynamic(() => import('../ThemeJadeGreen'));
-const ThemeKibela = dynamic(() => import('../ThemeKibela'));
-const ThemeMonoBlue = dynamic(() => import('../ThemeMonoBlue'));
-const ThemeNature = dynamic(() => import('../ThemeNature'));
-const ThemeSpring = dynamic(() => import('../ThemeSpring'));
-const ThemeWood = dynamic(() => import('../ThemeWood'));
+// const ThemeFireRed = dynamic(() => import('../ThemeFireRed'));
+// const ThemeFuture = dynamic(() => import('../ThemeFuture'));
+// const ThemeHalloween = dynamic(() => import('../ThemeHalloween'));
+// const ThemeHufflepuff = dynamic(() => import('../ThemeHufflepuff'));
+// const ThemeIsland = dynamic(() => import('../ThemeIsland'));
+// const ThemeJadeGreen = dynamic(() => import('../ThemeJadeGreen'));
+// const ThemeKibela = dynamic(() => import('../ThemeKibela'));
+// const ThemeMonoBlue = dynamic(() => import('../ThemeMonoBlue'));
+// const ThemeNature = dynamic(() => import('../ThemeNature'));
+// const ThemeSpring = dynamic(() => import('../ThemeSpring'));
+// const ThemeWood = dynamic(() => import('../ThemeWood'));
 
 
 
 
 type Props = {
 type Props = {
@@ -32,34 +32,34 @@ type Props = {
 
 
 export const ThemeProvider = ({ theme, children, colorScheme }: Props): JSX.Element => {
 export const ThemeProvider = ({ theme, children, colorScheme }: Props): JSX.Element => {
   switch (theme) {
   switch (theme) {
-    case GrowiThemes.ANTARCTIC:
-      return <ThemeAntarctic colorScheme={colorScheme}>{children}</ThemeAntarctic>;
-    case GrowiThemes.BLACKBOARD:
-      return <ThemeBlackboard>{children}</ThemeBlackboard>;
-    case GrowiThemes.CHRISTMAS:
-      return <ThemeChristmas colorScheme={colorScheme}>{children}</ThemeChristmas>;
-    case GrowiThemes.FIRE_RED:
-      return <ThemeFireRed>{children}</ThemeFireRed>;
-    case GrowiThemes.FUTURE:
-      return <ThemeFuture>{children}</ThemeFuture>;
-    case GrowiThemes.HALLOWEEN:
-      return <ThemeHalloween colorScheme={colorScheme}>{children}</ThemeHalloween>;
-    case GrowiThemes.HUFFLEPUFF:
-      return <ThemeHufflepuff colorScheme={colorScheme}>{children}</ThemeHufflepuff>;
-    case GrowiThemes.ISLAND:
-      return <ThemeIsland colorScheme={colorScheme}>{children}</ThemeIsland>;
-    case GrowiThemes.JADE_GREEN:
-      return <ThemeJadeGreen>{children}</ThemeJadeGreen>;
-    case GrowiThemes.KIBELA:
-      return <ThemeKibela>{children}</ThemeKibela>;
-    case GrowiThemes.MONO_BLUE:
-      return <ThemeMonoBlue>{children}</ThemeMonoBlue>;
-    case GrowiThemes.NATURE:
-      return <ThemeNature>{children}</ThemeNature>;
-    case GrowiThemes.SPRING:
-      return <ThemeSpring colorScheme={colorScheme}>{children}</ThemeSpring>;
-    case GrowiThemes.WOOD:
-      return <ThemeWood colorScheme={colorScheme}>{children}</ThemeWood>;
+    // case GrowiThemes.ANTARCTIC:
+    //   return <ThemeAntarctic colorScheme={colorScheme}>{children}</ThemeAntarctic>;
+    // case GrowiThemes.BLACKBOARD:
+    //   return <ThemeBlackboard>{children}</ThemeBlackboard>;
+    // case GrowiThemes.CHRISTMAS:
+    //   return <ThemeChristmas colorScheme={colorScheme}>{children}</ThemeChristmas>;
+    // case GrowiThemes.FIRE_RED:
+    //   return <ThemeFireRed>{children}</ThemeFireRed>;
+    // case GrowiThemes.FUTURE:
+    //   return <ThemeFuture>{children}</ThemeFuture>;
+    // case GrowiThemes.HALLOWEEN:
+    //   return <ThemeHalloween colorScheme={colorScheme}>{children}</ThemeHalloween>;
+    // case GrowiThemes.HUFFLEPUFF:
+    //   return <ThemeHufflepuff colorScheme={colorScheme}>{children}</ThemeHufflepuff>;
+    // case GrowiThemes.ISLAND:
+    //   return <ThemeIsland colorScheme={colorScheme}>{children}</ThemeIsland>;
+    // case GrowiThemes.JADE_GREEN:
+    //   return <ThemeJadeGreen>{children}</ThemeJadeGreen>;
+    // case GrowiThemes.KIBELA:
+    //   return <ThemeKibela>{children}</ThemeKibela>;
+    // case GrowiThemes.MONO_BLUE:
+    //   return <ThemeMonoBlue>{children}</ThemeMonoBlue>;
+    // case GrowiThemes.NATURE:
+    //   return <ThemeNature>{children}</ThemeNature>;
+    // case GrowiThemes.SPRING:
+    //   return <ThemeSpring colorScheme={colorScheme}>{children}</ThemeSpring>;
+    // case GrowiThemes.WOOD:
+    //   return <ThemeWood colorScheme={colorScheme}>{children}</ThemeWood>;
     default:
     default:
       return <ThemeDefault>{children}</ThemeDefault>;
       return <ThemeDefault>{children}</ThemeDefault>;
   }
   }

+ 1 - 1
packages/app/src/interfaces/editor-settings.ts

@@ -5,7 +5,7 @@ export interface ILintRule {
 }
 }
 
 
 export interface ITextlintSettings {
 export interface ITextlintSettings {
-  neverAskBeforeDownloadLargeFiles: boolean;
+  neverAskBeforeDownloadLargeFiles?: boolean;
   textlintRules: ILintRule[];
   textlintRules: ILintRule[];
 }
 }
 
 

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

@@ -10,16 +10,19 @@ import { SlackChannels } from '~/interfaces/user-trigger-notification';
 import {
 import {
   useCurrentUser, useDefaultIndentSize, useIsGuestUser,
   useCurrentUser, useDefaultIndentSize, useIsGuestUser,
 } from './context';
 } from './context';
-import { localStorageMiddleware } from './middlewares/sync-to-storage';
+// import { localStorageMiddleware } from './middlewares/sync-to-storage';
 import { useSWRxTagsInfo } from './page';
 import { useSWRxTagsInfo } from './page';
 import { useStaticSWR } from './use-static-swr';
 import { useStaticSWR } from './use-static-swr';
 
 
 
 
 type EditorSettingsOperation = {
 type EditorSettingsOperation = {
-  update: (updateData: Partial<IEditorSettings>) => void,
+  update: (updateData: Partial<IEditorSettings>) => Promise<void>,
   turnOffAskingBeforeDownloadLargeFiles: () => void,
   turnOffAskingBeforeDownloadLargeFiles: () => void,
 }
 }
 
 
+// TODO: Enable localStorageMiddleware
+//   - Unabling localStorageMiddleware occurrs a flickering problem when loading theme.
+//   - see: https://github.com/weseek/growi/pull/6781#discussion_r1000285786
 export const useEditorSettings = (): SWRResponseWithUtils<EditorSettingsOperation, IEditorSettings, Error> => {
 export const useEditorSettings = (): SWRResponseWithUtils<EditorSettingsOperation, IEditorSettings, Error> => {
   const { data: currentUser } = useCurrentUser();
   const { data: currentUser } = useCurrentUser();
   const { data: isGuestUser } = useIsGuestUser();
   const { data: isGuestUser } = useIsGuestUser();
@@ -27,11 +30,14 @@ export const useEditorSettings = (): SWRResponseWithUtils<EditorSettingsOperatio
   const swrResult = useSWRImmutable<IEditorSettings>(
   const swrResult = useSWRImmutable<IEditorSettings>(
     isGuestUser ? null : ['/personal-setting/editor-settings', currentUser?.username],
     isGuestUser ? null : ['/personal-setting/editor-settings', currentUser?.username],
     endpoint => apiv3Get(endpoint).then(result => result.data),
     endpoint => apiv3Get(endpoint).then(result => result.data),
-    { use: [localStorageMiddleware] }, // store to localStorage for initialization fastly
+    {
+      // use: [localStorageMiddleware], // store to localStorage for initialization fastly
+      // fallbackData: undefined,
+    },
   );
   );
 
 
   return withUtils<EditorSettingsOperation, IEditorSettings, Error>(swrResult, {
   return withUtils<EditorSettingsOperation, IEditorSettings, Error>(swrResult, {
-    update: (updateData) => {
+    update: async(updateData) => {
       const { data, mutate } = swrResult;
       const { data, mutate } = swrResult;
 
 
       if (data == null) {
       if (data == null) {
@@ -41,7 +47,7 @@ export const useEditorSettings = (): SWRResponseWithUtils<EditorSettingsOperatio
       mutate({ ...data, ...updateData }, false);
       mutate({ ...data, ...updateData }, false);
 
 
       // invoke API
       // invoke API
-      apiv3Put('/personal-setting/editor-settings', updateData);
+      await apiv3Put('/personal-setting/editor-settings', updateData);
     },
     },
     turnOffAskingBeforeDownloadLargeFiles: async() => {
     turnOffAskingBeforeDownloadLargeFiles: async() => {
       const { data, mutate } = swrResult;
       const { data, mutate } = swrResult;

+ 4 - 8
packages/app/src/stores/middlewares/sync-to-storage.ts

@@ -33,14 +33,10 @@ export const createSyncToStorageMiddlware = (
         initData = storageSerializer.deserialize(itemInStorage);
         initData = storageSerializer.deserialize(itemInStorage);
       }
       }
 
 
-      const swrNext = useSWRNext(key, fetcher, {
-        fallbackData: initData,
-        ...config,
-      });
+      config.fallbackData = initData;
+      const swrNext = useSWRNext(key, fetcher, config);
 
 
-      return {
-        ...swrNext,
-        // override mutate
+      return Object.assign(swrNext, {
         mutate: (data, shouldRevalidate) => {
         mutate: (data, shouldRevalidate) => {
           return swrNext.mutate(data, shouldRevalidate)
           return swrNext.mutate(data, shouldRevalidate)
             .then((value) => {
             .then((value) => {
@@ -48,7 +44,7 @@ export const createSyncToStorageMiddlware = (
               return value;
               return value;
             });
             });
         },
         },
-      };
+      });
     };
     };
   };
   };
 };
 };

+ 14 - 14
packages/app/src/styles/style-themes.scss

@@ -1,15 +1,15 @@
-@import '~/components/Theme/ThemeAntarctic.global.scss';
-@import '~/components/Theme/ThemeBlackboard.global.scss';
-@import '~/components/Theme/ThemeChristmas.global.scss';
+// @import '~/components/Theme/ThemeAntarctic.global.scss';
+// @import '~/components/Theme/ThemeBlackboard.global.scss';
+// @import '~/components/Theme/ThemeChristmas.global.scss';
 @import '~/components/Theme/ThemeDefault.global.scss';
 @import '~/components/Theme/ThemeDefault.global.scss';
-@import '~/components/Theme/ThemeFireRed.global.scss';
-@import '~/components/Theme/ThemeFuture.global.scss';
-@import '~/components/Theme/ThemeHalloween.global.scss';
-@import '~/components/Theme/ThemeHufflepuff.global.scss';
-@import '~/components/Theme/ThemeIsland.global.scss';
-@import '~/components/Theme/ThemeJadeGreen.global.scss';
-@import '~/components/Theme/ThemeKibela.global.scss';
-@import '~/components/Theme/ThemeMonoBlue.global.scss';
-@import '~/components/Theme/ThemeNature.global.scss';
-@import '~/components/Theme/ThemeSpring.global.scss';
-@import '~/components/Theme/ThemeWood.global.scss';
+// @import '~/components/Theme/ThemeFireRed.global.scss';
+// @import '~/components/Theme/ThemeFuture.global.scss';
+// @import '~/components/Theme/ThemeHalloween.global.scss';
+// @import '~/components/Theme/ThemeHufflepuff.global.scss';
+// @import '~/components/Theme/ThemeIsland.global.scss';
+// @import '~/components/Theme/ThemeJadeGreen.global.scss';
+// @import '~/components/Theme/ThemeKibela.global.scss';
+// @import '~/components/Theme/ThemeMonoBlue.global.scss';
+// @import '~/components/Theme/ThemeNature.global.scss';
+// @import '~/components/Theme/ThemeSpring.global.scss';
+// @import '~/components/Theme/ThemeWood.global.scss';