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

Merge pull request #4383 from weseek/master

Release slackbot-proxy v4.4.6-RC.0
Yuki Takei 4 лет назад
Родитель
Сommit
a2e47dc21b
100 измененных файлов с 3037 добавлено и 2769 удалено
  1. 2 0
      .devcontainer/Dockerfile
  2. 1 0
      .devcontainer/devcontainer.json
  3. 4 1
      .devcontainer/docker-compose.yml
  4. 1 9
      .eslintignore
  5. 12 15
      .eslintrc.js
  6. 17 0
      .github/dependabot.yml
  7. 3 0
      .github/git-pr-release-template.erb
  8. 51 0
      .github/release-drafter.yml
  9. 30 80
      .github/workflows/ci-slackbot-proxy.yml
  10. 67 139
      .github/workflows/ci.yml
  11. 62 0
      .github/workflows/draft-release.yml
  12. 46 0
      .github/workflows/pr-to-master.yml
  13. 6 8
      .github/workflows/release-rc.yml
  14. 8 8
      .github/workflows/release-slackbot-proxy.yml
  15. 108 40
      .github/workflows/release.yml
  16. 0 30
      .gitignore
  17. 4 0
      .markdownlint.yml
  18. 0 4
      .stylelintrc.json
  19. 27 6
      .vscode/launch.json
  20. 0 19
      .vscode/tasks.json
  21. 1731 0
      CHANGELOG.md
  22. 0 1951
      CHANGES.md
  23. 5 7
      README.md
  24. 5 7
      README_JP.md
  25. 22 0
      SECURITY.md
  26. 0 43
      app.json
  27. 0 39
      babel.config.js
  28. 0 43
      bin/generate-plugin-definitions-source.js
  29. 4 0
      bin/github-actions/bump-versions/README.md
  30. 18 0
      bin/github-actions/bump-versions/cli.js
  31. 71 0
      bin/github-actions/bump-versions/flow/bump-versions.js
  32. 16 0
      bin/github-actions/bump-versions/index.js
  33. 54 0
      bin/github-actions/bump-versions/step/printHelp.js
  34. 1 0
      bin/github-actions/list-branches.js
  35. 0 6
      bin/github-actions/update-readme.sh
  36. 12 0
      bump-versions.config.js
  37. 0 26
      config/env.dev.js
  38. 0 4
      config/env.prod.js
  39. 0 13
      config/index.js
  40. 0 14
      docker/docker-entrypoint.sh
  41. 2 2
      lerna.json
  42. 42 62
      package.json
  43. 26 0
      packages/app/.env.development
  44. 5 0
      packages/app/.env.production
  45. 6 0
      packages/app/.eslintignore
  46. 35 0
      packages/app/.eslintrc.js
  47. 22 0
      packages/app/.gitignore
  48. 0 0
      packages/app/.prettierignore
  49. 19 0
      packages/app/.stylelintrc.json
  50. 170 0
      packages/app/bin/cdn/cdn-resources-downloader.ts
  51. 6 8
      packages/app/bin/download-cdn-resources.ts
  52. 56 0
      packages/app/bin/generate-plugin-definitions-source.ts
  53. 6 0
      packages/app/bin/github-actions/update-readme.sh
  54. 2 0
      packages/app/bin/shrink-emojione-strategy.js
  55. 0 0
      packages/app/bin/templates/plugin-definitions.js.swig
  56. 9 0
      packages/app/config/cdn.js
  57. 4 0
      packages/app/config/ci/.env.local.for-ci
  58. 0 0
      packages/app/config/logger/config.dev.js
  59. 0 0
      packages/app/config/logger/config.prod.js
  60. 5 7
      packages/app/config/migrate.js
  61. 0 0
      packages/app/config/swagger-definition.js
  62. 58 54
      packages/app/config/webpack.common.js
  63. 4 4
      packages/app/config/webpack.dev.dll.js
  64. 7 7
      packages/app/config/webpack.dev.js
  65. 10 10
      packages/app/config/webpack.prod.js
  66. 36 29
      packages/app/docker/Dockerfile
  67. 5 5
      packages/app/docker/README.md
  68. 14 0
      packages/app/docker/docker-entrypoint.sh
  69. 0 0
      packages/app/docker/nocdn/env.prod.js
  70. 24 17
      packages/app/jest.config.js
  71. 76 52
      packages/app/package.json
  72. 0 0
      packages/app/public/favicon.ico
  73. 0 0
      packages/app/public/images/customize-settings/default-dark.svg
  74. 0 0
      packages/app/public/images/customize-settings/default-light.svg
  75. 0 0
      packages/app/public/images/customize-settings/fluid-dark.svg
  76. 0 0
      packages/app/public/images/customize-settings/fluid-light.svg
  77. 0 0
      packages/app/public/images/file-not-found.png
  78. 0 0
      packages/app/public/images/icons/editor/bold.svg
  79. 0 0
      packages/app/public/images/icons/editor/check.svg
  80. 0 0
      packages/app/public/images/icons/editor/code.svg
  81. 0 0
      packages/app/public/images/icons/editor/header.svg
  82. 0 0
      packages/app/public/images/icons/editor/italic.svg
  83. 0 0
      packages/app/public/images/icons/editor/link.svg
  84. 0 0
      packages/app/public/images/icons/editor/list-ol.svg
  85. 0 0
      packages/app/public/images/icons/editor/list-ul.svg
  86. 0 0
      packages/app/public/images/icons/editor/picture.svg
  87. 0 0
      packages/app/public/images/icons/editor/quote.svg
  88. 0 0
      packages/app/public/images/icons/editor/strikethrough.svg
  89. 0 0
      packages/app/public/images/icons/editor/table.svg
  90. 0 0
      packages/app/public/images/icons/emacs.png
  91. 0 0
      packages/app/public/images/icons/favicon/android-icon-144x144.png
  92. 0 0
      packages/app/public/images/icons/favicon/android-icon-192x192.png
  93. 0 0
      packages/app/public/images/icons/favicon/android-icon-36x36.png
  94. 0 0
      packages/app/public/images/icons/favicon/android-icon-48x48.png
  95. 0 0
      packages/app/public/images/icons/favicon/android-icon-72x72.png
  96. 0 0
      packages/app/public/images/icons/favicon/android-icon-96x96.png
  97. 0 0
      packages/app/public/images/icons/favicon/apple-icon-114x114.png
  98. 0 0
      packages/app/public/images/icons/favicon/apple-icon-120x120.png
  99. 0 0
      packages/app/public/images/icons/favicon/apple-icon-144x144.png
  100. 0 0
      packages/app/public/images/icons/favicon/apple-icon-152x152.png

+ 2 - 0
.devcontainer/Dockerfile

@@ -14,6 +14,8 @@ ARG USER_UID=1000
 ARG USER_GID=$USER_UID
 ARG USER_GID=$USER_UID
 
 
 RUN mkdir -p /workspace/growi/node_modules
 RUN mkdir -p /workspace/growi/node_modules
+RUN mkdir -p /workspace/growi/packages/app/node_modules
+RUN mkdir -p /workspace/growi/packages/slackbot-proxy/node_modules
 
 
 # [Optional] Update UID/GID if needed
 # [Optional] Update UID/GID if needed
 RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
 RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \

+ 1 - 0
.devcontainer/devcontainer.json

@@ -16,6 +16,7 @@
 	"extensions": [
 	"extensions": [
 		"dbaeumer.vscode-eslint",
 		"dbaeumer.vscode-eslint",
 		"eamodio.gitlens",
 		"eamodio.gitlens",
+    "firsttris.vscode-jest-runner",
 		"msjsdiag.debugger-for-chrome",
 		"msjsdiag.debugger-for-chrome",
 		"firefox-devtools.vscode-firefox-debug",
 		"firefox-devtools.vscode-firefox-debug",
 		"editorconfig.editorconfig",
 		"editorconfig.editorconfig",

+ 4 - 1
.devcontainer/docker-compose.yml

@@ -24,8 +24,9 @@ services:
     volumes:
     volumes:
       - ..:/workspace/growi:delegated
       - ..:/workspace/growi:delegated
       - node_modules:/workspace/growi/node_modules
       - node_modules:/workspace/growi/node_modules
+      - node_modules_app:/workspace/growi/packages/app/node_modules
+      - node_modules_slackbot-proxy:/workspace/growi/packages/slackbot-proxy/node_modules
       - ../../growi-docker-compose:/workspace/growi-docker-compose:delegated
       - ../../growi-docker-compose:/workspace/growi-docker-compose:delegated
-      - ../../node_modules:/workspace/node_modules:delegated
 
 
     tty: true
     tty: true
 
 
@@ -81,3 +82,5 @@ services:
       - /files/sqlite
       - /files/sqlite
 volumes:
 volumes:
   node_modules:
   node_modules:
+  node_modules_app:
+  node_modules_slackbot-proxy:

+ 1 - 9
.eslintignore

@@ -1,9 +1 @@
-/.github/**
-/.vscode/**
-/node_modules/**
-/packages/**
-/public/**
-/src/client/js/legacy/thirdparty-js/**
-/src/client/js/util/reveal/plugins/markdown.js
-/src/linter-checker/**
-/tmp/**
+node_modules/**

+ 12 - 15
.eslintrc.js

@@ -1,37 +1,34 @@
 module.exports = {
 module.exports = {
+  root: true, // https://eslint.org/docs/user-guide/configuring/configuration-files#cascading-and-hierarchy
   extends: [
   extends: [
     'weseek',
     'weseek',
-    'weseek/react',
-    "plugin:jest/recommended",
+    'weseek/typescript',
+    'plugin:jest/recommended',
   ],
   ],
   env: {
   env: {
-    jquery: true,
-    "jest/globals": true,
+    'jest/globals': true,
   },
   },
   globals: {
   globals: {
-    $: true,
-    jquery: true,
-    emojione: true,
-    hljs: true,
-    ScrollPosStyler: true,
-    window: true,
   },
   },
   plugins: [
   plugins: [
-    "jest",
+    'jest',
   ],
   ],
   rules: {
   rules: {
-    'indent': [
+    'import/prefer-default-export': 'off',
+    '@typescript-eslint/no-explicit-any': 'off',
+    indent: [
       'error',
       'error',
       2,
       2,
       {
       {
         SwitchCase: 1,
         SwitchCase: 1,
-        ignoredNodes: ['JSXElement *', 'JSXElement', 'JSXAttribute', 'JSXSpreadAttribute'],
         ArrayExpression: 'first',
         ArrayExpression: 'first',
         FunctionDeclaration: { body: 1, parameters: 2 },
         FunctionDeclaration: { body: 1, parameters: 2 },
         FunctionExpression: { body: 1, parameters: 2 },
         FunctionExpression: { body: 1, parameters: 2 },
       },
       },
     ],
     ],
-    // eslint-plugin-import rules
-    'import/no-unresolved': [2, { ignore: ['^@'] }], // ignore @alias/..., @commons/..., ...
+    'jest/no-standalone-expect': [
+      'error',
+      { additionalTestBlockFunctions: ['each.test'] },
+    ],
   },
   },
 };
 };

+ 17 - 0
.github/dependabot.yml

@@ -0,0 +1,17 @@
+version: 2
+updates:
+  - package-ecosystem: github-actions
+    directory: '/'
+    schedule:
+      interval: daily
+    commit-message:
+      prefix: ci
+      include: scope
+
+  - package-ecosystem: npm
+    directory: '/'
+    schedule:
+      interval: daily
+    commit-message:
+      prefix: ci
+      include: scope

+ 3 - 0
.github/git-pr-release-template.erb

@@ -0,0 +1,3 @@
+<%= ENV['GIT_PR_RELEASE_TITLE'] %>
+
+<%= ENV['GIT_PR_RELEASE_BODY'] %>

+ 51 - 0
.github/release-drafter.yml

@@ -0,0 +1,51 @@
+categories:
+  - title: 'BREAKING CHANGES'
+    labels:
+      - 'breaking'
+  - title: '💎 Features'
+    labels:
+      - 'feature'
+  - title: '🚀 Improvement'
+    labels:
+      - 'improvement'
+  - title: '🐛 Bug Fixes'
+    labels:
+      - 'bug'
+  - title: '🧰 Maintenance'
+    labels:
+      - 'support'
+      - 'dependencies'
+category-template: '### $TITLE'
+change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
+autolabeler:
+  - label: 'feature'
+    branch:
+      - '/^feat\/.+/'
+  - label: 'improvement'
+    branch:
+      - '/^imprv\/.+/'
+  - label: 'bug'
+    branch:
+      - '/^fix\/.+/'
+    title:
+      - '/^fix/i'
+  - label: 'support'
+    branch:
+      - '/^support\/.+/'
+    title:
+      - '/^support/i'
+      - '/^chore/i'
+      - '/^ci/i'
+      - '/^docs/i'
+      - '/^test/i'
+include-labels:
+  - breaking
+  - feature
+  - improvement
+  - bug
+  - support
+  - dependencies
+exclude-labels:
+  - 'exclude from changelog'
+template: |
+  $CHANGES

+ 30 - 80
.github/workflows/ci-slackbot-proxy.yml

@@ -5,13 +5,8 @@ on:
     branches-ignore:
     branches-ignore:
       - release/**
       - release/**
       - rc/**
       - rc/**
-      - tmp/**
-    paths:
-      - .github/workflows/ci-slackbot-proxy.yml
-      - packages/slack/**
-      - packages/slackbot-proxy/**
-      - package.json
-      - yarn.lock
+      - chore/**
+      - support/prepare-v**
 
 
 jobs:
 jobs:
 
 
@@ -24,30 +19,14 @@ jobs:
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
-    - name: Use Node.js ${{ matrix.node-version }}
-      uses: actions/setup-node@v1
+
+    - uses: actions/setup-node@v2
       with:
       with:
         node-version: ${{ matrix.node-version }}
         node-version: ${{ matrix.node-version }}
-    - name: Cache/Restore node_modules
-      id: cache-dependencies
-      uses: actions/cache@v2
-      with:
-        path: '**/node_modules'
-        key: ${{ runner.OS }}-node_modules-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-    - name: Get yarn cache dir
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
-      id: cache-yarn
-      run: echo "::set-output name=dir::$(yarn cache dir)"
-    - name: Cache/Restore yarn cache
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
-      uses: actions/cache@v2
-      with:
-        path: ${{ steps.cache-yarn.outputs.dir }}
-        key: ${{ runner.os }}-yarn-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-yarn-${{ matrix.node-version }}-
-    - name: Install dependencies
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
+    - name: lerna bootstrap
       run: |
       run: |
         npx lerna bootstrap
         npx lerna bootstrap
     - name: Print dependencies
     - name: Print dependencies
@@ -55,9 +34,13 @@ jobs:
         echo -n "node " && node -v
         echo -n "node " && node -v
         echo -n "npm " && npm -v
         echo -n "npm " && npm -v
         yarn list --depth=0
         yarn list --depth=0
+
+    - name: yarn lint
+      run: |
+        yarn lerna run lint --scope @growi/slack --scope @growi/slackbot-proxy
     - name: yarn test
     - name: yarn test
       run: |
       run: |
-        yarn lerna run test
+        yarn lerna run test --scope @growi/slack --scope @growi/slackbot-proxy
 
 
     - name: Slack Notification
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
       uses: weseek/ghaction-slack-notification@master
@@ -89,30 +72,14 @@ jobs:
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
-    - name: Use Node.js ${{ matrix.node-version }}
-      uses: actions/setup-node@v1
+
+    - uses: actions/setup-node@v2
       with:
       with:
         node-version: ${{ matrix.node-version }}
         node-version: ${{ matrix.node-version }}
-    - name: Cache/Restore node_modules
-      id: cache-dependencies
-      uses: actions/cache@v2
-      with:
-        path: '**/node_modules'
-        key: ${{ runner.OS }}-node_modules_dev-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-    - name: Get yarn cache dir
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
-      id: cache-yarn
-      run: echo "::set-output name=dir::$(yarn cache dir)"
-    - name: Cache/Restore yarn cache
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
-      uses: actions/cache@v2
-      with:
-        path: ${{ steps.cache-yarn.outputs.dir }}
-        key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-yarn-
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
     - name: lerna bootstrap
     - name: lerna bootstrap
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
       run: |
       run: |
         npx lerna bootstrap
         npx lerna bootstrap
     - name: Print dependencies
     - name: Print dependencies
@@ -120,10 +87,11 @@ jobs:
         echo -n "node " && node -v
         echo -n "node " && node -v
         echo -n "npm " && npm -v
         echo -n "npm " && npm -v
         yarn list --depth=0
         yarn list --depth=0
+
     - name: yarn dev:ci
     - name: yarn dev:ci
       working-directory: ./packages/slackbot-proxy
       working-directory: ./packages/slackbot-proxy
       run: |
       run: |
-        cp config/ci/.env.local.for-ci .env.local
+        cp config/ci/.env.local.for-ci .env.development.local
         yarn dev:ci
         yarn dev:ci
       env:
       env:
         TYPEORM_CONNECTION: mysql
         TYPEORM_CONNECTION: mysql
@@ -132,6 +100,7 @@ jobs:
         TYPEORM_DATABASE: growi-slackbot-proxy
         TYPEORM_DATABASE: growi-slackbot-proxy
         TYPEORM_USERNAME: root
         TYPEORM_USERNAME: root
         TYPEORM_PASSWORD:
         TYPEORM_PASSWORD:
+
     - name: Slack Notification
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
       uses: weseek/ghaction-slack-notification@master
       if: failure()
       if: failure()
@@ -162,36 +131,17 @@ jobs:
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
-    - name: Use Node.js ${{ matrix.node-version }}
-      uses: actions/setup-node@v1
+
+    - uses: actions/setup-node@v2
       with:
       with:
         node-version: ${{ matrix.node-version }}
         node-version: ${{ matrix.node-version }}
-    - name: Get Date
-      id: date
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
+    - name: Remove unnecessary packages
+      working-directory: ./packages
       run: |
       run: |
-        echo ::set-output name=YmdH::$(date '+%Y%m%d%H')
-        echo ::set-output name=Ymd::$(date '+%Y%m%d')
-        echo ::set-output name=Ym::$(date '+%Y%m')
-        echo ::set-output name=Y::$(date '+%Y')
-    - name: Cache/Restore node_modules
-      uses: actions/cache@v2
-      with:
-        path: '**/node_modules'
-        key: ${{ runner.OS }}-node_modules_prod-${{ matrix.node-version }}-${{ steps.date.outputs.YmdH }}
-        restore-keys: |
-          ${{ runner.os }}-node_modules_prod-${{ matrix.node-version }}-${{ steps.date.outputs.Ymd }}
-          ${{ runner.os }}-node_modules_prod-${{ matrix.node-version }}-${{ steps.date.outputs.Ym }}
-          ${{ runner.os }}-node_modules_prod-${{ matrix.node-version }}-${{ steps.date.outputs.Y }}
-    - name: Get yarn cache dir
-      id: cache-yarn
-      run: echo "::set-output name=dir::$(yarn cache dir)"
-    - name: Cache/Restore yarn cache
-      uses: actions/cache@v2
-      with:
-        path: ${{ steps.cache-yarn.outputs.dir }}
-        key: ${{ runner.os }}-yarn-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-yarn-
+        ls | egrep -v '^(slack|slackbot-proxy)$' | xargs rm -r
     - name: lerna bootstrap
     - name: lerna bootstrap
       run: |
       run: |
         npx lerna bootstrap
         npx lerna bootstrap
@@ -214,7 +164,7 @@ jobs:
     - name: yarn start:prod:ci
     - name: yarn start:prod:ci
       working-directory: ./packages/slackbot-proxy
       working-directory: ./packages/slackbot-proxy
       run: |
       run: |
-        cp config/ci/.env.local.for-ci .env.local
+        cp config/ci/.env.local.for-ci .env.production.local
         yarn start:prod:ci
         yarn start:prod:ci
       env:
       env:
         TYPEORM_CONNECTION: mysql
         TYPEORM_CONNECTION: mysql

+ 67 - 139
.github/workflows/ci.yml

@@ -5,18 +5,8 @@ on:
     branches-ignore:
     branches-ignore:
       - release/**
       - release/**
       - rc/**
       - rc/**
-      - tmp/**
-    paths:
-      - .github/workflows/ci.yml
-      - packages/app/**
-      - .eslint*
-      - .prettier*
-      - .stylelint*
-      - config/**
-      - resource/**
-      - src/**
-      - package.json
-      - yarn.lock
+      - chore/**
+      - support/prepare-v**
 
 
 jobs:
 jobs:
 
 
@@ -29,30 +19,14 @@ jobs:
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
-    - name: Use Node.js ${{ matrix.node-version }}
-      uses: actions/setup-node@v1
+
+    - uses: actions/setup-node@v2
       with:
       with:
         node-version: ${{ matrix.node-version }}
         node-version: ${{ matrix.node-version }}
-    - name: Cache/Restore node_modules
-      id: cache-dependencies
-      uses: actions/cache@v2
-      with:
-        path: '**/node_modules'
-        key: ${{ runner.OS }}-node_modules-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-    - name: Get yarn cache dir
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
-      id: cache-yarn
-      run: echo "::set-output name=dir::$(yarn cache dir)"
-    - name: Cache/Restore yarn cache
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
-      uses: actions/cache@v2
-      with:
-        path: ${{ steps.cache-yarn.outputs.dir }}
-        key: ${{ runner.os }}-yarn-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-yarn-${{ matrix.node-version }}-
-    - name: Install dependencies
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
+    - name: lerna bootstrap
       run: |
       run: |
         npx lerna bootstrap
         npx lerna bootstrap
     - name: Print dependencies
     - name: Print dependencies
@@ -60,9 +34,13 @@ jobs:
         echo -n "node " && node -v
         echo -n "node " && node -v
         echo -n "npm " && npm -v
         echo -n "npm " && npm -v
         yarn list --depth=0
         yarn list --depth=0
-    - name: yarn lint
+
+    - name: lerna run lint for plugins
       run: |
       run: |
-        yarn lint
+        yarn lerna run lint --scope @growi/plugin-*
+    - name: lerna run lint for app
+      run: |
+        yarn lerna run lint --scope @growi/app --scope @growi/core --scope @growi/ui
 
 
     - name: Slack Notification
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
       uses: weseek/ghaction-slack-notification@master
@@ -94,30 +72,14 @@ jobs:
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
-    - name: Use Node.js ${{ matrix.node-version }}
-      uses: actions/setup-node@v1
+
+    - uses: actions/setup-node@v2
       with:
       with:
         node-version: ${{ matrix.node-version }}
         node-version: ${{ matrix.node-version }}
-    - name: Cache/Restore node_modules
-      id: cache-dependencies
-      uses: actions/cache@v2
-      with:
-        path: '**/node_modules'
-        key: ${{ runner.OS }}-node_modules-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-    - name: Get yarn cache dir
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
-      id: cache-yarn
-      run: echo "::set-output name=dir::$(yarn cache dir)"
-    - name: Cache/Restore yarn cache
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
-      uses: actions/cache@v2
-      with:
-        path: ${{ steps.cache-yarn.outputs.dir }}
-        key: ${{ runner.os }}-yarn-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-yarn-${{ matrix.node-version }}-
-    - name: Install dependencies
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
+    - name: lerna bootstrap
       run: |
       run: |
         npx lerna bootstrap
         npx lerna bootstrap
     - name: Print dependencies
     - name: Print dependencies
@@ -125,17 +87,26 @@ jobs:
         echo -n "node " && node -v
         echo -n "node " && node -v
         echo -n "npm " && npm -v
         echo -n "npm " && npm -v
         yarn list --depth=0
         yarn list --depth=0
+
     - name: yarn test
     - name: yarn test
+      working-directory: ./packages/app
       run: |
       run: |
         yarn test
         yarn test
       env:
       env:
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi_test
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi_test
     - name: yarn test with MongoDB 3.6
     - name: yarn test with MongoDB 3.6
+      working-directory: ./packages/app
       run: |
       run: |
         yarn test
         yarn test
       env:
       env:
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb36.ports['27017'] }}/growi_test
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb36.ports['27017'] }}/growi_test
 
 
+    - name: Upload coverage report as artifact
+      uses: actions/upload-artifact@v2
+      with:
+        name: Coverage Report
+        path: packages/app/coverage
+
     - name: Slack Notification
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
       uses: weseek/ghaction-slack-notification@master
       if: failure()
       if: failure()
@@ -147,55 +118,29 @@ jobs:
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
 
 
-  build-dev:
+  launch-dev:
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
 
 
     strategy:
     strategy:
       matrix:
       matrix:
         node-version: [14.x]
         node-version: [14.x]
 
 
+    services:
+      mongodb:
+        image: mongo:4.4
+        ports:
+        - 27017/tcp
+
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
-    - name: Use Node.js ${{ matrix.node-version }}
-      uses: actions/setup-node@v1
+
+    - uses: actions/setup-node@v2
       with:
       with:
         node-version: ${{ matrix.node-version }}
         node-version: ${{ matrix.node-version }}
-    - name: Cache/Restore node_modules
-      id: cache-dependencies
-      uses: actions/cache@v2
-      with:
-        path: '**/node_modules'
-        key: ${{ runner.OS }}-node_modules_dev-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}
-    - name: Get Date
-      id: date
-      run: |
-        echo ::set-output name=YmdH::$(date '+%Y%m%d%H')
-        echo ::set-output name=Ymd::$(date '+%Y%m%d')
-        echo ::set-output name=Ym::$(date '+%Y%m')
-        echo ::set-output name=Y::$(date '+%Y')
-    - name: Cache/Restore node_modules/.cache/hard-source
-      uses: actions/cache@v2
-      with:
-        path: node_modules/.cache
-        key: ${{ runner.OS }}-hard_source_webpack-${{ matrix.node-version }}-${{ steps.date.outputs.YmdH }}
-        restore-keys: |
-          ${{ runner.os }}-hard_source_webpack-${{ matrix.node-version }}-${{ steps.date.outputs.Ymd }}
-          ${{ runner.os }}-hard_source_webpack-${{ matrix.node-version }}-${{ steps.date.outputs.Ym }}
-          ${{ runner.os }}-hard_source_webpack-${{ matrix.node-version }}-${{ steps.date.outputs.Y }}
-    - name: Get yarn cache dir
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
-      id: cache-yarn
-      run: echo "::set-output name=dir::$(yarn cache dir)"
-    - name: Cache/Restore yarn cache
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
-      uses: actions/cache@v2
-      with:
-        path: ${{ steps.cache-yarn.outputs.dir }}
-        key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-yarn-
-    - name: Install dependencies
-      if: steps.cache-dependencies.outputs.cache-hit != 'true'
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
+    - name: lerna bootstrap
       run: |
       run: |
         npx lerna bootstrap
         npx lerna bootstrap
     - name: Print dependencies
     - name: Print dependencies
@@ -203,9 +148,14 @@ jobs:
         echo -n "node " && node -v
         echo -n "node " && node -v
         echo -n "npm " && npm -v
         echo -n "npm " && npm -v
         yarn list --depth=0
         yarn list --depth=0
-    - name: yarn build:dev
+
+    - name: yarn dev:ci
+      working-directory: ./packages/app
       run: |
       run: |
-        yarn build:dev
+        cp config/ci/.env.local.for-ci .env.development.local
+        yarn dev:ci
+      env:
+        MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi_dev
 
 
     - name: Slack Notification
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
       uses: weseek/ghaction-slack-notification@master
@@ -218,7 +168,7 @@ jobs:
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
 
 
-  build-prod:
+  launch-prod:
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
 
 
     strategy:
     strategy:
@@ -237,37 +187,17 @@ jobs:
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
-    - name: Use Node.js ${{ matrix.node-version }}
-      uses: actions/setup-node@v1
+
+    - uses: actions/setup-node@v2
       with:
       with:
         node-version: ${{ matrix.node-version }}
         node-version: ${{ matrix.node-version }}
-    - name: Get Date
-      id: date
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
+    - name: Remove unnecessary packages
       run: |
       run: |
-        echo ::set-output name=YmdH::$(date '+%Y%m%d%H')
-        echo ::set-output name=Ymd::$(date '+%Y%m%d')
-        echo ::set-output name=Ym::$(date '+%Y%m')
-        echo ::set-output name=Y::$(date '+%Y')
-    - name: Cache/Restore node_modules
-      uses: actions/cache@v2
-      with:
-        path: '**/node_modules'
-        key: ${{ runner.OS }}-node_modules_prod-${{ matrix.node-version }}-${{ steps.date.outputs.YmdH }}
-        restore-keys: |
-          ${{ runner.os }}-node_modules_prod-${{ matrix.node-version }}-${{ steps.date.outputs.Ymd }}
-          ${{ runner.os }}-node_modules_prod-${{ matrix.node-version }}-${{ steps.date.outputs.Ym }}
-          ${{ runner.os }}-node_modules_prod-${{ matrix.node-version }}-${{ steps.date.outputs.Y }}
-    - name: Get yarn cache dir
-      id: cache-yarn
-      run: echo "::set-output name=dir::$(yarn cache dir)"
-    - name: Cache/Restore yarn cache
-      uses: actions/cache@v2
-      with:
-        path: ${{ steps.cache-yarn.outputs.dir }}
-        key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-yarn-
-    - name: Install dependencies
+        rm -rf packages/slackbot-proxy
+    - name: lerna bootstrap
       run: |
       run: |
         npx lerna bootstrap
         npx lerna bootstrap
     - name: Print dependencies
     - name: Print dependencies
@@ -277,8 +207,7 @@ jobs:
         yarn list --depth=0
         yarn list --depth=0
     - name: Build
     - name: Build
       run: |
       run: |
-        yarn lerna run build --scope @growi/slack
-        yarn lerna run build --scope @growi/app
+        yarn lerna run build
     - name: lerna bootstrap --production
     - name: lerna bootstrap --production
       run: |
       run: |
         npx lerna bootstrap -- --production
         npx lerna bootstrap -- --production
@@ -291,21 +220,20 @@ jobs:
       id: getdbname
       id: getdbname
       run: |
       run: |
         echo ::set-output name=suffix::$(echo '${{ matrix.node-version }}' | sed s/\\.//)
         echo ::set-output name=suffix::$(echo '${{ matrix.node-version }}' | sed s/\\.//)
-    - name: yarn server:prod:ci
+    - name: yarn server:ci
+      working-directory: ./packages/app
       run: |
       run: |
-        yarn server:prod:ci
+        cp config/ci/.env.local.for-ci .env.production.local
+        yarn server:ci
       env:
       env:
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi-${{ steps.getdbname.outputs.suffix }}
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi-${{ steps.getdbname.outputs.suffix }}
-    - name: yarn server:prod:ci with MongoDB 3.6
+    - name: yarn server:ci with MongoDB 3.6
+      working-directory: ./packages/app
       run: |
       run: |
-        yarn server:prod:ci
+        cp config/ci/.env.local.for-ci .env.production.local
+        yarn server:ci
       env:
       env:
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb36.ports['27017'] }}/growi-${{ steps.getdbname.outputs.suffix }}
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb36.ports['27017'] }}/growi-${{ steps.getdbname.outputs.suffix }}
-    - name: Upload report as artifact
-      uses: actions/upload-artifact@v2
-      with:
-        name: Report
-        path: report
 
 
     - name: Slack Notification
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
       uses: weseek/ghaction-slack-notification@master

+ 62 - 0
.github/workflows/draft-release.yml

@@ -0,0 +1,62 @@
+name: Draft Release
+
+on:
+  push:
+    branches:
+      - master
+
+jobs:
+
+  # Refs: https://github.com/release-drafter/release-drafter
+  update-release-draft:
+    runs-on: ubuntu-latest
+
+    outputs:
+      CURRENT_VERSION: ${{ steps.package-json.outputs.packageVersion }}
+      RELEASE_DRAFT_BODY: ${{ steps.release-drafter.outputs.body }}
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Retrieve information from package.json
+        uses: myrotvorets/info-from-package-json-action@1.1.0
+        id: package-json
+
+      # Drafts your next Release notes as Pull Requests are merged into "master"
+      - uses: release-drafter/release-drafter@v5
+        id: release-drafter
+        with:
+          name: v${{ steps.package-json.outputs.packageVersion }}
+          tag: v${{ steps.package-json.outputs.packageVersion }}
+          version: ${{ steps.package-json.outputs.packageVersion }}
+          disable-autolabeler: true
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+  # Refs: https://github.com/bakunyo/git-pr-release-action
+  update-release-pr:
+    needs: update-release-draft
+
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Get release version
+        id: release-version
+        run: |
+          RELEASE_VERSION=`npx semver -i patch ${{ needs.update-release-draft.outputs.CURRENT_VERSION }}`
+          echo ::set-output name=RELEASE_VERSION::$RELEASE_VERSION
+
+      - name: Create/Update Pull Request
+        uses: bakunyo/git-pr-release-action@master
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          GIT_PR_RELEASE_BRANCH_PRODUCTION: release/current
+          GIT_PR_RELEASE_BRANCH_STAGING: master
+          GIT_PR_RELEASE_TEMPLATE: .github/git-pr-release-template.erb
+          GIT_PR_RELEASE_TITLE: Release v${{ steps.release-version.outputs.RELEASE_VERSION }}
+          GIT_PR_RELEASE_BODY: ${{ needs.update-release-draft.outputs.RELEASE_DRAFT_BODY }}
+

+ 46 - 0
.github/workflows/pr-to-master.yml

@@ -0,0 +1,46 @@
+name: PR to master
+
+on:
+  pull_request:
+    branches:
+      - master
+    # Only following types are handled by the action, but one can default to all as well
+    types: [opened, reopened, edited, synchronize]
+
+jobs:
+
+  # Refs: https://github.com/release-drafter/release-drafter
+  auto-labeling:
+    runs-on: ubuntu-latest
+
+    if: ${{ !contains(github.event.pull_request.labels.*.name, 'exclude from changelog') }}
+
+    steps:
+      - uses: release-drafter/release-drafter@v5
+        with:
+          disable-releaser: true
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+  check-title:
+    runs-on: ubuntu-latest
+
+    if: |
+      (!contains( github.event.pull_request.labels.*.name, 'exclude from changelog' ) &&
+        !startsWith( github.head_ref, 'dependabot/' ))
+
+    steps:
+      - uses: amannn/action-semantic-pull-request@v3.4.2
+        with:
+          types: |
+            feat
+            imprv
+            fix
+            support
+            chore
+            ci
+            docs
+            test
+          requireScope: false
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

+ 6 - 8
.github/workflows/release-rc.yml

@@ -14,11 +14,9 @@ jobs:
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
 
 
-    - name: Setup semver
-      id: semver
-      run: |
-        semver=`npm run version --silent`
-        echo "::set-output name=SEMVER::$semver"
+    - name: Retrieve information from package.json
+      uses: myrotvorets/info-from-package-json-action@1.1.0
+      id: package-json
 
 
     - name: Docker meta
     - name: Docker meta
       id: meta
       id: meta
@@ -26,8 +24,8 @@ jobs:
       with:
       with:
         images: weseek/growi,ghcr.io/weseek/growi
         images: weseek/growi,ghcr.io/weseek/growi
         tags: |
         tags: |
-          type=raw,value=${{ steps.semver.outputs.SEMVER }}
-          type=raw,value=${{ steps.semver.outputs.SEMVER }}.{{sha}}
+          type=raw,value=${{ steps.package-json.outputs.packageVersion }}
+          type=raw,value=${{ steps.package-json.outputs.packageVersion }}.{{sha}}
 
 
     - name: Login to docker.io registry
     - name: Login to docker.io registry
       run: |
       run: |
@@ -55,7 +53,7 @@ jobs:
       uses: docker/build-push-action@v2
       uses: docker/build-push-action@v2
       with:
       with:
         context: .
         context: .
-        file: ./docker/Dockerfile
+        file: ./packages/app/docker/Dockerfile
         platforms: linux/amd64
         platforms: linux/amd64
         push: true
         push: true
         cache-from: type=local,src=/tmp/.buildx-cache
         cache-from: type=local,src=/tmp/.buildx-cache

+ 8 - 8
.github/workflows/release-slackbot-proxy.yml

@@ -1,9 +1,10 @@
 name: Release Docker Image for @growi/slackbot-proxy
 name: Release Docker Image for @growi/slackbot-proxy
 
 
 on:
 on:
-  push:
+  pull_request:
     branches:
     branches:
       - release/slackbot-proxy/**
       - release/slackbot-proxy/**
+    types: [closed]
 
 
 jobs:
 jobs:
 
 
@@ -12,13 +13,12 @@ jobs:
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
+      with:
+        ref: ${{ github.event.pull_request.base.ref }}
 
 
-    - name: Setup semver
-      id: semver
-      working-directory: ./packages/slackbot-proxy
-      run: |
-        semver=`npm run version --silent`
-        echo "::set-output name=SEMVER::$semver"
+    - name: Retrieve information from package.json
+      uses: myrotvorets/info-from-package-json-action@1.1.0
+      id: package-json
 
 
     - name: Docker meta
     - name: Docker meta
       id: meta
       id: meta
@@ -27,7 +27,7 @@ jobs:
         images: weseek/growi-slackbot-proxy,ghcr.io/weseek/growi-slackbot-proxy,asia.gcr.io/${{ secrets.GCP_PRJ_ID_SLACKBOT_PROXY }}/growi-slackbot-proxy
         images: weseek/growi-slackbot-proxy,ghcr.io/weseek/growi-slackbot-proxy,asia.gcr.io/${{ secrets.GCP_PRJ_ID_SLACKBOT_PROXY }}/growi-slackbot-proxy
         tags: |
         tags: |
           type=raw,value=latest
           type=raw,value=latest
-          type=raw,value=${{ steps.semver.outputs.SEMVER }}
+          type=raw,value=${{ steps.package-json.outputs.packageVersion }}
 
 
     - name: Login to docker.io registry
     - name: Login to docker.io registry
       run: |
       run: |

+ 108 - 40
.github/workflows/release.yml

@@ -1,57 +1,127 @@
 name: Release
 name: Release
 
 
 on:
 on:
-  push:
+  pull_request:
     branches:
     branches:
       - release/current
       - release/current
       - release/*.*.*
       - release/*.*.*
+    types: [closed]
 
 
 jobs:
 jobs:
-  github-release:
+  create-github-release:
 
 
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
 
 
+    if: github.event.pull_request.merged == true
+
     outputs:
     outputs:
-      RELEASE_VERSION: ${{ steps.bump-version.outputs.RELEASE_VERSION }}
+      RELEASED_VERSION: ${{ steps.package-json.outputs.packageVersion }}
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
+      with:
+        ref: ${{ github.event.pull_request.base.ref }}
 
 
-    - name: Init Git
+    - uses: actions/setup-node@v2
+      with:
+        node-version: '14'
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
+    - name: Install dependencies
       run: |
       run: |
-        git config --local user.name "GitHub Action"
-        git config --local user.email "info@weseek.co.jp"
-        git remote set-url origin "https://$GITHUB_ACTOR:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY"
+        npx lerna bootstrap
 
 
-    - name: Bump version
-      id: bump-version
+    - name: Bump versions
       run: |
       run: |
-        npm --no-git-tag-version version patch
-        export RELEASE_VERSION=`npm run version --silent`
-        sh ./bin/github-actions/update-readme.sh
-        echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV
-        echo ::set-output name=RELEASE_VERSION::$RELEASE_VERSION
+        node ./bin/github-actions/bump-versions -i patch
+        sh ./packages/app/bin/github-actions/update-readme.sh
 
 
-    - name: Checkout, Commit, Tag and Push
+    - name: Retrieve information from package.json
+      uses: myrotvorets/info-from-package-json-action@1.1.0
+      id: package-json
+
+    - name: Update Changelog
+      uses: stefanzweifel/changelog-updater-action@v1
+      with:
+        latest-version: v${{ steps.package-json.outputs.packageVersion }}
+        release-notes: ${{ github.event.pull_request.body }}
+
+    - name: Update README.md for docker image
+      working-directory: ./packages/app
       run: |
       run: |
-        TMP_RELEASE_BRANCH=tmp/release-${{ env.RELEASE_VERSION }}
-        git checkout -B $TMP_RELEASE_BRANCH
-        git commit -am "Release v${{ env.RELEASE_VERSION }}"
-        git tag -a v${{ env.RELEASE_VERSION }} -m "v${{ env.RELEASE_VERSION }}"
-        git push --follow-tags origin $TMP_RELEASE_BRANCH
-        git push --delete origin $TMP_RELEASE_BRANCH
-
-    - name: Upload release notes
-      uses: Roang-zero1/github-create-release-action@master
-      with:
-        created_tag: v${{ env.RELEASE_VERSION }}
-        changelog_file: CHANGES.md
+        sh ./bin/github-actions/update-readme.sh
+      env:
+        RELEASED_VERSION: ${{ steps.package-json.outputs.packageVersion }}
+
+    - name: Commit, Tag and Push
+      uses: stefanzweifel/git-auto-commit-action@v4
+      with:
+        branch: ${{ github.event.pull_request.base.ref }}
+        commit_message: Release v${{ steps.package-json.outputs.packageVersion }}
+        tagging_message: v${{ steps.package-json.outputs.packageVersion }}
+
+    - uses: ncipollo/release-action@v1
+      with:
+        body: ${{ github.event.pull_request.body }}
+        tag: v${{ steps.package-json.outputs.packageVersion }}
+        token: ${{ secrets.GITHUB_TOKEN }}
+
+    - name: Delete drafts
+      uses: hugo19941994/delete-draft-releases@v1.0.0
       env:
       env:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 
 
 
 
+  create-pr-for-next-rc:
+    needs: create-github-release
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        ref: v${{ needs.create-github-release.outputs.RELEASED_VERSION }}
+
+    - uses: actions/setup-node@v2
+      with:
+        node-version: '14'
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
+    - name: Install dependencies
+      run: |
+        npx lerna bootstrap
+
+    - name: Bump versions for next RC
+      run: |
+        node ./bin/github-actions/bump-versions -i prerelease
+
+    - name: Retrieve information from package.json
+      uses: myrotvorets/info-from-package-json-action@1.1.0
+      id: package-json
+
+    - name: Commit
+      uses: github-actions-x/commit@v2.8
+      with:
+        github-token: ${{ secrets.GITHUB_TOKEN }}
+        push-branch: support/prepare-v${{ steps.package-json.outputs.packageVersion }}
+        commit-message: 'Bump version'
+        name: GitHub Action
+
+    - name: Create PR
+      uses: repo-sync/pull-request@v2
+      with:
+        source_branch: support/prepare-v${{ steps.package-json.outputs.packageVersion }}
+        destination_branch: master
+        pr_title: Prepare v${{ steps.package-json.outputs.packageVersion }}
+        pr_label: exclude from changelog
+        pr_body: "An automated PR generated by ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
+        github_token: ${{ secrets.GITHUB_TOKEN }}
+
+
   build-image:
   build-image:
-    needs: github-release
+    needs: create-github-release
 
 
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
 
 
@@ -61,11 +131,8 @@ jobs:
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
-
-    - name: Checkout released tag
-      run: |
-        git fetch --tags
-        git checkout refs/tags/v${{ needs.github-release.outputs.RELEASE_VERSION }}
+      with:
+        ref: v${{ needs.create-github-release.outputs.RELEASED_VERSION }}
 
 
     - name: Setup suffix
     - name: Setup suffix
       id: suffix
       id: suffix
@@ -82,9 +149,9 @@ jobs:
           suffix=${{ steps.suffix.outputs.SUFFIX }}
           suffix=${{ steps.suffix.outputs.SUFFIX }}
         tags: |
         tags: |
           type=raw,value=latest
           type=raw,value=latest
-          type=semver,value=${{ needs.github-release.outputs.RELEASE_VERSION }},pattern={{major}}
-          type=semver,value=${{ needs.github-release.outputs.RELEASE_VERSION }},pattern={{major}}.{{minor}}
-          type=semver,value=${{ needs.github-release.outputs.RELEASE_VERSION }},pattern={{major}}.{{minor}}.{{patch}}
+          type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}
+          type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}.{{minor}}
+          type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}.{{minor}}.{{patch}}
 
 
     - name: Login to docker.io registry
     - name: Login to docker.io registry
       run: |
       run: |
@@ -104,15 +171,16 @@ jobs:
       uses: actions/cache@v2
       uses: actions/cache@v2
       with:
       with:
         path: /tmp/.buildx-cache
         path: /tmp/.buildx-cache
-        key: ${{ runner.os }}-buildx-app-${{ github.sha }}
+        key: ${{ runner.os }}-buildx-app-${{ matrix.flavor }}-${{ github.sha }}
         restore-keys: |
         restore-keys: |
+          ${{ runner.os }}-buildx-app-${{ matrix.flavor }}-
           ${{ runner.os }}-buildx-app-
           ${{ runner.os }}-buildx-app-
 
 
     - name: Build and push
     - name: Build and push
       uses: docker/build-push-action@v2
       uses: docker/build-push-action@v2
       with:
       with:
         context: .
         context: .
-        file: ./docker/Dockerfile
+        file: ./packages/app/docker/Dockerfile
         platforms: linux/amd64
         platforms: linux/amd64
         push: true
         push: true
         cache-from: type=local,src=/tmp/.buildx-cache
         cache-from: type=local,src=/tmp/.buildx-cache
@@ -130,14 +198,14 @@ jobs:
         username: wsmoogle
         username: wsmoogle
         password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
         password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
         repository: weseek/growi
         repository: weseek/growi
-        readme-filepath: ./docker/README.md
+        readme-filepath: ./packages/app/docker/README.md
 
 
     - name: Slack Notification
     - name: Slack Notification
       uses: weseek/ghaction-release-slack-notification@master
       uses: weseek/ghaction-release-slack-notification@master
       with:
       with:
         channel: '#release'
         channel: '#release'
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
-        created_tag: 'v${{ needs.github-release.outputs.RELEASE_VERSION }}${{ env.SUFFIX }}'
+        created_tag: 'v${{ needs.create-github-release.outputs.RELEASED_VERSION }}${{ steps.suffix.outputs.SUFFIX }}'
 
 
     - name: Check whether workspace is clean
     - name: Check whether workspace is clean
       run: |
       run: |

+ 0 - 30
.gitignore

@@ -8,36 +8,6 @@ node_modules
 # testing
 # testing
 coverage
 coverage
 
 
-# next.js
-/.next/
-/out/
-
-# production
-/build
-
-# dist
-/packages/**/dist/
-/report/
-/public/static/js
-/public/static/styles
-/public/uploads
-/tmp/
-
-# dist (for GROWI v4.x and below)
-/public/*.chunk.js
-/public/*.chunk.js.LICENSE
-/public/*.bundle.js
-/public/manifest.json
-/public/dll
-/public/js
-/public/styles
-/src/*/__build__/
-/__build__/**
-/src/*/dist/
-/.awcache
-.webpack.json
-/compiled/
-
 # misc
 # misc
 .DS_Store
 .DS_Store
 *.pem
 *.pem

+ 4 - 0
.markdownlint.yml

@@ -7,3 +7,7 @@ no-multiple-blanks: false
 no-duplicate-heading: false
 no-duplicate-heading: false
 no-inline-html: false
 no-inline-html: false
 no-trailing-punctuation: false
 no-trailing-punctuation: false
+
+MD002: false
+MD012: false
+MD041: false

+ 0 - 4
.stylelintrc.json

@@ -2,10 +2,6 @@
   "extends": [
   "extends": [
     "stylelint-config-recess-order"
     "stylelint-config-recess-order"
   ],
   ],
-  "ignoreFiles": [
-    "src/client/styles/scss/_override-bootstrap-variables.scss",
-    "src/linter-checker/test.scss"
-  ],
   "rules": {
   "rules": {
     "indentation": 2,
     "indentation": 2,
     "string-quotes": "single",
     "string-quotes": "single",

+ 27 - 6
.vscode/launch.json

@@ -14,10 +14,11 @@
         "type": "node",
         "type": "node",
         "request": "launch",
         "request": "launch",
         "name": "Debug: Server",
         "name": "Debug: Server",
+        "cwd": "${workspaceFolder}/packages/app",
         "runtimeExecutable": "npm",
         "runtimeExecutable": "npm",
         "runtimeArgs": [
         "runtimeArgs": [
           "run",
           "run",
-          "server:nolazy"
+          "dev:server"
         ],
         ],
         "port": 9229,
         "port": 9229,
         "restart": true,
         "restart": true,
@@ -30,9 +31,9 @@
         "name": "Debug: Chrome",
         "name": "Debug: Chrome",
         "sourceMaps": true,
         "sourceMaps": true,
         "sourceMapPathOverrides": {
         "sourceMapPathOverrides": {
-          "webpack:///*": "${workspaceFolder}/*"
+          "webpack:///*": "${workspaceFolder}/packages/app/*"
         },
         },
-        "webRoot": "${workspaceFolder}/public",
+        "webRoot": "${workspaceFolder}/packages/app/public",
         "url": "http://localhost:3000"
         "url": "http://localhost:3000"
       },
       },
       {
       {
@@ -41,15 +42,35 @@
         "name": "Debug: Firefox",
         "name": "Debug: Firefox",
         "reAttach": true,
         "reAttach": true,
         "url": "http://localhost:3000",
         "url": "http://localhost:3000",
-        "webRoot": "${workspaceFolder}/public",
+        "webRoot": "${workspaceFolder}/packages/app/public",
         "pathMappings": [
         "pathMappings": [
+          {
+            "url": "webpack:///core",
+            "path": "${workspaceFolder}/packages/core"
+          },
+          {
+            "url": "webpack:///plugin-attachment-refs",
+            "path": "${workspaceFolder}/packages/plugin-attachment-refs"
+          },
+          {
+            "url": "webpack:///plugin-pukiwiki-like-linker",
+            "path": "${workspaceFolder}/packages/plugin-pukiwiki-like-linker"
+          },
+          {
+            "url": "webpack:///plugin-lsx",
+            "path": "${workspaceFolder}/packages/plugin-lsx"
+          },
+          {
+            "url": "webpack:///ui",
+            "path": "${workspaceFolder}/packages/ui"
+          },
           {
           {
             "url": "webpack:///src",
             "url": "webpack:///src",
-            "path": "${workspaceFolder}/src"
+            "path": "${workspaceFolder}/packages/app/src"
           },
           },
           {
           {
             "url": "http://localhost:3000",
             "url": "http://localhost:3000",
-            "path": "${workspaceFolder}/public"
+            "path": "${workspaceFolder}/packages/app/public"
           }
           }
         ]
         ]
       }
       }

+ 0 - 19
.vscode/tasks.json

@@ -1,19 +0,0 @@
-{
-    // See https://go.microsoft.com/fwlink/?LinkId=733558
-    // for the documentation about the tasks.json format
-    "version": "2.0.0",
-    "tasks": [
-        {
-            "type": "npm",
-            "script": "build",
-            "problemMatcher": [
-                "$eslint-compact"
-            ]
-        },
-        {
-            "type": "npm",
-            "script": "server",
-            "problemMatcher": []
-        }
-    ]
-}

+ 1731 - 0
CHANGELOG.md

@@ -0,0 +1,1731 @@
+# Changelog
+
+## [Unreleased](https://github.com/weseek/growi/compare/v4.4.5...HEAD)
+
+*Please do not manually update this file. We've automated the process.*
+
+## [v4.4.5](https://github.com/weseek/growi/compare/v4.4.4...v4.4.5) - 2021-09-23
+
+### 🐛 Bug Fixes
+
+- fix: Revert #4347
+- fix: ERROR: Cannot find module 'tslib' on v4.4.4 (#4368) @yuki-takei
+
+### 🧰 Maintenance
+
+- support: bump @promster/express and @promster/server (#4370) @yuki-takei
+- support: Upgrade codemirror to 5.63.0 (#4364) @yuki-takei
+- ci(deps-dev): bump codemirror from 5.48.4 to 5.58.2 (#4363) @dependabot
+
+## [v4.4.4](https://github.com/weseek/growi/compare/v4.4.3...v4.4.4) (Discontinued) - 2021-09-22
+
+### 💎 Features
+
+- feat: Add Textlint support (#4228) @kaoritokashiki
+
+### 🚀 Improvement
+
+- imprv: Highlighting searching keyword (#4327) @yuki-takei
+
+### 🐛 Bug Fixes
+
+- fix: Backspace key on last line doesn't work in vim mode (#4347) @yuki-takei
+- fix: Recent Created of home is empty (#4345) @yuki-takei
+- fix: IME suggestion list obscures inputted text (#4335) @yuki-takei
+- fix: Highlighting section header (#4326) @yuki-takei
+
+### 🧰 Maintenance
+
+- chore: Update passport-saml 2.2.0 (#4360) @LuqmanHakim-Grune
+- ci(deps): bump http-errors from 1.6.2 to 1.8.0 (#4353) @dependabot
+- ci(deps-dev): bump @tsed/json-mapper from 6.43.0 to 6.70.1 (#4352) @dependabot
+- ci(deps): bump graceful-fs from 4.1.11 to 4.2.8 (#4351) @dependabot
+- ci(deps): bump myrotvorets/info-from-package-json-action from 0.0.2 to 1.1.0 (#4348) @dependabot
+- ci(deps): bump path-parse from 1.0.5 to 1.0.7 (#4126) @dependabot
+- ci(deps): bump tmpl from 1.0.4 to 1.0.5 (#4337) @dependabot
+
+## [v4.4.3](https://github.com/weseek/growi/compare/v4.4.2...v4.4.3) - 2021-09-17
+
+### 💎 Features
+
+- feat: Slack command permission for each channel (#4302) @hakumizuki
+
+### 🚀 Improvement
+
+- imprv: Copy buttons interaction (#4303) @maow89126
+- imprv: Use socket.io room (#4307) @hakumizuki
+- imprv: Recent changes of sidebar (#4293) @kaho819
+
+### 🐛 Bug Fixes
+
+- fix: Response to slackbot when no pages are found /growi search (#4321) @stevenfukase
+- fix: Keyword highlight styling in search result (#4312) @maow89126
+- fix(slackbot-proxy): Call next in connect-styled middleware (#4286) @yuki-takei
+
+### 🧰 Maintenance
+
+- chore: Refactor for "Slack command permission for each channel" (#4295) @zahmis
+- support: Update APIv3 docs for pages (#4280) @yuki-takei
+
+## [v4.4.2](https://github.com/weseek/growi/compare/v4.4.0...v4.4.2) - 2021-09-07
+
+### Changes
+
+- Release v4.4.1 (#4262) @github-actions
+
+### 🐛 Bug Fixes
+
+- fix: Plugin backend's permission (#4271) @yuki-takei
+
+### 🧰 Maintenance
+
+- support: Make lerna mode fixed (#4274) @yuki-takei
+- support: Make lerna mode fixed (#4263) @yuki-takei
+
+## v4.4.1 (Missing number)
+
+## [v4.4.0](https://github.com/weseek/growi/compare/v4.3.3...v4.4.0) (Discontinued) - 2021-09-06
+
+### Changes
+
+### BREAKING CHANGES
+
+- Official plugins are now preinstalled
+- It is no longer compatible with previous versions of official bots
+
+Upgrading Guide: [https://docs.growi.org/en/admin-guide/upgrading/44x.html](https://docs.growi.org/en/admin-guide/upgrading/44x.html)
+
+### 💎 Features
+
+- feat: Password resetting by users (#4135) @kaoritokashiki
+- feat: Copy bug report btn (#4200) @Mxchaeltrxn
+- Feature: User trigger notification and Global notification are available by new Slack integration
+
+### 🚀 Improvement
+
+- imprv: Add attachment button in editor navbar
+- imprv: Modified with proxy app installation tutorial (#4174) @hakumizuki
+- imprv: Slackbot proxy respone (#4194) @hakumizuki
+- imprv: Slackbot proxy respone (#4175, #4201) @zahmis
+- Imprv: Admin slack integration (#4190) @yuki-takei
+
+### 🐛 Bug Fixes
+
+- fix: Recursive rename operation from `/parent` to `/parent/child` (#4101) @miya
+- fix: adminRequired middleware for socket.io (#4245) @yuki-takei
+- fix: Encode spaces in page path in LinkEditModal
+
+### 🧰 Maintenance
+
+- support: Supress warnings for mongo (#4247) @yuki-takei
+- support: Add bump-versions script (#4241) @yuki-takei
+- support: New release workflow (#4236) @yuki-takei
+- Support: Create @growi/core package
+- Support: Create @growi/ui package
+- Support: Include official plugins as sub packages
+- Support: Upgrade libs
+
+## v4.3.3
+
+- Improvement: Welcome page markdown
+- Fix: Some recursive operation exclude descendant pages that are restricted for groups (Rename / Delete / Delete completely / Put back / Duplicate)
+- Fix: Layout is broken when editing users page ([#4128](https://github.com/weseek/growi/issues/4128))
+- Support: Upgrade libs
+
+## v4.3.2
+
+- Feature: Hufflpuff theme
+- Improvement: CodeMirror header styles
+- Improvement: CodeMirror syntax-highlighting fenced code blocks
+- Improvement: Slack Integration Settings: Error behavior when getting connection statuses
+- Improvement: Slack Integration Settings: Add links to docs
+- Improvement: /_api/v3/recent can be accessed with access token
+- Support: Using http-errors
+
+## v4.3.1
+
+- Fix: Build script for production
+
+## v4.3.0
+
+### BREAKING CHANGES
+
+- GROWI manages dependencies with `lerna`: Use `npx lerna bootstrap` instead of `yarn install`
+- GROWI includes some official plugins in default: Users no longer need to install [growi-plugin-lsx](https://github.com/weseek/growi-plugin-lsx), [growi-plugin-pukiwiki-like-linker](https://github.com/weseek/growi-plugin-pukiwiki-like-linker) and [growi-plugin-attachment-refs](https://github.com/weseek/growi-plugin-attachment-refs) before build client.
+
+Upgrading Guide: [https://docs.growi.org/en/admin-guide/upgrading/43x.html](https://docs.growi.org/en/admin-guide/upgrading/43x.html)
+
+### Updates
+
+- Feature: Enable/Disable option for share link
+- Feature: Re-send invitation mail from user management page
+- Improvement: Mark users who failed to send invitation emails
+- Fix: lsx plugin in the custom sidebar does not work when showing search result page
+- Support: Switch the official docker base image from Alpine based to Ubuntu based
+- Support: Upgrade libs
+
+## v4.2.21
+
+- Improvement: Headers style on built-in editor
+- Improvement: Codemirror is now scrollable one editor height of empty space into view at the bottom of the editor
+- Improvement: Upgrade mongodb driver to fix [NODE-2784](https://jira.mongodb.org/browse/NODE-2784)
+- Support: Upgrade libs
+
+## v4.2.20
+
+- Improvement: Error message when the password is too short
+- Improvement: Repeat XSS processing as a countermeasure against nesting
+- Fix: NoSQL injection of access-token-parser
+- Fix: Checking permission when operating share links
+- Fix: Invalid NaN label is shown when deletedAt of the page is undefined (Introduced by v4.2.8)
+
+## v4.2.19
+
+- Feature: Set max-age of the user's cookie with the env var `SESSION_MAX_AGE`
+- Feature: Set max-age of the user's cookie in admin page
+- Improvement: Change the first accessing page after installation to the top page
+- Support: Upgrade libs
+
+## v4.2.18
+
+- Feature: Convertible page contents width
+- Fix: Group selector of User Group Delete Modal does not show all groups
+- Fix: Global notification to Slack does not encode spaces of page path
+- Support: Upgrade libs
+
+## v4.2.17
+
+- Improvement: Invoke garbage collection when reindex all pages by elasticsearch
+- Improvement: Hide Sidebar at shared pages
+- Fix: No unsaved alert is displayed without difference the latest markdown and editor value
+- Support: Update libs
+
+## v4.2.16
+
+- Fix: "Only inside the group" causes an error (Introduced by v4.2.15)
+
+## v4.2.15
+
+- Improvement: toastr location for editing
+- Improvement: Handsontable with static backdrop to prevent from closing when backdrop is clicked
+- Fix: Accept invalid page path like `..%2f`
+- Fix: Pages updated date is corrupted after recursive operation (Introduced by v4.2.8)
+- Support: Upgrade libs
+
+## v4.2.14
+
+- Feature: Add an option to restrict publishing email property for new users
+- Improvement: Invite modal in admin page without email server settings
+- Improvement: Global notification settings in admin page without email server settings
+- Fix: Can create pages on the share route (Introduced by v4.2.8)
+- Fix: Pages restrected by group are excluded for recurrence operation (Introduced by v4.2.8)
+- Fix: Rename and duplicate to descendants path does not work correctly (Introduced by v4.2.8)
+- Support: Update libs
+
+## v4.2.13
+
+- Feature: Detect indent size automatically
+- Fix: Some API responses includes email unintentionally
+- Fix: An error always displayed in admin pages
+
+## v4.2.12
+
+- Feature: Custom Sidebar
+- Fix: Set language correctly for draw.io (diagrams.net)
+
+## v4.2.11
+
+- Fix: Rename decendants is not working (Introduced by v4.2.8)
+
+## v4.2.10
+
+- Feature: Staff Credits for apps on GROWI.cloud
+- Improvement: Hackmd button behavior when disabled
+- Improvement: Layout of comparing revisions
+- Fix: Empty trash is not working
+
+## v4.2.9
+
+- Feature: Comparing revisions
+- Improvement: Memory consumption when re-indexing for full text searching
+- Improvement: Site URL settings valildation
+- Fix: Show comfirmation when transiting page without save
+- Fix: Save slack channels history when user trigger notification is invoked
+- Fix: The label of alerts for move/rename/delete are borken
+
+## v4.2.8
+
+- Improvement: Performance for pages to rename/duplicate/delete/revert pages
+- Fix: Preview scrollbar doesn't sync to editor (Introduced by v4.2.6)
+- Fix: Failed to save temporaryUrlCached with using gcs (Introduced by v4.2.3)
+- Fix: Fixed not being able to update ses settings (Introduced by v4.2.0)
+- Fix: Fixed the display of updtedAt and createdAt being reversed
+- Fix: Pass app title value through the XSS filter
+
+## v4.2.7
+
+- Fix: Installer doesn't work on Chrome
+
+## v4.2.6
+
+- Feature: Add a button to jump to Comments section
+- Feature: Paste Bootstrap4 Grid HTML with GUI
+- Feature: Disable auto formating table option
+- Improvement: Layout of Edit Link Modal
+- Improvement: Focus to the first input when modal is opened
+- Improvement: Preview layout in edit mode
+- Improvement: Install process under redundant environment
+- Improvement: Add contributors
+- Fix: Upgrading to v4.x failed when the user uses Kibela Layout (Introduced by v4.2.0)
+- Fix: diagrams.net (draw.io) errors
+- Fix: Navbar is not rendered on old iOS
+- Support: Expose metrics with Promster
+- Support: Upgrade libs
+
+## v4.2.5
+
+- Improvement: Invoke garbage collection when reindex all pages by elasticsearch
+- Fix: MathJax rendering does not work
+
+## v4.2.4
+
+- Fix: Fixed an error when creating a new page with `Ctrl-S` (Introduced by v4.2.2)
+- Fix: Fixed a strange diff in PageHistory due to Pagination
+- Fix: Fixed that the user group page could not be found when using api from the outside
+
+## v4.2.3
+
+- Feature: Insert/edit links with GUI
+- Feature: Auto reconnecting to search service
+- Improvement: New style of params for Healthcheck API
+- Fix: Referencing attachments when `FILE_UPLOAD_DISABLED` is true
+- Fix: The message of timeline for restricted pages
+- Fix: Parameter validation for Import/Export Archive API
+- Fix: Prevent regexp for Search Tags API
+- Fix: Add `Content-Security-Policy` when referencing attachments
+- Fix: Sanitize at presentation time
+- Fix: Remove page path string from message for page lists and timeline when there is no contents
+
+## v4.2.2
+
+- Fix: Consecutive save operations with built-in editor fail (Introduced by v4.2.1)
+
+## v4.2.1
+
+- Fix: Consecutive save operations with HackMD fail (Introduced by v4.2.0)
+- Fix: Switching theme to kibela fail (Introduced by v4.2.0)
+
+## v4.2.0
+
+### BREAKING CHANGES
+
+- GROWI v4.2.x no longer support Kibela layout. Kibela theme is newly added and the configuration will migrate to it automatically.
+
+### Updates
+
+- Feature: File Upload Settings on admin pages
+- Improvement: Basic layout of page
+- Support: Support MongoDB 4.0, 4.2 and 4.4
+- Support: Upgrade libs
+
+## v4.1.13
+
+- Fix: MathJax rendering does not work
+
+## v4.1.12
+
+- Fix: Adjust line-height for pre under li
+- Fix: Emptying trash process is broken
+
+## v4.1.11
+
+- Improvement: Generating draft DOM id strategy
+- Fix: GROWI version downgrade causes a validation error for user.lang
+
+## v4.1.10
+
+- Fix: Make listing users API secure
+- Fix: Error message when the server denies guest user connecting with socket.io
+
+## v4.1.9
+
+- Feature: Environment variables to set max connection size to deliver push messages to all clients
+
+## v4.1.8
+
+- Improvement: Rebuilding progress bar colors for Full Text Search Management
+- Improvement: Support operations on page data with a null value for author
+
+## v4.1.7
+
+- Improvement: Fire global notification when a new page is created by uploading file
+- Fix: Change default `DRAWIO_URI` to embed.diagrams.net
+- Fix: An unhandled rejection occures when a user who does not send referer accesses
+
+## v4.1.6
+
+- Improvement: Hide Fab at admin pages
+- Fix: Presentation does not work
+- Fix: Update GrantSelector status when uploading a file to a new page
+- Fix: CopyDropdown origin refs draw.io host wrongly
+
+## v4.1.5
+
+- Feature: Independent S3 configuration and SES configuration for AWS
+- Fix: Author name does not displayed in page history
+- Fix: Hide unnecessary component when pringing
+
+## v4.1.4 (Discontinued)
+
+## v4.1.3
+
+- Feature: Create/edit linker with GUI
+- Improvement: Paging page histories
+- Improvement: Avoid using `cursor.snapshot()` in preparation for MongoDB version upgrade
+- Improvement: Allow to save "From e-mail address" only in App Settings
+- Improvement: Allow to empty "From e-mail address" in App Settings
+- Improvement: Export/Import archive data serially so as not to waste memory
+- Fix: To be able to delete attachment metadata even when the actual data does not exist
+- Fix: Limit the attrubutes of user data for `/_api/v3/users`
+- Fix: Prevent XSS with SVG
+- Upgrade libs
+
+## v4.1.2
+
+- Fix: Uploaded images do not displayed (Introduced by v4.1.1)
+
+## v4.1.1
+
+- Feature: External share link
+- Improvement: Optimize some features that operate revision data
+- Fix: Cmd+c/v/... does not work on Mac (Introduced by v4.1.0)
+- Fix: "Append params" switch of CopyDropdown does not work when multiple CopyDropdown instance exists
+- Fix: "Append params" switch of CopyDropdown escapes spaces
+- Fix: Blockdiag does not be rendered
+- Fix: Access token parser
+
+## v4.1.0
+
+### BREAKING CHANGES
+
+- GROWI v4.1.x no longer support Node.js v10.x
+- GROWI v4.1.x no longer support growi-plugin-attachment-refs@v1
+
+Upgrading Guide: [https://docs.growi.org/en/admin-guide/upgrading/41x.html](https://docs.growi.org/en/admin-guide/upgrading/41x.html)
+
+### Updates
+
+- Feature: Server settings synchronization for multiple GROWI Apps
+- Feature: Page status alert synchronization for multiple GROWI Apps
+- Feature: Smooth scroll for anchor links
+- Feature: Mirror Mode with [Konami Code](https://en.wikipedia.org/wiki/Konami_Code)
+- Improvement: Determine whether the "In Use" badge is displayed or not by attachment ID
+- Improvement: draw.io under NO_CDN environment
+- Fix: Deleting/renaming with recursive option affects pages that are inaccessible to active users
+- Fix: DrawioModal cuts without beginning/ending line
+- Fix: New settings of SMTP and AWS SES are not reflected when server is running
+- Fix: Sidebar layout broken when using Kibela layout
+- Support: Support Node.js v14
+- Support: Update libs
+
+## v4.0.11
+
+- Fix: Fab on search result page does not displayed
+- Fix: Adjust margin/padding for search result page
+- Fix: PageAlert broken (Introduced by v4.0.9)
+
+## v4.0.10
+
+- Improvement: Adjust ToC height
+- Fix: Fail to rename/delete a page set as "Anyone with the link"
+
+## v4.0.9
+
+- Feature: Detailed configurations for OpenID Connect
+- Improvement: Navigations
+- Improvement: Sticky admin navigation
+- Fix: Reseting password doesn't work
+- Fix: Styles for printing
+- Fix: Unable to create page with original path after emptying trash
+- I18n: Support zh-CN
+
+## v4.0.8 (Discontinued)
+
+## v4.0.7
+
+- Feature: Set request timeout for Elasticsearch with env var `ELASTICSEARCH_REQUEST_TIMEOUT`
+- Improvement: Apply styles faster on booting client
+- Fix: Styles are not applyed on installer
+- Fix: Remove last-resort `next()`
+- Fix: Enable/disable Notification settings couldn't change when either of the params is undefined
+- Fix: Text overflow
+
+## v4.0.6
+
+- Fix: Avatar images in Recent Changes are not shown
+- Fix: Full screen modal of Handsontable and Draw.io don't work
+- Fix: Shortcut for creating page respond with modifier key wrongly (Introduced by v4.0.5)
+
+## v4.0.5
+
+- Improvement: Return pre-defined session id when healthcheck
+- Improvement: Refactor caching for profile image
+- Improvement: Layout for global search help on mobile
+- Improvement: Layout for confidential notation
+- Fix: Shortcut for creating page doesn't work
+- Support: Dev in container
+- Support: Upgrade libs
+
+## v4.0.4
+
+- Feature: Drawer/Dock mode selector
+- Improvement: Admin pages navigation
+- Improvement: Ensure not to avoid session management even when accessing to healthcheck
+- Support: Refactor unstated utils
+- Support: Upgrade libs
+
+## v4.0.3
+
+- Feature: Copy page path dropdown with Append params switch
+- Improvement: Truncate overflowed user browsing history
+- Improvement: Tabs appearance on mobile
+- Improvement: Search help appearance on mobile
+- Improvement: Accessibility of login page
+- Fix: Editor was broken by long lines
+- Fix: Editor doesn't work on mobile
+- Fix: Word break in Recent Updated contents
+- Fix: navbar is broken on Safari
+
+## v4.0.2
+
+- Fix: Internal Server Error occurred when the guest user access to the pages that has likes
+- Fix: Some buttons are broken on Safari
+
+## v4.0.1
+
+- Improvement: Accessibility for Handsontable under dark mode
+- Improvement: Refactor '/pages.exist' API
+- Fix: Storing the state of sidebar
+- Fix: Comments order should be asc
+- Fix: Show/Hide replies button doesn't work
+- Fix: Tooltip doesn't work
+- Fix: Change the display of the scroll bar when modal is shown
+- Fix: Submit with enter key on Create/Rename modals
+- Fix: Show/Hide Unlink redirection button conditions
+- Fix: Link color in alerts
+- Support: Upgrade libs
+
+## v4.0.0
+
+### BREAKING CHANGES
+
+- Crowi Classic Behavior is removed
+- Crowi Classic Layout is removed
+- 'default-dark' theme is now merged as a dark mode variant of 'default' theme
+- 'blue-night' theme is now merged as a dark mode variant of 'mono-blue' theme
+
+Upgrading Guide: [https://docs.growi.org/en/admin-guide/upgrading/40x.html](https://docs.growi.org/en/admin-guide/upgrading/40x.html)
+
+### Updates
+
+- Feature: Sidebar
+- Feature: Recent changes on Sidebar
+- Feature: Switch Light/Dark Mode
+- Improvement: Migrate to Bootstrap 4
+- Improvement: Copy Page URL menu item to copy path dropdown
+- Improvement: Show contributors by Bootstrap Modal
+- Support: Upgrade libs
+
+## v3.8.1
+
+### BREAKING CHANGES
+
+- Now Elasticsearch requires the privilege `cluster:monitor/health` instead of `cluster:monitor/nodes/info`
+
+Upgrading Guide: [https://docs.growi.org/en/admin-guide/upgrading/38x.html](https://docs.growi.org/en/admin-guide/upgrading/38x.html)
+
+### Updates
+
+- Improvement: Change the health check method for Elasticsearch
+- Fix: Unset overflow-y style for Edit Tags Modal
+- Fix: Duplicate page source is overwrited (Introduced by 3.7.6)
+
+## v3.8.0  (Discontinued)
+
+## v3.7.7
+
+- Feature: Empty trash pages
+- Improvement: Behavior of Reconnect to Elasticsearch button
+- Fix: Duplicate page source is overwrited (Introduced by 3.7.6)
+
+## v3.7.6  (Discontinued)
+
+## v3.7.5
+
+- Fix: Draw.io diagrams rendered twice
+- Fix: Behavior of password reset modal is strange
+- Fix: Import GROWI Archive doesn't restore some data correctly
+- Fix: Attachments list on root page and users top pages
+- Fix: Trash page is no longer editable
+- Fix: Rendering Timeline on /trash
+
+## v3.7.4
+
+- Fix: Broken by displaying user image
+
+## v3.7.3
+
+- Feature: Profile Image Cropping
+- Improvement: Reactify users pages
+- Improvement: Detect language and adjust the order of first and last names when creating accounts in OAuth
+- Fix: Installation is broken when selecting Japanese (Introduced by 3.7.0)
+- Fix: Mathjax Rendering is unstable (workaround) (Introduced by 3.7.0)
+- Fix: Notification Setting couldn't update without slack token (Introduced by 3.6.6)
+- Support: Add GROWI Contributers
+
+## v3.7.2
+
+- Feature: User Management Filtering/Sort
+- Feature: Show env vars on Admin pages
+- Fix: Attachment row z-index
+- I18n: HackMD integration alert
+
+## v3.7.1
+
+- Improvement: Add an option that make it possible to choose what to send notifications
+- Improvement: Add the env var `DRAWIO_URI`
+- Improvement: Accessibility for 'spring' theme
+- Improvement: Editor scroll sync behaves strangely when using draw.io blocks
+- Fix: Coudn't upload file on Comment Editor (Introduced by 3.5.8)
+- I18n: HackMD integration
+
+## v3.7.0
+
+### BREAKING CHANGES
+
+None.
+
+Upgrading Guide: [https://docs.growi.org/en/admin-guide/upgrading/37x.html](https://docs.growi.org/en/admin-guide/upgrading/37x.html)
+
+### Updates
+
+- Feature: [Draw.io](https://www.draw.io/) Integration
+- Feature: SAML Attribute-based Login Control
+- Improvement: Reactify admin pages (Security)
+- Improvement: Behavior of pre-editing screen of HackMD when user needs to resume
+
+## v3.6.10
+
+- Fix: Redirect logic for users except for actives (Introduced by 3.6.9)
+
+## v3.6.9
+
+- Improvement: Redirection when login/logout
+- Improvement: Add home icon before '/'
+- Fix: Client crashed when the first login (Introduced by 3.6.8)
+
+## v3.6.8
+
+- Improvement: Show page history side-by-side
+- Improvement: Optimize markdown rendering
+- Improvement: Reactify admin pages (Navigation)
+- Fix: Reply comments collapsed are broken (Introduced by 3.6.7)
+- Support: Update libs
+
+## v3.6.7
+
+- Feature: Anchor link for comments
+- Improvement: Show error toastr when saving page is failed because of empty document
+- Fix: Admin Customise couldn't restore stored config value (Introduced by 3.6.2)
+- Fix: Admin Customise missed preview functions (Introduced by 3.6.2)
+- Fix: AWS doesn't work (Introduced by 3.6.4)
+- Fix: Ensure not to get unrelated indices information in Elasticsearch Management (Introduced by 3.6.6)
+- Support: Optimize bundles
+- Support: Optimize build-prod job with caching node_modules/.cache
+
+## v3.6.6
+
+- Feature: Reconnect to Elasticsearch from Full Text Search Management
+- Feature: Normalize indices of Elasticsearch from Full Text Search Management
+- Improvement: Add 'spring' theme
+- Improvement: Reactify admin pages (Notification)
+- Impromvement: Add `checkMiddlewaresStrictly` option to Healthcheck API
+- Improvement: Accessibility for History component under dark themes
+- Fix: Warning on client console when developing /admin/app
+- Support: Upgrade libs
+
+## v3.6.5 (Discontinued)
+
+## v3.6.4
+
+- Feature: Alert for stale page
+- Improvement: Reactify admin pages (Home)
+- Improvement: Reactify admin pages (App)
+- Improvement: Accessibility for editor icons of dark themes
+- Improvement: Accessibility for importing table data pane
+- Improvement: Resolve username and email when logging in with Google OAuth
+
+## v3.6.3
+
+- Improvement: Searching users in UserGroup Management
+- Fix: Repair google authentication by migrating to jaredhanson/passport-google-oauth2
+- Fix: Markdown Settings are broken by the button to import recommended settings
+- Support: Upgrade libs
+
+## v3.6.2
+
+- Improvement: Reactify admin pages (Customize)
+- Improvement: Ensure not to consider `[text|site](https://example.com]` as a row in the table
+- Improvement: Enter key behavior in markdown table
+- Fix: Pre-installed plugins in official docker image are not detected (Introduced by 3.6.0)
+- Fix: Emoji Autocomplete window does not float correctly (Introduced by 3.5.0)
+
+## v3.6.1
+
+### BREAKING CHANGES
+
+- GROWI v3.6.x no longer support Node.js v8.x
+- The name of database that is storing migrations meta data has been changed. This affects **only when `MONGO_URI` has parameters**. v3.5.x or above has a bug ([#1361](https://github.com/weseek/growi/issues/1361))
+
+Upgrading Guide: [https://docs.growi.org/en/admin-guide/upgrading/36x.html](https://docs.growi.org/en/admin-guide/upgrading/36x.html)
+
+### Updates
+
+- Improvement: Drop unnecessary MongoDB collection indexes
+- Improvement: Accessibility of Antarctic theme
+- Improvement: Reactify admin pages (Markdown Settings)
+- Fix: Appending tag is failed by wrong index of PageTagRelation (Introduced by 3.5.20)
+- Fix: Pages without heading slash is invalid but creatable
+- Fix: Connect to Elasticsearch with `httpAuth` param
+- Support: Support Node.js v12
+- Support: Optimize build in dev with hard-source-webpack-plugin
+- Support: Upgrade libs
+
+## v3.6.0 (Discontinued)
+
+## v3.5.25
+
+- Improvement: Disable ESC key to close Handsontable Modal
+- Fix: Exported data of empty collection is broken
+- Fix: Some components crash after when the page with attachment has exported/imported
+
+## v3.5.24
+
+- Fix: Plugins are not working on Heroku
+
+## v3.5.23
+
+- Fix: Global Notification failed to send e-mail
+- Fix: Pagination is not working for trash list
+- Fix: Healthcheck API with `?connectToMiddlewares` returns error
+- Support: Upgrade libs
+
+## v3.5.22
+
+- Improvement: Add `FILE_UPLOAD_DISABLED` env var
+
+## v3.5.21
+
+- Improvement: Cache control when retrieving attachment data
+- Fix: Inviting user doesn't work (Introduced by 3.5.20)
+
+## v3.5.20
+
+- Improvement: Organize MongoDB collection indexes uniqueness
+- Improvement: Reactify admin pages (External Account Management)
+- Fix: Search result or Timeline shows loading icon eternally when retrieving not accessible page
+- Support: Use SearchBox Elasticsearch Addon on Heroku
+- Support: Upgrade libs
+
+## v3.5.19 (Discontinued)
+
+## v3.5.18
+
+- Improvement: Import GROWI Archive
+- Improvement: Optimize handling promise of stream when exporting archive
+- Improvement: Optimize handling promise of stream when building indices
+- Improvement: Add link to [docs.growi.org](https://docs.growi.org)
+- Fix: Monospace font code is broken when printing on Mac
+
+## v3.5.17
+
+- Feature: Upload to GCS (Google Cloud Storage)
+- Feature: Statistics API
+- Improvement: Optimize exporting
+- Improvement: Show progress bar when exporting
+- Improvement: Validate collection combinations when importing
+- Improvement: Reactify admin pages
+- Fix: Use HTTP PlantUML URL in default (Introduced by 3.5.12)
+- Fix: Config default values
+- Support: REPL with `console` npm scripts
+
+## v3.5.16
+
+- Fix: Full Text Search doesn't work after when building indices (Introduced by 3.5.12)
+
+## v3.5.15
+
+- Feature: Import/Export Page data
+- Fix: The link to Sandbox on Markdown Help Modal doesn't work
+- Support: Upgrade libs
+
+## v3.5.14 (Discontinued)
+
+## v3.5.13
+
+- Feature: Re-edit comments
+- Support: [growi-plugin-attachment-refs](https://github.com/weseek/growi-plugin-attachment-refs)
+- Support: Upgrade libs
+
+## v3.5.12
+
+- Improvement: Use Elasticsearch Alias
+- Improvement: Connect to HTTPS PlantUML URL in default
+- Fix: Global Notification doesn't work after updating Webhook URL
+- Fix: User Trigger Notification is not be sent when channel is not specified
+- Support: Upgrade libs
+
+## v3.5.11
+
+- Fix: HackMD Editor shows 404 error when HackMD redirect to fqdn URI (Introduced by 3.5.8)
+- Fix: Timeline doesn't work (Introduced by 3.5.1)
+- Fix: Last Login field does not shown in /admin/user
+- Support: Upgrade libs
+
+## v3.5.10
+
+- Feature: Send Global Notification with Slack
+- Improvement: Show loading spinner when fetching page history data
+- Improvement: Hierarchical page link when the page is in /Trash
+- Fix: Code Highlight Theme does not change (Introduced by 3.5.2)
+- Support: Upgrade libs
+
+## v3.5.9
+
+- Fix: Editing table with Spreadsheet like GUI (Handsontable) is failed
+- Fix: Plugins are not initialized when first launching (Introduced by 3.5.0)
+- Support: Upgrade libs
+
+## v3.5.8
+
+- Improvement: Controls when HackMD/CodiMD has unsaved draft
+- Improvement: Show hints if HackMD/CodiMD integration is not working
+- Improvement: GROWI server obtains HackMD/CodiMD page id from the 302 response header
+- Improvement: Comment Thread Layout
+- Improvement: Show commented date with date distance format
+
+## v3.5.7 (Discontinued)
+
+## v3.5.6
+
+- Fix: Saving new page is failed when empty string tag is set
+- Fix: Link of Create template page button in New Page Modal is broken
+- Fix: Global Notification dows not work when creating/moving/deleting/like/comment
+
+## v3.5.5
+
+- Feature: Support S3-compatible object storage (e.g. MinIO)
+- Feature: Enable/Disable ID/Password Authentication
+- Improvement: Login Mechanism with HTTP Basic Authentication header
+- Improvement: Reactify Table Of Contents
+- Fix: Profile images are broken in User Management
+- Fix: Template page under root page doesn't work
+- Support: Upgrade libs
+
+## v3.5.4
+
+- Fix: List private pages wrongly
+- Fix: Global Notification Trigger Path does not parse glob correctly
+- Fix: Consecutive page deletion requests cause unexpected complete page deletion
+
+## v3.5.3
+
+- Improvement: Calculate string width when save with Spreadsheet like GUI (Handsontable)
+- Fix: Search Result Page doesn't work
+- Fix: Create/Update page API returns data includes author's password hash
+- Fix: Dropdown to copy page path/URL/MarkdownLink shows under CodeMirror vscrollbar
+- Fix: Link to /trash in Dropdown menu
+
+## v3.5.2
+
+- Feature: Remain metadata option when Move/Rename page
+- Improvement: Support code highlight for Swift and Kotlin
+- Fix: Couldn't restrict page with user group permission
+- Fix: Couldn't duplicate a page when it restricted by a user group permission
+- Fix: Consider timezone on admin page
+- Fix: Editor doesn't work on Microsoft Edge
+- Support: Upgrade libs
+
+## v3.5.1
+
+### BREAKING CHANGES
+
+- GROWI no longer supports Protection system with Basic Authentication
+- GROWI no longer supports Crowi Classic Authentication Mechanism
+- GROWI no lonnger supports plugins with schema version 2
+- The restriction mode of the root page (`/`) will be set 'Public'
+- The restriction mode of the root page (`/`) can not be changed after v 3.5.1
+
+Upgrading Guide: [https://docs.growi.org/en/admin-guide/upgrading/35x.html](https://docs.growi.org/en/admin-guide/upgrading/35x.html)
+
+### Updates
+
+- Feature: Comment Thread
+- Feature: OpenID Connect authentication
+- Feature: HTTP Basic authentication
+- Feature: Staff Credits with [Konami Code](https://en.wikipedia.org/wiki/Konami_Code)
+- Feature: Restricte Complete Deletion of Pages
+- Improvement Draft list
+- Fix: Deleting page completely
+- Fix: Search with `prefix:` param with CJK pathname
+- Fix: Could not edit UserGroup even if `PUBLIC_WIKI_ONLY` is not set
+- I18n: User Management Details
+- I18n: Group Management Details
+- Support: Apply unstated
+- Support: Use Babel 7
+- Support: Support plugins with schema version 3
+- Support: Abolish Old Config API
+- Support: Apply Jest for Tests
+- Support: Upgrade libs
+
+## v3.5.0 (Discontinued)
+
+## v3.4.7
+
+- Improvement: Handle private pages on group deletion
+- Fix: Searching with `tag:xxx` syntax doesn't work
+- Fix: Check CSRF when updating user data
+- Fix: `createdAt` field initialization
+- I18n: Import data page
+- I18n: Group Management page
+
+## v3.4.6
+
+- Feature: Tags
+- Feature: Dropdown to copy page path/URL/MarkdownLink
+- Feature: List of drafts
+- Improvement: Replace icons of Editor Tool Bar
+- Improvement: Show display name when mouse hover to user image
+- Fix: URL in slack message is broken on Safari
+- Fix: Registration does not work when basic auth is enabled
+- Support: Publish API docs with swagger-jsdoc and ReDoc
+- Support: Upgrade libs
+
+## v3.4.5
+
+- Improvement: Pass autolink through the XSS filter according to CommonMark Spec
+- Fix: Update ElasticSearch index when deleting/duplicating pages
+- Fix: Xss filter breaks PlantUML arrows
+- Support: Support growi-plugin-lsx@2.2.0
+- Support: Upgrade libs
+
+## v3.4.4
+
+- Fix: Comment component doesn't work
+
+## v3.4.3
+
+- Improvement: Add 'antarctic' theme
+- Support Apply eslint-config-airbnb based rules
+- Support Apply prettier and stylelint
+- Support: Upgrade libs
+
+## v3.4.2
+
+- Fix: Nofitication to Slack doesn't work (Introduced by 3.4.0)
+
+## v3.4.1
+
+- Fix: "Cannot find module 'stream-to-promise'" occured when build client with `FILE_UPLOAD=local`
+
+## v3.4.0
+
+### BREAKING CHANGES
+
+None.
+
+Upgrading Guide: [https://docs.growi.org/en/admin-guide/upgrading/34x.html](https://docs.growi.org/en/admin-guide/upgrading/34x.html)
+
+### Updates
+
+- Improvement: Restrict to access attachments when the user is not allowed to see page
+- Improvement: Show fans and visitors of page
+- Improvement: Full text search tokenizing
+- Improvement: Markdown comment on Crowi Classic Layout
+- Fix: Profile image is not displayed when `FILE_UPLOAD=mongodb`
+- Fix: Posting comment doesn't work under Crowi Classic Layout (Introduced by 3.1.5)
+- Fix: HackMD doesn't work when `siteUrl` ends with slash
+- Fix: Ensure not to be able to move/duplicate page to the path which has trailing slash
+- Support: Launch with Node.js v10
+- Support: Launch with MongoDB 3.6
+- Support: Launch with Elasticsearch 6.6
+- Support: Upgrade libs
+
+## v3.3.10
+
+- Feature: PlantUML and Blockdiag on presentation
+- Improvement: Render slides of presentation with GrowiRenderer
+- Fix: Unportalizing doesn't work
+- Support: Use mini-css-extract-plugin instead of extract extract-text-webpack-plugin
+- Support: Use terser-webpack-plugin instead of uglifyjs-webpack-plugin
+- Support: Upgrade libs
+
+## v3.3.9
+
+- Fix: Import from Qiita:Team doesn't work (Introduced by 3.3.0)
+- Fix: Typeahead shows autocomplete wrongly (Introduced by 3.3.8)
+- Support: Upgrade libs
+
+## v3.3.8
+
+- Fix: Move/Duplicate don't work (Introduced by 3.3.7)
+- Fix: Server doesn't respond when root page is restricted
+- Support: Upgrade libs
+
+## v3.3.7
+
+- Feature: Editor toolbar
+- Feature: `prefix:/path` searching syntax to filter with page path prefix
+- Feature: Add an option to filter only children to searching box of navbar
+- Improvement: Suggest page path when moving/duplicating/searching
+- Fix: Anonymous users couldn't search (Introduced by 3.3.6)
+- I18n: Searching help
+- Support: Prepare to suppoert Node.js v10
+- Support: Upgrade libs
+
+## v3.3.6
+
+- Improvement: Site URL settings must be set
+- Improvement: Site URL settings can be set with environment variable
+- Fix: "Anyone with the link" ACL doesn't work correctly (Introduced by 3.3.0)
+- Fix: Related pages list of /admin/user-group-detail/xxx doesn't show anything (Introduced by 3.3.0)
+- Fix: Diff of revision contents doesn't appeared when notifing with slack
+- Fix: NPE occured on /admin/security when Crowi Classic Auth Mechanism is set
+- Fix: Coudn't render Timing Diagram with PlantUML
+- I18n: Cheatsheet for editor
+- I18n: Some admin pages
+- Support: Upgrade libs
+
+## v3.3.5 (Discontinued)
+
+## v3.3.4
+
+- Improvement: SAML configuration with environment variables
+- Improvement: Upload file with pasting from clipboard
+- Fix: `/_api/revisions.get` doesn't populate author data correctly
+- Fix: Wrong OAuth callback url are shown at admin page
+- Fix: Connecting to MongoDB failed when processing migration
+- Support: Get ready to use new config management system
+
+## v3.3.3
+
+- Feature: Show line numbers to a code block
+- Feature: Bulk update the scope of descendant pages when create/update page
+- Improvement: The scope of ascendant page will be retrieved and set to controls in advance when creating a new page
+- Fix: Pages that is restricted by groups couldn't be shown in search result page
+- Fix: Pages order in search result page was wrong
+- Fix: Guest user can't search
+- Fix: Possibility that ExternalAccount deletion processing selects incorrect data
+- Support: Upgrade libs
+
+## v3.3.2
+
+- Fix: Specified Group ACL is not persisted correctly (Introduced by 3.3.0)
+
+## v3.3.1
+
+- Feature: NO_CDN Mode
+- Feature: Add option to show/hide restricted pages in list
+- Feature: MongoDB GridFS quota
+- Improvement: Refactor Access Control
+- Improvement: Checkbox behavior of task list
+- Improvement: Fixed search input on search result page
+- Improvement: Add 'christmas' theme
+- Improvement: Select default language of new users
+- Fix: Hide restricted pages contents in timeline
+- Support: Upgrade libs
+
+## v3.3.0 (Discontinued)
+
+## v3.2.10
+
+- Fix: Pages in trash are available to create
+- Fix: Couldn't create portal page under Crowi Classic Behavior
+- Fix: Table tag in Timeline/SearchResult missed border and BS3 styles
+- I18n: Installer
+
+## v3.2.9
+
+- Feature: Attachment Storing to MongoDB GridFS
+- Fix: row/col moving of Spreadsheet like GUI (Handsontable) doesn't work
+- Fix: Emoji AutoComplete dialog pops up at wrong position
+- Support: Upgrade libs
+
+## v3.2.8
+
+- Improvement: Add an option to use email for account link when using SAML federation
+- Fix: Editor layout is sometimes broken
+- Fix: Normalize table data for Spreadsheet like GUI (Handsontable) when import
+- Support: Improve development environment
+- Support: Upgrade libs
+
+## v3.2.7
+
+- Feature: Import CSV/TSV/HTML table on Spreadsheet like GUI (Handsontable)
+- Fix: Pasting table data copied from Excel includes unnecessary line breaks
+- Fix: Page break Preset 1 for Presentation mode is broken
+- Fix: Login Form when LDAP login failed caused 500 Internal Server Error
+
+## v3.2.6
+
+- Feature: Add select alignment buttons of Spreadsheet like GUI (Handsontable)
+- Improvement: Shrink the rows that have no diff of revision history page
+- Fix: Login form rejects weak password
+- Fix: An error occured by uploading attachment file when the page is not exists (Introduced by 2.3.5)
+- Support: Upgrade libs
+
+## v3.2.5
+
+- Improvement: Expandable Spreadsheet like GUI (Handsontable)
+- Improvement: Move/Resize rows/columns of Spreadsheet like GUI (Handsontable)
+- Improvement: Prevent XSS of New Page modal
+- Fix: Recent Created tab of user home shows wrong page list (Introduced by 3.2.4)
+- Support: Upgrade libs
+
+## v3.2.4
+
+- Feature: Edit table with Spreadsheet like GUI (Handsontable)
+- Feature: Paging recent created in users home
+- Improvement: Specify certificate for SAML Authentication
+- Fix: SAML Authentication didn't work (Introduced by 3.2.2)
+- Fix: Failed to create new page with title which includes RegEx special characters
+- Fix: Preventing XSS Settings are not applied in default (Introduced by 3.1.12)
+- Support: Mongoose migration mechanism
+- Support: Upgrade libs
+
+## v3.2.3
+
+- Feature: Kibela like layout
+- Improvement: Custom newpage separator for presentation view
+- Support: Shrink image size for themes which recently added
+
+## v3.2.2
+
+- Feature: SAML Authentication (SSO)
+- Improvement: Add 'wood' theme
+- Improvement: Add 'halloween' theme
+- Improvement: Add 'island' theme
+- Fix: Sending email function doesn't work
+- Support Upgrade libs
+
+## v3.2.1
+
+- Feature: Import data from esa.io
+- Feature: Import data from Qiita:Team
+- Feature: Add the endpoint for health check
+- Improvement: Adjust styles when printing
+- Fix: Renaming page doesn't work if the page was saved with shortcut
+- Support: Refactor directory structure
+- Support Upgrade libs
+
+## v3.2.0
+
+- Feature: HackMD integration so that user will be able to simultaneously edit with multiple people
+- Feature: Login with Twitter Account (OAuth)
+- Fix: The Initial scroll position is wrong when reloading the page
+
+## v3.1.14
+
+- Improvement: Show help for header search box
+- Improvement: Add Markdown Cheatsheet to Editor component
+- Fix: Couldn't delete page completely from search result page
+- Fix: Tabs of trash page are broken
+
+## v3.1.13
+
+- Feature: Global Notification
+- Feature: Send Global Notification with E-mail
+- Improvement: Add attribute mappings for email to LDAP settings
+- Support: Upgrade libs
+
+## v3.1.12
+
+- Feature: Add XSS Settings
+- Feature: Notify to Slack when comment
+- Improvement: Prevent XSS in various situations
+- Improvement: Show forbidden message when the user accesses to ungranted page
+- Improvement: Add overlay styles for pasting file to comment form
+- Fix: Omit unnecessary css link (Introduced by 3.1.10)
+- Fix: Invitation mail do not be sent
+- Fix: Edit template button on New Page modal doesn't work
+
+## v3.1.11
+
+- Fix: OAuth doesn't work in production because callback URL field cannot be specified (Introduced by 3.1.9)
+
+## v3.1.10
+
+- Fix: Enter key on react-bootstrap-typeahead doesn't submit (Introduced by 3.1.9)
+- Fix: CodeMirror of `/admin/customize` is broken (Introduced by 3.1.9)
+
+## v3.1.9
+
+- Feature: Login with Google Account (OAuth)
+- Feature: Login with GitHub Account (OAuth)
+- Feature: Attach files in Comment
+- Improvement: Write comment with CodeMirror Editor
+- Improvement: Post comment with `Ctrl-Enter`
+- Improvement: Place the commented page at the beginning of the list
+- Improvement: Resolve errors on IE11 (Experimental)
+- Support: Migrate to webpack 4
+- Support: Upgrade libs
+
+## v3.1.8 (Discontinued)
+
+## v3.1.7
+
+- Fix: Update hidden input 'pageForm[grant]' when save with `Ctrl-S`
+- Fix: Show alert message when conflict
+- Fix: `BLOCKDIAG_URI` environment variable doesn't work
+- Fix: Paste in markdown list doesn't work correctly
+- Support: Ensure to inject logger configuration from environment variables
+- Support: Upgrade libs
+
+## v3.1.6
+
+- Feature: Support [blockdiag](http://blockdiag.com)
+- Feature: Add `BLOCKDIAG_URI` environment variable
+- Fix: Select modal for group is not shown
+- Support: Upgrade libs
+
+## v3.1.5
+
+- Feature: Write comment with Markdown
+- Improvement: Support some placeholders for template page
+- Improvement: Omit unnecessary response header
+- Improvement: Support LDAP attribute mappings for user's full name
+- Improvement: Enable to scroll revision-toc
+- Fix: Posting to Slack doesn't work (Introduced by 3.1.0)
+- Fix: page.rename api doesn't work
+- Fix: HTML escaped characters in markdown are unescaped unexpectedly after page is saved
+- Fix: sanitize `#raw-text-original` content with 'entities'
+- Fix: Double newline character posted (Introduced by 3.1.4)
+- Fix: List and Comment components do not displayed (Introduced by 3.1.4)
+- Support: Upgrade libs
+
+## v3.1.4 (Discontinued)
+
+## v3.1.3 (Discontinued)
+
+## v3.1.2
+
+- Feature: Template page
+- Improvement: Add 'future' theme
+- Improvement: Modify syntax for Crowi compatible template feature
+- Improvement: Escape iframe tag in block codes
+- Support: Upgrade libs
+
+## v3.1.1
+
+- Improvement: Add 'blue-night' theme
+- Improvement: List up pages which restricted for Group ACL
+- Fix: PageGroupRelation didn't remove when page is removed completely
+
+## v3.1.0
+
+- Improvement: Group Access Control List - Select group modal
+- Improvement: Better input on mobile
+- Improvement: Detach code blocks correctly
+- Improvement: Auto-format markdown table which includes multibyte text
+- Improvement: Show icon when auto-format markdown table is activated
+- Improvement: Enable to switch show/hide border for highlight.js
+- Improvement: BindDN field allows also ActiveDirectory styles
+- Improvement: Show LDAP logs when testing login
+- Fix: Comment body doesn't break long terms
+- Fix: lsx plugin lists up pages that hit by forward match wrongly (Introduced by 3.0.4)
+- Fix: Editor is broken on IE11
+- Support: Multilingualize React components with i18next
+- Support: Organize dependencies
+- Support: Upgrade libs
+
+## v3.0.13
+
+- Improvement: Add Vim/Emacs/Sublime-Text icons for keybindings menu
+- Improvement: Add 'mono-blue' theme
+- Fix: Unportalize process failed silently
+- Fix: Sidebar breaks editor layouts
+- Support: Switch the logger from 'pino' to 'bunyan'
+- Support: Set the alias for 'debug' to the debug function of 'bunyan'
+- Support: Translate `/admin/security`
+- Support: Optimize bundles
+- Support: Optimize .eslintrc.js
+
+## v3.0.12
+
+- Feature: Support Vim/Emacs/Sublime-Text keybindings
+- Improvement: Add some CodeMirror themes (Eclipse, Dracula)
+- Improvement: Dynamic loading for CodeMirror theme files from CDN
+- Improvement: Prevent XSS when move/redirect/duplicate
+
+## v3.0.11
+
+- Fix: login.html is broken in iOS
+- Fix: Removing attachment is crashed
+- Fix: File-attaching error after new page creation
+- Support: Optimize development build
+- Support: Upgrade libs
+
+## v3.0.10
+
+- Improvement: Add 'nature' theme
+- Fix: Page list and Timeline layout for layout-growi
+- Fix: Adjust theme colors (Introduced by 3.0.9)
+
+## v3.0.9
+
+- Fix: Registering new LDAP User is failed (Introduced by 3.0.6)
+- Support: Organize scss for overriding bootstrap variables
+- Support: Upgrade libs
+
+## v3.0.8
+
+- Improvement: h1#revision-path occupies most of the screen when the page path is long
+- Improvement: Ensure not to save concealed email field to localStorage
+- Fix: Cannot input "c" and "e" on iOS
+
+## v3.0.7
+
+- Improvement: Enable to download an attached file with original name
+- Improvement: Use MongoDB for session store instead of Redis
+- Improvement: Update dropzone overlay icons and styles
+- Fix: Dropzone overlay elements doesn't show (Introduced by 3.0.0)
+- Fix: Broken page path of timeline (Introduced by 3.0.4)
+
+## v3.0.6
+
+- Improvement: Automatically bind external accounts newly logged in to local accounts when username match
+- Improvement: Simplify configuration for Slack Web API
+- Support: Use 'slack-node' instead of '@slack/client'
+- Support: Upgrade libs
+
+## v3.0.5
+
+- Improvement: Update lsx icons and styles
+- Fix: lsx plugins doesn't show page names
+
+## v3.0.4
+
+- Improvement: The option that switch whether add h1 section when create new page
+- Improvement: Encode page path that includes special character
+- Fix: Page-saving error after new page creation
+
+## v3.0.3
+
+- Fix: Login page is broken in iOS
+- Fix: Hide presentation tab if portal page
+- Fix: A few checkboxes doesn't work
+- Fix: Activating invited user form url is wrong
+- Support: Use postcss-loader and autoprefixer
+
+## v3.0.2
+
+- Feature: Group Access Control List
+- Feature: Add site theme selector
+- Feature: Add a control to switch whether email shown or hidden by user
+- Feature: Custom title tag content
+- Fix: bosai version
+- Support: Rename to GROWI
+- Support: Add dark theme
+- Support: Refreshing bootstrap theme and icons
+- Support: Use Browsersync instead of easy-livereload
+- Support: Upgrade libs
+
+## v3.0.1 (Discontinued)
+
+## v3.0.0 (Discontinued)
+
+## v2.4.4
+
+- Feature: Autoformat Markdown Table
+- Feature: highlight.js Theme Selector
+- Fix: The bug of updating numbering list by codemirror
+- Fix: Template LangProcessor doesn't work (Introduced by 2.4.0)
+- Support: Apply ESLint
+- Support: Upgrade libs
+
+## v2.4.3
+
+- Improvement: i18n in `/admin`
+- Improvement: Add `SESSION_NAME` environment variable
+- Fix: All Elements are cleared when the Check All button in DeletionMode
+- Support: Upgrade libs
+
+## v2.4.2
+
+- Improvement: Ensure to set absolute url from root when attaching files when `FILE_UPLOAD=local`
+- Fix: Inline code blocks that includes doller sign are broken
+- Fix: Comment count is not updated when a comment of the page is deleted
+- Improvement: i18n in `/admin` (WIP)
+- Support: Upgrade libs
+
+## v2.4.1
+
+- Feature: Custom Header HTML
+- Improvement: Add highlight.js languages
+- Fix: Couldn't connect to PLANTUML_URI (Introduced by 2.4.0)
+- Fix: Couldn't render UML which includes CJK (Introduced by 2.4.0)
+- Support: Upgrade libs
+
+## v2.4.0
+
+- Feature: Support Footnotes
+- Feature: Support Task lists
+- Feature: Support Table with CSV
+- Feature: Enable to render UML diagrams with public plantuml.com server
+- Feature: Enable to switch whether rendering MathJax in realtime or not
+- Improvement: Replace markdown parser with markdown-it
+- Improvement: Generate anchor of headers with header strings
+- Improvement: Enhanced Scroll Sync on Markdown Editor/Preview
+- Improvement: Update `#revision-body` tab contents after saving with `Ctrl-S`
+- Fix: 500 Internal Server Error occures when basic-auth configuration is set
+
+## v2.3.9
+
+- Fix: `Ctrl-/` doesn't work on Chrome
+- Fix: Close Shortcuts help with `Ctrl-/`, ESC key
+- Fix: Jump to last line wrongly when `.revision-head-edit-button` clicked
+- Support: Upgrade libs
+
+## v2.3.8
+
+- Feature: Suggest page path when creating pages
+- Improvement: Prevent keyboard shortcuts when modal is opened
+- Improvement: PageHistory UI
+- Improvement: Ensure to scroll when edit button of section clicked
+- Improvement: Enabled to toggle the style for active line
+- Support: Upgrade libs
+
+## v2.3.7
+
+- Fix: Open popups when `Ctrl+C` pressed (Introduced by 2.3.5)
+
+## v2.3.6
+
+- Feature: Theme Selector for Editor
+- Improvement: Remove unportalize button from crowi-plus layout
+- Fix: CSS for admin pages
+- Support: Shrink the size of libraries to include
+
+## v2.3.5
+
+- Feature: Enhanced Editor by CodeMirror
+- Feature: Emoji AutoComplete
+- Feature: Add keyboard shortcuts
+- Improvement: Attaching file with Dropzone.js
+- Improvement: Show shortcuts help with `Ctrl-/`
+- Fix: DOMs that has `.alert-info` class don't be displayed
+- Support: Switch and upgrade libs
+
+## v2.3.4 (Discontinued)
+
+## v2.3.3
+
+- Fix: The XSS Library escapes inline code blocks
+- Fix: NPE occurs on Elasticsearch when initial access
+- Fix: Couldn't invite users(failed to create)
+
+## v2.3.2
+
+- Improvement: Add LDAP group search options
+
+## v2.3.1
+
+- Fix: Blockquote doesn't work
+- Fix: Couldn't create user with first LDAP logging in
+
+## v2.3.0
+
+- Feature: LDAP Authentication
+- Improvement: Prevent XSS
+- Fix: node versions couldn't be shown
+- Support: Upgrade libs
+
+## v2.2.4
+
+- Fix: googleapis v23.0.0 lost the function `oauth2Client.setCredentials`
+- Fix: HeaderSearchBox didn't append 'q=' param when searching
+
+## v2.2.3
+
+- Fix: The server responds anything when using passport
+- Fix: Update `lastLoginAt` when login is success
+- Support: Replace moment with date-fns
+- Support: Upgrade react-bootstrap-typeahead
+- Improvement: Replace emojify.js with emojione
+
+## v2.2.2 (Discontinued)
+
+## v2.2.1
+
+- Feature: Duplicate page
+- Improve: Ensure that admin users can remove users waiting for approval
+- Fix: Modal doesn't work with React v16
+- Support: Upgrade React to 16
+- Support: Upgrade outdated libs
+
+## v2.2.0
+
+- Support: Merge official Crowi v1.6.3
+
+## v2.1.2
+
+- Improvement: Ensure to prevent suspending own account
+- Fix: Ensure to be able to use `.` for username when invited
+- Fix: monospace font for `code` tag
+
+## v2.1.1
+
+- Fix: The problem that React Modal doesn't work
+- Support: Lock some packages(react, react-dom, mongoose)
+
+## v2.1.0
+
+- Feature: Adopt Passport the authentication middleware
+- Feature: Selective batch deletion in search result page
+- Improvement: Ensure to be able to login with both of username or email
+- Fix: The problem that couldn't update user data in /me
+- Support: Upgrade outdated libs
+
+## v2.0.9
+
+- Fix: Server is down when a guest user accesses to someone's private pages
+- Support: Merge official Crowi (master branch)
+- Support: Upgrade outdated libs
+
+## v2.0.8
+
+- Fix: The problem that path including round bracket makes something bad
+- Fix: Recursively option processes also unexpedted pages
+- Fix: en_US translation
+
+## v2.0.7
+
+- Improvement: Add recursively option for Delete/Move/Putback operation
+- Improvement: Comment layout and sort order (crowi-plus Enhanced Layout)
+
+## v2.0.6
+
+- Fix: check whether `$APP_DIR/public/uploads` exists before creating symlink
+
+## v2.0.5
+
+- Improvement: Adjust styles for CodeMirror
+- Fix: File upload does not work when using crowi-plus-docker-compose and `FILE_UPLOAD=local` is set
+
+## v2.0.2 - 2.0.4 (Discontinued)
+
+## v2.0.1
+
+- Feature: Custom Script
+- Improvement: Adjust layout and styles for admin pages
+- Improvement: Record and show last updated date in user list page
+- Fix: Ignore Ctrl+(Shift+)Tab when editing (cherry-pick from the official)
+
+## v2.0.0
+
+- Feature: Enabled to integrate with Slack using Incoming Webhooks
+- Support: Upgrade all outdated libs
+
+## v1.2.16
+
+- Improvement: Condition for creating portal
+- Fix: Couldn't create new page after installation cleanly
+
+## v1.2.15
+
+- Improvement: Optimize cache settings for express server
+- Improvement: Add a logo link to the affix header
+- Fix: Child pages under `/trash` are not shown when applying crowi-plus Simplified Behavior
+
+## v1.2.14
+
+- Fix: Tabs(`a[data-toggle=tab][href=#...]`) push browser history twice
+- Fix: `a[href=#edit-form]` still save history even when disabling pushing states option
+
+## v1.2.13
+
+- Improvement: Enabled to switch whether to push states with History API when tabs changes
+- Fix: Layout of the Not Found page
+
+## v1.2.12 (Discontinued)
+
+## v1.2.11
+
+- Improvement: Enabled to open editing form from affix header
+- Improvement: Enabled to open editing form from each section headers
+
+## v1.2.10
+
+- Fix: Revise `server:prod:container` script for backward compatibility
+
+## v1.2.9
+
+- Improvement: Enabled to save with <kbd>⌘+S</kbd> on Mac
+- Improvement: Adopt the fastest logger 'pino'
+- Fix: The problem that can't upload profile image
+
+## v1.2.8
+
+- Fix: The problem that redirect doesn't work when using 'crowi-plus Simplified Behavior'
+
+## v1.2.7 (Discontinued)
+
+## v1.2.6
+
+- Fix: The problem that page_list widget doesn't show the picture of revision.author
+- Fix: Change implementation of Bootstrap3 toggle switch for admin pages
+
+## v1.2.5
+
+- Feature: crowi-plus Simplified Behavior
+- Improvement: Ensure to be able to disable Timeline feature
+
+## v1.2.4
+
+- Fix: Internal Server Error has occurred when a guest user visited the page someone added "liked"
+
+## v1.2.3
+
+- Improvement: Ensure to be able to use Presentation Mode even when not logged in
+- Improvement: Presentation Mode on IE11 (Experimental)
+- Fix: Broken Presentation Mode
+
+## v1.2.2
+
+- Support: Merge official Crowi (master branch)
+
+## v1.2.1
+
+- Fix: buildIndex error occured when access to installer
+
+## v1.2.0
+
+- Support: Merge official Crowi v1.6.2
+
+## v1.1.12
+
+- Feature: Remove Comment Button
+
+## v1.1.11
+
+- Fix: Omit Comment form from page_list (crowi-plus Enhanced Layout)
+- Fix: .search-box is broken on sm/xs screen
+
+## v1.1.10
+
+- Fix: .search-box is broken on sm/xs screen
+- Support: Browsable with IE11 (Experimental)
+
+## v1.1.9
+
+- Improvement: Ensure to generate indices of Elasticsearch when installed
+- Fix: Specify the version of Bonsai Elasticsearch on Heroku
+
+## v1.1.8
+
+- Fix: Depth of dropdown-menu when `.on-edit`
+- Fix: Error occured on saveing with `Ctrl-S`
+- Fix: Guest users browsing
+
+## v1.1.7
+
+- Feature: Add option to allow guest users to browse
+- Fix: crowi-plus Enhanced Layout
+
+## v1.1.6
+
+- Fix: crowi-plus Enhanced Layout
+
+## v1.1.5
+
+- Fix: crowi-plus Enhanced Layout
+- Support: Merge official Crowi v1.6.1 master branch [573144b]
+
+## v1.1.4
+
+- Feature: Ensure to select layout type from Admin Page
+- Feature: Add crowi-plus Enhanced Layout
+
+## v1.1.3
+
+- Improvement: Use POSIX-style paths (bollowed crowi/crowi#219 by @Tomasom)
+
+## v1.1.2
+
+- Imprv: Brushup fonts and styles
+- Fix: Ensure to specity revision id when saving with `Ctrl-S`
+
+## v1.1.1
+
+- Feature: Save with `Ctrl-S`
+- Imprv: Brushup fonts and styles
+
+## v1.1.0
+
+- Support: Merge official Crowi v1.6.1
+
+## v1.0.9
+
+- Feature: Delete user
+- Feature: Upload other than images
+
+## v1.0.8
+
+- Feature: Ensure to delete page completely
+- Feature: Ensure to delete redirect page
+- Fix: https access to Gravatar (this time for sure)
+
+## v1.0.7
+
+- Feature: Keyboard navigation for search box
+- Improvement: Intelligent Search
+
+## v1.0.6
+
+- Feature: Copy button that copies page path to clipboard
+- Fix: https access to Gravatar
+- Fix: server watching crash with `Error: read ECONNRESET` on Google Chrome
+
+## v1.0.5
+
+- Feature: Ensure to use Gravatar for profile image
+
+## v1.0.4
+
+- Improvement: Detach code blocks before preProcess
+- Support: Ensure to deploy to Heroku with INSTALL_PLUGINS env
+- Support: Ensure to load plugins easily when development
+
+## v1.0.3
+
+- Improvement: Adjust styles
+
+## v1.0.2
+
+- Improvement: For lsx
+
+## v1.0.1
+
+- Feature: Custom CSS
+- Support: Notify build failure to Slask
+
+## v1.0.0
+
+- Feature: Plugin mechanism
+- Feature: Switchable LineBreaks ON/OFF from admin page
+- Improvement: Exclude Environment-dependency
+- Improvement: Enhanced linker
+- Support: Add Dockerfile
+- Support: Abolish gulp
+- Support: LiveReload
+- Support: Update libs

+ 0 - 1951
CHANGES.md

@@ -1,1951 +0,0 @@
-# CHANGES
-
-## v4.3.0-RC
-
-* Support: Upgrade libs
-    * striptags
-
-### BREAKING CHANGES
-
-None.
-
-Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/43x.html>
-
-### Updates
-
-* Feature: New Slack Integration with Slack Bot
-    * Searching GROWI pages from Slack
-    * Creating GROWI pages from Slack
-        * Easy record conversations
-
-## v4.2.21
-
-* Improvement: Headers style on built-in editor
-* Improvement: Codemirror is now scrollable one editor height of empty space into view at the bottom of the editor
-* Improvement: Upgrade mongodb driver to fix [NODE-2784](https://jira.mongodb.org/browse/NODE-2784)
-* Support: Upgrade libs
-    * connect-mongo
-    * i18next
-    * migrate-mongo
-    * mongoose
-    * stream-to-promise
-    * validator
-    * ws
-    * nodemailer
-    * i18next-express-middleware
-    * growi-commons
-    * growi-plugin-attachment-refs
-    * growi-plugin-lsx
-
-## v4.2.20
-
-* Improvement: Error message when the password is too short
-* Improvement: Repeat XSS processing as a countermeasure against nesting 
-* Fix: NoSQL injection of access-token-parser
-* Fix: Checking permission when operating share links
-* Fix: Invalid NaN label is shown when deletedAt of the page is undefined
-    * Introduced by v4.2.8
-
-## v4.2.19
-
-* Feature: Set max-age of the user's cookie with the env var `SESSION_MAX_AGE`
-* Feature: Set max-age of the user's cookie in admin page
-* Improvement: Change the first accessing page after installation to the top page
-* Support: Upgrade libs
-    * string-width
-    * diff
-    * archiver
-
-## v4.2.18
-
-* Feature: Convertible page contents width
-* Fix: Group selector of User Group Delete Modal does not show all groups
-* Fix: Global notification to Slack does not encode spaces of page path
-* Support: Upgrade libs
-    * @google-cloud/storage
-
-## v4.2.17
-
-* Improvement: Invoke garbage collection when reindex all pages by elasticsearch
-* Improvement: Hide Sidebar at shared pages
-* Fix: No unsaved alert is displayed without difference the latest markdown and editor value
-* Support: Update libs
-    * eslint-config-weseek
-
-## v4.2.16
-
-* Fix: "Only inside the group" causes an error
-    * Introduced by v4.2.15
-
-## v4.2.15
-
-* Improvement: toastr location for editing
-* Improvement: Handsontable with static backdrop to prevent from closing when backdrop is clicked
-* Fix: Accept invalid page path like `..%2f`
-* Fix: Pages updated date is corrupted after recursive operation
-    * Introduced by v4.2.8
-* Support: Upgrade libs
-    * reactstrap
-
-
-## v4.2.14
-
-* Feature: Add an option to restrict publishing email property for new users
-* Improvement: Invite modal in admin page without email server settings
-* Improvement: Global notification settings in admin page without email server settings
-* Fix: Can create pages on the share route
-    * Introduced by v4.2.8
-* Fix: Pages restrected by group are excluded for recurrence operation
-    * Introduced by v4.2.8
-* Fix: Rename and duplicate to descendants path does not work correctly
-    * Introduced by v4.2.8
-* Support: Update libs
-    * bunyan
-    * browser-bunyan
-
-## v4.2.13
-
-* Feature: Detect indent size automatically
-* Fix: Some API responses includes email unintentionally
-* Fix: An error always displayed in admin pages
-
-## v4.2.12
-
-* Feature: Custom Sidebar
-* Fix: Set language correctly for draw.io (diagrams.net)
-
-## v4.2.11
-
-* Fix: Rename decendants is not working
-    * Introduced by v4.2.8
-
-
-## v4.2.10
-
-* Feature: Staff Credits for apps on GROWI.cloud
-* Improvement: Hackmd button behavior when disabled
-* Improvement: Layout of comparing revisions
-* Fix: Empty trash is not working
-
-## v4.2.9
-
-* Feature: Comparing revisions
-* Improvement: Memory consumption when re-indexing for full text searching
-* Improvement: Site URL settings valildation
-* Fix: Show comfirmation when transiting page without save
-* Fix: Save slack channels history when user trigger notification is invoked
-* Fix: The label of alerts for move/rename/delete are borken
-
-## v4.2.8
-
-* Improvement: Performance for pages to rename/duplicate/delete/revert pages
-* Fix: Preview scrollbar doesn't sync to editor
-    * Introduced by v4.2.6
-* Fix: Failed to save temporaryUrlCached with using gcs
-    * Introduced by v4.2.3
-* Fix: Fixed not being able to update ses settings
-    * Introduced by v4.2.0
-* Fix: Fixed the display of updtedAt and createdAt being reversed
-* Fix: Pass app title value through the XSS filter
-
-## v4.2.7
-
-* Fix: Installer doesn't work on Chrome
-
-## v4.2.6
-
-* Feature: Add a button to jump to Comments section
-* Feature: Paste Bootstrap4 Grid HTML with GUI
-* Feature: Disable auto formating table option
-* Improvement: Layout of Edit Link Modal
-* Improvement: Focus to the first input when modal is opened
-* Improvement: Preview layout in edit mode
-* Improvement: Install process under redundant environment
-* Improvement: Add contributors
-* Fix: Upgrading to v4.x failed when the user uses Kibela Layout
-    * Introduced by v4.2.0
-* Fix: diagrams.net (draw.io) errors
-* Fix: Navbar is not rendered on old iOS
-* Support: Expose metrics with Promster
-* Support: Upgrade libs
-    * axios
-
-## v4.2.5
-
-* Improvement: Invoke garbage collection when reindex all pages by elasticsearch
-    * Turned out not working -- 2021.05.01
-* Fix: MathJax rendering does not work
-
-## v4.2.4
-
-* Fix: Fixed an error when creating a new page with `Ctrl-S`
-    * Introduced by v4.2.2
-* Fix: Fixed a strange diff in PageHistory due to Pagination
-* Fix: Fixed that the user group page could not be found when using api from the outside
-
-## v4.2.3
-
-* Feature: Insert/edit links with GUI
-* Feature: Auto reconnecting to search service
-* Improvement: New style of params for Healthcheck API
-* Fix: Referencing attachments when `FILE_UPLOAD_DISABLED` is true
-* Fix: The message of timeline for restricted pages
-* Fix: Parameter validation for Import/Export Archive API
-* Fix: Prevent regexp for Search Tags API
-* Fix: Add `Content-Security-Policy` when referencing attachments
-* Fix: Sanitize at presentation time
-* Fix: Remove page path string from message for page lists and timeline when there is no contents
-
-## v4.2.2
-
-* Fix: Consecutive save operations with built-in editor fail
-    * Introduced by v4.2.1
-
-## v4.2.1
-
-* Fix: Consecutive save operations with HackMD fail
-    * Introduced by v4.2.0
-* Fix: Switching theme to kibela fail
-    * Introduced by v4.2.0
-
-## v4.2.0
-
-### BREAKING CHANGES
-
-* GROWI v4.2.x no longer support Kibela layout
-    * Kibela theme is newly added and the configuration will migrate to it automatically
-
-### Updates
-
-* Feature: File Upload Settings on admin pages
-* Improvement: Basic layout of page
-* Support: Support MongoDB 4.0, 4.2 and 4.4
-* Support: Upgrade libs
-    * migrate-mongo
-    * mongoose
-
-## v4.1.13
-
-* Fix: MathJax rendering does not work
-
-## v4.1.12
-
-* Fix: Adjust line-height for pre under li
-* Fix: Emptying trash process is broken
-
-## v4.1.11
-
-* Improvement: Generating draft DOM id strategy
-* Fix: GROWI version downgrade causes a validation error for user.lang
-
-## v4.1.10
-
-* Fix: Make listing users API secure
-* Fix: Error message when the server denies guest user connecting with socket.io
-
-## v4.1.9
-
-* Feature: Environment variables to set max connection size to deliver push messages to all clients
-
-## v4.1.8
-
-* Improvement: Rebuilding progress bar colors for Full Text Search Management
-* Improvement: Support operations on page data with a null value for author
-
-## v4.1.7
-
-* Improvement: Fire global notification when a new page is created by uploading file
-* Fix: Change default `DRAWIO_URI` to embed.diagrams.net
-* Fix: An unhandled rejection occures when a user who does not send referer accesses
-
-## v4.1.6
-
-* Improvement: Hide Fab at admin pages
-* Fix: Presentation does not work
-* Fix: Update GrantSelector status when uploading a file to a new page
-* Fix: CopyDropdown origin refs draw.io host wrongly
-
-## v4.1.5
-
-* Feature: Independent S3 configuration and SES configuration for AWS
-* Fix: Author name does not displayed in page history
-* Fix: Hide unnecessary component when pringing
-
-## v4.1.4 (Missing number)
-
-## v4.1.3
-
-* Feature: Create/edit linker with GUI
-* Improvement: Paging page histories
-* Improvement: Avoid using `cursor.snapshot()` in preparation for MongoDB version upgrade
-* Improvement: Allow to save "From e-mail address" only in App Settings
-* Improvement: Allow to empty "From e-mail address" in App Settings
-* Improvement: Export/Import archive data serially so as not to waste memory
-* Fix: To be able to delete attachment metadata even when the actual data does not exist
-* Fix: Limit the attrubutes of user data for `/_api/v3/users`
-* Fix: Prevent XSS with SVG
-* Upgrade libs
-    * optimize-css-assets-webpack-plugin
-    * terser-webpack-plugin
-
-## v4.1.2
-
-* Fix: Uploaded images do not displayed
-    * Introduced by v4.1.1
-
-## v4.1.1
-
-* Feature: External share link
-* Improvement: Optimize some features that operate revision data
-    * Page history
-    * Renaming pages
-    * Deleting pages
-* Fix: Cmd+c/v/... does not work on Mac
-    * Introduced by v4.1.0
-* Fix: "Append params" switch of CopyDropdown does not work when multiple CopyDropdown instance exists
-* Fix: "Append params" switch of CopyDropdown escapes spaces
-* Fix: Blockdiag does not be rendered
-* Fix: Access token parser
-
-## v4.1.0
-
-### BREAKING CHANGES
-
-* GROWI v4.1.x no longer support Node.js v10.x
-* GROWI v4.1.x no longer support growi-plugin-attachment-refs@v1
-
-Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/41x.html>
-
-### Updates
-
-* Feature: Server settings synchronization for multiple GROWI Apps
-* Feature: Page status alert synchronization for multiple GROWI Apps
-* Feature: Smooth scroll for anchor links
-* Feature: Mirror Mode with [Konami Code](https://en.wikipedia.org/wiki/Konami_Code)
-* Improvement: Determine whether the "In Use" badge is displayed or not by attachment ID
-* Improvement: draw.io under NO_CDN environment
-* Fix: Deleting/renaming with recursive option affects pages that are inaccessible to active users
-* Fix: DrawioModal cuts without beginning/ending line
-* Fix: New settings of SMTP and AWS SES are not reflected when server is running
-* Fix: Sidebar layout broken when using Kibela layout
-* Support: Support Node.js v14
-* Support: Update libs
-    * mathjax
-
-## v4.0.11
-
-* Fix: Fab on search result page does not displayed
-* Fix: Adjust margin/padding for search result page
-* Fix: PageAlert broken
-    * Introduced by v4.0.9
-
-## v4.0.10
-
-* Improvement: Adjust ToC height
-* Fix: Fail to rename/delete a page set as "Anyone with the link"
-
-## v4.0.9
-
-* Feature: Detailed configurations for OpenID Connect
-    * Authorization Endpoint
-    * Token Endpoint
-    * Revocation Endpoint
-    * Introspection Endpoint
-    * UserInfo Endpoint
-    * Registration Endpoint
-    * JSON Web Key Set URI
-* Improvement: Navigations
-    * New floating subnavigation
-    * New open drawer button
-    * New fixed bottom navbar on mobile
-    * New fixed bottom navbar for editor on mobile
-    * FAB (Floating action button)
-* Improvement: Sticky admin navigation
-* Fix: Reseting password doesn't work
-* Fix: Styles for printing
-* Fix: Unable to create page with original path after emptying trash
-* I18n: Support zh-CN
-
-## v4.0.8 (Missing number)
-
-## v4.0.7
-
-* Feature: Set request timeout for Elasticsearch with env var `ELASTICSEARCH_REQUEST_TIMEOUT`
-* Improvement: Apply styles faster on booting client
-* Fix: Styles are not applyed on installer
-* Fix: Remove last-resort `next()`
-* Fix: Enable/disable Notification settings couldn't change when either of the params is undefined
-* Fix: Text overflow
-
-## v4.0.6
-
-* Fix: Avatar images in Recent Changes are not shown
-* Fix: Full screen modal of Handsontable and Draw.io don't work
-* Fix: Shortcut for creating page respond with modifier key wrongly
-    * Introduced by v4.0.5
-
-## v4.0.5
-
-* Improvement: Return pre-defined session id when healthcheck
-* Improvement: Refactor caching for profile image
-* Improvement: Layout for global search help on mobile
-* Improvement: Layout for confidential notation
-* Fix: Shortcut for creating page doesn't work
-* Support: Dev in container
-* Support: Upgrade libs
-    * ldapjs
-    * node-sass
-
-
-## v4.0.4
-
-* Feature: Drawer/Dock mode selector
-* Improvement: Admin pages navigation
-* Improvement: Ensure not to avoid session management even when accessing to healthcheck
-* Support: Refactor unstated utils
-* Support: Upgrade libs
-    * connect-mongo
-    * connect-redis
-    * mongoose
-    * mongoose-gridfs
-    * mongoose-paginate-v2
-
-## v4.0.3
-
-* Feature: Copy page path dropdown with Append params switch
-* Improvement: Truncate overflowed user browsing history
-* Improvement: Tabs appearance on mobile
-* Improvement: Search help appearance on mobile
-* Improvement: Accessibility of login page
-* Fix: Editor was broken by long lines
-* Fix: Editor doesn't work on mobile
-* Fix: Word break in Recent Updated contents
-* Fix: navbar is broken on Safari
-
-## v4.0.2
-
-* Fix: Internal Server Error occurred when the guest user access to the pages that has likes
-* Fix: Some buttons are broken on Safari
-
-## v4.0.1
-
-* Improvement: Accessibility for Handsontable under dark mode
-* Improvement: Refactor '/pages.exist' API
-* Fix: Storing the state of sidebar
-* Fix: Comments order should be asc
-* Fix: Show/Hide replies button doesn't work
-* Fix: Tooltip doesn't work
-* Fix: Change the display of the scroll bar when modal is shown
-* Fix: Submit with enter key on Create/Rename modals
-* Fix: Show/Hide Unlink redirection button conditions
-* Fix: Link color in alerts
-* Support: Upgrade libs
-    * @atlaskit/drawer
-    * @atlaskit/navigation-next
-
-## v4.0.0
-
-### BREAKING CHANGES
-
-* Crowi Classic Behavior is removed
-* Crowi Classic Layout is removed
-* 'default-dark' theme is now merged as a dark mode variant of 'default' theme
-* 'blue-night' theme is now merged as a dark mode variant of 'mono-blue' theme
-
-Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/40x.html>
-
-### Updates
-
-* Feature: Sidebar
-* Feature: Recent changes on Sidebar
-* Feature: Switch Light/Dark Mode
-* Improvement: Migrate to Bootstrap 4
-* Improvement: Copy Page URL menu item to copy path dropdown
-* Improvement: Show contributors by Bootstrap Modal
-* Support: Upgrade libs
-    * bootstrap
-
-## v3.8.1
-
-### BREAKING CHANGES
-
-- Now Elasticsearch requires the privilege `cluster:monitor/health` instead of `cluster:monitor/nodes/info`
-
-Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/38x.html>
-
-### Updates
-
-* Improvement: Change the health check method for Elasticsearch
-* Fix: Unset overflow-y style for Edit Tags Modal
-* Fix: Duplicate page source is overwrited
-    * Introduced by 3.7.6
-
-## v3.8.0  (Missing number)
-
-## v3.7.7
-
-* Feature: Empty trash pages
-* Improvement: Behavior of Reconnect to Elasticsearch button
-* Fix: Duplicate page source is overwrited
-    * Introduced by 3.7.6
-
-## v3.7.6  (Missing number)
-
-## v3.7.5
-
-* Fix: Draw.io diagrams rendered twice
-* Fix: Behavior of password reset modal is strange
-* Fix: Import GROWI Archive doesn't restore some data correctly
-* Fix: Attachments list on root page and users top pages
-* Fix: Trash page is no longer editable
-* Fix: Rendering Timeline on /trash
-
-## v3.7.4
-
-* Fix: Broken by displaying user image
-
-## v3.7.3
-
-* Feature: Profile Image Cropping
-* Improvement: Reactify users pages
-* Improvement: Detect language and adjust the order of first and last names when creating accounts in OAuth
-* Fix: Installation is broken when selecting Japanese
-    * Introduced by 3.7.0
-* Fix: Mathjax Rendering is unstable (workaround)
-    * Introduced by 3.7.0
-* Fix: Notification Setting couldn't update without slack token
-    * Introduced by 3.6.6
-* Support: Add GROWI Contributers
-
-## v3.7.2
-
-* Feature: User Management Filtering/Sort
-* Feature: Show env vars on Admin pages
-* Fix: Attachment row z-index
-* I18n: HackMD integration alert
-
-## v3.7.1
-
-* Improvement: Add an option that make it possible to choose what to send notifications
-* Improvement: Add the env var `DRAWIO_URI`
-* Improvement: Accessibility for 'spring' theme
-* Improvement: Editor scroll sync behaves strangely when using draw.io blocks
-* Fix: Coudn't upload file on Comment Editor
-    * Introduced by 3.5.8
-* I18n: HackMD integration
-
-## v3.7.0
-
-### BREAKING CHANGES
-
-None.
-
-Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/37x.html>
-
-### Updates
-
-* Feature: [Draw.io](https://www.draw.io/) Integration
-* Feature: SAML Attribute-based Login Control
-* Improvement: Reactify admin pages (Security)
-* Improvement: Behavior of pre-editing screen of HackMD when user needs to resume
-
-## v3.6.10
-
-* Fix: Redirect logic for users except for actives
-    * Introduced by 3.6.9
-
-## v3.6.9
-
-* Improvement: Redirection when login/logout
-* Improvement: Add home icon before '/'
-* Fix: Client crashed when the first login
-    * Introduced by 3.6.8
-
-## v3.6.8
-
-* Improvement: Show page history side-by-side
-* Improvement: Optimize markdown rendering
-* Improvement: Reactify admin pages (Navigation)
-* Fix: Reply comments collapsed are broken
-    * Introduced by 3.6.7
-* Support: Update libs
-    * cross-env
-    * mkdirp
-    * diff2html
-    * jest
-    * stylelint
-
-## v3.6.7
-
-* Feature: Anchor link for comments
-* Improvement: Show error toastr when saving page is failed because of empty document
-* Fix: Admin Customise couldn't restore stored config value
-    * Introduced by 3.6.2
-* Fix: Admin Customise missed preview functions
-    * Introduced by 3.6.2
-* Fix: AWS doesn't work
-    * Introduced by 3.6.4
-* Fix: Ensure not to get unrelated indices information in Elasticsearch Management
-    * Introduced by 3.6.6
-* Support: Optimize bundles
-* Support: Optimize build-prod job with caching node_modules/.cache
-
-## v3.6.6
-
-* Feature: Reconnect to Elasticsearch from Full Text Search Management
-* Feature: Normalize indices of Elasticsearch from Full Text Search Management
-* Improvement: Add 'spring' theme
-* Improvement: Reactify admin pages (Notification)
-* Impromvement: Add `checkMiddlewaresStrictly` option to Healthcheck API
-* Improvement: Accessibility for History component under dark themes
-* Fix: Warning on client console when developing /admin/app
-* Support: Upgrade libs
-    * react-bootstrap-typeahead
-
-## v3.6.5 (Missing number)
-
-## v3.6.4
-
-* Feature: Alert for stale page
-* Improvement: Reactify admin pages (Home)
-* Improvement: Reactify admin pages (App)
-* Improvement: Accessibility for editor icons of dark themes
-* Improvement: Accessibility for importing table data pane
-* Improvement: Resolve username and email when logging in with Google OAuth
-
-## v3.6.3
-
-* Improvement: Searching users in UserGroup Management
-* Fix: Repair google authentication by migrating to jaredhanson/passport-google-oauth2
-* Fix: Markdown Settings are broken by the button to import recommended settings
-* Support: Upgrade libs
-    * check-node-version
-    * file-loader
-    * mini-css-extract-plugin
-
-## v3.6.2
-
-* Improvement: Reactify admin pages (Customize)
-* Improvement: Ensure not to consider `[text|site](https://example.com]` as a row in the table
-* Improvement: Enter key behavior in markdown table
-* Fix: Pre-installed plugins in official docker image are not detected
-    * Introduced by 3.6.0
-* Fix: Emoji Autocomplete window does not float correctly
-    * Introduced by 3.5.0
-
-## v3.6.1
-
-### BREAKING CHANGES
-
-* GROWI v3.6.x no longer support Node.js v8.x
-* The name of database that is storing migrations meta data has been changed
-    * This affects **only when `MONGO_URI` has parameters**
-    * v3.5.x or above has a bug ([#1361](https://github.com/weseek/growi/issues/1361))
-
-Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/36x.html>
-
-### Updates
-
-* Improvement: Drop unnecessary MongoDB collection indexes
-* Improvement: Accessibility of Antarctic theme
-* Improvement: Reactify admin pages (Markdown Settings)
-* Fix: Appending tag is failed by wrong index of PageTagRelation
-    * Introduced by 3.5.20
-* Fix: Pages without heading slash is invalid but creatable
-* Fix: Connect to Elasticsearch with `httpAuth` param
-* Support: Support Node.js v12
-* Support: Optimize build in dev with hard-source-webpack-plugin
-* Support: Upgrade libs
-    * growi-commons
-
-## v3.6.0 (Missing number)
-
-## v3.5.25
-
-* Improvement: Disable ESC key to close Handsontable Modal
-* Fix: Exported data of empty collection is broken
-* Fix: Some components crash after when the page with attachment has exported/imported
-
-## v3.5.24
-
-* Fix: Plugins are not working on Heroku
-
-## v3.5.23
-
-* Fix: Global Notification failed to send e-mail
-* Fix: Pagination is not working for trash list
-* Fix: Healthcheck API with `?connectToMiddlewares` returns error
-* Support: Upgrade libs
-    * growi-commons
-
-## v3.5.22
-
-* Improvement: Add `FILE_UPLOAD_DISABLED` env var
-
-## v3.5.21
-
-* Improvement: Cache control when retrieving attachment data
-* Fix: Inviting user doesn't work
-    * Introduced by 3.5.20
-
-## v3.5.20
-
-* Improvement: Organize MongoDB collection indexes uniqueness
-* Improvement: Reactify admin pages (External Account Management)
-* Fix: Search result or Timeline shows loading icon eternally when retrieving not accessible page
-* Support: Use SearchBox Elasticsearch Addon on Heroku
-* Support: Upgrade libs
-    * cross-env
-    * eslint-plugin-jest
-    * i18next
-    * i18next-browser-languagedetector
-    * migrate-mongo
-    * react-i18next
-    * validator
-
-## v3.5.19 (Missing number)
-
-## v3.5.18
-
-* Improvement: Import GROWI Archive
-    * Process asynchronously
-    * Collection configurations
-    * Selectable mode (insert/upsert/flush and insert)
-    * Safely mode settings for configs and users collections
-    * Show errors view
-* Improvement: Optimize handling promise of stream when exporting archive
-* Improvement: Optimize handling promise of stream when building indices
-* Improvement: Add link to [docs.growi.org](https://docs.growi.org)
-* Fix: Monospace font code is broken when printing on Mac
-
-## v3.5.17
-
-* Feature: Upload to GCS (Google Cloud Storage)
-* Feature: Statistics API
-* Improvement: Optimize exporting
-* Improvement: Show progress bar when exporting
-* Improvement: Validate collection combinations when importing
-* Improvement: Reactify admin pages
-* Fix: Use HTTP PlantUML URL in default
-    * Introduced by 3.5.12
-* Fix: Config default values
-* Support: REPL with `console` npm scripts
-
-## v3.5.16
-
-* Fix: Full Text Search doesn't work after when building indices
-    * Introduced by 3.5.12
-
-## v3.5.15
-
-* Feature: Import/Export Page data
-* Fix: The link to Sandbox on Markdown Help Modal doesn't work
-* Support: Upgrade libs
-    * codemirror
-
-## v3.5.14 (Missing number)
-
-## v3.5.13
-
-* Feature: Re-edit comments
-* Support: [growi-plugin-attachment-refs](https://github.com/weseek/growi-plugin-attachment-refs)
-* Support: Upgrade libs
-    * entities
-    * markdown-it
-
-## v3.5.12
-
-* Improvement: Use Elasticsearch Alias
-* Improvement: Connect to HTTPS PlantUML URL in default
-* Fix: Global Notification doesn't work after updating Webhook URL
-* Fix: User Trigger Notification is not be sent when channel is not specified
-* Support: Upgrade libs
-    * terser-webpack-plugin
-
-## v3.5.11
-
-* Fix: HackMD Editor shows 404 error when HackMD redirect to fqdn URI
-    * Introduced by 3.5.8
-* Fix: Timeline doesn't work
-    * Introduced by 3.5.1
-* Fix: Last Login field does not shown in /admin/user
-* Support: Upgrade libs
-    * env-cmd
-    * sass-loader
-    * webpack
-    * webpack-cli
-    * webpack-merge
-
-## v3.5.10
-
-* Feature: Send Global Notification with Slack
-* Improvement: Show loading spinner when fetching page history data
-* Improvement: Hierarchical page link when the page is in /Trash
-* Fix: Code Highlight Theme does not change
-    * Introduced by 3.5.2
-* Support: Upgrade libs
-    * date-fns
-    * eslint-config-weseek
-
-## v3.5.9
-
-* Fix: Editing table with Spreadsheet like GUI (Handsontable) is failed
-* Fix: Plugins are not initialized when first launching
-    * Introduced by 3.5.0
-* Support: Upgrade libs
-    * entities
-    * growi-commons
-    * openid-client
-    * rimraf
-    * style-loader
-
-## v3.5.8
-
-* Improvement: Controls when HackMD/CodiMD has unsaved draft
-* Improvement: Show hints if HackMD/CodiMD integration is not working
-* Improvement: GROWI server obtains HackMD/CodiMD page id from the 302 response header
-* Improvement: Comment Thread Layout
-* Improvement: Show commented date with date distance format
-
-## v3.5.7 (Missing number)
-
-## v3.5.6
-
-* Fix: Saving new page is failed when empty string tag is set
-* Fix: Link of Create template page button in New Page Modal is broken
-* Fix: Global Notification dows not work when creating/moving/deleting/like/comment
-
-## v3.5.5
-
-* Feature: Support S3-compatible object storage (e.g. MinIO)
-* Feature: Enable/Disable ID/Password Authentication
-* Improvement: Login Mechanism with HTTP Basic Authentication header
-* Improvement: Reactify Table Of Contents
-* Fix: Profile images are broken in User Management
-* Fix: Template page under root page doesn't work
-* Support: Upgrade libs
-    * csv-to-markdown-table
-    * express-validator
-    * markdown-it
-    * mini-css-extract-plugin
-    * react-hotkeys
-
-## v3.5.4
-
-* Fix: List private pages wrongly
-* Fix: Global Notification Trigger Path does not parse glob correctly
-* Fix: Consecutive page deletion requests cause unexpected complete page deletion
-
-## v3.5.3
-
-* Improvement: Calculate string width when save with Spreadsheet like GUI (Handsontable)
-* Fix: Search Result Page doesn't work
-* Fix: Create/Update page API returns data includes author's password hash
-* Fix: Dropdown to copy page path/URL/MarkdownLink shows under CodeMirror vscrollbar
-* Fix: Link to /trash in Dropdown menu
-
-## v3.5.2
-
-* Feature: Remain metadata option when Move/Rename page
-* Improvement: Support code highlight for Swift and Kotlin
-* Fix: Couldn't restrict page with user group permission
-* Fix: Couldn't duplicate a page when it restricted by a user group permission
-* Fix: Consider timezone on admin page
-* Fix: Editor doesn't work on Microsoft Edge
-* Support: Upgrade libs
-    * growi-commons
-
-## v3.5.1
-
-### BREAKING CHANGES
-
-* GROWI no longer supports
-    * Protection system with Basic Authentication
-    * Crowi Classic Authentication Mechanism
-    * [Crowi Template syntax](https://medium.com/crowi-book/crowi-v1-5-0-5a62e7c6be90)
-* GROWI no lonnger supports plugins with schema version 2
-    * Upgrade [weseek/growi-plugin-lsx](https://github.com/weseek/growi-plugin-lsx) to v3.0.0 or above
-    * Upgrade [weseek/growi-plugin-pukiwiki-like-linker
-](https://github.com/weseek/growi-plugin-pukiwiki-like-linker
-) to v3.0.0 or above
-* The restriction mode of the root page (`/`) will be set 'Public'
-* The restriction mode of the root page (`/`) can not be changed after v 3.5.1
-
-Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/35x.html>
-
-### Updates
-
-* Feature: Comment Thread
-* Feature: OpenID Connect authentication
-* Feature: HTTP Basic authentication
-* Feature: Staff Credits with [Konami Code](https://en.wikipedia.org/wiki/Konami_Code)
-* Feature: Restricte Complete Deletion of Pages
-* Improvement Draft list
-* Fix: Deleting page completely
-* Fix: Search with `prefix:` param with CJK pathname
-* Fix: Could not edit UserGroup even if `PUBLIC_WIKI_ONLY` is not set
-* I18n: User Management Details
-* I18n: Group Management Details
-* Support: Apply unstated
-* Support: Use Babel 7
-* Support: Support plugins with schema version 3
-* Support: Abolish Old Config API
-* Support: Apply Jest for Tests
-* Support: Upgrade libs
-    * async
-    * axios
-    * connect-mongo
-    * css-loader
-    * eslint
-    * eslint-config-weseek
-    * eslint-plugin-import
-    * eslint-plugin-jest
-    * eslint-plugin-react
-    * file-loader
-    * googleapis
-    * i18next
-    * migrate-mongo
-    * mini-css-extract-plugin
-    * mongoose
-    * mongoose-gridfs
-    * mongoose-unique-validator
-    * null-loader
-
-## v3.5.0 (Missing number)
-
-## v3.4.7
-
-* Improvement: Handle private pages on group deletion
-* Fix: Searching with `tag:xxx` syntax doesn't work
-* Fix: Check CSRF when updating user data
-* Fix: `createdAt` field initialization
-* I18n: Import data page
-* I18n: Group Management page
-
-## v3.4.6
-
-* Feature: Tags
-* Feature: Dropdown to copy page path/URL/MarkdownLink
-* Feature: List of drafts
-* Improvement: Replace icons of Editor Tool Bar
-* Improvement: Show display name when mouse hover to user image
-* Fix: URL in slack message is broken on Safari
-* Fix: Registration does not work when basic auth is enabled
-* Support: Publish API docs with swagger-jsdoc and ReDoc
-* Support: Upgrade libs
-    * cmd-env
-    * elasticsearch
-    * mongoose-gridfs
-    * node-dev
-    * null-loader
-    * react-codemirror
-
-## v3.4.5
-
-* Improvement: Pass autolink through the XSS filter according to CommonMark Spec
-* Fix: Update ElasticSearch index when deleting/duplicating pages
-* Fix: Xss filter breaks PlantUML arrows
-* Support: Support growi-plugin-lsx@2.2.0
-* Support: Upgrade libs
-    * growi-commons
-    * xss
-
-## v3.4.4
-
-* Fix: Comment component doesn't work
-
-## v3.4.3
-
-* Improvement: Add 'antarctic' theme
-* Support Apply eslint-config-airbnb based rules
-* Support Apply prettier and stylelint
-* Support: Upgrade libs
-    * csrf
-    * escape-string-regexp
-    * eslint
-    * express-session
-    * googleapis
-    * growi-commons
-    * i18next
-    * mini-css-extract-plugin
-    * nodemailer
-    * penpal
-    * react-i18next
-    * string-width
-
-## v3.4.2
-
-* Fix: Nofitication to Slack doesn't work
-    * Introduced by 3.4.0
-
-## v3.4.1
-
-* Fix: "Cannot find module 'stream-to-promise'" occured when build client with `FILE_UPLOAD=local`
-
-## v3.4.0
-
-### BREAKING CHANGES
-
-None.
-
-Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
-
-### Updates
-
-* Improvement: Restrict to access attachments when the user is not allowed to see page
-* Improvement: Show fans and visitors of page
-* Improvement: Full text search tokenizing
-* Improvement: Markdown comment on Crowi Classic Layout
-* Fix: Profile image is not displayed when `FILE_UPLOAD=mongodb`
-* Fix: Posting comment doesn't work under Crowi Classic Layout
-    * Introduced by 3.1.5
-* Fix: HackMD doesn't work when `siteUrl` ends with slash
-* Fix: Ensure not to be able to move/duplicate page to the path which has trailing slash
-* Support: Launch with Node.js v10
-* Support: Launch with MongoDB 3.6
-* Support: Launch with Elasticsearch 6.6
-* Support: Upgrade libs
-    * bootstrap-sass
-    * browser-sync
-    * react
-    * react-dom
-
-
-## v3.3.10
-
-* Feature: PlantUML and Blockdiag on presentation
-* Improvement: Render slides of presentation with GrowiRenderer
-* Fix: Unportalizing doesn't work
-* Support: Use mini-css-extract-plugin instead of extract extract-text-webpack-plugin
-* Support: Use terser-webpack-plugin instead of uglifyjs-webpack-plugin
-* Support: Upgrade libs
-    * csv-to-markdown-table
-    * file-loader
-    * googleapis
-    * i18next-browser-languagedetector
-    * mocha
-    * react-waypoint
-    * webpack
-    * webpack-assets-manifest
-    * webpack-cli
-    * webpack-merge
-
-## v3.3.9
-
-* Fix: Import from Qiita:Team doesn't work
-    * Introduced by 3.3.0
-* Fix: Typeahead shows autocomplete wrongly
-    * Introduced by 3.3.8
-* Support: Upgrade libs
-    * react-bootstrap-typeahead
-
-## v3.3.8
-
-* Fix: Move/Duplicate don't work
-    * Introduced by 3.3.7
-* Fix: Server doesn't respond when root page is restricted
-* Support: Upgrade libs
-    * react
-    * react-bootstrap-typeahead
-
-## v3.3.7
-
-* Feature: Editor toolbar
-* Feature: `prefix:/path` searching syntax to filter with page path prefix
-* Feature: Add an option to filter only children to searching box of navbar
-* Improvement: Suggest page path when moving/duplicating/searching
-* Fix: Anonymous users couldn't search
-    * Introduced by 3.3.6
-* I18n: Searching help
-* Support: Prepare to suppoert Node.js v10
-* Support: Upgrade libs
-    * node-sass
-
-## v3.3.6
-
-* Improvement: Site URL settings must be set
-* Improvement: Site URL settings can be set with environment variable
-* Fix: "Anyone with the link" ACL doesn't work correctly
-    * Introduced by 3.3.0
-* Fix: Related pages list of /admin/user-group-detail/xxx doesn't show anything
-    * Introduced by 3.3.0
-* Fix: Diff of revision contents doesn't appeared when notifing with slack
-* Fix: NPE occured on /admin/security when Crowi Classic Auth Mechanism is set
-* Fix: Coudn't render Timing Diagram with PlantUML
-* I18n: Cheatsheet for editor
-* I18n: Some admin pages
-* Support: Upgrade libs
-    * diff
-    * markdown-it-plantuml
-    * mongoose
-    * nodemailer
-    * mongoose-gridfs
-    * sinon
-    * sinon-chai
-
-## v3.3.5 (Missing number)
-
-## v3.3.4
-
-* Improvement: SAML configuration with environment variables
-* Improvement: Upload file with pasting from clipboard
-* Fix: `/_api/revisions.get` doesn't populate author data correctly
-* Fix: Wrong OAuth callback url are shown at admin page
-* Fix: Connecting to MongoDB failed when processing migration
-* Support: Get ready to use new config management system
-
-## v3.3.3
-
-* Feature: Show line numbers to a code block
-* Feature: Bulk update the scope of descendant pages when create/update page
-* Improvement: The scope of ascendant page will be retrieved and set to controls in advance when creating a new page
-* Fix: Pages that is restricted by groups couldn't be shown in search result page
-* Fix: Pages order in search result page was wrong
-* Fix: Guest user can't search
-* Fix: Possibility that ExternalAccount deletion processing selects incorrect data
-* Support: Upgrade libs
-    * bootstrap-sass
-    * i18next
-    * migrate-mongo
-    * string-width
-
-## v3.3.2
-
-* Fix: Specified Group ACL is not persisted correctly
-    * Introduced by 3.3.0
-
-## v3.3.1
-
-* Feature: NO_CDN Mode
-* Feature: Add option to show/hide restricted pages in list
-* Feature: MongoDB GridFS quota
-* Improvement: Refactor Access Control
-* Improvement: Checkbox behavior of task list
-* Improvement: Fixed search input on search result page
-* Improvement: Add 'christmas' theme
-* Improvement: Select default language of new users
-* Fix: Hide restricted pages contents in timeline
-* Support: Upgrade libs
-    * googleapis
-    * passport-saml
-
-## v3.3.0 (Missing number)
-
-## v3.2.10
-
-* Fix: Pages in trash are available to create
-* Fix: Couldn't create portal page under Crowi Classic Behavior
-* Fix: Table tag in Timeline/SearchResult missed border and BS3 styles
-* I18n: Installer
-
-
-## v3.2.9
-
-* Feature: Attachment Storing to MongoDB GridFS
-* Fix: row/col moving of Spreadsheet like GUI (Handsontable) doesn't work
-* Fix: Emoji AutoComplete dialog pops up at wrong position
-* Support: Upgrade libs
-    * codemirror
-    * react-codemirror2
-
-## v3.2.8
-
-* Improvement: Add an option to use email for account link when using SAML federation
-* Fix: Editor layout is sometimes broken
-* Fix: Normalize table data for Spreadsheet like GUI (Handsontable) when import
-* Support: Improve development environment
-* Support: Upgrade libs
-    * googleapis
-    * react-dropzone
-
-## v3.2.7
-
-* Feature: Import CSV/TSV/HTML table on Spreadsheet like GUI (Handsontable)
-* Fix: Pasting table data copied from Excel includes unnecessary line breaks
-* Fix: Page break Preset 1 for Presentation mode is broken
-* Fix: Login Form when LDAP login failed caused 500 Internal Server Error
-
-## v3.2.6
-
-* Feature: Add select alignment buttons of Spreadsheet like GUI (Handsontable)
-* Improvement: Shrink the rows that have no diff of revision history page
-* Fix: Login form rejects weak password
-* Fix: An error occured by uploading attachment file when the page is not exists
-    * Introduced by 2.3.5
-* Support: Upgrade libs
-    * i18next-express-middleware
-    * i18next-node-fs-backend
-    * i18next-sprintf-postprocessor
-
-## v3.2.5
-
-* Improvement: Expandable Spreadsheet like GUI (Handsontable)
-* Improvement: Move/Resize rows/columns of Spreadsheet like GUI (Handsontable)
-* Improvement: Prevent XSS of New Page modal
-* Fix: Recent Created tab of user home shows wrong page list
-    * Introduced by 3.2.4
-* Support: Upgrade libs
-    * @handsontable/react
-    * handsontable
-    * metismenu
-    * sinon
-
-## v3.2.4
-
-* Feature: Edit table with Spreadsheet like GUI (Handsontable)
-* Feature: Paging recent created in users home
-* Improvement: Specify certificate for SAML Authentication
-* Fix: SAML Authentication didn't work
-    * Introduced by 3.2.2
-* Fix: Failed to create new page with title which includes RegEx special characters
-* Fix: Preventing XSS Settings are not applied in default
-    * Introduced by 3.1.12
-* Support: Mongoose migration mechanism
-* Support: Upgrade libs
-    * googleapis
-    * mocha
-    * mongoose
-    * mongoose-paginate
-    * mongoose-unique-validator
-    * multer
-
-## v3.2.3
-
-* Feature: Kibela like layout
-* Improvement: Custom newpage separator for presentation view
-* Support: Shrink image size for themes which recently added
-
-## v3.2.2
-
-* Feature: SAML Authentication (SSO)
-* Improvement: Add 'wood' theme
-* Improvement: Add 'halloween' theme
-* Improvement: Add 'island' theme
-* Fix: Sending email function doesn't work
-* Support Upgrade libs
-    * style-loader
-
-## v3.2.1
-
-* Feature: Import data from esa.io
-* Feature: Import data from Qiita:Team
-* Feature: Add the endpoint for health check
-* Improvement: Adjust styles when printing
-* Fix: Renaming page doesn't work if the page was saved with shortcut
-* Support: Refactor directory structure
-* Support Upgrade libs
-    * file-loader
-    * googleapis
-    * postcss-loader
-    * sass-loader
-    * style-loader
-
-## v3.2.0
-
-* Feature: HackMD integration so that user will be able to simultaneously edit with multiple people
-* Feature: Login with Twitter Account (OAuth)
-* Fix: The Initial scroll position is wrong when reloading the page
-
-## v3.1.14
-
-* Improvement: Show help for header search box
-* Improvement: Add Markdown Cheatsheet to Editor component
-* Fix: Couldn't delete page completely from search result page
-* Fix: Tabs of trash page are broken
-
-## v3.1.13
-
-* Feature: Global Notification
-* Feature: Send Global Notification with E-mail
-* Improvement: Add attribute mappings for email to LDAP settings
-* Support: Upgrade libs
-    * autoprefixer
-    * css-loader
-    * method-override
-    * optimize-css-assets-webpack-plugin
-    * react
-    * react-bootstrap-typeahead
-    * react-dom
-
-
-## v3.1.12
-
-* Feature: Add XSS Settings
-* Feature: Notify to Slack when comment
-* Improvement: Prevent XSS in various situations
-* Improvement: Show forbidden message when the user accesses to ungranted page
-* Improvement: Add overlay styles for pasting file to comment form
-* Fix: Omit unnecessary css link
-    * Introduced by 3.1.10
-* Fix: Invitation mail do not be sent
-* Fix: Edit template button on New Page modal doesn't work
-
-## v3.1.11
-
-* Fix: OAuth doesn't work in production because callback URL field cannot be specified
-    * Introduced by 3.1.9
-
-## v3.1.10
-
-* Fix: Enter key on react-bootstrap-typeahead doesn't submit
-    * Introduced by 3.1.9
-* Fix: CodeMirror of `/admin/customize` is broken
-    * Introduced by 3.1.9
-
-## v3.1.9
-
-* Feature: Login with Google Account (OAuth)
-* Feature: Login with GitHub Account (OAuth)
-* Feature: Attach files in Comment
-* Improvement: Write comment with CodeMirror Editor
-* Improvement: Post comment with `Ctrl-Enter`
-* Improvement: Place the commented page at the beginning of the list
-* Improvement: Resolve errors on IE11 (Experimental)
-* Support: Migrate to webpack 4
-* Support: Upgrade libs
-    * eslint
-    * react-bootstrap-typeahead
-    * react-codemirror2
-    * webpack
-
-## v3.1.8 (Missing number)
-
-## v3.1.7
-
-* Fix: Update hidden input 'pageForm[grant]' when save with `Ctrl-S`
-* Fix: Show alert message when conflict
-* Fix: `BLOCKDIAG_URI` environment variable doesn't work
-* Fix: Paste in markdown list doesn't work correctly
-* Support: Ensure to inject logger configuration from environment variables
-* Support: Upgrade libs
-    * sinon
-    * sinon-chai
-
-## v3.1.6
-
-* Feature: Support [blockdiag](http://blockdiag.com)
-* Feature: Add `BLOCKDIAG_URI` environment variable
-* Fix: Select modal for group is not shown
-* Support: Upgrade libs
-    * googleapis
-    * throttle-debounce
-
-## v3.1.5
-
-* Feature: Write comment with Markdown
-* Improvement: Support some placeholders for template page
-* Improvement: Omit unnecessary response header
-* Improvement: Support LDAP attribute mappings for user's full name
-* Improvement: Enable to scroll revision-toc
-* Fix: Posting to Slack doesn't work
-    * Introduced by 3.1.0
-* Fix: page.rename api doesn't work
-* Fix: HTML escaped characters in markdown are unescaped unexpectedly after page is saved
-* Fix: sanitize `#raw-text-original` content with 'entities'
-* Fix: Double newline character posted
-    * Introduced by 3.1.4
-* Fix: List and Comment components do not displayed
-    * Introduced by 3.1.4
-* Support: Upgrade libs
-    * markdown-it-toc-and-anchor-with-slugid
-
-
-## v3.1.4 (Missing number)
-
-
-## v3.1.3 (Missing number)
-
-
-## v3.1.2
-
-* Feature: Template page
-* Improvement: Add 'future' theme
-* Improvement: Modify syntax for Crowi compatible template feature
-    * *before*
-
-        ~~~markdown
-        ``` template:/page/name
-        page contents
-        ```
-        ~~~
-
-    * *after*
-
-        ~~~plane
-        ::: template:/page/name
-        page contents
-        :::
-        ~~~
-
-* Improvement: Escape iframe tag in block codes
-* Support: Upgrade libs
-    * assets-webpack-plugin
-    * googleapis
-    * react-clipboard.js
-    * xss
-
-## v3.1.1
-
-* Improvement: Add 'blue-night' theme
-* Improvement: List up pages which restricted for Group ACL
-* Fix: PageGroupRelation didn't remove when page is removed completely
-
-
-## v3.1.0
-
-* Improvement: Group Access Control List - Select group modal
-* Improvement: Better input on mobile
-* Improvement: Detach code blocks correctly
-* Improvement: Auto-format markdown table which includes multibyte text
-* Improvement: Show icon when auto-format markdown table is activated
-* Improvement: Enable to switch show/hide border for highlight.js
-* Improvement: BindDN field allows also ActiveDirectory styles
-* Improvement: Show LDAP logs when testing login
-* Fix: Comment body doesn't break long terms
-* Fix: lsx plugin lists up pages that hit by forward match wrongly
-    * Introduced by 3.0.4
-* Fix: Editor is broken on IE11
-* Support: Multilingualize React components with i18next
-* Support: Organize dependencies
-* Support: Upgrade libs
-    * elasticsearch
-    * googleapis
-
-## v3.0.13
-
-* Improvement: Add Vim/Emacs/Sublime-Text icons for keybindings menu
-* Improvement: Add 'mono-blue' theme
-* Fix: Unportalize process failed silently
-* Fix: Sidebar breaks editor layouts
-* Support: Switch the logger from 'pino' to 'bunyan'
-* Support: Set the alias for 'debug' to the debug function of 'bunyan'
-* Support: Translate `/admin/security`
-* Support: Optimize bundles
-    * upgrade 'markdown-it-toc-and-anchor-with-slugid' and omit 'uslug'
-* Support: Optimize .eslintrc.js
-
-## v3.0.12
-
-* Feature: Support Vim/Emacs/Sublime-Text keybindings
-* Improvement: Add some CodeMirror themes (Eclipse, Dracula)
-* Improvement: Dynamic loading for CodeMirror theme files from CDN
-* Improvement: Prevent XSS when move/redirect/duplicate
-
-## v3.0.11
-
-* Fix: login.html is broken in iOS
-* Fix: Removing attachment is crashed
-* Fix: File-attaching error after new page creation
-* Support: Optimize development build
-* Support: Upgrade libs
-    * env-cmd
-    * googleapis
-    * sinon
-
-## v3.0.10
-
-* Improvement: Add 'nature' theme
-* Fix: Page list and Timeline layout for layout-growi
-* Fix: Adjust theme colors
-    * Introduced by 3.0.9
-
-## v3.0.9
-
-* Fix: Registering new LDAP User is failed
-    * Introduced by 3.0.6
-* Support: Organize scss for overriding bootstrap variables
-* Support: Upgrade libs
-    * codemirror
-    * react-codemirror2
-    * normalize-path
-    * style-loader
-
-## v3.0.8
-
-* Improvement: h1#revision-path occupies most of the screen when the page path is long
-* Improvement: Ensure not to save concealed email field to localStorage
-* Fix: Cannot input "c" and "e" on iOS
-
-## v3.0.7
-
-* Improvement: Enable to download an attached file with original name
-* Improvement: Use MongoDB for session store instead of Redis
-* Improvement: Update dropzone overlay icons and styles
-* Fix: Dropzone overlay elements doesn't show
-    * Introduced by 3.0.0
-* Fix: Broken page path of timeline
-    * Introduced by 3.0.4
-
-## v3.0.6
-
-* Improvement: Automatically bind external accounts newly logged in to local accounts when username match
-* Improvement: Simplify configuration for Slack Web API
-* Support: Use 'slack-node' instead of '@slack/client'
-* Support: Upgrade libs
-    * googleapis
-    * i18next
-    * i18next-express-middleware
-    * react-bootstrap-typeahead
-    * sass-loader
-    * uglifycss
-
-## v3.0.5
-
-* Improvement: Update lsx icons and styles
-* Fix: lsx plugins doesn't show page names
-
-## v3.0.4
-
-* Improvement: The option that switch whether add h1 section when create new page
-* Improvement: Encode page path that includes special character
-* Fix: Page-saving error after new page creation
-
-## v3.0.3
-
-* Fix: Login page is broken in iOS
-* Fix: Hide presentation tab if portal page
-* Fix: A few checkboxes doesn't work
-    * Invite user check with email in `/admin/user`
-    * Recursively check in rename modal
-    * Redirect check in rename modal
-* Fix: Activating invited user form url is wrong
-* Support: Use postcss-loader and autoprefixer
-
-## v3.0.2
-
-* Feature: Group Access Control List
-* Feature: Add site theme selector
-* Feature: Add a control to switch whether email shown or hidden by user
-* Feature: Custom title tag content
-* Fix: bosai version
-* Support: Rename to GROWI
-* Support: Add dark theme
-* Support: Refreshing bootstrap theme and icons
-* Support: Use Browsersync instead of easy-livereload
-* Support: Upgrade libs
-    * react-bootstrap
-    * react-bootstrap-typeahead
-    * react-clipboard.js
-
-## v3.0.1 (Missing number)
-
-## v3.0.0 (Missing number)
-
-## v2.4.4
-
-* Feature: Autoformat Markdown Table
-* Feature: highlight.js Theme Selector
-* Fix: The bug of updating numbering list by codemirror
-* Fix: Template LangProcessor doesn't work
-    * Introduced by 2.4.0
-* Support: Apply ESLint
-* Support: Upgrade libs
-    * react, react-dom
-    * codemirror, react-codemirror2
-
-## v2.4.3
-
-* Improvement: i18n in `/admin`
-* Improvement: Add `SESSION_NAME` environment variable
-* Fix: All Elements are cleared when the Check All button in DeletionMode
-* Support: Upgrade libs
-    * uglifycss
-    * sinon-chai
-
-## v2.4.2
-
-* Improvement: Ensure to set absolute url from root when attaching files when `FILE_UPLOAD=local`
-* Fix: Inline code blocks that includes doller sign are broken
-* Fix: Comment count is not updated when a comment of the page is deleted
-* Improvement: i18n in `/admin` (WIP)
-* Support: Upgrade libs
-    * googleapis
-    * markdown-it-plantuml
-
-## v2.4.1
-
-* Feature: Custom Header HTML
-* Improvement: Add highlight.js languages
-    * dockerfile, go, gradle, json, less, scss, typescript, yaml
-* Fix: Couldn't connect to PLANTUML_URI
-    * Introduced by 2.4.0
-* Fix: Couldn't render UML which includes CJK
-    * Introduced by 2.4.0
-* Support: Upgrade libs
-    * axios
-    * diff2html
-
-## v2.4.0
-
-* Feature: Support Footnotes
-* Feature: Support Task lists
-* Feature: Support Table with CSV
-* Feature: Enable to render UML diagrams with public plantuml.com server
-* Feature: Enable to switch whether rendering MathJax in realtime or not
-* Improvement: Replace markdown parser with markdown-it
-* Improvement: Generate anchor of headers with header strings
-* Improvement: Enhanced Scroll Sync on Markdown Editor/Preview
-* Improvement: Update `#revision-body` tab contents after saving with `Ctrl-S`
-* Fix: 500 Internal Server Error occures when basic-auth configuration is set
-
-## v2.3.9
-
-* Fix: `Ctrl-/` doesn't work on Chrome
-* Fix: Close Shortcuts help with `Ctrl-/`, ESC key
-* Fix: Jump to last line wrongly when `.revision-head-edit-button` clicked
-* Support: Upgrade libs
-    * googleapis
-
-## v2.3.8
-
-* Feature: Suggest page path when creating pages
-* Improvement: Prevent keyboard shortcuts when modal is opened
-* Improvement: PageHistory UI
-* Improvement: Ensure to scroll when edit button of section clicked
-* Improvement: Enabled to toggle the style for active line
-* Support: Upgrade libs
-    * style-loader
-    * react-codemirror2
-
-## v2.3.7
-
-* Fix: Open popups when `Ctrl+C` pressed
-    * Introduced by 2.3.5
-
-## v2.3.6
-
-* Feature: Theme Selector for Editor
-* Improvement: Remove unportalize button from crowi-plus layout
-* Fix: CSS for admin pages
-* Support: Shrink the size of libraries to include
-
-## v2.3.5
-
-* Feature: Enhanced Editor by CodeMirror
-* Feature: Emoji AutoComplete
-* Feature: Add keyboard shortcuts
-* Improvement: Attaching file with Dropzone.js
-* Improvement: Show shortcuts help with `Ctrl-/`
-* Fix: DOMs that has `.alert-info` class don't be displayed
-* Support: Switch and upgrade libs
-    * 8fold-marked -> marked
-    * react-bootstrap
-    * googleapis
-    * mongoose
-    * mongoose-unique-validator
-    * etc..
-
-## v2.3.4 (Missing number)
-
-## v2.3.3
-
-* Fix: The XSS Library escapes inline code blocks
-    * Degraded by 2.3.0
-* Fix: NPE occurs on Elasticsearch when initial access
-* Fix: Couldn't invite users(failed to create)
-
-## v2.3.2
-
-* Improvement: Add LDAP group search options
-
-## v2.3.1
-
-* Fix: Blockquote doesn't work
-    * Degraded by 2.3.0
-* Fix: Couldn't create user with first LDAP logging in
-
-## v2.3.0
-
-* Feature: LDAP Authentication
-* Improvement: Prevent XSS
-* Fix: node versions couldn't be shown
-* Support: Upgrade libs
-    * express-pino-logger
-
-## v2.2.4
-
-* Fix: googleapis v23.0.0 lost the function `oauth2Client.setCredentials`
-    * Degraded by 2.2.2 updates
-* Fix: HeaderSearchBox didn't append 'q=' param when searching
-    * Degraded by 2.2.3 updates
-
-## v2.2.3
-
-* Fix: The server responds anything when using passport
-    * Degraded by 2.2.2 updates
-* Fix: Update `lastLoginAt` when login is success
-* Support: Replace moment with date-fns
-* Support: Upgrade react-bootstrap-typeahead
-* Improvement: Replace emojify.js with emojione
-
-## v2.2.2 (Missing number)
-
-## v2.2.1
-
-* Feature: Duplicate page
-* Improve: Ensure that admin users can remove users waiting for approval
-* Fix: Modal doesn't work with React v16
-* Support: Upgrade React to 16
-* Support: Upgrade outdated libs
-
-## v2.2.0
-
-* Support: Merge official Crowi v1.6.3
-
-## v2.1.2
-
-* Improvement: Ensure to prevent suspending own account
-* Fix: Ensure to be able to use `.` for username when invited
-* Fix: monospace font for `<code></code>`
-
-## v2.1.1
-
-* Fix: The problem that React Modal doesn't work
-* Support: Lock some packages(react, react-dom, mongoose)
-
-## v2.1.0
-
-* Feature: Adopt Passport the authentication middleware
-* Feature: Selective batch deletion in search result page
-* Improvement: Ensure to be able to login with both of username or email
-* Fix: The problem that couldn't update user data in /me
-* Support: Upgrade outdated libs
-
-## v2.0.9
-
-* Fix: Server is down when a guest user accesses to someone's private pages
-* Support: Merge official Crowi (master branch)
-* Support: Upgrade outdated libs
-
-## v2.0.8
-
-* Fix: The problem that path including round bracket makes something bad
-* Fix: Recursively option processes also unexpedted pages
-* Fix: en_US translation
-
-## v2.0.7
-
-* Improvement: Add recursively option for Delete/Move/Putback operation
-* Improvement: Comment layout and sort order (crowi-plus Enhanced Layout)
-
-## v2.0.6
-
-* Fix: check whether `$APP_DIR/public/uploads` exists before creating symlink
-    * Fixed in weseek/crowi-plus-docker
-
-## v2.0.5
-
-* Improvement: Adjust styles for CodeMirror
-* Fix: File upload does not work when using crowi-plus-docker-compose and `FILE_UPLOAD=local` is set  
-    * Fixed in weseek/crowi-plus-docker
-
-## v2.0.2 - 2.0.4 (Missing number)
-
-## v2.0.1
-
-* Feature: Custom Script
-* Improvement: Adjust layout and styles for admin pages
-* Improvement: Record and show last updated date in user list page
-* Fix: Ignore Ctrl+(Shift+)Tab when editing (cherry-pick from the official)
-
-## v2.0.0
-
-* Feature: Enabled to integrate with Slack using Incoming Webhooks
-* Support: Upgrade all outdated libs
-
-## v1.2.16
-
-* Improvement: Condition for creating portal
-* Fix: Couldn't create new page after installation cleanly
-
-## v1.2.15
-
-* Improvement: Optimize cache settings for express server
-* Improvement: Add a logo link to the affix header
-* Fix: Child pages under `/trash` are not shown when applying crowi-plus Simplified Behavior
-
-## v1.2.14
-
-* Fix: Tabs(`a[data-toggle="tab"][href="#..."]`) push browser history twice
-* Fix: `a[href="#edit-form"]` still save history even when disabling pushing states option
-
-## v1.2.13
-
-* Improvement: Enabled to switch whether to push states with History API when tabs changes
-* Fix: Layout of the Not Found page
-
-## v1.2.12 (Missing number)
-
-## v1.2.11
-
-* Improvement: Enabled to open editing form from affix header
-* Improvement: Enabled to open editing form from each section headers
-
-## v1.2.10
-
-* Fix: Revise `server:prod:container` script for backward compatibility
-
-## v1.2.9
-
-* Improvement: Enabled to save with <kbd>⌘+S</kbd> on Mac
-* Improvement: Adopt the fastest logger 'pino'
-* Fix: The problem that can't upload profile image
-
-## v1.2.8
-
-* Fix: The problem that redirect doesn't work when using 'crowi-plus Simplified Behavior'
-
-## v1.2.7 (Missing number)
-
-## v1.2.6
-
-* Fix: The problem that page_list widget doesn't show the picture of revision.author
-* Fix: Change implementation of Bootstrap3 toggle switch for admin pages
-
-## v1.2.5
-
-* Feature: crowi-plus Simplified Behavior
-    * `/page` and `/page/` both shows the page
-    * `/nonexistent_page` shows editing form
-    * All pages shows the list of sub pages
-* Improvement: Ensure to be able to disable Timeline feature
-
-## v1.2.4
-
-* Fix: Internal Server Error has occurred when a guest user visited the page someone added "liked"
-
-## v1.2.3
-
-* Improvement: Ensure to be able to use Presentation Mode even when not logged in
-* Improvement: Presentation Mode on IE11 (Experimental)
-* Fix: Broken Presentation Mode
-
-## v1.2.2
-
-* Support: Merge official Crowi (master branch)
-
-## v1.2.1
-
-* Fix: buildIndex error occured when access to installer
-
-## v1.2.0
-
-* Support: Merge official Crowi v1.6.2
-
-## v1.1.12
-
-* Feature: Remove Comment Button
-
-## v1.1.11
-
-* Fix: Omit Comment form from page_list (crowi-plus Enhanced Layout)
-* Fix: .search-box is broken on sm/xs screen
-
-## v1.1.10
-
-* Fix: .search-box is broken on sm/xs screen
-* Support: Browsable with IE11 (Experimental)
-
-## v1.1.9
-
-* Improvement: Ensure to generate indices of Elasticsearch when installed
-* Fix: Specify the version of Bonsai Elasticsearch on Heroku
-
-## v1.1.8
-
-* Fix: Depth of dropdown-menu when `.on-edit`
-* Fix: Error occured on saveing with `Ctrl-S`
-* Fix: Guest users browsing
-
-## v1.1.7
-
-* Feature: Add option to allow guest users to browse
-* Fix: crowi-plus Enhanced Layout
-
-## v1.1.6
-
-* Fix: crowi-plus Enhanced Layout
-
-## v1.1.5
-
-* Fix: crowi-plus Enhanced Layout
-* Support: Merge official Crowi v1.6.1 master branch [573144b]
-
-## v1.1.4
-
-* Feature: Ensure to select layout type from Admin Page
-* Feature: Add crowi-plus Enhanced Layout
-
-## v1.1.3
-
-* Improvement: Use POSIX-style paths (bollowed crowi/crowi#219 by @Tomasom)
-
-## v1.1.2
-
-* Imprv: Brushup fonts and styles
-* Fix: Ensure to specity revision id when saving with `Ctrl-S`
-
-## v1.1.1
-
-* Feature: Save with `Ctrl-S`
-* Imprv: Brushup fonts and styles
-
-## v1.1.0
-
-* Support: Merge official Crowi v1.6.1
-
-## v1.0.9
-
-* Feature: Delete user
-* Feature: Upload other than images
-
-## v1.0.8
-
-* Feature: Ensure to delete page completely
-* Feature: Ensure to delete redirect page
-* Fix: https access to Gravatar (this time for sure)
-
-## v1.0.7
-
-* Feature: Keyboard navigation for search box
-* Improvement: Intelligent Search
-
-## v1.0.6
-
-* Feature: Copy button that copies page path to clipboard
-* Fix: https access to Gravatar
-* Fix: server watching crash with `Error: read ECONNRESET` on Google Chrome
-
-## v1.0.5
-
-* Feature: Ensure to use Gravatar for profile image
-
-## v1.0.4
-
-* Improvement: Detach code blocks before preProcess
-* Support: Ensure to deploy to Heroku with INSTALL_PLUGINS env
-* Support: Ensure to load plugins easily when development
-
-## v1.0.3
-
-* Improvement: Adjust styles
-
-## v1.0.2
-
-* Improvement: For lsx
-
-## v1.0.1
-
-* Feature: Custom CSS
-* Support: Notify build failure to Slask
-
-## v1.0.0
-
-* Feature: Plugin mechanism
-* Feature: Switchable LineBreaks ON/OFF from admin page
-* Improvement: Exclude Environment-dependency
-* Improvement: Enhanced linker
-* Support: Add Dockerfile
-* Support: Abolish gulp
-* Support: LiveReload
-* Support: Update libs

+ 5 - 7
README.md

@@ -97,13 +97,11 @@ See [GROWI Docs: Environment Variables](https://docs.growi.org/en/admin-guide/ad
 
 
 ## Command details
 ## Command details
 
 
-| command                | desc                                                    |
-| ---------------------- | ------------------------------------------------------- |
-| `yarn run build:prod`  | Build the client                                        |
-| `yarn run server:prod` | Launch the server                                       |
-| `yarn start`           | Invoke `yarn run build:prod` and `yarn run server:prod` |
-
-<!-- The following links do not exist -->
+| command           | desc                                                    |
+| ------------------| ------------------------------------------------------- |
+| `yarn app:build`  | Build GROWI app client                                  |
+| `yarn app:server` | Launch GROWI app server                                 |
+| `yarn start`      | Invoke `yarn app:build` and `yarn app:server`           |
 
 
 For more info, see [GROWI Docs: List of npm Commands](https://docs.growi.org/en/dev/startup-v2/launch-system.html#list-of-npm-commands).
 For more info, see [GROWI Docs: List of npm Commands](https://docs.growi.org/en/dev/startup-v2/launch-system.html#list-of-npm-commands).
 
 

+ 5 - 7
README_JP.md

@@ -96,13 +96,11 @@ Crowi からの移行は **[こちら](https://docs.growi.org/en/admin-guide/mig
 
 
 ## コマンド詳細
 ## コマンド詳細
 
 
-| コマンド               | 説明                                                             |
-| ---------------------- | ---------------------------------------------------------------- |
-| `yarn run build:prod`  | クライアントをビルドします。                                     |
-| `yarn run server:prod` | サーバーを起動します。                                           |
-| `yarn start`           | `yarn run build:prod` と `yarn run server:prod` を呼び出します。 |
-
-  <!-- 以下のリンクは存在しない (ja と en 両方) -->
+| コマンド          | 説明                                                    |
+| ------------------| ------------------------------------------------------- |
+| `yarn app:build`  | GROWI app クライアントをビルドします。                  |
+| `yarn app:server` | GROWI app サーバーを起動します。                        |
+| `yarn start`      | `yarn app:build` と `yarn app:server` を呼び出します。  |
 
 
 詳しくは [GROWI Docs: List of npm Commands](https://docs.growi.org/ja/dev/startup-v2/launch-system.html#npm-コマンドリスト)をご覧ください。
 詳しくは [GROWI Docs: List of npm Commands](https://docs.growi.org/ja/dev/startup-v2/launch-system.html#npm-コマンドリスト)をご覧ください。
 
 

+ 22 - 0
SECURITY.md

@@ -0,0 +1,22 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported          |
+| ------- | ------------------ |
+| 4.4.x   | :white_check_mark: |
+| < 4.3   | :x:                |
+
+## Reporting Security Issues
+
+**please do not report security vulnerabilities through public GitHub issues.**
+
+If you believe you have found a security vulnerability in any GROWI related repository, please report it to us using one of the methods described below.
+
+  * [Join our Slack team](https://growi-slackin.weseek.co.jp/) and send DM to `@yuki` who is the lead developer
+  * Report to JPCERT/CC ([en](https://www.jpcert.or.jp/english/ir/form.html)/[ja](https://www.jpcert.or.jp/form/))
+
+## Preferred Languages
+
+Communication in English and Japanese is possible.  
+In Japanese, we can reply more quickly. 

+ 0 - 43
app.json

@@ -1,43 +0,0 @@
-{
-  "name": "growi",
-  "description": "Team collaboration system with markdown",
-  "keywords": [
-    "wiki",
-    "communication"
-  ],
-  "repository": "https://github.com/weseek/growi",
-  "success_url": "/",
-  "env": {
-    "NODE_ENV": {
-      "description": "DO NOT CHANGE - 'yarn' needs this to install devDependencies",
-      "value": "development"
-    },
-    "FILE_UPLOAD": {
-      "description": "Attached files storage. - mongodb | aws | local | none",
-      "value": "mongodb",
-      "required": false
-    },
-    "SECRET_TOKEN": {
-      "description": "A secret key for verifying the integrity of signed cookies.",
-      "generator": "secret"
-    },
-    "PASSWORD_SEED": {
-      "description": "A password seed is used by password hash generator. ",
-      "generator": "secret"
-    },
-    "ADDITIONAL_PACKAGES": {
-      "description": "Space-separated list of npm package names to install.",
-      "value": "growi-plugin-lsx growi-plugin-pukiwiki-like-linker growi-plugin-attachment-refs react-images@1.0.0 react-motion",
-      "required": false
-    }
-  },
-  "addons": [
-    "mongolab",
-    {
-      "plan": "searchbox:starter",
-      "options": {
-        "es_version": "6"
-      }
-    }
-  ]
-}

+ 0 - 39
babel.config.js

@@ -1,39 +0,0 @@
-module.exports = function(api) {
-  api.cache(true);
-
-  const presets = [
-    [
-      '@babel/preset-env',
-      {
-        targets: {
-          node: 'current',
-        },
-      },
-    ],
-    '@babel/preset-react',
-  ];
-  const plugins = [
-    'lodash',
-    // transform
-    //  from `import { Button } from 'reactstrap';`
-    //  to   `import Row from 'reactstrap/Button';`
-    [
-      'transform-imports', {
-        reactstrap: {
-          // eslint-disable-next-line no-template-curly-in-string
-          transform: 'reactstrap/es/${member}',
-          preventFullImport: true,
-        },
-      },
-    ],
-    '@babel/plugin-proposal-optional-chaining',
-    [
-      '@babel/plugin-proposal-class-properties', { loose: true },
-    ],
-  ];
-
-  return {
-    presets,
-    plugins,
-  };
-};

+ 0 - 43
bin/generate-plugin-definitions-source.js

@@ -1,43 +0,0 @@
-/**
- * the tool for genetion of plugin definitions source code
- *
- * @author Yuki Takei <yuki@weseek.co.jp>
- */
-require('module-alias/register');
-const logger = require('@alias/logger')('growi:bin:generate-plugin-definitions-source');
-
-const fs = require('graceful-fs');
-const normalize = require('normalize-path');
-const swig = require('swig-templates');
-
-const helpers = require('@commons/util/helpers');
-const PluginUtils = require('@server/plugins/plugin-utils');
-
-const pluginUtils = new PluginUtils();
-
-const TEMPLATE = helpers.root('bin/templates/plugin-definitions.js.swig');
-const OUT = helpers.root('tmp/plugins/plugin-definitions.js');
-
-
-// list plugin names
-const pluginNames = pluginUtils.listPluginNames(helpers.root());
-logger.info('Detected plugins: ', pluginNames);
-
-// get definitions
-const definitions = pluginNames
-  .map((name) => {
-    return pluginUtils.generatePluginDefinition(name, true);
-  })
-  .map((definition) => {
-    // convert backslash to slash
-    definition.entries = definition.entries.map((entryPath) => {
-      return normalize(entryPath);
-    });
-    return definition;
-  });
-
-const compiledTemplate = swig.compileFile(TEMPLATE);
-const code = compiledTemplate({ definitions });
-
-// write
-fs.writeFileSync(OUT, code);

+ 4 - 0
bin/github-actions/bump-versions/README.md

@@ -0,0 +1,4 @@
+bump-versions.js
+==============
+
+Custom cli for bumping package versions based on [algolia/shipjs@0.23.3](https://github.com/algolia/shipjs/tree/v0.23.3/packages/shipjs)

+ 18 - 0
bin/github-actions/bump-versions/cli.js

@@ -0,0 +1,18 @@
+import { print, parseArgs } from 'shipjs/src/util';
+import bumpVersions from './flow/bump-versions';
+
+export async function cli(argv) {
+  const { fn, arg: argSpec } = bumpVersions;
+  try {
+    const opts = parseArgs(argSpec, argv);
+    await fn(opts);
+  }
+  catch (error) {
+    if (error.code === 'ARG_UNKNOWN_OPTION') {
+      print(error);
+    }
+    else {
+      throw error;
+    }
+  }
+}

+ 71 - 0
bin/github-actions/bump-versions/flow/bump-versions.js

@@ -0,0 +1,71 @@
+import semver from 'semver';
+import { loadConfig, getCurrentVersion, getReleaseType } from 'shipjs-lib';
+
+import printDryRunBanner from 'shipjs/src/step/printDryRunBanner';
+import confirmNextVersion from 'shipjs/src/step/prepare/confirmNextVersion';
+import updateVersion from 'shipjs/src/step/prepare/updateVersion';
+import updateVersionMonorepo from 'shipjs/src/step/prepare/updateVersionMonorepo';
+import installDependencies from 'shipjs/src/step/prepare/installDependencies';
+
+import printHelp from '../step/printHelp';
+
+async function bumpVersions({
+  help = false,
+  dir = '.',
+  dryRun = false,
+  increment = 'patch',
+  preid = 'RC',
+}) {
+  if (help) {
+    printHelp();
+    return;
+  }
+  if (dryRun) {
+    printDryRunBanner();
+  }
+
+  const config = await loadConfig(dir, 'bump-versions.config');
+
+  // get current version
+  const { monorepo } = config;
+  const currentVersion = monorepo && monorepo.mainVersionFile
+    ? getCurrentVersion(dir, monorepo.mainVersionFile)
+    : getCurrentVersion(dir);
+
+  // determine next version
+  let nextVersion = semver.inc(currentVersion, increment, preid); // set preid if type is 'prerelease'
+  nextVersion = await confirmNextVersion({
+    yes: true,
+    currentVersion,
+    nextVersion,
+    dryRun,
+  });
+  const releaseType = getReleaseType(nextVersion);
+
+  // update
+  const updateVersionFn = monorepo
+    ? updateVersionMonorepo
+    : updateVersion;
+  await updateVersionFn({
+    config, nextVersion, releaseType, dir, dryRun,
+  });
+}
+
+const arg = {
+  '--dir': String,
+  '--help': Boolean,
+  '--dry-run': Boolean,
+  '--increment': String,
+  '--preid': String,
+
+  // Aliases
+  '-d': '--dir',
+  '-h': '--help',
+  '-D': '--dry-run',
+  '-i': '--increment',
+};
+
+export default {
+  arg,
+  fn: bumpVersions,
+};

+ 16 - 0
bin/github-actions/bump-versions/index.js

@@ -0,0 +1,16 @@
+#!/usr/bin/env node
+
+// eslint-disable-next-line no-global-assign
+require = require('esm')(module);
+
+(async function() {
+  try {
+    process.env.SHIPJS = true;
+    await require('./cli').cli(process.argv);
+  }
+  catch (e) {
+    // eslint-disable-next-line no-console
+    console.error(e);
+    process.exit(1);
+  }
+}());

+ 54 - 0
bin/github-actions/bump-versions/step/printHelp.js

@@ -0,0 +1,54 @@
+import runStep from 'shipjs/src/step/runStep';
+import { print } from 'shipjs/src/util';
+import { bold, underline } from 'shipjs/src/color';
+
+export default () => runStep({}, () => {
+  const indent = line => `\t${line}`;
+
+  const help = '--help';
+  const dir = `--dir ${underline('PATH')}`;
+  const increment = `--increment ${underline('LEVEL')}`;
+  const preId = `--preid ${underline('IDENTIFIER')}`;
+  const dryRun = '--dry-run';
+  const all = [help, dir, increment, preId, dryRun]
+    .map(x => `[${x}]`)
+    .join(' ');
+
+  const messages = [
+    bold('NAME'),
+    indent('bump-versions - Bump versions of packages.'),
+    '',
+    bold('USAGE'),
+    indent(`node ./bin/github-actions/bump-versions ${all}`),
+    '',
+    bold('OPTIONS'),
+    indent(`-h, ${help}`),
+    indent('  Print this help'),
+    '',
+    indent(`-d, ${dir}`),
+    indent(
+      `  Specify the ${underline(
+        'PATH',
+      )} of the repository (default: the current directory).`,
+    ),
+    '',
+    indent(`-i, ${increment}`),
+    indent(
+      `  Specify the ${underline(
+        'LEVEL',
+      )} for semver.inc() to increment a version (default: 'patch').`,
+    ),
+    '',
+    indent(`${preId}`),
+    indent(
+      `  Specify the ${underline(
+        'IDENTIFIER',
+      )} for semver.inc() with 'prerelease' type (default: 'RC').`,
+    ),
+    '',
+    indent(`-D, ${dryRun}`),
+    indent('  Displays the steps without actually doing them.'),
+    '',
+  ];
+  print(messages.join('\n'));
+});

+ 1 - 0
bin/github-actions/list-branches.js

@@ -18,6 +18,7 @@ const EXCLUDE_PATTERNS = [
   // https://regex101.com/r/Lnx7Pz/3
   // https://regex101.com/r/Lnx7Pz/3
   /^dev\/[\d.x]*$/,
   /^dev\/[\d.x]*$/,
   /^release\/.+$/,
   /^release\/.+$/,
+  /^dependabot\/.+$/,
 ];
 ];
 const LEGAL_PATTERNS = [
 const LEGAL_PATTERNS = [
   /^master$/,
   /^master$/,

+ 0 - 6
bin/github-actions/update-readme.sh

@@ -1,6 +0,0 @@
-#!/bin/sh
-
-cd docker
-
-sed -i -e "s/^\([*] \[\`\)[^\`]\+\(\`, \`4\.3\`, .\+\]\)\(.\+\/blob\/v\).\+\(\/docker\/Dockerfile.\+\)$/\1${RELEASE_VERSION}\2\3${RELEASE_VERSION}\4/" README.md
-sed -i -e "s/^\([*] \[\`\)[^\`]\+\(\`, \`4\.3-nocdn\`, .\+\]\)\(.\+\/blob\/v\).\+\(\/docker\/Dockerfile.\+\)$/\1${RELEASE_VERSION}-nocdn\2\3${RELEASE_VERSION}\4/" README.md

+ 12 - 0
bump-versions.config.js

@@ -0,0 +1,12 @@
+/*
+ * Reference: https://community.algolia.com/shipjs/
+ */
+module.exports = {
+  monorepo: {
+    mainVersionFile: 'lerna.json',
+    packagesToBump: [
+      './',
+      'packages/*',
+    ],
+  },
+};

+ 0 - 26
config/env.dev.js

@@ -1,26 +0,0 @@
-module.exports = {
-  NODE_ENV: 'development',
-  FILE_UPLOAD: 'mongodb',
-  // MONGO_GRIDFS_TOTAL_LIMIT: 10485760,   // 10MB
-  MATHJAX: 1,
-  // NO_CDN: true,
-  MONGO_URI: 'mongodb://mongo:27017/growi',
-  // REDIS_URI: 'http://redis:6379',
-  // NCHAN_URI: 'http://nchan',
-  ELASTICSEARCH_URI: 'http://elasticsearch:9200/growi',
-  HACKMD_URI: 'http://localhost:3010',
-  HACKMD_URI_FOR_SERVER: 'http://hackmd:3000',
-  // DRAWIO_URI: 'http://localhost:8080/?offline=1&https=0',
-  // S2SMSG_PUBSUB_SERVER_TYPE: 'nchan',
-  // PUBLISH_OPEN_API: true,
-  // USER_UPPER_LIMIT: 0,
-  // DEV_HTTPS: true,
-  // FORCE_WIKI_MODE: 'private', // 'public', 'private', undefined
-  // PROMSTER_ENABLED: true,
-  // SLACK_SIGNING_SECRET: '',
-  // SLACK_BOT_TOKEN: '',
-  SALT_FOR_GTOP_TOKEN: 'proxy',
-  SALT_FOR_PTOG_TOKEN: 'growi',
-  // GROWI_CLOUD_URI: 'http://growi.cloud',
-  // GROWI_APP_ID_FOR_GROWI_CLOUD: '012345',
-};

+ 0 - 4
config/env.prod.js

@@ -1,4 +0,0 @@
-module.exports = {
-  NODE_ENV: 'production',
-  // FORMAT_NODE_LOG: false, // default: true
-};

+ 0 - 13
config/index.js

@@ -1,13 +0,0 @@
-function envShortName() {
-  switch (process.env.NODE_ENV) {
-    case 'production':
-      return 'prod';
-    default:
-      return 'dev';
-  }
-}
-
-module.exports = {
-  env: require(`./env.${envShortName()}`),
-  logger: require(`./logger/config.${envShortName()}`),
-};

+ 0 - 14
docker/docker-entrypoint.sh

@@ -1,14 +0,0 @@
-#!/bin/sh
-
-set -e
-
-# Support `FILE_UPLOAD=local`
-mkdir -p /data/uploads
-if [ ! -e "$appDir/public/uploads" ]; then
-  ln -s /data/uploads $appDir/public/uploads
-fi
-
-chown -R node:node /data/uploads
-chown -h node:node $appDir/public/uploads
-
-gosu node $@

+ 2 - 2
lerna.json

@@ -1,8 +1,8 @@
 {
 {
   "npmClient": "yarn",
   "npmClient": "yarn",
   "useWorkspaces": true,
   "useWorkspaces": true,
+  "version": "4.4.6-RC.0",
   "packages": [
   "packages": [
     "packages/*"
     "packages/*"
-  ],
-  "version": "independent"
+  ]
 }
 }

+ 42 - 62
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "growi",
   "name": "growi",
-  "version": "4.3.0-RC",
+  "version": "4.4.6-RC.0",
   "description": "Team collaboration software using markdown",
   "description": "Team collaboration software using markdown",
   "tags": [
   "tags": [
     "wiki",
     "wiki",
@@ -21,73 +21,53 @@
   },
   },
   "private": true,
   "private": true,
   "workspaces": {
   "workspaces": {
-    "packages": ["packages/*"],
-    "nohoist": ["**/slackbot-proxy/bootstrap"]
+    "packages": [
+      "packages/*"
+    ],
+    "nohoist": [
+      "**/slackbot-proxy/bootstrap"
+    ]
   },
   },
   "scripts": {
   "scripts": {
-    "build:api:jsdoc": "swagger-jsdoc -o tmp/swagger.json -d config/swagger-definition.js",
-    "build:apiv3:jsdoc": "cross-env API_VERSION=3 npm run build:api:jsdoc -- \"src/server/routes/apiv3/**/*.js\" \"src/server/models/**/*.js\"",
-    "build:apiv1:jsdoc": "cross-env API_VERSION=1 npm run build:api:jsdoc -- \"src/server/*/*.js\" \"src/server/models/**/*.js\"",
-    "build:dev:app:watch": "npm run build:dev:app -- --watch",
-    "build:dev:app:watch:poll": "npm run build:dev:app -- --watch --watch-poll",
-    "build:dev:app": "env-cmd -f config/env.dev.js webpack --config config/webpack.dev.js --progress",
-    "build:dev:watch": "npm run build:dev:app:watch",
-    "build:dev:watch:poll": "npm run build:dev:app:watch:poll",
-    "build:dev": "yarn build:dev:app",
-    "build:slack": "lerna run build --scope @growi/slack",
-    "build": "npm run build:dev:watch",
-    "build:poll": "npm run build:dev:watch:poll",
-    "clean:app": "rimraf -- public/js public/styles",
-    "clean:report": "rimraf -- report",
-    "clean": "npm-run-all -p clean:*",
-    "console": "env-cmd -f config/env.dev.js node --experimental-repl-await src/server/console.js",
-    "lint:js:fix": "eslint \"**/*.{js,jsx}\" --fix",
-    "lint:js": "eslint \"**/*.{js,jsx}\"",
-    "lint:styles:fix": "stylelint --fix src/client/styles/scss/**/*.scss",
-    "lint:styles": "stylelint src/client/styles/scss/**/*.scss",
-    "lint:swagger2openapi": "node node_modules/swagger2openapi/oas-validate tmp/swagger.json",
-    "lint": "npm-run-all -p lint:js lint:styles lint:swagger2openapi",
-    "migrate": "npm run migrate:up",
-    "migrate:create": "migrate-mongo create -f config/migrate.js -- ",
-    "migrate:status": "migrate-mongo status -f config/migrate.js",
-    "migrate:up": "migrate-mongo up -f config/migrate.js",
-    "migrate:down": "migrate-mongo down -f config/migrate.js",
-    "plugin:def": "node bin/generate-plugin-definitions-source.js",
-    "prebuild:dev:watch": "npm run prebuild:dev",
-    "prebuild:dev": "npm run clean:app && env-cmd -f config/env.dev.js npm run plugin:def && env-cmd -f config/env.dev.js npm run resource && yarn build:slack",
-    "prelint:swagger2openapi": "npm run build:apiv3:jsdoc",
-    "preserver:prod": "npm run migrate",
-    "prestart": "npm run build:prod",
-    "resource": "node bin/download-cdn-resources.js",
-    "i18n-json-merge:withTran": "rs-i18n -lan -- -t",
-    "i18n-json-merge:noTran": "rs-i18n -lan --",
-    "i18n-json-merge": "npm run i18n-json-merge:withTran --",
-    "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 --expose_gc --inspect src/server/app.js",
-    "server:prod:ci": "npm run server:prod -- --ci",
-    "server:prod": "env-cmd -f config/env.prod.js node --expose_gc src/server/app.js",
-    "server": "npm run server:dev",
-    "start": "npm run server:prod",
-    "test": "jest --config=config/jest.config.js --passWithNoTests -- ",
-    "version": "node -p \"require('./package.json').version\"",
-    "webpack": "webpack"
+    "start": "yarn app:server",
+    "prestart": "yarn app:build",
+    "app:build": "yarn lerna run build",
+    "app:server": "yarn lerna run server --scope @growi/app",
+    "slackbot-proxy:build": "yarn lerna run build --scope @growi/slackbot-proxy --scope @growi/slack",
+    "slackbot-proxy:server": "yarn lerna run start:prod --scope @growi/slackbot-proxy",
+    "//// scripts for backward compatibility": "",
+    "build:prod": "echo !!! CAUTION !!! ==> The script 'build:prod' is deprecated. Use 'yarn app:build' instead. && yarn app:build",
+    "server:prod": "echo !!! CAUTION !!! ==> The script 'server:prod' is deprecated. Use 'yarn app:build' instead. && yarn app:server"
   },
   },
   "dependencies": {
   "dependencies": {
+    "cross-env": "^7.0.0",
+    "dotenv-flow": "^3.2.0",
+    "npm-run-all": "^4.1.5",
+    "ts-node": "^9.1.1",
+    "tsconfig-paths": "^3.9.0",
+    "tslib": "^2.3.1",
+    "typescript": "^4.2.3"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "lerna": "^4.0.0"
-  },
-  "_moduleAliases": {
-    "@root": ".",
-    "@commons": "src/lib",
-    "@server": "src/server",
-    "@alias/logger": "src/lib/service/logger",
-    "debug": "src/lib/service/logger/alias-for-debug"
-  },
-  "jest": {
-    "moduleNameMapper": {
-      "@commons/(.*)": "<rootDir>/src/lib/$1"
-    }
+    "@types/jest": "^26.0.22",
+    "@types/node": "^14.14.35",
+    "@types/rewire": "^2.5.28",
+    "@typescript-eslint/eslint-plugin": "^4.28.5",
+    "@typescript-eslint/parser": "^4.28.5",
+    "eslint": "^7.31.0",
+    "eslint-config-weseek": "^1.1.0",
+    "eslint-import-resolver-typescript": "^2.4.0",
+    "eslint-plugin-import": "^2.23.4",
+    "eslint-plugin-jest": "^24.3.2",
+    "eslint-plugin-react": "^7.24.0",
+    "eslint-plugin-react-hooks": "^4.2.0",
+    "jest": "^27.0.6",
+    "jest-date-mock": "^1.0.8",
+    "jest-localstorage-mock": "^2.4.14",
+    "lerna": "^4.0.0",
+    "rewire": "^5.0.0",
+    "shipjs": "^0.23.3",
+    "ts-jest": "^27.0.4"
   },
   },
   "engines": {
   "engines": {
     "node": "^12 || ^14",
     "node": "^12 || ^14",

+ 26 - 0
packages/app/.env.development

@@ -0,0 +1,26 @@
+##
+## Handled by Next.js with dotenv or dotenv-flow
+## https://nextjs.org/docs/basic-features/environment-variables
+##
+FILE_UPLOAD=mongodb
+# MONGO_GRIDFS_TOTAL_LIMIT=10485760
+MATHJAX=1
+# NO_CDN=true
+MONGO_URI="mongodb://mongo:27017/growi"
+# REDIS_URI="http://redis:6379"
+# NCHAN_URI="http://nchan"
+ELASTICSEARCH_URI="http://elasticsearch:9200/growi"
+ELASTICSEARCH_REQUEST_TIMEOUT=15000
+HACKMD_URI="http://localhost:3010"
+HACKMD_URI_FOR_SERVER="http://hackmd:3000"
+# DRAWIO_URI="http://localhost:8080/?offline=1&https=0"
+# S2SMSG_PUBSUB_SERVER_TYPE=nchan
+# PUBLISH_OPEN_API=true
+# USER_UPPER_LIMIT=0
+# DEV_HTTPS=true
+# FORCE_WIKI_MODE=private
+# PROMSTER_ENABLED=true
+# SLACKBOT_WITHOUT_PROXY_SIGNING_SECRET=''
+# SLACKBOT_WITHOUT_PROXY_BOT_TOKEN=''
+# GROWI_CLOUD_URI='http://growi.cloud'
+# GROWI_APP_ID_FOR_GROWI_CLOUD=012345

+ 5 - 0
packages/app/.env.production

@@ -0,0 +1,5 @@
+##
+## Handled by Next.js with dotenv or dotenv-flow
+## https://nextjs.org/docs/basic-features/environment-variables
+##
+FORMAT_NODE_LOG=false

+ 6 - 0
packages/app/.eslintignore

@@ -0,0 +1,6 @@
+/dist/**
+/public/**
+/src/client/legacy/thirdparty-js/**
+/src/client/util/reveal/plugins/markdown.js
+/src/linter-checker/**
+/tmp/**

+ 35 - 0
packages/app/.eslintrc.js

@@ -0,0 +1,35 @@
+module.exports = {
+  extends: [
+    'weseek/react',
+    'weseek/typescript',
+  ],
+  env: {
+    jquery: true,
+  },
+  globals: {
+    $: true,
+    jquery: true,
+    emojione: true,
+    hljs: true,
+    ScrollPosStyler: true,
+    window: true,
+  },
+  settings: {
+    // resolve path aliases by eslint-import-resolver-typescript
+    'import/resolver': {
+      typescript: {},
+    },
+  },
+  rules: {
+    'no-restricted-imports': ['error', {
+      name: 'axios',
+      message: 'Please use src/utils/axios instead.',
+    }],
+    // set 'warn' temporarily -- 2021.08.02 Yuki Takei
+    '@typescript-eslint/explicit-module-boundary-types': ['warn'],
+    '@typescript-eslint/no-use-before-define': ['warn'],
+    '@typescript-eslint/no-this-alias': ['warn'],
+    '@typescript-eslint/no-var-requires': ['warn'],
+    'jest/no-done-callback': ['warn'],
+  },
+};

+ 22 - 0
packages/app/.gitignore

@@ -0,0 +1,22 @@
+# next.js
+/.next/
+/out/
+
+# dist
+/dist/
+/transpiled/
+/public/static/js
+/public/static/dict
+/public/static/styles
+/public/uploads
+/tmp/
+*.d.ts
+
+# dist (for GROWI v4.x and below)
+/public/*.chunk.js
+/public/*.chunk.js.LICENSE.txt
+/public/*.bundle.js
+/public/manifest.json
+/public/dll
+/public/js
+/public/styles

+ 0 - 0
.prettierignore → packages/app/.prettierignore


+ 19 - 0
packages/app/.stylelintrc.json

@@ -0,0 +1,19 @@
+{
+  "extends": [
+    "stylelint-config-recess-order"
+  ],
+  "ignoreFiles": [
+    "src/styles/_override-bootstrap-variables.scss",
+    "src/linter-checker/test.scss"
+  ],
+  "rules": {
+    "indentation": 2,
+    "string-quotes": "single",
+    "rule-empty-line-before": [ "always-multi-line", {
+      "except": ["after-single-line-comment", "first-nested"],
+      "ignore": ["after-comment", "inside-block"]
+    } ],
+    "selector-combinator-space-before": "always",
+    "selector-combinator-space-after": "always"
+  }
+}

+ 170 - 0
packages/app/bin/cdn/cdn-resources-downloader.ts

@@ -0,0 +1,170 @@
+import path from 'path';
+import { URL } from 'url';
+import urljoin from 'url-join';
+import { Transform } from 'stream';
+import replaceStream from 'replacestream';
+
+import {
+  cdnLocalScriptRoot, cdnLocalDictRoot, cdnLocalStyleRoot, cdnLocalStyleWebRoot,
+} from '^/config/cdn';
+import * as cdnManifests from '^/resource/cdn-manifests';
+
+import { CdnResource, CdnManifest } from '~/interfaces/cdn';
+import loggerFactory from '~/utils/logger';
+import { downloadTo } from '~/utils/download';
+
+const logger = loggerFactory('growi:service:CdnResourcesDownloader');
+
+export default class CdnResourcesDownloader {
+
+  async downloadAndWriteAll(): Promise<any> {
+    const cdnScriptResources: CdnResource[] = cdnManifests.js.map((manifest: CdnManifest) => {
+      return { manifest, outDir: cdnLocalScriptRoot };
+    });
+
+    const cdnDictResources: CdnResource[] = cdnManifests.dict.map((manifest: CdnManifest) => {
+      return { manifest, outDir: cdnLocalDictRoot };
+    });
+
+    const dictExtensionOptions = {
+      ext: 'gz',
+    };
+
+    const cdnStyleResources: CdnResource[] = cdnManifests.style.map((manifest) => {
+      return { manifest, outDir: cdnLocalStyleRoot };
+    });
+
+    const dlStylesOptions = {
+      replaceUrl: {
+        webroot: cdnLocalStyleWebRoot,
+      },
+    };
+
+    return Promise.all([
+      this.downloadScripts(cdnScriptResources),
+      this.downloadScripts(cdnDictResources, dictExtensionOptions),
+      this.downloadStyles(cdnStyleResources, dlStylesOptions),
+    ]);
+  }
+
+  /**
+   * Download script files from CDN
+   * @param cdnResources JavaScript resource data
+   * @param options
+   */
+  private async downloadScripts(cdnResources: CdnResource[], options?: any): Promise<any> {
+    logger.debug('Downloading scripts', cdnResources);
+
+    const opts = Object.assign({}, options);
+    const ext = opts.ext || 'js';
+
+    const promises = cdnResources.map((cdnResource) => {
+      const { manifest } = cdnResource;
+
+      logger.info(`Processing CdnResource '${manifest.name}'`);
+
+      return downloadTo(
+        manifest.url,
+        cdnResource.outDir,
+        `${manifest.name}.${ext}`,
+      );
+    });
+
+    return Promise.all(promises);
+  }
+
+  /**
+   * Download style sheet file from CDN
+   *  Assets in CSS is also downloaded
+   * @param cdnResources CSS resource data
+   * @param options
+   */
+  private async downloadStyles(cdnResources: CdnResource[], options?: any): Promise<any> {
+    logger.debug('Downloading styles', cdnResources);
+
+    const opts = Object.assign({}, options);
+    const ext = opts.ext || 'css';
+
+    // styles
+    const assetsResourcesStore: CdnResource[] = [];
+    const promisesForStyle = cdnResources.map((cdnResource) => {
+      const { manifest } = cdnResource;
+
+      logger.info(`Processing CdnResource '${manifest.name}'`);
+
+      let urlReplacer: Transform|null = null;
+
+      // generate replaceStream instance
+      if (opts.replaceUrl != null) {
+        urlReplacer = this.generateReplaceUrlInCssStream(cdnResource, assetsResourcesStore, opts.replaceUrl.webroot);
+      }
+
+      return downloadTo(
+        manifest.url,
+        cdnResource.outDir,
+        `${manifest.name}.${ext}`,
+        urlReplacer,
+      );
+    });
+
+    // wait until all styles are downloaded
+    await Promise.all(promisesForStyle);
+
+    logger.debug('Downloading assets', assetsResourcesStore);
+
+    // assets in css
+    const promisesForAssets = assetsResourcesStore.map((cdnResource) => {
+      const { manifest } = cdnResource;
+
+      logger.info(`Processing assts in css '${manifest.name}'`);
+
+      return downloadTo(
+        manifest.url,
+        cdnResource.outDir,
+        manifest.name,
+      );
+    });
+
+    return Promise.all(promisesForAssets);
+  }
+
+  /**
+   * Generate replaceStream instance to replace 'url(..)'
+   *
+   * e.g.
+   *  Before  : url(../images/logo.svg)
+   *  After   : url(/path/to/webroot/${cdnResources.name}/logo.svg)
+   *
+   * @param cdnResource CSS resource data
+   * @param assetsResourcesStore An array to store CdnResource that is detected by 'url()' in CSS
+   * @param webroot
+   */
+  private generateReplaceUrlInCssStream(cdnResource: CdnResource, assetsResourcesStore: CdnResource[], webroot: string): Transform {
+    return replaceStream(
+      /url\((?!['"]?data:)["']?(.+?)["']?\)/g, // https://regex101.com/r/Sds38A/3
+      (match, url) => {
+        // generate URL Object
+        const parsedUrl = url.startsWith('http')
+          ? new URL(url) // when url is fqcn
+          : new URL(url, cdnResource.manifest.url); // when url is relative
+        const basename = path.basename(parsedUrl.pathname);
+
+        logger.debug(`${cdnResource.manifest.name} has ${parsedUrl.toString()}`);
+
+        // add assets metadata to download later
+        const replacedCdnResource = {
+          manifest: {
+            name: basename,
+            url: parsedUrl.toString(),
+          },
+          outDir: path.join(cdnResource.outDir, cdnResource.manifest.name),
+        };
+        assetsResourcesStore.push(replacedCdnResource);
+
+        const replaceUrl = urljoin(webroot, cdnResource.manifest.name, basename);
+        return `url(${replaceUrl})`;
+      },
+    );
+  }
+
+}

+ 6 - 8
bin/download-cdn-resources.js → packages/app/bin/download-cdn-resources.ts

@@ -3,14 +3,15 @@
  *
  *
  * @author Yuki Takei <yuki@weseek.co.jp>
  * @author Yuki Takei <yuki@weseek.co.jp>
  */
  */
-require('module-alias/register');
+import { envUtils } from 'growi-commons';
 
 
-const logger = require('@alias/logger')('growi:bin:download-cdn-resources');
+import CdnResourcesDownloader from './cdn/cdn-resources-downloader';
+import loggerFactory from '../src/utils/logger';
 
 
-const { envUtils } = require('growi-commons');
+const logger = loggerFactory('growi:bin:download-cdn-resources');
 
 
 // check env var
 // check env var
-const noCdn = envUtils.toBoolean(process.env.NO_CDN);
+const noCdn: boolean = envUtils.toBoolean(process.env.NO_CDN);
 if (!noCdn) {
 if (!noCdn) {
   logger.info('Using CDN. No resources are downloaded.');
   logger.info('Using CDN. No resources are downloaded.');
   // exit
   // exit
@@ -19,13 +20,10 @@ if (!noCdn) {
 
 
 logger.info('This is NO_CDN mode. Start to download resources.');
 logger.info('This is NO_CDN mode. Start to download resources.');
 
 
-const CdnResourcesDownloader = require('@commons/service/cdn-resources-downloader');
-const CdnResourcesService = require('@commons/service/cdn-resources-service');
 
 
 const downloader = new CdnResourcesDownloader();
 const downloader = new CdnResourcesDownloader();
-const service = new CdnResourcesService();
 
 
-service.downloadAndWriteAll(downloader)
+downloader.downloadAndWriteAll()
   .then(() => {
   .then(() => {
     logger.info('Download is completed successfully');
     logger.info('Download is completed successfully');
   })
   })

+ 56 - 0
packages/app/bin/generate-plugin-definitions-source.ts

@@ -0,0 +1,56 @@
+/**
+ * the tool for genetion of plugin definitions source code
+ *
+ * @author Yuki Takei <yuki@weseek.co.jp>
+ */
+import fs from 'graceful-fs';
+import normalize from 'normalize-path';
+import swig from 'swig-templates';
+
+import { PluginDefinitionV4 } from '@growi/core';
+
+import PluginUtils from '../src/server/plugins/plugin-utils';
+import loggerFactory from '../src/utils/logger';
+import { resolveFromRoot } from '../src/utils/project-dir-utils';
+
+const logger = loggerFactory('growi:bin:generate-plugin-definitions-source');
+
+
+const pluginUtils = new PluginUtils();
+
+const TEMPLATE = resolveFromRoot('bin/templates/plugin-definitions.js.swig');
+const OUT = resolveFromRoot('tmp/plugins/plugin-definitions.js');
+
+// list plugin names
+const pluginNames: string[] = pluginUtils.listPluginNames();
+logger.info('Detected plugins: ', pluginNames);
+
+async function main(): Promise<void> {
+
+  // get definitions
+  const definitions: PluginDefinitionV4[] = [];
+  for (const pluginName of pluginNames) {
+    // eslint-disable-next-line no-await-in-loop
+    const definition = await pluginUtils.generatePluginDefinition(pluginName, true);
+    if (definition != null) {
+      definitions.push(definition);
+    }
+  }
+
+  definitions.map((definition) => {
+    // convert backslash to slash
+    definition.entries = definition.entries.map((entryPath) => {
+      return normalize(entryPath);
+    });
+    return definition;
+  });
+
+  const compiledTemplate = swig.compileFile(TEMPLATE);
+  const code = compiledTemplate({ definitions });
+
+  // write
+  fs.writeFileSync(OUT, code);
+
+}
+
+main();

+ 6 - 0
packages/app/bin/github-actions/update-readme.sh

@@ -0,0 +1,6 @@
+#!/bin/sh
+
+cd docker
+
+sed -i -e "s/^\([*] \[\`\)[^\`]\+\(\`, \`4\.4\`, .\+\]\)\(.\+\/blob\/v\).\+\(\/docker\/Dockerfile.\+\)$/\1${RELEASED_VERSION}\2\3${RELEASED_VERSION}\4/" README.md
+sed -i -e "s/^\([*] \[\`\)[^\`]\+\(\`, \`4\.4-nocdn\`, .\+\]\)\(.\+\/blob\/v\).\+\(\/docker\/Dockerfile.\+\)$/\1${RELEASED_VERSION}-nocdn\2\3${RELEASED_VERSION}\4/" README.md

+ 2 - 0
bin/shrink-emojione-strategy.js → packages/app/bin/shrink-emojione-strategy.js

@@ -3,6 +3,7 @@
  *
  *
  * @author Yuki Takei <yuki@weseek.co.jp>
  * @author Yuki Takei <yuki@weseek.co.jp>
  */
  */
+/*
 require('module-alias/register');
 require('module-alias/register');
 
 
 const fs = require('graceful-fs');
 const fs = require('graceful-fs');
@@ -30,3 +31,4 @@ Object.keys(emojiStrategy).forEach((unicode) => {
 
 
 // write
 // write
 fs.writeFileSync(OUT, JSON.stringify(shrinkedMap));
 fs.writeFileSync(OUT, JSON.stringify(shrinkedMap));
+*/

+ 0 - 0
bin/templates/plugin-definitions.js.swig → packages/app/bin/templates/plugin-definitions.js.swig


+ 9 - 0
packages/app/config/cdn.js

@@ -0,0 +1,9 @@
+import path from 'path';
+
+import { projectRoot } from '~/utils/project-dir-utils';
+
+export const cdnLocalScriptRoot = path.join(projectRoot, 'public/static/js/cdn');
+export const cdnLocalScriptWebRoot = '/static/js/cdn';
+export const cdnLocalDictRoot = path.join(projectRoot, 'public/static/dict/cdn');
+export const cdnLocalStyleRoot = path.join(projectRoot, 'public/static/styles/cdn');
+export const cdnLocalStyleWebRoot = '/static/styles/cdn';

+ 4 - 0
packages/app/config/ci/.env.local.for-ci

@@ -0,0 +1,4 @@
+FORMAT_NODE_LOG=true
+
+# disable Elasticsearch
+ELASTICSEARCH_URI=

+ 0 - 0
config/logger/config.dev.js → packages/app/config/logger/config.dev.js


+ 0 - 0
config/logger/config.prod.js → packages/app/config/logger/config.prod.js


+ 5 - 7
config/migrate.js → packages/app/config/migrate.js

@@ -5,11 +5,13 @@
  * @author Yuki Takei <yuki@weseek.co.jp>
  * @author Yuki Takei <yuki@weseek.co.jp>
  */
  */
 
 
-require('module-alias/register');
+import mongoose from 'mongoose';
+
+import { initMongooseGlobalSettings, getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 
 
 const { URL } = require('url');
 const { URL } = require('url');
 
 
-const { getMongoUri } = require('@commons/util/mongoose-utils');
+initMongooseGlobalSettings();
 
 
 const mongoUri = getMongoUri();
 const mongoUri = getMongoUri();
 
 
@@ -19,11 +21,7 @@ const url = new URL(mongoUri);
 const mongodb = {
 const mongodb = {
   url: mongoUri,
   url: mongoUri,
   databaseName: url.pathname.substring(1), // omit heading slash
   databaseName: url.pathname.substring(1), // omit heading slash
-  options: {
-    useNewUrlParser: true, // removes a deprecation warning when connecting
-    useUnifiedTopology: true,
-    useFindAndModify: false,
-  },
+  options: mongoOptions,
 };
 };
 
 
 module.exports = {
 module.exports = {

+ 0 - 0
config/swagger-definition.js → packages/app/config/swagger-definition.js


+ 58 - 54
config/webpack.common.js → packages/app/config/webpack.common.js

@@ -1,55 +1,55 @@
 /**
 /**
  * @author: Yuki Takei <yuki@weseek.co.jp>
  * @author: Yuki Takei <yuki@weseek.co.jp>
  */
  */
+const path = require('path');
 const webpack = require('webpack');
 const webpack = require('webpack');
 
 
 /*
 /*
- * Webpack Plugins
- */
+  * Webpack Plugins
+  */
 const WebpackAssetsManifest = require('webpack-assets-manifest');
 const WebpackAssetsManifest = require('webpack-assets-manifest');
 const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
 const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
-
-const helpers = require('../src/lib/util/helpers');
+const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
 
 
 /*
 /*
- * Webpack configuration
- *
- * See: http://webpack.github.io/docs/configuration.html#cli
- */
+  * Webpack configuration
+  *
+  * See: http://webpack.github.io/docs/configuration.html#cli
+  */
 module.exports = (options) => {
 module.exports = (options) => {
   return {
   return {
     mode: options.mode,
     mode: options.mode,
     entry: Object.assign({
     entry: Object.assign({
-      'js/boot':                      './src/client/js/boot',
-      'js/app':                       './src/client/js/app',
-      'js/admin':                     './src/client/js/admin',
-      'js/nologin':                   './src/client/js/nologin',
-      'js/legacy':                    './src/client/js/legacy/crowi',
-      'js/legacy-presentation':       './src/client/js/legacy/crowi-presentation',
-      'js/plugin':                    './src/client/js/plugin',
-      'js/ie11-polyfill':             './src/client/js/ie11-polyfill',
-      'js/hackmd-agent':              './src/client/js/hackmd-agent',
-      'js/hackmd-styles':             './src/client/js/hackmd-styles',
+      'js/boot':                      './src/client/boot',
+      'js/app':                       './src/client/app',
+      'js/admin':                     './src/client/admin',
+      'js/nologin':                   './src/client/nologin',
+      'js/legacy':                    './src/client/legacy/crowi',
+      'js/legacy-presentation':       './src/client/legacy/crowi-presentation',
+      'js/plugin':                    './src/client/plugin',
+      'js/hackmd-agent':              './src/client/hackmd-agent',
+      'js/hackmd-styles':             './src/client/hackmd-styles',
       // styles
       // styles
-      'styles/style-app':             './src/client/styles/scss/style-app.scss',
-      'styles/style-presentation':    './src/client/styles/scss/style-presentation.scss',
+      'styles/style-app':             './src/styles/style-app.scss',
+      'styles/style-presentation':    './src/styles/style-presentation.scss',
       // themes
       // themes
-      'styles/theme-default':         './src/client/styles/scss/theme/default.scss',
-      'styles/theme-nature':          './src/client/styles/scss/theme/nature.scss',
-      'styles/theme-mono-blue':       './src/client/styles/scss/theme/mono-blue.scss',
-      'styles/theme-future':          './src/client/styles/scss/theme/future.scss',
-      'styles/theme-kibela':          './src/client/styles/scss/theme/kibela.scss',
-      'styles/theme-halloween':       './src/client/styles/scss/theme/halloween.scss',
-      'styles/theme-christmas':          './src/client/styles/scss/theme/christmas.scss',
-      'styles/theme-wood':          './src/client/styles/scss/theme/wood.scss',
-      'styles/theme-island':      './src/client/styles/scss/theme/island.scss',
-      'styles/theme-antarctic':      './src/client/styles/scss/theme/antarctic.scss',
-      'styles/theme-spring':         './src/client/styles/scss/theme/spring.scss',
+      'styles/theme-default':         './src/styles/theme/default.scss',
+      'styles/theme-nature':          './src/styles/theme/nature.scss',
+      'styles/theme-mono-blue':       './src/styles/theme/mono-blue.scss',
+      'styles/theme-future':          './src/styles/theme/future.scss',
+      'styles/theme-kibela':          './src/styles/theme/kibela.scss',
+      'styles/theme-halloween':       './src/styles/theme/halloween.scss',
+      'styles/theme-christmas':       './src/styles/theme/christmas.scss',
+      'styles/theme-wood':            './src/styles/theme/wood.scss',
+      'styles/theme-island':          './src/styles/theme/island.scss',
+      'styles/theme-antarctic':       './src/styles/theme/antarctic.scss',
+      'styles/theme-spring':          './src/styles/theme/spring.scss',
+      'styles/theme-hufflepuff':      './src/styles/theme/hufflepuff.scss',
       // styles for external services
       // styles for external services
-      'styles/style-hackmd':          './src/client/styles/hackmd/style.scss',
+      'styles/style-hackmd':          './src/styles-hackmd/style.scss',
     }, options.entry || {}), // Merge with env dependent settings
     }, options.entry || {}), // Merge with env dependent settings
     output: Object.assign({
     output: Object.assign({
-      path: helpers.root('public'),
+      path: path.resolve(__dirname, '../public'),
       publicPath: '/',
       publicPath: '/',
       filename: '[name].bundle.js',
       filename: '[name].bundle.js',
     }, options.output || {}), // Merge with env dependent settings
     }, options.output || {}), // Merge with env dependent settings
@@ -59,34 +59,38 @@ module.exports = (options) => {
       jquery: 'jQuery',
       jquery: 'jQuery',
       emojione: 'emojione',
       emojione: 'emojione',
       hljs: 'hljs',
       hljs: 'hljs',
+      'dtrace-provider': 'dtrace-provider',
     },
     },
     resolve: {
     resolve: {
-      extensions: ['.js', '.jsx', '.json'],
-      modules: ((options.resolve && options.resolve.modules) || []).concat([helpers.root('node_modules')]),
-      alias: {
-        '@root': helpers.root('/'),
-        '@commons': helpers.root('src/lib'),
-        '@client': helpers.root('src/client'),
-        '@tmp': helpers.root('tmp'),
-        '@alias/logger': helpers.root('src/lib/service/logger'),
-        // replace bunyan
-        bunyan: 'browser-bunyan',
-      },
+      extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
+      plugins: [
+        new TsconfigPathsPlugin({
+          configFile: path.resolve(__dirname, '../tsconfig.build.client.json'),
+          extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
+        }),
+      ],
+    },
+    node: {
+      fs: 'empty',
     },
     },
     module: {
     module: {
       rules: options.module.rules.concat([
       rules: options.module.rules.concat([
         {
         {
-          test: /.jsx?$/,
+          test: /.(jsx?|tsx?)$/,
           exclude: {
           exclude: {
-            test:    helpers.root('node_modules'),
+            test: /node_modules/,
             exclude: [ // include as a result
             exclude: [ // include as a result
-              { test: helpers.root('node_modules', 'growi-plugin-') },
-              helpers.root('node_modules/growi-commons'),
-              helpers.root('node_modules/codemirror/src'),
+              { test: /node_modules\/growi-plugin-/ },
+              /node_modules\/growi-commons/,
+              /node_modules\/codemirror/,
             ],
             ],
           },
           },
           use: [{
           use: [{
-            loader: 'babel-loader?cacheDirectory',
+            loader: 'ts-loader',
+            options: {
+              transpileOnly: true,
+              configFile: path.resolve(__dirname, '../tsconfig.build.client.json'),
+            },
           }],
           }],
         },
         },
         {
         {
@@ -97,14 +101,14 @@ module.exports = (options) => {
           },
           },
         },
         },
         /*
         /*
-         * File loader for supporting images, for example, in CSS files.
-         */
+          * File loader for supporting images, for example, in CSS files.
+          */
         {
         {
           test: /\.(jpg|png|gif)$/,
           test: /\.(jpg|png|gif)$/,
           use: 'file-loader',
           use: 'file-loader',
         },
         },
         /* File loader for supporting fonts, for example, in CSS files.
         /* File loader for supporting fonts, for example, in CSS files.
-        */
+         */
         {
         {
           test: /\.(eot|woff2?|svg|ttf)([?]?.*)$/,
           test: /\.(eot|woff2?|svg|ttf)([?]?.*)$/,
           use: 'null-loader',
           use: 'null-loader',
@@ -166,7 +170,7 @@ module.exports = (options) => {
             test: /node_modules[\\/].*\.(js|jsx|json)$/,
             test: /node_modules[\\/].*\.(js|jsx|json)$/,
             chunks: (chunk) => {
             chunks: (chunk) => {
               // ignore patterns
               // ignore patterns
-              return chunk.name != null && !chunk.name.match(/boot|legacy-presentation|ie11-polyfill|hackmd-/);
+              return chunk.name != null && !chunk.name.match(/boot|legacy-presentation|hackmd-/);
             },
             },
             name: 'js/vendors',
             name: 'js/vendors',
             minSize: 1,
             minSize: 1,

+ 4 - 4
config/webpack.dev.dll.js → packages/app/config/webpack.dev.dll.js

@@ -1,8 +1,8 @@
 /**
 /**
  * @author: Yuki Takei <yuki@weseek.co.jp>
  * @author: Yuki Takei <yuki@weseek.co.jp>
  */
  */
+const path = require('path');
 const webpack = require('webpack');
 const webpack = require('webpack');
-const helpers = require('../src/lib/util/helpers');
 
 
 
 
 module.exports = {
 module.exports = {
@@ -34,17 +34,17 @@ module.exports = {
     ],
     ],
   },
   },
   output: {
   output: {
-    path: helpers.root('public/dll'),
+    path: path.resolve(__dirname, '../public/dll'),
     filename: 'dll.js',
     filename: 'dll.js',
     library: 'growi_dlls',
     library: 'growi_dlls',
   },
   },
   resolve: {
   resolve: {
     extensions: ['.js', '.json'],
     extensions: ['.js', '.json'],
-    modules: [helpers.root('src'), helpers.root('node_modules')],
+    modules: [path.resolve(__dirname, '../src'), path.resolve(__dirname, '../node_modules')],
   },
   },
   plugins: [
   plugins: [
     new webpack.DllPlugin({
     new webpack.DllPlugin({
-      path: helpers.root('public/dll/manifest.json'),
+      path: path.resolve(__dirname, '../public/dll/manifest.json'),
       name: 'growi_dlls',
       name: 'growi_dlls',
     }),
     }),
   ],
   ],

+ 7 - 7
config/webpack.dev.js → packages/app/config/webpack.dev.js

@@ -2,6 +2,8 @@
  * @author: Yuki Takei <yuki@weseek.co.jp>
  * @author: Yuki Takei <yuki@weseek.co.jp>
  */
  */
 
 
+const path = require('path');
+
 /*
 /*
  * Webpack Plugins
  * Webpack Plugins
  */
  */
@@ -9,8 +11,6 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
 const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
 const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
 const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
 const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
 
 
-const helpers = require('../src/lib/util/helpers');
-
 /**
 /**
  * Webpack Constants
  * Webpack Constants
  */
  */
@@ -20,7 +20,7 @@ module.exports = require('./webpack.common')({
   mode: 'development',
   mode: 'development',
   devtool: 'cheap-module-eval-source-map',
   devtool: 'cheap-module-eval-source-map',
   entry: {
   entry: {
-    'js/dev': './src/client/js/dev',
+    'js/dev': './src/client/dev',
   },
   },
   resolve: {
   resolve: {
     modules: ['../node_modules'],
     modules: ['../node_modules'],
@@ -35,8 +35,8 @@ module.exports = require('./webpack.common')({
           { loader: 'sass-loader', options: { sourceMap: true } },
           { loader: 'sass-loader', options: { sourceMap: true } },
         ],
         ],
         exclude: [
         exclude: [
-          helpers.root('src/client/styles/hackmd'),
-          helpers.root('src/client/styles/scss/style-presentation.scss'),
+          path.resolve(__dirname, '../src/styles-hackmd'),
+          path.resolve(__dirname, '../src/styles/style-presentation.scss'),
         ],
         ],
       },
       },
       { // Dump CSS for HackMD
       { // Dump CSS for HackMD
@@ -47,8 +47,8 @@ module.exports = require('./webpack.common')({
           'sass-loader',
           'sass-loader',
         ],
         ],
         include: [
         include: [
-          helpers.root('src/client/styles/hackmd'),
-          helpers.root('src/client/styles/scss/style-presentation.scss'),
+          path.resolve(__dirname, '../src/styles-hackmd'),
+          path.resolve(__dirname, '../src/styles/style-presentation.scss'),
         ],
         ],
       },
       },
     ],
     ],

+ 10 - 10
config/webpack.prod.js → packages/app/config/webpack.prod.js

@@ -2,19 +2,19 @@
  * @author: Yuki Takei <yuki@weseek.co.jp>
  * @author: Yuki Takei <yuki@weseek.co.jp>
  */
  */
 
 
+const path = require('path');
+
 /**
 /**
- * Webpack Plugins
- */
+  * Webpack Plugins
+  */
 const TerserPlugin = require('terser-webpack-plugin');
 const TerserPlugin = require('terser-webpack-plugin');
 const MiniCssExtractPlugin = require('mini-css-extract-plugin');
 const MiniCssExtractPlugin = require('mini-css-extract-plugin');
 const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
 const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
 const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
 const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
 
 
-const helpers = require('../src/lib/util/helpers');
-
 /**
 /**
- * Webpack Constants
- */
+  * Webpack Constants
+  */
 const { ANALYZE } = process.env;
 const { ANALYZE } = process.env;
 
 
 module.exports = require('./webpack.common')({
 module.exports = require('./webpack.common')({
@@ -35,7 +35,7 @@ module.exports = require('./webpack.common')({
             loader: 'postcss-loader',
             loader: 'postcss-loader',
             options: {
             options: {
               sourceMap: false,
               sourceMap: false,
-              plugins: (loader) => {
+              plugins: () => {
                 return [
                 return [
                   require('autoprefixer')(),
                   require('autoprefixer')(),
                 ];
                 ];
@@ -44,12 +44,12 @@ module.exports = require('./webpack.common')({
           },
           },
           'sass-loader',
           'sass-loader',
         ],
         ],
-        exclude: [helpers.root('src/client/js/legacy')],
+        exclude: [path.resolve(__dirname, '../src/client/legacy')],
       },
       },
       {
       {
         test: /\.(css|scss)$/,
         test: /\.(css|scss)$/,
         use: ['style-loader', 'css-loader', 'sass-loader'],
         use: ['style-loader', 'css-loader', 'sass-loader'],
-        include: [helpers.root('src/client/js/legacy')],
+        include: [path.resolve(__dirname, '../src/client/legacy')],
       },
       },
     ],
     ],
   },
   },
@@ -61,7 +61,7 @@ module.exports = require('./webpack.common')({
 
 
     new BundleAnalyzerPlugin({
     new BundleAnalyzerPlugin({
       analyzerMode: ANALYZE ? 'static' : 'disabled',
       analyzerMode: ANALYZE ? 'static' : 'disabled',
-      reportFilename: helpers.root('report/bundle-analyzer.html'),
+      reportFilename: path.resolve(__dirname, '../report/bundle-analyzer.html'),
       openAnalyzer: false,
       openAnalyzer: false,
     }),
     }),
 
 

+ 36 - 29
docker/Dockerfile → packages/app/docker/Dockerfile

@@ -17,16 +17,22 @@ COPY ./package.json .
 COPY ./yarn.lock .
 COPY ./yarn.lock .
 COPY ./lerna.json .
 COPY ./lerna.json .
 COPY ./packages/app/package.json packages/app/
 COPY ./packages/app/package.json packages/app/
+COPY ./packages/core/package.json packages/core/
+COPY ./packages/codemirror-textlint/package.json packages/codemirror-textlint/
+COPY ./packages/plugin-attachment-refs/package.json packages/plugin-attachment-refs/
+COPY ./packages/plugin-lsx/package.json packages/plugin-lsx/
+COPY ./packages/plugin-pukiwiki-like-linker/package.json packages/plugin-pukiwiki-like-linker/
 COPY ./packages/slack/package.json packages/slack/
 COPY ./packages/slack/package.json packages/slack/
+COPY ./packages/ui/package.json packages/ui/
 
 
 # setup
 # setup
 RUN yarn config set network-timeout 300000
 RUN yarn config set network-timeout 300000
 RUN npx lerna bootstrap
 RUN npx lerna bootstrap
 
 
 # make artifacts
 # make artifacts
-RUN tar cf node_modules.tar node_modules \
-  packages/app/node_modules \
-  packages/slack/node_modules
+RUN tar cf node_modules.tar \
+  node_modules \
+  packages/*/node_modules
 
 
 
 
 
 
@@ -34,14 +40,11 @@ RUN tar cf node_modules.tar node_modules \
 ## deps-resolver-prod
 ## deps-resolver-prod
 ##
 ##
 FROM deps-resolver AS deps-resolver-prod
 FROM deps-resolver AS deps-resolver-prod
-
-# shrink dependencies for production
-RUN yarn install --production
-
+RUN npx lerna bootstrap -- --production
 # make artifacts
 # make artifacts
-RUN tar cf node_modules.tar node_modules \
-  packages/app/node_modules \
-  packages/slack/node_modules
+RUN tar cf node_modules.tar \
+  node_modules \
+  packages/*/node_modules
 
 
 
 
 
 
@@ -88,16 +91,15 @@ COPY ./package.json ./
 COPY ./yarn.lock ./
 COPY ./yarn.lock ./
 COPY ./lerna.json ./
 COPY ./lerna.json ./
 COPY ./tsconfig.base.json ./
 COPY ./tsconfig.base.json ./
-COPY ./babel.config.js ./
-COPY ./bin ./bin
-COPY ./config ./config
-COPY ./public ./public
-COPY ./resource ./resource
-COPY ./src ./src
-COPY ./tmp ./tmp
 # copy all related packages
 # copy all related packages
-COPY packages/slack packages/slack
 COPY packages/app packages/app
 COPY packages/app packages/app
+COPY packages/core packages/core
+COPY packages/codemirror-textlint packages/codemirror-textlint
+COPY packages/plugin-attachment-refs packages/plugin-attachment-refs
+COPY packages/plugin-lsx packages/plugin-lsx
+COPY packages/plugin-pukiwiki-like-linker packages/plugin-pukiwiki-like-linker
+COPY packages/slack packages/slack
+COPY packages/ui packages/ui
 
 
 # build
 # build
 RUN yarn lerna run build
 RUN yarn lerna run build
@@ -106,15 +108,16 @@ RUN yarn lerna run build
 RUN tar cf packages.tar \
 RUN tar cf packages.tar \
   package.json \
   package.json \
   yarn.lock \
   yarn.lock \
-  config \
-  public \
-  resource \
-  src \
-  tmp \
-  packages/app/package.json \
-  packages/slack/package.json \
-  packages/slack/dist
-
+  tsconfig.base.json \
+  packages/app/config \
+  packages/app/public \
+  packages/app/resource \
+  packages/app/tmp \
+  packages/app/.env.production \
+  packages/app/tsconfig.base.json \
+  packages/app/tsconfig.json \
+  packages/*/package.json \
+  packages/*/dist
 
 
 
 
 
 
@@ -124,6 +127,8 @@ RUN tar cf packages.tar \
 FROM node:14-slim
 FROM node:14-slim
 LABEL maintainer Yuki Takei <yuki@weseek.co.jp>
 LABEL maintainer Yuki Takei <yuki@weseek.co.jp>
 
 
+ENV NODE_ENV production
+
 ENV appDir /opt/growi
 ENV appDir /opt/growi
 
 
 # Add gosu
 # Add gosu
@@ -154,12 +159,14 @@ RUN rm node_modules.tar packages.tar
 
 
 USER root
 USER root
 
 
-COPY docker/docker-entrypoint.sh /
+COPY packages/app/docker/docker-entrypoint.sh /
 RUN chmod 700 /docker-entrypoint.sh
 RUN chmod 700 /docker-entrypoint.sh
 RUN chown node:node ${appDir}
 RUN chown node:node ${appDir}
 
 
+WORKDIR ${appDir}/packages/app
+
 VOLUME /data
 VOLUME /data
 EXPOSE 3000
 EXPOSE 3000
 
 
 ENTRYPOINT ["/tini", "-e", "143", "--", "/docker-entrypoint.sh"]
 ENTRYPOINT ["/tini", "-e", "143", "--", "/docker-entrypoint.sh"]
-CMD ["yarn", "server:prod"]
+CMD ["node", "-r", "dotenv-flow/config", "--expose_gc", "dist/server/app.js"]

+ 5 - 5
docker/README.md → packages/app/docker/README.md

@@ -2,7 +2,7 @@
 GROWI Official docker image
 GROWI Official docker image
 ========================
 ========================
 
 
-[![Actions Status](https://github.com/weseek/growi/workflows/Release%20Docker%20Images/badge.svg)](https://github.com/weseek/growi/actions) [![docker-pulls](https://img.shields.io/docker/pulls/weseek/growi.svg)](https://hub.docker.com/r/weseek/growi/) [![](https://images.microbadger.com/badges/image/weseek/growi.svg)](https://microbadger.com/images/weseek/growi)
+[![Actions Status](https://github.com/weseek/growi/workflows/Release/badge.svg)](https://github.com/weseek/growi/actions) [![docker-pulls](https://img.shields.io/docker/pulls/weseek/growi.svg)](https://hub.docker.com/r/weseek/growi/) [![](https://images.microbadger.com/badges/image/weseek/growi.svg)](https://microbadger.com/images/weseek/growi)
 
 
 ![GROWI-x-docker](https://user-images.githubusercontent.com/1638767/38307565-105956e2-384f-11e8-8534-b1128522d68d.png)
 ![GROWI-x-docker](https://user-images.githubusercontent.com/1638767/38307565-105956e2-384f-11e8-8534-b1128522d68d.png)
 
 
@@ -10,10 +10,10 @@ GROWI Official docker image
 Supported tags and respective Dockerfile links
 Supported tags and respective Dockerfile links
 ------------------------------------------------
 ------------------------------------------------
 
 
-* [`4.3.0`, `4.3`, `4`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v4.3.0/docker/Dockerfile)
-* [`4.3.0-nocdn`, `4.3-nocdn`, `4-nocdn`, `latest-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v4.3.0/docker/Dockerfile)
-* [`4.2.0`, `4.2` (Dockerfile)](https://github.com/weseek/growi/blob/v4.2.0/docker/Dockerfile)
-* [`4.2.0-nocdn`, `4.2-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v4.2.0/docker/Dockerfile)
+* [`4.4.5`, `4.4`, `4`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v4.4.5/docker/Dockerfile)
+* [`4.4.5-nocdn`, `4.4-nocdn`, `4-nocdn`, `latest-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v4.4.5/docker/Dockerfile)
+* [`4.3.3`, `4.3` (Dockerfile)](https://github.com/weseek/growi/blob/v4.3.3/docker/Dockerfile)
+* [`4.3.3-nocdn`, `4.3-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v4.3.3/docker/Dockerfile)
 
 
 
 
 What is GROWI?
 What is GROWI?

+ 14 - 0
packages/app/docker/docker-entrypoint.sh

@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -e
+
+# Support `FILE_UPLOAD=local`
+mkdir -p /data/uploads
+if [ ! -e "./public/uploads" ]; then
+  ln -s /data/uploads ./public/uploads
+fi
+
+chown -R node:node /data/uploads
+chown -h node:node ./public/uploads
+
+gosu node $@

+ 0 - 0
docker/nocdn/env.prod.js → packages/app/docker/nocdn/env.prod.js


+ 24 - 17
config/jest.config.js → packages/app/jest.config.js

@@ -1,33 +1,35 @@
 // For a detailed explanation regarding each configuration property, visit:
 // For a detailed explanation regarding each configuration property, visit:
 // https://jestjs.io/docs/en/configuration.html
 // https://jestjs.io/docs/en/configuration.html
+// https://kulshekhar.github.io/ts-jest/user/config/
 
 
 const MODULE_NAME_MAPPING = {
 const MODULE_NAME_MAPPING = {
-  '@root/(.+)': '<rootDir>/$1',
-  '@commons/(.+)': '<rootDir>/src/lib/$1',
-  '@server/(.+)': '<rootDir>/src/server/$1',
-  '@alias/logger': '<rootDir>/src/lib/service/logger',
-  // -- doesn't work with unknown error -- 2019.06.19 Yuki Takei
-  // debug: '<rootDir>/src/lib/service/logger/alias-for-debug',
+  '^\\^/(.+)$': '<rootDir>/$1',
+  '^~/(.+)$': '<rootDir>/src/$1',
+  '^@growi/(.+)$': '<rootDir>/../$1/src',
 };
 };
 
 
 module.exports = {
 module.exports = {
   // Indicates whether each individual test should be reported during the run
   // Indicates whether each individual test should be reported during the run
   verbose: true,
   verbose: true,
 
 
-  rootDir: '../',
+  preset: 'ts-jest/presets/js-with-ts',
+
   globalSetup: '<rootDir>/src/test/global-setup.js',
   globalSetup: '<rootDir>/src/test/global-setup.js',
   globalTeardown: '<rootDir>/src/test/global-teardown.js',
   globalTeardown: '<rootDir>/src/test/global-teardown.js',
 
 
   projects: [
   projects: [
     {
     {
       displayName: 'server',
       displayName: 'server',
-      testEnvironment: 'node',
+
+      preset: 'ts-jest/presets/js-with-ts',
+
       rootDir: '.',
       rootDir: '.',
+      roots: ['<rootDir>/src'],
+      testEnvironment: 'node',
       setupFilesAfterEnv: ['<rootDir>/src/test/setup.js'],
       setupFilesAfterEnv: ['<rootDir>/src/test/setup.js'],
-      testMatch: ['<rootDir>/src/test/**/*.test.js'],
+      testMatch: ['<rootDir>/src/test/**/*.test.ts', '<rootDir>/src/test/**/*.test.js'],
       // Automatically clear mock calls and instances between every test
       // Automatically clear mock calls and instances between every test
       clearMocks: true,
       clearMocks: true,
-      // A map from regular expressions to module names that allow to stub out resources with a single module
       moduleNameMapper: MODULE_NAME_MAPPING,
       moduleNameMapper: MODULE_NAME_MAPPING,
     },
     },
     // {
     // {
@@ -37,19 +39,24 @@ module.exports = {
     // },
     // },
   ],
   ],
 
 
+  // Automatically clear mock calls and instances between every test
+  clearMocks: true,
 
 
   // Indicates whether the coverage information should be collected while executing the test
   // Indicates whether the coverage information should be collected while executing the test
-  // collectCoverage: false,
+  collectCoverage: true,
 
 
   // An array of glob patterns indicating a set of files for which coverage information should be collected
   // An array of glob patterns indicating a set of files for which coverage information should be collected
-  collectCoverageFrom: [
-    'src/client/**/*.js',
-    'src/lib/**/*.js',
-    'src/migrations/**/*.js',
-    'src/server/**/*.js',
-  ],
+  // collectCoverageFrom: undefined,
 
 
   // The directory where Jest should output its coverage files
   // The directory where Jest should output its coverage files
   coverageDirectory: 'coverage',
   coverageDirectory: 'coverage',
 
 
+  // An array of regexp pattern strings used to skip coverage collection
+  coveragePathIgnorePatterns: [
+    'index.ts',
+    '/config/',
+    '/resource/',
+    '/node_modules/',
+  ],
+
 };
 };

+ 76 - 52
packages/app/package.json

@@ -1,23 +1,68 @@
 {
 {
   "name": "@growi/app",
   "name": "@growi/app",
-  "version": "0.9.0-RC",
+  "version": "4.4.6-RC.0",
   "license": "MIT",
   "license": "MIT",
   "scripts": {
   "scripts": {
-    "build": "cd ../../ && env-cmd -f config/env.prod.js webpack --config config/webpack.prod.js --profile --bail",
-    "prebuild": "cd ../../ && yarn plugin:def && yarn resource"
+    "//// for production": "",
+    "start": "yarn build && yarn server",
+    "build": "run-p build:*",
+    "build:client": "yarn cross-env NODE_ENV=production webpack --config config/webpack.prod.js --profile --bail",
+    "build:server": "yarn cross-env NODE_ENV=production tsc -p tsconfig.build.server.json && tsc-alias -p tsconfig.build.server.json",
+    "clean": "npx shx rm -rf dist transpiled",
+    "prebuild": "yarn cross-env NODE_ENV=production run-p clean resources:*",
+    "postbuild": "npx shx mv transpiled/src dist && npx shx cp -r src/server/views dist/server/ && npx shx rm -rf transpiled",
+    "server": "yarn cross-env NODE_ENV=production node -r dotenv-flow/config --expose_gc dist/server/app.js",
+    "server:ci": "yarn server --ci",
+    "preserver": "yarn cross-env NODE_ENV=production yarn migrate",
+    "//// for development": "",
+    "dev": "run-p dev:client dev:server",
+    "dev:client": "yarn cross-env NODE_ENV=development webpack --config config/webpack.dev.js --progress --watch",
+    "dev:client:nowatch": "yarn cross-env NODE_ENV=development webpack --config config/webpack.dev.js",
+    "dev:server": "yarn cross-env NODE_ENV=development ts-node-dev --inspect --expose-gc -r tsconfig-paths/register -r dotenv-flow/config --transpile-only src/server/app.ts",
+    "predev:client": "yarn cross-env NODE_ENV=development run-p resources:*",
+    "predev:server": "yarn cross-env NODE_ENV=development yarn migrate",
+    "//// for CI": "",
+    "dev:ci": "yarn dev:client:nowatch && yarn dev:server --ci",
+    "predev:ci": "run-p resources:*",
+    "lint:typecheck": "npx tsc",
+    "lint:eslint": "eslint --quiet \"**/*.{js,jsx,ts,tsx}\"",
+    "lint:styles": "stylelint src/**/*.scss",
+    "lint:swagger2openapi": "node node_modules/.bin/oas-validate tmp/swagger.json",
+    "lint": "run-p lint:*",
+    "test": "cross-env NODE_ENV=test jest --passWithNoTests -- ",
+    "prelint:eslint": "yarn resources:plugin",
+    "prelint:swagger2openapi": "yarn openapi:v3",
+    "//// misc": "",
+    "console": "yarn cross-env NODE_ENV=development yarn ts-node --experimental-repl-await src/server/console.js",
+    "swagger-jsdoc": "swagger-jsdoc -o tmp/swagger.json -d config/swagger-definition.js",
+    "openapi:v3": "yarn cross-env API_VERSION=3 yarn swagger-jsdoc -- \"src/server/routes/apiv3/**/*.js\" \"src/server/models/**/*.js\"",
+    "openapi:v1": "yarn cross-env API_VERSION=1 yarn swagger-jsdoc -- \"src/server/*/*.js\" \"src/server/models/**/*.js\"",
+    "resources:plugin": "yarn ts-node bin/generate-plugin-definitions-source.ts",
+    "resources:dl-resources": "yarn ts-node bin/download-cdn-resources.ts",
+    "migrate": "yarn migrate:up",
+    "migrate:create": "yarn ts-node node_modules/.bin/migrate-mongo create -f config/migrate.js",
+    "migrate:status": "yarn ts-node node_modules/.bin/migrate-mongo status -f config/migrate.js",
+    "migrate:up": "yarn ts-node node_modules/.bin/migrate-mongo up -f config/migrate.js",
+    "migrate:down": "yarn ts-node node_modules/.bin/migrate-mongo down -f config/migrate.js",
+    "ts-node": "ts-node -r tsconfig-paths/register -r dotenv-flow/config --transpile-only"
   },
   },
   "// comments for dependencies": {
   "// comments for dependencies": {
     "openid-client": "Node.js 12 or higher is required for openid-client@3 and above.",
     "openid-client": "Node.js 12 or higher is required for openid-client@3 and above.",
-    "string-width": "5.0.0 or above uses ESM."
+    "escape-string-regexp": "5.0.0 or above exports only ESM",
+    "string-width": "5.0.0 or above exports only ESM."
   },
   },
   "dependencies": {
   "dependencies": {
+    "@browser-bunyan/console-formatted-stream": "^1.6.2",
     "@google-cloud/storage": "^5.8.5",
     "@google-cloud/storage": "^5.8.5",
-    "@growi/slack": "^0.9.0-RC",
-    "@kobalab/socket.io-session": "^1.0.3",
-    "@promster/express": "^5.0.1",
-    "@promster/server": "^6.0.0",
+    "@growi/codemirror-textlint": "^4.4.6-RC.0",
+    "@growi/plugin-attachment-refs": "^4.4.6-RC.0",
+    "@growi/plugin-pukiwiki-like-linker": "^4.4.6-RC.0",
+    "@growi/plugin-lsx": "^4.4.6-RC.0",
+    "@growi/slack": "^4.4.6-RC.0",
+    "@promster/express": "^5.1.0",
+    "@promster/server": "^6.0.3",
     "@slack/events-api": "^3.0.0",
     "@slack/events-api": "^3.0.0",
-    "@slack/web-api": "^6.2.3",
+    "@slack/web-api": "^6.2.4",
     "@slack/webhook": "^6.0.0",
     "@slack/webhook": "^6.0.0",
     "JSONStream": "^1.3.5",
     "JSONStream": "^1.3.5",
     "archiver": "^5.3.0",
     "archiver": "^5.3.0",
@@ -28,35 +73,31 @@
     "body-parser": "^1.18.2",
     "body-parser": "^1.18.2",
     "browser-bunyan": "^1.6.3",
     "browser-bunyan": "^1.6.3",
     "bunyan": "^1.8.15",
     "bunyan": "^1.8.15",
-    "bunyan-format": "^0.2.1",
     "check-node-version": "^4.1.0",
     "check-node-version": "^4.1.0",
     "connect-flash": "~0.1.1",
     "connect-flash": "~0.1.1",
     "connect-mongo": "^4.4.1",
     "connect-mongo": "^4.4.1",
     "connect-redis": "^4.0.4",
     "connect-redis": "^4.0.4",
     "cookie-parser": "^1.4.5",
     "cookie-parser": "^1.4.5",
-    "cross-env": "^7.0.0",
     "csrf": "^3.1.0",
     "csrf": "^3.1.0",
-    "date-fns": "^2.0.0",
+    "date-fns": "^2.23.0",
     "detect-indent": "^6.0.0",
     "detect-indent": "^6.0.0",
     "diff": "^5.0.0",
     "diff": "^5.0.0",
     "elasticsearch": "^16.0.0",
     "elasticsearch": "^16.0.0",
     "entities": "^2.0.0",
     "entities": "^2.0.0",
-    "env-cmd": "^10.0.1",
     "esa-nodejs": "^0.0.7",
     "esa-nodejs": "^0.0.7",
-    "escape-string-regexp": "^2.0.0",
+    "escape-string-regexp": "=4.0.0",
     "express": "^4.16.1",
     "express": "^4.16.1",
     "express-bunyan-logger": "^1.3.3",
     "express-bunyan-logger": "^1.3.3",
     "express-form": "~0.12.0",
     "express-form": "~0.12.0",
     "express-mongo-sanitize": "^2.1.0",
     "express-mongo-sanitize": "^2.1.0",
+    "express-rate-limit": "^5.3.0",
     "express-session": "^1.16.1",
     "express-session": "^1.16.1",
     "express-validator": "^6.1.1",
     "express-validator": "^6.1.1",
     "express-webpack-assets": "^0.1.0",
     "express-webpack-assets": "^0.1.0",
     "graceful-fs": "^4.1.11",
     "graceful-fs": "^4.1.11",
     "growi-commons": "^5.0.4",
     "growi-commons": "^5.0.4",
-    "growi-plugin-attachment-refs": "^2.0.2",
-    "growi-plugin-lsx": "^4.0.3",
-    "growi-plugin-pukiwiki-like-linker": "^3.1.0",
-    "helmet": "^3.13.0",
+    "helmet": "^4.6.0",
+    "http-errors": "~1.8.0",
     "i18next": "^20.3.2",
     "i18next": "^20.3.2",
     "i18next-express-middleware": "^2.0.0",
     "i18next-express-middleware": "^2.0.0",
     "i18next-node-fs-backend": "^2.1.0",
     "i18next-node-fs-backend": "^2.1.0",
@@ -67,25 +108,23 @@
     "method-override": "^3.0.0",
     "method-override": "^3.0.0",
     "migrate-mongo": "^8.2.2",
     "migrate-mongo": "^8.2.2",
     "mkdirp": "^1.0.3",
     "mkdirp": "^1.0.3",
-    "module-alias": "^2.0.6",
     "mongoose": "5.12.13",
     "mongoose": "5.12.13",
     "mongoose-gridfs": "^1.2.42",
     "mongoose-gridfs": "^1.2.42",
     "mongoose-paginate-v2": "^1.3.9",
     "mongoose-paginate-v2": "^1.3.9",
     "mongoose-unique-validator": "^2.0.3",
     "mongoose-unique-validator": "^2.0.3",
     "multer": "~1.4.0",
     "multer": "~1.4.0",
     "multer-autoreap": "^1.0.3",
     "multer-autoreap": "^1.0.3",
+    "nocache": "^3.0.1",
     "nodemailer": "^6.6.2",
     "nodemailer": "^6.6.2",
     "nodemailer-ses-transport": "~1.5.0",
     "nodemailer-ses-transport": "~1.5.0",
-    "npm-run-all": "^4.1.2",
     "openid-client": "=2.5.0",
     "openid-client": "=2.5.0",
-    "package-installed-version-sync": "^2.1.0",
     "passport": "^0.4.0",
     "passport": "^0.4.0",
     "passport-github": "^1.1.0",
     "passport-github": "^1.1.0",
     "passport-google-oauth20": "^2.0.0",
     "passport-google-oauth20": "^2.0.0",
     "passport-http": "^0.3.0",
     "passport-http": "^0.3.0",
     "passport-ldapauth": "^2.0.0",
     "passport-ldapauth": "^2.0.0",
     "passport-local": "^1.0.0",
     "passport-local": "^1.0.0",
-    "passport-saml": "^1.0.0",
+    "passport-saml": "^2.2.0",
     "passport-twitter": "^1.0.4",
     "passport-twitter": "^1.0.4",
     "prom-client": "^13.0.0",
     "prom-client": "^13.0.0",
     "react-card-flip": "^1.0.10",
     "react-card-flip": "^1.0.10",
@@ -93,9 +132,10 @@
     "reconnecting-websocket": "^4.4.0",
     "reconnecting-websocket": "^4.4.0",
     "redis": "^3.0.2",
     "redis": "^3.0.2",
     "rimraf": "^3.0.0",
     "rimraf": "^3.0.0",
-    "socket.io": "^2.3.0",
+    "socket.io": "^4.2.0",
     "stream-to-promise": "^3.0.0",
     "stream-to-promise": "^3.0.0",
     "string-width": "=4.2.2",
     "string-width": "=4.2.2",
+    "swagger-jsdoc": "^3.4.0",
     "swig-templates": "^2.0.2",
     "swig-templates": "^2.0.2",
     "uglifycss": "^0.0.29",
     "uglifycss": "^0.0.29",
     "universal-bunyan": "^0.9.2",
     "universal-bunyan": "^0.9.2",
@@ -107,34 +147,25 @@
   },
   },
   "// comments for defDependencies": {
   "// comments for defDependencies": {
     "@handsontable/react": "v3 requires handsontable >= 7.0.0.",
     "@handsontable/react": "v3 requires handsontable >= 7.0.0.",
-    "handsontable": "v7.0.0 or above is no loger MIT lisence."
+    "handsontable": "v7.0.0 or above is no loger MIT lisence.",
+    "ts-loader": "v9 is not compatible with webpack@5"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@alienfast/i18next-loader": "^1.0.16",
     "@alienfast/i18next-loader": "^1.0.16",
     "@atlaskit/drawer": "^5.3.7",
     "@atlaskit/drawer": "^5.3.7",
     "@atlaskit/navigation-next": "^8.0.5",
     "@atlaskit/navigation-next": "^8.0.5",
-    "@babel/core": "^7.4.5",
-    "@babel/plugin-proposal-class-properties": "^7.8.3",
-    "@babel/plugin-proposal-optional-chaining": "^7.9.0",
-    "@babel/polyfill": "^7.4.4",
-    "@babel/preset-env": "^7.4.5",
-    "@babel/preset-react": "^7.0.0",
+    "@growi/ui": "^4.4.6-RC.0",
     "@handsontable/react": "=2.1.0",
     "@handsontable/react": "=2.1.0",
     "@types/compression": "^1.7.0",
     "@types/compression": "^1.7.0",
     "@types/express": "^4.17.11",
     "@types/express": "^4.17.11",
     "@types/multer": "^1.4.5",
     "@types/multer": "^1.4.5",
-    "@types/node": "^14.14.35",
+    "@types/react-dom": "^17.0.9",
     "autoprefixer": "^9.0.0",
     "autoprefixer": "^9.0.0",
-    "babel-eslint": "^10.0.1",
-    "babel-loader": "^8.0.6",
-    "babel-plugin-lodash": "^3.3.4",
-    "babel-plugin-transform-imports": "^2.0.0",
     "bootstrap": "^4.5.0",
     "bootstrap": "^4.5.0",
-    "browser-bunyan": "^1.6.3",
     "browser-sync": "^2.26.3",
     "browser-sync": "^2.26.3",
     "bunyan-debug": "^2.0.0",
     "bunyan-debug": "^2.0.0",
     "cli": "~1.0.1",
     "cli": "~1.0.1",
-    "codemirror": "^5.48.4",
+    "codemirror": "^5.63.0",
     "colors": "^1.2.5",
     "colors": "^1.2.5",
     "connect-browser-sync": "^2.1.0",
     "connect-browser-sync": "^2.1.0",
     "core-js": "=2.6.9",
     "core-js": "=2.6.9",
@@ -142,22 +173,15 @@
     "csv-to-markdown-table": "^1.0.1",
     "csv-to-markdown-table": "^1.0.1",
     "diff2html": "^3.1.2",
     "diff2html": "^3.1.2",
     "eazy-logger": "^3.0.2",
     "eazy-logger": "^3.0.2",
-    "eslint": "^6.0.1",
-    "eslint-config-weseek": "^1.0.8",
-    "eslint-plugin-import": "^2.18.0",
-    "eslint-plugin-jest": "^23.0.3",
-    "eslint-plugin-react": "^7.14.2",
-    "eslint-plugin-react-hooks": "^4.0.4",
     "file-loader": "^5.0.2",
     "file-loader": "^5.0.2",
     "handsontable": "=6.2.2",
     "handsontable": "=6.2.2",
     "hard-source-webpack-plugin": "^0.13.1",
     "hard-source-webpack-plugin": "^0.13.1",
     "i18next-browser-languagedetector": "^4.0.1",
     "i18next-browser-languagedetector": "^4.0.1",
     "imports-loader": "^0.8.0",
     "imports-loader": "^0.8.0",
-    "jest": "^25.1.0",
-    "jest-date-mock": "^1.0.8",
     "jquery-slimscroll": "^1.3.8",
     "jquery-slimscroll": "^1.3.8",
     "jquery-ui": "^1.12.1",
     "jquery-ui": "^1.12.1",
     "jquery.cookie": "~1.4.1",
     "jquery.cookie": "~1.4.1",
+    "jshint": "^2.13.0",
     "load-css-file": "^1.0.0",
     "load-css-file": "^1.0.0",
     "lodash-webpack-plugin": "^0.11.5",
     "lodash-webpack-plugin": "^0.11.5",
     "markdown-it": "^10.0.0",
     "markdown-it": "^10.0.0",
@@ -172,7 +196,7 @@
     "markdown-it-toc-and-anchor-with-slugid": "^1.1.4",
     "markdown-it-toc-and-anchor-with-slugid": "^1.1.4",
     "markdown-table": "^1.1.1",
     "markdown-table": "^1.1.1",
     "mini-css-extract-plugin": "^0.9.0",
     "mini-css-extract-plugin": "^0.9.0",
-    "morgan": "^1.9.0",
+    "morgan": "^1.10.0",
     "node-dev": "^4.0.0",
     "node-dev": "^4.0.0",
     "node-sass": "^4.14.1",
     "node-sass": "^4.14.1",
     "normalize-path": "^3.0.0",
     "normalize-path": "^3.0.0",
@@ -192,26 +216,26 @@
     "react-frame-component": "^4.0.0",
     "react-frame-component": "^4.0.0",
     "react-hotkeys": "^2.0.0",
     "react-hotkeys": "^2.0.0",
     "react-i18next": "^11.1.0",
     "react-i18next": "^11.1.0",
-    "react-images": "1.0.0",
-    "react-motion": "^0.5.2",
-    "react-waypoint": "^9.0.0",
+    "react-waypoint": "^10.1.0",
     "reactstrap": "^8.9.0",
     "reactstrap": "^8.9.0",
     "replacestream": "^4.0.3",
     "replacestream": "^4.0.3",
     "reveal.js": "^3.5.0",
     "reveal.js": "^3.5.0",
-    "rs-i18n": "^0.0.9",
     "sass-loader": "^8.0.0",
     "sass-loader": "^8.0.0",
     "simple-load-script": "^1.0.2",
     "simple-load-script": "^1.0.2",
-    "socket.io-client": "^2.3.0",
+    "socket.io-client": "^4.2.0",
     "sticky-events": "^3.1.3",
     "sticky-events": "^3.1.3",
     "style-loader": "^1.0.0",
     "style-loader": "^1.0.0",
     "styled-components": "^5.0.1",
     "styled-components": "^5.0.1",
     "stylelint": "^13.2.0",
     "stylelint": "^13.2.0",
     "stylelint-config-recess-order": "^2.0.1",
     "stylelint-config-recess-order": "^2.0.1",
-    "swagger-jsdoc": "^3.4.0",
     "swagger2openapi": "^5.3.1",
     "swagger2openapi": "^5.3.1",
     "terser-webpack-plugin": "^4.1.0",
     "terser-webpack-plugin": "^4.1.0",
     "throttle-debounce": "^2.0.0",
     "throttle-debounce": "^2.0.0",
     "toastr": "^2.1.2",
     "toastr": "^2.1.2",
+    "ts-loader": "^8.3.0",
+    "ts-node-dev": "^1.1.6",
+    "tsc-alias": "^1.2.9",
+    "tsconfig-paths-webpack-plugin": "^3.5.1",
     "unstated": "^2.1.1",
     "unstated": "^2.1.1",
     "webpack": "^4.39.3",
     "webpack": "^4.39.3",
     "webpack-assets-manifest": "^3.1.1",
     "webpack-assets-manifest": "^3.1.1",

+ 0 - 0
public/favicon.ico → packages/app/public/favicon.ico


+ 0 - 0
public/images/customize-settings/default-dark.svg → packages/app/public/images/customize-settings/default-dark.svg


+ 0 - 0
public/images/customize-settings/default-light.svg → packages/app/public/images/customize-settings/default-light.svg


+ 0 - 0
public/images/customize-settings/fluid-dark.svg → packages/app/public/images/customize-settings/fluid-dark.svg


+ 0 - 0
public/images/customize-settings/fluid-light.svg → packages/app/public/images/customize-settings/fluid-light.svg


+ 0 - 0
public/images/file-not-found.png → packages/app/public/images/file-not-found.png


+ 0 - 0
public/images/icons/editor/bold.svg → packages/app/public/images/icons/editor/bold.svg


+ 0 - 0
public/images/icons/editor/check.svg → packages/app/public/images/icons/editor/check.svg


+ 0 - 0
public/images/icons/editor/code.svg → packages/app/public/images/icons/editor/code.svg


+ 0 - 0
public/images/icons/editor/header.svg → packages/app/public/images/icons/editor/header.svg


+ 0 - 0
public/images/icons/editor/italic.svg → packages/app/public/images/icons/editor/italic.svg


+ 0 - 0
public/images/icons/editor/link.svg → packages/app/public/images/icons/editor/link.svg


+ 0 - 0
public/images/icons/editor/list-ol.svg → packages/app/public/images/icons/editor/list-ol.svg


+ 0 - 0
public/images/icons/editor/list-ul.svg → packages/app/public/images/icons/editor/list-ul.svg


+ 0 - 0
public/images/icons/editor/picture.svg → packages/app/public/images/icons/editor/picture.svg


+ 0 - 0
public/images/icons/editor/quote.svg → packages/app/public/images/icons/editor/quote.svg


+ 0 - 0
public/images/icons/editor/strikethrough.svg → packages/app/public/images/icons/editor/strikethrough.svg


+ 0 - 0
public/images/icons/editor/table.svg → packages/app/public/images/icons/editor/table.svg


+ 0 - 0
public/images/icons/emacs.png → packages/app/public/images/icons/emacs.png


+ 0 - 0
public/images/icons/favicon/android-icon-144x144.png → packages/app/public/images/icons/favicon/android-icon-144x144.png


+ 0 - 0
public/images/icons/favicon/android-icon-192x192.png → packages/app/public/images/icons/favicon/android-icon-192x192.png


+ 0 - 0
public/images/icons/favicon/android-icon-36x36.png → packages/app/public/images/icons/favicon/android-icon-36x36.png


+ 0 - 0
public/images/icons/favicon/android-icon-48x48.png → packages/app/public/images/icons/favicon/android-icon-48x48.png


+ 0 - 0
public/images/icons/favicon/android-icon-72x72.png → packages/app/public/images/icons/favicon/android-icon-72x72.png


+ 0 - 0
public/images/icons/favicon/android-icon-96x96.png → packages/app/public/images/icons/favicon/android-icon-96x96.png


+ 0 - 0
public/images/icons/favicon/apple-icon-114x114.png → packages/app/public/images/icons/favicon/apple-icon-114x114.png


+ 0 - 0
public/images/icons/favicon/apple-icon-120x120.png → packages/app/public/images/icons/favicon/apple-icon-120x120.png


+ 0 - 0
public/images/icons/favicon/apple-icon-144x144.png → packages/app/public/images/icons/favicon/apple-icon-144x144.png


+ 0 - 0
public/images/icons/favicon/apple-icon-152x152.png → packages/app/public/images/icons/favicon/apple-icon-152x152.png


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