Steven Fukase 4 лет назад
Родитель
Сommit
ded083f802

+ 23 - 67
packages/app/src/components/Me/EditorSettings.tsx

@@ -4,15 +4,9 @@ import React, {
 import { useTranslation } from 'react-i18next';
 import PropTypes from 'prop-types';
 import AppContainer from '~/client/services/AppContainer';
-
-import EditorContainer from '~/client/services/EditorContainer';
 import { withUnstatedContainers } from '../UnstatedUtils';
-
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 
-type Props = {
-  appContainer: AppContainer,
-}
 
 const commonRulesMenuItems = [
   {
@@ -91,41 +85,39 @@ type LintRules = {
   isEnabled?: boolean;
 }
 
+type Props = {
+  appContainer: AppContainer,
+}
 
 const EditorSettingsBody: FC<Props> = (props) => {
   const { t } = useTranslation();
   const { appContainer } = props;
-  const [commonTextlintRules, setCommonTextlintRules] = useState<LintRules[]>([]);
-  const [japaneseTextlintRules, setJapaneseTextlintRules] = useState<LintRules[]>([]);
+  const [textlintRules, setTextlintRules] = useState<LintRules[]>([]);
 
   const initializeEditorSettings = async() => {
     const { data } = await appContainer.apiv3Get('/personal-setting/editor-settings');
 
-    if (data?.commonTextlintRules != null) {
-      setCommonTextlintRules(data?.commonTextlintRules);
-    }
-    if (data?.japaneseTextlintRules != null) {
-      setJapaneseTextlintRules(data?.japaneseTextlintRules);
+    if (data?.textlintSettings?.textlintRules != null) {
+      setTextlintRules(data.textlintSettings.textlintRules);
     }
 
     // If database is empty, add default rules to state
-    if (data?.commonTextlintRules.length === 0 || data?.commonTextlintRules == null) {
+    if (data?.textlintSettings?.textlintRules == null) {
       const defaultCommonRules = commonRulesMenuItems.map(rule => (
         {
           name: rule.name,
           isEnabled: true,
         }
       ));
-      setCommonTextlintRules(defaultCommonRules);
-    }
-    if (data?.japaneseTextlintRules.length === 0 || data?.japaneseTextlintRules == null) {
+
       const defaultJapaneseRules = japaneseRulesMenuItems.map(rule => (
         {
           name: rule.name,
           isEnabled: true,
         }
       ));
-      setJapaneseTextlintRules(defaultJapaneseRules);
+
+      setTextlintRules([...defaultCommonRules, ...defaultJapaneseRules]);
     }
   };
 
@@ -133,33 +125,16 @@ const EditorSettingsBody: FC<Props> = (props) => {
     initializeEditorSettings();
   }, []);
 
-  const commonRuleCheckboxHandler = (isChecked: boolean, ruleName: string) => {
-    setCommonTextlintRules(prevState => (
-      prevState.filter(rule => rule.name !== ruleName).concat({ name: ruleName, isEnabled: isChecked })
-    ));
-  };
-
-  const japaneseRuleCheckboxHandler = (isChecked: boolean, ruleName: string) => {
-    setJapaneseTextlintRules(prevState => (
+  const ruleCheckboxHandler = (isChecked: boolean, ruleName: string) => {
+    setTextlintRules(prevState => (
       prevState.filter(rule => rule.name !== ruleName).concat({ name: ruleName, isEnabled: isChecked })
     ));
   };
 
-  const updateCommonRuleHandler = async() => {
-    try {
-      const { data } = await appContainer.apiv3Put('/personal-setting/editor-settings', { commonTextlintRules });
-      setCommonTextlintRules(data?.commonTextlintRules);
-      toastSuccess(t('toaster.update_successed', { target: 'Updated Textlint Settings' }));
-    }
-    catch (err) {
-      toastError(err);
-    }
-  };
-
-  const updateJapaneseRuleHandler = async() => {
+  const updateRulesHandler = async() => {
     try {
-      const { data } = await appContainer.apiv3Put('/personal-setting/editor-settings', { japaneseTextlintRules });
-      setJapaneseTextlintRules(data?.japaneseTextlintRules);
+      const { data } = await appContainer.apiv3Put('/personal-setting/editor-settings', { textlintRules });
+      setTextlintRules(data.textlintSettings.textlintRules);
       toastSuccess(t('toaster.update_successed', { target: 'Updated Textlint Settings' }));
     }
     catch (err) {
@@ -167,17 +142,12 @@ const EditorSettingsBody: FC<Props> = (props) => {
     }
   };
 
-  const isCheckedInCommonRules = (ruleName: string) => (
-    commonTextlintRules.filter(stateRule => (
+  const isCheckedRule = (ruleName: string) => (
+    textlintRules.filter(stateRule => (
       stateRule.name === ruleName
     ))[0]?.isEnabled
   );
 
-  const isCheckedInJapaneseRules = (ruleName: string) => (
-    japaneseTextlintRules.filter(stateRule => (
-      stateRule.name === ruleName
-    ))[0]?.isEnabled
-  );
 
   return (
     <>
@@ -193,8 +163,8 @@ const EditorSettingsBody: FC<Props> = (props) => {
                 type="checkbox"
                 className="custom-control-input"
                 id={rule.name}
-                checked={isCheckedInCommonRules(rule.name)}
-                onChange={e => commonRuleCheckboxHandler(e.target.checked, rule.name)}
+                checked={isCheckedRule(rule.name)}
+                onChange={e => ruleCheckboxHandler(e.target.checked, rule.name)}
               />
               <label className="custom-control-label" htmlFor={rule.name}>
                 <strong>{rule.name}</strong>
@@ -204,25 +174,11 @@ const EditorSettingsBody: FC<Props> = (props) => {
               </p>
             </div>
           ))}
-
-          <div className="row my-3">
-            <div className="offset-4 col-5">
-              <button
-                type="button"
-                className="btn btn-primary"
-                onClick={updateCommonRuleHandler}
-              >
-                {t('Update')}
-              </button>
-            </div>
-          </div>
-
         </div>
       </div>
 
 
       <h2 className="border-bottom my-4">{t('editor_settings.japanese_settings.japanese_settings')}</h2>
-
       <div className="form-group row">
         <div className="offset-md-3 col-md-6 text-left">
           {japaneseRulesMenuItems.map(rule => (
@@ -234,8 +190,8 @@ const EditorSettingsBody: FC<Props> = (props) => {
                 type="checkbox"
                 className="custom-control-input"
                 id={rule.name}
-                checked={isCheckedInJapaneseRules(rule.name)}
-                onChange={e => japaneseRuleCheckboxHandler(e.target.checked, rule.name)}
+                checked={isCheckedRule(rule.name)}
+                onChange={e => ruleCheckboxHandler(e.target.checked, rule.name)}
               />
               <label className="custom-control-label" htmlFor={rule.name}>
                 <strong>{rule.name}</strong>
@@ -250,7 +206,7 @@ const EditorSettingsBody: FC<Props> = (props) => {
               <button
                 type="button"
                 className="btn btn-primary"
-                onClick={updateJapaneseRuleHandler}
+                onClick={updateRulesHandler}
               >
                 {t('Update')}
               </button>
@@ -265,7 +221,7 @@ const EditorSettingsBody: FC<Props> = (props) => {
   );
 };
 
-export const EditorSettings = withUnstatedContainers(EditorSettingsBody, [AppContainer, EditorContainer]);
+export const EditorSettings = withUnstatedContainers(EditorSettingsBody, [AppContainer]);
 
 EditorSettingsBody.propTypes = {
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,

+ 3 - 3
packages/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -882,7 +882,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
 
   render() {
     const mode = this.state.isGfmMode ? 'gfm-growi' : undefined;
-    const lint = this.props.isTextlintEnabled ? this.codemirrorLintConfig : false;
+    const lint = this.props?.isTextlintEnabled ? this.codemirrorLintConfig : false;
     const additionalClasses = Array.from(this.state.additionalClassSet).join(' ');
     const placeholder = this.state.isGfmMode ? 'Input with Markdown..' : 'Input with Plain Text..';
 
@@ -983,8 +983,8 @@ export default class CodeMirrorEditor extends AbstractEditor {
 }
 
 CodeMirrorEditor.propTypes = Object.assign({
-  editorOptions: PropTypes.object.isRequired,
-  isTextlintEnabled: PropTypes.bool.isRequired,
+  editorOptions: PropTypes.object,
+  isTextlintEnabled: PropTypes.bool,
   emojiStrategy: PropTypes.object,
   lineNumbers: PropTypes.bool,
   onMarkdownHelpButtonClicked: PropTypes.func,

+ 4 - 2
packages/app/src/server/routes/apiv3/personal-setting.js

@@ -4,6 +4,8 @@ import loggerFactory from '~/utils/logger';
 
 import { listLocaleIds } from '~/utils/locale-utils';
 
+import EditorSettings from '../../models/editor-settings';
+
 const logger = loggerFactory('growi:routes:apiv3:personal-setting');
 
 const express = require('express');
@@ -68,7 +70,7 @@ module.exports = (crowi) => {
   const csrf = require('../../middlewares/csrf')(crowi);
   const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
-  const { User, ExternalAccount, EditorSettings } = crowi.models;
+  const { User, ExternalAccount } = crowi.models;
 
   const validator = {
     personal: [
@@ -519,7 +521,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: editor settings
    */
-  router.get('/editor-settings', accessTokenParser, loginRequiredStrictly, csrf, validator.editorSettings, apiV3FormValidator, async(req, res) => {
+  router.get('/editor-settings', accessTokenParser, loginRequiredStrictly, async(req, res) => {
     try {
       const query = { userId: req.user.id };
       const response = await EditorSettings.findOne(query);