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

Merge pull request #3790 from weseek/feat/5923-delete-accordion

Feat/5923 delete accordion, 6098
itizawa 4 лет назад
Родитель
Сommit
c1fb55758a

+ 1 - 2
resource/locales/en_US/admin/admin.json

@@ -291,8 +291,7 @@
     },
     "use_env_var_if_empty": "If the value in the database is empty, the value of the environment variable <code>{{variable}}</code> is used.",
     "access_token_settings": {
-      "discard": "Discard",
-      "generate": "Generate"
+      "regenerate": "Regenerate"
     },
     "delete": "Delete",
     "integration_procedure": "Integration Procedure",

+ 1 - 2
resource/locales/ja_JP/admin/admin.json

@@ -289,8 +289,7 @@
     },
     "use_env_var_if_empty": "データベース側の値が空の場合、環境変数 <code>{{variable}}</code> の値を利用します",
     "access_token_settings": {
-      "discard": "破棄",
-      "generate": "発行"
+      "regenerate": "再発行"
     },
     "delete": "削除",
     "integration_procedure": "連携手順",

+ 1 - 2
resource/locales/zh_CN/admin/admin.json

@@ -299,8 +299,7 @@
     },
     "use_env_var_if_empty": "如果数据库中的值为空,则环境变量的值 <code>{{variable}}</code> 启用。",
     "access_token_settings": {
-      "discard": "丢弃",
-      "generate": "生成"
+      "regenerate": "再生"
     },
     "delete": "取消",
     "integration_procedure": "协作程序",

+ 0 - 65
src/client/js/components/Admin/SlackIntegration/AccessTokenSettings.jsx

@@ -1,65 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { CopyToClipboard } from 'react-copy-to-clipboard';
-import { toastSuccess } from '../../../util/apiNotification';
-
-const AccessTokenSettings = (props) => {
-  const { t } = useTranslation('admin');
-
-  const onClickDiscardButton = () => {
-    if (props.onClickDiscardButton != null) {
-      props.onClickDiscardButton();
-    }
-  };
-
-  const onClickGenerateToken = () => {
-    if (props.onClickGenerateToken != null) {
-      props.onClickGenerateToken();
-    }
-  };
-
-  const accessToken = props.accessToken ? props.accessToken : '';
-
-  return (
-    <div className="row">
-      <div className="col-lg-12">
-
-        <h2 className="admin-setting-header">Access Token</h2>
-
-        <div className="form-group row my-5">
-          <label className="text-left text-md-right col-md-3 col-form-label">Access Token</label>
-          <div className="col-md-6">
-            {accessToken.length === 0 ? (
-              <input className="form-control" type="text" value={accessToken} readOnly />
-            ) : (
-              <CopyToClipboard text={accessToken} onCopy={() => toastSuccess(t('admin:slack_integration.copied_to_clipboard'))}>
-                <input className="form-control" type="text" value={accessToken} readOnly />
-              </CopyToClipboard>
-            )}
-          </div>
-        </div>
-
-        <div className="row">
-          <div className="mx-auto">
-            <button type="button" className="btn btn-outline-secondary text-nowrap mx-1" onClick={onClickDiscardButton} disabled={accessToken.length === 0}>
-              {t('slack_integration.access_token_settings.discard')}
-            </button>
-            <button type="button" className="btn btn-primary text-nowrap mx-1" onClick={onClickGenerateToken}>
-              {t('slack_integration.access_token_settings.generate')}
-            </button>
-          </div>
-        </div>
-
-      </div>
-    </div>
-  );
-};
-
-AccessTokenSettings.propTypes = {
-  accessToken: PropTypes.string,
-  onClickDiscardButton: PropTypes.func,
-  onClickGenerateToken: PropTypes.func,
-};
-
-export default AccessTokenSettings;

+ 22 - 27
src/client/js/components/Admin/SlackIntegration/CustomBotWithProxySettings.jsx

@@ -13,10 +13,9 @@ const logger = loggerFactory('growi:SlackBotSettings');
 
 const CustomBotWithProxySettings = (props) => {
   const { appContainer, slackAppIntegrations, proxyServerUri } = props;
-  const [isDeleteConfirmModalShown, setIsDeleteConfirmModalShown] = useState(false);
-  const { t } = useTranslation();
-
   const [newProxyServerUri, setNewProxyServerUri] = useState();
+  const [integrationIdToDelete, setIntegrationIdToDelete] = useState(null);
+  const { t } = useTranslation();
 
   useEffect(() => {
     if (proxyServerUri != null) {
@@ -24,40 +23,37 @@ const CustomBotWithProxySettings = (props) => {
     }
   }, [proxyServerUri]);
 
+  const fetchSlackIntegrationData = () => {
+    if (props.fetchSlackIntegrationData != null) {
+      props.fetchSlackIntegrationData();
+    }
+  };
+
   const addSlackAppIntegrationHandler = async() => {
     // TODO GW-6067 implement
   };
 
-  const discardTokenHandler = async(tokenGtoP, tokenPtoG) => {
+  const deleteSlackAppIntegrationHandler = async() => {
     try {
       // GW-6068 set new value after this
-      await appContainer.apiv3.delete('/slack-integration-settings/slack-app-integration', { tokenGtoP, tokenPtoG });
+      await appContainer.apiv3.delete('/slack-integration-settings/slack-app-integration', { integrationIdToDelete });
+      fetchSlackIntegrationData();
+      toastSuccess(t('toaster.update_successed', { target: 'Token' }));
     }
     catch (err) {
       toastError(err);
-      logger(err);
+      logger.error(err);
     }
   };
 
-  const generateTokenHandler = async() => {
+  const generateAccessTokens = async() => {
     try {
       // GW-6068 set new value after this
       await appContainer.apiv3.put('/slack-integration-settings/access-tokens');
     }
     catch (err) {
       toastError(err);
-      logger(err);
-    }
-  };
-
-  const deleteSlackAppIntegrationHandler = async() => {
-    try {
-      // TODO GW-5923 delete SlackAppIntegration
-      // await appContainer.apiv3.put('/slack-integration-settings/custom-bot-with-proxy');
-      toastSuccess('success');
-    }
-    catch (err) {
-      toastError(err);
+      logger.error(err);
     }
   };
 
@@ -66,7 +62,7 @@ const CustomBotWithProxySettings = (props) => {
       await appContainer.apiv3.put('/slack-integration-settings/proxy-uri', {
         proxyUri: newProxyServerUri,
       });
-      toastSuccess(t('toaster.update_successed', { target: t('Proxy URL') }));
+      toastSuccess(t('toaster.update_successed', { target: 'Proxy URL' }));
     }
     catch (err) {
       toastError(err);
@@ -117,12 +113,12 @@ const CustomBotWithProxySettings = (props) => {
         {slackAppIntegrations.map((slackAppIntegration) => {
           const { tokenGtoP, tokenPtoG } = slackAppIntegration;
           return (
-            <React.Fragment key={slackAppIntegration.id}>
+            <React.Fragment key={slackAppIntegration._id}>
               <div className="d-flex justify-content-end">
                 <button
                   className="my-3 btn btn-outline-danger"
                   type="button"
-                  onClick={() => setIsDeleteConfirmModalShown(true)}
+                  onClick={() => setIntegrationIdToDelete(slackAppIntegration._id)}
                 >
                   <i className="icon-trash mr-1" />
                   {t('admin:slack_integration.delete')}
@@ -130,8 +126,7 @@ const CustomBotWithProxySettings = (props) => {
               </div>
               <WithProxyAccordions
                 botType="customBotWithProxy"
-                discardTokenHandler={() => discardTokenHandler(tokenGtoP, tokenPtoG)}
-                generateTokenHandler={generateTokenHandler}
+                onClickGenerateTokenBtn={generateAccessTokens}
                 tokenGtoP={tokenGtoP}
                 tokenPtoG={tokenPtoG}
               />
@@ -150,8 +145,8 @@ const CustomBotWithProxySettings = (props) => {
       </div>
       <DeleteSlackBotSettingsModal
         isResetAll={false}
-        isOpen={isDeleteConfirmModalShown}
-        onClose={() => setIsDeleteConfirmModalShown(false)}
+        isOpen={integrationIdToDelete != null}
+        onClose={() => setIntegrationIdToDelete(null)}
         onClickDeleteButton={deleteSlackAppIntegrationHandler}
       />
     </>
@@ -166,9 +161,9 @@ CustomBotWithProxySettings.defaultProps = {
 
 CustomBotWithProxySettings.propTypes = {
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-
   slackAppIntegrations: PropTypes.array,
   proxyServerUri: PropTypes.string,
+  fetchSlackIntegrationData: PropTypes.func,
 };
 
 export default CustomBotWithProxySettingsWrapper;

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

@@ -141,7 +141,13 @@ const SlackIntegration = (props) => {
       );
       break;
     case 'customBotWithProxy':
-      settingsComponent = <CustomBotWithProxySettings slackAppIntegrations={slackAppIntegrations} proxyServerUri={proxyServerUri} />;
+      settingsComponent = (
+        <CustomBotWithProxySettings
+          slackAppIntegrations={slackAppIntegrations}
+          proxyServerUri={proxyServerUri}
+          fetchSlackIntegrationData={fetchSlackIntegrationData}
+        />
+      );
       break;
   }
 

+ 13 - 32
src/client/js/components/Admin/SlackIntegration/WithProxyAccordions.jsx

@@ -73,15 +73,9 @@ const RegisteringProxyUrlProcess = () => {
 const GeneratingTokensAndRegisteringProxyServiceProcess = withUnstatedContainers((props) => {
   const { t } = useTranslation();
 
-  const generateTokenHandler = () => {
-    if (props.generateTokenHandler != null) {
-      props.generateTokenHandler();
-    }
-  };
-
-  const discardTokenHandler = () => {
-    if (props.discardTokenHandler != null) {
-      props.discardTokenHandler();
+  const onClickGenerateTokenBtn = () => {
+    if (props.onClickGenerateTokenBtn != null) {
+      props.onClickGenerateTokenBtn();
     }
   };
 
@@ -116,23 +110,13 @@ const GeneratingTokensAndRegisteringProxyServiceProcess = withUnstatedContainers
       </div>
 
       <div className="row my-3">
-        <div className="mx-auto">
-          <button
-            type="button"
-            className="btn btn-outline-secondary mx-2"
-            onClick={discardTokenHandler}
-            disabled={props.tokenGtoP == null || props.tokenPtoG == null}
-          >
-            { t('admin:slack_integration.access_token_settings.discard') }
-          </button>
-          <button
-            type="button"
-            className="btn btn-primary mx-2"
-            onClick={generateTokenHandler}
-          >
-            { t('admin:slack_integration.access_token_settings.generate') }
-          </button>
-        </div>
+        <button
+          type="button"
+          className="btn btn-primary mx-auto"
+          onClick={onClickGenerateTokenBtn}
+        >
+          { t('admin:slack_integration.access_token_settings.regenerate') }
+        </button>
       </div>
       <p className="font-weight-bold">2. {t('admin:slack_integration.accordion.register_for_growi_official_bot_proxy_service')}</p>
       <div className="d-flex flex-column align-items-center">
@@ -270,8 +254,7 @@ const WithProxyAccordions = (props) => {
       title: 'register_for_growi_official_bot_proxy_service',
       content: <GeneratingTokensAndRegisteringProxyServiceProcess
         growiUrl={props.appContainer.config.crowi.url}
-        discardTokenHandler={props.discardTokenHandler}
-        generateTokenHandler={props.generateTokenHandler}
+        onClickGenerateTokenBtn={props.onClickGenerateTokenBtn}
         tokenPtoG={props.tokenPtoG}
         tokenGtoP={props.tokenGtoP}
       />,
@@ -299,8 +282,7 @@ const WithProxyAccordions = (props) => {
       title: 'register_for_growi_official_bot_proxy_service',
       content: <GeneratingTokensAndRegisteringProxyServiceProcess
         growiUrl={props.appContainer.config.crowi.url}
-        discardTokenHandler={props.discardTokenHandler}
-        generateTokenHandler={props.generateTokenHandler}
+        onClickGenerateTokenBtn={props.onClickGenerateTokenBtn}
         tokenPtoG={props.tokenPtoG}
         tokenGtoP={props.tokenGtoP}
       />,
@@ -344,8 +326,7 @@ const OfficialBotSettingsAccordionsWrapper = withUnstatedContainers(WithProxyAcc
 WithProxyAccordions.propTypes = {
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   botType: PropTypes.string.isRequired,
-  discardTokenHandler: PropTypes.func,
-  generateTokenHandler: PropTypes.func,
+  onClickGenerateTokenBtn: PropTypes.func,
   tokenPtoG: PropTypes.string,
   tokenGtoP: PropTypes.string,
 };

+ 6 - 11
src/server/routes/apiv3/slack-integration-settings.js

@@ -59,17 +59,12 @@ module.exports = (crowi) => {
       body('proxyUri').if(value => value !== '').trim().matches(/^(https?:\/\/)/)
         .isURL({ require_tld: false }),
     ],
-    AccessTokens: [
-      query('tokenGtoP').trim().not().isEmpty()
-        .isString()
-        .isLength({ min: 1 }),
-      query('tokenPtoG').trim().not().isEmpty()
-        .isString()
-        .isLength({ min: 1 }),
-    ],
     RelationTest: [
       body('slackappintegrationsId').isMongoId(),
     ],
+    deleteIntegration: [
+      query('integrationIdToDelete').isMongoId(),
+    ],
     SlackChannel: [
       body('channel').trim().not().isEmpty()
         .isString(),
@@ -406,11 +401,11 @@ module.exports = (crowi) => {
    *          200:
    *            description: Succeeded to delete access tokens for slack
    */
-  router.delete('/slack-app-integration', validator.AccessTokens, apiV3FormValidator, async(req, res) => {
+  router.delete('/slack-app-integration', validator.deleteIntegration, apiV3FormValidator, async(req, res) => {
     const SlackAppIntegration = mongoose.model('SlackAppIntegration');
-    const { tokenGtoP, tokenPtoG } = req.query;
+    const { integrationIdToDelete } = req.query;
     try {
-      const response = await SlackAppIntegration.findOneAndDelete({ tokenGtoP, tokenPtoG });
+      const response = await SlackAppIntegration.findOneAndDelete({ _id: integrationIdToDelete });
       return res.apiv3({ response });
     }
     catch (error) {