zahmis 4 лет назад
Родитель
Сommit
0ba32245fe

+ 8 - 0
packages/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySettingsAccordion.jsx

@@ -7,6 +7,7 @@ import { withUnstatedContainers } from '../../UnstatedUtils';
 import MessageBasedOnConnection from './MessageBasedOnConnection';
 import CustomBotWithoutProxySecretTokenSection from './CustomBotWithoutProxySecretTokenSection';
 import { addLogs } from './slak-integration-util';
+import ManageCommandsProcessWithoutProxy from './ManageCommandsProcessWithoutProxy';
 
 
 export const botInstallationStep = {
@@ -125,6 +126,13 @@ const CustomBotWithoutProxySettingsAccordion = (props) => {
         defaultIsActive={defaultOpenAccordionKeys.has(botInstallationStep.CONNECTION_TEST)}
         // eslint-disable-next-line max-len
         title={<><span className="mr-2">④</span>{t('admin:slack_integration.accordion.test_connection')}{isLatestConnectionSuccess && <i className="ml-3 text-success fa fa-check"></i>}</>}
+      >
+        <ManageCommandsProcessWithoutProxy />
+      </Accordion>
+      <Accordion
+        defaultIsActive={defaultOpenAccordionKeys.has(botInstallationStep.CONNECTION_TEST)}
+        // eslint-disable-next-line max-len
+        title={<><span className="mr-2">⑤</span>{t('admin:slack_integration.accordion.test_connection')}{isLatestConnectionSuccess && <i className="ml-3 text-success fa fa-check"></i>}</>}
       >
         <p className="text-center m-4">{t('admin:slack_integration.accordion.test_connection_by_pressing_button')}</p>
         <div className="d-flex justify-content-center">

+ 287 - 0
packages/app/src/components/Admin/SlackIntegration/ManageCommandsProcessWithoutProxy.jsx

@@ -0,0 +1,287 @@
+import React, { useCallback, useState } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { defaultSupportedCommandsNameForBroadcastUse, defaultSupportedCommandsNameForSingleUse } from '@growi/slack';
+import loggerFactory from '~/utils/logger';
+
+import { toastSuccess, toastError } from '../../../client/util/apiNotification';
+
+const logger = loggerFactory('growi:SlackIntegration:ManageCommandsProcess');
+
+const PermissionTypes = {
+  ALLOW_ALL: 'allowAll',
+  DENY_ALL: 'denyAll',
+  ALLOW_SPECIFIED: 'allowSpecified',
+};
+
+// const CommandUsageTypes = {
+//   BROADCAST_USE: 'broadcastUse',
+//   SINGLE_USE: 'singleUse',
+// };
+
+// A utility function that returns the new state but identical to the previous state
+const getUpdatedChannelsList = (prevState, commandName, value) => {
+  // string to array
+  const allowedChannelsArray = value.split(',');
+  // trim whitespace from all elements
+  const trimedAllowedChannelsArray = allowedChannelsArray.map(channelName => channelName.trim());
+
+  prevState[commandName] = trimedAllowedChannelsArray;
+  return prevState;
+};
+
+// A utility function that returns the new state
+const getUpdatedPermissionSettings = (prevState, commandName, value) => {
+  const newState = { ...prevState };
+  switch (value) {
+    case PermissionTypes.ALLOW_ALL:
+      newState[commandName] = true;
+      break;
+    case PermissionTypes.DENY_ALL:
+      newState[commandName] = false;
+      break;
+    case PermissionTypes.ALLOW_SPECIFIED:
+      newState[commandName] = [];
+      break;
+    default:
+      logger.error('Not implemented');
+      break;
+  }
+
+  return newState;
+};
+
+// A utility function that returns the permission type from the permission value
+const getPermissionTypeFromValue = (value) => {
+  if (Array.isArray(value)) {
+    return PermissionTypes.ALLOW_SPECIFIED;
+  }
+  if (typeof value === 'boolean') {
+    return value ? PermissionTypes.ALLOW_ALL : PermissionTypes.DENY_ALL;
+  }
+  logger.error('The value type must be boolean or string[]');
+};
+
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+const ManageCommandsProcess = ({
+  apiv3Put, slackAppIntegrationId, permissionsForBroadcastUseCommands, permissionsForSingleUseCommands,
+}) => {
+  const { t } = useTranslation();
+
+  const [permissionsForBroadcastUseCommandsState, setPermissionsForBroadcastUseCommandsState] = useState({
+    search: permissionsForBroadcastUseCommands.search,
+  });
+  const [permissionsForSingleUseCommandsState, setPermissionsForSingleUseCommandsState] = useState({
+    create: permissionsForSingleUseCommands.create,
+    togetter: permissionsForSingleUseCommands.togetter,
+  });
+  const [currentPermissionTypes, setCurrentPermissionTypes] = useState(() => {
+    const initialState = {};
+    Object.entries(permissionsForBroadcastUseCommandsState).forEach((entry) => {
+      const [commandName, value] = entry;
+      initialState[commandName] = getPermissionTypeFromValue(value);
+    });
+    Object.entries(permissionsForSingleUseCommandsState).forEach((entry) => {
+      const [commandName, value] = entry;
+      initialState[commandName] = getPermissionTypeFromValue(value);
+    });
+    return initialState;
+  });
+
+  const updatePermissionsForBroadcastUseCommandsState = useCallback((e) => {
+    const { target } = e;
+    const { name: commandName, value } = target;
+
+    // update state
+    setPermissionsForBroadcastUseCommandsState(prev => getUpdatedPermissionSettings(prev, commandName, value));
+    setCurrentPermissionTypes((prevState) => {
+      const newState = { ...prevState };
+      newState[commandName] = value;
+      return newState;
+    });
+  }, []);
+
+  // const updatePermissionsForSingleUseCommandsState = useCallback((e) => {
+  //   const { target } = e;
+  //   const { name: commandName, value } = target;
+
+  //   // update state
+  //   setPermissionsForSingleUseCommandsState(prev => getUpdatedPermissionSettings(prev, commandName, value));
+  //   setCurrentPermissionTypes((prevState) => {
+  //     const newState = { ...prevState };
+  //     newState[commandName] = value;
+  //     return newState;
+  //   });
+  // }, []);
+
+  const updateChannelsListForBroadcastUseCommandsState = useCallback((e) => {
+    const { target } = e;
+    const { name: commandName, value } = target;
+    // update state
+    setPermissionsForBroadcastUseCommandsState(prev => getUpdatedChannelsList(prev, commandName, value));
+  }, []);
+
+  const updateChannelsListForSingleUseCommandsState = useCallback((e) => {
+    const { target } = e;
+    const { name: commandName, value } = target;
+    // update state
+    setPermissionsForSingleUseCommandsState(prev => getUpdatedChannelsList(prev, commandName, value));
+  }, []);
+
+  const updateCommandsHandler = async(e) => {
+    try {
+      await apiv3Put(`/slack-integration-settings/slack-app-integrations/${slackAppIntegrationId}/supported-commands`, {
+        permissionsForBroadcastUseCommands: permissionsForBroadcastUseCommandsState,
+        permissionsForSingleUseCommands: permissionsForSingleUseCommandsState,
+      });
+      toastSuccess(t('toaster.update_successed', { target: 'Token' }));
+    }
+    catch (err) {
+      toastError(err);
+      logger.error(err);
+    }
+  };
+
+  const PermissionSettingForEachCommandComponent = ({ commandName, commandUsageType }) => {
+    const hiddenClass = currentPermissionTypes[commandName] === PermissionTypes.ALLOW_SPECIFIED ? '' : 'd-none';
+    // const isCommandBroadcastUse = commandUsageType === CommandUsageTypes.BROADCAST_USE;
+
+    const permissionSettings = ['search'];
+    const permission = permissionSettings[commandName];
+    if (permission === undefined) logger.error('Must be implemented');
+
+    const textareaDefaultValue = Array.isArray(permission) ? permission.join(',') : '';
+
+    return (
+      <div className="my-1 mb-2">
+        <div className="row align-items-center mb-3">
+          <p className="col my-auto text-capitalize align-middle">{commandName}</p>
+          <div className="col dropdown">
+            <button
+              className="btn btn-outline-secondary dropdown-toggle text-right col-12 col-md-auto"
+              type="button"
+              id="dropdownMenuButton"
+              data-toggle="dropdown"
+              aria-haspopup="true"
+              aria-expanded="true"
+            >
+              <span className="float-left">
+                {currentPermissionTypes[commandName] === PermissionTypes.ALLOW_ALL
+                && t('admin:slack_integration.accordion.allow_all')}
+                {currentPermissionTypes[commandName] === PermissionTypes.DENY_ALL
+                && t('admin:slack_integration.accordion.deny_all')}
+                {currentPermissionTypes[commandName] === PermissionTypes.ALLOW_SPECIFIED
+                && t('admin:slack_integration.accordion.allow_specified')}
+              </span>
+            </button>
+            <div className="dropdown-menu">
+              <button
+                className="dropdown-item"
+                type="button"
+                name={commandName}
+                value={PermissionTypes.ALLOW_ALL}
+                onClick={updatePermissionsForBroadcastUseCommandsState}
+              >
+                {t('admin:slack_integration.accordion.allow_all_long')}
+              </button>
+              <button
+                className="dropdown-item"
+                type="button"
+                name={commandName}
+                value={PermissionTypes.DENY_ALL}
+                onClick={updatePermissionsForBroadcastUseCommandsState}
+              >
+                {t('admin:slack_integration.accordion.deny_all_long')}
+              </button>
+              <button
+                className="dropdown-item"
+                type="button"
+                name={commandName}
+                value={PermissionTypes.ALLOW_SPECIFIED}
+                onClick={updatePermissionsForBroadcastUseCommandsState}
+              >
+                {t('admin:slack_integration.accordion.allow_specified_long')}
+              </button>
+            </div>
+          </div>
+        </div>
+        <div className={`row-12 row-md-6 ${hiddenClass}`}>
+          <textarea
+            className="form-control"
+            type="textarea"
+            name={commandName}
+            defaultValue={textareaDefaultValue}
+            onChange={updateChannelsListForBroadcastUseCommandsState}
+          />
+          <p className="form-text text-muted small">
+            {t('admin:slack_integration.accordion.allowed_channels_description', { commandName })}
+            <br />
+          </p>
+        </div>
+      </div>
+    );
+  };
+
+  PermissionSettingForEachCommandComponent.propTypes = {
+    commandName: PropTypes.string,
+    commandUsageType: PropTypes.string,
+  };
+
+  const PermissionSettingsForEachCommandTypeComponent = ({ commandUsageType }) => {
+    // const isCommandBroadcastUse = commandUsageType === CommandUsageTypes.BROADCAST_USE;
+    const defaultCommandsName = ['seach'];
+    return (
+      <>
+        {/* <p className="font-weight-bold mb-0">{isCommandBroadcastUse ? 'Multiple GROWI' : 'Single GROWI'}</p> */}
+        <p className="text-muted mb-2">
+          {t('admin:slack_integration.accordion.multiple_growi_command')}
+        </p>
+        <div className="custom-control custom-checkbox">
+          <div className="row mb-5 d-block">
+            {['search'].map((commandName) => {
+              // eslint-disable-next-line max-len
+              return <PermissionSettingForEachCommandComponent key={`${commandName}-component`} commandName={commandName} commandUsageType={commandUsageType} />;
+            })}
+          </div>
+        </div>
+      </>
+    );
+  };
+
+  PermissionSettingsForEachCommandTypeComponent.propTypes = {
+    commandUsageType: PropTypes.string,
+  };
+
+
+  return (
+    <div className="py-4 px-5">
+      <p className="mb-4 font-weight-bold">{t('admin:slack_integration.accordion.manage_commands')}</p>
+      <div className="row d-flex flex-column align-items-center">
+
+        <div className="col-8">
+          {Object.values(['search']).map((commandUsageType) => {
+            return <PermissionSettingsForEachCommandTypeComponent key={commandUsageType} commandUsageType={commandUsageType} />;
+          })}
+        </div>
+      </div>
+      <div className="row">
+        <button
+          type="submit"
+          className="btn btn-primary mx-auto"
+          onClick={updateCommandsHandler}
+        >
+          { t('Update') }
+        </button>
+      </div>
+    </div>
+  );
+};
+
+ManageCommandsProcess.propTypes = {
+  apiv3Put: PropTypes.func,
+  slackAppIntegrationId: PropTypes.string.isRequired,
+  permissionsForBroadcastUseCommands: PropTypes.object.isRequired,
+  permissionsForSingleUseCommands: PropTypes.object.isRequired,
+};
+
+export default ManageCommandsProcess;

+ 2 - 1
packages/app/src/components/Admin/SlackIntegration/SlackIntegration.jsx

@@ -40,7 +40,7 @@ const SlackIntegration = (props) => {
     try {
       const { data } = await appContainer.apiv3.get('/slack-integration-settings');
       const {
-        slackSigningSecret, slackBotToken, slackSigningSecretEnvVars, slackBotTokenEnvVars, slackAppIntegrations, proxyServerUri,
+        slackSigningSecret, slackBotToken, slackSigningSecretEnvVars, slackBotTokenEnvVars, slackAppIntegrations, proxyServerUri, commandPermission,
       } = data.settings;
 
       setErrorMsg(data.errorMsg);
@@ -53,6 +53,7 @@ const SlackIntegration = (props) => {
       setSlackBotTokenEnv(slackBotTokenEnvVars);
       setSlackAppIntegrations(slackAppIntegrations);
       setProxyServerUri(proxyServerUri);
+      console.log(commandPermission);
     }
     catch (err) {
       toastError(err);