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

Merge branch 'master' of https://github.com/weseek/growi into imprv/gw5979-update-socket.io-4.0

* 'master' of https://github.com/weseek/growi: (223 commits)
  update debug settings
  remove unnecessary lines
  fix npm scripts
  organize npm scripts for linting and testing
  rename test script
  fix dependencies for migration
  fix dependencies for migration
  bugfix of npm scripts
  organize npm scripts
  fix migration scripts
  add typecheck when ci
  update ci settings
  use dotenv-flow
  mv env files
  mv swagger-jsdoc to dependencies
  mv dist dir after build
  fix tsconfig
  fix build server settings
  fix ci settings
  revert config/logger
  ...

# Conflicts:
#	yarn.lock

** Resolve Conflict By Master HEAD (by Theirs)
Luqman Grune 4 лет назад
Родитель
Сommit
6d8abbbe4e
100 измененных файлов с 549 добавлено и 461 удалено
  1. 1 9
      .eslintignore
  2. 8 15
      .eslintrc.js
  3. 5 8
      .github/workflows/ci-slackbot-proxy.yml
  4. 28 23
      .github/workflows/ci.yml
  5. 0 30
      .gitignore
  6. 0 4
      .stylelintrc.json
  7. 7 6
      .vscode/launch.json
  8. 0 19
      .vscode/tasks.json
  9. 3 1
      CHANGES.md
  10. 5 7
      README.md
  11. 5 7
      README_JP.md
  12. 0 43
      app.json
  13. 0 39
      babel.config.js
  14. 0 26
      config/env.dev.js
  15. 0 4
      config/env.prod.js
  16. 0 13
      config/index.js
  17. 18 58
      package.json
  18. 27 0
      packages/app/.env.development
  19. 5 0
      packages/app/.env.production
  20. 5 0
      packages/app/.eslintignore
  21. 35 0
      packages/app/.eslintrc.js
  22. 21 0
      packages/app/.gitignore
  23. 0 0
      packages/app/.prettierignore
  24. 19 0
      packages/app/.stylelintrc.json
  25. 158 0
      packages/app/bin/cdn/cdn-resources-downloader.ts
  26. 6 8
      packages/app/bin/download-cdn-resources.ts
  27. 17 12
      packages/app/bin/generate-plugin-definitions-source.ts
  28. 0 0
      packages/app/bin/github-actions/update-readme.sh
  29. 2 0
      packages/app/bin/shrink-emojione-strategy.js
  30. 0 0
      packages/app/bin/templates/plugin-definitions.js.swig
  31. 8 0
      packages/app/config/cdn.js
  32. 2 0
      packages/app/config/ci/.env.local.for-ci
  33. 0 0
      packages/app/config/logger/config.dev.js
  34. 0 0
      packages/app/config/logger/config.prod.js
  35. 1 3
      packages/app/config/migrate.js
  36. 0 0
      packages/app/config/swagger-definition.js
  37. 54 53
      packages/app/config/webpack.common.js
  38. 4 4
      packages/app/config/webpack.dev.dll.js
  39. 7 7
      packages/app/config/webpack.dev.js
  40. 10 10
      packages/app/config/webpack.prod.js
  41. 0 0
      packages/app/docker/Dockerfile
  42. 0 0
      packages/app/docker/README.md
  43. 0 0
      packages/app/docker/docker-entrypoint.sh
  44. 0 0
      packages/app/docker/nocdn/env.prod.js
  45. 23 17
      packages/app/jest.config.js
  46. 65 35
      packages/app/package.json
  47. 0 0
      packages/app/public/favicon.ico
  48. 0 0
      packages/app/public/images/customize-settings/default-dark.svg
  49. 0 0
      packages/app/public/images/customize-settings/default-light.svg
  50. 0 0
      packages/app/public/images/customize-settings/fluid-dark.svg
  51. 0 0
      packages/app/public/images/customize-settings/fluid-light.svg
  52. 0 0
      packages/app/public/images/file-not-found.png
  53. 0 0
      packages/app/public/images/icons/editor/bold.svg
  54. 0 0
      packages/app/public/images/icons/editor/check.svg
  55. 0 0
      packages/app/public/images/icons/editor/code.svg
  56. 0 0
      packages/app/public/images/icons/editor/header.svg
  57. 0 0
      packages/app/public/images/icons/editor/italic.svg
  58. 0 0
      packages/app/public/images/icons/editor/link.svg
  59. 0 0
      packages/app/public/images/icons/editor/list-ol.svg
  60. 0 0
      packages/app/public/images/icons/editor/list-ul.svg
  61. 0 0
      packages/app/public/images/icons/editor/picture.svg
  62. 0 0
      packages/app/public/images/icons/editor/quote.svg
  63. 0 0
      packages/app/public/images/icons/editor/strikethrough.svg
  64. 0 0
      packages/app/public/images/icons/editor/table.svg
  65. 0 0
      packages/app/public/images/icons/emacs.png
  66. 0 0
      packages/app/public/images/icons/favicon/android-icon-144x144.png
  67. 0 0
      packages/app/public/images/icons/favicon/android-icon-192x192.png
  68. 0 0
      packages/app/public/images/icons/favicon/android-icon-36x36.png
  69. 0 0
      packages/app/public/images/icons/favicon/android-icon-48x48.png
  70. 0 0
      packages/app/public/images/icons/favicon/android-icon-72x72.png
  71. 0 0
      packages/app/public/images/icons/favicon/android-icon-96x96.png
  72. 0 0
      packages/app/public/images/icons/favicon/apple-icon-114x114.png
  73. 0 0
      packages/app/public/images/icons/favicon/apple-icon-120x120.png
  74. 0 0
      packages/app/public/images/icons/favicon/apple-icon-144x144.png
  75. 0 0
      packages/app/public/images/icons/favicon/apple-icon-152x152.png
  76. 0 0
      packages/app/public/images/icons/favicon/apple-icon-180x180.png
  77. 0 0
      packages/app/public/images/icons/favicon/apple-icon-57x57.png
  78. 0 0
      packages/app/public/images/icons/favicon/apple-icon-60x60.png
  79. 0 0
      packages/app/public/images/icons/favicon/apple-icon-72x72.png
  80. 0 0
      packages/app/public/images/icons/favicon/apple-icon-76x76.png
  81. 0 0
      packages/app/public/images/icons/favicon/apple-icon-precomposed.png
  82. 0 0
      packages/app/public/images/icons/favicon/apple-icon.png
  83. 0 0
      packages/app/public/images/icons/favicon/browserconfig.xml
  84. 0 0
      packages/app/public/images/icons/favicon/favicon-16x16.png
  85. 0 0
      packages/app/public/images/icons/favicon/favicon-32x32.png
  86. 0 0
      packages/app/public/images/icons/favicon/favicon-96x96.png
  87. 0 0
      packages/app/public/images/icons/favicon/manifest.json
  88. 0 0
      packages/app/public/images/icons/favicon/ms-icon-144x144.png
  89. 0 0
      packages/app/public/images/icons/favicon/ms-icon-150x150.png
  90. 0 0
      packages/app/public/images/icons/favicon/ms-icon-310x310.png
  91. 0 0
      packages/app/public/images/icons/favicon/ms-icon-70x70.png
  92. 0 0
      packages/app/public/images/icons/fx.svg
  93. 0 0
      packages/app/public/images/icons/slack/mark-color.svg
  94. 0 0
      packages/app/public/images/icons/slack/mark-monochrome_black.svg
  95. 0 0
      packages/app/public/images/icons/slack/mark-monochrome_white.svg
  96. 0 0
      packages/app/public/images/icons/slack/slack-logo-dark-off.svg
  97. 0 0
      packages/app/public/images/icons/slack/slack-logo-dark-on.svg
  98. 0 0
      packages/app/public/images/icons/slack/slack-logo-off.svg
  99. 0 0
      packages/app/public/images/icons/slack/slack-logo-on.svg
  100. 0 0
      packages/app/public/images/icons/sublime.png

+ 1 - 9
.eslintignore

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

+ 8 - 15
.eslintrc.js

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

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

@@ -6,12 +6,6 @@ on:
       - release/**
       - rc/**
       - tmp/**
-    paths:
-      - .github/workflows/ci-slackbot-proxy.yml
-      - packages/slack/**
-      - packages/slackbot-proxy/**
-      - package.json
-      - yarn.lock
 
 jobs:
 
@@ -55,9 +49,12 @@ jobs:
         echo -n "node " && node -v
         echo -n "npm " && npm -v
         yarn list --depth=0
+    - name: yarn lint
+      run: |
+        yarn lerna run lint --scope @growi/slack --scope @growi/slackbot-proxy
     - name: yarn test
       run: |
-        yarn lerna run test
+        yarn lerna run test --scope @growi/slack --scope @growi/slackbot-proxy
 
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
@@ -202,7 +199,7 @@ jobs:
         yarn list --depth=0
     - name: lerna run build
       run: |
-        yarn lerna run build
+        yarn lerna run build --scope @growi/slack --scope @growi/slackbot-proxy
     - name: lerna bootstrap --production
       run: |
         npx lerna bootstrap -- --production

+ 28 - 23
.github/workflows/ci.yml

@@ -6,17 +6,6 @@ on:
       - release/**
       - rc/**
       - tmp/**
-    paths:
-      - .github/workflows/ci.yml
-      - packages/app/**
-      - .eslint*
-      - .prettier*
-      - .stylelint*
-      - config/**
-      - resource/**
-      - src/**
-      - package.json
-      - yarn.lock
 
 jobs:
 
@@ -60,9 +49,12 @@ jobs:
         echo -n "node " && node -v
         echo -n "npm " && npm -v
         yarn list --depth=0
-    - name: yarn lint
+    - name: lerna run lint for plugins
       run: |
-        yarn lint
+        yarn lerna run lint --scope @growi/plugin-pukiwiki-like-linker
+    - name: lerna run lint for app
+      run: |
+        yarn lerna run lint --scope @growi/app
 
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
@@ -126,11 +118,13 @@ jobs:
         echo -n "npm " && npm -v
         yarn list --depth=0
     - name: yarn test
+      working-directory: ./packages/app
       run: |
         yarn test
       env:
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi_test
     - name: yarn test with MongoDB 3.6
+      working-directory: ./packages/app
       run: |
         yarn test
       env:
@@ -147,13 +141,19 @@ jobs:
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
-  build-dev:
+  launch-dev:
     runs-on: ubuntu-latest
 
     strategy:
       matrix:
         node-version: [14.x]
 
+    services:
+      mongodb:
+        image: mongo:4.4
+        ports:
+        - 27017/tcp
+
     steps:
     - uses: actions/checkout@v2
     - name: Use Node.js ${{ matrix.node-version }}
@@ -203,9 +203,13 @@ jobs:
         echo -n "node " && node -v
         echo -n "npm " && npm -v
         yarn list --depth=0
-    - name: yarn build:dev
+    - name: yarn dev:ci
+      working-directory: ./packages/app
       run: |
-        yarn build:dev
+        cp config/ci/.env.local.for-ci .env.local
+        yarn dev:ci
+      env:
+        MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi_dev
 
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
@@ -218,7 +222,7 @@ jobs:
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
-  build-prod:
+  launch-prod:
     runs-on: ubuntu-latest
 
     strategy:
@@ -277,8 +281,7 @@ jobs:
         yarn list --depth=0
     - name: Build
       run: |
-        yarn lerna run build --scope @growi/slack
-        yarn lerna run build --scope @growi/app
+        yarn lerna run build --scope @growi/slack --scope @growi/app
     - name: lerna bootstrap --production
       run: |
         npx lerna bootstrap -- --production
@@ -291,14 +294,16 @@ jobs:
       id: getdbname
       run: |
         echo ::set-output name=suffix::$(echo '${{ matrix.node-version }}' | sed s/\\.//)
-    - name: yarn server:prod:ci
+    - name: yarn server:ci
+      working-directory: ./packages/app
       run: |
-        yarn server:prod:ci
+        yarn server:ci
       env:
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi-${{ steps.getdbname.outputs.suffix }}
-    - name: yarn server:prod:ci with MongoDB 3.6
+    - name: yarn server:ci with MongoDB 3.6
+      working-directory: ./packages/app
       run: |
-        yarn server:prod:ci
+        yarn server:ci
       env:
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb36.ports['27017'] }}/growi-${{ steps.getdbname.outputs.suffix }}
     - name: Upload report as artifact

+ 0 - 30
.gitignore

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

+ 0 - 4
.stylelintrc.json

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

+ 7 - 6
.vscode/launch.json

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

+ 0 - 19
.vscode/tasks.json

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

+ 3 - 1
CHANGES.md

@@ -2,9 +2,11 @@
 
 ## v4.3.3-RC
 
-*
 * Support: Upgrade libs
+    * @slack/web-api
     * escape-string-regexp
+    * morgan
+
 ## v4.3.2
 
 * Feature: Hufflpuff theme

+ 5 - 7
README.md

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

+ 5 - 7
README_JP.md

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

+ 0 - 43
app.json

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

+ 0 - 39
babel.config.js

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

+ 0 - 26
config/env.dev.js

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

+ 0 - 4
config/env.prod.js

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

+ 0 - 13
config/index.js

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

+ 18 - 58
package.json

@@ -25,71 +25,31 @@
     "nohoist": ["**/slackbot-proxy/bootstrap"]
   },
   "scripts": {
-    "build:api:jsdoc": "swagger-jsdoc -o tmp/swagger.json -d config/swagger-definition.js",
-    "build:apiv3:jsdoc": "cross-env API_VERSION=3 npm run build:api:jsdoc -- \"src/server/routes/apiv3/**/*.js\" \"src/server/models/**/*.js\"",
-    "build:apiv1:jsdoc": "cross-env API_VERSION=1 npm run build:api:jsdoc -- \"src/server/*/*.js\" \"src/server/models/**/*.js\"",
-    "build:dev:app:watch": "npm run build:dev:app -- --watch",
-    "build:dev:app:watch:poll": "npm run build:dev:app -- --watch --watch-poll",
-    "build:dev:app": "env-cmd -f config/env.dev.js webpack --config config/webpack.dev.js --progress",
-    "build:dev:watch": "npm run build:dev:app:watch",
-    "build:dev:watch:poll": "npm run build:dev:app:watch:poll",
-    "build:dev": "yarn build:dev:app",
-    "build:prod": "yarn lerna run build --scope @growi/app --scope @growi/slack",
-    "build:slack": "lerna run build --scope @growi/slack",
-    "build": "npm run build:dev:watch",
-    "build:poll": "npm run build:dev:watch:poll",
-    "clean:app": "rimraf -- public/js public/styles",
-    "clean:report": "rimraf -- report",
-    "clean": "npm-run-all -p clean:*",
-    "console": "env-cmd -f config/env.dev.js node --experimental-repl-await src/server/console.js",
-    "lint:js:fix": "eslint \"**/*.{js,jsx}\" --fix",
-    "lint:js": "eslint \"**/*.{js,jsx}\"",
-    "lint:styles:fix": "stylelint --fix src/client/styles/scss/**/*.scss",
-    "lint:styles": "stylelint src/client/styles/scss/**/*.scss",
-    "lint:swagger2openapi": "node node_modules/swagger2openapi/oas-validate tmp/swagger.json",
-    "lint": "npm-run-all -p lint:js lint:styles lint:swagger2openapi",
-    "migrate": "npm run migrate:up",
-    "migrate:create": "migrate-mongo create -f config/migrate.js -- ",
-    "migrate:status": "migrate-mongo status -f config/migrate.js",
-    "migrate:up": "migrate-mongo up -f config/migrate.js",
-    "migrate:down": "migrate-mongo down -f config/migrate.js",
-    "plugin:def": "node bin/generate-plugin-definitions-source.js",
-    "prebuild:dev:watch": "npm run prebuild:dev",
-    "prebuild:dev": "npm run clean:app && env-cmd -f config/env.dev.js npm run plugin:def && env-cmd -f config/env.dev.js npm run resource && yarn build:slack",
-    "prelint:swagger2openapi": "npm run build:apiv3:jsdoc",
-    "preserver:prod": "npm run migrate",
-    "prestart": "npm run build:prod",
-    "resource": "node bin/download-cdn-resources.js",
-    "i18n-json-merge:withTran": "rs-i18n -lan -- -t",
-    "i18n-json-merge:noTran": "rs-i18n -lan --",
-    "i18n-json-merge": "npm run i18n-json-merge:withTran --",
-    "server:nolazy": "env-cmd -f config/env.dev.js node-dev --nolazy --inspect src/server/app.js",
-    "server:dev": "env-cmd -f config/env.dev.js node-dev --expose_gc --inspect src/server/app.js",
-    "server:prod:ci": "npm run server:prod -- --ci",
-    "server:prod": "env-cmd -f config/env.prod.js node --expose_gc src/server/app.js",
-    "server": "npm run server:dev",
-    "start": "npm run server:prod",
-    "test": "jest --config=config/jest.config.js --passWithNoTests -- ",
+    "start": "yarn app:server",
+    "prestart": "yarn app:build",
+    "app:build": "yarn lerna run build --scope @growi/app --scope @growi/slack --scope @growi/plugin-pukiwiki-like-linker",
+    "app:server": "yarn lerna run server --scope @growi/app",
+    "slackbot-proxy:build": "yarn lerna run build --scope @growi/slackbot-proxy --scope @growi/slack",
+    "slackbot-proxy:server": "yarn lerna run start:prod --scope @growi/slackbot-proxy",
     "version": "node -p \"require('./package.json').version\"",
-    "webpack": "webpack"
+    "//// scripts for backward compatibility": "",
+    "build:prod": "echo !!! CAUTION !!! ==> The script 'build:prod' is deprecated. Use 'yarn app:build' instead. && yarn app:build",
+    "server:prod": "echo !!! CAUTION !!! ==> The script 'server:prod' is deprecated. Use 'yarn app:build' instead. && yarn app:server"
   },
   "dependencies": {
   },
   "devDependencies": {
+    "@typescript-eslint/eslint-plugin": "^4.28.5",
+    "@typescript-eslint/parser": "^4.28.5",
+    "eslint": "^7.31.0",
+    "eslint-config-weseek": "^1.1.0",
+    "eslint-import-resolver-typescript": "^2.4.0",
+    "eslint-plugin-import": "^2.23.4",
+    "eslint-plugin-jest": "^24.3.2",
+    "eslint-plugin-react": "^7.24.0",
+    "eslint-plugin-react-hooks": "^4.2.0",
     "lerna": "^4.0.0"
   },
-  "_moduleAliases": {
-    "@root": ".",
-    "@commons": "src/lib",
-    "@server": "src/server",
-    "@alias/logger": "src/lib/service/logger",
-    "debug": "src/lib/service/logger/alias-for-debug"
-  },
-  "jest": {
-    "moduleNameMapper": {
-      "@commons/(.*)": "<rootDir>/src/lib/$1"
-    }
-  },
   "engines": {
     "node": "^12 || ^14",
     "npm": ">=6.11.3 <7",

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

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

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

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

+ 5 - 0
packages/app/.eslintignore

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

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

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

+ 21 - 0
packages/app/.gitignore

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

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


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

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

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

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

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

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

+ 17 - 12
bin/generate-plugin-definitions-source.js → packages/app/bin/generate-plugin-definitions-source.ts

@@ -3,24 +3,24 @@
  *
  * @author Yuki Takei <yuki@weseek.co.jp>
  */
-require('module-alias/register');
-const logger = require('@alias/logger')('growi:bin:generate-plugin-definitions-source');
+import fs from 'graceful-fs';
+import normalize from 'normalize-path';
+import swig from 'swig-templates';
 
-const fs = require('graceful-fs');
-const normalize = require('normalize-path');
-const swig = require('swig-templates');
+import PluginUtils from '../src/server/plugins/plugin-utils';
+import loggerFactory from '../src/utils/logger';
+import { resolveFromRoot } from '../src/utils/project-dir-utils';
 
-const helpers = require('@commons/util/helpers');
-const PluginUtils = require('@server/plugins/plugin-utils');
+const logger = loggerFactory('growi:bin:generate-plugin-definitions-source');
 
-const pluginUtils = new PluginUtils();
 
-const TEMPLATE = helpers.root('bin/templates/plugin-definitions.js.swig');
-const OUT = helpers.root('tmp/plugins/plugin-definitions.js');
+const pluginUtils = new PluginUtils();
 
+const TEMPLATE = resolveFromRoot('bin/templates/plugin-definitions.js.swig');
+const OUT = resolveFromRoot('tmp/plugins/plugin-definitions.js');
 
 // list plugin names
-const pluginNames = pluginUtils.listPluginNames(helpers.root());
+const pluginNames: string[] = pluginUtils.listPluginNames();
 logger.info('Detected plugins: ', pluginNames);
 
 // get definitions
@@ -29,12 +29,17 @@ const definitions = pluginNames
     return pluginUtils.generatePluginDefinition(name, true);
   })
   .map((definition) => {
+    if (definition == null) {
+      return null;
+    }
+
     // convert backslash to slash
     definition.entries = definition.entries.map((entryPath) => {
       return normalize(entryPath);
     });
     return definition;
-  });
+  })
+  .filter(definition => definition != null);
 
 const compiledTemplate = swig.compileFile(TEMPLATE);
 const code = compiledTemplate({ definitions });

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


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

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

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


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

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

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

@@ -0,0 +1,2 @@
+# disable Elasticsearch
+ELASTICSEARCH_URI=

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


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


+ 1 - 3
config/migrate.js → packages/app/config/migrate.js

@@ -5,11 +5,9 @@
  * @author Yuki Takei <yuki@weseek.co.jp>
  */
 
-require('module-alias/register');
-
 const { URL } = require('url');
 
-const { getMongoUri } = require('@commons/util/mongoose-utils');
+const { getMongoUri } = require('~/server/util/mongoose-utils');
 
 const mongoUri = getMongoUri();
 

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


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

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

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

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

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

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

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

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

+ 0 - 0
docker/Dockerfile → packages/app/docker/Dockerfile


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


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


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


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

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

+ 65 - 35
packages/app/package.json

@@ -1,23 +1,66 @@
 {
   "name": "@growi/app",
-  "version": "0.9.0-RC",
+  "version": "4.3.3-RC",
   "license": "MIT",
   "scripts": {
-    "build": "cd ../../ && env-cmd -f config/env.prod.js webpack --config config/webpack.prod.js --profile --bail",
-    "prebuild": "cd ../../ && yarn plugin:def && yarn resource"
+    "//// for production": "",
+    "start": "yarn build && yarn server",
+    "build": "run-p build:*",
+    "build:client": "cross-env NODE_ENV=production webpack --config config/webpack.prod.js --profile --bail",
+    "build:server": "cross-env NODE_ENV=production tsc -p tsconfig.build.server.json && tsc-alias -p tsconfig.build.server.json",
+    "prebuild": "run-p resources:*",
+    "postbuild": "npx shx mv transpiled/src dist && npx shx rm -r transpiled",
+    "server": "cross-env NODE_ENV=production node -r dotenv-flow/config --expose_gc dist/server/app.js",
+    "server:ci": "yarn server --ci",
+    "preserver": "yarn migrate",
+    "//// for development": "",
+    "dev": "run-p dev:client dev:server",
+    "dev:client": "cross-env NODE_ENV=development webpack --config config/webpack.dev.js --progress --watch",
+    "dev:client:nowatch": "cross-env NODE_ENV=development webpack --config config/webpack.dev.js",
+    "dev:server": "cross-env NODE_ENV=development yarn ts-node-dev src/server/app.ts --expose_gc --inspect",
+    "predev:client": "run-p resources:*",
+    "predev:server": "yarn migrate",
+    "//// for CI": "",
+    "dev:ci": "yarn dev:client:nowatch && yarn dev:server --ci",
+    "predev:ci": "run-p resources:*",
+    "lint:typecheck": "npx tsc",
+    "lint:eslint": "eslint --quiet \"**/*.{js,jsx,ts,tsx}\"",
+    "lint:styles": "stylelint src/**/*.scss",
+    "lint:swagger2openapi": "node node_modules/.bin/oas-validate tmp/swagger.json",
+    "lint": "run-p lint:*",
+    "test": "cross-env NODE_ENV=test jest --passWithNoTests -- ",
+    "prelint:eslint": "yarn resources:plugin",
+    "prelint:swagger2openapi": "yarn openapi:v3",
+    "//// misc": "",
+    "console": "cross-env NODE_ENV=development yarn ts-node --experimental-repl-await src/server/console.js",
+    "swagger-jsdoc": "swagger-jsdoc -o tmp/swagger.json -d config/swagger-definition.js",
+    "openapi:v3": "cross-env API_VERSION=3 yarn swagger-jsdoc -- \"src/server/routes/apiv3/**/*.js\" \"src/server/models/**/*.js\"",
+    "openapi:v1": "cross-env API_VERSION=1 yarn swagger-jsdoc -- \"src/server/*/*.js\" \"src/server/models/**/*.js\"",
+    "resources:plugin": "yarn ts-node bin/generate-plugin-definitions-source.ts",
+    "resources:dl-resources": "yarn ts-node bin/download-cdn-resources.ts",
+    "migrate": "yarn migrate:up",
+    "migrate:create": "yarn ts-node node_modules/.bin/migrate-mongo create -f config/migrate.js",
+    "migrate:status": "yarn ts-node node_modules/.bin/migrate-mongo status -f config/migrate.js",
+    "migrate:up": "yarn ts-node node_modules/.bin/migrate-mongo up -f config/migrate.js",
+    "migrate:down": "yarn ts-node node_modules/.bin/migrate-mongo down -f config/migrate.js",
+    "ts-node": "ts-node -r tsconfig-paths/register -r dotenv-flow/config --transpile-only",
+    "ts-node-dev": "ts-node-dev -r tsconfig-paths/register -r dotenv-flow/config --transpile-only"
   },
   "// comments for dependencies": {
     "openid-client": "Node.js 12 or higher is required for openid-client@3 and above.",
-    "string-width": "5.0.0 or above uses ESM."
+    "escape-string-regexp": "5.0.0 or above exports only ESM",
+    "string-width": "5.0.0 or above exports only ESM."
   },
   "dependencies": {
+    "@browser-bunyan/console-formatted-stream": "^1.6.2",
     "@google-cloud/storage": "^5.8.5",
-    "@growi/slack": "^0.9.0-RC",
+    "@growi/plugin-pukiwiki-like-linker": "^4.3.3-RC",
+    "@growi/slack": "^4.3.3-RC",
     "@kobalab/socket.io-session": "^1.0.3",
     "@promster/express": "^5.0.1",
     "@promster/server": "^6.0.0",
     "@slack/events-api": "^3.0.0",
-    "@slack/web-api": "^6.2.3",
+    "@slack/web-api": "^6.2.4",
     "@slack/webhook": "^6.0.0",
     "JSONStream": "^1.3.5",
     "archiver": "^5.3.0",
@@ -28,7 +71,6 @@
     "body-parser": "^1.18.2",
     "browser-bunyan": "^1.6.3",
     "bunyan": "^1.8.15",
-    "bunyan-format": "^0.2.1",
     "check-node-version": "^4.1.0",
     "connect-flash": "~0.1.1",
     "connect-mongo": "^4.4.1",
@@ -39,11 +81,11 @@
     "date-fns": "^2.0.0",
     "detect-indent": "^6.0.0",
     "diff": "^5.0.0",
+    "dotenv-flow": "^3.2.0",
     "elasticsearch": "^16.0.0",
     "entities": "^2.0.0",
-    "env-cmd": "^10.0.1",
     "esa-nodejs": "^0.0.7",
-    "escape-string-regexp": "^5.0.0",
+    "escape-string-regexp": "=4.0.0",
     "express": "^4.16.1",
     "express-bunyan-logger": "^1.3.3",
     "express-form": "~0.12.0",
@@ -55,7 +97,6 @@
     "growi-commons": "^5.0.4",
     "growi-plugin-attachment-refs": "^2.0.2",
     "growi-plugin-lsx": "^4.0.3",
-    "growi-plugin-pukiwiki-like-linker": "^3.1.0",
     "helmet": "^3.13.0",
     "http-errors": "~1.6.2",
     "i18next": "^20.3.2",
@@ -68,7 +109,6 @@
     "method-override": "^3.0.0",
     "migrate-mongo": "^8.2.2",
     "mkdirp": "^1.0.3",
-    "module-alias": "^2.0.6",
     "mongoose": "5.12.13",
     "mongoose-gridfs": "^1.2.42",
     "mongoose-paginate-v2": "^1.3.9",
@@ -79,7 +119,6 @@
     "nodemailer-ses-transport": "~1.5.0",
     "npm-run-all": "^4.1.2",
     "openid-client": "=2.5.0",
-    "package-installed-version-sync": "^2.1.0",
     "passport": "^0.4.0",
     "passport-github": "^1.1.0",
     "passport-google-oauth20": "^2.0.0",
@@ -97,7 +136,11 @@
     "socket.io": "^4.0.0",
     "stream-to-promise": "^3.0.0",
     "string-width": "=4.2.2",
+    "swagger-jsdoc": "^3.4.0",
     "swig-templates": "^2.0.2",
+    "ts-node": "^9.1.1",
+    "tsconfig-paths": "^3.9.0",
+    "typescript": "^4.2.3",
     "uglifycss": "^0.0.29",
     "universal-bunyan": "^0.9.2",
     "unzipper": "^0.10.5",
@@ -108,30 +151,21 @@
   },
   "// comments for defDependencies": {
     "@handsontable/react": "v3 requires handsontable >= 7.0.0.",
-    "handsontable": "v7.0.0 or above is no loger MIT lisence."
+    "handsontable": "v7.0.0 or above is no loger MIT lisence.",
+    "ts-loader": "v9 is not compatible with webpack@5"
   },
   "devDependencies": {
     "@alienfast/i18next-loader": "^1.0.16",
     "@atlaskit/drawer": "^5.3.7",
     "@atlaskit/navigation-next": "^8.0.5",
-    "@babel/core": "^7.4.5",
-    "@babel/plugin-proposal-class-properties": "^7.8.3",
-    "@babel/plugin-proposal-optional-chaining": "^7.9.0",
-    "@babel/polyfill": "^7.4.4",
-    "@babel/preset-env": "^7.4.5",
-    "@babel/preset-react": "^7.0.0",
     "@handsontable/react": "=2.1.0",
     "@types/compression": "^1.7.0",
     "@types/express": "^4.17.11",
     "@types/multer": "^1.4.5",
     "@types/node": "^14.14.35",
+    "@types/react-dom": "^17.0.9",
     "autoprefixer": "^9.0.0",
-    "babel-eslint": "^10.0.1",
-    "babel-loader": "^8.0.6",
-    "babel-plugin-lodash": "^3.3.4",
-    "babel-plugin-transform-imports": "^2.0.0",
     "bootstrap": "^4.5.0",
-    "browser-bunyan": "^1.6.3",
     "browser-sync": "^2.26.3",
     "bunyan-debug": "^2.0.0",
     "cli": "~1.0.1",
@@ -143,18 +177,12 @@
     "csv-to-markdown-table": "^1.0.1",
     "diff2html": "^3.1.2",
     "eazy-logger": "^3.0.2",
-    "eslint": "^6.0.1",
-    "eslint-config-weseek": "^1.0.8",
-    "eslint-plugin-import": "^2.18.0",
-    "eslint-plugin-jest": "^23.0.3",
-    "eslint-plugin-react": "^7.14.2",
-    "eslint-plugin-react-hooks": "^4.0.4",
     "file-loader": "^5.0.2",
     "handsontable": "=6.2.2",
     "hard-source-webpack-plugin": "^0.13.1",
     "i18next-browser-languagedetector": "^4.0.1",
     "imports-loader": "^0.8.0",
-    "jest": "^25.1.0",
+    "jest": "^27.0.6",
     "jest-date-mock": "^1.0.8",
     "jquery-slimscroll": "^1.3.8",
     "jquery-ui": "^1.12.1",
@@ -173,7 +201,7 @@
     "markdown-it-toc-and-anchor-with-slugid": "^1.1.4",
     "markdown-table": "^1.1.1",
     "mini-css-extract-plugin": "^0.9.0",
-    "morgan": "^1.9.0",
+    "morgan": "^1.10.0",
     "node-dev": "^4.0.0",
     "node-sass": "^4.14.1",
     "normalize-path": "^3.0.0",
@@ -195,11 +223,10 @@
     "react-i18next": "^11.1.0",
     "react-images": "1.0.0",
     "react-motion": "^0.5.2",
-    "react-waypoint": "^9.0.0",
+    "react-waypoint": "^10.1.0",
     "reactstrap": "^8.9.0",
     "replacestream": "^4.0.3",
     "reveal.js": "^3.5.0",
-    "rs-i18n": "^0.0.9",
     "sass-loader": "^8.0.0",
     "simple-load-script": "^1.0.2",
     "socket.io-client": "^4.0.0",
@@ -208,11 +235,14 @@
     "styled-components": "^5.0.1",
     "stylelint": "^13.2.0",
     "stylelint-config-recess-order": "^2.0.1",
-    "swagger-jsdoc": "^3.4.0",
     "swagger2openapi": "^5.3.1",
     "terser-webpack-plugin": "^4.1.0",
     "throttle-debounce": "^2.0.0",
     "toastr": "^2.1.2",
+    "ts-jest": "^27.0.4",
+    "ts-loader": "^8.3.0",
+    "ts-node-dev": "^1.1.6",
+    "tsc-alias": "^1.2.9",
     "unstated": "^2.1.1",
     "webpack": "^4.39.3",
     "webpack-assets-manifest": "^3.1.1",

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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


+ 0 - 0
public/images/icons/favicon/apple-icon-180x180.png → packages/app/public/images/icons/favicon/apple-icon-180x180.png


+ 0 - 0
public/images/icons/favicon/apple-icon-57x57.png → packages/app/public/images/icons/favicon/apple-icon-57x57.png


+ 0 - 0
public/images/icons/favicon/apple-icon-60x60.png → packages/app/public/images/icons/favicon/apple-icon-60x60.png


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


+ 0 - 0
public/images/icons/favicon/apple-icon-76x76.png → packages/app/public/images/icons/favicon/apple-icon-76x76.png


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


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


+ 0 - 0
public/images/icons/favicon/browserconfig.xml → packages/app/public/images/icons/favicon/browserconfig.xml


+ 0 - 0
public/images/icons/favicon/favicon-16x16.png → packages/app/public/images/icons/favicon/favicon-16x16.png


+ 0 - 0
public/images/icons/favicon/favicon-32x32.png → packages/app/public/images/icons/favicon/favicon-32x32.png


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


+ 0 - 0
public/images/icons/favicon/manifest.json → packages/app/public/images/icons/favicon/manifest.json


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


+ 0 - 0
public/images/icons/favicon/ms-icon-150x150.png → packages/app/public/images/icons/favicon/ms-icon-150x150.png


+ 0 - 0
public/images/icons/favicon/ms-icon-310x310.png → packages/app/public/images/icons/favicon/ms-icon-310x310.png


+ 0 - 0
public/images/icons/favicon/ms-icon-70x70.png → packages/app/public/images/icons/favicon/ms-icon-70x70.png


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


+ 0 - 0
public/images/icons/slack/mark-color.svg → packages/app/public/images/icons/slack/mark-color.svg


+ 0 - 0
public/images/icons/slack/mark-monochrome_black.svg → packages/app/public/images/icons/slack/mark-monochrome_black.svg


+ 0 - 0
public/images/icons/slack/mark-monochrome_white.svg → packages/app/public/images/icons/slack/mark-monochrome_white.svg


+ 0 - 0
public/images/icons/slack/slack-logo-dark-off.svg → packages/app/public/images/icons/slack/slack-logo-dark-off.svg


+ 0 - 0
public/images/icons/slack/slack-logo-dark-on.svg → packages/app/public/images/icons/slack/slack-logo-dark-on.svg


+ 0 - 0
public/images/icons/slack/slack-logo-off.svg → packages/app/public/images/icons/slack/slack-logo-off.svg


+ 0 - 0
public/images/icons/slack/slack-logo-on.svg → packages/app/public/images/icons/slack/slack-logo-on.svg


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


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