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

Merge branch 'imprv/128939-reconfigure-sidbar' into imprv/128939-129305-fix-inner-personal-dropdown

Tatsuya Ise 2 лет назад
Родитель
Сommit
52ed3cb30a
100 измененных файлов с 653 добавлено и 668 удалено
  1. 2 2
      apps/app/package.json
  2. 1 4
      apps/app/src/client/services/page-operation.ts
  3. 22 22
      apps/app/src/components/Admin/App/AppSetting.jsx
  4. 12 12
      apps/app/src/components/Admin/App/AwsSetting.tsx
  5. 1 1
      apps/app/src/components/Admin/App/ConfirmModal.tsx
  6. 5 5
      apps/app/src/components/Admin/App/FileUploadSetting.tsx
  7. 2 2
      apps/app/src/components/Admin/App/GcsSetting.tsx
  8. 6 6
      apps/app/src/components/Admin/App/MailSetting.tsx
  9. 6 6
      apps/app/src/components/Admin/App/QuestionnaireSettings.tsx
  10. 4 4
      apps/app/src/components/Admin/App/SesSetting.tsx
  11. 1 1
      apps/app/src/components/Admin/App/SiteUrlSetting.tsx
  12. 8 8
      apps/app/src/components/Admin/App/SmtpSetting.tsx
  13. 4 6
      apps/app/src/components/Admin/AuditLog/DateRangePicker.tsx
  14. 3 5
      apps/app/src/components/Admin/AuditLog/SearchUsernameTypeahead.tsx
  15. 3 3
      apps/app/src/components/Admin/AuditLog/SelectActionDropdown.tsx
  16. 28 20
      apps/app/src/components/Admin/AuditLogManagement.tsx
  17. 1 1
      apps/app/src/components/Admin/Customize/CustomizeCssSetting.tsx
  18. 3 3
      apps/app/src/components/Admin/Customize/CustomizeFunctionOption.tsx
  19. 4 4
      apps/app/src/components/Admin/Customize/CustomizeFunctionSetting.tsx
  20. 6 6
      apps/app/src/components/Admin/Customize/CustomizeLogoSetting.tsx
  21. 1 1
      apps/app/src/components/Admin/Customize/CustomizeNoscriptSetting.tsx
  22. 1 1
      apps/app/src/components/Admin/Customize/CustomizeScriptSetting.tsx
  23. 6 6
      apps/app/src/components/Admin/Customize/CustomizeSidebarSetting.tsx
  24. 1 1
      apps/app/src/components/Admin/Customize/CustomizeTitle.tsx
  25. 2 2
      apps/app/src/components/Admin/Customize/PagingSizeUncontrolledDropdown.jsx
  26. 3 3
      apps/app/src/components/Admin/ElasticsearchManagement/ElasticsearchManagement.tsx
  27. 4 4
      apps/app/src/components/Admin/ExportArchiveData/SelectCollectionsModal.tsx
  28. 3 3
      apps/app/src/components/Admin/G2GDataTransfer.tsx
  29. 3 3
      apps/app/src/components/Admin/G2GDataTransferExportForm.tsx
  30. 21 21
      apps/app/src/components/Admin/ImportData/GrowiArchive/ImportCollectionConfigurationModal.jsx
  31. 3 3
      apps/app/src/components/Admin/ImportData/GrowiArchive/ImportCollectionItem.jsx
  32. 3 3
      apps/app/src/components/Admin/ImportData/GrowiArchive/ImportForm.jsx
  33. 2 3
      apps/app/src/components/Admin/ImportData/GrowiArchive/UploadForm.jsx
  34. 12 12
      apps/app/src/components/Admin/ImportData/ImportDataPageContents.jsx
  35. 5 5
      apps/app/src/components/Admin/LegacySlackIntegration/SlackConfiguration.jsx
  36. 5 5
      apps/app/src/components/Admin/MarkdownSetting/IndentForm.tsx
  37. 7 7
      apps/app/src/components/Admin/MarkdownSetting/LineBreakForm.jsx
  38. 11 11
      apps/app/src/components/Admin/MarkdownSetting/XssForm.jsx
  39. 6 6
      apps/app/src/components/Admin/Notification/GlobalNotification.jsx
  40. 3 3
      apps/app/src/components/Admin/Notification/GlobalNotificationList.jsx
  41. 12 12
      apps/app/src/components/Admin/Notification/ManageGlobalNotification.tsx
  42. 3 3
      apps/app/src/components/Admin/Notification/TriggerEventCheckBox.jsx
  43. 2 2
      apps/app/src/components/Admin/Notification/UserTriggerNotification.jsx
  44. 10 10
      apps/app/src/components/Admin/Security/GitHubSecuritySettingContents.jsx
  45. 10 10
      apps/app/src/components/Admin/Security/GoogleSecuritySettingContents.jsx
  46. 4 4
      apps/app/src/components/Admin/Security/LdapAuthTest.tsx
  47. 30 30
      apps/app/src/components/Admin/Security/LdapSecuritySettingContents.jsx
  48. 13 13
      apps/app/src/components/Admin/Security/LocalSecuritySettingContents.jsx
  49. 48 48
      apps/app/src/components/Admin/Security/OidcSecuritySettingContents.jsx
  50. 14 14
      apps/app/src/components/Admin/Security/SamlSecuritySettingContents.jsx
  51. 14 14
      apps/app/src/components/Admin/Security/SecuritySetting.jsx
  52. 3 3
      apps/app/src/components/Admin/Security/ShareLinkSetting.tsx
  53. 3 3
      apps/app/src/components/Admin/SlackIntegration/CustomBotWithProxySettings.jsx
  54. 4 4
      apps/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySettingsAccordion.jsx
  55. 2 2
      apps/app/src/components/Admin/SlackIntegration/ManageCommandsProcess.jsx
  56. 2 2
      apps/app/src/components/Admin/SlackIntegration/ManageCommandsProcessWithoutProxy.jsx
  57. 4 3
      apps/app/src/components/Admin/SlackIntegration/SlackAppIntegrationControl.tsx
  58. 11 11
      apps/app/src/components/Admin/SlackIntegration/WithProxyAccordions.jsx
  59. 1 1
      apps/app/src/components/Admin/UserGroup/UserGroupDeleteModal.tsx
  60. 5 5
      apps/app/src/components/Admin/UserGroup/UserGroupForm.tsx
  61. 5 5
      apps/app/src/components/Admin/UserGroup/UserGroupModal.tsx
  62. 3 3
      apps/app/src/components/Admin/UserGroupDetail/CheckBoxForSerchUserOption.jsx
  63. 3 3
      apps/app/src/components/Admin/UserGroupDetail/RadioButtonForSerchUserOption.jsx
  64. 3 3
      apps/app/src/components/Admin/UserGroupDetail/UpdateParentConfirmModal.tsx
  65. 1 1
      apps/app/src/components/Admin/UserGroupDetail/UserGroupUserFormByInput.jsx
  66. 4 4
      apps/app/src/components/Admin/UserManagement.tsx
  67. 1 1
      apps/app/src/components/Admin/Users/PasswordResetModal.jsx
  68. 5 5
      apps/app/src/components/Admin/Users/UserInviteModal.jsx
  69. 1 1
      apps/app/src/components/Bookmarks/BookmarkFolderMenuItem.tsx
  70. 3 3
      apps/app/src/components/Common/ImageCropModal.tsx
  71. 4 4
      apps/app/src/components/CompleteUserRegistrationForm.tsx
  72. 2 2
      apps/app/src/components/CreateTemplateModal.jsx
  73. 2 2
      apps/app/src/components/DataTransferForm.tsx
  74. 2 2
      apps/app/src/components/DeleteBookmarkFolderModal.tsx
  75. 2 2
      apps/app/src/components/EmptyTrashModal.tsx
  76. 5 5
      apps/app/src/components/InstallerForm.tsx
  77. 4 4
      apps/app/src/components/InvitedForm.tsx
  78. 7 7
      apps/app/src/components/LoginForm.tsx
  79. 1 1
      apps/app/src/components/Me/ApiSettings.tsx
  80. 19 19
      apps/app/src/components/Me/BasicInfoSettings.tsx
  81. 4 4
      apps/app/src/components/Me/InAppNotificationSettings.tsx
  82. 4 4
      apps/app/src/components/Me/OtherSettings.tsx
  83. 3 3
      apps/app/src/components/Me/PasswordSettings.jsx
  84. 6 6
      apps/app/src/components/Me/ProfileImageSettings.tsx
  85. 0 6
      apps/app/src/components/Navbar/GlobalSearch.module.scss
  86. 2 2
      apps/app/src/components/Navbar/GlobalSearch.tsx
  87. 3 3
      apps/app/src/components/Navbar/SubNavButtons.tsx
  88. 3 3
      apps/app/src/components/Page/CopyDropdown.jsx
  89. 11 11
      apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLinkForm.tsx
  90. 10 10
      apps/app/src/components/PageAlert/FixPageGrantAlert.tsx
  91. 1 1
      apps/app/src/components/PageComment/CommentEditor.tsx
  92. 8 8
      apps/app/src/components/PageDeleteModal.tsx
  93. 10 10
      apps/app/src/components/PageDuplicateModal.tsx
  94. 3 3
      apps/app/src/components/PageEditor/EditorNavbarBottom.tsx
  95. 8 8
      apps/app/src/components/PageEditor/GridEditModal.jsx
  96. 13 13
      apps/app/src/components/PageEditor/LinkEditModal.tsx
  97. 6 6
      apps/app/src/components/PageEditor/MarkdownTableDataImportForm.tsx
  98. 7 7
      apps/app/src/components/PageEditor/OptionsSelector.tsx
  99. 49 59
      apps/app/src/components/PageEditor/PageEditor.tsx
  100. 6 6
      apps/app/src/components/PageHistory/PageRevisionTable.tsx

+ 2 - 2
apps/app/package.json

@@ -172,7 +172,7 @@
     "react-multiline-clamp": "^2.0.0",
     "react-scroll": "^1.8.7",
     "react-syntax-highlighter": "^15.5.0",
-    "react-toastify": "^9.1.1",
+    "react-toastify": "^9.1.3",
     "react-use-ripple": "^1.5.2",
     "reactstrap": "^9.2.0",
     "reconnecting-websocket": "^4.4.0",
@@ -194,7 +194,7 @@
     "string-width": "=4.2.2",
     "superjson": "^1.9.1",
     "swagger-jsdoc": "^6.1.0",
-    "swr": "^2.0.3",
+    "swr": "^2.2.2",
     "throttle-debounce": "^5.0.0",
     "uglifycss": "^0.0.29",
     "universal-bunyan": "^0.9.2",

+ 1 - 4
apps/app/src/client/services/page-operation.ts

@@ -165,10 +165,7 @@ export const useSaveOrUpdate = (): SaveOrUpdateFunction => {
       res = await updatePage(pageId, revisionId, markdown, options);
     }
 
-    // The updateFn should be a promise or asynchronous function to handle the remote mutation
-    // it should return updated data. see: https://swr.vercel.app/docs/mutation#optimistic-updates
-    // Moreover, `async() => false` does not work since it's too fast to be calculated.
-    await mutateIsEnabledUnsavedWarning(new Promise(r => setTimeout(() => r(false), 10)), { optimisticData: () => false });
+    mutateIsEnabledUnsavedWarning(false);
 
     return res;
   }, [mutateIsEnabledUnsavedWarning]);

+ 22 - 22
apps/app/src/components/Admin/App/AppSetting.jsx

@@ -34,8 +34,8 @@ const AppSetting = (props) => {
 
   return (
     <React.Fragment>
-      <div className="form-group row">
-        <label className="text-start text-md-right col-md-3 col-form-label">{t('admin:app_setting.site_name')}</label>
+      <div className="row">
+        <label className="text-start text-md-end col-md-3 col-form-label">{t('admin:app_setting.site_name')}</label>
         <div className="col-md-6">
           <input
             className="form-control"
@@ -50,9 +50,9 @@ const AppSetting = (props) => {
         </div>
       </div>
 
-      <div className="row form-group mb-5">
+      <div className="row mb-5">
         <label
-          className="text-start text-md-right col-md-3 col-form-label"
+          className="text-start text-md-end col-md-3 col-form-label"
         >
           {t('admin:app_setting.confidential_name')}
         </label>
@@ -70,9 +70,9 @@ const AppSetting = (props) => {
         </div>
       </div>
 
-      <div className="row form-group mb-5">
+      <div className="row mb-5">
         <label
-          className="text-start text-md-right col-md-3 col-form-label"
+          className="text-start text-md-end col-md-3 col-form-label"
         >
           {t('admin:app_setting.default_language')}
         </label>
@@ -83,11 +83,11 @@ const AppSetting = (props) => {
               const fixedT = i18n.getFixedT(locale, 'admin');
 
               return (
-                <div key={locale} className="custom-control custom-radio custom-control-inline">
+                <div key={locale} className="form-check form-check-inline">
                   <input
                     type="radio"
                     id={`radioLang${locale}`}
-                    className="custom-control-input"
+                    className="form-check-input"
                     name="globalLang"
                     value={locale}
                     checked={adminAppContainer.state.globalLang === locale}
@@ -95,7 +95,7 @@ const AppSetting = (props) => {
                       adminAppContainer.changeGlobalLang(e.target.value);
                     }}
                   />
-                  <label className="custom-control-label" htmlFor={`radioLang${locale}`}>{fixedT('meta.display_name')}</label>
+                  <label className="form-label form-check-label" htmlFor={`radioLang${locale}`}>{fixedT('meta.display_name')}</label>
                 </div>
               );
             })
@@ -103,53 +103,53 @@ const AppSetting = (props) => {
         </div>
       </div>
 
-      <div className="row form-group mb-5">
+      <div className="row mb-5">
         <label
-          className="text-start text-md-right col-md-3 col-form-label"
+          className="text-start text-md-end col-md-3 col-form-label"
         >
           {t('admin:app_setting.default_mail_visibility')}
         </label>
         <div className="col-md-6 py-2">
 
-          <div className="custom-control custom-radio custom-control-inline">
+          <div className="form-check form-check-inline">
             <input
               type="radio"
               id="radio-email-show"
-              className="custom-control-input"
+              className="form-check-input"
               name="mailVisibility"
               checked={adminAppContainer.state.isEmailPublishedForNewUser === true}
               onChange={() => { adminAppContainer.changeIsEmailPublishedForNewUserShow(true) }}
             />
-            <label className="custom-control-label" htmlFor="radio-email-show">{t('commons:Show')}</label>
+            <label className="form-label form-check-label" htmlFor="radio-email-show">{t('commons:Show')}</label>
           </div>
 
-          <div className="custom-control custom-radio custom-control-inline">
+          <div className="form-check form-check-inline">
             <input
               type="radio"
               id="radio-email-hide"
-              className="custom-control-input"
+              className="form-check-input"
               name="mailVisibility"
               checked={adminAppContainer.state.isEmailPublishedForNewUser === false}
               onChange={() => { adminAppContainer.changeIsEmailPublishedForNewUserShow(false) }}
             />
-            <label className="custom-control-label" htmlFor="radio-email-hide">{t('commons:Hide')}</label>
+            <label className="form-label form-check-label" htmlFor="radio-email-hide">{t('commons:Hide')}</label>
           </div>
 
         </div>
       </div>
 
-      <div className="row form-group mb-5">
+      <div className="row mb-5">
         <label
-          className="text-start text-md-right col-md-3 col-form-label"
+          className="text-start text-md-end col-md-3 col-form-label"
         >
           {/* {t('admin:app_setting.file_uploading')} */}
         </label>
         <div className="col-md-6">
-          <div className="custom-control custom-checkbox custom-checkbox-info">
+          <div className="form-check form-check-info">
             <input
               type="checkbox"
               id="cbFileUpload"
-              className="custom-control-input"
+              className="form-check-input"
               name="fileUpload"
               checked={adminAppContainer.state.fileUpload}
               onChange={(e) => {
@@ -157,7 +157,7 @@ const AppSetting = (props) => {
               }}
             />
             <label
-              className="custom-control-label"
+              className="form-label form-check-label"
               htmlFor="cbFileUpload"
             >
               {t('admin:app_setting.enable_files_except_image')}

+ 12 - 12
apps/app/src/components/Admin/App/AwsSetting.tsx

@@ -21,8 +21,8 @@ export const AwsSettingMolecule = (props: AwsSettingMoleculeProps): JSX.Element
   return (
     <>
 
-      <div className="row form-group my-3">
-        <label className="text-start text-md-right col-md-3 col-form-label">
+      <div className="row my-3">
+        <label className="text-start text-md-end col-md-3 col-form-label">
           {t('admin:app_setting.file_delivery_method')}
         </label>
 
@@ -65,8 +65,8 @@ export const AwsSettingMolecule = (props: AwsSettingMoleculeProps): JSX.Element
         </div>
       </div>
 
-      <div className="row form-group">
-        <label className="text-start text-md-right col-md-3 col-form-label">
+      <div className="row">
+        <label className="text-start text-md-end col-md-3 col-form-label">
           {t('admin:app_setting.region')}
         </label>
         <div className="col-md-6">
@@ -81,8 +81,8 @@ export const AwsSettingMolecule = (props: AwsSettingMoleculeProps): JSX.Element
         </div>
       </div>
 
-      <div className="row form-group">
-        <label className="text-start text-md-right col-md-3 col-form-label">
+      <div className="row">
+        <label className="text-start text-md-end col-md-3 col-form-label">
           {t('admin:app_setting.custom_endpoint')}
         </label>
         <div className="col-md-6">
@@ -99,8 +99,8 @@ export const AwsSettingMolecule = (props: AwsSettingMoleculeProps): JSX.Element
         </div>
       </div>
 
-      <div className="row form-group">
-        <label className="text-start text-md-right col-md-3 col-form-label">
+      <div className="row">
+        <label className="text-start text-md-end col-md-3 col-form-label">
           {t('admin:app_setting.bucket_name')}
         </label>
         <div className="col-md-6">
@@ -116,8 +116,8 @@ export const AwsSettingMolecule = (props: AwsSettingMoleculeProps): JSX.Element
         </div>
       </div>
 
-      <div className="row form-group">
-        <label className="text-start text-md-right col-md-3 col-form-label">
+      <div className="row">
+        <label className="text-start text-md-end col-md-3 col-form-label">
           Access key ID
         </label>
         <div className="col-md-6">
@@ -132,8 +132,8 @@ export const AwsSettingMolecule = (props: AwsSettingMoleculeProps): JSX.Element
         </div>
       </div>
 
-      <div className="row form-group">
-        <label className="text-start text-md-right col-md-3 col-form-label">
+      <div className="row">
+        <label className="text-start text-md-end col-md-3 col-form-label">
           Secret access key
         </label>
         <div className="col-md-6">

+ 1 - 1
apps/app/src/components/Admin/App/ConfirmModal.tsx

@@ -30,7 +30,7 @@ export const ConfirmModal: FC<ConfirmModalProps> = (props: ConfirmModalProps) =>
   };
 
   return (
-    <Modal isOpen={props.isModalOpen} toggle={onCancel} className="">
+    <Modal isOpen={props.isModalOpen} toggle={onCancel}>
       <ModalHeader tag="h4" toggle={onCancel} className="bg-danger">
         <i className="icon-fw icon-question" />
         {t('Warning')}

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

@@ -37,25 +37,25 @@ export const FileUploadSettingMolecule = React.memo((props: FileUploadSettingMol
         </span>
       </p>
 
-      <div className="row form-group mb-3">
-        <label className="text-start text-md-right col-md-3 col-form-label">
+      <div className="row mb-3">
+        <label className="text-start text-md-end col-md-3 col-form-label">
           {t('admin:app_setting.file_upload_method')}
         </label>
 
         <div className="col-md-6 py-2">
           {fileUploadTypes.map((type) => {
             return (
-              <div key={type} className="custom-control custom-radio custom-control-inline">
+              <div key={type} className="form-check form-check-inline">
                 <input
                   type="radio"
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="file-upload-type"
                   id={`file-upload-type-radio-${type}`}
                   checked={props.fileUploadType === type}
                   disabled={props.isFixedFileUploadByEnvVar}
                   onChange={(e) => { props?.onChangeFileUploadType(e, type) }}
                 />
-                <label className="custom-control-label" htmlFor={`file-upload-type-radio-${type}`}>{t(`admin:app_setting.${type}_label`)}</label>
+                <label className="form-label form-check-label" htmlFor={`file-upload-type-radio-${type}`}>{t(`admin:app_setting.${type}_label`)}</label>
               </div>
             );
           })}

+ 2 - 2
apps/app/src/components/Admin/App/GcsSetting.tsx

@@ -32,8 +32,8 @@ export const GcsSettingMolecule = (props: GcsSettingMoleculeProps): JSX.Element
   return (
     <>
 
-      <div className="row form-group my-3">
-        <label className="text-start text-md-right col-md-3 col-form-label">
+      <div className="row my-3">
+        <label className="text-start text-md-end col-md-3 col-form-label">
           {t('admin:app_setting.file_delivery_method')}
         </label>
 

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

@@ -49,7 +49,7 @@ const MailSetting = (props: Props) => {
       {!adminAppContainer.state.isMailerSetup && (
         <div className="alert alert-danger"><i className="icon-exclamation"></i> {t('admin:app_setting.mailer_is_not_set_up')}</div>
       )}
-      <div className="row form-group mb-5">
+      <div className="row mb-5">
         <label className="col-md-3 col-form-label text-end">{t('admin:app_setting.from_e-mail_address')}</label>
         <div className="col-md-6">
           <input
@@ -62,17 +62,17 @@ const MailSetting = (props: Props) => {
         </div>
       </div>
 
-      <div className="row form-group mb-5">
-        <label className="text-start text-md-right col-md-3 col-form-label">
+      <div className="row mb-5">
+        <label className="form-label text-start text-md-end col-md-3 col-form-label">
           {t('admin:app_setting.transmission_method')}
         </label>
         <div className="col-md-6 py-2">
           {transmissionMethods.map((method) => {
             return (
-              <div key={method} className="custom-control custom-radio custom-control-inline">
+              <div key={method} className="form-check form-check-inline">
                 <input
                   type="radio"
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="transmission-method"
                   id={`transmission-method-radio-${method}`}
                   checked={adminAppContainer.state.transmissionMethod === method}
@@ -80,7 +80,7 @@ const MailSetting = (props: Props) => {
                     adminAppContainer.changeTransmissionMethod(method);
                   }}
                 />
-                <label className="custom-control-label" htmlFor={`transmission-method-radio-${method}`}>{t(`admin:app_setting.${method}_label`)}</label>
+                <label className="form-label form-check-label" htmlFor={`transmission-method-radio-${method}`}>{t(`admin:app_setting.${method}_label`)}</label>
               </div>
             );
           })}

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

@@ -72,31 +72,31 @@ const QuestionnaireSettings = (): JSX.Element => {
       {!isLoading && (
         <>
           <div className="row my-3">
-            <div className="custom-control custom-switch custom-checkbox-info col-md-5 offset-md-5">
+            <div className="form-check form-switch form-check-info col-md-5 offset-md-5">
               <input
                 type="checkbox"
-                className="custom-control-input"
+                className="form-check-input"
                 id="isQuestionnaireEnabled"
                 checked={isQuestionnaireEnabled}
                 onChange={onChangeIsQuestionnaireEnabledHandler}
               />
-              <label className="custom-control-label" htmlFor="isQuestionnaireEnabled">
+              <label className="form-label form-check-label" htmlFor="isQuestionnaireEnabled">
                 {t('app_setting.enable_questionnaire')}
               </label>
             </div>
           </div>
 
           <div className="row my-4">
-            <div className="custom-control custom-checkbox custom-checkbox-info col-md-5 offset-md-5">
+            <div className="form-check form-check-info col-md-5 offset-md-5">
               <input
                 type="checkbox"
-                className="custom-control-input"
+                className="form-check-input"
                 id="isAppSiteUrlHashed"
                 checked={isAppSiteUrlHashed}
                 onChange={onChangeisAppSiteUrlHashedHandler}
                 disabled={!isQuestionnaireEnabled}
               />
-              <label className="custom-control-label" htmlFor="isAppSiteUrlHashed">
+              <label className="form-label form-check-label" htmlFor="isAppSiteUrlHashed">
                 {t('app_setting.anonymize_app_site_url')}
               </label>
               <p className="form-text text-muted small">

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

@@ -16,8 +16,8 @@ const SmtpSetting = (props: Props) => {
     <React.Fragment>
       <div id="mail-smtp" className="tab-pane active mt-5">
 
-        <div className="row form-group">
-          <label className="text-start text-md-right col-md-3 col-form-label">
+        <div className="row">
+          <label className="text-start text-md-end col-md-3 col-form-label">
             Access key ID
           </label>
           <div className="col-md-6">
@@ -32,8 +32,8 @@ const SmtpSetting = (props: Props) => {
           </div>
         </div>
 
-        <div className="row form-group">
-          <label className="text-start text-md-right col-md-3 col-form-label">
+        <div className="row">
+          <label className="text-start text-md-end col-md-3 col-form-label">
             Secret access key
           </label>
           <div className="col-md-6">

+ 1 - 1
apps/app/src/components/Admin/App/SiteUrlSetting.tsx

@@ -53,7 +53,7 @@ const SiteUrlSetting = (props: Props) => {
         </div>
       ) }
 
-      <div className="row form-group">
+      <div className="row">
         <div className="col-md-9 offset-md-3">
           <table className="table settings-table">
             <colgroup>

+ 8 - 8
apps/app/src/components/Admin/App/SmtpSetting.tsx

@@ -19,8 +19,8 @@ const SmtpSetting = (props: Props) => {
   return (
     <React.Fragment>
       <div id="mail-smtp" className="tab-pane active mt-5">
-        <div className="row form-group">
-          <label className="text-start text-md-right col-md-3 col-form-label">
+        <div className="row">
+          <label className="text-start text-md-end col-md-3 col-form-label">
             {t('admin:app_setting.host')}
           </label>
           <div className="col-md-6">
@@ -33,8 +33,8 @@ const SmtpSetting = (props: Props) => {
           </div>
         </div>
 
-        <div className="row form-group">
-          <label className="text-start text-md-right col-md-3 col-form-label">
+        <div className="row">
+          <label className="text-start text-md-end col-md-3 col-form-label">
             {t('admin:app_setting.port')}
           </label>
           <div className="col-md-6">
@@ -46,8 +46,8 @@ const SmtpSetting = (props: Props) => {
           </div>
         </div>
 
-        <div className="row form-group">
-          <label className="text-start text-md-right col-md-3 col-form-label">
+        <div className="row">
+          <label className="text-start text-md-end col-md-3 col-form-label">
             {t('admin:app_setting.user')}
           </label>
           <div className="col-md-6">
@@ -60,8 +60,8 @@ const SmtpSetting = (props: Props) => {
           </div>
         </div>
 
-        <div className="row form-group">
-          <label className="text-start text-md-right col-md-3 col-form-label">
+        <div className="row">
+          <label className="text-start text-md-end col-md-3 col-form-label">
             {t('Password')}
           </label>
           <div className="col-md-6">

+ 4 - 6
apps/app/src/components/Admin/AuditLog/DateRangePicker.tsx

@@ -18,11 +18,9 @@ const CustomInput = forwardRef<HTMLInputElement, CustomInputProps>((props: Custo
 
   return (
     <div className="input-group admin-audit-log">
-      <div className="input-group-prepend">
-        <span className="input-group-text">
-          <i className="fa fa-fw fa-calendar" />
-        </span>
-      </div>
+      <span className="input-group-text">
+        <i className="fa fa-fw fa-calendar" />
+      </span>
       <input
         ref={ref}
         type="text"
@@ -62,7 +60,7 @@ export const DateRangePicker: FC<DateRangePickerProps> = (props: DateRangePicker
   }, [onChange]);
 
   return (
-    <div className="btn-group me-2">
+    <div className="me-2">
       <DatePicker
         selectsRange
         startDate={startDate}

+ 3 - 5
apps/app/src/components/Admin/AuditLog/SearchUsernameTypeahead.tsx

@@ -110,11 +110,9 @@ const SearchUsernameTypeaheadSubstance: ForwardRefRenderFunction<IClearable, Pro
 
   return (
     <div className="input-group me-2">
-      <div className="input-group-prepend">
-        <span className="input-group-text">
-          <i className="icon-people" />
-        </span>
-      </div>
+      <span className="input-group-text">
+        <i className="icon-people" />
+      </span>
       <AsyncTypeahead
         ref={typeaheadRef}
         id="search-username-typeahead-asynctypeahead"

+ 3 - 3
apps/app/src/components/Admin/AuditLog/SelectActionDropdown.tsx

@@ -84,20 +84,20 @@ export const SelectActionDropdown: FC<Props> = (props: Props) => {
         {dropdownItems.map(item => (
           <div key={item.actionCategory}>
             <div className="dropdown-item">
-              <div className="form-group px-2 m-0">
+              <div className="px-2 m-0">
                 <input
                   type="checkbox"
                   className="form-check-input"
                   defaultChecked
                   onChange={(e) => { multipleActionCheckboxChangedHandler(item.actions, e.target.checked) }}
                 />
-                <label className="form-check-label">{t(`admin:audit_log_action_category.${item.actionCategory}`)}</label>
+                <label className="form-label form-check-label">{t(`admin:audit_log_action_category.${item.actionCategory}`)}</label>
               </div>
             </div>
             {
               item.actions.map(action => (
                 <div className="dropdown-item" key={action}>
-                  <div className="form-group px-4 m-0">
+                  <div className="px-4 m-0">
                     <input
                       type="checkbox"
                       className="form-check-input"

+ 28 - 20
apps/app/src/components/Admin/AuditLogManagement.tsx

@@ -172,28 +172,36 @@ export const AuditLogManagement: FC = () => {
         <AuditLogSettings />
       ) : (
         <>
-          <div className="form-inline mb-3">
-            <SearchUsernameTypeahead
-              ref={typeaheadRef}
-              onChange={setUsernamesHandler}
-            />
+          <div className="row row-cols-lg-auto mb-3 g-3">
+            <div className="col-12">
+              <SearchUsernameTypeahead
+                ref={typeaheadRef}
+                onChange={setUsernamesHandler}
+              />
+            </div>
 
-            <DateRangePicker
-              startDate={startDate}
-              endDate={endDate}
-              onChange={datePickerChangedHandler}
-            />
+            <div className="col-12">
+              <DateRangePicker
+                startDate={startDate}
+                endDate={endDate}
+                onChange={datePickerChangedHandler}
+              />
+            </div>
 
-            <SelectActionDropdown
-              actionMap={actionMap}
-              availableActions={auditLogAvailableActionsData || []}
-              onChangeAction={actionCheckboxChangedHandler}
-              onChangeMultipleAction={multipleActionCheckboxChangedHandler}
-            />
+            <div className="col-12">
+              <SelectActionDropdown
+                actionMap={actionMap}
+                availableActions={auditLogAvailableActionsData || []}
+                onChangeAction={actionCheckboxChangedHandler}
+                onChangeMultipleAction={multipleActionCheckboxChangedHandler}
+              />
+            </div>
 
-            <button type="button" className="btn btn-link" onClick={clearButtonPushedHandler}>
-              {t('admin:audit_log_management.clear')}
-            </button>
+            <div className="col-12">
+              <button type="button" className="btn btn-link" onClick={clearButtonPushedHandler}>
+                {t('admin:audit_log_management.clear')}
+              </button>
+            </div>
           </div>
 
           <p
@@ -224,7 +232,7 @@ export const AuditLogManagement: FC = () => {
             />
 
             <div className="admin-audit-log ms-3">
-              <label htmlFor="jumpPageInput" className="me-1 text-secondary">Jump To Page</label>
+              <label htmlFor="jumpPageInput" className="form-label me-1 text-secondary">Jump To Page</label>
               <input
                 id="jumpPageInput"
                 type="text"

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

@@ -41,7 +41,7 @@ const CustomizeCssSetting = (props: Props): JSX.Element => {
             </CardBody>
           </Card>
 
-          <div className="form-group">
+          <div>
             <textarea
               className="form-control"
               name="customizeCss"

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

@@ -16,15 +16,15 @@ const CustomizeFunctionOption = (props: Props): JSX.Element => {
 
   return (
     <React.Fragment>
-      <div className="custom-control custom-checkbox custom-checkbox-success">
+      <div className="form-check form-check-success">
         <input
-          className="custom-control-input"
+          className="form-check-input"
           type="checkbox"
           id={optionId}
           checked={isChecked}
           onChange={onChecked}
         />
-        <label className="custom-control-label" htmlFor={optionId}>
+        <label className="form-label form-check-label" htmlFor={optionId}>
           <strong>{label}</strong>
         </label>
       </div>

+ 4 - 4
apps/app/src/components/Admin/Customize/CustomizeFunctionSetting.tsx

@@ -44,7 +44,7 @@ const CustomizeFunctionSetting = (props: Props): JSX.Element => {
           </Card>
 
 
-          <div className="form-group row">
+          <div className="row">
             <div className="offset-md-3 col-md-6 text-start">
               <CustomizeFunctionOption
                 optionId="isEnabledAttachTitleHeader"
@@ -88,7 +88,7 @@ const CustomizeFunctionSetting = (props: Props): JSX.Element => {
             onChangeDropdownItem={adminCustomizeContainer.switchPageListLimitationXL}
           />
 
-          <div className="form-group row">
+          <div className="row">
             <div className="offset-md-3 col-md-6 text-start">
               <CustomizeFunctionOption
                 optionId="isEnabledStaleNotification"
@@ -103,7 +103,7 @@ const CustomizeFunctionSetting = (props: Props): JSX.Element => {
             </div>
           </div>
 
-          <div className="form-group row">
+          <div className="row">
             <div className="offset-md-3 col-md-6 text-start">
               <CustomizeFunctionOption
                 optionId="isAllReplyShown"
@@ -118,7 +118,7 @@ const CustomizeFunctionSetting = (props: Props): JSX.Element => {
             </div>
           </div>
 
-          <div className="form-group row">
+          <div className="row">
             <div className="offset-md-3 col-md-6 text-start">
               <CustomizeFunctionOption
                 optionId="isSearchScopeChildrenAsDefault"

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

@@ -83,17 +83,17 @@ const CustomizeLogoSetting = (): JSX.Element => {
             <div className="row">
               <div className="col-md-6 col-12 mb-3 mb-md-0">
                 <h4>
-                  <div className="custom-control custom-radio radio-primary">
+                  <div className="form-check radio-primary">
                     <input
                       type="radio"
                       id="radioDefaultLogo"
-                      className="custom-control-input"
+                      className="form-check-input"
                       form="formImageType"
                       name="imagetypeForm[isDefaultLogo]"
                       checked={isDefaultLogoSelected}
                       onChange={() => { setIsDefaultLogoSelected(true) }}
                     />
-                    <label className="custom-control-label" htmlFor="radioDefaultLogo">
+                    <label className="form-check-label" htmlFor="radioDefaultLogo">
                       {t('admin:customize_settings.default_logo')}
                     </label>
                   </div>
@@ -102,17 +102,17 @@ const CustomizeLogoSetting = (): JSX.Element => {
               </div>
               <div className="col-md-6 col-12">
                 <h4>
-                  <div className="custom-control custom-radio radio-primary">
+                  <div className="form-check radio-primary">
                     <input
                       type="radio"
                       id="radioUploadLogo"
-                      className="custom-control-input"
+                      className="form-check-input"
                       form="formImageType"
                       name="imagetypeForm[isDefaultLogo]"
                       checked={!isDefaultLogoSelected}
                       onChange={() => { setIsDefaultLogoSelected(false) }}
                     />
-                    <label className="custom-control-label" htmlFor="radioUploadLogo">
+                    <label className="form-check-label" htmlFor="radioUploadLogo">
                       { t('admin:customize_settings.upload_logo') }
                     </label>
                   </div>

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

@@ -45,7 +45,7 @@ const CustomizeNoscriptSetting = (props: Props): JSX.Element => {
             </CardBody>
           </Card>
 
-          <div className="form-group">
+          <div>
             <textarea
               className="form-control"
               name="customizeNoscript"

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

@@ -42,7 +42,7 @@ const CustomizeScriptSetting = (props: Props): JSX.Element => {
             </CardBody>
           </Card>
 
-          <div className="form-group">
+          <div>
             <textarea
               className="form-control"
               name="customizeScript"

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

@@ -77,31 +77,31 @@ const CustomizeSidebarsetting = (): JSX.Element => {
           </Card>
 
           <div className="px-3">
-            <div className="custom-control custom-radio my-3">
+            <div className="form-check my-3">
               <input
                 type="radio"
                 id="is-open"
-                className="custom-control-input"
+                className="form-check-input"
                 name="mailVisibility"
                 checked={isSidebarDrawerMode === false && isSidebarClosedAtDockMode === false}
                 disabled={isSidebarDrawerMode}
                 onChange={() => setIsSidebarClosedAtDockMode(false)}
               />
-              <label className="custom-control-label" htmlFor="is-open">
+              <label className="form-label form-check-label" htmlFor="is-open">
                 {t('customize_settings.default_sidebar_mode.dock_mode_default_open')}
               </label>
             </div>
-            <div className="custom-control custom-radio my-3">
+            <div className="form-check my-3">
               <input
                 type="radio"
                 id="is-closed"
-                className="custom-control-input"
+                className="form-check-input"
                 name="mailVisibility"
                 checked={isSidebarDrawerMode === false && isSidebarClosedAtDockMode === true}
                 disabled={isSidebarDrawerMode}
                 onChange={() => setIsSidebarClosedAtDockMode(true)}
               />
-              <label className="custom-control-label" htmlFor="is-closed">
+              <label className="form-label form-check-label" htmlFor="is-closed">
                 {t('customize_settings.default_sidebar_mode.dock_mode_default_close')}
               </label>
             </div>

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

@@ -63,7 +63,7 @@ export const CustomizeTitle: FC = () => {
           <br />
           Default Output Example: <code className="xml">&lt;title&gt;Page name - My GROWI&lt;&#047;title&gt;</code>
         </div>
-        <div className="form-group col-12">
+        <div className="col-12">
           <input
             className="form-control"
             defaultValue={currentCustomizeTitle}

+ 2 - 2
apps/app/src/components/Admin/Customize/PagingSizeUncontrolledDropdown.jsx

@@ -17,10 +17,10 @@ const PagingSizeUncontrolledDropdown = (props) => {
 
   return (
     <React.Fragment>
-      <div className="form-group row">
+      <div className="row">
         <div className="offset-md-3 col-md-6 text-start">
           <div className="my-0 w-100">
-            <label>{props.label}</label>
+            <label className="form-label">{props.label}</label>
           </div>
           <UncontrolledDropdown>
             <DropdownToggle className="text-end col-6" caret>

+ 3 - 3
apps/app/src/components/Admin/ElasticsearchManagement/ElasticsearchManagement.tsx

@@ -167,7 +167,7 @@ const ElasticsearchManagement = () => {
 
       {/* Controls */}
       <div className="row">
-        <label className="col-md-3 col-form-label text-start text-md-right">{ t('full_text_search_management.reconnect') }</label>
+        <label className="col-md-3 col-form-label text-start text-md-end">{ t('full_text_search_management.reconnect') }</label>
         <div className="col-md-6">
           <ReconnectControls
             isEnabled={isReconnectBtnEnabled}
@@ -180,7 +180,7 @@ const ElasticsearchManagement = () => {
       <hr />
 
       <div className="row">
-        <label className="col-md-3 col-form-label text-start text-md-right">{ t('full_text_search_management.normalize') }</label>
+        <label className="col-md-3 col-form-label text-start text-md-end">{ t('full_text_search_management.normalize') }</label>
         <div className="col-md-6">
           <NormalizeIndicesControls
             isRebuildingProcessing={isRebuildingProcessing}
@@ -193,7 +193,7 @@ const ElasticsearchManagement = () => {
       <hr />
 
       <div className="row">
-        <label className="col-md-3 col-form-label text-start text-md-right">{ t('full_text_search_management.rebuild') }</label>
+        <label className="col-md-3 col-form-label text-start text-md-end">{ t('full_text_search_management.rebuild') }</label>
         <div className="col-md-6">
           <RebuildIndexControls
             isRebuildingProcessing={isRebuildingProcessing}

+ 4 - 4
apps/app/src/components/Admin/ExportArchiveData/SelectCollectionsModal.tsx

@@ -107,24 +107,24 @@ const SelectCollectionsModal = (props: Props): JSX.Element => {
   }, [selectedCollections, t]);
 
   const renderCheckboxes = useCallback((collectionNames, color?) => {
-    const checkboxColor = color ? `custom-checkbox-${color}` : 'custom-checkbox-info';
+    const checkboxColor = color ? `form-check-${color}` : 'form-check-info';
 
     return (
-      <div className={`custom-control custom-checkbox ${checkboxColor}`}>
+      <div className={`form-check ${checkboxColor}`}>
         <div className="row">
           {collectionNames.map((collectionName) => {
             return (
               <div className="col-sm-6 my-1" key={collectionName}>
                 <input
                   type="checkbox"
-                  className="custom-control-input"
+                  className="form-check-input"
                   id={collectionName}
                   name={collectionName}
                   value={collectionName}
                   checked={selectedCollections.has(collectionName)}
                   onChange={toggleCheckbox}
                 />
-                <label className="text-capitalize custom-control-label ms-3" htmlFor={collectionName}>
+                <label className="form-label text-capitalize form-check-label ms-3" htmlFor={collectionName}>
                   {collectionName}
                 </label>
               </div>

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

@@ -229,7 +229,7 @@ const G2GDataTransfer = (): JSX.Element => {
       )}
 
       <form onSubmit={startTransfer}>
-        <div className="form-group row mt-3">
+        <div className="row mt-3">
           <div className="col-9">
             <input
               className="form-control"
@@ -258,14 +258,14 @@ const G2GDataTransfer = (): JSX.Element => {
 
       <h2 className="border-bottom mt-5">{t('commons:g2g_data_transfer.transfer_data_to_this_growi')}</h2>
 
-      <div className="form-group row mt-4">
+      <div className="row mt-4">
         <div className="col-md-3">
           <button type="button" className="btn btn-primary w-100" onClick={onClickHandler}>
             {t('commons:g2g_data_transfer.publish_transfer_key')}
           </button>
         </div>
         <div className="col-md-9">
-          <div className="input-group-prepend mx-1">
+          <div className=" mx-1">
             <input className="form-control" type="text" value={transferKey} readOnly />
             <CustomCopyToClipBoard textToBeCopied={transferKey} message="admin:slack_integration.copied_to_clipboard" />
           </div>

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

@@ -199,13 +199,13 @@ const G2GDataTransferExportForm = (props: Props): JSX.Element => {
 
   return (
     <>
-      <form className="form-inline mt-3">
-        <div className="form-group">
+      <form className="mt-3 row row-cols-lg-auto g-3 align-items-center">
+        <div className="col-12">
           <button type="button" className="btn btn-sm btn-outline-secondary me-2" onClick={checkAll}>
             <i className="fa fa-check-square-o"></i> {t('admin:export_management.check_all')}
           </button>
         </div>
-        <div className="form-group">
+        <div className="col-12">
           <button type="button" className="btn btn-sm btn-outline-secondary me-2" onClick={uncheckAll}>
             <i className="fa fa-square-o"></i> {t('admin:export_management.uncheck_all')}
           </button>

+ 21 - 21
apps/app/src/components/Admin/ImportData/GrowiArchive/ImportCollectionConfigurationModal.jsx

@@ -66,28 +66,28 @@ class ImportCollectionConfigurationModal extends React.Component {
     /* eslint-disable react/no-unescaped-entities */
     return (
       <>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt4"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.isOverwriteAuthorWithCurrentUser || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ isOverwriteAuthorWithCurrentUser: !option.isOverwriteAuthorWithCurrentUser })}
           />
-          <label htmlFor="cbOpt4" className="custom-control-label">
+          <label htmlFor="cbOpt4" className="form-label form-check-label">
             {t(`${translationBase}.overwrite_author.label`)}
             <p className="form-text text-muted mt-0" dangerouslySetInnerHTML={{ __html: t(`${translationBase}.overwrite_author.desc`) }} />
           </label>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt1"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.makePublicForGrant2 || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ makePublicForGrant2: !option.makePublicForGrant2 })}
           />
-          <label htmlFor="cbOpt1" className="custom-control-label">
+          <label htmlFor="cbOpt1" className="form-label form-check-label">
             {t(`${translationBase}.set_public_to_page.label`, { from: t('Anyone with the link') })}
             <p
               className="form-text text-muted mt-0"
@@ -95,15 +95,15 @@ class ImportCollectionConfigurationModal extends React.Component {
             />
           </label>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt2"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.makePublicForGrant4 || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ makePublicForGrant4: !option.makePublicForGrant4 })}
           />
-          <label htmlFor="cbOpt2" className="custom-control-label">
+          <label htmlFor="cbOpt2" className="form-label form-check-label">
             {t(`${translationBase}.set_public_to_page.label`, { from: t('Only me') })}
             <p
               className="form-text text-muted mt-0"
@@ -111,15 +111,15 @@ class ImportCollectionConfigurationModal extends React.Component {
             />
           </label>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt3"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.makePublicForGrant5 || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ makePublicForGrant5: !option.makePublicForGrant5 })}
           />
-          <label htmlFor="cbOpt3" className="custom-control-label">
+          <label htmlFor="cbOpt3" className="form-label form-check-label">
             {t(`${translationBase}.set_public_to_page.label`, { from: t('Only inside the group') })}
             <p
               className="form-text text-muted mt-0"
@@ -127,28 +127,28 @@ class ImportCollectionConfigurationModal extends React.Component {
             />
           </label>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt5"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.initPageMetadatas || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ initPageMetadatas: !option.initPageMetadatas })}
           />
-          <label htmlFor="cbOpt5" className="custom-control-label">
+          <label htmlFor="cbOpt5" className="form-label form-check-label">
             {t(`${translationBase}.initialize_meta_datas.label`)}
             <p className="form-text text-muted mt-0" dangerouslySetInnerHTML={{ __html: t(`${translationBase}.initialize_meta_datas.desc`) }} />
           </label>
         </div>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt6"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.initHackmdDatas || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ initHackmdDatas: !option.initHackmdDatas })}
           />
-          <label htmlFor="cbOpt6" className="custom-control-label">
+          <label htmlFor="cbOpt6" className="form-label form-check-label">
             {t(`${translationBase}.initialize_hackmd_related_datas.label`)}
             <p className="form-text text-muted mt-0" dangerouslySetInnerHTML={{ __html: t(`${translationBase}.initialize_hackmd_related_datas.desc`) }} />
           </label>
@@ -167,15 +167,15 @@ class ImportCollectionConfigurationModal extends React.Component {
     /* eslint-disable react/no-unescaped-entities */
     return (
       <>
-        <div className="custom-control custom-checkbox custom-checkbox-warning">
+        <div className="form-check form-check-warning">
           <input
             id="cbOpt1"
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             checked={option.isOverwriteAuthorWithCurrentUser || false} // add ' || false' to avoid uncontrolled input warning
             onChange={() => this.changeHandler({ isOverwriteAuthorWithCurrentUser: !option.isOverwriteAuthorWithCurrentUser })}
           />
-          <label htmlFor="cbOpt1" className="custom-control-label">
+          <label htmlFor="cbOpt1" className="form-label form-check-label">
             {t(`${translationBase}.overwrite_author.label`)}
             <p className="form-text text-muted mt-0" dangerouslySetInnerHTML={{ __html: t(`${translationBase}.overwrite_author.desc`) }} />
           </label>

+ 3 - 3
apps/app/src/components/Admin/ImportData/GrowiArchive/ImportCollectionItem.jsx

@@ -81,18 +81,18 @@ export default class ImportCollectionItem extends React.Component {
     } = this.props;
 
     return (
-      <div className="custom-control custom-checkbox custom-checkbox-info my-0">
+      <div className="form-check form-check-info my-0">
         <input
           type="checkbox"
           id={collectionName}
           name={collectionName}
-          className="custom-control-input"
+          className="form-check-input"
           value={collectionName}
           checked={isSelected}
           disabled={isImporting}
           onChange={this.changeHandler}
         />
-        <label className="text-capitalize custom-control-label" htmlFor={collectionName}>
+        <label className="form-label text-capitalize form-check-label" htmlFor={collectionName}>
           {collectionName}
         </label>
       </div>

+ 3 - 3
apps/app/src/components/Admin/ImportData/GrowiArchive/ImportForm.jsx

@@ -446,13 +446,13 @@ class ImportForm extends React.Component {
 
     return (
       <>
-        <form className="form-inline">
-          <div className="form-group">
+        <form className="row row-cols-lg-auto g-3 align-items-center">
+          <div className="col-12">
             <button type="button" className="btn btn-sm btn-outline-secondary me-2" onClick={this.checkAll}>
               <i className="fa fa-check-square-o"></i> {t('admin:export_management.check_all')}
             </button>
           </div>
-          <div className="form-group">
+          <div className="col-12">
             <button type="button" className="btn btn-sm btn-outline-secondary me-2" onClick={this.uncheckAll}>
               <i className="fa fa-square-o"></i> {t('admin:export_management.uncheck_all')}
             </button>

+ 2 - 3
apps/app/src/components/Admin/ImportData/GrowiArchive/UploadForm.jsx

@@ -60,7 +60,7 @@ class UploadForm extends React.Component {
     return (
       <form onSubmit={this.uploadZipFile}>
         <fieldset>
-          <div className="form-group row">
+          <div className="row">
             <label htmlFor="file" className="col-md-3 col-form-label col-form-label-sm">
               {t('admin:importer_management.growi_settings.growi_archive_file')}
             </label>
@@ -68,14 +68,13 @@ class UploadForm extends React.Component {
               <input
                 type="file"
                 name="file"
-                className="form-control-file"
                 accept=".zip"
                 ref={this.inputRef}
                 onChange={this.changeFileName}
               />
             </div>
           </div>
-          <div className="form-group row">
+          <div className="row">
             <div className="mx-auto">
               <button type="submit" className="btn btn-primary" disabled={!this.validateForm()}>
                 {t('admin:importer_management.growi_settings.upload')}

+ 12 - 12
apps/app/src/components/Admin/ImportData/ImportDataPageContents.jsx

@@ -63,12 +63,12 @@ class ImportDataPageContents extends React.Component {
               </ul>
             </div>
 
-            <div className="form-group row">
+            <div className="row">
               <input type="password" name="dummypass" style={{ display: 'none', top: '-100px', left: '-100px' }} />
             </div>
 
-            <div className="form-group row">
-              <label htmlFor="settingForm[importer:esa:team_name]" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label htmlFor="settingForm[importer:esa:team_name]" className="text-start text-md-end col-md-3 col-form-label">
                 {t('importer_management.esa_settings.team_name')}
               </label>
               <div className="col-md-6">
@@ -83,8 +83,8 @@ class ImportDataPageContents extends React.Component {
 
             </div>
 
-            <div className="form-group row">
-              <label htmlFor="settingForm[importer:esa:access_token]" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label htmlFor="settingForm[importer:esa:access_token]" className="text-start text-md-end col-md-3 col-form-label">
                 {t('importer_management.esa_settings.access_token')}
               </label>
               <div className="col-md-6">
@@ -98,7 +98,7 @@ class ImportDataPageContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
+            <div className="row">
               <div className="offset-md-3 col-md-6">
                 <input
                   id="testConnectionToEsa"
@@ -169,11 +169,11 @@ class ImportDataPageContents extends React.Component {
               </ul>
             </div>
 
-            <div className="form-group row">
+            <div className="row">
               <input type="password" name="dummypass" style={{ display: 'none', top: '-100px', left: '-100px' }} />
             </div>
-            <div className="form-group row">
-              <label htmlFor="settingForm[importer:qiita:team_name]" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label htmlFor="settingForm[importer:qiita:team_name]" className="text-start text-md-end col-md-3 col-form-label">
                 {t('importer_management.qiita_settings.team_name')}
               </label>
               <div className="col-md-6">
@@ -187,8 +187,8 @@ class ImportDataPageContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
-              <label htmlFor="settingForm[importer:qiita:access_token]" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label htmlFor="settingForm[importer:qiita:access_token]" className="text-start text-md-end col-md-3 col-form-label">
                 {t('importer_management.qiita_settings.access_token')}
               </label>
               <div className="col-md-6">
@@ -203,7 +203,7 @@ class ImportDataPageContents extends React.Component {
             </div>
 
 
-            <div className="form-group row">
+            <div className="row">
               <div className="offset-md-3 col-md-6">
                 <input
                   id="testConnectionToQiita"

+ 5 - 5
apps/app/src/components/Admin/LegacySlackIntegration/SlackConfiguration.jsx

@@ -65,7 +65,7 @@ class SlackConfiguration extends React.Component {
             <h2 className="border-bottom mb-5">{t('notification_settings.slack_incoming_configuration')}</h2>
 
             <div className="row mb-3">
-              <label className="col-md-3 text-start text-md-right">Webhook URL</label>
+              <label className="form-label col-md-3 text-start text-md-end">Webhook URL</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -78,15 +78,15 @@ class SlackConfiguration extends React.Component {
 
             <div className="row mb-3">
               <div className="offset-md-3 col-md-6 text-start">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     type="checkbox"
-                    className="custom-control-input"
+                    className="form-check-input"
                     id="cbPrioritizeIWH"
                     checked={adminSlackIntegrationLegacyContainer.state.isIncomingWebhookPrioritized || false}
                     onChange={() => { adminSlackIntegrationLegacyContainer.switchIsIncomingWebhookPrioritized() }}
                   />
-                  <label className="custom-control-label" htmlFor="cbPrioritizeIWH">
+                  <label className="form-label form-check-label" htmlFor="cbPrioritizeIWH">
                     {t('notification_settings.prioritize_webhook')}
                   </label>
                 </div>
@@ -117,7 +117,7 @@ class SlackConfiguration extends React.Component {
               </div>
 
               <div className="row mb-5">
-                <label className="col-md-3 text-start text-md-right">OAuth access token</label>
+                <label className="form-label col-md-3 text-start text-md-end">OAuth access token</label>
                 <div className="col-md-6">
                   <input
                     className="form-control"

+ 5 - 5
apps/app/src/components/Admin/MarkdownSetting/IndentForm.tsx

@@ -41,7 +41,7 @@ const IndentForm = (props: Props) => {
     return (
       <div className="col">
         <div>
-          <label htmlFor="adminPreferredIndentSize">{t('markdown_settings.indent_options.indentSize')}</label>
+          <label htmlFor="adminPreferredIndentSize" className="form-label">{t('markdown_settings.indent_options.indentSize')}</label>
           <UncontrolledDropdown id="adminPreferredIndentSize">
             <DropdownToggle caret className="col-3 col-sm-2 col-md-5 col-lg-5 col-xl-3 text-end">
               <span className="float-start">
@@ -74,17 +74,17 @@ const IndentForm = (props: Props) => {
 
     return (
       <div className="col">
-        <div className="custom-control custom-checkbox custom-checkbox-success">
+        <div className="form-check form-check-success">
           <input
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             id="isIndentSizeForced"
             checked={isIndentSizeForced || false}
             onChange={() => {
               adminMarkDownContainer.setState({ isIndentSizeForced: !isIndentSizeForced });
             }}
           />
-          <label className="custom-control-label" htmlFor="isIndentSizeForced">
+          <label className="form-label form-check-label" htmlFor="isIndentSizeForced">
             {t('markdown_settings.indent_options.disallow_indent_change')}
           </label>
         </div>
@@ -97,7 +97,7 @@ const IndentForm = (props: Props) => {
 
   return (
     <React.Fragment>
-      <fieldset className="form-group row row-cols-1 row-cols-md-2 mx-3">
+      <fieldset className="row row-cols-1 row-cols-md-2 mx-3">
         {renderIndentSizeOption(props)}
         {renderIndentForceOption(props)}
       </fieldset>

+ 7 - 7
apps/app/src/components/Admin/MarkdownSetting/LineBreakForm.jsx

@@ -43,15 +43,15 @@ class LineBreakForm extends React.Component {
 
     return (
       <div className="col">
-        <div className="custom-control custom-checkbox custom-checkbox-success">
+        <div className="form-check form-check-success">
           <input
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             id="isEnabledLinebreaks"
             checked={isEnabledLinebreaks}
             onChange={() => { adminMarkDownContainer.setState({ isEnabledLinebreaks: !isEnabledLinebreaks }) }}
           />
-          <label className="custom-control-label" htmlFor="isEnabledLinebreaks">
+          <label className="form-label form-check-label" htmlFor="isEnabledLinebreaks">
             {t('markdown_settings.lineBreak_options.enable_lineBreak') }
           </label>
         </div>
@@ -68,15 +68,15 @@ class LineBreakForm extends React.Component {
 
     return (
       <div className="col">
-        <div className="custom-control custom-checkbox custom-checkbox-success">
+        <div className="form-check form-check-success">
           <input
             type="checkbox"
-            className="custom-control-input"
+            className="form-check-input"
             id="isEnabledLinebreaksInComments"
             checked={isEnabledLinebreaksInComments}
             onChange={() => { adminMarkDownContainer.setState({ isEnabledLinebreaksInComments: !isEnabledLinebreaksInComments }) }}
           />
-          <label className="custom-control-label" htmlFor="isEnabledLinebreaksInComments">
+          <label className="form-label form-check-label" htmlFor="isEnabledLinebreaksInComments">
             {t('markdown_settings.lineBreak_options.enable_lineBreak_for_comment') }
           </label>
         </div>
@@ -90,7 +90,7 @@ class LineBreakForm extends React.Component {
 
     return (
       <React.Fragment>
-        <fieldset className="form-group row row-cols-1 row-cols-md-2 mx-3">
+        <fieldset className="row row-cols-1 row-cols-md-2 mx-3">
           {this.renderLineBreakOption()}
           {this.renderLineBreakInCommentOption()}
         </fieldset>

+ 11 - 11
apps/app/src/components/Admin/MarkdownSetting/XssForm.jsx

@@ -45,20 +45,20 @@ class XssForm extends React.Component {
     const rehypeRecommendedAttributes = JSON.stringify(sanitizeDefaultSchema.attributes);
 
     return (
-      <div className="form-group col-12 my-3">
+      <div className="col-12 my-3">
         <div className="row">
 
           <div className="col-md-6 col-sm-12 align-self-start mb-4">
-            <div className="custom-control custom-radio">
+            <div className="form-check">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id="xssOption1"
                 name="XssOption"
                 checked={xssOption === RehypeSanitizeOption.RECOMMENDED}
                 onChange={() => { adminMarkDownContainer.setState({ xssOption: RehypeSanitizeOption.RECOMMENDED }) }}
               />
-              <label className="custom-control-label w-100" htmlFor="xssOption1">
+              <label className="form-label form-check-label w-100" htmlFor="xssOption1">
                 <p className="fw-bold">{t('markdown_settings.xss_options.recommended_setting')}</p>
                 <div className="mt-4">
                   <div className="d-flex justify-content-between">
@@ -91,16 +91,16 @@ class XssForm extends React.Component {
           </div>
 
           <div className="col-md-6 col-sm-12 align-self-start mb-4">
-            <div className="custom-control custom-radio">
+            <div className="form-check">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id="xssOption2"
                 name="XssOption"
                 checked={xssOption === RehypeSanitizeOption.CUSTOM}
                 onChange={() => { adminMarkDownContainer.setState({ xssOption: RehypeSanitizeOption.CUSTOM }) }}
               />
-              <label className="custom-control-label w-100" htmlFor="xssOption2">
+              <label className="form-label form-check-label w-100" htmlFor="xssOption2">
                 <p className="fw-bold">{t('markdown_settings.xss_options.custom_whitelist')}</p>
                 <WhitelistInput customizable />
               </label>
@@ -118,18 +118,18 @@ class XssForm extends React.Component {
     return (
       <React.Fragment>
         <fieldset className="col-12">
-          <div className="form-group">
+          <div>
             <div className="col-8 offset-4 my-3">
-              <div className="custom-control custom-switch custom-checkbox-success">
+              <div className="form-check form-switch form-check-success">
                 <input
                   type="checkbox"
-                  className="custom-control-input"
+                  className="form-check-input"
                   id="XssEnable"
                   name="isEnabledXss"
                   checked={isEnabledXss}
                   onChange={adminMarkDownContainer.switchEnableXss}
                 />
-                <label className="custom-control-label w-100" htmlFor="XssEnable">
+                <label className="form-label form-check-label w-100" htmlFor="XssEnable">
                   {t('markdown_settings.xss_options.enable_xss_prevention')}
                 </label>
               </div>

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

@@ -42,15 +42,15 @@ const GlobalNotification = (props) => {
       </p>
       <div className="row mb-4">
         <div className="col-md-8 offset-md-2">
-          <div className="custom-control custom-checkbox custom-checkbox-success">
+          <div className="form-check form-check-success">
             <input
               id="isNotificationForOwnerPageEnabled"
-              className="custom-control-input"
+              className="form-check-input"
               type="checkbox"
               checked={adminNotificationContainer.state.isNotificationForOwnerPageEnabled || false}
               onChange={() => { adminNotificationContainer.switchIsNotificationForOwnerPageEnabled() }}
             />
-            <label className="custom-control-label" htmlFor="isNotificationForOwnerPageEnabled">
+            <label className="form-label form-check-label" htmlFor="isNotificationForOwnerPageEnabled">
               {/* eslint-disable-next-line react/no-danger */}
               <span dangerouslySetInnerHTML={{ __html: t('notification_settings.just_me_notification_help') }} />
             </label>
@@ -60,15 +60,15 @@ const GlobalNotification = (props) => {
 
       <div className="row mb-4">
         <div className="col-md-8 offset-md-2">
-          <div className="custom-control custom-checkbox custom-checkbox-success">
+          <div className="form-check form-check-success">
             <input
               id="isNotificationForGroupPageEnabled"
-              className="custom-control-input"
+              className="form-check-input"
               type="checkbox"
               checked={adminNotificationContainer.state.isNotificationForGroupPageEnabled || false}
               onChange={() => { adminNotificationContainer.switchIsNotificationForGroupPageEnabled() }}
             />
-            <label className="custom-control-label" htmlFor="isNotificationForGroupPageEnabled">
+            <label className="form-label form-check-label" htmlFor="isNotificationForGroupPageEnabled">
               {/* eslint-disable-next-line react/no-danger */}
               <span dangerouslySetInnerHTML={{ __html: t('notification_settings.group_notification_help') }} />
             </label>

+ 3 - 3
apps/app/src/components/Admin/Notification/GlobalNotificationList.jsx

@@ -80,15 +80,15 @@ class GlobalNotificationList extends React.Component {
           return (
             <tr key={notification._id}>
               <td className="align-middle td-abs-center">
-                <div className="custom-control custom-switch custom-checkbox-success">
+                <div className="form-check form-switch form-check-success">
                   <input
                     type="checkbox"
-                    className="custom-control-input"
+                    className="form-check-input"
                     id={notification._id}
                     defaultChecked={notification.isEnabled}
                     onClick={() => this.toggleIsEnabled(notification)}
                   />
-                  <label className="custom-control-label" htmlFor={notification._id} />
+                  <label className="form-label form-check-label" htmlFor={notification._id} />
                 </div>
               </td>
               <td>

+ 12 - 12
apps/app/src/components/Admin/Notification/ManageGlobalNotification.tsx

@@ -126,12 +126,12 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
 
         <div className="col-sm-4">
           <h3>
-            <label htmlFor="triggerPath">{t('notification_settings.trigger_path')}
+            <label htmlFor="triggerPath" className="form-label">{t('notification_settings.trigger_path')}
               {/* eslint-disable-next-line react/no-danger */}
               <small dangerouslySetInnerHTML={{ __html: t('notification_settings.trigger_path_help', '<code>*</code>') }} />
             </label>
           </h3>
-          <div className="form-group">
+          <div>
             <input
               className="form-control"
               type="text"
@@ -143,10 +143,10 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
           </div>
 
           <h3>{t('notification_settings.notify_to')}</h3>
-          <div className="form-group form-inline">
-            <div className="custom-control custom-radio">
+          <div>
+            <div className="form-check">
               <input
-                className="custom-control-input"
+                className="form-check-input"
                 type="radio"
                 id="mail"
                 name="notifyType"
@@ -154,13 +154,13 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
                 checked={notifyType === NotifyType.Email}
                 onChange={() => { setNotifyType(NotifyType.Email) }}
               />
-              <label className="custom-control-label" htmlFor="mail">
+              <label className="form-label form-check-label" htmlFor="mail">
                 <p className="fw-bold">Email</p>
               </label>
             </div>
-            <div className="custom-control custom-radio ms-2">
+            <div className="form-check ms-2">
               <input
-                className="custom-control-input"
+                className="form-check-input"
                 type="radio"
                 id="slack"
                 name="notifyType"
@@ -168,7 +168,7 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
                 checked={notifyType === NotifyType.SLACK}
                 onChange={() => { setNotifyType(NotifyType.SLACK) }}
               />
-              <label className="custom-control-label" htmlFor="slack">
+              <label className="form-label form-check-label" htmlFor="slack">
                 <p className="fw-bold">Slack</p>
               </label>
             </div>
@@ -178,7 +178,7 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
             ? (
               <>
                 <div className="input-group notify-to-option" id="mail-input">
-                  <div className="input-group-prepend">
+                  <div>
                     <span className="input-group-text" id="mail-addon"><i className="ti ti-email" /></span>
                   </div>
                   <input
@@ -206,7 +206,7 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
             : (
               <>
                 <div className="input-group notify-to-option" id="slack-input">
-                  <div className="input-group-prepend">
+                  <div>
                     <span className="input-group-text" id="slack-channel-addon"><i className="fa fa-hashtag" /></span>
                   </div>
                   <input
@@ -228,7 +228,7 @@ const ManageGlobalNotification = (props: Props): JSX.Element => {
         </div>
 
         <div className="offset-1 col-sm-5">
-          <div className="form-group">
+          <div>
             <h3>{t('notification_settings.trigger_events')}</h3>
             <div className="my-1">
               <TriggerEventCheckBox

+ 3 - 3
apps/app/src/components/Admin/Notification/TriggerEventCheckBox.jsx

@@ -7,15 +7,15 @@ const TriggerEventCheckBox = (props) => {
   const { t } = props;
 
   return (
-    <div className={`custom-control custom-checkbox custom-checkbox-${props.checkbox}`}>
+    <div className={`form-check form-check-${props.checkbox}`}>
       <input
-        className="custom-control-input"
+        className="form-check-input"
         type="checkbox"
         id={`trigger-event-${props.event}`}
         checked={props.checked}
         onChange={props.onChange}
       />
-      <label className="custom-control-label" htmlFor={`trigger-event-${props.event}`}>
+      <label className="form-label form-check-label" htmlFor={`trigger-event-${props.event}`}>
         {props.children}{' '}
         {t(`notification_settings.event_${props.event}`)}
       </label>

+ 2 - 2
apps/app/src/components/Admin/Notification/UserTriggerNotification.jsx

@@ -111,11 +111,11 @@ class UserTriggerNotification extends React.Component {
 
               <td>
                 <div className="input-group notify-to-option" id="slack-input">
-                  <div className="input-group-prepend">
+                  <div>
                     <span className="input-group-text"><i className="fa fa-hashtag" /></span>
                   </div>
                   <input
-                    className="form-control form-inline"
+                    className="form-control"
                     type="text"
                     name="channel"
                     value={this.state.channel}

+ 10 - 10
apps/app/src/components/Admin/Security/GitHubSecuritySettingContents.jsx

@@ -56,17 +56,17 @@ class GitHubSecurityManagementContents extends React.Component {
           </div>
         )}
 
-        <div className="form-group row">
+        <div className="row">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 id="isGitHubEnabled"
-                className="custom-control-input"
+                className="form-check-input"
                 type="checkbox"
                 checked={adminGeneralSecurityContainer.state.isGitHubEnabled || false}
                 onChange={() => { adminGeneralSecurityContainer.switchIsGitHubOAuthEnabled() }}
               />
-              <label className="custom-control-label" htmlFor="isGitHubEnabled">
+              <label className="form-label form-check-label" htmlFor="isGitHubEnabled">
                 {t('security_settings.OAuth.GitHub.enable_github')}
               </label>
             </div>
@@ -76,7 +76,7 @@ class GitHubSecurityManagementContents extends React.Component {
         </div>
 
         <div className="row mb-5">
-          <label className="col-12 col-md-3 text-start text-md-right py-2">{t('security_settings.callback_URL')}</label>
+          <label className="form-label col-12 col-md-3 text-start text-md-end py-2">{t('security_settings.callback_URL')}</label>
           <div className="col-12 col-md-6">
             <input
               className="form-control"
@@ -104,7 +104,7 @@ class GitHubSecurityManagementContents extends React.Component {
             <h3 className="border-bottom">{t('security_settings.configuration')}</h3>
 
             <div className="row mb-5">
-              <label htmlFor="githubClientId" className="col-3 text-end py-2">{t('security_settings.clientID')}</label>
+              <label htmlFor="githubClientId" className="col-3 text-end py-2 form-label">{t('security_settings.clientID')}</label>
               <div className="col-6">
                 <input
                   className="form-control"
@@ -120,7 +120,7 @@ class GitHubSecurityManagementContents extends React.Component {
             </div>
 
             <div className="row mb-5">
-              <label htmlFor="githubClientSecret" className="col-3 text-end py-2">{t('security_settings.client_secret')}</label>
+              <label htmlFor="githubClientSecret" className="col-3 text-end py-2 form-label">{t('security_settings.client_secret')}</label>
               <div className="col-6">
                 <input
                   className="form-control"
@@ -137,16 +137,16 @@ class GitHubSecurityManagementContents extends React.Component {
 
             <div className="row mb-5">
               <div className="offset-3 col-6 text-start">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByUserNameGitHub"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminGitHubSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser || false}
                     onChange={() => { adminGitHubSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="custom-control-label"
+                    className="form-check-label"
                     htmlFor="bindByUserNameGitHub"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat email matching as identical') }}
                   />

+ 10 - 10
apps/app/src/components/Admin/Security/GoogleSecuritySettingContents.jsx

@@ -54,17 +54,17 @@ class GoogleSecurityManagementContents extends React.Component {
           </div>
         )}
 
-        <div className="form-group row">
+        <div className="row">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 id="isGoogleEnabled"
-                className="custom-control-input"
+                className="form-check-input"
                 type="checkbox"
                 checked={adminGeneralSecurityContainer.state.isGoogleEnabled || false}
                 onChange={() => { adminGeneralSecurityContainer.switchIsGoogleOAuthEnabled() }}
               />
-              <label className="custom-control-label" htmlFor="isGoogleEnabled">
+              <label className="form-label form-check-label" htmlFor="isGoogleEnabled">
                 {t('security_settings.OAuth.Google.enable_google')}
               </label>
             </div>
@@ -74,7 +74,7 @@ class GoogleSecurityManagementContents extends React.Component {
         </div>
 
         <div className="row mb-5">
-          <label className="col-12 col-md-3 text-start text-md-right py-2">{t('security_settings.callback_URL')}</label>
+          <label className="form-label col-12 col-md-3 text-start text-md-end py-2">{t('security_settings.callback_URL')}</label>
           <div className="col-12 col-md-6">
             <input
               className="form-control"
@@ -102,7 +102,7 @@ class GoogleSecurityManagementContents extends React.Component {
             <h3 className="border-bottom">{t('security_settings.configuration')}</h3>
 
             <div className="row mb-5">
-              <label htmlFor="googleClientId" className="col-3 text-end py-2">{t('security_settings.clientID')}</label>
+              <label htmlFor="googleClientId" className="col-3 text-end py-2 form-label">{t('security_settings.clientID')}</label>
               <div className="col-6">
                 <input
                   className="form-control"
@@ -118,7 +118,7 @@ class GoogleSecurityManagementContents extends React.Component {
             </div>
 
             <div className="row mb-5">
-              <label htmlFor="googleClientSecret" className="col-3 text-end py-2">{t('security_settings.client_secret')}</label>
+              <label htmlFor="googleClientSecret" className="col-3 text-end py-2 form-label">{t('security_settings.client_secret')}</label>
               <div className="col-6">
                 <input
                   className="form-control"
@@ -135,16 +135,16 @@ class GoogleSecurityManagementContents extends React.Component {
 
             <div className="row mb-5">
               <div className="offset-3 col-6">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByUserNameGoogle"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminGoogleSecurityContainer.state.isSameEmailTreatedAsIdenticalUser || false}
                     onChange={() => { adminGoogleSecurityContainer.switchIsSameEmailTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="custom-control-label"
+                    className="form-check-label"
                     htmlFor="bindByUserNameGoogle"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat email matching as identical') }}
                   />

+ 4 - 4
apps/app/src/components/Admin/Security/LdapAuthTest.tsx

@@ -89,7 +89,7 @@ export const LdapAuthTest = (props: LdapAuthTestProps): JSX.Element => {
     <React.Fragment>
       {successMessage !== '' && <div className="alert alert-success">{successMessage}</div>}
       {errorMessage !== '' && <div className="alert alert-warning">{errorMessage}</div>}
-      <div className="form-group row">
+      <div className="row">
         <label htmlFor="username" className="col-3 col-form-label">{t('username')}</label>
         <div className="col-6">
           <input
@@ -101,7 +101,7 @@ export const LdapAuthTest = (props: LdapAuthTestProps): JSX.Element => {
           />
         </div>
       </div>
-      <div className="form-group row">
+      <div className="row">
         <label htmlFor="password" className="col-3 col-form-label">{t('Password')}</label>
         <div className="col-6">
           <input
@@ -115,8 +115,8 @@ export const LdapAuthTest = (props: LdapAuthTestProps): JSX.Element => {
         </div>
       </div>
 
-      <div className="form-group">
-        <label><h5>Logs</h5></label>
+      <div>
+        <label className="form-label"><h5>Logs</h5></label>
         <textarea id="taLogs" className="col form-control" rows={4} value={logs} readOnly />
       </div>
 

+ 30 - 30
apps/app/src/components/Admin/Security/LdapSecuritySettingContents.jsx

@@ -58,17 +58,17 @@ class LdapSecuritySettingContents extends React.Component {
           LDAP
         </h2>
 
-        <div className="form-group row">
+        <div className="row">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 id="isLdapEnabled"
-                className="custom-control-input"
+                className="form-check-input"
                 type="checkbox"
                 checked={isLdapEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsLdapEnabled() }}
               />
-              <label className="custom-control-label" htmlFor="isLdapEnabled">
+              <label className="form-label form-check-label" htmlFor="isLdapEnabled">
                 {t('security_settings.ldap.enable_ldap')}
               </label>
             </div>
@@ -83,8 +83,8 @@ class LdapSecuritySettingContents extends React.Component {
 
             <h3 className="border-bottom">{t('security_settings.configuration')}</h3>
 
-            <div className="form-group row">
-              <label htmlFor="serverUrl" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label htmlFor="serverUrl" className="text-start text-md-end col-md-3 col-form-label">
                 Server URL
               </label>
               <div className="col-md-6">
@@ -106,8 +106,8 @@ class LdapSecuritySettingContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
-              <label className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label className="form-label text-start text-md-end col-md-3 col-form-label">
                 <strong>{t('security_settings.ldap.bind_mode')}</strong>
               </label>
               <div className="col-md-6">
@@ -136,8 +136,8 @@ class LdapSecuritySettingContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
-              <label className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label className="form-label text-start text-md-end col-md-3 col-form-label">
                 <strong>Bind DN</strong>
               </label>
               <div className="col-md-6">
@@ -171,8 +171,8 @@ class LdapSecuritySettingContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
-              <div htmlFor="bindDNPassword" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <div htmlFor="bindDNPassword" className="text-start text-md-end col-md-3 col-form-label">
                 <strong>{t('security_settings.ldap.bind_DN_password')}</strong>
               </div>
               <div className="col-md-6">
@@ -202,8 +202,8 @@ class LdapSecuritySettingContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
-              <label className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label className="form-label text-start text-md-end col-md-3 col-form-label">
                 <strong>{t('security_settings.ldap.search_filter')}</strong>
               </label>
               <div className="col-md-6">
@@ -238,8 +238,8 @@ class LdapSecuritySettingContents extends React.Component {
               Attribute Mapping ({t('security_settings.optional')})
             </h3>
 
-            <div className="form-group row">
-              <label className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label className="form-label text-start text-md-end col-md-3 col-form-label">
                 <strong htmlFor="attrMapUsername">{t('username')}</strong>
               </label>
               <div className="col-md-6">
@@ -258,18 +258,18 @@ class LdapSecuritySettingContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
+            <div className="row">
               <div className="offset-md-3 col-md-6">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     type="checkbox"
-                    className="custom-control-input"
+                    className="form-check-input"
                     id="isSameUsernameTreatedAsIdenticalUser"
                     checked={adminLdapSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser}
                     onChange={() => { adminLdapSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="custom-control-label"
+                    className="form-check-label"
                     htmlFor="isSameUsernameTreatedAsIdenticalUser"
                     // eslint-disable-next-line react/no-danger
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat username matching as identical') }}
@@ -282,8 +282,8 @@ class LdapSecuritySettingContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
-              <label className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label className="form-label text-start text-md-end col-md-3 col-form-label">
                 <strong htmlFor="attrMapMail">{t('Email')}</strong>
               </label>
               <div className="col-md-6">
@@ -303,8 +303,8 @@ class LdapSecuritySettingContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
-              <label className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label className="form-label text-start text-md-end col-md-3 col-form-label">
                 <strong htmlFor="attrMapName">{t('Name')}</strong>
               </label>
               <div className="col-md-6">
@@ -328,8 +328,8 @@ class LdapSecuritySettingContents extends React.Component {
               {t('security_settings.ldap.group_search_filter')} ({t('security_settings.optional')})
             </h3>
 
-            <div className="form-group row">
-              <label className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label className="form-label text-start text-md-end col-md-3 col-form-label">
                 <strong htmlFor="groupSearchBase">{t('security_settings.ldap.group_search_base_DN')}</strong>
               </label>
               <div className="col-md-6">
@@ -350,8 +350,8 @@ class LdapSecuritySettingContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
-              <label className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label className="form-label text-start text-md-end col-md-3 col-form-label">
                 <strong htmlFor="groupSearchFilter">{t('security_settings.ldap.group_search_filter')}</strong>
               </label>
               <div className="col-md-6">
@@ -381,8 +381,8 @@ class LdapSecuritySettingContents extends React.Component {
               </div>
             </div>
 
-            <div className="form-group row">
-              <label className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row">
+              <label className="form-label text-start text-md-end col-md-3 col-form-label">
                 <strong htmlFor="groupDnProperty">{t('security_settings.ldap.group_search_user_DN_property')}</strong>
               </label>
               <div className="col-md-6">

+ 13 - 13
apps/app/src/components/Admin/Security/LocalSecuritySettingContents.jsx

@@ -64,16 +64,16 @@ class LocalSecuritySettingContents extends React.Component {
 
         <div className="row mb-5">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 type="checkbox"
-                className="custom-control-input"
+                className="form-check-input"
                 id="isLocalEnabled"
                 checked={isLocalEnabled}
                 onChange={() => adminGeneralSecurityContainer.switchIsLocalEnabled()}
                 disabled={adminLocalSecurityContainer.state.useOnlyEnvVars}
               />
-              <label className="custom-control-label" htmlFor="isLocalEnabled">
+              <label className="form-label form-check-label" htmlFor="isLocalEnabled">
                 {t('security_settings.Local.enable_local')}
               </label>
             </div>
@@ -88,7 +88,7 @@ class LocalSecuritySettingContents extends React.Component {
             <h3 className="border-bottom">{t('security_settings.configuration')}</h3>
 
             <div className="row">
-              <div className="col-12 col-md-3 text-start text-md-right py-2">
+              <div className="col-12 col-md-3 text-start text-md-end py-2">
                 <strong>{t('security_settings.register_limitation')}</strong>
               </div>
               <div className="col-12 col-md-6">
@@ -139,7 +139,7 @@ class LocalSecuritySettingContents extends React.Component {
               </div>
             </div>
             <div className="row">
-              <div className="col-12 col-md-3 text-start text-md-right">
+              <div className="col-12 col-md-3 text-start text-md-end">
                 <strong dangerouslySetInnerHTML={{ __html: t('security_settings.The whitelist of registration permission E-mail address') }} />
               </div>
               <div className="col-12 col-md-6">
@@ -163,17 +163,17 @@ class LocalSecuritySettingContents extends React.Component {
             </div>
 
             <div className="row">
-              <label className="col-12 col-md-3 text-start text-md-right  col-form-label">{t('security_settings.Local.password_reset_by_users')}</label>
+              <label className="col-12 col-md-3 text-start text-md-end  col-form-label">{t('security_settings.Local.password_reset_by_users')}</label>
               <div className="col-12 col-md-6">
-                <div className="custom-control custom-switch custom-checkbox-success">
+                <div className="form-check form-switch form-check-success">
                   <input
                     type="checkbox"
-                    className="custom-control-input"
+                    className="form-check-input"
                     id="isPasswordResetEnabled"
                     checked={isPasswordResetEnabled}
                     onChange={() => adminLocalSecurityContainer.switchIsPasswordResetEnabled()}
                   />
-                  <label className="custom-control-label" htmlFor="isPasswordResetEnabled">
+                  <label className="form-label form-check-label" htmlFor="isPasswordResetEnabled">
                     {t('security_settings.Local.enable_password_reset_by_users')}
                   </label>
                 </div>
@@ -192,17 +192,17 @@ class LocalSecuritySettingContents extends React.Component {
             </div>
 
             <div className="row">
-              <label className="col-12 col-md-3 text-start text-md-right  col-form-label">{t('security_settings.Local.email_authentication')}</label>
+              <label className="col-12 col-md-3 text-start text-md-end  col-form-label">{t('security_settings.Local.email_authentication')}</label>
               <div className="col-12 col-md-6">
-                <div className="custom-control custom-switch custom-checkbox-success">
+                <div className="form-check form-switch form-check-success">
                   <input
                     type="checkbox"
-                    className="custom-control-input"
+                    className="form-check-input"
                     id="isEmailAuthenticationEnabled"
                     checked={isEmailAuthenticationEnabled}
                     onChange={() => adminLocalSecurityContainer.switchIsEmailAuthenticationEnabled()}
                   />
-                  <label className="custom-control-label" htmlFor="isEmailAuthenticationEnabled">
+                  <label className="form-label form-check-label" htmlFor="isEmailAuthenticationEnabled">
                     {t('security_settings.Local.enable_email_authentication')}
                   </label>
                 </div>

+ 48 - 48
apps/app/src/components/Admin/Security/OidcSecuritySettingContents.jsx

@@ -48,17 +48,17 @@ class OidcSecurityManagementContents extends React.Component {
           {t('security_settings.OAuth.OIDC.name')}
         </h2>
 
-        <div className="row mb-5 form-group">
+        <div className="row mb-5">
           <div className="offset-3 col-6">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 id="isOidcEnabled"
-                className="custom-control-input"
+                className="form-check-input"
                 type="checkbox"
                 checked={adminGeneralSecurityContainer.state.isOidcEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsOidcEnabled() }}
               />
-              <label className="custom-control-label" htmlFor="isOidcEnabled">
+              <label className="form-label form-check-label" htmlFor="isOidcEnabled">
                 {t('security_settings.OAuth.enable_oidc')}
               </label>
             </div>
@@ -67,8 +67,8 @@ class OidcSecurityManagementContents extends React.Component {
           </div>
         </div>
 
-        <div className="row mb-5 form-group">
-          <label className="text-start text-md-right col-md-3 col-form-label">{t('security_settings.callback_URL')}</label>
+        <div className="row mb-5">
+          <label className="text-start text-md-end col-md-3 col-form-label">{t('security_settings.callback_URL')}</label>
           <div className="col-md-6">
             <input
               className="form-control"
@@ -94,8 +94,8 @@ class OidcSecurityManagementContents extends React.Component {
 
             <h3 className="border-bottom">{t('security_settings.configuration')}</h3>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcProviderName" className="text-start text-md-right col-md-3 col-form-label">{t('security_settings.providerName')}</label>
+            <div className="row mb-5">
+              <label htmlFor="oidcProviderName" className="text-start text-md-end col-md-3 col-form-label">{t('security_settings.providerName')}</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -107,8 +107,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcIssuerHost" className="text-start text-md-right col-md-3 col-form-label">{t('security_settings.issuerHost')}</label>
+            <div className="row mb-5">
+              <label htmlFor="oidcIssuerHost" className="text-start text-md-end col-md-3 col-form-label">{t('security_settings.issuerHost')}</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -123,8 +123,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcClientId" className="text-start text-md-right col-md-3 col-form-label">{t('security_settings.clientID')}</label>
+            <div className="row mb-5">
+              <label htmlFor="oidcClientId" className="text-start text-md-end col-md-3 col-form-label">{t('security_settings.clientID')}</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -139,8 +139,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcClientSecret" className="text-start text-md-right col-md-3 col-form-label">{t('security_settings.client_secret')}</label>
+            <div className="row mb-5">
+              <label htmlFor="oidcClientSecret" className="text-start text-md-end col-md-3 col-form-label">{t('security_settings.client_secret')}</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -155,8 +155,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcAuthorizationEndpoint" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row mb-5">
+              <label htmlFor="oidcAuthorizationEndpoint" className="text-start text-md-end col-md-3 col-form-label">
                 {t('security_settings.authorization_endpoint')}
               </label>
               <div className="col-md-6">
@@ -173,8 +173,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcTokenEndpoint" className="text-start text-md-right col-md-3 col-form-label">{t('security_settings.token_endpoint')}</label>
+            <div className="row mb-5">
+              <label htmlFor="oidcTokenEndpoint" className="text-start text-md-end col-md-3 col-form-label">{t('security_settings.token_endpoint')}</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -189,8 +189,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcRevocationEndpoint" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row mb-5">
+              <label htmlFor="oidcRevocationEndpoint" className="text-start text-md-end col-md-3 col-form-label">
                 {t('security_settings.revocation_endpoint')}
               </label>
               <div className="col-md-6">
@@ -207,8 +207,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcIntrospectionEndpoint" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row mb-5">
+              <label htmlFor="oidcIntrospectionEndpoint" className="text-start text-md-end col-md-3 col-form-label">
                 {t('security_settings.introspection_endpoint')}
               </label>
               <div className="col-md-6">
@@ -225,8 +225,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcUserInfoEndpoint" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row mb-5">
+              <label htmlFor="oidcUserInfoEndpoint" className="text-start text-md-end col-md-3 col-form-label">
                 {t('security_settings.userinfo_endpoint')}
               </label>
               <div className="col-md-6">
@@ -243,8 +243,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcEndSessionEndpoint" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row mb-5">
+              <label htmlFor="oidcEndSessionEndpoint" className="text-start text-md-end col-md-3 col-form-label">
                 {t('security_settings.end_session_endpoint')}
               </label>
               <div className="col-md-6">
@@ -261,8 +261,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcRegistrationEndpoint" className="text-start text-md-right col-md-3 col-form-label">
+            <div className="row mb-5">
+              <label htmlFor="oidcRegistrationEndpoint" className="text-start text-md-end col-md-3 col-form-label">
                 {t('security_settings.registration_endpoint')}
               </label>
               <div className="col-md-6">
@@ -279,8 +279,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcJWKSUri" className="text-start text-md-right col-md-3 col-form-label">{t('security_settings.jwks_uri')}</label>
+            <div className="row mb-5">
+              <label htmlFor="oidcJWKSUri" className="text-start text-md-end col-md-3 col-form-label">{t('security_settings.jwks_uri')}</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -299,8 +299,8 @@ class OidcSecurityManagementContents extends React.Component {
               Attribute Mapping ({t('security_settings.optional')})
             </h3>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcAttrMapId" className="text-start text-md-right col-md-3 col-form-label">Identifier</label>
+            <div className="row mb-5">
+              <label htmlFor="oidcAttrMapId" className="text-start text-md-end col-md-3 col-form-label">Identifier</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -315,8 +315,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcAttrMapUserName" className="text-start text-md-right col-md-3 col-form-label">{t('username')}</label>
+            <div className="row mb-5">
+              <label htmlFor="oidcAttrMapUserName" className="text-start text-md-end col-md-3 col-form-label">{t('username')}</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -331,8 +331,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcAttrMapName" className="text-start text-md-right col-md-3 col-form-label">{t('Name')}</label>
+            <div className="row mb-5">
+              <label htmlFor="oidcAttrMapName" className="text-start text-md-end col-md-3 col-form-label">{t('Name')}</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -347,8 +347,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label htmlFor="oidcAttrMapEmail" className="text-start text-md-right col-md-3 col-form-label">{t('Email')}</label>
+            <div className="row mb-5">
+              <label htmlFor="oidcAttrMapEmail" className="text-start text-md-end col-md-3 col-form-label">{t('Email')}</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -363,8 +363,8 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
-              <label className="text-start text-md-right col-md-3 col-form-label">{t('security_settings.callback_URL')}</label>
+            <div className="row mb-5">
+              <label className="form-label text-start text-md-end col-md-3 col-form-label">{t('security_settings.callback_URL')}</label>
               <div className="col-md-6">
                 <input
                   className="form-control"
@@ -385,18 +385,18 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
+            <div className="row mb-5">
               <div className="offset-md-3 col-md-6">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByUserName-oidc"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminOidcSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser}
                     onChange={() => { adminOidcSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="custom-control-label"
+                    className="form-label form-check-label"
                     htmlFor="bindByUserName-oidc"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat username matching as identical') }}
                   />
@@ -407,18 +407,18 @@ class OidcSecurityManagementContents extends React.Component {
               </div>
             </div>
 
-            <div className="row mb-5 form-group">
+            <div className="row mb-5">
               <div className="offset-md-3 col-md-6">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByEmail-oidc"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminOidcSecurityContainer.state.isSameEmailTreatedAsIdenticalUser || false}
                     onChange={() => { adminOidcSecurityContainer.switchIsSameEmailTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="custom-control-label"
+                    className="form-label form-check-label"
                     htmlFor="bindByEmail-oidc"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat email matching as identical') }}
                   />

+ 14 - 14
apps/app/src/components/Admin/Security/SamlSecuritySettingContents.jsx

@@ -64,18 +64,18 @@ class SamlSecurityManagementContents extends React.Component {
           />
         )}
 
-        <div className="row form-group mb-5">
+        <div className="row mb-5">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 id="isSamlEnabled"
-                className="custom-control-input"
+                className="form-check-input"
                 type="checkbox"
                 checked={adminGeneralSecurityContainer.state.isSamlEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsSamlEnabled() }}
                 disabled={adminSamlSecurityContainer.state.useOnlyEnvVars}
               />
-              <label className="custom-control-label" htmlFor="isSamlEnabled">
+              <label className="form-label form-check-label" htmlFor="isSamlEnabled">
                 {t('security_settings.SAML.enable_saml')}
               </label>
             </div>
@@ -84,8 +84,8 @@ class SamlSecurityManagementContents extends React.Component {
           </div>
         </div>
 
-        <div className="row form-group mb-5">
-          <label className="text-start text-md-right col-md-3 col-form-label">{t('security_settings.callback_URL')}</label>
+        <div className="row mb-5">
+          <label className="text-start text-md-end col-md-3 col-form-label">{t('security_settings.callback_URL')}</label>
           <div className="col-md-6">
             <input
               className="form-control"
@@ -390,18 +390,18 @@ pWVdnzS1VCO8fKsJ7YYIr+JmHvseph3kFUOI5RqkCcMZlKUv83aUThsTHw==
               Attribute Mapping Options
             </h3>
 
-            <div className="row form-group mb-5">
+            <div className="row mb-5">
               <div className="offset-md-3 col-md-6 text-start">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByUserName-SAML"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminSamlSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser || false}
                     onChange={() => { adminSamlSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="custom-control-label"
+                    className="form-label form-check-label"
                     htmlFor="bindByUserName-SAML"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat username matching as identical') }}
                   />
@@ -412,18 +412,18 @@ pWVdnzS1VCO8fKsJ7YYIr+JmHvseph3kFUOI5RqkCcMZlKUv83aUThsTHw==
               </div>
             </div>
 
-            <div className="row form-group mb-5">
+            <div className="row mb-5">
               <div className="offset-md-3 col-md-6 text-start">
-                <div className="custom-control custom-checkbox custom-checkbox-success">
+                <div className="form-check form-check-success">
                   <input
                     id="bindByEmail-SAML"
-                    className="custom-control-input"
+                    className="form-check-input"
                     type="checkbox"
                     checked={adminSamlSecurityContainer.state.isSameEmailTreatedAsIdenticalUser || false}
                     onChange={() => { adminSamlSecurityContainer.switchIsSameEmailTreatedAsIdenticalUser() }}
                   />
                   <label
-                    className="custom-control-label"
+                    className="form-label form-check-label"
                     htmlFor="bindByEmail-SAML"
                     dangerouslySetInnerHTML={{ __html: t('security_settings.Treat email matching as identical') }}
                   />

+ 14 - 14
apps/app/src/components/Admin/Security/SecuritySetting.jsx

@@ -252,7 +252,7 @@ class SecuritySetting extends React.Component {
     return (
       <div key={`page-delete-permission-dropdown-${deletionType}`} className="row">
 
-        <div className="col-md-3 text-md-right">
+        <div className="col-md-3 text-md-end">
           {!isRecursiveDeletion(deletionType) && isTypeDeletion(deletionType) && (
             <strong>{t('security_settings.page_delete')}</strong>
           )}
@@ -356,15 +356,15 @@ class SecuritySetting extends React.Component {
               <tr>
                 <th scope="row">{ t('only_me') }</th>
                 <td>
-                  <div className="custom-control custom-switch custom-checkbox-success">
+                  <div className="form-check form-switch form-check-success">
                     <input
                       type="checkbox"
-                      className="custom-control-input"
+                      className="form-check-input"
                       id="isShowRestrictedByOwner"
                       checked={!adminGeneralSecurityContainer.state.isShowRestrictedByOwner}
                       onChange={() => { adminGeneralSecurityContainer.switchIsShowRestrictedByOwner() }}
                     />
-                    <label className="custom-control-label" htmlFor="isShowRestrictedByOwner">
+                    <label className="form-label form-check-label" htmlFor="isShowRestrictedByOwner">
                       {t('security_settings.displayed_or_hidden')}
                     </label>
                   </div>
@@ -373,15 +373,15 @@ class SecuritySetting extends React.Component {
               <tr>
                 <th scope="row">{ t('only_inside_the_group') }</th>
                 <td>
-                  <div className="custom-control custom-switch custom-checkbox-success">
+                  <div className="form-check form-switch form-check-success">
                     <input
                       type="checkbox"
-                      className="custom-control-input"
+                      className="form-check-input"
                       id="isShowRestrictedByGroup"
                       checked={!adminGeneralSecurityContainer.state.isShowRestrictedByGroup}
                       onChange={() => { adminGeneralSecurityContainer.switchIsShowRestrictedByGroup() }}
                     />
-                    <label className="custom-control-label" htmlFor="isShowRestrictedByGroup">
+                    <label className="form-label form-check-label" htmlFor="isShowRestrictedByGroup">
                       {t('security_settings.displayed_or_hidden')}
                     </label>
                   </div>
@@ -393,7 +393,7 @@ class SecuritySetting extends React.Component {
 
         <h4>{t('security_settings.page_access_rights')}</h4>
         <div className="row mb-4">
-          <div className="col-md-3 text-md-right py-2">
+          <div className="col-md-3 text-md-end py-2">
             <strong>{t('security_settings.Guest Users Access')}</strong>
           </div>
           <div className="col-md-9">
@@ -456,15 +456,15 @@ class SecuritySetting extends React.Component {
         <h4>{t('security_settings.user_homepage_deletion.user_homepage_deletion')}</h4>
         <div className="row mb-4">
           <div className="col-6 offset-3">
-            <div className="custom-control custom-switch custom-checkbox-success">
+            <div className="form-check form-switch form-check-success">
               <input
                 type="checkbox"
-                className="custom-control-input"
+                className="form-check-input"
                 id="is-user-page-deletion-enabled"
                 checked={adminGeneralSecurityContainer.state.isUsersHomepageDeletionEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsUsersHomepageDeletionEnabled() }}
               />
-              <label className="custom-control-label" htmlFor="is-user-page-deletion-enabled">
+              <label className="form-label form-check-label" htmlFor="is-user-page-deletion-enabled">
                 {t('security_settings.user_homepage_deletion.enable_user_homepage_deletion')}
               </label>
             </div>
@@ -476,8 +476,8 @@ class SecuritySetting extends React.Component {
         </div>
 
         <h4>{t('security_settings.session')}</h4>
-        <div className="form-group row">
-          <label className="text-start text-md-right col-md-3 col-form-label">{t('security_settings.max_age')}</label>
+        <div className="row">
+          <label className="text-start text-md-end col-md-3 col-form-label">{t('security_settings.max_age')}</label>
           <div className="col-md-6">
             <input
               className="form-control col-md-3"
@@ -499,7 +499,7 @@ class SecuritySetting extends React.Component {
         </div>
 
         <div className="row my-3">
-          <div className="text-center text-md-left offset-md-3 col-md-5">
+          <div className="text-center text-md-start offset-md-3 col-md-5">
             <button type="button" className="btn btn-primary" disabled={adminGeneralSecurityContainer.retrieveError != null} onClick={this.putSecuritySetting}>
               {t('Update')}
             </button>

+ 3 - 3
apps/app/src/components/Admin/Security/ShareLinkSetting.tsx

@@ -116,15 +116,15 @@ const ShareLinkSetting = (props: ShareLinkSettingProps) => {
       <h4>{t('security_settings.share_link_rights')}</h4>
       <div className="row mb-5">
         <div className="col-6 offset-3">
-          <div className="custom-control custom-switch custom-checkbox-success">
+          <div className="form-check form-switch form-check-success">
             <input
               type="checkbox"
-              className="custom-control-input"
+              className="form-check-input"
               id="disableLinkSharing"
               checked={!disableLinkSharing}
               onChange={() => switchDisableLinkSharing()}
             />
-            <label className="custom-control-label" htmlFor="disableLinkSharing">
+            <label className="form-label form-check-label" htmlFor="disableLinkSharing">
               {t('security_settings.enable_link_sharing')}
             </label>
           </div>

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

@@ -107,8 +107,8 @@ const CustomBotWithProxySettings = (props) => {
             connectionStatuses={connectionStatuses}
           />
 
-          <div className="form-group row my-4">
-            <label className="text-start text-md-right col-md-3 col-form-label mt-3">Proxy URL</label>
+          <div className="row my-4">
+            <label className="text-start text-md-end col-md-3 col-form-label mt-3">Proxy URL</label>
             <div className="col-md-6 mt-3">
               <input
                 className="form-control"
@@ -118,7 +118,7 @@ const CustomBotWithProxySettings = (props) => {
                 onChange={(e) => { setNewProxyServerUri(e.target.value) }}
               />
             </div>
-            <div className="col-md-2 mt-3 text-center text-md-left">
+            <div className="col-md-2 mt-3 text-center text-md-start">
               <button type="button" className="btn btn-primary" onClick={updateProxyUri}>{ t('Update') }</button>
             </div>
           </div>

+ 4 - 4
apps/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySettingsAccordion.jsx

@@ -145,9 +145,9 @@ const CustomBotWithoutProxySettingsAccordion = (props) => {
           <i className="icon-info">{t('admin:slack_integration.accordion.test_connection_only_public_channel')}</i>
         </p>
         <div className="d-flex justify-content-center">
-          <form className="form-row align-items-center" onSubmit={e => submitForm(e)}>
+          <form className="align-items-center" onSubmit={e => submitForm(e)}>
             <div className="input-group col-8">
-              <div className="input-group-prepend">
+              <div>
                 <span className="input-group-text" id="slack-channel-addon"><i className="fa fa-hashtag" /></span>
               </div>
               <input
@@ -171,8 +171,8 @@ const CustomBotWithoutProxySettingsAccordion = (props) => {
 
         <form>
           <div className="row my-3 justify-content-center">
-            <div className="form-group slack-connection-log col-md-4">
-              <label className="mb-1"><p className="border-info slack-connection-log-title ps-2 m-0">Logs</p></label>
+            <div className="slack-connection-log col-md-4">
+              <label className="form-label mb-1"><p className="border-info slack-connection-log-title ps-2 m-0">Logs</p></label>
               <textarea
                 className="form-control card border-info slack-connection-log-body rounded-3"
                 rows="5"

+ 2 - 2
apps/app/src/components/Admin/SlackIntegration/ManageCommandsProcess.jsx

@@ -84,7 +84,7 @@ const PermissionSettingForEachPermissionTypeComponent = ({
   return (
     <div className="my-1 mb-2">
       <div className="row align-items-center mb-3">
-        <p className="col-md-5 text-md-right mb-2">
+        <p className="col-md-5 text-md-end mb-2">
           <strong className="text-capitalize">{keyName}</strong>
           {singleCommandDescription && (
             <small className="form-text text-muted small">
@@ -305,7 +305,7 @@ const ManageCommandsProcess = ({
           </div>
         )}
 
-        <div className="custom-control custom-checkbox">
+        <div className="form-check">
           <div className="row mb-5 d-block">
             {defaultCommandsName.map(keyName => (
               <PermissionSettingForEachPermissionTypeComponent

+ 2 - 2
apps/app/src/components/Admin/SlackIntegration/ManageCommandsProcessWithoutProxy.jsx

@@ -220,7 +220,7 @@ const ManageCommandsProcessWithoutProxy = ({ commandPermission, eventActionsPerm
       <p className="mb-4 fw-bold">{t('admin:slack_integration.accordion.growi_commands')}</p>
       <div className="row d-flex flex-column align-items-center">
         <div className="col-8">
-          <div className="custom-control custom-checkbox">
+          <div className="form-check">
             <div className="row mb-5 d-block">
               { defaultCommandsName.map((commandName) => {
                 // eslint-disable-next-line max-len
@@ -241,7 +241,7 @@ const ManageCommandsProcessWithoutProxy = ({ commandPermission, eventActionsPerm
       <p className="mb-4 fw-bold">Events</p>
       <div className="row d-flex flex-column align-items-center">
         <div className="col-8">
-          <div className="custom-control custom-checkbox">
+          <div className="form-check">
             <div className="row mb-5 d-block">
               { defaultSupportedSlackEventActions.map(actionName => (
                 <SinglePermissionSettingComponent

+ 4 - 3
apps/app/src/components/Admin/SlackIntegration/SlackAppIntegrationControl.tsx

@@ -1,4 +1,5 @@
 import React, { FC } from 'react';
+
 import { useTranslation } from 'next-i18next';
 
 type Props = {
@@ -19,9 +20,9 @@ export const SlackAppIntegrationControl: FC<Props> = (props: Props) => {
 
   return (
     <div className="d-flex align-items-center">
-      <div className="my-1 custom-control custom-switch">
+      <div className="my-1 form-check form-switch">
         <input
-          className="custom-control-input"
+          className="form-check-input"
           id={inputId}
           type="checkbox"
           checked={isPrimary}
@@ -32,7 +33,7 @@ export const SlackAppIntegrationControl: FC<Props> = (props: Props) => {
             }
           }}
         />
-        <label className="custom-control-label" htmlFor={inputId}>
+        <label className="form-label form-check-label" htmlFor={inputId}>
           Primary
         </label>
       </div>

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

@@ -137,19 +137,19 @@ const GeneratingTokensAndRegisteringProxyServiceProcess = (props) => {
   return (
     <div className="py-4 px-5">
       <p className="fw-bold">1. {t('admin:slack_integration.accordion.generate_access_token')}</p>
-      <div className="form-group row">
-        <label className="text-start text-md-right col-md-3 col-form-label">Access Token Proxy to GROWI</label>
+      <div className="row">
+        <label className="text-start text-md-end col-md-3 col-form-label">Access Token Proxy to GROWI</label>
         <div className="col-md-6">
-          <div className="input-group-prepend mx-1">
+          <div className=" mx-1">
             <input className="form-control" type="text" value={props.tokenPtoG || ''} readOnly />
             <CustomCopyToClipBoard textToBeCopied={props.tokenPtoG || ''} message="admin:slack_integration.copied_to_clipboard"></CustomCopyToClipBoard>
           </div>
         </div>
       </div>
-      <div className="form-group row">
-        <label className="text-start text-md-right col-md-3 col-form-label">Access Token GROWI to Proxy</label>
+      <div className="row">
+        <label className="text-start text-md-end col-md-3 col-form-label">Access Token GROWI to Proxy</label>
         <div className="col-md-6">
-          <div className="input-group-prepend mx-1">
+          <div className=" mx-1">
             <input className="form-control" type="text" value={props.tokenGtoP || ''} readOnly />
             <CustomCopyToClipBoard textToBeCopied={props.tokenGtoP || ''} message="admin:slack_integration.copied_to_clipboard"></CustomCopyToClipBoard>
           </div>
@@ -184,7 +184,7 @@ const GeneratingTokensAndRegisteringProxyServiceProcess = (props) => {
               dangerouslySetInnerHTML={{ __html: t('admin:slack_integration.accordion.paste_growi_url') }}
             />
             <div className="input-group align-items-center ps-2 mb-3">
-              <div className="input-group-prepend w-75">
+              <div className="w-75">
                 <input className="form-control" type="text" value={props.growiUrl} readOnly />
                 <CustomCopyToClipBoard textToBeCopied={props.growiUrl} message="admin:slack_integration.copied_to_clipboard"></CustomCopyToClipBoard>
               </div>
@@ -243,9 +243,9 @@ const TestProcess = ({
         <i className="icon-info">{t('admin:slack_integration.accordion.test_connection_only_public_channel')}</i>
       </p>
       <div className="d-flex justify-content-center">
-        <form className="form-row justify-content-center" onSubmit={e => submitForm(e)}>
+        <form className="justify-content-center" onSubmit={e => submitForm(e)}>
           <div className="input-group col-8">
-            <div className="input-group-prepend">
+            <div>
               <span className="input-group-text" id="slack-channel-addon"><i className="fa fa-hashtag" /></span>
             </div>
             <input
@@ -268,8 +268,8 @@ const TestProcess = ({
       <MessageBasedOnConnection isLatestConnectionSuccess={isLatestConnectionSuccess} logsValue={logsValue} />
       <form>
         <div className="row my-3 justify-content-center">
-          <div className="form-group slack-connection-log col-md-4">
-            <label className="mb-1"><p className="border-info slack-connection-log-title ps-2 m-0">Logs</p></label>
+          <div className="slack-connection-log col-md-4">
+            <label className="form-label mb-1"><p className="border-info slack-connection-log-title ps-2 m-0">Logs</p></label>
             <textarea
               className="form-control card border-info slack-connection-log-body rounded-3"
               rows="5"

+ 1 - 1
apps/app/src/components/Admin/UserGroup/UserGroupDeleteModal.tsx

@@ -196,7 +196,7 @@ export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
       </ModalBody>
       <ModalFooter>
         <form className="d-flex justify-content-between w-100" onSubmit={handleSubmit}>
-          <div className="d-flex form-group mb-0">
+          <div className="d-flex mb-0">
             {renderPageActionSelector()}
             {renderGroupSelector()}
           </div>

+ 5 - 5
apps/app/src/components/Admin/UserGroup/UserGroupForm.tsx

@@ -63,14 +63,14 @@ export const UserGroupForm: FC<Props> = (props: Props) => {
 
         {
           userGroup?.createdAt != null && (
-            <div className="form-group row">
+            <div className="row">
               <p className="col-md-2 col-form-label">{t('Created')}</p>
               <p className="col-md-4 my-auto">{dateFnsFormat(new Date(userGroup.createdAt), 'yyyy-MM-dd')}</p>
             </div>
           )
         }
 
-        <div className="form-group row">
+        <div className="row">
           <label htmlFor="name" className="col-md-2 col-form-label">
             {t('user_group_management.group_name')}
           </label>
@@ -87,7 +87,7 @@ export const UserGroupForm: FC<Props> = (props: Props) => {
           </div>
         </div>
 
-        <div className="form-group row">
+        <div className="row">
           <label htmlFor="description" className="col-md-2 col-form-label">
             {t('Description')}
           </label>
@@ -96,7 +96,7 @@ export const UserGroupForm: FC<Props> = (props: Props) => {
           </div>
         </div>
 
-        <div className="form-group row">
+        <div className="row">
           <label htmlFor="parent" className="col-md-2 col-form-label">
             {t('user_group_management.parent_group')}
           </label>
@@ -143,7 +143,7 @@ export const UserGroupForm: FC<Props> = (props: Props) => {
           </div>
         </div>
 
-        <div className="form-group row">
+        <div className="row">
           <div className="offset-md-2 col-md-10">
             <button type="submit" className="btn btn-primary">
               {submitButtonLabel}

+ 5 - 5
apps/app/src/components/Admin/UserGroup/UserGroupModal.tsx

@@ -74,8 +74,8 @@ export const UserGroupModal: FC<Props> = (props: Props) => {
         </ModalHeader>
 
         <ModalBody>
-          <div className="form-group">
-            <label htmlFor="name">
+          <div>
+            <label htmlFor="name" className="form-label">
               {t('user_group_management.group_name')}
             </label>
             <input
@@ -89,8 +89,8 @@ export const UserGroupModal: FC<Props> = (props: Props) => {
             />
           </div>
 
-          <div className="form-group">
-            <label htmlFor="description">
+          <div>
+            <label htmlFor="description" className="form-label">
               {t('Description')}
             </label>
             <textarea className="form-control" name="description" value={currentDescription} onChange={onChangeDescriptionHandler} />
@@ -103,7 +103,7 @@ export const UserGroupModal: FC<Props> = (props: Props) => {
         </ModalBody>
 
         <ModalFooter>
-          <div className="form-group">
+          <div>
             <button type="submit" className="btn btn-primary">
               {buttonLabel}
             </button>

+ 3 - 3
apps/app/src/components/Admin/UserGroupDetail/CheckBoxForSerchUserOption.jsx

@@ -9,15 +9,15 @@ class CheckBoxForSerchUserOption extends React.Component {
   render() {
     const { t, option } = this.props;
     return (
-      <div className="custom-control custom-checkbox custom-checkbox-info" key={`isAlso${option}Searched`}>
+      <div className="form-check form-check-info" key={`isAlso${option}Searched`}>
         <input
           type="checkbox"
           id={`isAlso${option}Searched`}
-          className="custom-control-input"
+          className="form-check-input"
           checked={this.props.checked}
           onChange={this.props.onChange}
         />
-        <label className="text-capitalize custom-control-label ms-3" htmlFor={`isAlso${option}Searched`}>
+        <label className="form-label text-capitalize form-check-label ms-3" htmlFor={`isAlso${option}Searched`}>
           {t('admin:user_group_management.add_modal.enable_option', { option })}
         </label>
       </div>

+ 3 - 3
apps/app/src/components/Admin/UserGroupDetail/RadioButtonForSerchUserOption.jsx

@@ -9,15 +9,15 @@ const RadioButtonForSerchUserOption = (props) => {
   const { searchType } = props;
   const { t } = useTranslation();
   return (
-    <div className="custom-control custom-radio custom-control-inline" key={`${searchType}Match`}>
+    <div className="form-check form-check-inline" key={`${searchType}Match`}>
       <input
         type="radio"
         id={`${searchType}Match`}
-        className="custom-control-input"
+        className="form-check-input"
         checked={props.checked}
         onChange={props.onChange}
       />
-      <label className="text-capitalize custom-control-label ms-3" htmlFor={`${searchType}Match`}>
+      <label className="form-label text-capitalize form-check-label ms-3" htmlFor={`${searchType}Match`}>
         {t(`admin:user_group_management.add_modal.${searchType}_match`)}
       </label>
     </div>

+ 3 - 3
apps/app/src/components/Admin/UserGroupDetail/UpdateParentConfirmModal.tsx

@@ -43,16 +43,16 @@ export const UpdateParentConfirmModal: FC = () => {
                 {t('admin:user_group_management.update_parent_confirm_modal.danger_message')}
               </div>
 
-              <div className="custom-control custom-checkbox custom-checkbox-succsess ps-5">
+              <div className="form-check form-check-succsess ps-5">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="forceUpdateParents"
                   id="forceUpdateParents"
                   type="checkbox"
                   checked={isForceUpdate}
                   onChange={() => setForceUpdate(!isForceUpdate)}
                 />
-                <label className="custom-control-label" htmlFor="forceUpdateParents">
+                <label className="form-label form-check-label" htmlFor="forceUpdateParents">
                   {t('admin:user_group_management.update_parent_confirm_modal.force_update_parents_label')}
                   <p className="form-text text-muted mt-0">{t('admin:user_group_management.update_parent_confirm_modal.force_update_parents_description')}</p>
                 </label>

+ 1 - 1
apps/app/src/components/Admin/UserGroupDetail/UserGroupUserFormByInput.jsx

@@ -115,7 +115,7 @@ class UserGroupUserFormByInput extends React.Component {
     const inputProps = { autoComplete: 'off' };
 
     return (
-      <div className="form-group row">
+      <div className="row">
         <div className="col-8 pe-0">
           <AsyncTypeahead
             {...this.props}

+ 4 - 4
apps/app/src/components/Admin/UserManagement.tsx

@@ -81,15 +81,15 @@ const UserManagement = (props: UserManagementProps) => {
 
   const renderCheckbox = (status: string, statusLabel: string, statusColor: string) => {
     return (
-      <div className={`custom-control custom-checkbox custom-checkbox-${statusColor} me-2`}>
+      <div className={`form-check form-check-${statusColor} me-2`}>
         <input
-          className="custom-control-input"
+          className="form-check-input"
           type="checkbox"
           id={`c_${status}`}
           checked={adminUsersContainer.isSelected(status)}
           onChange={() => clickHandler(status)}
         />
-        <label className="custom-control-label" htmlFor={`c_${status}`}>
+        <label className="form-label form-check-label" htmlFor={`c_${status}`}>
           <span className={`badge rounded-pill bg-${statusColor} d-inline-block vt mt-1`}>
             {statusLabel}
           </span>
@@ -165,7 +165,7 @@ const UserManagement = (props: UserManagementProps) => {
           </div>
 
           <div className="offset-md-1 col-md-6 my-2">
-            <div className="form-inline">
+            <div>
               {renderCheckbox('all', 'All', 'secondary')}
               {renderCheckbox('registered', 'Approval Pending', 'info')}
               {renderCheckbox('active', 'Active', 'success')}

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

@@ -69,7 +69,7 @@ class PasswordResetModal extends React.Component {
     return (
       <div className="d-flex col text-start ms-1 ps-0">
         {!isMailerSetup ? (
-          <label className="form-text text-muted" dangerouslySetInnerHTML={{ __html: t('admin:mailer_setup_required') }} />
+          <label className="form-label form-text text-muted" dangerouslySetInnerHTML={{ __html: t('admin:mailer_setup_required') }} />
         ) : (
           <>
             <p className="me-2">To:</p>

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

@@ -67,7 +67,7 @@ class UserInviteModal extends React.Component {
 
     return (
       <>
-        <label>{t('admin:user_management.invite_modal.emails')}</label>
+        <label className="form-label">{t('admin:user_management.invite_modal.emails')}</label>
         <p>
           {t('admin:user_management.invite_modal.description1')}
           <br />
@@ -105,16 +105,16 @@ class UserInviteModal extends React.Component {
 
     return (
       <>
-        <div className="col text-start custom-control custom-checkbox custom-checkbox-info text-start" onChange={this.handleCheckBox}>
+        <div className="col text-start form-check form-check-info" onChange={this.handleCheckBox}>
           <input
             type="checkbox"
             id="sendEmail"
-            className="custom-control-input"
+            className="form-check-input"
             name="sendEmail"
             defaultChecked={this.state.sendEmail}
             disabled={!isMailerSetup}
           />
-          <label className="custom-control-label" htmlFor="sendEmail">
+          <label className="form-label form-check-label" htmlFor="sendEmail">
             {t('admin:user_management.invite_modal.invite_thru_email')}
           </label>
           {isMailerSetup
@@ -151,7 +151,7 @@ class UserInviteModal extends React.Component {
 
     return (
       <>
-        <label className="me-3 text-start" style={{ flex: 1 }}>
+        <label className="form-label me-3 text-start" style={{ flex: 1 }}>
           <text className="text-danger">{t('admin:user_management.invite_modal.send_temporary_password')}</text>
           <text>{t('admin:user_management.invite_modal.send_email')}</text>
         </label>

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

@@ -19,7 +19,7 @@ export const BookmarkFolderMenuItem: React.FC<{
         onChange={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 form-label">
         {itemName}
       </label>
     </div>

+ 3 - 3
apps/app/src/components/Common/ImageCropModal.tsx

@@ -162,15 +162,15 @@ const ImageCropModal: FC<Props> = (props: Props) => {
         </button>
         { !showCropOption && (
           <div className="me-auto">
-            <div className="custom-control custom-switch ">
+            <div className="form-check form-switch">
               <input
                 id="cropImageOption"
-                className="custom-control-input me-auto"
+                className="form-check-input me-auto"
                 type="checkbox"
                 checked={isCropImage}
                 onChange={() => { setIsCropImage(!isCropImage) }}
               />
-              <label className="custom-control-label" htmlFor="cropImageOption">
+              <label className="form-label form-check-label" htmlFor="cropImageOption">
                 { t('crop_image_modal.image_crop') }
               </label>
             </div>

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

@@ -111,14 +111,14 @@ const CompleteUserRegistrationForm: React.FC<Props> = (props: Props) => {
               <input type="hidden" name="token" value={token} />
 
               <div className="input-group">
-                <div className="input-group-prepend">
+                <div>
                   <span className="input-group-text"><i className="icon-envelope"></i></span>
                 </div>
                 <input type="text" className="form-control" placeholder={t('Email')} disabled value={email} />
               </div>
 
               <div className="input-group" id="input-group-username">
-                <div className="input-group-prepend">
+                <div>
                   <span className="input-group-text"><i className="icon-user"></i></span>
                 </div>
                 <input
@@ -138,7 +138,7 @@ const CompleteUserRegistrationForm: React.FC<Props> = (props: Props) => {
               )}
 
               <div className="input-group">
-                <div className="input-group-prepend">
+                <div>
                   <span className="input-group-text"><i className="icon-tag"></i></span>
                 </div>
                 <input
@@ -154,7 +154,7 @@ const CompleteUserRegistrationForm: React.FC<Props> = (props: Props) => {
               </div>
 
               <div className="input-group">
-                <div className="input-group-prepend">
+                <div>
                   <span className="input-group-text"><i className="icon-lock"></i></span>
                 </div>
                 <input

+ 2 - 2
apps/app/src/components/CreateTemplateModal.jsx

@@ -47,8 +47,8 @@ const CreateTemplateModal = (props) => {
         {t('template.modal_label.Create/Edit Template Page')}
       </ModalHeader>
       <ModalBody>
-        <div className="form-group">
-          <label className="mb-4">
+        <div>
+          <label className="form-label mb-4">
             <code>{parentPath}</code><br />
             { t('template.modal_label.Create template under') }
           </label>

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

@@ -16,14 +16,14 @@ const DataTransferForm = (): JSX.Element => {
         <strong>{ t('g2g_data_transfer.transfer_data_to_this_growi')}</strong>
       </p>
 
-      <div className="form-group row mt-3">
+      <div className="row mt-3">
         <div className="col-md-12">
           <button type="button" className="btn btn-primary w-100" onClick={generateTransferKey}>
             {t('g2g_data_transfer.publish_transfer_key')}
           </button>
         </div>
         <div className="col-md-12 mt-1">
-          <div className="input-group-prepend">
+          <div>
             <input className="form-control" type="text" value={transferKey} readOnly />
             <CustomCopyToClipBoard textToBeCopied={transferKey} message="copied_to_clipboard" />
           </div>

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

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

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

@@ -65,8 +65,8 @@ const EmptyTrashModal: FC = () => {
         {t('modal_empty.empty_the_trash')}
       </ModalHeader>
       <ModalBody>
-        <div className="form-group grw-scrollable-modal-body pb-1">
-          <label>{ t('modal_delete.deleting_page') }:</label><br />
+        <div className="grw-scrollable-modal-body pb-1">
+          <label className="form-label">{ t('modal_delete.deleting_page') }:</label><br />
           {/* Todo: change the way to show path on modal when too many pages are selected */}
           {renderPagePaths()}
         </div>

+ 5 - 5
apps/app/src/components/InstallerForm.tsx

@@ -100,7 +100,7 @@ const InstallerForm = memo((): JSX.Element => {
         <form role="form" id="register-form" className="col-md-12" onSubmit={submitHandler}>
           <div className="dropdown mb-3">
             <div className="input-group">
-              <div className="input-group-prepend dropdown-with-icon">
+              <div className=" dropdown-with-icon">
                 <i className="input-group-text icon-bubbles border-0 rounded-0" />
               </div>
               <button
@@ -147,7 +147,7 @@ const InstallerForm = memo((): JSX.Element => {
           </div>
 
           <div className={`input-group mb-3${hasErrorClass}`}>
-            <div className="input-group-prepend">
+            <div>
               <span className="input-group-text"><i className="icon-user" /></span>
             </div>
             <input
@@ -163,7 +163,7 @@ const InstallerForm = memo((): JSX.Element => {
           <p className="form-text">{ unavailableUserId }</p>
 
           <div className="input-group mb-3">
-            <div className="input-group-prepend">
+            <div>
               <span className="input-group-text"><i className="icon-tag" /></span>
             </div>
             <input
@@ -177,7 +177,7 @@ const InstallerForm = memo((): JSX.Element => {
           </div>
 
           <div className="input-group mb-3">
-            <div className="input-group-prepend">
+            <div>
               <span className="input-group-text"><i className="icon-envelope" /></span>
             </div>
             <input
@@ -191,7 +191,7 @@ const InstallerForm = memo((): JSX.Element => {
           </div>
 
           <div className="input-group mb-3">
-            <div className="input-group-prepend">
+            <div>
               <span className="input-group-text"><i className="icon-lock" /></span>
             </div>
             <input

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

@@ -82,7 +82,7 @@ export const InvitedForm = (props: InvitedFormProps): JSX.Element => {
       <form role="form" onSubmit={submitHandler} id="invited-form">
         {/* Email Form */}
         <div className="input-group">
-          <div className="input-group-prepend">
+          <div>
             <span className="input-group-text">
               <i className="icon-envelope"></i>
             </span>
@@ -99,7 +99,7 @@ export const InvitedForm = (props: InvitedFormProps): JSX.Element => {
         </div>
         {/* UserID Form */}
         <div className="input-group" id="input-group-username">
-          <div className="input-group-prepend">
+          <div>
             <span className="input-group-text">
               <i className="icon-user"></i>
             </span>
@@ -115,7 +115,7 @@ export const InvitedForm = (props: InvitedFormProps): JSX.Element => {
         </div>
         {/* Name Form */}
         <div className="input-group">
-          <div className="input-group-prepend">
+          <div>
             <span className="input-group-text">
               <i className="icon-tag"></i>
             </span>
@@ -131,7 +131,7 @@ export const InvitedForm = (props: InvitedFormProps): JSX.Element => {
         </div>
         {/* Password Form */}
         <div className="input-group">
-          <div className="input-group-prepend">
+          <div>
             <span className="input-group-text">
               <i className="icon-lock"></i>
             </span>

+ 7 - 7
apps/app/src/components/LoginForm.tsx

@@ -195,7 +195,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
 
         <form role="form" onSubmit={handleLoginWithLocalSubmit} id="login-form">
           <div className="input-group">
-            <div className="input-group-prepend">
+            <div>
               <span className="input-group-text">
                 <i className="icon-user"></i>
               </span>
@@ -209,7 +209,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
               name="usernameForLogin"
             />
             {isLdapStrategySetup && (
-              <div className="input-group-append">
+              <div>
                 <small className="input-group-text text-success">
                   <i className="icon-fw icon-check"></i> LDAP
                 </small>
@@ -218,7 +218,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
           </div>
 
           <div className="input-group">
-            <div className="input-group-prepend">
+            <div>
               <span className="input-group-text">
                 <i className="icon-lock"></i>
               </span>
@@ -421,7 +421,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
           {!isEmailAuthenticationEnabled && (
             <div>
               <div className="input-group" id="input-group-username">
-                <div className="input-group-prepend">
+                <div>
                   <span className="input-group-text">
                     <i className="icon-user"></i>
                   </span>
@@ -441,7 +441,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
                 <span id="help-block-username"></span>
               </p>
               <div className="input-group">
-                <div className="input-group-prepend">
+                <div>
                   <span className="input-group-text">
                     <i className="icon-tag"></i>
                   </span>
@@ -461,7 +461,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
           )}
 
           <div className="input-group">
-            <div className="input-group-prepend">
+            <div>
               <span className="input-group-text">
                 <i className="icon-envelope"></i>
               </span>
@@ -497,7 +497,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
           {!isEmailAuthenticationEnabled && (
             <div>
               <div className="input-group">
-                <div className="input-group-prepend">
+                <div>
                   <span className="input-group-text">
                     <i className="icon-lock"></i>
                   </span>

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

@@ -33,7 +33,7 @@ const ApiSettings = React.memo((): JSX.Element => {
       <h2 className="border-bottom my-4">{ t('API Token Settings') }</h2>
 
       <div className="row mb-3">
-        <label htmlFor="apiToken" className="col-md-3 text-md-right">{t('Current API Token')}</label>
+        <label htmlFor="apiToken" className="col-md-3 text-md-end form-label">{t('Current API Token')}</label>
         <div className="col-md-6">
           {personalSettingsData?.apiToken != null
             ? (

+ 19 - 19
apps/app/src/components/Me/BasicInfoSettings.tsx

@@ -49,8 +49,8 @@ export const BasicInfoSettings = (): JSX.Element => {
   return (
     <>
 
-      <div className="form-group row">
-        <label htmlFor="userForm[name]" className="text-start text-md-right col-md-3 col-form-label">{t('Name')}</label>
+      <div className="row">
+        <label htmlFor="userForm[name]" className="text-start text-md-end col-md-3 col-form-label">{t('Name')}</label>
         <div className="col-md-6">
           <input
             className="form-control"
@@ -62,8 +62,8 @@ export const BasicInfoSettings = (): JSX.Element => {
         </div>
       </div>
 
-      <div className="form-group row">
-        <label htmlFor="userForm[email]" className="text-start text-md-right col-md-3 col-form-label">{t('Email')}</label>
+      <div className="row">
+        <label htmlFor="userForm[email]" className="text-start text-md-end col-md-3 col-form-label">{t('Email')}</label>
         <div className="col-md-6">
           <input
             className="form-control"
@@ -83,36 +83,36 @@ export const BasicInfoSettings = (): JSX.Element => {
         </div>
       </div>
 
-      <div className="form-group row">
-        <label className="text-start text-md-right col-md-3 col-form-label">{t('Disclose E-mail')}</label>
+      <div className="row">
+        <label className="text-start text-md-end col-md-3 col-form-label">{t('Disclose E-mail')}</label>
         <div className="col-md-6">
-          <div className="custom-control custom-radio custom-control-inline">
+          <div className="form-check form-check-inline">
             <input
               type="radio"
               id="radioEmailShow"
-              className="custom-control-input"
+              className="form-check-input"
               name="userForm[isEmailPublished]"
               checked={personalSettingsInfo?.isEmailPublished === true}
               onChange={() => changePersonalSettingsHandler({ isEmailPublished: true })}
             />
-            <label className="custom-control-label" htmlFor="radioEmailShow">{t('Show')}</label>
+            <label className="form-label form-check-label" htmlFor="radioEmailShow">{t('Show')}</label>
           </div>
-          <div className="custom-control custom-radio custom-control-inline">
+          <div className="form-check form-check-inline">
             <input
               type="radio"
               id="radioEmailHide"
-              className="custom-control-input"
+              className="form-check-input"
               name="userForm[isEmailPublished]"
               checked={personalSettingsInfo?.isEmailPublished === false}
               onChange={() => changePersonalSettingsHandler({ isEmailPublished: false })}
             />
-            <label className="custom-control-label" htmlFor="radioEmailHide">{t('Hide')}</label>
+            <label className="form-label form-check-label" htmlFor="radioEmailHide">{t('Hide')}</label>
           </div>
         </div>
       </div>
 
-      <div className="form-group row">
-        <label className="text-start text-md-right col-md-3 col-form-label">{t('Language')}</label>
+      <div className="row">
+        <label className="text-start text-md-end col-md-3 col-form-label">{t('Language')}</label>
         <div className="col-md-6">
           {
             i18nConfig.locales.map((locale) => {
@@ -120,24 +120,24 @@ export const BasicInfoSettings = (): JSX.Element => {
               const fixedT = i18n.getFixedT(locale);
 
               return (
-                <div key={locale} className="custom-control custom-radio custom-control-inline">
+                <div key={locale} className="form-check form-check-inline">
                   <input
                     type="radio"
                     id={`radioLang${locale}`}
-                    className="custom-control-input"
+                    className="form-check-input"
                     name="userForm[lang]"
                     checked={personalSettingsInfo?.lang === locale}
                     onChange={() => changePersonalSettingsHandler({ lang: locale })}
                   />
-                  <label className="custom-control-label" htmlFor={`radioLang${locale}`}>{fixedT('meta.display_name') as string}</label>
+                  <label className="form-label form-check-label" htmlFor={`radioLang${locale}`}>{fixedT('meta.display_name') as string}</label>
                 </div>
               );
             })
           }
         </div>
       </div>
-      <div className="form-group row">
-        <label htmlFor="userForm[slackMemberId]" className="text-start text-md-right col-md-3 col-form-label">{t('Slack Member ID')}</label>
+      <div className="row">
+        <label htmlFor="userForm[slackMemberId]" className="text-start text-md-end col-md-3 col-form-label">{t('Slack Member ID')}</label>
         <div className="col-md-6">
           <input
             className="form-control"

+ 4 - 4
apps/app/src/components/Me/InAppNotificationSettings.tsx

@@ -69,21 +69,21 @@ const InAppNotificationSettings: FC = () => {
     <>
       <h2 className="border-bottom my-4">{t('in_app_notification_settings.subscribe_settings')}</h2>
 
-      <div className="form-group row">
+      <div className="row">
         <div className="offset-md-3 col-md-6 text-start">
           {subscribeRulesMenuItems.map(rule => (
             <div
               key={rule.name}
-              className="custom-control custom-switch custom-checkbox-success"
+              className="form-check form-switch form-check-success"
             >
               <input
                 type="checkbox"
-                className="custom-control-input"
+                className="form-check-input"
                 id={rule.name}
                 checked={isCheckedRule(rule.name, subscribeRules)}
                 onChange={e => ruleCheckboxHandler(rule.name, e.target.checked)}
               />
-              <label className="custom-control-label" htmlFor={rule.name}>
+              <label className="form-label form-check-label" htmlFor={rule.name}>
                 <strong>{rule.name}</strong>
               </label>
               <p className="form-text text-muted small">

+ 4 - 4
apps/app/src/components/Me/OtherSettings.tsx

@@ -50,20 +50,20 @@ const OtherSettings = (): JSX.Element => {
         </div>
       )}
 
-      <div className="form-group row">
+      <div className="row">
         <div className="offset-md-3 col-md-6 text-start">
           {!isLoadingCurrentUser && (
-            <div className="custom-control custom-switch custom-checkbox-primary">
+            <div className="form-check form-switch form-check-primary">
               <span id="grw-questionnaire-settings-toggle-wrapper">
                 <input
                   type="checkbox"
-                  className="custom-control-input"
+                  className="form-check-input"
                   id="isQuestionnaireEnabled"
                   checked={growiIsQuestionnaireEnabled && isQuestionnaireEnabled}
                   onChange={onChangeIsQuestionnaireEnabledHandler}
                   disabled={!growiIsQuestionnaireEnabled}
                 />
-                <label className="custom-control-label" htmlFor="isQuestionnaireEnabled">
+                <label className="form-label form-check-label" htmlFor="isQuestionnaireEnabled">
                   {t('questionnaire.enable_questionnaire')}
                 </label>
               </span>

+ 3 - 3
apps/app/src/components/Me/PasswordSettings.jsx

@@ -92,7 +92,7 @@ class PasswordSettings extends React.Component {
         {(this.state.isPasswordSet)
         && (
           <div className="row mb-3">
-            <label htmlFor="oldPassword" className="col-md-3 text-md-right">{ t('personal_settings.current_password') }</label>
+            <label htmlFor="oldPassword" className="col-md-3 text-md-end form-label">{ t('personal_settings.current_password') }</label>
             <div className="col-md-5">
               <input
                 className="form-control"
@@ -105,7 +105,7 @@ class PasswordSettings extends React.Component {
           </div>
         )}
         <div className="row mb-3">
-          <label htmlFor="newPassword" className="col-md-3 text-md-right">{t('personal_settings.new_password') }</label>
+          <label htmlFor="newPassword" className="col-md-3 text-md-end form-label">{t('personal_settings.new_password') }</label>
           <div className="col-md-5">
             {/* to prevent autocomplete username into userForm[email] in BasicInfoSettings component */}
             {/* https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion */}
@@ -120,7 +120,7 @@ class PasswordSettings extends React.Component {
           </div>
         </div>
         <div className={`row mb-3 ${isIncorrectConfirmPassword && 'has-error'}`}>
-          <label htmlFor="newPasswordConfirm" className="col-md-3 text-md-right">{t('personal_settings.new_password_confirm') }</label>
+          <label htmlFor="newPasswordConfirm" className="col-md-3 text-md-end form-label">{t('personal_settings.new_password_confirm') }</label>
           <div className="col-md-5">
             <input
               className="form-control"

+ 6 - 6
apps/app/src/components/Me/ProfileImageSettings.tsx

@@ -94,17 +94,17 @@ const ProfileImageSettings = (): JSX.Element => {
       <div className="row">
         <div className="col-md-6 col-12 mb-3 mb-md-0">
           <h4>
-            <div className="custom-control custom-radio radio-primary">
+            <div className="form-check radio-primary">
               <input
                 type="radio"
                 id="radioGravatar"
-                className="custom-control-input"
+                className="form-check-input"
                 form="formImageType"
                 name="imagetypeForm[isGravatarEnabled]"
                 checked={isGravatarEnabled}
                 onChange={() => setGravatarEnabled(true)}
               />
-              <label className="custom-control-label" htmlFor="radioGravatar">
+              <label className="form-label form-check-label" htmlFor="radioGravatar">
                 <img src={GRAVATAR_DEFAULT} data-vrt-blackout-profile /> Gravatar
               </label>
               <a href="https://gravatar.com/">
@@ -117,17 +117,17 @@ const ProfileImageSettings = (): JSX.Element => {
 
         <div className="col-md-6 col-12">
           <h4>
-            <div className="custom-control custom-radio radio-primary">
+            <div className="form-check radio-primary">
               <input
                 type="radio"
                 id="radioUploadPicture"
-                className="custom-control-input"
+                className="form-check-input"
                 form="formImageType"
                 name="imagetypeForm[isGravatarEnabled]"
                 checked={!isGravatarEnabled}
                 onChange={() => setGravatarEnabled(false)}
               />
-              <label className="custom-control-label" htmlFor="radioUploadPicture">
+              <label className="form-label form-check-label" htmlFor="radioUploadPicture">
                 { t('Upload Image') }
               </label>
             </div>

+ 0 - 6
apps/app/src/components/Navbar/GlobalSearch.module.scss

@@ -33,12 +33,6 @@
     }
   }
 
-  .form-group:not(.has-error) {
-    .rbt-input.form-control {
-      border: none;
-    }
-  }
-
   .grw-shortcut-key-indicator {
     position: absolute;
     top: 0;

+ 2 - 2
apps/app/src/components/Navbar/GlobalSearch.tsx

@@ -88,9 +88,9 @@ export const GlobalSearch = (props: GlobalSearchProps): JSX.Element => {
   }
 
   return (
-    <div className={`grw-global-search ${styles['grw-global-search']} form-group mb-0 d-print-none ${isSearchServiceReachable ? '' : 'has-error'}`}>
+    <div className={`grw-global-search ${styles['grw-global-search']} mb-0 d-print-none ${isSearchServiceReachable ? '' : 'has-error'}`}>
       <div className="input-group flex-nowrap">
-        <div className={`input-group-prepend ${dropup ? 'dropup' : ''}`}>
+        <div className={` ${dropup ? 'dropup' : ''}`}>
           <button
             className="btn btn-secondary dropdown-toggle py-0"
             type="button"

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

@@ -45,15 +45,15 @@ const WideViewMenuItem = (props: WideViewMenuItemProps): JSX.Element => {
       onClick={() => onClickMenuItem(!(expandContentWidth))}
       className="grw-page-control-dropdown-item"
     >
-      <div className="custom-control custom-switch ms-1">
+      <div className="form-check form-switch ms-1">
         <input
           id="switchContentWidth"
-          className="custom-control-input"
+          className="form-check-input"
           type="checkbox"
           checked={expandContentWidth}
           onChange={() => {}}
         />
-        <label className="custom-control-label" htmlFor="switchContentWidth">
+        <label className="form-label form-check-label" htmlFor="switchContentWidth">
           { t('wide_view') }
         </label>
       </div>

+ 3 - 3
apps/app/src/components/Page/CopyDropdown.jsx

@@ -127,15 +127,15 @@ const CopyDropdown = (props) => {
               { t('copy_to_clipboard.Copy to clipboard') }
             </DropdownItem>
             { !isShareLinkMode && (
-              <div className="px-3 custom-control custom-switch custom-switch-sm">
+              <div className="px-3 form-check form-switch form-switch-sm">
                 <input
                   type="checkbox"
                   id={customSwitchForParamsId}
-                  className="custom-control-input"
+                  className="form-check-input"
                   checked={isParamsAppended}
                   onChange={toggleAppendParams}
                 />
-                <label className="custom-control-label small" htmlFor={customSwitchForParamsId}>Append params</label>
+                <label className="form-label form-check-label small" htmlFor={customSwitchForParamsId}>Append params</label>
               </div>
             ) }
           </div>

+ 11 - 11
apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLinkForm.tsx

@@ -106,34 +106,34 @@ export const ShareLinkForm: FC<Props> = (props: Props) => {
       <div className=" p-3">
 
         {/* ExpirationTypeOptions */}
-        <div className="form-group row">
+        <div className="row">
           <label htmlFor="inputDesc" className="col-md-5 col-form-label">{t('share_links.expire')}</label>
           <div className="col-md-7">
 
-            <div className="custom-control custom-radio form-group ">
+            <div className="form-check">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id="customRadio1"
                 name="expirationType"
                 value="customRadio1"
                 checked={expirationType === ExpirationType.UNLIMITED}
                 onChange={() => { handleChangeExpirationType(ExpirationType.UNLIMITED) }}
               />
-              <label className="custom-control-label" htmlFor="customRadio1">{t('share_links.Unlimited')}</label>
+              <label className="form-label form-check-label" htmlFor="customRadio1">{t('share_links.Unlimited')}</label>
             </div>
 
-            <div className="custom-control custom-radio  form-group">
+            <div className="form-check">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id="customRadio2"
                 value="customRadio2"
                 checked={expirationType === ExpirationType.NUMBER_OF_DAYS}
                 onChange={() => { handleChangeExpirationType(ExpirationType.NUMBER_OF_DAYS) }}
                 name="expirationType"
               />
-              <label className="custom-control-label" htmlFor="customRadio2">
+              <label className="form-label form-check-label" htmlFor="customRadio2">
                 <div className="row align-items-center m-0">
                   <input
                     type="number"
@@ -149,17 +149,17 @@ export const ShareLinkForm: FC<Props> = (props: Props) => {
               </label>
             </div>
 
-            <div className="custom-control custom-radio form-group text-nowrap mb-0">
+            <div className="form-check text-nowrap mb-0">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id="customRadio3"
                 name="expirationType"
                 value="customRadio3"
                 checked={expirationType === ExpirationType.CUSTOM}
                 onChange={() => { handleChangeExpirationType(ExpirationType.CUSTOM) }}
               />
-              <label className="custom-control-label" htmlFor="customRadio3">
+              <label className="form-label form-check-label" htmlFor="customRadio3">
                 {t('share_links.Custom')}
               </label>
               <div className="d-inline-flex flex-wrap">
@@ -185,7 +185,7 @@ export const ShareLinkForm: FC<Props> = (props: Props) => {
         </div>
 
         {/* DescriptionForm */}
-        <div className="form-group row">
+        <div className="row">
           <label htmlFor="inputDesc" className="col-md-5 col-form-label">{t('share_links.description')}</label>
           <div className="col-md-4">
             <input

+ 10 - 10
apps/app/src/components/PageAlert/FixPageGrantAlert.tsx

@@ -125,7 +125,7 @@ const FixPageGrantModal = (props: ModalProps): JSX.Element => {
     return (
       <>
         <ModalBody>
-          <div className="form-group">
+          <div>
             {/* eslint-disable-next-line react/no-danger */}
             <p className="mb-2" dangerouslySetInnerHTML={{ __html: t('fix_page_grant.modal.need_to_fix_grant') }} />
 
@@ -133,9 +133,9 @@ const FixPageGrantModal = (props: ModalProps): JSX.Element => {
             {renderGrantDataLabel()}
 
             <div className="ms-2">
-              <div className="custom-control custom-radio mb-3">
+              <div className="form-check mb-3">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="grantRestricted"
                   id="grantRestricted"
                   type="radio"
@@ -143,13 +143,13 @@ const FixPageGrantModal = (props: ModalProps): JSX.Element => {
                   checked={selectedGrant === PageGrant.GRANT_RESTRICTED}
                   onChange={() => setSelectedGrant(PageGrant.GRANT_RESTRICTED)}
                 />
-                <label className="custom-control-label" htmlFor="grantRestricted">
+                <label className="form-label form-check-label" htmlFor="grantRestricted">
                   { t('fix_page_grant.modal.radio_btn.restrected') }
                 </label>
               </div>
-              <div className="custom-control custom-radio mb-3">
+              <div className="form-check mb-3">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="grantUser"
                   id="grantUser"
                   type="radio"
@@ -157,13 +157,13 @@ const FixPageGrantModal = (props: ModalProps): JSX.Element => {
                   checked={selectedGrant === PageGrant.GRANT_OWNER}
                   onChange={() => setSelectedGrant(PageGrant.GRANT_OWNER)}
                 />
-                <label className="custom-control-label" htmlFor="grantUser">
+                <label className="form-label form-check-label" htmlFor="grantUser">
                   { t('fix_page_grant.modal.radio_btn.only_me') }
                 </label>
               </div>
-              <div className="custom-control custom-radio d-flex mb-3">
+              <div className="form-check d-flex mb-3">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="grantUserGroup"
                   id="grantUserGroup"
                   type="radio"
@@ -171,7 +171,7 @@ const FixPageGrantModal = (props: ModalProps): JSX.Element => {
                   checked={selectedGrant === PageGrant.GRANT_USER_GROUP}
                   onChange={() => setSelectedGrant(PageGrant.GRANT_USER_GROUP)}
                 />
-                <label className="custom-control-label" htmlFor="grantUserGroup">
+                <label className="form-label form-check-label" htmlFor="grantUserGroup">
                   { t('fix_page_grant.modal.radio_btn.grant_group') }
                 </label>
                 <div className="dropdown ms-2">

+ 1 - 1
apps/app/src/components/PageComment/CommentEditor.tsx

@@ -335,7 +335,7 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
 
             {isSlackConfigured && isSlackEnabled != null
               && (
-                <div className="form-inline align-self-center me-md-2">
+                <div className="align-self-center me-md-2">
                   <SlackNotification
                     isSlackEnabled={isSlackEnabled}
                     slackChannels={slackChannels}

+ 8 - 8
apps/app/src/components/PageDeleteModal.tsx

@@ -182,16 +182,16 @@ const PageDeleteModal: FC = () => {
 
   function renderDeleteRecursivelyForm() {
     return (
-      <div className="custom-control custom-checkbox custom-checkbox-warning">
+      <div className="form-check form-check-warning">
         <input
-          className="custom-control-input"
+          className="form-check-input"
           id="deleteRecursively"
           type="checkbox"
           checked={isDeleteRecursively}
           onChange={changeIsDeleteRecursivelyHandler}
           // disabled // Todo: enable this at https://redmine.weseek.co.jp/issues/82222
         />
-        <label className="custom-control-label" htmlFor="deleteRecursively">
+        <label className="form-label form-check-label" htmlFor="deleteRecursively">
           { t('modal_delete.delete_recursively') }
           <p className="form-text text-muted mt-0"> { t('modal_delete.recursively') }</p>
         </label>
@@ -201,9 +201,9 @@ const PageDeleteModal: FC = () => {
 
   function renderDeleteCompletelyForm() {
     return (
-      <div className="custom-control custom-checkbox custom-checkbox-danger">
+      <div className="form-check form-check-danger">
         <input
-          className="custom-control-input"
+          className="form-check-input"
           name="completely"
           id="deleteCompletely"
           type="checkbox"
@@ -211,7 +211,7 @@ const PageDeleteModal: FC = () => {
           checked={isDeleteCompletely}
           onChange={changeIsDeleteCompletelyHandler}
         />
-        <label className="custom-control-label" htmlFor="deleteCompletely">
+        <label className="form-label form-check-label" htmlFor="deleteCompletely">
           { t('modal_delete.delete_completely')}
           <p className="form-text text-muted mt-0"> { t('modal_delete.completely') }</p>
         </label>
@@ -259,8 +259,8 @@ const PageDeleteModal: FC = () => {
 
     return (
       <>
-        <div className="form-group grw-scrollable-modal-body pb-1">
-          <label>{ t('modal_delete.deleting_page') }:</label><br />
+        <div className="grw-scrollable-modal-body pb-1">
+          <label className="form-label">{ t('modal_delete.deleting_page') }:</label><br />
           {/* Todo: change the way to show path on modal when too many pages are selected */}
           {renderPagePathsToDelete()}
         </div>

+ 10 - 10
apps/app/src/components/PageDuplicateModal.tsx

@@ -157,13 +157,13 @@ const PageDuplicateModal = (): JSX.Element => {
 
     return (
       <>
-        <div className="form-group"><label>{t('modal_duplicate.label.Current page name')}</label><br />
+        <div><label className="form-label">{t('modal_duplicate.label.Current page name')}</label><br />
           <code>{path}</code>
         </div>
-        <div className="form-group">
-          <label htmlFor="duplicatePageName">{ t('modal_duplicate.label.New page name') }</label><br />
+        <div>
+          <label className="form-label" htmlFor="duplicatePageName">{ t('modal_duplicate.label.New page name') }</label><br />
           <div className="input-group">
-            <div className="input-group-prepend">
+            <div>
               <span className="input-group-text">{siteUrl}</span>
             </div>
             <div className="flex-fill">
@@ -193,32 +193,32 @@ const PageDuplicateModal = (): JSX.Element => {
           <p className="text-danger">Error: Target path is duplicated.</p>
         ) }
 
-        <div className="custom-control custom-checkbox custom-checkbox-warning mb-3">
+        <div className="form-check form-check-warning mb-3">
           <input
-            className="custom-control-input"
+            className="form-check-input"
             name="recursively"
             id="cbDuplicateRecursively"
             type="checkbox"
             checked={isDuplicateRecursively}
             onChange={changeIsDuplicateRecursivelyHandler}
           />
-          <label className="custom-control-label" htmlFor="cbDuplicateRecursively">
+          <label className="form-label form-check-label" htmlFor="cbDuplicateRecursively">
             { t('modal_duplicate.label.Recursively') }
             <p className="form-text text-muted mt-0">{ t('modal_duplicate.help.recursive') }</p>
           </label>
 
           <div>
             {isDuplicateRecursively && existingPaths.length !== 0 && (
-              <div className="custom-control custom-checkbox custom-checkbox-warning">
+              <div className="form-check form-check-warning">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   name="withoutExistRecursively"
                   id="cbDuplicatewithoutExistRecursively"
                   type="checkbox"
                   checked={isDuplicateRecursivelyWithoutExistPath}
                   onChange={() => setIsDuplicateRecursivelyWithoutExistPath(!isDuplicateRecursivelyWithoutExistPath)}
                 />
-                <label className="custom-control-label" htmlFor="cbDuplicatewithoutExistRecursively">
+                <label className="form-label form-check-label" htmlFor="cbDuplicatewithoutExistRecursively">
                   { t('modal_duplicate.label.Duplicate without exist path') }
                 </label>
               </div>

+ 3 - 3
apps/app/src/components/PageEditor/EditorNavbarBottom.tsx

@@ -101,11 +101,11 @@ const EditorNavbarBottom = (): JSX.Element => {
       )
       }
       <div className={`flex-expand-horiz align-items-center border-top px-2 px-md-3 ${additionalClasses.join(' ')}`}>
-        <form className="form-inline">
+        <form>
           { isDeviceSmallerThanMd && renderDrawerButton() }
           { isOptionsSelectorEnabled && !isDeviceSmallerThanMd && <OptionsSelector /> }
         </form>
-        <form className="form-inline flex-nowrap ms-auto">
+        <form className="flex-nowrap ms-auto">
           {/* Responsive Design for the SlackNotification */}
           {/* Button or the normal Slack banner */}
           {isSlackConfigured && (isDeviceSmallerThanMd ? (
@@ -141,7 +141,7 @@ const EditorNavbarBottom = (): JSX.Element => {
         <Collapse isOpen={isExpanded}>
           <div className="px-2"> {/* set padding for border-top */}
             <div className={`navbar navbar-expand border-top px-0 ${additionalClasses.join(' ')}`}>
-              <form className="form-inline ms-auto">
+              <form className="ms-auto">
                 <OptionsSelector />
               </form>
             </div>

+ 8 - 8
apps/app/src/components/PageEditor/GridEditModal.jsx

@@ -92,16 +92,16 @@ class GridEditModal extends React.Component {
     const { t } = this.props;
     const output = Object.entries(resSizeObj).map((responsiveSizeForMap) => {
       return (
-        <div key={responsiveSizeForMap[0]} className="custom-control custom-radio custom-control-inline">
+        <div key={responsiveSizeForMap[0]} className="form-check form-check-inline">
           <input
             type="radio"
-            className="custom-control-input"
+            className="form-check-input"
             id={responsiveSizeForMap[1].displayText}
             value={responsiveSizeForMap[1].displayText}
             checked={this.state.responsiveSize === responsiveSizeForMap[0]}
             onChange={e => this.checkResposiveSize(responsiveSizeForMap[0])}
           />
-          <label className="custom-control-label" htmlFor={responsiveSizeForMap[1].displayText}>
+          <label className="form-label form-check-label" htmlFor={responsiveSizeForMap[1].displayText}>
             {t(responsiveSizeForMap[1].displayText)}
           </label>
         </div>
@@ -198,9 +198,9 @@ class GridEditModal extends React.Component {
           <div className="row">
             <div className="col-12">
               <h3 className="grw-modal-head">{t('grid_edit.grid_settings')}</h3>
-              <form className="form-group mb-0">
-                <div className="form-group row my-3">
-                  <label className="col-sm-3" htmlFor="gridPattern">
+              <form className="mb-0">
+                <div className="row my-3">
+                  <label className="form-label col-sm-3" htmlFor="gridPattern">
                     {t('grid_edit.grid_pattern')}
                   </label>
                   <div className="col-sm-9">
@@ -219,8 +219,8 @@ class GridEditModal extends React.Component {
                     </div>
                   </div>
                 </div>
-                <div className="form-group row">
-                  <label className="col-sm-3" htmlFor="breakPoint">
+                <div className="row">
+                  <label className="form-label col-sm-3" htmlFor="breakPoint">
                     {t('grid_edit.break_point')}
                   </label>
                   <div className="col-sm-9">

+ 13 - 13
apps/app/src/components/PageEditor/LinkEditModal.tsx

@@ -242,10 +242,10 @@ export const LinkEditModal = (): JSX.Element => {
     return (
       <>
         <h3 className="grw-modal-head">{t('link_edit.set_link_and_label')}</h3>
-        <form className="form-group">
+        <form>
           <div className="form-gorup my-3">
             <div className="input-group flex-nowrap">
-              <div className="input-group-prepend">
+              <div>
                 <span className="input-group-text">{t('link_edit.link')}</span>
               </div>
               <SearchTypeahead
@@ -255,7 +255,7 @@ export const LinkEditModal = (): JSX.Element => {
                 keywordOnInit={linkInputValue}
                 autoFocus
               />
-              <div className="d-none d-sm-block input-group-append">
+              <div className="d-none d-sm-block">
                 <button type="button" id="preview-btn" className={`btn btn-info btn-page-preview ${styles['btn-page-preview']}`}>
                   <PagePreviewIcon />
                 </button>
@@ -275,7 +275,7 @@ export const LinkEditModal = (): JSX.Element => {
           </div>
           <div className="form-gorup my-3">
             <div className="input-group flex-nowrap">
-              <div className="input-group-prepend">
+              <div>
                 <span className="input-group-text">{t('link_edit.label')}</span>
               </div>
               <input
@@ -297,33 +297,33 @@ export const LinkEditModal = (): JSX.Element => {
   const renderPathFormatForm = (): JSX.Element => {
     return (
       <div className="card well pt-3">
-        <form className="form-group mb-0">
-          <div className="form-group mb-0 row">
-            <label className="col-sm-3">{t('link_edit.path_format')}</label>
+        <form className="mb-0">
+          <div className="mb-0 row">
+            <label className="form-label col-sm-3">{t('link_edit.path_format')}</label>
             <div className="col-sm-9">
-              <div className="custom-control custom-checkbox custom-checkbox-info custom-control-inline">
+              <div className="form-check form-check-info form-check-inline">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   id="relativePath"
                   type="checkbox"
                   checked={isUseRelativePath}
                   onChange={toggleIsUseRelativePath}
                   disabled={!linkInputValue.startsWith('/') || linkerType === Linker.types.growiLink}
                 />
-                <label className="custom-control-label" htmlFor="relativePath">
+                <label className="form-label form-check-label" htmlFor="relativePath">
                   {t('link_edit.use_relative_path')}
                 </label>
               </div>
-              <div className="custom-control custom-checkbox custom-checkbox-info custom-control-inline">
+              <div className="form-check form-check-info form-check-inline">
                 <input
-                  className="custom-control-input"
+                  className="form-check-input"
                   id="permanentLink"
                   type="checkbox"
                   checked={isUsePermanentLink}
                   onChange={toggleIsUsePamanentLink}
                   disabled={permalink === '' || linkerType === Linker.types.growiLink}
                 />
-                <label className="custom-control-label" htmlFor="permanentLink">
+                <label className="form-label form-check-label" htmlFor="permanentLink">
                   {t('link_edit.use_permanent_link')}
                 </label>
               </div>

+ 6 - 6
apps/app/src/components/PageEditor/MarkdownTableDataImportForm.tsx

@@ -52,8 +52,8 @@ export const MarkdownTableDataImportForm = (props: MarkdownTableDataImportFormPr
 
   return (
     <form className="data-import-form">
-      <div className="form-group">
-        <label htmlFor="data-import-form-type-select">{t('select_data_format')}</label>
+      <div>
+        <label htmlFor="data-import-form-type-select" className="form-label">{t('select_data_format')}</label>
         <select
           id="data-import-form-type-select"
           className="form-control"
@@ -66,8 +66,8 @@ export const MarkdownTableDataImportForm = (props: MarkdownTableDataImportFormPr
           <option value="html">HTML</option>
         </select>
       </div>
-      <div className="form-group">
-        <label htmlFor="data-import-form-type-textarea">{t('import_data')}</label>
+      <div>
+        <label htmlFor="data-import-form-type-textarea" className="form-label">{t('import_data')}</label>
         <textarea
           id="data-import-form-type-textarea"
           className="form-control"
@@ -77,8 +77,8 @@ export const MarkdownTableDataImportForm = (props: MarkdownTableDataImportFormPr
         />
       </div>
       <Collapse isOpen={parserErrorMessage != null}>
-        <div className="form-group">
-          <label htmlFor="data-import-form-type-textarea-alert">{t('parse_error')}</label>
+        <div>
+          <label htmlFor="data-import-form-type-textarea-alert" className="form-label">{t('parse_error')}</label>
           <textarea
             id="data-import-form-type-textarea-alert"
             className="form-control"

+ 7 - 7
apps/app/src/components/PageEditor/OptionsSelector.tsx

@@ -36,10 +36,10 @@ const ThemeSelector = (): JSX.Element => {
 
   return (
     <div className="input-group flex-nowrap">
-      <div className="input-group-prepend">
+      <div>
         <span className="input-group-text" id="igt-theme">Theme</span>
       </div>
-      <div className="input-group-append dropup">
+      <div className="dropup">
         <button
           type="button"
           className="btn btn-outline-secondary dropdown-toggle"
@@ -91,10 +91,10 @@ const KeymapSelector = memo((): JSX.Element => {
 
   return (
     <div className="input-group flex-nowrap">
-      <div className="input-group-prepend">
+      <div>
         <span className="input-group-text" id="igt-keymap">Keymap</span>
       </div>
-      <div className="input-group-append dropup">
+      <div className="dropup">
         <button
           type="button"
           className="btn btn-outline-secondary dropdown-toggle"
@@ -133,10 +133,10 @@ const IndentSizeSelector = memo(({ isIndentSizeForced, selectedIndentSize, onCha
 
   return (
     <div className="input-group flex-nowrap">
-      <div className="input-group-prepend">
+      <div>
         <span className="input-group-text" id="igt-indent">Indent</span>
       </div>
-      <div className="input-group-append dropup">
+      <div className="dropup">
         <button
           type="button"
           className="btn btn-outline-secondary dropdown-toggle"
@@ -216,7 +216,7 @@ const ConfigurationDropdown = memo((): JSX.Element => {
   }, [editorSettings, t, update]);
 
   return (
-    <div className="my-0 form-group">
+    <div className="my-0">
       <Dropdown
         direction="up"
         className="grw-editor-configuration-dropdown"

+ 49 - 59
apps/app/src/components/PageEditor/PageEditor.tsx

@@ -5,10 +5,9 @@ import React, {
 import EventEmitter from 'events';
 import nodePath from 'path';
 
-
 import type { IPageHasId } from '@growi/core';
 import { pathUtils } from '@growi/core/dist/utils';
-import { CodeMirrorEditorContainer, useCodeMirrorEditorMain } from '@growi/editor';
+import { CodeMirrorEditorMain, GlobalCodeMirrorEditorKey, useCodeMirrorEditorIsolated } from '@growi/editor';
 import detectIndent from 'detect-indent';
 import { useTranslation } from 'next-i18next';
 import { useRouter } from 'next/router';
@@ -17,7 +16,6 @@ import { throttle, debounce } from 'throttle-debounce';
 import { useUpdateStateAfterSave, useSaveOrUpdate } from '~/client/services/page-operation';
 import { apiGet, apiPostForm } from '~/client/util/apiv1-client';
 import { toastError, toastSuccess } from '~/client/util/toastr';
-import { IEditorMethods } from '~/interfaces/editor-methods';
 import { OptionsToSave } from '~/interfaces/page-operation';
 import { SocketEventName } from '~/interfaces/websocket';
 import {
@@ -57,7 +55,6 @@ import loggerFactory from '~/utils/logger';
 import Preview from './Preview';
 import scrollSyncHelper from './ScrollSyncHelper';
 
-
 import '@growi/editor/dist/style.css';
 
 
@@ -115,15 +112,16 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   const { mutate: mutateRemoteRevisionLastUpdatedAt } = useRemoteRevisionLastUpdatedAt();
   const { mutate: mutateRemoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdateUser();
 
-  const { data: codemirrorEditor } = useCodeMirrorEditorMain(codeMirrorEditorContainerRef.current);
-  const { initDoc, focus: focusToEditor, setCaretLine } = codemirrorEditor ?? {};
+  const { data: socket } = useGlobalSocket();
 
   const { data: rendererOptions } = usePreviewOptions();
   const { mutate: mutateIsEnabledUnsavedWarning } = useIsEnabledUnsavedWarning();
-  const saveOrUpdate = useSaveOrUpdate();
+  const { mutate: mutateIsConflict } = useIsConflict();
 
+  const saveOrUpdate = useSaveOrUpdate();
   const updateStateAfterSave = useUpdateStateAfterSave(pageId, { supressEditingMarkdownMutation: true });
 
+
   // TODO: remove workaround
   // for https://redmine.weseek.co.jp/issues/125923
   const [createdPageRevisionIdWithAttachment, setCreatedPageRevisionIdWithAttachment] = useState();
@@ -132,6 +130,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   // for https://redmine.weseek.co.jp/issues/125923
   const currentRevisionId = currentPage?.revision?._id ?? createdPageRevisionIdWithAttachment;
 
+  const initialValueRef = useRef('');
   const initialValue = useMemo(() => {
     if (!isNotFound) {
       return editingMarkdown ?? '';
@@ -145,15 +144,33 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     if (templateBodyData != null) {
       initialValue += `${templateBodyData}\n`;
     }
+
     return initialValue;
 
   }, [isNotFound, currentPathname, editingMarkdown, isEnabledAttachTitleHeader, templateBodyData]);
 
+  useEffect(() => {
+    // set to ref
+    initialValueRef.current = initialValue;
+  }, [initialValue]);
+
+
   const [markdownToPreview, setMarkdownToPreview] = useState<string>(initialValue);
+  const setMarkdownPreviewWithDebounce = useMemo(() => debounce(100, throttle(150, (value: string) => {
+    setMarkdownToPreview(value);
+  })), []);
+  const mutateIsEnabledUnsavedWarningWithDebounce = useMemo(() => debounce(600, throttle(900, (value: string) => {
+    // Displays an unsaved warning alert
+    mutateIsEnabledUnsavedWarning(value !== initialValueRef.current);
+  })), [mutateIsEnabledUnsavedWarning]);
 
-  const { data: socket } = useGlobalSocket();
+  const markdownChangedHandler = useCallback((value: string) => {
+    setMarkdownPreviewWithDebounce(value);
+    mutateIsEnabledUnsavedWarningWithDebounce(value);
+  }, [mutateIsEnabledUnsavedWarningWithDebounce, setMarkdownPreviewWithDebounce]);
 
-  const { mutate: mutateIsConflict } = useIsConflict();
+
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
 
 
   const checkIsConflict = useCallback((data) => {
@@ -197,17 +214,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     return optionsToSave;
   }, [grantData, isSlackEnabled, pageTags]);
 
-  const setMarkdownWithDebounce = useMemo(() => debounce(100, throttle(150, (value: string, isClean: boolean) => {
-    setMarkdownToPreview(value);
-
-    // Displays an unsaved warning alert
-    mutateIsEnabledUnsavedWarning(!isClean);
-  })), [mutateIsEnabledUnsavedWarning]);
-
-
-  const markdownChangedHandler = useCallback((value: string, isClean: boolean): void => {
-    setMarkdownWithDebounce(value, isClean);
-  }, [setMarkdownWithDebounce]);
 
   const save = useCallback(async(opts?: {slackChannels: string, overwriteScopesOfDescendants?: boolean}): Promise<IPageHasId | null> => {
     if (currentPathname == null || optionsToSave == null) {
@@ -221,10 +227,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
       mutateWaitingSaveProcessing(true);
 
       const { page } = await saveOrUpdate(
-        // TODO: get contents from the custom hook
-        // refs: https://redmine.weseek.co.jp/issues/128973
-        // markdownToSave.current,
-        '',
+        codeMirrorEditor?.getDoc() ?? '',
         { pageId, path: currentPagePath || currentPathname, revisionId: currentRevisionId },
         options,
       );
@@ -250,16 +253,13 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     }
 
   }, [
+    codeMirrorEditor,
     currentPathname, optionsToSave, grantData, isSlackEnabled, saveOrUpdate, pageId,
     currentPagePath, currentRevisionId,
     mutateWaitingSaveProcessing, mutateRemotePageId, mutateRemoteRevisionId, mutateRemoteRevisionLastUpdatedAt, mutateRemoteRevisionLastUpdateUser,
   ]);
 
   const saveAndReturnToViewHandler = useCallback(async(opts: {slackChannels: string, overwriteScopesOfDescendants?: boolean}) => {
-    if (editorMode !== EditorMode.Editor) {
-      return;
-    }
-
     const page = await save(opts);
     if (page == null) {
       return;
@@ -272,13 +272,9 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
       updateStateAfterSave?.();
     }
     mutateEditorMode(EditorMode.View);
-  }, [editorMode, save, isNotFound, mutateEditorMode, router, updateStateAfterSave]);
+  }, [save, isNotFound, mutateEditorMode, router, updateStateAfterSave]);
 
   const saveWithShortcut = useCallback(async() => {
-    if (editorMode !== EditorMode.Editor) {
-      return;
-    }
-
     const page = await save();
     if (page == null) {
       return;
@@ -293,7 +289,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     toastSuccess(t('toaster.save_succeeded'));
     mutateEditorMode(EditorMode.Editor);
 
-  }, [editorMode, isNotFound, mutateEditorMode, router, save, t, updateStateAfterSave]);
+  }, [isNotFound, mutateEditorMode, router, save, t, updateStateAfterSave]);
 
 
   /**
@@ -301,12 +297,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
    * @param {any} file
    */
   const uploadHandler = useCallback(async(file) => {
-    // TODO: implement
-    // refs: https://redmine.weseek.co.jp/issues/126528
-    // if (editorRef.current == null) {
-    //   return;
-    // }
-
     try {
       // eslint-disable-next-line @typescript-eslint/no-explicit-any
       let res: any = await apiGet('/attachments.limit', {
@@ -326,11 +316,9 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
       if (pageId != null) {
         formData.append('page_id', pageId);
       }
-      // TODO: get contents from the custom hook
-      // refs: https://redmine.weseek.co.jp/issues/128973
-      // if (pageId == null && markdownToSave.current != null) {
-      //   formData.append('page_body', markdownToSave.current);
-      // }
+      if (pageId == null) {
+        formData.append('page_body', codeMirrorEditor?.getDoc() ?? '');
+      }
 
       res = await apiPostForm('/attachments.add', formData);
       const attachment = res.attachment;
@@ -366,7 +354,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
       // refs: https://redmine.weseek.co.jp/issues/126528
       // editorRef.current.terminateUploadingState();
     }
-  }, [currentPagePath, mutateCurrentPage, mutateCurrentPageId, mutateIsLatestRevision, pageId]);
+  }, [codeMirrorEditor, currentPagePath, mutateCurrentPage, mutateCurrentPageId, mutateIsLatestRevision, pageId]);
 
 
   const scrollPreviewByEditorLine = useCallback((line: number) => {
@@ -484,21 +472,20 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     if (initialValue == null) {
       return;
     }
-    // markdownToSave.current = initialValue;
-    initDoc?.(initialValue);
+    codeMirrorEditor?.initDoc(initialValue);
     setMarkdownToPreview(initialValue);
     mutateIsEnabledUnsavedWarning(false);
-  }, [initDoc, initialValue, mutateIsEnabledUnsavedWarning]);
+  }, [codeMirrorEditor, initialValue, mutateIsEnabledUnsavedWarning]);
 
   // initial caret line
   useEffect(() => {
-    setCaretLine?.();
-  }, [setCaretLine]);
+    codeMirrorEditor?.setCaretLine();
+  }, [codeMirrorEditor]);
 
   // set handler to set caret line
   useEffect(() => {
     const handler = (line) => {
-      setCaretLine?.(line);
+      codeMirrorEditor?.setCaretLine(line);
 
       if (previewRef.current != null) {
         scrollSyncHelper.scrollPreview(previewRef.current, line);
@@ -509,7 +496,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     return function cleanup() {
       globalEmitter.removeListener('setCaretLine', handler);
     };
-  }, [setCaretLine]);
+  }, [codeMirrorEditor]);
 
   // set handler to save and return to View
   useEffect(() => {
@@ -523,9 +510,9 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   // set handler to focus
   useLayoutEffect(() => {
     if (editorMode === EditorMode.Editor) {
-      focusToEditor?.();
+      codeMirrorEditor?.focus();
     }
-  }, [editorMode, focusToEditor]);
+  }, [codeMirrorEditor, editorMode]);
 
   // Detect indent size from contents (only when users are allowed to change it)
   useEffect(() => {
@@ -546,9 +533,9 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   // when transitioning to a different page, if the initialValue is the same,
   // UnControlled CodeMirror value does not reset, so explicitly set the value to initialValue
   const onRouterChangeComplete = useCallback(() => {
-    initDoc?.(initialValue);
-    setCaretLine?.();
-  }, [initDoc, initialValue, setCaretLine]);
+    codeMirrorEditor?.initDoc(initialValue);
+    codeMirrorEditor?.setCaretLine();
+  }, [codeMirrorEditor, initialValue]);
 
   useEffect(() => {
     router.events.on('routeChangeComplete', onRouterChangeComplete);
@@ -582,7 +569,10 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
           onUpload={uploadHandler}
           onSave={saveWithShortcut}
         /> */}
-        <CodeMirrorEditorContainer ref={codeMirrorEditorContainerRef} />
+        <CodeMirrorEditorMain
+          onChange={markdownChangedHandler}
+          onSave={saveWithShortcut}
+        />
       </div>
       <div className="page-editor-preview-container flex-expand-vert d-none d-lg-flex">
         <Preview

+ 6 - 6
apps/app/src/components/PageHistory/PageRevisionTable.tsx

@@ -157,33 +157,33 @@ export const PageRevisionTable = (props: PageRevisionTableProps): JSX.Element =>
         </td>
         <td className="col-1">
           {(hasDiff || revisionId === sourceRevision?._id) && (
-            <div className="custom-control custom-radio custom-control-inline me-0">
+            <div className="form-check form-check-inline me-0">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id={`compareSource-${revisionId}`}
                 name="compareSource"
                 value={revisionId}
                 checked={revisionId === sourceRevision?._id}
                 onChange={() => onChangeSourceInvoked(revision)}
               />
-              <label className="custom-control-label" htmlFor={`compareSource-${revisionId}`} />
+              <label className="form-label form-check-label" htmlFor={`compareSource-${revisionId}`} />
             </div>
           )}
         </td>
         <td className="col-2">
           {(hasDiff || revisionId === targetRevision?._id) && (
-            <div className="custom-control custom-radio custom-control-inline me-0">
+            <div className="form-check form-check-inline me-0">
               <input
                 type="radio"
-                className="custom-control-input"
+                className="form-check-input"
                 id={`compareTarget-${revisionId}`}
                 name="compareTarget"
                 value={revisionId}
                 checked={revisionId === targetRevision?._id}
                 onChange={() => onChangeTargetInvoked(revision)}
               />
-              <label className="custom-control-label" htmlFor={`compareTarget-${revisionId}`} />
+              <label className="form-label form-check-label" htmlFor={`compareTarget-${revisionId}`} />
             </div>
           )}
         </td>

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