Przeglądaj źródła

Merge pull request #1442 from weseek/imprv/refactor-admin-markdown

Imprv/refactor admin markdown
Yuki Takei 6 lat temu
rodzic
commit
dd9209d464

+ 2 - 2
src/client/js/app.jsx

@@ -55,7 +55,7 @@ import TagContainer from './services/TagContainer';
 import UserGroupDetailContainer from './services/UserGroupDetailContainer';
 import AdminUsersContainer from './services/AdminUsersContainer';
 import WebsocketContainer from './services/WebsocketContainer';
-import MarkDownSettingContainer from './services/MarkDownSettingContainer';
+import AdminMarkDownContainer from './services/AdminMarkDownContainer';
 import AdminExternalAccountsContainer from './services/AdminExternalAccountsContainer';
 
 const logger = loggerFactory('growi:app');
@@ -199,7 +199,7 @@ if (adminUserGroupDetailElem != null) {
 
 const adminMarkDownSettingElem = document.getElementById('admin-markdown-setting');
 if (adminMarkDownSettingElem != null) {
-  const markDownSettingContainer = new MarkDownSettingContainer(appContainer);
+  const markDownSettingContainer = new AdminMarkDownContainer(appContainer);
   ReactDOM.render(
     <Provider inject={[injectableContainers, markDownSettingContainer]}>
       <I18nextProvider i18n={i18n}>

+ 21 - 14
src/client/js/components/Admin/MarkdownSetting/LineBreakForm.jsx

@@ -8,7 +8,7 @@ import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
 import AppContainer from '../../../services/AppContainer';
-import MarkDownSettingContainer from '../../../services/MarkDownSettingContainer';
+import AdminMarkDownContainer from '../../../services/AdminMarkDownContainer';
 
 const logger = loggerFactory('growi:importer');
 
@@ -25,7 +25,7 @@ class LineBreakForm extends React.Component {
     const { t } = this.props;
 
     try {
-      await this.props.markDownSettingContainer.updateLineBreakSetting();
+      await this.props.adminMarkDownContainer.updateLineBreakSetting();
       toastSuccess(t('markdown_setting.updated_lineBreak'));
     }
     catch (err) {
@@ -35,8 +35,8 @@ class LineBreakForm extends React.Component {
   }
 
   renderLineBreakOption() {
-    const { t, markDownSettingContainer } = this.props;
-    const { isEnabledLinebreaks } = markDownSettingContainer.state;
+    const { t, adminMarkDownContainer } = this.props;
+    const { isEnabledLinebreaks } = adminMarkDownContainer.state;
 
     const helpLineBreak = { __html: t('markdown_setting.Enable Line Break desc') };
 
@@ -48,10 +48,10 @@ class LineBreakForm extends React.Component {
               type="checkbox"
               id="isEnabledLinebreaks"
               checked={isEnabledLinebreaks}
-              onChange={() => { markDownSettingContainer.setState({ isEnabledLinebreaks: !isEnabledLinebreaks }) }}
+              onChange={() => { adminMarkDownContainer.setState({ isEnabledLinebreaks: !isEnabledLinebreaks }) }}
             />
             <label htmlFor="isEnabledLinebreaks">
-              { t('markdown_setting.Enable Line Break') }
+              {t('markdown_setting.Enable Line Break')}
             </label>
           </div>
           <p className="help-block" dangerouslySetInnerHTML={helpLineBreak} />
@@ -61,8 +61,8 @@ class LineBreakForm extends React.Component {
   }
 
   renderLineBreakInCommentOption() {
-    const { t, markDownSettingContainer } = this.props;
-    const { isEnabledLinebreaksInComments } = markDownSettingContainer.state;
+    const { t, adminMarkDownContainer } = this.props;
+    const { isEnabledLinebreaksInComments } = adminMarkDownContainer.state;
 
     const helpLineBreakInComment = { __html: t('markdown_setting.Enable Line Break for comment desc') };
 
@@ -74,10 +74,10 @@ class LineBreakForm extends React.Component {
               type="checkbox"
               id="isEnabledLinebreaksInComments"
               checked={isEnabledLinebreaksInComments}
-              onChange={() => { markDownSettingContainer.setState({ isEnabledLinebreaksInComments: !isEnabledLinebreaksInComments }) }}
+              onChange={() => { adminMarkDownContainer.setState({ isEnabledLinebreaksInComments: !isEnabledLinebreaksInComments }) }}
             />
             <label htmlFor="isEnabledLinebreaksInComments">
-              { t('markdown_setting.Enable Line Break for comment') }
+              {t('markdown_setting.Enable Line Break for comment')}
             </label>
           </div>
           <p className="help-block" dangerouslySetInnerHTML={helpLineBreakInComment} />
@@ -87,7 +87,7 @@ class LineBreakForm extends React.Component {
   }
 
   render() {
-    const { t } = this.props;
+    const { t, adminMarkDownContainer } = this.props;
 
     return (
       <React.Fragment>
@@ -97,7 +97,14 @@ class LineBreakForm extends React.Component {
         </fieldset>
         <div className="form-group my-3">
           <div className="col-xs-offset-4 col-xs-5">
-            <button type="submit" className="btn btn-primary" onClick={this.onClickSubmit}>{ t('Update') }</button>
+            <button
+              type="submit"
+              className="btn btn-primary"
+              onClick={this.onClickSubmit}
+              disabled={adminMarkDownContainer.state.retrieveError != null}
+            >
+              {t('Update')}
+            </button>
           </div>
         </div>
       </React.Fragment>
@@ -110,13 +117,13 @@ class LineBreakForm extends React.Component {
  * Wrapper component for using unstated
  */
 const LineBreakFormWrapper = (props) => {
-  return createSubscribedElement(LineBreakForm, props, [AppContainer, MarkDownSettingContainer]);
+  return createSubscribedElement(LineBreakForm, props, [AppContainer, AdminMarkDownContainer]);
 };
 
 LineBreakForm.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  markDownSettingContainer: PropTypes.instanceOf(MarkDownSettingContainer).isRequired,
+  adminMarkDownContainer: PropTypes.instanceOf(AdminMarkDownContainer).isRequired,
 };
 
 export default withTranslation()(LineBreakFormWrapper);

+ 22 - 1
src/client/js/components/Admin/MarkdownSetting/MarkDownSetting.jsx

@@ -2,15 +2,35 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
+import loggerFactory from '@alias/logger';
+
 import { createSubscribedElement } from '../../UnstatedUtils';
+import { toastError } from '../../../util/apiNotification';
 
 import AppContainer from '../../../services/AppContainer';
 import LineBreakForm from './LineBreakForm';
 import PresentationForm from './PresentationForm';
 import XssForm from './XssForm';
+import AdminMarkDownContainer from '../../../services/AdminMarkDownContainer';
+
+const logger = loggerFactory('growi:MarkDown');
 
 class MarkdownSetting extends React.Component {
 
+  async componentDidMount() {
+    const { adminMarkDownContainer } = this.props;
+
+    try {
+      await adminMarkDownContainer.retrieveMarkdownData();
+    }
+    catch (err) {
+      toastError(err);
+      adminMarkDownContainer.setState({ retrieveError: err });
+      logger.error(err);
+    }
+
+  }
+
   render() {
     const { t } = this.props;
 
@@ -43,12 +63,13 @@ class MarkdownSetting extends React.Component {
 }
 
 const MarkdownSettingWrapper = (props) => {
-  return createSubscribedElement(MarkdownSetting, props, [AppContainer]);
+  return createSubscribedElement(MarkdownSetting, props, [AppContainer, AdminMarkDownContainer]);
 };
 
 MarkdownSetting.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  adminMarkDownContainer: PropTypes.instanceOf(AdminMarkDownContainer).isRequired,
 
 };
 

+ 12 - 12
src/client/js/components/Admin/MarkdownSetting/PresentationForm.jsx

@@ -7,7 +7,7 @@ import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
 import AppContainer from '../../../services/AppContainer';
-import MarkDownSettingContainer from '../../../services/MarkDownSettingContainer';
+import AdminMarkDownContainer from '../../../services/AdminMarkDownContainer';
 
 const logger = loggerFactory('growi:markdown:presentation');
 
@@ -23,7 +23,7 @@ class PresentationForm extends React.Component {
     const { t } = this.props;
 
     try {
-      await this.props.markDownSettingContainer.updatePresentationSetting();
+      await this.props.adminMarkDownContainer.updatePresentationSetting();
       toastSuccess(t('markdown_setting.updated_presentation'));
     }
     catch (err) {
@@ -34,8 +34,8 @@ class PresentationForm extends React.Component {
 
 
   render() {
-    const { t, markDownSettingContainer } = this.props;
-    const { pageBreakSeparator, pageBreakCustomSeparator } = markDownSettingContainer.state;
+    const { t, adminMarkDownContainer } = this.props;
+    const { pageBreakSeparator, pageBreakCustomSeparator } = adminMarkDownContainer.state;
 
     return (
       <fieldset className="form-group row my-2">
@@ -49,7 +49,7 @@ class PresentationForm extends React.Component {
             type="radio"
             id="pageBreakOption1"
             checked={pageBreakSeparator === 1}
-            onChange={() => markDownSettingContainer.switchPageBreakSeparator(1)}
+            onChange={() => adminMarkDownContainer.switchPageBreakSeparator(1)}
           />
           <label htmlFor="pageBreakOption1">
             <p className="font-weight-bold">{ t('markdown_setting.Preset one separator') }</p>
@@ -65,7 +65,7 @@ class PresentationForm extends React.Component {
             type="radio"
             id="pageBreakOption2"
             checked={pageBreakSeparator === 2}
-            onChange={() => markDownSettingContainer.switchPageBreakSeparator(2)}
+            onChange={() => adminMarkDownContainer.switchPageBreakSeparator(2)}
           />
           <label htmlFor="pageBreakOption2">
             <p className="font-weight-bold">{ t('markdown_setting.Preset two separator') }</p>
@@ -81,7 +81,7 @@ class PresentationForm extends React.Component {
             type="radio"
             id="pageBreakOption3"
             checked={pageBreakSeparator === 3}
-            onChange={() => markDownSettingContainer.switchPageBreakSeparator(3)}
+            onChange={() => adminMarkDownContainer.switchPageBreakSeparator(3)}
           />
           <label htmlFor="pageBreakOption3">
             <p className="font-weight-bold">{ t('markdown_setting.Custom separator') }</p>
@@ -89,8 +89,8 @@ class PresentationForm extends React.Component {
               { t('markdown_setting.Custom separator desc') }
               <input
                 className="form-control"
-                value={pageBreakCustomSeparator}
-                onChange={(e) => { markDownSettingContainer.setPageBreakCustomSeparator(e.target.value) }}
+                defaultValue={pageBreakCustomSeparator}
+                onChange={(e) => { adminMarkDownContainer.setPageBreakCustomSeparator(e.target.value) }}
               />
             </div>
           </label>
@@ -98,7 +98,7 @@ class PresentationForm extends React.Component {
 
         <div className="form-group my-3">
           <div className="col-xs-offset-4 col-xs-5">
-            <div className="btn btn-primary" onClick={this.onClickSubmit}>{ t('Update') }</div>
+            <div className="btn btn-primary" onClick={this.onClickSubmit} disabled={adminMarkDownContainer.state.retrieveError != null}>{ t('Update') }</div>
           </div>
         </div>
 
@@ -109,13 +109,13 @@ class PresentationForm extends React.Component {
 }
 
 const PresentationFormWrapper = (props) => {
-  return createSubscribedElement(PresentationForm, props, [AppContainer, MarkDownSettingContainer]);
+  return createSubscribedElement(PresentationForm, props, [AppContainer, AdminMarkDownContainer]);
 };
 
 PresentationForm.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  markDownSettingContainer: PropTypes.instanceOf(MarkDownSettingContainer).isRequired,
+  adminMarkDownContainer: PropTypes.instanceOf(AdminMarkDownContainer).isRequired,
 
 };
 

+ 10 - 10
src/client/js/components/Admin/MarkdownSetting/PresentationLineBreakOptions.jsx

@@ -5,13 +5,13 @@ import { withTranslation } from 'react-i18next';
 import { createSubscribedElement } from '../../UnstatedUtils';
 
 import AppContainer from '../../../services/AppContainer';
-import MarkDownSettingContainer from '../../../services/MarkDownSettingContainer';
+import AdminMarkDownContainer from '../../../services/AdminMarkDownContainer';
 
 class PresentationLineBreakOptions extends React.Component {
 
   render() {
-    const { t, markDownSettingContainer } = this.props;
-    const { pageBreakOption, customRegularExpression } = markDownSettingContainer.state;
+    const { t, adminMarkDownContainer } = this.props;
+    const { pageBreakOption, customRegularExpression } = adminMarkDownContainer.state;
 
     return (
       <Fragment>
@@ -20,7 +20,7 @@ class PresentationLineBreakOptions extends React.Component {
             type="radio"
             id="pageBreakOption1"
             checked={pageBreakOption === 1}
-            onChange={() => { markDownSettingContainer.setState({ pageBreakOption: 1 }) }}
+            onChange={() => { adminMarkDownContainer.setState({ pageBreakOption: 1 }) }}
           />
           <label htmlFor="pageBreakOption1">
             <p className="font-weight-bold">{ t('markdown_setting.Preset one separator') }</p>
@@ -36,7 +36,7 @@ class PresentationLineBreakOptions extends React.Component {
             type="radio"
             id="pageBreakOption2"
             checked={pageBreakOption === 2}
-            onChange={() => { markDownSettingContainer.setState({ pageBreakOption: 2 }) }}
+            onChange={() => { adminMarkDownContainer.setState({ pageBreakOption: 2 }) }}
           />
           <label htmlFor="pageBreakOption2">
             <p className="font-weight-bold">{ t('markdown_setting.Preset two separator') }</p>
@@ -52,7 +52,7 @@ class PresentationLineBreakOptions extends React.Component {
             type="radio"
             id="pageBreakOption3"
             checked={pageBreakOption === 3}
-            onChange={() => { markDownSettingContainer.setState({ pageBreakOption: 3 }) }}
+            onChange={() => { adminMarkDownContainer.setState({ pageBreakOption: 3 }) }}
           />
           <label htmlFor="pageBreakOption3">
             <p className="font-weight-bold">{ t('markdown_setting.Custom separator') }</p>
@@ -60,8 +60,8 @@ class PresentationLineBreakOptions extends React.Component {
               { t('markdown_setting.Custom separator desc') }
               <input
                 className="form-control"
-                value={customRegularExpression}
-                onChange={(e) => { markDownSettingContainer.setState({ customRegularExpression: e.target.value }) }}
+                defaultValue={customRegularExpression}
+                onChange={(e) => { adminMarkDownContainer.setState({ customRegularExpression: e.target.value }) }}
               />
             </div>
           </label>
@@ -73,13 +73,13 @@ class PresentationLineBreakOptions extends React.Component {
 }
 
 const PresentationLineBreakOptionsWrapper = (props) => {
-  return createSubscribedElement(PresentationLineBreakOptions, props, [AppContainer, MarkDownSettingContainer]);
+  return createSubscribedElement(PresentationLineBreakOptions, props, [AppContainer, AdminMarkDownContainer]);
 };
 
 PresentationLineBreakOptions.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  markDownSettingContainer: PropTypes.instanceOf(MarkDownSettingContainer).isRequired,
+  adminMarkDownContainer: PropTypes.instanceOf(AdminMarkDownContainer).isRequired,
 
 };
 

+ 16 - 16
src/client/js/components/Admin/MarkdownSetting/WhiteListInput.jsx

@@ -6,52 +6,52 @@ import { createSubscribedElement } from '../../UnstatedUtils';
 import { tags, attrs } from '../../../../../lib/service/xss/recommended-whitelist';
 
 import AppContainer from '../../../services/AppContainer';
-import MarkDownSettingContainer from '../../../services/MarkDownSettingContainer';
+import AdminMarkDownContainer from '../../../services/AdminMarkDownContainer';
 
 class WhiteListInput extends React.Component {
 
   renderRecommendTagBtn() {
-    const { t, markDownSettingContainer } = this.props;
+    const { t, adminMarkDownContainer } = this.props;
 
     return (
-      <p id="btn-import-tags" className="btn btn-xs btn-primary" onClick={() => { markDownSettingContainer.setState({ tagWhiteList: tags }) }}>
+      <p id="btn-import-tags" className="btn btn-xs btn-primary" onClick={() => { adminMarkDownContainer.setState({ tagWhiteList: tags }) }}>
         { t('markdown_setting.import_recommended', 'tags') }
       </p>
     );
   }
 
   renderRecommendAttrBtn() {
-    const { t, markDownSettingContainer } = this.props;
+    const { t, adminMarkDownContainer } = this.props;
 
     return (
-      <p id="btn-import-tags" className="btn btn-xs btn-primary" onClick={() => { markDownSettingContainer.setState({ attrWhiteList: attrs }) }}>
+      <p id="btn-import-tags" className="btn btn-xs btn-primary" onClick={() => { adminMarkDownContainer.setState({ attrWhiteList: attrs }) }}>
         { t('markdown_setting.import_recommended', 'Attrs') }
       </p>
     );
   }
 
   renderTagValue() {
-    const { customizable, markDownSettingContainer } = this.props;
+    const { customizable, adminMarkDownContainer } = this.props;
 
     if (customizable) {
-      return markDownSettingContainer.state.tagWhiteList;
+      return adminMarkDownContainer.state.tagWhiteList;
     }
 
     return tags;
   }
 
   renderAttrValue() {
-    const { customizable, markDownSettingContainer } = this.props;
+    const { customizable, adminMarkDownContainer } = this.props;
 
     if (customizable) {
-      return markDownSettingContainer.state.attrWhiteList;
+      return adminMarkDownContainer.state.attrWhiteList;
     }
 
     return attrs;
   }
 
   render() {
-    const { t, customizable, markDownSettingContainer } = this.props;
+    const { t, customizable, adminMarkDownContainer } = this.props;
 
     return (
       <>
@@ -66,8 +66,8 @@ class WhiteListInput extends React.Component {
             rows="6"
             cols="40"
             readOnly={!customizable}
-            value={this.renderTagValue()}
-            onChange={(e) => { markDownSettingContainer.setState({ tagWhiteList: e.target.value }) }}
+            defaultValue={this.renderTagValue()}
+            onChange={(e) => { adminMarkDownContainer.setState({ tagWhiteList: e.target.value }) }}
           />
         </div>
         <div className="m-t-15">
@@ -81,8 +81,8 @@ class WhiteListInput extends React.Component {
             rows="6"
             cols="40"
             readOnly={!customizable}
-            value={this.renderAttrValue()}
-            onChange={(e) => { markDownSettingContainer.setState({ attrWhiteList: e.target.value }) }}
+            defaultValue={this.renderAttrValue()}
+            onChange={(e) => { adminMarkDownContainer.setState({ attrWhiteList: e.target.value }) }}
           />
         </div>
       </>
@@ -92,13 +92,13 @@ class WhiteListInput extends React.Component {
 }
 
 const WhiteListWrapper = (props) => {
-  return createSubscribedElement(WhiteListInput, props, [AppContainer, MarkDownSettingContainer]);
+  return createSubscribedElement(WhiteListInput, props, [AppContainer, AdminMarkDownContainer]);
 };
 
 WhiteListInput.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  markDownSettingContainer: PropTypes.instanceOf(MarkDownSettingContainer).isRequired,
+  adminMarkDownContainer: PropTypes.instanceOf(AdminMarkDownContainer).isRequired,
 
   customizable: PropTypes.bool.isRequired,
 };

+ 13 - 13
src/client/js/components/Admin/MarkdownSetting/XssForm.jsx

@@ -7,7 +7,7 @@ import { createSubscribedElement } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
 import AppContainer from '../../../services/AppContainer';
-import MarkDownSettingContainer from '../../../services/MarkDownSettingContainer';
+import AdminMarkDownContainer from '../../../services/AdminMarkDownContainer';
 
 import WhiteListInput from './WhiteListInput';
 
@@ -25,7 +25,7 @@ class XssForm extends React.Component {
     const { t } = this.props;
 
     try {
-      await this.props.markDownSettingContainer.updateXssSetting();
+      await this.props.adminMarkDownContainer.updateXssSetting();
       toastSuccess(t('markdown_setting.updated_xss'));
     }
     catch (err) {
@@ -35,8 +35,8 @@ class XssForm extends React.Component {
   }
 
   xssOptions() {
-    const { t, markDownSettingContainer } = this.props;
-    const { xssOption } = markDownSettingContainer.state;
+    const { t, adminMarkDownContainer } = this.props;
+    const { xssOption } = adminMarkDownContainer.state;
 
     return (
       <fieldset className="form-group col-xs-12 my-3">
@@ -46,7 +46,7 @@ class XssForm extends React.Component {
             id="xssOption1"
             name="XssOption"
             checked={xssOption === 1}
-            onChange={() => { markDownSettingContainer.setState({ xssOption: 1 }) }}
+            onChange={() => { adminMarkDownContainer.setState({ xssOption: 1 }) }}
           />
           <label htmlFor="xssOption1">
             <p className="font-weight-bold">{ t('markdown_setting.Ignore all tags') }</p>
@@ -62,7 +62,7 @@ class XssForm extends React.Component {
             id="xssOption2"
             name="XssOption"
             checked={xssOption === 2}
-            onChange={() => { markDownSettingContainer.setState({ xssOption: 2 }) }}
+            onChange={() => { adminMarkDownContainer.setState({ xssOption: 2 }) }}
           />
           <label htmlFor="xssOption2">
             <p className="font-weight-bold">{ t('markdown_setting.Recommended setting') }</p>
@@ -76,7 +76,7 @@ class XssForm extends React.Component {
             id="xssOption3"
             name="XssOption"
             checked={xssOption === 3}
-            onChange={() => { markDownSettingContainer.setState({ xssOption: 3 }) }}
+            onChange={() => { adminMarkDownContainer.setState({ xssOption: 3 }) }}
           />
           <label htmlFor="xssOption3">
             <p className="font-weight-bold">{ t('markdown_setting.Custom Whitelist') }</p>
@@ -88,8 +88,8 @@ class XssForm extends React.Component {
   }
 
   render() {
-    const { t, markDownSettingContainer } = this.props;
-    const { isEnabledXss } = markDownSettingContainer.state;
+    const { t, adminMarkDownContainer } = this.props;
+    const { isEnabledXss } = adminMarkDownContainer.state;
 
     return (
       <React.Fragment>
@@ -103,7 +103,7 @@ class XssForm extends React.Component {
                   className="form-check-input"
                   name="isEnabledXss"
                   checked={isEnabledXss}
-                  onChange={markDownSettingContainer.switchEnableXss}
+                  onChange={adminMarkDownContainer.switchEnableXss}
                 />
                 <label htmlFor="XssEnable">
                   { t('markdown_setting.Enable XSS prevention') }
@@ -114,7 +114,7 @@ class XssForm extends React.Component {
           </div>
           <div className="form-group my-3">
             <div className="col-xs-offset-4 col-xs-5">
-              <div className="btn btn-primary" onClick={this.onClickSubmit}>{ t('Update') }</div>
+              <div className="btn btn-primary" onClick={this.onClickSubmit} disabled={adminMarkDownContainer.state.retrieveError != null}> {t('Update')}</div>
             </div>
           </div>
         </form>
@@ -125,13 +125,13 @@ class XssForm extends React.Component {
 }
 
 const XssFormWrapper = (props) => {
-  return createSubscribedElement(XssForm, props, [AppContainer, MarkDownSettingContainer]);
+  return createSubscribedElement(XssForm, props, [AppContainer, AdminMarkDownContainer]);
 };
 
 XssForm.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  markDownSettingContainer: PropTypes.instanceOf(MarkDownSettingContainer).isRequired,
+  adminMarkDownContainer: PropTypes.instanceOf(AdminMarkDownContainer).isRequired,
 };
 
 export default withTranslation()(XssFormWrapper);

+ 43 - 12
src/client/js/services/MarkDownSettingContainer.js → src/client/js/services/AdminMarkDownContainer.js

@@ -1,10 +1,16 @@
 import { Container } from 'unstated';
 
+import loggerFactory from '@alias/logger';
+
+import { toastError } from '../util/apiNotification';
+
+const logger = loggerFactory('growi:services:AdminMarkdownContainer');
+
 /**
  * Service container for admin markdown setting page (MarkDownSetting.jsx)
  * @extends {Container} unstated Container
  */
-export default class MarkDownSettingContainer extends Container {
+export default class AdminMarkDownContainer extends Container {
 
   constructor(appContainer) {
     super();
@@ -12,16 +18,15 @@ export default class MarkDownSettingContainer extends Container {
     this.appContainer = appContainer;
 
     this.state = {
-      isEnabledLinebreaks: appContainer.config.isEnabledLinebreaks,
-      isEnabledLinebreaksInComments: appContainer.config.isEnabledLinebreaksInComments,
-      pageBreakSeparator: appContainer.config.pageBreakSeparator,
-      pageBreakCustomSeparator: appContainer.config.pageBreakCustomSeparator || '',
-      // pageBreakOption: appContainer.config.pageBreakOption,
-      customRegularExpression: appContainer.config.customRegularExpression || '',
-      isEnabledXss: (appContainer.config.xssOption != null),
-      xssOption: appContainer.config.xssOption,
-      tagWhiteList: appContainer.config.tagWhiteList || '',
-      attrWhiteList: appContainer.config.attrWhiteList || '',
+      retrieveError: null,
+      isEnabledLinebreaks: false,
+      isEnabledLinebreaksInComments: false,
+      pageBreakSeparator: 1,
+      pageBreakCustomSeparator: '',
+      isEnabledXss: false,
+      xssOption: 1,
+      tagWhiteList: '',
+      attrWhiteList: '',
     };
 
     this.switchEnableXss = this.switchEnableXss.bind(this);
@@ -31,7 +36,33 @@ export default class MarkDownSettingContainer extends Container {
    * Workaround for the mangling in production build to break constructor.name
    */
   static getClassName() {
-    return 'MarkDownSettingContainer';
+    return 'AdminMarkDownContainer';
+  }
+
+  /**
+   * retrieve markdown data
+   */
+  async retrieveMarkdownData() {
+    try {
+      const response = await this.appContainer.apiv3.get('/markdown-setting/');
+      const { markdownParams } = response.data;
+
+      this.setState({
+        isEnabledLinebreaks: markdownParams.isEnabledLinebreaks,
+        isEnabledLinebreaksInComments: markdownParams.isEnabledLinebreaksInComments,
+        pageBreakSeparator: markdownParams.pageBreakSeparator,
+        pageBreakCustomSeparator: markdownParams.pageBreakCustomSeparator || '',
+        isEnabledXss: markdownParams.isEnabledXss,
+        xssOption: markdownParams.xssOption,
+        tagWhiteList: markdownParams.tagWhiteList || '',
+        attrWhiteList: markdownParams.attrWhiteList || '',
+      });
+
+    }
+    catch (err) {
+      logger.error(err);
+      toastError(new Error('Failed to fetch data'));
+    }
   }
 
   /**

+ 0 - 8
src/server/form/admin/markdown.js

@@ -1,8 +0,0 @@
-const form = require('express-form');
-
-const field = form.field;
-
-module.exports = form(
-  field('markdownSetting[markdown:isEnabledLinebreaks]').trim().toBooleanStrict(),
-  field('markdownSetting[markdown:isEnabledLinebreaksInComments]').trim().toBooleanStrict(),
-);

+ 0 - 8
src/server/form/admin/markdownPresentation.js

@@ -1,8 +0,0 @@
-const form = require('express-form');
-
-const field = form.field;
-
-module.exports = form(
-  field('markdownSetting[markdown:presentation:pageBreakSeparator]').trim().toInt(),
-  field('markdownSetting[markdown:presentation:pageBreakCustomSeparator]').trim(),
-);

+ 0 - 10
src/server/form/admin/markdownXss.js

@@ -1,10 +0,0 @@
-const form = require('express-form');
-
-const field = form.field;
-
-module.exports = form(
-  field('markdownSetting[markdown:xss:isEnabledPrevention]').trim().toBooleanStrict(),
-  field('markdownSetting[markdown:xss:option]').trim().toInt(),
-  field('markdownSetting[markdown:xss:tagWhiteList]').trim(),
-  field('markdownSetting[markdown:xss:attrWhiteList]').trim(),
-);

+ 0 - 3
src/server/form/index.js

@@ -25,9 +25,6 @@ module.exports = {
     securityPassportGitHub: require('./admin/securityPassportGitHub'),
     securityPassportTwitter: require('./admin/securityPassportTwitter'),
     securityPassportOidc: require('./admin/securityPassportOidc'),
-    markdown: require('./admin/markdown'),
-    markdownXss: require('./admin/markdownXss'),
-    markdownPresentation: require('./admin/markdownPresentation'),
     customcss: require('./admin/customcss'),
     customscript: require('./admin/customscript'),
     customheader: require('./admin/customheader'),

+ 0 - 15
src/server/routes/admin.js

@@ -137,21 +137,6 @@ module.exports = function(crowi, app) {
     });
   };
 
-  // app.post('/admin/markdown/presentationSetting' , admin.markdown.presentationSetting);
-  actions.markdown.presentationSetting = async function(req, res) {
-    const markdownSetting = req.form.markdownSetting;
-
-    if (req.form.isValid) {
-      await configManager.updateConfigsInTheSameNamespace('markdown', markdownSetting);
-      req.flash('successMessage', ['Successfully updated!']);
-    }
-    else {
-      req.flash('errorMessage', req.form.errors);
-    }
-
-    return res.redirect('/admin/markdown');
-  };
-
   // app.get('/admin/customize' , admin.customize.index);
   actions.customize = {};
   actions.customize.index = function(req, res) {

+ 78 - 74
src/server/routes/apiv3/markdown-setting.js

@@ -38,45 +38,47 @@ const validator = {
  *
  *  components:
  *    schemas:
- *      LineBreakParams:
+ *      CustomizeParams:
  *        type: object
- *        properties:
- *          isEnabledLinebreaks:
- *            type: boolean
- *            description: enable lineBreak
- *          isEnabledLinebreaksInComments:
- *            type: boolean
- *            description: enable lineBreak in comment
- *      PresentationParams:
- *        type: object
- *        properties:
- *          pageBreakSeparator:
- *            type: number
- *            description: number of pageBreakSeparator
- *          pageBreakCustomSeparator:
- *            type: string
- *            description: string of pageBreakCustomSeparator
- *      XssParams:
- *        type: object
- *        properties:
- *          isEnabledPrevention:
- *            type: boolean
- *            description: enable xss
- *          xssOption:
- *            type: number
- *            description: number of xss option
- *          tagWhiteList:
- *            type: array
- *            description: array of tag whiteList
- *            items:
- *              type: string
- *              description: tag whitelist
- *          attrWhiteList:
- *            type: array
- *            description: array of attr whiteList
- *            items:
- *              type: string
- *              description: attr whitelist
+ *          LineBreakParams:
+ *            type: object
+ *            properties:
+ *              isEnabledLinebreaks:
+ *                type: boolean
+ *                description: enable lineBreak
+ *              isEnabledLinebreaksInComments:
+ *                type: boolean
+ *                description: enable lineBreak in comment
+ *          PresentationParams:
+ *            type: object
+ *            properties:
+ *              pageBreakSeparator:
+ *                type: number
+ *                description: number of pageBreakSeparator
+ *              pageBreakCustomSeparator:
+ *                type: string
+ *                description: string of pageBreakCustomSeparator
+ *          XssParams:
+ *            type: object
+ *            properties:
+ *              isEnabledPrevention:
+ *                type: boolean
+ *                description: enable xss
+ *              xssOption:
+ *                type: number
+ *                description: number of xss option
+ *              tagWhiteList:
+ *                type: array
+ *                description: array of tag whiteList
+ *                items:
+ *                  type: string
+ *                  description: tag whitelist
+ *              attrWhiteList:
+ *                type: array
+ *                description: array of attr whiteList
+ *                items:
+ *                  type: string
+ *                  description: attr whitelist
  */
 
 module.exports = (crowi) => {
@@ -86,6 +88,38 @@ module.exports = (crowi) => {
 
   const { ApiV3FormValidator } = crowi.middlewares;
 
+  /**
+   * @swagger
+   *
+   *    /markdown-setting/:
+   *      get:
+   *        tags: [MarkDownSettind]
+   *        description: Get markdown paramators
+   *        responses:
+   *          200:
+   *            description: params of markdown
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    markdonwParams:
+   *                      $ref: '#/components/schemas/CustomizeParams'
+   */
+  router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
+    const markdownParams = {
+      isEnabledLinebreaks: await crowi.configManager.getConfig('markdown', 'markdown:isEnabledLinebreaks'),
+      isEnabledLinebreaksInComments: await crowi.configManager.getConfig('markdown', 'markdown:isEnabledLinebreaksInComments'),
+      pageBreakSeparator: await crowi.configManager.getConfig('markdown', 'markdown:presentation:pageBreakSeparator'),
+      pageBreakCustomSeparator: await crowi.configManager.getConfig('markdown', 'markdown:presentation:pageBreakCustomSeparator'),
+      isEnabledXss: await crowi.configManager.getConfig('markdown', 'markdown:xss:isEnabledPrevention'),
+      xssOption: await crowi.configManager.getConfig('markdown', 'markdown:xss:option'),
+      tagWhiteList: await crowi.configManager.getConfig('markdown', 'markdown:xss:tagWhiteList'),
+      attrWhiteList: await crowi.configManager.getConfig('markdown', 'markdown:xss:attrWhiteList'),
+    };
+
+    return res.apiv3({ markdownParams });
+  });
+
   /**
    * @swagger
    *
@@ -100,12 +134,7 @@ module.exports = (crowi) => {
    *              schema:
    *                type: object
    *                properties:
-   *                  isEnabledLinebreaks:
-   *                    description: enable lineBreak
-   *                    type: boolean
-   *                  isEnabledLinebreaksInComments:
-   *                    description: enable lineBreak in comment
-   *                    type: boolean
+   *                  $ref: '#/components/schemas/CustomizeParams/LineBreakParams'
    *        responses:
    *          200:
    *            description: Succeeded to update lineBreak setting
@@ -113,8 +142,7 @@ module.exports = (crowi) => {
    *              application/json:
    *                schema:
    *                  properties:
-   *                    status:
-   *                      $ref: '#/components/schemas/LineBreakParams'
+   *                    $ref: '#/components/schemas/CustomizeParams/LineBreakParams'
    */
   router.put('/lineBreak', loginRequiredStrictly, adminRequired, csrf, validator.lineBreak, ApiV3FormValidator, async(req, res) => {
 
@@ -153,12 +181,7 @@ module.exports = (crowi) => {
    *              schema:
    *                type: object
    *                properties:
-   *                  pageBreakSeparator:
-   *                    description: number of pageBreakSeparator
-   *                    type: number
-   *                  pageBreakCustomSeparator:
-   *                    description: string of pageBreakCustomSeparator
-   *                    type: string
+   *                  $ref: '#/components/schemas/CustomizeParams/PresentationParams'
    *        responses:
    *          200:
    *            description: Succeeded to update presentation setting
@@ -166,8 +189,7 @@ module.exports = (crowi) => {
    *              application/json:
    *                schema:
    *                  properties:
-   *                    status:
-   *                      $ref: '#/components/schemas/PresentationParams'
+   *                    $ref: '#/components/schemas/CustomizeParams/PresentationParams'
    */
   router.put('/presentation', loginRequiredStrictly, adminRequired, csrf, validator.presentationSetting, ApiV3FormValidator, async(req, res) => {
     if (req.body.pageBreakSeparator === 3 && req.body.pageBreakCustomSeparator === '') {
@@ -209,24 +231,7 @@ module.exports = (crowi) => {
    *              schema:
    *                type: object
    *                properties:
-   *                  isEnabledPrevention:
-   *                    description: enable xss
-   *                    type: boolean
-   *                  xssOption:
-   *                    description: number of xss option
-   *                    type: number
-   *                  tagWhiteList:
-   *                    description: array of tag whiteList
-   *                    type: array
-   *                    items:
-   *                      type: string
-   *                      description: tag whitelist
-   *                  attrWhiteList:
-   *                    description: array of attr whiteList
-   *                    type: array
-   *                    items:
-   *                      type: string
-   *                      description: attr whitelist
+   *                  $ref: '#/components/schemas/CustomizeParams/XssParams'
    *        responses:
    *          200:
    *            description: Succeeded to update xss setting
@@ -234,8 +239,7 @@ module.exports = (crowi) => {
    *              application/json:
    *                schema:
    *                  properties:
-   *                    status:
-   *                      $ref: '#/components/schemas/XssParams'
+   *                    $ref: '#/components/schemas/CustomizeParams/XssParams'
    */
   router.put('/xss', loginRequiredStrictly, adminRequired, csrf, validator.xssSetting, ApiV3FormValidator, async(req, res) => {
     if (req.body.isEnabledXss && req.body.xssOption == null) {