Преглед изворни кода

Merge branch 'create-function-settings-frontside' into create-highlight-setting-frontside

# Conflicts:
#	src/client/js/components/Admin/Common/AdminDropdownOption.jsx
itizawa пре 6 година
родитељ
комит
33bb09ed2b

+ 7 - 2
.vscode/launch.json

@@ -4,6 +4,12 @@
     // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
     "version": "0.2.0",
     "configurations": [
+      {
+        "type": "node",
+        "request": "attach",
+        "name": "Debug: Attach Debugger to Server",
+        "port": 9229
+      },
       {
         "type": "node",
         "request": "launch",
@@ -11,10 +17,9 @@
         "runtimeExecutable": "npm",
         "runtimeArgs": [
           "run",
-          "server:debug"
+          "server:nolazy"
         ],
         "port": 9229,
-        "timeout": 30000,
         "restart": true,
         "console": "integratedTerminal",
         "internalConsoleOptions": "neverOpen"

+ 2 - 2
package.json

@@ -53,8 +53,8 @@
     "preserver:prod": "npm run migrate",
     "prestart": "npm run build:prod",
     "resource": "node bin/download-cdn-resources.js",
-    "server:debug": "env-cmd -f config/env.dev.js node-dev --inspect src/server/app.js",
-    "server:dev": "env-cmd -f config/env.dev.js node-dev --respawn src/server/app.js",
+    "server:nolazy": "env-cmd -f config/env.dev.js node-dev --nolazy --inspect src/server/app.js",
+    "server:dev": "env-cmd -f config/env.dev.js node-dev --inspect src/server/app.js",
     "server:prod:ci": "npm run server:prod -- --ci",
     "server:prod": "env-cmd -f config/env.prod.js node src/server/app.js",
     "server": "npm run server:dev",

+ 17 - 22
src/client/js/components/Admin/Common/AdminDropdownOption.jsx

@@ -2,31 +2,26 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import FormGroup from 'react-bootstrap/es/FormGroup';
-import FormControl from 'react-bootstrap/es/FormControl';
-import ControlLabel from 'react-bootstrap/es/ControlLabel';
-
 class AdminDropdownOption extends React.PureComponent {
 
   render() {
+
+    const menuItem = this.props.options.map((option) => {
+      return <button key={option} className="dropdown-item" type="button" onClick={() => this.props.onChangeValue(option)}>{option}</button>;
+    });
+
     return (
-      <div className="form-group row">
-        <div className="col-xs-offset-3 col-xs-6 text-left">
-          <FormGroup controlId="formControlsSelect" className="my-0">
-            <ControlLabel>{this.props.label}</ControlLabel>
-            <FormControl
-              componentClass="select"
-              placeholder="select"
-              className="btn-group-sm selectpicker"
-              onChange={event => this.props.onChange(event.target.value)}
-            >
-              {this.props.options.map((option) => {
-                return <option key={option} value={option}>{option}</option>;
-              })}
-            </FormControl>
-          </FormGroup>
-          {this.props.children}
+      <div className="my-0 form-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}
+          </button>
+          <div className="dropdown-menu" aria-labelledby="dropdownMenuLink">
+            {menuItem}
+          </div>
         </div>
+        {this.props.children}
       </div>
     );
   }
@@ -36,9 +31,9 @@ class AdminDropdownOption extends React.PureComponent {
 AdminDropdownOption.propTypes = {
   t: PropTypes.func.isRequired, // i18next
 
-  value: PropTypes.oneOfType(PropTypes.string, PropTypes.number).isRequired,
+  selectedValue: PropTypes.oneOfType(PropTypes.string, PropTypes.number).isRequired,
   label: PropTypes.string.isRequired,
-  onChange: PropTypes.func.isRequired,
+  onChangeValue: PropTypes.func.isRequired,
   options: PropTypes.array.isRequired,
   children: PropTypes.object.isRequired,
 };

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

@@ -13,7 +13,7 @@ import AdminCustomizeContainer from '../../../services/AdminCustomizeContainer';
 import CustomizeBehaviorOption from './CustomizeBehaviorOption';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 
-const logger = loggerFactory('growi:importer');
+const logger = loggerFactory('growi:Customize');
 
 class CustomizeBehaviorSetting extends React.Component {
 

+ 14 - 16
src/client/js/components/Admin/Customize/CustomizeFunctionOption.jsx

@@ -6,22 +6,20 @@ class CustomizeFunctionOption extends React.PureComponent {
 
   render() {
     return (
-      <div className="form-group row">
-        <div className="col-xs-offset-3 col-xs-9 text-left">
-          <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>
+        <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>
-      </div>
+        {this.props.children}
+      </React.Fragment>
     );
   }
 
@@ -34,7 +32,7 @@ CustomizeFunctionOption.propTypes = {
   label: PropTypes.string.isRequired,
   isChecked: PropTypes.bool.isRequired,
   onChecked: PropTypes.func.isRequired,
-  children: PropTypes.array.isRequired,
+  children: PropTypes.object.isRequired,
 };
 
 export default withTranslation()(CustomizeFunctionOption);

+ 62 - 48
src/client/js/components/Admin/Customize/CustomizeFunctionSetting.jsx

@@ -45,54 +45,68 @@ class CustomizeBehaviorSetting extends React.Component {
         <h2>{t('customize_page.Function')}</h2>
         <p className="well">{ t('customize_page.function_choose') }</p>
 
-        <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') }
-          </p>
-          <p className="help-block">
-            { t('customize_page.performance_decrease') }<br />
-            { t('customize_page.list_page_display') }
-          </p>
-        </CustomizeFunctionOption>
-
-        <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>
-
-        <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>
-
-        <AdminDropdownOption
-          label={t('customize_page.recent_created__n_draft_num_desc')}
-          value={adminCustomizeContainer.state.currentRecentCreatedLimit}
-          onChange={(value) => { adminCustomizeContainer.switchRecentCreatedLimit(value) }}
-          options={[10, 30, 50]}
-        >
-          <p className="help-block">
-            { t('customize_page.recently_created_n_draft_num_desc') }
-          </p>
-        </AdminDropdownOption>
+        <div className="form-group row">
+          <div className="col-xs-offset-2 col-xs-8 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-2 col-xs-8 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-2 col-xs-8 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-2 col-xs-8 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>

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

@@ -8,7 +8,7 @@ import { toastSuccess, toastError } from '../../../util/apiNotification';
 
 import AppContainer from '../../../services/AppContainer';
 
-const logger = loggerFactory('growi:importer');
+const logger = loggerFactory('growi:LineBreak');
 
 class LineBreakSetting extends React.Component {
 

+ 5 - 1
src/client/js/services/AdminCustomizeContainer.js

@@ -112,7 +112,11 @@ export default class AdminCustomizeContainer extends Container {
    * @return {string} Behavior
    */
   async updateCustomizeBehavior() {
-    // TODO GW-497 create apiV3
+    const response = await this.appContainer.apiv3.put('/customize-setting/behavior', {
+      behaviorType: this.state.currentBehavior,
+    });
+    const { customizedParams } = response.data;
+    return customizedParams;
   }
 
   /**

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

@@ -185,6 +185,7 @@ module.exports = function(crowi) {
       highlightJsStyle: crowi.configManager.getConfig('crowi', 'customize:highlightJsStyle'),
       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,

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

@@ -1,7 +1,7 @@
 /* eslint-disable no-unused-vars */
 const loggerFactory = require('@alias/logger');
 
-const logger = loggerFactory('growi:routes:apiv3:user-group');
+const logger = loggerFactory('growi:routes:apiv3:customize-setting');
 
 const express = require('express');
 
@@ -75,5 +75,49 @@ module.exports = (crowi) => {
     }
   });
 
+  validator.behavior = [
+    body('behaviorType').isString(),
+  ];
+
+  /**
+   * @swagger
+   *
+   *    /customize-setting/behavior:
+   *      put:
+   *        tags: [CustomizeSetting]
+   *        description: Update behavior
+   *        requestBody:
+   *          required: true
+   *          content:
+   *            application/json:
+   *              schama:
+   *                type: object
+   *                properties:
+   *                  behaviorType:
+   *                    description: type of behavior
+   *                    type: string
+   *      responses:
+   *          200:
+   *            description: Succeeded to update behavior
+   */
+  router.put('/behavior', loginRequiredStrictly, adminRequired, csrf, validator.behavior, ApiV3FormValidator, async(req, res) => {
+    const requestParams = {
+      'customize:behavior': req.body.behaviorType,
+    };
+
+    try {
+      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      const customizedParams = {
+        behaviorType: await crowi.configManager.getConfig('crowi', 'customize:behavior'),
+      };
+      return res.apiv3({ customizedParams });
+    }
+    catch (err) {
+      const msg = 'Error occurred in updating behavior';
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(msg, 'update-behavior-failed'));
+    }
+  });
+
   return router;
 };