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

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

jam411 3 лет назад
Родитель
Сommit
93efc26188
100 измененных файлов с 288 добавлено и 3892 удалено
  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:
   - package-ecosystem: github-actions
     directory: '/'
-    open-pull-requests-limit: 0
+    open-pull-requests-limit: 3
     schedule:
       interval: monthly
     commit-message:
@@ -11,7 +11,7 @@ updates:
 
   - package-ecosystem: npm
     directory: '/'
-    open-pull-requests-limit: 0
+    open-pull-requests-limit: 3
     schedule:
       interval: weekly
     commit-message:
@@ -22,4 +22,5 @@ updates:
       - dependency-name: string-width
       - dependency-name: "@handsontable/react"
       - dependency-name: handsontable
+      - dependency-name: reveal.js
 

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

@@ -41,6 +41,10 @@ on:
         type: boolean
         default: false
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
 
 jobs:
 
@@ -57,7 +61,7 @@ jobs:
     uses: weseek/growi/.github/workflows/reusable-app-prod.yml@master
     with:
       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-config-video: ${{ inputs.cypress-config-video || false }}
     secrets:
@@ -73,7 +77,7 @@ jobs:
 
     with:
       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
     secrets:
       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/ui/**
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+
 jobs:
   lint:
     runs-on: ubuntu-latest

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

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

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

@@ -45,7 +45,7 @@ jobs:
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v1
+      uses: github/codeql-action/init@v2
       with:
         languages: ${{ matrix.language }}
         # 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).
     # If this step fails, then you should remove it and run the build manually (see below)
     - name: Autobuild
-      uses: github/codeql-action/autobuild@v1
+      uses: github/codeql-action/autobuild@v2
 
     # ℹ️ Command-line programs to run using the OS shell.
     # 📚 https://git.io/JvXDl
@@ -70,4 +70,4 @@ jobs:
     #   make release
 
     - 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:
       - master
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+
 jobs:
 
   # 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
     types: [opened, reopened, edited, synchronize]
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+
 jobs:
 
   # 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 }}
 
     - name: Authenticate to Google Cloud for GROWI.cloud
-      uses: google-github-actions/auth@v0
+      uses: google-github-actions/auth@v1
       with:
         credentials_json: '${{ secrets.GCP_SA_KEY_SLACKBOT_PROXY }}'
 
     - name: Setup gcloud
-      uses: google-github-actions/setup-gcloud@v0
+      uses: google-github-actions/setup-gcloud@v1
 
     - name: Configure docker for gcloud
       run: |
@@ -75,7 +75,7 @@ jobs:
         mv /tmp/.buildx-cache-new /tmp/.buildx-cache
 
     - name: Add tag
-      uses: anothrNick/github-tag-action@1.38.0
+      uses: anothrNick/github-tag-action@v1
       env:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         CUSTOM_TAG: v${{ steps.package-json.outputs.packageVersion }}

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

@@ -126,29 +126,17 @@ jobs:
 
     runs-on: ubuntu-latest
 
-    strategy:
-      matrix:
-        flavor: [default, nocdn]
-
     steps:
     - uses: actions/checkout@v3
       with:
         ref: v${{ needs.create-github-release.outputs.RELEASED_VERSION }}
         lfs: true
 
-    - name: Setup suffix
-      id: suffix
-      run: |
-        [[ ${{ matrix.flavor }} = "nocdn" ]] && suffix="-nocdn" || suffix=""
-        echo "SUFFIX=$suffix" >> $GITHUB_OUTPUT
-
     - name: Docker meta
       id: meta
       uses: docker/metadata-action@v4
       with:
         images: weseek/growi,ghcr.io/weseek/growi
-        flavor: |
-          suffix=${{ steps.suffix.outputs.SUFFIX }}
         tags: |
           type=raw,value=latest
           type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}
@@ -178,8 +166,6 @@ jobs:
         file: ./packages/app/docker/Dockerfile
         platforms: linux/amd64
         push: true
-        build-args: |
-          flavor=${{ matrix.flavor }}
         builder: ${{ steps.buildx.outputs.name }}
         cache-from: type=gha
         cache-to: type=gha,mode=max
@@ -198,7 +184,7 @@ jobs:
       with:
         channel: '#release'
         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
       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
 
-ARG flavor=default
-
 
 ##
 ## 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
 
@@ -80,20 +78,11 @@ RUN tar -xf 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
 ##
-FROM prebuilder-${flavor} AS builder
+FROM prebuilder AS builder
 
 ENV optDir /opt
 

+ 1 - 4
packages/app/package.json

@@ -9,7 +9,7 @@
     "build:client": "yarn next build",
     "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",
-    "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",
     "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",
@@ -100,7 +100,6 @@
     "diff": "^5.0.0",
     "diff_match_patch": "^0.1.1",
     "ejs": "^3.1.8",
-    "entities": "^2.0.0",
     "esa-node": "^0.2.2",
     "escape-string-regexp": "=4.0.0",
     "eslint-plugin-regex": "^1.8.0",
@@ -110,7 +109,6 @@
     "express-mongo-sanitize": "^2.1.0",
     "express-session": "^1.16.1",
     "express-validator": "^6.14.0",
-    "express-webpack-assets": "^0.1.0",
     "extensible-custom-error": "^0.0.7",
     "graceful-fs": "^4.1.11",
     "hast-util-select": "^5.0.2",
@@ -182,7 +180,6 @@
     "string-width": "=4.2.2",
     "superjson": "^1.9.1",
     "swagger-jsdoc": "^6.1.0",
-    "swig-templates": "^2.0.2",
     "swr": "^1.3.0",
     "throttle-debounce": "^3.0.1",
     "toastr": "^2.1.2",

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

@@ -60,6 +60,7 @@
   "Presentation Mode": "Presentation",
   "The end": "The end",
   "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 bookmarked yet": "No users have bookmarked yet",

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

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

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

@@ -56,7 +56,8 @@
   "No_attachments_yet": "暂无附件",
 	"Presentation Mode": "演示文稿",
   "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 bookmarked yet": "还没有用户加入书签",
   "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:
 
-Email: {{ email }}
-Password: {{ password }}
+Email: <%- email -%>
+Password: <%- password -%>
 (This password was auto generated. Update required at the first time you logging in)
 
 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:
 
-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:
-{{ 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
 
-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.
 
 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
 
-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.
 
-{{ 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.

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

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

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

@@ -1,12 +1,12 @@
 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.
 
-{{ 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.

+ 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:
 
-Email: {{ email }}
-Password: {{ password }}
+Email: <%- email -%>
+Password: <%- password -%>
 (This password was auto generated. Update required at the first time you logging in)
 
 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:
 
-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:
-{{ 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アドレスで再度お試しください。
 
 もしこのリクエストに心当たりがない場合は、このメールを無視してください。
 
 -------------------------------------------------------------------------
 
-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:
 
-Email: {{ email }}
-Password: {{ password }}
+Email: <%- email -%>
+Password: <%- password -%>
 (This password was auto generated. Update required at the first time you logging in)
 
 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:
 
-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:
-{{ 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 }}失效。
 

+ 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 PresentationIcon from '../Icons/PresentationIcon';
 import ShareLinkIcon from '../Icons/ShareLinkIcon';
+import { NotAvailableForNow } from '../NotAvailableForNow';
 import { Skeleton } from '../Skeleton';
 
 import type { AuthorInfoProps } from './AuthorInfo';
@@ -86,16 +87,18 @@ const PageOperationMenuItems = (props: PageOperationMenuItemsProps): JSX.Element
   return (
     <>
       {/* 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 */}
       <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 { useTranslation } from 'next-i18next';
-import { Disable } from 'react-disable';
-import { UncontrolledTooltip } from 'reactstrap';
 
 import { useIsGuestUser } from '~/stores/context';
 
+import { NotAvailable } from './NotAvailable';
+
+
 type NotAvailableForGuestProps = {
   children: JSX.Element
 }
 
-export const NotAvailableForGuest = ({ children }: NotAvailableForGuestProps): JSX.Element => {
+export const NotAvailableForGuest = React.memo(({ children }: NotAvailableForGuestProps): JSX.Element => {
   const { t } = useTranslation();
-
   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 (
-    <>
-      <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';
 
-const swig = require('swig-templates');
-
 const logger = loggerFactory('growi:crowi:dev');
 
 
@@ -99,33 +97,6 @@ class CrowiDev {
     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) {
     const next = nextFactory(this.crowi);
     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 mongoose from 'mongoose';
 
-import { i18n, localePath } from '^/config/next-i18next.config';
-
 import loggerFactory from '~/utils/logger';
 import { resolveFromRoot } from '~/utils/project-dir-utils';
 
@@ -22,12 +20,6 @@ module.exports = function(crowi, app) {
   const expressSession = require('express-session');
   const flash = require('connect-flash');
   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 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 avoidSessionRoutes = require('../routes/avoid-session-routes');
-  // const i18nUserSettingDetector = require('../util/i18nUserSettingDetector');
 
   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());
 
 
@@ -122,10 +90,6 @@ module.exports = function(crowi, app) {
   ));
   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());
 
   // inject rawBody to req
@@ -173,11 +137,6 @@ module.exports = function(crowi, app) {
   app.use(injectCurrentuserToLocalvars);
   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.
   //       For now, req.t returns string given to req.t(string)
   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 */
 
 const logger = loggerFactory('growi:routes:hackmd');
-const path = require('path');
 
 const hackmdFiles = require('@growi/hackmd');
 const axios = require('axios');
 const ejs = require('ejs');
-const fs = require('graceful-fs');
-const swig = require('swig-templates');
 
 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
       // prevent from unexpecting attack doing unzip file (path traversal attack)
       // FOR EXAMPLE
-      // ../../src/server/views/admin/markdown.html
+      // ../../src/server/example.html
       if (fileName.match(/(\.\.\/|\.\.\\)/)) {
         logger.error('File path is not appropriate.', fileName);
         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 swig from 'swig-templates';
 
 import loggerFactory from '~/utils/logger';
 
 import S2sMessage from '../models/vo/s2s-message';
+
 import { S2sMessageHandlable } from './s2s-messaging/handlable';
 
 const logger = loggerFactory('growi:service:mail');
 
+
 type MailConfig = {
   to?: 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.');
     }
 
+    const renderFilePromisified = promisify(ejs.renderFile);
+
     const templateVars = config.vars || {};
-    const output = await swig.renderFile(
+    const output = await renderFilePromisified(
       config.template,
       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>

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