]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-16242 Better file structure
authorJeremy Davis <jeremy.davis@sonarsource.com>
Wed, 6 Apr 2022 15:14:47 +0000 (17:14 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 13 Apr 2022 20:03:16 +0000 (20:03 +0000)
19 files changed:
server/sonar-web/src/main/js/apps/account/Account.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/account/__tests__/Account-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/account/__tests__/__snapshots__/Account-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/account/components/Account.tsx [deleted file]
server/sonar-web/src/main/js/apps/account/components/Security.tsx [deleted file]
server/sonar-web/src/main/js/apps/account/components/Tokens.tsx [deleted file]
server/sonar-web/src/main/js/apps/account/components/__tests__/Account-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/account/components/__tests__/Security-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/account/components/__tests__/Tokens-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Account-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Security-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Tokens-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/account/routes.ts
server/sonar-web/src/main/js/apps/account/security/Security.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/account/security/Tokens.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/account/security/__tests__/Security-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/account/security/__tests__/Tokens-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/account/security/__tests__/__snapshots__/Security-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/account/security/__tests__/__snapshots__/Tokens-test.tsx.snap [new file with mode: 0644]

diff --git a/server/sonar-web/src/main/js/apps/account/Account.tsx b/server/sonar-web/src/main/js/apps/account/Account.tsx
new file mode 100644 (file)
index 0000000..32a5118
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { Helmet } from 'react-helmet-async';
+import A11ySkipTarget from '../../app/components/a11y/A11ySkipTarget';
+import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext';
+import Suggestions from '../../app/components/embed-docs-modal/Suggestions';
+import handleRequiredAuthentication from '../../helpers/handleRequiredAuthentication';
+import { translate } from '../../helpers/l10n';
+import { CurrentUser, LoggedInUser } from '../../types/users';
+import './account.css';
+import Nav from './components/Nav';
+import UserCard from './components/UserCard';
+
+interface Props {
+  currentUser: CurrentUser;
+}
+
+export class Account extends React.PureComponent<Props> {
+  componentDidMount() {
+    if (!this.props.currentUser.isLoggedIn) {
+      handleRequiredAuthentication();
+    }
+  }
+
+  render() {
+    const { currentUser, children } = this.props;
+
+    if (!currentUser.isLoggedIn) {
+      return null;
+    }
+
+    const title = translate('my_account.page');
+    return (
+      <div id="account-page">
+        <Suggestions suggestions="account" />
+        <Helmet defaultTitle={title} defer={false} titleTemplate={`%s - ${title}`} />
+        <A11ySkipTarget anchor="account_main" />
+        <header className="account-header">
+          <div className="account-container clearfix">
+            <UserCard user={currentUser as LoggedInUser} />
+            <Nav />
+          </div>
+        </header>
+
+        {children}
+      </div>
+    );
+  }
+}
+
+export default withCurrentUserContext(Account);
diff --git a/server/sonar-web/src/main/js/apps/account/__tests__/Account-test.tsx b/server/sonar-web/src/main/js/apps/account/__tests__/Account-test.tsx
new file mode 100644 (file)
index 0000000..98e4f98
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
+import { mockCurrentUser } from '../../../helpers/testMocks';
+import { Account } from '../Account';
+
+jest.mock('../../../helpers/handleRequiredAuthentication', () => jest.fn());
+
+it('should render correctly', () => {
+  const wrapper = shallowRender();
+  expect(wrapper).toMatchSnapshot();
+});
+
+it('should not render for anonymous user', () => {
+  const wrapper = shallowRender({ currentUser: mockCurrentUser({ isLoggedIn: false }) });
+  expect(wrapper.type()).toBeNull();
+  expect(handleRequiredAuthentication).toBeCalled();
+});
+
+function shallowRender(props: Partial<Account['props']> = {}) {
+  return shallow(<Account currentUser={mockCurrentUser({ isLoggedIn: true })} {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/apps/account/__tests__/__snapshots__/Account-test.tsx.snap b/server/sonar-web/src/main/js/apps/account/__tests__/__snapshots__/Account-test.tsx.snap
new file mode 100644 (file)
index 0000000..c346a37
--- /dev/null
@@ -0,0 +1,37 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+  id="account-page"
+>
+  <Suggestions
+    suggestions="account"
+  />
+  <Helmet
+    defaultTitle="my_account.page"
+    defer={false}
+    encodeSpecialCharacters={true}
+    prioritizeSeoTags={false}
+    titleTemplate="%s - my_account.page"
+  />
+  <A11ySkipTarget
+    anchor="account_main"
+  />
+  <header
+    className="account-header"
+  >
+    <div
+      className="account-container clearfix"
+    >
+      <UserCard
+        user={
+          Object {
+            "isLoggedIn": true,
+          }
+        }
+      />
+      <Nav />
+    </div>
+  </header>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/account/components/Account.tsx b/server/sonar-web/src/main/js/apps/account/components/Account.tsx
deleted file mode 100644 (file)
index 672f3fa..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget';
-import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
-import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
-import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
-import { translate } from '../../../helpers/l10n';
-import { CurrentUser, LoggedInUser } from '../../../types/users';
-import '../account.css';
-import Nav from './Nav';
-import UserCard from './UserCard';
-
-interface Props {
-  currentUser: CurrentUser;
-}
-
-export class Account extends React.PureComponent<Props> {
-  componentDidMount() {
-    if (!this.props.currentUser.isLoggedIn) {
-      handleRequiredAuthentication();
-    }
-  }
-
-  render() {
-    const { currentUser, children } = this.props;
-
-    if (!currentUser.isLoggedIn) {
-      return null;
-    }
-
-    const title = translate('my_account.page');
-    return (
-      <div id="account-page">
-        <Suggestions suggestions="account" />
-        <Helmet defaultTitle={title} defer={false} titleTemplate={`%s - ${title}`} />
-        <A11ySkipTarget anchor="account_main" />
-        <header className="account-header">
-          <div className="account-container clearfix">
-            <UserCard user={currentUser as LoggedInUser} />
-            <Nav />
-          </div>
-        </header>
-
-        {children}
-      </div>
-    );
-  }
-}
-
-export default withCurrentUserContext(Account);
diff --git a/server/sonar-web/src/main/js/apps/account/components/Security.tsx b/server/sonar-web/src/main/js/apps/account/components/Security.tsx
deleted file mode 100644 (file)
index 1cc827c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
-import ResetPasswordForm from '../../../components/common/ResetPasswordForm';
-import { translate } from '../../../helpers/l10n';
-import { LoggedInUser } from '../../../types/users';
-import Tokens from './Tokens';
-
-export interface SecurityProps {
-  currentUser: LoggedInUser;
-}
-
-export function Security({ currentUser }: SecurityProps) {
-  return (
-    <div className="account-body account-container">
-      <Helmet defer={false} title={translate('my_account.security')} />
-      <Tokens login={currentUser.login} />
-      {currentUser.local && (
-        <section className="boxed-group">
-          <h2 className="spacer-bottom">{translate('my_profile.password.title')}</h2>
-          <ResetPasswordForm className="boxed-group-inner" user={currentUser} />
-        </section>
-      )}
-    </div>
-  );
-}
-
-export default withCurrentUserContext(Security);
diff --git a/server/sonar-web/src/main/js/apps/account/components/Tokens.tsx b/server/sonar-web/src/main/js/apps/account/components/Tokens.tsx
deleted file mode 100644 (file)
index 44c67d9..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import * as React from 'react';
-import InstanceMessage from '../../../components/common/InstanceMessage';
-import { translate } from '../../../helpers/l10n';
-import TokensForm from '../../users/components/TokensForm';
-
-interface Props {
-  login: string;
-}
-
-export default function Tokens({ login }: Props) {
-  return (
-    <div className="boxed-group">
-      <h2>{translate('users.tokens')}</h2>
-      <div className="boxed-group-inner">
-        <div className="big-spacer-bottom big-spacer-right markdown">
-          <InstanceMessage message={translate('my_account.tokens_description')} />
-        </div>
-
-        <TokensForm deleteConfirmation="modal" login={login} />
-      </div>
-    </div>
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/account/components/__tests__/Account-test.tsx b/server/sonar-web/src/main/js/apps/account/components/__tests__/Account-test.tsx
deleted file mode 100644 (file)
index 4c8e60e..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import handleRequiredAuthentication from '../../../../helpers/handleRequiredAuthentication';
-import { mockCurrentUser } from '../../../../helpers/testMocks';
-import { Account } from '../Account';
-
-jest.mock('../../../../helpers/handleRequiredAuthentication', () => jest.fn());
-
-it('should render correctly', () => {
-  const wrapper = shallowRender();
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should not render for anonymous user', () => {
-  const wrapper = shallowRender({ currentUser: mockCurrentUser({ isLoggedIn: false }) });
-  expect(wrapper.type()).toBeNull();
-  expect(handleRequiredAuthentication).toBeCalled();
-});
-
-function shallowRender(props: Partial<Account['props']> = {}) {
-  return shallow(<Account currentUser={mockCurrentUser({ isLoggedIn: true })} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/apps/account/components/__tests__/Security-test.tsx b/server/sonar-web/src/main/js/apps/account/components/__tests__/Security-test.tsx
deleted file mode 100644 (file)
index 30c1668..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockLoggedInUser } from '../../../../helpers/testMocks';
-import { Security, SecurityProps } from '../Security';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot('local user');
-  expect(shallowRender({ currentUser: mockLoggedInUser({ local: false }) })).toMatchSnapshot(
-    'non-local user'
-  );
-});
-
-function shallowRender(props: Partial<SecurityProps> = {}) {
-  return shallow(<Security currentUser={mockLoggedInUser({ local: true })} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/apps/account/components/__tests__/Tokens-test.tsx b/server/sonar-web/src/main/js/apps/account/components/__tests__/Tokens-test.tsx
deleted file mode 100644 (file)
index 821b507..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import Tokens from '../Tokens';
-
-it('renders', () => {
-  expect(shallow(<Tokens login="user" />)).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Account-test.tsx.snap b/server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Account-test.tsx.snap
deleted file mode 100644 (file)
index c346a37..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  id="account-page"
->
-  <Suggestions
-    suggestions="account"
-  />
-  <Helmet
-    defaultTitle="my_account.page"
-    defer={false}
-    encodeSpecialCharacters={true}
-    prioritizeSeoTags={false}
-    titleTemplate="%s - my_account.page"
-  />
-  <A11ySkipTarget
-    anchor="account_main"
-  />
-  <header
-    className="account-header"
-  >
-    <div
-      className="account-container clearfix"
-    >
-      <UserCard
-        user={
-          Object {
-            "isLoggedIn": true,
-          }
-        }
-      />
-      <Nav />
-    </div>
-  </header>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Security-test.tsx.snap b/server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Security-test.tsx.snap
deleted file mode 100644 (file)
index 28b532f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: local user 1`] = `
-<div
-  className="account-body account-container"
->
-  <Helmet
-    defer={false}
-    encodeSpecialCharacters={true}
-    prioritizeSeoTags={false}
-    title="my_account.security"
-  />
-  <Tokens
-    login="luke"
-  />
-  <section
-    className="boxed-group"
-  >
-    <h2
-      className="spacer-bottom"
-    >
-      my_profile.password.title
-    </h2>
-    <ResetPasswordForm
-      className="boxed-group-inner"
-      user={
-        Object {
-          "groups": Array [],
-          "isLoggedIn": true,
-          "local": true,
-          "login": "luke",
-          "name": "Skywalker",
-          "scmAccounts": Array [],
-        }
-      }
-    />
-  </section>
-</div>
-`;
-
-exports[`should render correctly: non-local user 1`] = `
-<div
-  className="account-body account-container"
->
-  <Helmet
-    defer={false}
-    encodeSpecialCharacters={true}
-    prioritizeSeoTags={false}
-    title="my_account.security"
-  />
-  <Tokens
-    login="luke"
-  />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Tokens-test.tsx.snap b/server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Tokens-test.tsx.snap
deleted file mode 100644 (file)
index 67efe51..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<div
-  className="boxed-group"
->
-  <h2>
-    users.tokens
-  </h2>
-  <div
-    className="boxed-group-inner"
-  >
-    <div
-      className="big-spacer-bottom big-spacer-right markdown"
-    >
-      <InstanceMessage
-        message="my_account.tokens_description"
-      />
-    </div>
-    <TokensForm
-      deleteConfirmation="modal"
-      login="user"
-    />
-  </div>
-</div>
-`;
index 81f047bbb7d349690183a7e34ca7e023742f0f07..618015e79557feba56781ecc71428d4309050e71 100644 (file)
@@ -21,14 +21,14 @@ import { lazyLoadComponent } from '../../components/lazyLoadComponent';
 
 const routes = [
   {
-    component: lazyLoadComponent(() => import('./components/Account')),
+    component: lazyLoadComponent(() => import('./Account')),
     childRoutes: [
       {
         indexRoute: { component: lazyLoadComponent(() => import('./profile/Profile')) }
       },
       {
         path: 'security',
-        component: lazyLoadComponent(() => import('./components/Security'))
+        component: lazyLoadComponent(() => import('./security/Security'))
       },
       {
         path: 'projects',
diff --git a/server/sonar-web/src/main/js/apps/account/security/Security.tsx b/server/sonar-web/src/main/js/apps/account/security/Security.tsx
new file mode 100644 (file)
index 0000000..1cc827c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { Helmet } from 'react-helmet-async';
+import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
+import ResetPasswordForm from '../../../components/common/ResetPasswordForm';
+import { translate } from '../../../helpers/l10n';
+import { LoggedInUser } from '../../../types/users';
+import Tokens from './Tokens';
+
+export interface SecurityProps {
+  currentUser: LoggedInUser;
+}
+
+export function Security({ currentUser }: SecurityProps) {
+  return (
+    <div className="account-body account-container">
+      <Helmet defer={false} title={translate('my_account.security')} />
+      <Tokens login={currentUser.login} />
+      {currentUser.local && (
+        <section className="boxed-group">
+          <h2 className="spacer-bottom">{translate('my_profile.password.title')}</h2>
+          <ResetPasswordForm className="boxed-group-inner" user={currentUser} />
+        </section>
+      )}
+    </div>
+  );
+}
+
+export default withCurrentUserContext(Security);
diff --git a/server/sonar-web/src/main/js/apps/account/security/Tokens.tsx b/server/sonar-web/src/main/js/apps/account/security/Tokens.tsx
new file mode 100644 (file)
index 0000000..44c67d9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import InstanceMessage from '../../../components/common/InstanceMessage';
+import { translate } from '../../../helpers/l10n';
+import TokensForm from '../../users/components/TokensForm';
+
+interface Props {
+  login: string;
+}
+
+export default function Tokens({ login }: Props) {
+  return (
+    <div className="boxed-group">
+      <h2>{translate('users.tokens')}</h2>
+      <div className="boxed-group-inner">
+        <div className="big-spacer-bottom big-spacer-right markdown">
+          <InstanceMessage message={translate('my_account.tokens_description')} />
+        </div>
+
+        <TokensForm deleteConfirmation="modal" login={login} />
+      </div>
+    </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/account/security/__tests__/Security-test.tsx b/server/sonar-web/src/main/js/apps/account/security/__tests__/Security-test.tsx
new file mode 100644 (file)
index 0000000..30c1668
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockLoggedInUser } from '../../../../helpers/testMocks';
+import { Security, SecurityProps } from '../Security';
+
+it('should render correctly', () => {
+  expect(shallowRender()).toMatchSnapshot('local user');
+  expect(shallowRender({ currentUser: mockLoggedInUser({ local: false }) })).toMatchSnapshot(
+    'non-local user'
+  );
+});
+
+function shallowRender(props: Partial<SecurityProps> = {}) {
+  return shallow(<Security currentUser={mockLoggedInUser({ local: true })} {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/apps/account/security/__tests__/Tokens-test.tsx b/server/sonar-web/src/main/js/apps/account/security/__tests__/Tokens-test.tsx
new file mode 100644 (file)
index 0000000..821b507
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import Tokens from '../Tokens';
+
+it('renders', () => {
+  expect(shallow(<Tokens login="user" />)).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/account/security/__tests__/__snapshots__/Security-test.tsx.snap b/server/sonar-web/src/main/js/apps/account/security/__tests__/__snapshots__/Security-test.tsx.snap
new file mode 100644 (file)
index 0000000..28b532f
--- /dev/null
@@ -0,0 +1,55 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: local user 1`] = `
+<div
+  className="account-body account-container"
+>
+  <Helmet
+    defer={false}
+    encodeSpecialCharacters={true}
+    prioritizeSeoTags={false}
+    title="my_account.security"
+  />
+  <Tokens
+    login="luke"
+  />
+  <section
+    className="boxed-group"
+  >
+    <h2
+      className="spacer-bottom"
+    >
+      my_profile.password.title
+    </h2>
+    <ResetPasswordForm
+      className="boxed-group-inner"
+      user={
+        Object {
+          "groups": Array [],
+          "isLoggedIn": true,
+          "local": true,
+          "login": "luke",
+          "name": "Skywalker",
+          "scmAccounts": Array [],
+        }
+      }
+    />
+  </section>
+</div>
+`;
+
+exports[`should render correctly: non-local user 1`] = `
+<div
+  className="account-body account-container"
+>
+  <Helmet
+    defer={false}
+    encodeSpecialCharacters={true}
+    prioritizeSeoTags={false}
+    title="my_account.security"
+  />
+  <Tokens
+    login="luke"
+  />
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/account/security/__tests__/__snapshots__/Tokens-test.tsx.snap b/server/sonar-web/src/main/js/apps/account/security/__tests__/__snapshots__/Tokens-test.tsx.snap
new file mode 100644 (file)
index 0000000..67efe51
--- /dev/null
@@ -0,0 +1,26 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders 1`] = `
+<div
+  className="boxed-group"
+>
+  <h2>
+    users.tokens
+  </h2>
+  <div
+    className="boxed-group-inner"
+  >
+    <div
+      className="big-spacer-bottom big-spacer-right markdown"
+    >
+      <InstanceMessage
+        message="my_account.tokens_description"
+      />
+    </div>
+    <TokensForm
+      deleteConfirmation="modal"
+      login="user"
+    />
+  </div>
+</div>
+`;