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

Merge branch 'master' into imprv/gw-4349-me-setting-layout

yusuketk 5 лет назад
Родитель
Сommit
6dde1b4f65

+ 1 - 0
resource/locales/en_US/translation.json

@@ -190,6 +190,7 @@
     }
   },
   "page_me_apitoken": {
+    "api_token": "API Token",
     "notice": {
       "apitoken_issued": "API token is not issued.",
       "update_token1": "You can update to generate a new API token.",

+ 1 - 0
resource/locales/ja_JP/translation.json

@@ -193,6 +193,7 @@
     }
   },
   "page_me_apitoken": {
+    "api_token": "API Token",
     "notice": {
       "apitoken_issued": "API Token が設定されていません。",
       "update_token1": "API Token を更新すると、自動的に新しい Token が生成されます。",

+ 1 - 0
resource/locales/zh_CN/translation.json

@@ -192,6 +192,7 @@
 		}
 	},
 	"page_me_apitoken": {
+    "api_token": "API Token",
 		"notice": {
 			"apitoken_issued": "API token 未发布。",
 			"update_token1": "您可以更新以生成新的API令牌。",

+ 30 - 3
src/client/js/components/Admin/Notification/NotificationSetting.jsx

@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useMemo } from 'react';
 import PropTypes from 'prop-types';
 
 import loggerFactory from '@alias/logger';
@@ -10,7 +10,11 @@ import { withLoadingSppiner } from '../../SuspenseUtils';
 
 import AdminNotificationContainer from '../../../services/AdminNotificationContainer';
 
-import NotificationSettingContents from './NotificationSettingContents';
+import CustomNavigation from '../../CustomNavigation';
+
+import SlackAppConfiguration from './SlackAppConfiguration';
+import UserTriggerNotification from './UserTriggerNotification';
+import GlobalNotification from './GlobalNotification';
 
 const logger = loggerFactory('growi:NotificationSetting');
 
@@ -36,7 +40,30 @@ function NotificationSetting(props) {
     throw new Error(`${retrieveErrors.length} errors occured`);
   }
 
-  return <NotificationSettingContents />;
+  const navTabMapping = useMemo(() => {
+    return {
+      slack_configuration: {
+        Icon: () => <i className="icon-settings" />,
+        Content: SlackAppConfiguration,
+        i18n: 'Slack configuration',
+        index: 0,
+      },
+      user_trigger_notification: {
+        Icon: () => <i className="icon-settings" />,
+        Content: UserTriggerNotification,
+        i18n: 'User trigger notification',
+        index: 1,
+      },
+      global_notification: {
+        Icon: () => <i className="icon-settings" />,
+        Content: GlobalNotification,
+        i18n: 'Global notification',
+        index: 2,
+      },
+    };
+  }, []);
+
+  return <CustomNavigation navTabMapping={navTabMapping} />;
 }
 
 const NotificationSettingWithUnstatedContainer = withUnstatedContainers(withLoadingSppiner(NotificationSetting), [AdminNotificationContainer]);

+ 0 - 98
src/client/js/components/Admin/Notification/NotificationSettingContents.jsx

@@ -1,98 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { withTranslation } from 'react-i18next';
-import {
-  TabContent, TabPane, Nav, NavItem, NavLink,
-} from 'reactstrap';
-
-import { withUnstatedContainers } from '../../UnstatedUtils';
-
-import AppContainer from '../../../services/AppContainer';
-import AdminNotificationContainer from '../../../services/AdminNotificationContainer';
-
-import SlackAppConfiguration from './SlackAppConfiguration';
-import UserTriggerNotification from './UserTriggerNotification';
-import GlobalNotification from './GlobalNotification';
-
-
-class NotificationSettingContents extends React.Component {
-
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      activeTab: 'slack-configuration',
-      // Prevent unnecessary rendering
-      activeComponents: new Set(['slack-configuration']),
-    };
-
-    this.toggleActiveTab = this.toggleActiveTab.bind(this);
-  }
-
-  toggleActiveTab(activeTab) {
-    this.setState({
-      activeTab, activeComponents: this.state.activeComponents.add(activeTab),
-    });
-  }
-
-  render() {
-    const { activeTab, activeComponents } = this.state;
-
-    return (
-      <React.Fragment>
-        <Nav tabs>
-          <NavItem>
-            <NavLink
-              className={`${activeTab === 'slack-configuration' && 'active'} `}
-              onClick={() => { this.toggleActiveTab('slack-configuration') }}
-              href="#slack-configuration"
-            >
-              <i className="icon-settings"></i> Slack configuration
-            </NavLink>
-          </NavItem>
-          <NavItem>
-            <NavLink
-              className={`${activeTab === 'user-trigger-notification' && 'active'} `}
-              onClick={() => { this.toggleActiveTab('user-trigger-notification') }}
-              href="#user-trigger-notification"
-            >
-              <i className="icon-settings"></i> User trigger notification
-            </NavLink>
-          </NavItem>
-          <NavItem>
-            <NavLink
-              className={`${activeTab === 'global-notification' && 'active'} `}
-              onClick={() => { this.toggleActiveTab('global-notification') }}
-              href="#global-notification"
-            >
-              <i className="icon-settings"></i> Global notification
-            </NavLink>
-          </NavItem>
-        </Nav>
-        <TabContent activeTab={activeTab}>
-          <TabPane tabId="slack-configuration">
-            {activeComponents.has('slack-configuration') && <SlackAppConfiguration />}
-          </TabPane>
-          <TabPane tabId="user-trigger-notification">
-            {activeComponents.has('user-trigger-notification') && <UserTriggerNotification />}
-          </TabPane>
-          <TabPane tabId="global-notification">
-            {activeComponents.has('global-notification') && <GlobalNotification />}
-          </TabPane>
-        </TabContent>
-      </React.Fragment>
-    );
-  }
-
-}
-
-const NotificationSettingContentsWrapper = withUnstatedContainers(NotificationSettingContents, [AppContainer, AdminNotificationContainer]);
-
-NotificationSettingContents.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  adminNotificationContainer: PropTypes.instanceOf(AdminNotificationContainer).isRequired,
-
-};
-
-export default withTranslation()(NotificationSettingContentsWrapper);

+ 87 - 166
src/client/js/components/Admin/Security/SecurityManagementContents.jsx

@@ -1,13 +1,7 @@
-import React, { Fragment } from 'react';
+import React, { Fragment, useMemo } from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
-import {
-  TabContent, TabPane, Nav, NavItem, NavLink,
-} from 'reactstrap';
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
-
-import AppContainer from '../../../services/AppContainer';
 import LdapSecuritySetting from './LdapSecuritySetting';
 import LocalSecuritySetting from './LocalSecuritySetting';
 import SamlSecuritySetting from './SamlSecuritySetting';
@@ -20,177 +14,104 @@ import TwitterSecuritySetting from './TwitterSecuritySetting';
 import FacebookSecuritySetting from './FacebookSecuritySetting';
 import ShareLinkSetting from './ShareLinkSetting';
 
-class SecurityManagementContents extends React.Component {
-
-  constructor() {
-    super();
-
-    this.state = {
-      activeTab: 'passport-local',
-      // Prevent unnecessary rendering
-      activeComponents: new Set(['passport-local']),
+import CustomNavigation from '../../CustomNavigation';
+
+function SecurityManagementContents(props) {
+  const { t } = props;
+
+  const navTabMapping = useMemo(() => {
+    return {
+      passport_local: {
+        Icon: () => <i className="fa fa-users" />,
+        Content: LocalSecuritySetting,
+        i18n: 'ID/Pass',
+        index: 0,
+      },
+      passport_ldap: {
+        Icon: () => <i className="fa fa-sitemap" />,
+        Content: LdapSecuritySetting,
+        i18n: 'LDAP',
+        index: 1,
+      },
+      passport_saml: {
+        Icon: () => <i className="fa fa-key" />,
+        Content: SamlSecuritySetting,
+        i18n: 'SAML',
+        index: 2,
+      },
+      passport_oidc: {
+        Icon: () => <i className="fa fa-key" />,
+        Content: OidcSecuritySetting,
+        i18n: 'OIDC',
+        index: 3,
+      },
+      passport_basic: {
+        Icon: () => <i className="fa fa-lock" />,
+        Content: BasicSecuritySetting,
+        i18n: 'BASIC',
+        index: 4,
+      },
+      passport_google: {
+        Icon: () => <i className="fa fa-google" />,
+        Content: GoogleSecuritySetting,
+        i18n: 'Google',
+        index: 5,
+      },
+      passport_github: {
+        Icon: () => <i className="fa fa-github" />,
+        Content: GitHubSecuritySetting,
+        i18n: 'GitHub',
+        index: 6,
+      },
+      passport_twitter: {
+        Icon: () => <i className="fa fa-twitter" />,
+        Content: TwitterSecuritySetting,
+        i18n: 'Twitter',
+        index: 7,
+      },
+      passport_facebook: {
+        Icon: () => <i className="fa fa-facebook" />,
+        Content: FacebookSecuritySetting,
+        i18n: '(TBD) Facebook',
+        index: 8,
+      },
     };
+  }, []);
 
-    this.toggleActiveTab = this.toggleActiveTab.bind(this);
-  }
-
-  toggleActiveTab(activeTab) {
-    this.setState({
-      activeTab, activeComponents: this.state.activeComponents.add(activeTab),
-    });
-  }
 
-  render() {
-    const { t } = this.props;
-    const { activeTab, activeComponents } = this.state;
-    return (
-      <Fragment>
-        <div className="mb-5">
-          <SecuritySetting />
-        </div>
+  return (
+    <Fragment>
+      <div className="mb-5">
+        <SecuritySetting />
+      </div>
 
-        {/* Shared Link List */}
-        <div className="mb-5">
-          <ShareLinkSetting />
-        </div>
+      {/* Shared Link List */}
+      <div className="mb-5">
+        <ShareLinkSetting />
+      </div>
 
 
-        {/* XSS configuration link */}
-        <div className="mb-5">
-          <h2 className="border-bottom">{t('security_setting.xss_prevent_setting')}</h2>
-          <div className="text-center">
-            <a style={{ fontSize: 'large' }} href="/admin/markdown/#preventXSS">
-              <i className="fa-fw icon-login"></i> {t('security_setting.xss_prevent_setting_link')}
-            </a>
-          </div>
+      {/* XSS configuration link */}
+      <div className="mb-5">
+        <h2 className="border-bottom">{t('security_setting.xss_prevent_setting')}</h2>
+        <div className="text-center">
+          <a style={{ fontSize: 'large' }} href="/admin/markdown/#preventXSS">
+            <i className="fa-fw icon-login"></i> {t('security_setting.xss_prevent_setting_link')}
+          </a>
         </div>
+      </div>
 
-        <div className="auth-mechanism-configurations">
-          <h2 className="border-bottom">{t('security_setting.Authentication mechanism settings')}</h2>
-          <Nav tabs>
-            <NavItem>
-              <NavLink
-                className={`${activeTab === 'passport-local' && 'active'} `}
-                onClick={() => { this.toggleActiveTab('passport-local') }}
-                href="#passport-local"
-              >
-                <i className="fa fa-users" /> ID/Pass
-              </NavLink>
-            </NavItem>
-            <NavItem>
-              <NavLink
-                className={`${activeTab === 'passport-ldap' && 'active'} `}
-                onClick={() => { this.toggleActiveTab('passport-ldap') }}
-                href="#passport-ldap"
-              >
-                <i className="fa fa-sitemap" /> LDAP
-              </NavLink>
-            </NavItem>
-            <NavItem>
-              <NavLink
-                className={`${activeTab === 'passport-saml' && 'active'} `}
-                onClick={() => { this.toggleActiveTab('passport-saml') }}
-                href="#passport-saml"
-              >
-                <i className="fa fa-key" /> SAML
-              </NavLink>
-            </NavItem>
-            <NavItem>
-              <NavLink
-                className={`${activeTab === 'passport-oidc' && 'active'} `}
-                onClick={() => { this.toggleActiveTab('passport-oidc') }}
-                href="#passport-oidc"
-              >
-                <i className="fa fa-openid" /> OIDC
-              </NavLink>
-            </NavItem>
-            <NavItem>
-              <NavLink
-                className={`${activeTab === 'passport-basic' && 'active'} `}
-                onClick={() => { this.toggleActiveTab('passport-basic') }}
-                href="#passport-basic"
-              >
-                <i className="fa fa-lock" /> BASIC
-              </NavLink>
-            </NavItem>
-            <NavItem>
-              <NavLink
-                className={`${activeTab === 'passport-google' && 'active'} `}
-                onClick={() => { this.toggleActiveTab('passport-google') }}
-                href="#passport-google"
-              >
-                <i className="fa fa-google" /> Google
-              </NavLink>
-            </NavItem>
-            <NavItem>
-              <NavLink
-                className={`${activeTab === 'passport-github' && 'active'} `}
-                onClick={() => { this.toggleActiveTab('passport-github') }}
-                href="#passport-github"
-              >
-                <i className="fa fa-github" /> GitHub
-              </NavLink>
-            </NavItem>
-            <NavItem>
-              <NavLink
-                className={`${activeTab === 'passport-twitter' && 'active'} `}
-                onClick={() => { this.toggleActiveTab('passport-twitter') }}
-                href="#passport-twitter"
-              >
-                <i className="fa fa-twitter" /> Twitter
-              </NavLink>
-            </NavItem>
-            <NavItem>
-              <NavLink
-                className={`${activeTab === 'passport-facebook' && 'active'} `}
-                onClick={() => { this.toggleActiveTab('passport-facebook') }}
-                href="#passport-facebook"
-              >
-                <i className="fa fa-facebook" /> (TBD) Facebook
-              </NavLink>
-            </NavItem>
-          </Nav>
-          <TabContent activeTab={activeTab} className="mt-2">
-            <TabPane tabId="passport-local">
-              {activeComponents.has('passport-local') && <LocalSecuritySetting />}
-            </TabPane>
-            <TabPane tabId="passport-ldap">
-              {activeComponents.has('passport-ldap') && <LdapSecuritySetting />}
-            </TabPane>
-            <TabPane tabId="passport-saml">
-              {activeComponents.has('passport-saml') && <SamlSecuritySetting />}
-            </TabPane>
-            <TabPane tabId="passport-oidc">
-              {activeComponents.has('passport-oidc') && <OidcSecuritySetting />}
-            </TabPane>
-            <TabPane tabId="passport-basic">
-              {activeComponents.has('passport-basic') && <BasicSecuritySetting />}
-            </TabPane>
-            <TabPane tabId="passport-google">
-              {activeComponents.has('passport-google') && <GoogleSecuritySetting />}
-            </TabPane>
-            <TabPane tabId="passport-github">
-              {activeComponents.has('passport-github') && <GitHubSecuritySetting />}
-            </TabPane>
-            <TabPane tabId="passport-twitter">
-              {activeComponents.has('passport-twitter') && <TwitterSecuritySetting />}
-            </TabPane>
-            <TabPane tabId="passport-facebook">
-              {activeComponents.has('passport-facebook') && <FacebookSecuritySetting />}
-            </TabPane>
-          </TabContent>
-        </div>
-      </Fragment>
-    );
-  }
+      <div className="auth-mechanism-configurations">
+        <h2 className="border-bottom">{t('security_setting.Authentication mechanism settings')}</h2>
+        <CustomNavigation navTabMapping={navTabMapping} />
+      </div>
+    </Fragment>
+  );
 
 }
 
 SecurityManagementContents.propTypes = {
   t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
 };
 
-const SecurityManagementContentsWrapper = withUnstatedContainers(SecurityManagementContents, [AppContainer]);
-
-export default withTranslation()(SecurityManagementContentsWrapper);
+export default withTranslation()(SecurityManagementContents);

+ 1 - 1
src/client/js/components/Me/ApiSettings.jsx

@@ -25,7 +25,7 @@ class ApiSettings extends React.Component {
       await appContainer.apiv3Put('/personal-setting/api-token');
 
       await personalContainer.retrievePersonalData();
-      toastSuccess(t('toaster.update_successed', { target: t('personal_settings.update_password') }));
+      toastSuccess(t('toaster.update_successed', { target: t('page_me_apitoken.api_token') }));
     }
     catch (err) {
       toastError(err);

+ 1 - 1
src/client/js/components/Me/PasswordSettings.jsx

@@ -55,7 +55,7 @@ class PasswordSettings extends React.Component {
       });
       this.setState({ oldPassword: '', newPassword: '', newPasswordConfirm: '' });
       await personalContainer.retrievePersonalData();
-      toastSuccess(t('toaster.update_successed', { target: t('personal_settings.update_password') }));
+      toastSuccess(t('toaster.update_successed', { target: t('Password') }));
     }
     catch (err) {
       toastError(err);