Răsfoiți Sursa

Merge pull request #6726 from weseek/fix/106123-normalization-custom-title

fix: Normalization Custom Title
Yuki Takei 3 ani în urmă
părinte
comite
a6ab34509b

+ 1 - 1
packages/app/src/components/Admin/Customize/Customize.jsx

@@ -19,7 +19,7 @@ import CustomizeLogoSetting from './CustomizeLogoSetting';
 import CustomizeScriptSetting from './CustomizeScriptSetting';
 import CustomizeScriptSetting from './CustomizeScriptSetting';
 import CustomizeSidebarSetting from './CustomizeSidebarSetting';
 import CustomizeSidebarSetting from './CustomizeSidebarSetting';
 import CustomizeThemeSetting from './CustomizeThemeSetting';
 import CustomizeThemeSetting from './CustomizeThemeSetting';
-import CustomizeTitle from './CustomizeTitle';
+import { CustomizeTitle } from './CustomizeTitle';
 
 
 const logger = loggerFactory('growi:services:AdminCustomizePage');
 const logger = loggerFactory('growi:services:AdminCustomizePage');
 
 

+ 0 - 96
packages/app/src/components/Admin/Customize/CustomizeTitle.jsx

@@ -1,96 +0,0 @@
-/* eslint-disable max-len */
-import React from 'react';
-
-import { withTranslation } from 'next-i18next';
-import PropTypes from 'prop-types';
-import { Card, CardBody } from 'reactstrap';
-
-import AdminCustomizeContainer from '~/client/services/AdminCustomizeContainer';
-import { toastSuccess, toastError } from '~/client/util/apiNotification';
-
-import { withUnstatedContainers } from '../../UnstatedUtils';
-import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
-
-class CustomizeTitle extends React.Component {
-
-  constructor(props) {
-    super(props);
-
-    this.onClickSubmit = this.onClickSubmit.bind(this);
-  }
-
-  async onClickSubmit() {
-    const { t, adminCustomizeContainer } = this.props;
-
-    try {
-      await adminCustomizeContainer.updateCustomizeTitle();
-      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_setting.custom_title') }));
-    }
-    catch (err) {
-      toastError(err);
-    }
-  }
-
-  render() {
-    const { t, adminCustomizeContainer } = this.props;
-    const { currentCustomizeTitle } = adminCustomizeContainer.state;
-
-    return (
-      <React.Fragment>
-        <div className="row">
-          <div className="col-12">
-            <h2 className="admin-setting-header">{t('admin:customize_setting.custom_title')}</h2>
-          </div>
-
-          <div className="col-12">
-            <Card className="card well">
-              <CardBody className="px-0 py-2">
-                {/* eslint-disable react/no-danger */}
-                <p dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.custom_title_detail') }} />
-                <ul>
-                  <li>
-                    <span dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.custom_title_detail_placeholder1') }} />
-                  </li>
-                  <li>
-                    <span dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.custom_title_detail_placeholder2') }} />
-                  </li>
-                  <li>
-                    <span dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.custom_title_detail_placeholder3') }} />
-                  </li>
-                </ul>
-                {/* eslint-enable react/no-danger */}
-              </CardBody>
-            </Card>
-          </div>
-
-          {/* TODO i18n */}
-          <div className="form-text text-muted col-12">
-            Default Value: <code>&#123;&#123;pagename&#125;&#125; - &#123;&#123;sitename&#125;&#125;</code>
-            <br />
-            Default Output Example: <code className="xml">&lt;title&gt;Page name - My GROWI&lt;&#047;title&gt;</code>
-          </div>
-          <div className="form-group col-12">
-            <input
-              className="form-control"
-              defaultValue={currentCustomizeTitle}
-              onChange={(e) => { adminCustomizeContainer.changeCustomizeTitle(e.target.value) }}
-            />
-          </div>
-          <div className="col-12">
-            <AdminUpdateButtonRow onClick={this.onClickSubmit} disabled={adminCustomizeContainer.state.retrieveError != null} />
-          </div>
-        </div>
-      </React.Fragment>
-    );
-  }
-
-}
-
-const CustomizeTitleWrapper = withUnstatedContainers(CustomizeTitle, [AdminCustomizeContainer]);
-
-CustomizeTitle.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-  adminCustomizeContainer: PropTypes.instanceOf(AdminCustomizeContainer).isRequired,
-};
-
-export default withTranslation()(CustomizeTitleWrapper);

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

@@ -0,0 +1,79 @@
+import React, { FC, useState } from 'react';
+
+import { useTranslation } from 'next-i18next';
+import { Card, CardBody } from 'reactstrap';
+
+import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Put } from '~/client/util/apiv3-client';
+import { useCustomizeTitle } from '~/stores/context';
+
+import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
+
+export const CustomizeTitle: FC = () => {
+
+  const { t } = useTranslation('admin');
+
+  const { data: customizeTitle } = useCustomizeTitle();
+
+  const [currentCustomizeTitle, setCrrentCustomizeTitle] = useState(customizeTitle);
+
+  const onClickSubmit = async() => {
+    try {
+      await apiv3Put('/customize-setting/customize-title', {
+        customizeTitle: currentCustomizeTitle,
+      });
+      toastSuccess(t('toaster.update_successed', { target: t('admin:customize_setting.custom_title') }));
+    }
+    catch (err) {
+      toastError(err);
+    }
+  };
+
+  return (
+    <React.Fragment>
+      <div className="row">
+        <div className="col-12">
+          <h2 className="admin-setting-header">{t('admin:customize_settings.custom_title')}</h2>
+        </div>
+
+        <div className="col-12">
+          <Card className="card well">
+            <CardBody className="px-0 py-2">
+              {/* eslint-disable react/no-danger */}
+              <p dangerouslySetInnerHTML={{ __html: t('admin:customize_settings.custom_title_detail') }} />
+              <ul>
+                <li>
+                  <span dangerouslySetInnerHTML={{ __html: t('admin:customize_settings.custom_title_detail_placeholder1') }} />
+                </li>
+                <li>
+                  <span dangerouslySetInnerHTML={{ __html: t('admin:customize_settings.custom_title_detail_placeholder2') }} />
+                </li>
+                <li>
+                  <span dangerouslySetInnerHTML={{ __html: t('admin:customize_settings.custom_title_detail_placeholder3') }} />
+                </li>
+              </ul>
+              {/* eslint-enable react/no-danger */}
+            </CardBody>
+          </Card>
+        </div>
+
+        {/* TODO i18n */}
+        <div className="form-text text-muted col-12">
+            Default Value: <code>&#123;&#123;pagename&#125;&#125; - &#123;&#123;sitename&#125;&#125;</code>
+          <br />
+            Default Output Example: <code className="xml">&lt;title&gt;Page name - My GROWI&lt;&#047;title&gt;</code>
+        </div>
+        <div className="form-group col-12">
+          <input
+            className="form-control"
+            defaultValue={currentCustomizeTitle}
+            onChange={(e) => { setCrrentCustomizeTitle(e.target.value) }}
+          />
+        </div>
+        <div className="col-12">
+          <AdminUpdateButtonRow onClick={onClickSubmit} disabled={false} />
+        </div>
+      </div>
+    </React.Fragment>
+  );
+};

+ 4 - 3
packages/app/src/components/Layout/AdminLayout.tsx

@@ -13,6 +13,7 @@ const AdminNotFoundPage = dynamic(() => import('../Admin/NotFoundPage').then(mod
 
 
 type Props = {
 type Props = {
   title: string
   title: string
+  componentTitle: string
   /**
   /**
    * Set the current option of AdminNavigation
    * Set the current option of AdminNavigation
    * Expected it is in ["home", "app", "security", "markdown", "customize", "importer", "export",
    * Expected it is in ["home", "app", "security", "markdown", "customize", "importer", "export",
@@ -24,7 +25,7 @@ type Props = {
 
 
 
 
 const AdminLayout = ({
 const AdminLayout = ({
-  children, title, selectedNavOpt,
+  children, title, selectedNavOpt, componentTitle,
 }: Props): JSX.Element => {
 }: Props): JSX.Element => {
 
 
   const AdminNavigation = dynamic(() => import('~/components/Admin/Common/AdminNavigation'), { ssr: false });
   const AdminNavigation = dynamic(() => import('~/components/Admin/Common/AdminNavigation'), { ssr: false });
@@ -35,8 +36,8 @@ const AdminLayout = ({
       <div className={`admin-page ${styles['admin-page']}`}>
       <div className={`admin-page ${styles['admin-page']}`}>
         <GrowiNavbar />
         <GrowiNavbar />
 
 
-        <header className="py-0 position-relative">
-          <h1 className="title px-3">{title}</h1>
+        <header className="py-0 container-fluid">
+          <h1 className="title px-3">{componentTitle}</h1>
         </header>
         </header>
         <div id="main" className="main">
         <div id="main" className="main">
           <div className="container-fluid">
           <div className="container-fluid">

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

@@ -34,12 +34,12 @@ import PluginUtils from '~/server/plugins/plugin-utils';
 import ConfigLoader from '~/server/service/config-loader';
 import ConfigLoader from '~/server/service/config-loader';
 import {
 import {
   useCurrentUser, /* useSearchServiceConfigured, */ useIsAclEnabled, useIsMailerSetup, useIsSearchServiceReachable, useSiteUrl,
   useCurrentUser, /* useSearchServiceConfigured, */ useIsAclEnabled, useIsMailerSetup, useIsSearchServiceReachable, useSiteUrl,
-  useAuditLogEnabled, useAuditLogAvailableActions, useIsSearchPage,
+  useAuditLogEnabled, useAuditLogAvailableActions, useIsSearchPage, useCustomizeTitle,
 } from '~/stores/context';
 } from '~/stores/context';
 import { useIsMaintenanceMode } from '~/stores/maintenanceMode';
 import { useIsMaintenanceMode } from '~/stores/maintenanceMode';
 
 
 import {
 import {
-  CommonProps, getServerSideCommonProps, getNextI18NextConfig,
+  CommonProps, getServerSideCommonProps, getNextI18NextConfig, useCustomTitle,
 } from '../utils/commons';
 } from '../utils/commons';
 
 
 
 
@@ -82,6 +82,7 @@ type Props = CommonProps & {
   auditLogEnabled: boolean,
   auditLogEnabled: boolean,
   auditLogAvailableActions: SupportedActionType[],
   auditLogAvailableActions: SupportedActionType[],
 
 
+  customizeTitle: string,
   siteUrl: string,
   siteUrl: string,
 };
 };
 
 
@@ -207,6 +208,8 @@ const AdminMarkdownSettingsPage: NextPage<Props> = (props: Props) => {
   useAuditLogEnabled(props.auditLogEnabled);
   useAuditLogEnabled(props.auditLogEnabled);
   useAuditLogAvailableActions(props.auditLogAvailableActions);
   useAuditLogAvailableActions(props.auditLogAvailableActions);
 
 
+  useCustomizeTitle(props.customizeTitle);
+
   const injectableContainers: Container<any>[] = [];
   const injectableContainers: Container<any>[] = [];
 
 
   if (isClient()) {
   if (isClient()) {
@@ -269,7 +272,7 @@ const AdminMarkdownSettingsPage: NextPage<Props> = (props: Props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers, ...adminSecurityContainers]}>
     <Provider inject={[...injectableContainers, ...adminSecurityContainers]}>
-      <AdminLayout title={targetPage.title} selectedNavOpt={firstPath}>
+      <AdminLayout title={useCustomTitle(props, targetPage.title)} selectedNavOpt={firstPath} componentTitle={targetPage.title}>
         {targetPage.component}
         {targetPage.component}
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>
@@ -299,6 +302,7 @@ async function injectServerConfigurations(context: GetServerSidePropsContext, pr
 
 
   props.auditLogEnabled = crowi.configManager.getConfig('crowi', 'app:auditLogEnabled');
   props.auditLogEnabled = crowi.configManager.getConfig('crowi', 'app:auditLogEnabled');
   props.auditLogAvailableActions = activityService.getAvailableActions(false);
   props.auditLogAvailableActions = activityService.getAvailableActions(false);
+  props.customizeTitle = crowi.configManager.getConfig('crowi', 'customize:title');
 }
 }
 
 
 /**
 /**

+ 4 - 0
packages/app/src/stores/context.tsx

@@ -258,6 +258,10 @@ export const useShowPageLimitationXL = (initialData?: number): SWRResponse<numbe
   return useStaticSWR('showPageLimitationXL', initialData);
   return useStaticSWR('showPageLimitationXL', initialData);
 };
 };
 
 
+export const useCustomizeTitle = (initialData?: string): SWRResponse<string, Error> => {
+  return useStaticSWR('CustomizeTitle', initialData);
+};
+
 /** **********************************************************
 /** **********************************************************
  *                     Computed contexts
  *                     Computed contexts
  *********************************************************** */
  *********************************************************** */