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

Merge pull request #1339 from weseek/create-function-settings-frontside

Create function settings frontside
itizawa 6 лет назад
Родитель
Сommit
f91b1a803c

+ 2 - 1
resource/locales/en-US/translation.json

@@ -678,7 +678,8 @@
     "recent_created__n_draft_num_desc": "Number of Recently Created Pages & Drafts Displayed",
     "recently_created_n_draft_num_desc": "Number of recently created pages and drafts displayed on user page",
     "update_layout_success": "Succeeded to update layout",
-    "update_behavior_success": "Succeeded to update behavior"
+    "update_behavior_success": "Succeeded to update behavior",
+    "update_function_success": "Succeeded to update function"
   },
 
   "user_management": {

+ 2 - 1
resource/locales/ja/translation.json

@@ -662,7 +662,8 @@
     "recent_created__n_draft_num_desc": "最近作成したページと下書きの表示数",
     "recently_created_n_draft_num_desc": "ホーム画面の Recently Created での、1ページの表示数を設定します。",
     "update_layout_success": "レイアウトを更新しました",
-    "update_behavior_success": "挙動を更新しました"
+    "update_behavior_success": "挙動を更新しました",
+    "update_function_success": "機能を更新しました"
   },
 
   "user_management": {

+ 47 - 0
src/client/js/components/Admin/Common/AdminDropdownOption.jsx

@@ -0,0 +1,47 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+class AdminDropdownOption extends React.PureComponent {
+
+  render() {
+
+    const menuItem = this.props.options.map((option) => {
+      return (
+        <li key={option} role="presentation" type="button" onClick={() => this.props.onChangeValue(option)}>
+          <a role="menuitem" tabIndex="-1">{option}</a>
+        </li>
+      );
+    });
+
+    return (
+      <div className="my-0 btn-group">
+        <label>{this.props.label}</label>
+        <div className="dropdown">
+          <button className="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+            {this.props.selectedValue}
+            <span className="ml-2 caret"></span>
+          </button>
+          {/* TODO adjust dropdown after BS4 */}
+          <ul className="dropdown-menu" role="menu">
+            {menuItem}
+          </ul>
+        </div>
+        {this.props.children}
+      </div>
+    );
+  }
+
+}
+
+AdminDropdownOption.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+
+  selectedValue: PropTypes.number.isRequired,
+  label: PropTypes.string.isRequired,
+  onChangeValue: PropTypes.func.isRequired,
+  options: PropTypes.array.isRequired,
+  children: PropTypes.object.isRequired,
+};
+
+export default withTranslation()(AdminDropdownOption);

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

@@ -8,6 +8,7 @@ import AppContainer from '../../../services/AppContainer';
 import { createSubscribedElement } from '../../UnstatedUtils';
 import CustomizeLayoutSetting from './CustomizeLayoutSetting';
 import CustomizeBehaviorSetting from './CustomizeBehaviorSetting';
+import CustomizeFunctionSetting from './CustomizeFunctionSetting';
 
 class Customize extends React.Component {
 
@@ -22,8 +23,9 @@ class Customize extends React.Component {
         <div className="my-3">
           <CustomizeBehaviorSetting />
         </div>
-        <legend>{t('customize_page.Function')}</legend>
-        {/* 機能フォームの react componentをここで呼ぶ(GW-276) */}
+        <div className="my-3">
+          <CustomizeFunctionSetting />
+        </div>
         <legend>{t('customize_page.Code Highlight')}</legend>
         {/* コードハイライトフォームの react componentをここで呼ぶ(GW-277) */}
         <legend>{t('customize_page.custom_title')}</legend>

+ 38 - 0
src/client/js/components/Admin/Customize/CustomizeFunctionOption.jsx

@@ -0,0 +1,38 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+class CustomizeFunctionOption extends React.PureComponent {
+
+  render() {
+    return (
+      <React.Fragment>
+        <div className="checkbox checkbox-success">
+          <input
+            type="checkbox"
+            id={this.props.optionId}
+            checked={this.props.isChecked}
+            onChange={this.props.onChecked}
+          />
+          <label htmlFor={this.props.optionId}>
+            <strong>{this.props.label}</strong>
+          </label>
+        </div>
+        {this.props.children}
+      </React.Fragment>
+    );
+  }
+
+}
+
+CustomizeFunctionOption.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+
+  optionId: PropTypes.string.isRequired,
+  label: PropTypes.string.isRequired,
+  isChecked: PropTypes.bool.isRequired,
+  onChecked: PropTypes.func.isRequired,
+  children: PropTypes.object.isRequired,
+};
+
+export default withTranslation()(CustomizeFunctionOption);

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

@@ -0,0 +1,128 @@
+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';
+
+import AppContainer from '../../../services/AppContainer';
+
+import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
+import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
+import CustomizeFunctionOption from './CustomizeFunctionOption';
+import AdminDropdownOption from '../Common/AdminDropdownOption';
+
+const logger = loggerFactory('growi:importer');
+
+class CustomizeBehaviorSetting extends React.Component {
+
+  constructor(props) {
+    super(props);
+
+    this.onClickSubmit = this.onClickSubmit.bind(this);
+  }
+
+  async onClickSubmit() {
+    const { t, adminCustomizeContainer } = this.props;
+
+    try {
+      await adminCustomizeContainer.updateCustomizeFunction();
+      toastSuccess(t('customize_page.update_function_success'));
+    }
+    catch (err) {
+      toastError(err);
+      logger.error(err);
+    }
+  }
+
+  render() {
+    const { t, adminCustomizeContainer } = this.props;
+
+    return (
+      <React.Fragment>
+        <h2>{t('customize_page.Function')}</h2>
+        <p className="well">{ t('customize_page.function_choose') }</p>
+
+        <div className="form-group row">
+          <div className="col-xs-offset-3 col-xs-6 text-left">
+            <CustomizeFunctionOption
+              optionId="isEnabledTimeline"
+              label={t('customize_page.Timeline function')}
+              isChecked={adminCustomizeContainer.state.isEnabledTimeline}
+              onChecked={() => { adminCustomizeContainer.switchEnableTimeline() }}
+            >
+              <p className="help-block">
+                { t('customize_page.subpage_display') }<br />
+                { t('customize_page.performance_decrease') }<br />
+                { t('customize_page.list_page_display') }
+              </p>
+            </CustomizeFunctionOption>
+          </div>
+        </div>
+
+        <div className="form-group row">
+          <div className="col-xs-offset-3 col-xs-6 text-left">
+            <CustomizeFunctionOption
+              optionId="isSavedStatesOfTabChanges"
+              label={t('customize_page.tab_switch')}
+              isChecked={adminCustomizeContainer.state.isSavedStatesOfTabChanges}
+              onChecked={() => { adminCustomizeContainer.switchSavedStatesOfTabChanges() }}
+            >
+              <p className="help-block">
+                { t('customize_page.save_edit') }<br />
+                { t('customize_page.by_invalidating') }
+              </p>
+            </CustomizeFunctionOption>
+          </div>
+        </div>
+
+        <div className="form-group row">
+          <div className="col-xs-offset-3 col-xs-6 text-left">
+            <CustomizeFunctionOption
+              optionId="isEnabledAttachTitleHeader"
+              label={t('customize_page.attach_title_header')}
+              isChecked={adminCustomizeContainer.state.isEnabledAttachTitleHeader}
+              onChecked={() => { adminCustomizeContainer.switchEnabledAttachTitleHeader() }}
+            >
+              <p className="help-block">
+                { t('customize_page.attach_title_header_desc') }
+              </p>
+            </CustomizeFunctionOption>
+          </div>
+        </div>
+
+        <div className="form-group row">
+          <div className="col-xs-offset-3 col-xs-6 text-left">
+            <AdminDropdownOption
+              label={t('customize_page.recent_created__n_draft_num_desc')}
+              selectedValue={adminCustomizeContainer.state.currentRecentCreatedLimit}
+              onChangeValue={(value) => { adminCustomizeContainer.switchRecentCreatedLimit(value) }}
+              options={[10, 30, 50]}
+            >
+              <p className="help-block">
+                { t('customize_page.recently_created_n_draft_num_desc') }
+              </p>
+            </AdminDropdownOption>
+          </div>
+        </div>
+
+        <AdminUpdateButtonRow onClick={this.onClickSubmit} />
+      </React.Fragment>
+    );
+  }
+
+}
+
+const CustomizeBehaviorSettingWrapper = (props) => {
+  return createSubscribedElement(CustomizeBehaviorSetting, props, [AppContainer, AdminCustomizeContainer]);
+};
+
+CustomizeBehaviorSetting.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  adminCustomizeContainer: PropTypes.instanceOf(AdminCustomizeContainer).isRequired,
+};
+
+export default withTranslation()(CustomizeBehaviorSettingWrapper);

+ 41 - 0
src/client/js/services/AdminCustomizeContainer.js

@@ -15,6 +15,10 @@ export default class AdminCustomizeContainer extends Container {
       currentTheme: appContainer.config.themeType,
       currentLayout: appContainer.config.layoutType,
       currentBehavior: appContainer.config.behaviorType,
+      isEnabledTimeline: appContainer.config.isEnabledTimeline,
+      isSavedStatesOfTabChanges: appContainer.config.isSavedStatesOfTabChanges,
+      isEnabledAttachTitleHeader: appContainer.config.isEnabledAttachTitleHeader,
+      currentRecentCreatedLimit: appContainer.config.recentCreatedLimit,
     };
 
   }
@@ -51,6 +55,34 @@ export default class AdminCustomizeContainer extends Container {
     this.setState({ currentBehavior: behaviorName });
   }
 
+  /**
+   * Switch enabledTimeLine
+   */
+  switchEnableTimeline() {
+    this.setState({ isEnabledTimeline:  !this.state.isEnabledTimeline });
+  }
+
+  /**
+   * Switch savedStatesOfTabChanges
+   */
+  switchSavedStatesOfTabChanges() {
+    this.setState({ isSavedStatesOfTabChanges:  !this.state.isSavedStatesOfTabChanges });
+  }
+
+  /**
+   * Switch enabledAttachTitleHeader
+   */
+  switchEnabledAttachTitleHeader() {
+    this.setState({ isEnabledAttachTitleHeader:  !this.state.isEnabledAttachTitleHeader });
+  }
+
+  /**
+   * Switch recentCreatedLimit
+   */
+  switchRecentCreatedLimit(value) {
+    this.setState({ currentRecentCreatedLimit: value });
+  }
+
   /**
    * Update layout
    * @memberOf AdminCustomizeContainer
@@ -78,4 +110,13 @@ export default class AdminCustomizeContainer extends Container {
     return customizedParams;
   }
 
+  /**
+   * Update function
+   * @memberOf AdminCustomizeContainer
+   * @return {string} Functions
+   */
+  async updateCustomizeFunction() {
+    // TODO GW-506 create apiV3
+  }
+
 }

+ 1 - 0
src/server/models/config.js

@@ -184,6 +184,7 @@ module.exports = function(crowi) {
       attrWhiteList: crowi.xssService.getAttrWhiteList(),
       highlightJsStyleBorder: crowi.configManager.getConfig('crowi', 'customize:highlightJsStyleBorder'),
       isSavedStatesOfTabChanges: crowi.configManager.getConfig('crowi', 'customize:isSavedStatesOfTabChanges'),
+      isEnabledAttachTitleHeader: crowi.configManager.getConfig('crowi', 'customize:isEnabledAttachTitleHeader'),
       hasSlackConfig: crowi.slackNotificationService.hasSlackConfig(),
       env: {
         PLANTUML_URI: env.PLANTUML_URI || null,