diff options
7 files changed, 104 insertions, 103 deletions
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 431674c5dec..80aa2ec2b75 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,7 +24,6 @@ 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 { @@ -32,27 +31,27 @@ import { useIsGitLabProjectQuery, } from '../../../../queries/devops-integration'; import { useGithubProvisioningEnabledQuery } from '../../../../queries/identity-provider/github'; -import { useGilabProvisioningEnabledQuery } from '../../../../queries/identity-provider/gitlab'; import { isApplication, isProject } from '../../../../types/component'; import { Component } from '../../../../types/types'; import ApplyTemplate from './ApplyTemplate'; interface Props { component: Component; + isProjectManaged: boolean; loadHolders: () => void; } export default function PageHeader(props: Readonly<Props>) { - const { component, loadHolders } = props; + const { component, loadHolders, isProjectManaged } = props; const { configuration, key, qualifier, visibility } = component; const [applyTemplateModal, setApplyTemplateModal] = React.useState(false); const { data: isGitHubProject } = useIsGitHubProjectQuery(key); const { data: isGitLabProject } = useIsGitLabProjectQuery(key); const { data: githubProvisioningStatus } = useGithubProvisioningEnabledQuery(); - const { data: gitlabProvisioningStatus } = useGilabProvisioningEnabledQuery(); + // to know if we are provisioning with GitLab: managed + GitLab project const provisionedByGitHub = isGitHubProject && !!githubProvisioningStatus; - const provisionedByGitLab = isGitLabProject && !!gitlabProvisioningStatus; + const provisionedByGitLab = isGitLabProject && isProjectManaged; const provisioned = provisionedByGitHub || provisionedByGitLab; const canApplyPermissionTemplate = configuration?.canApplyPermissionTemplate && !provisioned; @@ -107,7 +106,6 @@ export default function PageHeader(props: Readonly<Props>) { </p> <div className="sw-mt-2"> {provisionedByGitHub && <GitHubSynchronisationWarning short />} - {provisionedByGitLab && <GitLabSynchronisationWarning short />} </div> </> )} @@ -116,11 +114,6 @@ export default function PageHeader(props: Readonly<Props>) { {translate('project_permission.local_project_with_github_provisioning')} </FlagMessage> )} - {gitlabProvisioningStatus && !isGitLabProject && ( - <FlagMessage variant="warning" className="sw-mt-2"> - {translate('project_permission.local_project_with_gitlab_provisioning')} - </FlagMessage> - )} </div> </div> {canApplyPermissionTemplate && ( diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/PermissionsProjectApp.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/PermissionsProjectApp.tsx index c1e5708966a..c0d22a92660 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/PermissionsProjectApp.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/PermissionsProjectApp.tsx @@ -21,8 +21,9 @@ import { LargeCenteredLayout, PageContentFontWrapper } from 'design-system'; import { noop, without } from 'lodash'; import * as React from 'react'; import { Helmet } from 'react-helmet-async'; -import { Visibility } from '~sonar-aligned/types/component'; +import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component'; import * as api from '../../../../api/permissions'; +import { getComponents } from '../../../../api/project-management'; import withComponentContext from '../../../../app/components/componentContext/withComponentContext'; import AllHoldersList from '../../../../components/permissions/AllHoldersList'; import { FilterOption } from '../../../../components/permissions/SearchForm'; @@ -48,6 +49,7 @@ interface State { filter: FilterOption; groups: PermissionGroup[]; groupsPaging?: Paging; + isProjectManaged: boolean; loading: boolean; query: string; selectedPermission?: string; @@ -67,12 +69,14 @@ class PermissionsProjectApp extends React.PureComponent<Props, State> { loading: true, query: '', users: [], + isProjectManaged: false, }; } componentDidMount() { this.mounted = true; this.loadHolders(); + this.getIsProjectManaged(); } componentWillUnmount() { @@ -122,6 +126,21 @@ class PermissionsProjectApp extends React.PureComponent<Props, State> { }, this.stopLoading); }; + getIsProjectManaged = () => { + if (this.props.component.qualifier === ComponentQualifier.Project) { + getComponents({ projects: this.props.component.key }) + .then((response) => { + if (this.mounted) { + const { managed } = response.components[0]; + this.setState({ + isProjectManaged: !!managed, + }); + } + }) + .catch(noop); + } + }; + handleLoadMore = () => { const { usersPaging, groupsPaging } = this.state; this.setState({ loading: true }); @@ -332,6 +351,7 @@ class PermissionsProjectApp extends React.PureComponent<Props, State> { users, usersPaging, groupsPaging, + isProjectManaged, } = this.state; let order = PERMISSIONS_ORDER_BY_QUALIFIER[component.qualifier]; @@ -345,9 +365,14 @@ class PermissionsProjectApp extends React.PureComponent<Props, State> { <PageContentFontWrapper className="sw-my-8 sw-body-sm"> <Helmet defer={false} title={translate('permissions.page')} /> - <PageHeader component={component} loadHolders={this.loadHolders} /> + <PageHeader + isProjectManaged={isProjectManaged} + component={component} + loadHolders={this.loadHolders} + /> <div> <PermissionsProjectVisibility + isProjectManaged={isProjectManaged} component={component} handleVisibilityChange={this.handleVisibilityChange} isLoading={loading} @@ -380,6 +405,7 @@ class PermissionsProjectApp extends React.PureComponent<Props, State> { users={users} usersPaging={usersPaging} permissions={permissions} + isProjectManaged={isProjectManaged} /> </PageContentFontWrapper> </LargeCenteredLayout> diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/PermissionsProjectVisibility.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/PermissionsProjectVisibility.tsx index 8cde3d10676..abb7a4706f0 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/PermissionsProjectVisibility.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/PermissionsProjectVisibility.tsx @@ -25,29 +25,26 @@ import { useIsGitLabProjectQuery, } from '../../../../queries/devops-integration'; import { useGithubProvisioningEnabledQuery } from '../../../../queries/identity-provider/github'; -import { useGilabProvisioningEnabledQuery } from '../../../../queries/identity-provider/gitlab'; import { Component } from '../../../../types/types'; interface Props { component: Component; handleVisibilityChange: (visibility: string) => void; isLoading: boolean; + isProjectManaged: boolean; } export default function PermissionsProjectVisibility(props: Readonly<Props>) { - const { component, handleVisibilityChange, isLoading } = props; + const { component, handleVisibilityChange, isLoading, isProjectManaged } = props; const canTurnToPrivate = component.configuration?.canUpdateProjectVisibilityToPrivate; const { data: isGitHubProject } = useIsGitHubProjectQuery(component.key); const { data: isGitLabProject } = useIsGitLabProjectQuery(component.key); const { data: gitHubProvisioningStatus, isFetching: isFetchingGitHubProvisioningStatus } = useGithubProvisioningEnabledQuery(); - const { data: gitLabProvisioningStatus, isFetching: isFetchingGitLabProvisioningStatus } = - useGilabProvisioningEnabledQuery(); - const isFetching = isFetchingGitHubProvisioningStatus || isFetchingGitLabProvisioningStatus; + const isFetching = isFetchingGitHubProvisioningStatus; const isDisabled = - (isGitHubProject && !!gitHubProvisioningStatus) || - (isGitLabProject && !!gitLabProvisioningStatus); + (isGitHubProject && !!gitHubProvisioningStatus) || (isGitLabProject && isProjectManaged); return ( <VisibilitySelector 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 e011d4c9c86..e7e2585b60d 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,16 +21,17 @@ 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'; import PermissionsServiceMock from '../../../../../api/mocks/PermissionsServiceMock'; +import ProjectManagementServiceMock from '../../../../../api/mocks/ProjectsManagementServiceMock'; +import SettingsServiceMock from '../../../../../api/mocks/SettingsServiceMock'; import SystemServiceMock from '../../../../../api/mocks/SystemServiceMock'; -import { mockGitlabConfiguration } from '../../../../../helpers/mocks/alm-integrations'; import { mockComponent } from '../../../../../helpers/mocks/component'; import { mockGitHubConfiguration } from '../../../../../helpers/mocks/dop-translation'; import { mockPermissionGroup, mockPermissionUser } from '../../../../../helpers/mocks/permissions'; +import { mockProject } from '../../../../../helpers/mocks/projects'; import { PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE, PERMISSIONS_ORDER_FOR_VIEW, @@ -44,7 +45,6 @@ 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'; @@ -54,8 +54,9 @@ let dopTranslationHandler: DopTranslationServiceMock; let githubHandler: GithubProvisioningServiceMock; let gitlabHandler: GitlabProvisioningServiceMock; let almHandler: AlmSettingsServiceMock; +let settingsHandler: SettingsServiceMock; +let projectHandler: ProjectManagementServiceMock; let systemHandler: SystemServiceMock; -let computeEngineHandler: ComputeEngineServiceMock; beforeAll(() => { serviceMock = new PermissionsServiceMock(); @@ -63,8 +64,9 @@ beforeAll(() => { githubHandler = new GithubProvisioningServiceMock(dopTranslationHandler); gitlabHandler = new GitlabProvisioningServiceMock(); almHandler = new AlmSettingsServiceMock(); + settingsHandler = new SettingsServiceMock(); + projectHandler = new ProjectManagementServiceMock(settingsHandler); systemHandler = new SystemServiceMock(); - computeEngineHandler = new ComputeEngineServiceMock(); }); afterEach(() => { @@ -73,7 +75,8 @@ afterEach(() => { githubHandler.reset(); gitlabHandler.reset(); almHandler.reset(); - computeEngineHandler.reset(); + settingsHandler.reset(); + projectHandler.reset(); }); describe('rendering', () => { @@ -451,17 +454,13 @@ describe('GitHub 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, + almHandler.handleSetProjectBinding(AlmKeys.GitLab, { + almSetting: 'test', + repository: 'test', + monorepo: false, + project: 'my-project', }); + projectHandler.setProjects([mockProject({ key: 'my-project', managed: true })]); }); it('should not allow to change visibility for GitLab Project with auto-provisioning', async () => { @@ -470,9 +469,6 @@ describe('GitLab provisioning', () => { dopTranslationHandler.gitHubConfigurations.push( mockGitHubConfiguration({ provisioningType: ProvisioningType.jit }), ); - gitlabHandler.setGitlabConfigurations([ - mockGitlabConfiguration({ id: '1', enabled: true, provisioningType: ProvisioningType.auto }), - ]); almHandler.handleSetProjectBinding(AlmKeys.GitLab, { almSetting: 'test', repository: 'test', @@ -493,9 +489,6 @@ describe('GitLab provisioning', () => { it('should allow to change visibility for non-GitLab Project', async () => { const user = userEvent.setup(); const ui = getPageObject(user); - gitlabHandler.setGitlabConfigurations([ - mockGitlabConfiguration({ id: '1', enabled: true, provisioningType: ProvisioningType.auto }), - ]); almHandler.handleSetProjectBinding(AlmKeys.GitHub, { almSetting: 'test', repository: 'test', @@ -515,15 +508,13 @@ describe('GitLab provisioning', () => { it('should allow to change visibility for GitLab Project with disabled 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', }); + projectHandler.setProjects([mockProject({ key: 'my-project', managed: false })]); renderPermissionsProjectApp({}, { featureList: [Feature.GitlabProvisioning] }); await ui.appLoaded(); @@ -537,9 +528,6 @@ describe('GitLab provisioning', () => { 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', @@ -614,9 +602,8 @@ describe('GitLab provisioning', () => { 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 }), - ]); + + projectHandler.setProjects([mockProject({ key: 'my-project', managed: false })]); almHandler.handleSetProjectBinding(AlmKeys.GitLab, { almSetting: 'test', repository: 'test', @@ -644,15 +631,22 @@ describe('GitLab provisioning', () => { it('should allow to change permissions for non-GitLab Project', async () => { const user = userEvent.setup(); + projectHandler.reset(); + projectHandler.setProjects([mockProject({ key: 'my-project', managed: false })]); + almHandler.reset(); + almHandler.handleSetProjectBinding(AlmKeys.BitbucketServer, { + almSetting: 'test', + repository: 'test', + monorepo: false, + project: 'my-project', + }); + 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(); 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 80b95d13e2c..3c0f93d2bec 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 @@ -48,7 +48,6 @@ export function getPageObject(user: UserEvent) { 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/AllHoldersList.tsx b/server/sonar-web/src/main/js/components/permissions/AllHoldersList.tsx index 9ee04386a93..3828b10a77b 100644 --- a/server/sonar-web/src/main/js/components/permissions/AllHoldersList.tsx +++ b/server/sonar-web/src/main/js/components/permissions/AllHoldersList.tsx @@ -34,6 +34,7 @@ interface Props { filter: FilterOption; groups: PermissionGroup[]; groupsPaging?: Paging; + isProjectManaged?: boolean; loading?: boolean; onFilter: (filter: string) => void; onGrantPermissionToGroup: (group: string, permission: string) => Promise<void>; @@ -96,6 +97,7 @@ export default class AllHoldersList extends React.PureComponent<Props> { permissions, selectedPermission, loading = false, + isProjectManaged, } = this.props; const { count, total } = this.getPaging(); @@ -114,6 +116,7 @@ export default class AllHoldersList extends React.PureComponent<Props> { <BasicSeparator className="sw-mt-4" /> </div> <HoldersList + isProjectManaged={!!isProjectManaged} loading={loading} filter={filter} groups={groups} 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 82482841c02..9f109eb7db8 100644 --- a/server/sonar-web/src/main/js/components/permissions/HoldersList.tsx +++ b/server/sonar-web/src/main/js/components/permissions/HoldersList.tsx @@ -25,7 +25,6 @@ import { translate } from '../../helpers/l10n'; import { isPermissionDefinitionGroup } from '../../helpers/permissions'; 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'; @@ -35,6 +34,7 @@ interface Props { filter?: string; groups: PermissionGroup[]; isComponentPrivate?: boolean; + isProjectManaged: boolean; loading?: boolean; onSelectPermission?: (permission: string) => void; onToggleGroup: (group: PermissionGroup, permission: string) => Promise<void>; @@ -108,58 +108,47 @@ export default class HoldersList extends React.PureComponent< } renderItem(item: PermissionUser | PermissionGroup, permissions: PermissionDefinitions) { - const { selectedPermission, isComponentPrivate } = this.props; + const { selectedPermission, isComponentPrivate, isProjectManaged } = this.props; + return ( <UseQuery key={this.getKey(item)} query={useIsGitHubProjectQuery}> {({ data: isGitHubProject }) => ( <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 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 && item.managed} + removeOnly={ + (isGitHubProject && !!githubProvisioningStatus && !item.managed) || + (isGitLabProject && isProjectManaged && !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 && item.managed} + removeOnly={ + (isGitHubProject && !!githubProvisioningStatus && !item.managed) || + (isGitLabProject && isProjectManaged && !item.managed) + } + /> )} - </UseQuery> + </> )} </UseQuery> )} |