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

Resolved conflict merging master

Taichi Masuyama 3 лет назад
Родитель
Сommit
3897bd39a5
47 измененных файлов с 110 добавлено и 96 удалено
  1. 2 2
      packages/app/src/components/Admin/App/AppSetting.jsx
  2. 2 2
      packages/app/src/components/Admin/App/FileUploadSetting.tsx
  3. 2 2
      packages/app/src/components/Admin/App/MailSetting.tsx
  4. 1 1
      packages/app/src/components/Admin/App/PluginSetting.tsx
  5. 1 1
      packages/app/src/components/Admin/App/SiteUrlSetting.tsx
  6. 1 1
      packages/app/src/components/Admin/Customize/CustomizeCssSetting.tsx
  7. 1 1
      packages/app/src/components/Admin/Customize/CustomizeFunctionSetting.tsx
  8. 1 1
      packages/app/src/components/Admin/Customize/CustomizeHeaderSetting.tsx
  9. 1 1
      packages/app/src/components/Admin/Customize/CustomizeLayoutSetting.tsx
  10. 3 3
      packages/app/src/components/Admin/Customize/CustomizeLogoSetting.tsx
  11. 1 1
      packages/app/src/components/Admin/Customize/CustomizeScriptSetting.tsx
  12. 3 2
      packages/app/src/components/Admin/Customize/CustomizeSidebarSetting.tsx
  13. 1 1
      packages/app/src/components/Admin/Customize/CustomizeThemeSetting.tsx
  14. 1 1
      packages/app/src/components/Admin/Customize/CustomizeTitle.tsx
  15. 1 1
      packages/app/src/components/Admin/MarkdownSetting/IndentForm.tsx
  16. 1 1
      packages/app/src/components/Admin/MarkdownSetting/LineBreakForm.jsx
  17. 1 1
      packages/app/src/components/Admin/MarkdownSetting/PresentationForm.jsx
  18. 1 1
      packages/app/src/components/Admin/MarkdownSetting/XssForm.jsx
  19. 1 1
      packages/app/src/components/Admin/Notification/GlobalNotification.jsx
  20. 1 1
      packages/app/src/components/Admin/Security/SecuritySetting.jsx
  21. 2 2
      packages/app/src/components/Admin/SlackIntegration/CustomBotWithProxySettings.jsx
  22. 1 1
      packages/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySecretTokenSection.jsx
  23. 2 2
      packages/app/src/components/Admin/SlackIntegration/ManageCommandsProcess.jsx
  24. 2 2
      packages/app/src/components/Admin/SlackIntegration/ManageCommandsProcessWithoutProxy.jsx
  25. 1 1
      packages/app/src/components/Admin/SlackIntegration/OfficialBotSettings.jsx
  26. 1 1
      packages/app/src/components/Admin/SlackIntegration/WithProxyAccordions.jsx
  27. 2 2
      packages/app/src/components/Admin/UserGroup/UserGroupPage.tsx
  28. 5 5
      packages/app/src/components/Admin/UserGroupDetail/UserGroupDetailPage.tsx
  29. 1 1
      packages/app/src/components/Me/ApiSettings.tsx
  30. 1 1
      packages/app/src/components/Me/BasicInfoSettings.tsx
  31. 1 1
      packages/app/src/components/Me/EditorSettings.tsx
  32. 1 1
      packages/app/src/components/Me/InAppNotificationSettings.tsx
  33. 2 2
      packages/app/src/components/Me/PasswordSettings.jsx
  34. 3 3
      packages/app/src/components/Me/ProfileImageSettings.tsx
  35. 1 1
      packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx
  36. 22 14
      packages/app/src/components/PageEditor/CodeMirrorEditor.jsx
  37. 2 2
      packages/app/src/components/PasswordResetExecutionForm.tsx
  38. 9 7
      packages/app/src/components/Sidebar/Tag.tsx
  39. 3 3
      packages/app/src/pages/admin/[[...path]].page.tsx
  40. 1 1
      packages/app/src/pages/forgot-password.page.tsx
  41. 1 1
      packages/app/src/pages/me/[[...path]].page.tsx
  42. 1 1
      packages/app/src/pages/reset-password.page.tsx
  43. 1 1
      packages/app/src/pages/tags.page.tsx
  44. 3 1
      packages/app/src/server/routes/index.js
  45. 7 8
      packages/app/test/cypress/integration/20-basic-features/access-to-page.spec.ts
  46. 2 2
      packages/app/test/cypress/integration/21-basic-features-for-guest/access-to-page.spec.ts
  47. 5 3
      packages/app/test/cypress/integration/60-home/home.spec.ts

+ 2 - 2
packages/app/src/components/Admin/App/AppSetting.jsx

@@ -18,12 +18,12 @@ const logger = loggerFactory('growi:appSettings');
 
 const AppSetting = (props) => {
   const { adminAppContainer } = props;
-  const { t } = useTranslation('admin');
+  const { t } = useTranslation(['admin', 'commons']);
 
   const submitHandler = useCallback(async() => {
     try {
       await adminAppContainer.updateAppSettingHandler();
-      toastSuccess(t('toaster.update_successed', { target: t('commons:headers.app_settings') }));
+      toastSuccess(t('toaster.update_successed', { target: t('headers.app_settings'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 2 - 2
packages/app/src/components/Admin/App/FileUploadSetting.tsx

@@ -18,7 +18,7 @@ type Props = {
 
 
 const FileUploadSetting = (props: Props) => {
-  const { t } = useTranslation();
+  const { t } = useTranslation(['admin', 'commons']);
   const { adminAppContainer } = props;
   const { fileUploadType } = adminAppContainer.state;
   const fileUploadTypes = ['aws', 'gcs', 'gridfs', 'local'];
@@ -26,7 +26,7 @@ const FileUploadSetting = (props: Props) => {
   const submitHandler = useCallback(async() => {
     try {
       await adminAppContainer.updateFileUploadSettingHandler();
-      toastSuccess(t('toaster.update_successed', { target: t('admin:app_setting.file_upload_settings') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:app_setting.file_upload_settings'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 2 - 2
packages/app/src/components/Admin/App/MailSetting.tsx

@@ -17,7 +17,7 @@ type Props = {
 
 
 const MailSetting = (props: Props) => {
-  const { t } = useTranslation();
+  const { t } = useTranslation(['admin', 'commons']);
   const { adminAppContainer } = props;
 
   const transmissionMethods = ['smtp', 'ses'];
@@ -25,7 +25,7 @@ const MailSetting = (props: Props) => {
   async function submitHandler() {
     try {
       await adminAppContainer.updateMailSettingHandler();
-      toastSuccess(t('toaster.update_successed', { target: t('admin:app_setting.ses_settings') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:app_setting.ses_settings'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/App/PluginSetting.tsx

@@ -23,7 +23,7 @@ const PluginSetting = (props: Props) => {
   const submitHandler = useCallback(async() => {
     try {
       await adminAppContainer.updatePluginSettingHandler();
-      toastSuccess(t('toaster.update_successed', { target: t('admin:app_setting.plugin_settings') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:app_setting.plugin_settings'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/App/SiteUrlSetting.tsx

@@ -24,7 +24,7 @@ const SiteUrlSetting = (props: Props) => {
   const submitHandler = useCallback(async() => {
     try {
       await adminAppContainer.updateSiteUrlSettingHandler();
-      toastSuccess(t('toaster.update_successed', { target: t('Site URL settings') }));
+      toastSuccess(t('toaster.update_successed', { target: t('Site URL settings'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/Customize/CustomizeCssSetting.tsx

@@ -21,7 +21,7 @@ const CustomizeCssSetting = (props: Props): JSX.Element => {
   const onClickSubmit = useCallback(async() => {
     try {
       await adminCustomizeContainer.updateCustomizeCss();
-      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.custom_css') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.custom_css'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/Customize/CustomizeFunctionSetting.tsx

@@ -25,7 +25,7 @@ const CustomizeFunctionSetting = (props: Props): JSX.Element => {
 
     try {
       await adminCustomizeContainer.updateCustomizeFunction();
-      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.function') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.function'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/Customize/CustomizeHeaderSetting.tsx

@@ -21,7 +21,7 @@ const CustomizeHeaderSetting = (props: Props): JSX.Element => {
   const onClickSubmit = useCallback(async() => {
     try {
       await adminCustomizeContainer.updateCustomizeHeader();
-      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.custom_header') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.custom_header'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/Customize/CustomizeLayoutSetting.tsx

@@ -19,7 +19,7 @@ const CustomizeLayoutSetting = (): JSX.Element => {
   const onClickSubmit = async() => {
     try {
       await apiv3Put('/customize-setting/layout', { isContainerFluid });
-      toastSuccess(t('toaster.update_successed', { target: t('customize_settings.layout') }));
+      toastSuccess(t('toaster.update_successed', { target: t('customize_settings.layout'), ns: 'commons' }));
       mutateLayoutSetting();
     }
     catch (err) {

+ 3 - 3
packages/app/src/components/Admin/Customize/CustomizeLogoSetting.tsx

@@ -59,7 +59,7 @@ const CustomizeLogoSetting = (): JSX.Element => {
       const { customizedParams } = response.data;
       setIsDefaultLogo(customizedParams.isDefaultLogo);
       setCustomizedLogoSrc(customizedParams.customizedLogoSrc);
-      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.custom_logo') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.custom_logo'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);
@@ -70,7 +70,7 @@ const CustomizeLogoSetting = (): JSX.Element => {
     try {
       await apiv3Delete('/customize-setting/delete-brand-logo');
       setCustomizedLogoSrc(null);
-      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.current_logo') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.current_logo'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);
@@ -86,7 +86,7 @@ const CustomizeLogoSetting = (): JSX.Element => {
       formData.append('file', croppedImage);
       const { data } = await apiv3PostForm('/customize-setting/upload-brand-logo', formData);
       setCustomizedLogoSrc(data.attachment.filePathProxied);
-      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.current_logo') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.current_logo'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/Customize/CustomizeScriptSetting.tsx

@@ -21,7 +21,7 @@ const CustomizeScriptSetting = (props: Props): JSX.Element => {
   const onClickSubmit = useCallback(async() => {
     try {
       await adminCustomizeContainer.updateCustomizeScript();
-      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.custom_script') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.custom_script'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 3 - 2
packages/app/src/components/Admin/Customize/CustomizeSidebarSetting.tsx

@@ -8,7 +8,8 @@ import { useSWRxSidebarConfig } from '~/stores/ui';
 import { useNextThemes } from '~/stores/use-next-themes';
 
 const CustomizeSidebarsetting = (): JSX.Element => {
-  const { t } = useTranslation('admin');
+  const { t } = useTranslation(['admin', 'commons']);
+
   const {
     update, isSidebarDrawerMode, isSidebarClosedAtDockMode, setIsSidebarDrawerMode, setIsSidebarClosedAtDockMode,
   } = useSWRxSidebarConfig();
@@ -20,7 +21,7 @@ const CustomizeSidebarsetting = (): JSX.Element => {
   const onClickSubmit = useCallback(async() => {
     try {
       await update();
-      toastSuccess(t('toaster.update_successed', { target: t('customize_settings.default_sidebar_mode.title') }));
+      toastSuccess(t('toaster.update_successed', { target: t('customize_settings.default_sidebar_mode.title'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/Customize/CustomizeThemeSetting.tsx

@@ -35,7 +35,7 @@ const CustomizeThemeSetting = (props: Props): JSX.Element => {
         });
       }
 
-      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.theme') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.theme'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/Customize/CustomizeTitle.tsx

@@ -22,7 +22,7 @@ export const CustomizeTitle: FC = () => {
       await apiv3Put('/customize-setting/customize-title', {
         customizeTitle: currentCustomizeTitle,
       });
-      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.custom_title') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_settings.custom_title'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/MarkdownSetting/IndentForm.tsx

@@ -26,7 +26,7 @@ const IndentForm = (props: Props) => {
   const onClickSubmit = useCallback(async(props) => {
     try {
       await props.adminMarkDownContainer.updateIndentSetting();
-      toastSuccess(t('toaster.update_successed', { target: t('markdown_settings.indent_header') }));
+      toastSuccess(t('toaster.update_successed', { target: t('markdown_settings.indent_header'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/MarkdownSetting/LineBreakForm.jsx

@@ -27,7 +27,7 @@ class LineBreakForm extends React.Component {
 
     try {
       await this.props.adminMarkDownContainer.updateLineBreakSetting();
-      toastSuccess(t('toaster.update_successed', { target: t('markdown_settings.lineBreak_header') }));
+      toastSuccess(t('toaster.update_successed', { target: t('markdown_settings.lineBreak_header'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/MarkdownSetting/PresentationForm.jsx

@@ -25,7 +25,7 @@ class PresentationForm extends React.Component {
 
     try {
       await this.props.adminMarkDownContainer.updatePresentationSetting();
-      toastSuccess(t('toaster.update_successed', { target: t('markdown_settings.presentation_header') }));
+      toastSuccess(t('toaster.update_successed', { target: t('markdown_settings.presentation_header'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/MarkdownSetting/XssForm.jsx

@@ -28,7 +28,7 @@ class XssForm extends React.Component {
 
     try {
       await this.props.adminMarkDownContainer.updateXssSetting();
-      toastSuccess(t('toaster.update_successed', { target: t('markdown_settings.xss_header') }));
+      toastSuccess(t('toaster.update_successed', { target: t('markdown_settings.xss_header'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/Notification/GlobalNotification.jsx

@@ -22,7 +22,7 @@ const GlobalNotification = (props) => {
   const onClickSubmit = useCallback(async() => {
     try {
       await adminNotificationContainer.updateGlobalNotificationForPages();
-      toastSuccess(t('toaster.update_successed', { target: t('external_notification.external_notification') }));
+      toastSuccess(t('toaster.update_successed', { target: t('external_notification.external_notification'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/Security/SecuritySetting.jsx

@@ -453,7 +453,7 @@ class SecuritySetting extends React.Component {
           ].map(arr => this.renderPageDeletePermission(arr[0], arr[1], arr[2], arr[3]))
         }
 
-        <h4>{t('security_settings.session')}aa</h4>
+        <h4>{t('security_settings.session')}</h4>
         <div className="form-group row">
           <label className="text-left text-md-right col-md-3 col-form-label">{t('security_settings.max_age')}</label>
           <div className="col-md-6">

+ 2 - 2
packages/app/src/components/Admin/SlackIntegration/CustomBotWithProxySettings.jsx

@@ -50,7 +50,7 @@ const CustomBotWithProxySettings = (props) => {
       if (onPrimaryUpdated != null) {
         onPrimaryUpdated();
       }
-      toastSuccess(t('toaster.update_successed', { target: 'Primary' }));
+      toastSuccess(t('toaster.update_successed', { target: 'Primary', ns: 'commons' }));
     }
     catch (err) {
       toastError(err, 'Failed to change isPrimary');
@@ -77,7 +77,7 @@ const CustomBotWithProxySettings = (props) => {
       await apiv3Put('/slack-integration-settings/proxy-uri', {
         proxyUri: newProxyServerUri,
       });
-      toastSuccess(t('toaster.update_successed', { target: 'Proxy URL' }));
+      toastSuccess(t('toaster.update_successed', { target: 'Proxy URL', ns: 'commons' }));
     }
     catch (err) {
       toastError(err, 'Failed to update');

+ 1 - 1
packages/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySecretTokenSection.jsx

@@ -38,7 +38,7 @@ const CustomBotWithoutProxySecretTokenSection = (props) => {
         onUpdatedSecretToken(inputSigningSecret, inputBotToken);
       }
 
-      toastSuccess(t('toaster.update_successed', { target: t('admin:slack_integration.custom_bot_without_proxy_settings') }));
+      toastSuccess(t('toaster.update_successed', { target: t('admin:slack_integration.custom_bot_without_proxy_settings'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 2 - 2
packages/app/src/components/Admin/SlackIntegration/ManageCommandsProcess.jsx

@@ -1,8 +1,8 @@
 import React, { useCallback, useState } from 'react';
 
 import { defaultSupportedCommandsNameForBroadcastUse, defaultSupportedCommandsNameForSingleUse, defaultSupportedSlackEventActions } from '@growi/slack';
-import PropTypes from 'prop-types';
 import { useTranslation } from 'next-i18next';
+import PropTypes from 'prop-types';
 
 import { apiv3Put } from '~/client/util/apiv3-client';
 import loggerFactory from '~/utils/logger';
@@ -265,7 +265,7 @@ const ManageCommandsProcess = ({
         permissionsForSingleUseCommands: permissionsForSingleUseCommandsState,
         permissionsForSlackEventActions: permissionsForEventsState,
       });
-      toastSuccess(t('toaster.update_successed', { target: 'Token' }));
+      toastSuccess(t('toaster.update_successed', { target: 'Token', ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 2 - 2
packages/app/src/components/Admin/SlackIntegration/ManageCommandsProcessWithoutProxy.jsx

@@ -1,8 +1,8 @@
 import React, { useCallback, useEffect, useState } from 'react';
 
 import { defaultSupportedCommandsNameForBroadcastUse, defaultSupportedCommandsNameForSingleUse, defaultSupportedSlackEventActions } from '@growi/slack';
-import PropTypes from 'prop-types';
 import { useTranslation } from 'next-i18next';
+import PropTypes from 'prop-types';
 
 import { apiv3Put } from '~/client/util/apiv3-client';
 import loggerFactory from '~/utils/logger';
@@ -207,7 +207,7 @@ const ManageCommandsProcessWithoutProxy = ({ commandPermission, eventActionsPerm
         commandPermission: editingCommandPermission,
         eventActionsPermission: editingEventActionsPermission,
       });
-      toastSuccess(t('toaster.update_successed', { target: 'the permission for commands' }));
+      toastSuccess(t('toaster.update_successed', { target: 'the permission for commands', ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Admin/SlackIntegration/OfficialBotSettings.jsx

@@ -46,7 +46,7 @@ const OfficialBotSettings = (props) => {
       if (onPrimaryUpdated != null) {
         onPrimaryUpdated();
       }
-      toastSuccess(t('toaster.update_successed', { target: 'Primary' }));
+      toastSuccess(t('toaster.update_successed', { target: 'Primary', ns: 'commons' }));
     }
     catch (err) {
       toastError(err, 'Failed to change isPrimary');

+ 1 - 1
packages/app/src/components/Admin/SlackIntegration/WithProxyAccordions.jsx

@@ -153,7 +153,7 @@ const GeneratingTokensAndRegisteringProxyServiceProcess = withUnstatedContainers
       if (props.onUpdateTokens != null) {
         props.onUpdateTokens();
       }
-      toastSuccess(t('toaster.update_successed', { target: 'Token' }));
+      toastSuccess(t('toaster.update_successed', { target: 'Token', ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 2 - 2
packages/app/src/components/Admin/UserGroup/UserGroupPage.tsx

@@ -93,7 +93,7 @@ export const UserGroupPage: FC = () => {
         description: userGroupData.description,
       });
 
-      toastSuccess(t('toaster.update_successed', { target: t('UserGroup') }));
+      toastSuccess(t('toaster.update_successed', { target: t('UserGroup'), ns: 'commons' }));
 
       // mutate
       await mutateUserGroups();
@@ -112,7 +112,7 @@ export const UserGroupPage: FC = () => {
         description: userGroupData.description,
       });
 
-      toastSuccess(t('toaster.update_successed', { target: t('UserGroup') }));
+      toastSuccess(t('toaster.update_successed', { target: t('UserGroup'), ns: 'commons' }));
 
       // mutate
       await mutateUserGroups();

+ 5 - 5
packages/app/src/components/Admin/UserGroupDetail/UserGroupDetailPage.tsx

@@ -124,10 +124,10 @@ const UserGroupDetailPage = (props: Props): JSX.Element => {
     async(targetGroup: IUserGroupHasId, userGroupData: Partial<IUserGroupHasId>, forceUpdateParents: boolean): Promise<void> => {
       try {
         await updateUserGroup(targetGroup, userGroupData, forceUpdateParents);
-        toastSuccess(t('toaster.update_successed', { target: t('UserGroup') }));
+        toastSuccess(t('toaster.update_successed', { target: t('UserGroup'), ns: 'commons' }));
       }
       catch {
-        toastError(t('toaster.update_failed', { target: t('UserGroup') }));
+        toastError(t('toaster.update_failed', { target: t('UserGroup'), ns: 'commons' }));
       }
     },
     [t, updateUserGroup],
@@ -205,7 +205,7 @@ const UserGroupDetailPage = (props: Props): JSX.Element => {
         parentId: userGroupData.parent,
       });
 
-      toastSuccess(t('toaster.update_successed', { target: t('UserGroup') }));
+      toastSuccess(t('toaster.update_successed', { target: t('UserGroup'), ns: 'commons' }));
 
       // mutate
       mutateChildUserGroups();
@@ -244,7 +244,7 @@ const UserGroupDetailPage = (props: Props): JSX.Element => {
         parentId: currentUserGroupId,
       });
 
-      toastSuccess(t('toaster.update_successed', { target: t('UserGroup') }));
+      toastSuccess(t('toaster.update_successed', { target: t('UserGroup'), ns: 'commons' }));
 
       // mutate
       mutateChildUserGroups();
@@ -296,7 +296,7 @@ const UserGroupDetailPage = (props: Props): JSX.Element => {
         parentId: null,
       });
 
-      toastSuccess(t('toaster.update_successed', { target: t('UserGroup') }));
+      toastSuccess(t('toaster.update_successed', { target: t('UserGroup'), ns: 'commons' }));
 
       // mutate
       mutateChildUserGroups();

+ 1 - 1
packages/app/src/components/Me/ApiSettings.tsx

@@ -19,7 +19,7 @@ const ApiSettings = React.memo((): JSX.Element => {
       await apiv3Put('/personal-setting/api-token');
       mutateDatabaseData();
 
-      toastSuccess(t('toaster.update_successed', { target: t('page_me_apitoken.api_token') }));
+      toastSuccess(t('toaster.update_successed', { target: t('page_me_apitoken.api_token'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Me/BasicInfoSettings.tsx

@@ -22,7 +22,7 @@ export const BasicInfoSettings = (): JSX.Element => {
     try {
       await updateBasicInfo();
       sync();
-      toastSuccess(t('toaster.update_successed', { target: t('Basic Info') }));
+      toastSuccess(t('toaster.update_successed', { target: t('Basic Info'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Me/EditorSettings.tsx

@@ -234,7 +234,7 @@ export const EditorSettings = memo((): JSX.Element => {
   const updateRulesHandler = useCallback(async() => {
     try {
       await updateEditorSettings({ textlintSettings: { textlintRules } });
-      toastSuccess(t('toaster.update_successed', { target: 'Updated Textlint Settings' }));
+      toastSuccess(t('toaster.update_successed', { target: 'Updated Textlint Settings', ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Me/InAppNotificationSettings.tsx

@@ -54,7 +54,7 @@ const InAppNotificationSettings: FC = () => {
     try {
       const { data } = await apiv3Put('/personal-setting/in-app-notification-settings', { subscribeRules });
       setSubscribeRules(data.subscribeRules);
-      toastSuccess(t('toaster.update_successed', { target: 'InAppNotification Settings' }));
+      toastSuccess(t('toaster.update_successed', { target: 'InAppNotification Settings', ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 2 - 2
packages/app/src/components/Me/PasswordSettings.jsx

@@ -1,7 +1,7 @@
 import React, { useCallback } from 'react';
 
-import PropTypes from 'prop-types';
 import { useTranslation } from 'next-i18next';
+import PropTypes from 'prop-types';
 
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
@@ -52,7 +52,7 @@ class PasswordSettings extends React.Component {
       if (onSubmit != null) {
         onSubmit();
       }
-      toastSuccess(t('toaster.update_successed', { target: t('Password') }));
+      toastSuccess(t('toaster.update_successed', { target: t('Password'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 3 - 3
packages/app/src/components/Me/ProfileImageSettings.tsx

@@ -48,7 +48,7 @@ const ProfileImageSettings = (): JSX.Element => {
       formData.append('file', croppedImage);
       const response = await apiPostForm('/attachments.uploadProfileImage', formData);
 
-      toastSuccess(t('toaster.update_successed', { target: t('Current Image') }));
+      toastSuccess(t('toaster.update_successed', { target: t('Current Image'), ns: 'commons' }));
 
       // eslint-disable-next-line @typescript-eslint/no-explicit-any
       setUploadedPictureSrc((response as any).attachment.filePathProxied);
@@ -64,7 +64,7 @@ const ProfileImageSettings = (): JSX.Element => {
       await apiPost('/attachments.removeProfileImage');
 
       setUploadedPictureSrc(undefined);
-      toastSuccess(t('toaster.update_successed', { target: t('Current Image') }));
+      toastSuccess(t('toaster.update_successed', { target: t('Current Image'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);
@@ -78,7 +78,7 @@ const ProfileImageSettings = (): JSX.Element => {
       const { userData } = response.data;
       setGravatarEnabled(userData.isGravatarEnabled);
 
-      toastSuccess(t('toaster.update_successed', { target: t('Set Profile Image') }));
+      toastSuccess(t('toaster.update_successed', { target: t('Set Profile Image'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -330,7 +330,7 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
                     pageId={pageId}
                     revisionId={revisionId}
                     shareLinkId={shareLinkId}
-                    path={path}
+                    path={path ?? currentPathname} // If the page is empty, "path" is undefined
                     disableSeenUserInfoPopover={isSharedUser}
                     showPageControlDropdown={isAbleToShowPageManagement}
                     additionalMenuItemRenderer={additionalMenuItemsRenderer}

+ 22 - 14
packages/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -23,7 +23,8 @@ import EditorIcon from './EditorIcon';
 import EmojiPicker from './EmojiPicker';
 import EmojiPickerHelper from './EmojiPickerHelper';
 import GridEditModal from './GridEditModal';
-import geu from './GridEditorUtil';
+// TODO: re-impl with https://redmine.weseek.co.jp/issues/107248
+// import geu from './GridEditorUtil';
 // import HandsontableModal from './HandsontableModal';
 import LinkEditModal from './LinkEditModal';
 import mdu from './MarkdownDrawioUtil';
@@ -152,7 +153,8 @@ class CodeMirrorEditor extends AbstractEditor {
     this.renderCheatsheetModalButton = this.renderCheatsheetModalButton.bind(this);
 
     this.makeHeaderHandler = this.makeHeaderHandler.bind(this);
-    this.showGridEditorHandler = this.showGridEditorHandler.bind(this);
+    // TODO: re-impl with https://redmine.weseek.co.jp/issues/107248
+    // this.showGridEditorHandler = this.showGridEditorHandler.bind(this);
     this.showLinkEditHandler = this.showLinkEditHandler.bind(this);
     this.showHandsonTableHandler = this.showHandsonTableHandler.bind(this);
 
@@ -858,9 +860,10 @@ class CodeMirrorEditor extends AbstractEditor {
     cm.focus();
   }
 
-  showGridEditorHandler() {
-    this.gridEditModal.current.show(geu.getGridHtml(this.getCodeMirror()));
-  }
+  // TODO: re-impl with https://redmine.weseek.co.jp/issues/107248
+  // showGridEditorHandler() {
+  //   this.gridEditModal.current.show(geu.getGridHtml(this.getCodeMirror()));
+  // }
 
   showLinkEditHandler() {
     this.linkEditModal.current.show(markdownLinkUtil.getMarkdownLink(this.getCodeMirror()));
@@ -998,15 +1001,16 @@ class CodeMirrorEditor extends AbstractEditor {
       >
         <EditorIcon icon="Image" />
       </Button>,
-      <Button
-        key="nav-item-grid"
-        color={null}
-        size="sm"
-        title="Grid"
-        onClick={this.showGridEditorHandler}
-      >
-        <EditorIcon icon="Grid" />
-      </Button>,
+      // TODO: re-impl with https://redmine.weseek.co.jp/issues/107248
+      // <Button
+      //   key="nav-item-grid"
+      //   color={null}
+      //   size="sm"
+      //   title="Grid"
+      //   onClick={this.showGridEditorHandler}
+      // >
+      //   <EditorIcon icon="Grid" />
+      // </Button>,
       <Button
         key="nav-item-table"
         color={null}
@@ -1119,10 +1123,14 @@ class CodeMirrorEditor extends AbstractEditor {
         { this.renderCheatsheetOverlay() }
         { this.renderEmojiPicker() }
 
+        {/*
+        // TODO: re-impl with https://redmine.weseek.co.jp/issues/107248
         <GridEditModal
           ref={this.gridEditModal}
           onSave={(grid) => { return geu.replaceGridWithHtmlWithEditor(this.getCodeMirror(), grid) }}
         />
+         */}
+
         <LinkEditModal
           ref={this.linkEditModal}
           onSave={(linkText) => { return markdownLinkUtil.replaceFocusedMarkdownLinkWithEditor(this.getCodeMirror(), linkText) }}

+ 2 - 2
packages/app/src/components/PasswordResetExecutionForm.tsx

@@ -11,7 +11,7 @@ const logger = loggerFactory('growi:passwordReset');
 
 
 const PasswordResetExecutionForm: FC = () => {
-  const { t } = useTranslation();
+  const { t } = useTranslation(['translation', 'commons']);
 
   const [newPassword, setNewPassword] = useState('');
   const [newPasswordConfirm, setNewPasswordConfirm] = useState('');
@@ -41,7 +41,7 @@ const PasswordResetExecutionForm: FC = () => {
 
       setValidationErrorI18n('');
 
-      toastSuccess(t('toaster.update_successed', { target: t('Password') }));
+      toastSuccess(t('toaster.update_successed', { target: t('Password'), ns: 'commons' }));
     }
     catch (err) {
       toastError(err);

+ 9 - 7
packages/app/src/components/Sidebar/Tag.tsx

@@ -58,13 +58,15 @@ const Tag: FC = () => {
           </div>
         )
         : (
-          <TagList
-            tagData={tagData}
-            totalTags={totalCount}
-            activePage={activePage}
-            onChangePage={setOffsetByPageNumber}
-            pagingLimit={PAGING_LIMIT}
-          />
+          <div data-testid="grw-tags-list">
+            <TagList
+              tagData={tagData}
+              totalTags={totalCount}
+              activePage={activePage}
+              onChangePage={setOffsetByPageNumber}
+              pagingLimit={PAGING_LIMIT}
+            />
+          </div>
         )
       }
 

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

@@ -86,7 +86,7 @@ type Props = CommonProps & {
   siteUrl: string,
 };
 
-const AdminMarkdownSettingsPage: NextPage<Props> = (props: Props) => {
+const AdminPage: NextPage<Props> = (props: Props) => {
 
   const { t } = useTranslation('admin');
   const router = useRouter();
@@ -335,11 +335,11 @@ export const getServerSideProps: GetServerSideProps = async(context: GetServerSi
   }
 
   injectServerConfigurations(context, props);
-  await injectNextI18NextConfigurations(context, props, ['admin']);
+  await injectNextI18NextConfigurations(context, props, ['admin', 'commons']);
 
   return {
     props,
   };
 };
 
-export default AdminMarkdownSettingsPage;
+export default AdminPage;

+ 1 - 1
packages/app/src/pages/forgot-password.page.tsx

@@ -50,7 +50,7 @@ export const getServerSideProps: GetServerSideProps = async(context: GetServerSi
 
   const props: CommonProps = result.props as CommonProps;
 
-  await injectNextI18NextConfigurations(context, props, ['translation']);
+  await injectNextI18NextConfigurations(context, props, ['translation', 'commons']);
 
   return {
     props,

+ 1 - 1
packages/app/src/pages/me/[[...path]].page.tsx

@@ -198,7 +198,7 @@ export const getServerSideProps: GetServerSideProps = async(context: GetServerSi
 
   await injectUserUISettings(context, props);
   await injectServerConfigurations(context, props);
-  await injectNextI18NextConfigurations(context, props, ['translation', 'admin']);
+  await injectNextI18NextConfigurations(context, props, ['translation', 'admin', 'commons']);
 
   return {
     props,

+ 1 - 1
packages/app/src/pages/reset-password.page.tsx

@@ -62,7 +62,7 @@ export const getServerSideProps: GetServerSideProps = async(context: GetServerSi
     props.email = email;
   }
 
-  await injectNextI18NextConfigurations(context, props, ['translation']);
+  await injectNextI18NextConfigurations(context, props, ['translation', 'commons']);
 
   return {
     props,

+ 1 - 1
packages/app/src/pages/tags.page.tsx

@@ -63,7 +63,7 @@ const TagPage: NextPage<CommonProps> = (props: Props) => {
       <Head>
       </Head>
       <BasicLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')}>
-        <div className="grw-container-convertible mb-5 pb-5">
+        <div className="grw-container-convertible mb-5 pb-5" data-testid="tags-page">
           <h2 className="my-3">{`${t('Tags')}(${totalCount})`}</h2>
           <div className="px-3 mb-5 text-center">
             <TagCloudBox tags={tagData} minSize={20} />

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

@@ -85,6 +85,9 @@ module.exports = function(crowi, app) {
 
   app.get('/register'                 , applicationInstalled, login.preLogin, login.register);
 
+  // load before "/admin/*"
+  app.get('/admin/export/:fileName'             , loginRequiredStrictly , adminRequired ,admin.export.api.validators.export.download(), admin.export.download);
+
   app.get('/admin/*'                    , applicationInstalled, loginRequiredStrictly , adminRequired , next.delegateToNext);
   app.get('/admin'                    , applicationInstalled, loginRequiredStrictly , adminRequired , next.delegateToNext);
   // app.get('/admin/app'                , applicationInstalled, loginRequiredStrictly , adminRequired , admin.app.index);
@@ -153,7 +156,6 @@ module.exports = function(crowi, app) {
 
   // export management for admin
   // app.get('/admin/export'                       , loginRequiredStrictly , adminRequired ,admin.export.index);
-  // app.get('/admin/export/:fileName'             , loginRequiredStrictly , adminRequired ,admin.export.api.validators.export.download(), admin.export.download);
 
   // app.get('/admin/*'                            , loginRequiredStrictly ,adminRequired, admin.notFound.index);
 

+ 7 - 8
packages/app/test/cypress/integration/20-basic-features/access-to-page.spec.ts

@@ -18,13 +18,13 @@ context('Access to page', () => {
   it('/Sandbox with anchor hash is successfully loaded', () => {
     cy.visit('/Sandbox#Headers');
 
-    // hide fab
-    cy.getByTestid('grw-fab-container').invoke('attr', 'style', 'display: none');
+    // hide fab // disable fab for sticky-events warning
+    // cy.getByTestid('grw-fab-container').invoke('attr', 'style', 'display: none');
 
     // remove animation for screenshot
     // remove 'blink' class because ::after element cannot be operated
     // https://stackoverflow.com/questions/5041494/selecting-and-manipulating-css-pseudo-elements-such-as-before-and-after-usin/21709814#21709814
-    cy.get('#Headers').invoke('removeClass', 'blink');
+    cy.get('#mdcont-headers').invoke('removeClass', 'blink');
 
     cy.screenshot(`${ssPrefix}-sandbox-headers`);
   });
@@ -32,7 +32,6 @@ context('Access to page', () => {
   it('/Sandbox/Math is successfully loaded', () => {
     cy.visit('/Sandbox/Math');
 
-    cy.get('mjx-container').should('be.visible');
     // eslint-disable-next-line cypress/no-unnecessary-waiting
     cy.wait(2000); // wait for 2 seconds for MathJax.typesetPromise();
 
@@ -71,10 +70,10 @@ context('Access to /me page', () => {
     cy.screenshot(`${ssPrefix}-me`);
   });
 
-  it('Draft page is successfully shown', () => {
-    cy.visit('/me/drafts');
-    cy.screenshot(`${ssPrefix}-draft-page`);
-  });
+  // it('Draft page is successfully shown', () => {
+  //   cy.visit('/me/drafts');
+  //   cy.screenshot(`${ssPrefix}-draft-page`);
+  // });
 
 });
 

+ 2 - 2
packages/app/test/cypress/integration/21-basic-features-for-guest/access-to-page.spec.ts

@@ -14,8 +14,8 @@ context('Access to page by guest', () => {
     // eslint-disable-next-line cypress/no-unnecessary-waiting
     cy.wait(500);
 
-    // hide fab
-    cy.getByTestid('grw-fab-container').invoke('attr', 'style', 'display: none');
+    // hide fab // disable fab for sticky-events warning
+    // cy.getByTestid('grw-fab-container').invoke('attr', 'style', 'display: none');
 
     cy.screenshot(`${ssPrefix}-sandbox-headers`);
   });

+ 5 - 3
packages/app/test/cypress/integration/60-home/home.spec.ts

@@ -15,7 +15,9 @@ context('Access Home', () => {
     cy.getByTestid('grw-personal-dropdown').click();
     cy.getByTestid('grw-personal-dropdown').find('.dropdown-menu .btn-group > .btn-outline-secondary:eq(0)').click();
 
-    cy.getByTestid('grw-user-page').should('be.visible');
+    cy.get('.grw-users-info').should('be.visible');
+    // for check download toc data
+    cy.get('.toc-link').should('be.visible');
 
     cy.screenshot(`${ssPrefix}-visit-home`);
   });
@@ -34,8 +36,8 @@ context('Access User settings', () => {
     // collapse sidebar
     cy.collapseSidebar(true);
     cy.visit('/me');
-    // hide fab
-    cy.getByTestid('grw-fab-container').invoke('attr', 'style', 'display: none');
+    // hide fab // disable fab for sticky-events warning
+    // cy.getByTestid('grw-fab-container').invoke('attr', 'style', 'display: none');
   });
 
   it('Access User information', () => {