فهرست منبع

Merge branch 'dev/7.0.x' into support/reactstrap-version-up

ryoji-s 2 سال پیش
والد
کامیت
4a8f7b0df6
100فایلهای تغییر یافته به همراه527 افزوده شده و 713 حذف شده
  1. 0 7
      .github/release-drafter-dev-7.0.x.yml
  2. 0 7
      .github/release-drafter-master.yml
  3. 6 0
      .github/release-drafter.yml
  4. 11 9
      .github/workflows/draft-release.yml
  5. 4 4
      .github/workflows/release.yml
  6. 8 1
      CHANGELOG.md
  7. 14 1
      apps/app/.eslintrc.js
  8. 14 12
      apps/app/_obsolete/src/components/Navbar/GrowiNavbar.tsx
  9. 1 1
      apps/app/_obsolete/src/components/Navbar/GrowiSubNavigationSwitcher.tsx
  10. 1 1
      apps/app/_obsolete/src/components/PageEditor/ConflictDiffModal.tsx
  11. 32 28
      apps/app/src/components/Admin/App/FileUploadSetting.tsx
  12. 6 4
      apps/app/src/components/Admin/App/QuestionnaireSettings.tsx
  13. 0 4
      apps/app/src/components/Admin/Common/AdminInstallButtonRow.tsx
  14. 16 16
      apps/app/src/components/Admin/Common/AdminNavigation.tsx
  15. 2 6
      apps/app/src/components/Admin/Customize/CustomizeLogoSetting.tsx
  16. 11 3
      apps/app/src/components/Admin/Customize/CustomizeNoscriptSetting.tsx
  17. 11 3
      apps/app/src/components/Admin/Customize/CustomizeScriptSetting.tsx
  18. 2 2
      apps/app/src/components/Admin/Customize/CustomizeTitle.tsx
  19. 1 1
      apps/app/src/components/Admin/Customize/ThemeColorBox.tsx
  20. 5 5
      apps/app/src/components/Admin/G2GDataTransfer.tsx
  21. 7 7
      apps/app/src/components/Admin/G2GDataTransferExportForm.tsx
  22. 1 1
      apps/app/src/components/Admin/LegacySlackIntegration/LegacySlackIntegration.jsx
  23. 25 23
      apps/app/src/components/Admin/ManageExternalAccount.tsx
  24. 18 10
      apps/app/src/components/Admin/Notification/GlobalNotification.jsx
  25. 9 22
      apps/app/src/components/Admin/Security/DeleteAllShareLinksModal.jsx
  26. 0 2
      apps/app/src/components/Admin/Security/SecurityManagement.tsx
  27. 0 1
      apps/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySecretTokenSection.jsx
  28. 9 21
      apps/app/src/components/Admin/SlackIntegration/DeleteSlackBotSettingsModal.jsx
  29. 1 3
      apps/app/src/components/Admin/SlackIntegration/WithProxyAccordions.jsx
  30. 10 5
      apps/app/src/components/Admin/Users/PasswordResetModal.jsx
  31. 1 2
      apps/app/src/components/Admin/Users/UserInviteModal.jsx
  32. 0 243
      apps/app/src/components/ArchiveCreateModal.jsx
  33. 9 3
      apps/app/src/components/BookmarkButtons.tsx
  34. 8 10
      apps/app/src/components/Bookmarks/BookmarkFolderItem.tsx
  35. 2 2
      apps/app/src/components/Bookmarks/BookmarkFolderItemControl.tsx
  36. 5 6
      apps/app/src/components/Bookmarks/BookmarkFolderMenu.tsx
  37. 2 2
      apps/app/src/components/Bookmarks/BookmarkFolderMenuItem.tsx
  38. 2 2
      apps/app/src/components/Bookmarks/BookmarkFolderNameInput.tsx
  39. 1 1
      apps/app/src/components/Bookmarks/BookmarkFolderTree.tsx
  40. 1 1
      apps/app/src/components/Bookmarks/BookmarkItem.tsx
  41. 1 1
      apps/app/src/components/Bookmarks/DragAndDropWrapper.tsx
  42. 1 2
      apps/app/src/components/CompleteUserRegistration.tsx
  43. 1 1
      apps/app/src/components/CompleteUserRegistrationForm.tsx
  44. 1 1
      apps/app/src/components/DeleteBookmarkFolderModal.tsx
  45. 1 5
      apps/app/src/components/DescendantsPageList.tsx
  46. 3 2
      apps/app/src/components/Hotkeys/Subscribers/EditPage.jsx
  47. 1 1
      apps/app/src/components/Hotkeys/Subscribers/FocusToGlobalSearch.jsx
  48. 0 1
      apps/app/src/components/Hotkeys/Subscribers/ShowStaffCredit.jsx
  49. 4 2
      apps/app/src/components/Icons/CompressIcon.tsx
  50. 2 1
      apps/app/src/components/Icons/ExpandIcon.tsx
  51. 6 4
      apps/app/src/components/Icons/FolderIcon.tsx
  52. 2 2
      apps/app/src/components/InvitedForm.tsx
  53. 47 29
      apps/app/src/components/LoginForm.tsx
  54. 1 1
      apps/app/src/components/Me/AssociateModal.tsx
  55. 15 9
      apps/app/src/components/Me/OtherSettings.tsx
  56. 3 3
      apps/app/src/components/Navbar/AuthorInfo.tsx
  57. 15 9
      apps/app/src/components/Navbar/GrowiContextualSubNavigation.tsx
  58. 1 1
      apps/app/src/components/NotFoundPage.tsx
  59. 1 1
      apps/app/src/components/Page/RenderTagLabels.tsx
  60. 1 1
      apps/app/src/components/Page/RevisionRenderer.tsx
  61. 11 16
      apps/app/src/components/Page/TagEditModal.tsx
  62. 1 1
      apps/app/src/components/Page/TagLabels.tsx
  63. 1 1
      apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLinkList.tsx
  64. 5 3
      apps/app/src/components/PageAlert/PageRedirectedAlert.tsx
  65. 7 7
      apps/app/src/components/PageCreateModal.jsx
  66. 2 6
      apps/app/src/components/PageDuplicateModal.tsx
  67. 1 1
      apps/app/src/components/PageEditor/Cheatsheet.tsx
  68. 2 2
      apps/app/src/components/PageEditor/Editor.tsx
  69. 1 1
      apps/app/src/components/PageEditor/EditorIcon.jsx
  70. 6 4
      apps/app/src/components/PageEditor/LinkEditModal.tsx
  71. 2 1
      apps/app/src/components/PageHistory/PageRevisionTable.tsx
  72. 2 1
      apps/app/src/components/PageHistory/Revision.tsx
  73. 1 1
      apps/app/src/components/PageHistory/RevisionDiff.tsx
  74. 20 17
      apps/app/src/components/PageList/PageListItemL.tsx
  75. 1 1
      apps/app/src/components/PagePathHierarchicalLink.tsx
  76. 2 2
      apps/app/src/components/PageRenameModal.tsx
  77. 3 3
      apps/app/src/components/PageSideContents.tsx
  78. 36 36
      apps/app/src/components/PageStatusAlert.tsx
  79. 1 1
      apps/app/src/components/PasswordResetRequestForm.tsx
  80. 3 3
      apps/app/src/components/PutbackPageModal.jsx
  81. 1 1
      apps/app/src/components/ReactMarkdownComponents/LightBox.tsx
  82. 1 1
      apps/app/src/components/ReactMarkdownComponents/NextLink.tsx
  83. 12 12
      apps/app/src/components/ReactMarkdownComponents/RichAttachment.tsx
  84. 1 1
      apps/app/src/components/ReactMarkdownComponents/TableWithEditButton.tsx
  85. 2 1
      apps/app/src/components/SavePageControls.tsx
  86. 2 1
      apps/app/src/components/Script/DrawioViewerScript.tsx
  87. 1 1
      apps/app/src/components/SearchPage/SearchPageBase.tsx
  88. 1 2
      apps/app/src/components/SearchTypeahead.tsx
  89. 2 2
      apps/app/src/components/ShortcutsModal.tsx
  90. 1 0
      apps/app/src/components/Sidebar/Bookmarks/BookmarkContents.tsx
  91. 2 2
      apps/app/src/components/Sidebar/PageTree/Item.tsx
  92. 1 1
      apps/app/src/components/Sidebar/PageTree/PageTreeContentSkeleton.tsx
  93. 12 6
      apps/app/src/components/Sidebar/PersonalDropdown.tsx
  94. 4 3
      apps/app/src/components/Sidebar/RecentChanges/RecentChangesContentSkeleton.tsx
  95. 7 4
      apps/app/src/components/Sidebar/RecentChanges/RecentChangesSubstance.tsx
  96. 1 1
      apps/app/src/components/Sidebar/Sidebar.tsx
  97. 1 1
      apps/app/src/components/Sidebar/SidebarNav.tsx
  98. 1 1
      apps/app/src/components/Sidebar/Tag.tsx
  99. 1 1
      apps/app/src/components/StaffCredit/StaffCredit.tsx
  100. 2 4
      apps/app/src/components/TableOfContents.tsx

+ 0 - 7
.github/release-drafter-dev-7.0.x.yml

@@ -1,7 +0,0 @@
-_extends: growi:.github/release-drafter.yml
-
-prerelease: true
-
-# Filter previous releases to consider only those with the tags starts with 'v6.2'
-include-pre-releases: true
-tag-prefix: v7.0

+ 0 - 7
.github/release-drafter-master.yml

@@ -1,7 +0,0 @@
-_extends: growi:.github/release-drafter.yml
-
-prerelease: true
-
-# Filter previous releases to consider only those with the master branch
-include-pre-releases: true
-filter-by-commitish: true

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

@@ -1,3 +1,9 @@
+prerelease: true
+
+# Filter previous releases to consider target_commitish
+include-pre-releases: true
+filter-by-commitish: true
+
 categories:
 categories:
   - title: 'BREAKING CHANGES'
   - title: 'BREAKING CHANGES'
     labels:
     labels:

+ 11 - 9
.github/workflows/draft-release.yml

@@ -29,17 +29,10 @@ jobs:
         uses: myrotvorets/info-from-package-json-action@1.2.0
         uses: myrotvorets/info-from-package-json-action@1.2.0
         id: package-json
         id: package-json
 
 
-      - name: Determine config file
-        id: determine-config-name
-        run: |
-          BRANCH_NAME="${{ github.ref_name }}"
-          BRANCH_NAME_REPLACED=${BRANCH_NAME/\//-}
-          echo "value=release-drafter-$BRANCH_NAME_REPLACED.yml" >> $GITHUB_OUTPUT
-
       - uses: release-drafter/release-drafter@v5
       - uses: release-drafter/release-drafter@v5
         id: release-drafter
         id: release-drafter
         with:
         with:
-          config-name: ${{ steps.determine-config-name.outputs.value }}
+          config-name: release-drafter.yml
           name: v${{ steps.package-json.outputs.packageVersion }}
           name: v${{ steps.package-json.outputs.packageVersion }}
           tag: v${{ steps.package-json.outputs.packageVersion }}
           tag: v${{ steps.package-json.outputs.packageVersion }}
           version: ${{ steps.package-json.outputs.packageVersion }}
           version: ${{ steps.package-json.outputs.packageVersion }}
@@ -64,11 +57,20 @@ jobs:
           RELEASE_VERSION=`npx semver -i patch ${{ needs.update-release-draft.outputs.CURRENT_VERSION }}`
           RELEASE_VERSION=`npx semver -i patch ${{ needs.update-release-draft.outputs.CURRENT_VERSION }}`
           echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_OUTPUT
           echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_OUTPUT
 
 
+      - name: Get base branch
+        id: base-branch
+        run: |
+          GITHUB_REF_NAME=${{ github.ref_name }}
+          WILDCARD_VERSION=${GITHUB_REF_NAME#dev/}
+          # set "release/current" or "release/X.X.x" to BASE_BRANCH
+          BASE_BRANCH=release/${{ github.ref_name == 'master' && 'current' || '$WILDCARD_VERSION' }}
+          echo "BASE_BRANCH=$BASE_BRANCH" >> $GITHUB_OUTPUT
+
       - name: Create/Update Pull Request
       - name: Create/Update Pull Request
         uses: bakunyo/git-pr-release-action@master
         uses: bakunyo/git-pr-release-action@master
         env:
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          GIT_PR_RELEASE_BRANCH_PRODUCTION: release/current
+          GIT_PR_RELEASE_BRANCH_PRODUCTION: ${{ steps.base-branch.outputs.BASE_BRANCH }}
           GIT_PR_RELEASE_BRANCH_STAGING: ${{ github.ref_name }}
           GIT_PR_RELEASE_BRANCH_STAGING: ${{ github.ref_name }}
           GIT_PR_RELEASE_TEMPLATE: .github/git-pr-release-template.erb
           GIT_PR_RELEASE_TEMPLATE: .github/git-pr-release-template.erb
           GIT_PR_RELEASE_TITLE: Release v${{ steps.release-version.outputs.RELEASE_VERSION }}
           GIT_PR_RELEASE_TITLE: Release v${{ steps.release-version.outputs.RELEASE_VERSION }}

+ 4 - 4
.github/workflows/release.yml

@@ -63,11 +63,11 @@ jobs:
         commit_message: Release v${{ steps.package-json.outputs.packageVersion }}
         commit_message: Release v${{ steps.package-json.outputs.packageVersion }}
         tagging_message: v${{ steps.package-json.outputs.packageVersion }}
         tagging_message: v${{ steps.package-json.outputs.packageVersion }}
 
 
-    - uses: ncipollo/release-action@v1
+    - uses: softprops/action-gh-release@v1
       with:
       with:
         body: ${{ github.event.pull_request.body }}
         body: ${{ github.event.pull_request.body }}
-        tag: v${{ steps.package-json.outputs.packageVersion }}
-        token: ${{ secrets.GITHUB_TOKEN }}
+        tag_name: v${{ steps.package-json.outputs.packageVersion }}
+        target_commitish: ${{ github.head_ref }}
 
 
     - name: Delete drafts
     - name: Delete drafts
       uses: hugo19941994/delete-draft-releases@v1.0.1
       uses: hugo19941994/delete-draft-releases@v1.0.1
@@ -118,7 +118,7 @@ jobs:
       uses: repo-sync/pull-request@v2
       uses: repo-sync/pull-request@v2
       with:
       with:
         source_branch: support/prepare-v${{ steps.package-json.outputs.packageVersion }}
         source_branch: support/prepare-v${{ steps.package-json.outputs.packageVersion }}
-        destination_branch: master
+        destination_branch: ${{ github.head_ref }}
         pr_title: Prepare v${{ steps.package-json.outputs.packageVersion }}
         pr_title: Prepare v${{ steps.package-json.outputs.packageVersion }}
         pr_label: flag/exclude-from-changelog,type/prepare-next-version
         pr_label: flag/exclude-from-changelog,type/prepare-next-version
         pr_body: "[skip ci] An automated PR generated by create-pr-for-next-rc"
         pr_body: "[skip ci] An automated PR generated by create-pr-for-next-rc"

+ 8 - 1
CHANGELOG.md

@@ -1,9 +1,16 @@
 # Changelog
 # Changelog
 
 
-## [Unreleased](https://github.com/weseek/growi/compare/v6.1.11...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v6.1.12...HEAD)
 
 
 *Please do not manually update this file. We've automated the process.*
 *Please do not manually update this file. We've automated the process.*
 
 
+## [v6.1.12](https://github.com/weseek/growi/compare/v6.1.11...v6.1.12) - 2023-08-14
+
+### 🐛 Bug Fixes
+
+- fix: Consider an empty page when renaming and duplicating (v6.1.x) (#7980) @yuki-takei
+- fix: Do not work image tag properties (#7977) @jam411
+
 ## [v6.1.11](https://github.com/weseek/growi/compare/v6.1.10...v6.1.11) - 2023-08-07
 ## [v6.1.11](https://github.com/weseek/growi/compare/v6.1.10...v6.1.11) - 2023-08-07
 
 
 ### 🐛 Bug Fixes
 ### 🐛 Bug Fixes

+ 14 - 1
apps/app/.eslintrc.js

@@ -1,6 +1,7 @@
 module.exports = {
 module.exports = {
   extends: [
   extends: [
     'next/core-web-vitals',
     'next/core-web-vitals',
+    'weseek/react',
   ],
   ],
   plugins: [
   plugins: [
     'regex',
     'regex',
@@ -32,11 +33,23 @@ module.exports = {
     '@typescript-eslint/no-this-alias': ['warn'],
     '@typescript-eslint/no-this-alias': ['warn'],
   },
   },
   overrides: [
   overrides: [
+    {
+      // enable the rule specifically for JavaScript files
+      files: ['*.js', '*.jsx'],
+      rules: {
+        // set 'warn' temporarily -- 2023.08.14 Yuki Takei
+        'react/prop-types': 'warn',
+        // set 'warn' temporarily -- 2023.08.14 Yuki Takei
+        'no-unused-vars': ['warn'],
+      },
+    },
     {
     {
       // enable the rule specifically for TypeScript files
       // enable the rule specifically for TypeScript files
       files: ['*.ts', '*.tsx'],
       files: ['*.ts', '*.tsx'],
       rules: {
       rules: {
-        // '@typescript-eslint/explicit-module-boundary-types': ['error'],
+        'no-unused-vars': 'off',
+        // set 'warn' temporarily -- 2023.08.14 Yuki Takei
+        'react/prop-types': 'warn',
         // set 'warn' temporarily -- 2022.07.25 Yuki Takei
         // set 'warn' temporarily -- 2022.07.25 Yuki Takei
         '@typescript-eslint/explicit-module-boundary-types': ['warn'],
         '@typescript-eslint/explicit-module-boundary-types': ['warn'],
       },
       },

+ 14 - 12
apps/app/_obsolete/src/components/Navbar/GrowiNavbar.tsx

@@ -38,18 +38,20 @@ const NavbarRight = memo((): JSX.Element => {
     return (
     return (
       <>
       <>
         {!isReadOnlyUser
         {!isReadOnlyUser
-          && <li className="nav-item d-none d-md-block">
-            <button
-              className="px-md-3 nav-link btn-create-page border-0 bg-transparent"
-              type="button"
-              ref={newButtonRef}
-              data-testid="newPageBtn"
-              onClick={() => openCreateModal(currentPagePath || '')}
-            >
-              <i className="icon-pencil mr-2"></i>
-              <span className="d-none d-lg-block">{ t('commons:New') }</span>
-            </button>
-          </li>
+          && (
+            <li className="nav-item d-none d-md-block">
+              <button
+                className="px-md-3 nav-link btn-create-page border-0 bg-transparent"
+                type="button"
+                ref={newButtonRef}
+                data-testid="newPageBtn"
+                onClick={() => openCreateModal(currentPagePath || '')}
+              >
+                <i className="icon-pencil mr-2"></i>
+                <span className="d-none d-lg-block">{ t('commons:New') }</span>
+              </button>
+            </li>
+          )
         }
         }
       </>
       </>
     );
     );

+ 1 - 1
apps/app/_obsolete/src/components/Navbar/GrowiSubNavigationSwitcher.tsx

@@ -83,7 +83,7 @@ export const GrowiSubNavigationSwitcher = (props: GrowiSubNavigationSwitcherProp
   }
   }
 
 
   return (
   return (
-    <div className={`${styles['grw-subnav-switcher']} ${isSticky ? '' : 'grw-subnav-switcher-hidden'}`} data-testid="grw-subnav-switcher" >
+    <div className={`${styles['grw-subnav-switcher']} ${isSticky ? '' : 'grw-subnav-switcher-hidden'}`} data-testid="grw-subnav-switcher">
       <div
       <div
         id="grw-subnav-fixed-container"
         id="grw-subnav-fixed-container"
         className={`grw-subnav-fixed-container ${styles['grw-subnav-fixed-container']} position-fixed grw-subnav-append-shadow-container`}
         className={`grw-subnav-fixed-container ${styles['grw-subnav-fixed-container']} position-fixed grw-subnav-append-shadow-container`}

+ 1 - 1
apps/app/_obsolete/src/components/PageEditor/ConflictDiffModal.tsx

@@ -340,5 +340,5 @@ export const ConflictDiffModal = (props: ConflictDiffModalProps): JSX.Element =>
     afterResolvedHandler,
     afterResolvedHandler,
   };
   };
 
 
-  return <ConflictDiffModalCore {...propsForCore}/>;
+  return <ConflictDiffModalCore {...propsForCore} />;
 };
 };

+ 32 - 28
apps/app/src/components/Admin/App/FileUploadSetting.tsx

@@ -70,34 +70,38 @@ export const FileUploadSettingMolecule = React.memo((props: FileUploadSettingMol
         )}
         )}
       </div>
       </div>
 
 
-      {props.fileUploadType === 'aws' && <AwsSettingMolecule
-        s3ReferenceFileWithRelayMode={props.s3ReferenceFileWithRelayMode}
-        s3Region={props.s3Region}
-        s3CustomEndpoint={props.s3CustomEndpoint}
-        s3Bucket={props.s3Bucket}
-        s3AccessKeyId={props.s3AccessKeyId}
-        s3SecretAccessKey={props.s3SecretAccessKey}
-        onChangeS3ReferenceFileWithRelayMode={props.onChangeS3ReferenceFileWithRelayMode}
-        onChangeS3Region={props.onChangeS3Region}
-        onChangeS3CustomEndpoint={props.onChangeS3CustomEndpoint}
-        onChangeS3Bucket={props.onChangeS3Bucket}
-        onChangeS3AccessKeyId={props.onChangeS3AccessKeyId}
-        onChangeS3SecretAccessKey={props.onChangeS3SecretAccessKey}
-      />}
-      {props.fileUploadType === 'gcs' && <GcsSettingMolecule
-        gcsReferenceFileWithRelayMode={props.gcsReferenceFileWithRelayMode}
-        gcsUseOnlyEnvVars={props.gcsUseOnlyEnvVars}
-        gcsApiKeyJsonPath={props.gcsApiKeyJsonPath}
-        gcsBucket={props.gcsBucket}
-        gcsUploadNamespace={props.gcsUploadNamespace}
-        envGcsApiKeyJsonPath={props.envGcsApiKeyJsonPath}
-        envGcsBucket={props.envGcsBucket}
-        envGcsUploadNamespace={props.envGcsUploadNamespace}
-        onChangeGcsReferenceFileWithRelayMode={props.onChangeGcsReferenceFileWithRelayMode}
-        onChangeGcsApiKeyJsonPath={props.onChangeGcsApiKeyJsonPath}
-        onChangeGcsBucket={props.onChangeGcsBucket}
-        onChangeGcsUploadNamespace={props.onChangeGcsUploadNamespace}
-      />}
+      {props.fileUploadType === 'aws' && (
+        <AwsSettingMolecule
+          s3ReferenceFileWithRelayMode={props.s3ReferenceFileWithRelayMode}
+          s3Region={props.s3Region}
+          s3CustomEndpoint={props.s3CustomEndpoint}
+          s3Bucket={props.s3Bucket}
+          s3AccessKeyId={props.s3AccessKeyId}
+          s3SecretAccessKey={props.s3SecretAccessKey}
+          onChangeS3ReferenceFileWithRelayMode={props.onChangeS3ReferenceFileWithRelayMode}
+          onChangeS3Region={props.onChangeS3Region}
+          onChangeS3CustomEndpoint={props.onChangeS3CustomEndpoint}
+          onChangeS3Bucket={props.onChangeS3Bucket}
+          onChangeS3AccessKeyId={props.onChangeS3AccessKeyId}
+          onChangeS3SecretAccessKey={props.onChangeS3SecretAccessKey}
+        />
+      )}
+      {props.fileUploadType === 'gcs' && (
+        <GcsSettingMolecule
+          gcsReferenceFileWithRelayMode={props.gcsReferenceFileWithRelayMode}
+          gcsUseOnlyEnvVars={props.gcsUseOnlyEnvVars}
+          gcsApiKeyJsonPath={props.gcsApiKeyJsonPath}
+          gcsBucket={props.gcsBucket}
+          gcsUploadNamespace={props.gcsUploadNamespace}
+          envGcsApiKeyJsonPath={props.envGcsApiKeyJsonPath}
+          envGcsBucket={props.envGcsBucket}
+          envGcsUploadNamespace={props.envGcsUploadNamespace}
+          onChangeGcsReferenceFileWithRelayMode={props.onChangeGcsReferenceFileWithRelayMode}
+          onChangeGcsApiKeyJsonPath={props.onChangeGcsApiKeyJsonPath}
+          onChangeGcsBucket={props.onChangeGcsBucket}
+          onChangeGcsUploadNamespace={props.onChangeGcsUploadNamespace}
+        />
+      )}
     </>
     </>
   );
   );
 });
 });

+ 6 - 4
apps/app/src/components/Admin/App/QuestionnaireSettings.tsx

@@ -63,9 +63,11 @@ const QuestionnaireSettings = (): JSX.Element => {
         </span>
         </span>
       </p>
       </p>
 
 
-      {isLoading && <div className="text-muted text-center mb-5">
-        <i className="fa fa-2x fa-spinner fa-pulse mr-1" />
-      </div>}
+      {isLoading && (
+        <div className="text-muted text-center mb-5">
+          <i className="fa fa-2x fa-spinner fa-pulse mr-1" />
+        </div>
+      )}
 
 
       {!isLoading && (
       {!isLoading && (
         <>
         <>
@@ -103,7 +105,7 @@ const QuestionnaireSettings = (): JSX.Element => {
             </div>
             </div>
           </div>
           </div>
 
 
-          <AdminUpdateButtonRow onClick={onSubmitHandler}/>
+          <AdminUpdateButtonRow onClick={onSubmitHandler} />
         </>
         </>
       )}
       )}
     </div>
     </div>

+ 0 - 4
apps/app/src/components/Admin/Common/AdminInstallButtonRow.tsx

@@ -1,7 +1,5 @@
 import React from 'react';
 import React from 'react';
 
 
-import { useTranslation } from 'next-i18next';
-
 type Props = {
 type Props = {
   onClick: () => void,
   onClick: () => void,
   disabled: boolean,
   disabled: boolean,
@@ -9,8 +7,6 @@ type Props = {
 }
 }
 
 
 export const AdminInstallButtonRow = (props: Props): JSX.Element => {
 export const AdminInstallButtonRow = (props: Props): JSX.Element => {
-  // TODO: const { t } = useTranslation('admin');
-
   return (
   return (
     <div className="row my-3">
     <div className="row my-3">
       <div className="mx-auto">
       <div className="mx-auto">

+ 16 - 16
apps/app/src/components/Admin/Common/AdminNavigation.tsx

@@ -86,22 +86,22 @@ export const AdminNavigation = (): JSX.Element => {
     return (
     return (
       <>
       <>
         {/* eslint-disable no-multi-spaces */}
         {/* eslint-disable no-multi-spaces */}
-        <MenuLink menu="home"                       isListGroupItems={isListGroupItems} isActive={pathname === '/admin'} isRoot />
-        <MenuLink menu="app"                        isListGroupItems={isListGroupItems} isActive={isActiveMenu('/app')} />
-        <MenuLink menu="security"                   isListGroupItems={isListGroupItems} isActive={isActiveMenu('/security')} />
-        <MenuLink menu="markdown"                   isListGroupItems={isListGroupItems} isActive={isActiveMenu('/markdown')} />
-        <MenuLink menu="customize"                  isListGroupItems={isListGroupItems} isActive={isActiveMenu('/customize')} />
-        <MenuLink menu="importer"                   isListGroupItems={isListGroupItems} isActive={isActiveMenu('/importer')} />
-        <MenuLink menu="export"                     isListGroupItems={isListGroupItems} isActive={isActiveMenu('/export')} />
-        <MenuLink menu="data-transfer"              isListGroupItems={isListGroupItems} isActive={isActiveMenu('/data-transfer')} />
-        <MenuLink menu="notification"               isListGroupItems={isListGroupItems} isActive={isActiveMenu(['/notification', '/global-notification'])} />
-        <MenuLink menu="slack-integration"          isListGroupItems={isListGroupItems} isActive={isActiveMenu('/slack-integration')} />
-        <MenuLink menu="slack-integration-legacy"   isListGroupItems={isListGroupItems} isActive={isActiveMenu('/slack-integration-legacy')} />
-        <MenuLink menu="users"                      isListGroupItems={isListGroupItems} isActive={isActiveMenu('/users')} />
-        <MenuLink menu="user-groups"                isListGroupItems={isListGroupItems} isActive={isActiveMenu(['/user-groups', 'user-group-detail'])} />
-        <MenuLink menu="audit-log"                  isListGroupItems={isListGroupItems} isActive={isActiveMenu('/audit-log')} />
-        <MenuLink menu="plugins"                    isListGroupItems={isListGroupItems} isActive={isActiveMenu('/plugins')} />
-        <MenuLink menu="search"                     isListGroupItems={isListGroupItems} isActive={isActiveMenu('/search')} />
+        <MenuLink menu="home" isListGroupItems={isListGroupItems} isActive={pathname === '/admin'} isRoot />
+        <MenuLink menu="app" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/app')} />
+        <MenuLink menu="security" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/security')} />
+        <MenuLink menu="markdown" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/markdown')} />
+        <MenuLink menu="customize" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/customize')} />
+        <MenuLink menu="importer" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/importer')} />
+        <MenuLink menu="export" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/export')} />
+        <MenuLink menu="data-transfer" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/data-transfer')} />
+        <MenuLink menu="notification" isListGroupItems={isListGroupItems} isActive={isActiveMenu(['/notification', '/global-notification'])} />
+        <MenuLink menu="slack-integration" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/slack-integration')} />
+        <MenuLink menu="slack-integration-legacy" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/slack-integration-legacy')} />
+        <MenuLink menu="users" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/users')} />
+        <MenuLink menu="user-groups" isListGroupItems={isListGroupItems} isActive={isActiveMenu(['/user-groups', 'user-group-detail'])} />
+        <MenuLink menu="audit-log" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/audit-log')} />
+        <MenuLink menu="plugins" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/plugins')} />
+        <MenuLink menu="search" isListGroupItems={isListGroupItems} isActive={isActiveMenu('/search')} />
         {growiCloudUri != null && growiAppIdForGrowiCloud != null
         {growiCloudUri != null && growiAppIdForGrowiCloud != null
           && (
           && (
             <a
             <a

+ 2 - 6
apps/app/src/components/Admin/Customize/CustomizeLogoSetting.tsx

@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo, useState } from 'react';
+import React, { useCallback, useState } from 'react';
 
 
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 
 
@@ -26,10 +26,6 @@ const CustomizeLogoSetting = (): JSX.Element => {
   const [isDefaultLogoSelected, setIsDefaultLogoSelected] = useState<boolean>(isDefaultLogo ?? true);
   const [isDefaultLogoSelected, setIsDefaultLogoSelected] = useState<boolean>(isDefaultLogo ?? true);
   const [retrieveError, setRetrieveError] = useState<any>();
   const [retrieveError, setRetrieveError] = useState<any>();
 
 
-  const currentLogo = useMemo(() => {
-    return isDefaultLogo ? DEFAULT_LOGO : CUSTOMIZED_LOGO;
-  }, [isDefaultLogo]);
-
   const onSelectFile = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
   const onSelectFile = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
     if (e.target.files != null && e.target.files.length > 0) {
     if (e.target.files != null && e.target.files.length > 0) {
       const reader = new FileReader();
       const reader = new FileReader();
@@ -129,7 +125,7 @@ const CustomizeLogoSetting = (): JSX.Element => {
                     {isCustomizedLogoUploaded && (
                     {isCustomizedLogoUploaded && (
                       <>
                       <>
                         <p>
                         <p>
-                          <img src='/attachment/brand-logo' className="picture picture-lg " id="settingBrandLogo" width="64" />
+                          <img src={CUSTOMIZED_LOGO} className="picture picture-lg " id="settingBrandLogo" width="64" />
                         </p>
                         </p>
                         <button type="button" className="btn btn-danger" onClick={onClickDeleteBtn}>
                         <button type="button" className="btn btn-danger" onClick={onClickDeleteBtn}>
                           { t('admin:customize_settings.delete_logo') }
                           { t('admin:customize_settings.delete_logo') }

+ 11 - 3
apps/app/src/components/Admin/Customize/CustomizeNoscriptSetting.tsx

@@ -61,13 +61,21 @@ const CustomizeNoscriptSetting = (props: Props): JSX.Element => {
             */}
             */}
           </div>
           </div>
 
 
-          <a className="text-muted"
-            data-toggle="collapse" href="#collapseExampleHtml" role="button" aria-expanded="false" aria-controls="collapseExampleHtml">
+          <a
+            className="text-muted"
+            data-toggle="collapse"
+            href="#collapseExampleHtml"
+            role="button"
+            aria-expanded="false"
+            aria-controls="collapseExampleHtml"
+          >
             <i className="fa fa-fw fa-chevron-right" aria-hidden="true"></i>
             <i className="fa fa-fw fa-chevron-right" aria-hidden="true"></i>
             Example for Google Tag Manager
             Example for Google Tag Manager
           </a>
           </a>
           <div className="collapse" id="collapseExampleHtml">
           <div className="collapse" id="collapseExampleHtml">
-            <PrismAsyncLight style={oneDark} language={'javascript'}
+            <PrismAsyncLight
+              style={oneDark}
+              language="javascript"
             >
             >
               {`<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
               {`<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
   height="0"
   height="0"

+ 11 - 3
apps/app/src/components/Admin/Customize/CustomizeScriptSetting.tsx

@@ -58,13 +58,21 @@ const CustomizeScriptSetting = (props: Props): JSX.Element => {
             */}
             */}
           </div>
           </div>
 
 
-          <a className="text-muted"
-            data-toggle="collapse" href="#collapseExampleScript" role="button" aria-expanded="false" aria-controls="collapseExampleScript">
+          <a
+            className="text-muted"
+            data-toggle="collapse"
+            href="#collapseExampleScript"
+            role="button"
+            aria-expanded="false"
+            aria-controls="collapseExampleScript"
+          >
             <i className="fa fa-fw fa-chevron-right" aria-hidden="true"></i>
             <i className="fa fa-fw fa-chevron-right" aria-hidden="true"></i>
             Example for Google Tag Manager
             Example for Google Tag Manager
           </a>
           </a>
           <div className="collapse" id="collapseExampleScript">
           <div className="collapse" id="collapseExampleScript">
-            <PrismAsyncLight style={oneDark} language={'javascript'}
+            <PrismAsyncLight
+              style={oneDark}
+              language="javascript"
             >
             >
               {`(function(w,d,s,l,i){
               {`(function(w,d,s,l,i){
 w[l]=w[l]||[];
 w[l]=w[l]||[];

+ 2 - 2
apps/app/src/components/Admin/Customize/CustomizeTitle.tsx

@@ -59,9 +59,9 @@ export const CustomizeTitle: FC = () => {
 
 
         {/* TODO i18n */}
         {/* TODO i18n */}
         <div className="form-text text-muted col-12">
         <div className="form-text text-muted col-12">
-            Default Value: <code>&#123;&#123;pagename&#125;&#125; - &#123;&#123;sitename&#125;&#125;</code>
+          Default Value: <code>&#123;&#123;pagename&#125;&#125; - &#123;&#123;sitename&#125;&#125;</code>
           <br />
           <br />
-            Default Output Example: <code className="xml">&lt;title&gt;Page name - My GROWI&lt;&#047;title&gt;</code>
+          Default Output Example: <code className="xml">&lt;title&gt;Page name - My GROWI&lt;&#047;title&gt;</code>
         </div>
         </div>
         <div className="form-group col-12">
         <div className="form-group col-12">
           <input
           <input

+ 1 - 1
apps/app/src/components/Admin/Customize/ThemeColorBox.tsx

@@ -35,7 +35,7 @@ export const ThemeColorBox = (props: Props): JSX.Element => {
         </svg>
         </svg>
       </a>
       </a>
       <span className="theme-option-name"><b>{ name }</b></span>
       <span className="theme-option-name"><b>{ name }</b></span>
-      { !isPresetTheme && <span className='theme-option-badge badge badge-primary mt-1'>Plugin</span> }
+      { !isPresetTheme && <span className="theme-option-badge badge badge-primary mt-1">Plugin</span> }
     </div>
     </div>
   );
   );
 
 

+ 5 - 5
apps/app/src/components/Admin/G2GDataTransfer.tsx

@@ -1,5 +1,5 @@
 import React, {
 import React, {
-  ChangeEvent, useCallback, useEffect, useState,
+  useCallback, useEffect, useState,
 } from 'react';
 } from 'react';
 
 
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
@@ -217,7 +217,7 @@ const G2GDataTransfer = (): JSX.Element => {
             onChangeGcsBucket={onChangeGcsBucketHandler}
             onChangeGcsBucket={onChangeGcsBucketHandler}
             onChangeGcsUploadNamespace={onChangeGcsUploadNamespaceHandler}
             onChangeGcsUploadNamespace={onChangeGcsUploadNamespaceHandler}
           /> */}
           /> */}
-          <h3 className='mb-1'>{t('export_management.export_archive_data')}</h3>
+          <h3 className="mb-1">{t('export_management.export_archive_data')}</h3>
           <G2GDataTransferExportForm
           <G2GDataTransferExportForm
             allCollectionNames={collections}
             allCollectionNames={collections}
             selectedCollections={selectedCollections}
             selectedCollections={selectedCollections}
@@ -246,12 +246,12 @@ const G2GDataTransfer = (): JSX.Element => {
       </form>
       </form>
 
 
       {isTransferring && (
       {isTransferring && (
-        <div className='border rounded p-4'>
+        <div className="border rounded p-4">
           <div>
           <div>
-            <G2GDataTransferStatusIcon className='mr-2 mb-2' status={g2gProgress.mongo} /> MongoDB
+            <G2GDataTransferStatusIcon className="mr-2 mb-2" status={g2gProgress.mongo} /> MongoDB
           </div>
           </div>
           <div>
           <div>
-            <G2GDataTransferStatusIcon className='mr-2' status={g2gProgress.attachments} /> Attachments
+            <G2GDataTransferStatusIcon className="mr-2" status={g2gProgress.attachments} /> Attachments
           </div>
           </div>
         </div>
         </div>
       )}
       )}

+ 7 - 7
apps/app/src/components/Admin/G2GDataTransferExportForm.tsx

@@ -122,7 +122,7 @@ const G2GDataTransferExportForm = (props: Props): JSX.Element => {
     );
     );
   };
   };
 
 
-  const WarnForGroups = ({ errors }): JSX.Element => {
+  const WarnForGroups = ({ errors }: { errors: Error[] }): JSX.Element => {
     if (errors.length === 0) {
     if (errors.length === 0) {
       return <></>;
       return <></>;
     }
     }
@@ -130,8 +130,8 @@ const G2GDataTransferExportForm = (props: Props): JSX.Element => {
     return (
     return (
       <div className="alert alert-warning">
       <div className="alert alert-warning">
         <ul>
         <ul>
-          {errors.map((error, i) => {
-            return <li key={i}>{error}</li>;
+          {errors.map((error) => {
+            return <li>{error.message}</li>;
           })}
           })}
         </ul>
         </ul>
       </div>
       </div>
@@ -162,7 +162,7 @@ const G2GDataTransferExportForm = (props: Props): JSX.Element => {
     });
     });
 
 
     // TODO: エラー対応
     // TODO: エラー対応
-    return <GroupImportItems groupList={collectionNames} groupName='Other' errors={[]} />;
+    return <GroupImportItems groupList={collectionNames} groupName="Other" errors={[]} />;
   };
   };
 
 
   const configurationModal = useMemo(() => {
   const configurationModal = useMemo(() => {
@@ -224,9 +224,9 @@ const G2GDataTransferExportForm = (props: Props): JSX.Element => {
       </div>
       </div>
 
 
       {/* TODO: エラー追加 */}
       {/* TODO: エラー追加 */}
-      <GroupImportItems groupList={GROUPS_PAGE} groupName='Page' errors={[]} />
-      <GroupImportItems groupList={GROUPS_USER} groupName='User' errors={[]} />
-      <GroupImportItems groupList={GROUPS_CONFIG} groupName='Config' errors={[]} />
+      <GroupImportItems groupList={GROUPS_PAGE} groupName="Page" errors={[]} />
+      <GroupImportItems groupList={GROUPS_USER} groupName="User" errors={[]} />
+      <GroupImportItems groupList={GROUPS_CONFIG} groupName="Config" errors={[]} />
       <OtherImportItems />
       <OtherImportItems />
 
 
       {configurationModal}
       {configurationModal}

+ 1 - 1
apps/app/src/components/Admin/LegacySlackIntegration/LegacySlackIntegration.jsx

@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo, useState } from 'react';
+import React, { useEffect } from 'react';
 
 
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';

+ 25 - 23
apps/app/src/components/Admin/ManageExternalAccount.tsx

@@ -46,32 +46,34 @@ const ManageExternalAccount = (props: ManageExternalAccountProps): JSX.Element =
     />
     />
   );
   );
 
 
-  return <>
-    <p>
-      <Link
-        href="/admin/users"
-        prefetch={false}
-        className="btn btn-outline-secondary"
-      >
-        <i className="icon-fw ti ti-arrow-left" aria-hidden="true"></i>
-        {t('admin:user_management.back_to_user_management')}
-      </Link>
-    </p>
-    <h2>{t('admin:user_management.external_account_list')}</h2>
-    {(totalAccounts !== 0) ? (
-      <>
-        {pager}
-        <ExternalAccountTable />
-        {pager}
-      </>
-    )
-      : (
+  return (
+    <>
+      <p>
+        <Link
+          href="/admin/users"
+          prefetch={false}
+          className="btn btn-outline-secondary"
+        >
+          <i className="icon-fw ti ti-arrow-left" aria-hidden="true"></i>
+          {t('admin:user_management.back_to_user_management')}
+        </Link>
+      </p>
+      <h2>{t('admin:user_management.external_account_list')}</h2>
+      {(totalAccounts !== 0) ? (
         <>
         <>
-          { t('admin:user_management.external_account_none') }
+          {pager}
+          <ExternalAccountTable />
+          {pager}
         </>
         </>
       )
       )
-    }
-  </>;
+        : (
+          <>
+            { t('admin:user_management.external_account_none') }
+          </>
+        )
+      }
+    </>
+  );
 };
 };
 
 
 const ManageExternalAccountWrapper = withUnstatedContainers(ManageExternalAccount, [AdminExternalAccountsContainer]);
 const ManageExternalAccountWrapper = withUnstatedContainers(ManageExternalAccount, [AdminExternalAccountsContainer]);

+ 18 - 10
apps/app/src/components/Admin/Notification/GlobalNotification.jsx

@@ -39,7 +39,8 @@ const GlobalNotification = (props) => {
       <p className="card well">
       <p className="card well">
         {/* eslint-disable-next-line react/no-danger */}
         {/* eslint-disable-next-line react/no-danger */}
         <span dangerouslySetInnerHTML={{ __html: t('notification_settings.link_notification_help') }} />
         <span dangerouslySetInnerHTML={{ __html: t('notification_settings.link_notification_help') }} />
-      </p><div className="row mb-4">
+      </p>
+      <div className="row mb-4">
         <div className="col-md-8 offset-md-2">
         <div className="col-md-8 offset-md-2">
           <div className="custom-control custom-checkbox custom-checkbox-success">
           <div className="custom-control custom-checkbox custom-checkbox-success">
             <input
             <input
@@ -47,14 +48,17 @@ const GlobalNotification = (props) => {
               className="custom-control-input"
               className="custom-control-input"
               type="checkbox"
               type="checkbox"
               checked={adminNotificationContainer.state.isNotificationForOwnerPageEnabled || false}
               checked={adminNotificationContainer.state.isNotificationForOwnerPageEnabled || false}
-              onChange={() => { adminNotificationContainer.switchIsNotificationForOwnerPageEnabled() } } />
+              onChange={() => { adminNotificationContainer.switchIsNotificationForOwnerPageEnabled() }}
+            />
             <label className="custom-control-label" htmlFor="isNotificationForOwnerPageEnabled">
             <label className="custom-control-label" htmlFor="isNotificationForOwnerPageEnabled">
               {/* eslint-disable-next-line react/no-danger */}
               {/* eslint-disable-next-line react/no-danger */}
               <span dangerouslySetInnerHTML={{ __html: t('notification_settings.just_me_notification_help') }} />
               <span dangerouslySetInnerHTML={{ __html: t('notification_settings.just_me_notification_help') }} />
             </label>
             </label>
           </div>
           </div>
         </div>
         </div>
-      </div><div className="row mb-4">
+      </div>
+
+      <div className="row mb-4">
         <div className="col-md-8 offset-md-2">
         <div className="col-md-8 offset-md-2">
           <div className="custom-control custom-checkbox custom-checkbox-success">
           <div className="custom-control custom-checkbox custom-checkbox-success">
             <input
             <input
@@ -62,7 +66,8 @@ const GlobalNotification = (props) => {
               className="custom-control-input"
               className="custom-control-input"
               type="checkbox"
               type="checkbox"
               checked={adminNotificationContainer.state.isNotificationForGroupPageEnabled || false}
               checked={adminNotificationContainer.state.isNotificationForGroupPageEnabled || false}
-              onChange={() => { adminNotificationContainer.switchIsNotificationForGroupPageEnabled() } } />
+              onChange={() => { adminNotificationContainer.switchIsNotificationForGroupPageEnabled() }}
+            />
             <label className="custom-control-label" htmlFor="isNotificationForGroupPageEnabled">
             <label className="custom-control-label" htmlFor="isNotificationForGroupPageEnabled">
               {/* eslint-disable-next-line react/no-danger */}
               {/* eslint-disable-next-line react/no-danger */}
               <span dangerouslySetInnerHTML={{ __html: t('notification_settings.group_notification_help') }} />
               <span dangerouslySetInnerHTML={{ __html: t('notification_settings.group_notification_help') }} />
@@ -81,13 +86,16 @@ const GlobalNotification = (props) => {
           </button>
           </button>
         </div>
         </div>
       </div>
       </div>
+
       <h2 className="border-bottom mb-5">{t('notification_settings.notification_list')}
       <h2 className="border-bottom mb-5">{t('notification_settings.notification_list')}
-        <button className="btn btn-outline-secondary pull-right"
-          type="button" onClick={() => router.push('/admin/global-notification/new')}>{t('notification_settings.add_notification')}</button>
-        {/* <a href="/admin/global-notification/new">
-      <p className="btn btn-outline-secondary pull-right">{t('notification_setting.add_notification')}</p>
-    </a> */}
-      </h2><table className="table table-bordered">
+        <button
+          className="btn btn-outline-secondary pull-right"
+          type="button"
+          onClick={() => router.push('/admin/global-notification/new')}
+        >{t('notification_settings.add_notification')}
+        </button>
+      </h2>
+      <table className="table table-bordered">
         <thead>
         <thead>
           <tr>
           <tr>
             <th>ON/OFF</th>
             <th>ON/OFF</th>

+ 9 - 22
apps/app/src/components/Admin/Security/DeleteAllShareLinksModal.jsx

@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useCallback } from 'react';
 
 
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
@@ -7,29 +7,16 @@ import {
 } from 'reactstrap';
 } from 'reactstrap';
 
 
 const DeleteAllShareLinksModal = React.memo((props) => {
 const DeleteAllShareLinksModal = React.memo((props) => {
-  const { t } = props;
+  const { t, onClickDeleteButton, onClose } = props;
 
 
-  function closeModal() {
-    if (props.onClose == null) {
-      return;
-    }
+  const deleteAllLinkHandler = useCallback(() => {
+    onClickDeleteButton?.();
+    onClose?.();
+  }, [onClickDeleteButton, onClose]);
 
 
-    props.onClose();
-  }
-
-  function deleteAllLinkHandler() {
-    if (props.onClickDeleteButton == null) {
-      return;
-    }
-
-    props.onClickDeleteButton();
-
-    closeModal();
-  }
-
-  function closeButtonHandler() {
-    closeModal();
-  }
+  const closeButtonHandler = useCallback(() => {
+    onClose?.();
+  }, [onClose]);
 
 
   return (
   return (
     <Modal isOpen={props.isOpen} toggle={closeButtonHandler} className="page-comment-delete-modal">
     <Modal isOpen={props.isOpen} toggle={closeButtonHandler} className="page-comment-delete-modal">

+ 0 - 2
apps/app/src/components/Admin/Security/SecurityManagement.tsx

@@ -1,7 +1,5 @@
 import React, { useEffect, useCallback } from 'react';
 import React, { useEffect, useCallback } from 'react';
 
 
-import PropTypes from 'prop-types';
-
 import AdminGeneralSecurityContainer from '~/client/services/AdminGeneralSecurityContainer';
 import AdminGeneralSecurityContainer from '~/client/services/AdminGeneralSecurityContainer';
 import { toastError } from '~/client/util/toastr';
 import { toastError } from '~/client/util/toastr';
 import { toArrayIfNot } from '~/utils/array-utils';
 import { toArrayIfNot } from '~/utils/array-utils';

+ 0 - 1
apps/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySecretTokenSection.jsx

@@ -6,7 +6,6 @@ import PropTypes from 'prop-types';
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { toastSuccess, toastError } from '~/client/util/toastr';
 import { toastSuccess, toastError } from '~/client/util/toastr';
 
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 
 
 
 

+ 9 - 21
apps/app/src/components/Admin/SlackIntegration/DeleteSlackBotSettingsModal.jsx

@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useCallback } from 'react';
 
 
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
@@ -7,28 +7,16 @@ import {
 } from 'reactstrap';
 } from 'reactstrap';
 
 
 const DeleteSlackBotSettingsModal = React.memo((props) => {
 const DeleteSlackBotSettingsModal = React.memo((props) => {
-  const { t } = useTranslation();
+  const { t, onClickDeleteButton, onClose } = useTranslation();
 
 
-  function closeModal() {
-    if (props.onClose == null) {
-      return;
-    }
+  const deleteSlackCredentialsHandler = useCallback(() => {
+    onClickDeleteButton?.();
+    onClose?.();
+  }, [onClickDeleteButton, onClose]);
 
 
-    props.onClose();
-  }
-
-  function deleteSlackCredentialsHandler() {
-    if (props.onClickDeleteButton == null) {
-      return;
-    }
-    props.onClickDeleteButton();
-
-    closeModal();
-  }
-
-  function closeButtonHandler() {
-    closeModal();
-  }
+  const closeButtonHandler = useCallback(() => {
+    onClose?.();
+  }, [onClose]);
 
 
   return (
   return (
     <Modal isOpen={props.isOpen} toggle={closeButtonHandler} className="page-comment-delete-modal">
     <Modal isOpen={props.isOpen} toggle={closeButtonHandler} className="page-comment-delete-modal">

+ 1 - 3
apps/app/src/components/Admin/SlackIntegration/WithProxyAccordions.jsx

@@ -1,11 +1,9 @@
 /* eslint-disable react/prop-types */
 /* eslint-disable react/prop-types */
-import React, { useState, useCallback } from 'react';
+import React, { useState } from 'react';
 
 
 import { SlackbotType } from '@growi/slack';
 import { SlackbotType } from '@growi/slack';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
-import { CopyToClipboard } from 'react-copy-to-clipboard';
-import { Tooltip } from 'reactstrap';
 
 
 import { apiv3Put, apiv3Post } from '~/client/util/apiv3-client';
 import { apiv3Put, apiv3Post } from '~/client/util/apiv3-client';
 import { toastSuccess, toastError } from '~/client/util/toastr';
 import { toastSuccess, toastError } from '~/client/util/toastr';

+ 10 - 5
apps/app/src/components/Admin/Users/PasswordResetModal.jsx

@@ -30,7 +30,7 @@ class PasswordResetModal extends React.Component {
   }
   }
 
 
   async resetPassword() {
   async resetPassword() {
-    const { t, userForPasswordResetModal } = this.props;
+    const { userForPasswordResetModal } = this.props;
     try {
     try {
       const res = await apiv3Put('/users/reset-password', { id: userForPasswordResetModal._id });
       const res = await apiv3Put('/users/reset-password', { id: userForPasswordResetModal._id });
       const { newPassword } = res.data;
       const { newPassword } = res.data;
@@ -47,9 +47,13 @@ class PasswordResetModal extends React.Component {
 
 
     return (
     return (
       <>
       <>
-        <button type="submit" className={`btn ${isEmailSent ? 'btn-secondary' : 'btn-primary'}`}
-          onClick={this.onClickSendNewPasswordButton} disabled={!isMailerSetup || isEmailSending || isEmailSent}>
-          {isEmailSending && <i className='fa fa-spinner fa-pulse mx-2' />}
+        <button
+          type="submit"
+          className={`btn ${isEmailSent ? 'btn-secondary' : 'btn-primary'}`}
+          onClick={this.onClickSendNewPasswordButton}
+          disabled={!isMailerSetup || isEmailSending || isEmailSent}
+        >
+          {isEmailSending && <i className="fa fa-spinner fa-pulse mx-2" />}
           {!isEmailSending && (isEmailSent ? t('commons:Done') : t('commons:Send'))}
           {!isEmailSending && (isEmailSent ? t('commons:Done') : t('commons:Send'))}
         </button>
         </button>
         <button type="submit" className="btn btn-danger" onClick={this.props.onClose}>
         <button type="submit" className="btn btn-danger" onClick={this.props.onClose}>
@@ -119,7 +123,7 @@ class PasswordResetModal extends React.Component {
               {showPassword ? temporaryPassword : maskedPassword}
               {showPassword ? temporaryPassword : maskedPassword}
             </span>
             </span>
           </code>
           </code>
-          <CopyToClipboard text={ temporaryPassword } onCopy={() => this.setState({ showTooltip: true })}>
+          <CopyToClipboard text={temporaryPassword} onCopy={() => this.setState({ showTooltip: true })}>
             <button id="copy-tooltip" type="button" className="btn btn-outline-secondary border-0">
             <button id="copy-tooltip" type="button" className="btn btn-outline-secondary border-0">
               <i className="fa fa-clone" aria-hidden="true"></i>
               <i className="fa fa-clone" aria-hidden="true"></i>
             </button>
             </button>
@@ -210,6 +214,7 @@ const PasswordResetModalWrapperFC = (props) => {
 PasswordResetModal.propTypes = {
 PasswordResetModal.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   t: PropTypes.func.isRequired, // i18next
 
 
+  isMailerSetup: PropTypes.bool.isRequired,
   isOpen: PropTypes.bool.isRequired,
   isOpen: PropTypes.bool.isRequired,
   onClose: PropTypes.func.isRequired,
   onClose: PropTypes.func.isRequired,
   userForPasswordResetModal: PropTypes.object,
   userForPasswordResetModal: PropTypes.object,

+ 1 - 2
apps/app/src/components/Admin/Users/UserInviteModal.jsx

@@ -208,8 +208,6 @@ class UserInviteModal extends React.Component {
 
 
   async handleSubmit() {
   async handleSubmit() {
     const { adminUsersContainer } = this.props;
     const { adminUsersContainer } = this.props;
-    // eslint-disable-next-line no-unused-vars
-    const { isCreateUserButtonPushed } = this.state;
 
 
     this.setState({ isCreateUserButtonPushed: true });
     this.setState({ isCreateUserButtonPushed: true });
 
 
@@ -295,6 +293,7 @@ const UserInviteModalWrapper = withUnstatedContainers(UserInviteModalWrapperFC,
 UserInviteModal.propTypes = {
 UserInviteModal.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   t: PropTypes.func.isRequired, // i18next
   adminUsersContainer: PropTypes.instanceOf(AdminUsersContainer).isRequired,
   adminUsersContainer: PropTypes.instanceOf(AdminUsersContainer).isRequired,
+  isMailerSetup: PropTypes.bool.isRequired,
 };
 };
 
 
 export default UserInviteModalWrapper;
 export default UserInviteModalWrapper;

+ 0 - 243
apps/app/src/components/ArchiveCreateModal.jsx

@@ -1,243 +0,0 @@
-import React, { useState, useCallback } from 'react';
-
-import { useTranslation } from 'next-i18next';
-import PropTypes from 'prop-types';
-import {
-  Modal, ModalHeader, ModalBody, ModalFooter,
-} from 'reactstrap';
-
-import { apiv3Post } from '~/client/util/apiv3-client';
-import { toastSuccess, toastError } from '~/client/util/toastr';
-
-
-const ArchiveCreateModal = (props) => {
-  const { t } = useTranslation();
-  const { appContainer } = props;
-  const [isCommentDownload, setIsCommentDownload] = useState(false);
-  const [isAttachmentFileDownload, setIsAttachmentFileDownload] = useState(false);
-  const [isSubordinatedPageDownload, setIsSubordinatedPageDownload] = useState(false);
-  const [fileType, setFileType] = useState('markdown');
-  const [hierarchyType, setHierarchyType] = useState('allSubordinatedPage');
-  const [hierarchyValue, setHierarchyValue] = useState(1);
-
-  function changeIsCommentDownloadHandler() {
-    setIsCommentDownload(!isCommentDownload);
-  }
-
-  function changeIsAttachmentFileDownloadHandler() {
-    setIsAttachmentFileDownload(!isAttachmentFileDownload);
-  }
-
-  function changeIsSubordinatedPageDownloadHandler() {
-    setIsSubordinatedPageDownload(!isSubordinatedPageDownload);
-  }
-
-  function closeModalHandler() {
-    if (props.onClose == null) {
-      return;
-    }
-
-    props.onClose();
-  }
-
-  const handleChangeFileType = useCallback(
-    (filetype) => {
-      setFileType(filetype);
-    },
-    [],
-  );
-
-  function handleChangeSubordinatedType(hierarchyType) {
-    setHierarchyType(hierarchyType);
-  }
-
-  function handleHierarchyDepth(hierarchyValue) {
-    setHierarchyValue(hierarchyValue);
-  }
-
-
-  async function done() {
-    try {
-      await apiv3Post('/page/archive', {
-        rootPagePath: props.path,
-        isCommentDownload,
-        isAttachmentFileDownload,
-        isSubordinatedPageDownload,
-        fileType,
-        hierarchyType,
-        hierarchyValue,
-      });
-      toastSuccess(t('Submitted the request to create the archive'));
-      closeModalHandler();
-    }
-    catch (e) {
-      toastError(e);
-    }
-  }
-
-  return (
-    <Modal isOpen={props.isOpen} toggle={closeModalHandler}>
-      <ModalHeader tag="h4" toggle={closeModalHandler} className="bg-primary text-white">
-        {t('Create Archive Page')}
-      </ModalHeader>
-      <ModalBody>
-        <div className="form-group">
-          <div className="form-group">
-            <label>{t('Target page')}</label>
-            <br />
-            <code>{props.path}</code>
-          </div>
-
-          <div className="custom-control-inline">
-            <label>{t('File type')}: </label>
-          </div>
-          <div className="custom-control custom-radio custom-control-inline ">
-            <input
-              type="radio"
-              className="custom-control-input"
-              id="customRadio1"
-              name="isFileType"
-              value="customRadio1"
-              checked={fileType === 'markdown'}
-              onChange={() => {
-                handleChangeFileType('markdown');
-              }}
-            />
-            <label className="custom-control-label" htmlFor="customRadio1">
-              MarkDown(.md)
-            </label>
-          </div>
-
-          <div className="custom-control custom-radio custom-control-inline ">
-            <input
-              type="radio"
-              className="custom-control-input"
-              id="customRadio2"
-              name="isFileType"
-              value="customRadio2"
-              checked={fileType === 'pdf'}
-              onChange={() => {
-                handleChangeFileType('pdf');
-              }}
-            />
-            <label className="custom-control-label" htmlFor="customRadio2">
-              PDF(.pdf)
-            </label>
-          </div>
-        </div>
-
-        <div className="my-1 custom-control custom-checkbox custom-checkbox-info">
-          <input
-            className="custom-control-input"
-            name="comment"
-            id="commentFile"
-            type="checkbox"
-            checked={isCommentDownload}
-            onChange={changeIsCommentDownloadHandler}
-          />
-          <label className="custom-control-label" htmlFor="commentFile">
-            {t('Include Comment')}
-          </label>
-        </div>
-        <div className="my-1 custom-control custom-checkbox custom-checkbox-info">
-          <input
-            className="custom-control-input"
-            id="downloadFile"
-            type="checkbox"
-            checked={isAttachmentFileDownload}
-            onChange={changeIsAttachmentFileDownloadHandler}
-          />
-          <label className="custom-control-label" htmlFor="downloadFile">
-            {t('Include Attachment File')}
-          </label>
-        </div>
-        <div className="my-1 custom-control custom-checkbox custom-checkbox-info">
-          <input
-            className="custom-control-input"
-            id="subordinatedFile"
-            type="checkbox"
-            checked={isSubordinatedPageDownload}
-            onChange={changeIsSubordinatedPageDownloadHandler}
-          />
-          <label className="custom-control-label" htmlFor="subordinatedFile">
-            {t('Include Subordinated Page')}
-          </label>
-          {isSubordinatedPageDownload && (
-            <>
-              <div className="FormGroup">
-                <div className="my-1 custom-control custom-radio custom-control-inline ">
-                  <input
-                    type="radio"
-                    className="custom-control-input"
-                    id="customRadio3"
-                    name="isSubordinatedType"
-                    value="customRadio3"
-                    disabled={!isSubordinatedPageDownload}
-                    checked={hierarchyType === 'allSubordinatedPage'}
-                    onChange={() => {
-                      handleChangeSubordinatedType('allSubordinatedPage');
-                    }}
-                  />
-                  <label className="custom-control-label" htmlFor="customRadio3">
-                    {t('All Subordinated Page')}
-                  </label>
-                </div>
-              </div>
-              <div className="FormGroup">
-                <div className="my-1 custom-control custom-radio custom-control-inline">
-                  <input
-                    type="radio"
-                    className="custom-control-input"
-                    id="customRadio4"
-                    name="isSubordinatedType"
-                    value="customRadio4"
-                    disabled={!isSubordinatedPageDownload}
-                    checked={hierarchyType === 'decideHierarchy'}
-                    onChange={() => {
-                      handleChangeSubordinatedType('decideHierarchy');
-                    }}
-                  />
-                  <label className="my-1 custom-control-label" htmlFor="customRadio4">
-                    {t('Specify Hierarchy')}
-                  </label>
-                </div>
-              </div>
-              <div className="my-1 custom-control costom-control-inline">
-                <input
-                  type="number"
-                  min="1"
-                  max="10"
-                  disabled={hierarchyType === 'allSubordinatedPage'}
-                  value={hierarchyValue}
-                  placeholder="1"
-                  onChange={(e) => {
-                    handleHierarchyDepth(e.target.value);
-                  }}
-                />
-              </div>
-            </>
-          )}
-        </div>
-      </ModalBody>
-      <ModalFooter>
-        {/* TO DO implement correct number at GW-3053 */}
-        合計{props.totalPages}ページ取得
-        {props.errorMessage}
-        <button type="button" className="btn btn-primary" onClick={done}>
-          Done
-        </button>
-      </ModalFooter>
-    </Modal>
-  );
-};
-
-ArchiveCreateModal.propTypes = {
-  // appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  isOpen: PropTypes.bool.isRequired,
-  onClose: PropTypes.func,
-  path: PropTypes.string.isRequired,
-  totalPages: PropTypes.number,
-  errorMessage: PropTypes.string,
-};
-
-export default ArchiveCreateModal;

+ 9 - 3
apps/app/src/components/BookmarkButtons.tsx

@@ -64,12 +64,18 @@ export const BookmarkButtons: FC<Props> = (props: Props) => {
     <div className={`btn-group btn-group-bookmark ${styles['btn-group-bookmark']}`} role="group" aria-label="Bookmark buttons">
     <div className={`btn-group btn-group-bookmark ${styles['btn-group-bookmark']}`} role="group" aria-label="Bookmark buttons">
 
 
       <BookmarkFolderMenu
       <BookmarkFolderMenu
-        isOpen={isBookmarkFolderMenuOpen} pageId={pageId} isBookmarked={isBookmarked ?? false}
+        isOpen={isBookmarkFolderMenuOpen}
+        pageId={pageId}
+        isBookmarked={isBookmarked ?? false}
         onToggle={toggleBookmarkFolderMenuHandler}
         onToggle={toggleBookmarkFolderMenuHandler}
         onUnbookmark={unbookmarkHandler}
         onUnbookmark={unbookmarkHandler}
       >
       >
-        <DropdownToggle id='bookmark-dropdown-btn' color="transparent" className={`shadow-none btn btn-bookmark border-0
-          ${isBookmarked ? 'active' : ''} ${isGuestUser ? 'disabled' : ''}`}>
+        <DropdownToggle
+          id="bookmark-dropdown-btn"
+          color="transparent"
+          className={`shadow-none btn btn-bookmark border-0
+          ${isBookmarked ? 'active' : ''} ${isGuestUser ? 'disabled' : ''}`}
+        >
           <i className={`fa ${isBookmarked ? 'fa-bookmark' : 'fa-bookmark-o'}`}></i>
           <i className={`fa ${isBookmarked ? 'fa-bookmark' : 'fa-bookmark-o'}`}></i>
         </DropdownToggle>
         </DropdownToggle>
       </BookmarkFolderMenu>
       </BookmarkFolderMenu>

+ 8 - 10
apps/app/src/components/Bookmarks/BookmarkFolderItem.tsx

@@ -174,7 +174,7 @@ export const BookmarkFolderItem: FC<BookmarkFolderItemProps> = (props: BookmarkF
           bookmarkedPage={bookmark.page}
           bookmarkedPage={bookmark.page}
           level={level + 1}
           level={level + 1}
           parentFolder={bookmarkFolder}
           parentFolder={bookmarkFolder}
-          canMoveToRoot={true}
+          canMoveToRoot
           onClickDeleteMenuItemHandler={onClickDeleteMenuItemHandler}
           onClickDeleteMenuItemHandler={onClickDeleteMenuItemHandler}
           bookmarkFolderTreeMutation={bookmarkFolderTreeMutation}
           bookmarkFolderTreeMutation={bookmarkFolderTreeMutation}
         />
         />
@@ -222,7 +222,7 @@ export const BookmarkFolderItem: FC<BookmarkFolderItemProps> = (props: BookmarkF
         isDropable={isDropable}
         isDropable={isDropable}
       >
       >
         <li
         <li
-          className={'list-group-item list-group-item-action border-0 py-0 pr-3 d-flex align-items-center'}
+          className="list-group-item list-group-item-action border-0 py-0 pr-3 d-flex align-items-center"
           onClick={loadChildFolder}
           onClick={loadChildFolder}
           style={{ paddingLeft }}
           style={{ paddingLeft }}
         >
         >
@@ -239,11 +239,9 @@ export const BookmarkFolderItem: FC<BookmarkFolderItemProps> = (props: BookmarkF
               </button>
               </button>
             )}
             )}
           </div>
           </div>
-          {
-            <div>
-              <FolderIcon isOpen={isOpen} />
-            </div>
-          }
+          <div>
+            <FolderIcon isOpen={isOpen} />
+          </div>
           {isRenameAction ? (
           {isRenameAction ? (
             <BookmarkFolderNameInput
             <BookmarkFolderNameInput
               onClickOutside={() => setIsRenameAction(false)}
               onClickOutside={() => setIsRenameAction(false)}
@@ -252,8 +250,8 @@ export const BookmarkFolderItem: FC<BookmarkFolderItemProps> = (props: BookmarkF
             />
             />
           ) : (
           ) : (
             <>
             <>
-              <div className='grw-foldertree-title-anchor pl-2' >
-                <p className={'text-truncate m-auto '}>{name}</p>
+              <div className="grw-foldertree-title-anchor pl-2">
+                <p className="text-truncate m-auto ">{name}</p>
               </div>
               </div>
             </>
             </>
           )}
           )}
@@ -276,7 +274,7 @@ export const BookmarkFolderItem: FC<BookmarkFolderItemProps> = (props: BookmarkF
               {/* Maximum folder hierarchy of 2 levels */}
               {/* Maximum folder hierarchy of 2 levels */}
               {!(bookmarkFolder.parent != null) && (
               {!(bookmarkFolder.parent != null) && (
                 <button
                 <button
-                  id='create-bookmark-folder-button'
+                  id="create-bookmark-folder-button"
                   type="button"
                   type="button"
                   className="border-0 rounded btn btn-page-item-control p-0 grw-visible-on-hover"
                   className="border-0 rounded btn btn-page-item-control p-0 grw-visible-on-hover"
                   onClick={onClickPlusButton}
                   onClick={onClickPlusButton}

+ 2 - 2
apps/app/src/components/Bookmarks/BookmarkFolderItemControl.tsx

@@ -47,10 +47,10 @@ export const BookmarkFolderItemControl: React.FC<{
           {t('Rename')}
           {t('Rename')}
         </DropdownItem>
         </DropdownItem>
 
 
-        <DropdownItem divider/>
+        <DropdownItem divider />
 
 
         <DropdownItem
         <DropdownItem
-          className='pt-2 grw-page-control-dropdown-item text-danger'
+          className="pt-2 grw-page-control-dropdown-item text-danger"
           onClick={onClickDelete}
           onClick={onClickDelete}
         >
         >
           <i className="icon-fw icon-trash grw-page-control-dropdown-icon"></i>
           <i className="icon-fw icon-trash grw-page-control-dropdown-icon"></i>

+ 5 - 6
apps/app/src/components/Bookmarks/BookmarkFolderMenu.tsx

@@ -1,6 +1,5 @@
 import React, { useCallback, useMemo, useState } from 'react';
 import React, { useCallback, useMemo, useState } from 'react';
 
 
-// import { getCustomModifiers } from '@growi/ui/dist/utils';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import { DropdownItem, DropdownMenu, UncontrolledDropdown } from 'reactstrap';
 import { DropdownItem, DropdownMenu, UncontrolledDropdown } from 'reactstrap';
 
 
@@ -117,7 +116,7 @@ export const BookmarkFolderMenu = (props: BookmarkFolderMenuProps): JSX.Element
         <DropdownItem
         <DropdownItem
           toggle={false}
           toggle={false}
           onClick={onUnbookmarkHandler}
           onClick={onUnbookmarkHandler}
-          className={'grw-bookmark-folder-menu-item text-danger'}
+          className="grw-bookmark-folder-menu-item text-danger"
         >
         >
           <i className="fa fa-bookmark"></i>{' '}
           <i className="fa fa-bookmark"></i>{' '}
           <span className="mx-2">
           <span className="mx-2">
@@ -160,7 +159,7 @@ export const BookmarkFolderMenu = (props: BookmarkFolderMenuProps): JSX.Element
                 {folder.children?.map(child => (
                 {folder.children?.map(child => (
                   <div key={child._id}>
                   <div key={child._id}>
                     <div
                     <div
-                      className='dropdown-item grw-bookmark-folder-menu-item list-group-item list-group-item-action border-0 py-0'
+                      className="dropdown-item grw-bookmark-folder-menu-item list-group-item list-group-item-action border-0 py-0"
                       style={{ paddingLeft: '60px' }}
                       style={{ paddingLeft: '60px' }}
                       tabIndex={0}
                       tabIndex={0}
                       role="menuitem"
                       role="menuitem"
@@ -187,14 +186,14 @@ export const BookmarkFolderMenu = (props: BookmarkFolderMenuProps): JSX.Element
       isOpen={isOpen}
       isOpen={isOpen}
       onToggle={toggleHandler}
       onToggle={toggleHandler}
       direction={isBookmarkFolderExists ? 'up' : 'down'}
       direction={isBookmarkFolderExists ? 'up' : 'down'}
-      className='grw-bookmark-folder-dropdown'
+      className="grw-bookmark-folder-dropdown"
     >
     >
       {children}
       {children}
       <DropdownMenu
       <DropdownMenu
         end
         end
         persist
         persist
-        strategy='fixed'
-        className='grw-bookmark-folder-menu'
+        strategy="fixed"
+        className="grw-bookmark-folder-menu"
       >
       >
         { renderBookmarkMenuItem() }
         { renderBookmarkMenuItem() }
       </DropdownMenu>
       </DropdownMenu>

+ 2 - 2
apps/app/src/components/Bookmarks/BookmarkFolderMenuItem.tsx

@@ -10,7 +10,7 @@ export const BookmarkFolderMenuItem: React.FC<{
   isSelected,
   isSelected,
 }) => {
 }) => {
   return (
   return (
-    <div className='d-flex justify-content-start grw-bookmark-folder-menu-item-title'>
+    <div className="d-flex justify-content-start grw-bookmark-folder-menu-item-title">
       <input
       <input
         type="radio"
         type="radio"
         checked={isSelected}
         checked={isSelected}
@@ -19,7 +19,7 @@ export const BookmarkFolderMenuItem: React.FC<{
         onChange={e => e.stopPropagation()}
         onChange={e => e.stopPropagation()}
         onClick={e => e.stopPropagation()}
         onClick={e => e.stopPropagation()}
       />
       />
-      <label htmlFor={`bookmark-folder-menu-item-${itemId}`} className='p-2 m-0'>
+      <label htmlFor={`bookmark-folder-menu-item-${itemId}`} className="p-2 m-0">
         {itemName}
         {itemName}
       </label>
       </label>
     </div>
     </div>

+ 2 - 2
apps/app/src/components/Bookmarks/BookmarkFolderNameInput.tsx

@@ -1,6 +1,6 @@
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 
 
-import { inputValidator, ValidationTarget } from '~/client/util/input-validator';
+import { ValidationTarget } from '~/client/util/input-validator';
 import ClosableTextInput from '~/components/Common/ClosableTextInput';
 import ClosableTextInput from '~/components/Common/ClosableTextInput';
 
 
 
 
@@ -19,7 +19,7 @@ export const BookmarkFolderNameInput = (props: Props): JSX.Element => {
   return (
   return (
     <div className="flex-fill folder-name-input">
     <div className="flex-fill folder-name-input">
       <ClosableTextInput
       <ClosableTextInput
-        value={ value }
+        value={value}
         placeholder={t('bookmark_folder.input_placeholder')}
         placeholder={t('bookmark_folder.input_placeholder')}
         onClickOutside={onClickOutside}
         onClickOutside={onClickOutside}
         onPressEnter={onPressEnter}
         onPressEnter={onPressEnter}

+ 1 - 1
apps/app/src/components/Bookmarks/BookmarkFolderTree.tsx

@@ -102,7 +102,7 @@ export const BookmarkFolderTree: React.FC<Props> = (props: Props) => {
   // };
   // };
 
 
   return (
   return (
-    <div className={`grw-folder-tree-container ${styles['grw-folder-tree-container']}`} >
+    <div className={`grw-folder-tree-container ${styles['grw-folder-tree-container']}`}>
       <ul className={`grw-foldertree ${styles['grw-foldertree']} list-group px-2 py-2`}>
       <ul className={`grw-foldertree ${styles['grw-foldertree']} list-group px-2 py-2`}>
         {bookmarkFolders?.map((bookmarkFolder) => {
         {bookmarkFolders?.map((bookmarkFolder) => {
           return (
           return (

+ 1 - 1
apps/app/src/components/Bookmarks/BookmarkItem.tsx

@@ -164,7 +164,7 @@ export const BookmarkItem = (props: Props): JSX.Element => {
           )
           )
           : <PageListItemS page={bookmarkedPage} pageTitle={pageTitle} isNarrowView />}
           : <PageListItemS page={bookmarkedPage} pageTitle={pageTitle} isNarrowView />}
 
 
-        <div className='grw-foldertree-control'>
+        <div className="grw-foldertree-control">
           <PageItemControl
           <PageItemControl
             pageId={bookmarkedPage._id}
             pageId={bookmarkedPage._id}
             isEnableActions
             isEnableActions

+ 1 - 1
apps/app/src/components/Bookmarks/DragAndDropWrapper.tsx

@@ -66,7 +66,7 @@ export const DragAndDropWrapper = (props: DragAndDropWrapperProps): JSX.Element
   };
   };
 
 
   return (
   return (
-    <div ref={c => getRef(c)} className={`grw-drag-drop-container ${isOver ? 'grw-accept-drop-item' : ''}` }>
+    <div ref={c => getRef(c)} className={`grw-drag-drop-container ${isOver ? 'grw-accept-drop-item' : ''}`}>
       {children}
       {children}
     </div>
     </div>
   );
   );

+ 1 - 2
apps/app/src/components/CompleteUserRegistration.tsx

@@ -1,7 +1,6 @@
 import React, { FC } from 'react';
 import React, { FC } from 'react';
 
 
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
-import Link from 'next/link';
 
 
 export const CompleteUserRegistration: FC = () => {
 export const CompleteUserRegistration: FC = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
@@ -14,7 +13,7 @@ export const CompleteUserRegistration: FC = () => {
             <span>{t('login.registration_successful')}</span>
             <span>{t('login.registration_successful')}</span>
           </p>
           </p>
           {/* If the transition source is "/login", use <a /> tag since the transition will not occur if next/link is used. */}
           {/* If the transition source is "/login", use <a /> tag since the transition will not occur if next/link is used. */}
-          <a href='/login'>
+          <a href="/login">
             <i className="icon-login mr-1" />{t('Sign in is here')}
             <i className="icon-login mr-1" />{t('Sign in is here')}
           </a>
           </a>
         </div>
         </div>

+ 1 - 1
apps/app/src/components/CompleteUserRegistrationForm.tsx

@@ -170,7 +170,7 @@ const CompleteUserRegistrationForm: React.FC<Props> = (props: Props) => {
               </div>
               </div>
 
 
               <div className="input-group justify-content-center d-flex mt-5">
               <div className="input-group justify-content-center d-flex mt-5">
-                <button disabled={forceDisableForm || disableForm} className="btn btn-fill" id="register">
+                <button type="button" disabled={forceDisableForm || disableForm} className="btn btn-fill" id="register">
                   <div className="eff"></div>
                   <div className="eff"></div>
                   <span className="btn-label"><i className="icon-user-follow"></i></span>
                   <span className="btn-label"><i className="icon-user-follow"></i></span>
                   <span className="btn-label-text">{t('Create')}</span>
                   <span className="btn-label-text">{t('Create')}</span>

+ 1 - 1
apps/app/src/components/DeleteBookmarkFolderModal.tsx

@@ -48,7 +48,7 @@ const DeleteBookmarkFolderModal: FC = () => {
       <ModalBody>
       <ModalBody>
         <div className="form-group pb-1">
         <div className="form-group pb-1">
           <label>{ t('bookmark_folder.delete_modal.modal_body_description') }:</label><br />
           <label>{ t('bookmark_folder.delete_modal.modal_body_description') }:</label><br />
-          <FolderIcon isOpen={false}/> {deleteBookmarkFolderModalData?.bookmarkFolder?.name}
+          <FolderIcon isOpen={false} /> {deleteBookmarkFolderModalData?.bookmarkFolder?.name}
         </div>
         </div>
         {t('bookmark_folder.delete_modal.modal_body_alert')}
         {t('bookmark_folder.delete_modal.modal_body_alert')}
       </ModalBody>
       </ModalBody>

+ 1 - 5
apps/app/src/components/DescendantsPageList.tsx

@@ -82,10 +82,6 @@ const DescendantsPageListSubstance = (props: SubstanceProps): JSX.Element => {
     }
     }
   }, [onPagePutBacked, t]);
   }, [onPagePutBacked, t]);
 
 
-  function setPageNumber(selectedPageNumber) {
-    setActivePage(selectedPageNumber);
-  }
-
   if (pagingResult == null) {
   if (pagingResult == null) {
     return (
     return (
       <div className="wiki">
       <div className="wiki">
@@ -113,7 +109,7 @@ const DescendantsPageListSubstance = (props: SubstanceProps): JSX.Element => {
         <div className="my-4">
         <div className="my-4">
           <PaginationWrapper
           <PaginationWrapper
             activePage={activePage}
             activePage={activePage}
-            changePage={setPageNumber}
+            changePage={selectedPageNumber => setActivePage(selectedPageNumber)}
             totalItemsCount={pagingResult.totalCount}
             totalItemsCount={pagingResult.totalCount}
             pagingLimit={pagingResult.limit}
             pagingLimit={pagingResult.limit}
             align="center"
             align="center"

+ 3 - 2
apps/app/src/components/Hotkeys/Subscribers/EditPage.jsx

@@ -1,8 +1,9 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
+
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
 
 
-import { EditorMode, useEditorMode } from '~/stores/ui';
 import { useIsEditable } from '~/stores/context';
 import { useIsEditable } from '~/stores/context';
+import { EditorMode, useEditorMode } from '~/stores/ui';
 
 
 const EditPage = (props) => {
 const EditPage = (props) => {
   const { data: isEditable } = useIsEditable();
   const { data: isEditable } = useIsEditable();

+ 1 - 1
apps/app/src/components/Hotkeys/Subscribers/FocusToGlobalSearch.jsx

@@ -1,4 +1,4 @@
-import { FC, useEffect } from 'react';
+import { useEffect } from 'react';
 
 
 import { useIsEditable } from '~/stores/context';
 import { useIsEditable } from '~/stores/context';
 import { useGlobalSearchFormRef } from '~/stores/ui';
 import { useGlobalSearchFormRef } from '~/stores/ui';

+ 0 - 1
apps/app/src/components/Hotkeys/Subscribers/ShowStaffCredit.jsx

@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
 
 
 import StaffCredit from '../../StaffCredit/StaffCredit';
 import StaffCredit from '../../StaffCredit/StaffCredit';

+ 4 - 2
apps/app/src/components/Icons/CompressIcon.tsx

@@ -2,7 +2,8 @@ import React from 'react';
 
 
 export const CompressIcon = ():JSX.Element => {
 export const CompressIcon = ():JSX.Element => {
   return (
   return (
-    <svg xmlns="http://www.w3.org/2000/svg"
+    <svg
+      xmlns="http://www.w3.org/2000/svg"
       width="18"
       width="18"
       height="18"
       height="18"
       viewBox="0 0 45 45"
       viewBox="0 0 45 45"
@@ -11,7 +12,8 @@ export const CompressIcon = ():JSX.Element => {
         fill="currentColor"
         fill="currentColor"
         d="M22.45 44v-7.9l-3.85 3.8-2.1-2.1 7.45-7.4 7.35 7.4-2.1
         d="M22.45 44v-7.9l-3.85 3.8-2.1-2.1 7.45-7.4 7.35 7.4-2.1
             2.1-3.75-3.8V44ZM8.05 27.5v-3H40v3Zm0-6.05v-3H40v3Zm15.9-5.85-7.4-7.4 2.1-2.1
             2.1-3.75-3.8V44ZM8.05 27.5v-3H40v3Zm0-6.05v-3H40v3Zm15.9-5.85-7.4-7.4 2.1-2.1
-            3.75 3.8V2h3v7.9l3.85-3.8 2.1 2.1Z"/>
+            3.75 3.8V2h3v7.9l3.85-3.8 2.1 2.1Z"
+      />
     </svg>
     </svg>
   );
   );
 };
 };

+ 2 - 1
apps/app/src/components/Icons/ExpandIcon.tsx

@@ -2,7 +2,8 @@ import React from 'react';
 
 
 export const ExpandIcon = (): JSX.Element => {
 export const ExpandIcon = (): JSX.Element => {
   return (
   return (
-    <svg xmlns="http://www.w3.org/2000/svg"
+    <svg
+      xmlns="http://www.w3.org/2000/svg"
       width="18"
       width="18"
       height="18"
       height="18"
       viewBox="0 0 45 45"
       viewBox="0 0 45 45"

+ 6 - 4
apps/app/src/components/Icons/FolderIcon.tsx

@@ -10,12 +10,14 @@ export const FolderIcon = (props: Props): JSX.Element => {
     <>
     <>
       {!isOpen ? (
       {!isOpen ? (
         <svg
         <svg
-          width ="20"
-          height ="20"
+          width="20"
+          height="20"
           viewBox="0 0 24 24"
           viewBox="0 0 24 24"
         >
         >
-          <path fill="currentColor"
-            d="M20,18H4V8H20M20,6H12L10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6Z" />
+          <path
+            fill="currentColor"
+            d="M20,18H4V8H20M20,6H12L10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6Z"
+          />
         </svg>
         </svg>
       ) : (
       ) : (
         <svg
         <svg

+ 2 - 2
apps/app/src/components/InvitedForm.tsx

@@ -58,8 +58,8 @@ export const InvitedForm = (props: InvitedFormProps): JSX.Element => {
       <>
       <>
         { loginErrors != null && loginErrors.length > 0 ? (
         { loginErrors != null && loginErrors.length > 0 ? (
           <p className="alert alert-danger">
           <p className="alert alert-danger">
-            { loginErrors.map((err, index) => {
-              return <span key={index}>{ t(err.message) }<br/></span>;
+            { loginErrors.map((err) => {
+              return <span>{ t(err.message) }<br /></span>;
             }) }
             }) }
           </p>
           </p>
         ) : (
         ) : (

+ 47 - 29
apps/app/src/components/LoginForm.tsx

@@ -141,8 +141,9 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
     if (errors == null || errors.length === 0) return <></>;
     if (errors == null || errors.length === 0) return <></>;
     return (
     return (
       <div className="alert alert-danger">
       <div className="alert alert-danger">
-        {errors.map((err, index) => {
-          return <small key={index} dangerouslySetInnerHTML={{ __html: tWithOpt(err.message, err.args) }}></small>;
+        {errors.map((err) => {
+          // eslint-disable-next-line react/no-danger
+          return <small dangerouslySetInnerHTML={{ __html: tWithOpt(err.message, err.args) }}></small>;
         })}
         })}
       </div>
       </div>
     );
     );
@@ -153,12 +154,11 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
     if (errors == null || errors.length === 0) return <></>;
     if (errors == null || errors.length === 0) return <></>;
     return (
     return (
       <ul className="alert alert-danger">
       <ul className="alert alert-danger">
-        {errors.map((err, index) => {
-          return (
-            <li key={index} className={index > 0 ? 'mt-1' : ''}>
-              {tWithOpt(err.message, err.args)}
-            </li>);
-        })}
+        {errors.map((err, index) => (
+          <li className={index > 0 ? 'mt-1' : ''}>
+            {tWithOpt(err.message, err.args)}
+          </li>
+        ))}
       </ul>
       </ul>
     );
     );
   }, [tWithOpt]);
   }, [tWithOpt]);
@@ -180,13 +180,13 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
       <>
       <>
         {/* !! - DO NOT DELETE HIDDEN ELEMENT - !! -- 7.12 ryoji-s */}
         {/* !! - DO NOT DELETE HIDDEN ELEMENT - !! -- 7.12 ryoji-s */}
         {/* Import font-awesome to prevent MongoStore.js "Unable to find the session to touch" error */}
         {/* Import font-awesome to prevent MongoStore.js "Unable to find the session to touch" error */}
-        <div className='sr-only'>
+        <div className="sr-only">
           <i className="fa fa-spinner fa-pulse" />
           <i className="fa fa-spinner fa-pulse" />
         </div>
         </div>
         {/* !! - END OF HIDDEN ELEMENT - !! */}
         {/* !! - END OF HIDDEN ELEMENT - !! */}
         {isLdapSetupFailed && (
         {isLdapSetupFailed && (
           <div className="alert alert-warning small">
           <div className="alert alert-warning small">
-            <strong><i className="icon-fw icon-info"></i>{t('login.enabled_ldap_has_configuration_problem')}</strong><br/>
+            <strong><i className="icon-fw icon-info"></i>{t('login.enabled_ldap_has_configuration_problem')}</strong><br />
             <span dangerouslySetInnerHTML={{ __html: t('login.set_env_var_for_logs') }}></span>
             <span dangerouslySetInnerHTML={{ __html: t('login.set_env_var_for_logs') }}></span>
           </div>
           </div>
         )}
         )}
@@ -200,8 +200,14 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
                 <i className="icon-user"></i>
                 <i className="icon-user"></i>
               </span>
               </span>
             </div>
             </div>
-            <input type="text" className="form-control rounded-0" data-testid="tiUsernameForLogin" placeholder="Username or E-mail"
-              onChange={(e) => { setUsernameForLogin(e.target.value) }} name="usernameForLogin" />
+            <input
+              type="text"
+              className="form-control rounded-0"
+              data-testid="tiUsernameForLogin"
+              placeholder="Username or E-mail"
+              onChange={(e) => { setUsernameForLogin(e.target.value) }}
+              name="usernameForLogin"
+            />
             {isLdapStrategySetup && (
             {isLdapStrategySetup && (
               <div className="input-group-append">
               <div className="input-group-append">
                 <small className="input-group-text text-success">
                 <small className="input-group-text text-success">
@@ -217,8 +223,14 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
                 <i className="icon-lock"></i>
                 <i className="icon-lock"></i>
               </span>
               </span>
             </div>
             </div>
-            <input type="password" className="form-control rounded-0" data-testid="tiPasswordForLogin" placeholder="Password"
-              onChange={(e) => { setPasswordForLogin(e.target.value) }} name="passwordForLogin" />
+            <input
+              type="password"
+              className="form-control rounded-0"
+              data-testid="tiPasswordForLogin"
+              placeholder="Password"
+              onChange={(e) => { setPasswordForLogin(e.target.value) }}
+              name="passwordForLogin"
+            />
           </div>
           </div>
 
 
           <div className="input-group my-4">
           <div className="input-group my-4">
@@ -387,13 +399,11 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
         {
         {
           registerErrors != null && registerErrors.length > 0 && (
           registerErrors != null && registerErrors.length > 0 && (
             <p className="alert alert-danger">
             <p className="alert alert-danger">
-              {registerErrors.map((err, index) => {
-                return (
-                  <span key={index}>
-                    {t(err.message)}<br/>
-                  </span>
-                );
-              })}
+              {registerErrors.map(err => (
+                <span>
+                  {t(err.message)}<br />
+                </span>
+              ))}
             </p>
             </p>
           )
           )
         }
         }
@@ -406,7 +416,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
           )
           )
         }
         }
 
 
-        <form role="form" onSubmit={e => handleRegisterFormSubmit(e, registerAction) } id="register-form">
+        <form role="form" onSubmit={e => handleRegisterFormSubmit(e, registerAction)} id="register-form">
 
 
           {!isEmailAuthenticationEnabled && (
           {!isEmailAuthenticationEnabled && (
             <div>
             <div>
@@ -437,13 +447,15 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
                   </span>
                   </span>
                 </div>
                 </div>
                 {/* name */}
                 {/* name */}
-                <input type="text"
+                <input
+                  type="text"
                   className="form-control rounded-0"
                   className="form-control rounded-0"
                   onChange={(e) => { setNameForRegister(e.target.value) }}
                   onChange={(e) => { setNameForRegister(e.target.value) }}
                   placeholder={t('Name')}
                   placeholder={t('Name')}
                   name="name"
                   name="name"
                   defaultValue={props.name}
                   defaultValue={props.name}
-                  required />
+                  required
+                />
               </div>
               </div>
             </div>
             </div>
           )}
           )}
@@ -455,7 +467,8 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
               </span>
               </span>
             </div>
             </div>
             {/* email */}
             {/* email */}
-            <input type="email"
+            <input
+              type="email"
               disabled={!isMailerSetup && isEmailAuthenticationEnabled}
               disabled={!isMailerSetup && isEmailAuthenticationEnabled}
               className="form-control rounded-0"
               className="form-control rounded-0"
               onChange={(e) => { setEmailForRegister(e.target.value) }}
               onChange={(e) => { setEmailForRegister(e.target.value) }}
@@ -490,12 +503,14 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
                   </span>
                   </span>
                 </div>
                 </div>
                 {/* Password */}
                 {/* Password */}
-                <input type="password"
+                <input
+                  type="password"
                   className="form-control rounded-0"
                   className="form-control rounded-0"
                   onChange={(e) => { setPasswordForRegister(e.target.value) }}
                   onChange={(e) => { setPasswordForRegister(e.target.value) }}
                   placeholder={t('Password')}
                   placeholder={t('Password')}
                   name="password"
                   name="password"
-                  required />
+                  required
+                />
               </div>
               </div>
             </div>
             </div>
           )}
           )}
@@ -503,6 +518,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
           {/* Sign up button (submit) */}
           {/* Sign up button (submit) */}
           <div className="input-group justify-content-center my-4">
           <div className="input-group justify-content-center my-4">
             <button
             <button
+              type="button"
               className="btn btn-fill rounded-0"
               className="btn btn-fill rounded-0"
               id="register"
               id="register"
               disabled={(!isMailerSetup && isEmailAuthenticationEnabled) || isLoading}
               disabled={(!isMailerSetup && isEmailAuthenticationEnabled) || isLoading}
@@ -525,7 +541,8 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
               id="login"
               id="login"
               className="link-switch"
               className="link-switch"
               style={{ pointerEvents: isLoading ? 'none' : 'auto' }}
               style={{ pointerEvents: isLoading ? 'none' : 'auto' }}
-              onClick={switchForm}>
+              onClick={switchForm}
+            >
               <i className="icon-fw icon-login"></i>
               <i className="icon-fw icon-login"></i>
               {t('Sign in is here')}
               {t('Sign in is here')}
             </a>
             </a>
@@ -566,7 +583,8 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
                       id="register"
                       id="register"
                       className="link-switch"
                       className="link-switch"
                       style={{ pointerEvents: isLoading ? 'none' : 'auto' }}
                       style={{ pointerEvents: isLoading ? 'none' : 'auto' }}
-                      onClick={switchForm}>
+                      onClick={switchForm}
+                    >
                       <i className="ti ti-check-box"></i> {t('Sign up is here')}
                       <i className="ti ti-check-box"></i> {t('Sign up is here')}
                     </a>
                     </a>
                   </div>
                   </div>

+ 1 - 1
apps/app/src/components/Me/AssociateModal.tsx

@@ -61,7 +61,7 @@ const AssociateModal = (props: Props): JSX.Element => {
       </ModalHeader>
       </ModalHeader>
       <ModalBody>
       <ModalBody>
         <div>
         <div>
-          <Nav tabs className='mb-2'>
+          <Nav tabs className="mb-2">
             <NavLink
             <NavLink
               className={activeTab === 1 ? 'active' : ''}
               className={activeTab === 1 ? 'active' : ''}
               onClick={() => setActiveTab(1)}
               onClick={() => setActiveTab(1)}

+ 15 - 9
apps/app/src/components/Me/OtherSettings.tsx

@@ -44,9 +44,11 @@ const OtherSettings = (): JSX.Element => {
     <>
     <>
       <h2 className="border-bottom my-4">{t('questionnaire.settings')}</h2>
       <h2 className="border-bottom my-4">{t('questionnaire.settings')}</h2>
 
 
-      {isLoadingCurrentUser && <div className="text-muted text-center mb-5">
-        <i className="fa fa-2x fa-spinner fa-pulse mr-1" />
-      </div>}
+      {isLoadingCurrentUser && (
+        <div className="text-muted text-center mb-5">
+          <i className="fa fa-2x fa-spinner fa-pulse mr-1" />
+        </div>
+      )}
 
 
       <div className="form-group row">
       <div className="form-group row">
         <div className="offset-md-3 col-md-6 text-left">
         <div className="offset-md-3 col-md-6 text-left">
@@ -68,9 +70,11 @@ const OtherSettings = (): JSX.Element => {
               <p className="form-text text-muted small">
               <p className="form-text text-muted small">
                 {t('questionnaire.personal_settings_explanation')}
                 {t('questionnaire.personal_settings_explanation')}
               </p>
               </p>
-              {!growiIsQuestionnaireEnabled && <UncontrolledTooltip placement="bottom" target="grw-questionnaire-settings-toggle-wrapper">
-                {t('questionnaire.disabled_by_admin')}
-              </UncontrolledTooltip> }
+              {!growiIsQuestionnaireEnabled && (
+                <UncontrolledTooltip placement="bottom" target="grw-questionnaire-settings-toggle-wrapper">
+                  {t('questionnaire.disabled_by_admin')}
+                </UncontrolledTooltip>
+              ) }
             </div>
             </div>
           )}
           )}
         </div>
         </div>
@@ -90,9 +94,11 @@ const OtherSettings = (): JSX.Element => {
               {t('Update')}
               {t('Update')}
             </button>
             </button>
           </span>
           </span>
-          {!growiIsQuestionnaireEnabled && <UncontrolledTooltip placement="bottom" target="grw-questionnaire-settings-update-btn-wrapper">
-            {t('questionnaire.disabled_by_admin')}
-          </UncontrolledTooltip>}
+          {!growiIsQuestionnaireEnabled && (
+            <UncontrolledTooltip placement="bottom" target="grw-questionnaire-settings-update-btn-wrapper">
+              {t('questionnaire.disabled_by_admin')}
+            </UncontrolledTooltip>
+          )}
         </div>
         </div>
       </div>
       </div>
     </>
     </>

+ 3 - 3
apps/app/src/components/Navbar/AuthorInfo.tsx

@@ -39,11 +39,11 @@ export const AuthorInfo = (props: AuthorInfoProps): JSX.Element => {
 
 
   if (locate === 'footer') {
   if (locate === 'footer') {
     try {
     try {
-      return <p>{infoLabelForFooter} {format(new Date(date), formatType)} by <UserPicture user={user} size="sm"/> {userLabel}</p>;
+      return <p>{infoLabelForFooter} {format(new Date(date), formatType)} by <UserPicture user={user} size="sm" /> {userLabel}</p>;
     }
     }
     catch (err) {
     catch (err) {
       if (err instanceof RangeError) {
       if (err instanceof RangeError) {
-        return <p>{nullinfoLabelForFooter} <UserPicture user={user} size="sm"/> {userLabel}</p>;
+        return <p>{nullinfoLabelForFooter} <UserPicture user={user} size="sm" /> {userLabel}</p>;
       }
       }
       return <></>;
       return <></>;
     }
     }
@@ -61,7 +61,7 @@ export const AuthorInfo = (props: AuthorInfoProps): JSX.Element => {
   return (
   return (
     <div className="d-flex align-items-center">
     <div className="d-flex align-items-center">
       <div className="mr-2">
       <div className="mr-2">
-        <UserPicture user={user} size="sm"/>
+        <UserPicture user={user} size="sm" />
       </div>
       </div>
       <div>
       <div>
         <div>{infoLabelForSubNav} {userLabel}</div>
         <div>{infoLabelForSubNav} {userLabel}</div>

+ 15 - 9
apps/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -339,11 +339,14 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
         return (
         return (
           <>
           <>
             {!isReadOnlyUser
             {!isReadOnlyUser
-              && <CreateTemplateMenuItems
-                onClickTemplateMenuItem={templateMenuItemClickHandler}
-              />
+              && (
+                <CreateTemplateMenuItems
+                  onClickTemplateMenuItem={templateMenuItemClickHandler}
+                />
+              )
             }
             }
-          </>);
+          </>
+        );
       }
       }
       return (
       return (
         <>
         <>
@@ -352,11 +355,14 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
             revisionId={revisionId}
             revisionId={revisionId}
             isLinkSharingDisabled={isLinkSharingDisabled}
             isLinkSharingDisabled={isLinkSharingDisabled}
           />
           />
-          {!isReadOnlyUser && <>
-            <DropdownItem divider />
-            <CreateTemplateMenuItems
-              onClickTemplateMenuItem={templateMenuItemClickHandler}
-            /></>
+          {!isReadOnlyUser && (
+            <>
+              <DropdownItem divider />
+              <CreateTemplateMenuItems
+                onClickTemplateMenuItem={templateMenuItemClickHandler}
+              />
+            </>
+          )
           }
           }
         </>
         </>
       );
       );

+ 1 - 1
apps/app/src/components/NotFoundPage.tsx

@@ -21,7 +21,7 @@ const NotFoundPage = (props: NotFoundPageProps): JSX.Element => {
     return {
     return {
       pagelist: {
       pagelist: {
         Icon: PageListIcon,
         Icon: PageListIcon,
-        Content: () => <DescendantsPageList path={path}/>,
+        Content: () => <DescendantsPageList path={path} />,
         i18n: t('page_list'),
         i18n: t('page_list'),
       },
       },
       timeLine: {
       timeLine: {

+ 1 - 1
apps/app/src/components/Page/RenderTagLabels.tsx

@@ -41,7 +41,7 @@ const RenderTagLabels = React.memo((props: RenderTagLabelsProps) => {
               onClick={openEditorHandler}
               onClick={openEditorHandler}
             >
             >
               { isTagsEmpty && <>{ t('Add tags for this page') }</>}
               { isTagsEmpty && <>{ t('Add tags for this page') }</>}
-              <i className={`icon-plus ${isTagsEmpty && 'ml-1'}`}/>
+              <i className={`icon-plus ${isTagsEmpty && 'ml-1'}`} />
             </a>
             </a>
           </div>
           </div>
         </NotAvailableForReadOnlyUser>
         </NotAvailableForReadOnlyUser>

+ 1 - 1
apps/app/src/components/Page/RevisionRenderer.tsx

@@ -21,7 +21,7 @@ const ErrorFallback: React.FC<FallbackProps> = React.memo(({ error, resetErrorBo
     <div role="alert">
     <div role="alert">
       <p>Something went wrong:</p>
       <p>Something went wrong:</p>
       <pre>{error.message}</pre>
       <pre>{error.message}</pre>
-      <button className='btn btn-primary' onClick={resetErrorBoundary}>Reload</button>
+      <button type="button" className="btn btn-primary" onClick={resetErrorBoundary}>Reload</button>
     </div>
     </div>
   );
   );
 });
 });

+ 11 - 16
apps/app/src/components/Page/TagEditModal.tsx

@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useCallback } from 'react';
 
 
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import {
 import {
@@ -15,32 +15,27 @@ type Props = {
 };
 };
 
 
 function TagEditModal(props: Props): JSX.Element {
 function TagEditModal(props: Props): JSX.Element {
+  const { onClose, onTagsUpdated } = props;
+
   const [tags, setTags] = useState<string[]>([]);
   const [tags, setTags] = useState<string[]>([]);
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
-  function onTagsUpdatedByTagsInput(tags: string[]) {
-    setTags(tags);
-  }
-
   useEffect(() => {
   useEffect(() => {
     setTags(props.tags);
     setTags(props.tags);
   }, [props.tags]);
   }, [props.tags]);
 
 
-  function closeModalHandler() {
-    if (props.onClose == null) {
-      return;
-    }
-    props.onClose();
-  }
+  const closeModalHandler = useCallback(() => {
+    onClose?.();
+  }, [onClose]);
 
 
-  function handleSubmit() {
-    if (props.onTagsUpdated == null) {
+  const handleSubmit = useCallback(() => {
+    if (onTagsUpdated == null) {
       return;
       return;
     }
     }
 
 
-    props.onTagsUpdated(tags);
+    onTagsUpdated(tags);
     closeModalHandler();
     closeModalHandler();
-  }
+  }, [closeModalHandler, onTagsUpdated, tags]);
 
 
   return (
   return (
     <Modal isOpen={props.isOpen} toggle={closeModalHandler} id="edit-tag-modal" autoFocus={false}>
     <Modal isOpen={props.isOpen} toggle={closeModalHandler} id="edit-tag-modal" autoFocus={false}>
@@ -48,7 +43,7 @@ function TagEditModal(props: Props): JSX.Element {
         {t('tag_edit_modal.edit_tags')}
         {t('tag_edit_modal.edit_tags')}
       </ModalHeader>
       </ModalHeader>
       <ModalBody>
       <ModalBody>
-        <TagsInput tags={tags} onTagsUpdated={onTagsUpdatedByTagsInput} autoFocus />
+        <TagsInput tags={tags} onTagsUpdated={tags => setTags(tags)} autoFocus />
       </ModalBody>
       </ModalBody>
       <ModalFooter>
       <ModalFooter>
         <button type="button" className="btn btn-primary" onClick={handleSubmit}>
         <button type="button" className="btn btn-primary" onClick={handleSubmit}>

+ 1 - 1
apps/app/src/components/Page/TagLabels.tsx

@@ -37,7 +37,7 @@ export const TagLabels:FC<Props> = (props: Props) => {
   return (
   return (
     <>
     <>
       <div className={`${styles['grw-tag-labels']} grw-tag-labels d-flex align-items-center`} data-testid="grw-tag-labels">
       <div className={`${styles['grw-tag-labels']} grw-tag-labels d-flex align-items-center`} data-testid="grw-tag-labels">
-        <i className="tag-icon icon-tag mr-2"/>
+        <i className="tag-icon icon-tag mr-2" />
         <RenderTagLabels
         <RenderTagLabels
           tags={tags}
           tags={tags}
           openEditorModal={openEditorModal}
           openEditorModal={openEditorModal}

+ 1 - 1
apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLinkList.tsx

@@ -50,7 +50,7 @@ const ShareLinkTr = (props: ShareLinkTrProps): JSX.Element => {
         {shareLink.description}
         {shareLink.description}
       </td>
       </td>
       <td style={{ verticalAlign: 'middle' }}>
       <td style={{ verticalAlign: 'middle' }}>
-        {shareLink.expiredAt && <span >{dateFnsFormat(new Date(shareLink.expiredAt), 'yyyy-MM-dd HH:mm')}</span>}
+        {shareLink.expiredAt && <span>{dateFnsFormat(new Date(shareLink.expiredAt), 'yyyy-MM-dd HH:mm')}</span>}
       </td>
       </td>
       <td style={{ maxWidth: '0', textAlign: 'center' }}>
       <td style={{ maxWidth: '0', textAlign: 'center' }}>
         <button className="btn btn-outline-warning" type="button" onClick={onDelete}>
         <button className="btn btn-outline-warning" type="button" onClick={onDelete}>

+ 5 - 3
apps/app/src/components/PageAlert/PageRedirectedAlert.tsx

@@ -32,9 +32,11 @@ export const PageRedirectedAlert = React.memo((): JSX.Element => {
   }
   }
 
 
   if (isUnlinked) {
   if (isUnlinked) {
-    return (<div className="alert alert-info d-edit-none py-3 px-4">
-      <strong>{ t('Unlinked') }: </strong> { t('page_page.notice.unlinked') }
-    </div>);
+    return (
+      <div className="alert alert-info d-edit-none py-3 px-4">
+        <strong>{ t('Unlinked') }: </strong> { t('page_page.notice.unlinked') }
+      </div>
+    );
   }
   }
 
 
   return (
   return (

+ 7 - 7
apps/app/src/components/PageCreateModal.jsx

@@ -1,5 +1,5 @@
 import React, {
 import React, {
-  useEffect, useState, useMemo,
+  useEffect, useState, useMemo, useCallback,
 } from 'react';
 } from 'react';
 
 
 import { pagePathUtils, pathUtils } from '@growi/core/dist/utils';
 import { pagePathUtils, pathUtils } from '@growi/core/dist/utils';
@@ -107,7 +107,7 @@ const PageCreateModal = () => {
    * join path, check if creatable, then redirect
    * join path, check if creatable, then redirect
    * @param {string} paths
    * @param {string} paths
    */
    */
-  async function redirectToEditor(...paths) {
+  const redirectToEditor = useCallback(async(...paths) => {
     try {
     try {
       const editorPath = generateEditorPath(...paths);
       const editorPath = generateEditorPath(...paths);
       await router.push(editorPath);
       await router.push(editorPath);
@@ -119,7 +119,7 @@ const PageCreateModal = () => {
     catch (err) {
     catch (err) {
       toastError(err);
       toastError(err);
     }
     }
-  }
+  }, [closeCreateModal, mutateEditorMode, router]);
 
 
   /**
   /**
    * access today page
    * access today page
@@ -139,9 +139,9 @@ const PageCreateModal = () => {
     redirectToEditor(pageNameInput);
     redirectToEditor(pageNameInput);
   }
   }
 
 
-  function ppacSubmitHandler(input) {
+  const ppacSubmitHandler = useCallback((input) => {
     redirectToEditor(input);
     redirectToEditor(input);
-  }
+  }, [redirectToEditor]);
 
 
   /**
   /**
    * access template page
    * access template page
@@ -277,7 +277,7 @@ const PageCreateModal = () => {
 
 
           <div className="d-sm-flex align-items-center justify-items-between">
           <div className="d-sm-flex align-items-center justify-items-between">
 
 
-            <UncontrolledButtonDropdown id="dd-template-type" className='flex-fill text-center'>
+            <UncontrolledButtonDropdown id="dd-template-type" className="flex-fill text-center">
               <DropdownToggle id="template-type" caret>
               <DropdownToggle id="template-type" caret>
                 {template == null && t('template.option_label.select')}
                 {template == null && t('template.option_label.select')}
                 {template === 'children' && t('template.children.label')}
                 {template === 'children' && t('template.children.label')}
@@ -299,7 +299,7 @@ const PageCreateModal = () => {
               <button
               <button
                 data-testid="grw-btn-edit-page"
                 data-testid="grw-btn-edit-page"
                 type="button"
                 type="button"
-                className='grw-btn-create-page btn btn-outline-primary rounded-pill text-nowrap ml-3'
+                className="grw-btn-create-page btn btn-outline-primary rounded-pill text-nowrap ml-3"
                 onClick={createTemplatePage}
                 onClick={createTemplatePage}
                 disabled={template == null}
                 disabled={template == null}
               >
               >

+ 2 - 6
apps/app/src/components/PageDuplicateModal.tsx

@@ -80,14 +80,10 @@ const PageDuplicateModal = (): JSX.Element => {
     }
     }
   }, [isOpened, pageNameInput, subordinatedPages, checkExistPathsDebounce, page]);
   }, [isOpened, pageNameInput, subordinatedPages, checkExistPathsDebounce, page]);
 
 
-  /**
-   * change pageNameInput for PagePathAutoComplete
-   * @param {string} value
-   */
-  function ppacInputChangeHandler(value) {
+  const ppacInputChangeHandler = useCallback((value: string) => {
     setErrs(null);
     setErrs(null);
     setPageNameInput(value);
     setPageNameInput(value);
-  }
+  }, []);
 
 
   /**
   /**
    * change pageNameInput
    * change pageNameInput

+ 1 - 1
apps/app/src/components/PageEditor/Cheatsheet.tsx

@@ -38,7 +38,7 @@ export const Cheatsheet = (): JSX.Element => {
         className="code-highlighted"
         className="code-highlighted"
         PreTag="div"
         PreTag="div"
         style={oneDark}
         style={oneDark}
-        language={'text'}
+        language="text"
       >
       >
         {String(CheetSheetElm).replace(/\n$/, '')}
         {String(CheetSheetElm).replace(/\n$/, '')}
       </PrismAsyncLight>
       </PrismAsyncLight>

+ 2 - 2
apps/app/src/components/PageEditor/Editor.tsx

@@ -248,7 +248,7 @@ const Editor: ForwardRefRenderFunction<IEditorMethods, EditorPropsType> = (props
     };
     };
 
 
     return (
     return (
-      <Modal isOpen={isCheatsheetModalShown} toggle={hideCheatsheetModal} className={`modal-gfm-cheatsheet ${styles['modal-gfm-cheatsheet']}`} size={'lg'} >
+      <Modal isOpen={isCheatsheetModalShown} toggle={hideCheatsheetModal} className={`modal-gfm-cheatsheet ${styles['modal-gfm-cheatsheet']}`} size="lg">
         <ModalHeader tag="h4" toggle={hideCheatsheetModal} className="bg-primary text-light">
         <ModalHeader tag="h4" toggle={hideCheatsheetModal} className="bg-primary text-light">
           <i className="icon-fw icon-question" />Markdown help
           <i className="icon-fw icon-question" />Markdown help
         </ModalHeader>
         </ModalHeader>
@@ -282,7 +282,7 @@ const Editor: ForwardRefRenderFunction<IEditorMethods, EditorPropsType> = (props
 
 
   return (
   return (
     <>
     <>
-      <div style={flexContainer} className={`editor-container ${styles['editor-container']}`} >
+      <div style={flexContainer} className={`editor-container ${styles['editor-container']}`}>
         <Dropzone
         <Dropzone
           ref={dropzoneRef}
           ref={dropzoneRef}
           accept={getAcceptableType()}
           accept={getAcceptableType()}

+ 1 - 1
apps/app/src/components/PageEditor/EditorIcon.jsx

@@ -144,7 +144,7 @@ const EditorIcon = (props) => {
       // TODO: fix
       // TODO: fix
       return (
       return (
         <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="currentColor" className="bi bi-filetype-md" viewBox="-2 -3 28 21">
         <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="currentColor" className="bi bi-filetype-md" viewBox="-2 -3 28 21">
-          <path fillRule="evenodd" d="M14 4.5V14a2 2 0 0 1-2 2H9v-1h3a1 1 0 0 0 1-1V4.5h-2A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v9H2V2a2 2 0 0 1 2-2h5.5L14 4.5ZM.706 13.189v2.66H0V11.85h.806l1.14 2.596h.026l1.14-2.596h.8v3.999h-.716v-2.66h-.038l-.946 2.159h-.516l-.952-2.16H.706Zm3.919 2.66V11.85h1.459c.406 0 .741.078 1.005.234.263.157.46.383.589.68.13.297.196.655.196 1.075 0 .422-.066.784-.196 1.084-.131.301-.33.53-.595.689-.264.158-.597.237-1 .237H4.626Zm1.353-3.354h-.562v2.707h.562c.186 0 .347-.028.484-.082a.8.8 0 0 0 .334-.252 1.14 1.14 0 0 0 .196-.422c.045-.168.067-.365.067-.592a2.1 2.1 0 0 0-.117-.753.89.89 0 0 0-.354-.454c-.159-.102-.362-.152-.61-.152Z"/>
+          <path fillRule="evenodd" d="M14 4.5V14a2 2 0 0 1-2 2H9v-1h3a1 1 0 0 0 1-1V4.5h-2A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v9H2V2a2 2 0 0 1 2-2h5.5L14 4.5ZM.706 13.189v2.66H0V11.85h.806l1.14 2.596h.026l1.14-2.596h.8v3.999h-.716v-2.66h-.038l-.946 2.159h-.516l-.952-2.16H.706Zm3.919 2.66V11.85h1.459c.406 0 .741.078 1.005.234.263.157.46.383.589.68.13.297.196.655.196 1.075 0 .422-.066.784-.196 1.084-.131.301-.33.53-.595.689-.264.158-.597.237-1 .237H4.626Zm1.353-3.354h-.562v2.707h.562c.186 0 .347-.028.484-.082a.8.8 0 0 0 .334-.252 1.14 1.14 0 0 0 .196-.422c.045-.168.067-.365.067-.592a2.1 2.1 0 0 0-.117-.753.89.89 0 0 0-.354-.454c-.159-.102-.362-.152-.61-.152Z" />
         </svg>
         </svg>
       );
       );
   }
   }

+ 6 - 4
apps/app/src/components/PageEditor/LinkEditModal.tsx

@@ -262,9 +262,11 @@ export const LinkEditModal = (): JSX.Element => {
                 <Popover trigger="focus" placement="right" isOpen={isPreviewOpen} target="preview-btn" toggle={toggleIsPreviewOpen}>
                 <Popover trigger="focus" placement="right" isOpen={isPreviewOpen} target="preview-btn" toggle={toggleIsPreviewOpen}>
                   <PopoverBody>
                   <PopoverBody>
                     {markdown != null && pagePath != null && rendererOptions != null
                     {markdown != null && pagePath != null && rendererOptions != null
-                    && <div className={`linkedit-preview ${styles['linkedit-preview']}`}>
-                      <Preview markdown={markdown} pagePath={pagePath} rendererOptions={rendererOptions} />
-                    </div>
+                    && (
+                      <div className={`linkedit-preview ${styles['linkedit-preview']}`}>
+                        <Preview markdown={markdown} pagePath={pagePath} rendererOptions={rendererOptions} />
+                      </div>
+                    )
                     }
                     }
                   </PopoverBody>
                   </PopoverBody>
                 </Popover>
                 </Popover>
@@ -357,7 +359,7 @@ export const LinkEditModal = (): JSX.Element => {
         </div>
         </div>
       </ModalBody>
       </ModalBody>
       <ModalFooter>
       <ModalFooter>
-        { previewError && <span className='text-danger'>{previewError}</span>}
+        { previewError && <span className="text-danger">{previewError}</span>}
         <button type="button" className="btn btn-sm btn-outline-secondary mx-1" onClick={close}>
         <button type="button" className="btn btn-sm btn-outline-secondary mx-1" onClick={close}>
           {t('Cancel')}
           {t('Cancel')}
         </button>
         </button>

+ 2 - 1
apps/app/src/components/PageHistory/PageRevisionTable.tsx

@@ -224,7 +224,8 @@ export const PageRevisionTable = (props: PageRevisionTableProps): JSX.Element =>
           currentPageId={currentPageId}
           currentPageId={currentPageId}
           currentPagePath={currentPagePath}
           currentPagePath={currentPagePath}
           onClose={onClose}
           onClose={onClose}
-        />)
+        />
+      )
       }
       }
     </>
     </>
   );
   );

+ 2 - 1
apps/app/src/components/PageHistory/Revision.tsx

@@ -36,7 +36,8 @@ export const Revision = (props: RevisionProps): JSX.Element => {
 
 
     return (
     return (
       <div className={`${styles['revision-history-main']} ${styles['revision-history-main-nodiff']}
       <div className={`${styles['revision-history-main']} ${styles['revision-history-main-nodiff']}
-        revision-history-main revision-history-main-nodiff my-1 d-flex align-items-center`}>
+        revision-history-main revision-history-main-nodiff my-1 d-flex align-items-center`}
+      >
         <div className="picture-container">
         <div className="picture-container">
           { pic }
           { pic }
         </div>
         </div>

+ 1 - 1
apps/app/src/components/PageHistory/RevisionDiff.tsx

@@ -49,7 +49,7 @@ export const RevisionDiff = (props: RevisioinDiffProps): JSX.Element => {
 
 
   return (
   return (
     <div className={`${styles['revision-diff-container']}`}>
     <div className={`${styles['revision-diff-container']}`}>
-      <div className='comparison-header'>
+      <div className="comparison-header">
         <div className="container pt-1 pr-0">
         <div className="container pt-1 pr-0">
           <div className="row">
           <div className="row">
             <div className="col comparison-source-wrapper pt-1 px-0">
             <div className="col comparison-source-wrapper pt-1 px-0">

+ 20 - 17
apps/app/src/components/PageList/PageListItemL.tsx

@@ -198,7 +198,7 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
           {onCheckboxChanged != null && (
           {onCheckboxChanged != null && (
             <div className="d-flex align-items-center justify-content-center">
             <div className="d-flex align-items-center justify-content-center">
               <Input
               <Input
-                type='checkbox'
+                type="checkbox"
                 id={`cbSelect-${pageData._id}`}
                 id={`cbSelect-${pageData._id}`}
                 data-testid="cb-select"
                 data-testid="cb-select"
                 innerRef={inputRef}
                 innerRef={inputRef}
@@ -228,7 +228,8 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
                 <span className="h5 mb-0">
                 <span className="h5 mb-0">
                   {/* Use permanent links to care for pages with the same name (Cannot use page path url) */}
                   {/* Use permanent links to care for pages with the same name (Cannot use page path url) */}
                   <span className="grw-page-path-hierarchical-link text-break">
                   <span className="grw-page-path-hierarchical-link text-break">
-                    <Link legacyBehavior
+                    <Link
+                      legacyBehavior
                       href={returnPathForURL(pageData.path, pageData._id)}
                       href={returnPathForURL(pageData.path, pageData._id)}
                       prefetch={false}
                       prefetch={false}
                     >
                     >
@@ -255,21 +256,23 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
 
 
               {/* doropdown icon includes page control buttons */}
               {/* doropdown icon includes page control buttons */}
               {hasBrowsingRights
               {hasBrowsingRights
-                && <div className="ml-auto">
-                  <PageItemControl
-                    alignEnd
-                    pageId={pageData._id}
-                    pageInfo={isIPageInfoForListing(pageMeta) ? pageMeta : undefined}
-                    isEnableActions={isEnableActions}
-                    isReadOnlyUser={isReadOnlyUser}
-                    forceHideMenuItems={forceHideMenuItems}
-                    onClickBookmarkMenuItem={bookmarkMenuItemClickHandler}
-                    onClickRenameMenuItem={renameMenuItemClickHandler}
-                    onClickDuplicateMenuItem={duplicateMenuItemClickHandler}
-                    onClickDeleteMenuItem={deleteMenuItemClickHandler}
-                    onClickRevertMenuItem={revertMenuItemClickHandler}
-                  />
-                </div>
+                && (
+                  <div className="ml-auto">
+                    <PageItemControl
+                      alignEnd
+                      pageId={pageData._id}
+                      pageInfo={isIPageInfoForListing(pageMeta) ? pageMeta : undefined}
+                      isEnableActions={isEnableActions}
+                      isReadOnlyUser={isReadOnlyUser}
+                      forceHideMenuItems={forceHideMenuItems}
+                      onClickBookmarkMenuItem={bookmarkMenuItemClickHandler}
+                      onClickRenameMenuItem={renameMenuItemClickHandler}
+                      onClickDuplicateMenuItem={duplicateMenuItemClickHandler}
+                      onClickDeleteMenuItem={deleteMenuItemClickHandler}
+                      onClickRevertMenuItem={revertMenuItemClickHandler}
+                    />
+                  </div>
+                )
               }
               }
             </div>
             </div>
             <div className="page-list-snippet py-1">
             <div className="page-list-snippet py-1">

+ 1 - 1
apps/app/src/components/PagePathHierarchicalLink.tsx

@@ -86,7 +86,7 @@ const PagePathHierarchicalLink = memo((props: PagePathHierarchicalLinkProps): JS
           shouldDangerouslySetInnerHTML
           shouldDangerouslySetInnerHTML
             // eslint-disable-next-line react/no-danger
             // eslint-disable-next-line react/no-danger
             ? <a className="page-segment" dangerouslySetInnerHTML={{ __html: linkedPagePathByHtml.pathName }}></a>
             ? <a className="page-segment" dangerouslySetInnerHTML={{ __html: linkedPagePathByHtml.pathName }}></a>
-            : <a className="page-segment" >{linkedPagePath.pathName}</a>
+            : <a className="page-segment">{linkedPagePath.pathName}</a>
         }
         }
       </Link>
       </Link>
 
 

+ 2 - 2
apps/app/src/components/PageRenameModal.tsx

@@ -166,10 +166,10 @@ const PageRenameModal = (): JSX.Element => {
     }
     }
   }, [isOpened, pageNameInput, subordinatedPages, checkExistPathsDebounce, page, checkIsUsersHomepageDebounce]);
   }, [isOpened, pageNameInput, subordinatedPages, checkExistPathsDebounce, page, checkIsUsersHomepageDebounce]);
 
 
-  function ppacInputChangeHandler(value) {
+  const ppacInputChangeHandler = useCallback((value: string) => {
     setErrs(null);
     setErrs(null);
     setPageNameInput(value);
     setPageNameInput(value);
-  }
+  }, []);
 
 
   /**
   /**
    * change pageNameInput
    * change pageNameInput

+ 3 - 3
apps/app/src/components/PageSideContents.tsx

@@ -57,7 +57,7 @@ export const PageSideContents = (props: PageSideContentsProps): JSX.Element => {
             {/* Do not display CountBadge if '/trash/*': https://github.com/weseek/growi/pull/7600 */}
             {/* Do not display CountBadge if '/trash/*': https://github.com/weseek/growi/pull/7600 */}
             { !isTrash && pageInfo != null
             { !isTrash && pageInfo != null
               ? <CountBadge count={(pageInfo as IPageInfoForOperation).descendantCount} offset={1} />
               ? <CountBadge count={(pageInfo as IPageInfoForOperation).descendantCount} offset={1} />
-              : <div className='px-2'></div>}
+              : <div className="px-2"></div>}
           </button>
           </button>
         )}
         )}
       </div>
       </div>
@@ -65,7 +65,7 @@ export const PageSideContents = (props: PageSideContentsProps): JSX.Element => {
       {/* Comments */}
       {/* Comments */}
       {!isTopPagePath && (
       {!isTopPagePath && (
         <div className={`mt-2 grw-page-accessories-control ${styles['grw-page-accessories-control']}`}>
         <div className={`mt-2 grw-page-accessories-control ${styles['grw-page-accessories-control']}`}>
-          <Link to={'page-comments'} offset={-120}>
+          <Link to="page-comments" offset={-120}>
             <button
             <button
               type="button"
               type="button"
               className="btn btn-block btn-outline-secondary grw-btn-page-accessories rounded-pill d-flex justify-content-between align-items-center"
               className="btn btn-block btn-outline-secondary grw-btn-page-accessories rounded-pill d-flex justify-content-between align-items-center"
@@ -75,7 +75,7 @@ export const PageSideContents = (props: PageSideContentsProps): JSX.Element => {
               <span>Comments</span>
               <span>Comments</span>
               { pageInfo != null
               { pageInfo != null
                 ? <CountBadge count={(pageInfo as IPageInfoForOperation).commentCount} />
                 ? <CountBadge count={(pageInfo as IPageInfoForOperation).commentCount} />
-                : <div className='px-2'></div>}
+                : <div className="px-2"></div>}
             </button>
             </button>
           </Link>
           </Link>
         </div>
         </div>

+ 36 - 36
apps/app/src/components/PageStatusAlert.tsx

@@ -57,15 +57,15 @@ export const PageStatusAlert = (): JSX.Element => {
     return {
     return {
       additionalClasses: ['bg-success', 'd-hackmd-none'],
       additionalClasses: ['bg-success', 'd-hackmd-none'],
       label:
       label:
-        <>
-          <i className="icon-fw icon-people"></i>
-          {t('hackmd.someone_editing')}
-        </>,
+  <>
+    <i className="icon-fw icon-people"></i>
+    {t('hackmd.someone_editing')}
+  </>,
       btn:
       btn:
-        <a href="#hackmd" key="btnOpenHackmdSomeoneEditing" className="btn btn-outline-white">
-          <i className="fa fa-fw fa-file-text-o mr-1"></i>
-          Open HackMD Editor
-        </a>,
+  <a href="#hackmd" key="btnOpenHackmdSomeoneEditing" className="btn btn-outline-white">
+    <i className="fa fa-fw fa-file-text-o mr-1"></i>
+    Open HackMD Editor
+  </a>,
     };
     };
   }, [t]);
   }, [t]);
 
 
@@ -73,15 +73,15 @@ export const PageStatusAlert = (): JSX.Element => {
     return {
     return {
       additionalClasses: ['bg-success', 'd-hackmd-none'],
       additionalClasses: ['bg-success', 'd-hackmd-none'],
       label:
       label:
-        <>
-          <i className="icon-fw icon-pencil"></i>
-          {t('hackmd.this_page_has_draft')}
-        </>,
+  <>
+    <i className="icon-fw icon-pencil"></i>
+    {t('hackmd.this_page_has_draft')}
+  </>,
       btn:
       btn:
-        <button onClick={() => mutateEditorMode(EditorMode.HackMD)} className="btn btn-outline-white">
-          <i className="fa fa-fw fa-file-text-o mr-1"></i>
-          Open HackMD Editor
-        </button>,
+  <button type="button" onClick={() => mutateEditorMode(EditorMode.HackMD)} className="btn btn-outline-white">
+    <i className="fa fa-fw fa-file-text-o mr-1"></i>
+    Open HackMD Editor
+  </button>,
     };
     };
   }, [mutateEditorMode, t]);
   }, [mutateEditorMode, t]);
 
 
@@ -97,27 +97,27 @@ export const PageStatusAlert = (): JSX.Element => {
     return {
     return {
       additionalClasses: ['bg-warning'],
       additionalClasses: ['bg-warning'],
       label:
       label:
-        <>
-          <i className="icon-fw icon-bulb"></i>
-          {label1}
-        </>,
+  <>
+    <i className="icon-fw icon-bulb"></i>
+    {label1}
+  </>,
       btn:
       btn:
-        <>
-          <button type="button" onClick={() => refreshPage()} className="btn btn-outline-white mr-4">
-            <i className="icon-fw icon-reload mr-1"></i>
-            {t('Load latest')}
-          </button>
-          { isConflict && (
-            <button
-              type="button"
-              onClick={onClickResolveConflict}
-              className="btn btn-outline-white"
-            >
-              <i className="fa fa-fw fa-file-text-o mr-1"></i>
-              {t('modal_resolve_conflict.resolve_conflict')}
-            </button>
-          )}
-        </>,
+  <>
+    <button type="button" onClick={() => refreshPage()} className="btn btn-outline-white mr-4">
+      <i className="icon-fw icon-reload mr-1"></i>
+      {t('Load latest')}
+    </button>
+    { isConflict && (
+      <button
+        type="button"
+        onClick={onClickResolveConflict}
+        className="btn btn-outline-white"
+      >
+        <i className="fa fa-fw fa-file-text-o mr-1"></i>
+        {t('modal_resolve_conflict.resolve_conflict')}
+      </button>
+    )}
+  </>,
     };
     };
   }, [remoteRevisionLastUpdateUser, isConflict, t, onClickResolveConflict, refreshPage]);
   }, [remoteRevisionLastUpdateUser, isConflict, t, onClickResolveConflict, refreshPage]);
 
 

+ 1 - 1
apps/app/src/components/PasswordResetRequestForm.tsx

@@ -66,7 +66,7 @@ const PasswordResetRequestForm: FC = () => {
           </div>
           </div>
         </>
         </>
       )}
       )}
-      <Link href='/login' prefetch={false}>
+      <Link href="/login" prefetch={false}>
         <i className="icon-login mr-1" />{t('forgot_password.return_to_login')}
         <i className="icon-login mr-1" />{t('forgot_password.return_to_login')}
       </Link>
       </Link>
     </form>
     </form>

+ 3 - 3
apps/app/src/components/PutbackPageModal.jsx

@@ -116,13 +116,13 @@ const PutBackPageModal = () => {
   return (
   return (
     <Modal isOpen={isOpened} toggle={closeModalHandler} data-testid="put-back-page-modal">
     <Modal isOpen={isOpened} toggle={closeModalHandler} data-testid="put-back-page-modal">
       <ModalHeader tag="h4" toggle={closeModalHandler} className="bg-info text-light">
       <ModalHeader tag="h4" toggle={closeModalHandler} className="bg-info text-light">
-        <HeaderContent/>
+        <HeaderContent />
       </ModalHeader>
       </ModalHeader>
       <ModalBody>
       <ModalBody>
-        <BodyContent/>
+        <BodyContent />
       </ModalBody>
       </ModalBody>
       <ModalFooter>
       <ModalFooter>
-        <FooterContent/>
+        <FooterContent />
       </ModalFooter>
       </ModalFooter>
     </Modal>
     </Modal>
   );
   );

+ 1 - 1
apps/app/src/components/ReactMarkdownComponents/LightBox.tsx

@@ -6,7 +6,7 @@ export const LightBox = (props) => {
   const [toggler, setToggler] = useState(false);
   const [toggler, setToggler] = useState(false);
   return (
   return (
     <>
     <>
-      <img {...props.node.properties} onClick={() => setToggler(!toggler)}/>
+      <img {...props.node.properties} onClick={() => setToggler(!toggler)} />
       <FsLightbox
       <FsLightbox
         toggler={toggler}
         toggler={toggler}
         sources={[props.src]}
         sources={[props.src]}

+ 1 - 1
apps/app/src/components/ReactMarkdownComponents/NextLink.tsx

@@ -61,7 +61,7 @@ export const NextLink = (props: Props): JSX.Element => {
   if (isExternalLink(href, siteUrl)) {
   if (isExternalLink(href, siteUrl)) {
     return (
     return (
       <a id={id} href={href} className={className} target="_blank" rel="noopener noreferrer" {...dataAttributes}>
       <a id={id} href={href} className={className} target="_blank" rel="noopener noreferrer" {...dataAttributes}>
-        {children}&nbsp;<i className='icon-share-alt small'></i>
+        {children}&nbsp;<i className="icon-share-alt small"></i>
       </a>
       </a>
     );
     );
   }
   }

+ 12 - 12
apps/app/src/components/ReactMarkdownComponents/RichAttachment.tsx

@@ -26,7 +26,7 @@ export const RichAttachment: React.FC<{
   }, [attachment, openDeleteAttachmentModal, remove]);
   }, [attachment, openDeleteAttachmentModal, remove]);
 
 
   if (attachment == null) {
   if (attachment == null) {
-    return <span className='text-muted'>{t('rich_attachment.attachment_not_be_found')}</span>;
+    return <span className="text-muted">{t('rich_attachment.attachment_not_be_found')}</span>;
   }
   }
 
 
   const {
   const {
@@ -46,34 +46,34 @@ export const RichAttachment: React.FC<{
     || createdAt == null
     || createdAt == null
     || fileSize == null
     || fileSize == null
   ) {
   ) {
-    return <span className='text-muted'>{t('rich_attachment.attachment_not_be_found')}</span>;
+    return <span className="text-muted">{t('rich_attachment.attachment_not_be_found')}</span>;
   }
   }
 
 
   return (
   return (
     <div className={`${styles.attachment} d-inline-block`}>
     <div className={`${styles.attachment} d-inline-block`}>
       <div className="my-2 p-2 card">
       <div className="my-2 p-2 card">
         <div className="p-1 card-body d-flex align-items-center">
         <div className="p-1 card-body d-flex align-items-center">
-          <div className='mr-2 px-0 d-flex align-items-center justify-content-center'>
-            <img src='/images/icons/editor/attachment.svg' className="attachment-icon" alt='attachment icon'/>
+          <div className="mr-2 px-0 d-flex align-items-center justify-content-center">
+            <img src="/images/icons/editor/attachment.svg" className="attachment-icon" alt="attachment icon" />
           </div>
           </div>
-          <div className='pl-0'>
-            <div className='d-inline-block'>
+          <div className="pl-0">
+            <div className="d-inline-block">
               <a target="_blank" rel="noopener noreferrer" href={filePathProxied}>
               <a target="_blank" rel="noopener noreferrer" href={filePathProxied}>
                 {attachmentName || originalName}
                 {attachmentName || originalName}
               </a>
               </a>
               <a className="ml-2 attachment-download" href={downloadPathProxied}>
               <a className="ml-2 attachment-download" href={downloadPathProxied}>
-                <i className="icon-cloud-download"/>
+                <i className="icon-cloud-download" />
               </a>
               </a>
               <a className="ml-2 text-danger attachment-delete" onClick={onClickTrashButtonHandler}>
               <a className="ml-2 text-danger attachment-delete" onClick={onClickTrashButtonHandler}>
-                <i className="icon-trash"/>
+                <i className="icon-trash" />
               </a>
               </a>
             </div>
             </div>
-            <div className='d-flex align-items-center'>
-              <UserPicture user={creator} size="sm"/>
-              <span className='ml-2 text-muted'>
+            <div className="d-flex align-items-center">
+              <UserPicture user={creator} size="sm" />
+              <span className="ml-2 text-muted">
                 {new Date(createdAt).toLocaleString('en-US')}
                 {new Date(createdAt).toLocaleString('en-US')}
               </span>
               </span>
-              <span className='ml-2 pl-2 border-left text-muted'>{prettyBytes(fileSize)}</span>
+              <span className="ml-2 pl-2 border-left text-muted">{prettyBytes(fileSize)}</span>
             </div>
             </div>
           </div>
           </div>
         </div>
         </div>

+ 1 - 1
apps/app/src/components/ReactMarkdownComponents/TableWithEditButton.tsx

@@ -42,7 +42,7 @@ export const TableWithEditButton = React.memo((props: TableWithEditButtonProps):
   return (
   return (
     <div className={`editable-with-handsontable ${styles['editable-with-handsontable']}`}>
     <div className={`editable-with-handsontable ${styles['editable-with-handsontable']}`}>
       { showEditButton && (
       { showEditButton && (
-        <button className="handsontable-modal-trigger" onClick={editButtonClickHandler}>
+        <button type="button" className="handsontable-modal-trigger" onClick={editButtonClickHandler}>
           <i className="icon-note"></i>
           <i className="icon-note"></i>
         </button>
         </button>
       )}
       )}

+ 2 - 1
apps/app/src/components/SavePageControls.tsx

@@ -92,7 +92,8 @@ export const SavePageControls = (props: SavePageControlsProps): JSX.Element | nu
 
 
       <UncontrolledButtonDropdown direction="up">
       <UncontrolledButtonDropdown direction="up">
         <Button
         <Button
-          id="caret" data-testid="save-page-btn"
+          id="caret"
+          data-testid="save-page-btn"
           color="primary"
           color="primary"
           className="btn-submit"
           className="btn-submit"
           onClick={save}
           onClick={save}

+ 2 - 1
apps/app/src/components/Script/DrawioViewerScript.tsx

@@ -39,7 +39,8 @@ export const DrawioViewerScript = (): JSX.Element => {
   return (
   return (
     <Head>
     <Head>
       <script
       <script
-        type="text/javascript" async
+        type="text/javascript"
+        async
         src={(new URL('/js/viewer.min.js', rendererConfig.drawioUri)).toString()}
         src={(new URL('/js/viewer.min.js', rendererConfig.drawioUri)).toString()}
         onLoad={loadedHandler}
         onLoad={loadedHandler}
       />
       />

+ 1 - 1
apps/app/src/components/SearchPage/SearchPageBase.tsx

@@ -199,7 +199,7 @@ const SearchPageBaseSubstance: ForwardRefRenderFunction<ISelectableAll & IReturn
                       pages={pages}
                       pages={pages}
                       selectedPageId={selectedPageWithMeta?.data._id}
                       selectedPageId={selectedPageWithMeta?.data._id}
                       forceHideMenuItems={forceHideMenuItems}
                       forceHideMenuItems={forceHideMenuItems}
-                      onPageSelected={page => (setSelectedPageWithMeta(page)) }
+                      onPageSelected={page => (setSelectedPageWithMeta(page))}
                       onCheckboxChanged={checkboxChangedHandler}
                       onCheckboxChanged={checkboxChangedHandler}
                     />
                     />
                   </div>
                   </div>

+ 1 - 2
apps/app/src/components/SearchTypeahead.tsx

@@ -64,7 +64,7 @@ const SearchTypeahead: ForwardRefRenderFunction<IFocusable, Props> = (props: Pro
   const [searchKeyword, setSearchKeyword] = useState('');
   const [searchKeyword, setSearchKeyword] = useState('');
   const [isForcused, setFocused] = useState(false);
   const [isForcused, setFocused] = useState(false);
 
 
-  const { data: searchResult, error: searchError } = useSWRxSearch(
+  const { data: searchResult, error: searchError, isLoading } = useSWRxSearch(
     disableIncrementalSearch ? null : searchKeyword,
     disableIncrementalSearch ? null : searchKeyword,
     null,
     null,
     { limit: 10 },
     { limit: 10 },
@@ -219,7 +219,6 @@ const SearchTypeahead: ForwardRefRenderFunction<IFocusable, Props> = (props: Pro
     );
     );
   }, [disableIncrementalSearch, helpElement, input, isForcused]);
   }, [disableIncrementalSearch, helpElement, input, isForcused]);
 
 
-  const isLoading = searchResult !== undefined && searchError == null;
   const isOpenAlways = helpElement != null;
   const isOpenAlways = helpElement != null;
 
 
   return (
   return (

+ 2 - 2
apps/app/src/components/ShortcutsModal.tsx

@@ -64,7 +64,7 @@ const ShortcutsModal = (): JSX.Element => {
                     {/* eslint-disable-next-line react/no-danger */}
                     {/* eslint-disable-next-line react/no-danger */}
                     <span dangerouslySetInnerHTML={{ __html: t('modal_shortcuts.global.Show Contributors') }} />:
                     <span dangerouslySetInnerHTML={{ __html: t('modal_shortcuts.global.Show Contributors') }} />:
                   </th>
                   </th>
-                  <td className='text-nowrap'>
+                  <td className="text-nowrap">
                     <a href="{ t('modal_shortcuts.global.konami_code_url') }" target="_blank">
                     <a href="{ t('modal_shortcuts.global.konami_code_url') }" target="_blank">
                       {t('modal_shortcuts.global.Konami Code')}
                       {t('modal_shortcuts.global.Konami Code')}
                     </a>
                     </a>
@@ -80,7 +80,7 @@ const ShortcutsModal = (): JSX.Element => {
                 </tr>
                 </tr>
                 <tr>
                 <tr>
                   <th>{t('modal_shortcuts.global.MirrorMode')}:</th>
                   <th>{t('modal_shortcuts.global.MirrorMode')}:</th>
-                  <td className='text-nowrap'>
+                  <td className="text-nowrap">
                     <a href="{ t('modal_shortcuts.global.konami_code_url') }" target="_blank">
                     <a href="{ t('modal_shortcuts.global.konami_code_url') }" target="_blank">
                       {t('modal_shortcuts.global.Konami Code')}
                       {t('modal_shortcuts.global.Konami Code')}
                     </a>
                     </a>

+ 1 - 0
apps/app/src/components/Sidebar/Bookmarks/BookmarkContents.tsx

@@ -41,6 +41,7 @@ export const BookmarkContents = (): JSX.Element => {
     <>
     <>
       <div className="col-8 mb-2 ">
       <div className="col-8 mb-2 ">
         <button
         <button
+          type="button"
           className="btn btn-block btn-outline-secondary rounded-pill d-flex justify-content-start align-middle"
           className="btn btn-block btn-outline-secondary rounded-pill d-flex justify-content-start align-middle"
           onClick={onClickNewBookmarkFolder}
           onClick={onClickNewBookmarkFolder}
         >
         >

+ 2 - 2
apps/app/src/components/Sidebar/PageTree/Item.tsx

@@ -502,7 +502,7 @@ const Item: FC<ItemProps> = (props: ItemProps) => {
             >
             >
               {/* pass the color property to reactstrap dropdownToggle props. https://6-4-0--reactstrap.netlify.app/components/dropdowns/  */}
               {/* pass the color property to reactstrap dropdownToggle props. https://6-4-0--reactstrap.netlify.app/components/dropdowns/  */}
               <DropdownToggle color="transparent" className="border-0 rounded btn-page-item-control p-0 grw-visible-on-hover mr-1">
               <DropdownToggle color="transparent" className="border-0 rounded btn-page-item-control p-0 grw-visible-on-hover mr-1">
-                <i id='option-button-in-page-tree' className="icon-options fa fa-rotate-90 p-1"></i>
+                <i id="option-button-in-page-tree" className="icon-options fa fa-rotate-90 p-1"></i>
               </DropdownToggle>
               </DropdownToggle>
             </PageItemControl>
             </PageItemControl>
           </div>
           </div>
@@ -512,7 +512,7 @@ const Item: FC<ItemProps> = (props: ItemProps) => {
           <NotAvailableForGuest>
           <NotAvailableForGuest>
             <NotAvailableForReadOnlyUser>
             <NotAvailableForReadOnlyUser>
               <button
               <button
-                id='page-create-button-in-page-tree'
+                id="page-create-button-in-page-tree"
                 type="button"
                 type="button"
                 className="border-0 rounded btn btn-page-item-control p-0 grw-visible-on-hover"
                 className="border-0 rounded btn btn-page-item-control p-0 grw-visible-on-hover"
                 onClick={onClickPlusButton}
                 onClick={onClickPlusButton}

+ 1 - 1
apps/app/src/components/Sidebar/PageTree/PageTreeContentSkeleton.tsx

@@ -7,7 +7,7 @@ import styles from './ItemsTree.module.scss';
 const PageTreeContentSkeleton = (): JSX.Element => {
 const PageTreeContentSkeleton = (): JSX.Element => {
 
 
   return (
   return (
-    <ul className={`grw-pagetree ${styles['grw-pagetree']} list-group py-3`} >
+    <ul className={`grw-pagetree ${styles['grw-pagetree']} list-group py-3`}>
       <Skeleton additionalClass={`${styles['grw-pagetree-item-skeleton-text']} pr-3`} />
       <Skeleton additionalClass={`${styles['grw-pagetree-item-skeleton-text']} pr-3`} />
       <Skeleton additionalClass={`${styles['grw-pagetree-item-skeleton-text-child']} pr-3`} />
       <Skeleton additionalClass={`${styles['grw-pagetree-item-skeleton-text-child']} pr-3`} />
       <Skeleton additionalClass={`${styles['grw-pagetree-item-skeleton-text-child']} pr-3`} />
       <Skeleton additionalClass={`${styles['grw-pagetree-item-skeleton-text-child']} pr-3`} />

+ 12 - 6
apps/app/src/components/Sidebar/PersonalDropdown.tsx

@@ -19,9 +19,11 @@ export const PersonalDropdown = (): JSX.Element => {
   const [isQuestionnaireModalOpen, setQuestionnaireModalOpen] = useState(false);
   const [isQuestionnaireModalOpen, setQuestionnaireModalOpen] = useState(false);
 
 
   if (currentUser == null) {
   if (currentUser == null) {
-    return <div className="text-muted text-center mb-5">
-      <i className="fa fa-2x fa-spinner fa-pulse mr-1" />
-    </div>;
+    return (
+      <div className="text-muted text-center mb-5">
+        <i className="fa fa-2x fa-spinner fa-pulse mr-1" />
+      </div>
+    );
   }
   }
 
 
   const logoutHandler = async() => {
   const logoutHandler = async() => {
@@ -40,9 +42,12 @@ export const PersonalDropdown = (): JSX.Element => {
         {/* Button */}
         {/* Button */}
         {/* remove .dropdown-toggle for hide caret */}
         {/* remove .dropdown-toggle for hide caret */}
         {/* See https://stackoverflow.com/a/44577512/13183572 */}
         {/* See https://stackoverflow.com/a/44577512/13183572 */}
-        <button type="button"
+        <button
+          type="button"
           className="btn btn-primary"
           className="btn btn-primary"
-          data-bs-toggle="dropdown" data-testid="personal-dropdown-button" aria-expanded="false"
+          data-bs-toggle="dropdown"
+          data-testid="personal-dropdown-button"
+          aria-expanded="false"
         >
         >
           <UserPicture user={currentUser} noLink noTooltip /><span className="ml-1 d-none d-lg-inline-block">&nbsp;{currentUser.name}</span>
           <UserPicture user={currentUser} noLink noTooltip /><span className="ml-1 d-none d-lg-inline-block">&nbsp;{currentUser.name}</span>
         </button>
         </button>
@@ -86,7 +91,8 @@ export const PersonalDropdown = (): JSX.Element => {
             data-testid="grw-proactive-questionnaire-modal-toggle-btn"
             data-testid="grw-proactive-questionnaire-modal-toggle-btn"
             type="button"
             type="button"
             className="dropdown-item"
             className="dropdown-item"
-            onClick={() => setQuestionnaireModalOpen(true)}>
+            onClick={() => setQuestionnaireModalOpen(true)}
+          >
             <i className="icon-fw icon-pencil"></i>{t('personal_dropdown.feedback')}
             <i className="icon-fw icon-pencil"></i>{t('personal_dropdown.feedback')}
           </button>
           </button>
 
 

+ 4 - 3
apps/app/src/components/Sidebar/RecentChanges/RecentChangesContentSkeleton.tsx

@@ -11,7 +11,7 @@ const SkeletonItem = () => {
   return (
   return (
     <li className={`list-group-item ${styles['list-group-item']} ${isSmall ? 'py-2' : 'py-3'} px-0`}>
     <li className={`list-group-item ${styles['list-group-item']} ${isSmall ? 'py-2' : 'py-3'} px-0`}>
       <div className="d-flex w-100">
       <div className="d-flex w-100">
-        <Skeleton additionalClass='rounded-circle picture' roundedPill />
+        <Skeleton additionalClass="rounded-circle picture" roundedPill />
         <div className="flex-grow-1 ml-2">
         <div className="flex-grow-1 ml-2">
           <Skeleton additionalClass={`grw-recent-changes-skeleton-small ${styles['grw-recent-changes-skeleton-small']}`} />
           <Skeleton additionalClass={`grw-recent-changes-skeleton-small ${styles['grw-recent-changes-skeleton-small']}`} />
           <Skeleton additionalClass={`grw-recent-changes-skeleton-h5 ${styles['grw-recent-changes-skeleton-h5']} ${isSmall ? 'my-0' : 'my-2'}`} />
           <Skeleton additionalClass={`grw-recent-changes-skeleton-h5 ${styles['grw-recent-changes-skeleton-h5']} ${isSmall ? 'my-0' : 'my-2'}`} />
@@ -32,9 +32,10 @@ const RecentChangesContentSkeleton = (): JSX.Element => {
         <SkeletonItem />
         <SkeletonItem />
         <SkeletonItem />
         <SkeletonItem />
         <SkeletonItem />
         <SkeletonItem />
-        <li className={'list-group-item p-0'}></li>
+        <li className="list-group-item p-0"></li>
       </ul>
       </ul>
-    </div>);
+    </div>
+  );
 };
 };
 
 
 export default RecentChangesContentSkeleton;
 export default RecentChangesContentSkeleton;

+ 7 - 4
apps/app/src/components/Sidebar/RecentChanges/RecentChangesSubstance.tsx

@@ -19,6 +19,7 @@ import { SidebarHeaderReloadButton } from '../SidebarHeaderReloadButton';
 import styles from './RecentChangesSubstance.module.scss';
 import styles from './RecentChangesSubstance.module.scss';
 
 
 
 
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
 const logger = loggerFactory('growi:History');
 const logger = loggerFactory('growi:History');
 
 
 type PageItemLowerProps = {
 type PageItemLowerProps = {
@@ -88,9 +89,11 @@ const PageItem = memo(({ page, isSmall }: PageItemProps): JSX.Element => {
             <PagePathHierarchicalLink linkedPagePath={linkedPagePathLatter} basePath={dPagePath.isRoot ? undefined : dPagePath.former} />
             <PagePathHierarchicalLink linkedPagePath={linkedPagePathLatter} basePath={dPagePath.isRoot ? undefined : dPagePath.former} />
             {locked}
             {locked}
           </h5>
           </h5>
-          {!isSmall && <div className="grw-tag-labels mt-1 mb-2">
-            { tagElements }
-          </div>}
+          {!isSmall && (
+            <div className="grw-tag-labels mt-1 mb-2">
+              { tagElements }
+            </div>
+          )}
           <PageItemLower page={page} />
           <PageItemLower page={page} />
         </div>
         </div>
       </div>
       </div>
@@ -128,7 +131,7 @@ export const RecentChangesHeader = ({ isSmall, onSizeChange }: HeaderProps): JSX
 
 
   return (
   return (
     <>
     <>
-      <SidebarHeaderReloadButton onClick={() => mutate()}/>
+      <SidebarHeaderReloadButton onClick={() => mutate()} />
       <div className="d-flex align-items-center">
       <div className="d-flex align-items-center">
         <div className={`grw-recent-changes-resize-button ${styles['grw-recent-changes-resize-button']} custom-control custom-switch ml-1`}>
         <div className={`grw-recent-changes-resize-button ${styles['grw-recent-changes-resize-button']} custom-control custom-switch ml-1`}>
           <input
           <input

+ 1 - 1
apps/app/src/components/Sidebar/Sidebar.tsx

@@ -297,7 +297,7 @@ export const Sidebar = memo((): JSX.Element => {
       <div className={`${grwSidebarClass} ${sidebarModeClass} ${isOpenClass} d-print-none`} data-testid="grw-sidebar">
       <div className={`${grwSidebarClass} ${sidebarModeClass} ${isOpenClass} d-print-none`} data-testid="grw-sidebar">
         <div className="data-layout-container">
         <div className="data-layout-container">
           <div
           <div
-            className='navigation transition-enabled'
+            className="navigation transition-enabled"
             onMouseEnter={hoverOnHandler}
             onMouseEnter={hoverOnHandler}
             onMouseLeave={hoverOutHandler}
             onMouseLeave={hoverOutHandler}
           >
           >

+ 1 - 1
apps/app/src/components/Sidebar/SidebarNav.tsx

@@ -133,7 +133,7 @@ export const SidebarNav: FC<Props> = (props: Props) => {
 
 
         {isAdmin && <SecondaryItem label="Admin" iconName="settings" href="/admin" />}
         {isAdmin && <SecondaryItem label="Admin" iconName="settings" href="/admin" />}
         {/* <SecondaryItem label="Draft" iconName="file_copy" href="/me/drafts" /> */}
         {/* <SecondaryItem label="Draft" iconName="file_copy" href="/me/drafts" /> */}
-        <SecondaryItem label="Help" iconName="help" href={ growiCloudUri != null ? 'https://growi.cloud/help/' : 'https://docs.growi.org' } isBlank />
+        <SecondaryItem label="Help" iconName="help" href={growiCloudUri != null ? 'https://growi.cloud/help/' : 'https://docs.growi.org'} isBlank />
         <SecondaryItem label="Trash" iconName="delete" href="/trash" />
         <SecondaryItem label="Trash" iconName="delete" href="/trash" />
       </div>
       </div>
     </div>
     </div>

+ 1 - 1
apps/app/src/components/Sidebar/Tag.tsx

@@ -47,7 +47,7 @@ const Tag: FC = () => {
     <div className="grw-container-convertible container-lg px-4 mb-5 pb-5" data-testid="grw-sidebar-content-tags">
     <div className="grw-container-convertible container-lg px-4 mb-5 pb-5" data-testid="grw-sidebar-content-tags">
       <div className="grw-sidebar-content-header py-3 d-flex">
       <div className="grw-sidebar-content-header py-3 d-flex">
         <h3 className="mb-0">{t('Tags')}</h3>
         <h3 className="mb-0">{t('Tags')}</h3>
-        <SidebarHeaderReloadButton onClick={() => onReload()}/>
+        <SidebarHeaderReloadButton onClick={() => onReload()} />
       </div>
       </div>
 
 
       <h3 className="my-3">{t('tag_list')}</h3>
       <h3 className="my-3">{t('tag_list')}</h3>

+ 1 - 1
apps/app/src/components/StaffCredit/StaffCredit.tsx

@@ -13,7 +13,7 @@ import loggerFactory from '~/utils/logger';
 import styles from './StaffCredit.module.scss';
 import styles from './StaffCredit.module.scss';
 
 
 
 
-// eslint-disable-next-line no-unused-vars
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
 const logger = loggerFactory('growi:cli:StaffCredit');
 const logger = loggerFactory('growi:cli:StaffCredit');
 
 
 
 

+ 2 - 4
apps/app/src/components/TableOfContents.tsx

@@ -13,7 +13,7 @@ import styles from './TableOfContents.module.scss';
 
 
 const { isUserPage: _isUserPage } = pagePathUtils;
 const { isUserPage: _isUserPage } = pagePathUtils;
 
 
-// eslint-disable-next-line no-unused-vars
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
 const logger = loggerFactory('growi:TableOfContents');
 const logger = loggerFactory('growi:TableOfContents');
 
 
 const TableOfContents = (): JSX.Element => {
 const TableOfContents = (): JSX.Element => {
@@ -61,9 +61,7 @@ const TableOfContents = (): JSX.Element => {
           className="revision-toc-content mb-3"
           className="revision-toc-content mb-3"
         >
         >
           {/* parse blank to show toc (https://github.com/weseek/growi/pull/6277) */}
           {/* parse blank to show toc (https://github.com/weseek/growi/pull/6277) */}
-          <ReactMarkdown {...rendererOptions}>
-            {''}
-          </ReactMarkdown>
+          <ReactMarkdown {...rendererOptions}>{' '}</ReactMarkdown>
         </div>
         </div>
       </StickyStretchableScroller>
       </StickyStretchableScroller>
     </div>
     </div>

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است