Răsfoiți Sursa

Merge pull request #1617 from weseek/fix/fetch-config-before-rendering

Fix/fetch config before rendering
Yuki Takei 6 ani în urmă
părinte
comite
14fe6e5165

+ 1 - 0
src/client/js/components/Admin/CustomCssEditor.jsx

@@ -21,6 +21,7 @@ export default class CustomCssEditor extends React.Component {
       <CodeMirror
         value={this.props.value}
         autoFocus
+        detach
         options={{
           mode: 'css',
           lineNumbers: true,

+ 1 - 0
src/client/js/components/Admin/CustomHeaderEditor.jsx

@@ -19,6 +19,7 @@ export default class CustomHeaderEditor extends React.Component {
       <CodeMirror
         value={this.props.value}
         autoFocus
+        detach
         options={{
           mode: 'htmlmixed',
           lineNumbers: true,

+ 1 - 0
src/client/js/components/Admin/CustomScriptEditor.jsx

@@ -21,6 +21,7 @@ export default class CustomScriptEditor extends React.Component {
       <CodeMirror
         value={this.props.value}
         autoFocus
+        detach
         options={{
           mode: 'javascript',
           lineNumbers: true,

+ 13 - 6
src/client/js/components/Admin/Customize/Customize.jsx

@@ -3,8 +3,6 @@ import React, { Fragment } from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import loggerFactory from '@alias/logger';
-
 import AppContainer from '../../../services/AppContainer';
 import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
 
@@ -20,25 +18,34 @@ import CustomizeScriptSetting from './CustomizeScriptSetting';
 import CustomizeHeaderSetting from './CustomizeHeaderSetting';
 import CustomizeTitle from './CustomizeTitle';
 
-const logger = loggerFactory('growi:Customize');
-
 class Customize extends React.Component {
 
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      isRetrieving: true,
+    };
+
+  }
+
   async componentDidMount() {
     const { adminCustomizeContainer } = this.props;
 
     try {
       await adminCustomizeContainer.retrieveCustomizeData();
+      this.setState({ isRetrieving: false });
     }
     catch (err) {
       toastError(err);
-      adminCustomizeContainer.setState({ retrieveError: err });
-      logger.error(err);
     }
 
   }
 
   render() {
+    if (this.state.isRetrieving) {
+      return null;
+    }
 
     return (
       <Fragment>

+ 0 - 4
src/client/js/components/Admin/Customize/CustomizeBehaviorSetting.jsx

@@ -3,8 +3,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import loggerFactory from '@alias/logger';
-
 import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
@@ -14,7 +12,6 @@ import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
 import CustomizeBehaviorOption from './CustomizeBehaviorOption';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 
-const logger = loggerFactory('growi:Customize');
 
 class CustomizeBehaviorSetting extends React.Component {
 
@@ -33,7 +30,6 @@ class CustomizeBehaviorSetting extends React.Component {
     }
     catch (err) {
       toastError(err);
-      logger.error(err);
     }
   }
 

+ 1 - 16
src/client/js/components/Admin/Customize/CustomizeCssSetting.jsx

@@ -2,8 +2,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import loggerFactory from '@alias/logger';
-
 import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
@@ -13,25 +11,14 @@ import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 import CustomCssEditor from '../CustomCssEditor';
 
-const logger = loggerFactory('growi:Customize');
-
 class CustomizeCssSetting extends React.Component {
 
   constructor(props) {
     super(props);
 
-    this.state = {
-      editorInputValue: '',
-    };
-
     this.onClickSubmit = this.onClickSubmit.bind(this);
   }
 
-  componentDidMount() {
-    const { customizeCss } = this.props.appContainer.getConfig();
-    this.setState({ editorInputValue: customizeCss || '' });
-  }
-
   async onClickSubmit() {
     const { t, adminCustomizeContainer } = this.props;
 
@@ -41,7 +28,6 @@ class CustomizeCssSetting extends React.Component {
     }
     catch (err) {
       toastError(err);
-      logger.error(err);
     }
   }
 
@@ -58,8 +44,7 @@ class CustomizeCssSetting extends React.Component {
         <div className="form-group">
           <div className="col-xs-12">
             <CustomCssEditor
-              // The value passed must be immutable
-              value={this.state.editorInputValue}
+              value={adminCustomizeContainer.state.currentCustomizeCss || ''}
               onChange={(inputValue) => { adminCustomizeContainer.changeCustomizeCss(inputValue) }}
             />
           </div>

+ 0 - 5
src/client/js/components/Admin/Customize/CustomizeFunctionSetting.jsx

@@ -2,8 +2,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import loggerFactory from '@alias/logger';
-
 import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
@@ -13,8 +11,6 @@ import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 import CustomizeFunctionOption from './CustomizeFunctionOption';
 
-const logger = loggerFactory('growi:importer');
-
 class CustomizeBehaviorSetting extends React.Component {
 
   constructor(props) {
@@ -32,7 +28,6 @@ class CustomizeBehaviorSetting extends React.Component {
     }
     catch (err) {
       toastError(err);
-      logger.error(err);
     }
   }
 

+ 1 - 16
src/client/js/components/Admin/Customize/CustomizeHeaderSetting.jsx

@@ -2,8 +2,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import loggerFactory from '@alias/logger';
-
 import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
@@ -13,25 +11,14 @@ import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 import CustomHeaderEditor from '../CustomHeaderEditor';
 
-const logger = loggerFactory('growi:Customize');
-
 class CustomizeHeaderSetting extends React.Component {
 
   constructor(props) {
     super(props);
 
-    this.state = {
-      editorInputValue: '',
-    };
-
     this.onClickSubmit = this.onClickSubmit.bind(this);
   }
 
-  componentDidMount() {
-    const { customizeHeader } = this.props.appContainer.getConfig();
-    this.setState({ editorInputValue: customizeHeader || '' });
-  }
-
   async onClickSubmit() {
     const { t, adminCustomizeContainer } = this.props;
 
@@ -41,7 +28,6 @@ class CustomizeHeaderSetting extends React.Component {
     }
     catch (err) {
       toastError(err);
-      logger.error(err);
     }
   }
 
@@ -68,8 +54,7 @@ class CustomizeHeaderSetting extends React.Component {
 
         <div className="col-xs-12">
           <CustomHeaderEditor
-            // The value passed must be immutable
-            value={this.state.editorInputValue}
+            value={adminCustomizeContainer.state.currentCustomizeHeader || ''}
             onChange={(inputValue) => { adminCustomizeContainer.changeCustomizeHeader(inputValue) }}
           />
         </div>

+ 0 - 5
src/client/js/components/Admin/Customize/CustomizeHighlightSetting.jsx

@@ -3,8 +3,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import loggerFactory from '@alias/logger';
-
 import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
@@ -13,8 +11,6 @@ import AppContainer from '../../../services/AppContainer';
 import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 
-const logger = loggerFactory('growi:customizeHighlight');
-
 class CustomizeHighlightSetting extends React.Component {
 
   constructor(props) {
@@ -32,7 +28,6 @@ class CustomizeHighlightSetting extends React.Component {
     }
     catch (err) {
       toastError(err);
-      logger.error(err);
     }
   }
 

+ 0 - 6
src/client/js/components/Admin/Customize/CustomizeLayoutSetting.jsx

@@ -2,8 +2,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import loggerFactory from '@alias/logger';
-
 import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
@@ -14,9 +12,6 @@ import CustomizeThemeOptions from './CustomizeThemeOptions';
 import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 
-const logger = loggerFactory('growi:importer');
-
-
 class CustomizeLayoutSetting extends React.Component {
 
   constructor(props) {
@@ -34,7 +29,6 @@ class CustomizeLayoutSetting extends React.Component {
     }
     catch (err) {
       toastError(err);
-      logger.error(err);
     }
   }
 

+ 1 - 16
src/client/js/components/Admin/Customize/CustomizeScriptSetting.jsx

@@ -2,8 +2,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import loggerFactory from '@alias/logger';
-
 import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
@@ -13,25 +11,14 @@ import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 import CustomScriptEditor from '../CustomScriptEditor';
 
-const logger = loggerFactory('growi:customizeScript');
-
 class CustomizeScriptSetting extends React.Component {
 
   constructor(props) {
     super(props);
 
-    this.state = {
-      editorInputValue: '',
-    };
-
     this.onClickSubmit = this.onClickSubmit.bind(this);
   }
 
-  componentDidMount() {
-    const { customizeScript } = this.props.appContainer.getConfig();
-    this.setState({ editorInputValue: customizeScript || '' });
-  }
-
   async onClickSubmit() {
     const { t, adminCustomizeContainer } = this.props;
 
@@ -41,7 +28,6 @@ class CustomizeScriptSetting extends React.Component {
     }
     catch (err) {
       toastError(err);
-      logger.error(err);
     }
   }
 
@@ -89,8 +75,7 @@ class CustomizeScriptSetting extends React.Component {
         <div className="form-group">
           <div className="col-xs-12">
             <CustomScriptEditor
-              // The value passed must be immutable
-              value={this.state.editorInputValue}
+              value={adminCustomizeContainer.state.currentCustomizeScript || ''}
               onChange={(inputValue) => { adminCustomizeContainer.changeCustomizeScript(inputValue) }}
             />
           </div>

+ 1 - 6
src/client/js/components/Admin/Customize/CustomizeTitle.jsx

@@ -2,16 +2,12 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import loggerFactory from '@alias/logger';
-
 import AppContainer from '../../../services/AppContainer';
 import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
-const logger = loggerFactory('growi:Customize');
-
 class CustomizeTitle extends React.Component {
 
   constructor(props) {
@@ -29,7 +25,6 @@ class CustomizeTitle extends React.Component {
     }
     catch (err) {
       toastError(err);
-      logger.error(err);
     }
   }
 
@@ -42,7 +37,7 @@ class CustomizeTitle extends React.Component {
         <h2 className="admin-setting-header">{t('admin:customize_setting.custom_title')}</h2>
         <p
           className="well"
-          // eslint-disable-next-line react/no-danger, max-len
+          // eslint-disable-next-line react/no-danger
           dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.custom_title_detail') }}
         />
         {/* TODO i18n */}

+ 118 - 54
src/client/js/services/AdminCustomizeContainer.js

@@ -88,8 +88,9 @@ export default class AdminCustomizeContainer extends Container {
       this.setState({ currentHighlightJsStyleName: this.state.highlightJsCssSelectorOptions[customizeParams.styleName].name });
     }
     catch (err) {
+      this.setState({ retrieveError: err });
       logger.error(err);
-      toastError(new Error('Failed to fetch data'));
+      throw new Error('Failed to fetch data');
     }
   }
 
@@ -237,98 +238,153 @@ export default class AdminCustomizeContainer extends Container {
   /**
    * Update layout
    * @memberOf AdminCustomizeContainer
-   * @return {Array} Appearance
    */
   async updateCustomizeLayoutAndTheme() {
-    const response = await this.appContainer.apiv3.put('/customize-setting/layout-theme', {
-      layoutType: this.state.currentLayout,
-      themeType: this.state.currentTheme,
-    });
-    const { customizedParams } = response.data;
-    return customizedParams;
+    try {
+      const response = await this.appContainer.apiv3.put('/customize-setting/layout-theme', {
+        layoutType: this.state.currentLayout,
+        themeType: this.state.currentTheme,
+      });
+      const { customizedParams } = response.data;
+      this.setState({
+        layoutType: customizedParams.layoutType,
+        themeType: customizedParams.themeType,
+      });
+    }
+    catch (err) {
+      logger.error(err);
+      throw new Error('Failed to update data');
+    }
   }
 
   /**
    * Update behavior
    * @memberOf AdminCustomizeContainer
-   * @return {string} Behavior
    */
   async updateCustomizeBehavior() {
-    const response = await this.appContainer.apiv3.put('/customize-setting/behavior', {
-      behaviorType: this.state.currentBehavior,
-    });
-    const { customizedParams } = response.data;
-    return customizedParams;
+    try {
+      const response = await this.appContainer.apiv3.put('/customize-setting/behavior', {
+        behaviorType: this.state.currentBehavior,
+      });
+      const { customizedParams } = response.data;
+      this.setState({
+        behaviorType: customizedParams.behaviorType,
+      });
+    }
+    catch (err) {
+      logger.error(err);
+      throw new Error('Failed to update data');
+    }
   }
 
   /**
    * Update function
    * @memberOf AdminCustomizeContainer
-   * @return {string} Functions
    */
   async updateCustomizeFunction() {
-    const response = await this.appContainer.apiv3.put('/customize-setting/function', {
-      isEnabledTimeline: this.state.isEnabledTimeline,
-      isSavedStatesOfTabChanges: this.state.isSavedStatesOfTabChanges,
-      isEnabledAttachTitleHeader: this.state.isEnabledAttachTitleHeader,
-      recentCreatedLimit: this.state.currentRecentCreatedLimit,
-      isEnabledStaleNotification: this.state.isEnabledStaleNotification,
-    });
-    const { customizedParams } = response.data;
-    return customizedParams;
+    try {
+      const response = await this.appContainer.apiv3.put('/customize-setting/function', {
+        isEnabledTimeline: this.state.isEnabledTimeline,
+        isSavedStatesOfTabChanges: this.state.isSavedStatesOfTabChanges,
+        isEnabledAttachTitleHeader: this.state.isEnabledAttachTitleHeader,
+        recentCreatedLimit: this.state.currentRecentCreatedLimit,
+        isEnabledStaleNotification: this.state.isEnabledStaleNotification,
+      });
+      const { customizedParams } = response.data;
+      this.setState({
+        isEnabledTimeline: customizedParams.isEnabledTimeline,
+        isSavedStatesOfTabChanges: customizedParams.isSavedStatesOfTabChanges,
+        isEnabledAttachTitleHeader: customizedParams.isEnabledAttachTitleHeader,
+        recentCreatedLimit: customizedParams.currentRecentCreatedLimit,
+        isEnabledStaleNotification: customizedParams.isEnabledStaleNotification,
+      });
+    }
+    catch (err) {
+      logger.error(err);
+      throw new Error('Failed to update data');
+    }
   }
 
   /**
    * Update code highlight
    * @memberOf AdminCustomizeContainer
-   * @return {Array} Code highlight
    */
   async updateHighlightJsStyle() {
-    const response = await this.appContainer.apiv3.put('/customize-setting/highlight', {
-      highlightJsStyle: this.state.currentHighlightJsStyleId,
-      highlightJsStyleBorder: this.state.isHighlightJsStyleBorderEnabled,
-    });
-    const { customizedParams } = response.data;
-    return customizedParams;
+    try {
+      const response = await this.appContainer.apiv3.put('/customize-setting/highlight', {
+        highlightJsStyle: this.state.currentHighlightJsStyleId,
+        highlightJsStyleBorder: this.state.isHighlightJsStyleBorderEnabled,
+      });
+      const { customizedParams } = response.data;
+      this.setState({
+        highlightJsStyle: customizedParams.highlightJsStyle,
+        highlightJsStyleBorder: customizedParams.highlightJsStyleBorder,
+      });
+    }
+    catch (err) {
+      logger.error(err);
+      throw new Error('Failed to update data');
+    }
   }
 
   /**
    * Update customTitle
    * @memberOf AdminCustomizeContainer
-   * @return {string} Customize title
    */
   async updateCustomizeTitle() {
-    const response = await this.appContainer.apiv3.put('/customize-setting/customize-title', {
-      customizeTitle: this.state.currentCustomizeTitle,
-    });
-    const { customizedParams } = response.data;
-    return customizedParams;
+    try {
+      const response = await this.appContainer.apiv3.put('/customize-setting/customize-title', {
+        customizeTitle: this.state.currentCustomizeTitle,
+      });
+      const { customizedParams } = response.data;
+      this.setState({
+        customizeTitle: customizedParams.customizeTitle,
+      });
+    }
+    catch (err) {
+      logger.error(err);
+      throw new Error('Failed to update data');
+    }
   }
 
   /**
    * Update customHeader
    * @memberOf AdminCustomizeContainer
-   * @return {string} Customize html header
    */
   async updateCustomizeHeader() {
-    const response = await this.appContainer.apiv3.put('/customize-setting/customize-header', {
-      customizeHeader: this.state.currentCustomizeHeader,
-    });
-    const { customizedParams } = response.data;
-    return customizedParams;
+    try {
+      const response = await this.appContainer.apiv3.put('/customize-setting/customize-header', {
+        customizeHeader: this.state.currentCustomizeHeader,
+      });
+      const { customizedParams } = response.data;
+      this.setState({
+        currentCustomizeHeader: customizedParams.customizeHeader,
+      });
+    }
+    catch (err) {
+      logger.error(err);
+      throw new Error('Failed to update data');
+    }
   }
 
   /**
    * Update customCss
    * @memberOf AdminCustomizeContainer
-   * @return {string} Customize css
    */
   async updateCustomizeCss() {
-    const response = await this.appContainer.apiv3.put('/customize-setting/customize-css', {
-      customizeCss: this.state.currentCustomizeCss,
-    });
-    const { customizedParams } = response.data;
-    return customizedParams;
+    try {
+      const response = await this.appContainer.apiv3.put('/customize-setting/customize-css', {
+        customizeCss: this.state.currentCustomizeCss,
+      });
+      const { customizedParams } = response.data;
+      this.setState({
+        currentCustomizeCss: customizedParams.customizeCss,
+      });
+    }
+    catch (err) {
+      logger.error(err);
+      throw new Error('Failed to update data');
+    }
   }
 
   /**
@@ -337,11 +393,19 @@ export default class AdminCustomizeContainer extends Container {
    * @return {string} Customize scripts
    */
   async updateCustomizeScript() {
-    const response = await this.appContainer.apiv3.put('/customize-setting/customize-script', {
-      customizeScript: this.state.currentCustomizeScript,
-    });
-    const { customizedParams } = response.data;
-    return customizedParams;
+    try {
+      const response = await this.appContainer.apiv3.put('/customize-setting/customize-script', {
+        customizeScript: this.state.currentCustomizeScript,
+      });
+      const { customizedParams } = response.data;
+      this.setState({
+        currentCustomizeScript: customizedParams.customizeScript,
+      });
+    }
+    catch (err) {
+      logger.error(err);
+      throw new Error('Failed to update data');
+    }
   }
 
 }

+ 1 - 1
src/server/routes/apiv3/customize-setting.js

@@ -168,7 +168,7 @@ module.exports = (crowi) => {
       styleBorder: await crowi.configManager.getConfig('crowi', 'customize:highlightJsStyleBorder'),
       customizeTitle: await crowi.configManager.getConfig('crowi', 'customize:title'),
       customizeHeader: await crowi.configManager.getConfig('crowi', 'customize:header'),
-      customizeCss: await crowi.configManager.getConfig('crowi', 'customize:header'),
+      customizeCss: await crowi.configManager.getConfig('crowi', 'customize:css'),
       customizeScript: await crowi.configManager.getConfig('crowi', 'customize:script'),
     };