فهرست منبع

Merge branch 'master' into support/107699-next-PageStatusAlert

Yuken Tezuka 3 سال پیش
والد
کامیت
5a6121c928
68فایلهای تغییر یافته به همراه392 افزوده شده و 321 حذف شده
  1. 1 1
      lerna.json
  2. 1 1
      package.json
  3. 8 8
      packages/app/package.json
  4. 8 5
      packages/app/public/static/locales/en_US/admin.json
  5. 5 2
      packages/app/public/static/locales/en_US/commons.json
  6. 0 3
      packages/app/public/static/locales/en_US/translation.json
  7. 7 4
      packages/app/public/static/locales/ja_JP/admin.json
  8. 5 2
      packages/app/public/static/locales/ja_JP/commons.json
  9. 1 2
      packages/app/public/static/locales/ja_JP/translation.json
  10. 7 4
      packages/app/public/static/locales/zh_CN/admin.json
  11. 5 2
      packages/app/public/static/locales/zh_CN/commons.json
  12. 0 1
      packages/app/public/static/locales/zh_CN/translation.json
  13. 2 2
      packages/app/src/components/Admin/App/AppSetting.jsx
  14. 1 1
      packages/app/src/components/Admin/App/AppSettingsPageContents.tsx
  15. 6 6
      packages/app/src/components/Admin/App/SiteUrlSetting.tsx
  16. 3 3
      packages/app/src/components/Admin/Notification/NotificationSetting.jsx
  17. 1 1
      packages/app/src/components/Admin/Notification/UserTriggerNotification.jsx
  18. 1 1
      packages/app/src/components/Admin/Security/LocalSecuritySettingContents.jsx
  19. 13 11
      packages/app/src/components/Admin/Security/ShareLinkSetting.tsx
  20. 1 1
      packages/app/src/components/Admin/UserManagement.tsx
  21. 2 1
      packages/app/src/components/Admin/Users/GiveAdminButton.tsx
  22. 2 1
      packages/app/src/components/Admin/Users/RemoveAdminMenuItem.tsx
  23. 2 1
      packages/app/src/components/Admin/Users/StatusSuspendMenuItem.tsx
  24. 0 132
      packages/app/src/components/Admin/Users/UserMenu.jsx
  25. 5 0
      packages/app/src/components/Admin/Users/UserMenu.module.scss
  26. 114 0
      packages/app/src/components/Admin/Users/UserMenu.tsx
  27. 1 1
      packages/app/src/components/Common/ImageCropModal.tsx
  28. 4 2
      packages/app/src/components/InAppNotification/InAppNotificationPage.tsx
  29. 1 1
      packages/app/src/components/Navbar/AuthorInfo.module.scss
  30. 8 11
      packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx
  31. 2 2
      packages/app/src/components/Navbar/GrowiSubNavigation.module.scss
  32. 3 3
      packages/app/src/components/Navbar/GrowiSubNavigation.tsx
  33. 1 1
      packages/app/src/components/Navbar/PageEditorModeManager.module.scss
  34. 1 1
      packages/app/src/components/Page/TagLabels.module.scss
  35. 4 4
      packages/app/src/components/Page/TagLabels.tsx
  36. 1 1
      packages/app/src/components/PageComment.module.scss
  37. 2 2
      packages/app/src/components/PageComment.tsx
  38. 1 1
      packages/app/src/components/PageComment/Comment.module.scss
  39. 10 10
      packages/app/src/components/PageCommentSkeleton.tsx
  40. 1 1
      packages/app/src/components/PageContentFooter.module.scss
  41. 2 2
      packages/app/src/components/PageContentFooter.tsx
  42. 1 1
      packages/app/src/components/PageEditor/HandsontableModal.tsx
  43. 3 3
      packages/app/src/components/Skeleton.tsx
  44. 15 2
      packages/app/src/pages/[[...path]].page.tsx
  45. 2 2
      packages/app/src/stores/context.tsx
  46. 0 5
      packages/app/src/styles/_user.scss
  47. 2 2
      packages/app/src/styles/theme/_apply-colors-dark.scss
  48. 2 2
      packages/app/src/styles/theme/_apply-colors-light.scss
  49. 64 34
      packages/app/test/cypress/integration/20-basic-features/access-to-page.spec.ts
  50. 1 1
      packages/app/test/cypress/integration/20-basic-features/click-page-icons.spec.ts
  51. 1 0
      packages/app/test/cypress/integration/20-basic-features/use-tools.spec.ts
  52. 1 0
      packages/app/test/cypress/integration/21-basic-features-for-guest/access-to-page.spec.ts
  53. 2 0
      packages/app/test/cypress/integration/30-search/search.spec.ts
  54. 1 1
      packages/app/test/cypress/integration/50-sidebar/access-to-side-bar.spec.ts
  55. 4 4
      packages/app/test/cypress/integration/60-home/home.spec.ts
  56. 13 0
      packages/app/test/cypress/support/commands.ts
  57. 2 0
      packages/app/test/cypress/support/index.ts
  58. 1 1
      packages/codemirror-textlint/package.json
  59. 1 1
      packages/core/package.json
  60. 11 1
      packages/core/src/interfaces/user.ts
  61. 1 1
      packages/hackmd/package.json
  62. 1 1
      packages/plugin-attachment-refs/package.json
  63. 4 4
      packages/plugin-lsx/package.json
  64. 1 1
      packages/remark-growi-plugin/package.json
  65. 1 1
      packages/slack/package.json
  66. 2 2
      packages/slackbot-proxy/package.json
  67. 10 10
      packages/slackbot-proxy/src/services/SelectGrowiService.ts
  68. 2 2
      packages/ui/package.json

+ 1 - 1
lerna.json

@@ -1,7 +1,7 @@
 {
 {
   "npmClient": "yarn",
   "npmClient": "yarn",
   "useWorkspaces": true,
   "useWorkspaces": true,
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "packages": [
   "packages": [
     "packages/*"
     "packages/*"
   ]
   ]

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "growi",
   "name": "growi",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "description": "Team collaboration software using markdown",
   "description": "Team collaboration software using markdown",
   "tags": [
   "tags": [
     "wiki",
     "wiki",

+ 8 - 8
packages/app/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@growi/app",
   "name": "@growi/app",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "license": "MIT",
   "license": "MIT",
   "scripts": {
   "scripts": {
     "//// for production": "",
     "//// for production": "",
@@ -65,12 +65,12 @@
     "@elastic/elasticsearch7": "npm:@elastic/elasticsearch@^7.17.0",
     "@elastic/elasticsearch7": "npm:@elastic/elasticsearch@^7.17.0",
     "@godaddy/terminus": "^4.9.0",
     "@godaddy/terminus": "^4.9.0",
     "@google-cloud/storage": "^5.8.5",
     "@google-cloud/storage": "^5.8.5",
-    "@growi/codemirror-textlint": "^6.0.0-RC.8",
-    "@growi/core": "^6.0.0-RC.8",
-    "@growi/hackmd": "^6.0.0-RC.8",
-    "@growi/plugin-attachment-refs": "^6.0.0-RC.8",
-    "@growi/plugin-lsx": "^6.0.0-RC.8",
-    "@growi/slack": "^6.0.0-RC.8",
+    "@growi/codemirror-textlint": "^6.0.0-RC.9",
+    "@growi/core": "^6.0.0-RC.9",
+    "@growi/hackmd": "^6.0.0-RC.9",
+    "@growi/plugin-attachment-refs": "^6.0.0-RC.9",
+    "@growi/plugin-lsx": "^6.0.0-RC.9",
+    "@growi/slack": "^6.0.0-RC.9",
     "@promster/express": "^7.0.2",
     "@promster/express": "^7.0.2",
     "@promster/server": "^7.0.4",
     "@promster/server": "^7.0.4",
     "@slack/events-api": "^3.0.0",
     "@slack/events-api": "^3.0.0",
@@ -205,7 +205,7 @@
     "handsontable": "v7.0.0 or above is no loger MIT lisence."
     "handsontable": "v7.0.0 or above is no loger MIT lisence."
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@growi/ui": "^6.0.0-RC.8",
+    "@growi/ui": "^6.0.0-RC.9",
     "@handsontable/react": "=2.1.0",
     "@handsontable/react": "=2.1.0",
     "@icon/themify-icons": "1.0.1-alpha.3",
     "@icon/themify-icons": "1.0.1-alpha.3",
     "@next/bundle-analyzer": "^12.2.3",
     "@next/bundle-analyzer": "^12.2.3",

+ 8 - 5
packages/app/public/static/locales/en_US/admin.json

@@ -329,9 +329,12 @@
     "site_name": "Site name",
     "site_name": "Site name",
     "sitename_change": "You can change site name which is used for header and HTML title.",
     "sitename_change": "You can change site name which is used for header and HTML title.",
     "header_content": "The contents entered here will be shown in the header etc.",
     "header_content": "The contents entered here will be shown in the header etc.",
-    "site_url_desc": "This is for the site URL setting.",
-    "site_url_warn": "Some features don't work because the site URL is not set.",
-    "siteurl_help": "Site full URL beginning from <code>http://</code> or <code>https://</code>.",
+    "site_url": {
+      "title": "Site URL settings",
+      "desc": "This is for the site URL setting.",
+      "warn": "Some features don't work because the site URL is not set.",
+      "help": "Site full URL beginning from <code>http://</code> or <code>https://</code>."
+    },
     "confidential_name": "Confidential name",
     "confidential_name": "Confidential name",
     "confidential_example": "ex): internal use only",
     "confidential_example": "ex): internal use only",
     "default_language": "Default language for new users",
     "default_language": "Default language for new users",
@@ -377,7 +380,7 @@
     "custom_endpoint_change": "Input the URL of the endpoint of an object storage service like MinIO that has a S3-compatible API.  Amazon S3 is used if empty.",
     "custom_endpoint_change": "Input the URL of the endpoint of an object storage service like MinIO that has a S3-compatible API.  Amazon S3 is used if empty.",
     "plugin_settings": "Plugin settings",
     "plugin_settings": "Plugin settings",
     "enable_plugin_loading": "Enable plugin loading",
     "enable_plugin_loading": "Enable plugin loading",
-    "load_plugins": "Load_plugins",
+    "load_plugins": "Load plugins",
     "enable": "Enable",
     "enable": "Enable",
     "disable": "Disable",
     "disable": "Disable",
     "use_env_var_if_empty": "If the value in the database is empty, the value of the environment variable <code>{{variable}}</code> is used.",
     "use_env_var_if_empty": "If the value in the database is empty, the value of the environment variable <code>{{variable}}</code> is used.",
@@ -577,7 +580,7 @@
     "export": "Export",
     "export": "Export",
     "cancel": "Cancel",
     "cancel": "Cancel",
     "file": "File",
     "file": "File",
-    "growi_version": "Growi Version",
+    "growi_version": "GROWI Version",
     "collections": "Collections",
     "collections": "Collections",
     "exported_at": "Exported At",
     "exported_at": "Exported At",
     "export_menu": "Export Menu",
     "export_menu": "Export Menu",

+ 5 - 2
packages/app/public/static/locales/en_US/commons.json

@@ -1,4 +1,9 @@
 {
 {
+  "Show": "Show",
+  "Hide": "Hide",
+  "Add": "Add",
+  "Reset": "Reset",
+
   "meta": {
   "meta": {
     "display_name": "English"
     "display_name": "English"
   },
   },
@@ -55,7 +60,6 @@
     "image_crop": "Image Crop",
     "image_crop": "Image Crop",
     "crop": "Crop",
     "crop": "Crop",
     "save": "Save",
     "save": "Save",
-    "reset": "Reset",
     "cancel": "Cancel"
     "cancel": "Cancel"
   },
   },
 
 
@@ -63,7 +67,6 @@
     "title": "Edit Table",
     "title": "Edit Table",
     "data_import": "Data Import",
     "data_import": "Data Import",
     "save": "Save",
     "save": "Save",
-    "reset": "Reset",
     "cancel": "Cancel",
     "cancel": "Cancel",
     "done": "Done",
     "done": "Done",
     "data_import_form": {
     "data_import_form": {

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

@@ -100,8 +100,6 @@
   "Updated": "Updated",
   "Updated": "Updated",
   "Upload new image": "Upload new image",
   "Upload new image": "Upload new image",
   "Connected": "Connected",
   "Connected": "Connected",
-  "Show": "Show",
-  "Hide": "Hide",
   "Loading": "Loading...",
   "Loading": "Loading...",
   "Disclose E-mail": "Disclose E-mail",
   "Disclose E-mail": "Disclose E-mail",
   "page exists": "this page already exists",
   "page exists": "this page already exists",
@@ -115,7 +113,6 @@
   "V5 Page Migration": "Convert To V5 Compatibility",
   "V5 Page Migration": "Convert To V5 Compatibility",
   "GROWI.5.0_new_schema": "GROWI.5.0 new schema",
   "GROWI.5.0_new_schema": "GROWI.5.0 new schema",
   "See_more_detail_on_new_schema": "See more detail on <a href='https://docs.growi.org/en/admin-guide/upgrading/50x.html#about-the-new-v5-compatible-format' target='_blank'>{{title}}</a> <i class='icon-share-alt'></i> ",
   "See_more_detail_on_new_schema": "See more detail on <a href='https://docs.growi.org/en/admin-guide/upgrading/50x.html#about-the-new-v5-compatible-format' target='_blank'>{{title}}</a> <i class='icon-share-alt'></i> ",
-  "Site URL settings": "Site URL settings",
   "external_account_management": "External Account Management",
   "external_account_management": "External Account Management",
   "UserGroup": "UserGroup",
   "UserGroup": "UserGroup",
   "Basic Settings": "Basic Settings",
   "Basic Settings": "Basic Settings",

+ 7 - 4
packages/app/public/static/locales/ja_JP/admin.json

@@ -355,9 +355,12 @@
     "site_name": "サイト名",
     "site_name": "サイト名",
     "sitename_change": "ヘッダーや HTML タイトルに使用されるサイト名を変更できます。",
     "sitename_change": "ヘッダーや HTML タイトルに使用されるサイト名を変更できます。",
     "header_content": "ここに入力した内容は、ヘッダー等に表示されます。",
     "header_content": "ここに入力した内容は、ヘッダー等に表示されます。",
-    "site_url_desc": "サイトURLを設定します。",
-    "site_url_warn": "サイトURLが設定されていないため、一部機能が動作しない状態になっています。",
-    "siteurl_help": "<code>http://</code> または <code>https://</code> から始まるサイトのURL",
+    "site_url": {
+      "title": "サイトURL設定",
+      "desc": "サイトURLを設定します。",
+      "warn": "サイトURLが設定されていないため、一部機能が動作しない状態になっています。",
+      "help": "<code>http://</code> または <code>https://</code> から始まるサイトのURL"
+    },
     "confidential_name": "コンフィデンシャル表示",
     "confidential_name": "コンフィデンシャル表示",
     "confidential_example": "例: 社外秘",
     "confidential_example": "例: 社外秘",
     "default_language": "新規ユーザーのデフォルト設定言語",
     "default_language": "新規ユーザーのデフォルト設定言語",
@@ -531,7 +534,7 @@
     "export": "エクスポート",
     "export": "エクスポート",
     "cancel": "キャンセル",
     "cancel": "キャンセル",
     "file": "ファイル名",
     "file": "ファイル名",
-    "growi_version": "Growi バージョン",
+    "growi_version": "GROWI バージョン",
     "collections": "コレクション",
     "collections": "コレクション",
     "exported_at": "エクスポートされた時間",
     "exported_at": "エクスポートされた時間",
     "export_menu": "エクスポートメニュー",
     "export_menu": "エクスポートメニュー",

+ 5 - 2
packages/app/public/static/locales/ja_JP/commons.json

@@ -1,4 +1,9 @@
 {
 {
+  "Show": "公開",
+  "Hide": "非公開",
+  "Add": "追加",
+  "Reset": "リセット",
+
   "meta": {
   "meta": {
     "display_name": "日本語"
     "display_name": "日本語"
   },
   },
@@ -55,7 +60,6 @@
     "image_crop": "画像の切り抜き",
     "image_crop": "画像の切り抜き",
     "crop": "トリミング",
     "crop": "トリミング",
     "save": "保存",
     "save": "保存",
-    "reset": "リセット",
     "cancel": "キャンセル"
     "cancel": "キャンセル"
   },
   },
 
 
@@ -63,7 +67,6 @@
     "title": "テーブル編集",
     "title": "テーブル編集",
     "data_import": "データインポート",
     "data_import": "データインポート",
     "save": "保存",
     "save": "保存",
-    "reset": "リセット",
     "cancel": "キャンセル",
     "cancel": "キャンセル",
     "done": "完了",
     "done": "完了",
     "data_import_form": {
     "data_import_form": {

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

@@ -110,7 +110,6 @@
   "V5 Page Migration": "V5 互換形式 への変換",
   "V5 Page Migration": "V5 互換形式 への変換",
   "GROWI.5.0_new_schema": "GROWI.5.0における新スキーマについて",
   "GROWI.5.0_new_schema": "GROWI.5.0における新スキーマについて",
   "See_more_detail_on_new_schema": "詳しくは<a href='https://docs.growi.org/ja/admin-guide/upgrading/50x.html#新しい-v5-互換形式について' target='_blank'>{{title}}</a><i class='icon-share-alt'></i>を参照ください。",
   "See_more_detail_on_new_schema": "詳しくは<a href='https://docs.growi.org/ja/admin-guide/upgrading/50x.html#新しい-v5-互換形式について' target='_blank'>{{title}}</a><i class='icon-share-alt'></i>を参照ください。",
-  "Site URL settings": "サイトURL設定",
   "external_account_management": "外部アカウント管理",
   "external_account_management": "外部アカウント管理",
   "UserGroup": "グループ",
   "UserGroup": "グループ",
   "Basic Settings": "基本設定",
   "Basic Settings": "基本設定",
@@ -324,7 +323,7 @@
   },
   },
   "page_page": {
   "page_page": {
     "notice": {
     "notice": {
-      "version": "これは現在の版ではありません。",
+      "version": "これは最新のバージョンではありません。",
       "redirected": "リダイレクト元 >>",
       "redirected": "リダイレクト元 >>",
       "redirected_period":"",
       "redirected_period":"",
       "unlinked": "このページへのリダイレクトは削除されました。",
       "unlinked": "このページへのリダイレクトは削除されました。",

+ 7 - 4
packages/app/public/static/locales/zh_CN/admin.json

@@ -360,9 +360,12 @@
     "site_name": "网站名称 ",
     "site_name": "网站名称 ",
     "sitename_change": "您可以更改用于标题和HTML标题的网站名称。",
     "sitename_change": "您可以更改用于标题和HTML标题的网站名称。",
     "header_content": "此处输入的内容将显示在标题等中。",
     "header_content": "此处输入的内容将显示在标题等中。",
-    "site_url_desc": "用于网站URL设置。",
-    "site_url_warn": "某些功能不起作用,因为未设置网站URL。",
-    "siteurl_help": "网站完整URL起始于 <code>http://</code> or <code>https://</code>.",
+    "site_url": {
+      "title": "主页URL设置",
+      "desc": "用于网站URL设置。",
+      "warn": "某些功能不起作用,因为未设置网站URL。",
+      "help": "网站完整URL起始于 <code>http://</code> or <code>https://</code>."
+    },
     "confidential_name": "内部名称",
     "confidential_name": "内部名称",
     "confidential_example": "ex):仅供内部使用",
     "confidential_example": "ex):仅供内部使用",
     "default_language": "新用户的默认语言",
     "default_language": "新用户的默认语言",
@@ -623,7 +626,7 @@
     "export": "导出",
     "export": "导出",
     "cancel": "取消",
     "cancel": "取消",
     "file": "文件",
     "file": "文件",
-    "growi_version": "Growi Version",
+    "growi_version": "GROWI Version",
     "collections": "Collections",
     "collections": "Collections",
     "exported_at": "Exported At",
     "exported_at": "Exported At",
     "export_menu": "导出菜单",
     "export_menu": "导出菜单",

+ 5 - 2
packages/app/public/static/locales/zh_CN/commons.json

@@ -1,4 +1,9 @@
 {
 {
+	"Show": "显示",
+	"Hide": "隐藏",
+  "Add": "添加",
+  "Reset": "重启",
+
   "meta": {
   "meta": {
     "display_name": "简体中文"
     "display_name": "简体中文"
   },
   },
@@ -55,7 +60,6 @@
     "image_crop": "图像裁剪",
     "image_crop": "图像裁剪",
     "crop": "修剪",
     "crop": "修剪",
     "save": "节省",
     "save": "节省",
-    "reset": "重启",
     "cancel": "取消"
     "cancel": "取消"
   },
   },
 
 
@@ -63,7 +67,6 @@
     "title": "编辑表格",
     "title": "编辑表格",
     "data_import": "数据导入",
     "data_import": "数据导入",
     "save": "节省",
     "save": "节省",
-    "reset": "重启",
     "cancel": "取消",
     "cancel": "取消",
     "done": "完毕",
     "done": "完毕",
     "data_import_form": {
     "data_import_form": {

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

@@ -117,7 +117,6 @@
   "V5 Page Migration": "转换为V5的兼容性",
   "V5 Page Migration": "转换为V5的兼容性",
   "GROWI.5.0_new_schema": "GROWI.5.0 new schema",
   "GROWI.5.0_new_schema": "GROWI.5.0 new schema",
   "See_more_detail_on_new_schema": "更多详情请见<a href='https://docs.growi.org/en/admin-guide/upgrading/50x.html#about-the-new-v5-compatible-format' target='_blank'> {{title}}</a> <i class='icon-share-alt'></i> ",
   "See_more_detail_on_new_schema": "更多详情请见<a href='https://docs.growi.org/en/admin-guide/upgrading/50x.html#about-the-new-v5-compatible-format' target='_blank'> {{title}}</a> <i class='icon-share-alt'></i> ",
-	"Site URL settings": "主页URL设置",
 	"Markdown Settings": "Markdown设置",
 	"Markdown Settings": "Markdown设置",
 	"Notification Settings": "通知设置",
 	"Notification Settings": "通知设置",
 	"external_account_management": "外部账户管理",
 	"external_account_management": "外部账户管理",

+ 2 - 2
packages/app/src/components/Admin/App/AppSetting.jsx

@@ -120,7 +120,7 @@ const AppSetting = (props) => {
               checked={adminAppContainer.state.isEmailPublishedForNewUser === true}
               checked={adminAppContainer.state.isEmailPublishedForNewUser === true}
               onChange={() => { adminAppContainer.changeIsEmailPublishedForNewUserShow(true) }}
               onChange={() => { adminAppContainer.changeIsEmailPublishedForNewUserShow(true) }}
             />
             />
-            <label className="custom-control-label" htmlFor="radio-email-show">{t('Show')}</label>
+            <label className="custom-control-label" htmlFor="radio-email-show">{t('commons:Show')}</label>
           </div>
           </div>
 
 
           <div className="custom-control custom-radio custom-control-inline">
           <div className="custom-control custom-radio custom-control-inline">
@@ -132,7 +132,7 @@ const AppSetting = (props) => {
               checked={adminAppContainer.state.isEmailPublishedForNewUser === false}
               checked={adminAppContainer.state.isEmailPublishedForNewUser === false}
               onChange={() => { adminAppContainer.changeIsEmailPublishedForNewUserShow(false) }}
               onChange={() => { adminAppContainer.changeIsEmailPublishedForNewUserShow(false) }}
             />
             />
-            <label className="custom-control-label" htmlFor="radio-email-hide">{t('Hide')}</label>
+            <label className="custom-control-label" htmlFor="radio-email-hide">{t('commons:Hide')}</label>
           </div>
           </div>
 
 
         </div>
         </div>

+ 1 - 1
packages/app/src/components/Admin/App/AppSettingsPageContents.tsx

@@ -89,7 +89,7 @@ const AppSettingsPageContents = (props: Props) => {
 
 
       <div className="row mt-5">
       <div className="row mt-5">
         <div className="col-lg-12">
         <div className="col-lg-12">
-          <h2 className="admin-setting-header">{t('Site URL settings')}</h2>
+          <h2 className="admin-setting-header">{t('app_setting.site_url.title')}</h2>
           <SiteUrlSetting />
           <SiteUrlSetting />
         </div>
         </div>
       </div>
       </div>

+ 6 - 6
packages/app/src/components/Admin/App/SiteUrlSetting.tsx

@@ -17,14 +17,14 @@ type Props = {
 }
 }
 
 
 const SiteUrlSetting = (props: Props) => {
 const SiteUrlSetting = (props: Props) => {
-  const { t } = useTranslation();
+  const { t } = useTranslation('admin', { keyPrefix: 'app_setting' });
   const { adminAppContainer } = props;
   const { adminAppContainer } = props;
 
 
 
 
   const submitHandler = useCallback(async() => {
   const submitHandler = useCallback(async() => {
     try {
     try {
       await adminAppContainer.updateSiteUrlSettingHandler();
       await adminAppContainer.updateSiteUrlSettingHandler();
-      toastSuccess(t('toaster.update_successed', { target: t('Site URL settings'), ns: 'commons' }));
+      toastSuccess(t('toaster.update_successed', { target: t('site_url.title') }));
     }
     }
     catch (err) {
     catch (err) {
       toastError(err);
       toastError(err);
@@ -34,9 +34,9 @@ const SiteUrlSetting = (props: Props) => {
 
 
   return (
   return (
     <React.Fragment>
     <React.Fragment>
-      <p className="card well">{t('admin:app_setting.site_url_desc')}</p>
+      <p className="card well">{t('site_url.desc')}</p>
       {!adminAppContainer.state.isSetSiteUrl
       {!adminAppContainer.state.isSetSiteUrl
-          && (<p className="alert alert-danger"><i className="icon-exclamation"></i> {t('admin:app_setting.site_url_warn')}</p>)}
+          && (<p className="alert alert-danger"><i className="icon-exclamation"></i> {t('site_url.warn')}</p>)}
 
 
       <div className="row form-group">
       <div className="row form-group">
         <div className="col-md-9 offset-md-3">
         <div className="col-md-9 offset-md-3">
@@ -64,14 +64,14 @@ const SiteUrlSetting = (props: Props) => {
                   />
                   />
                   <p className="form-text text-muted">
                   <p className="form-text text-muted">
                     {/* eslint-disable-next-line react/no-danger */}
                     {/* eslint-disable-next-line react/no-danger */}
-                    <span dangerouslySetInnerHTML={{ __html: t('admin:app_setting.siteurl_help') }} />
+                    <span dangerouslySetInnerHTML={{ __html: t('site_url.help') }} />
                   </p>
                   </p>
                 </td>
                 </td>
                 <td>
                 <td>
                   <input className="form-control" type="text" value={adminAppContainer.state.envSiteUrl || ''} readOnly />
                   <input className="form-control" type="text" value={adminAppContainer.state.envSiteUrl || ''} readOnly />
                   <p className="form-text text-muted">
                   <p className="form-text text-muted">
                     {/* eslint-disable-next-line react/no-danger */}
                     {/* eslint-disable-next-line react/no-danger */}
-                    <span dangerouslySetInnerHTML={{ __html: t('admin:app_setting.use_env_var_if_empty', { variable: 'APP_SITE_URL' }) }} />
+                    <span dangerouslySetInnerHTML={{ __html: t('use_env_var_if_empty', { variable: 'APP_SITE_URL' }) }} />
                   </p>
                   </p>
                 </td>
                 </td>
               </tr>
               </tr>

+ 3 - 3
packages/app/src/components/Admin/Notification/NotificationSetting.jsx

@@ -35,7 +35,7 @@ const Badge = ({ isEnabled }) => {
     : <span className="badge badge-secondary">{t('external_notification.disabled')}</span>;
     : <span className="badge badge-secondary">{t('external_notification.disabled')}</span>;
 };
 };
 
 
-const SkeltonListItem = () => (
+const SkeletonListItem = () => (
   <li className="list-group-item">
   <li className="list-group-item">
     <h4 className="mb-2">
     <h4 className="mb-2">
       <span className="badge badge-secondary">――</span>
       <span className="badge badge-secondary">――</span>
@@ -74,7 +74,7 @@ const LegacySlackIntegrationListItem = ({ isEnabled }) => {
     <li className="list-group-item">
     <li className="list-group-item">
       <h4>
       <h4>
         <Badge isEnabled={isEnabled} />
         <Badge isEnabled={isEnabled} />
-        <a href="/admin/slack-integration-legacy" className="ml-2">{t('legacy_slack_integration')}</a>
+        <a href="/admin/slack-integration-legacy" className="ml-2">{t('slack_integration_legacy.slack_integration_legacy')}</a>
       </h4>
       </h4>
       { isEnabled && (
       { isEnabled && (
         <ul className="mt-2 pl-4">
         <ul className="mt-2 pl-4">
@@ -144,7 +144,7 @@ function NotificationSetting(props) {
     <div data-testid="admin-notification">
     <div data-testid="admin-notification">
       <h2 className="admin-setting-header">{t('external_notification.header_status')}</h2>
       <h2 className="admin-setting-header">{t('external_notification.header_status')}</h2>
       <ul className="list-group">
       <ul className="list-group">
-        { !isMounted && <SkeltonListItem />}
+        { !isMounted && <SkeletonListItem />}
         { isMounted && (
         { isMounted && (
           <>
           <>
             <SlackIntegrationListItem isEnabled={isSlackEnabled} currentBotType={currentBotType} />
             <SlackIntegrationListItem isEnabled={isSlackEnabled} currentBotType={currentBotType} />

+ 1 - 1
packages/app/src/components/Admin/Notification/UserTriggerNotification.jsx

@@ -129,7 +129,7 @@ class UserTriggerNotification extends React.Component {
                 </p>
                 </p>
               </td>
               </td>
               <td>
               <td>
-                <button type="button" className="btn btn-primary" disabled={!this.validateForm()} onClick={this.onClickSubmit}>{t('add')}</button>
+                <button type="button" className="btn btn-primary" disabled={!this.validateForm()} onClick={this.onClickSubmit}>{t('commons:Add')}</button>
               </td>
               </td>
             </tr>
             </tr>
             {userNotifications.length > 0 && userNotifications.map((notification) => {
             {userNotifications.length > 0 && userNotifications.map((notification) => {

+ 1 - 1
packages/app/src/components/Admin/Security/LocalSecuritySettingContents.jsx

@@ -100,7 +100,7 @@ class LocalSecuritySettingContents extends React.Component {
 
 
             <div className="row">
             <div className="row">
               <div className="col-12 col-md-3 text-left text-md-right py-2">
               <div className="col-12 col-md-3 text-left text-md-right py-2">
-                <strong>{t('Register limitation')}</strong>
+                <strong>{t('security_settings.Register limitation')}</strong>
               </div>
               </div>
               <div className="col-12 col-md-6">
               <div className="col-12 col-md-6">
                 <div className="dropdown">
                 <div className="dropdown">

+ 13 - 11
packages/app/src/components/Admin/Security/ShareLinkSetting.tsx

@@ -134,19 +134,21 @@ const ShareLinkSetting = (props: ShareLinkSettingProps) => {
         </div>
         </div>
       </div>
       </div>
       <h4>{t('security_settings.all_share_links')}</h4>
       <h4>{t('security_settings.all_share_links')}</h4>
-      <Pager
-        activePage={shareLinksActivePage}
-        pagingHandler={getShareLinkList}
-        totalLinks={totalshareLinks}
-        limit={shareLinksPagingLimit}
-      />
 
 
       {(shareLinks.length !== 0) ? (
       {(shareLinks.length !== 0) ? (
-        <ShareLinkList
-          shareLinks={shareLinks}
-          onClickDeleteButton={deleteLinkById}
-          isAdmin
-        />
+        <>
+          <Pager
+            activePage={shareLinksActivePage}
+            pagingHandler={getShareLinkList}
+            totalLinks={totalshareLinks}
+            limit={shareLinksPagingLimit}
+          />
+          <ShareLinkList
+            shareLinks={shareLinks}
+            onClickDeleteButton={deleteLinkById}
+            isAdmin
+          />
+        </>
       )
       )
         : (<p className="text-center">{t('security_settings.No_share_links')}</p>
         : (<p className="text-center">{t('security_settings.No_share_links')}</p>
         )
         )

+ 1 - 1
packages/app/src/components/Admin/UserManagement.tsx

@@ -182,7 +182,7 @@ const UserManagement = (props: UserManagementProps) => {
               onClick={resetButtonClickHandler}
               onClick={resetButtonClickHandler}
             >
             >
               <span className="icon-refresh mr-1"></span>
               <span className="icon-refresh mr-1"></span>
-              Reset
+              {t('commons:Reset')}
             </button>
             </button>
           </div>
           </div>
         </div>
         </div>

+ 2 - 1
packages/app/src/components/Admin/Users/GiveAdminButton.tsx

@@ -39,6 +39,7 @@ const GiveAdminButton = (props: GiveAdminButtonProps): JSX.Element => {
 /**
 /**
  * Wrapper component for using unstated
  * Wrapper component for using unstated
  */
  */
-const GiveAdminButtonWrapper = withUnstatedContainers(GiveAdminButton, [AdminUsersContainer]);
+// eslint-disable-next-line max-len
+const GiveAdminButtonWrapper: React.ForwardRefExoticComponent<Pick<any, string | number | symbol> & React.RefAttributes<any>> = withUnstatedContainers(GiveAdminButton, [AdminUsersContainer]);
 
 
 export default GiveAdminButtonWrapper;
 export default GiveAdminButtonWrapper;

+ 2 - 1
packages/app/src/components/Admin/Users/RemoveAdminMenuItem.tsx

@@ -58,6 +58,7 @@ const RemoveAdminMenuItem = (props: Props): JSX.Element => {
 /**
 /**
 * Wrapper component for using unstated
 * Wrapper component for using unstated
 */
 */
-const RemoveAdminMenuItemWrapper = withUnstatedContainers(RemoveAdminMenuItem, [AdminUsersContainer]);
+// eslint-disable-next-line max-len
+const RemoveAdminMenuItemWrapper: React.ForwardRefExoticComponent<Pick<any, string | number | symbol> & React.RefAttributes<any>> = withUnstatedContainers(RemoveAdminMenuItem, [AdminUsersContainer]);
 
 
 export default RemoveAdminMenuItemWrapper;
 export default RemoveAdminMenuItemWrapper;

+ 2 - 1
packages/app/src/components/Admin/Users/StatusSuspendMenuItem.tsx

@@ -56,6 +56,7 @@ const StatusSuspendMenuItem = (props: Props): JSX.Element => {
 /**
 /**
  * Wrapper component for using unstated
  * Wrapper component for using unstated
  */
  */
-const StatusSuspendMenuItemWrapper = withUnstatedContainers(StatusSuspendMenuItem, [AdminUsersContainer]);
+// eslint-disable-next-line max-len
+const StatusSuspendMenuItemWrapper: React.ForwardRefExoticComponent<Pick<any, string | number | symbol> & React.RefAttributes<any>> = withUnstatedContainers(StatusSuspendMenuItem, [AdminUsersContainer]);
 
 
 export default StatusSuspendMenuItemWrapper;
 export default StatusSuspendMenuItemWrapper;

+ 0 - 132
packages/app/src/components/Admin/Users/UserMenu.jsx

@@ -1,132 +0,0 @@
-import React, { Fragment } from 'react';
-
-import { useTranslation } from 'next-i18next';
-import PropTypes from 'prop-types';
-import {
-  UncontrolledDropdown, DropdownToggle, DropdownMenu,
-} from 'reactstrap';
-
-import AdminUsersContainer from '~/client/services/AdminUsersContainer';
-
-import { withUnstatedContainers } from '../../UnstatedUtils';
-
-import GiveAdminButton from './GiveAdminButton';
-import RemoveAdminMenuItem from './RemoveAdminMenuItem';
-import SendInvitationEmailButton from './SendInvitationEmailButton';
-import StatusActivateButton from './StatusActivateButton';
-import StatusSuspendedMenuItem from './StatusSuspendMenuItem';
-import UserRemoveButton from './UserRemoveButton';
-
-
-class UserMenu extends React.Component {
-
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      isInvitationEmailSended: this.props.user.isInvitationEmailSended,
-    };
-
-    this.onPasswordResetClicked = this.onPasswordResetClicked.bind(this);
-    this.onSuccessfullySentInvitationEmail = this.onSuccessfullySentInvitationEmail.bind(this);
-  }
-
-  onPasswordResetClicked() {
-    this.props.adminUsersContainer.showPasswordResetModal(this.props.user);
-  }
-
-  onSuccessfullySentInvitationEmail() {
-    this.setState({ isInvitationEmailSended: true });
-  }
-
-  renderEditMenu() {
-    const { t } = this.props;
-
-    return (
-      <Fragment>
-        <li className="dropdown-divider"></li>
-        <li className="dropdown-header">{t('admin:user_management.user_table.edit_menu')}</li>
-        <li>
-          <button className="dropdown-item" type="button" onClick={this.onPasswordResetClicked}>
-            <i className="icon-fw icon-key"></i>{ t('admin:user_management.reset_password') }
-          </button>
-        </li>
-      </Fragment>
-    );
-  }
-
-  renderStatusMenu() {
-    const { t, user } = this.props;
-    const { isInvitationEmailSended } = this.state;
-
-    return (
-      <Fragment>
-        <li className="dropdown-divider"></li>
-        <li className="dropdown-header">{t('user_management.status')}</li>
-        <li>
-          {(user.status === 1 || user.status === 3) && <StatusActivateButton user={user} />}
-          {user.status === 2 && <StatusSuspendedMenuItem user={user} />}
-          {user.status === 5 && (
-            <SendInvitationEmailButton
-              user={user}
-              isInvitationEmailSended={isInvitationEmailSended}
-              onSuccessfullySentInvitationEmail={this.onSuccessfullySentInvitationEmail}
-            />
-          )}
-          {(user.status === 1 || user.status === 3 || user.status === 5) && <UserRemoveButton user={user} />}
-        </li>
-      </Fragment>
-    );
-  }
-
-  renderAdminMenu() {
-    const { t, user } = this.props;
-
-    return (
-      <Fragment>
-        <li className="dropdown-divider pl-0"></li>
-        <li className="dropdown-header">{t('admin:user_management.user_table.administrator_menu')}</li>
-        <li>
-          {user.admin === true && <RemoveAdminMenuItem user={user} />}
-          {user.admin === false && <GiveAdminButton user={user} />}
-        </li>
-      </Fragment>
-    );
-  }
-
-  render() {
-    const { user } = this.props;
-    const { isInvitationEmailSended } = this.state;
-
-    return (
-      <UncontrolledDropdown id="userMenu" size="sm">
-        <DropdownToggle caret color="secondary" outline>
-          <i className="icon-settings" />
-          {(user.status === 5 && !isInvitationEmailSended) && <i className="fa fa-circle text-danger grw-usermenu-notification-icon" />}
-        </DropdownToggle>
-        <DropdownMenu positionFixed>
-          {this.renderEditMenu()}
-          {user.status !== 4 && this.renderStatusMenu()}
-          {user.status === 2 && this.renderAdminMenu()}
-        </DropdownMenu>
-      </UncontrolledDropdown>
-    );
-  }
-
-}
-
-const UserMenuWrapperFC = (props) => {
-  const { t } = useTranslation('admin');
-  return <UserMenu t={t} {...props} />;
-};
-
-const UserMenuWrapper = withUnstatedContainers(UserMenuWrapperFC, [AdminUsersContainer]);
-
-UserMenu.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-  adminUsersContainer: PropTypes.instanceOf(AdminUsersContainer).isRequired,
-
-  user: PropTypes.object.isRequired,
-};
-
-export default UserMenuWrapper;

+ 5 - 0
packages/app/src/components/Admin/Users/UserMenu.module.scss

@@ -0,0 +1,5 @@
+.grw-usermenu-notification-icon :global {
+  position: absolute;
+  top: -4px;
+  left: 30px;
+}

+ 114 - 0
packages/app/src/components/Admin/Users/UserMenu.tsx

@@ -0,0 +1,114 @@
+import React, { useState, useCallback } from 'react';
+
+import { IUserHasId, USER_STATUS } from '@growi/core';
+import { useTranslation } from 'next-i18next';
+import {
+  UncontrolledDropdown, DropdownToggle, DropdownMenu,
+} from 'reactstrap';
+
+import AdminUsersContainer from '~/client/services/AdminUsersContainer';
+
+import { withUnstatedContainers } from '../../UnstatedUtils';
+
+import GiveAdminButton from './GiveAdminButton';
+import RemoveAdminMenuItem from './RemoveAdminMenuItem';
+import SendInvitationEmailButton from './SendInvitationEmailButton';
+import StatusActivateButton from './StatusActivateButton';
+import StatusSuspendedMenuItem from './StatusSuspendMenuItem';
+import UserRemoveButton from './UserRemoveButton';
+
+import styles from './UserMenu.module.scss';
+
+type UserMenuProps = {
+  adminUsersContainer: AdminUsersContainer,
+  user: IUserHasId,
+}
+
+const UserMenu = (props: UserMenuProps) => {
+  const { t } = useTranslation('admin');
+
+  const { adminUsersContainer, user } = props;
+
+  const [isInvitationEmailSended, setIsInvitationEmailSended] = useState<boolean>(user.isInvitationEmailSended);
+
+  const onClickPasswordResetHandler = useCallback(async() => {
+    await adminUsersContainer.showPasswordResetModal(user);
+  }, [adminUsersContainer, user]);
+
+  const onSuccessfullySentInvitationEmailHandler = useCallback(() => {
+    setIsInvitationEmailSended(true);
+  }, []);
+
+  const renderEditMenu = useCallback(() => {
+    return (
+      <>
+        <li className="dropdown-divider"></li>
+        <li className="dropdown-header">{t('user_management.user_table.edit_menu')}</li>
+        <li>
+          <button className="dropdown-item" type="button" onClick={onClickPasswordResetHandler}>
+            <i className="icon-fw icon-key"></i>{ t('user_management.reset_password') }
+          </button>
+        </li>
+      </>
+    );
+  }, [onClickPasswordResetHandler, t]);
+
+  const renderStatusMenu = useCallback(() => {
+    return (
+      <>
+        <li className="dropdown-divider"></li>
+        <li className="dropdown-header">{t('user_management.status')}</li>
+        <li>
+          {(user.status === USER_STATUS.REGISTERED || user.status === USER_STATUS.SUSPENDED) && <StatusActivateButton user={user} />}
+          {user.status === USER_STATUS.ACTIVE && <StatusSuspendedMenuItem user={user} />}
+          {user.status === USER_STATUS.INVITED && (
+            <SendInvitationEmailButton
+              user={user}
+              isInvitationEmailSended={isInvitationEmailSended}
+              onSuccessfullySentInvitationEmail={onSuccessfullySentInvitationEmailHandler}
+            />
+          )}
+          {(user.status === USER_STATUS.REGISTERED || user.status === USER_STATUS.SUSPENDED || user.status === USER_STATUS.INVITED)
+          && <UserRemoveButton user={user} />}
+        </li>
+      </>
+    );
+  }, [isInvitationEmailSended, onSuccessfullySentInvitationEmailHandler, t, user]);
+
+  const renderAdminMenu = useCallback(() => {
+    return (
+      <>
+        <li className="dropdown-divider pl-0"></li>
+        <li className="dropdown-header">{t('user_management.user_table.administrator_menu')}</li>
+        <li>
+          {user.admin === true && <RemoveAdminMenuItem user={user} />}
+          {user.admin === false && <GiveAdminButton user={user} />}
+        </li>
+      </>
+    );
+  }, [t, user]);
+
+  return (
+    <UncontrolledDropdown id="userMenu" size="sm">
+      <DropdownToggle caret color="secondary" outline>
+        <i className="icon-settings" />
+        {(user.status === USER_STATUS.INVITED && !isInvitationEmailSended)
+        && <i className={`fa fa-circle text-danger grw-usermenu-notification-icon ${styles['grw-usermenu-notification-icon']}`} />}
+      </DropdownToggle>
+      <DropdownMenu positionFixed>
+        {renderEditMenu()}
+        {user.status !== USER_STATUS.DELETED && renderStatusMenu()}
+        {user.status === USER_STATUS.ACTIVE && renderAdminMenu()}
+      </DropdownMenu>
+    </UncontrolledDropdown>
+  );
+
+};
+
+/**
+* Wrapper component for using unstated
+*/
+// eslint-disable-next-line max-len
+const UserMenuWrapper: React.ForwardRefExoticComponent<Pick<any, string | number | symbol> & React.RefAttributes<any>> = withUnstatedContainers(UserMenu, [AdminUsersContainer]);
+
+export default UserMenuWrapper;

+ 1 - 1
packages/app/src/components/Common/ImageCropModal.tsx

@@ -158,7 +158,7 @@ const ImageCropModal: FC<Props> = (props: Props) => {
       </ModalBody>
       </ModalBody>
       <ModalFooter>
       <ModalFooter>
         <button type="button" className="btn btn-outline-danger rounded-pill mr-auto" disabled={!isCropImage} onClick={reset}>
         <button type="button" className="btn btn-outline-danger rounded-pill mr-auto" disabled={!isCropImage} onClick={reset}>
-          {t('crop_image_modal.reset')}
+          {t('commons:Reset')}
         </button>
         </button>
         { !showCropOption && (
         { !showCropOption && (
           <div className="mr-auto">
           <div className="mr-auto">

+ 4 - 2
packages/app/src/components/InAppNotification/InAppNotificationPage.tsx

@@ -64,7 +64,7 @@ export const InAppNotificationPage: FC = () => {
 
 
     if (notificationData == null) {
     if (notificationData == null) {
       return (
       return (
-        <div className="wiki">
+        <div className="wiki" data-testid="grw-in-app-notification-page-spinner">
           <div className="text-muted text-center">
           <div className="text-muted text-center">
             <i className="fa fa-2x fa-spinner fa-pulse mr-1"></i>
             <i className="fa fa-2x fa-spinner fa-pulse mr-1"></i>
           </div>
           </div>
@@ -138,7 +138,9 @@ export const InAppNotificationPage: FC = () => {
   };
   };
 
 
   return (
   return (
-    <CustomNavAndContents navTabMapping={navTabMapping} tabContentClasses={['mt-4']} />
+    <div data-testid="grw-in-app-notification-page">
+      <CustomNavAndContents navTabMapping={navTabMapping} tabContentClasses={['mt-4']} />
+    </div>
   );
   );
 };
 };
 
 

+ 1 - 1
packages/app/src/components/Navbar/AuthorInfo.module.scss

@@ -25,7 +25,7 @@ $date-font-size: 11px;
   }
   }
 }
 }
 
 
-.grw-author-info-skelton :global {
+.grw-author-info-skeleton :global {
   width: 139px;
   width: 139px;
   height: calc((#{$author-font-size} + #{$date-font-size}) * #{bs.$line-height-base});
   height: calc((#{$author-font-size} + #{$date-font-size}) * #{bs.$line-height-base});
 }
 }

+ 8 - 11
packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -35,7 +35,7 @@ import AttachmentIcon from '../Icons/AttachmentIcon';
 import HistoryIcon from '../Icons/HistoryIcon';
 import HistoryIcon from '../Icons/HistoryIcon';
 import PresentationIcon from '../Icons/PresentationIcon';
 import PresentationIcon from '../Icons/PresentationIcon';
 import ShareLinkIcon from '../Icons/ShareLinkIcon';
 import ShareLinkIcon from '../Icons/ShareLinkIcon';
-import { Skelton } from '../Skelton';
+import { Skeleton } from '../Skeleton';
 
 
 import type { AuthorInfoProps } from './AuthorInfo';
 import type { AuthorInfoProps } from './AuthorInfo';
 import { GrowiSubNavigation } from './GrowiSubNavigation';
 import { GrowiSubNavigation } from './GrowiSubNavigation';
@@ -45,22 +45,22 @@ import AuthorInfoStyles from './AuthorInfo.module.scss';
 import PageEditorModeManagerStyles from './PageEditorModeManager.module.scss';
 import PageEditorModeManagerStyles from './PageEditorModeManager.module.scss';
 
 
 
 
-const AuthorInfoSkelton = () => <Skelton additionalClass={`${AuthorInfoStyles['grw-author-info-skelton']} py-1`} />;
+const AuthorInfoSkeleton = () => <Skeleton additionalClass={`${AuthorInfoStyles['grw-author-info-skeleton']} py-1`} />;
 
 
 
 
 const PageEditorModeManager = dynamic(
 const PageEditorModeManager = dynamic(
   () => import('./PageEditorModeManager'),
   () => import('./PageEditorModeManager'),
-  { ssr: false, loading: () => <Skelton additionalClass={`${PageEditorModeManagerStyles['grw-page-editor-mode-manager-skelton']}`} /> },
+  { ssr: false, loading: () => <Skeleton additionalClass={`${PageEditorModeManagerStyles['grw-page-editor-mode-manager-skeleton']}`} /> },
 );
 );
 // TODO: If enable skeleton, we get hydration error when create a page from PageCreateModal
 // TODO: If enable skeleton, we get hydration error when create a page from PageCreateModal
-// { ssr: false, loading: () => <Skelton additionalClass='btn-skelton py-2' /> },
+// { ssr: false, loading: () => <Skeleton additionalClass='btn-skeleton py-2' /> },
 const SubNavButtons = dynamic<SubNavButtonsProps>(
 const SubNavButtons = dynamic<SubNavButtonsProps>(
   () => import('./SubNavButtons').then(mod => mod.SubNavButtons),
   () => import('./SubNavButtons').then(mod => mod.SubNavButtons),
   { ssr: false, loading: () => <></> },
   { ssr: false, loading: () => <></> },
 );
 );
 const AuthorInfo = dynamic<AuthorInfoProps>(() => import('./AuthorInfo').then(mod => mod.AuthorInfo), {
 const AuthorInfo = dynamic<AuthorInfoProps>(() => import('./AuthorInfo').then(mod => mod.AuthorInfo), {
   ssr: false,
   ssr: false,
-  loading: AuthorInfoSkelton,
+  loading: AuthorInfoSkeleton,
 });
 });
 
 
 type PageOperationMenuItemsProps = {
 type PageOperationMenuItemsProps = {
@@ -229,10 +229,7 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
 
 
   useEffect(() => {
   useEffect(() => {
     if (pageId === null && templateTagData != null) {
     if (pageId === null && templateTagData != null) {
-      const tags = templateTagData.split(',').filter((str: string) => {
-        return str !== ''; // filter empty values
-      });
-      mutatePageTagsForEditors(tags);
+      mutatePageTagsForEditors(templateTagData);
     }
     }
   }, [pageId, mutatePageTagsForEditors, templateTagData, mutateSWRTagsInfo]);
   }, [pageId, mutatePageTagsForEditors, templateTagData, mutateSWRTagsInfo]);
 
 
@@ -387,13 +384,13 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
               <li className="pb-1">
               <li className="pb-1">
                 { currentPage != null
                 { currentPage != null
                   ? <AuthorInfo user={currentPage.creator as IUser} date={currentPage.createdAt} mode="create" locate="subnav" />
                   ? <AuthorInfo user={currentPage.creator as IUser} date={currentPage.createdAt} mode="create" locate="subnav" />
-                  : <AuthorInfoSkelton />
+                  : <AuthorInfoSkeleton />
                 }
                 }
               </li>
               </li>
               <li className="mt-1 pt-1 border-top">
               <li className="mt-1 pt-1 border-top">
                 { currentPage != null
                 { currentPage != null
                   ? <AuthorInfo user={currentPage.lastUpdateUser as IUser} date={currentPage.updatedAt} mode="update" locate="subnav" />
                   ? <AuthorInfo user={currentPage.lastUpdateUser as IUser} date={currentPage.updatedAt} mode="update" locate="subnav" />
-                  : <AuthorInfoSkelton />
+                  : <AuthorInfoSkeleton />
                 }
                 }
               </li>
               </li>
             </ul>
             </ul>

+ 2 - 2
packages/app/src/components/Navbar/GrowiSubNavigation.module.scss

@@ -59,7 +59,7 @@
       }
       }
     }
     }
 
 
-    .btn-skelton {
+    .btn-skeleton {
       @extend %subnav-buttons-height;
       @extend %subnav-buttons-height;
       width: 100%;
       width: 100%;
     }
     }
@@ -140,7 +140,7 @@
         min-height: 90px;
         min-height: 90px;
       }
       }
 
 
-      .btn-skelton {
+      .btn-skeleton {
         @extend %compact-subnav-buttons-height;
         @extend %compact-subnav-buttons-height;
         width: 100%;
         width: 100%;
       }
       }

+ 3 - 3
packages/app/src/components/Navbar/GrowiSubNavigation.tsx

@@ -6,7 +6,7 @@ import {
   EditorMode, useEditorMode,
   EditorMode, useEditorMode,
 } from '~/stores/ui';
 } from '~/stores/ui';
 
 
-import { TagLabelsSkelton } from '../Page/TagLabels';
+import { TagLabelsSkeleton } from '../Page/TagLabels';
 import PagePathNav from '../PagePathNav';
 import PagePathNav from '../PagePathNav';
 
 
 import DrawerToggler from './DrawerToggler';
 import DrawerToggler from './DrawerToggler';
@@ -17,7 +17,7 @@ import styles from './GrowiSubNavigation.module.scss';
 
 
 const TagLabels = dynamic(() => import('../Page/TagLabels').then(mod => mod.TagLabels), {
 const TagLabels = dynamic(() => import('../Page/TagLabels').then(mod => mod.TagLabels), {
   ssr: false,
   ssr: false,
-  loading: TagLabelsSkelton,
+  loading: TagLabelsSkeleton,
 });
 });
 
 
 
 
@@ -71,7 +71,7 @@ export const GrowiSubNavigation = (props: GrowiSubNavigationProps): JSX.Element
             <div className="grw-taglabels-container">
             <div className="grw-taglabels-container">
               { tags != null
               { tags != null
                 ? <TagLabels tags={tags} isGuestUser={isGuestUser ?? false} tagsUpdateInvoked={tagsUpdatedHandler} />
                 ? <TagLabels tags={tags} isGuestUser={isGuestUser ?? false} tagsUpdateInvoked={tagsUpdatedHandler} />
-                : <TagLabelsSkelton />
+                : <TagLabelsSkeleton />
               }
               }
             </div>
             </div>
           ) }
           ) }

+ 1 - 1
packages/app/src/components/Navbar/PageEditorModeManager.module.scss

@@ -35,7 +35,7 @@ $btn-line-height: 1.2rem;
   }
   }
 }
 }
 
 
-.grw-page-editor-mode-manager-skelton :global {
+.grw-page-editor-mode-manager-skeleton :global {
 
 
   width: 213px;
   width: 213px;
   height: calc($btn-line-height + bs.$btn-padding-y*2 + bs.$btn-border-width*2);
   height: calc($btn-line-height + bs.$btn-padding-y*2 + bs.$btn-border-width*2);

+ 1 - 1
packages/app/src/components/Page/TagLabels.module.scss

@@ -11,7 +11,7 @@ $grw-tag-label-font-size: 12px;
 }
 }
 
 
 
 
-.grw-tag-labels-skelton :global {
+.grw-tag-labels-skeleton :global {
   width: 137px;
   width: 137px;
   height: calc(#{$grw-tag-label-font-size} + #{bs.$badge-padding-y} * 2);
   height: calc(#{$grw-tag-label-font-size} + #{bs.$badge-padding-y} * 2);
   font-size: $grw-tag-label-font-size; // set font-size to use the same em value in bs.$badge-padding-y(https://getbootstrap.jp/docs/5.0/components/badge/#variables)
   font-size: $grw-tag-label-font-size; // set font-size to use the same em value in bs.$badge-padding-y(https://getbootstrap.jp/docs/5.0/components/badge/#variables)

+ 4 - 4
packages/app/src/components/Page/TagLabels.tsx

@@ -1,6 +1,6 @@
 import React, { FC, useState } from 'react';
 import React, { FC, useState } from 'react';
 
 
-import { Skelton } from '../Skelton';
+import { Skeleton } from '../Skeleton';
 
 
 import RenderTagLabels from './RenderTagLabels';
 import RenderTagLabels from './RenderTagLabels';
 import TagEditModal from './TagEditModal';
 import TagEditModal from './TagEditModal';
@@ -13,8 +13,8 @@ type Props = {
   tagsUpdateInvoked?: (tags: string[]) => Promise<void> | void,
   tagsUpdateInvoked?: (tags: string[]) => Promise<void> | void,
 }
 }
 
 
-export const TagLabelsSkelton = (): JSX.Element => {
-  return <Skelton additionalClass={`${styles['grw-tag-labels-skelton']} py-1`} />;
+export const TagLabelsSkeleton = (): JSX.Element => {
+  return <Skeleton additionalClass={`${styles['grw-tag-labels-skeleton']} py-1`} />;
 };
 };
 
 
 export const TagLabels:FC<Props> = (props: Props) => {
 export const TagLabels:FC<Props> = (props: Props) => {
@@ -31,7 +31,7 @@ export const TagLabels:FC<Props> = (props: Props) => {
   };
   };
 
 
   if (tags == null) {
   if (tags == null) {
-    return <TagLabelsSkelton />;
+    return <TagLabelsSkeleton />;
   }
   }
 
 
   return (
   return (

+ 1 - 1
packages/app/src/components/PageComment.module.scss

@@ -14,7 +14,7 @@
   }
   }
 
 
   // TODO: Refacotr Soft-coding
   // TODO: Refacotr Soft-coding
-  .page-comment-button-skelton {
+  .page-comment-button-skeleton {
     width: 70.0167px;
     width: 70.0167px;
     height: 26.3833px;
     height: 26.3833px;
     margin-top: 0.5em;
     margin-top: 0.5em;

+ 2 - 2
packages/app/src/components/PageComment.tsx

@@ -18,7 +18,7 @@ import { Comment } from './PageComment/Comment';
 import { CommentEditorProps } from './PageComment/CommentEditor';
 import { CommentEditorProps } from './PageComment/CommentEditor';
 import { DeleteCommentModalProps } from './PageComment/DeleteCommentModal';
 import { DeleteCommentModalProps } from './PageComment/DeleteCommentModal';
 import { ReplyComments } from './PageComment/ReplyComments';
 import { ReplyComments } from './PageComment/ReplyComments';
-import { PageCommentSkelton } from './PageCommentSkelton';
+import { PageCommentSkeleton } from './PageCommentSkeleton';
 
 
 import styles from './PageComment.module.scss';
 import styles from './PageComment.module.scss';
 
 
@@ -123,7 +123,7 @@ export const PageComment: FC<PageCommentProps> = memo((props:PageCommentProps):
       return <PageCommentRoot />;
       return <PageCommentRoot />;
     }
     }
     return (
     return (
-      <PageCommentSkelton commentTitleClasses={commentTitleClasses}/>
+      <PageCommentSkeleton commentTitleClasses={commentTitleClasses}/>
     );
     );
   }
   }
 
 

+ 1 - 1
packages/app/src/components/PageComment/Comment.module.scss

@@ -86,7 +86,7 @@
   }
   }
 
 
   // TODO: Refacotr Soft-coding
   // TODO: Refacotr Soft-coding
-  .page-comment-comment-body-skelton {
+  .page-comment-comment-body-skeleton {
     position: relative;
     position: relative;
     height: 66px;
     height: 66px;
     padding: 1em;
     padding: 1em;

+ 10 - 10
packages/app/src/components/PageCommentSkelton.tsx → packages/app/src/components/PageCommentSkeleton.tsx

@@ -1,17 +1,17 @@
 import React from 'react';
 import React from 'react';
 
 
-import { Skelton } from './Skelton';
+import { Skeleton } from './Skeleton';
 
 
 import styles from './PageComment.module.scss';
 import styles from './PageComment.module.scss';
 import CommentStyles from './PageComment/Comment.module.scss';
 import CommentStyles from './PageComment/Comment.module.scss';
 import CommentEditorStyles from './PageComment/CommentEditor.module.scss';
 import CommentEditorStyles from './PageComment/CommentEditor.module.scss';
 
 
-type PageCommentSkeltonProps = {
+type PageCommentSkeletonProps = {
   commentTitleClasses?: string,
   commentTitleClasses?: string,
   roundedPill?: boolean,
   roundedPill?: boolean,
 }
 }
 
 
-export const PageCommentSkelton = (props: PageCommentSkeltonProps): JSX.Element => {
+export const PageCommentSkeleton = (props: PageCommentSkeletonProps): JSX.Element => {
   const {
   const {
     commentTitleClasses,
     commentTitleClasses,
   } = props;
   } = props;
@@ -27,27 +27,27 @@ export const PageCommentSkelton = (props: PageCommentSkeltonProps): JSX.Element
               <div className={`${CommentStyles['comment-styles']} page-comment-thread pb-5  page-comment-thread-no-replies`}>
               <div className={`${CommentStyles['comment-styles']} page-comment-thread pb-5  page-comment-thread-no-replies`}>
                 <div className='page-comment flex-column'>
                 <div className='page-comment flex-column'>
                   <div className='page-commnet-writer'>
                   <div className='page-commnet-writer'>
-                    <Skelton additionalClass='rounded-circle picture' roundedPill />
+                    <Skeleton additionalClass='rounded-circle picture' roundedPill />
                   </div>
                   </div>
-                  <Skelton additionalClass="page-comment-comment-body-skelton grw-skelton" />
+                  <Skeleton additionalClass="page-comment-comment-body-skeleton grw-skeleton" />
                 </div>
                 </div>
                 <div className='page-comment flex-column ml-4 ml-sm-5 mr-3'>
                 <div className='page-comment flex-column ml-4 ml-sm-5 mr-3'>
                   <div className='page-commnet-writer mt-3'>
                   <div className='page-commnet-writer mt-3'>
-                    <Skelton additionalClass='rounded-circle picture' roundedPill />
+                    <Skeleton additionalClass='rounded-circle picture' roundedPill />
                   </div>
                   </div>
-                  <Skelton additionalClass="page-comment-comment-body-skelton grw-skelton mt-3" />
+                  <Skeleton additionalClass="page-comment-comment-body-skeleton grw-skeleton mt-3" />
                 </div>
                 </div>
                 <div className="text-right">
                 <div className="text-right">
-                  <Skelton additionalClass="page-comment-button-skelton btn btn-outline-secondary btn-sm grw-skelton" />
+                  <Skeleton additionalClass="page-comment-button-skeleton btn btn-outline-secondary btn-sm grw-skeleton" />
                 </div>
                 </div>
               </div>
               </div>
             </div>
             </div>
             <div className={`${CommentEditorStyles['comment-editor-styles']} form page-comment-form`}>
             <div className={`${CommentEditorStyles['comment-editor-styles']} form page-comment-form`}>
               <div className='comment-form'>
               <div className='comment-form'>
                 <div className='comment-form-user'>
                 <div className='comment-form-user'>
-                  <Skelton additionalClass='rounded-circle picture' roundedPill />
+                  <Skeleton additionalClass='rounded-circle picture' roundedPill />
                 </div>
                 </div>
-                <Skelton additionalClass="page-comment-commenteditorlazyrenderer-body-skelton grw-skelton" />
+                <Skeleton additionalClass="page-comment-commenteditorlazyrenderer-body-skeleton grw-skeleton" />
               </div>
               </div>
             </div>
             </div>
           </div>
           </div>

+ 1 - 1
packages/app/src/components/PageContentFooter.module.scss

@@ -7,7 +7,7 @@
   }
   }
 }
 }
 // TODO: Should Soft Coding see: https://github.com/weseek/growi/pull/6404
 // TODO: Should Soft Coding see: https://github.com/weseek/growi/pull/6404
-.page-content-footer-skelton :global {
+.page-content-footer-skeleton :global {
   width: 300px;
   width: 300px;
   height: 20px;
   height: 20px;
 }
 }

+ 2 - 2
packages/app/src/components/PageContentFooter.tsx

@@ -6,13 +6,13 @@ import dynamic from 'next/dynamic';
 import { useSWRxCurrentPage } from '~/stores/page';
 import { useSWRxCurrentPage } from '~/stores/page';
 
 
 import type { AuthorInfoProps } from './Navbar/AuthorInfo';
 import type { AuthorInfoProps } from './Navbar/AuthorInfo';
-import { Skelton } from './Skelton';
+import { Skeleton } from './Skeleton';
 
 
 import styles from './PageContentFooter.module.scss';
 import styles from './PageContentFooter.module.scss';
 
 
 const AuthorInfo = dynamic<AuthorInfoProps>(() => import('./Navbar/AuthorInfo').then(mod => mod.AuthorInfo), {
 const AuthorInfo = dynamic<AuthorInfoProps>(() => import('./Navbar/AuthorInfo').then(mod => mod.AuthorInfo), {
   ssr: false,
   ssr: false,
-  loading: () => <Skelton additionalClass={`${styles['page-content-footer-skelton']} mb-3`} />,
+  loading: () => <Skeleton additionalClass={`${styles['page-content-footer-skeleton']} mb-3`} />,
 });
 });
 
 
 export type PageContentFooterProps = {
 export type PageContentFooterProps = {

+ 1 - 1
packages/app/src/components/PageEditor/HandsontableModal.tsx

@@ -495,7 +495,7 @@ export const HandsontableModal = (): JSX.Element => {
         </div>
         </div>
       </ModalBody>
       </ModalBody>
       <ModalFooter className="grw-modal-footer">
       <ModalFooter className="grw-modal-footer">
-        <button type="button" className="btn btn-danger" onClick={reset}>{t('handsontable_modal.reset')}</button>
+        <button type="button" className="btn btn-danger" onClick={reset}>{t('commons:Reset')}</button>
         <div className="ml-auto">
         <div className="ml-auto">
           <button type="button" className="mr-2 btn btn-secondary" onClick={cancel}>{t('handsontable_modal.cancel')}</button>
           <button type="button" className="mr-2 btn btn-secondary" onClick={cancel}>{t('handsontable_modal.cancel')}</button>
           <button type="button" className="btn btn-primary" onClick={save}>{t('handsontable_modal.done')}</button>
           <button type="button" className="btn btn-primary" onClick={save}>{t('handsontable_modal.done')}</button>

+ 3 - 3
packages/app/src/components/Skelton.tsx → packages/app/src/components/Skeleton.tsx

@@ -1,18 +1,18 @@
 import React from 'react';
 import React from 'react';
 
 
-type SkeltonProps = {
+type SkeletonProps = {
   additionalClass?: string,
   additionalClass?: string,
   roundedPill?: boolean,
   roundedPill?: boolean,
 }
 }
 
 
-export const Skelton = (props: SkeltonProps): JSX.Element => {
+export const Skeleton = (props: SkeletonProps): JSX.Element => {
   const {
   const {
     additionalClass, roundedPill,
     additionalClass, roundedPill,
   } = props;
   } = props;
 
 
   return (
   return (
     <div className={`${additionalClass ?? ''}`}>
     <div className={`${additionalClass ?? ''}`}>
-      <div className={`grw-skelton h-100 w-100 ${roundedPill ?? ''}`}></div>
+      <div className={`grw-skeleton h-100 w-100 ${roundedPill ?? ''}`}></div>
     </div>
     </div>
   );
   );
 };
 };

+ 15 - 2
packages/app/src/pages/[[...path]].page.tsx

@@ -62,7 +62,7 @@ import {
   useIsEnabledStaleNotification, useIsIdenticalPath,
   useIsEnabledStaleNotification, useIsIdenticalPath,
   useIsSearchServiceConfigured, useIsSearchServiceReachable, useDisableLinkSharing,
   useIsSearchServiceConfigured, useIsSearchServiceReachable, useDisableLinkSharing,
   useDrawioUri, useHackmdUri, useDefaultIndentSize, useIsIndentSizeForced,
   useDrawioUri, useHackmdUri, useDefaultIndentSize, useIsIndentSizeForced,
-  useIsAclEnabled, useIsSearchPage,
+  useIsAclEnabled, useIsSearchPage, useTemplateTagData,
   useCsrfToken, useIsSearchScopeChildrenAsDefault, useCurrentPageId, useCurrentPathname,
   useCsrfToken, useIsSearchScopeChildrenAsDefault, useCurrentPageId, useCurrentPathname,
   useIsSlackConfigured, useRendererConfig, useEditingMarkdown,
   useIsSlackConfigured, useRendererConfig, useEditingMarkdown,
   useEditorConfig, useIsAllReplyShown, useIsUploadableFile, useIsUploadableImage, useCustomizedLogoSrc, useIsContainerFluid,
   useEditorConfig, useIsAllReplyShown, useIsUploadableFile, useIsUploadableImage, useCustomizedLogoSrc, useIsContainerFluid,
@@ -144,6 +144,9 @@ type Props = CommonProps & {
   isNotCreatablePage: boolean,
   isNotCreatablePage: boolean,
   // isAbleToDeleteCompletely: boolean,
   // isAbleToDeleteCompletely: boolean,
 
 
+  templateTagData?: string[],
+  templateBodyData?: string,
+
   isSearchServiceConfigured: boolean,
   isSearchServiceConfigured: boolean,
   isSearchServiceReachable: boolean,
   isSearchServiceReachable: boolean,
   isSearchScopeChildrenAsDefault: boolean,
   isSearchScopeChildrenAsDefault: boolean,
@@ -213,6 +216,8 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   useIsEnabledStaleNotification(props.isEnabledStaleNotification);
   useIsEnabledStaleNotification(props.isEnabledStaleNotification);
   useIsSearchPage(false);
   useIsSearchPage(false);
 
 
+  useTemplateTagData(props.templateTagData);
+
   useIsSearchServiceConfigured(props.isSearchServiceConfigured);
   useIsSearchServiceConfigured(props.isSearchServiceConfigured);
   useIsSearchServiceReachable(props.isSearchServiceReachable);
   useIsSearchServiceReachable(props.isSearchServiceReachable);
   useIsSearchScopeChildrenAsDefault(props.isSearchScopeChildrenAsDefault);
   useIsSearchScopeChildrenAsDefault(props.isSearchScopeChildrenAsDefault);
@@ -246,7 +251,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   useCurrentRevisionId(props.currentRevisionId);
   useCurrentRevisionId(props.currentRevisionId);
 
 
   const { data: currentPage } = useSWRxCurrentPage(undefined, pageWithMeta?.data ?? null); // store initial data
   const { data: currentPage } = useSWRxCurrentPage(undefined, pageWithMeta?.data ?? null); // store initial data
-  useEditingMarkdown(pageWithMeta?.data.revision?.body ?? '');
+  useEditingMarkdown(pageWithMeta?.data.revision?.body ?? props.templateBodyData ?? '');
 
 
   const { data: grantData } = useSWRxIsGrantNormalized(pageId);
   const { data: grantData } = useSWRxIsGrantNormalized(pageId);
   const { mutate: mutateSelectedGrant } = useSelectedGrant();
   const { mutate: mutateSelectedGrant } = useSelectedGrant();
@@ -421,6 +426,14 @@ async function injectPageData(context: GetServerSidePropsContext, props: Props):
     props.currentRevisionId = props.isLatestRevision && page.latestRevision != null ? page.latestRevision.toString() : revisionId;
     props.currentRevisionId = props.isLatestRevision && page.latestRevision != null ? page.latestRevision.toString() : revisionId;
   }
   }
 
 
+  if (page == null && user != null) {
+    const templateData = await Page.findTemplate(props.currentPathname);
+    if (templateData != null) {
+      props.templateTagData = templateData.templateTags as string[];
+      props.templateBodyData = templateData.templateBody as string;
+    }
+  }
+
   props.pageWithMeta = pageWithMeta;
   props.pageWithMeta = pageWithMeta;
 }
 }
 
 

+ 2 - 2
packages/app/src/stores/context.tsx

@@ -72,8 +72,8 @@ export const useIsNotFound = (initialData?: boolean): SWRResponse<boolean, Error
   return useContextSWR<boolean, Error>('isNotFound', initialData, { fallbackData: false });
   return useContextSWR<boolean, Error>('isNotFound', initialData, { fallbackData: false });
 };
 };
 
 
-export const useTemplateTagData = (initialData?: Nullable<string>): SWRResponse<Nullable<string>, Error> => {
-  return useContextSWR<Nullable<string>, Error>('templateTagData', initialData);
+export const useTemplateTagData = (initialData?: string[]): SWRResponse<string[], Error> => {
+  return useContextSWR<string[], Error>('templateTagData', initialData);
 };
 };
 
 
 export const useIsSharedUser = (initialData?: boolean): SWRResponse<boolean, Error> => {
 export const useIsSharedUser = (initialData?: boolean): SWRResponse<boolean, Error> => {

+ 0 - 5
packages/app/src/styles/_user.scss

@@ -8,11 +8,6 @@ $easeInOutCubic: cubic-bezier(0.65, 0, 0.35, 1);
 /*
 /*
  * Styles
  * Styles
  */
  */
-.grw-usermenu-notification-icon {
-  position: absolute;
-  top: -4px;
-  left: 30px;
-}
 
 
 .draft-list-item {
 .draft-list-item {
   .icon-container {
   .icon-container {

+ 2 - 2
packages/app/src/styles/theme/_apply-colors-dark.scss

@@ -524,8 +524,8 @@ ul.pagination {
 }
 }
 
 
 /*
 /*
- * skelton
+ * skeleton
  */
  */
-.grw-skelton {
+.grw-skeleton {
   background-color: lighten($bgcolor-subnav, 15%);
   background-color: lighten($bgcolor-subnav, 15%);
 }
 }

+ 2 - 2
packages/app/src/styles/theme/_apply-colors-light.scss

@@ -416,8 +416,8 @@ $dropdown-link-active-bg: $bgcolor-dropdown-link-active;
 }
 }
 
 
 /*
 /*
- * skelton
+ * skeleton
  */
  */
-.grw-skelton {
+.grw-skeleton {
   background-color: darken($bgcolor-subnav, 10%);
   background-color: darken($bgcolor-subnav, 10%);
 }
 }

+ 64 - 34
packages/app/test/cypress/integration/20-basic-features/access-to-page.spec.ts

@@ -17,6 +17,7 @@ context('Access to page', () => {
 
 
   it('/Sandbox with anchor hash is successfully loaded', () => {
   it('/Sandbox with anchor hash is successfully loaded', () => {
     cy.visit('/Sandbox#Headers');
     cy.visit('/Sandbox#Headers');
+    cy.waitUntilSkeletonDisappear();
 
 
     // hide fab // disable fab for sticky-events warning
     // hide fab // disable fab for sticky-events warning
     // cy.getByTestid('grw-fab-container').invoke('attr', 'style', 'display: none');
     // cy.getByTestid('grw-fab-container').invoke('attr', 'style', 'display: none');
@@ -26,7 +27,6 @@ context('Access to page', () => {
     // https://stackoverflow.com/questions/5041494/selecting-and-manipulating-css-pseudo-elements-such-as-before-and-after-usin/21709814#21709814
     // https://stackoverflow.com/questions/5041494/selecting-and-manipulating-css-pseudo-elements-such-as-before-and-after-usin/21709814#21709814
     cy.get('#mdcont-headers').invoke('removeClass', 'blink');
     cy.get('#mdcont-headers').invoke('removeClass', 'blink');
 
 
-    cy.get('.grw-skelton').should('not.exist');
     cy.screenshot(`${ssPrefix}-sandbox-headers`);
     cy.screenshot(`${ssPrefix}-sandbox-headers`);
   });
   });
 
 
@@ -41,8 +41,12 @@ context('Access to page', () => {
 
 
   it('/Sandbox with edit is successfully loaded', () => {
   it('/Sandbox with edit is successfully loaded', () => {
     cy.visit('/Sandbox');
     cy.visit('/Sandbox');
-    cy.get('.grw-skelton', { timeout: 30000 }).should('not.exist');
-    cy.get('#grw-subnav-container', { timeout: 30000 }).should('be.visible').within(()=>{
+    cy.waitUntilSkeletonDisappear();
+
+    cy.get('#grw-subnav-container', { timeout: 30000 }).should('be.visible').within(() => {
+
+      // eslint-disable-next-line cypress/no-unnecessary-waiting
+      cy.wait(2000);
       cy.getByTestid('editor-button', { timeout: 30000 }).should('be.visible').click();
       cy.getByTestid('editor-button', { timeout: 30000 }).should('be.visible').click();
     })
     })
     cy.getByTestid('navbar-editor', { timeout: 30000 }).should('be.visible');
     cy.getByTestid('navbar-editor', { timeout: 30000 }).should('be.visible');
@@ -52,7 +56,7 @@ context('Access to page', () => {
   it('/user/admin is successfully loaded', () => {
   it('/user/admin is successfully loaded', () => {
     cy.visit('/user/admin', {  });
     cy.visit('/user/admin', {  });
 
 
-    cy.get('.grw-skelton').should('not.exist');
+    cy.waitUntilSkeletonDisappear();
     // for check download toc data
     // for check download toc data
     cy.get('.toc-link').should('be.visible');
     cy.get('.toc-link').should('be.visible');
 
 
@@ -141,34 +145,57 @@ context('Access to Template Editing Mode', () => {
     cy.collapseSidebar(true);
     cy.collapseSidebar(true);
   });
   });
 
 
+  // TODO: 109057
+  // it('Access to Template Editor mode for only child pages successfully', () => {
+  //   cy.visit('/Sandbox/Bootstrap4', {  });
+  //   cy.waitUntilSkeletonDisappear();
+
+  //   cy.get('#grw-subnav-container').within(() => {
+  //     cy.getByTestid('open-page-item-control-btn').should('be.visible');
+  //     cy.getByTestid('open-page-item-control-btn').click();
+  //     cy.getByTestid('open-page-template-modal-btn').should('be.visible');
+  //     cy.getByTestid('open-page-template-modal-btn').click();
+  //   });
+
+  //   cy.getByTestid('page-template-modal').should('be.visible');
+  //   cy.screenshot(`${ssPrefix}-open-page-template-bootstrap4`);
+
+  // Todo: `@`alias may be changed. This code was made in an attempt to solve the error of element being dettached from the dom which couldn't be solved at this time.
+  // Wait for Todo: 109057 is solved and fix or leave the code below for better test code.
+  //   cy.getByTestid('template-button-children').as('template-button-children');
+  //   cy.get('@template-button-children').should('be.visible').click();
+  //   cy.waitUntilSkeletonDisappear();
+
+  //   cy.getByTestid('navbar-editor').should('be.visible').then(()=>{
+  //     cy.url().should('include', '/_template#edit');
+  //     cy.screenshot();
+  //   });
+  // });
 
 
-  it('Access to Template Editor mode for only child pages successfully', () => {
-     cy.visit('/Sandbox/Bootstrap4', {  });
-     cy.get('#grw-subnav-container').within(() => {
-       cy.getByTestid('open-page-item-control-btn').click();
-       cy.getByTestid('open-page-template-modal-btn').click();
-    });
-
-     cy.getByTestid('page-template-modal').should('be.visible')
-     cy.screenshot(`${ssPrefix}-open-page-template-bootstrap4`);
-     cy.getByTestid('template-button-children').click();
-     cy.url().should('include', '/_template#edit');
-     cy.screenshot();
-  });
-
-  it('Access to Template Editor mode including decendants successfully', () => {
-    cy.visit('/Sandbox/Bootstrap4', {  });
-    cy.get('#grw-subnav-container').within(() => {
-      cy.getByTestid('open-page-item-control-btn').click();
-      cy.getByTestid('open-page-template-modal-btn').click();
-   });
-
-    cy.getByTestid('page-template-modal').should('be.visible')
-    // cy.screenshot(`${ssPrefix}-open-page-template-bootstrap4`);
-    cy.getByTestid('template-button-decendants').click();
-    cy.url().should('include', '/__template#edit');
-    cy.screenshot();
- });
+  // TODO: 109057
+  // it('Access to Template Editor mode including decendants successfully', () => {
+  //   cy.visit('/Sandbox/Bootstrap4', {  });
+  //   cy.waitUntilSkeletonDisappear();
+
+  //   cy.get('#grw-subnav-container').within(() => {
+  //     cy.getByTestid('open-page-item-control-btn').should('be.visible');
+  //     cy.getByTestid('open-page-item-control-btn').click();
+  //     cy.getByTestid('open-page-template-modal-btn').should('be.visible');
+  //     cy.getByTestid('open-page-template-modal-btn').click();
+  //   });
+  //   cy.getByTestid('page-template-modal').should('be.visible');
+
+  // Todo: `@`alias may be changed. This code was made in an attempt to solve the error of element being dettached from the dom which couldn't be solved at this time.
+  // Wait for Todo: 109057 is solved and fix or leave the code below for better test code.
+  //   cy.getByTestid('template-button-decendants').as('template-button-decendants');
+  //   cy.get('@template-button-decendants').should('be.visible').click();
+  //   cy.waitUntilSkeletonDisappear();
+
+  //   cy.getByTestid('navbar-editor').should('be.visible').then(()=>{
+  //     cy.url().should('include', '/__template#edit');
+  //     cy.screenshot();
+  //   });
+  // });
 
 
 });
 });
 
 
@@ -184,17 +211,20 @@ context('Access to /me/all-in-app-notifications', () => {
     cy.collapseSidebar(true);
     cy.collapseSidebar(true);
   });
   });
 
 
-  it('All In-App Notification list is successfully loaded', () => {
+  it('All In-App Notification list is successfully loaded', { scrollBehavior: false },() => {
     cy.visit('/');
     cy.visit('/');
-    cy.get('.notification-wrapper > a').click();
+    cy.get('.notification-wrapper').click();
     cy.get('.notification-wrapper > .dropdown-menu > a').click();
     cy.get('.notification-wrapper > .dropdown-menu > a').click();
 
 
+    cy.getByTestid('grw-in-app-notification-page').should('be.visible');
+    cy.getByTestid('grw-in-app-notification-page-spinner').should('not.exist');
+
     cy.screenshot(`${ssPrefix}-see-all`, { capture: 'viewport' });
     cy.screenshot(`${ssPrefix}-see-all`, { capture: 'viewport' });
 
 
     cy.get('.grw-custom-nav-tab > div > ul > li:nth-child(2) > a').click();
     cy.get('.grw-custom-nav-tab > div > ul > li:nth-child(2) > a').click();
+    cy.getByTestid('grw-in-app-notification-page-spinner').should('not.exist');
 
 
     cy.screenshot(`${ssPrefix}-see-unread`, { capture: 'viewport' });
     cy.screenshot(`${ssPrefix}-see-unread`, { capture: 'viewport' });
    });
    });
 
 
 })
 })
-

+ 1 - 1
packages/app/test/cypress/integration/20-basic-features/click-page-icons.spec.ts

@@ -77,7 +77,7 @@ context('Click page icons button', () => {
 
 
   it('Successfully display list of "seen by user"', () => {
   it('Successfully display list of "seen by user"', () => {
     cy.visit('/Sandbox');
     cy.visit('/Sandbox');
-    cy.get('.grw-skelton').should('not.exist');
+    cy.waitUntilSkeletonDisappear();
     // eslint-disable-next-line cypress/no-unnecessary-waiting
     // eslint-disable-next-line cypress/no-unnecessary-waiting
     cy.wait(2000); // wait for get method
     cy.wait(2000); // wait for get method
     cy.get('#grw-subnav-container').within(() => {
     cy.get('#grw-subnav-container').within(() => {

+ 1 - 0
packages/app/test/cypress/integration/20-basic-features/use-tools.spec.ts

@@ -191,6 +191,7 @@ context('Page Accessories Modal', () => {
      cy.visit('/Sandbox/Bootstrap4', {  });
      cy.visit('/Sandbox/Bootstrap4', {  });
      cy.get('#grw-subnav-container').within(() => {
      cy.get('#grw-subnav-container').within(() => {
       cy.getByTestid('open-page-item-control-btn').within(() => {
       cy.getByTestid('open-page-item-control-btn').within(() => {
+        cy.getByTestid('open-page-item-control-btn').should('be.visible');
         cy.get('button.btn-page-item-control').click({force: true});
         cy.get('button.btn-page-item-control').click({force: true});
       });
       });
        cy.getByTestid('open-page-accessories-modal-btn-with-attachment-data-tab').click();
        cy.getByTestid('open-page-accessories-modal-btn-with-attachment-data-tab').click();

+ 1 - 0
packages/app/test/cypress/integration/21-basic-features-for-guest/access-to-page.spec.ts

@@ -3,6 +3,7 @@ context('Access to page by guest', () => {
 
 
   it('/Sandbox is successfully loaded', () => {
   it('/Sandbox is successfully loaded', () => {
     cy.visit('/Sandbox');
     cy.visit('/Sandbox');
+    cy.waitUntilSpinnerDisappear();
     cy.getByTestid('grw-pagetree-item-container').should('be.visible');
     cy.getByTestid('grw-pagetree-item-container').should('be.visible');
     cy.collapseSidebar(true, true);
     cy.collapseSidebar(true, true);
     cy.screenshot(`${ssPrefix}-sandbox`);
     cy.screenshot(`${ssPrefix}-sandbox`);

+ 2 - 0
packages/app/test/cypress/integration/30-search/search.spec.ts

@@ -155,6 +155,8 @@ context('Search all pages', () => {
     const tag = 'help';
     const tag = 'help';
     const searchText = `tag:${tag}`;
     const searchText = `tag:${tag}`;
     cy.visit('/');
     cy.visit('/');
+    cy.waitUntilSkeletonDisappear();
+
     // Add tag
     // Add tag
     cy.get('#edit-tags-btn-wrapper-for-tooltip > a').click({force: true});
     cy.get('#edit-tags-btn-wrapper-for-tooltip > a').click({force: true});
     cy.get('#edit-tag-modal').should('be.visible');
     cy.get('#edit-tag-modal').should('be.visible');

+ 1 - 1
packages/app/test/cypress/integration/50-sidebar/access-to-side-bar.spec.ts

@@ -165,7 +165,7 @@ context('Access to sidebar', () => {
   //   });
   //   });
   //   cy.screenshot(`${ssPrefix}access-to-drafts-page`);
   //   cy.screenshot(`${ssPrefix}access-to-drafts-page`);
   // });
   // });
-  it('Successfully access to Growi Docs page', () => {
+  it('Successfully access to GROWI Docs page', () => {
     cy.visit('/');
     cy.visit('/');
     cy.get('.grw-sidebar-nav-secondary-container').within(() => {
     cy.get('.grw-sidebar-nav-secondary-container').within(() => {
       cy.get('a[href*="https://docs.growi.org"]').then(($a) => {
       cy.get('a[href*="https://docs.growi.org"]').then(($a) => {

+ 4 - 4
packages/app/test/cypress/integration/60-home/home.spec.ts

@@ -15,13 +15,13 @@ context('Access Home', () => {
     cy.getByTestid('grw-personal-dropdown').click();
     cy.getByTestid('grw-personal-dropdown').click();
     cy.getByTestid('grw-personal-dropdown').find('.dropdown-menu .btn-group > .btn-outline-secondary:eq(0)').click();
     cy.getByTestid('grw-personal-dropdown').find('.dropdown-menu .btn-group > .btn-outline-secondary:eq(0)').click();
 
 
-    cy.get('.grw-skelton').should('not.exist');
-    // for check download toc data
-    cy.get('.toc-link').should('be.visible');
-
     // eslint-disable-next-line cypress/no-unnecessary-waiting
     // eslint-disable-next-line cypress/no-unnecessary-waiting
     cy.wait(2000); // wait for calcViewHeight and rendering
     cy.wait(2000); // wait for calcViewHeight and rendering
 
 
+    cy.waitUntilSkeletonDisappear();
+    // for check download toc data
+    cy.get('.toc-link').should('be.visible');
+
     // same screenshot is taken in access-to-page.spec
     // same screenshot is taken in access-to-page.spec
     cy.screenshot(`${ssPrefix}-visit-home`);
     cy.screenshot(`${ssPrefix}-visit-home`);
   });
   });

+ 13 - 0
packages/app/test/cypress/support/commands.ts

@@ -41,6 +41,19 @@ Cypress.Commands.add('login', (username, password) => {
   });
   });
 });
 });
 
 
+/**
+ * use only for the pages which use component with skeleton
+ */
+Cypress.Commands.add('waitUntilSkeletonDisappear', () => {
+  cy.get('.grw-skeleton').should('exist');
+  cy.get('.grw-skeleton').should('not.exist');
+});
+
+Cypress.Commands.add('waitUntilSpinnerDisappear', () => {
+  cy.get('.fa-spinner').should('exist');
+  cy.get('.fa-spinner').should('not.exist');
+});
+
 let isSidebarCollapsed: boolean | undefined;
 let isSidebarCollapsed: boolean | undefined;
 
 
 Cypress.Commands.add('collapseSidebar', (isCollapsed, force=false) => {
 Cypress.Commands.add('collapseSidebar', (isCollapsed, force=false) => {

+ 2 - 0
packages/app/test/cypress/support/index.ts

@@ -37,6 +37,8 @@ declare global {
        getByTestid(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<Element>>,
        getByTestid(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<Element>>,
        login(username: string, password: string): Chainable<void>,
        login(username: string, password: string): Chainable<void>,
        collapseSidebar(isCollapsed: boolean, force?: boolean): Chainable<void>,
        collapseSidebar(isCollapsed: boolean, force?: boolean): Chainable<void>,
+       waitUntilSkeletonDisappear(): Chainable<void>,
+       waitUntilSpinnerDisappear(): Chainable<void>,
     }
     }
   }
   }
 }
 }

+ 1 - 1
packages/codemirror-textlint/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@growi/codemirror-textlint",
   "name": "@growi/codemirror-textlint",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "license": "MIT",
   "license": "MIT",
   "main": "dist/index.js",
   "main": "dist/index.js",
   "scripts": {
   "scripts": {

+ 1 - 1
packages/core/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@growi/core",
   "name": "@growi/core",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "description": "GROWI Core Libraries",
   "description": "GROWI Core Libraries",
   "license": "MIT",
   "license": "MIT",
   "keywords": [
   "keywords": [

+ 11 - 1
packages/core/src/interfaces/user.ts

@@ -15,12 +15,13 @@ export type IUser = {
   admin: boolean,
   admin: boolean,
   apiToken?: string,
   apiToken?: string,
   isEmailPublished: boolean,
   isEmailPublished: boolean,
+  isInvitationEmailSended: boolean,
   lang: Lang,
   lang: Lang,
   slackMemberId?: string,
   slackMemberId?: string,
   createdAt: Date,
   createdAt: Date,
   lastLoginAt?: Date,
   lastLoginAt?: Date,
   introduction: string,
   introduction: string,
-  status: number,
+  status: IUserStatus,
 }
 }
 
 
 export type IUserGroupRelation = {
 export type IUserGroupRelation = {
@@ -36,6 +37,15 @@ export type IUserGroup = {
   parent: Ref<IUserGroupHasId> | null;
   parent: Ref<IUserGroupHasId> | null;
 }
 }
 
 
+export const USER_STATUS = {
+  REGISTERED: 1,
+  ACTIVE: 2,
+  SUSPENDED: 3,
+  DELETED: 4,
+  INVITED: 5,
+} as const;
+export type IUserStatus = typeof USER_STATUS[keyof typeof USER_STATUS]
+
 export type IUserHasId = IUser & HasObjectId;
 export type IUserHasId = IUser & HasObjectId;
 export type IUserGroupHasId = IUserGroup & HasObjectId;
 export type IUserGroupHasId = IUserGroup & HasObjectId;
 export type IUserGroupRelationHasId = IUserGroupRelation & HasObjectId;
 export type IUserGroupRelationHasId = IUserGroupRelation & HasObjectId;

+ 1 - 1
packages/hackmd/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@growi/hackmd",
   "name": "@growi/hackmd",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "description": "GROWI js and css files to use hackmd",
   "description": "GROWI js and css files to use hackmd",
   "license": "MIT",
   "license": "MIT",
   "main": "dist/index.js",
   "main": "dist/index.js",

+ 1 - 1
packages/plugin-attachment-refs/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@growi/plugin-attachment-refs",
   "name": "@growi/plugin-attachment-refs",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "description": "GROWI Plugin to add ref/refimg/refs/refsimg tags",
   "description": "GROWI Plugin to add ref/refimg/refs/refsimg tags",
   "license": "MIT",
   "license": "MIT",
   "keywords": [
   "keywords": [

+ 4 - 4
packages/plugin-lsx/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@growi/plugin-lsx",
   "name": "@growi/plugin-lsx",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "description": "GROWI plugin to list pages",
   "description": "GROWI plugin to list pages",
   "license": "MIT",
   "license": "MIT",
   "keywords": ["growi", "growi-plugin"],
   "keywords": ["growi", "growi-plugin"],
@@ -23,9 +23,9 @@
     "test": ""
     "test": ""
   },
   },
   "dependencies": {
   "dependencies": {
-    "@growi/core": "^6.0.0-RC.8",
-    "@growi/remark-growi-plugin": "^6.0.0-RC.8",
-    "@growi/ui": "^6.0.0-RC.8"
+    "@growi/core": "^6.0.0-RC.9",
+    "@growi/remark-growi-plugin": "^6.0.0-RC.9",
+    "@growi/ui": "^6.0.0-RC.9"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "eslint-plugin-regex": "^1.8.0",
     "eslint-plugin-regex": "^1.8.0",

+ 1 - 1
packages/remark-growi-plugin/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@growi/remark-growi-plugin",
   "name": "@growi/remark-growi-plugin",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "description": "remark plugin to support GROWI plugin (forked from remark-directive@2.0.1)",
   "description": "remark plugin to support GROWI plugin (forked from remark-directive@2.0.1)",
   "license": "MIT",
   "license": "MIT",
   "keywords": [
   "keywords": [

+ 1 - 1
packages/slack/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@growi/slack",
   "name": "@growi/slack",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "license": "MIT",
   "license": "MIT",
   "main": "dist/index.js",
   "main": "dist/index.js",
   "typings": "dist/index.d.ts",
   "typings": "dist/index.d.ts",

+ 2 - 2
packages/slackbot-proxy/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@growi/slackbot-proxy",
   "name": "@growi/slackbot-proxy",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "license": "MIT",
   "license": "MIT",
   "scripts": {
   "scripts": {
     "build": "yarn tsc && tsc-alias -p tsconfig.build.json",
     "build": "yarn tsc && tsc-alias -p tsconfig.build.json",
@@ -26,7 +26,7 @@
   },
   },
   "dependencies": {
   "dependencies": {
     "@godaddy/terminus": "^4.9.0",
     "@godaddy/terminus": "^4.9.0",
-    "@growi/slack": "^6.0.0-RC.8",
+    "@growi/slack": "^6.0.0-RC.9",
     "@slack/oauth": "^2.0.1",
     "@slack/oauth": "^2.0.1",
     "@slack/web-api": "^6.2.4",
     "@slack/web-api": "^6.2.4",
     "@tsed/common": "^6.43.0",
     "@tsed/common": "^6.43.0",

+ 10 - 10
packages/slackbot-proxy/src/services/SelectGrowiService.ts

@@ -146,9 +146,9 @@ export class SelectGrowiService implements GrowiCommandProcessor<SelectGrowiComm
 
 
     const selectGrowiValue = interactionPayloadAccessor.firstAction()?.value;
     const selectGrowiValue = interactionPayloadAccessor.firstAction()?.value;
     if (selectGrowiValue == null) {
     if (selectGrowiValue == null) {
-      logger.error('Growi command failed: The first action element must have the value parameter.');
+      logger.error('GROWI command failed: The first action element must have the value parameter.');
       await respond(responseUrl, {
       await respond(responseUrl, {
-        text: 'Growi command failed',
+        text: 'GROWI command failed',
         blocks: [
         blocks: [
           markdownSectionBlock('Error occurred while processing GROWI command.'),
           markdownSectionBlock('Error occurred while processing GROWI command.'),
         ],
         ],
@@ -159,9 +159,9 @@ export class SelectGrowiService implements GrowiCommandProcessor<SelectGrowiComm
 
 
 
 
     if (growiCommand == null) {
     if (growiCommand == null) {
-      logger.error('Growi command failed: The first action value must have growiCommand parameter.');
+      logger.error('GROWI command failed: The first action value must have growiCommand parameter.');
       await respond(responseUrl, {
       await respond(responseUrl, {
-        text: 'Growi command failed',
+        text: 'GROWI command failed',
         blocks: [
         blocks: [
           markdownSectionBlock('Error occurred while processing GROWI command.'),
           markdownSectionBlock('Error occurred while processing GROWI command.'),
         ],
         ],
@@ -183,9 +183,9 @@ export class SelectGrowiService implements GrowiCommandProcessor<SelectGrowiComm
       installation = await this.installationRepository.findByTeamIdOrEnterpriseId(installationId!);
       installation = await this.installationRepository.findByTeamIdOrEnterpriseId(installationId!);
     }
     }
     catch (err) {
     catch (err) {
-      logger.error('Growi command failed: No installation found.\n', err);
+      logger.error('GROWI command failed: No installation found.\n', err);
       await respond(responseUrl, {
       await respond(responseUrl, {
-        text: 'Growi command failed',
+        text: 'GROWI command failed',
         blocks: [
         blocks: [
           markdownSectionBlock('Error occurred while processing GROWI command.'),
           markdownSectionBlock('Error occurred while processing GROWI command.'),
         ],
         ],
@@ -200,9 +200,9 @@ export class SelectGrowiService implements GrowiCommandProcessor<SelectGrowiComm
       .getOne();
       .getOne();
 
 
     if (relation == null) {
     if (relation == null) {
-      logger.error('Growi command failed: No installation found.');
+      logger.error('GROWI command failed: No installation found.');
       await respond(responseUrl, {
       await respond(responseUrl, {
-        text: 'Growi command failed',
+        text: 'GROWI command failed',
         blocks: [
         blocks: [
           markdownSectionBlock('Error occurred while processing GROWI command.'),
           markdownSectionBlock('Error occurred while processing GROWI command.'),
         ],
         ],
@@ -213,9 +213,9 @@ export class SelectGrowiService implements GrowiCommandProcessor<SelectGrowiComm
     // increment sendCommandBody
     // increment sendCommandBody
     const channel = interactionPayloadAccessor.getChannel();
     const channel = interactionPayloadAccessor.getChannel();
     if (channel == null) {
     if (channel == null) {
-      logger.error('Growi command failed: channel not found.');
+      logger.error('GROWI command failed: channel not found.');
       await respond(responseUrl, {
       await respond(responseUrl, {
-        text: 'Growi command failed',
+        text: 'GROWI command failed',
         blocks: [
         blocks: [
           markdownSectionBlock('Error occurred while processing GROWI command.'),
           markdownSectionBlock('Error occurred while processing GROWI command.'),
         ],
         ],

+ 2 - 2
packages/ui/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@growi/ui",
   "name": "@growi/ui",
-  "version": "6.0.0-RC.8",
+  "version": "6.0.0-RC.9",
   "description": "GROWI UI Libraries",
   "description": "GROWI UI Libraries",
   "license": "MIT",
   "license": "MIT",
   "keywords": ["growi"],
   "keywords": ["growi"],
@@ -17,7 +17,7 @@
     "test": "jest --verbose"
     "test": "jest --verbose"
   },
   },
   "dependencies": {
   "dependencies": {
-    "@growi/core": "^6.0.0-RC.8"
+    "@growi/core": "^6.0.0-RC.9"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "eslint-plugin-regex": "^1.8.0",
     "eslint-plugin-regex": "^1.8.0",