]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-19966 Remove list of groups in the users' list
authorguillaume-peoch-sonarsource <guillaume.peoch@sonarsource.com>
Wed, 26 Jul 2023 11:41:22 +0000 (13:41 +0200)
committersonartech <sonartech@sonarsource.com>
Mon, 31 Jul 2023 20:03:32 +0000 (20:03 +0000)
server/sonar-web/src/main/js/api/mocks/UsersServiceMock.ts
server/sonar-web/src/main/js/apps/users/__tests__/UsersApp-it.tsx
server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx [deleted file]
server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx

index 9ea5dbfec9ae29332aafd71aaefc71528679cd40..71f4e22684773fb844783ab9d5db1ab5133e5814 100644 (file)
@@ -57,8 +57,7 @@ const DEFAULT_USERS = [
     sonarQubeLastConnectionDate: '2023-06-27T17:08:59+0200',
     sonarLintLastConnectionDate: '2023-05-27T17:08:59+0200',
     email: 'alice.merveille@wonderland.com',
-    // groups: ['group1', 'group2', 'group3', 'group4'],
-    groupsCount: 4,
+    groupsCount: 2,
   }),
   mockRestUser({
     managed: false,
@@ -339,6 +338,7 @@ export default class UsersServiceMock {
 
   handleAddUserToGroup: typeof addUserToGroup = ({ name }) => {
     this.groups = this.groups.map((g) => (g.name === name ? { ...g, selected: true } : g));
+    this.users.find((u) => u.login === 'alice.merveille')!.groupsCount++;
     return this.reply({});
   };
 
@@ -354,6 +354,7 @@ export default class UsersServiceMock {
       }
       return g;
     });
+    this.users.find((u) => u.login === 'alice.merveille')!.groupsCount--;
     return isDefault
       ? Promise.reject({
           errors: [{ msg: 'Cannot remove Default group' }],
index 0fa5d92e89ec05d53c267fb8b3c3068efd0dfc1e..dc7b33c2f8578a1cdbab68c11fa8f7ea94b5e4a5 100644 (file)
@@ -256,21 +256,6 @@ describe('in non managed mode', () => {
     expect(ui.dialogCreateUser.query()).not.toBeInTheDocument();
   });
 
-  it("should be able to see user's group", async () => {
-    const user = userEvent.setup();
-    renderUsersApp();
-
-    await act(async () =>
-      expect(await within(await ui.aliceRow.find()).findByText('group1')).toBeInTheDocument()
-    );
-    expect(within(ui.aliceRow.get()).queryByText('group4')).not.toBeInTheDocument();
-    expect(within(ui.aliceRow.get()).getByText('more_x.2')).toBeInTheDocument();
-    await user.click(within(ui.aliceRow.get()).getByText('more_x.2'));
-    expect(within(ui.aliceRow.get()).queryByText('more_x.2')).not.toBeInTheDocument();
-    expect(await within(ui.aliceRow.get()).findByText('group4')).toBeInTheDocument();
-    expect(ui.bobUpdateGroupButton.get()).toBeInTheDocument();
-  });
-
   it('should render all users', async () => {
     renderUsersApp();
 
@@ -297,34 +282,44 @@ describe('in non managed mode', () => {
   it('should be able to edit the groups of a user', async () => {
     const user = userEvent.setup();
     renderUsersApp();
+    expect(await within(await ui.aliceRow.find()).findByText('2')).toBeInTheDocument();
 
     await act(async () => user.click(await ui.aliceUpdateGroupButton.find()));
     expect(await ui.dialogGroups.find()).toBeInTheDocument();
 
     expect(ui.getGroups()).toHaveLength(2);
 
-    await user.click(await ui.allFilter.find());
+    await act(async () => user.click(await ui.allFilter.find()));
     expect(ui.getGroups()).toHaveLength(3);
 
-    await user.click(ui.unselectedFilter.get());
+    await act(() => user.click(ui.unselectedFilter.get()));
     expect(ui.reloadButton.query()).not.toBeInTheDocument();
-    await user.click(ui.getGroups()[0]);
+    await act(() => user.click(ui.getGroups()[0]));
     expect(await ui.reloadButton.find()).toBeInTheDocument();
 
-    await user.click(ui.selectedFilter.get());
+    await act(() => user.click(ui.selectedFilter.get()));
     expect(ui.getGroups()).toHaveLength(3);
-    expect(ui.reloadButton.query()).not.toBeInTheDocument();
-    await user.click(ui.getGroups()[1]);
+
+    await act(() => user.click(ui.doneButton.get()));
+    expect(ui.dialogGroups.query()).not.toBeInTheDocument();
+    expect(await within(await ui.aliceRow.find()).findByText('3')).toBeInTheDocument();
+
+    await act(async () => user.click(await ui.aliceUpdateGroupButton.find()));
+
+    await user.click(ui.selectedFilter.get());
+
+    await act(() => user.click(ui.getGroups()[1]));
     expect(await ui.reloadButton.find()).toBeInTheDocument();
-    await user.click(ui.reloadButton.get());
+    await act(() => user.click(ui.reloadButton.get()));
     expect(ui.getGroups()).toHaveLength(2);
 
-    await user.type(within(ui.dialogGroups.get()).getByRole('searchbox'), '3');
+    await act(() => user.type(within(ui.dialogGroups.get()).getByRole('searchbox'), '3'));
 
     expect(ui.getGroups()).toHaveLength(1);
 
     await act(() => user.click(ui.doneButton.get()));
     expect(ui.dialogGroups.query()).not.toBeInTheDocument();
+    expect(await within(await ui.aliceRow.find()).findByText('2')).toBeInTheDocument();
   });
 
   it('should update user', async () => {
diff --git a/server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx b/server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx
deleted file mode 100644 (file)
index d384ffb..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 { RestUser } from '../../../api/users';
-import { ButtonIcon, ButtonLink } from '../../../components/controls/buttons';
-import BulletListIcon from '../../../components/icons/BulletListIcon';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import GroupsForm from './GroupsForm';
-
-interface Props {
-  groups: string[];
-  user: RestUser<'admin'>;
-  manageProvider: string | undefined;
-}
-
-const GROUPS_LIMIT = 3;
-
-export default function UserGroups(props: Props) {
-  const { groups, user, manageProvider } = props;
-
-  const [openForm, setOpenForm] = React.useState(false);
-  const [showMore, setShowMore] = React.useState(false);
-
-  const limit = groups.length > GROUPS_LIMIT ? GROUPS_LIMIT - 1 : GROUPS_LIMIT;
-  return (
-    <ul>
-      {groups.slice(0, limit).map((group) => (
-        <li className="little-spacer-bottom" key={group}>
-          {group}
-        </li>
-      ))}
-      {groups.length > GROUPS_LIMIT &&
-        showMore &&
-        groups.slice(limit).map((group) => (
-          <li className="little-spacer-bottom" key={group}>
-            {group}
-          </li>
-        ))}
-      <li className="little-spacer-bottom">
-        {groups.length > GROUPS_LIMIT && !showMore && (
-          <ButtonLink
-            className="js-user-more-groups spacer-right"
-            onClick={() => setShowMore(!showMore)}
-          >
-            {translateWithParameters('more_x', groups.length - limit)}
-          </ButtonLink>
-        )}
-        {manageProvider === undefined && (
-          <ButtonIcon
-            aria-label={translateWithParameters('users.update_users_groups', user.login)}
-            className="js-user-groups button-small"
-            onClick={() => setOpenForm(true)}
-            tooltip={translate('users.update_groups')}
-          >
-            <BulletListIcon />
-          </ButtonIcon>
-        )}
-      </li>
-      {openForm && <GroupsForm onClose={() => setOpenForm(false)} user={user} />}
-    </ul>
-  );
-}
index 5147301baeb66beedb5067c95a631ab4698a1794..e5c6a7f4c885e5b5683aedc0cb6a17495bc30217 100644 (file)
@@ -23,8 +23,9 @@ import { ButtonIcon } from '../../../components/controls/buttons';
 import BulletListIcon from '../../../components/icons/BulletListIcon';
 import DateFromNow from '../../../components/intl/DateFromNow';
 import LegacyAvatar from '../../../components/ui/LegacyAvatar';
-import { translateWithParameters } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { IdentityProvider } from '../../../types/types';
+import GroupsForm from './GroupsForm';
 import TokensFormModal from './TokensFormModal';
 import UserActions from './UserActions';
 import UserListItemIdentity from './UserListItemIdentity';
@@ -43,6 +44,7 @@ export default function UserListItem(props: UserListItemProps) {
     name,
     login,
     managed,
+    groupsCount,
     tokensCount,
     avatar,
     sonarQubeLastConnectionDate,
@@ -51,6 +53,7 @@ export default function UserListItem(props: UserListItemProps) {
   } = user;
 
   const [openTokenForm, setOpenTokenForm] = React.useState(false);
+  const [openGroupForm, setOpenGroupForm] = React.useState(false);
 
   return (
     <tr>
@@ -74,8 +77,17 @@ export default function UserListItem(props: UserListItemProps) {
         <DateFromNow date={sonarLintLastConnectionDate ?? ''} hourPrecision />
       </td>
       <td className="thin nowrap text-middle">
-        {user.groupsCount}
-        {/* <UserGroups groups={user.groupsCount} manageProvider={manageProvider} user={user} /> */}
+        {groupsCount}
+        {manageProvider === undefined && (
+          <ButtonIcon
+            aria-label={translateWithParameters('users.update_users_groups', user.login)}
+            className="js-user-groups spacer-left button-small"
+            onClick={() => setOpenGroupForm(true)}
+            tooltip={translate('users.update_groups')}
+          >
+            <BulletListIcon />
+          </ButtonIcon>
+        )}
       </td>
       <td className="thin nowrap text-middle">
         {tokensCount}
@@ -96,6 +108,7 @@ export default function UserListItem(props: UserListItemProps) {
       )}
 
       {openTokenForm && <TokensFormModal onClose={() => setOpenTokenForm(false)} user={user} />}
+      {openGroupForm && <GroupsForm onClose={() => setOpenGroupForm(false)} user={user} />}
     </tr>
   );
 }