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

Merge branch 'master' into imprv/7151-slack-review

Yuki Takei 4 лет назад
Родитель
Сommit
668963993a

+ 6 - 0
packages/app/resource/locales/en_US/admin/admin.json

@@ -252,6 +252,12 @@
     "download": "Download",
     "download": "Download",
     "delete": "Delete"
     "delete": "Delete"
   },
   },
+  "external_notification": {
+    "enabled": "Enabled",
+    "disabled": "Disabled",
+    "header_status": "Slack Integration Status",
+    "caution_enabled": "CAUTION: Currently, notifications that are configured in this page will send only to the Slack Workspace set as primary."
+  },
   "slack_integration": {
   "slack_integration": {
     "selecting_bot_types": {
     "selecting_bot_types": {
       "slack_bot": "Slack bot",
       "slack_bot": "Slack bot",

+ 6 - 0
packages/app/resource/locales/ja_JP/admin/admin.json

@@ -252,6 +252,12 @@
     "page_skip": "既に GROWI 側に同名のページが存在する場合、そのページはスキップされます",
     "page_skip": "既に GROWI 側に同名のページが存在する場合、そのページはスキップされます",
     "Directory_hierarchy_tag": "ディレクトリ階層タグ"
     "Directory_hierarchy_tag": "ディレクトリ階層タグ"
   },
   },
+  "external_notification": {
+    "enabled": "有効",
+    "disabled": "無効",
+    "header_status": "Slack 連携の状態",
+    "caution_enabled": "CAUTION: このページで設定される通知は、Primary として設定された Slack ワークスペースにのみ送信されます。 "
+  },
   "slack_integration": {
   "slack_integration": {
     "selecting_bot_types": {
     "selecting_bot_types": {
       "slack_bot": "Slack bot",
       "slack_bot": "Slack bot",

+ 6 - 0
packages/app/resource/locales/zh_CN/admin/admin.json

@@ -262,6 +262,12 @@
     "download": "下载",
     "download": "下载",
     "delete": "删除"
     "delete": "删除"
   },
   },
+  "external_notification": {
+    "enabled": "Enabled",
+    "disabled": "Disabled",
+    "header_status": "Slack整合状态",
+    "caution_enabled": "CAUTION: 目前,在此页面中配置的通知只会通知设置为主要的 Slack 工作区。 "
+  },
   "slack_integration": {
   "slack_integration": {
     "selecting_bot_types": {
     "selecting_bot_types": {
       "slack_bot": "Slack bot",
       "slack_bot": "Slack bot",

+ 9 - 0
packages/app/src/client/services/AdminNotificationContainer.js

@@ -13,6 +13,11 @@ export default class AdminNotificationContainer extends Container {
 
 
     this.state = {
     this.state = {
       retrieveError: null,
       retrieveError: null,
+
+      isSlackbotConfigured: null,
+      isSlackLegacyConfigured: null,
+      currentBotType: null,
+
       userNotifications: [],
       userNotifications: [],
       isNotificationForOwnerPageEnabled: false,
       isNotificationForOwnerPageEnabled: false,
       isNotificationForGroupPageEnabled: false,
       isNotificationForGroupPageEnabled: false,
@@ -36,6 +41,10 @@ export default class AdminNotificationContainer extends Container {
     const { notificationParams } = response.data;
     const { notificationParams } = response.data;
 
 
     this.setState({
     this.setState({
+      isSlackbotConfigured: notificationParams.isSlackbotConfigured,
+      isSlackLegacyConfigured: notificationParams.isSlackLegacyConfigured,
+      currentBotType: notificationParams.currentBotType,
+
       userNotifications: notificationParams.userNotifications,
       userNotifications: notificationParams.userNotifications,
       isNotificationForOwnerPageEnabled: notificationParams.isNotificationForOwnerPageEnabled,
       isNotificationForOwnerPageEnabled: notificationParams.isNotificationForOwnerPageEnabled,
       isNotificationForGroupPageEnabled: notificationParams.isNotificationForGroupPageEnabled,
       isNotificationForGroupPageEnabled: notificationParams.isNotificationForGroupPageEnabled,

+ 1 - 0
packages/app/src/client/services/AdminSlackIntegrationLegacyContainer.js

@@ -14,6 +14,7 @@ export default class AdminSlackIntegrationLegacyContainer extends Container {
     this.dummyWebhookUrlForError = 1;
     this.dummyWebhookUrlForError = 1;
 
 
     this.state = {
     this.state = {
+      isSlackbotConfigured: false,
       retrieveError: null,
       retrieveError: null,
       selectSlackOption: 'Incoming Webhooks',
       selectSlackOption: 'Incoming Webhooks',
       webhookUrl: this.dummyWebhookUrl,
       webhookUrl: this.dummyWebhookUrl,

+ 93 - 1
packages/app/src/components/Admin/Notification/NotificationSetting.jsx

@@ -3,7 +3,10 @@ import React, {
 } from 'react';
 } from 'react';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
 
 
-import { TabContent, TabPane } from 'reactstrap';
+import {
+  Card, CardBody, TabContent, TabPane,
+} from 'reactstrap';
+import { useTranslation } from 'react-i18next';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
 import { withUnstatedContainers } from '../../UnstatedUtils';
 import { withUnstatedContainers } from '../../UnstatedUtils';
@@ -21,9 +24,76 @@ import GlobalNotification from './GlobalNotification';
 const logger = loggerFactory('growi:NotificationSetting');
 const logger = loggerFactory('growi:NotificationSetting');
 
 
 let retrieveErrors = null;
 let retrieveErrors = null;
+
+
+// eslint-disable-next-line react/prop-types
+const Badge = ({ isEnabled }) => {
+  const { t } = useTranslation();
+
+  return isEnabled
+    ? <span className="badge badge-success">{t('admin:external_notification.enabled')}</span>
+    : <span className="badge badge-secondary">{t('admin:external_notification.disabled')}</span>;
+};
+
+const SkeltonListItem = () => (
+  <li className="list-group-item">
+    <h4 className="mb-2">
+      <span className="badge badge-secondary">――</span>
+      <span className="ml-2">...</span>
+    </h4>
+  </li>
+);
+
+// eslint-disable-next-line react/prop-types
+const SlackIntegrationListItem = ({ isEnabled, currentBotType }) => {
+  const { t } = useTranslation();
+
+  const isCautionVisible = currentBotType === 'officialBot' || currentBotType === 'customBotWithProxy';
+
+  return (
+    <li className="list-group-item">
+      <h4>
+        <Badge isEnabled={isEnabled} />
+        <a href="/admin/slack-integration" className="ml-2">{t('slack_integration')}</a>
+      </h4>
+      { isCautionVisible && (
+        <ul className="mt-2 pl-4">
+          {/* eslint-disable-next-line react/no-danger */}
+          <li dangerouslySetInnerHTML={{ __html: t('admin:external_notification.caution_enabled') }} />
+        </ul>
+      ) }
+    </li>
+  );
+};
+
+// eslint-disable-next-line react/prop-types
+const LegacySlackIntegrationListItem = ({ isEnabled }) => {
+  const { t } = useTranslation();
+
+  return (
+    <li className="list-group-item">
+      <h4>
+        <Badge isEnabled={isEnabled} />
+        <a href="/admin/slack-integration-legacy" className="ml-2">{t('legacy_slack_integration')}</a>
+      </h4>
+      { isEnabled && (
+        <ul className="mt-2 pl-4">
+          <li>
+            {/* eslint-disable-next-line react/no-danger */}
+            <span className="text-danger" dangerouslySetInnerHTML={{ __html: t('admin:slack_integration_legacy.alert_deplicated') }}></span>
+          </li>
+        </ul>
+      ) }
+    </li>
+  );
+};
+
 function NotificationSetting(props) {
 function NotificationSetting(props) {
   const { adminNotificationContainer } = props;
   const { adminNotificationContainer } = props;
 
 
+  const { t } = useTranslation();
+
+  const [isMounted, setMounted] = useState(false);
   const [activeTab, setActiveTab] = useState('user_trigger_notification');
   const [activeTab, setActiveTab] = useState('user_trigger_notification');
   const [activeComponents, setActiveComponents] = useState(new Set(['user_trigger_notification']));
   const [activeComponents, setActiveComponents] = useState(new Set(['user_trigger_notification']));
 
 
@@ -42,6 +112,9 @@ function NotificationSetting(props) {
       logger.error(errs);
       logger.error(errs);
       retrieveErrors = errs;
       retrieveErrors = errs;
     }
     }
+    finally {
+      setMounted(true);
+    }
   }, [adminNotificationContainer]);
   }, [adminNotificationContainer]);
 
 
   useEffect(() => {
   useEffect(() => {
@@ -63,8 +136,27 @@ function NotificationSetting(props) {
     };
     };
   }, []);
   }, []);
 
 
+  const { isSlackbotConfigured, isSlackLegacyConfigured, currentBotType } = adminNotificationContainer.state;
+  const isSlackEnabled = isSlackbotConfigured;
+  const isSlackLegacyEnabled = !isSlackbotConfigured && isSlackLegacyConfigured;
+
   return (
   return (
     <>
     <>
+      <h2 className="admin-setting-header">{t('admin:external_notification.header_status')}</h2>
+      <ul className="list-group">
+        { !isMounted && <SkeltonListItem />}
+        { isMounted && (
+          <>
+            <SlackIntegrationListItem isEnabled={isSlackEnabled} currentBotType={currentBotType} />
+            {/* Legacy Slack Integration become visible only when new Slack Integration is disabled */}
+            { !isSlackEnabled && <LegacySlackIntegrationListItem isEnabled={isSlackLegacyEnabled} /> }
+          </>
+        ) }
+      </ul>
+
+
+      <h2 className="admin-setting-header mt-5">{t('Notification Settings')}</h2>
+
       <CustomNavTab activeTab={activeTab} navTabMapping={navTabMapping} onNavSelected={switchActiveTab} hideBorderBottom />
       <CustomNavTab activeTab={activeTab} navTabMapping={navTabMapping} onNavSelected={switchActiveTab} hideBorderBottom />
 
 
       <TabContent activeTab={activeTab} className="p-5">
       <TabContent activeTab={activeTab} className="p-5">

+ 5 - 0
packages/app/src/server/routes/apiv3/notification-setting.js

@@ -118,6 +118,11 @@ module.exports = (crowi) => {
   router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
   router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
 
 
     const notificationParams = {
     const notificationParams = {
+      // status of slack intagration
+      isSlackbotConfigured: crowi.slackIntegrationService.isSlackbotConfigured,
+      isSlackLegacyConfigured: crowi.slackIntegrationService.isSlackLegacyConfigured,
+      currentBotType: await crowi.configManager.getConfig('crowi', 'slackbot:currentBotType'),
+
       userNotifications: await UpdatePost.findAll(),
       userNotifications: await UpdatePost.findAll(),
       isNotificationForOwnerPageEnabled: await crowi.configManager.getConfig('notification', 'notification:owner-page:isEnabled'),
       isNotificationForOwnerPageEnabled: await crowi.configManager.getConfig('notification', 'notification:owner-page:isEnabled'),
       isNotificationForGroupPageEnabled: await crowi.configManager.getConfig('notification', 'notification:group-page:isEnabled'),
       isNotificationForGroupPageEnabled: await crowi.configManager.getConfig('notification', 'notification:group-page:isEnabled'),