|
@@ -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">
|