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

Merge branch 'master' into feat/gw7925-normalize-cypress-test

ryoji-s 3 лет назад
Родитель
Сommit
39d9c387d3
63 измененных файлов с 285 добавлено и 1613 удалено
  1. 4 13
      .github/workflows/ci-app-prod.yml
  2. 2 8
      .github/workflows/ci-app.yml
  3. 1 0
      .github/workflows/ci-slackbot-proxy.yml
  4. 2 0
      .github/workflows/codeql-analysis.yml
  5. 5 0
      apps/app/next.config.js
  6. 1 3
      apps/app/package.json
  7. 0 3
      apps/app/public/static/dict/base.dat.gz
  8. 0 3
      apps/app/public/static/dict/cc.dat.gz
  9. 0 3
      apps/app/public/static/dict/check.dat.gz
  10. 0 3
      apps/app/public/static/dict/tid.dat.gz
  11. 0 3
      apps/app/public/static/dict/tid_map.dat.gz
  12. 0 3
      apps/app/public/static/dict/tid_pos.dat.gz
  13. 0 3
      apps/app/public/static/dict/unk.dat.gz
  14. 0 3
      apps/app/public/static/dict/unk_char.dat.gz
  15. 0 3
      apps/app/public/static/dict/unk_compat.dat.gz
  16. 0 3
      apps/app/public/static/dict/unk_invoke.dat.gz
  17. 0 3
      apps/app/public/static/dict/unk_map.dat.gz
  18. 0 3
      apps/app/public/static/dict/unk_pos.dat.gz
  19. 1 40
      apps/app/public/static/locales/en_US/translation.json
  20. 0 5
      apps/app/public/static/locales/ja_JP/translation.json
  21. 1 39
      apps/app/public/static/locales/zh_CN/translation.json
  22. 0 2
      apps/app/src/components/Admin/Notification/NotificationSetting.jsx
  23. 0 7
      apps/app/src/components/Admin/Security/SecurityManagementContents.jsx
  24. 62 64
      apps/app/src/components/CustomNavigation/CustomNav.tsx
  25. 2 1
      apps/app/src/components/CustomNavigation/CustomTabContent.tsx
  26. 0 2
      apps/app/src/components/DescendantsPageListModal.tsx
  27. 0 2
      apps/app/src/components/InAppNotification/InAppNotificationPage.tsx
  28. 17 261
      apps/app/src/components/Me/EditorSettings.tsx
  29. 6 13
      apps/app/src/components/Me/PersonalSettings.jsx
  30. 0 2
      apps/app/src/components/NotFoundPage.tsx
  31. 1 4
      apps/app/src/components/PageAccessoriesModal.tsx
  32. 0 2
      apps/app/src/components/PageComment/CommentEditor.tsx
  33. 1 3
      apps/app/src/components/PageEditor.tsx
  34. 0 30
      apps/app/src/components/PageEditor/CodeMirrorEditor.jsx
  35. 0 69
      apps/app/src/components/PageEditor/DownloadDictModal.tsx
  36. 0 1
      apps/app/src/components/PageEditor/Editor.tsx
  37. 4 72
      apps/app/src/components/PageEditor/OptionsSelector.tsx
  38. 0 1
      apps/app/src/components/TrashPageList.tsx
  39. 8 3
      apps/app/src/components/UncontrolledCodeMirror.tsx
  40. 0 12
      apps/app/src/interfaces/editor-settings.ts
  41. 1 2
      apps/app/src/interfaces/ui.ts
  42. 0 2
      apps/app/src/pages/installer.page.tsx
  43. 1 11
      apps/app/src/server/models/editor-settings.ts
  44. 0 14
      apps/app/src/server/routes/apiv3/personal-setting.js
  45. 3 0
      apps/app/src/server/service/page.ts
  46. 0 17
      apps/app/src/stores/editor.tsx
  47. 1 16
      apps/app/test/cypress/integration/60-home/60-home--home.spec.ts
  48. 0 2
      apps/app/tsconfig.build.client.json
  49. 0 2
      apps/app/tsconfig.json
  50. 2 1
      package.json
  51. 0 2
      packages/codemirror-textlint/.eslintignore
  52. 0 1
      packages/codemirror-textlint/.gitignore
  53. 0 51
      packages/codemirror-textlint/package.json
  54. 0 151
      packages/codemirror-textlint/src/index.ts
  55. 0 9
      packages/codemirror-textlint/src/utils/logger/index.ts
  56. 0 9
      packages/codemirror-textlint/tsconfig.base.json
  57. 0 17
      packages/codemirror-textlint/tsconfig.build.json
  58. 0 7
      packages/codemirror-textlint/tsconfig.json
  59. 4 0
      packages/remark-lsx/package.json
  60. 2 4
      packages/remark-lsx/src/server/routes/lsx.ts
  61. 1 1
      packages/remark-lsx/src/services/renderer/lsx.ts
  62. 1 0
      packages/remark-lsx/vite.server.config.ts
  63. 151 599
      yarn.lock

+ 4 - 13
.github/workflows/ci-app-prod.yml

@@ -11,15 +11,10 @@ on:
       - tsconfig.base.json
       - turbo.json
       - yarn.lock
+      - package.json
       - apps/app/**
       - '!apps/app/docker/**'
-      - packages/codemirror-textlint/**
-      - packages/core/**
-      - packages/preset-themes/**
-      - packages/presentation/**
-      - packages/remark-*/**
-      - packages/slack/**
-      - packages/ui/**
+      - packages/**
   pull_request:
     branches:
       - master
@@ -31,14 +26,10 @@ on:
       - tsconfig.base.json
       - yarn.lock
       - turbo.json
+      - package.json
       - apps/app/**
       - '!apps/app/docker/**'
-      - packages/codemirror-textlint/**
-      - packages/core/**
-      - packages/preset-themes/**
-      - packages/remark-*/**
-      - packages/slack/**
-      - packages/ui/**
+      - packages/**
   workflow_call:
     inputs:
       cypress-config-video:

+ 2 - 8
.github/workflows/ci-app.yml

@@ -11,16 +11,10 @@ on:
       - tsconfig.base.json
       - turbo.json
       - yarn.lock
+      - package.json
       - apps/app/**
       - '!apps/app/docker/**'
-      - packages/codemirror-textlint/**
-      - packages/core/**
-      - packages/hackmd/**
-      - packages/presentation/**
-      - packages/preset-themes/**
-      - packages/remark-*/**
-      - packages/slack/**
-      - packages/ui/**
+      - packages/**
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}

+ 1 - 0
.github/workflows/ci-slackbot-proxy.yml

@@ -12,6 +12,7 @@ on:
       - tsconfig.base.json
       - turbo.json
       - yarn.lock
+      - package.json
       - apps/slackbot-proxy/**
       - '!apps/slackbot-proxy/docker/**'
       - packages/slack/**

+ 2 - 0
.github/workflows/codeql-analysis.yml

@@ -16,12 +16,14 @@ on:
     branches: [ master, dev/*, release/current ]
     paths:
       - .github/workflows/codeql-analysis.yml
+      - apps/**
       - packages/**
   pull_request:
     # The branches below must be a subset of the branches above
     branches: [ master ]
     paths:
       - .github/workflows/codeql-analysis.yml
+      - apps/**
       - packages/**
   schedule:
     - cron: '28 20 * * 6'

+ 5 - 0
apps/app/next.config.js

@@ -19,7 +19,11 @@ const getTranspilePackages = () => {
     'react-markdown',
     'unified',
     'markdown-table',
+    'bail',
+    'ccount',
+    'character-entities',
     'character-entities-html4',
+    'character-entities-legacy',
     'comma-separated-tokens',
     'decode-named-character-reference',
     'escape-string-regexp',
@@ -27,6 +31,7 @@ const getTranspilePackages = () => {
     'html-void-elements',
     'is-absolute-url',
     'longest-streak',
+    'micromark',
     'property-information',
     'space-separated-tokens',
     'stringify-entities',

+ 1 - 3
apps/app/package.json

@@ -60,7 +60,6 @@
     "@elastic/elasticsearch7": "npm:@elastic/elasticsearch@^7.17.0",
     "@godaddy/terminus": "^4.9.0",
     "@google-cloud/storage": "^5.8.5",
-    "@growi/codemirror-textlint": "^6.1.0-RC.0",
     "@growi/core": "^6.1.0-RC.0",
     "@growi/hackmd": "^6.1.0-RC.0",
     "@growi/preset-themes": "^6.1.0-RC.0",
@@ -213,7 +212,7 @@
     "codemirror": "^5.64.0",
     "connect-browser-sync": "^2.1.0",
     "core-js": "=2.6.9",
-    "diff2html": "^3.1.2",
+    "diff2html": "^3.4.35",
     "eazy-logger": "^3.1.0",
     "emoji-mart": "npm:panta82-emoji-mart@^3.0.1",
     "eslint-plugin-cypress": "^2.12.1",
@@ -223,7 +222,6 @@
     "i18next-hmr": "^1.11.0",
     "jquery-slimscroll": "^1.3.8",
     "jquery.cookie": "~1.4.1",
-    "jshint": "^2.13.0",
     "load-css-file": "^1.0.0",
     "material-icons": "^1.11.3",
     "morgan": "^1.10.0",

+ 0 - 3
apps/app/public/static/dict/base.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:0803327762e1c93ca731e4319ab8343340f2806bb84941207782cde9d2d5a8eb
-size 3956825

+ 0 - 3
apps/app/public/static/dict/cc.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:02b7631be0d4de3a1a75cd9f9cc51536e4f94c9e6b389b813e06ba0f6e7de765
-size 1692067

+ 0 - 3
apps/app/public/static/dict/check.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:193ae0035fff6fe812b58d9ee730e7a7d7ee601d918481ce51075c58114f6cc9
-size 3111633

+ 0 - 3
apps/app/public/static/dict/tid.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:d43d831cb6fb0f0a411739cd287a6d5e998e121a8daca614df14a81a0dcac586
-size 1605820

+ 0 - 3
apps/app/public/static/dict/tid_map.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:33efd5ffd87a70f669add093fa39dee44341d58f940844ef107c8fd98bb795b2
-size 1485576

+ 0 - 3
apps/app/public/static/dict/tid_pos.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:60dbfc99a6ab993f30c5dab648bec6ad7f9aaefa5c14e1843837d95e509f8895
-size 5916009

+ 0 - 3
apps/app/public/static/dict/unk.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:f7f991cdeb9bfd3e9c0e4577cc50ee0815a11c508cccd444a9d3ab3c81521100
-size 10512

+ 0 - 3
apps/app/public/static/dict/unk_char.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:9a8e86fd9aff32d323fbb59f5a7006f05927a11f8173c90712cc56293aeb3225
-size 306

+ 0 - 3
apps/app/public/static/dict/unk_compat.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:50f60aa29bc2e86c2903ab8c825bb6fa604d2b294d96941c1d3924259791899d
-size 338

+ 0 - 3
apps/app/public/static/dict/unk_invoke.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6b210889548457c3006913afd12c8b525562255f2709e404604be9614a25e94c
-size 1140

+ 0 - 3
apps/app/public/static/dict/unk_map.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6df12460e5477230bb6fd9641def918b699fc0a8868016b6c9f794488630509b
-size 1190

+ 0 - 3
apps/app/public/static/dict/unk_pos.dat.gz

@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:5b183a29f281acc7e0542beca47b83f7985047c0a2d27e78a66f32276be5ad11
-size 10540

+ 1 - 40
apps/app/public/static/locales/en_US/translation.json

@@ -247,41 +247,7 @@
     }
   },
   "editor_settings": {
-    "editor_settings": "Editor Settings",
-    "common_settings": {
-      "common_settings": "Common Settings",
-      "common_misspellings": "Textlint rules to find common misspellings from Wikipedia.",
-      "max_comma": "Textlint rule is that limit maximum ten(,) count of sentence. Default: 4",
-      "sentence_length": "Textlint rules that limit Maximum Length of Sentence. Default: 100",
-      "en_capitalization": "Textlint rule that check capitalization in english text.",
-      "no_unmatched_pair": "Textlint rule that check unmatched pairs like ( and ]",
-      "date_weekday_mismatch": "Textlint rule that found mismatch between date and weekday.",
-      "no_kangxi_radicals": "Textlint rule to prevent using kangxi radicals.",
-      "no_surrogate_pair": "Detects surrogate pairs (D800-DBFF and DC00-DFFF) in sentences.",
-      "no_zero_width_spaces": "Textlint rule that disallow zero width spaces.",
-      "period_in_list_item": "Textlint rule that check with or without period in list item.",
-      "use_si_units": "Use of units other than SI unit units is prohibited."
-
-      },
-    "japanese_settings": {
-      "japanese_settings": "Japanese Settings",
-      "ja_no_abusage": "Textlint rules to check for common misuse.",
-      "ja_hiragana_keishikimeishi": "Textlint rules to check easy-to-read Keishikimeishi(pronouns) written in Hiragana than Kanji.",
-      "ja_no_inappropriate_words": "Textlint rules to check for inappropriate expressions",
-      "ja_no_mixed_period": "Textlint rules to check that a paragraph always has a punctuation mark at the end.",
-      "ja_no_redundant_expression": "Textlint rules that prohibits redundant expressions. Redundant expressions are expressions that make sense even if they are omitted from the sentence.",
-      "max_kanji_continuous_len": "Textlint rules that limits the maximum number of consecutive Kanji. Default: 5",
-      "max_ten": "Textlint rule is that limit maximum ten(、) count of sentence.",
-      "no_double_negative_ja": "Textlint rules that detects double negation.",
-      "no_doubled_conjunction": "Textlint rules to check duplicated same conjunctions.",
-      "no_doubled_joshi": "Textlint rules that checks that the same particle appears consecutively in one sentence.",
-      "no_dropping_the_ra": "Textlint rules that detects the word dropping the ra.",
-      "no_hankaku_kana": "Textlint rules that disallow to use Half-width kana.",
-      "prefer_tari_tari": "Textlint rules that checks tari tari.",
-      "ja_unnatural_alphabet": "Detects unnatural alphabets.",
-      "no_mixed_zenkaku_and_hankaku_alphabet": "Check for mixed full-width and half-width alphabets.",
-      "no_nfd": "textlint rule that disallow to use NFD like UTF8-MAC Sonant mark."
-    }
+    "editor_settings": "Editor Settings"
   },
   "search_help": {
     "title": "Searching Help",
@@ -444,11 +410,6 @@
       "Post": "Post"
     }
   },
-  "modal_enable_textlint": {
-    "confirm_download_dict_and_enable_textlint": "Are you sure you want to enable Textlint? This will download 20MB of dictionary file.",
-    "enable_textlint": "Enable Textlint",
-    "dont_ask_again": "Don't ask again"
-  },
   "modal_resolve_conflict": {
     "file_conflicting_with_newer_remote": "This file is conflicting with newer remote file",
     "resolve_conflict_message": "Please select page body",

+ 0 - 5
apps/app/public/static/locales/ja_JP/translation.json

@@ -444,11 +444,6 @@
       "Post": "投稿"
     }
   },
-  "modal_enable_textlint": {
-    "confirm_download_dict_and_enable_textlint": "Textlintを有効にしますか?20MBの辞書ファイルをダウンロードします。",
-    "enable_textlint": "Textlintを有効にする",
-    "dont_ask_again": "常に許可する"
-  },
   "modal_resolve_conflict": {
     "file_conflicting_with_newer_remote": "サーバー側の新しいファイルと衝突します。",
     "resolve_conflict_message": "ページ本文を選んでください",

+ 1 - 39
apps/app/public/static/locales/zh_CN/translation.json

@@ -239,40 +239,7 @@
     }
   },
   "editor_settings": {
-    "editor_settings": "编辑器设置",
-    "common_settings": {
-      "common_settings": "常用设置",
-      "common_misspellings": "从 Wikipedia 中查找常见拼写错误的 Textlint。",
-      "max_comma": "Textlint 规则是限制句子的最大十(,)个计数。默认:4。",
-      "sentence_length": "限制最大句子长度的 Textlint 默认: 100。",
-      "en_capitalization": "检查英文文本大小写的 Textlint 规则。",
-      "no_unmatched_pair": "检查不匹配对的 Textlint 规则,如 ( 和 ]",
-      "date_weekday_mismatch": "发现日期和工作日之间不匹配的 Textlint 规则。",
-      "no_kangxi_radicals": "防止使用康熙部首的 Textlint 规则。",
-      "no_surrogate_pair": "检测句子中的代理对(D800-DBFF 和 DC00-DFFF)。",
-      "no_zero_width_spaces": "不允许零宽度空格的 Textlint 规则。",
-      "period_in_list_item": "在列表项中检查是否有句点的 Textlint 规则。",
-      "use_si_units": "禁止使用 SI 单位以外的单位。"
-      },
-    "japanese_settings": {
-      "japanese_settings": "日语设置",
-      "ja_no_abusage": "用于检查常见误用的 Textlint 规则。",
-      "ja_hiragana_keishikimeishi": "Textlint 规则检查易于阅读的 Keishikimeishi(代词)用平假名而不是汉字编写。",
-      "ja_no_inappropriate_words": "Textlint 规则来检查不适当的表达",
-      "ja_no_mixed_period": "Textlint 规则用于检查段落末尾是否总是有标点符号。",
-      "ja_no_redundant_expression": "禁止冗余表达式的 Textlint 规则。冗余表达式是即使从句子中省略也有意义的表达式。",
-      "max_kanji_continuous_len": "限制连续汉字的最大数量的 Textlint 规则。默认:5。",
-      "max_ten": "Textlint 规则是限制句子的最大十(、)个计数。",
-      "no_double_negative_ja": "检测双重否定的 Textlint 规则。",
-      "no_doubled_conjunction": "Textlint 规则来检查重复的相同连词。",
-      "no_doubled_joshi": "Textlint 规则,用于检查同一个粒子是否连续出现在一个句子中。",
-      "no_dropping_the_ra": "检测丢弃 ra 的单词的 Textlint 规则。",
-      "no_hankaku_kana": "不允许使用半角假名的 Textlint 规则。",
-      "prefer_tari_tari": "检查 tari tari 的 Textlint 规则。",
-      "ja_unnatural_alphabet": "检测不自然的字母。",
-      "no_mixed_zenkaku_and_hankaku_alphabet": "检查混合的全角和半角字母。",
-      "no_nfd": "禁止使用 UTF8-MAC 浊音等 NFD。"
-    }
+    "editor_settings": "编辑器设置"
   },
 	"search_help": {
 		"title": "搜索帮助",
@@ -433,11 +400,6 @@
 			"Post": "提交"
 		}
 	},
-  "modal_enable_textlint": {
-    "confirm_download_dict_and_enable_textlint": "您确定要启用 Textlint 吗?这将下载 20MB 的字典文件。",
-    "enable_textlint": "启用Textlint",
-    "dont_ask_again": "不要再问"
-  },
   "modal_resolve_conflict": {
     "file_conflicting_with_newer_remote": "此文件与较新的远程文件冲突",
     "resolve_conflict_message": "选择页面正文",

+ 0 - 2
apps/app/src/components/Admin/Notification/NotificationSetting.jsx

@@ -126,12 +126,10 @@ function NotificationSetting(props) {
       user_trigger_notification: {
         Icon: () => <i className="icon-settings" />,
         i18n: 'User trigger notification',
-        index: 0,
       },
       global_notification: {
         Icon: () => <i className="icon-settings" />,
         i18n: 'Global notification',
-        index: 1,
       },
     };
   }, []);

+ 0 - 7
apps/app/src/components/Admin/Security/SecurityManagementContents.jsx

@@ -32,37 +32,30 @@ const SecurityManagementContents = () => {
       passport_local: {
         Icon: () => <i className="fa fa-users" />,
         i18n: 'ID/Pass',
-        index: 0,
       },
       passport_ldap: {
         Icon: () => <i className="fa fa-sitemap" />,
         i18n: 'LDAP',
-        index: 1,
       },
       passport_saml: {
         Icon: () => <i className="fa fa-key" />,
         i18n: 'SAML',
-        index: 2,
       },
       passport_oidc: {
         Icon: () => <i className="fa fa-key" />,
         i18n: 'OIDC',
-        index: 3,
       },
       passport_google: {
         Icon: () => <i className="fa fa-google" />,
         i18n: 'Google',
-        index: 4,
       },
       passport_github: {
         Icon: () => <i className="fa fa-github" />,
         i18n: 'GitHub',
-        index: 5,
       },
       // passport_facebook: {
       //   Icon: () => <i className="fa fa-facebook" />,
       //   i18n: '(TBD) Facebook',
-      //   index: 7,
       // },
     };
   }, []);

+ 62 - 64
apps/app/src/components/CustomNavigation/CustomNav.jsx → apps/app/src/components/CustomNavigation/CustomNav.tsx

@@ -2,16 +2,20 @@ import React, {
   useEffect, useState, useRef, useMemo, useCallback,
 } from 'react';
 
-import PropTypes from 'prop-types';
+import { Breakpoint } from '@growi/ui/dist/interfaces/breakpoints';
 import {
   Nav, NavItem, NavLink,
 } from 'reactstrap';
 
+import { ICustomNavTabMappings } from '~/interfaces/ui';
+
 import styles from './CustomNav.module.scss';
 
 
-function getBreakpointOneLevelLarger(breakpoint) {
+function getBreakpointOneLevelLarger(breakpoint: Breakpoint): Omit<Breakpoint, 'xs' | 'sm'> {
   switch (breakpoint) {
+    case 'xs':
+      return 'sm';
     case 'sm':
       return 'md';
     case 'md':
@@ -25,12 +29,18 @@ function getBreakpointOneLevelLarger(breakpoint) {
 }
 
 
-export const CustomNavDropdown = (props) => {
+type CustomNavDropdownProps = {
+  navTabMapping: ICustomNavTabMappings,
+  activeTab: string,
+  onNavSelected?: (selectedTabKey: string) => void,
+};
+
+export const CustomNavDropdown = (props: CustomNavDropdownProps): JSX.Element => {
   const {
     activeTab, navTabMapping, onNavSelected,
   } = props;
 
-  const activeObj = navTabMapping[activeTab];
+  const { Icon, i18n } = navTabMapping[activeTab];
 
   const menuItemClickHandler = useCallback((key) => {
     if (onNavSelected != null) {
@@ -48,16 +58,15 @@ export const CustomNavDropdown = (props) => {
         aria-expanded="false"
       >
         <span className="float-left">
-          { activeObj != null && (
-            <><activeObj.Icon /> {activeObj.i18n}</>
-          ) }
+          { Icon != null && <Icon /> } {i18n}
         </span>
       </button>
       <div className="dropdown-menu dropdown-menu-right">
         {Object.entries(navTabMapping).map(([key, value]) => {
 
           const isActive = activeTab === key;
-          const isLinkEnabled = value.isLinkEnabled != null ? value.isLinkEnabled(value) : true;
+          const _isLinkEnabled = value.isLinkEnabled ?? true;
+          const isLinkEnabled = typeof _isLinkEnabled === 'boolean' ? _isLinkEnabled : _isLinkEnabled(value);
           const { Icon, i18n } = value;
 
           return (
@@ -68,7 +77,7 @@ export const CustomNavDropdown = (props) => {
               disabled={!isLinkEnabled}
               onClick={() => menuItemClickHandler(key)}
             >
-              <Icon /> {i18n}
+              { Icon != null && <Icon /> } {i18n}
             </button>
           );
         })}
@@ -77,23 +86,29 @@ export const CustomNavDropdown = (props) => {
   );
 };
 
-CustomNavDropdown.propTypes = {
-  navTabMapping: PropTypes.object.isRequired,
-  activeTab: PropTypes.string,
-  onNavSelected: PropTypes.func,
-};
 
+type CustomNavTabProps = {
+  activeTab: string,
+  navTabMapping: ICustomNavTabMappings,
+  onNavSelected?: (selectedTabKey: string) => void,
+  hideBorderBottom?: boolean,
+  breakpointToHideInactiveTabsDown?: Breakpoint,
+  navRightElement?: JSX.Element,
+};
 
-export const CustomNavTab = (props) => {
-  const navContainer = useRef();
+export const CustomNavTab = (props: CustomNavTabProps): JSX.Element => {
   const [sliderWidth, setSliderWidth] = useState(0);
   const [sliderMarginLeft, setSliderMarginLeft] = useState(0);
 
   const {
-    activeTab, navTabMapping, onNavSelected, hideBorderBottom, breakpointToHideInactiveTabsDown, navRightElement,
+    activeTab, navTabMapping, onNavSelected,
+    hideBorderBottom,
+    breakpointToHideInactiveTabsDown, navRightElement,
   } = props;
 
-  const navTabRefs = useMemo(() => {
+  const navContainerRef = useRef<HTMLDivElement>(null);
+
+  const navTabRefs: { [key: string]: HTMLAnchorElement } = useMemo(() => {
     const obj = {};
     Object.keys(navTabMapping).forEach((key) => {
       obj[key] = React.createRef();
@@ -107,9 +122,9 @@ export const CustomNavTab = (props) => {
     }
   }, [onNavSelected]);
 
-  function registerNavLink(key, elm) {
-    if (elm != null) {
-      navTabRefs[key] = elm;
+  function registerNavLink(key: string, anchorElem: HTMLAnchorElement | null) {
+    if (anchorElem != null) {
+      navTabRefs[key] = anchorElem;
     }
   }
 
@@ -123,27 +138,28 @@ export const CustomNavTab = (props) => {
       return;
     }
 
-    if (navContainer == null) {
+    if (navContainerRef.current == null) {
       return;
     }
 
-    let tempML = 0;
+    const navContainer = navContainerRef.current;
 
-    const styles = Object.entries(navTabRefs).map((el) => {
-      const width = getPercentage(el[1].offsetWidth, navContainer.current.offsetWidth);
-      const marginLeft = tempML;
-      tempML += width;
-      return { width, marginLeft };
-    });
-    const { width, marginLeft } = styles[navTabMapping[activeTab].index];
+    let marginLeft = 0;
+    for (const [key, anchorElem] of Object.entries(navTabRefs)) {
+      const width = getPercentage(anchorElem.offsetWidth, navContainer.offsetWidth);
 
-    setSliderWidth(width);
-    setSliderMarginLeft(marginLeft);
+      if (key === activeTab) {
+        setSliderWidth(width);
+        setSliderMarginLeft(marginLeft);
+        break;
+      }
 
+      marginLeft += width;
+    }
   }, [activeTab, navTabRefs, navTabMapping]);
 
   // determine inactive classes to hide NavItem
-  const inactiveClassnames = [];
+  const inactiveClassnames: string[] = [];
   if (breakpointToHideInactiveTabsDown != null) {
     const breakpointOneLevelLarger = getBreakpointOneLevelLarger(breakpointToHideInactiveTabsDown);
     inactiveClassnames.push('d-none');
@@ -152,12 +168,13 @@ export const CustomNavTab = (props) => {
 
   return (
     <div className={`grw-custom-nav-tab ${styles['grw-custom-nav-tab']}`}>
-      <div ref={navContainer} className="d-flex justify-content-between">
+      <div ref={navContainerRef} className="d-flex justify-content-between">
         <Nav className="nav-title">
           {Object.entries(navTabMapping).map(([key, value]) => {
 
             const isActive = activeTab === key;
-            const isLinkEnabled = value.isLinkEnabled != null ? value.isLinkEnabled(value) : true;
+            const _isLinkEnabled = value.isLinkEnabled ?? true;
+            const isLinkEnabled = typeof _isLinkEnabled === 'boolean' ? _isLinkEnabled : _isLinkEnabled(value);
             const { Icon, i18n } = value;
 
             return (
@@ -166,7 +183,7 @@ export const CustomNavTab = (props) => {
                 className={`p-0 ${isActive ? 'active' : inactiveClassnames.join(' ')}`}
               >
                 <NavLink type="button" key={key} innerRef={elm => registerNavLink(key, elm)} disabled={!isLinkEnabled} onClick={() => navLinkClickHandler(key)}>
-                  <Icon /> {i18n}
+                  { Icon != null && <Icon /> } {i18n}
                 </NavLink>
               </NavItem>
             );
@@ -181,27 +198,23 @@ export const CustomNavTab = (props) => {
 
 };
 
-CustomNavTab.propTypes = {
-  activeTab: PropTypes.string.isRequired,
-  navTabMapping: PropTypes.object.isRequired,
-  onNavSelected: PropTypes.func,
-  hideBorderBottom: PropTypes.bool,
-  breakpointToHideInactiveTabsDown: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
-  navRightElement: PropTypes.node,
-};
 
-CustomNavTab.defaultProps = {
-  hideBorderBottom: false,
+type CustomNavProps = {
+  activeTab: string,
+  navTabMapping: ICustomNavTabMappings,
+  onNavSelected?: (selectedTabKey: string) => void,
+  hideBorderBottom?: boolean,
+  breakpointToHideInactiveTabsDown?: Breakpoint,
+  breakpointToSwitchDropdownDown?: Breakpoint,
 };
 
-
-const CustomNav = (props) => {
+const CustomNav = (props: CustomNavProps): JSX.Element => {
 
   const tabClassnames = ['d-none'];
   const dropdownClassnames = ['d-block'];
 
   // determine classes to show/hide
-  const breakpointOneLevelLarger = getBreakpointOneLevelLarger(props.breakpointToSwitchDropdownDown);
+  const breakpointOneLevelLarger = getBreakpointOneLevelLarger(props.breakpointToSwitchDropdownDown ?? 'sm');
   tabClassnames.push(`d-${breakpointOneLevelLarger}-block`);
   dropdownClassnames.push(`d-${breakpointOneLevelLarger}-none`);
 
@@ -218,19 +231,4 @@ const CustomNav = (props) => {
 
 };
 
-CustomNav.propTypes = {
-  activeTab: PropTypes.string.isRequired,
-  navTabMapping: PropTypes.object.isRequired,
-  onNavSelected: PropTypes.func,
-  hideBorderBottom: PropTypes.bool,
-  breakpointToHideInactiveTabsDown: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
-  breakpointToSwitchDropdownDown: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
-};
-
-CustomNav.defaultProps = {
-  hideBorderBottom: false,
-  breakpointToSwitchDropdownDown: 'sm',
-};
-
-
 export default CustomNav;

+ 2 - 1
apps/app/src/components/CustomNavigation/CustomTabContent.tsx

@@ -24,11 +24,12 @@ const CustomTabContent = (props: Props): JSX.Element => {
       {Object.entries(navTabMapping).map(([key, value]) => {
 
         const { Content } = value;
+        const content = Content != null ? <Content /> : <></>;
 
         return (
           <TabPane key={key} tabId={key}>
             <LazyRenderer shouldRender={key === activeTab}>
-              <Content />
+              {content}
             </LazyRenderer>
           </TabPane>
         );

+ 0 - 2
apps/app/src/components/DescendantsPageListModal.tsx

@@ -54,7 +54,6 @@ export const DescendantsPageListModal = (): JSX.Element => {
           return <DescendantsPageList path={status.path} />;
         },
         i18n: t('page_list'),
-        index: 0,
         isLinkEnabled: () => !isSharedUser,
       },
       timeline: {
@@ -66,7 +65,6 @@ export const DescendantsPageListModal = (): JSX.Element => {
           return <PageTimeline />;
         },
         i18n: t('Timeline View'),
-        index: 1,
         isLinkEnabled: () => !isSharedUser,
       },
     };

+ 0 - 2
apps/app/src/components/InAppNotification/InAppNotificationPage.tsx

@@ -127,13 +127,11 @@ export const InAppNotificationPage: FC = () => {
       Icon: () => <></>,
       Content: () => InAppNotificationCategoryByStatus(),
       i18n: t('in_app_notification.all'),
-      index: 0,
     },
     external_accounts: {
       Icon: () => <></>,
       Content: () => InAppNotificationCategoryByStatus(InAppNotificationStatuses.STATUS_UNOPENED),
       i18n: t('in_app_notification.unopend'),
-      index: 1,
     },
   };
 

+ 17 - 261
apps/app/src/components/Me/EditorSettings.tsx

@@ -1,273 +1,28 @@
-import React, {
-  Dispatch, memo,
-  FC, SetStateAction, useCallback, useEffect, useState,
-  useMemo,
-} from 'react';
-
-import { useTranslation } from 'next-i18next';
-
-import { toastSuccess, toastError } from '~/client/util/toastr';
-import { useEditorSettings } from '~/stores/editor';
-
-
-type EditorSettingsBodyProps = Record<string, never>;
-
-type RuleListGroupProps = {
-  title: string;
-  ruleList: RulesMenuItem[]
-  textlintRules: LintRule[]
-  setTextlintRules: Dispatch<SetStateAction<LintRule[]>>
-}
-
-type LintRule = {
-  name: string
-  options?: unknown
-  isEnabled?: boolean
-}
-
-type RulesMenuItem = {
-  name: string
-  description: string
-}
-
-
-const commonRulesMenuItems = [
-  {
-    name: 'common-misspellings',
-    description: 'editor_settings.common_settings.common_misspellings',
-  },
-  {
-    name: 'max-comma',
-    description: 'editor_settings.common_settings.max_comma',
-  },
-  {
-    name: 'sentence-length',
-    description: 'editor_settings.common_settings.sentence_length',
-  },
-  // {  // omit because en-pos package is too big
-  //   name: 'en-capitalization',
-  //   description: 'editor_settings.common_settings.en_capitalization',
-  // },
-  {
-    name: 'no-unmatched-pair',
-    description: 'editor_settings.common_settings.no_unmatched_pair',
-  },
-  {
-    name: 'date-weekday-mismatch',
-    description: 'editor_settings.common_settings.date_weekday_mismatch',
-  },
-  {
-    name: 'no-kangxi-radicals',
-    description: 'editor_settings.common_settings.no_kangxi_radicals',
-  },
-  {
-    name: 'no-surrogate-pair',
-    description: 'editor_settings.common_settings.no_surrogate_pair',
-  },
-  {
-    name: 'no-zero-width-spaces',
-    description: 'editor_settings.common_settings.no_zero_width_spaces',
-  },
-  {
-    name: 'period-in-list-item',
-    description: 'editor_settings.common_settings.period_in_list_item',
-  },
-  {
-    name: 'use-si-units',
-    description: 'editor_settings.common_settings.use_si_units',
-  },
-];
-
-const japaneseRulesMenuItems = [
-  {
-    name: 'ja-hiragana-keishikimeishi',
-    description: 'editor_settings.japanese_settings.ja_hiragana_keishikimeishi',
-  },
-  {
-    name: 'ja-no-abusage',
-    description: 'editor_settings.japanese_settings.ja_no_abusage',
-  },
-  {
-    name: 'ja-no-inappropriate-words',
-    description: 'editor_settings.japanese_settings.ja_no_inappropriate_words',
-  },
-  {
-    name: 'ja-no-mixed-period',
-    description: 'editor_settings.japanese_settings.ja_no_mixed_period',
-  },
-  {
-    name: 'ja-no-redundant-expression',
-    description: 'editor_settings.japanese_settings.ja_no_redundant_expression',
-  },
-  {
-    name: 'max-kanji-continuous-len',
-    description: 'editor_settings.japanese_settings.max_kanji_continuous_len',
-  },
-  {
-    name: 'max-ten',
-    description: 'editor_settings.japanese_settings.max_ten',
-  },
-  {
-    name: 'no-double-negative-ja',
-    description: 'editor_settings.japanese_settings.no_double_negative_ja',
-  },
-  {
-    name: 'no-doubled-conjunction',
-    description: 'editor_settings.japanese_settings.no_doubled_conjunction',
-  },
-  {
-    name: 'no-doubled-joshi',
-    description: 'editor_settings.japanese_settings.no_doubled_joshi',
-  },
-  {
-    name: 'no-dropping-the-ra',
-    description: 'editor_settings.japanese_settings.no_dropping_the_ra',
-  },
-  {
-    name: 'no-hankaku-kana',
-    description: 'editor_settings.japanese_settings.no_hankaku_kana',
-  },
-  {
-    name: 'prefer-tari-tari',
-    description: 'editor_settings.japanese_settings.prefer_tari_tari',
-  },
-  {
-    name: 'ja-unnatural-alphabet',
-    description: 'editor_settings.japanese_settings.ja_unnatural_alphabet',
-  },
-  {
-    name: 'no-mixed-zenkaku-and-hankaku-alphabet',
-    description: 'editor_settings.japanese_settings.no_mixed_zenkaku_and_hankaku_alphabet',
-  },
-  {
-    name: 'no-nfd',
-    description: 'editor_settings.japanese_settings.no_nfd',
-  },
-
-];
-
-
-const RuleListGroup: FC<RuleListGroupProps> = ({
-  title, ruleList, textlintRules, setTextlintRules,
-}: RuleListGroupProps) => {
-  const { t } = useTranslation();
-
-  const isCheckedRule = (ruleName: string) => (
-    textlintRules.find(stateRule => (
-      stateRule.name === ruleName
-    ))?.isEnabled || false
-  );
-
-  const ruleCheckboxHandler = (isChecked: boolean, ruleName: string) => {
-    setTextlintRules(prevState => (
-      prevState.filter(rule => rule.name !== ruleName).concat({ name: ruleName, isEnabled: isChecked })
-    ));
-  };
-
-  return (
-    <>
-      <h2 className="border-bottom my-4">{t(title)}</h2>
-      <div className="form-group row">
-        <div className="offset-md-3 col-md-6 text-left">
-          {ruleList.map(rule => (
-            <div
-              key={rule.name}
-              className="custom-control custom-switch custom-checkbox-success"
-            >
-              <input
-                type="checkbox"
-                className="custom-control-input"
-                id={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>
-              </label>
-              <p className="form-text text-muted small">
-                {t(rule.description)}
-              </p>
-            </div>
-          ))}
-        </div>
-      </div>
-    </>
-  );
-};
-
-const createRulesFromDefaultList = (rule: { name: string }) => (
-  {
-    name: rule.name,
-    isEnabled: true,
-  }
-);
-
+import { memo } from 'react';
 
 export const EditorSettings = memo((): JSX.Element => {
-  const { t } = useTranslation();
-  const [textlintRules, setTextlintRules] = useState<LintRule[]>([]);
+  // const { t } = useTranslation();
 
-  const { data: dataEditorSettings, update: updateEditorSettings } = useEditorSettings();
+  // const { data: dataEditorSettings, update: updateEditorSettings } = useEditorSettings();
 
-  const defaultRules = useMemo(() => {
-    const defaultCommonRules = commonRulesMenuItems.map(rule => createRulesFromDefaultList(rule));
-    const defaultJapaneseRules = japaneseRulesMenuItems.map(rule => createRulesFromDefaultList(rule));
+  // const updateRulesHandler = useCallback(async() => {
+  //   try {
+  //     await updateEditorSettings({ textlintSettings: { textlintRules } });
+  //     toastSuccess(t('toaster.update_successed', { target: 'Updated Textlint Settings', ns: 'commons' }));
+  //   }
+  //   catch (err) {
+  //     toastError(err);
+  //   }
+  // }, [t, textlintRules, updateEditorSettings]);
 
-    return [...defaultCommonRules, ...defaultJapaneseRules];
-  }, []);
-
-  const initializeEditorSettings = useCallback(() => {
-    if (dataEditorSettings == null) {
-      return;
-    }
-
-    const retrievedRules: LintRule[] | undefined = dataEditorSettings?.textlintSettings?.textlintRules;
-
-    // If database is empty, add default rules to state
-    if (retrievedRules != null && retrievedRules.length > 0) {
-      setTextlintRules(retrievedRules);
-      return;
-    }
-    setTextlintRules(defaultRules);
-  }, [dataEditorSettings, defaultRules]);
-
-  const updateRulesHandler = useCallback(async() => {
-    try {
-      await updateEditorSettings({ textlintSettings: { textlintRules } });
-      toastSuccess(t('toaster.update_successed', { target: 'Updated Textlint Settings', ns: 'commons' }));
-    }
-    catch (err) {
-      toastError(err);
-    }
-  }, [t, textlintRules, updateEditorSettings]);
-
-  useEffect(() => {
-    initializeEditorSettings();
-  }, [initializeEditorSettings]);
-
-  if (textlintRules == null) {
-    return (
-      <div className="text-muted text-center">
-        <i className="fa fa-2x fa-spinner fa-pulse"></i>
-      </div>
-    );
-  }
+  // useEffect(() => {
+  //   initializeEditorSettings();
+  // }, [initializeEditorSettings]);
 
   return (
     <div data-testid="grw-editor-settings">
-      <RuleListGroup
-        title="editor_settings.common_settings.common_settings"
-        ruleList={commonRulesMenuItems}
-        textlintRules={textlintRules}
-        setTextlintRules={setTextlintRules}
-      />
-      <RuleListGroup
-        title="editor_settings.japanese_settings.japanese_settings"
-        ruleList={japaneseRulesMenuItems}
-        textlintRules={textlintRules}
-        setTextlintRules={setTextlintRules}
-      />
 
+      {/*
       <div className="row my-3">
         <div className="offset-4 col-5">
           <button
@@ -280,6 +35,7 @@ export const EditorSettings = memo((): JSX.Element => {
           </button>
         </div>
       </div>
+      */}
     </div>
   );
 });

+ 6 - 13
apps/app/src/components/Me/PersonalSettings.jsx

@@ -1,13 +1,12 @@
 
 import React, { useMemo } from 'react';
 
-import PropTypes from 'prop-types';
 import { useTranslation } from 'next-i18next';
 
 import CustomNavAndContents from '../CustomNavigation/CustomNavAndContents';
 
 import ApiSettings from './ApiSettings';
-import { EditorSettings } from './EditorSettings';
+// import { EditorSettings } from './EditorSettings';
 import ExternalAccountLinkedMe from './ExternalAccountLinkedMe';
 import InAppNotificationSettings from './InAppNotificationSettings';
 import PasswordSettings from './PasswordSettings';
@@ -23,37 +22,31 @@ const PersonalSettings = () => {
         Icon: () => <i className="icon-fw icon-user"></i>,
         Content: UserSettings,
         i18n: t('User Information'),
-        index: 0,
       },
       external_accounts: {
         Icon: () => <i className="icon-fw icon-share-alt"></i>,
         Content: ExternalAccountLinkedMe,
         i18n: t('admin:user_management.external_accounts'),
-        index: 1,
       },
       password_settings: {
         Icon: () => <i className="icon-fw icon-lock"></i>,
         Content: PasswordSettings,
         i18n: t('Password Settings'),
-        index: 2,
       },
       api_settings: {
         Icon: () => <i className="icon-fw icon-paper-plane"></i>,
         Content: ApiSettings,
         i18n: t('API Settings'),
-        index: 3,
-      },
-      editor_settings: {
-        Icon: () => <i className="icon-fw icon-pencil"></i>,
-        Content: EditorSettings,
-        i18n: t('editor_settings.editor_settings'),
-        index: 4,
       },
+      // editor_settings: {
+      //   Icon: () => <i className="icon-fw icon-pencil"></i>,
+      //   Content: EditorSettings,
+      //   i18n: t('editor_settings.editor_settings'),
+      // },
       in_app_notification_settings: {
         Icon: () => <i className="icon-fw icon-bell"></i>,
         Content: InAppNotificationSettings,
         i18n: t('in_app_notification_settings.in_app_notification_settings'),
-        index: 5,
       },
     };
   }, [t]);

+ 0 - 2
apps/app/src/components/NotFoundPage.tsx

@@ -24,13 +24,11 @@ const NotFoundPage = (props: NotFoundPageProps): JSX.Element => {
         Icon: PageListIcon,
         Content: () => <DescendantsPageList path={path} />,
         i18n: t('page_list'),
-        index: 0,
       },
       timeLine: {
         Icon: TimeLineIcon,
         Content: PageTimeline,
         i18n: t('Timeline View'),
-        index: 1,
       },
     };
   }, [path, t]);

+ 1 - 4
apps/app/src/components/PageAccessoriesModal.tsx

@@ -78,7 +78,6 @@ const PageAccessoriesModal = (): JSX.Element => {
           return <PageHistory onClose={close} sourceRevisionId={sourceRevisionId} targetRevisionId={targetRevisionId}/>;
         },
         i18n: t('History'),
-        index: 0,
         isLinkEnabled: () => !isGuestUser && !isSharedUser,
       },
       [PageAccessoriesModalContents.Attachment]: {
@@ -87,7 +86,6 @@ const PageAccessoriesModal = (): JSX.Element => {
           return <PageAttachment />;
         },
         i18n: t('attachment_data'),
-        index: 1,
       },
       [PageAccessoriesModalContents.ShareLink]: {
         Icon: ShareLinkIcon,
@@ -95,7 +93,6 @@ const PageAccessoriesModal = (): JSX.Element => {
           return <ShareLink />;
         },
         i18n: t('share_links.share_link_management'),
-        index: 2,
         isLinkEnabled: () => !isGuestUser && !isSharedUser && !isLinkSharingDisabled,
       },
     };
@@ -133,7 +130,7 @@ const PageAccessoriesModal = (): JSX.Element => {
           activeTab={activeTab}
           navTabMapping={navTabMapping}
           breakpointToHideInactiveTabsDown="md"
-          onNavSelected={(v) => {
+          onNavSelected={(v: PageAccessoriesModalContents) => {
             setActiveTab(v);
           }}
           hideBorderBottom

+ 0 - 2
apps/app/src/components/PageComment/CommentEditor.tsx

@@ -36,12 +36,10 @@ const navTabMapping = {
   comment_editor: {
     Icon: () => <i className="icon-settings" />,
     i18n: 'Write',
-    index: 0,
   },
   comment_preview: {
     Icon: () => <i className="icon-settings" />,
     i18n: 'Preview',
-    index: 1,
   },
 };
 

+ 1 - 3
apps/app/src/components/PageEditor.tsx

@@ -25,7 +25,7 @@ import {
   useIsEditable, useIsUploadableFile, useIsUploadableImage, useIsIndentSizeForced,
 } from '~/stores/context';
 import {
-  useCurrentIndentSize, useIsSlackEnabled, useIsTextlintEnabled, usePageTagsForEditors,
+  useCurrentIndentSize, useIsSlackEnabled, usePageTagsForEditors,
   useIsEnabledUnsavedWarning,
   useIsConflict,
   useEditingMarkdown,
@@ -93,7 +93,6 @@ const PageEditor = React.memo((): JSX.Element => {
   const { mutate: mutateWaitingSaveProcessing } = useWaitingSaveProcessing();
   const { data: editorMode, mutate: mutateEditorMode } = useEditorMode();
   const { data: isSlackEnabled } = useIsSlackEnabled();
-  const { data: isTextlintEnabled } = useIsTextlintEnabled();
   const { data: isIndentSizeForced } = useIsIndentSizeForced();
   const { data: currentIndentSize, mutate: mutateCurrentIndentSize } = useCurrentIndentSize();
   const { data: isUploadableFile } = useIsUploadableFile();
@@ -536,7 +535,6 @@ const PageEditor = React.memo((): JSX.Element => {
           value={initialValue}
           isUploadable={isUploadable}
           isUploadableFile={isUploadableFile}
-          isTextlintEnabled={isTextlintEnabled}
           indentSize={currentIndentSize}
           onScroll={editorScrolledHandler}
           onScrollCursorIntoView={editorScrollCursorIntoViewHandler}

+ 0 - 30
apps/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -1,8 +1,6 @@
 import React, { useCallback, memo } from 'react';
 
-import { createValidator } from '@growi/codemirror-textlint';
 import { commands } from 'codemirror';
-import { JSHINT } from 'jshint';
 import * as loadCssSync from 'load-css-file';
 import PropTypes from 'prop-types';
 import { Button } from 'reactstrap';
@@ -36,10 +34,6 @@ import SimpleCheatsheet from './SimpleCheatsheet';
 
 import styles from './CodeMirrorEditor.module.scss';
 
-// Textlint
-window.JSHINT = JSHINT;
-window.kuromojin = { dicPath: '/static/dict' };
-
 require('codemirror/addon/hint/show-hint.css'); // Import from CodeMirrorEditor.module.scss not working
 require('codemirror/addon/display/placeholder');
 require('codemirror/addon/edit/matchbrackets');
@@ -57,7 +51,6 @@ require('codemirror/addon/fold/foldgutter');
 require('codemirror/addon/fold/markdown-fold');
 require('codemirror/addon/fold/brace-fold');
 require('codemirror/addon/display/placeholder');
-require('codemirror/addon/lint/lint');
 require('~/client/util/codemirror/autorefresh.ext');
 require('~/client/util/codemirror/drawio-fold.ext');
 require('~/client/util/codemirror/gfm-growi.mode');
@@ -208,8 +201,6 @@ class CodeMirrorEditor extends AbstractEditor {
   componentWillReceiveProps(nextProps) {
     this.initializeEditorSettings(nextProps.editorSettings);
 
-    this.initializeTextlint(nextProps.isTextlintEnabled, nextProps.editorSettings);
-
     // fold drawio section
     this.foldDrawioSection();
   }
@@ -232,19 +223,6 @@ class CodeMirrorEditor extends AbstractEditor {
     }
   }
 
-  async initializeTextlint(isTextlintEnabled, editorSettings) {
-    if (!isTextlintEnabled || editorSettings == null) {
-      return;
-    }
-
-    const textlintRules = editorSettings.textlintSettings?.textlintRules;
-
-    // If database has empty array, pass null instead to enable all default rules
-    const rulesForValidator = (textlintRules == null || textlintRules.length === 0) ? null : textlintRules;
-    this.textlintValidator = createValidator(rulesForValidator);
-    this.codemirrorLintConfig = { getAnnotations: this.textlintValidator, async: true };
-  }
-
   getCodeMirror() {
     return this.cm.current?.editor;
   }
@@ -1071,9 +1049,6 @@ class CodeMirrorEditor extends AbstractEditor {
 
 
   render() {
-    const { isTextlintEnabled } = this.props;
-
-    const lint = isTextlintEnabled ? this.codemirrorLintConfig : false;
     const additionalClasses = Array.from(this.state.additionalClassSet).join(' ');
     const placeholder = this.state.isGfmMode ? 'Input with Markdown..' : 'Input with Plain Text..';
 
@@ -1081,9 +1056,6 @@ class CodeMirrorEditor extends AbstractEditor {
     if (this.props.lineNumbers != null) {
       gutters.push('CodeMirror-linenumbers', 'CodeMirror-foldgutter');
     }
-    if (isTextlintEnabled) {
-      gutters.push('CodeMirror-lint-markers');
-    }
 
     return (
       <div className={`grw-codemirror-editor ${styles['grw-codemirror-editor']}`}>
@@ -1119,7 +1091,6 @@ class CodeMirrorEditor extends AbstractEditor {
               'Shift-Tab': 'indentLess',
               'Ctrl-Q': (cm) => { cm.foldCode(cm.getCursor()) },
             },
-            lint,
           }}
           onCursor={this.cursorHandlerDebounced}
           onScroll={(editor, data) => {
@@ -1166,7 +1137,6 @@ class CodeMirrorEditor extends AbstractEditor {
 }
 
 CodeMirrorEditor.propTypes = Object.assign({
-  isTextlintEnabled: PropTypes.bool,
   lineNumbers: PropTypes.bool,
   editorSettings: PropTypes.object.isRequired,
   onMarkdownHelpButtonClicked: PropTypes.func,

+ 0 - 69
apps/app/src/components/PageEditor/DownloadDictModal.tsx

@@ -1,69 +0,0 @@
-import React, { useState } from 'react';
-
-import { useTranslation } from 'next-i18next';
-import {
-  Modal, ModalHeader, ModalBody, ModalFooter,
-} from 'reactstrap';
-
-type DownloadDictModalProps = {
-  isModalOpen: boolean
-  onEnableTextlint?: (isSkipAskingAgainChecked: boolean) => void;
-  onCancel?: () => void;
-};
-
-export const DownloadDictModal = (props: DownloadDictModalProps): JSX.Element => {
-  const { t } = useTranslation('');
-  const [isSkipAskingAgainChecked, setIsSkipAskingAgainChecked] = useState(false);
-
-  const onCancel = () => {
-    if (props.onCancel != null) {
-      props.onCancel();
-    }
-  };
-
-  const onConfirmEnableTextlint = () => {
-    if (props.onEnableTextlint != null) {
-      props.onEnableTextlint(isSkipAskingAgainChecked);
-    }
-  };
-
-  return (
-    <Modal isOpen={props.isModalOpen} toggle={onCancel} className="">
-      <ModalHeader tag="h4" toggle={onCancel} className="bg-warning">
-        <i className="icon-fw icon-question" />
-        Warning
-      </ModalHeader>
-      <ModalBody>
-        {t('modal_enable_textlint.confirm_download_dict_and_enable_textlint')}
-      </ModalBody>
-      <ModalFooter>
-        <div className="mr-3 custom-control custom-checkbox custom-checkbox-info">
-          <input
-            type="checkbox"
-            className="custom-control-input"
-            id="dont-ask-again"
-            checked={isSkipAskingAgainChecked}
-            onChange={e => setIsSkipAskingAgainChecked(e.target.checked)}
-          />
-          <label className="custom-control-label align-center" htmlFor="dont-ask-again">
-            {t('modal_enable_textlint.dont_ask_again')}
-          </label>
-        </div>
-        <button
-          type="button"
-          className="btn btn-outline-secondary"
-          onClick={onCancel}
-        >
-          {t('Cancel')}
-        </button>
-        <button
-          type="button"
-          className="btn btn-outline-primary ml-3"
-          onClick={onConfirmEnableTextlint}
-        >
-          {t('modal_enable_textlint.enable_textlint')}
-        </button>
-      </ModalFooter>
-    </Modal>
-  );
-};

+ 0 - 1
apps/app/src/components/PageEditor/Editor.tsx

@@ -32,7 +32,6 @@ export type EditorPropsType = {
   noCdn?: boolean,
   isUploadable?: boolean,
   isUploadableFile?: boolean,
-  isTextlintEnabled?: boolean,
   onChange?: (newValue: string, isClean?: boolean) => void,
   onUpload?: (file) => void,
   editorSettings?: IEditorSettings,

+ 4 - 72
apps/app/src/components/PageEditor/OptionsSelector.tsx

@@ -8,12 +8,10 @@ import {
 } from 'reactstrap';
 
 import { useIsIndentSizeForced } from '~/stores/context';
-import { useEditorSettings, useIsTextlintEnabled, useCurrentIndentSize } from '~/stores/editor';
+import { useEditorSettings, useCurrentIndentSize } from '~/stores/editor';
 
 import { DEFAULT_THEME, KeyMapMode } from '../../interfaces/editor-settings';
 
-import { DownloadDictModal } from './DownloadDictModal';
-
 
 const AVAILABLE_THEMES = [
   'eclipse', 'elegant', 'neo', 'mdn-like', 'material', 'dracula', 'monokai', 'twilight',
@@ -162,19 +160,13 @@ const IndentSizeSelector = memo(({ isIndentSizeForced, selectedIndentSize, onCha
 IndentSizeSelector.displayName = 'IndentSizeSelector';
 
 
-type ConfigurationDropdownProps = {
-  onConfirmEnableTextlint?: () => void,
-}
-
-const ConfigurationDropdown = memo(({ onConfirmEnableTextlint }: ConfigurationDropdownProps): JSX.Element => {
+const ConfigurationDropdown = memo((): JSX.Element => {
   const { t } = useTranslation();
 
   const [isCddMenuOpened, setCddMenuOpened] = useState(false);
 
   const { data: editorSettings, update } = useEditorSettings();
 
-  const { data: isTextlintEnabled, mutate: mutateTextlintEnabled } = useIsTextlintEnabled();
-
   const renderActiveLineMenuItem = useCallback(() => {
     if (editorSettings == null) {
       return <></>;
@@ -223,44 +215,6 @@ const ConfigurationDropdown = memo(({ onConfirmEnableTextlint }: ConfigurationDr
     );
   }, [editorSettings, t, update]);
 
-  const renderIsTextlintEnabledMenuItem = useCallback(() => {
-    if (editorSettings == null) {
-      return <></>;
-    }
-
-    const clickHandler = () => {
-      if (isTextlintEnabled) {
-        mutateTextlintEnabled(false);
-        return;
-      }
-
-      if (editorSettings.textlintSettings?.neverAskBeforeDownloadLargeFiles) {
-        mutateTextlintEnabled(true);
-        return;
-      }
-
-      if (onConfirmEnableTextlint != null) {
-        onConfirmEnableTextlint();
-      }
-    };
-
-    const iconClasses = ['text-info'];
-    if (isTextlintEnabled) {
-      iconClasses.push('ti ti-check');
-    }
-    const iconClassName = iconClasses.join(' ');
-
-    return (
-      <DropdownItem toggle={false} onClick={clickHandler}>
-        <div className="d-flex justify-content-between">
-          <span className="icon-container"></span>
-          <span className="menuitem-label">Textlint</span>
-          <span className="icon-container"><i className={iconClassName}></i></span>
-        </div>
-      </DropdownItem>
-    );
-  }, [editorSettings, isTextlintEnabled, mutateTextlintEnabled, onConfirmEnableTextlint]);
-
   return (
     <div className="my-0 form-group">
       <Dropdown
@@ -277,7 +231,6 @@ const ConfigurationDropdown = memo(({ onConfirmEnableTextlint }: ConfigurationDr
         <DropdownMenu>
           {renderActiveLineMenuItem()}
           {renderMarkdownTableAutoFormattingMenuItem()}
-          {renderIsTextlintEnabledMenuItem()}
           {/* <DropdownItem divider /> */}
         </DropdownMenu>
 
@@ -291,10 +244,7 @@ ConfigurationDropdown.displayName = 'ConfigurationDropdown';
 
 
 export const OptionsSelector = (): JSX.Element => {
-  const [isDownloadDictModalShown, setDownloadDictModalShown] = useState(false);
-
-  const { data: editorSettings, turnOffAskingBeforeDownloadLargeFiles } = useEditorSettings();
-  const { mutate: mutateTextlintEnabled } = useIsTextlintEnabled();
+  const { data: editorSettings } = useEditorSettings();
   const { data: isIndentSizeForced } = useIsIndentSizeForced();
   const { data: currentIndentSize, mutate: mutateCurrentIndentSize } = useCurrentIndentSize();
 
@@ -319,27 +269,9 @@ export const OptionsSelector = (): JSX.Element => {
           />
         </span>
         <span className="ml-2 ml-sm-4">
-          <ConfigurationDropdown
-            onConfirmEnableTextlint={() => setDownloadDictModalShown(true)}
-          />
+          <ConfigurationDropdown />
         </span>
       </div>
-
-      { editorSettings != null && !editorSettings.textlintSettings?.neverAskBeforeDownloadLargeFiles && (
-        <DownloadDictModal
-          isModalOpen={isDownloadDictModalShown}
-          onEnableTextlint={(isSkipAskingAgainChecked) => {
-            mutateTextlintEnabled(true);
-
-            if (isSkipAskingAgainChecked) {
-              turnOffAskingBeforeDownloadLargeFiles();
-            }
-
-            setDownloadDictModalShown(false);
-          }}
-          onCancel={() => setDownloadDictModalShown(false)}
-        />
-      )}
     </>
   );
 

+ 0 - 1
apps/app/src/components/TrashPageList.tsx

@@ -87,7 +87,6 @@ export const TrashPageList = (): JSX.Element => {
         Icon: PageListIcon,
         Content: DescendantsPageListForTrash,
         i18n: t('page_list'),
-        index: 0,
       },
     };
   }, [t]);

+ 8 - 3
apps/app/src/components/UncontrolledCodeMirror.tsx

@@ -2,8 +2,13 @@ import React, {
   useCallback, useRef, MutableRefObject,
 } from 'react';
 
-import { commands, Editor } from 'codemirror';
-import { ICodeMirror, UnControlled as CodeMirror } from 'react-codemirror2';
+import codemirror, { commands, Editor } from 'codemirror';
+import { type ICodeMirror, UnControlled as CodeMirror } from 'react-codemirror2';
+
+declare global {
+  // eslint-disable-next-line vars-on-top, no-var
+  var CodeMirror: ICodeMirror;
+}
 
 // set save handler
 // CommandActions in @types/codemirror does not include 'save' but actualy exists
@@ -14,7 +19,7 @@ import { ICodeMirror, UnControlled as CodeMirror } from 'react-codemirror2';
   }
 };
 
-window.CodeMirror = require('codemirror');
+window.CodeMirror = codemirror;
 require('codemirror/addon/display/placeholder');
 require('~/client/util/codemirror/gfm-growi.mode');
 

+ 0 - 12
apps/app/src/interfaces/editor-settings.ts

@@ -1,14 +1,3 @@
-export interface ILintRule {
-  name: string;
-  options?: unknown;
-  isEnabled?: boolean;
-}
-
-export interface ITextlintSettings {
-  neverAskBeforeDownloadLargeFiles?: boolean;
-  textlintRules: ILintRule[];
-}
-
 export const DEFAULT_THEME = 'elegant';
 
 const KeyMapMode = {
@@ -25,7 +14,6 @@ export interface IEditorSettings {
   keymapMode: undefined | KeyMapMode,
   styleActiveLine: boolean,
   autoFormatMarkdownTable: boolean,
-  textlintSettings: undefined | ITextlintSettings;
 }
 
 export type EditorConfig = {

+ 1 - 2
apps/app/src/interfaces/ui.ts

@@ -12,10 +12,9 @@ export type SidebarContentsType = typeof SidebarContentsType[keyof typeof Sideba
 
 
 export type ICustomTabContent = {
-  Content: () => JSX.Element,
+  Content?: () => JSX.Element,
   i18n?: string,
   Icon?: () => JSX.Element,
-  index?: number,
   isLinkEnabled?: boolean | ((content: ICustomTabContent) => boolean),
 };
 

+ 0 - 2
apps/app/src/pages/installer.page.tsx

@@ -46,13 +46,11 @@ const InstallerPage: NextPage<Props> = (props: Props) => {
         Icon: () => <i className="icon-fw icon-user"></i>,
         Content: InstallerForm,
         i18n: t('installer.tab'),
-        index: 0,
       },
       external_accounts: {
         Icon: () => <i className="icon-fw icon-share-alt"></i>,
         Content: DataTransferForm,
         i18n: tCommons('g2g_data_transfer.tab'),
-        index: 1,
       },
     };
   }, [t, tCommons]);

+ 1 - 11
apps/app/src/server/models/editor-settings.ts

@@ -2,7 +2,7 @@ import {
   Schema, Model, Document,
 } from 'mongoose';
 
-import { IEditorSettings, ITextlintSettings } from '~/interfaces/editor-settings';
+import { IEditorSettings } from '~/interfaces/editor-settings';
 
 import { getOrCreateModel } from '../util/mongoose-utils';
 
@@ -12,22 +12,12 @@ export interface EditorSettingsDocument extends IEditorSettings, Document {
 }
 export type EditorSettingsModel = Model<EditorSettingsDocument>
 
-const textlintSettingsSchema = new Schema<ITextlintSettings>({
-  neverAskBeforeDownloadLargeFiles: { type: Boolean, default: false },
-  textlintRules: {
-    type: [
-      { name: { type: String }, options: { type: Object }, isEnabled: { type: Boolean } },
-    ],
-  },
-});
-
 const editorSettingsSchema = new Schema<EditorSettingsDocument, EditorSettingsModel>({
   userId: { type: Schema.Types.ObjectId },
   theme: { type: String },
   keymapMode: { type: String },
   styleActiveLine: { type: Boolean, default: false },
   autoFormatMarkdownTable: { type: Boolean, default: true },
-  textlintSettings: textlintSettingsSchema,
 });
 
 

+ 0 - 14
apps/app/src/server/routes/apiv3/personal-setting.js

@@ -118,10 +118,6 @@ module.exports = (crowi) => {
       body('keymapMode').optional().isString(),
       body('styleActiveLine').optional().isBoolean(),
       body('autoFormatMarkdownTable').optional().isBoolean(),
-      body('textlintSettings.neverAskBeforeDownloadLargeFiles').optional().isBoolean(),
-      body('textlintSettings.textlintRules.*.name').optional().isString(),
-      body('textlintSettings.textlintRules.*.options').optional(),
-      body('textlintSettings.textlintRules.*.isEnabled').optional().isBoolean(),
     ],
     inAppNotificationSettings: [
       body('defaultSubscribeRules.*.name').isString(),
@@ -539,22 +535,12 @@ module.exports = (crowi) => {
 
     const {
       theme, keymapMode, styleActiveLine, autoFormatMarkdownTable,
-      textlintSettings,
     } = body;
 
     const document = {
       theme, keymapMode, styleActiveLine, autoFormatMarkdownTable,
     };
 
-    if (textlintSettings != null) {
-      if (textlintSettings.neverAskBeforeDownloadLargeFiles != null) {
-        Object.assign(document, { 'textlintSettings.neverAskBeforeDownloadLargeFiles': textlintSettings.neverAskBeforeDownloadLargeFiles });
-      }
-      if (textlintSettings.textlintRules != null) {
-        Object.assign(document, { 'textlintSettings.textlintRules': textlintSettings.textlintRules });
-      }
-    }
-
     // Insert if document does not exist, and return new values
     // See: https://mongoosejs.com/docs/api.html#model_Model.findOneAndUpdate
     const options = { upsert: true, new: true };

+ 3 - 0
apps/app/src/server/service/page.ts

@@ -1468,6 +1468,9 @@ class PageService {
 
           throw err;
         }
+        finally {
+          this.pageEvent.emit('syncDescendantsUpdate', deletedPage, user);
+        }
       })();
     }
     else {

+ 0 - 17
apps/app/src/stores/editor.tsx

@@ -29,7 +29,6 @@ export const useEditingMarkdown = (initialData?: string): SWRResponse<string, Er
 
 type EditorSettingsOperation = {
   update: (updateData: Partial<IEditorSettings>) => Promise<void>,
-  turnOffAskingBeforeDownloadLargeFiles: () => void,
 }
 
 // TODO: Enable localStorageMiddleware
@@ -61,25 +60,9 @@ export const useEditorSettings = (): SWRResponseWithUtils<EditorSettingsOperatio
       // invoke API
       await apiv3Put('/personal-setting/editor-settings', updateData);
     },
-    turnOffAskingBeforeDownloadLargeFiles: async() => {
-      const { data, mutate } = swrResult;
-
-      if (data == null) {
-        return;
-      }
-
-      // invoke API
-      await apiv3Put('/personal-setting/editor-settings', { textlintSettings: { neverAskBeforeDownloadLargeFiles: true } });
-      // revalidate
-      mutate();
-    },
   });
 };
 
-export const useIsTextlintEnabled = (): SWRResponse<boolean, Error> => {
-  return useStaticSWR<boolean, Error>('isTextlintEnabled', undefined, { fallbackData: false });
-};
-
 export const useCurrentIndentSize = (): SWRResponse<number, Error> => {
   const { data: defaultIndentSize } = useDefaultIndentSize();
   return useStaticSWR<number, Error>(

+ 1 - 16
apps/app/test/cypress/integration/60-home/60-home--home.spec.ts

@@ -115,23 +115,8 @@ context('Access User settings', () => {
     });
   });
 
-  it('Access Editor setting', () => {
-    cy.getByTestid('grw-personal-settings').find('.nav-title.nav li:eq(4) a').click();
-    cy.scrollTo('top');
-    cy.getByTestid('grw-editor-settings').should('be.visible');
-    cy.screenshot(`${ssPrefix}-editor-setting-1`);
-    cy.getByTestid('grw-editor-settings-update-button').click();
-    cy.get('.Toastify__toast').should('be.visible');
-    cy.screenshot(`${ssPrefix}-editor-setting-2`);
-
-    cy.get('.Toastify__toast').should('be.visible').within(() => {
-      cy.get('.Toastify__close-button').should('be.visible').click();
-      cy.get('.Toastify__progress-bar').invoke('attr', 'style', 'display: none')
-    });
-  });
-
   it('Access In-app notification setting', () => {
-    cy.getByTestid('grw-personal-settings').find('.nav-title.nav li:eq(5) a').click();
+    cy.getByTestid('grw-personal-settings').find('.nav-title.nav li:eq(4) a').click();
     cy.scrollTo('top');
     cy.screenshot(`${ssPrefix}-in-app-notification-setting-1`);
     cy.getByTestid('grw-in-app-notification-settings-update-button').click();

+ 0 - 2
apps/app/tsconfig.build.client.json

@@ -13,8 +13,6 @@
       "~/*": ["./src/*"],
       "^/*": ["./*"],
 
-      "@growi/codemirror-textlint": ["../../packages/codemirror-textlint/src"],
-
       "debug": ["./src/server/utils/logger/alias-for-debug"]
     }
   }

+ 0 - 2
apps/app/tsconfig.json

@@ -12,8 +12,6 @@
       "~/*": ["./src/*"],
       "^/*": ["./*"],
 
-      "@growi/codemirror-textlint": ["../../packages/codemirror-textlint/src"],
-
       "debug": ["./src/server/utils/logger/alias-for-debug"]
     }
   },

+ 2 - 1
package.json

@@ -26,6 +26,7 @@
       "apps/*"
     ],
     "nohoist": [
+      "**/uvu/*",
       "**/slackbot-proxy/bootstrap"
     ]
   },
@@ -93,7 +94,7 @@
     "ts-node-dev": "^2.0.0",
     "typescript": "~4.9",
     "unplugin-swc": "^1.3.2",
-    "vite": "^4.1.1",
+    "vite": "^4.2.2",
     "vite-plugin-dts": "^2.0.0-beta.0"
   },
   "engines": {

+ 0 - 2
packages/codemirror-textlint/.eslintignore

@@ -1,2 +0,0 @@
-/dist/**
-/types/**

+ 0 - 1
packages/codemirror-textlint/.gitignore

@@ -1 +0,0 @@
-/dist

+ 0 - 51
packages/codemirror-textlint/package.json

@@ -1,51 +0,0 @@
-{
-  "name": "@growi/codemirror-textlint",
-  "version": "6.1.0-RC.0",
-  "license": "MIT",
-  "main": "dist/index.js",
-  "scripts": {
-    "build": "yarn tsc && tsc-alias -p tsconfig.build.json",
-    "clean": "npx -y shx rm -rf dist",
-    "tsc": "tsc -p tsconfig.build.json",
-    "tsc:w": "yarn tsc -w",
-    "lint": "yarn eslint src --ext .ts",
-    "lint:fix": "yarn eslint src --ext .ts --fix"
-  },
-  "dependencies": {},
-  "devDependencies": {
-    "@textlint-rule/textlint-rule-no-unmatched-pair": "^1.0.8",
-    "@textlint/kernel": "^12.0.2",
-    "@types/codemirror": "^5.60.2",
-    "eslint-plugin-regex": "^1.8.0",
-    "textlint-message-to-codemirror": "^1.0.0",
-    "textlint-plugin-markdown": "^4.0.6",
-    "textlint-rule-common-misspellings": "^1.0.1",
-    "textlint-rule-date-weekday-mismatch": "^1.0.6",
-    "textlint-rule-ja-hiragana-keishikimeishi": "^1.1.0",
-    "textlint-rule-ja-no-abusage": "^3.0.0",
-    "textlint-rule-ja-no-inappropriate-words": "^2.0.0",
-    "textlint-rule-ja-no-mixed-period": "^2.1.1",
-    "textlint-rule-ja-no-redundant-expression": "^4.0.0",
-    "textlint-rule-ja-unnatural-alphabet": "^2.0.1",
-    "textlint-rule-max-comma": "^2.0.2",
-    "textlint-rule-max-kanji-continuous-len": "^1.1.1",
-    "textlint-rule-max-ten": "^4.0.2",
-    "textlint-rule-no-double-negative-ja": "^2.0.0",
-    "textlint-rule-no-doubled-conjunction": "^2.0.2",
-    "textlint-rule-no-doubled-joshi": "^4.0.0",
-    "textlint-rule-no-dropping-the-ra": "^3.0.0",
-    "textlint-rule-no-hankaku-kana": "^1.0.2",
-    "textlint-rule-no-kangxi-radicals": "^0.2.0",
-    "textlint-rule-no-mixed-zenkaku-and-hankaku-alphabet": "^1.0.1",
-    "textlint-rule-no-nfd": "^1.0.2",
-    "textlint-rule-no-surrogate-pair": "^1.0.1",
-    "textlint-rule-no-zero-width-spaces": "^1.0.1",
-    "textlint-rule-period-in-list-item": "^0.3.2",
-    "textlint-rule-prefer-tari-tari": "^1.0.3",
-    "textlint-rule-sentence-length": "^3.0.0",
-    "textlint-rule-use-si-units": "^1.0.2"
-  },
-  "peerDependencies": {
-    "codemirror": "^5.62.3"
-  }
-}

+ 0 - 151
packages/codemirror-textlint/src/index.ts

@@ -1,151 +0,0 @@
-import textlintRuleNoUnmatchedPair from '@textlint-rule/textlint-rule-no-unmatched-pair';
-import { TextlintKernel, TextlintKernelRule, TextlintRuleOptions } from '@textlint/kernel';
-import { AsyncLinter, Annotation } from 'codemirror/addon/lint/lint';
-import textlintToCodeMirror from 'textlint-message-to-codemirror';
-import textlintRuleCommonMisspellings from 'textlint-rule-common-misspellings';
-import textlintRuleDateWeekdayMismatch from 'textlint-rule-date-weekday-mismatch';
-// import textlintRuleEnCapitalization from 'textlint-rule-en-capitalization';  // omit because en-pos package is too big
-import textlintRuleJaHiraganaKeishikimeishi from 'textlint-rule-ja-hiragana-keishikimeishi';
-import textlintRuleJaNoAbusage from 'textlint-rule-ja-no-abusage';
-import textlintRuleJaNoInappropriateWords from 'textlint-rule-ja-no-inappropriate-words';
-import textlintRuleJaNoMixedPeriod from 'textlint-rule-ja-no-mixed-period';
-import textlintRuleJaNoRedundantExpression from 'textlint-rule-ja-no-redundant-expression';
-import textlintRuleJaUnnaturalAlphabet from 'textlint-rule-ja-unnatural-alphabet';
-import textlintRuleMaxComma from 'textlint-rule-max-comma';
-import textlintRuleMaxKanjiContinuousLen from 'textlint-rule-max-kanji-continuous-len';
-import textlintRuleMaxTen from 'textlint-rule-max-ten';
-import textlintRuleNoDoubleNegativeJa from 'textlint-rule-no-double-negative-ja';
-import textlintRuleNoDoubledConjunction from 'textlint-rule-no-doubled-conjunction';
-import textlintRuleNoDoubledJoshi from 'textlint-rule-no-doubled-joshi';
-import textlintRuleNoDroppingTheRa from 'textlint-rule-no-dropping-the-ra';
-import textlintRuleNoHankakuKana from 'textlint-rule-no-hankaku-kana';
-import textlintRuleNoKangxiRadicals from 'textlint-rule-no-kangxi-radicals';
-import textlintRuleNoMixedZenkakuAndHankakuAlphabet from 'textlint-rule-no-mixed-zenkaku-and-hankaku-alphabet';
-import textlintRuleNoNfd from 'textlint-rule-no-nfd';
-import textlintRuleNoSurrogatePair from 'textlint-rule-no-surrogate-pair';
-import textlintRuleNoZeroWidthSpaces from 'textlint-rule-no-zero-width-spaces';
-import textlintRulePeriodInListItem from 'textlint-rule-period-in-list-item';
-import textlintRulePreferTariTari from 'textlint-rule-prefer-tari-tari';
-import textlintRuleSentenceLength from 'textlint-rule-sentence-length';
-import textlintRuleUseSiUnits from 'textlint-rule-use-si-units';
-
-import { loggerFactory } from './utils/logger';
-
-type RulesConfigObj = {
-  name: string,
-  options?: unknown,
-  isEnabled?: boolean,
-}
-
-type RuleExtension = {
-  ext: string
-}
-
-const ruleModulesList = {
-  'no-unmatched-pair': textlintRuleNoUnmatchedPair,
-  'common-misspellings': textlintRuleCommonMisspellings,
-  'date-weekday-mismatch': textlintRuleDateWeekdayMismatch,
-  // 'en-capitalization': textlintRuleEnCapitalization, // omit because en-pos package is too big
-  'ja-hiragana-keishikimeishi': textlintRuleJaHiraganaKeishikimeishi,
-  'ja-no-abusage': textlintRuleJaNoAbusage,
-  'ja-no-inappropriate-words': textlintRuleJaNoInappropriateWords,
-  'ja-no-mixed-period': textlintRuleJaNoMixedPeriod,
-  'ja-no-redundant-expression': textlintRuleJaNoRedundantExpression,
-  'ja-unnatural-alphabet': textlintRuleJaUnnaturalAlphabet,
-  'max-comma': textlintRuleMaxComma,
-  'max-kanji-continuous-len': textlintRuleMaxKanjiContinuousLen,
-  'max-ten': textlintRuleMaxTen,
-  'no-double-negative-ja': textlintRuleNoDoubleNegativeJa,
-  'no-doubled-conjunction': textlintRuleNoDoubledConjunction,
-  'no-doubled-joshi': textlintRuleNoDoubledJoshi,
-  'no-dropping-the-ra': textlintRuleNoDroppingTheRa,
-  'no-hankaku-kana': textlintRuleNoHankakuKana,
-  'no-kangxi-radicals': textlintRuleNoKangxiRadicals,
-  'no-mixed-zenkaku-and-hankaku-alphabet': textlintRuleNoMixedZenkakuAndHankakuAlphabet,
-  'no-nfd': textlintRuleNoNfd,
-  'no-surrogate-pair': textlintRuleNoSurrogatePair,
-  'no-zero-width-spaces': textlintRuleNoZeroWidthSpaces,
-  'period-in-list-item': textlintRulePeriodInListItem,
-  'prefer-tari-tari': textlintRulePreferTariTari,
-  'sentence-length': textlintRuleSentenceLength,
-  'use-si-units': textlintRuleUseSiUnits,
-};
-
-const logger = loggerFactory('growi:codemirror:codemirror-textlint');
-const kernel = new TextlintKernel();
-const textlintOption: TextlintRuleOptions<RuleExtension> = {
-  ext: '.md',
-  plugins: [
-    {
-      pluginId: 'markdown',
-      plugin: require('textlint-plugin-markdown'),
-    },
-  ],
-};
-
-const createSetupRules = (rules, ruleOptions): TextlintKernelRule[] => (
-  Object.keys(rules).map(ruleName => (
-    {
-      ruleId: ruleName,
-      rule: rules[ruleName],
-      options: ruleOptions[ruleName],
-    }
-  ))
-);
-
-
-export const createValidator = (rulesConfigArray: RulesConfigObj[] | null): AsyncLinter<RulesConfigObj[] | null> => {
-  if (rulesConfigArray != null) {
-    const filteredConfigArray = rulesConfigArray
-      .filter((rule) => {
-        if (ruleModulesList[rule.name] == null) {
-          logger.error(`Textlint rule ${rule.name} is not installed`);
-        }
-        return (ruleModulesList[rule.name] != null && rule.isEnabled !== false);
-      });
-
-    const rules = filteredConfigArray
-      .reduce((rules, rule) => {
-        rules[rule.name] = ruleModulesList[rule.name];
-        return rules;
-      }, {});
-
-    const rulesOption = filteredConfigArray
-      .reduce((rules, rule) => {
-        rules[rule.name] = rule.options || {};
-        return rules;
-      }, {});
-
-    Object.assign(
-      textlintOption,
-      { rules: createSetupRules(rules, rulesOption) },
-    );
-  }
-
-  const defaultSetupRules: TextlintKernelRule[] = Object.entries(ruleModulesList)
-    .map(ruleName => ({
-      ruleId: ruleName[0],
-      rule: ruleName[1],
-    }));
-
-  if (rulesConfigArray == null) {
-    Object.assign(
-      textlintOption,
-      { rules: defaultSetupRules },
-    );
-  }
-
-  return (text, callback) => {
-    if (!text) {
-      callback([]);
-      return;
-    }
-    kernel
-      .lintText(text, textlintOption)
-      .then((result) => {
-        const lintMessages = result.messages;
-        const lintErrors: Annotation[] = lintMessages.map(textlintToCodeMirror);
-        callback(lintErrors);
-      });
-  };
-};

+ 0 - 9
packages/codemirror-textlint/src/utils/logger/index.ts

@@ -1,9 +0,0 @@
-import Logger from 'bunyan';
-import { createLogger } from 'universal-bunyan';
-
-export const loggerFactory = function(name: string): Logger {
-  return createLogger({
-    name,
-    config: { default: 'info' },
-  });
-};

+ 0 - 9
packages/codemirror-textlint/tsconfig.base.json

@@ -1,9 +0,0 @@
-{
-  "$schema": "http://json.schemastore.org/tsconfig",
-  "extends": "../../tsconfig.base.json",
-  "compilerOptions": {
-  },
-  "include": [
-    "src"
-  ]
-}

+ 0 - 17
packages/codemirror-textlint/tsconfig.build.json

@@ -1,17 +0,0 @@
-{
-  "$schema": "http://json.schemastore.org/tsconfig",
-  "extends": "./tsconfig.base.json",
-  "compilerOptions": {
-    "rootDir": "./src",
-    "outDir": "dist",
-    "declaration": true,
-    "noResolve": false,
-    "preserveConstEnums": true,
-    "sourceMap": false,
-    "noEmit": false,
-
-    "baseUrl": ".",
-    "paths": {
-    }
-  }
-}

+ 0 - 7
packages/codemirror-textlint/tsconfig.json

@@ -1,7 +0,0 @@
-{
-  "$schema": "http://json.schemastore.org/tsconfig",
-  "extends": "./tsconfig.base.json",
-  "compilerOptions": {
-    "baseUrl": "."
-  }
-}

+ 4 - 0
packages/remark-lsx/package.json

@@ -21,10 +21,14 @@
     "lint:typecheck": "tsc",
     "lint": "run-p lint:*"
   },
+  "// comments for dependencies": {
+    "escape-string-regexp": "5.0.0 or above exports only ESM"
+  },
   "dependencies": {
     "@growi/core": "^6.1.0-RC.0",
     "@growi/remark-growi-directive": "^6.1.0-RC.0",
     "@growi/ui": "^6.1.0-RC.0",
+    "escape-string-regexp": "^4.0.0",
     "swr": "^2.0.3"
   },
   "devDependencies": {

+ 2 - 4
packages/remark-lsx/src/server/routes/lsx.ts

@@ -176,9 +176,10 @@ class Lsx {
 
 }
 
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
 export const routesFactory = (crowi): any => {
   const Page = crowi.model('Page');
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
   const actions: any = {};
 
   /**
@@ -194,9 +195,6 @@ export const routesFactory = (crowi): any => {
     const builder = new Page.PageQueryBuilder(baseQuery);
     builder.addConditionToListOnlyDescendants(pagePath);
 
-    builder
-      .addConditionToExcludeTrashed();
-
     return Page.addConditionToFilteringByViewerForList(builder, user);
   }
 

+ 1 - 1
packages/remark-lsx/src/services/renderer/lsx.ts

@@ -18,7 +18,7 @@ type DirectiveAttributes = Record<string, string>
 
 export const remarkPlugin: Plugin = function() {
   return (tree) => {
-    visit(tree, (node, index) => {
+    visit(tree, (node) => {
       if (node.type === remarkGrowiDirectivePluginType.Text || node.type === remarkGrowiDirectivePluginType.Leaf) {
         if (typeof node.name !== 'string') {
           return;

+ 1 - 0
packages/remark-lsx/vite.server.config.ts

@@ -23,6 +23,7 @@ export default defineConfig({
       },
       external: [
         'axios',
+        'escape-string-regexp',
         'http-errors',
         'is-absolute-url',
         'react',

Разница между файлами не показана из-за своего большого размера
+ 151 - 599
yarn.lock


Некоторые файлы не были показаны из-за большого количества измененных файлов