From 7b5a8425edd0395326491b1355bae8980de906fe Mon Sep 17 00:00:00 2001 From: Mathieu Suen Date: Wed, 19 May 2021 13:51:02 +0200 Subject: [PATCH] SONAR-14805 Add import action for bitbucket cloud onboarding --- .../src/main/js/api/alm-integrations.ts | 10 ++ .../project/BitbucketCloudProjectCreate.tsx | 53 ++++-- .../BitbucketCloudProjectCreateRender.tsx | 7 +- .../project/BitbucketCloudSearchForm.tsx | 29 ++- .../BitbucketCloudProjectCreate-test.tsx | 64 +++++-- ...BitbucketCloudProjectCreateRender-test.tsx | 3 +- .../BitbucketCloudSearchForm-test.tsx | 13 +- .../BitbucketCloudProjectCreate-test.tsx.snap | 2 + ...cketCloudProjectCreateRender-test.tsx.snap | 1 + .../BitbucketCloudSearchForm-test.tsx.snap | 165 +++++++++++++++++- 10 files changed, 306 insertions(+), 41 deletions(-) diff --git a/server/sonar-web/src/main/js/api/alm-integrations.ts b/server/sonar-web/src/main/js/api/alm-integrations.ts index f98c7ff105f..aa0b4c6907c 100644 --- a/server/sonar-web/src/main/js/api/alm-integrations.ts +++ b/server/sonar-web/src/main/js/api/alm-integrations.ts @@ -156,6 +156,16 @@ export function getGithubClientId(almSetting: string): Promise<{ clientId?: stri return getJSON('/api/alm_integrations/get_github_client_id', { almSetting }); } +export function importBitbucketCloudRepository( + almSetting: string, + repositorySlug: string +): Promise<{ project: ProjectBase }> { + return postJSON('/api/alm_integrations/import_bitbucketcloud_repo', { + almSetting, + repositorySlug + }).catch(throwGlobalError); +} + export function importGithubRepository( almSetting: string, organization: string, diff --git a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreate.tsx index a9d9f6efe1b..0a08a013fac 100644 --- a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreate.tsx @@ -19,8 +19,11 @@ */ import * as React from 'react'; import { WithRouterProps } from 'react-router'; -import { searchForBitbucketCloudRepositories } from '../../../api/alm-integrations'; -import { BitbucketCloudRepository, BitbucketRepository } from '../../../types/alm-integration'; +import { + importBitbucketCloudRepository, + searchForBitbucketCloudRepositories +} from '../../../api/alm-integrations'; +import { BitbucketCloudRepository } from '../../../types/alm-integration'; import { AlmSettingsInstance } from '../../../types/alm-settings'; import BitbucketCloudProjectCreateRenderer from './BitbucketCloudProjectCreateRender'; @@ -32,21 +35,20 @@ interface Props extends Pick { } interface State { - settings: AlmSettingsInstance; + importingSlug?: string; + isLastPage?: boolean; loading: boolean; loadingMore: boolean; - isLastPage?: boolean; projectsPaging: Omit; + resetPat: boolean; repositories: BitbucketCloudRepository[]; - searchResults?: BitbucketRepository[]; - selectedRepository?: BitbucketRepository; searching: boolean; searchQuery: string; + settings: AlmSettingsInstance; showPersonalAccessTokenForm: boolean; - resetPat: boolean; } -export const BITBUCKET_PROJECTS_PAGESIZE = 30; +export const BITBUCKET_CLOUD_PROJECTS_PAGESIZE = 30; export default class BitbucketCloudProjectCreate extends React.PureComponent { mounted = false; @@ -55,14 +57,14 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent { this.setState({ showPersonalAccessTokenForm: false }); this.cleanUrl(); + this.setState({ loading: true }); await this.fetchData(); + this.setState({ loading: false }); }; cleanUrl = () => { @@ -122,7 +126,7 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent { if (this.mounted) { this.setState({ - projectsPaging: { pageIndex: 1, pageSize: BITBUCKET_PROJECTS_PAGESIZE }, + projectsPaging: { pageIndex: 1, pageSize: BITBUCKET_CLOUD_PROJECTS_PAGESIZE }, repositories: [], resetPat: true, showPersonalAccessTokenForm: true @@ -136,7 +140,7 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent { @@ -166,9 +170,32 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent { + const { settings } = this.state; + + if (!settings) { + return; + } + + this.setState({ importingSlug: repositorySlug }); + + const result = await importBitbucketCloudRepository(settings.key, repositorySlug).catch( + () => undefined + ); + + if (this.mounted) { + this.setState({ importingSlug: undefined }); + + if (result) { + this.props.onProjectCreate([result.project.key]); + } + } + }; + render() { const { canAdmin, loadingBindings, location } = this.props; const { + importingSlug, isLastPage = true, settings, loading, @@ -181,11 +208,13 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent void; onLoadMore: () => void; onPersonalAccessTokenCreated: () => void; onSearch: (searchQuery: string) => void; @@ -41,12 +42,14 @@ export interface BitbucketCloudProjectCreateRendererProps { searching: boolean; searchQuery: string; showPersonalAccessTokenForm: boolean; + settings?: AlmSettingsInstance; } export default function BitbucketCloudProjectCreateRenderer( props: BitbucketCloudProjectCreateRendererProps ) { const { + importingSlug, isLastPage, settings, canAdmin, @@ -90,10 +93,12 @@ export default function BitbucketCloudProjectCreateRenderer( /> ) : ( void; onLoadMore: () => void; onSearch: (searchQuery: string) => void; repositories?: BitbucketCloudRepository[]; @@ -50,7 +52,14 @@ function getRepositoryUrl(workspace: string, slug: string) { } export default function BitbucketCloudSearchForm(props: BitbucketCloudSearchFormProps) { - const { isLastPage, loadingMore, repositories = [], searching, searchQuery } = props; + const { + importingSlug, + isLastPage, + loadingMore, + repositories = [], + searching, + searchQuery + } = props; if (repositories.length === 0 && searchQuery.length === 0 && !searching) { return ( @@ -136,11 +145,14 @@ export default function BitbucketCloudSearchForm(props: BitbucketCloudSearchForm ) : ( )} @@ -150,11 +162,12 @@ export default function BitbucketCloudSearchForm(props: BitbucketCloudSearchForm )}
- {translateWithParameters( - 'x_of_y_shown', - formatMeasure(repositories.length, 'INT', null), - isLastPage ? formatMeasure(repositories.length, 'INT', null) : translate('unknown') - )} + {isLastPage && + translateWithParameters( + 'x_of_y_shown', + formatMeasure(repositories.length, 'INT', null), + formatMeasure(repositories.length, 'INT', null) + )} {!isLastPage && ( +
+ +`; + exports[`Should render correctly: Loading more 1`] = `