aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps
diff options
context:
space:
mode:
authorstanislavh <stanislav.honcharov@sonarsource.com>2022-12-22 12:29:28 +0100
committersonartech <sonartech@sonarsource.com>2022-12-30 20:02:50 +0000
commit959f6e157c0a6da4a09369ce0d78f5e916bb0232 (patch)
tree40873358ef33fa923609ee4defec40885a99d276 /server/sonar-web/src/main/js/apps
parent32ff596c042f0d95ad1b2a575a3867fd6fc775c9 (diff)
downloadsonarqube-959f6e157c0a6da4a09369ce0d78f5e916bb0232.tar.gz
sonarqube-959f6e157c0a6da4a09369ce0d78f5e916bb0232.zip
SONAR-13167 Handle large lists of permission templates
Diffstat (limited to 'server/sonar-web/src/main/js/apps')
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/PermissionTemplatesApp.tsx (renamed from server/sonar-web/src/main/js/apps/permission-templates/components/App.tsx)4
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/Template.tsx274
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/App-test.tsx60
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/PermissionTemplatesApp-it.tsx124
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/Template-test.tsx127
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/App-test.tsx.snap95
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/Template-test.tsx.snap96
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/routes.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.tsx123
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/global/components/App.tsx53
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/AllHoldersList-test.tsx97
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/App-test.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/__snapshots__/AllHoldersList-test.tsx.snap436
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/__snapshots__/App-test.tsx.snap86
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/App.tsx55
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/App-test.tsx.snap124
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/AllHoldersList.tsx (renamed from server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.tsx)89
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/HoldersList.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/SearchForm.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/GroupHolder-test.tsx93
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/HoldersList-test.tsx64
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/PermissionCell-test.tsx89
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/UserHolder-test.tsx68
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/HoldersList-test.tsx.snap328
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/PermissionCell-test.tsx.snap89
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/UserHolder-test.tsx.snap182
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectManagementApp-it.tsx2
27 files changed, 600 insertions, 2173 deletions
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/App.tsx b/server/sonar-web/src/main/js/apps/permission-templates/components/PermissionTemplatesApp.tsx
index fce2ef87a33..220da5a796d 100644
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/permission-templates/components/PermissionTemplatesApp.tsx
@@ -42,7 +42,7 @@ interface State {
permissionTemplates: PermissionTemplate[];
}
-export class App extends React.PureComponent<Props, State> {
+export class PermissionTemplatesApp extends React.PureComponent<Props, State> {
mounted = false;
state: State = {
ready: false,
@@ -121,4 +121,4 @@ export class App extends React.PureComponent<Props, State> {
}
}
-export default withRouter(withAppStateContext(App));
+export default withRouter(withAppStateContext(PermissionTemplatesApp));
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/Template.tsx b/server/sonar-web/src/main/js/apps/permission-templates/components/Template.tsx
index 7e0ad42157c..9842655d55e 100644
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/Template.tsx
+++ b/server/sonar-web/src/main/js/apps/permission-templates/components/Template.tsx
@@ -17,13 +17,14 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { without } from 'lodash';
import * as React from 'react';
import { Helmet } from 'react-helmet-async';
import * as api from '../../../api/permissions';
import { translate } from '../../../helpers/l10n';
-import { PermissionGroup, PermissionTemplate, PermissionUser } from '../../../types/types';
-import HoldersList from '../../permissions/shared/components/HoldersList';
-import SearchForm from '../../permissions/shared/components/SearchForm';
+import { Paging, PermissionGroup, PermissionTemplate, PermissionUser } from '../../../types/types';
+import AllHoldersList from '../../permissions/shared/components/AllHoldersList';
+import { FilterOption } from '../../permissions/shared/components/SearchForm';
import {
convertToPermissionDefinitions,
PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE,
@@ -38,12 +39,14 @@ interface Props {
}
interface State {
- filter: string;
+ filter: FilterOption;
groups: PermissionGroup[];
+ groupsPaging?: Paging;
loading: boolean;
query: string;
selectedPermission?: string;
users: PermissionUser[];
+ usersPaging?: Paging;
}
export default class Template extends React.PureComponent<Props, State> {
@@ -65,84 +68,185 @@ export default class Template extends React.PureComponent<Props, State> {
this.mounted = false;
}
- requestHolders = (realQuery?: string) => {
+ loadUsersAndGroups = (usersPage?: number, groupsPage?: number) => {
this.setState({ loading: true });
const { template } = this.props;
const { query, filter, selectedPermission } = this.state;
- const requests = [];
- const finalQuery = realQuery != null ? realQuery : query;
+ const getUsers: Promise<{ paging?: Paging; users: PermissionUser[] }> =
+ filter !== 'groups'
+ ? api.getPermissionTemplateUsers({
+ templateId: template.id,
+ q: query || null,
+ permission: selectedPermission,
+ p: usersPage,
+ })
+ : Promise.resolve({ paging: undefined, users: [] });
- if (filter !== 'groups') {
- requests.push(api.getPermissionTemplateUsers(template.id, finalQuery, selectedPermission));
- } else {
- requests.push(Promise.resolve([]));
+ const getGroups: Promise<{ paging?: Paging; groups: PermissionGroup[] }> =
+ filter !== 'users'
+ ? api.getPermissionTemplateGroups({
+ templateId: template.id,
+ q: query || null,
+ permission: selectedPermission,
+ p: groupsPage,
+ })
+ : Promise.resolve({ paging: undefined, groups: [] });
+
+ return Promise.all([getUsers, getGroups]);
+ };
+
+ requestHolders = async () => {
+ const [{ users, paging: usersPaging }, { groups, paging: groupsPaging }] =
+ await this.loadUsersAndGroups();
+
+ if (this.mounted) {
+ this.setState({
+ groups,
+ groupsPaging,
+ loading: false,
+ users,
+ usersPaging,
+ });
}
+ };
- if (filter !== 'users') {
- requests.push(api.getPermissionTemplateGroups(template.id, finalQuery, selectedPermission));
- } else {
- requests.push(Promise.resolve([]));
+ onLoadMore = async () => {
+ const { usersPaging, groupsPaging } = this.state;
+ this.setState({
+ loading: true,
+ });
+ const [usersResponse, groupsResponse] = await this.loadUsersAndGroups(
+ usersPaging ? usersPaging.pageIndex + 1 : 1,
+ groupsPaging ? groupsPaging.pageIndex + 1 : 1
+ );
+ if (this.mounted) {
+ this.setState(({ groups, users }) => ({
+ groups: [...groups, ...groupsResponse.groups],
+ groupsPaging: groupsResponse.paging,
+ loading: false,
+ users: [...users, ...usersResponse.users],
+ usersPaging: usersResponse.paging,
+ }));
}
- return Promise.all(requests).then(([users, groups]) => {
- if (this.mounted) {
- this.setState({
- users,
- groups,
- loading: false,
+ };
+
+ removePermissionFromEntity = <T extends { login?: string; name: string; permissions: string[] }>(
+ entities: T[],
+ entity: string,
+ permission: string
+ ): T[] =>
+ entities.map((candidate) =>
+ candidate.name === entity || candidate.login === entity
+ ? { ...candidate, permissions: without(candidate.permissions, permission) }
+ : candidate
+ );
+
+ addPermissionToEntity = <T extends { login?: string; name: string; permissions: string[] }>(
+ entities: T[],
+ entity: string,
+ permission: string
+ ): T[] =>
+ entities.map((candidate) =>
+ candidate.name === entity || candidate.login === entity
+ ? { ...candidate, permissions: [...candidate.permissions, permission] }
+ : candidate
+ );
+
+ grantPermissionToUser = (login: string, permission: string) => {
+ const { template } = this.props;
+ const isProjectCreator = login === '<creator>';
+
+ this.setState(({ users }) => ({
+ users: this.addPermissionToEntity(users, login, permission),
+ }));
+
+ const request = isProjectCreator
+ ? api.addProjectCreatorToTemplate(template.id, permission)
+ : api.grantTemplatePermissionToUser({
+ templateId: template.id,
+ login,
+ permission,
});
- }
+
+ return request.then(this.props.refresh).catch(() => {
+ this.setState(({ users }) => ({
+ users: this.removePermissionFromEntity(users, login, permission),
+ }));
});
};
- handleToggleUser = (user: PermissionUser, permission: string) => {
- if (user.login === '<creator>') {
- return this.handleToggleProjectCreator(user, permission);
- }
+ revokePermissionFromUser = (login: string, permission: string) => {
const { template } = this.props;
- const hasPermission = user.permissions.includes(permission);
- const data: { templateId: string; login: string; permission: string } = {
- templateId: template.id,
- login: user.login,
- permission,
- };
-
- const request = hasPermission
- ? api.revokeTemplatePermissionFromUser(data)
- : api.grantTemplatePermissionToUser(data);
- return request.then(() => this.requestHolders()).then(this.props.refresh);
+ const isProjectCreator = login === '<creator>';
+
+ this.setState(({ users }) => ({
+ users: this.removePermissionFromEntity(users, login, permission),
+ }));
+
+ const request = isProjectCreator
+ ? api.removeProjectCreatorFromTemplate(template.id, permission)
+ : api.revokeTemplatePermissionFromUser({
+ templateId: template.id,
+ login,
+ permission,
+ });
+
+ return request.then(this.props.refresh).catch(() => {
+ this.setState(({ users }) => ({
+ users: this.addPermissionToEntity(users, login, permission),
+ }));
+ });
};
- handleToggleProjectCreator = (user: PermissionUser, permission: string) => {
+ grantPermissionToGroup = (groupName: string, permission: string) => {
const { template } = this.props;
- const hasPermission = user.permissions.includes(permission);
- const request = hasPermission
- ? api.removeProjectCreatorFromTemplate(template.id, permission)
- : api.addProjectCreatorToTemplate(template.id, permission);
- return request.then(() => this.requestHolders()).then(this.props.refresh);
+
+ this.setState(({ groups }) => ({
+ groups: this.addPermissionToEntity(groups, groupName, permission),
+ }));
+
+ return api
+ .grantTemplatePermissionToGroup({
+ templateId: template.id,
+ groupName,
+ permission,
+ })
+ .then(this.props.refresh)
+ .catch(() => {
+ this.setState(({ groups }) => ({
+ groups: this.removePermissionFromEntity(groups, groupName, permission),
+ }));
+ });
};
- handleToggleGroup = (group: PermissionGroup, permission: string) => {
+ revokePermissionFromGroup = (groupName: string, permission: string) => {
const { template } = this.props;
- const hasPermission = group.permissions.includes(permission);
- const data = {
- templateId: template.id,
- groupName: group.name,
- permission,
- };
- const request = hasPermission
- ? api.revokeTemplatePermissionFromGroup(data)
- : api.grantTemplatePermissionToGroup(data);
- return request.then(() => this.requestHolders()).then(this.props.refresh);
+
+ this.setState(({ groups }) => ({
+ groups: this.removePermissionFromEntity(groups, groupName, permission),
+ }));
+
+ return api
+ .revokeTemplatePermissionFromGroup({
+ templateId: template.id,
+ groupName,
+ permission,
+ })
+ .then(this.props.refresh)
+ .catch(() => {
+ this.setState(({ groups }) => ({
+ groups: this.addPermissionToEntity(groups, groupName, permission),
+ }));
+ });
};
handleSearch = (query: string) => {
- this.setState({ query });
- this.requestHolders(query);
+ this.setState({ query }, this.requestHolders);
};
- handleFilter = (filter: string) => {
+ handleFilter = (filter: FilterOption) => {
this.setState({ filter }, this.requestHolders);
};
@@ -169,16 +273,21 @@ export default class Template extends React.PureComponent<Props, State> {
};
render() {
+ const { template, topQualifiers } = this.props;
+ const { users, loading, groups, groupsPaging, usersPaging, selectedPermission, filter, query } =
+ this.state;
const permissions = convertToPermissionDefinitions(
PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE,
'projects_role'
);
- const allUsers = [...this.state.users];
+ const allUsers = [...users];
- const creatorPermissions = this.props.template.permissions
+ const creatorPermissions = template.permissions
.filter((p) => p.withProjectCreator)
.map((p) => p.key);
+ let usersPagingWithCreator = usersPaging;
+
if (this.shouldDisplayCreator(creatorPermissions)) {
const creator = {
login: '<creator>',
@@ -187,38 +296,43 @@ export default class Template extends React.PureComponent<Props, State> {
};
allUsers.unshift(creator);
+ usersPagingWithCreator = usersPaging
+ ? { ...usersPaging, total: usersPaging.total + 1 }
+ : undefined;
}
return (
<div className="page page-limited">
- <Helmet defer={false} title={this.props.template.name} />
+ <Helmet defer={false} title={template.name} />
<TemplateHeader
- loading={this.state.loading}
+ loading={loading}
refresh={this.props.refresh}
- template={this.props.template}
- topQualifiers={this.props.topQualifiers}
+ template={template}
+ topQualifiers={topQualifiers}
/>
- <TemplateDetails template={this.props.template} />
+ <TemplateDetails template={template} />
- <HoldersList
- groups={this.state.groups}
- onSelectPermission={this.handleSelectPermission}
- onToggleGroup={this.handleToggleGroup}
- onToggleUser={this.handleToggleUser}
- permissions={permissions}
- selectedPermission={this.state.selectedPermission}
- showPublicProjectsWarning={true}
+ <AllHoldersList
+ filter={filter}
+ grantPermissionToGroup={this.grantPermissionToGroup}
+ grantPermissionToUser={this.grantPermissionToUser}
+ groups={groups}
+ groupsPaging={groupsPaging}
+ loading={loading}
+ onFilter={this.handleFilter}
+ onLoadMore={this.onLoadMore}
+ onQuery={this.handleSearch}
+ query={query}
+ revokePermissionFromGroup={this.revokePermissionFromGroup}
+ revokePermissionFromUser={this.revokePermissionFromUser}
users={allUsers}
- >
- <SearchForm
- filter={this.state.filter}
- onFilter={this.handleFilter}
- onSearch={this.handleSearch}
- query={this.state.query}
- />
- </HoldersList>
+ usersPaging={usersPagingWithCreator}
+ permissions={permissions}
+ selectedPermission={selectedPermission}
+ onSelectPermission={this.handleSelectPermission}
+ />
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/App-test.tsx
deleted file mode 100644
index 839206fa0a6..00000000000
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/App-test.tsx
+++ /dev/null
@@ -1,60 +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 { mockAppState, mockLocation } from '../../../../helpers/testMocks';
-import { waitAndUpdate } from '../../../../helpers/testUtils';
-import { App } from '../App';
-
-jest.mock('../../../../api/permissions', () => ({
- getPermissionTemplates: jest.fn().mockResolvedValue({
- permissionTemplates: [
- {
- id: '1',
- name: 'Default template',
- description: 'Default permission template',
- createdAt: '2019-02-07T17:23:26+0100',
- updatedAt: '2019-02-07T17:23:26+0100',
- permissions: [
- { key: 'admin', usersCount: 0, groupsCount: 1, withProjectCreator: false },
- { key: 'codeviewer', usersCount: 0, groupsCount: 1, withProjectCreator: false },
- ],
- },
- ],
- defaultTemplates: [{ templateId: '1', qualifier: 'TRK' }],
- permissions: [
- { key: 'admin', name: 'Administer', description: 'Admin permission' },
- { key: 'codeviewer', name: 'See Source Code', description: 'Code viewer permission' },
- ],
- }),
-}));
-
-it('should render correctly', async () => {
- const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<App['props']> = {}) {
- return shallow(
- <App location={mockLocation()} appState={mockAppState({ qualifiers: ['TRK'] })} {...props} />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/PermissionTemplatesApp-it.tsx b/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/PermissionTemplatesApp-it.tsx
new file mode 100644
index 00000000000..aef8dfe04ee
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/PermissionTemplatesApp-it.tsx
@@ -0,0 +1,124 @@
+/*
+ * 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 userEvent from '@testing-library/user-event';
+import React from 'react';
+import { byRole } from 'testing-library-selector';
+import PermissionTemplateServiceMock from '../../../../api/mocks/PermissionTemplateServiceMock';
+import { mockAppState } from '../../../../helpers/testMocks';
+import { renderApp } from '../../../../helpers/testReactTestingUtils';
+import PermissionTemplatesApp from '../PermissionTemplatesApp';
+
+const serviceMock = new PermissionTemplateServiceMock();
+
+beforeEach(() => {
+ serviceMock.reset();
+});
+
+const ui = {
+ templateLink1: byRole('link', { name: 'Permission Template 1' }),
+ adminUserBrowseCheckboxChecked: byRole('checkbox', {
+ name: `checked permission 'projects_role.user' for user 'Admin Admin'`,
+ }),
+ adminUserBrowseCheckboxUnchecked: byRole('checkbox', {
+ name: `unchecked permission 'projects_role.user' for user 'Admin Admin'`,
+ }),
+ adminUserAdministerCheckboxChecked: byRole('checkbox', {
+ name: `checked permission 'projects_role.admin' for user 'Admin Admin'`,
+ }),
+ adminUserAdministerCheckboxUnchecked: byRole('checkbox', {
+ name: `unchecked permission 'projects_role.admin' for user 'Admin Admin'`,
+ }),
+
+ anyoneGroupBrowseCheckboxChecked: byRole('checkbox', {
+ name: `checked permission 'projects_role.user' for group 'Anyone'`,
+ }),
+ anyoneGroupBrowseCheckboxUnchecked: byRole('checkbox', {
+ name: `unchecked permission 'projects_role.user' for group 'Anyone'`,
+ }),
+
+ anyoneGroupCodeviewCheckboxChecked: byRole('checkbox', {
+ name: `checked permission 'projects_role.codeviewer' for group 'Anyone'`,
+ }),
+ anyoneGroupCodeviewCheckboxUnchecked: byRole('checkbox', {
+ name: `unchecked permission 'projects_role.codeviewer' for group 'Anyone'`,
+ }),
+
+ showMoreButton: byRole('button', { name: 'show_more' }),
+ whiteUserBrowseCheckbox: byRole('checkbox', {
+ name: `unchecked permission 'projects_role.user' for user 'White'`,
+ }),
+};
+
+it('grants/revokes permission from users or groups', async () => {
+ const user = userEvent.setup();
+ renderPermissionTemplatesApp();
+
+ await user.click(await ui.templateLink1.find());
+
+ // User
+ expect(ui.adminUserBrowseCheckboxUnchecked.get()).not.toBeChecked();
+ await user.click(ui.adminUserBrowseCheckboxUnchecked.get());
+ expect(ui.adminUserBrowseCheckboxChecked.get()).toBeChecked();
+
+ expect(ui.adminUserAdministerCheckboxChecked.get()).toBeChecked();
+ await user.click(ui.adminUserAdministerCheckboxChecked.get());
+ expect(ui.adminUserAdministerCheckboxUnchecked.get()).not.toBeChecked();
+
+ // Group
+ expect(ui.anyoneGroupBrowseCheckboxUnchecked.get()).not.toBeChecked();
+ await user.click(ui.anyoneGroupBrowseCheckboxUnchecked.get());
+ expect(ui.anyoneGroupBrowseCheckboxChecked.get()).toBeChecked();
+
+ expect(ui.anyoneGroupCodeviewCheckboxChecked.get()).toBeChecked();
+ await user.click(ui.anyoneGroupCodeviewCheckboxChecked.get());
+ expect(ui.anyoneGroupCodeviewCheckboxUnchecked.get()).not.toBeChecked();
+
+ // Handles error on permission change
+ serviceMock.updatePermissionChangeAllowance(false);
+ await user.click(ui.adminUserBrowseCheckboxChecked.get());
+ expect(ui.adminUserBrowseCheckboxChecked.get()).toBeChecked();
+
+ await user.click(ui.anyoneGroupCodeviewCheckboxUnchecked.get());
+ expect(ui.anyoneGroupCodeviewCheckboxUnchecked.get()).not.toBeChecked();
+
+ await user.click(ui.adminUserBrowseCheckboxChecked.get());
+ expect(ui.adminUserBrowseCheckboxChecked.get()).toBeChecked();
+
+ await user.click(ui.adminUserAdministerCheckboxUnchecked.get());
+ expect(ui.adminUserAdministerCheckboxUnchecked.get()).not.toBeChecked();
+});
+
+it('loads more items on Show More', async () => {
+ const user = userEvent.setup();
+ renderPermissionTemplatesApp();
+
+ await user.click(await ui.templateLink1.find());
+
+ expect(ui.whiteUserBrowseCheckbox.query()).not.toBeInTheDocument();
+ await user.click(ui.showMoreButton.get());
+ expect(ui.whiteUserBrowseCheckbox.get()).toBeInTheDocument();
+});
+
+function renderPermissionTemplatesApp() {
+ renderApp('admin/permission_templates', <PermissionTemplatesApp />, {
+ appState: mockAppState({ qualifiers: ['TRK'] }),
+ });
+}
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/Template-test.tsx b/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/Template-test.tsx
deleted file mode 100644
index a06d0fb8bf3..00000000000
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/Template-test.tsx
+++ /dev/null
@@ -1,127 +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 {
- grantTemplatePermissionToGroup,
- grantTemplatePermissionToUser,
- revokeTemplatePermissionFromGroup,
- revokeTemplatePermissionFromUser,
-} from '../../../../api/permissions';
-import Template from '../Template';
-
-jest.mock('../../../../api/permissions', () => ({
- revokeTemplatePermissionFromUser: jest.fn().mockResolvedValue({}),
- grantTemplatePermissionToUser: jest.fn().mockResolvedValue({}),
- grantTemplatePermissionToGroup: jest.fn().mockResolvedValue({}),
- revokeTemplatePermissionFromGroup: jest.fn().mockResolvedValue({}),
- getPermissionTemplateGroups: jest.fn().mockResolvedValue([]),
- getPermissionTemplateUsers: jest.fn().mockResolvedValue([]),
-}));
-
-it('render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('revoke group permission if granted', async () => {
- const wrapper = shallowRender();
- const group = {
- name: 'foo',
- permissions: ['bar'],
- };
- wrapper.setState({
- groups: [group],
- });
- await wrapper.instance().handleToggleGroup(group, 'bar');
- expect(revokeTemplatePermissionFromGroup).toHaveBeenCalledWith({
- groupName: 'foo',
- templateId: '1',
- permission: 'bar',
- });
-});
-
-it('grant group permission', async () => {
- const wrapper = shallowRender();
- const group = {
- name: 'foo',
- permissions: [],
- };
- wrapper.setState({
- groups: [group],
- });
- await wrapper.instance().handleToggleGroup(group, 'bar');
- expect(grantTemplatePermissionToGroup).toHaveBeenCalledWith({
- groupName: 'foo',
- templateId: '1',
- permission: 'bar',
- });
-});
-
-it('revoke user permission if granted', async () => {
- const wrapper = shallowRender();
- const user = {
- login: 'foo',
- name: 'foo',
- permissions: ['bar'],
- };
- wrapper.setState({
- users: [user],
- });
- await wrapper.instance().handleToggleUser(user, 'bar');
- expect(revokeTemplatePermissionFromUser).toHaveBeenCalledWith({
- templateId: '1',
- login: 'foo',
- permission: 'bar',
- });
-});
-
-it('grant user permission', async () => {
- const wrapper = shallowRender();
- const user = {
- login: 'foo',
- name: 'foo',
- permissions: [],
- };
- wrapper.setState({
- users: [user],
- });
- await wrapper.instance().handleToggleUser(user, 'bar');
- expect(grantTemplatePermissionToUser).toHaveBeenCalledWith({
- templateId: '1',
- login: 'foo',
- permission: 'bar',
- });
-});
-
-function shallowRender() {
- return shallow<Template>(
- <Template
- refresh={async () => {}}
- template={{
- id: '1',
- createdAt: '2020-01-01',
- name: 'test',
- defaultFor: [],
- permissions: [],
- }}
- topQualifiers={[]}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/App-test.tsx.snap
deleted file mode 100644
index df6976323cd..00000000000
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/App-test.tsx.snap
+++ /dev/null
@@ -1,95 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div>
- <Suggestions
- suggestions="permission_templates"
- />
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- prioritizeSeoTags={false}
- title="permission_templates.page"
- />
- <Home
- permissionTemplates={[]}
- permissions={[]}
- ready={false}
- refresh={[Function]}
- topQualifiers={
- [
- "TRK",
- ]
- }
- />
-</div>
-`;
-
-exports[`should render correctly 2`] = `
-<div>
- <Suggestions
- suggestions="permission_templates"
- />
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- prioritizeSeoTags={false}
- title="permission_templates.page"
- />
- <Home
- permissionTemplates={
- [
- {
- "createdAt": "2019-02-07T17:23:26+0100",
- "defaultFor": [
- "TRK",
- ],
- "description": "Default permission template",
- "id": "1",
- "name": "Default template",
- "permissions": [
- {
- "description": "Code viewer permission",
- "groupsCount": 1,
- "key": "codeviewer",
- "name": "See Source Code",
- "usersCount": 0,
- "withProjectCreator": false,
- },
- {
- "description": "Admin permission",
- "groupsCount": 1,
- "key": "admin",
- "name": "Administer",
- "usersCount": 0,
- "withProjectCreator": false,
- },
- ],
- "updatedAt": "2019-02-07T17:23:26+0100",
- },
- ]
- }
- permissions={
- [
- {
- "description": "Code viewer permission",
- "key": "codeviewer",
- "name": "See Source Code",
- },
- {
- "description": "Admin permission",
- "key": "admin",
- "name": "Administer",
- },
- ]
- }
- ready={true}
- refresh={[Function]}
- topQualifiers={
- [
- "TRK",
- ]
- }
- />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/Template-test.tsx.snap b/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/Template-test.tsx.snap
deleted file mode 100644
index cc47b3c3113..00000000000
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/Template-test.tsx.snap
+++ /dev/null
@@ -1,96 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`render correctly 1`] = `
-<div
- className="page page-limited"
->
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- prioritizeSeoTags={false}
- title="test"
- />
- <TemplateHeader
- loading={true}
- refresh={[Function]}
- template={
- {
- "createdAt": "2020-01-01",
- "defaultFor": [],
- "id": "1",
- "name": "test",
- "permissions": [],
- }
- }
- topQualifiers={[]}
- />
- <TemplateDetails
- template={
- {
- "createdAt": "2020-01-01",
- "defaultFor": [],
- "id": "1",
- "name": "test",
- "permissions": [],
- }
- }
- />
- <HoldersList
- groups={[]}
- onSelectPermission={[Function]}
- onToggleGroup={[Function]}
- onToggleUser={[Function]}
- permissions={
- [
- {
- "description": "projects_role.user.desc",
- "key": "user",
- "name": "projects_role.user",
- },
- {
- "description": "projects_role.codeviewer.desc",
- "key": "codeviewer",
- "name": "projects_role.codeviewer",
- },
- {
- "description": "projects_role.issueadmin.desc",
- "key": "issueadmin",
- "name": "projects_role.issueadmin",
- },
- {
- "description": "projects_role.securityhotspotadmin.desc",
- "key": "securityhotspotadmin",
- "name": "projects_role.securityhotspotadmin",
- },
- {
- "description": "projects_role.admin.desc",
- "key": "admin",
- "name": "projects_role.admin",
- },
- {
- "description": "projects_role.scan.desc",
- "key": "scan",
- "name": "projects_role.scan",
- },
- ]
- }
- showPublicProjectsWarning={true}
- users={
- [
- {
- "login": "<creator>",
- "name": "permission_templates.project_creators",
- "permissions": [],
- },
- ]
- }
- >
- <SearchForm
- filter="all"
- onFilter={[Function]}
- onSearch={[Function]}
- query=""
- />
- </HoldersList>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/routes.tsx b/server/sonar-web/src/main/js/apps/permission-templates/routes.tsx
index 5b57573de98..94c9098b655 100644
--- a/server/sonar-web/src/main/js/apps/permission-templates/routes.tsx
+++ b/server/sonar-web/src/main/js/apps/permission-templates/routes.tsx
@@ -19,8 +19,8 @@
*/
import React from 'react';
import { Route } from 'react-router-dom';
-import App from './components/App';
+import PermissionTemplatesApp from './components/PermissionTemplatesApp';
-const routes = () => <Route path="permission_templates" element={<App />} />;
+const routes = () => <Route path="permission_templates" element={<PermissionTemplatesApp />} />;
export default routes;
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.tsx b/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.tsx
deleted file mode 100644
index 03512413299..00000000000
--- a/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.tsx
+++ /dev/null
@@ -1,123 +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 withAppStateContext from '../../../../app/components/app-state/withAppStateContext';
-import ListFooter from '../../../../components/controls/ListFooter';
-import { AppState } from '../../../../types/appstate';
-import { ComponentQualifier } from '../../../../types/component';
-import { Paging, PermissionGroup, PermissionUser } from '../../../../types/types';
-import HoldersList from '../../shared/components/HoldersList';
-import SearchForm from '../../shared/components/SearchForm';
-import {
- convertToPermissionDefinitions,
- filterPermissions,
- PERMISSIONS_ORDER_GLOBAL,
-} from '../../utils';
-
-interface StateProps {
- appState: AppState;
-}
-
-interface OwnProps {
- filter: string;
- grantPermissionToGroup: (groupName: string, permission: string) => Promise<void>;
- grantPermissionToUser: (login: string, permission: string) => Promise<void>;
- groups: PermissionGroup[];
- groupsPaging?: Paging;
- loading?: boolean;
- onLoadMore: () => void;
- onFilter: (filter: string) => void;
- onSearch: (query: string) => void;
- query: string;
- revokePermissionFromGroup: (groupName: string, permission: string) => Promise<void>;
- revokePermissionFromUser: (login: string, permission: string) => Promise<void>;
- users: PermissionUser[];
- usersPaging?: Paging;
-}
-
-type Props = StateProps & OwnProps;
-
-export class AllHoldersList extends React.PureComponent<Props> {
- handleToggleUser = (user: PermissionUser, permission: string) => {
- const hasPermission = user.permissions.includes(permission);
- if (hasPermission) {
- return this.props.revokePermissionFromUser(user.login, permission);
- }
- return this.props.grantPermissionToUser(user.login, permission);
- };
-
- handleToggleGroup = (group: PermissionGroup, permission: string) => {
- const hasPermission = group.permissions.includes(permission);
-
- if (hasPermission) {
- return this.props.revokePermissionFromGroup(group.name, permission);
- }
- return this.props.grantPermissionToGroup(group.name, permission);
- };
-
- render() {
- const { appState, filter, groups, groupsPaging, users, usersPaging, loading, query } =
- this.props;
- const l10nPrefix = 'global_permissions';
-
- const hasPortfoliosEnabled = appState.qualifiers.includes(ComponentQualifier.Portfolio);
- const hasApplicationsEnabled = appState.qualifiers.includes(ComponentQualifier.Application);
- const permissions = convertToPermissionDefinitions(
- filterPermissions(PERMISSIONS_ORDER_GLOBAL, hasApplicationsEnabled, hasPortfoliosEnabled),
- l10nPrefix
- );
-
- let count = 0;
- let total = 0;
- if (filter !== 'users') {
- count += groups.length;
- total += groupsPaging ? groupsPaging.total : groups.length;
- }
- if (filter !== 'groups') {
- count += users.length;
- total += usersPaging ? usersPaging.total : users.length;
- }
-
- return (
- <>
- <HoldersList
- filter={filter}
- groups={groups}
- loading={loading}
- onToggleGroup={this.handleToggleGroup}
- onToggleUser={this.handleToggleUser}
- permissions={permissions}
- query={query}
- users={users}
- >
- <SearchForm
- filter={filter}
- onFilter={this.props.onFilter}
- onSearch={this.props.onSearch}
- query={query}
- />
- </HoldersList>
- <ListFooter count={count} loadMore={this.props.onLoadMore} total={total} />
- </>
- );
- }
-}
-
-export default withAppStateContext(AllHoldersList);
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/App.tsx b/server/sonar-web/src/main/js/apps/permissions/global/components/App.tsx
index a412b8f2db8..715cab70c88 100644
--- a/server/sonar-web/src/main/js/apps/permissions/global/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/global/components/App.tsx
@@ -21,15 +21,27 @@ import { without } from 'lodash';
import * as React from 'react';
import { Helmet } from 'react-helmet-async';
import * as api from '../../../../api/permissions';
+import withAppStateContext from '../../../../app/components/app-state/withAppStateContext';
import Suggestions from '../../../../components/embed-docs-modal/Suggestions';
import { translate } from '../../../../helpers/l10n';
+import { AppState } from '../../../../types/appstate';
+import { ComponentQualifier } from '../../../../types/component';
import { Paging, PermissionGroup, PermissionUser } from '../../../../types/types';
+import AllHoldersList from '../../shared/components/AllHoldersList';
+import { FilterOption } from '../../shared/components/SearchForm';
import '../../styles.css';
-import AllHoldersList from './AllHoldersList';
+import {
+ convertToPermissionDefinitions,
+ filterPermissions,
+ PERMISSIONS_ORDER_GLOBAL,
+} from '../../utils';
import PageHeader from './PageHeader';
+interface Props {
+ appState: AppState;
+}
interface State {
- filter: 'all' | 'groups' | 'users';
+ filter: FilterOption;
groups: PermissionGroup[];
groupsPaging?: Paging;
loading: boolean;
@@ -37,11 +49,10 @@ interface State {
users: PermissionUser[];
usersPaging?: Paging;
}
-
-export default class App extends React.PureComponent<{}, State> {
+export class App extends React.PureComponent<Props, State> {
mounted = false;
- constructor(props: {}) {
+ constructor(props: Props) {
super(props);
this.state = {
filter: 'all',
@@ -117,7 +128,7 @@ export default class App extends React.PureComponent<{}, State> {
}, this.stopLoading);
};
- onFilter = (filter: 'all' | 'groups' | 'users') => {
+ onFilter = (filter: FilterOption) => {
this.setState({ filter }, this.loadHolders);
};
@@ -260,28 +271,40 @@ export default class App extends React.PureComponent<{}, State> {
};
render() {
+ const { appState } = this.props;
+ const { filter, groups, groupsPaging, users, usersPaging, loading, query } = this.state;
+
+ const hasPortfoliosEnabled = appState.qualifiers.includes(ComponentQualifier.Portfolio);
+ const hasApplicationsEnabled = appState.qualifiers.includes(ComponentQualifier.Application);
+ const permissions = convertToPermissionDefinitions(
+ filterPermissions(PERMISSIONS_ORDER_GLOBAL, hasApplicationsEnabled, hasPortfoliosEnabled),
+ 'global_permissions'
+ );
return (
<div className="page page-limited">
<Suggestions suggestions="global_permissions" />
<Helmet defer={false} title={translate('global_permissions.permission')} />
- <PageHeader loading={this.state.loading} />
+ <PageHeader loading={loading} />
<AllHoldersList
- filter={this.state.filter}
+ permissions={permissions}
+ filter={filter}
grantPermissionToGroup={this.grantPermissionToGroup}
grantPermissionToUser={this.grantPermissionToUser}
- groups={this.state.groups}
- groupsPaging={this.state.groupsPaging}
- loading={this.state.loading}
+ groups={groups}
+ groupsPaging={groupsPaging}
+ loading={loading}
onFilter={this.onFilter}
onLoadMore={this.onLoadMore}
- onSearch={this.onSearch}
- query={this.state.query}
+ onQuery={this.onSearch}
+ query={query}
revokePermissionFromGroup={this.revokePermissionFromGroup}
revokePermissionFromUser={this.revokePermissionFromUser}
- users={this.state.users}
- usersPaging={this.state.usersPaging}
+ users={users}
+ usersPaging={usersPaging}
/>
</div>
);
}
}
+
+export default withAppStateContext(App);
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/AllHoldersList-test.tsx b/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/AllHoldersList-test.tsx
deleted file mode 100644
index 5a2f9686d8c..00000000000
--- a/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/AllHoldersList-test.tsx
+++ /dev/null
@@ -1,97 +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 { mockPermissionGroup, mockPermissionUser } from '../../../../../helpers/mocks/permissions';
-import { mockAppState } from '../../../../../helpers/testMocks';
-import { ComponentQualifier } from '../../../../../types/component';
-import { AllHoldersList } from '../AllHoldersList';
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot('default');
- expect(shallowRender({ filter: 'users' })).toMatchSnapshot('filter users');
- expect(shallowRender({ filter: 'groups' })).toMatchSnapshot('filter groups');
- expect(
- shallowRender({
- appState: mockAppState({
- qualifiers: [ComponentQualifier.Project, ComponentQualifier.Application],
- }),
- })
- ).toMatchSnapshot('applications available');
- expect(
- shallowRender({
- appState: mockAppState({
- qualifiers: [ComponentQualifier.Project, ComponentQualifier.Portfolio],
- }),
- })
- ).toMatchSnapshot('portfolios available');
-});
-
-it('should correctly toggle user permissions', () => {
- const grantPermissionToUser = jest.fn();
- const revokePermissionFromUser = jest.fn();
- const grantPermission = 'applicationcreator';
- const revokePermission = 'provisioning';
- const user = mockPermissionUser();
- const wrapper = shallowRender({ grantPermissionToUser, revokePermissionFromUser });
- const instance = wrapper.instance();
-
- instance.handleToggleUser(user, grantPermission);
- expect(grantPermissionToUser).toHaveBeenCalledWith(user.login, grantPermission);
-
- instance.handleToggleUser(user, revokePermission);
- expect(revokePermissionFromUser).toHaveBeenCalledWith(user.login, revokePermission);
-});
-
-it('should correctly toggle group permissions', () => {
- const grantPermissionToGroup = jest.fn();
- const revokePermissionFromGroup = jest.fn();
- const grantPermission = 'applicationcreator';
- const revokePermission = 'provisioning';
- const group = mockPermissionGroup();
- const wrapper = shallowRender({ grantPermissionToGroup, revokePermissionFromGroup });
- const instance = wrapper.instance();
-
- instance.handleToggleGroup(group, grantPermission);
- expect(grantPermissionToGroup).toHaveBeenCalledWith(group.name, grantPermission);
-
- instance.handleToggleGroup(group, revokePermission);
- expect(revokePermissionFromGroup).toHaveBeenCalledWith(group.name, revokePermission);
-});
-
-function shallowRender(props: Partial<AllHoldersList['props']> = {}) {
- return shallow<AllHoldersList>(
- <AllHoldersList
- appState={mockAppState({ qualifiers: [ComponentQualifier.Project] })}
- filter=""
- grantPermissionToGroup={jest.fn()}
- grantPermissionToUser={jest.fn()}
- groups={[mockPermissionGroup()]}
- onLoadMore={jest.fn()}
- onFilter={jest.fn()}
- onSearch={jest.fn()}
- query=""
- revokePermissionFromGroup={jest.fn()}
- revokePermissionFromUser={jest.fn()}
- users={[mockPermissionUser()]}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/App-test.tsx
index fbece66cf41..11dbd9998e5 100644
--- a/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/App-test.tsx
@@ -25,9 +25,10 @@ import {
revokePermissionFromGroup,
revokePermissionFromUser,
} from '../../../../../api/permissions';
+import { mockAppState } from '../../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../../helpers/testUtils';
import { ANYONE } from '../../../shared/components/GroupHolder';
-import App from '../App';
+import { App } from '../App';
jest.mock('../../../../../api/permissions', () => ({
getGlobalPermissionsGroups: jest.fn().mockResolvedValue({
@@ -130,5 +131,5 @@ describe('should manage state correctly', () => {
});
function shallowRender(props: Partial<App['props']> = {}) {
- return shallow<App>(<App {...props} />);
+ return shallow<App>(<App appState={mockAppState()} {...props} />);
}
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/__snapshots__/AllHoldersList-test.tsx.snap b/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/__snapshots__/AllHoldersList-test.tsx.snap
deleted file mode 100644
index 829c3a7c22d..00000000000
--- a/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/__snapshots__/AllHoldersList-test.tsx.snap
+++ /dev/null
@@ -1,436 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: applications available 1`] = `
-<Fragment>
- <HoldersList
- filter=""
- groups={
- [
- {
- "name": "sonar-admins",
- "permissions": [
- "provisioning",
- ],
- },
- ]
- }
- onToggleGroup={[Function]}
- onToggleUser={[Function]}
- permissions={
- [
- {
- "description": "global_permissions.admin.desc",
- "key": "admin",
- "name": "global_permissions.admin",
- },
- {
- "category": "administer",
- "permissions": [
- {
- "description": "global_permissions.gateadmin.desc",
- "key": "gateadmin",
- "name": "global_permissions.gateadmin",
- },
- {
- "description": "global_permissions.profileadmin.desc",
- "key": "profileadmin",
- "name": "global_permissions.profileadmin",
- },
- ],
- },
- {
- "description": "global_permissions.scan.desc",
- "key": "scan",
- "name": "global_permissions.scan",
- },
- {
- "category": "creator",
- "permissions": [
- {
- "description": "global_permissions.provisioning.desc",
- "key": "provisioning",
- "name": "global_permissions.provisioning",
- },
- {
- "description": "global_permissions.applicationcreator.desc",
- "key": "applicationcreator",
- "name": "global_permissions.applicationcreator",
- },
- ],
- },
- ]
- }
- query=""
- users={
- [
- {
- "active": true,
- "local": true,
- "login": "john.doe",
- "name": "johndoe",
- "permissions": [
- "provisioning",
- ],
- },
- ]
- }
- >
- <SearchForm
- filter=""
- onFilter={[MockFunction]}
- onSearch={[MockFunction]}
- query=""
- />
- </HoldersList>
- <ListFooter
- count={2}
- loadMore={[MockFunction]}
- total={2}
- />
-</Fragment>
-`;
-
-exports[`should render correctly: default 1`] = `
-<Fragment>
- <HoldersList
- filter=""
- groups={
- [
- {
- "name": "sonar-admins",
- "permissions": [
- "provisioning",
- ],
- },
- ]
- }
- onToggleGroup={[Function]}
- onToggleUser={[Function]}
- permissions={
- [
- {
- "description": "global_permissions.admin.desc",
- "key": "admin",
- "name": "global_permissions.admin",
- },
- {
- "category": "administer",
- "permissions": [
- {
- "description": "global_permissions.gateadmin.desc",
- "key": "gateadmin",
- "name": "global_permissions.gateadmin",
- },
- {
- "description": "global_permissions.profileadmin.desc",
- "key": "profileadmin",
- "name": "global_permissions.profileadmin",
- },
- ],
- },
- {
- "description": "global_permissions.scan.desc",
- "key": "scan",
- "name": "global_permissions.scan",
- },
- {
- "category": "creator",
- "permissions": [
- {
- "description": "global_permissions.provisioning.desc",
- "key": "provisioning",
- "name": "global_permissions.provisioning",
- },
- ],
- },
- ]
- }
- query=""
- users={
- [
- {
- "active": true,
- "local": true,
- "login": "john.doe",
- "name": "johndoe",
- "permissions": [
- "provisioning",
- ],
- },
- ]
- }
- >
- <SearchForm
- filter=""
- onFilter={[MockFunction]}
- onSearch={[MockFunction]}
- query=""
- />
- </HoldersList>
- <ListFooter
- count={2}
- loadMore={[MockFunction]}
- total={2}
- />
-</Fragment>
-`;
-
-exports[`should render correctly: filter groups 1`] = `
-<Fragment>
- <HoldersList
- filter="groups"
- groups={
- [
- {
- "name": "sonar-admins",
- "permissions": [
- "provisioning",
- ],
- },
- ]
- }
- onToggleGroup={[Function]}
- onToggleUser={[Function]}
- permissions={
- [
- {
- "description": "global_permissions.admin.desc",
- "key": "admin",
- "name": "global_permissions.admin",
- },
- {
- "category": "administer",
- "permissions": [
- {
- "description": "global_permissions.gateadmin.desc",
- "key": "gateadmin",
- "name": "global_permissions.gateadmin",
- },
- {
- "description": "global_permissions.profileadmin.desc",
- "key": "profileadmin",
- "name": "global_permissions.profileadmin",
- },
- ],
- },
- {
- "description": "global_permissions.scan.desc",
- "key": "scan",
- "name": "global_permissions.scan",
- },
- {
- "category": "creator",
- "permissions": [
- {
- "description": "global_permissions.provisioning.desc",
- "key": "provisioning",
- "name": "global_permissions.provisioning",
- },
- ],
- },
- ]
- }
- query=""
- users={
- [
- {
- "active": true,
- "local": true,
- "login": "john.doe",
- "name": "johndoe",
- "permissions": [
- "provisioning",
- ],
- },
- ]
- }
- >
- <SearchForm
- filter="groups"
- onFilter={[MockFunction]}
- onSearch={[MockFunction]}
- query=""
- />
- </HoldersList>
- <ListFooter
- count={1}
- loadMore={[MockFunction]}
- total={1}
- />
-</Fragment>
-`;
-
-exports[`should render correctly: filter users 1`] = `
-<Fragment>
- <HoldersList
- filter="users"
- groups={
- [
- {
- "name": "sonar-admins",
- "permissions": [
- "provisioning",
- ],
- },
- ]
- }
- onToggleGroup={[Function]}
- onToggleUser={[Function]}
- permissions={
- [
- {
- "description": "global_permissions.admin.desc",
- "key": "admin",
- "name": "global_permissions.admin",
- },
- {
- "category": "administer",
- "permissions": [
- {
- "description": "global_permissions.gateadmin.desc",
- "key": "gateadmin",
- "name": "global_permissions.gateadmin",
- },
- {
- "description": "global_permissions.profileadmin.desc",
- "key": "profileadmin",
- "name": "global_permissions.profileadmin",
- },
- ],
- },
- {
- "description": "global_permissions.scan.desc",
- "key": "scan",
- "name": "global_permissions.scan",
- },
- {
- "category": "creator",
- "permissions": [
- {
- "description": "global_permissions.provisioning.desc",
- "key": "provisioning",
- "name": "global_permissions.provisioning",
- },
- ],
- },
- ]
- }
- query=""
- users={
- [
- {
- "active": true,
- "local": true,
- "login": "john.doe",
- "name": "johndoe",
- "permissions": [
- "provisioning",
- ],
- },
- ]
- }
- >
- <SearchForm
- filter="users"
- onFilter={[MockFunction]}
- onSearch={[MockFunction]}
- query=""
- />
- </HoldersList>
- <ListFooter
- count={1}
- loadMore={[MockFunction]}
- total={1}
- />
-</Fragment>
-`;
-
-exports[`should render correctly: portfolios available 1`] = `
-<Fragment>
- <HoldersList
- filter=""
- groups={
- [
- {
- "name": "sonar-admins",
- "permissions": [
- "provisioning",
- ],
- },
- ]
- }
- onToggleGroup={[Function]}
- onToggleUser={[Function]}
- permissions={
- [
- {
- "description": "global_permissions.admin.desc",
- "key": "admin",
- "name": "global_permissions.admin",
- },
- {
- "category": "administer",
- "permissions": [
- {
- "description": "global_permissions.gateadmin.desc",
- "key": "gateadmin",
- "name": "global_permissions.gateadmin",
- },
- {
- "description": "global_permissions.profileadmin.desc",
- "key": "profileadmin",
- "name": "global_permissions.profileadmin",
- },
- ],
- },
- {
- "description": "global_permissions.scan.desc",
- "key": "scan",
- "name": "global_permissions.scan",
- },
- {
- "category": "creator",
- "permissions": [
- {
- "description": "global_permissions.provisioning.desc",
- "key": "provisioning",
- "name": "global_permissions.provisioning",
- },
- {
- "description": "global_permissions.portfoliocreator.desc",
- "key": "portfoliocreator",
- "name": "global_permissions.portfoliocreator",
- },
- ],
- },
- ]
- }
- query=""
- users={
- [
- {
- "active": true,
- "local": true,
- "login": "john.doe",
- "name": "johndoe",
- "permissions": [
- "provisioning",
- ],
- },
- ]
- }
- >
- <SearchForm
- filter=""
- onFilter={[MockFunction]}
- onSearch={[MockFunction]}
- query=""
- />
- </HoldersList>
- <ListFooter
- count={2}
- loadMore={[MockFunction]}
- total={2}
- />
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/__snapshots__/App-test.tsx.snap
index d53531cfe3d..5017c675591 100644
--- a/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/__snapshots__/App-test.tsx.snap
@@ -16,7 +16,7 @@ exports[`should render correctly 1`] = `
<PageHeader
loading={true}
/>
- <withAppStateContext(AllHoldersList)
+ <AllHoldersList
filter="all"
grantPermissionToGroup={[Function]}
grantPermissionToUser={[Function]}
@@ -24,7 +24,46 @@ exports[`should render correctly 1`] = `
loading={true}
onFilter={[Function]}
onLoadMore={[Function]}
- onSearch={[Function]}
+ onQuery={[Function]}
+ permissions={
+ [
+ {
+ "description": "global_permissions.admin.desc",
+ "key": "admin",
+ "name": "global_permissions.admin",
+ },
+ {
+ "category": "administer",
+ "permissions": [
+ {
+ "description": "global_permissions.gateadmin.desc",
+ "key": "gateadmin",
+ "name": "global_permissions.gateadmin",
+ },
+ {
+ "description": "global_permissions.profileadmin.desc",
+ "key": "profileadmin",
+ "name": "global_permissions.profileadmin",
+ },
+ ],
+ },
+ {
+ "description": "global_permissions.scan.desc",
+ "key": "scan",
+ "name": "global_permissions.scan",
+ },
+ {
+ "category": "creator",
+ "permissions": [
+ {
+ "description": "global_permissions.provisioning.desc",
+ "key": "provisioning",
+ "name": "global_permissions.provisioning",
+ },
+ ],
+ },
+ ]
+ }
query=""
revokePermissionFromGroup={[Function]}
revokePermissionFromUser={[Function]}
@@ -49,7 +88,7 @@ exports[`should render correctly 2`] = `
<PageHeader
loading={false}
/>
- <withAppStateContext(AllHoldersList)
+ <AllHoldersList
filter="all"
grantPermissionToGroup={[Function]}
grantPermissionToUser={[Function]}
@@ -81,7 +120,46 @@ exports[`should render correctly 2`] = `
loading={false}
onFilter={[Function]}
onLoadMore={[Function]}
- onSearch={[Function]}
+ onQuery={[Function]}
+ permissions={
+ [
+ {
+ "description": "global_permissions.admin.desc",
+ "key": "admin",
+ "name": "global_permissions.admin",
+ },
+ {
+ "category": "administer",
+ "permissions": [
+ {
+ "description": "global_permissions.gateadmin.desc",
+ "key": "gateadmin",
+ "name": "global_permissions.gateadmin",
+ },
+ {
+ "description": "global_permissions.profileadmin.desc",
+ "key": "profileadmin",
+ "name": "global_permissions.profileadmin",
+ },
+ ],
+ },
+ {
+ "description": "global_permissions.scan.desc",
+ "key": "scan",
+ "name": "global_permissions.scan",
+ },
+ {
+ "category": "creator",
+ "permissions": [
+ {
+ "description": "global_permissions.provisioning.desc",
+ "key": "provisioning",
+ "name": "global_permissions.provisioning",
+ },
+ ],
+ },
+ ]
+ }
query=""
revokePermissionFromGroup={[Function]}
revokePermissionFromUser={[Function]}
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/App.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/App.tsx
index 692896eb771..5de217f0141 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/App.tsx
@@ -25,8 +25,10 @@ import withComponentContext from '../../../../app/components/componentContext/wi
import VisibilitySelector from '../../../../components/common/VisibilitySelector';
import { translate } from '../../../../helpers/l10n';
import { Component, Paging, PermissionGroup, PermissionUser } from '../../../../types/types';
+import AllHoldersList from '../../shared/components/AllHoldersList';
+import { FilterOption } from '../../shared/components/SearchForm';
import '../../styles.css';
-import AllHoldersList from './AllHoldersList';
+import { convertToPermissionDefinitions, PERMISSIONS_ORDER_BY_QUALIFIER } from '../../utils';
import PageHeader from './PageHeader';
import PublicProjectDisclaimer from './PublicProjectDisclaimer';
@@ -37,7 +39,7 @@ interface Props {
interface State {
disclaimer: boolean;
- filter: string;
+ filter: FilterOption;
groups: PermissionGroup[];
groupsPaging?: Paging;
loading: boolean;
@@ -138,7 +140,7 @@ export class App extends React.PureComponent<Props, State> {
}, this.stopLoading);
};
- handleFilterChange = (filter: string) => {
+ handleFilterChange = (filter: FilterOption) => {
if (this.mounted) {
this.setState({ filter }, this.loadHolders);
}
@@ -340,18 +342,31 @@ export class App extends React.PureComponent<Props, State> {
render() {
const { component } = this.props;
+ const {
+ filter,
+ groups,
+ disclaimer,
+ loading,
+ selectedPermission,
+ query,
+ users,
+ usersPaging,
+ groupsPaging,
+ } = this.state;
const canTurnToPrivate =
component.configuration && component.configuration.canUpdateProjectVisibilityToPrivate;
+ let order = PERMISSIONS_ORDER_BY_QUALIFIER[component.qualifier];
+ if (component.visibility === 'public') {
+ order = without(order, 'user', 'codeviewer');
+ }
+ const permissions = convertToPermissionDefinitions(order, 'projects_role');
+
return (
<div className="page page-limited" id="project-permissions-page">
<Helmet defer={false} title={translate('permissions.page')} />
- <PageHeader
- component={component}
- loadHolders={this.loadHolders}
- loading={this.state.loading}
- />
+ <PageHeader component={component} loadHolders={this.loadHolders} loading={loading} />
<div>
<VisibilitySelector
canTurnToPrivate={canTurnToPrivate}
@@ -359,7 +374,7 @@ export class App extends React.PureComponent<Props, State> {
onChange={this.handleVisibilityChange}
visibility={component.visibility}
/>
- {this.state.disclaimer && (
+ {disclaimer && (
<PublicProjectDisclaimer
component={component}
onClose={this.closeDisclaimer}
@@ -368,22 +383,22 @@ export class App extends React.PureComponent<Props, State> {
)}
</div>
<AllHoldersList
- component={component}
- filter={this.state.filter}
+ filter={filter}
grantPermissionToGroup={this.grantPermissionToGroup}
grantPermissionToUser={this.grantPermissionToUser}
- groups={this.state.groups}
- groupsPaging={this.state.groupsPaging}
- onFilterChange={this.handleFilterChange}
+ groups={groups}
+ groupsPaging={groupsPaging}
+ onFilter={this.handleFilterChange}
onLoadMore={this.onLoadMore}
- onPermissionSelect={this.handlePermissionSelect}
- onQueryChange={this.handleQueryChange}
- query={this.state.query}
+ onSelectPermission={this.handlePermissionSelect}
+ onQuery={this.handleQueryChange}
+ query={query}
revokePermissionFromGroup={this.revokePermissionFromGroup}
revokePermissionFromUser={this.revokePermissionFromUser}
- selectedPermission={this.state.selectedPermission}
- users={this.state.users}
- usersPaging={this.state.usersPaging}
+ selectedPermission={selectedPermission}
+ users={users}
+ usersPaging={usersPaging}
+ permissions={permissions}
/>
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/App-test.tsx.snap
index 336c8df9469..de21fda0f30 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/App-test.tsx.snap
@@ -44,36 +44,48 @@ exports[`should render correctly 1`] = `
/>
</div>
<AllHoldersList
- component={
- {
- "breadcrumbs": [],
- "key": "my-project",
- "name": "MyProject",
- "qualifier": "TRK",
- "qualityGate": {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": [
- {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": [],
- }
- }
filter="all"
grantPermissionToGroup={[Function]}
grantPermissionToUser={[Function]}
groups={[]}
- onFilterChange={[Function]}
+ onFilter={[Function]}
onLoadMore={[Function]}
- onPermissionSelect={[Function]}
- onQueryChange={[Function]}
+ onQuery={[Function]}
+ onSelectPermission={[Function]}
+ permissions={
+ [
+ {
+ "description": "projects_role.user.desc",
+ "key": "user",
+ "name": "projects_role.user",
+ },
+ {
+ "description": "projects_role.codeviewer.desc",
+ "key": "codeviewer",
+ "name": "projects_role.codeviewer",
+ },
+ {
+ "description": "projects_role.issueadmin.desc",
+ "key": "issueadmin",
+ "name": "projects_role.issueadmin",
+ },
+ {
+ "description": "projects_role.securityhotspotadmin.desc",
+ "key": "securityhotspotadmin",
+ "name": "projects_role.securityhotspotadmin",
+ },
+ {
+ "description": "projects_role.admin.desc",
+ "key": "admin",
+ "name": "projects_role.admin",
+ },
+ {
+ "description": "projects_role.scan.desc",
+ "key": "scan",
+ "name": "projects_role.scan",
+ },
+ ]
+ }
query=""
revokePermissionFromGroup={[Function]}
revokePermissionFromUser={[Function]}
@@ -126,28 +138,6 @@ exports[`should render correctly 2`] = `
/>
</div>
<AllHoldersList
- component={
- {
- "breadcrumbs": [],
- "key": "my-project",
- "name": "MyProject",
- "qualifier": "TRK",
- "qualityGate": {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": [
- {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": [],
- }
- }
filter="all"
grantPermissionToGroup={[Function]}
grantPermissionToUser={[Function]}
@@ -176,10 +166,44 @@ exports[`should render correctly 2`] = `
"total": 2,
}
}
- onFilterChange={[Function]}
+ onFilter={[Function]}
onLoadMore={[Function]}
- onPermissionSelect={[Function]}
- onQueryChange={[Function]}
+ onQuery={[Function]}
+ onSelectPermission={[Function]}
+ permissions={
+ [
+ {
+ "description": "projects_role.user.desc",
+ "key": "user",
+ "name": "projects_role.user",
+ },
+ {
+ "description": "projects_role.codeviewer.desc",
+ "key": "codeviewer",
+ "name": "projects_role.codeviewer",
+ },
+ {
+ "description": "projects_role.issueadmin.desc",
+ "key": "issueadmin",
+ "name": "projects_role.issueadmin",
+ },
+ {
+ "description": "projects_role.securityhotspotadmin.desc",
+ "key": "securityhotspotadmin",
+ "name": "projects_role.securityhotspotadmin",
+ },
+ {
+ "description": "projects_role.admin.desc",
+ "key": "admin",
+ "name": "projects_role.admin",
+ },
+ {
+ "description": "projects_role.scan.desc",
+ "key": "scan",
+ "name": "projects_role.scan",
+ },
+ ]
+ }
query=""
revokePermissionFromGroup={[Function]}
revokePermissionFromUser={[Function]}
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.tsx b/server/sonar-web/src/main/js/apps/permissions/shared/components/AllHoldersList.tsx
index 3da32067a8b..ba781321cc8 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/components/AllHoldersList.tsx
@@ -17,31 +17,36 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { without } from 'lodash';
import * as React from 'react';
import ListFooter from '../../../../components/controls/ListFooter';
-import { Component, Paging, PermissionGroup, PermissionUser } from '../../../../types/types';
+import {
+ Paging,
+ PermissionDefinition,
+ PermissionDefinitionGroup,
+ PermissionGroup,
+ PermissionUser,
+} from '../../../../types/types';
import HoldersList from '../../shared/components/HoldersList';
-import SearchForm from '../../shared/components/SearchForm';
-import { convertToPermissionDefinitions, PERMISSIONS_ORDER_BY_QUALIFIER } from '../../utils';
+import SearchForm, { FilterOption } from '../../shared/components/SearchForm';
interface Props {
- component: Component;
- filter: string;
- grantPermissionToGroup: (group: string, permission: string) => Promise<void>;
- grantPermissionToUser: (user: string, permission: string) => Promise<void>;
+ filter: FilterOption;
+ query: string;
+ onFilter: (filter: string) => void;
+ onQuery: (query: string) => void;
groups: PermissionGroup[];
groupsPaging?: Paging;
- onLoadMore: () => void;
- onFilterChange: (filter: string) => void;
- onPermissionSelect: (permissions?: string) => void;
- onQueryChange: (query: string) => void;
- query: string;
revokePermissionFromGroup: (group: string, permission: string) => Promise<void>;
- revokePermissionFromUser: (user: string, permission: string) => Promise<void>;
- selectedPermission?: string;
+ grantPermissionToGroup: (group: string, permission: string) => Promise<void>;
users: PermissionUser[];
usersPaging?: Paging;
+ revokePermissionFromUser: (user: string, permission: string) => Promise<void>;
+ grantPermissionToUser: (user: string, permission: string) => Promise<void>;
+ permissions: Array<PermissionDefinition | PermissionDefinitionGroup>;
+ onLoadMore: () => void;
+ selectedPermission?: string;
+ onSelectPermission?: (permissions?: string) => void;
+ loading?: boolean;
}
export default class AllHoldersList extends React.PureComponent<Props> {
@@ -50,9 +55,8 @@ export default class AllHoldersList extends React.PureComponent<Props> {
if (hasPermission) {
return this.props.revokePermissionFromUser(user.login, permission);
- } else {
- return this.props.grantPermissionToUser(user.login, permission);
}
+ return this.props.grantPermissionToUser(user.login, permission);
};
handleToggleGroup = (group: PermissionGroup, permission: string) => {
@@ -60,29 +64,13 @@ export default class AllHoldersList extends React.PureComponent<Props> {
if (hasPermission) {
return this.props.revokePermissionFromGroup(group.name, permission);
- } else {
- return this.props.grantPermissionToGroup(group.name, permission);
}
- };
- handleSelectPermission = (permission?: string) => {
- this.props.onPermissionSelect(permission);
+ return this.props.grantPermissionToGroup(group.name, permission);
};
- render() {
- const {
- component: { qualifier, visibility },
- filter,
- groups,
- groupsPaging,
- users,
- usersPaging,
- } = this.props;
- let order = PERMISSIONS_ORDER_BY_QUALIFIER[qualifier];
- if (visibility === 'public') {
- order = without(order, 'user', 'codeviewer');
- }
- const permissions = convertToPermissionDefinitions(order, 'projects_role');
+ getPaging = () => {
+ const { filter, groups, groupsPaging, users, usersPaging } = this.props;
let count = 0;
let total = 0;
@@ -95,25 +83,32 @@ export default class AllHoldersList extends React.PureComponent<Props> {
total += usersPaging ? usersPaging.total : users.length;
}
+ return { count, total };
+ };
+
+ render() {
+ const { filter, query, groups, users, permissions, selectedPermission, loading } = this.props;
+ const { count, total } = this.getPaging();
+
return (
<>
<HoldersList
- filter={this.props.filter}
- groups={this.props.groups}
- isComponentPrivate={visibility !== 'public'}
- onSelectPermission={this.handleSelectPermission}
+ loading={loading}
+ filter={filter}
+ groups={groups}
+ onSelectPermission={this.props.onSelectPermission}
onToggleGroup={this.handleToggleGroup}
onToggleUser={this.handleToggleUser}
permissions={permissions}
- query={this.props.query}
- selectedPermission={this.props.selectedPermission}
- users={this.props.users}
+ query={query}
+ selectedPermission={selectedPermission}
+ users={users}
>
<SearchForm
- filter={this.props.filter}
- onFilter={this.props.onFilterChange}
- onSearch={this.props.onQueryChange}
- query={this.props.query}
+ filter={filter}
+ onFilter={this.props.onFilter}
+ onSearch={this.props.onQuery}
+ query={query}
/>
</HoldersList>
<ListFooter count={count} loadMore={this.props.onLoadMore} total={total} />
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/HoldersList.tsx b/server/sonar-web/src/main/js/apps/permissions/shared/components/HoldersList.tsx
index 77336553bf5..3699486e725 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/HoldersList.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/components/HoldersList.tsx
@@ -131,6 +131,7 @@ export default class HoldersList extends React.PureComponent<Props, State> {
}
return item.name;
});
+
const [itemWithPermissions, itemWithoutPermissions] = partition(items, (item) =>
this.getItemInitialPermissionsCount(item)
);
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/SearchForm.tsx b/server/sonar-web/src/main/js/apps/permissions/shared/components/SearchForm.tsx
index e46ed4a4cb6..b4339b45643 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/SearchForm.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/components/SearchForm.tsx
@@ -22,9 +22,10 @@ import ButtonToggle from '../../../../components/controls/ButtonToggle';
import SearchBox from '../../../../components/controls/SearchBox';
import { translate } from '../../../../helpers/l10n';
+export type FilterOption = 'all' | 'users' | 'groups';
interface Props {
- filter: string;
- onFilter: (value: string) => void;
+ filter: FilterOption;
+ onFilter: (value: FilterOption) => void;
onSearch: (value: string) => void;
query: string;
}
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/GroupHolder-test.tsx b/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/GroupHolder-test.tsx
deleted file mode 100644
index 3f4a2f82ff2..00000000000
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/GroupHolder-test.tsx
+++ /dev/null
@@ -1,93 +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 { render, screen, waitFor } from '@testing-library/react';
-import * as React from 'react';
-import { mockPermissionGroup } from '../../../../../helpers/mocks/permissions';
-import { Permissions } from '../../../../../types/permissions';
-import GroupHolder, { ANYONE } from '../GroupHolder';
-
-it('should disable PermissionCell checkboxes when waiting for the promise to return', async () => {
- renderComponent();
-
- const checkbox = screen.getAllByRole('checkbox')[0];
- expect(checkbox).not.toHaveClass('disabled');
- checkbox.click();
-
- await waitFor(() => {
- expect(checkbox).toHaveClass('disabled');
- });
-
- await waitFor(() => {
- expect(checkbox).not.toHaveClass('disabled');
- });
-});
-
-it('should disable all PermissionCell checkboxes for group "Anyone" for a private project', () => {
- renderComponent({ isComponentPrivate: true });
-
- const checkboxes = screen.getAllByRole('checkbox');
-
- ['Foo', 'Bar', 'Admin'].forEach((permission, idx) => {
- expect(checkboxes[idx]).toHaveAttribute(
- 'aria-label',
- `disabled permission '${permission}' for group 'Anyone'`
- );
- });
-});
-
-it('should disable the "admin" PermissionCell checkbox for group "Anyone" for a public project', () => {
- renderComponent();
-
- expect(
- screen.getByLabelText("unchecked permission 'Foo' for group 'Anyone'")
- ).toBeInTheDocument();
-
- expect(
- screen.getByLabelText("unchecked permission 'Bar' for group 'Anyone'")
- ).toBeInTheDocument();
-
- expect(
- screen.getByLabelText("disabled permission 'Admin' for group 'Anyone'")
- ).toBeInTheDocument();
-});
-
-const renderComponent = (props: Partial<GroupHolder['props']> = {}) =>
- render(
- <table>
- <tbody>
- <GroupHolder
- group={mockPermissionGroup({ id: 'foobar', name: ANYONE })}
- onToggle={jest.fn().mockResolvedValue(null)}
- permissions={[
- {
- category: 'baz',
- permissions: [
- { key: 'foo', name: 'Foo', description: '' },
- { key: 'bar', name: 'Bar', description: '' },
- ],
- },
- { key: Permissions.Admin, name: 'Admin', description: '' },
- ]}
- selectedPermission="bar"
- {...props}
- />
- </tbody>
- </table>
- );
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/HoldersList-test.tsx b/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/HoldersList-test.tsx
deleted file mode 100644
index 4a575c6ffe3..00000000000
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/HoldersList-test.tsx
+++ /dev/null
@@ -1,64 +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 { ANYONE } from '../GroupHolder';
-import HoldersList from '../HoldersList';
-
-const permissions = [
- { key: 'foo', name: 'Foo', description: '' },
- {
- category: 'admin',
- permissions: [
- { key: 'bar', name: 'Bar', description: '' },
- { key: 'baz', name: 'Baz', description: '' },
- ],
- },
-];
-
-const groups = [
- { id: 'foobar', name: 'Foobar', permissions: ['bar'] },
- { id: 'barbaz', name: 'Barbaz', permissions: ['bar'] },
- { id: 'anyone', name: ANYONE, permissions: ['bar'] },
- { id: 'abc', name: 'abc', permissions: [] },
-];
-
-const users = [
- { login: 'foobar', name: 'Foobar', permissions: ['bar'] },
- { login: 'barbaz', name: 'Barbaz', permissions: ['bar'] },
- { login: 'bcd', name: 'bcd', permissions: [] },
-];
-
-const elementsContainer = (
- <HoldersList
- groups={groups}
- isComponentPrivate={true}
- onSelectPermission={jest.fn(() => Promise.resolve())}
- onToggleGroup={jest.fn(() => Promise.resolve())}
- onToggleUser={jest.fn(() => Promise.resolve())}
- permissions={permissions}
- selectedPermission="bar"
- users={users}
- />
-);
-
-it('should display users and groups', () => {
- expect(shallow(elementsContainer)).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/PermissionCell-test.tsx b/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/PermissionCell-test.tsx
deleted file mode 100644
index c3d96bc4414..00000000000
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/PermissionCell-test.tsx
+++ /dev/null
@@ -1,89 +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 PermissionCell from '../PermissionCell';
-
-const permissionItem = {
- id: 'baz',
- name: 'Baz',
- permissions: ['baz'],
-};
-
-const permission = { key: 'baz', name: 'Baz', description: '' };
-const permissionGroup = {
- category: 'admin',
- permissions: [
- { key: 'foo', name: 'Foo', description: '' },
- { key: 'baz', name: 'Baz', description: '' },
- ],
-};
-it('should display an unchecked checkbox', () => {
- expect(
- shallow(
- <PermissionCell
- loading={[]}
- onCheck={jest.fn()}
- permission={{ ...permission, key: 'bar' }}
- permissionItem={permissionItem}
- />
- )
- ).toMatchSnapshot();
-});
-
-it('should display multiple checkboxes with one checked', () => {
- expect(
- shallow(
- <PermissionCell
- loading={[]}
- onCheck={jest.fn()}
- permission={permissionGroup}
- permissionItem={permissionItem}
- />
- )
- ).toMatchSnapshot();
-});
-
-it('should display a disabled checkbox', () => {
- expect(
- shallow(
- <PermissionCell
- loading={['baz']}
- onCheck={jest.fn()}
- permission={permission}
- permissionItem={permissionItem}
- />
- )
- ).toMatchSnapshot();
-});
-
-it('should display a checked checkbox', () => {
- expect(
- shallow(
- <PermissionCell
- loading={[]}
- onCheck={jest.fn()}
- permission={permission}
- permissionItem={permissionItem}
- selectedPermission="baz"
- />
- )
- ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/UserHolder-test.tsx b/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/UserHolder-test.tsx
deleted file mode 100644
index cca4b7ff392..00000000000
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/UserHolder-test.tsx
+++ /dev/null
@@ -1,68 +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 { mockPermissionUser } from '../../../../../helpers/mocks/permissions';
-import { waitAndUpdate } from '../../../../../helpers/testUtils';
-import UserHolder from '../UserHolder';
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot('default');
- expect(shallowRender({ user: mockPermissionUser({ login: '<creator>' }) })).toMatchSnapshot(
- 'creator'
- );
-});
-
-it('should disabled PermissionCell checkboxes when waiting for promise to return', async () => {
- const wrapper = shallowRender();
- expect(wrapper.state().loading).toEqual([]);
-
- wrapper.instance().handleCheck(true, 'baz');
- wrapper.update();
- expect(wrapper.state().loading).toEqual(['baz']);
-
- wrapper.instance().handleCheck(true, 'bar');
- wrapper.update();
- expect(wrapper.state().loading).toEqual(['baz', 'bar']);
-
- await waitAndUpdate(wrapper);
- expect(wrapper.state().loading).toEqual([]);
-});
-
-function shallowRender(props: Partial<UserHolder['props']> = {}) {
- return shallow<UserHolder>(
- <UserHolder
- onToggle={jest.fn().mockResolvedValue(null)}
- permissions={[
- {
- category: 'admin',
- permissions: [
- { key: 'foo', name: 'Foo', description: '' },
- { key: 'bar', name: 'Bar', description: '' },
- ],
- },
- { key: 'baz', name: 'Baz', description: '' },
- ]}
- selectedPermission="bar"
- user={mockPermissionUser({ email: 'john.doe@sonarsource.com', name: 'John Doe' })}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/HoldersList-test.tsx.snap b/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/HoldersList-test.tsx.snap
deleted file mode 100644
index d792e9b5e58..00000000000
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/HoldersList-test.tsx.snap
+++ /dev/null
@@ -1,328 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display users and groups 1`] = `
-<div
- className="boxed-group boxed-group-inner"
->
- <table
- className="data zebra permissions-table"
- >
- <thead>
- <tr>
- <td
- className="nowrap bordered-bottom"
- />
- <PermissionHeader
- key="foo"
- onSelectPermission={[MockFunction]}
- permission={
- {
- "description": "",
- "key": "foo",
- "name": "Foo",
- }
- }
- selectedPermission="bar"
- />
- <PermissionHeader
- key="admin"
- onSelectPermission={[MockFunction]}
- permission={
- {
- "category": "admin",
- "permissions": [
- {
- "description": "",
- "key": "bar",
- "name": "Bar",
- },
- {
- "description": "",
- "key": "baz",
- "name": "Baz",
- },
- ],
- }
- }
- selectedPermission="bar"
- />
- </tr>
- </thead>
- <tbody>
- <GroupHolder
- group={
- {
- "id": "anyone",
- "name": "Anyone",
- "permissions": [
- "bar",
- ],
- }
- }
- isComponentPrivate={true}
- key="group-anyone"
- onToggle={[Function]}
- permissions={
- [
- {
- "description": "",
- "key": "foo",
- "name": "Foo",
- },
- {
- "category": "admin",
- "permissions": [
- {
- "description": "",
- "key": "bar",
- "name": "Bar",
- },
- {
- "description": "",
- "key": "baz",
- "name": "Baz",
- },
- ],
- },
- ]
- }
- selectedPermission="bar"
- />
- <UserHolder
- key="user-barbaz"
- onToggle={[Function]}
- permissions={
- [
- {
- "description": "",
- "key": "foo",
- "name": "Foo",
- },
- {
- "category": "admin",
- "permissions": [
- {
- "description": "",
- "key": "bar",
- "name": "Bar",
- },
- {
- "description": "",
- "key": "baz",
- "name": "Baz",
- },
- ],
- },
- ]
- }
- selectedPermission="bar"
- user={
- {
- "login": "barbaz",
- "name": "Barbaz",
- "permissions": [
- "bar",
- ],
- }
- }
- />
- <GroupHolder
- group={
- {
- "id": "barbaz",
- "name": "Barbaz",
- "permissions": [
- "bar",
- ],
- }
- }
- isComponentPrivate={true}
- key="group-barbaz"
- onToggle={[Function]}
- permissions={
- [
- {
- "description": "",
- "key": "foo",
- "name": "Foo",
- },
- {
- "category": "admin",
- "permissions": [
- {
- "description": "",
- "key": "bar",
- "name": "Bar",
- },
- {
- "description": "",
- "key": "baz",
- "name": "Baz",
- },
- ],
- },
- ]
- }
- selectedPermission="bar"
- />
- <UserHolder
- key="user-foobar"
- onToggle={[Function]}
- permissions={
- [
- {
- "description": "",
- "key": "foo",
- "name": "Foo",
- },
- {
- "category": "admin",
- "permissions": [
- {
- "description": "",
- "key": "bar",
- "name": "Bar",
- },
- {
- "description": "",
- "key": "baz",
- "name": "Baz",
- },
- ],
- },
- ]
- }
- selectedPermission="bar"
- user={
- {
- "login": "foobar",
- "name": "Foobar",
- "permissions": [
- "bar",
- ],
- }
- }
- />
- <GroupHolder
- group={
- {
- "id": "foobar",
- "name": "Foobar",
- "permissions": [
- "bar",
- ],
- }
- }
- isComponentPrivate={true}
- key="group-foobar"
- onToggle={[Function]}
- permissions={
- [
- {
- "description": "",
- "key": "foo",
- "name": "Foo",
- },
- {
- "category": "admin",
- "permissions": [
- {
- "description": "",
- "key": "bar",
- "name": "Bar",
- },
- {
- "description": "",
- "key": "baz",
- "name": "Baz",
- },
- ],
- },
- ]
- }
- selectedPermission="bar"
- />
- <tr>
- <td
- className="divider"
- colSpan={20}
- />
- </tr>
- <tr />
- <GroupHolder
- group={
- {
- "id": "abc",
- "name": "abc",
- "permissions": [],
- }
- }
- isComponentPrivate={true}
- key="group-abc"
- onToggle={[Function]}
- permissions={
- [
- {
- "description": "",
- "key": "foo",
- "name": "Foo",
- },
- {
- "category": "admin",
- "permissions": [
- {
- "description": "",
- "key": "bar",
- "name": "Bar",
- },
- {
- "description": "",
- "key": "baz",
- "name": "Baz",
- },
- ],
- },
- ]
- }
- selectedPermission="bar"
- />
- <UserHolder
- key="user-bcd"
- onToggle={[Function]}
- permissions={
- [
- {
- "description": "",
- "key": "foo",
- "name": "Foo",
- },
- {
- "category": "admin",
- "permissions": [
- {
- "description": "",
- "key": "bar",
- "name": "Bar",
- },
- {
- "description": "",
- "key": "baz",
- "name": "Baz",
- },
- ],
- },
- ]
- }
- selectedPermission="bar"
- user={
- {
- "login": "bcd",
- "name": "bcd",
- "permissions": [],
- }
- }
- />
- </tbody>
- </table>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/PermissionCell-test.tsx.snap b/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/PermissionCell-test.tsx.snap
deleted file mode 100644
index 9f7c78df5a5..00000000000
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/PermissionCell-test.tsx.snap
+++ /dev/null
@@ -1,89 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display a checked checkbox 1`] = `
-<td
- className="permission-column text-center text-middle selected"
->
- <Checkbox
- checked={true}
- disabled={false}
- id="baz"
- label="checked permission 'Baz' for user 'Baz'"
- onCheck={[MockFunction]}
- thirdState={false}
- />
-</td>
-`;
-
-exports[`should display a disabled checkbox 1`] = `
-<td
- className="permission-column text-center text-middle"
->
- <Checkbox
- checked={true}
- disabled={true}
- id="baz"
- label="disabled permission 'Baz' for user 'Baz'"
- onCheck={[MockFunction]}
- thirdState={false}
- />
-</td>
-`;
-
-exports[`should display an unchecked checkbox 1`] = `
-<td
- className="permission-column text-center text-middle"
->
- <Checkbox
- checked={false}
- disabled={false}
- id="bar"
- label="unchecked permission 'Baz' for user 'Baz'"
- onCheck={[MockFunction]}
- thirdState={false}
- />
-</td>
-`;
-
-exports[`should display multiple checkboxes with one checked 1`] = `
-<td
- className="text-middle"
->
- <div
- key="foo"
- >
- <Checkbox
- checked={false}
- disabled={false}
- id="foo"
- label="unchecked permission 'Foo' for user 'Baz'"
- onCheck={[MockFunction]}
- thirdState={false}
- >
- <span
- className="little-spacer-left"
- >
- Foo
- </span>
- </Checkbox>
- </div>
- <div
- key="baz"
- >
- <Checkbox
- checked={true}
- disabled={false}
- id="baz"
- label="checked permission 'Baz' for user 'Baz'"
- onCheck={[MockFunction]}
- thirdState={false}
- >
- <span
- className="little-spacer-left"
- >
- Baz
- </span>
- </Checkbox>
- </div>
-</td>
-`;
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/UserHolder-test.tsx.snap b/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/UserHolder-test.tsx.snap
deleted file mode 100644
index 1133c690cb2..00000000000
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/__tests__/__snapshots__/UserHolder-test.tsx.snap
+++ /dev/null
@@ -1,182 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: creator 1`] = `
-<tr>
- <td
- className="nowrap text-middle"
- >
- <div>
- <strong>
- johndoe
- </strong>
- </div>
- <div
- className="little-spacer-top"
- style={
- {
- "whiteSpace": "normal",
- }
- }
- >
- permission_templates.project_creators.explanation
- </div>
- </td>
- <PermissionCell
- key="admin"
- loading={[]}
- onCheck={[Function]}
- permission={
- {
- "category": "admin",
- "permissions": [
- {
- "description": "",
- "key": "foo",
- "name": "Foo",
- },
- {
- "description": "",
- "key": "bar",
- "name": "Bar",
- },
- ],
- }
- }
- permissionItem={
- {
- "active": true,
- "local": true,
- "login": "<creator>",
- "name": "johndoe",
- "permissions": [
- "provisioning",
- ],
- }
- }
- selectedPermission="bar"
- />
- <PermissionCell
- key="baz"
- loading={[]}
- onCheck={[Function]}
- permission={
- {
- "description": "",
- "key": "baz",
- "name": "Baz",
- }
- }
- permissionItem={
- {
- "active": true,
- "local": true,
- "login": "<creator>",
- "name": "johndoe",
- "permissions": [
- "provisioning",
- ],
- }
- }
- selectedPermission="bar"
- />
-</tr>
-`;
-
-exports[`should render correctly: default 1`] = `
-<tr>
- <td
- className="nowrap text-middle"
- >
- <div
- className="display-flex-center"
- >
- <withAppStateContext(Avatar)
- className="text-middle big-spacer-right flex-0"
- name="John Doe"
- size={36}
- />
- <div
- className="max-width-100"
- >
- <div
- className="max-width-100 text-ellipsis"
- >
- <strong>
- John Doe
- </strong>
- <span
- className="note spacer-left"
- >
- john.doe
- </span>
- </div>
- <div
- className="little-spacer-top max-width-100 text-ellipsis"
- >
- john.doe@sonarsource.com
- </div>
- </div>
- </div>
- </td>
- <PermissionCell
- key="admin"
- loading={[]}
- onCheck={[Function]}
- permission={
- {
- "category": "admin",
- "permissions": [
- {
- "description": "",
- "key": "foo",
- "name": "Foo",
- },
- {
- "description": "",
- "key": "bar",
- "name": "Bar",
- },
- ],
- }
- }
- permissionItem={
- {
- "active": true,
- "email": "john.doe@sonarsource.com",
- "local": true,
- "login": "john.doe",
- "name": "John Doe",
- "permissions": [
- "provisioning",
- ],
- }
- }
- selectedPermission="bar"
- />
- <PermissionCell
- key="baz"
- loading={[]}
- onCheck={[Function]}
- permission={
- {
- "description": "",
- "key": "baz",
- "name": "Baz",
- }
- }
- permissionItem={
- {
- "active": true,
- "email": "john.doe@sonarsource.com",
- "local": true,
- "login": "john.doe",
- "name": "John Doe",
- "permissions": [
- "provisioning",
- ],
- }
- }
- selectedPermission="bar"
- />
-</tr>
-`;
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectManagementApp-it.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectManagementApp-it.tsx
index 4255f24f0af..3810e34f325 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectManagementApp-it.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectManagementApp-it.tsx
@@ -26,8 +26,6 @@ import { renderAppWithAdminContext } from '../../../helpers/testReactTestingUtil
import { ComponentQualifier, Visibility } from '../../../types/component';
import routes from '../routes';
-jest.mock('../../../api/permissions');
-
jest.mock('../../../api/components', () => ({
getComponents: jest.fn().mockResolvedValue({
paging: { total: 0 },