Explorar el Código

Merge branch 'master' into feat/sticky-event-features

jam411 hace 3 años
padre
commit
93efc26188
Se han modificado 100 ficheros con 288 adiciones y 3892 borrados
  1. 3 2
      .github/dependabot.yml
  2. 6 2
      .github/workflows/ci-app-prod.yml
  3. 5 0
      .github/workflows/ci-app.yml
  4. 5 0
      .github/workflows/ci-slackbot-proxy.yml
  5. 3 3
      .github/workflows/codeql-analysis.yml
  6. 26 0
      .github/workflows/dependabot-auto-approve.yml
  7. 5 0
      .github/workflows/draft-release.yml
  8. 5 0
      .github/workflows/pr-to-master.yml
  9. 3 3
      .github/workflows/release-slackbot-proxy.yml
  10. 1 15
      .github/workflows/release.yml
  11. 13 0
      .mergify.yml
  12. 0 191
      packages/app/_obsolete/config/webpack.common.js
  13. 0 49
      packages/app/_obsolete/config/webpack.dev.dll.js
  14. 0 81
      packages/app/_obsolete/config/webpack.dev.js
  15. 0 77
      packages/app/_obsolete/config/webpack.prod.js
  16. 0 167
      packages/app/_obsolete/src/client/app.jsx
  17. 0 69
      packages/app/_obsolete/src/client/base.jsx
  18. 0 5
      packages/app/_obsolete/src/client/boot.js
  19. 0 60
      packages/app/_obsolete/src/client/installer.jsx
  20. 0 52
      packages/app/_obsolete/src/client/legacy/crowi.js
  21. 0 142
      packages/app/_obsolete/src/client/nologin.jsx
  22. 0 55
      packages/app/_obsolete/src/client/plugin.js
  23. 0 133
      packages/app/_obsolete/src/client/services/AppContainer.js
  24. 0 214
      packages/app/_obsolete/src/client/services/ContextExtractor.tsx
  25. 0 358
      packages/app/_obsolete/src/client/services/PageContainer.js
  26. 0 144
      packages/app/_obsolete/src/components/MyDraftList/Draft.tsx
  27. 0 192
      packages/app/_obsolete/src/components/MyDraftList/MyDraftList.jsx
  28. 0 76
      packages/app/_obsolete/src/util/i18n.js
  29. 0 17
      packages/app/_obsolete/src/util/old-ios.js
  30. 3 14
      packages/app/docker/Dockerfile
  31. 1 4
      packages/app/package.json
  32. 1 0
      packages/app/public/static/locales/en_US/translation.json
  33. 1 0
      packages/app/public/static/locales/ja_JP/translation.json
  34. 2 1
      packages/app/public/static/locales/zh_CN/translation.json
  35. 6 6
      packages/app/resource/locales/en_US/admin/userInvitation.txt
  36. 8 8
      packages/app/resource/locales/en_US/admin/userWaitingActivation.txt
  37. 3 3
      packages/app/resource/locales/en_US/notifications/comment.txt
  38. 4 4
      packages/app/resource/locales/en_US/notifications/notActiveUser.txt
  39. 2 2
      packages/app/resource/locales/en_US/notifications/pageCreate.txt
  40. 2 2
      packages/app/resource/locales/en_US/notifications/pageDelete.txt
  41. 2 2
      packages/app/resource/locales/en_US/notifications/pageEdit.txt
  42. 2 2
      packages/app/resource/locales/en_US/notifications/pageLike.txt
  43. 2 2
      packages/app/resource/locales/en_US/notifications/pageMove.txt
  44. 4 4
      packages/app/resource/locales/en_US/notifications/passwordReset.txt
  45. 1 1
      packages/app/resource/locales/en_US/notifications/passwordResetSuccessful.txt
  46. 4 4
      packages/app/resource/locales/en_US/notifications/userActivation.txt
  47. 6 6
      packages/app/resource/locales/ja_JP/admin/userInvitation.txt
  48. 8 8
      packages/app/resource/locales/ja_JP/admin/userWaitingActivation.txt
  49. 4 4
      packages/app/resource/locales/ja_JP/notifications/notActiveUser.txt
  50. 4 4
      packages/app/resource/locales/ja_JP/notifications/passwordReset.txt
  51. 1 1
      packages/app/resource/locales/ja_JP/notifications/passwordResetSuccessful.txt
  52. 4 4
      packages/app/resource/locales/ja_JP/notifications/userActivation.txt
  53. 6 6
      packages/app/resource/locales/zh_CN/admin/userInvitation.txt
  54. 8 8
      packages/app/resource/locales/zh_CN/admin/userWaitingActivation.txt
  55. 3 3
      packages/app/resource/locales/zh_CN/notifications/comment.txt
  56. 4 4
      packages/app/resource/locales/zh_CN/notifications/notActiveUser.txt
  57. 2 2
      packages/app/resource/locales/zh_CN/notifications/pageCreate.txt
  58. 2 2
      packages/app/resource/locales/zh_CN/notifications/pageDelete.txt
  59. 2 2
      packages/app/resource/locales/zh_CN/notifications/pageEdit.txt
  60. 2 2
      packages/app/resource/locales/zh_CN/notifications/pageLike.txt
  61. 2 2
      packages/app/resource/locales/zh_CN/notifications/pageMove.txt
  62. 3 3
      packages/app/resource/locales/zh_CN/notifications/passwordReset.txt
  63. 1 1
      packages/app/resource/locales/zh_CN/notifications/passwordResetSuccessful.txt
  64. 4 4
      packages/app/resource/locales/zh_CN/notifications/userActivation.txt
  65. 13 10
      packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx
  66. 35 0
      packages/app/src/components/NotAvailable.tsx
  67. 15 19
      packages/app/src/components/NotAvailableForGuest.tsx
  68. 27 0
      packages/app/src/components/NotAvailableForNow.tsx
  69. 0 12
      packages/app/src/lib/util/isSecurityEnv.js
  70. 0 29
      packages/app/src/server/crowi/dev.js
  71. 0 41
      packages/app/src/server/crowi/express-init.js
  72. 0 3
      packages/app/src/server/routes/hackmd.js
  73. 1 1
      packages/app/src/server/service/import.js
  74. 8 2
      packages/app/src/server/service/mail.ts
  75. 0 15
      packages/app/src/server/util/i18nUserSettingDetector.js
  76. 0 133
      packages/app/src/server/util/middlewares.js
  77. 0 208
      packages/app/src/server/util/swigFunctions.js
  78. 0 1
      packages/app/src/server/views/500.html
  79. 0 45
      packages/app/src/server/views/forgot-password.html
  80. 0 60
      packages/app/src/server/views/forgot-password/error.html
  81. 0 95
      packages/app/src/server/views/installer.html
  82. 0 150
      packages/app/src/server/views/invited.html
  83. 0 43
      packages/app/src/server/views/layout-growi/base/layout.html
  84. 0 24
      packages/app/src/server/views/layout-growi/expired_shared_page.html
  85. 0 25
      packages/app/src/server/views/layout-growi/forbidden.html
  86. 0 30
      packages/app/src/server/views/layout-growi/identical-path-page.html
  87. 0 20
      packages/app/src/server/views/layout-growi/not_creatable.html
  88. 0 32
      packages/app/src/server/views/layout-growi/not_found.html
  89. 0 16
      packages/app/src/server/views/layout-growi/not_found_shared_page.html
  90. 0 35
      packages/app/src/server/views/layout-growi/page.html
  91. 0 31
      packages/app/src/server/views/layout-growi/page_list.html
  92. 0 44
      packages/app/src/server/views/layout-growi/shared_page.html
  93. 0 43
      packages/app/src/server/views/layout-growi/user_page.html
  94. 0 155
      packages/app/src/server/views/layout/layout.html
  95. 0 171
      packages/app/src/server/views/login.html
  96. 0 40
      packages/app/src/server/views/maintenance-mode.html
  97. 0 21
      packages/app/src/server/views/me/all-in-app-notifications.html
  98. 0 21
      packages/app/src/server/views/me/drafts.html
  99. 0 21
      packages/app/src/server/views/me/index.html
  100. 0 64
      packages/app/src/server/views/page_presentation.html

+ 3 - 2
.github/dependabot.yml.org → .github/dependabot.yml

@@ -2,7 +2,7 @@ version: 2
 updates:
 updates:
   - package-ecosystem: github-actions
   - package-ecosystem: github-actions
     directory: '/'
     directory: '/'
-    open-pull-requests-limit: 0
+    open-pull-requests-limit: 3
     schedule:
     schedule:
       interval: monthly
       interval: monthly
     commit-message:
     commit-message:
@@ -11,7 +11,7 @@ updates:
 
 
   - package-ecosystem: npm
   - package-ecosystem: npm
     directory: '/'
     directory: '/'
-    open-pull-requests-limit: 0
+    open-pull-requests-limit: 3
     schedule:
     schedule:
       interval: weekly
       interval: weekly
     commit-message:
     commit-message:
@@ -22,4 +22,5 @@ updates:
       - dependency-name: string-width
       - dependency-name: string-width
       - dependency-name: "@handsontable/react"
       - dependency-name: "@handsontable/react"
       - dependency-name: handsontable
       - dependency-name: handsontable
+      - dependency-name: reveal.js
 
 

+ 6 - 2
.github/workflows/ci-app-prod.yml

@@ -41,6 +41,10 @@ on:
         type: boolean
         type: boolean
         default: false
         default: false
 
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
 
 
 jobs:
 jobs:
 
 
@@ -57,7 +61,7 @@ jobs:
     uses: weseek/growi/.github/workflows/reusable-app-prod.yml@master
     uses: weseek/growi/.github/workflows/reusable-app-prod.yml@master
     with:
     with:
       node-version: 16.x
       node-version: 16.x
-      skip-cypress: ${{ contains( github.event.pull_request.labels.*.name, 'dependencies' ) && contains( github.event.pull_request.labels.*.name, 'github_actions' ) }}
+      skip-cypress: ${{ contains( github.event.pull_request.labels.*.name, 'dependencies' ) }}
       cypress-report-artifact-name: Cypress report
       cypress-report-artifact-name: Cypress report
       cypress-config-video: ${{ inputs.cypress-config-video || false }}
       cypress-config-video: ${{ inputs.cypress-config-video || false }}
     secrets:
     secrets:
@@ -73,7 +77,7 @@ jobs:
 
 
     with:
     with:
       node-version: 16.x
       node-version: 16.x
-      skip-reg-suit: ${{ contains( github.event.pull_request.labels.*.name, 'dependencies' ) && contains( github.event.pull_request.labels.*.name, 'github_actions' ) }}
+      skip-reg-suit: ${{ contains( github.event.pull_request.labels.*.name, 'dependencies' ) }}
       cypress-report-artifact-name: Cypress report
       cypress-report-artifact-name: Cypress report
     secrets:
     secrets:
       REG_NOTIFY_GITHUB_PLUGIN_CLIENTID: ${{ secrets.REG_NOTIFY_GITHUB_PLUGIN_CLIENTID }}
       REG_NOTIFY_GITHUB_PLUGIN_CLIENTID: ${{ secrets.REG_NOTIFY_GITHUB_PLUGIN_CLIENTID }}

+ 5 - 0
.github/workflows/ci-app.yml

@@ -20,6 +20,11 @@ on:
       - packages/slack/**
       - packages/slack/**
       - packages/ui/**
       - packages/ui/**
 
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+
 jobs:
 jobs:
   lint:
   lint:
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest

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

@@ -16,6 +16,11 @@ on:
       - '!packages/slackbot-proxy/docker/**'
       - '!packages/slackbot-proxy/docker/**'
       - packages/slack/**
       - packages/slack/**
 
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+
 jobs:
 jobs:
 
 
   test:
   test:

+ 3 - 3
.github/workflows/codeql-analysis.yml

@@ -45,7 +45,7 @@ jobs:
 
 
     # Initializes the CodeQL tools for scanning.
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v1
+      uses: github/codeql-action/init@v2
       with:
       with:
         languages: ${{ matrix.language }}
         languages: ${{ matrix.language }}
         # If you wish to specify custom queries, you can do so here or in a config file.
         # If you wish to specify custom queries, you can do so here or in a config file.
@@ -56,7 +56,7 @@ jobs:
     # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
     # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
     # If this step fails, then you should remove it and run the build manually (see below)
     # If this step fails, then you should remove it and run the build manually (see below)
     - name: Autobuild
     - name: Autobuild
-      uses: github/codeql-action/autobuild@v1
+      uses: github/codeql-action/autobuild@v2
 
 
     # ℹ️ Command-line programs to run using the OS shell.
     # ℹ️ Command-line programs to run using the OS shell.
     # 📚 https://git.io/JvXDl
     # 📚 https://git.io/JvXDl
@@ -70,4 +70,4 @@ jobs:
     #   make release
     #   make release
 
 
     - name: Perform CodeQL Analysis
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v1
+      uses: github/codeql-action/analyze@v2

+ 26 - 0
.github/workflows/dependabot-auto-approve.yml

@@ -0,0 +1,26 @@
+# by https://zenn.dev/nemuki/articles/dependabot-auto-merge
+name: Auto approve on dependabot PR at patch update
+
+on:
+  pull_request_target:
+    types: [opened, reopened, synchronize]
+
+permissions:
+  pull-requests: write
+
+jobs:
+  dependabot-auto-approve:
+    runs-on: ubuntu-latest
+    if: ${{ github.actor == 'dependabot[bot]' }}
+    steps:
+      - name: Dependabot metadata
+        id: dependabot-metadata
+        uses: dependabot/fetch-metadata@v1
+        with:
+          github-token: '${{ secrets.GITHUB_TOKEN }}'
+      - name: Approve a PR
+        if: ${{ steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch' }}
+        run: gh pr review --approve "$PR_URL"
+        env:
+          PR_URL: ${{ github.event.pull_request.html_url }}
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

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

@@ -5,6 +5,11 @@ on:
     branches:
     branches:
       - master
       - master
 
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+
 jobs:
 jobs:
 
 
   # Refs: https://github.com/release-drafter/release-drafter
   # Refs: https://github.com/release-drafter/release-drafter

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

@@ -7,6 +7,11 @@ on:
     # Only following types are handled by the action, but one can default to all as well
     # Only following types are handled by the action, but one can default to all as well
     types: [opened, reopened, edited, synchronize]
     types: [opened, reopened, edited, synchronize]
 
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+
 jobs:
 jobs:
 
 
   # Refs: https://github.com/release-drafter/release-drafter
   # Refs: https://github.com/release-drafter/release-drafter

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

@@ -43,12 +43,12 @@ jobs:
         password: ${{ secrets.DOCKER_REGISTRY_ON_GITHUB_PASSWORD }}
         password: ${{ secrets.DOCKER_REGISTRY_ON_GITHUB_PASSWORD }}
 
 
     - name: Authenticate to Google Cloud for GROWI.cloud
     - name: Authenticate to Google Cloud for GROWI.cloud
-      uses: google-github-actions/auth@v0
+      uses: google-github-actions/auth@v1
       with:
       with:
         credentials_json: '${{ secrets.GCP_SA_KEY_SLACKBOT_PROXY }}'
         credentials_json: '${{ secrets.GCP_SA_KEY_SLACKBOT_PROXY }}'
 
 
     - name: Setup gcloud
     - name: Setup gcloud
-      uses: google-github-actions/setup-gcloud@v0
+      uses: google-github-actions/setup-gcloud@v1
 
 
     - name: Configure docker for gcloud
     - name: Configure docker for gcloud
       run: |
       run: |
@@ -75,7 +75,7 @@ jobs:
         mv /tmp/.buildx-cache-new /tmp/.buildx-cache
         mv /tmp/.buildx-cache-new /tmp/.buildx-cache
 
 
     - name: Add tag
     - name: Add tag
-      uses: anothrNick/github-tag-action@1.38.0
+      uses: anothrNick/github-tag-action@v1
       env:
       env:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         CUSTOM_TAG: v${{ steps.package-json.outputs.packageVersion }}
         CUSTOM_TAG: v${{ steps.package-json.outputs.packageVersion }}

+ 1 - 15
.github/workflows/release.yml

@@ -126,29 +126,17 @@ jobs:
 
 
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
 
 
-    strategy:
-      matrix:
-        flavor: [default, nocdn]
-
     steps:
     steps:
     - uses: actions/checkout@v3
     - uses: actions/checkout@v3
       with:
       with:
         ref: v${{ needs.create-github-release.outputs.RELEASED_VERSION }}
         ref: v${{ needs.create-github-release.outputs.RELEASED_VERSION }}
         lfs: true
         lfs: true
 
 
-    - name: Setup suffix
-      id: suffix
-      run: |
-        [[ ${{ matrix.flavor }} = "nocdn" ]] && suffix="-nocdn" || suffix=""
-        echo "SUFFIX=$suffix" >> $GITHUB_OUTPUT
-
     - name: Docker meta
     - name: Docker meta
       id: meta
       id: meta
       uses: docker/metadata-action@v4
       uses: docker/metadata-action@v4
       with:
       with:
         images: weseek/growi,ghcr.io/weseek/growi
         images: weseek/growi,ghcr.io/weseek/growi
-        flavor: |
-          suffix=${{ steps.suffix.outputs.SUFFIX }}
         tags: |
         tags: |
           type=raw,value=latest
           type=raw,value=latest
           type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}
           type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}
@@ -178,8 +166,6 @@ jobs:
         file: ./packages/app/docker/Dockerfile
         file: ./packages/app/docker/Dockerfile
         platforms: linux/amd64
         platforms: linux/amd64
         push: true
         push: true
-        build-args: |
-          flavor=${{ matrix.flavor }}
         builder: ${{ steps.buildx.outputs.name }}
         builder: ${{ steps.buildx.outputs.name }}
         cache-from: type=gha
         cache-from: type=gha
         cache-to: type=gha,mode=max
         cache-to: type=gha,mode=max
@@ -198,7 +184,7 @@ jobs:
       with:
       with:
         channel: '#release'
         channel: '#release'
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
-        created_tag: 'v${{ needs.create-github-release.outputs.RELEASED_VERSION }}${{ steps.suffix.outputs.SUFFIX }}'
+        created_tag: 'v${{ needs.create-github-release.outputs.RELEASED_VERSION }}'
 
 
     - name: Check whether workspace is clean
     - name: Check whether workspace is clean
       run: |
       run: |

+ 13 - 0
.mergify.yml

@@ -0,0 +1,13 @@
+pull_request_rules:
+  - name: Automatic merge for Dependabot pull requests
+    conditions:
+      - author = dependabot[bot]
+      - '#approved-reviews-by >= 1'
+      - check-success = "lint (16.x)"
+      - check-success = "test (16.x)"
+      - check-success = "launch-dev (16.x)"
+      - check-success = "test-prod-node14 / launch-prod"
+      - check-success = "test-prod-node16 / launch-prod"
+    actions:
+      merge:
+        method: merge

+ 0 - 191
packages/app/_obsolete/config/webpack.common.js

@@ -1,191 +0,0 @@
-/* eslint-disable */
-/**
- * @author: Yuki Takei <yuki@weseek.co.jp>
- */
-const path = require('path');
-
-const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
-const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
-const webpack = require('webpack');
-
-/*
-  * Webpack Plugins
-  */
-const WebpackAssetsManifest = require('webpack-assets-manifest');
-
-/*
-  * Webpack configuration
-  *
-  * See: http://webpack.github.io/docs/configuration.html#cli
-  */
-module.exports = (options) => {
-  return {
-    mode: options.mode,
-    entry: Object.assign({
-      'js/boot':                      './src/client/boot',
-      'js/app':                       './src/client/app',
-      'js/admin':                     './src/client/admin',
-      'js/nologin':                   './src/client/nologin',
-      'js/installer':                   './src/client/installer',
-      '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/style-app':             './src/styles/style-app.scss',
-      'styles/style-presentation':    './src/styles/style-presentation.scss',
-      // themes
-      '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/theme-fire-red':      './src/styles/theme/fire-red.scss',
-      'styles/theme-jade-green':      './src/styles/theme/jade-green.scss',
-      'styles/theme-blackboard':      './src/styles/theme/blackboard.scss',
-      // styles for external services
-      'styles/style-hackmd':          './src/styles-hackmd/style.scss',
-    }, options.entry || {}), // Merge with env dependent settings
-    output: Object.assign({
-      path: path.resolve(__dirname, '../public'),
-      publicPath: '/',
-      filename: '[name].bundle.js',
-    }, options.output || {}), // Merge with env dependent settings
-    externals: {
-      // require("jquery") is external and available
-      //  on the global var jQuery
-      jquery: 'jQuery',
-      hljs: 'hljs',
-      'dtrace-provider': 'dtrace-provider',
-    },
-    resolve: {
-      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: 'empty',
-    },
-    module: {
-      rules: options.module.rules.concat([
-        {
-          test: /.(jsx?|tsx?)$/,
-          exclude: {
-            test: /node_modules/,
-            exclude: [ // include as a result
-              /node_modules\/codemirror/,
-            ],
-          },
-          use: [{
-            loader: 'ts-loader',
-            options: {
-              transpileOnly: true,
-              configFile: path.resolve(__dirname, '../tsconfig.build.client.json'),
-            },
-          }],
-        },
-        {
-          test: /locales/,
-          loader: '@alienfast/i18next-loader',
-          options: {
-            basenameAsNamespace: true,
-          },
-        },
-        /*
-          * File loader for supporting images, for example, in CSS files.
-          */
-        {
-          test: /\.(jpg|png|gif)$/,
-          use: 'file-loader',
-        },
-        /* File loader for supporting fonts, for example, in CSS files.
-         */
-        {
-          test: /\.(eot|woff2?|svg|ttf)([?]?.*)$/,
-          use: 'null-loader',
-        },
-      ]),
-    },
-    plugins: options.plugins.concat([
-
-      new WebpackAssetsManifest({ publicPath: true }),
-
-      new webpack.DefinePlugin({
-        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
-      }),
-
-      // ignore
-      new webpack.IgnorePlugin(/^\.\/lib\/deflate\.js/, /markdown-it-plantuml/),
-      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
-
-      new LodashModuleReplacementPlugin({
-        flattening: true,
-      }),
-
-      new webpack.ProvidePlugin({ // refs externals
-        jQuery: 'jquery',
-        $: 'jquery',
-      }),
-
-    ]),
-
-    devtool: options.devtool,
-    target: 'web', // Make web variables accessible to webpack, e.g. window
-    optimization: {
-      namedModules: true,
-      splitChunks: {
-        cacheGroups: {
-          style_commons: {
-            test: /\.(sc|sa|c)ss$/,
-            chunks: (chunk) => {
-              // ignore patterns
-              return chunk.name != null && !chunk.name.match(/style-|theme-|legacy-presentation/);
-            },
-            name: 'styles/style-commons',
-            minSize: 1,
-            priority: 30,
-            enforce: true,
-          },
-          commons: {
-            test: /(src|resource)[\\/].*\.(js|jsx|json)$/,
-            chunks: (chunk) => {
-              // ignore patterns
-              return chunk.name != null && !chunk.name.match(/boot/);
-            },
-            name: 'js/commons',
-            minChunks: 2,
-            minSize: 1,
-            priority: 20,
-          },
-          vendors: {
-            test: /node_modules[\\/].*\.(js|jsx|json)$/,
-            chunks: (chunk) => {
-              // ignore patterns
-              return chunk.name != null && !chunk.name.match(/boot|legacy-presentation|hackmd-/);
-            },
-            name: 'js/vendors',
-            minSize: 1,
-            priority: 10,
-            enforce: true,
-          },
-        },
-      },
-      minimizer: options.optimization.minimizer || [],
-    },
-    performance: options.performance || {},
-    stats: options.stats || {},
-  };
-};

+ 0 - 49
packages/app/_obsolete/config/webpack.dev.dll.js

@@ -1,49 +0,0 @@
-/* eslint-disable */
-/**
- * @author: Yuki Takei <yuki@weseek.co.jp>
- */
-const path = require('path');
-const webpack = require('webpack');
-
-
-module.exports = {
-  mode: 'development',
-  entry: {
-    dlls: [
-      // Libraries
-      'axios',
-      'browser-bunyan', 'bunyan-format',
-      'codemirror', 'react-codemirror2',
-      'date-fns',
-      'diff2html',
-      'debug',
-      'entities',
-      'i18next', 'i18next-browser-languagedetector',
-      'jquery-slimscroll',
-      'lodash', 'pako',
-      'markdown-it', 'csv-to-markdown-table',
-      'react', 'react-dom',
-      'reactstrap', 'react-bootstrap-typeahead',
-      'react-i18next', 'react-dropzone', 'react-hotkeys', 'react-copy-to-clipboard', 'react-waypoint',
-      'socket.io-client',
-      'toastr',
-      'unstated',
-      'xss',
-    ],
-  },
-  output: {
-    path: path.resolve(__dirname, '../public/dll'),
-    filename: 'dll.js',
-    library: 'growi_dlls',
-  },
-  resolve: {
-    extensions: ['.js', '.json'],
-    modules: [path.resolve(__dirname, '../src'), path.resolve(__dirname, '../node_modules')],
-  },
-  plugins: [
-    new webpack.DllPlugin({
-      path: path.resolve(__dirname, '../public/dll/manifest.json'),
-      name: 'growi_dlls',
-    }),
-  ],
-};

+ 0 - 81
packages/app/_obsolete/config/webpack.dev.js

@@ -1,81 +0,0 @@
-/* eslint-disable */
-/**
- * @author: Yuki Takei <yuki@weseek.co.jp>
- */
-
-const path = require('path');
-
-/*
- * Webpack Plugins
- */
-const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
-const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
-
-/**
- * Webpack Constants
- */
-const { ANALYZE } = process.env;
-
-module.exports = require('./webpack.common')({
-  mode: 'development',
-  devtool: 'cheap-module-eval-source-map',
-  entry: {
-    'js/dev': './src/client/dev',
-  },
-  resolve: {
-    modules: ['../node_modules'],
-  },
-  module: {
-    rules: [
-      {
-        test: /\.(css|scss)$/,
-        use: [
-          'style-loader',
-          { loader: 'css-loader', options: { sourceMap: true } },
-          { loader: 'sass-loader', options: { sourceMap: true } },
-        ],
-        exclude: [
-          path.resolve(__dirname, '../src/styles-hackmd'),
-          path.resolve(__dirname, '../src/styles/style-presentation.scss'),
-        ],
-      },
-      { // Dump CSS for HackMD
-        test: /\.(css|scss)$/,
-        use: [
-          MiniCssExtractPlugin.loader,
-          'css-loader',
-          'sass-loader',
-        ],
-        include: [
-          path.resolve(__dirname, '../src/styles-hackmd'),
-          path.resolve(__dirname, '../src/styles/style-presentation.scss'),
-        ],
-      },
-    ],
-  },
-  plugins: [
-
-    new MiniCssExtractPlugin({
-      filename: '[name].bundle.css',
-    }),
-
-    new BundleAnalyzerPlugin({
-      analyzerMode: ANALYZE ? 'server' : 'disabled',
-    }),
-
-    new HardSourceWebpackPlugin(),
-    new HardSourceWebpackPlugin.ExcludeModulePlugin([
-      {
-        // see https://github.com/mzgoddard/hard-source-webpack-plugin/blob/master/README.md#excludemoduleplugin
-        test: /mini-css-extract-plugin[\\/]dist[\\/]loader/,
-      },
-    ]),
-
-  ],
-  optimization: {},
-  performance: {
-    hints: false,
-  },
-
-});

+ 0 - 77
packages/app/_obsolete/config/webpack.prod.js

@@ -1,77 +0,0 @@
-/* eslint-disable */
-/**
- * @author: Yuki Takei <yuki@weseek.co.jp>
- */
-
-const path = require('path');
-
-/**
-  * Webpack Plugins
-  */
-const TerserPlugin = require('terser-webpack-plugin');
-const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
-const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
-
-/**
-  * Webpack Constants
-  */
-const { ANALYZE_BUNDLE_SIZE } = process.env;
-
-module.exports = require('./webpack.common')({
-  mode: 'production',
-  devtool: undefined,
-  output: {
-    filename: '[name].[chunkhash].bundle.js',
-    chunkFilename: '[name].[chunkhash].chunk.js',
-  },
-  module: {
-    rules: [
-      {
-        test: /\.(css|scss)$/,
-        use: [
-          MiniCssExtractPlugin.loader,
-          'css-loader',
-          {
-            loader: 'postcss-loader',
-            options: {
-              sourceMap: false,
-              postcssOptions: {
-                plugins: [
-                  require('autoprefixer')(),
-                ],
-              },
-            },
-          },
-          'sass-loader',
-        ],
-        exclude: [path.resolve(__dirname, '../src/client/legacy')],
-      },
-      {
-        test: /\.(css|scss)$/,
-        use: ['style-loader', 'css-loader', 'sass-loader'],
-        include: [path.resolve(__dirname, '../src/client/legacy')],
-      },
-    ],
-  },
-  plugins: [
-
-    new MiniCssExtractPlugin({
-      filename: '[name].[hash].css',
-    }),
-
-    new BundleAnalyzerPlugin({
-      analyzerMode: ANALYZE_BUNDLE_SIZE ? 'static' : 'disabled',
-      reportFilename: path.resolve(__dirname, '../report/bundle-analyzer.html'),
-      openAnalyzer: false,
-    }),
-
-  ],
-  optimization: {
-    minimize: true,
-    minimizer: [
-      new TerserPlugin({}),
-      new OptimizeCSSAssetsPlugin({}),
-    ],
-  },
-});

+ 0 - 167
packages/app/_obsolete/src/client/app.jsx

@@ -1,167 +0,0 @@
-import React from 'react';
-
-import { DndProvider } from 'react-dnd';
-import { HTML5Backend } from 'react-dnd-html5-backend';
-import ReactDOM from 'react-dom';
-import { I18nextProvider } from 'react-i18next';
-import { SWRConfig } from 'swr';
-import { Provider } from 'unstated';
-
-import ContextExtractor from '~/client/services/ContextExtractor';
-import EditorContainer from '~/client/services/EditorContainer';
-import PageContainer from '~/client/services/PageContainer';
-import { IdenticalPathPage } from '~/components/IdenticalPathPage';
-import PrivateLegacyPages from '~/components/PrivateLegacyPages';
-import loggerFactory from '~/utils/logger';
-import { swrGlobalConfiguration } from '~/utils/swr-utils';
-
-import ErrorBoundary from '../components/ErrorBoudary';
-import Fab from '../components/Fab';
-import ForbiddenPage from '../components/ForbiddenPage';
-import RecentlyCreatedIcon from '../components/Icons/RecentlyCreatedIcon';
-import InAppNotificationPage from '../components/InAppNotification/InAppNotificationPage';
-import PersonalSettings from '../components/Me/PersonalSettings';
-import MyDraftList from '../components/MyDraftList/MyDraftList';
-import GrowiContextualSubNavigation from '../components/Navbar/GrowiContextualSubNavigation';
-import GrowiSubNavigationSwitcher from '../components/Navbar/GrowiSubNavigationSwitcher';
-import NotFoundPage from '../components/NotFoundPage';
-import { Page } from '../components/Page';
-import DisplaySwitcher from '../components/Page/DisplaySwitcher';
-import RedirectedAlert from '../components/Page/RedirectedAlert';
-import ShareLinkAlert from '../components/Page/ShareLinkAlert';
-import { PageComment } from '../components/PageComment';
-import CommentEditorLazyRenderer from '../components/PageComment/CommentEditorLazyRenderer';
-import PageContentFooter from '../components/PageContentFooter';
-import BookmarkList from '../components/PageList/BookmarkList';
-import PageStatusAlert from '../components/PageStatusAlert';
-import { PageTimeline } from '../components/PageTimeline';
-import RecentCreated from '../components/RecentCreated/RecentCreated';
-import { SearchPage } from '../components/SearchPage';
-import Sidebar from '../components/Sidebar';
-import TrashPageList from '../components/TrashPageList';
-
-import { appContainer, componentMappings } from './base';
-
-const logger = loggerFactory('growi:cli:app');
-
-appContainer.initContents();
-
-const { i18n } = appContainer;
-const socketIoContainer = appContainer.getContainer('SocketIoContainer');
-
-// create unstated container instance
-const pageContainer = new PageContainer(appContainer);
-const editorContainer = new EditorContainer(appContainer);
-const injectableContainers = [
-  appContainer, socketIoContainer, pageContainer, editorContainer,
-];
-
-logger.info('unstated containers have been initialized');
-
-/**
- * define components
- *  key: id of element
- *  value: React Element
- */
-Object.assign(componentMappings, {
-  'grw-sidebar-wrapper': <Sidebar />,
-
-  'search-page': <SearchPage appContainer={appContainer} />,
-  'private-regacy-pages': <PrivateLegacyPages appContainer={appContainer} />,
-
-  'all-in-app-notifications': <InAppNotificationPage />,
-  'identical-path-page': <IdenticalPathPage />,
-
-  // 'revision-history': <PageHistory pageId={pageId} />,
-
-  'grw-page-status-alert-container': <PageStatusAlert />,
-
-  'maintenance-mode-content': <MaintenanceModeContent />,
-
-  'trash-page-list-container': <TrashPageList />,
-
-  'not-found-page': <NotFoundPage />,
-
-  'forbidden-page': <ForbiddenPage isLinkSharingDisabled={appContainer.config.disableLinkSharing} />,
-
-  'page-timeline': <PageTimeline />,
-
-  'personal-setting': <PersonalSettings />,
-  'my-drafts': <MyDraftList />,
-
-  'grw-fab-container': <Fab />,
-
-  'share-link-alert': <ShareLinkAlert />,
-  'redirected-alert': <RedirectedAlert />,
-});
-
-// additional definitions if data exists
-if (pageContainer.state.pageId != null) {
-  Object.assign(componentMappings, {
-    'page-comments-list': <PageComment appContainer={appContainer} pageId={pageContainer.state.pageId} isReadOnly={false} titleAlign="left" />,
-    'page-comment-write': <CommentEditorLazyRenderer appContainer={appContainer} pageId={pageContainer.state.pageId} />,
-    'page-content-footer': <PageContentFooter
-      createdAt={new Date(pageContainer.state.createdAt)}
-      updatedAt={new Date(pageContainer.state.updatedAt)}
-      creator={pageContainer.state.creator}
-      revisionAuthor={pageContainer.state.revisionAuthor}
-    />,
-
-    'recent-created-icon': <RecentlyCreatedIcon />,
-  });
-}
-if (pageContainer.state.creator != null) {
-  Object.assign(componentMappings, {
-    'user-created-list': <RecentCreated userId={pageContainer.state.creator._id} />,
-    'user-bookmark-list': <BookmarkList userId={pageContainer.state.creator._id} />,
-  });
-}
-if (pageContainer.state.path != null) {
-  Object.assign(componentMappings, {
-    // eslint-disable-next-line quote-props
-    'page': <Page />,
-    'grw-subnav-container': <GrowiContextualSubNavigation isLinkSharingDisabled={appContainer.config.disableLinkSharing} />,
-    'grw-subnav-switcher-container': <GrowiSubNavigationSwitcher isLinkSharingDisabled={appContainer.config.disableLinkSharing} />,
-    'display-switcher': <DisplaySwitcher />,
-  });
-}
-
-const renderMainComponents = () => {
-  Object.keys(componentMappings).forEach((key) => {
-    const elem = document.getElementById(key);
-    if (elem) {
-      ReactDOM.render(
-        <I18nextProvider i18n={i18n}>
-          <ErrorBoundary>
-            <SWRConfig value={swrGlobalConfiguration}>
-              <Provider inject={injectableContainers}>
-                <DndProvider backend={HTML5Backend}>
-                  {componentMappings[key]}
-                </DndProvider>
-              </Provider>
-            </SWRConfig>
-          </ErrorBoundary>
-        </I18nextProvider>,
-        elem,
-      );
-    }
-  });
-};
-
-// extract context before rendering main components
-const elem = document.getElementById('growi-context-extractor');
-if (elem != null) {
-  ReactDOM.render(
-    <SWRConfig value={swrGlobalConfiguration}>
-      <ContextExtractor></ContextExtractor>
-    </SWRConfig>,
-    elem,
-    renderMainComponents,
-  );
-}
-else {
-  renderMainComponents();
-}
-
-// initialize scrollpos-styler
-ScrollPosStyler.init();

+ 0 - 69
packages/app/_obsolete/src/client/base.jsx

@@ -1,69 +0,0 @@
-import React from 'react';
-
-import EventEmitter from 'events';
-
-import AppContainer from '~/client/services/AppContainer';
-import { DescendantsPageListModal } from '~/components/DescendantsPageListModal';
-import PutbackPageModal from '~/components/PutbackPageModal';
-import ShortcutsModal from '~/components/ShortcutsModal';
-import SystemVersion from '~/components/SystemVersion';
-import InterceptorManager from '~/services/interceptor-manager';
-import loggerFactory from '~/utils/logger';
-
-import EmptyTrashModal from '../components/EmptyTrashModal';
-import HotkeysManager from '../components/Hotkeys/HotkeysManager';
-import { GrowiNavbar } from '../components/Navbar/GrowiNavbar';
-import { GrowiNavbarBottom } from '../components/Navbar/GrowiNavbarBottom';
-import PageAccessoriesModal from '../components/PageAccessoriesModal';
-import PageCreateModal from '../components/PageCreateModal';
-import PageDeleteModal from '../components/PageDeleteModal';
-import PageDuplicateModal from '../components/PageDuplicateModal';
-import PagePresentationModal from '../components/PagePresentationModal';
-import PageRenameModal from '../components/PageRenameModal';
-
-import ShowPageAccessoriesModal from './services/ShowPageAccessoriesModal';
-
-const logger = loggerFactory('growi:cli:app');
-
-if (!window) {
-  window = {};
-}
-
-window.globalEmitter = new EventEmitter();
-window.interceptorManager = new InterceptorManager();
-
-// create unstated container instance
-const appContainer = new AppContainer();
-
-appContainer.initApp();
-
-logger.info('AppContainer has been initialized');
-
-/**
- * define components
- *  key: id of element
- *  value: React Element
- */
-const componentMappings = {
-  'grw-navbar': <GrowiNavbar />,
-  'grw-navbar-bottom-container': <GrowiNavbarBottom />,
-
-  'page-create-modal': <PageCreateModal />,
-  'page-delete-modal': <PageDeleteModal />,
-  'empty-trash-modal': <EmptyTrashModal />,
-  'page-duplicate-modal': <PageDuplicateModal />,
-  'page-rename-modal': <PageRenameModal />,
-  'page-presentation-modal': <PagePresentationModal />,
-  'page-accessories-modal': <PageAccessoriesModal />,
-  'descendants-page-list-modal': <DescendantsPageListModal />,
-  'page-put-back-modal': <PutbackPageModal />,
-  'shortcuts-modal': <ShortcutsModal />,
-
-  'grw-hotkeys-manager': <HotkeysManager />,
-  'system-version': <SystemVersion />,
-
-
-  'show-page-accessories-modal': <ShowPageAccessoriesModal />,
-};
-
-export { appContainer, componentMappings };

+ 0 - 5
packages/app/_obsolete/src/client/boot.js

@@ -1,5 +0,0 @@
-import {
-  applyOldIos,
-} from './util/old-ios';
-
-applyOldIos();

+ 0 - 60
packages/app/_obsolete/src/client/installer.jsx

@@ -1,60 +0,0 @@
-import React from 'react';
-
-import ReactDOM from 'react-dom';
-import { I18nextProvider } from 'react-i18next';
-import { SWRConfig } from 'swr';
-
-
-import { swrGlobalConfiguration } from '~/utils/swr-utils';
-
-import InstallerForm from '../components/InstallerForm';
-
-import ContextExtractor from './services/ContextExtractor';
-import { i18nFactory } from './util/i18n';
-
-const i18n = i18nFactory();
-
-const componentMappings = {};
-
-// render InstallerForm
-const installerFormContainerElem = document.getElementById('installer-form-container');
-if (installerFormContainerElem) {
-  const userName = installerFormContainerElem.dataset.userName;
-  const name = installerFormContainerElem.dataset.name;
-  const email = installerFormContainerElem.dataset.email;
-
-  Object.assign(componentMappings, {
-    'installer-form-container': <InstallerForm userName={userName} name={name} email={email} />,
-  });
-}
-
-const renderMainComponents = () => {
-  Object.keys(componentMappings).forEach((key) => {
-    const elem = document.getElementById(key);
-    if (elem) {
-      ReactDOM.render(
-        <I18nextProvider i18n={i18n}>
-          <SWRConfig value={swrGlobalConfiguration}>
-            {componentMappings[key]}
-          </SWRConfig>
-        </I18nextProvider>,
-        elem,
-      );
-    }
-  });
-};
-
-// extract context before rendering main components
-const elem = document.getElementById('growi-context-extractor');
-if (elem != null) {
-  ReactDOM.render(
-    <SWRConfig value={swrGlobalConfiguration}>
-      <ContextExtractor></ContextExtractor>
-    </SWRConfig>,
-    elem,
-    renderMainComponents,
-  );
-}
-else {
-  renderMainComponents();
-}

+ 0 - 52
packages/app/_obsolete/src/client/legacy/crowi.js

@@ -1,52 +0,0 @@
-/* eslint-disable react/jsx-filename-extension */
-require('jquery.cookie');
-
-const Crowi = {};
-
-if (!window) {
-  window = {};
-}
-window.Crowi = Crowi;
-
-Crowi.setCaretLine = function(line) {
-  // eslint-disable-next-line no-undef
-  globalEmitter.emit('setCaretLine', line);
-};
-
-// original: middleware.swigFilter
-Crowi.userPicture = function(user) {
-  if (!user) {
-    return '/images/icons/user.svg';
-  }
-
-  return user.image || '/images/icons/user.svg';
-};
-
-Crowi.initClassesByOS = function() {
-  // add classes to cmd-key by OS
-  const platform = navigator.platform.toLowerCase();
-  const isMac = (platform.indexOf('mac') > -1);
-
-  document.querySelectorAll('.system-version .cmd-key').forEach((element) => {
-    if (isMac) {
-      element.classList.add('mac');
-    }
-    else {
-      element.classList.add('win');
-    }
-  });
-
-  document.querySelectorAll('#shortcuts-modal .cmd-key').forEach((element) => {
-    if (isMac) {
-      element.classList.add('mac');
-    }
-    else {
-      element.classList.add('win', 'key-longer');
-    }
-  });
-};
-
-// adjust min-height of page for print temporarily
-window.onbeforeprint = function() {
-  $('#page-wrapper').css('min-height', '0px');
-};

+ 0 - 142
packages/app/_obsolete/src/client/nologin.jsx

@@ -1,142 +0,0 @@
-import React from 'react';
-
-import ReactDOM from 'react-dom';
-import { I18nextProvider } from 'react-i18next';
-import { SWRConfig } from 'swr';
-import { Provider } from 'unstated';
-
-
-import AppContainer from '~/client/services/AppContainer';
-import CompleteUserRegistrationForm from '~/components/CompleteUserRegistrationForm';
-import { swrGlobalConfiguration } from '~/utils/swr-utils';
-
-import LoginForm from '../components/LoginForm';
-import PasswordResetExecutionForm from '../components/PasswordResetExecutionForm';
-import PasswordResetRequestForm from '../components/PasswordResetRequestForm';
-
-import ContextExtractor from './services/ContextExtractor';
-import { i18nFactory } from './util/i18n';
-
-const i18n = i18nFactory();
-
-
-const componentMappings = {};
-
-const appContainer = new AppContainer();
-appContainer.initApp();
-
-// render loginForm
-const loginFormElem = document.getElementById('login-form');
-if (loginFormElem) {
-  const username = loginFormElem.dataset.username;
-  const name = loginFormElem.dataset.name;
-  const email = loginFormElem.dataset.email;
-  const isRegistrationEnabled = loginFormElem.dataset.isRegistrationEnabled === 'true';
-  const isEmailAuthenticationEnabled = loginFormElem.dataset.isEmailAuthenticationEnabled === 'true';
-  const registrationMode = loginFormElem.dataset.registrationMode;
-  const isPasswordResetEnabled = loginFormElem.dataset.isPasswordResetEnabled === 'true';
-
-
-  let registrationWhiteList = loginFormElem.dataset.registrationWhiteList;
-  registrationWhiteList = registrationWhiteList.length > 0
-    ? registrationWhiteList = loginFormElem.dataset.registrationWhiteList.split(',')
-    : registrationWhiteList = [];
-
-
-  const isLocalStrategySetup = loginFormElem.dataset.isLocalStrategySetup === 'true';
-  const isLdapStrategySetup = loginFormElem.dataset.isLdapStrategySetup === 'true';
-  const objOfIsExternalAuthEnableds = {
-    google: loginFormElem.dataset.isGoogleAuthEnabled === 'true',
-    github: loginFormElem.dataset.isGithubAuthEnabled === 'true',
-    facebook: loginFormElem.dataset.isFacebookAuthEnabled === 'true',
-    saml: loginFormElem.dataset.isSamlAuthEnabled === 'true',
-    oidc: loginFormElem.dataset.isOidcAuthEnabled === 'true',
-  };
-
-  Object.assign(componentMappings, {
-    [loginFormElem.id]: (
-      <LoginForm
-        username={username}
-        name={name}
-        email={email}
-        isRegistrationEnabled={isRegistrationEnabled}
-        isEmailAuthenticationEnabled={isEmailAuthenticationEnabled}
-        registrationMode={registrationMode}
-        registrationWhiteList={registrationWhiteList}
-        isPasswordResetEnabled={isPasswordResetEnabled}
-        isLocalStrategySetup={isLocalStrategySetup}
-        isLdapStrategySetup={isLdapStrategySetup}
-        objOfIsExternalAuthEnableds={objOfIsExternalAuthEnableds}
-      />
-    ),
-  });
-}
-
-// render PasswordResetRequestForm
-const passwordResetRequestFormElem = document.getElementById('password-reset-request-form');
-if (passwordResetRequestFormElem) {
-  Object.assign(componentMappings, {
-    [passwordResetRequestFormElem.id]: <PasswordResetRequestForm />,
-  });
-}
-
-// render PasswordResetExecutionForm
-const passwordResetExecutionFormElem = document.getElementById('password-reset-execution-form');
-if (passwordResetExecutionFormElem) {
-  Object.assign(componentMappings, {
-    [passwordResetExecutionFormElem.id]: <PasswordResetExecutionForm />,
-  });
-}
-
-// render UserActivationForm
-const UserActivationForm = document.getElementById('user-activation-form');
-if (UserActivationForm) {
-  const messageErrors = UserActivationForm.dataset.messageErrors;
-  const inputs = UserActivationForm.dataset.inputs;
-  const email = UserActivationForm.dataset.email;
-  const token = UserActivationForm.dataset.token;
-
-  Object.assign(componentMappings, {
-    [UserActivationForm.id]: (
-      <CompleteUserRegistrationForm
-        messageErrors={messageErrors}
-        inputs={inputs}
-        email={email}
-        token={token}
-      />
-    ),
-  });
-}
-
-const renderMainComponents = () => {
-  Object.keys(componentMappings).forEach((key) => {
-    const elem = document.getElementById(key);
-    if (elem) {
-      ReactDOM.render(
-        <I18nextProvider i18n={i18n}>
-          <SWRConfig value={swrGlobalConfiguration}>
-            <Provider inject={[appContainer]}>
-              {componentMappings[key]}
-            </Provider>
-          </SWRConfig>
-        </I18nextProvider>,
-        elem,
-      );
-    }
-  });
-};
-
-// extract context before rendering main components
-const elem = document.getElementById('growi-context-extractor');
-if (elem != null) {
-  ReactDOM.render(
-    <SWRConfig value={swrGlobalConfiguration}>
-      <ContextExtractor></ContextExtractor>
-    </SWRConfig>,
-    elem,
-    renderMainComponents,
-  );
-}
-else {
-  renderMainComponents();
-}

+ 0 - 55
packages/app/_obsolete/src/client/plugin.js

@@ -1,55 +0,0 @@
-import loggerFactory from '~/utils/logger';
-
-const logger = loggerFactory('growi:plugin');
-
-export default class GrowiPlugin {
-
-  /**
-   * process plugin entry
-   *
-   * @param {AppContainer} appContainer
-   *
-   * @memberof CrowiPlugin
-   */
-  // eslint-disable-next-line @typescript-eslint/no-unused-vars
-  installAll(appContainer) {
-    // import plugin definitions
-    let definitions = [];
-    try {
-      definitions = require('^/tmp/plugins/plugin-definitions');
-    }
-    catch (e) {
-      logger.error('failed to load definitions');
-      logger.error(e);
-      return;
-    }
-
-    definitions.forEach((definition) => {
-      const meta = definition.meta;
-
-      switch (meta.pluginSchemaVersion) {
-        // v1, v2 and v3 is deprecated
-        case 1:
-          logger.warn('pluginSchemaVersion 1 is deprecated', definition);
-          break;
-        case 2:
-          logger.warn('pluginSchemaVersion 2 is deprecated', definition);
-          break;
-        case 3:
-          logger.warn('pluginSchemaVersion 2 is deprecated', definition);
-          break;
-        case 4:
-          definition.entries.forEach((entry) => {
-            entry(appContainer);
-          });
-          break;
-        default:
-          logger.warn('Unsupported schema version', meta.pluginSchemaVersion);
-      }
-    });
-
-  }
-
-}
-
-window.growiPlugin = new GrowiPlugin();

+ 0 - 133
packages/app/_obsolete/src/client/services/AppContainer.js

@@ -1,133 +0,0 @@
-import { Container } from 'unstated';
-
-// import { i18nFactory } from '../util/i18n';
-
-/**
- * Service container related to options for Application
- * @extends {Container} unstated Container
- */
-export default class AppContainer extends Container {
-
-  constructor() {
-    super();
-
-    this.config = JSON.parse(document.getElementById('growi-context-hydrate').textContent || '{}');
-
-    // init i18n
-    const currentUserElem = document.getElementById('growi-current-user');
-    let userLocaleId;
-    if (currentUserElem != null) {
-      const currentUser = JSON.parse(currentUserElem.textContent);
-      userLocaleId = currentUser?.lang;
-    }
-    // this.i18n = i18nFactory(userLocaleId);
-
-    this.containerInstances = {};
-    this.componentInstances = {};
-  }
-
-  /**
-   * Workaround for the mangling in production build to break constructor.name
-   */
-  static getClassName() {
-    return 'AppContainer';
-  }
-
-  initApp() {
-    this.injectToWindow();
-  }
-
-  initContents() {
-    const body = document.querySelector('body');
-
-    this.isDocSaved = true;
-
-    const isPluginEnabled = body.dataset.pluginEnabled === 'true';
-    if (isPluginEnabled) {
-      this.initPlugins();
-    }
-
-    this.injectToWindow();
-  }
-
-  initPlugins() {
-    const growiPlugin = window.growiPlugin;
-    growiPlugin.installAll(this);
-  }
-
-  injectToWindow() {
-    // for fix lint error
-
-    // window.appContainer = this;
-
-    // const growiRenderer = new GrowiRenderer(this.getConfig());
-    // growiRenderer.init();
-
-    // window.growiRenderer = growiRenderer;
-
-    // // backward compatibility
-    // window.crowi = this;
-    // window.crowiRenderer = window.growiRenderer;
-    // window.crowiPlugin = window.growiPlugin;
-  }
-
-  getConfig() {
-    return this.config;
-  }
-
-  /**
-   * Register unstated container instance
-   * @param {object} instance unstated container instance
-   */
-  registerContainer(instance) {
-    if (instance == null) {
-      throw new Error('The specified instance must not be null');
-    }
-
-    const className = instance.constructor.getClassName();
-
-    if (this.containerInstances[className] != null) {
-      throw new Error('The specified instance couldn\'t register because the same type object has already been registered');
-    }
-
-    this.containerInstances[className] = instance;
-  }
-
-  /**
-   * Get registered unstated container instance
-   * !! THIS METHOD SHOULD ONLY BE USED FROM unstated CONTAINERS !!
-   * !! From component instances, inject containers with `import { Subscribe } from 'unstated'` !!
-   *
-   * @param {string} className
-   */
-  getContainer(className) {
-    return this.containerInstances[className];
-  }
-
-
-  /*
-  * Note: Use globalEmitter instaead of registerComponentInstance and getComponentInstance
-  */
-
-  /**
-   * Register React component instance
-   * @param {string} id
-   * @param {object} instance React component instance
-   */
-  // registerComponentInstance(id, instance) {
-  //   if (instance == null) {
-  //     throw new Error('The specified instance must not be null');
-  //   }
-
-  //   this.componentInstances[id] = instance;
-  // }
-
-  /**
-   * Get registered React component instance
-   * @param {string} id
-   */
-  // getComponentInstance(id) {
-  //   return this.componentInstances[id];
-  // }
-
-}

+ 0 - 214
packages/app/_obsolete/src/client/services/ContextExtractor.tsx

@@ -1,214 +0,0 @@
-/* eslint-disable */
-import React, { FC, useEffect, useState } from 'react';
-
-import { pagePathUtils } from '@growi/core';
-
-import { CustomWindow } from '~/interfaces/global';
-import { IUserUISettings } from '~/interfaces/user-ui-settings';
-// import { generatePreviewRenderer } from '~/services/renderer/growi-renderer';
-import {
-  useIsDeviceSmallerThanMd, useIsDeviceSmallerThanLg,
-  usePreferDrawerModeByUser, usePreferDrawerModeOnEditByUser, useSidebarCollapsed, useCurrentSidebarContents, useCurrentProductNavWidth,
-  useSelectedGrant,
-} from '~/stores/ui';
-import { useSetupGlobalSocket, useSetupGlobalAdminSocket } from '~/stores/websocket';
-
-import {
-  useSiteUrl,
-  useDeleteUsername, useDeletedAt, useHasChildren, useHasDraftOnHackmd,
-  useIsTrashPage, useIsUserPage, useLastUpdateUsername,
-  useCurrentPageId, usePageIdOnHackmd, usePageUser, useCurrentPagePath, useRevisionCreatedAt, useRevisionId, useRevisionIdHackmdSynced,
-  useShareLinkId, useShareLinksNumber, useTemplateTagData, useCurrentUser, useTargetAndAncestors,
-  useIsSearchPage, useIsForbidden, useIsIdenticalPath, useHasParent,
-  useIsAclEnabled, useIsSearchServiceConfigured, useIsSearchServiceReachable, useIsEnabledAttachTitleHeader,
-  useDefaultIndentSize, useIsIndentSizeForced, useCsrfToken, useGrowiVersion, useAuditLogEnabled,
-  useActivityExpirationSeconds, useAuditLogAvailableActions, useRendererConfig,
-} from '../../stores/context';
-
-const { isTrashPage: _isTrashPage } = pagePathUtils;
-
-const jsonNull = 'null';
-
-const ContextExtractorOnce: FC = () => {
-
-  const mainContent = document.querySelector('#content-main');
-  const notFoundContentForPt = document.getElementById('growi-pagetree-not-found-context');
-  const notFoundContext = document.getElementById('growi-not-found-context');
-  const forbiddenContent = document.getElementById('forbidden-page');
-
-  // get csrf token from body element
-  // DO NOT REMOVE: uploading attachment data requires appContainer.csrfToken
-  const body = document.querySelector('body');
-  const csrfToken = body?.dataset.csrftoken;
-
-  /*
-   * App Context from DOM
-   */
-  const currentUser = JSON.parse(document.getElementById('growi-current-user')?.textContent || jsonNull);
-
-  /*
-   * Settings from context-hydrate DOM
-   */
-  const configByContextHydrate = JSON.parse(document.getElementById('growi-context-hydrate')?.textContent || jsonNull);
-
-  /*
-   * UserUISettings from DOM
-   */
-  const userUISettings: Partial<IUserUISettings> = JSON.parse(document.getElementById('growi-user-ui-settings')?.textContent || jsonNull);
-
-  /*
-   * Page Context from DOM
-   */
-  const revisionId = mainContent?.getAttribute('data-page-revision-id');
-  const path = decodeURI(mainContent?.getAttribute('data-path') || '');
-  // assign `null` to avoid returning empty string
-  const pageId = mainContent?.getAttribute('data-page-id') || null;
-
-  const revisionCreatedAt = +(mainContent?.getAttribute('data-page-revision-created') || '');
-
-  const deletedAt = mainContent?.getAttribute('data-page-deleted-at') || null;
-  const isIdenticalPath = JSON.parse(mainContent?.getAttribute('data-identical-path') || jsonNull) ?? false;
-  const isUserPage = JSON.parse(mainContent?.getAttribute('data-page-user') || jsonNull) != null;
-  const isTrashPage = _isTrashPage(path);
-  const isNotCreatable = JSON.parse(mainContent?.getAttribute('data-page-is-not-creatable') || jsonNull) ?? false;
-  const isForbidden = forbiddenContent != null;
-  const pageUser = JSON.parse(mainContent?.getAttribute('data-page-user') || jsonNull);
-  const hasChildren = JSON.parse(mainContent?.getAttribute('data-page-has-children') || jsonNull);
-  const hasParent = JSON.parse(mainContent?.getAttribute('data-has-parent') || jsonNull);
-  const templateTagData = mainContent?.getAttribute('data-template-tags') || null;
-  const shareLinksNumber = mainContent?.getAttribute('data-share-links-number');
-  const shareLinkId = JSON.parse(mainContent?.getAttribute('data-share-link-id') || jsonNull);
-  const revisionIdHackmdSynced = mainContent?.getAttribute('data-page-revision-id-hackmd-synced') || null;
-  const lastUpdateUsername = mainContent?.getAttribute('data-page-last-update-username') || null;
-  const deleteUsername = mainContent?.getAttribute('data-page-delete-username') || null;
-  const pageIdOnHackmd = mainContent?.getAttribute('data-page-id-on-hackmd') || null;
-  const hasDraftOnHackmd = !!mainContent?.getAttribute('data-page-has-draft-on-hackmd');
-  const targetAndAncestors = JSON.parse(document.getElementById('growi-pagetree-target-and-ancestors')?.textContent || jsonNull);
-  const notFoundTargetPathOrId = JSON.parse(notFoundContentForPt?.getAttribute('data-not-found-target-path-or-id') || jsonNull);
-  const isSearchPage = document.getElementById('search-page') != null;
-  const isEmptyPage = JSON.parse(mainContent?.getAttribute('data-page-is-empty') || jsonNull) ?? false;
-
-  const grant = +(mainContent?.getAttribute('data-page-grant') || 1);
-  const grantGroupId = mainContent?.getAttribute('data-page-grant-group') || null;
-  const grantGroupName = mainContent?.getAttribute('data-page-grant-group-name') || null;
-
-  /*
-   * use static swr
-   */
-  useCsrfToken(csrfToken);
-
-  // App
-  useCurrentUser(currentUser);
-
-  // UserUISettings
-  usePreferDrawerModeByUser(userUISettings?.preferDrawerModeByUser ?? configByContextHydrate.isSidebarDrawerMode);
-  usePreferDrawerModeOnEditByUser(userUISettings?.preferDrawerModeOnEditByUser);
-  useSidebarCollapsed(userUISettings?.isSidebarCollapsed ?? configByContextHydrate.isSidebarClosedAtDockMode);
-  useCurrentSidebarContents(userUISettings?.currentSidebarContents);
-  useCurrentProductNavWidth(userUISettings?.currentProductNavWidth);
-
-  // hydrated config
-  useSiteUrl(configByContextHydrate.crowi.url);
-  useIsAclEnabled(configByContextHydrate.isAclEnabled);
-  useIsSearchServiceConfigured(configByContextHydrate.isSearchServiceConfigured);
-  useIsSearchServiceReachable(configByContextHydrate.isSearchServiceReachable);
-  useIsEnabledAttachTitleHeader(configByContextHydrate.isEnabledAttachTitleHeader);
-  useIsIndentSizeForced(configByContextHydrate.isIndentSizeForced);
-  useDefaultIndentSize(configByContextHydrate.adminPreferredIndentSize);
-  useAuditLogEnabled(configByContextHydrate.auditLogEnabled);
-  useActivityExpirationSeconds(configByContextHydrate.activityExpirationSeconds);
-  useAuditLogAvailableActions(configByContextHydrate.auditLogAvailableActions);
-  useGrowiVersion(configByContextHydrate.crowi.version);
-  useRendererConfig({
-    isEnabledLinebreaks: configByContextHydrate.isEnabledLinebreaks,
-    isEnabledLinebreaksInComments: configByContextHydrate.isEnabledLinebreaksInComments,
-    adminPreferredIndentSize: configByContextHydrate.adminPreferredIndentSize,
-    isIndentSizeForced: configByContextHydrate.isIndentSizeForced,
-
-    isEnabledXssPrevention: configByContextHydrate.isEnabledXssPrevention,
-    attrWhiteList: configByContextHydrate.attrWhiteList,
-    tagWhiteList: configByContextHydrate.tagWhiteList,
-    highlightJsStyleBorder: configByContextHydrate.highlightJsStyleBorder,
-
-    plantumlUri: configByContextHydrate.env.PLANTUML_URI,
-    blockdiagUri: configByContextHydrate.env.BLOCKDIAG_URI,
-  });
-  // useNoCdn(configByContextHydrate.env.NO_CDN);
-  // useUploadableImage(configByContextHydrate.upload.image);
-  // useUploadableFile(configByContextHydrate.upload.file);
-
-  // Page
-  useDeleteUsername(deleteUsername);
-  useDeletedAt(deletedAt);
-  useHasChildren(hasChildren);
-  useHasDraftOnHackmd(hasDraftOnHackmd);
-  useIsIdenticalPath(isIdenticalPath);
-  // useIsNotCreatable(isNotCreatable);
-  useIsForbidden(isForbidden);
-  // useIsTrashPage(isTrashPage);
-  useIsUserPage(isUserPage);
-  useLastUpdateUsername(lastUpdateUsername);
-  useCurrentPageId(pageId);
-  usePageIdOnHackmd(pageIdOnHackmd);
-  usePageUser(pageUser);
-  useCurrentPagePath(path);
-  useRevisionCreatedAt(revisionCreatedAt);
-  useRevisionId(revisionId);
-  useRevisionIdHackmdSynced(revisionIdHackmdSynced);
-  useShareLinkId(shareLinkId);
-  useShareLinksNumber(shareLinksNumber);
-  useTemplateTagData(templateTagData);
-  useTargetAndAncestors(targetAndAncestors);
-  useIsSearchPage(isSearchPage);
-  useHasParent(hasParent);
-
-  // Navigation
-  usePreferDrawerModeByUser();
-  usePreferDrawerModeOnEditByUser();
-  useIsDeviceSmallerThanMd();
-
-  // Editor
-  // useSelectedGrant(grant);
-  // useSelectedGrantGroupId(grantGroupId);
-  // useSelectedGrantGroupName(grantGroupName);
-
-  // SearchResult
-  useIsDeviceSmallerThanLg();
-
-  // Global Socket
-  useSetupGlobalSocket();
-  const shouldInitAdminSock = !!currentUser?.isAdmin;
-  useSetupGlobalAdminSocket(shouldInitAdminSock);
-
-  // TODO: Remove this code when reveal.js is omitted. see: https://github.com/weseek/growi/pull/6223
-  // Do not access this property from other than reveal.js plugins.
-  // (window as CustomWindow).previewRenderer = generatePreviewRenderer(
-  //   {
-  //     isEnabledXssPrevention: configByContextHydrate.isEnabledXssPrevention,
-  //     attrWhiteList: configByContextHydrate.attrWhiteList,
-  //     tagWhiteList: configByContextHydrate.tagWhiteList,
-  //     highlightJsStyleBorder: configByContextHydrate.highlightJsStyleBorder,
-  //     env: {
-  //       MATHJAX: configByContextHydrate.env.MATHJAX,
-  //       PLANTUML_URI: configByContextHydrate.env.PLANTUML_URI,
-  //       BLOCKDIAG_URI: configByContextHydrate.env.BLOCKDIAG_URI,
-  //     },
-  //   },
-  //   null,
-  //   path,
-  // );
-
-  return null;
-};
-
-const ContextExtractor: FC = React.memo(() => {
-  const [isRunOnce, setRunOnce] = useState(false);
-
-  useEffect(() => {
-    setRunOnce(true);
-  }, []);
-
-  return isRunOnce ? null : <ContextExtractorOnce></ContextExtractorOnce>;
-});
-
-export default ContextExtractor;

+ 0 - 358
packages/app/_obsolete/src/client/services/PageContainer.js

@@ -1,358 +0,0 @@
-import { pagePathUtils } from '@growi/core';
-import * as entities from 'entities';
-import * as toastr from 'toastr';
-import { Container } from 'unstated';
-
-
-import { EditorMode } from '~/stores/ui';
-import loggerFactory from '~/utils/logger';
-
-import {
-  DetachCodeBlockInterceptor,
-  RestoreCodeBlockInterceptor,
-} from '../../services/renderer/interceptor/detach-code-blocks';
-import {
-  DrawioInterceptor,
-} from '../../services/renderer/interceptor/drawio-interceptor';
-
-const { isTrashPage } = pagePathUtils;
-
-const logger = loggerFactory('growi:services:PageContainer');
-
-/**
- * Service container related to Page
- * @extends {Container} unstated Container
- */
-export default class PageContainer extends Container {
-
-  constructor(appContainer) {
-    super();
-
-    this.appContainer = appContainer;
-    this.appContainer.registerContainer(this);
-
-    this.state = {};
-
-    const mainContent = document.querySelector('#content-main');
-    if (mainContent == null) {
-      logger.debug('#content-main element is not exists');
-      return;
-    }
-
-    const revisionId = mainContent.getAttribute('data-page-revision-id');
-    const path = decodeURI(mainContent.getAttribute('data-path'));
-
-    this.state = {
-      // local page data
-      markdown: null, // will be initialized after initStateMarkdown()
-      pageId: mainContent.getAttribute('data-page-id'),
-      revisionId,
-      revisionCreatedAt: +mainContent.getAttribute('data-page-revision-created'),
-      path,
-      isEmpty: mainContent.getAttribute('data-page-is-empty'),
-
-      deletedAt: mainContent.getAttribute('data-page-deleted-at') || null,
-
-      isUserPage: JSON.parse(mainContent.getAttribute('data-page-user')) != null,
-      isTrashPage: isTrashPage(path),
-      isNotCreatable: JSON.parse(mainContent.getAttribute('data-page-is-not-creatable')),
-      isPageExist: mainContent.getAttribute('data-page-id') != null,
-
-      pageUser: JSON.parse(mainContent.getAttribute('data-page-user')),
-      tags: null,
-      hasChildren: JSON.parse(mainContent.getAttribute('data-page-has-children')),
-      templateTagData: mainContent.getAttribute('data-template-tags') || null,
-      shareLinksNumber: mainContent.getAttribute('data-share-links-number'),
-      shareLinkId: JSON.parse(mainContent.getAttribute('data-share-link-id') || null),
-
-      // latest(on remote) information
-      remoteRevisionId: revisionId,
-      remoteRevisionBody: null,
-      remoteRevisionUpdateAt: null,
-      revisionIdHackmdSynced: mainContent.getAttribute('data-page-revision-id-hackmd-synced') || null,
-      lastUpdateUsername: mainContent.getAttribute('data-page-last-update-username') || null,
-      deleteUsername: mainContent.getAttribute('data-page-delete-username') || null,
-      pageIdOnHackmd: mainContent.getAttribute('data-page-id-on-hackmd') || null,
-      hasDraftOnHackmd: !!mainContent.getAttribute('data-page-has-draft-on-hackmd'),
-      isHackmdDraftUpdatingInRealtime: false,
-      isConflictDiffModalOpen: false,
-    };
-
-    // parse creator, lastUpdateUser and revisionAuthor
-    try {
-      this.state.creator = JSON.parse(mainContent.getAttribute('data-page-creator'));
-    }
-    catch (e) {
-      logger.warn('The data of \'data-page-creator\' is invalid', e);
-    }
-    try {
-      this.state.revisionAuthor = JSON.parse(mainContent.getAttribute('data-page-revision-author'));
-      this.state.lastUpdateUser = JSON.parse(mainContent.getAttribute('data-page-revision-author'));
-    }
-    catch (e) {
-      logger.warn('The data of \'data-page-revision-author\' is invalid', e);
-    }
-
-    const { interceptorManager } = window;
-    interceptorManager.addInterceptor(new DetachCodeBlockInterceptor(), 10); // process as soon as possible
-    interceptorManager.addInterceptor(new DrawioInterceptor(), 20);
-    interceptorManager.addInterceptor(new RestoreCodeBlockInterceptor(), 900); // process as late as possible
-
-    this.initStateMarkdown();
-
-    this.save = this.save.bind(this);
-
-    this.emitJoinPageRoomRequest = this.emitJoinPageRoomRequest.bind(this);
-    this.emitJoinPageRoomRequest();
-
-    this.addWebSocketEventHandlers = this.addWebSocketEventHandlers.bind(this);
-    this.addWebSocketEventHandlers();
-
-    const unlinkPageButton = document.getElementById('unlink-page-button');
-    if (unlinkPageButton != null) {
-      unlinkPageButton.addEventListener('click', async() => {
-        try {
-          const res = await apiPost('/pages.unlink', { path });
-          window.location.href = encodeURI(`${res.path}?unlinked=true`);
-        }
-        catch (err) {
-          toastError(err);
-        }
-      });
-    }
-
-  }
-
-  /**
-   * Workaround for the mangling in production build to break constructor.name
-   */
-  static getClassName() {
-    return 'PageContainer';
-  }
-
-  /**
-   * initialize state for markdown data
-   * [Already SWRized]
-   */
-  initStateMarkdown() {
-    let pageContent = '';
-
-    const rawText = document.getElementById('raw-text-original');
-    if (rawText) {
-      pageContent = rawText.innerHTML;
-    }
-    const markdown = entities.decodeHTML(pageContent);
-
-    this.state.markdown = markdown;
-  }
-
-  setLatestRemotePageData(s2cMessagePageUpdated) {
-    const newState = {
-      remoteRevisionId: s2cMessagePageUpdated.revisionId,
-      remoteRevisionBody: s2cMessagePageUpdated.revisionBody,
-      remoteRevisionUpdateAt: s2cMessagePageUpdated.revisionUpdateAt,
-      revisionIdHackmdSynced: s2cMessagePageUpdated.revisionIdHackmdSynced,
-      // TODO // TODO remove lastUpdateUsername and refactor parts that lastUpdateUsername is used
-      lastUpdateUsername: s2cMessagePageUpdated.lastUpdateUsername,
-      lastUpdateUser: s2cMessagePageUpdated.remoteLastUpdateUser,
-    };
-
-    if (s2cMessagePageUpdated.hasDraftOnHackmd != null) {
-      newState.hasDraftOnHackmd = s2cMessagePageUpdated.hasDraftOnHackmd;
-    }
-
-    this.setState(newState);
-  }
-
-  /**
-   * save success handler
-   * @param {object} page Page instance
-   * @param {Array[Tag]} tags Array of Tag
-   * @param {object} revision Revision instance
-   */
-  updateStateAfterSave(page, tags, revision, editorMode) {
-    // update state of PageContainer
-    // const newState = {
-    //   pageId: page._id,
-    //   revisionId: revision._id,
-    //   revisionCreatedAt: new Date(revision.createdAt).getTime() / 1000,
-    //   remoteRevisionId: revision._id,
-    //   revisionAuthor: revision.author,
-    //   revisionIdHackmdSynced: page.revisionHackmdSynced,
-    //   hasDraftOnHackmd: page.hasDraftOnHackmd,
-    //   markdown: revision.body,
-    //   createdAt: page.createdAt,
-    //   updatedAt: page.updatedAt,
-    // };
-    // if (tags != null) {
-    //   newState.tags = tags;
-    // }
-    // this.setState(newState);
-
-    // PageEditorByHackmd component
-    // const pageEditorByHackmd = this.appContainer.getComponentInstance('PageEditorByHackmd');
-    // if (pageEditorByHackmd != null) {
-    //   // reset
-    //   if (editorMode !== EditorMode.HackMD) {
-    //     pageEditorByHackmd.reset();
-    //   }
-    // }
-  }
-
-  /**
-   * update page meta data
-   * @param {object} page Page instance
-   * @param {object} revision Revision instance
-   * @param {String[]} tags Array of Tag
-   */
-  updatePageMetaData(page, revision, tags) {
-
-    const newState = {
-      revisionId: revision._id,
-      revisionCreatedAt: new Date(revision.createdAt).getTime() / 1000,
-      remoteRevisionId: revision._id,
-      revisionAuthor: revision.author,
-      revisionIdHackmdSynced: page.revisionHackmdSynced,
-      hasDraftOnHackmd: page.hasDraftOnHackmd,
-      updatedAt: page.updatedAt,
-    };
-    if (tags != null) {
-      newState.tags = tags;
-    }
-
-    this.setState(newState);
-
-  }
-
-  /**
-   * Save page
-   * @param {string} markdown
-   * @param {object} optionsToSave
-   * @return {object} { page: Page, tags: Tag[] }
-   */
-  async save(markdown, editorMode, optionsToSave = {}) {
-    const { pageId, path } = this.state;
-    let { revisionId } = this.state;
-    const options = Object.assign({}, optionsToSave);
-
-    if (editorMode === EditorMode.HackMD) {
-      // set option to sync
-      options.isSyncRevisionToHackmd = true;
-      revisionId = this.state.revisionIdHackmdSynced;
-    }
-
-    let res;
-    if (pageId == null) {
-      res = await this.createPage(path, markdown, options);
-    }
-    else {
-      res = await this.updatePage(pageId, revisionId, markdown, options);
-    }
-
-    this.updateStateAfterSave(res.page, res.tags, res.revision, editorMode);
-    return res;
-  }
-
-
-  showSuccessToastr() {
-    toastr.success(undefined, 'Saved successfully', {
-      closeButton: true,
-      progressBar: true,
-      newestOnTop: false,
-      showDuration: '100',
-      hideDuration: '100',
-      timeOut: '1200',
-      extendedTimeOut: '150',
-    });
-  }
-
-  showErrorToastr(error) {
-    toastr.error(error.message, 'Error occured', {
-      closeButton: true,
-      progressBar: true,
-      newestOnTop: false,
-      showDuration: '100',
-      hideDuration: '100',
-      timeOut: '3000',
-    });
-  }
-
-  // replaced accompanied by omiting container: https://github.com/weseek/growi/pull/6968
-  // // request to server so the client to join a room for each page
-  // emitJoinPageRoomRequest() {
-  //   const socketIoContainer = this.appContainer.getContainer('SocketIoContainer');
-  //   const socket = socketIoContainer.getSocket();
-  //   socket.emit('join:page', { socketId: socket.id, pageId: this.state.pageId });
-  // }
-
-  addWebSocketEventHandlers() {
-    // eslint-disable-next-line @typescript-eslint/no-this-alias
-    const pageContainer = this;
-    const socketIoContainer = this.appContainer.getContainer('SocketIoContainer');
-    const socket = socketIoContainer.getSocket();
-
-    socket.on('page:create', (data) => {
-      logger.debug({ obj: data }, `websocket on 'page:create'`); // eslint-disable-line quotes
-
-      // update remote page data
-      const { s2cMessagePageUpdated } = data;
-      if (s2cMessagePageUpdated.pageId === pageContainer.state.pageId) {
-        pageContainer.setLatestRemotePageData(s2cMessagePageUpdated);
-      }
-    });
-
-    // replaced accompanied by omiting container: https://github.com/weseek/growi/pull/6968
-    // socket.on('page:update', (data) => {
-    //   logger.debug({ obj: data }, `websocket on 'page:update'`); // eslint-disable-line quotes
-
-    //   // update remote page data
-    //   const { s2cMessagePageUpdated } = data;
-    //   if (s2cMessagePageUpdated.pageId === pageContainer.state.pageId) {
-    //     pageContainer.setLatestRemotePageData(s2cMessagePageUpdated);
-    //   }
-    // });
-
-    socket.on('page:delete', (data) => {
-      logger.debug({ obj: data }, `websocket on 'page:delete'`); // eslint-disable-line quotes
-
-      // update remote page data
-      const { s2cMessagePageUpdated } = data;
-      if (s2cMessagePageUpdated.pageId === pageContainer.state.pageId) {
-        pageContainer.setLatestRemotePageData(s2cMessagePageUpdated);
-      }
-    });
-
-    socket.on('page:editingWithHackmd', (data) => {
-      logger.debug({ obj: data }, `websocket on 'page:editingWithHackmd'`); // eslint-disable-line quotes
-
-      // update isHackmdDraftUpdatingInRealtime
-      const { s2cMessagePageUpdated } = data;
-      if (s2cMessagePageUpdated.pageId === pageContainer.state.pageId) {
-        pageContainer.setState({ isHackmdDraftUpdatingInRealtime: true });
-      }
-    });
-
-  }
-
-  /* TODO GW-325 */
-  retrieveMyBookmarkList() {
-  }
-
-  async resolveConflict(markdown, editorMode, optionsToSave) {
-
-    const { pageId, remoteRevisionId, path } = this.state;
-    const editorContainer = this.appContainer.getContainer('EditorContainer');
-
-    const res = await this.updatePage(pageId, remoteRevisionId, markdown, optionsToSave);
-
-    editorContainer.clearDraft(path);
-    this.updateStateAfterSave(res.page, res.tags, res.revision, editorMode);
-
-    window.globalEmitter.emit('updateEditorValue', markdown);
-
-    editorContainer.setState({ tags: res.tags });
-
-    return res;
-  }
-
-}

+ 0 - 144
packages/app/_obsolete/src/components/MyDraftList/Draft.tsx

@@ -1,144 +0,0 @@
-import React, { useState } from 'react';
-
-import { useTranslation } from 'next-i18next';
-import { CopyToClipboard } from 'react-copy-to-clipboard';
-import ReactMarkdown from 'react-markdown';
-import {
-  Collapse,
-  UncontrolledTooltip,
-} from 'reactstrap';
-
-import { useDraftOptions } from '~/stores/renderer';
-
-type DraftProps = {
-  path: string,
-  isExist: boolean,
-  index: number,
-  markdown: string,
-  clearDraft: (path: string) => void,
-}
-
-export const Draft = (props: DraftProps): JSX.Element => {
-
-  const {
-    path, isExist, index, markdown, clearDraft,
-  } = props;
-  const { t } = useTranslation();
-  const { data: rendererOptions } = useDraftOptions();
-  const [isPanelExpanded, setIsPanelExpanded] = useState(false);
-  const [showCopiedMessage, setShowCopiedMessage] = useState(false);
-
-  const changeToolTipLabel = () => {
-    setShowCopiedMessage(true);
-    setTimeout(() => {
-      setShowCopiedMessage(false);
-    }, 1000);
-  };
-
-  const collapsePanelHandler = () => {
-    setIsPanelExpanded(false);
-  };
-
-  const expandPanelHandler = () => {
-    setIsPanelExpanded(true);
-  };
-
-  const Controls = () => {
-
-    const tooltipTargetId = `draft-copied-tooltip_${index}`;
-
-    return (
-      <div className="icon-container">
-        {isExist
-          ? null
-          : (
-            <a
-              href={`${path}#edit`}
-              target="_blank"
-              rel="noopener noreferrer"
-              data-toggle="tooltip"
-              title={t('Edit')}
-            >
-              <i className="mx-2 icon-note" />
-            </a>
-          )
-        }
-        <span id={tooltipTargetId}>
-          <CopyToClipboard text={markdown} onCopy={changeToolTipLabel}>
-            <a
-              className="text-center draft-copy"
-            >
-              <i className="mx-2 ti-clipboard" />
-            </a>
-          </CopyToClipboard>
-        </span>
-        <UncontrolledTooltip placement="top" target={tooltipTargetId} fade={false} trigger="hover">
-          { showCopiedMessage && (
-            <strong>copied!</strong>
-          ) }
-          { !showCopiedMessage && (
-            <span>{t('Copy')}</span>
-          ) }
-        </UncontrolledTooltip>
-        <a
-          className="text-danger text-center"
-          data-toggle="tooltip"
-          data-placement="top"
-          title={t('Delete')}
-          onClick={() => { return clearDraft(path) }}
-        >
-          <i className="mx-2 icon-trash" />
-        </a>
-      </div>
-    );
-  };
-
-  const AccordionTitle = () => {
-    const iconClass = isPanelExpanded ? 'fa-rotate-90' : '';
-
-    return (
-      <span>
-
-        <span className="mr-2 draft-path" onClick={() => setIsPanelExpanded(!isPanelExpanded)}>
-          <i className={`fa fa-fw fa-angle-right mr-2 ${iconClass}`}></i>
-          {path}
-        </span>
-        { isExist && (
-          <span className="badge badge-warning">{t('page exists')}</span>
-        ) }
-        { !isExist && (
-          <span className="badge badge-info">draft</span>
-        ) }
-
-        <a className="ml-2" href={path}><i className="icon icon-login"></i></a>
-      </span>
-    );
-  };
-
-
-  return (
-    <div className="accordion draft-list-item" role="tablist">
-      <div className="card">
-
-        <div className="card-header d-flex" role="tab">
-          <AccordionTitle/>
-
-          <div className="flex-grow-1"></div>
-
-          <Controls/>
-        </div>
-
-        <Collapse isOpen={isPanelExpanded} onEntering={expandPanelHandler} onExiting={collapsePanelHandler}>
-          <div className="card-body">
-            { isPanelExpanded && (
-              <ReactMarkdown {...rendererOptions} className='wiki'>
-                {markdown}
-              </ReactMarkdown>
-            ) }
-          </div>
-        </Collapse>
-
-      </div>
-    </div>
-  );
-};

+ 0 - 192
packages/app/_obsolete/src/components/MyDraftList/MyDraftList.jsx

@@ -1,192 +0,0 @@
-import React from 'react';
-
-import { useTranslation } from 'next-i18next';
-import PropTypes from 'prop-types';
-
-import PageContainer from '~/client/services/PageContainer';
-import { apiGet } from '~/client/util/apiv1-client';
-
-import PaginationWrapper from '../PaginationWrapper';
-import { withUnstatedContainers } from '../UnstatedUtils';
-
-import { Draft } from './Draft';
-
-class MyDraftList extends React.Component {
-
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      drafts: [],
-      currentDrafts: [],
-      activePage: 1,
-      totalDrafts: 0,
-      pagingLimit: Infinity,
-    };
-
-    this.handlePage = this.handlePage.bind(this);
-    this.getDraftsFromLocalStorage = this.getDraftsFromLocalStorage.bind(this);
-    this.getCurrentDrafts = this.getCurrentDrafts.bind(this);
-    this.clearDraft = this.clearDraft.bind(this);
-    this.clearAllDrafts = this.clearAllDrafts.bind(this);
-  }
-
-  async UNSAFE_componentWillMount() {
-    await this.getDraftsFromLocalStorage();
-    this.getCurrentDrafts(1);
-  }
-
-  async handlePage(selectedPage) {
-    await this.getDraftsFromLocalStorage();
-    await this.getCurrentDrafts(selectedPage);
-  }
-
-  async getDraftsFromLocalStorage() {
-    const draftsAsObj = this.props.editorContainer.drafts;
-
-    if (draftsAsObj == null) {
-      return;
-    }
-
-    const res = await apiGet('/pages.exist', {
-      pagePaths: JSON.stringify(Object.keys(draftsAsObj)),
-    });
-
-    // {'/a': '#a', '/b': '#b'} => [{path: '/a', markdown: '#a'}, {path: '/b', markdown: '#b'}]
-    const drafts = Object.entries(draftsAsObj).map((d) => {
-      const path = d[0];
-      return {
-        path,
-        markdown: d[1],
-        isExist: res.pages[path],
-      };
-    });
-
-    this.setState({ drafts, totalDrafts: drafts.length });
-  }
-
-  getCurrentDrafts(selectPageNumber) {
-
-    const limit = 50; // implement only this component.(this default value is 50 (pageLimitationL))
-
-    const totalDrafts = this.state.drafts.length;
-    const activePage = selectPageNumber;
-
-    const currentDrafts = this.state.drafts.slice((activePage - 1) * limit, activePage * limit);
-
-    this.setState({
-      currentDrafts,
-      activePage,
-      totalDrafts,
-      pagingLimit: limit,
-    });
-  }
-
-  /**
-   * generate Elements of Draft
-   *
-   * @param {any} drafts Array of pages Model Obj
-   *
-   */
-  generateDraftList(drafts) {
-    return drafts.map((draft, index) => {
-      return (
-        <Draft
-          index={index}
-          key={draft.path}
-          path={draft.path}
-          markdown={draft.markdown}
-          isExist={draft.isExist}
-          clearDraft={this.clearDraft}
-        />
-      );
-    });
-  }
-
-  clearDraft(path) {
-    // this.props.editorContainer.clearDraft(path);
-
-    this.setState((prevState) => {
-      return {
-        drafts: prevState.drafts.filter((draft) => { return draft.path !== path }),
-        currentDrafts: prevState.drafts.filter((draft) => { return draft.path !== path }),
-      };
-    });
-  }
-
-  clearAllDrafts() {
-    // this.props.editorContainer.clearAllDrafts();
-
-    this.setState({
-      drafts: [],
-      currentDrafts: [],
-      activePage: 1,
-      totalDrafts: 0,
-      pagingLimit: Infinity,
-    });
-  }
-
-  render() {
-    const { t } = this.props;
-
-    const draftList = this.generateDraftList(this.state.currentDrafts);
-    const totalCount = this.state.totalDrafts;
-
-    return (
-      <div className="page-list-container-create ">
-        { totalCount === 0
-          && <span className="mt-2">No drafts yet.</span>
-        }
-
-        { totalCount > 0 && (
-          <React.Fragment>
-            <div className="d-flex justify-content-between mt-2">
-              <h4>Total: {totalCount} drafts</h4>
-              <div className="align-self-center">
-                <button type="button" className="btn btn-sm btn-outline-danger" onClick={this.clearAllDrafts}>
-                  <i className="icon-fw icon-fire"></i>
-                  {t('delete_all')}
-                </button>
-              </div>
-            </div>
-
-            <div className="tab-pane mt-2 accordion" id="draft-list">
-              {draftList}
-            </div>
-            <PaginationWrapper
-              activePage={this.state.activePage}
-              changePage={this.handlePage}
-              totalItemsCount={this.state.totalDrafts}
-              pagingLimit={this.state.pagingLimit}
-              align="center"
-              size="sm"
-            />
-          </React.Fragment>
-        ) }
-
-      </div>
-    );
-  }
-
-}
-
-MyDraftList.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-
-  pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
-  // editorContainer: PropTypes.instanceOf(EditorContainer).isRequired,
-};
-
-const MyDraftListWrapperFC = (props) => {
-  const { t } = useTranslation();
-  return <MyDraftList t={t} {...props} />;
-};
-
-export default MyDraftListWrapperFC;
-
-/**
- * Wrapper component for using unstated
- */
-// const MyDraftListWrapper = withUnstatedContainers(MyDraftListWrapperFC, [PageContainer, EditorContainer]);
-
-// export default MyDraftListWrapper;

+ 0 - 76
packages/app/_obsolete/src/util/i18n.js

@@ -1,76 +0,0 @@
-
-/* eslint-disable */
-import i18n from 'i18next';
-import LanguageDetector from 'i18next-browser-languagedetector';
-import { initReactI18next } from 'react-i18next';
-
-import locales from '^/public/static/locales';
-
-const aliasesMapping = {};
-Object.values(locales).forEach((locale) => {
-  if (locale.meta.aliases == null) {
-    return;
-  }
-  locale.meta.aliases.forEach((alias) => {
-    aliasesMapping[alias] = locale.meta.id;
-  });
-});
-
-/*
-* Note: This file will be deleted. use "^/config/next-i18next.config" instead
-*/
-// extract metadata list from 'public/static/locales/${locale}/meta.json'
-export const localeMetadatas = Object.values(locales).map(locale => locale.meta);
-
-export const i18nFactory = (userLocaleId) => {
-  // setup LanguageDetector
-  const langDetector = new LanguageDetector();
-  langDetector.addDetector({
-    name: 'userSettingDetector',
-    lookup(options) {
-      return userLocaleId;
-    },
-  });
-  // Wrapper to convert lang after detected from browser
-  langDetector.addDetector({
-    name: 'navigatorWrapperToConvertByAlias',
-    lookup(options) {
-      const results = langDetector.detectors.navigator.lookup(options);
-      const lang = results[0];
-      if (lang == null) {
-        return;
-      }
-
-      return aliasesMapping[lang] || lang;
-    },
-  });
-
-  i18n
-    .use(langDetector)
-    .use(initReactI18next) // if not using I18nextProvider
-    .init({
-      debug: (process.env.NODE_ENV !== 'production'),
-      resources: locales,
-      load: 'currentOnly',
-
-      fallbackLng: 'en_US',
-      detection: {
-        order: ['userSettingDetector', 'navigatorWrapperToConvertByAlias', 'querystring'],
-      },
-
-      interpolation: {
-        escapeValue: false, // not needed for react!!
-      },
-
-      // react i18next special options (optional)
-      react: {
-        wait: false,
-        withRef: true,
-        bindI18n: 'languageChanged loaded',
-        bindStore: 'added removed',
-        nsMode: 'default',
-      },
-    });
-
-  return i18n;
-};

+ 0 - 17
packages/app/_obsolete/src/util/old-ios.js

@@ -1,17 +0,0 @@
-const userAgent = window.navigator.userAgent.toLowerCase();
-// https://youtrack.weseek.co.jp/issue/GW-4826
-const isOldIos = /(iphone|ipad|ipod) os (9|10|11|12)/.test(userAgent);
-
-/**
- * Apply 'oldIos' attribute to <html></html>
- */
-function applyOldIos() {
-  if (isOldIos) {
-    document.documentElement.setAttribute('old-ios', 'true');
-  }
-}
-
-export {
-  // eslint-disable-next-line import/prefer-default-export
-  applyOldIos,
-};

+ 3 - 14
packages/app/docker/Dockerfile

@@ -1,7 +1,5 @@
 # syntax = docker/dockerfile:1.4
 # syntax = docker/dockerfile:1.4
 
 
-ARG flavor=default
-
 
 
 ##
 ##
 ## packages-json-picker
 ## packages-json-picker
@@ -63,9 +61,9 @@ RUN tar -cf node_modules.tar \
 
 
 
 
 ##
 ##
-## prebuilder-default
+## prebuilder
 ##
 ##
-FROM node:16-slim AS prebuilder-default
+FROM node:16-slim AS prebuilder
 
 
 ENV optDir /opt
 ENV optDir /opt
 
 
@@ -80,20 +78,11 @@ RUN tar -xf node_modules.tar
 RUN rm node_modules.tar
 RUN rm node_modules.tar
 
 
 
 
-##
-## prebuilder-nocdn
-##
-FROM prebuilder-default AS prebuilder-nocdn
-
-# add dotenv file for NO_CDN
-COPY packages/app/docker/nocdn/.env.production.local ${optDir}/packages/app/
-
-
 
 
 ##
 ##
 ## builder
 ## builder
 ##
 ##
-FROM prebuilder-${flavor} AS builder
+FROM prebuilder AS builder
 
 
 ENV optDir /opt
 ENV optDir /opt
 
 

+ 1 - 4
packages/app/package.json

@@ -9,7 +9,7 @@
     "build:client": "yarn next build",
     "build:client": "yarn next build",
     "prebuild:client": "tsc -p tsconfig.build.next.config.json",
     "prebuild:client": "tsc -p tsconfig.build.next.config.json",
     "build:server": "yarn cross-env NODE_ENV=production tsc -p tsconfig.build.server.json && tsc-alias -p tsconfig.build.server-tsc-alias.json",
     "build:server": "yarn cross-env NODE_ENV=production tsc -p tsconfig.build.server.json && tsc-alias -p tsconfig.build.server-tsc-alias.json",
-    "postbuild:server": "npx -y shx echo \"Listing files under transpiled\" && npx -y shx ls transpiled && npx -y shx mv transpiled/src dist && npx -y shx cp -r transpiled/config/* config && npx -y shx cp -r src/server/views dist/server/ && npx -y shx rm -rf transpiled",
+    "postbuild:server": "npx -y shx echo \"Listing files under transpiled\" && npx -y shx ls transpiled && npx -y shx mv transpiled/src dist && npx -y shx cp -r transpiled/config/* config && npx -y shx rm -rf transpiled",
     "clean": "npx -y shx rm -rf dist transpiled",
     "clean": "npx -y shx rm -rf dist transpiled",
     "prebuild": "yarn cross-env NODE_ENV=production run-p clean resources:*",
     "prebuild": "yarn cross-env NODE_ENV=production run-p clean resources:*",
     "server": "yarn cross-env NODE_ENV=production node -r dotenv-flow/config dist/server/app.js",
     "server": "yarn cross-env NODE_ENV=production node -r dotenv-flow/config dist/server/app.js",
@@ -100,7 +100,6 @@
     "diff": "^5.0.0",
     "diff": "^5.0.0",
     "diff_match_patch": "^0.1.1",
     "diff_match_patch": "^0.1.1",
     "ejs": "^3.1.8",
     "ejs": "^3.1.8",
-    "entities": "^2.0.0",
     "esa-node": "^0.2.2",
     "esa-node": "^0.2.2",
     "escape-string-regexp": "=4.0.0",
     "escape-string-regexp": "=4.0.0",
     "eslint-plugin-regex": "^1.8.0",
     "eslint-plugin-regex": "^1.8.0",
@@ -110,7 +109,6 @@
     "express-mongo-sanitize": "^2.1.0",
     "express-mongo-sanitize": "^2.1.0",
     "express-session": "^1.16.1",
     "express-session": "^1.16.1",
     "express-validator": "^6.14.0",
     "express-validator": "^6.14.0",
-    "express-webpack-assets": "^0.1.0",
     "extensible-custom-error": "^0.0.7",
     "extensible-custom-error": "^0.0.7",
     "graceful-fs": "^4.1.11",
     "graceful-fs": "^4.1.11",
     "hast-util-select": "^5.0.2",
     "hast-util-select": "^5.0.2",
@@ -182,7 +180,6 @@
     "string-width": "=4.2.2",
     "string-width": "=4.2.2",
     "superjson": "^1.9.1",
     "superjson": "^1.9.1",
     "swagger-jsdoc": "^6.1.0",
     "swagger-jsdoc": "^6.1.0",
-    "swig-templates": "^2.0.2",
     "swr": "^1.3.0",
     "swr": "^1.3.0",
     "throttle-debounce": "^3.0.1",
     "throttle-debounce": "^3.0.1",
     "toastr": "^2.1.2",
     "toastr": "^2.1.2",

+ 1 - 0
packages/app/public/static/locales/en_US/translation.json

@@ -60,6 +60,7 @@
   "Presentation Mode": "Presentation",
   "Presentation Mode": "Presentation",
   "The end": "The end",
   "The end": "The end",
   "Not available for guest": "Not available for guest",
   "Not available for guest": "Not available for guest",
+  "Not available in this version": "Not available in this version",
   "No users have liked this yet": "No users have liked this yet",
   "No users have liked this yet": "No users have liked this yet",
   "No users have liked this yet.": "No users have liked this yet.",
   "No users have liked this yet.": "No users have liked this yet.",
   "No users have bookmarked yet": "No users have bookmarked yet",
   "No users have bookmarked yet": "No users have bookmarked yet",

+ 1 - 0
packages/app/public/static/locales/ja_JP/translation.json

@@ -57,6 +57,7 @@
   "Presentation Mode": "プレゼンテーション",
   "Presentation Mode": "プレゼンテーション",
   "The end": "おしまい",
   "The end": "おしまい",
   "Not available for guest": "ゲストユーザーは利用できません",
   "Not available for guest": "ゲストユーザーは利用できません",
+  "Not available in this version": "このバージョンでは利用できません",
   "No users have liked this yet": "いいねをしているユーザーはいません",
   "No users have liked this yet": "いいねをしているユーザーはいません",
   "No users have bookmarked yet": "ブックマークしているユーザーはいません",
   "No users have bookmarked yet": "ブックマークしているユーザーはいません",
   "Create Archive Page": "アーカイブページの作成",
   "Create Archive Page": "アーカイブページの作成",

+ 2 - 1
packages/app/public/static/locales/zh_CN/translation.json

@@ -56,7 +56,8 @@
   "No_attachments_yet": "暂无附件",
   "No_attachments_yet": "暂无附件",
 	"Presentation Mode": "演示文稿",
 	"Presentation Mode": "演示文稿",
   "The end": "结束",
   "The end": "结束",
-  "Not available for guest": "Not available for guest",
+  "Not available for guest": "不提供给客人",
+  "Not available in this version": "此版本中不提供",
   "No users have liked this yet": "还没有用户喜欢这个",
   "No users have liked this yet": "还没有用户喜欢这个",
   "No users have bookmarked yet": "还没有用户加入书签",
   "No users have bookmarked yet": "还没有用户加入书签",
   "Create Archive Page": "创建归档页",
   "Create Archive Page": "创建归档页",

+ 6 - 6
packages/app/resource/locales/en_US/admin/userInvitation.txt

@@ -1,14 +1,14 @@
-Hi, {{ email }}
+Hi, <%- email -%>
 
 
 You are invited to our Wiki, you can log in with following account:
 You are invited to our Wiki, you can log in with following account:
 
 
-Email: {{ email }}
-Password: {{ password }}
+Email: <%- email -%>
+Password: <%- password -%>
 (This password was auto generated. Update required at the first time you logging in)
 (This password was auto generated. Update required at the first time you logging in)
 
 
 We are waiting for you!
 We are waiting for you!
-{{ url }}
+<%- url -%>
 
 
 --
 --
-{{ appTitle }}
-{{ url }}
+<%- appTitle -%>
+<%- url -%>

+ 8 - 8
packages/app/resource/locales/en_US/admin/userWaitingActivation.txt

@@ -1,21 +1,21 @@
-Hi, {{ adminUser.name }}
+Hi, <%- adminUser.name -%>
 
 
-A user registered to {{ appTitle }}.
+A user registered to <%- appTitle -%>.
 
 
 
 
 ====
 ====
 Created user:
 Created user:
 
 
-Name: {{ createdUser.name }}
-User Name: {{ createdUser.username }}
-Email: {{ createdUser.email }}
+Name: <%- createdUser.name -%>
+User Name: <%- createdUser.username -%>
+Email: <%- createdUser.email -%>
 ====
 ====
 
 
 Please do some action with following URL:
 Please do some action with following URL:
-{{ url }}/admin/users
+<%- url -%>/admin/users
 
 
 
 
 --
 --
-{{ appTitle }}
-{{ url }}
+<%- appTitle -%>
+<%- url -%>
 
 

+ 3 - 3
packages/app/resource/locales/en_US/notifications/comment.txt

@@ -1,9 +1,9 @@
-{{ username }} commented on {{ path }}.
+<%- username }} commented on {{ path -%>.
 
 
 ----------------------
 ----------------------
 
 
-{{ comment }}
+<%- comment -%>
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 4 - 4
packages/app/resource/locales/en_US/notifications/notActiveUser.txt

@@ -1,13 +1,13 @@
 Password Reset
 Password Reset
 
 
-Hi, {{ email }}
+Hi, <%- email -%>
 
 
-A request has been received to change the password from {{ appTitle }}.
+A request has been received to change the password from <%- appTitle -%>.
 However, this email is not registerd. Please try again with different email.
 However, this email is not registerd. Please try again with different email.
 
 
 If you did not request a password reset, you can safely ignore this email.
 If you did not request a password reset, you can safely ignore this email.
 
 
 -------------------------------------------------------------------------
 -------------------------------------------------------------------------
 
 
-GROWI: {{ appTitle }}
-URL: {{ url }}
+GROWI: <%- appTitle -%>
+URL: <%- url -%>

+ 2 - 2
packages/app/resource/locales/en_US/notifications/pageCreate.txt

@@ -1,5 +1,5 @@
-{{ username }} created a new page under {{ path }}.
+<%- username -%> created a new page under <%- path -%>.
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 2 - 2
packages/app/resource/locales/en_US/notifications/pageDelete.txt

@@ -1,5 +1,5 @@
-{{ username }} deleted the page  {{ path }}.
+<%- username -%> deleted the page  <%- path -%>.
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 2 - 2
packages/app/resource/locales/en_US/notifications/pageEdit.txt

@@ -1,5 +1,5 @@
-{{ username }} edited the page {{ path }}.
+<%- username -%> edited the page <%- path -%>.
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 2 - 2
packages/app/resource/locales/en_US/notifications/pageLike.txt

@@ -1,5 +1,5 @@
-{{ username }} liked the page {{ path }}.
+<%- username -%> liked the page <%- path -%>.
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 2 - 2
packages/app/resource/locales/en_US/notifications/pageMove.txt

@@ -1,5 +1,5 @@
-{{ username }} renamed the page {{ oldPath }} to {{ newPath }}.
+<%- username -%> renamed the page <%- oldPath -%> to <%- newPath -%>.
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 4 - 4
packages/app/resource/locales/en_US/notifications/passwordReset.txt

@@ -1,12 +1,12 @@
 Password Reset
 Password Reset
 
 
-Hi, {{ email }}
+Hi, <%- email -%>
 
 
-A request has been received to change the password your GROWI ({{ appTitle }}) account.
+A request has been received to change the password your GROWI (<%- appTitle -%>) account.
 To reset your password, click on the link below.
 To reset your password, click on the link below.
 
 
-{{ url }}
+<%- url -%>
 
 
-This link will expire in 10 minutes at  {{ expiredAt }}.
+This link will expire in 10 minutes at  <%- expiredAt -%>.
 
 
 If you did not request a password reset, you can safely ignore this email.
 If you did not request a password reset, you can safely ignore this email.

+ 1 - 1
packages/app/resource/locales/en_US/notifications/passwordResetSuccessful.txt

@@ -1,6 +1,6 @@
 Password Reset Successful
 Password Reset Successful
 
 
-Hi {{ email }}
+Hi <%- email -%>
 
 
 Your password has been successfully reset.
 Your password has been successfully reset.
 Please log in with your new password.
 Please log in with your new password.

+ 4 - 4
packages/app/resource/locales/en_US/notifications/userActivation.txt

@@ -1,12 +1,12 @@
 Account confirmation
 Account confirmation
 
 
-Hi, {{ email }}
+Hi, <%- email -%>
 
 
-An acount has been created in GROWI ({{ appTitle }}).
+An acount has been created in GROWI (<%- appTitle -%>).
 To activate your account, click on the link below.
 To activate your account, click on the link below.
 
 
-{{ url }}
+<%- url -%>
 
 
-This link will expire in 1 hour at  {{ expiredAt }}.
+This link will expire in 1 hour at  <%- expiredAt -%>.
 
 
 If you did not created the account, you can safely ignore this email.
 If you did not created the account, you can safely ignore this email.

+ 6 - 6
packages/app/resource/locales/ja_JP/admin/userInvitation.txt

@@ -1,14 +1,14 @@
-Hi, {{ email }}
+Hi, <%- email -%>
 
 
 You are invited to our Wiki, you can log in with following account:
 You are invited to our Wiki, you can log in with following account:
 
 
-Email: {{ email }}
-Password: {{ password }}
+Email: <%- email -%>
+Password: <%- password -%>
 (This password was auto generated. Update required at the first time you logging in)
 (This password was auto generated. Update required at the first time you logging in)
 
 
 We are waiting for you!
 We are waiting for you!
-{{ url }}
+<%- url -%>
 
 
 --
 --
-{{ appTitle }}
-{{ url }}
+<%- appTitle -%>
+<%- url -%>

+ 8 - 8
packages/app/resource/locales/ja_JP/admin/userWaitingActivation.txt

@@ -1,21 +1,21 @@
-Hi, {{ adminUser.name }}
+Hi, <%- adminUser.name -%>
 
 
-A user registered to {{ appTitle }}.
+A user registered to <%- appTitle -%>.
 
 
 
 
 ====
 ====
 Created user:
 Created user:
 
 
-Name: {{ createdUser.name }}
-User Name: {{ createdUser.username }}
-Email: {{ createdUser.email }}
+Name: <%- createdUser.name -%>
+User Name: <%- createdUser.username -%>
+Email: <%- createdUser.email -%>
 ====
 ====
 
 
 Please do some action with following URL:
 Please do some action with following URL:
-{{ url }}/admin/users
+<%- url -%>/admin/users
 
 
 
 
 --
 --
-{{ appTitle }}
-{{ url }}
+<%- appTitle -%>
+<%- url -%>
 
 

+ 4 - 4
packages/app/resource/locales/ja_JP/notifications/notActiveUser.txt

@@ -1,13 +1,13 @@
 パスワードリセット
 パスワードリセット
 
 
-こんにちは、 {{ email }}
+こんにちは、 <%- email -%>
 
 
-{{ appTitle }} からパスワード再設定のリクエストがありましたが、このemailは登録されておりません。
+<%- appTitle -%> からパスワード再設定のリクエストがありましたが、このemailは登録されておりません。
 他のemailアドレスで再度お試しください。
 他のemailアドレスで再度お試しください。
 
 
 もしこのリクエストに心当たりがない場合は、このメールを無視してください。
 もしこのリクエストに心当たりがない場合は、このメールを無視してください。
 
 
 -------------------------------------------------------------------------
 -------------------------------------------------------------------------
 
 
-GROWI: {{ appTitle }}
-URL: {{ url }}
+GROWI: <%- appTitle -%>
+URL: <%- url -%>

+ 4 - 4
packages/app/resource/locales/ja_JP/notifications/passwordReset.txt

@@ -1,12 +1,12 @@
 パスワード リセット
 パスワード リセット
 
 
-こんにちは, {{ email }}
+こんにちは, <%- email -%>
 
 
-あなたのGROWI ({{ appTitle }}) アカウントから、パスワード再設定のリクエストがありました。
+あなたのGROWI (<%- appTitle -%>) アカウントから、パスワード再設定のリクエストがありました。
 パスワードをリセットするには、以下のリンクをクリックしてください。
 パスワードをリセットするには、以下のリンクをクリックしてください。
 
 
-{{ url }}
+<%- url -%>
 
 
-このリンクは10分後の {{ expiredAt }} に失効します。
+このリンクは10分後の <%- expiredAt -%> に失効します。
 
 
 もしこのリクエストに心当たりがない場合は、このメールを無視してください。
 もしこのリクエストに心当たりがない場合は、このメールを無視してください。

+ 1 - 1
packages/app/resource/locales/ja_JP/notifications/passwordResetSuccessful.txt

@@ -1,6 +1,6 @@
 パスワードリセットに成功
 パスワードリセットに成功
 
 
-こんにちは、 {{ email }}
+こんにちは、 <%- email -%>
 
 
 あなたのパスワードは正常にリセットされました。
 あなたのパスワードは正常にリセットされました。
 新しいパスワードでログインしてください。
 新しいパスワードでログインしてください。

+ 4 - 4
packages/app/resource/locales/ja_JP/notifications/userActivation.txt

@@ -1,13 +1,13 @@
 仮登録完了のお知らせ
 仮登録完了のお知らせ
 
 
-{{ email }} さん
+<%- email -%> さん
 
 
-GROWI ({{ appTitle }}) で仮登録が完了いたしました。
+GROWI (<%- appTitle -%>) で仮登録が完了いたしました。
 
 
 ご本人様確認のため、下記リンクをクリックし、アカウントの本登録を完了させて下さい。
 ご本人様確認のため、下記リンクをクリックし、アカウントの本登録を完了させて下さい。
 
 
-{{ url }}
+<%- url -%>
 
 
-このリンクは1時間後の {{ expiredAt }} に失効します。
+このリンクは1時間後の <%- expiredAt -%> に失効します。
 
 
 ※当メールの内容に心当たりがない場合は、このメールを無視してください。
 ※当メールの内容に心当たりがない場合は、このメールを無視してください。

+ 6 - 6
packages/app/resource/locales/zh_CN/admin/userInvitation.txt

@@ -1,14 +1,14 @@
-Hi, {{ email }}
+Hi, <%- email -%>
 
 
 You are invited to our Wiki, you can log in with following account:
 You are invited to our Wiki, you can log in with following account:
 
 
-Email: {{ email }}
-Password: {{ password }}
+Email: <%- email -%>
+Password: <%- password -%>
 (This password was auto generated. Update required at the first time you logging in)
 (This password was auto generated. Update required at the first time you logging in)
 
 
 We are waiting for you!
 We are waiting for you!
-{{ url }}
+<%- url -%>
 
 
 --
 --
-{{ appTitle }}
-{{ url }}
+<%- appTitle -%>
+<%- url -%>

+ 8 - 8
packages/app/resource/locales/zh_CN/admin/userWaitingActivation.txt

@@ -1,21 +1,21 @@
-Hi, {{ adminUser.name }}
+Hi, <%- adminUser.name -%>
 
 
-A user registered to {{ appTitle }}.
+A user registered to <%- appTitle -%>.
 
 
 
 
 ====
 ====
 Created user:
 Created user:
 
 
-Name: {{ createdUser.name }}
-User Name: {{ createdUser.username }}
-Email: {{ createdUser.email }}
+Name: <%- createdUser.name -%>
+User Name: <%- createdUser.username -%>
+Email: <%- createdUser.email -%>
 ====
 ====
 
 
 Please do some action with following URL:
 Please do some action with following URL:
-{{ url }}/admin/users
+<%- url -%>/admin/users
 
 
 
 
 --
 --
-{{ appTitle }}
-{{ url }}
+<%- appTitle -%>
+<%- url -%>
 
 

+ 3 - 3
packages/app/resource/locales/zh_CN/notifications/comment.txt

@@ -1,9 +1,9 @@
-{{ username }} commented on {{ path }}.
+<%- username -%> commented on <%- path -%>.
 
 
 ----------------------
 ----------------------
 
 
-{{ comment }}
+<%- comment -%>
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 4 - 4
packages/app/resource/locales/zh_CN/notifications/notActiveUser.txt

@@ -1,13 +1,13 @@
 重设密码
 重设密码
 
 
-嗨,{{电子邮件}}
+嗨,<%-电子邮件-%>
 
 
-已收到来自 {{appTitle}} 的更改密码请求。
+已收到来自 <%-appTitle-%> 的更改密码请求。
 但是,此电子邮件未注册。请使用其他电子邮件重试。
 但是,此电子邮件未注册。请使用其他电子邮件重试。
 
 
 如果您没有要求重置密码,则可以放心地忽略此电子邮件。
 如果您没有要求重置密码,则可以放心地忽略此电子邮件。
 
 
 -------------------------------------------------------------------------
 -------------------------------------------------------------------------
 
 
-GROWI: {{ appTitle }}
-URL: {{ url }}
+GROWI: <%- appTitle -%>
+URL: <%- url -%>

+ 2 - 2
packages/app/resource/locales/zh_CN/notifications/pageCreate.txt

@@ -1,5 +1,5 @@
-{{ username }} created a new page under {{ path }}.
+<%- username -%> created a new page under <%- path -%>.
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 2 - 2
packages/app/resource/locales/zh_CN/notifications/pageDelete.txt

@@ -1,5 +1,5 @@
-{{ username }} deleted the page  {{ path }}.
+<%- username -%> deleted the page  <%- path -%>.
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 2 - 2
packages/app/resource/locales/zh_CN/notifications/pageEdit.txt

@@ -1,5 +1,5 @@
-{{ username }} edited the page {{ path }}.
+<%- username -%> edited the page <%- path -%>.
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 2 - 2
packages/app/resource/locales/zh_CN/notifications/pageLike.txt

@@ -1,5 +1,5 @@
-{{ username }} liked the page {{ path }}.
+<%- username -%> liked the page <%- path -%>.
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 2 - 2
packages/app/resource/locales/zh_CN/notifications/pageMove.txt

@@ -1,5 +1,5 @@
-{{ username }} renamed the page {{ oldPath }} to {{ newPath }}.
+<%- username -%> renamed the page <%- oldPath -%> to <%- newPath -%>.
 
 
 ----------------------
 ----------------------
 
 
-Growi: {{ appTitle }}
+Growi: <%- appTitle -%>

+ 3 - 3
packages/app/resource/locales/zh_CN/notifications/passwordReset.txt

@@ -1,11 +1,11 @@
 重设密码
 重设密码
 
 
-嗨,{{ email }}
+嗨,<%- email -%>
 
 
-已收到更改您 GROWI ({{appTitle}}) 帐户 密码的请求。
+已收到更改您 GROWI (<%-appTitle-%>) 帐户 密码的请求。
 要重置密码,请单击下面的链接。
 要重置密码,请单击下面的链接。
 
 
-{{ url }}
+<%- url -%>
 
 
 这个链接在10分钟后的{ expiredAt }}失效。
 这个链接在10分钟后的{ expiredAt }}失效。
 
 

+ 1 - 1
packages/app/resource/locales/zh_CN/notifications/passwordResetSuccessful.txt

@@ -1,6 +1,6 @@
 密码重置成功
 密码重置成功
 
 
-嗨, {{email}}
+嗨, <%-email-%>
 
 
 您的密码已成功重置。
 您的密码已成功重置。
 请使用您的新密码登录。
 请使用您的新密码登录。

+ 4 - 4
packages/app/resource/locales/zh_CN/notifications/userActivation.txt

@@ -1,12 +1,12 @@
 确认账户创建
 确认账户创建
 
 
-致{{ email }}
+致<%- email -%>
 
 
-已使用 GROWI ({{ appTitle }}) 创建帐户。
+已使用 GROWI (<%- appTitle -%>) 创建帐户。
 单击下面的链接以激活您的帐户。
 单击下面的链接以激活您的帐户。
 
 
-{{ url }}
+<%- url -%>
 
 
-这个链接将在1小时后即{{ expiredAt }}失效。
+这个链接将在1小时后即<%- expiredAt -%>失效。
 
 
 如果您尚未创建,请忽略此电子邮件。
 如果您尚未创建,请忽略此电子邮件。

+ 13 - 10
packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -33,6 +33,7 @@ import AttachmentIcon from '../Icons/AttachmentIcon';
 import HistoryIcon from '../Icons/HistoryIcon';
 import HistoryIcon from '../Icons/HistoryIcon';
 import PresentationIcon from '../Icons/PresentationIcon';
 import PresentationIcon from '../Icons/PresentationIcon';
 import ShareLinkIcon from '../Icons/ShareLinkIcon';
 import ShareLinkIcon from '../Icons/ShareLinkIcon';
+import { NotAvailableForNow } from '../NotAvailableForNow';
 import { Skeleton } from '../Skeleton';
 import { Skeleton } from '../Skeleton';
 
 
 import type { AuthorInfoProps } from './AuthorInfo';
 import type { AuthorInfoProps } from './AuthorInfo';
@@ -86,16 +87,18 @@ const PageOperationMenuItems = (props: PageOperationMenuItemsProps): JSX.Element
   return (
   return (
     <>
     <>
       {/* Presentation */}
       {/* Presentation */}
-      <DropdownItem
-        onClick={() => openPresentationModal(hrefForPresentationModal)}
-        data-testid="open-presentation-modal-btn"
-        className="grw-page-control-dropdown-item"
-      >
-        <i className="icon-fw grw-page-control-dropdown-icon">
-          <PresentationIcon />
-        </i>
-        { t('Presentation Mode') }
-      </DropdownItem>
+      <NotAvailableForNow>
+        <DropdownItem
+          onClick={() => openPresentationModal(hrefForPresentationModal)}
+          data-testid="open-presentation-modal-btn"
+          className="grw-page-control-dropdown-item"
+        >
+          <i className="icon-fw grw-page-control-dropdown-icon">
+            <PresentationIcon />
+          </i>
+          { t('Presentation Mode') }
+        </DropdownItem>
+      </NotAvailableForNow>
 
 
       {/* Export markdown */}
       {/* Export markdown */}
       <DropdownItem
       <DropdownItem

+ 35 - 0
packages/app/src/components/NotAvailable.tsx

@@ -0,0 +1,35 @@
+import React from 'react';
+
+import { TFunction } from 'next-i18next';
+import { Disable } from 'react-disable';
+import { UncontrolledTooltip, UncontrolledTooltipProps } from 'reactstrap';
+
+type NotAvailableProps = {
+  children: JSX.Element
+  isDisabled: boolean
+  title: ReturnType<TFunction>
+  classNamePrefix?: string
+  placement?: UncontrolledTooltipProps['placement']
+}
+
+export const NotAvailable = ({
+  children, isDisabled, title, classNamePrefix = 'grw-not-available', placement = 'top',
+}: NotAvailableProps): JSX.Element => {
+
+  if (!isDisabled) {
+    return children;
+  }
+
+  const id = `${classNamePrefix}-${Math.random().toString(32).substring(2)}`;
+
+  return (
+    <>
+      <div id={id}>
+        <Disable disabled={isDisabled}>
+          {children}
+        </Disable>
+      </div>
+      <UncontrolledTooltip placement={placement} target={id}>{title}</UncontrolledTooltip>
+    </>
+  );
+};

+ 15 - 19
packages/app/src/components/NotAvailableForGuest.tsx

@@ -1,35 +1,31 @@
 import React from 'react';
 import React from 'react';
 
 
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
-import { Disable } from 'react-disable';
-import { UncontrolledTooltip } from 'reactstrap';
 
 
 import { useIsGuestUser } from '~/stores/context';
 import { useIsGuestUser } from '~/stores/context';
 
 
+import { NotAvailable } from './NotAvailable';
+
+
 type NotAvailableForGuestProps = {
 type NotAvailableForGuestProps = {
   children: JSX.Element
   children: JSX.Element
 }
 }
 
 
-export const NotAvailableForGuest = ({ children }: NotAvailableForGuestProps): JSX.Element => {
+export const NotAvailableForGuest = React.memo(({ children }: NotAvailableForGuestProps): JSX.Element => {
   const { t } = useTranslation();
   const { t } = useTranslation();
-
   const { data: isGuestUser } = useIsGuestUser();
   const { data: isGuestUser } = useIsGuestUser();
-  const isDisabled = !!isGuestUser;
-
-  if (!isGuestUser) {
-    return children;
-  }
 
 
-  const id = `grw-not-available-for-guest-${Math.random().toString(32).substring(2)}`;
+  const isDisabled = !!isGuestUser;
+  const title = t('Not available for guest');
 
 
   return (
   return (
-    <>
-      <div id={id}>
-        <Disable disabled={isDisabled}>
-          { children }
-        </Disable>
-      </div>
-      <UncontrolledTooltip placement="top" target={id}>{t('Not available for guest')}</UncontrolledTooltip>
-    </>
+    <NotAvailable
+      isDisabled={isDisabled}
+      title={title}
+      classNamePrefix="grw-not-available-for-guest"
+    >
+      {children}
+    </NotAvailable>
   );
   );
-};
+});
+NotAvailableForGuest.displayName = 'NotAvailableForGuest';

+ 27 - 0
packages/app/src/components/NotAvailableForNow.tsx

@@ -0,0 +1,27 @@
+import React from 'react';
+
+import { useTranslation } from 'next-i18next';
+
+import { NotAvailable } from './NotAvailable';
+
+
+type NotAvailableForNowProps = {
+  children: JSX.Element
+}
+
+export const NotAvailableForNow = React.memo(({ children }: NotAvailableForNowProps): JSX.Element => {
+  const { t } = useTranslation();
+
+  const title = t('Not available in this version');
+
+  return (
+    <NotAvailable
+      isDisabled
+      title={title}
+      classNamePrefix="grw-not-available-for-now"
+    >
+      {children}
+    </NotAvailable>
+  );
+});
+NotAvailableForNow.displayName = 'NotAvailableForNow';

+ 0 - 12
packages/app/src/lib/util/isSecurityEnv.js

@@ -1,12 +0,0 @@
-/**
- * return whether env belongs to Security settings
- * @param {string} key ex. 'security:passport-saml:isEnabled' is true
- * @returns {boolean}
- * @memberof envUtils
- */
-const isSecurityEnv = (key) => {
-  const array = key.split(':');
-  return (array[0] === 'security');
-};
-
-module.exports = isSecurityEnv;

+ 0 - 29
packages/app/src/server/crowi/dev.js

@@ -8,8 +8,6 @@ import loggerFactory from '~/utils/logger';
 
 
 import nextFactory from '../routes/next';
 import nextFactory from '../routes/next';
 
 
-const swig = require('swig-templates');
-
 const logger = loggerFactory('growi:crowi:dev');
 const logger = loggerFactory('growi:crowi:dev');
 
 
 
 
@@ -99,33 +97,6 @@ class CrowiDev {
     this.setupNextjsStackFrame(app);
     this.setupNextjsStackFrame(app);
   }
   }
 
 
-  // setupHeaderDebugger(app) {
-  //   logger.debug('setupHeaderDebugger');
-
-  //   app.use((req, res, next) => {
-  //     onHeaders(res, () => {
-  //       logger.debug('HEADERS GOING TO BE WRITTEN');
-  //     });
-  //     next();
-  //   });
-  // }
-
-  // setupBrowserSync(app) {
-  //   logger.debug('setupBrowserSync');
-
-  //   const browserSync = require('browser-sync');
-  //   const bs = browserSync.create().init({
-  //     logSnippet: false,
-  //     notify: false,
-  //     files: [
-  //       `${this.crowi.viewsDir}/**/*.html`,
-  //       `${this.crowi.publicDir}/**/*.js`,
-  //       `${this.crowi.publicDir}/**/*.css`,
-  //     ],
-  //   });
-  //   app.use(require('connect-browser-sync')(bs));
-  // }
-
   setupNextBundleAnalyzer(app) {
   setupNextBundleAnalyzer(app) {
     const next = nextFactory(this.crowi);
     const next = nextFactory(this.crowi);
     app.use('/analyze', express.static(path.resolve(__dirname, '../../../.next/analyze')));
     app.use('/analyze', express.static(path.resolve(__dirname, '../../../.next/analyze')));

+ 0 - 41
packages/app/src/server/crowi/express-init.js

@@ -2,8 +2,6 @@ import { manifestPath as presetThemesManifestPath } from '@growi/preset-themes';
 import csrf from 'csurf';
 import csrf from 'csurf';
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
-import { i18n, localePath } from '^/config/next-i18next.config';
-
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 import { resolveFromRoot } from '~/utils/project-dir-utils';
 import { resolveFromRoot } from '~/utils/project-dir-utils';
 
 
@@ -22,12 +20,6 @@ module.exports = function(crowi, app) {
   const expressSession = require('express-session');
   const expressSession = require('express-session');
   const flash = require('connect-flash');
   const flash = require('connect-flash');
   const mongoSanitize = require('express-mongo-sanitize');
   const mongoSanitize = require('express-mongo-sanitize');
-  const swig = require('swig-templates');
-  const webpackAssets = require('express-webpack-assets');
-  // const i18next = require('i18next');
-  // const i18nFsBackend = require('i18next-node-fs-backend');
-  // const i18nSprintf = require('i18next-sprintf-postprocessor');
-  // const i18nMiddleware = require('i18next-express-middleware');
 
 
   const promster = require('../middlewares/promster')(crowi, app);
   const promster = require('../middlewares/promster')(crowi, app);
   const registerSafeRedirect = require('../middlewares/safe-redirect')();
   const registerSafeRedirect = require('../middlewares/safe-redirect')();
@@ -35,33 +27,9 @@ module.exports = function(crowi, app) {
   const autoReconnectToS2sMsgServer = require('../middlewares/auto-reconnect-to-s2s-msg-server')(crowi);
   const autoReconnectToS2sMsgServer = require('../middlewares/auto-reconnect-to-s2s-msg-server')(crowi);
 
 
   const avoidSessionRoutes = require('../routes/avoid-session-routes');
   const avoidSessionRoutes = require('../routes/avoid-session-routes');
-  // const i18nUserSettingDetector = require('../util/i18nUserSettingDetector');
 
 
   const env = crowi.node_env;
   const env = crowi.node_env;
 
 
-  // const lngDetector = new i18nMiddleware.LanguageDetector();
-  // lngDetector.addDetector(i18nUserSettingDetector);
-
-  // i18next
-  //   .use(lngDetector)
-  //   .use(i18nFsBackend)
-  //   .use(i18nSprintf)
-  //   .init({
-  //     // debug: true,
-  //     fallbackLng: ['en_US'],
-  //     whitelist: i18n.locales,
-  //     backend: {
-  //       loadPath: `${localePath}/{{lng}}/translation.json`,
-  //     },
-  //     detection: {
-  //       order: ['userSettingDetector', 'header', 'navigator'],
-  //     },
-  //     overloadTranslationOptionHandler: i18nSprintf.overloadTranslationOptionHandler,
-
-  //     // change nsSeparator from ':' to '::' because ':' is used in config keys and these are used in i18n keys
-  //     nsSeparator: '::',
-  //   });
-
   app.use(compression());
   app.use(compression());
 
 
 
 
@@ -122,10 +90,6 @@ module.exports = function(crowi, app) {
   ));
   ));
   app.use('/static/plugins', express.static(path.resolve(__dirname, '../../../tmp/plugins')));
   app.use('/static/plugins', express.static(path.resolve(__dirname, '../../../tmp/plugins')));
 
 
-  app.engine('html', swig.renderFile);
-  // app.set('view cache', false);  // Default: true in production, otherwise undefined. -- 2017.07.04 Yuki Takei
-  app.set('view engine', 'html');
-  app.set('views', crowi.viewsDir);
   app.use(methodOverride());
   app.use(methodOverride());
 
 
   // inject rawBody to req
   // inject rawBody to req
@@ -173,11 +137,6 @@ module.exports = function(crowi, app) {
   app.use(injectCurrentuserToLocalvars);
   app.use(injectCurrentuserToLocalvars);
   app.use(autoReconnectToS2sMsgServer);
   app.use(autoReconnectToS2sMsgServer);
 
 
-  const middlewares = require('../util/middlewares')(crowi, app);
-  app.use(middlewares.swigFilters(swig));
-  app.use(middlewares.swigFunctions());
-
-  // app.use(i18nMiddleware.handle(i18next));
   // TODO: Remove this workaround implementation when i18n works correctly.
   // TODO: Remove this workaround implementation when i18n works correctly.
   //       For now, req.t returns string given to req.t(string)
   //       For now, req.t returns string given to req.t(string)
   app.use((req, res, next) => {
   app.use((req, res, next) => {

+ 0 - 3
packages/app/src/server/routes/hackmd.js

@@ -3,13 +3,10 @@ import loggerFactory from '~/utils/logger';
 /* eslint-disable no-use-before-define */
 /* eslint-disable no-use-before-define */
 
 
 const logger = loggerFactory('growi:routes:hackmd');
 const logger = loggerFactory('growi:routes:hackmd');
-const path = require('path');
 
 
 const hackmdFiles = require('@growi/hackmd');
 const hackmdFiles = require('@growi/hackmd');
 const axios = require('axios');
 const axios = require('axios');
 const ejs = require('ejs');
 const ejs = require('ejs');
-const fs = require('graceful-fs');
-const swig = require('swig-templates');
 
 
 const ApiResponse = require('../util/apiResponse');
 const ApiResponse = require('../util/apiResponse');
 
 

+ 1 - 1
packages/app/src/server/service/import.js

@@ -396,7 +396,7 @@ class ImportService {
       // https://regex101.com/r/mD4eZs/6
       // https://regex101.com/r/mD4eZs/6
       // prevent from unexpecting attack doing unzip file (path traversal attack)
       // prevent from unexpecting attack doing unzip file (path traversal attack)
       // FOR EXAMPLE
       // FOR EXAMPLE
-      // ../../src/server/views/admin/markdown.html
+      // ../../src/server/example.html
       if (fileName.match(/(\.\.\/|\.\.\\)/)) {
       if (fileName.match(/(\.\.\/|\.\.\\)/)) {
         logger.error('File path is not appropriate.', fileName);
         logger.error('File path is not appropriate.', fileName);
         return;
         return;

+ 8 - 2
packages/app/src/server/service/mail.ts

@@ -1,13 +1,17 @@
+import { promisify } from 'util';
+
+import ejs from 'ejs';
 import nodemailer from 'nodemailer';
 import nodemailer from 'nodemailer';
-import swig from 'swig-templates';
 
 
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
 import S2sMessage from '../models/vo/s2s-message';
 import S2sMessage from '../models/vo/s2s-message';
+
 import { S2sMessageHandlable } from './s2s-messaging/handlable';
 import { S2sMessageHandlable } from './s2s-messaging/handlable';
 
 
 const logger = loggerFactory('growi:service:mail');
 const logger = loggerFactory('growi:service:mail');
 
 
+
 type MailConfig = {
 type MailConfig = {
   to?: string,
   to?: string,
   from?: string,
   from?: string,
@@ -190,8 +194,10 @@ class MailService implements S2sMessageHandlable {
       throw new Error('Mailer is not completed to set up. Please set up SMTP or AWS setting.');
       throw new Error('Mailer is not completed to set up. Please set up SMTP or AWS setting.');
     }
     }
 
 
+    const renderFilePromisified = promisify(ejs.renderFile);
+
     const templateVars = config.vars || {};
     const templateVars = config.vars || {};
-    const output = await swig.renderFile(
+    const output = await renderFilePromisified(
       config.template,
       config.template,
       templateVars,
       templateVars,
     );
     );

+ 0 - 15
packages/app/src/server/util/i18nUserSettingDetector.js

@@ -1,15 +0,0 @@
-module.exports = {
-  name: 'userSettingDetector',
-
-  lookup(req, res, options) {
-    if (req.user == null) {
-      return null;
-    }
-
-    return req.user.lang || null;
-  },
-
-  cacheUserlanguage(req, res, lng, options) {
-    // nothing to do
-  },
-};

+ 0 - 133
packages/app/src/server/util/middlewares.js

@@ -1,133 +0,0 @@
-import loggerFactory from '~/utils/logger';
-
-// don't add any more middlewares to this file.
-// all new middlewares should be an independent file under /server/middlewares
-// eslint-disable-next-line no-unused-vars
-
-const { pathUtils } = require('@growi/core');
-const { formatDistanceStrict } = require('date-fns');
-const entities = require('entities');
-
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:lib:middlewares');
-
-module.exports = (crowi) => {
-  const { configManager } = crowi;
-
-  const middlewares = {};
-
-  middlewares.swigFunctions = function() {
-    return function(req, res, next) {
-      require('../util/swigFunctions')(crowi, req, res.locals);
-      next();
-    };
-  };
-
-  middlewares.swigFilters = function(swig) {
-
-    return function(req, res, next) {
-      swig.setFilter('path2name', (string) => {
-        const name = string.replace(/(\/)$/, '');
-
-        if (name.match(/.+\/([^/]+\/\d{4}\/\d{2}\/\d{2})$/)) { // /.../hoge/YYYY/MM/DD 形式のページ
-          return name.replace(/.+\/([^/]+\/\d{4}\/\d{2}\/\d{2})$/, '$1');
-        }
-        if (name.match(/.+\/([^/]+\/\d{4}\/\d{2})$/)) { // /.../hoge/YYYY/MM 形式のページ
-          return name.replace(/.+\/([^/]+\/\d{4}\/\d{2})$/, '$1');
-        }
-        if (name.match(/.+\/([^/]+\/\d{4})$/)) { // /.../hoge/YYYY 形式のページ
-          return name.replace(/.+\/([^/]+\/\d{4})$/, '$1');
-        }
-
-        return name.replace(/.+\/(.+)?$/, '$1'); // ページの末尾を拾う
-      });
-
-      swig.setFilter('normalizeDateInPath', (path) => {
-        const patterns = [
-          [/20(\d{2})(\d{2})(\d{2})(.+)/g, '20$1/$2/$3/$4'],
-          [/20(\d{2})(\d{2})(\d{2})/g, '20$1/$2/$3'],
-          [/20(\d{2})(\d{2})(.+)/g, '20$1/$2/$3'],
-          [/20(\d{2})(\d{2})/g, '20$1/$2'],
-          [/20(\d{2})_(\d{1,2})_(\d{1,2})_?(.+)/g, '20$1/$2/$3/$4'],
-          [/20(\d{2})_(\d{1,2})_(\d{1,2})/g, '20$1/$2/$3'],
-          [/20(\d{2})_(\d{1,2})_?(.+)/g, '20$1/$2/$3'],
-          [/20(\d{2})_(\d{1,2})/g, '20$1/$2'],
-        ];
-
-        for (let i = 0; i < patterns.length; i++) {
-          const mat = patterns[i][0];
-          const rep = patterns[i][1];
-          if (path.match(mat)) {
-            return path.replace(mat, rep);
-          }
-        }
-
-        return path;
-      });
-
-      swig.setFilter('datetz', (input, format) => {
-        // timezone
-        const swigFilters = require('swig-templates/lib/filters');
-        return swigFilters.date(input, format, crowi.appService.getTzoffset());
-      });
-
-      swig.setFilter('dateDistance', (input) => {
-        return formatDistanceStrict(input, new Date());
-      });
-
-      swig.setFilter('nl2br', (string) => {
-        return string
-          .replace(/\n/g, '<br>');
-      });
-
-      swig.setFilter('removeTrailingSlash', (string) => {
-        return pathUtils.removeTrailingSlash(string);
-      });
-
-      swig.setFilter('addTrailingSlash', (string) => {
-        return pathUtils.addTrailingSlash(string);
-      });
-
-      swig.setFilter('presentation', (string) => {
-        // 手抜き
-        return string
-          .replace(/\s(https?.+(jpe?g|png|gif))\s/, '\n\n\n![]($1)\n\n\n');
-      });
-
-      swig.setFilter('encodeHTML', (string) => {
-        return entities.encodeHTML(string);
-      });
-
-      swig.setFilter('preventXss', (string) => {
-        return crowi.xss.process(string);
-      });
-
-      swig.setFilter('slice', (list, start, end) => {
-        return list.slice(start, end);
-      });
-
-      swig.setFilter('push', (list, element) => {
-        list.push(element);
-        return list;
-      });
-
-      next();
-    };
-  };
-
-  middlewares.awsEnabled = function() {
-    return function(req, res, next) {
-      if ((configManager.getConfig('crowi', 'aws:s3Region') !== '' || this.configManager.getConfig('crowi', 'aws:s3CustomEndpoint') !== '')
-          && configManager.getConfig('crowi', 'aws:s3Bucket') !== ''
-          && configManager.getConfig('crowi', 'aws:s3AccessKeyId') !== ''
-          && configManager.getConfig('crowi', 'aws:s3SecretAccessKey') !== '') {
-        req.flash('globalError', req.t('message.aws_sttings_required'));
-        return res.redirect('/');
-      }
-
-      return next();
-    };
-  };
-
-  return middlewares;
-};

+ 0 - 208
packages/app/src/server/util/swigFunctions.js

@@ -1,208 +0,0 @@
-module.exports = function(crowi, req, locals) {
-  const debug = require('debug')('growi:lib:swigFunctions');
-  const stringWidth = require('string-width');
-
-  const { pathUtils } = require('@growi/core');
-
-  const Page = crowi.model('Page');
-  const User = crowi.model('User');
-  const {
-    configManager,
-    cdnResourcesService,
-    passportService,
-    appService,
-    aclService,
-    customizeService,
-    pageService,
-  } = crowi;
-  debug('initializing swigFunctions');
-
-  locals.nodeVersion = function() {
-    return crowi.runtimeVersions.versions.node ? crowi.runtimeVersions.versions.node.version : '-';
-  };
-  locals.npmVersion = function() {
-    return crowi.runtimeVersions.versions.npm ? crowi.runtimeVersions.versions.npm.version : '-';
-  };
-  locals.yarnVersion = function() {
-    return crowi.runtimeVersions.versions.yarn ? crowi.runtimeVersions.versions.yarn.version : '-';
-  };
-
-  locals.getAppTitleFontSize = function(appTitle) {
-    const appTitleWidth = stringWidth(appTitle);
-    let fontSize = 22;
-    if (appTitleWidth < 13) { /* do nothing */ }
-    else if (appTitleWidth < 21) {
-      fontSize -= 3 * (Math.floor((appTitleWidth - 13) / 3) + 1);
-    }
-    else {
-      fontSize = 11;
-    }
-    return fontSize;
-  };
-
-  /**
-   * @see ConfigManager#getConfig
-   */
-  locals.getConfig = configManager.getConfig.bind(configManager);
-
-  /**
-   * **Do not use this unless absolutely necessary. Use getConfig instead.**
-   */
-  locals.getConfigFromDB = configManager.getConfigFromDB.bind(configManager);
-
-  /**
-   * **Do not use this unless absolutely necessary. Use getConfig instead.**
-   */
-  locals.getConfigFromEnvVars = configManager.getConfigFromEnvVars.bind(configManager);
-
-  /**
-   * pass service/utils instances to swig
-   */
-  locals.appService = appService;
-  locals.aclService = aclService;
-  locals.customizeService = customizeService;
-  locals.passportService = passportService;
-  locals.pageService = pageService;
-  locals.pathUtils = pathUtils;
-
-  locals.noCdn = function() {
-    return cdnResourcesService.noCdn;
-  };
-
-  locals.cdnScriptTag = function(name) {
-    return cdnResourcesService.getScriptTagByName(name);
-  };
-  locals.cdnScriptTagsByGroup = function(group) {
-    const tags = cdnResourcesService.getScriptTagsByGroup(group);
-    return tags.join('\n');
-  };
-
-  locals.cdnStyleTag = function(name) {
-    return cdnResourcesService.getStyleTagByName(name);
-  };
-
-  locals.cdnStyleTagsByGroup = function(group) {
-    const tags = cdnResourcesService.getStyleTagsByGroup(group);
-    return tags.join('\n');
-  };
-
-  locals.cdnHighlightJsStyleTag = function(styleName) {
-    return cdnResourcesService.getHighlightJsStyleTag(styleName);
-  };
-
-  /**
-   * return true if enabled but strategy has some problem
-   */
-  locals.isLdapSetupFailed = function() {
-    return (
-      configManager.getConfig('crowi', 'security:passport-ldap:isEnabled')
-      && !passportService.isLdapStrategySetup
-    );
-  };
-
-  locals.getSamlMissingMandatoryConfigKeys = function() {
-    return crowi.passportService.getSamlMissingMandatoryConfigKeys();
-  };
-
-  locals.isHackmdSetup = function() {
-    return process.env.HACKMD_URI != null;
-  };
-
-  locals.parentPath = function(path) {
-    if (path === '/') {
-      return path;
-    }
-
-    if (path.match(/.+\/$/)) {
-      return path;
-    }
-
-    return `${path}/`;
-  };
-
-  locals.isUserPageList = function(path) {
-    if (path.match(/^\/user\/[^/]+\/$/)) {
-      return true;
-    }
-
-    return false;
-  };
-
-  locals.isTopPage = function() {
-    const path = req.path || '';
-    if (path === '/') {
-      return true;
-    }
-
-    return false;
-  };
-
-  locals.isTrashPage = function(path = '') {
-    if (path.match(/^\/trash(\/.*)?$/)) {
-      return true;
-    }
-
-    return false;
-  };
-
-  locals.userPageRoot = function(user) {
-    if (!user || !user.username) {
-      return '';
-    }
-    return `/user/${user.username}`;
-  };
-
-  locals.pagesDataForTimeline = function(pages) {
-    return pages.map((page) => {
-      return {
-        id: page.id,
-        path: page.path,
-        revision: page.revision,
-      };
-    });
-  };
-
-  locals.attachTitleHeader = function(path) {
-    return pathUtils.attachTitleHeader(path);
-  };
-
-  locals.css = {
-    grant(pageData) {
-      if (!pageData) {
-        return '';
-      }
-
-      switch (pageData.grant) {
-        case Page.GRANT_PUBLIC:
-          return 'grant-public';
-        case Page.GRANT_RESTRICTED:
-          return 'grant-restricted';
-        // case Page.GRANT_SPECIFIED:
-        //  return 'grant-specified';
-        //  break;
-        case Page.GRANT_OWNER:
-          return 'grant-owner';
-        default:
-          break;
-      }
-      return '';
-    },
-    userStatus(user) {
-      switch (user.status) {
-        case User.STATUS_REGISTERED:
-          return 'label-info';
-        case User.STATUS_ACTIVE:
-          return 'label-success';
-        case User.STATUS_SUSPENDED:
-          return 'label-warning';
-        case User.STATUS_DELETED:
-          return 'label-danger';
-        case User.STATUS_INVITED:
-          return 'label-info';
-        default:
-          break;
-      }
-      return '';
-    },
-  };
-};

+ 0 - 1
packages/app/src/server/views/500.html

@@ -1 +0,0 @@
-Error: {{ error.message }}

+ 0 - 45
packages/app/src/server/views/forgot-password.html

@@ -1,45 +0,0 @@
-{% extends './layout/layout.html' %}
-
-{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('forgot_password.forgot_password')) }}{% endblock %}
-
-
-{#
-  # Remove default contents
-  #}
- {% block html_head_loading_legacy %}
- {% endblock %}
- {% block html_head_loading_app %}
- {% endblock %}
- {% block layout_head_nav %}
- {% endblock %}
- {% block sidebar %}
- {% endblock %}
- {% block head_warn_alert_siteurl_undefined %}
- {% endblock %}
- {% block fixed-controls %}
- {% endblock %}
-
- {% block html_additional_headers %}
-   <script src="{{ webpack_asset('js/nologin.js') }}" defer></script>
- {% endblock %}
-
-{% block layout_main %}
-
-  <div id="main" class="main">
-    <div id="content-main" class="content-main container-lg">
-      <div class="container">
-        <div class="row justify-content-md-center">
-          <div class="col-md-6 mt-5">
-            <div class="text-center">
-              <h1><i class="icon-lock large"></i></h1>
-              <h1 class="text-center">{{ t('forgot_password.forgot_password') }}</h1>
-              <h3>{{ t('forgot_password.password_reset_request_desc') }}</h3>
-              <div id="password-reset-request-form"></div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-
-{% endblock %}

+ 0 - 60
packages/app/src/server/views/forgot-password/error.html

@@ -1,60 +0,0 @@
-{% extends '../layout/layout.html' %}
-
-{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('forgot_password.reset_password')) }}{% endblock %}
-
-
-{#
-  # Remove default contents
-  #}
- {% block html_head_loading_legacy %}
- {% endblock %}
- {% block html_head_loading_app %}
- {% endblock %}
- {% block layout_head_nav %}
- {% endblock %}
- {% block sidebar %}
- {% endblock %}
- {% block head_warn_alert_siteurl_undefined %}
- {% endblock %}
- {% block fixed-controls %}
- {% endblock %}
-
- {% block html_additional_headers %}
-   <script src="{{ webpack_asset('js/nologin.js') }}" defer></script>
- {% endblock %}
-
-{% block layout_main %}
-
-  <div id="main" class="main">
-    <div id="content-main" class="content-main container-lg">
-      <div class="container">
-        <div class="row justify-content-md-center">
-          <div class="col-md-6 mt-5">
-            <div class="text-center">
-              <h1><i class="icon-lock-open large"></i></h1>
-              <h2 class="text-center">{{ t('forgot_password.reset_password') }}</h2>
-
-                {% if key === 'password-reset-is-unavailable' %}
-                <h3 class="text-muted">This feature is unavailable.</h3>
-                {% endif %}
-
-                {% if key === 'password-reset-order-is-not-appropriate' %}
-                <div>
-                  <div class="alert alert-warning mb-3">
-                    <h2>{{ t('forgot_password.incorrect_token_or_expired_url') }}</h2>
-                  </div>
-                  <a href="/forgot-password" class="link-switch">
-                    <i class="icon-key"></i> {{ t('forgot_password.forgot_password') }}
-                  </a>
-                </div>
-                {% endif %}
-
-            </div>
-          </div>
-        </div>
-      </div>
-
-    </div>
-  </div>
-
-{% endblock %}

+ 0 - 95
packages/app/src/server/views/installer.html

@@ -1,95 +0,0 @@
-<!DOCTYPE html>
-<html>
-{% block html_head %}
-<head>
-  <meta charset="utf-8">
-  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-  <title>{{ customizeService.generateCustomTitleForFixedPageName(t('installer.setup')) }}</title>
-  <meta name="description" content="">
-  <meta name="author" content="">
-
-  <meta name="viewport" content="width=device-width,initial-scale=1">
-
-  <meta name="apple-mobile-web-app-title" content="{{ appService.getAppTitle() | preventXss }}">
-
-  {% include './widget/headers/favicon.html' %}
-
-  {{ cdnScriptTagsByGroup('basis') }}
-
-  {% include './widget/headers/scripts-for-dev.html' %}
-
-  <script src="{{ webpack_asset('js/boot.js') }}"></script>
-
-  <script src="{{ webpack_asset('js/vendors.js') }}" defer></script>
-  <script src="{{ webpack_asset('js/commons.js') }}" defer></script>
-
-  <!-- styles -->
-  {% include './widget/headers/styles-for-app.html' %}
-  {% block theme_css_block %}
-    {% include './widget/headers/styles-theme.html' with {themeName: 'default'} %}
-  {% endblock %}
-
-  {{ cdnStyleTagsByGroup('basis') }}
-
-  <script src="{{ webpack_asset('js/installer.js') }}" defer></script>
-
-</head>
-{% endblock %}
-
-{% block html_body %}
-<body
-  class="installer nologin growi"
-  {% block html_base_attr %}{% endblock %}
- >
-
-<div id="growi-context-extractor"></div>
-
-<div id="wrapper">
-
-  <!-- Page Content -->
-  <div id="page-wrapper">
-    <div class="main container-fluid">
-
-      <div class="row">
-        <div class="col-md-12">
-          <div class="login-header mx-auto">
-            <div class="logo">{% include 'widget/logo.html' %}</div>
-            <h1 class="my-3">GROWI</h1>
-
-            <div class="login-form-errors px-3">
-              {% if req.form.errors.length > 0 %}
-              <div class="alert alert-danger">
-                <ul class="mb-0">
-                {% for error in req.form.errors %}
-                  <li>{{ error }}</li>
-                {% endfor %}
-                </ul>
-              </div>
-              {% endif %}
-            </div>
-          </div>
-        </div>
-        <div class="col-md-12">
-          <div id="installer-form-container"
-            data-user-name="{{ req.body.registerForm.username }}"
-            data-name="{{ req.body.registerForm.name }}"
-            data-email="{{ req.body.registerForm.email }}">
-          </div>
-        </div>
-      </div>{# /.row #}
-
-    </div>
-  </div><!-- /#page-wrapper -->
-
-</div><!-- /#wrapper -->
-
-{% block body_end %}
-{% endblock %}
-</body>
-{% endblock %}
-
-<script type="application/json" id="growi-context-hydrate">
-{{ local_config|json|safe|preventXss }}
-</script>
-
-</html>

+ 0 - 150
packages/app/src/server/views/invited.html

@@ -1,150 +0,0 @@
-{% extends 'layout/layout.html' %}
-
-{% block html_base_css %}invited nologin{% endblock %}
-
-{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName('Registration') }}{% endblock %}
-
-
-
-{#
-  # Remove default contents
-  #}
- {% block html_head_loading_legacy %}
- {% endblock %}
- {% block html_head_loading_app %}
- {% endblock %}
- {% block layout_head_nav %}
- {% endblock %}
- {% block sidebar %}
- {% endblock %}
- {% block head_warn_alert_siteurl_undefined %}
- {% endblock %}
- {% block fixed-controls %}
- {% endblock %}
-
-
-
- {% block layout_main %}
-
-<div class="main container-fluid">
-
-  <div class="row">
-
-    <div class="login-header offset-4 col-sm-4">
-      <div class="logo">{% include 'widget/logo.html' %}</div>
-      <h1>GROWI</h1>
-
-      <div id="login-form-errors">
-        {% set errorMessages = req.flash('errorMessages') %}
-        {% if errorMessages.length > 0 %}
-        <div class="alert alert-danger">
-          <ul class="mb-0">
-          {% for error in errorMessages %}
-            <li>{{ error }}</li>
-          {% endfor %}
-          </ul>
-        </div>
-        {% endif %}
-
-        {% set message = req.flash('warningMessage') %}
-        {% if message.length %}
-        <div class="alert alert-danger">
-          {{ message }}
-        </div>
-        {% endif %}
-
-        {% if req.form.errors.length > 0 %}
-        <div class="alert alert-danger">
-          <ul>
-          {% for error in req.form.errors %}
-            <li>{{ error }}</li>
-          {% endfor %}
-          </ul>
-        </div>
-        {% endif %}
-      </div>
-    </div>
-
-    <div class="login-dialog grw-pt-10px p-b-10 offset-4 col-sm-4" id="login-dialog">
-      <p class="alert alert-success">
-        <strong>アカウントの作成</strong><br>
-        <small>招待を受け取ったメールアドレスでアカウントを作成します</small>
-      </p>
-
-      <form role="form" action="/login/activateInvited" method="post" id="invited-form">
-
-        <div class="input-group">
-          <div class="input-group-prepend">
-            <span class="input-group-text"><i class="icon-envelope"></i></span>
-          </div>
-          <input type="text" class="form-control" disabled value="{{ user.email }}">
-        </div>
-        <div class="input-group" id="input-group-username">
-          <div class="input-group-prepend">
-            <span class="input-group-text"><i class="icon-user"></i></span>
-          </div>
-          <input type="text" class="form-control" placeholder="{{ t('User ID') }}" name="invitedForm[username]" value="{{ req.body.invitedForm.username }}" required>
-        </div>
-        <p class="form-text text-muted">
-          <span id="help-block-username"></span>
-        </p>
-
-        <div class="input-group">
-          <div class="input-group-prepend">
-            <span class="input-group-text"><i class="icon-tag"></i></span>
-          </div>
-          <input type="text" class="form-control" placeholder="{{ t('Name') }}" name="invitedForm[name]" value="{{ req.body.invitedForm.name }}" required>
-        </div>
-
-
-        <div class="input-group">
-          <div class="input-group-prepend">
-            <span class="input-group-text"><i class="icon-lock"></i></span>
-          </div>
-          <input type="password" class="form-control" placeholder="{{ t('Password') }}" name="invitedForm[password]" required>
-        </div>
-
-        <div class="input-group justify-content-center d-flex mt-5">
-          <input type="hidden" name="_csrf" value="{{ req.csrfToken() }}">
-          <button type="submit" class="btn btn-fill" id="register">
-            <div class="eff"></div>
-            <span class="btn-label"><i class="icon-user-follow"></i></span>
-            <span class="btn-label-text">{{ t('Create') }}</span>
-          </button>
-        </div>
-
-        <div class="input-group mt-5 d-flex justify-content-center">
-          <a href="https://growi.org" class="link-growi-org">
-            <span class="growi">GROWI</span>.<span class="org">ORG
-          </a>
-        </div>
-      </form>
-    </div>
-
-  </div>{# /.row #}
-
-</div>{# /.main #}
-
-<script>
-$(function() {
-  $('#invited-form input[name="invitedForm[username]"]').change(function(e) {
-    var username = $(this).val();
-    $('#login-dialog').removeClass('has-error');
-    $('#input-group-username').removeClass('has-error');
-    $('#help-block-username').html("");
-
-    $.getJSON('/_api/v3/check-username', {username: username}, function(json) {
-      if (!json.valid) {
-        $('#help-block-username').html(
-          '<i class="icon-fw icon-ban"></i>このユーザーIDは利用できません。'
-        );
-        $('#login-dialog').addClass('has-error');
-        $('#input-group-username').addClass('has-error');
-      }
-    });
-  });
-});
-</script>
-
-{% endblock %}
-

+ 0 - 43
packages/app/src/server/views/layout-growi/base/layout.html

@@ -1,43 +0,0 @@
-{% extends '../../layout/layout.html' %}
-
-{% block html_additional_headers %}
-  {% parent %}
-  {{ cdnScriptTag('highlight-addons') }}
-  {{ cdnScriptTag('drawio-viewer') }}
-{% endblock %}
-
-{% block layout_main %}
-<div class="h-100 d-flex flex-column justify-content-between">
-
-  <div id="growi-context-extractor"></div>
-
-  {% block content_header_wrapper %}
-    <header class="py-0">
-      {% block content_header %}
-        <div id="grw-subnav-container"></div>
-      {% endblock %}
-    </header>
-    <div id="grw-subnav-switcher-container" class="d-edit-none"></div>
-    <div id="grw-subnav-sticky-trigger" class="sticky-top"></div>
-    <div id="grw-fav-sticky-trigger" class="sticky-top"></div>
-  {% endblock %}
-
-  <div class="flex-grow-1">
-    <div id="main" class="main {% if page %}{{ css.grant(page) }}{% endif %}">
-      {% block content_main_before %}
-      {% endblock %}
-
-      {% block content_main %}
-      {% endblock content_main %}
-
-      {% block content_main_after %}
-      {% endblock %}
-    </div>
-  </div>
-
-  <footer class="footer d-edit-none">
-    {% block content_footer %}{% endblock %}
-  </footer>
-
-</div>
-{% endblock %} {# layout_main #}

+ 0 - 24
packages/app/src/server/views/layout-growi/expired_shared_page.html

@@ -1,24 +0,0 @@
-{% extends './shared_page.html' %}
-
-{% block html_title %}
-  {{ customizeService.generateCustomTitle('Page is expired') }}
-{% endblock %}
-
-{% block content_main %}
-  <div class="container-lg">
-
-    <div
-      id="is-shared-page"
-      data-share-link-expired-at="{% if sharelink.expiredAt %}{{ sharelink.expiredAt|datetz('Y/m/d H:i:s')}}{% endif %}"
-      data-share-link-created-at="{{ sharelink.createdAt|datetz('Y/m/d H:i:s')}}"
-    >
-      <div id="share-link-alert"></div>
-
-      <h2 class="text-muted mt-4">
-        <i class="icon-ban" aria-hidden="true"></i>
-        Page is expired
-      </h2>
-    </div>
-
-  </div>
-{% endblock %}

+ 0 - 25
packages/app/src/server/views/layout-growi/forbidden.html

@@ -1,25 +0,0 @@
-{% extends 'base/layout.html' %}
-
-
-{% block content_main_before %}
-  <div class="container-lg">
-    {% include '../widget/page_alerts.html' %}
-  </div>
-{% endblock %}
-
-{% block content_main %}
-  <div
-    id="content-main"
-    class="content-main page-list"
-    data-path="{{ encodeURI(path) }}"
-    data-current-user="{% if user %}{{ user._id.toString() }}{% endif %}"
-    data-page-is-not-creatable="true"
-    >
-  </div>
-  <div class="container-lg" id="forbidden-page"></div>
-{% endblock %}
-
-{% block body_end %}
-  <div id="crowi-modals">
-  </div>
-{% endblock %}

+ 0 - 30
packages/app/src/server/views/layout-growi/identical-path-page.html

@@ -1,30 +0,0 @@
-{% extends 'base/layout.html' %}
-
-{% block content_main_before %}
-{% endblock %}
-
-
-{% block content_main %}
-  <div class="grw-container-convertible">
-
-    <div id="content-main" class="content-main d-flex"
-      data-path="{{ encodeURI(path) }}"
-      data-current-user="{% if user %}{{ user._id.toString() }}{% endif %}"
-      data-page-is-not-creatable="true"
-      data-identical-path="true"
-    >
-      <div class="flex-grow-1 flex-basis-0 mw-0">
-        <div
-          id="identical-path-page"
-          data-identical-path-pages="{{ identicalPathPages|json }}"
-        ></div>
-      </div>
-      <div id="page-context"></div>
-    </div>
-
-  </div>
-{% endblock %}
-
-{% block content_footer %}
-  <div id="page-content-footer"></div>
-{% endblock %}

+ 0 - 20
packages/app/src/server/views/layout-growi/not_creatable.html

@@ -1,20 +0,0 @@
-{% extends 'base/layout.html' %}
-
-
-{% block content_main_before %}
-  <div class="container-lg">
-    {% include '../widget/page_alerts.html' %}
-  </div>
-{% endblock %}
-
-
-{% block content_main %}
-  <div class="container-lg">
-    {% include '../widget/not_creatable_content.html' %}
-  </div>
-{% endblock %}
-
-{% block body_end %}
-  <div id="crowi-modals">
-  </div>
-{% endblock %}

+ 0 - 32
packages/app/src/server/views/layout-growi/not_found.html

@@ -1,32 +0,0 @@
-{% extends 'base/layout.html' %}
-
-{% block html_base_css %}not-found-page{% endblock %}
-
-{% block content_main_before %}
-  <div
-    id="growi-pagetree-not-found-context"
-    data-not-found-target-path-or-id="{% if notFoundTargetPathOrId %}{{notFoundTargetPathOrId|json}}{% endif %}"
-  >
-  </div>
-  <div
-    id="growi-not-found-context"
-    data-page-id="{%if pageId %}{{pageId.toString()}}{% endif %}"
-  >
-  </div>
-  <div class="grw-container-convertible">
-    {% include '../widget/page_alerts.html' %}
-  </div>
-{% endblock %}
-
-
-{% block content_main %}
-  <div class="grw-container-convertible">
-    {% include '../widget/not_found_content.html' %}
-  </div>
-{% endblock %}
-
-{% block body_end %}
-  <div id="presentation-layer" class="fullscreen-layer">
-    <div id="presentation-container"></div>
-  </div>
-{% endblock %}

+ 0 - 16
packages/app/src/server/views/layout-growi/not_found_shared_page.html

@@ -1,16 +0,0 @@
-{% extends './shared_page.html' %}
-
-{% block html_title %}
-  {{ customizeService.generateCustomTitle('Page is not found') }}
-{% endblock %}
-
-{% block content_main %}
-  <div class="container-lg">
-
-    <h2 class="text-muted mt-4">
-      <i class="icon-ban" aria-hidden="true"></i>
-      Page is not found
-    </h2>
-
-  </div>
-{% endblock %}

+ 0 - 35
packages/app/src/server/views/layout-growi/page.html

@@ -1,35 +0,0 @@
-{% extends 'base/layout.html' %}
-
-{% block html_additional_headers %}
-  {% parent %}
-
-  <!-- OGP -->
-  <meta property="og:site_name" content="{{ appService.getAppTitle() | preventXss }}" />
-  <meta property="og:title" content="{{ page.path | preventXss }}" />
-  <meta property="og:url" content="{{ appService.getSiteUrl() | preventXss }}/{{ page.id }}" />
-  <meta property="og:type" content="article" />
-  <meta property="og:image" content="{{ appService.getSiteUrl() | preventXss }}/ogp/{{ page.id }}" />
-{% endblock %}
-
-{% block content_main_before %}
-{% endblock %}
-
-
-{% block content_main %}
-  <div class="grw-container-convertible">
-
-    {% include '../widget/page_content.html' %}
-
-  </div>
-{% endblock %}
-
-{% block content_footer %}
-  {% include 'widget/comments.html' %}
-  <div id="page-content-footer"></div>
-{% endblock %}
-
-{% block body_end %}
-  <div id="presentation-layer" class="fullscreen-layer">
-    <div id="presentation-container"></div>
-  </div>
-{% endblock %}

+ 0 - 31
packages/app/src/server/views/layout-growi/page_list.html

@@ -1,31 +0,0 @@
-{% extends 'base/layout.html' %}
-
-
-{% block content_main_before %}
-{% endblock %}
-
-
-{% block content_main %}
-  <div class="grw-container-convertible">
-    {% include '../widget/page_content.html' %}
-  </div>
-{% endblock %}
-
-
-{% block content_main_after %}
-  {% if isTrashPage(path) %}
-    <div class="grw-container-convertible">
-      <div id="trash-page-list-container"></div>
-    </div>
-  {% endif %}
-{% endblock %}
-
-{% block content_footer %}
-  <div id="page-content-footer"></div>
-{% endblock %}
-
-{% block body_end %}
-  <div id="presentation-layer" class="fullscreen-layer">
-    <div id="presentation-container"></div>
-  </div>
-{% endblock %}

+ 0 - 44
packages/app/src/server/views/layout-growi/shared_page.html

@@ -1,44 +0,0 @@
-{% extends 'base/layout.html' %}
-
-{% block content_header_wrapper %}
-<header class="py-0">
-  {% block content_header %}
-    <div id="grw-subnav-container"></div>
-  {% endblock %}
-</header>
-<div id="grw-subnav-switcher-container" class="d-edit-none"></div>
-<div id="grw-subnav-sticky-trigger" class="sticky-top"></div>
-<div id="grw-fav-sticky-trigger" class="sticky-top"></div>
-{% endblock %}
-
-{% block content_main_before %}
-{% endblock %}
-{% block search %}
-{% endblock %}
-{% block head_warn_alert_siteurl_undefined %}
-{% endblock %}
-{% block sidebar %}
-{% endblock %}
-
-{% block content_main %}
-  <div class="grw-container-convertible">
-
-    <div
-      id="is-shared-page"
-      data-share-link-expired-at="{% if sharelink.expiredAt %}{{ sharelink.expiredAt|datetz('Y/m/d H:i:s')}}{% endif %}"
-      data-share-link-created-at="{{ sharelink.createdAt|datetz('Y/m/d H:i:s')}}"
-    >
-      <div id="share-link-alert"></div>
-
-      {% include '../widget/page_content.html' %}
-
-    </div>
-
-  </div>
-{% endblock %}
-
-{% block body_end %}
-  <div id="presentation-layer" class="fullscreen-layer">
-    <div id="presentation-container"></div>
-  </div>
-{% endblock %}

+ 0 - 43
packages/app/src/server/views/layout-growi/user_page.html

@@ -1,43 +0,0 @@
-{% extends 'page.html' %}
-
-{% block content_main %}
-  <div class="grw-container-convertible user-page" data-testid="grw-user-page">
-
-    {% include '../widget/page_content.html' %}
-
-  </div>
-{% endblock %}
-
-{% block content_footer %}
-  {% include 'widget/comments.html' %}
-
-  {% if page %}
-    <div class="container-lg user-page-footer py-5">
-
-      <div class="grw-user-page-list-m d-edit-none">
-        <h2 class="grw-user-page-header border-bottom pb-2 mb-3" id="bookmarks-list">
-          <i class="fa fa-fw fa-bookmark-o" style="font-size: 1.3em"></i>
-          Bookmarks
-        </h2>
-        <div class="page-list" id="user-bookmark-list">
-          <div class="page-list-container">
-          </div>
-        </div>
-      </div>
-
-      <div class="grw-user-page-list-m mt-5 d-edit-none">
-        <h2 class="grw-user-page-header border-bottom pb-2 mb-3" id="recently-created-list">
-          <i id="recent-created-icon" class="mr-1"></i>
-          Recently Created
-        </h2>
-        <div class="page-list" id="user-created-list">
-          <div class="page-list-container">
-          </div>
-        </div>
-      </div>
-
-    </div>
-  {% endif %}
-
-  <div id="page-content-footer"></div>
-{% endblock %}

+ 0 - 155
packages/app/src/server/views/layout/layout.html

@@ -1,155 +0,0 @@
-<!DOCTYPE html>
-<html>
-{% block html_head %}
-<head>
-  <meta charset="utf-8">
-  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-  <title>{% block html_title %}{{ customizeService.generateCustomTitle(page || path) }}{% endblock %}</title>
-  <meta name="description" content="">
-  <meta name="author" content="">
-
-  <meta name="viewport" content="width=device-width,initial-scale=1">
-
-  <meta name="apple-mobile-web-app-title" content="{{ appService.getAppTitle() | preventXss }}">
-
-  {{ getConfig('crowi', 'customize:header') | default('') }}
-
-  {% include '../widget/headers/favicon.html' %}
-
-  {{ cdnScriptTagsByGroup('basis') }}
-
-  {% if local_config.env.MATHJAX %}
-    {% include '../widget/headers/mathjax.html' %}
-  {% endif %}
-
-  {% include '../widget/headers/drawio.html' %}
-
-  {% include '../widget/headers/scripts-for-dev.html' %}
-
-  <script src="{{ webpack_asset('js/boot.js') }}"></script>
-
-  <script src="{{ webpack_asset('js/vendors.js') }}" defer></script>
-  <script src="{{ webpack_asset('js/commons.js') }}" defer></script>
-  {% block html_head_loading_legacy %}
-    <script src="{{ webpack_asset('js/legacy.js') }}" defer></script>
-  {% endblock %}
-  {% block html_head_loading_app %}
-    <script src="{{ webpack_asset('js/app.js') }}" defer></script>
-  {% endblock %}
-
-  <!-- styles -->
-  {% include '../widget/headers/styles-for-app.html' %}
-  {% block theme_css_block %}
-    {% set themeName = getConfig('crowi', 'customize:theme') %}
-    {% include '../widget/headers/styles-theme.html' with {themeName: themeName} %}
-  {% endblock %}
-
-  {{ cdnStyleTagsByGroup('basis') }}
-  {{ cdnHighlightJsStyleTag(getConfig('crowi', 'customize:highlightJsStyle')) }}
-
-  {% block html_additional_headers %}{% endblock %}
-
-  <style>
-    {{ customizeService.getCustomCss() }}
-  </style>
-</head>
-{% endblock %}
-
-{% block html_body %}
-{% set additionalBodyClasses = []; %}
-{% block html_additional_body_classes %}{% endblock %}
-
-{% if page.expandContentWidth !== undefined %}
-  {% set isContainerFluid = page.expandContentWidth; %}
-{% else %}
-  {% set isContainerFluid = getConfig('crowi', 'customize:isContainerFluid'); %}
-{% endif %}
-
-{% if isContainerFluid  %}
-  {% set additionalBodyClasses = additionalBodyClasses|push('growi-layout-fluid') %}
-{% endif %}
-
-<body
-  class="{% block html_base_css %}{% endblock %} growi {{ additionalBodyClasses|join(' ') }}"
-  {% block html_base_attr %}{% endblock %}
- >
-
-<div id="growi-context-extractor"></div>
-
-<div id="wrapper">
-
-  {% block layout_head_nav %}
-    <nav id="grw-navbar" class="navbar grw-navbar navbar-expand navbar-dark sticky-top mb-0 px-0"></nav>
-  {% endblock  %} {# layout_head_nav #}
-
-  {% block head_warn_breaking_changes %}{% include '../widget/alert_breaking_changes.html' %}{% endblock %}
-
-  <div id="page-wrapper" class="page-wrapper d-flex d-print-block">
-    {% block sidebar %}
-    <div id="grw-sidebar-wrapper"></div>
-    {% endblock %}
-
-    <div class="flex-fill mw-0">
-      {% block head_warn_alert_siteurl_undefined %}{% include '../widget/alert_siteurl_undefined.html' %}{% endblock %}
-      {% block layout_main %}{% endblock %}
-    </div>
-  </div>
-
-  <div id="grw-navbar-bottom-container"></div>
-
-</div><!-- /#wrapper -->
-
-{% block fixed-controls %}
-<div id="grw-fab-container" data-testid="grw-fab-container"></div>
-{% endblock %}
-
-<div id="grw-hotkeys-manager"></div>
-
-<div id="system-version"></div>
-
-<div id="page-create-modal"></div>
-<div id="page-delete-modal"></div>
-<div id="empty-trash-modal"></div>
-<div id="page-duplicate-modal"></div>
-<div id="page-rename-modal"></div>
-<div id="page-presentation-modal"></div>
-<div id="page-accessories-modal"></div>
-<div id="descendants-page-list-modal"></div>
-<div id="page-put-back-modal"></div>
-<div id="show-page-accessories-modal"></div>
-<div id="shortcuts-modal"></div>
-
-
-{% block body_end %}
-{% endblock %}
-</body>
-{% endblock %}
-
-<script type="application/json" id="growi-context-hydrate">
-{{ local_config|json|safe|preventXss }}
-</script>
-
-{% if user != null %}
-  <script type="application/json" id="growi-current-user">
-  {{ user|json|safe|preventXss }}
-  </script>
-{% endif %}
-{% if userUISettings != null %}
-  <script type="application/json" id="growi-user-ui-settings">
-  {{ userUISettings|json|safe }}
-  </script>
-{% endif %}
-{% if targetAndAncestors != null %}
-  <script type="application/json" id="growi-pagetree-target-and-ancestors">
-  {{ targetAndAncestors|json|safe }}
-  </script>
-{% endif %}
-
-
-{% block custom_script %}
-<script>
-  {{ customizeService.getCustomScript() }}
-</script>
-{% endblock %}
-
-</html>

+ 0 - 171
packages/app/src/server/views/login.html

@@ -1,171 +0,0 @@
-{% extends 'layout/layout.html' %}
-
-{% block html_base_css %}login-page nologin{% endblock %}
-
-{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('Sign in')) }}{% endblock %}
-
-
-
-{#
- # Remove default contents
- #}
-{% block html_head_loading_legacy %}
-{% endblock %}
-{% block html_head_loading_app %}
-{% endblock %}
-{% block layout_head_nav %}
-{% endblock %}
-{% block sidebar %}
-{% endblock %}
-{% block head_warn_alert_siteurl_undefined %}
-{% endblock %}
-{% block fixed-controls %}
-{% endblock %}
-
-{% block html_additional_headers %}
-  <script src="{{ webpack_asset('js/nologin.js') }}" defer></script>
-{% endblock %}
-
-{% block layout_main %}
-
-<div class="main container-fluid">
-
-  <div class="row">
-    <div class="col-md-12">
-      <div class="login-header mx-auto">
-        <div class="logo mb-3">{% include 'widget/logo.html' %}</div>
-        <h1>{{ appService.getAppTitle() | preventXss }}</h1>
-
-          <div class="login-form-errors px-3">
-            {% if isLdapSetupFailed() %}
-            <div class="alert alert-warning small">
-              <strong><i class="icon-fw icon-info"></i>LDAP is enabled but the configuration has something wrong.</strong>
-              <br>
-              (Please set the environment variables <code>DEBUG=crowi:service:PassportService</code> to get the logs)
-            </div>
-            {% endif %}
-
-            {#
-            # The case that there already exists a user whose username matches ID of the newly created LDAP user
-            # https://github.com/weseek/growi/issues/193
-            #}
-            {% set failedProviderForDuplicatedUsernameException = req.flash('provider-DuplicatedUsernameException') %}
-            {% if failedProviderForDuplicatedUsernameException != null %}
-            <div class="alert alert-warning small">
-              <p><strong><i class="icon-fw icon-ban"></i>DuplicatedUsernameException occured</strong></p>
-              <p>
-                Your {{ failedProviderForDuplicatedUsernameException }} authentication was succeess, but a new user could not be created.
-                See the issue <a href="https://github.com/weseek/growi/issues/193">#193</a>.
-              </p>
-            </div>
-            {% endif %}
-
-            {% set success = req.flash('successMessage') %}
-            {% if success.length %}
-            <div class="alert alert-success">
-              {{ success }}
-            </div>
-            {% endif %}
-
-            {% set warn = req.flash('warningMessage') %}
-            {% if warn.length %}
-            {% for w in warn %}
-            <div class="alert alert-warning">
-              {{ w }}
-            </div>
-            {% endfor %}
-            {% endif %}
-
-            {% set error = req.flash('errorMessage') %}
-            {% if error.length %}
-            {% for e in error %}
-            <div class="alert alert-danger">
-              {{ e }}
-            </div>
-            {% endfor %}
-            {% endif %}
-
-            {% set errorMessages = req.flash('errorMessages') %}
-            {% if errorMessages.length > 0 %}
-            <div class="alert alert-danger">
-              <ul class="mb-0">
-              {% for error in errorMessages %}
-                <li>{{ error }}</li>
-              {% endfor %}
-              </ul>
-            </div>
-            {% endif %}
-
-            {% if req.form.errors.length > 0 %}
-            <div class="alert alert-danger">
-              <ul class="mb-0">
-              {% for error in req.form.errors %}
-                <li>{{ error }}</li>
-              {% endfor %}
-              </ul>
-            </div>
-            {% endif %}
-          </div>
-          <div id="register-form-errors" class="px-3">
-            {% set message = req.flash('registerWarningMessage') %}
-            {% if message.length %}
-            <div class="alert alert-danger">
-              {% for msg in message %}
-              {{ msg }}<br>
-              {% endfor  %}
-            </div>
-            {% endif %}
-          </div>
-      </div>
-
-      {% set registrationMode = getConfig('crowi', 'security:registrationMode') %}
-      {% set isRegistrationEnabled = passportService.isLocalStrategySetup && registrationMode != 'Closed' %}
-      {% set isPasswordResetEnabled = getConfig('crowi', 'security:passport-local:isPasswordResetEnabled') %}
-      {% set isEmailAuthenticationEnabled = getConfig('crowi', 'security:passport-local:isEmailAuthenticationEnabled') %}
-      <div
-        id="login-form"
-        data-is-registering="{{ req.query.register or req.body.registerForm or isRegistering }}"
-        data-username ="{{ req.body.registerForm.username }}"
-        data-name ="{{ req.body.registerForm.name }}"
-        data-email ="{{ req.body.registerForm.email || req.flash('email') }}"
-        data-is-registration-enabled="{{ isRegistrationEnabled }}"
-        data-registration-mode = "{{ registrationMode }}"
-        data-registration-white-list = "{{ getConfig('crowi', 'security:registrationWhiteList') }}"
-        data-is-password-reset-enabled = "{{ isPasswordResetEnabled }}"
-        data-is-email-authentication-enabled = "{{ isEmailAuthenticationEnabled }}"
-        data-is-local-strategy-setup = "{{ passportService.isLocalStrategySetup }}"
-        data-is-ldap-strategy-setup = "{{ passportService.isLdapStrategySetup}}"
-        data-is-google-auth-enabled = "{{ getConfig('crowi', 'security:passport-google:isEnabled') }}"
-        data-is-github-auth-enabled = "{{ getConfig('crowi', 'security:passport-github:isEnabled') }}"
-        data-is-facebook-auth-enabled = "{{ getConfig('crowi', 'security:passport-facebook:isEnabled') }}"
-        data-is-saml-auth-enabled = "{{ getConfig('crowi', 'security:passport-saml:isEnabled') }}"
-        data-is-oidc-auth-enabled = "{{ getConfig('crowi', 'security:passport-oidc:isEnabled') }}"
-        data-is-basic-auth-enabled = "{{ getConfig('crowi', 'security:passport-basic:isEnabled') }}"
-      ></div>
-    </div>
-  </div>
-</div>
-
-{% endblock %}
-
-
-{% block body_end %}
-<script>
-  $('#register-form input[name="registerForm[username]"]').change(function(e) {
-    var username = $(this).val();
-    $('#login-dialog').removeClass('has-error');
-    $('#input-group-username').removeClass('has-error');
-    $('#help-block-username').html("");
-
-    $.getJSON('/_api/v3/check-username', {username: username}, function(json) {
-      if (!json.valid) {
-        $('#help-block-username').html(
-          '<i class="icon-fw icon-ban"></i> This User ID is not available.'
-        );
-        $('#login-dialog').addClass('has-error');
-        $('#input-group-username').addClass('has-error');
-      }
-    });
-  });
-</script>
-{% endblock %}

+ 0 - 40
packages/app/src/server/views/maintenance-mode.html

@@ -1,40 +0,0 @@
-{% extends './layout/layout.html' %}
-
-{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('maintenance_mode.maintenance_mode')) }}{% endblock %}
-
-
-
-{#
-  # Remove default contents
-  #}
- {% block html_head_loading_legacy %}
- {% endblock %}
- {% block layout_head_nav %}
- {% endblock %}
- {% block sidebar %}
- {% endblock %}
- {% block head_warn_alert_siteurl_undefined %}
- {% endblock %}
- {% block fixed-controls %}
- {% endblock %}
-
-
-{% block layout_main %}
-<div id="main" class="main">
-  <div id="content-main" class="content-main container-lg">
-    <div class="container">
-      <div class="row justify-content-md-center">
-        <div class="col-md-6 mt-5">
-          <div class="text-center">
-            <h1><i class="icon-exclamation large"></i></h1>
-            <h1 class="text-center">{{ t('maintenance_mode.maintenance_mode') }}</h1>
-            <h3>{{ t('maintenance_mode.growi_is_under_maintenance') }}</h3>
-            <hr />
-            <div id="maintenance-mode-content"></div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
-{% endblock %}

+ 0 - 21
packages/app/src/server/views/me/all-in-app-notifications.html

@@ -1,21 +0,0 @@
-{% extends '../layout/layout.html' %}
-
-{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('in_app_notification.notification_list')) }}{% endblock %}
-
-{% block layout_main %}
-
-{% block content_header_wrapper %}
-<header class="py-3">
-  <div class="container-fluid">
-    <h1 class="title">{{ t('in_app_notification.notification_list') }}</h1>
-  </div>
-</header>
-<div id="grw-fav-sticky-trigger" class="sticky-top"></div>
-{% endblock %}
-
-<div id="main" class="main">
-  <div id="content-main" class="content-main grw-container-convertible">
-    <div id="all-in-app-notifications"></div>
-  </div>
-</div>
-{% endblock %}

+ 0 - 21
packages/app/src/server/views/me/drafts.html

@@ -1,21 +0,0 @@
-{% extends '../layout/layout.html' %}
-
-{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('My Drafts')) }}{% endblock %}
-
-{% block layout_main %}
-
-{% block content_header_wrapper %}
-<header class="py-3">
-  <div class="container-fluid">
-    <h1 class="title">{{ t('My Drafts') }}</h1>
-  </div>
-</header>
-<div id="grw-fav-sticky-trigger" class="sticky-top"></div>
-{% endblock %}
-
-<div id="main" class="main">
-  <div id="content-main" class="content-main grw-container-convertible">
-    <div id="my-drafts"></div>
-  </div>
-</div>
-{% endblock %}

+ 0 - 21
packages/app/src/server/views/me/index.html

@@ -1,21 +0,0 @@
-{% extends '../layout/layout.html' %}
-
-{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('User Settings')) }}{% endblock %}
-
-{% block layout_main %}
-
-{% block content_header_wrapper %}
-<header class="py-3">
-  <div class="container-fluid">
-    <h1 class="title">{{ t('User Settings') }}</h1>
-  </div>
-</header>
-<div id="grw-fav-sticky-trigger" class="sticky-top"></div>
-{% endblock %}
-
-<div id="main" class="main">
-  <div id="content-main" class="content-main container-lg">
-    <div id="personal-setting"></div>
-  </div>
-</div>
-{% endblock %}

+ 0 - 64
packages/app/src/server/views/page_presentation.html

@@ -1,64 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <meta name="apple-mobile-web-app-capable" content="yes" />
-    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
-
-    {{ getConfig('crowi', 'customize:header') | default('') }}
-
-    <!-- polyfills for IE11 -->
-    <script>
-      var userAgent = window.navigator.userAgent.toLowerCase();
-      if (userAgent.indexOf('msie') != -1 || userAgent.indexOf('trident') != -1) {
-        var scriptElement = document.createElement('script');
-        scriptElement.src = 'https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.23.0/polyfill.min.js';
-        var headElement = document.getElementsByTagName('head')[0];
-        headElement.appendChild(scriptElement);
-      }
-    </script>
-
-    {{ cdnScriptTagsByGroup('basis') }}
-
-    {% if env === 'development' %}
-      <script src="{{ webpack_asset('js/dev.js') }}" async></script>
-    {% endif %}
-
-    <script src="{{ webpack_asset('js/legacy-presentation.js') }}" defer></script>
-    <link rel="stylesheet" href="{{ webpack_asset('styles/style-presentation.css') }}">
-
-    <title>{{ page.path | path2name | preventXss }} | {{ page.path | preventXss }}</title>
-
-    {{ cdnStyleTagsByGroup('basis') }}
-    {{ cdnHighlightJsStyleTag(getConfig('crowi', 'customize:highlightJsStyle')) }}
-
-    <style>
-      {{ customizeService.getCustomCss() }}
-    </style>
-  </head>
-  <body>
-    <div class="reveal">
-      <div class="slides">
-        {% set pageBreakSeparator = getConfig('markdown', 'markdown:presentation:pageBreakSeparator') | default(1) %}
-        {% set pageBreakCustomSeparator = getConfig('markdown', 'markdown:presentation:pageBreakCustomSeparator') | default('') %}
-
-        {% if 3 === pageBreakSeparator %}
-          {% set dataSeparator = pageBreakCustomSeparator %}
-        {% elseif 2 === pageBreakSeparator %}
-          {% set dataSeparator = "\n-----\n" %}
-        {% else %}
-          {% set dataSeparator = "\n\n\n" %}
-        {% endif %}
-
-        <section data-markdown data-separator="{{dataSeparator}}">
-          <script type="text/template">
-{{ revision.body|presentation|safe }}
-          </script>
-        </section>
-        <section  data-markdown># {{ t('The end') }}</section>
-      </div>
-    </div>
-
-  </body>
-</html>

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio