aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorguillaume-peoch-sonarsource <guillaume.peoch@sonarsource.com>2024-08-13 15:36:20 +0200
committersonartech <sonartech@sonarsource.com>2024-08-19 20:02:45 +0000
commit06834faf485721e8674b830c46a229441ed70623 (patch)
treeea0ee2ebf6383bf611c1b69154bb79522708735e /server
parent5c6dd397bcb5579cf1f9ceaa71de391c4fe3e36c (diff)
downloadsonarqube-06834faf485721e8674b830c46a229441ed70623.tar.gz
sonarqube-06834faf485721e8674b830c46a229441ed70623.zip
SONAR-22559 Make permissions read-only for GitLab projects
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/PermissionTemplatesApp-it.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/PermissionsGlobal-it.tsx21
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/PermissionsProject-it.tsx152
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/test-utils.ts5
-rw-r--r--server/sonar-web/src/main/js/components/permissions/GroupHolder.tsx39
-rw-r--r--server/sonar-web/src/main/js/components/permissions/HoldersList.tsx77
-rw-r--r--server/sonar-web/src/main/js/components/permissions/UserHolder.tsx28
8 files changed, 291 insertions, 42 deletions
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
index 4cc8417df20..77353140542 100644
--- 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
@@ -23,8 +23,11 @@ import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
import { uniq } from 'lodash';
import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
import { ComponentQualifier } from '~sonar-aligned/types/component';
+import AlmSettingsServiceMock from '../../../../api/mocks/AlmSettingsServiceMock';
+import ComputeEngineServiceMock from '../../../../api/mocks/ComputeEngineServiceMock';
import DopTranslationServiceMock from '../../../../api/mocks/DopTranslationServiceMock';
import GithubProvisioningServiceMock from '../../../../api/mocks/GithubProvisioningServiceMock';
+import GitlabProvisioningServiceMock from '../../../../api/mocks/GitlabProvisioningServiceMock';
import PermissionsServiceMock from '../../../../api/mocks/PermissionsServiceMock';
import { mockGitHubConfiguration } from '../../../../helpers/mocks/dop-translation';
import { mockPermissionGroup, mockPermissionUser } from '../../../../helpers/mocks/permissions';
@@ -40,11 +43,17 @@ import routes from '../../routes';
const serviceMock = new PermissionsServiceMock();
const dopTranslationHandler = new DopTranslationServiceMock();
const githubHandler = new GithubProvisioningServiceMock(dopTranslationHandler);
+const gitlabHandler = new GitlabProvisioningServiceMock();
+const almHandler = new AlmSettingsServiceMock();
+const computeEngineHandler = new ComputeEngineServiceMock();
beforeEach(() => {
serviceMock.reset();
dopTranslationHandler.reset();
githubHandler.reset();
+ gitlabHandler.reset();
+ almHandler.reset();
+ computeEngineHandler.reset();
});
describe('rendering', () => {
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/PermissionsGlobal-it.tsx b/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/PermissionsGlobal-it.tsx
index 4400f2036fa..2aea662cae4 100644
--- a/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/PermissionsGlobal-it.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/global/components/__tests__/PermissionsGlobal-it.tsx
@@ -21,6 +21,11 @@ import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { without } from 'lodash';
import { ComponentQualifier } from '~sonar-aligned/types/component';
+import AlmSettingsServiceMock from '../../../../../api/mocks/AlmSettingsServiceMock';
+import ComputeEngineServiceMock from '../../../../../api/mocks/ComputeEngineServiceMock';
+import DopTranslationServiceMock from '../../../../../api/mocks/DopTranslationServiceMock';
+import GithubProvisioningServiceMock from '../../../../../api/mocks/GithubProvisioningServiceMock';
+import GitlabProvisioningServiceMock from '../../../../../api/mocks/GitlabProvisioningServiceMock';
import PermissionsServiceMock from '../../../../../api/mocks/PermissionsServiceMock';
import { mockPermissionGroup, mockPermissionUser } from '../../../../../helpers/mocks/permissions';
import { PERMISSIONS_ORDER_GLOBAL } from '../../../../../helpers/permissions';
@@ -33,12 +38,28 @@ import { globalPermissionsRoutes } from '../../../routes';
import { flattenPermissionsList, getPageObject } from '../../../test-utils';
let serviceMock: PermissionsServiceMock;
+let dopTranslationHandler: DopTranslationServiceMock;
+let githubHandler: GithubProvisioningServiceMock;
+let gitlabHandler: GitlabProvisioningServiceMock;
+let almHandler: AlmSettingsServiceMock;
+let computeEngineHandler: ComputeEngineServiceMock;
+
beforeAll(() => {
serviceMock = new PermissionsServiceMock();
+ dopTranslationHandler = new DopTranslationServiceMock();
+ githubHandler = new GithubProvisioningServiceMock(dopTranslationHandler);
+ gitlabHandler = new GitlabProvisioningServiceMock();
+ almHandler = new AlmSettingsServiceMock();
+ computeEngineHandler = new ComputeEngineServiceMock();
});
afterEach(() => {
serviceMock.reset();
+ dopTranslationHandler.reset();
+ githubHandler.reset();
+ gitlabHandler.reset();
+ almHandler.reset();
+ computeEngineHandler.reset();
});
describe('rendering', () => {
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx
index 6b6b1a35411..431674c5dec 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx
@@ -24,6 +24,7 @@ import * as React from 'react';
import { Image } from '~sonar-aligned/components/common/Image';
import { isPortfolioLike } from '~sonar-aligned/helpers/component';
import GitHubSynchronisationWarning from '../../../../app/components/GitHubSynchronisationWarning';
+import GitLabSynchronisationWarning from '../../../../app/components/GitLabSynchronisationWarning';
import { translate, translateWithParameters } from '../../../../helpers/l10n';
import { isDefined } from '../../../../helpers/types';
import {
@@ -106,6 +107,7 @@ export default function PageHeader(props: Readonly<Props>) {
</p>
<div className="sw-mt-2">
{provisionedByGitHub && <GitHubSynchronisationWarning short />}
+ {provisionedByGitLab && <GitLabSynchronisationWarning short />}
</div>
</>
)}
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/PermissionsProject-it.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/PermissionsProject-it.tsx
index 8a190f4aa90..e011d4c9c86 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/PermissionsProject-it.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/PermissionsProject-it.tsx
@@ -21,6 +21,7 @@ import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
import AlmSettingsServiceMock from '../../../../../api/mocks/AlmSettingsServiceMock';
+import ComputeEngineServiceMock from '../../../../../api/mocks/ComputeEngineServiceMock';
import DopTranslationServiceMock from '../../../../../api/mocks/DopTranslationServiceMock';
import GithubProvisioningServiceMock from '../../../../../api/mocks/GithubProvisioningServiceMock';
import GitlabProvisioningServiceMock from '../../../../../api/mocks/GitlabProvisioningServiceMock';
@@ -43,6 +44,7 @@ import { ComponentContextShape } from '../../../../../types/component';
import { Feature } from '../../../../../types/features';
import { Permissions } from '../../../../../types/permissions';
import { ProvisioningType } from '../../../../../types/provisioning';
+import { TaskStatuses, TaskTypes } from '../../../../../types/tasks';
import { Component, PermissionGroup, PermissionUser, Provider } from '../../../../../types/types';
import { projectPermissionsRoutes } from '../../../routes';
import { getPageObject } from '../../../test-utils';
@@ -53,6 +55,8 @@ let githubHandler: GithubProvisioningServiceMock;
let gitlabHandler: GitlabProvisioningServiceMock;
let almHandler: AlmSettingsServiceMock;
let systemHandler: SystemServiceMock;
+let computeEngineHandler: ComputeEngineServiceMock;
+
beforeAll(() => {
serviceMock = new PermissionsServiceMock();
dopTranslationHandler = new DopTranslationServiceMock();
@@ -60,6 +64,7 @@ beforeAll(() => {
gitlabHandler = new GitlabProvisioningServiceMock();
almHandler = new AlmSettingsServiceMock();
systemHandler = new SystemServiceMock();
+ computeEngineHandler = new ComputeEngineServiceMock();
});
afterEach(() => {
@@ -68,6 +73,7 @@ afterEach(() => {
githubHandler.reset();
gitlabHandler.reset();
almHandler.reset();
+ computeEngineHandler.reset();
});
describe('rendering', () => {
@@ -243,7 +249,7 @@ it('should correctly handle pagination', async () => {
expect(screen.getAllByRole('row').length).toBe(21);
});
-describe('GH provisioning', () => {
+describe('GitHub provisioning', () => {
beforeEach(() => {
systemHandler.setProvider(Provider.Github);
});
@@ -442,9 +448,20 @@ describe('GH provisioning', () => {
});
});
-describe('GL provisioning', () => {
+describe('GitLab provisioning', () => {
beforeEach(() => {
systemHandler.setProvider(Provider.Gitlab);
+ computeEngineHandler.addTask({
+ status: TaskStatuses.InProgress,
+ executedAt: '2022-02-03T11:55:35+0200',
+ type: TaskTypes.GitlabProvisioning,
+ });
+ computeEngineHandler.addTask({
+ status: TaskStatuses.Failed,
+ executedAt: '2022-02-03T11:45:35+0200',
+ errorMessage: "T'es mauvais Jacques",
+ type: TaskTypes.GitlabProvisioning,
+ });
});
it('should not allow to change visibility for GitLab Project with auto-provisioning', async () => {
@@ -516,6 +533,137 @@ describe('GL provisioning', () => {
await ui.turnProjectPrivate();
expect(ui.visibilityRadio(Visibility.Private).get()).toBeChecked();
});
+
+ it('should have disabled permissions for GitLab Project', async () => {
+ const user = userEvent.setup();
+ const ui = getPageObject(user);
+ gitlabHandler.setGitlabConfigurations([
+ mockGitlabConfiguration({ id: '1', enabled: true, provisioningType: ProvisioningType.auto }),
+ ]);
+ almHandler.handleSetProjectBinding(AlmKeys.GitLab, {
+ almSetting: 'test',
+ repository: 'test',
+ monorepo: false,
+ project: 'my-project',
+ });
+ renderPermissionsProjectApp(
+ {},
+ { featureList: [Feature.GitlabProvisioning] },
+ {
+ component: mockComponent({ visibility: Visibility.Private }),
+ },
+ );
+ await ui.appLoaded();
+
+ expect(ui.pageTitle.get()).toBeInTheDocument();
+ await waitFor(() =>
+ expect(ui.pageTitle.get()).toHaveAccessibleName(/project_permission.managed/),
+ );
+ expect(ui.pageTitle.byRole('img').get()).toBeInTheDocument();
+ expect(ui.gitlabExplanations.get()).toBeInTheDocument();
+
+ expect(ui.projectPermissionCheckbox('John', Permissions.Admin).get()).toBeChecked();
+ expect(ui.projectPermissionCheckbox('John', Permissions.Admin).get()).toBeDisabled();
+ expect(ui.projectPermissionCheckbox('Alexa', Permissions.IssueAdmin).get()).toBeChecked();
+ expect(ui.projectPermissionCheckbox('Alexa', Permissions.IssueAdmin).get()).toBeEnabled();
+ await ui.toggleProjectPermission('Alexa', Permissions.IssueAdmin);
+ expect(ui.confirmRemovePermissionDialog.get()).toBeInTheDocument();
+ expect(ui.confirmRemovePermissionDialog.get()).toHaveTextContent(
+ `${Permissions.IssueAdmin}Alexa`,
+ );
+ await user.click(ui.confirmRemovePermissionDialog.byRole('button', { name: 'confirm' }).get());
+ expect(ui.projectPermissionCheckbox('Alexa', Permissions.IssueAdmin).get()).not.toBeChecked();
+
+ expect(ui.projectPermissionCheckbox('sonar-users', Permissions.Browse).get()).toBeChecked();
+ expect(ui.projectPermissionCheckbox('sonar-users', Permissions.Browse).get()).toBeEnabled();
+ await ui.toggleProjectPermission('sonar-users', Permissions.Browse);
+ expect(ui.confirmRemovePermissionDialog.get()).toBeInTheDocument();
+ expect(ui.confirmRemovePermissionDialog.get()).toHaveTextContent(
+ `${Permissions.Browse}sonar-users`,
+ );
+ await user.click(ui.confirmRemovePermissionDialog.byRole('button', { name: 'confirm' }).get());
+ expect(ui.projectPermissionCheckbox('sonar-users', Permissions.Browse).get()).not.toBeChecked();
+ expect(ui.projectPermissionCheckbox('sonar-admins', Permissions.Admin).get()).toBeChecked();
+ expect(ui.projectPermissionCheckbox('sonar-admins', Permissions.Admin).get()).toHaveAttribute(
+ 'disabled',
+ );
+
+ const johnRow = screen.getAllByRole('row')[4];
+ expect(johnRow).toHaveTextContent('John');
+ expect(ui.gitlabLogo.get(johnRow)).toBeInTheDocument();
+ const alexaRow = screen.getAllByRole('row')[5];
+ expect(alexaRow).toHaveTextContent('Alexa');
+ expect(ui.gitlabLogo.query(alexaRow)).not.toBeInTheDocument();
+ const usersGroupRow = screen.getAllByRole('row')[1];
+ expect(usersGroupRow).toHaveTextContent('sonar-users');
+ expect(ui.gitlabLogo.query(usersGroupRow)).not.toBeInTheDocument();
+ const adminsGroupRow = screen.getAllByRole('row')[2];
+ expect(adminsGroupRow).toHaveTextContent('sonar-admins');
+ expect(ui.gitlabLogo.query(adminsGroupRow)).toBeInTheDocument();
+
+ expect(ui.applyTemplateBtn.query()).not.toBeInTheDocument();
+
+ // not possible to grant permissions at all
+ expect(
+ screen
+ .getAllByRole('checkbox', { checked: false })
+ .every((item) => item.getAttributeNames().includes('disabled')),
+ ).toBe(true);
+ });
+
+ it('should allow to change permissions for GitLab Project without auto-provisioning', async () => {
+ const user = userEvent.setup();
+ const ui = getPageObject(user);
+ gitlabHandler.setGitlabConfigurations([
+ mockGitlabConfiguration({ id: '1', enabled: true, provisioningType: ProvisioningType.jit }),
+ ]);
+ almHandler.handleSetProjectBinding(AlmKeys.GitLab, {
+ almSetting: 'test',
+ repository: 'test',
+ monorepo: false,
+ project: 'my-project',
+ });
+ renderPermissionsProjectApp(
+ { visibility: Visibility.Private },
+ { featureList: [Feature.GitlabProvisioning] },
+ );
+ await ui.appLoaded();
+
+ expect(ui.pageTitle.get()).toBeInTheDocument();
+ expect(ui.pageTitle.byRole('img').query()).not.toBeInTheDocument();
+
+ expect(ui.applyTemplateBtn.get()).toBeInTheDocument();
+
+ // no restrictions
+ expect(
+ screen
+ .getAllByRole('checkbox')
+ .every((item) => item.getAttributeNames().includes('disabled')),
+ ).toBe(false);
+ });
+
+ it('should allow to change permissions for non-GitLab Project', async () => {
+ const user = userEvent.setup();
+ const ui = getPageObject(user);
+ gitlabHandler.setGitlabConfigurations([
+ mockGitlabConfiguration({ id: '1', enabled: true, provisioningType: ProvisioningType.auto }),
+ ]);
+ renderPermissionsProjectApp({}, { featureList: [Feature.GitlabProvisioning] });
+ await ui.appLoaded();
+
+ expect(ui.pageTitle.get()).toBeInTheDocument();
+ expect(ui.nonGitLabProjectWarning.get()).toBeInTheDocument();
+ expect(ui.pageTitle.byRole('img').query()).not.toBeInTheDocument();
+
+ expect(ui.applyTemplateBtn.get()).toBeInTheDocument();
+
+ // no restrictions
+ expect(
+ screen
+ .getAllByRole('checkbox')
+ .every((item) => item.getAttributeNames().includes('disabled')),
+ ).toBe(false);
+ });
});
function renderPermissionsProjectApp(
diff --git a/server/sonar-web/src/main/js/apps/permissions/test-utils.ts b/server/sonar-web/src/main/js/apps/permissions/test-utils.ts
index f2adfc57989..80b95d13e2c 100644
--- a/server/sonar-web/src/main/js/apps/permissions/test-utils.ts
+++ b/server/sonar-web/src/main/js/apps/permissions/test-utils.ts
@@ -40,12 +40,15 @@ export function getPageObject(user: UserEvent) {
}),
visibilityRadio: (visibility: Visibility) =>
byRole('radio', { name: `visibility.${visibility}` }),
- githubLogo: byRole('img', { name: 'project_permission.github_managed' }),
+ githubLogo: byRole('img', { name: 'project_permission.managed.alm.github' }),
githubExplanations: byText('roles.page.description.github'),
+ gitlabLogo: byRole('img', { name: 'project_permission.managed.alm.gitlab' }),
+ gitlabExplanations: byText('roles.page.description.gitlab'),
confirmRemovePermissionDialog: byRole('dialog', {
name: 'project_permission.remove_only_confirmation_title',
}),
nonGHProjectWarning: byText('project_permission.local_project_with_github_provisioning'),
+ nonGitLabProjectWarning: byText('project_permission.local_project_with_gitlab_provisioning'),
makePublicDisclaimer: byText(
'projects_role.are_you_sure_to_turn_project_to_public.warning.TRK',
),
diff --git a/server/sonar-web/src/main/js/components/permissions/GroupHolder.tsx b/server/sonar-web/src/main/js/components/permissions/GroupHolder.tsx
index 19b3369f9fe..1c2e15b7a0a 100644
--- a/server/sonar-web/src/main/js/components/permissions/GroupHolder.tsx
+++ b/server/sonar-web/src/main/js/components/permissions/GroupHolder.tsx
@@ -21,7 +21,7 @@
import { Badge, ContentCell, TableRowInteractive, UserGroupIcon } from 'design-system';
import * as React from 'react';
import { Image } from '~sonar-aligned/components/common/Image';
-import { translate } from '../../helpers/l10n';
+import { translate, translateWithParameters } from '../../helpers/l10n';
import { isPermissionDefinitionGroup } from '../../helpers/permissions';
import { isDefined } from '../../helpers/types';
import { Permissions } from '../../types/permissions';
@@ -30,9 +30,10 @@ import PermissionCell from './PermissionCell';
import usePermissionChange from './usePermissionChange';
interface Props {
- disabled?: boolean;
group: PermissionGroup;
isComponentPrivate?: boolean;
+ isGitHubUser: boolean | undefined;
+ isGitLabUser: boolean | undefined;
onToggle: (group: PermissionGroup, permission: string) => Promise<void>;
permissions: PermissionDefinitions;
removeOnly?: boolean;
@@ -42,8 +43,15 @@ interface Props {
export const ANYONE = 'Anyone';
export default function GroupHolder(props: Props) {
- const { group, isComponentPrivate, permissions, selectedPermission, disabled, removeOnly } =
- props;
+ const {
+ group,
+ isComponentPrivate,
+ permissions,
+ selectedPermission,
+ removeOnly,
+ isGitHubUser,
+ isGitLabUser,
+ } = props;
const { loading, handleCheck, modal } = usePermissionChange({
holder: group,
onToggle: props.onToggle,
@@ -64,15 +72,30 @@ export default function GroupHolder(props: Props) {
<div className="sw-flex-1 sw-text-ellipsis sw-whitespace-nowrap sw-overflow-hidden sw-min-w-0">
<strong>{group.name}</strong>
</div>
- {disabled && (
+ {isGitHubUser && (
<Image
alt="github"
className="sw-ml-2"
- aria-label={translate('project_permission.github_managed')}
+ aria-label={translateWithParameters(
+ 'project_permission.managed',
+ translate('alm.github'),
+ )}
height={16}
src="/images/alm/github.svg"
/>
)}
+ {isGitLabUser && (
+ <Image
+ alt="gitlab"
+ className="sw-ml-2"
+ aria-label={translateWithParameters(
+ 'project_permission.managed',
+ translate('alm.gitlab'),
+ )}
+ height={16}
+ src="/images/alm/gitlab.svg"
+ />
+ )}
{group.name === ANYONE && (
<Badge className="sw-ml-2" variant="deleted">
{translate('deprecated')}
@@ -93,7 +116,9 @@ export default function GroupHolder(props: Props) {
return (
<PermissionCell
disabled={
- disabled || (group.name === ANYONE && (isComponentPrivate || isAdminPermission))
+ isGitHubUser ||
+ isGitLabUser ||
+ (group.name === ANYONE && (isComponentPrivate || isAdminPermission))
}
removeOnly={removeOnly}
key={permissionKey}
diff --git a/server/sonar-web/src/main/js/components/permissions/HoldersList.tsx b/server/sonar-web/src/main/js/components/permissions/HoldersList.tsx
index 30b1afe643b..82482841c02 100644
--- a/server/sonar-web/src/main/js/components/permissions/HoldersList.tsx
+++ b/server/sonar-web/src/main/js/components/permissions/HoldersList.tsx
@@ -23,8 +23,9 @@ import * as React from 'react';
import UseQuery from '../../helpers/UseQuery';
import { translate } from '../../helpers/l10n';
import { isPermissionDefinitionGroup } from '../../helpers/permissions';
-import { useIsGitHubProjectQuery } from '../../queries/devops-integration';
+import { useIsGitHubProjectQuery, useIsGitLabProjectQuery } from '../../queries/devops-integration';
import { useGithubProvisioningEnabledQuery } from '../../queries/identity-provider/github';
+import { useGilabProvisioningEnabledQuery } from '../../queries/identity-provider/gitlab';
import { Dict, PermissionDefinitions, PermissionGroup, PermissionUser } from '../../types/types';
import GroupHolder from './GroupHolder';
import PermissionHeader from './PermissionHeader';
@@ -111,32 +112,56 @@ export default class HoldersList extends React.PureComponent<
return (
<UseQuery key={this.getKey(item)} query={useIsGitHubProjectQuery}>
{({ data: isGitHubProject }) => (
- <UseQuery query={useGithubProvisioningEnabledQuery}>
- {({ data: githubProvisioningStatus }) => (
- <>
- {this.isPermissionUser(item) ? (
- <UserHolder
- key={`user-${item.login}`}
- onToggle={this.handleUserToggle}
- permissions={permissions}
- selectedPermission={selectedPermission}
- user={item}
- disabled={isGitHubProject && !!githubProvisioningStatus && item.managed}
- removeOnly={isGitHubProject && !!githubProvisioningStatus && !item.managed}
- />
- ) : (
- <GroupHolder
- group={item}
- isComponentPrivate={isComponentPrivate}
- key={`group-${item.id || item.name}`}
- onToggle={this.handleGroupToggle}
- permissions={permissions}
- selectedPermission={selectedPermission}
- disabled={isGitHubProject && !!githubProvisioningStatus && item.managed}
- removeOnly={isGitHubProject && !!githubProvisioningStatus && !item.managed}
- />
+ <UseQuery key={this.getKey(item)} query={useIsGitLabProjectQuery}>
+ {({ data: isGitLabProject }) => (
+ <UseQuery query={useGilabProvisioningEnabledQuery}>
+ {({ data: gitlabProvisioningStatus }) => (
+ <UseQuery query={useGithubProvisioningEnabledQuery}>
+ {({ data: githubProvisioningStatus }) => (
+ <>
+ {this.isPermissionUser(item) ? (
+ <UserHolder
+ key={`user-${item.login}`}
+ onToggle={this.handleUserToggle}
+ permissions={permissions}
+ selectedPermission={selectedPermission}
+ user={item}
+ isGitHubUser={
+ isGitHubProject && !!githubProvisioningStatus && item.managed
+ }
+ isGitLabUser={
+ isGitLabProject && !!gitlabProvisioningStatus && item.managed
+ }
+ removeOnly={
+ (isGitHubProject && !!githubProvisioningStatus && !item.managed) ||
+ (isGitLabProject && !!gitlabProvisioningStatus && !item.managed)
+ }
+ />
+ ) : (
+ <GroupHolder
+ group={item}
+ isComponentPrivate={isComponentPrivate}
+ key={`group-${item.id || item.name}`}
+ onToggle={this.handleGroupToggle}
+ permissions={permissions}
+ selectedPermission={selectedPermission}
+ isGitHubUser={
+ isGitHubProject && !!githubProvisioningStatus && item.managed
+ }
+ isGitLabUser={
+ isGitLabProject && !!gitlabProvisioningStatus && item.managed
+ }
+ removeOnly={
+ (isGitHubProject && !!githubProvisioningStatus && !item.managed) ||
+ (isGitLabProject && !!gitlabProvisioningStatus && !item.managed)
+ }
+ />
+ )}
+ </>
+ )}
+ </UseQuery>
)}
- </>
+ </UseQuery>
)}
</UseQuery>
)}
diff --git a/server/sonar-web/src/main/js/components/permissions/UserHolder.tsx b/server/sonar-web/src/main/js/components/permissions/UserHolder.tsx
index b0088590290..a3f2133775a 100644
--- a/server/sonar-web/src/main/js/components/permissions/UserHolder.tsx
+++ b/server/sonar-web/src/main/js/components/permissions/UserHolder.tsx
@@ -21,7 +21,7 @@
import { Avatar, ContentCell, Note, TableRowInteractive } from 'design-system';
import * as React from 'react';
import { Image } from '~sonar-aligned/components/common/Image';
-import { translate } from '../../helpers/l10n';
+import { translate, translateWithParameters } from '../../helpers/l10n';
import { isPermissionDefinitionGroup } from '../../helpers/permissions';
import { isDefined } from '../../helpers/types';
import { PermissionDefinitions, PermissionUser } from '../../types/types';
@@ -29,7 +29,8 @@ import PermissionCell from './PermissionCell';
import usePermissionChange from './usePermissionChange';
interface Props {
- disabled?: boolean;
+ isGitHubUser: boolean | undefined;
+ isGitLabUser: boolean | undefined;
onToggle: (user: PermissionUser, permission: string) => Promise<void>;
permissions: PermissionDefinitions;
removeOnly?: boolean;
@@ -38,7 +39,7 @@ interface Props {
}
export default function UserHolder(props: Props) {
- const { user, disabled, removeOnly, permissions, selectedPermission } = props;
+ const { user, removeOnly, permissions, selectedPermission, isGitHubUser, isGitLabUser } = props;
const { loading, handleCheck, modal } = usePermissionChange({
holder: user,
onToggle: props.onToggle,
@@ -52,7 +53,7 @@ export default function UserHolder(props: Props) {
loading={loading}
onCheck={handleCheck}
permission={permission}
- disabled={disabled}
+ disabled={isGitHubUser || isGitLabUser}
removeOnly={removeOnly}
permissionItem={user}
prefixID={user.login}
@@ -91,15 +92,30 @@ export default function UserHolder(props: Props) {
<strong>{user.name}</strong>
<Note className="sw-ml-2">{user.login}</Note>
</div>
- {disabled && (
+ {isGitHubUser && (
<Image
alt="github"
className="sw-ml-2"
height={16}
- aria-label={translate('project_permission.github_managed')}
+ aria-label={translateWithParameters(
+ 'project_permission.managed',
+ translate('alm.github'),
+ )}
src="/images/alm/github.svg"
/>
)}
+ {isGitLabUser && (
+ <Image
+ alt="gitlab"
+ className="sw-ml-2"
+ height={16}
+ aria-label={translateWithParameters(
+ 'project_permission.managed',
+ translate('alm.gitlab'),
+ )}
+ src="/images/alm/gitlab.svg"
+ />
+ )}
</div>
{isDefined(user.email) && (
<div className="sw-mt-2 sw-max-w-100 sw-text-ellipsis sw-whitespace-nowrap sw-overflow-hidden">