Explorar el Código

Merge branch 'feat/growi-bot' into feat/create-done-mark-in-acordion-header

zahmis hace 5 años
padre
commit
cb0a307496

BIN
public/images/slack-integration/impossible.png


BIN
public/images/slack-integration/possible.png


BIN
public/images/slack-integration/triangle-basic-gray.png


+ 0 - 3
resource/locales/en_US/admin/admin.json

@@ -264,9 +264,6 @@
       "without_proxy": "without proxy",
       "without_proxy": "without proxy",
       "with_proxy": "with proxy",
       "with_proxy": "with proxy",
       "recommended": "Recommended",
       "recommended": "Recommended",
-      "for_beginners": "- For beginners -",
-      "for_intermediate": "- For intermediates -",
-      "for_advanced": "- For advanced -",
       "set_up": "Set up",
       "set_up": "Set up",
       "multiple_workspaces_integration": "Multiple workspaces integration",
       "multiple_workspaces_integration": "Multiple workspaces integration",
       "security_control": "Security control",
       "security_control": "Security control",

+ 0 - 3
resource/locales/ja_JP/admin/admin.json

@@ -262,9 +262,6 @@
       "without_proxy": "without proxy",
       "without_proxy": "without proxy",
       "with_proxy": "with proxy",
       "with_proxy": "with proxy",
       "recommended": "おすすめ",
       "recommended": "おすすめ",
-      "for_beginners": "- 初心者向け -",
-      "for_intermediate": "- 中級者向け -",
-      "for_advanced": "- 上級者向け -",
       "set_up": "セットアップ",
       "set_up": "セットアップ",
       "multiple_workspaces_integration": "複数ワークスペースとの連携",
       "multiple_workspaces_integration": "複数ワークスペースとの連携",
       "security_control": "セキュリティコントロール",
       "security_control": "セキュリティコントロール",

+ 0 - 3
resource/locales/zh_CN/admin/admin.json

@@ -272,9 +272,6 @@
       "without_proxy": "without proxy",
       "without_proxy": "without proxy",
       "with_proxy": "with proxy",
       "with_proxy": "with proxy",
       "recommended": "受到推崇的",
       "recommended": "受到推崇的",
-      "for_beginners": "- 对于初学者 -",
-      "for_intermediate": "- 对于中级 -",
-      "for_advanced": "- 对于高级 -",
       "set_up": "设置",
       "set_up": "设置",
       "multiple_workspaces_integration": "集成到多个工作区",
       "multiple_workspaces_integration": "集成到多个工作区",
       "security_control": "安全控制",
       "security_control": "安全控制",

+ 99 - 0
src/client/js/components/Admin/SlackIntegration/BotTypeCard.jsx

@@ -0,0 +1,99 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+
+
+const botDetails = {
+  officialBot: {
+    botType: 'officialBot',
+    botTypeCategory: 'official_bot',
+    setUp: 'easy',
+    multiWSIntegration: 'possible',
+    securityControl: 'impossible',
+  },
+  customBotWithoutProxy: {
+    botType: 'customBotWithoutProxy',
+    botTypeCategory: 'custom_bot',
+    supplementaryBotName: 'without_proxy',
+    setUp: 'normal',
+    multiWSIntegration: 'impossible',
+    securityControl: 'possible',
+  },
+  customBotWithProxy: {
+    botType: 'customBotWithProxy',
+    botTypeCategory: 'custom_bot',
+    supplementaryBotName: 'with_proxy',
+    setUp: 'hard',
+    multiWSIntegration: 'possible',
+    securityControl: 'possible',
+  },
+};
+
+const BotTypeCard = (props) => {
+  const { t } = useTranslation('admin');
+
+  return (
+    <div
+      className={`card admin-bot-card rounded border-radius-sm shadow ${props.isActive ? 'border-primary' : ''}`}
+      onClick={() => props.handleBotTypeSelect(botDetails[props.botType].botType)}
+      role="button"
+      key={props.botType}
+    >
+      <div>
+        <h3 className={`card-header mb-0 py-3
+              ${props.botType === 'officialBot' ? 'd-flex align-items-center justify-content-center' : 'text-center'}
+              ${props.isActive ? 'bg-primary text-light' : ''}`}
+        >
+          <span className="mr-2">
+            {t(`admin:slack_integration.selecting_bot_types.${botDetails[props.botType].botTypeCategory}`)}
+          </span>
+
+          {/*  A recommended badge is shown on official bot card, supplementary names are shown on Custom bot cards   */}
+          {props.botType === 'officialBot'
+          ? (
+            <span className="badge badge-info mr-2">
+              {t('admin:slack_integration.selecting_bot_types.recommended')}
+            </span>
+          ) : (
+            <span className="supplementary-bot-name mr-2">
+              {t(`admin:slack_integration.selecting_bot_types.${botDetails[props.botType].supplementaryBotName}`)}
+            </span>
+          )}
+
+          {/* TODO: add an appropriate links by GW-5614 */}
+          <i className={`fa fa-external-link btn-link ${props.isActive ? 'bg-primary text-light' : ''}`} aria-hidden="true"></i>
+        </h3>
+      </div>
+      <div className="card-body p-4">
+        <div className="card-text">
+          <div className="my-2">
+            <div className="d-flex justify-content-between mb-3">
+              {/* TODO add image of difficulties by GW-5638
+               <span>{t('admin:slack_integration.selecting_bot_types.set_up')}</span>
+               <span className={`bot-type-disc-${value.setUp}`}>{t(`admin:slack_integration.selecting_bot_types.${value.setUp}`)}</span>  */}
+
+
+            </div>
+            <div className="d-flex justify-content-between mb-3">
+              <span>{t('admin:slack_integration.selecting_bot_types.multiple_workspaces_integration')}</span>
+              <img className="bot-type-disc" src={`/images/slack-integration/${botDetails[props.botType].multiWSIntegration}.png`} alt="" />
+            </div>
+            <div className="d-flex justify-content-between">
+              <span>{t('admin:slack_integration.selecting_bot_types.security_control')}</span>
+              <img className="bot-type-disc" src={`/images/slack-integration/${botDetails[props.botType].securityControl}.png`} alt="" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+
+};
+
+BotTypeCard.propTypes = {
+  isActive: PropTypes.bool.isRequired,
+  botType: PropTypes.string.isRequired,
+  handleBotTypeSelect: PropTypes.func.isRequired,
+};
+
+export default BotTypeCard;

+ 2 - 1
src/client/js/components/Admin/SlackIntegration/CustomBotWithoutProxySettings.jsx

@@ -7,7 +7,7 @@ import { withUnstatedContainers } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 import SlackGrowiBridging from './SlackGrowiBridging';
 import SlackGrowiBridging from './SlackGrowiBridging';
-import CustomBotWithoutProxySettingsAccordion from './CustomBotWithoutProxySettingsAccordion';
+import CustomBotWithoutProxySettingsAccordion, { botInstallationStep } from './CustomBotWithoutProxySettingsAccordion';
 
 
 
 
 const CustomBotWithoutProxySettings = (props) => {
 const CustomBotWithoutProxySettings = (props) => {
@@ -159,6 +159,7 @@ const CustomBotWithoutProxySettings = (props) => {
 
 
       <div className="my-5 mx-3">
       <div className="my-5 mx-3">
         <CustomBotWithoutProxySettingsAccordion
         <CustomBotWithoutProxySettingsAccordion
+          activeStep={botInstallationStep.CREATE_BOT}
           isRgisterSlackCredentials={isRgisterSlackCredentials}
           isRgisterSlackCredentials={isRgisterSlackCredentials}
           isSendTestMessage={isSendTestMessage}
           isSendTestMessage={isSendTestMessage}
           setIsSendTestMessage={setIsSendTestMessage}
           setIsSendTestMessage={setIsSendTestMessage}

+ 35 - 25
src/client/js/components/Admin/SlackIntegration/CustomBotWithoutProxySettingsAccordion.jsx

@@ -5,22 +5,30 @@ import { Collapse } from 'reactstrap';
 import AppContainer from '../../../services/AppContainer';
 import AppContainer from '../../../services/AppContainer';
 import { withUnstatedContainers } from '../../UnstatedUtils';
 import { withUnstatedContainers } from '../../UnstatedUtils';
 
 
-const CustomBotWithoutProxySettingsAccordion = (props) => {
-  const {
-    appContainer, isRgisterSlackCredentials, isSendTestMessage,
-  } = props;
+
+export const botInstallationStep = {
+  CREATE_BOT: 'create-bot',
+  INSTALL_BOT: 'install-bot',
+  REGISTER_SLACK_CONFIGURATION: 'register-slack-configuration',
+  CONNECTION_TEST: 'connection-test',
+};
+
+const CustomBotWithoutProxySettingsAccordion = ({
+  appContainer, activeStep, isRgisterSlackCredentials, isSendTestMessage, setIsSendTestMessage,
+}) => {
   const { t } = useTranslation('admin');
   const { t } = useTranslation('admin');
-  const [openAccordionIndexes, setOpenAccordionIndexes] = useState(new Set());
+  const [openAccordionIndexes, setOpenAccordionIndexes] = useState(new Set([activeStep]));
   const [connectionErrorCode, setConnectionErrorCode] = useState(null);
   const [connectionErrorCode, setConnectionErrorCode] = useState(null);
   const [connectionErrorMessage, setConnectionErrorMessage] = useState(null);
   const [connectionErrorMessage, setConnectionErrorMessage] = useState(null);
 
 
-  const onToggleAccordionHandler = (i) => {
+
+  const onToggleAccordionHandler = (installationStep) => {
     const accordionIndexes = new Set(openAccordionIndexes);
     const accordionIndexes = new Set(openAccordionIndexes);
-    if (accordionIndexes.has(i)) {
-      accordionIndexes.delete(i);
+    if (accordionIndexes.has(installationStep)) {
+      accordionIndexes.delete(installationStep);
     }
     }
     else {
     else {
-      accordionIndexes.add(i);
+      accordionIndexes.add(installationStep);
     }
     }
     setOpenAccordionIndexes(accordionIndexes);
     setOpenAccordionIndexes(accordionIndexes);
   };
   };
@@ -33,10 +41,10 @@ const CustomBotWithoutProxySettingsAccordion = (props) => {
         // TODO put proper request
         // TODO put proper request
         channel: 'testchannel',
         channel: 'testchannel',
       });
       });
-      props.setIsSendTestMessage(true);
+      setIsSendTestMessage(true);
     }
     }
     catch (err) {
     catch (err) {
-      props.setIsSendTestMessage(false);
+      setIsSendTestMessage(false);
       setConnectionErrorCode(err[0].code);
       setConnectionErrorCode(err[0].code);
       setConnectionErrorMessage(err[0].message);
       setConnectionErrorMessage(err[0].message);
     }
     }
@@ -49,15 +57,15 @@ const CustomBotWithoutProxySettingsAccordion = (props) => {
         <div
         <div
           className="card-header font-weight-normal py-3 d-flex justify-content-between"
           className="card-header font-weight-normal py-3 d-flex justify-content-between"
           role="button"
           role="button"
-          onClick={() => onToggleAccordionHandler(0)}
+          onClick={() => onToggleAccordionHandler(botInstallationStep.CREATE_BOT)}
         >
         >
           <p className="mb-0 text-primary"><span className="mr-2">①</span>{t('slack_integration.without_proxy.create_bot')}</p>
           <p className="mb-0 text-primary"><span className="mr-2">①</span>{t('slack_integration.without_proxy.create_bot')}</p>
-          {openAccordionIndexes.has(0)
+          {openAccordionIndexes.has(botInstallationStep.CREATE_BOT)
             ? <i className="fa fa-chevron-up" />
             ? <i className="fa fa-chevron-up" />
             : <i className="fa fa-chevron-down" />
             : <i className="fa fa-chevron-down" />
           }
           }
         </div>
         </div>
-        <Collapse isOpen={openAccordionIndexes.has(0)}>
+        <Collapse isOpen={openAccordionIndexes.has(botInstallationStep.CREATE_BOT)}>
           <div className="card-body">
           <div className="card-body">
 
 
             <div className="row my-5">
             <div className="row my-5">
@@ -87,15 +95,15 @@ const CustomBotWithoutProxySettingsAccordion = (props) => {
         <div
         <div
           className="card-header font-weight-normal py-3 d-flex justify-content-between"
           className="card-header font-weight-normal py-3 d-flex justify-content-between"
           role="button"
           role="button"
-          onClick={() => onToggleAccordionHandler(1)}
+          onClick={() => onToggleAccordionHandler(botInstallationStep.INSTALL_BOT)}
         >
         >
           <p className="mb-0 text-primary"><span className="mr-2">②</span>{t('slack_integration.without_proxy.install_bot_to_slack')}</p>
           <p className="mb-0 text-primary"><span className="mr-2">②</span>{t('slack_integration.without_proxy.install_bot_to_slack')}</p>
-          {openAccordionIndexes.has(1)
+          {openAccordionIndexes.has(botInstallationStep.INSTALL_BOT)
             ? <i className="fa fa-chevron-up" />
             ? <i className="fa fa-chevron-up" />
             : <i className="fa fa-chevron-down" />
             : <i className="fa fa-chevron-down" />
           }
           }
         </div>
         </div>
-        <Collapse isOpen={openAccordionIndexes.has(1)}>
+        <Collapse isOpen={openAccordionIndexes.has(botInstallationStep.INSTALL_BOT)}>
           <div className="card-body py-5">
           <div className="card-body py-5">
             <div className="container w-75">
             <div className="container w-75">
               <p>1. Install your app をクリックします。</p>
               <p>1. Install your app をクリックします。</p>
@@ -118,19 +126,20 @@ const CustomBotWithoutProxySettingsAccordion = (props) => {
         <div
         <div
           className="card-header font-weight-normal py-3 d-flex justify-content-between"
           className="card-header font-weight-normal py-3 d-flex justify-content-between"
           role="button"
           role="button"
-          onClick={() => onToggleAccordionHandler(2)}
+          onClick={() => onToggleAccordionHandler(botInstallationStep.REGISTER_SLACK_CONFIGURATION)}
         >
         >
           <p className="mb-0 text-primary">
           <p className="mb-0 text-primary">
             <span className="mr-2">③</span>
             <span className="mr-2">③</span>
             {t('slack_integration.without_proxy.register_secret_and_token')}
             {t('slack_integration.without_proxy.register_secret_and_token')}
             {isRgisterSlackCredentials && <i className="ml-3 text-success fa fa-check"></i>}
             {isRgisterSlackCredentials && <i className="ml-3 text-success fa fa-check"></i>}
           </p>
           </p>
-          {openAccordionIndexes.has(2)
+
+          {openAccordionIndexes.has(botInstallationStep.REGISTER_SLACK_CONFIGURATION)
             ? <i className="fa fa-chevron-up" />
             ? <i className="fa fa-chevron-up" />
             : <i className="fa fa-chevron-down" />
             : <i className="fa fa-chevron-down" />
           }
           }
         </div>
         </div>
-        <Collapse isOpen={openAccordionIndexes.has(2)}>
+        <Collapse isOpen={openAccordionIndexes.has(botInstallationStep.REGISTER_SLACK_CONFIGURATION)}>
           <div className="card-body">
           <div className="card-body">
             BODY 3
             BODY 3
           </div>
           </div>
@@ -141,19 +150,18 @@ const CustomBotWithoutProxySettingsAccordion = (props) => {
         <div
         <div
           className="card-header font-weight-normal py-3 d-flex justify-content-between"
           className="card-header font-weight-normal py-3 d-flex justify-content-between"
           role="button"
           role="button"
-          onClick={() => onToggleAccordionHandler(3)}
+          onClick={() => onToggleAccordionHandler(botInstallationStep.CONNECTION_TEST)}
         >
         >
-          <p className="mb-0 text-primary">
-            <span className="mr-2">④</span>
+          <p className="mb-0 text-primary"><span className="mr-2">④</span>
             {t('slack_integration.without_proxy.test_connection')}
             {t('slack_integration.without_proxy.test_connection')}
             {isSendTestMessage && <i className="ml-3 text-success fa fa-check"></i>}
             {isSendTestMessage && <i className="ml-3 text-success fa fa-check"></i>}
           </p>
           </p>
-          {openAccordionIndexes.has(3)
+          {openAccordionIndexes.has(botInstallationStep.CONNECTION_TEST)
             ? <i className="fa fa-chevron-up" />
             ? <i className="fa fa-chevron-up" />
             : <i className="fa fa-chevron-down" />
             : <i className="fa fa-chevron-down" />
           }
           }
         </div>
         </div>
-        <Collapse isOpen={openAccordionIndexes.has(3)}>
+        <Collapse isOpen={openAccordionIndexes.has(botInstallationStep.CONNECTION_TEST)}>
           <div className="card-body">
           <div className="card-body">
             <p className="text-center m-4">以下のテストボタンを押して、Slack連携が完了しているかの確認をしましょう</p>
             <p className="text-center m-4">以下のテストボタンを押して、Slack連携が完了しているかの確認をしましょう</p>
             <div className="d-flex justify-content-center">
             <div className="d-flex justify-content-center">
@@ -185,6 +193,8 @@ CustomBotWithoutProxySettingsAccordion.propTypes = {
   isRgisterSlackCredentials: PropTypes.bool,
   isRgisterSlackCredentials: PropTypes.bool,
   isSendTestMessage: PropTypes.bool,
   isSendTestMessage: PropTypes.bool,
   setIsSendTestMessage: PropTypes.func,
   setIsSendTestMessage: PropTypes.func,
+
+  activeStep: PropTypes.oneOf(Object.values(botInstallationStep)).isRequired,
 };
 };
 
 
 export default CustomBotWithoutProxySettingsAccordionWrapper;
 export default CustomBotWithoutProxySettingsAccordionWrapper;

+ 15 - 137
src/client/js/components/Admin/SlackIntegration/SlackIntegration.jsx

@@ -10,7 +10,9 @@ import OfficialBotSettings from './OfficialBotSettings';
 import CustomBotWithoutProxySettings from './CustomBotWithoutProxySettings';
 import CustomBotWithoutProxySettings from './CustomBotWithoutProxySettings';
 import CustomBotWithProxySettings from './CustomBotWithProxySettings';
 import CustomBotWithProxySettings from './CustomBotWithProxySettings';
 import ConfirmBotChangeModal from './ConfirmBotChangeModal';
 import ConfirmBotChangeModal from './ConfirmBotChangeModal';
+import BotTypeCard from './BotTypeCard';
 
 
+const botTypes = ['officialBot', 'customBotWithoutProxy', 'customBotWithProxy'];
 
 
 const SlackIntegration = (props) => {
 const SlackIntegration = (props) => {
   const { appContainer } = props;
   const { appContainer } = props;
@@ -90,28 +92,19 @@ const SlackIntegration = (props) => {
   let settingsComponent = null;
   let settingsComponent = null;
 
 
   switch (currentBotType) {
   switch (currentBotType) {
-    case 'official-bot':
+    case 'officialBot':
       settingsComponent = <OfficialBotSettings />;
       settingsComponent = <OfficialBotSettings />;
       break;
       break;
-    case 'custom-bot-without-proxy':
+    case 'customBotWithoutProxy':
       settingsComponent = (
       settingsComponent = (
         <CustomBotWithoutProxySettings />
         <CustomBotWithoutProxySettings />
       );
       );
       break;
       break;
-    case 'custom-bot-with-proxy':
+    case 'customBotWithProxy':
       settingsComponent = <CustomBotWithProxySettings />;
       settingsComponent = <CustomBotWithProxySettings />;
       break;
       break;
   }
   }
 
 
-  const showBotTypeLevel = (level) => {
-    return <span>{t(`admin:slack_integration.selecting_bot_types.${level}`)}</span>;
-  };
-  const showBotTypeLabel = (label) => {
-    return <span>{t(`admin:slack_integration.selecting_bot_types.${label}`)}</span>;
-  };
-  const showBotTypeDiscription = (desc) => {
-    return <span className={`bot-type-disc-${desc}`}>{t(`admin:slack_integration.selecting_bot_types.${desc}`)}</span>;
-  };
 
 
   return (
   return (
     <>
     <>
@@ -142,131 +135,16 @@ const SlackIntegration = (props) => {
 
 
         <div className="row my-4">
         <div className="row my-4">
           <div className="card-deck mx-auto">
           <div className="card-deck mx-auto">
-
-            <div
-              className={`card admin-bot-card mx-3 rounded border-radius-sm shadow ${currentBotType === 'official-bot' ? 'border-primary' : ''}`}
-              onClick={() => handleBotTypeSelect('official-bot')}
-              role="button"
-            >
-              <div>
-                <h3 className={`card-header mb-0 py-3 text-center ${currentBotType === 'official-bot' ? 'bg-primary text-light' : ''}`}>
-                  <span className="mr-2">
-                    {t('admin:slack_integration.selecting_bot_types.official_bot')}
-                  </span>
-                  <span className="badge badge-info mr-2">
-                    {t('admin:slack_integration.selecting_bot_types.recommended')}
-                  </span>
-                  {/* TODO: add an appropriate link by GW-5614 */}
-                  <i className={`fa fa-external-link btn-link ${currentBotType === 'official-bot' ? 'bg-primary text-light' : ''}`} aria-hidden="true"></i>
-                </h3>
-              </div>
-              <div className="card-body p-4">
-                <p className="card-text">
-                  <div className="text-center">
-                    {showBotTypeLevel('for_beginners')}
-                  </div>
-                  <div className="my-4">
-                    <div className="d-flex justify-content-between mb-2">
-                      {showBotTypeLabel('set_up')}
-                      {showBotTypeDiscription('easy')}
-                    </div>
-                    <div className="d-flex justify-content-between mb-2">
-                      {showBotTypeLabel('multiple_workspaces_integration')}
-                      {showBotTypeDiscription('possible')}
-                    </div>
-                    <div className="d-flex justify-content-between">
-                      {showBotTypeLabel('security_control')}
-                      {showBotTypeDiscription('impossible')}
-                    </div>
-                  </div>
-                </p>
-              </div>
-            </div>
-
-            <div
-              className={`card admin-bot-card mx-3 rounded shadow ${currentBotType === 'custom-bot-without-proxy' ? 'border-primary' : ''}`}
-              onClick={() => handleBotTypeSelect('custom-bot-without-proxy')}
-              role="button"
-            >
-              <h3 className={`card-header mb-0 py-3 text-center text-nowrap  ${currentBotType === 'custom-bot-without-proxy' ? 'bg-primary text-light' : ''}`}>
-                <span className="mr-2">
-                  {t('admin:slack_integration.selecting_bot_types.custom_bot')}
-                </span>
-                <span className="supplementary-desc mr-2">
-                  {t('admin:slack_integration.selecting_bot_types.without_proxy')}
-                </span>
-                {/* TODO: add an appropriate link by GW-5614 */}
-                <i
-                  className={`fa fa-external-link btn-link ${currentBotType === 'custom-bot-without-proxy' ? 'bg-primary text-light' : ''}`}
-                  aria-hidden="true"
-                >
-                </i>
-              </h3>
-              <div className="card-body p-4">
-                <p className="card-text">
-                  <div className="text-center">
-                    {showBotTypeLevel('for_intermediate')}
-                  </div>
-                  <div className="my-4">
-                    <div className="d-flex justify-content-between mb-2">
-                      {showBotTypeLabel('set_up')}
-                      {showBotTypeDiscription('normal')}
-                    </div>
-                    <div className="d-flex justify-content-between mb-2">
-                      {showBotTypeLabel('multiple_workspaces_integration')}
-                      {showBotTypeDiscription('impossible')}
-                    </div>
-                    <div className="d-flex justify-content-between">
-                      {showBotTypeLabel('security_control')}
-                      {showBotTypeDiscription('possible')}
-                    </div>
-                  </div>
-                </p>
-              </div>
-            </div>
-
-            <div
-              className={`card admin-bot-card mx-3 rounded shadow ${currentBotType === 'custom-bot-with-proxy' ? 'border-primary' : ''}`}
-              onClick={() => handleBotTypeSelect('custom-bot-with-proxy')}
-              role="button"
-            >
-              <h3 className={`card-header mb-0 py-3 text-center text-nowrap ${currentBotType === 'custom-bot-with-proxy' ? 'bg-primary text-light' : ''}`}>
-                <span className="mr-2">
-                  {t('admin:slack_integration.selecting_bot_types.custom_bot')}
-                </span>
-                <span className="supplementary-desc mr-2">
-                  {t('admin:slack_integration.selecting_bot_types.with_proxy')}
-                </span>
-                {/* TODO: add an appropriate link by GW-5614 */}
-                <i
-                  className={`fa fa-external-link btn-link ${currentBotType === 'custom-bot-with-proxy' ? 'bg-primary text-light' : ''}`}
-                  aria-hidden="true"
-                >
-                </i>
-              </h3>
-              <div className="card-body p-4">
-                <p className="card-text">
-                  <div className="text-center">
-                    {showBotTypeLevel('for_advanced')}
-                  </div>
-                  <div className="my-4">
-                    <div className="d-flex justify-content-between mb-2">
-                      {showBotTypeLabel('set_up')}
-                      {showBotTypeDiscription('hard')}
-                    </div>
-                    <div className="d-flex justify-content-between mb-2">
-                      {showBotTypeLabel('multiple_workspaces_integration')}
-                      {showBotTypeDiscription('possible')}
-                    </div>
-                    <div className="d-flex justify-content-between">
-                      {showBotTypeLabel('security_control')}
-                      {showBotTypeDiscription('impossible')}
-                    </div>
-                  </div>
-                </p>
-              </div>
-            </div>
-
+            {botTypes.map((botType) => {
+              return (
+                <BotTypeCard
+                  key={botType}
+                  botType={botType}
+                  isActive={currentBotType === botType}
+                  handleBotTypeSelect={handleBotTypeSelect}
+                />
+              );
+            })}
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>

+ 1 - 1
src/client/styles/scss/_admin.scss

@@ -90,7 +90,7 @@
     .btn-link {
     .btn-link {
       font-size: 1rem;
       font-size: 1rem;
     }
     }
-    .supplementary-desc {
+    .supplementary-bot-name {
       font-size: 1rem;
       font-size: 1rem;
     }
     }
     .badge-info {
     .badge-info {

+ 2 - 14
src/client/styles/scss/theme/_apply-colors.scss

@@ -596,19 +596,7 @@ mark.rbt-highlight-text {
   Slack Integration
   Slack Integration
 */
 */
 .selecting-bot-type {
 .selecting-bot-type {
-  .bot-type-disc-easy {
-    color: #33d541;
-  }
-  .bot-type-disc-normal {
-    color: #e6a63c;
-  }
-  .bot-type-disc-hard {
-    color: #ff5757;
-  }
-  .bot-type-disc-possible {
-    color: $info;
-  }
-  .bot-type-disc-impossible {
-    color: $gray-500;
+  .bot-type-disc {
+    width: 20px;
   }
   }
 }
 }

+ 1 - 1
src/server/routes/apiv3/slack-integration.js

@@ -54,7 +54,7 @@ module.exports = (crowi) => {
     ],
     ],
     SlackIntegration: [
     SlackIntegration: [
       body('currentBotType')
       body('currentBotType')
-        .isIn(['official-bot', 'custom-bot-without-proxy', 'custom-bot-with-proxy']),
+        .isIn(['officialBot', 'customBotWithoutProxy', 'customBotWithProxy']),
     ],
     ],
     NotificationTestToSlackWorkSpace: [
     NotificationTestToSlackWorkSpace: [
       body('channel').isString(),
       body('channel').isString(),

+ 1 - 1
src/server/service/config-loader.js

@@ -418,7 +418,7 @@ const ENV_VAR_NAME_TO_CONFIG_INFO = {
   },
   },
   SLACK_BOT_TYPE: {
   SLACK_BOT_TYPE: {
     ns:      'crowi',
     ns:      'crowi',
-    key:     'slackbot:currentBotType', // 'official-bot' || 'custom-bot-without-proxy' || 'custom-bot-with-proxy'
+    key:     'slackbot:currentBotType', // 'officialBot' || 'customBotWithoutProxy' || 'customBotWithProxy'
     type:    TYPES.STRING,
     type:    TYPES.STRING,
     default: null,
     default: null,
   },
   },