diff options
author | guillaume-peoch-sonarsource <guillaume.peoch@sonarsource.com> | 2024-08-13 15:36:20 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-08-19 20:02:45 +0000 |
commit | 06834faf485721e8674b830c46a229441ed70623 (patch) | |
tree | ea0ee2ebf6383bf611c1b69154bb79522708735e /server | |
parent | 5c6dd397bcb5579cf1f9ceaa71de391c4fe3e36c (diff) | |
download | sonarqube-06834faf485721e8674b830c46a229441ed70623.tar.gz sonarqube-06834faf485721e8674b830c46a229441ed70623.zip |
SONAR-22559 Make permissions read-only for GitLab projects
Diffstat (limited to 'server')
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"> |