From: Grégoire Aubert Date: Fri, 21 Jun 2019 07:10:32 +0000 (+0200) Subject: SC-781 Remove special behavior to bind personal organization X-Git-Tag: 8.0~398 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=27631acbf487a755813765d5f53afbf80bd4c8ee;p=sonarqube.git SC-781 Remove special behavior to bind personal organization * Update documentation talking about personal orgs * Drop unused organization/delete route --- diff --git a/server/sonar-docs/src/pages/analysis/overview.md b/server/sonar-docs/src/pages/analysis/overview.md index e807b6e755e..b5577af5461 100644 --- a/server/sonar-docs/src/pages/analysis/overview.md +++ b/server/sonar-docs/src/pages/analysis/overview.md @@ -6,10 +6,10 @@ url: /analysis/overview/ ## Prepare your organization -A project must belong to an [organization](/organizations/overview/). Create one if you intend to collaborate with your team mates, or use your personal organization for test purposes. +A project must belong to an [organization](/organizations/overview/). You need to create one to analyze a project and collaborate with your team mates. [[info]] -| ** Important note for private code:** Newly created organizations and personal organizations are under a free plan by default. This means projects analyzed on these organizations are public by default: the code will be browsable by anyone. If you want private projects, you should [upgrade your organization to a paid plan](/sonarcloud-pricing/). +| ** Important note for private code:** Newly created organizations are under a free plan by default. This means projects analyzed on these organizations are public by default: the code will be browsable by anyone. If you want private projects, you should [upgrade your organization to a paid plan](/sonarcloud-pricing/). Find the key of your organization, you will need it at later stages. It can be found on the top right corner of your organization's header. diff --git a/server/sonar-docs/src/pages/sonarcloud/organizations/index.md b/server/sonar-docs/src/pages/sonarcloud/organizations/index.md index 33694461f68..22d57f1dee4 100644 --- a/server/sonar-docs/src/pages/sonarcloud/organizations/index.md +++ b/server/sonar-docs/src/pages/sonarcloud/organizations/index.md @@ -12,10 +12,6 @@ An organization consists of: * [Members](/organizations/manage-team/), who can have different permissions on the projects * [Quality Profiles](/instance-administration/quality-profiles/) and [Quality Gates](/user-guide/quality-gates/), which can be customized and shared accross projects -There are 2 kind of organizations: -* **Personal organizations**. Each account has a personal organization linked to it. This is typically where open-source developers host their personal projects. It is not possible to delete this kind of organization. -* **Standard organization**. This is the kind of organization that users want to create for their companies or for their open-source communities. As soon as you want to collaborate, it is a good idea to create such an organization. - Organizations can be on: * **Free plan**. This is the default plan. Every project in an organization on the free plan is public. * **Paid plan**. This plan unlocks the ability to have private projects. Go to the "Billing" page of your organization to upgrade it to the paid plan. diff --git a/server/sonar-web/src/main/js/app/types.d.ts b/server/sonar-web/src/main/js/app/types.d.ts index 7e741303ff7..2f0712d6aeb 100644 --- a/server/sonar-web/src/main/js/app/types.d.ts +++ b/server/sonar-web/src/main/js/app/types.d.ts @@ -37,7 +37,6 @@ declare namespace T { export interface AlmOrganization extends OrganizationBase { almUrl: string; key: string; - personal: boolean; privateRepos: number; publicRepos: number; } @@ -440,7 +439,6 @@ declare namespace T { local?: boolean; login: string; name: string; - personalOrganization?: string; scmAccounts: string[]; settings?: CurrentUserSetting[]; } @@ -519,7 +517,6 @@ declare namespace T { alm?: { key: string; membersSync: boolean; url: string }; adminPages?: Extension[]; canUpdateProjectsVisibilityToPrivate?: boolean; - guarded?: boolean; isDefault?: boolean; key: string; pages?: Extension[]; diff --git a/server/sonar-web/src/main/js/apps/create/organization/AutoPersonalOrganizationBind.tsx b/server/sonar-web/src/main/js/apps/create/organization/AutoPersonalOrganizationBind.tsx deleted file mode 100644 index 9a1afec98b4..00000000000 --- a/server/sonar-web/src/main/js/apps/create/organization/AutoPersonalOrganizationBind.tsx +++ /dev/null @@ -1,122 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 { FormattedMessage } from 'react-intl'; -import OrganizationDetailsForm from './OrganizationDetailsForm'; -import OrganizationDetailsStep from './OrganizationDetailsStep'; -import PlanStep from './PlanStep'; -import { Step } from './utils'; -import { ClearButton } from '../../../components/ui/buttons'; -import OrganizationAvatar from '../../../components/common/OrganizationAvatar'; -import { getBaseUrl } from '../../../helpers/urls'; -import { translate } from '../../../helpers/l10n'; -import { sanitizeAlmId } from '../../../helpers/almIntegrations'; - -interface Props { - almApplication: T.AlmApplication; - almInstallId?: string; - almOrganization: T.AlmOrganization; - handleCancelImport: () => void; - handleOrgDetailsFinish: (organization: T.Organization) => Promise; - handleOrgDetailsStepOpen: () => void; - importPersonalOrg: T.Organization; - onDone: () => void; - organization?: T.Organization; - step: Step; - subscriptionPlans?: T.SubscriptionPlan[]; - updateOrganization: ( - organization: T.Organization & { installationId?: string } - ) => Promise; -} - -export default class AutoPersonalOrganizationBind extends React.PureComponent { - handleCreateOrganization = () => { - const { organization } = this.props; - if (!organization) { - return Promise.reject(); - } - return this.props.updateOrganization({ - ...organization, - installationId: this.props.almInstallId - }); - }; - - handleOrgDetailsFinish = (organization: T.Organization) => { - return this.props.handleOrgDetailsFinish({ - ...organization, - key: this.props.importPersonalOrg.key - }); - }; - - render() { - const { almApplication, importPersonalOrg, organization, step, subscriptionPlans } = this.props; - return ( - <> - -
- - ), - name: {this.props.almOrganization.name}, - personalAvatar: importPersonalOrg && ( - - ), - personalName: importPersonalOrg && {importPersonalOrg.name} - }} - /> - -
- -
- {subscriptionPlans !== undefined && ( - - )} - - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/create/organization/CreateOrganization.tsx b/server/sonar-web/src/main/js/apps/create/organization/CreateOrganization.tsx index a08e71d5859..824127e4810 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/CreateOrganization.tsx +++ b/server/sonar-web/src/main/js/apps/create/organization/CreateOrganization.tsx @@ -24,7 +24,7 @@ import { times } from 'lodash'; import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; import { withRouter, WithRouterProps } from 'react-router'; -import { createOrganization, updateOrganization } from './actions'; +import { createOrganization } from './actions'; import { ORGANIZATION_IMPORT_REDIRECT_TO_PROJECT_TIMESTAMP, parseQuery, @@ -37,7 +37,6 @@ import { } from './utils'; import AlmApplicationInstalling from './AlmApplicationInstalling'; import AutoOrganizationCreate from './AutoOrganizationCreate'; -import AutoPersonalOrganizationBind from './AutoPersonalOrganizationBind'; import ManualOrganizationCreate from './ManualOrganizationCreate'; import RemoteOrganizationChoose from './RemoteOrganizationChoose'; import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget'; @@ -55,11 +54,7 @@ import { } from '../../../api/alm-integration'; import { getSubscriptionPlans } from '../../../api/billing'; import * as api from '../../../api/organizations'; -import { - hasAdvancedALMIntegration, - isPersonal, - sanitizeAlmId -} from '../../../helpers/almIntegrations'; +import { hasAdvancedALMIntegration, sanitizeAlmId } from '../../../helpers/almIntegrations'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { addWhitePageClass, removeWhitePageClass } from '../../../helpers/pages'; import { get, remove } from '../../../helpers/storage'; @@ -75,9 +70,6 @@ interface Props { ) => Promise; currentUser: T.LoggedInUser; deleteOrganization: (key: string) => Promise; - updateOrganization: ( - organization: T.Organization & { installationId?: string } - ) => Promise; userOrganizations: T.Organization[]; skipOnboarding: () => void; } @@ -287,11 +279,9 @@ export class CreateOrganization extends React.PureComponent { + getHeader = (bindingExistingOrg: boolean) => { if (bindingExistingOrg) { return translate('onboarding.binding_organization'); - } else if (importPersonalOrg) { - return translate('onboarding.import_organization.personal.page.header'); } else { return translate('onboarding.create_organization.page.header'); } @@ -336,8 +326,8 @@ export class CreateOrganization extends React.PureComponent { - const { currentUser, location } = this.props; + renderContent = (almInstallId?: string) => { + const { location } = this.props; const { state } = this; const { organization, step, subscriptionPlans } = state; const { tab = 'auto' } = (location.state || {}) as LocationState; @@ -365,21 +355,6 @@ export class CreateOrganization extends React.PureComponent - ); - } - return ( <> @@ -419,8 +394,7 @@ export class CreateOrganization extends React.PureComponent - !alm && key !== currentUser.personalOrganization && actions.admin + ({ actions = {}, alm }) => !alm && actions.admin )} /> ) : ( @@ -438,19 +412,15 @@ export class CreateOrganization extends React.PureComponent; } - const { almOrganization, bindingExistingOrg, subscriptionPlans } = this.state; - const importPersonalOrg = isPersonal(almOrganization) - ? this.props.userOrganizations.find(o => o.key === currentUser.personalOrganization) - : undefined; - const header = this.getHeader(bindingExistingOrg, !!importPersonalOrg); - + const { bindingExistingOrg, subscriptionPlans } = this.state; + const header = this.getHeader(bindingExistingOrg); const startedPrice = subscriptionPlans && subscriptionPlans[0] && subscriptionPlans[0].price; return ( @@ -463,17 +433,13 @@ export class CreateOrganization extends React.PureComponent {header} - {!importPersonalOrg && startedPrice !== undefined && ( + {startedPrice !== undefined && (

{translate('onboarding.create_organization.page.description')}

)} - {this.state.loading ? ( - - ) : ( - this.renderContent(query.almInstallId, importPersonalOrg) - )} + {this.state.loading ? : this.renderContent(query.almInstallId)} ); @@ -483,7 +449,6 @@ export class CreateOrganization extends React.PureComponent; interface Props { infoBlock?: React.ReactNode; - keyReadOnly?: boolean; onContinue: (organization: T.Organization) => Promise; organization?: T.Organization; submitText: string; @@ -132,12 +131,10 @@ export default class OrganizationDetailsForm extends React.PureComponent - {!keyReadOnly && ( - - )} +
{translate( diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx index 1ce72fbeece..0deff24f195 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx @@ -107,7 +107,7 @@ function shallowRender(props: Partial = {}) { { - const updateOrganization = jest.fn().mockResolvedValue({ key: personalOrg.key }); - const handleOrgDetailsFinish = jest.fn(); - const wrapper = shallowRender({ - almInstallId: 'id-foo', - importPersonalOrg: personalOrg, - handleOrgDetailsFinish, - updateOrganization - }); - - expect(wrapper).toMatchSnapshot(); - - wrapper.find('OrganizationDetailsForm').prop('onContinue')(personalOrg); - await waitAndUpdate(wrapper); - expect(handleOrgDetailsFinish).toBeCalled(); - - wrapper.setProps({ organization: personalOrg }); - wrapper.find('PlanStep').prop('createOrganization')(); - expect(updateOrganization).toBeCalledWith({ ...personalOrg, installationId: 'id-foo' }); -}); - -it('should allow to cancel org import', () => { - const handleCancelImport = jest.fn(); - const wrapper = shallowRender({ - almInstallId: 'id-foo', - importPersonalOrg: personalOrg, - handleCancelImport - }); - - click(wrapper.find('ClearButton')); - expect(handleCancelImport).toBeCalled(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx index 0f9760727c9..7a529d39c70 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx @@ -63,7 +63,6 @@ jest.mock('../../../../api/alm-integration', () => ({ description: 'Continuous Code Quality', key: 'sonarsource', name: 'SonarSource', - personal: false, privateRepos: 0, publicRepos: 3, url: 'https://www.sonarsource.com' @@ -83,12 +82,11 @@ jest.mock('../../../../helpers/storage', () => ({ })); const user = mockLoggedInUser(); -const fooAlmOrganization = mockAlmOrganization({ personal: true }); +const fooAlmOrganization = mockAlmOrganization(); const fooBarAlmOrganization = mockAlmOrganization({ avatar: 'https://avatars3.githubusercontent.com/u/37629810?v=4', key: 'Foo&Bar', - name: 'Foo & Bar', - personal: true + name: 'Foo & Bar' }); const boundOrganization = { key: 'foobar', name: 'Foo & Bar' }; @@ -132,22 +130,9 @@ it('should render with auto tab selected and manual disabled', async () => { expect(getOrganizations).toHaveBeenCalled(); }); -it('should render with auto personal organization bind page', async () => { - (getAlmOrganization as jest.Mock).mockResolvedValueOnce({ - almOrganization: fooAlmOrganization - }); - const wrapper = shallowRender({ - currentUser: { ...user, externalProvider: 'github', personalOrganization: 'foo' }, - location: { query: { installation_id: 'foo' } } as Location - }); - expect(wrapper).toMatchSnapshot(); - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); -}); - it('should render with organization bind page', async () => { (getAlmOrganization as jest.Mock).mockResolvedValueOnce({ - almOrganization: { ...fooAlmOrganization, personal: false } + almOrganization: fooAlmOrganization }); const wrapper = shallowRender({ currentUser: { ...user, externalProvider: 'github' }, @@ -235,7 +220,7 @@ it('should redirect to projects creation page after creation', async () => { state: { organization: 'foo', tab: 'manual' } }); - wrapper.setState({ almOrganization: { ...fooAlmOrganization, personal: false } }); + wrapper.setState({ almOrganization: fooAlmOrganization }); (get as jest.Mock).mockReturnValueOnce(Date.now().toString()); wrapper.instance().handleOrgCreated('foo'); expect(push).toHaveBeenCalledWith({ @@ -246,7 +231,7 @@ it('should redirect to projects creation page after creation', async () => { it('should display AutoOrganizationCreate with already bound organization', async () => { (getAlmOrganization as jest.Mock).mockResolvedValueOnce({ - almOrganization: { ...fooBarAlmOrganization, personal: false }, + almOrganization: fooBarAlmOrganization, boundOrganization }); (get as jest.Mock) @@ -344,7 +329,6 @@ function createComponent(props: Partial = {}) { router={mockRouter()} routes={[]} skipOnboarding={jest.fn()} - updateOrganization={jest.fn()} userOrganizations={[ mockOrganizationWithAdminActions(), mockOrganizationWithAdminActions(mockOrganizationWithAlm({ key: 'bar', name: 'Bar' })), diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanStep-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanStep-test.tsx index 58a2f95af78..8cdf7afba77 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanStep-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanStep-test.tsx @@ -80,7 +80,7 @@ it('should upgrade', async () => { it('should preselect paid plan', async () => { const wrapper = shallow( - -
- , - "name": - foo - , - "personalAvatar": , - "personalName": - Personal Org - , - } - } - /> - -
- -
- - -`; diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap index aa76ac05400..3e5bdda098a 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap @@ -1,92 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should render with auto personal organization bind page 1`] = ` - -`; - -exports[`should render with auto personal organization bind page 2`] = ` - - -
- -
-

- - onboarding.import_organization.personal.page.header - -

-
- -
-
-`; - exports[`should render with auto tab displayed 1`] = ` ({ bindAlmOrganization: jest.fn().mockResolvedValue({}) @@ -64,26 +63,3 @@ describe('#createOrganization', () => { expect(syncMembers).toHaveBeenCalledWith(org.key); }); }); - -describe('#updateOrganization', () => { - it('should update and dispatch', async () => { - const org = mockOrganization(); - const { key, ...changes } = org; - const promise = actions.updateOrganization(org)(dispatch); - - expect(updateOrganization).toHaveBeenCalledWith(key, changes); - const returnValue = await promise; - expect(dispatch).toHaveBeenCalledWith({ changes, key, type: 'UPDATE_ORGANIZATION' }); - expect(returnValue).toBe(key); - }); - - it('should update and bind', () => { - const org = { ...mockOrganization(), installationId: '1' }; - const { key, installationId, ...changes } = org; - const promise = actions.updateOrganization(org)(dispatch); - - expect(updateOrganization).toHaveBeenCalledWith(key, changes); - expect(bindAlmOrganization).toHaveBeenCalledWith({ organization: key, installationId }); - return promise; - }); -}); diff --git a/server/sonar-web/src/main/js/apps/create/organization/actions.ts b/server/sonar-web/src/main/js/apps/create/organization/actions.ts index 38b90fff706..950156f2876 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/actions.ts +++ b/server/sonar-web/src/main/js/apps/create/organization/actions.ts @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { Dispatch } from 'redux'; -import { bindAlmOrganization } from '../../../api/alm-integration'; import * as api from '../../../api/organizations'; import * as actions from '../../../store/organizations'; import { isGithub } from '../../../helpers/almIntegrations'; @@ -39,17 +38,3 @@ export function createOrganization({ }); }; } - -export function updateOrganization(organization: T.Organization & { installationId?: string }) { - return (dispatch: Dispatch) => { - const { key, installationId, ...changes } = organization; - const promises = [api.updateOrganization(key, changes)]; - if (installationId) { - promises.push(bindAlmOrganization({ organization: key, installationId })); - } - return Promise.all(promises).then(() => { - dispatch(actions.updateOrganization(key, changes)); - return organization.key; - }); - }; -} diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/MembersListHeader.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/MembersListHeader.tsx index fa4f38355fb..012a3bd4d13 100644 --- a/server/sonar-web/src/main/js/apps/organizationMembers/MembersListHeader.tsx +++ b/server/sonar-web/src/main/js/apps/organizationMembers/MembersListHeader.tsx @@ -25,18 +25,12 @@ import { translate, translateWithParameters } from '../../helpers/l10n'; import { formatMeasure } from '../../helpers/measures'; export interface Props { - currentUser: T.LoggedInUser; handleSearch: (query?: string) => void; organization: T.Organization; total?: number; } -export default function MembersListHeader({ - currentUser, - handleSearch, - organization, - total -}: Props) { +export default function MembersListHeader({ handleSearch, organization, total }: Props) { return ( } diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembers.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembers.tsx index 5440ef11efe..c0ee1942a5e 100644 --- a/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembers.tsx +++ b/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembers.tsx @@ -212,7 +212,6 @@ export default class OrganizationMembers extends React.PureComponent { expect(shallowRender({ total: undefined })).toMatchSnapshot(); @@ -50,19 +46,9 @@ it('should render a help tooltip', () => { ).toMatchSnapshot(); }); -it('should not render link in help tooltip', () => { - expect( - shallowRender({ - currentUser: mockLoggedInUser({ personalOrganization: 'foo' }), - organization: mockOrganizationWithAlm({}, { membersSync: true }) - }).find('HelpTooltip') - ).toMatchSnapshot(); -}); - function shallowRender(props: Partial = {}) { return shallow( organization.members.auto_sync_total_help.github

-
- } -/> -`; - -exports[`should render a help tooltip 1`] = ` - +

- organization.members.auto_sync_total_help.github + + organization.members.see_all_members_on_x.github +

- -
-

- - organization.members.see_all_members_on_x.github - -

-
+ )} } /> @@ -52,18 +36,17 @@ exports[`should render a help tooltip 2`] = `

organization.members.auto_sync_total_help.bitbucket

- -
-

- - organization.members.see_all_members_on_x.bitbucket - -

-
+
+

+ + organization.members.see_all_members_on_x.bitbucket + +

+ )} } /> diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap index 78bbd758aa1..b10011aca00 100644 --- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap @@ -72,15 +72,6 @@ exports[`should fetch members and render for non-admin 2`] = ` refreshMembers={[Function]} /> ; } diff --git a/server/sonar-web/src/main/js/apps/organizations/routes.ts b/server/sonar-web/src/main/js/apps/organizations/routes.ts index 21f0dd439c7..6a5e4df50a0 100644 --- a/server/sonar-web/src/main/js/apps/organizations/routes.ts +++ b/server/sonar-web/src/main/js/apps/organizations/routes.ts @@ -72,13 +72,8 @@ const routes = [ childRoutes: qualityGatesRoutes }, { - component: lazyLoad(() => - import('./components/OrganizationAccessContainer').then(lib => ({ - default: lib.OrganizationAdminAccess - })) - ), + component: lazyLoad(() => import('./components/OrganizationAccessContainer')), childRoutes: [ - { path: 'delete', component: lazyLoad(() => import('./components/OrganizationDelete')) }, { path: 'edit', component: lazyLoad(() => import('./components/OrganizationEdit')) }, { path: 'groups', component: lazyLoad(() => import('../groups/components/App')) }, { diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx index be329f2055e..1228a602cce 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx @@ -29,16 +29,13 @@ import { translate } from '../../../helpers/l10n'; import '../styles.css'; export interface Props { - currentUser: T.LoggedInUser; onClose: VoidFunction; onOpenProjectOnboarding: VoidFunction; userOrganizations: T.Organization[]; } export function OnboardingModal(props: Props) { - const { currentUser, onClose, onOpenProjectOnboarding, userOrganizations } = props; - - const organizations = userOrganizations.filter(o => o.key !== currentUser.personalOrganization); + const { onClose, onOpenProjectOnboarding, userOrganizations } = props; const header = translate('onboarding.header'); return ( @@ -46,7 +43,7 @@ export function OnboardingModal(props: Props) { contentLabel={header} onRequestClose={onClose} shouldCloseOnOverlayClick={false} - size={organizations.length > 0 ? 'medium' : 'small'}> + size={userOrganizations.length > 0 ? 'medium' : 'small'}>

{translate('onboarding.header')}

{translate('onboarding.header.description')}

@@ -59,7 +56,7 @@ export function OnboardingModal(props: Props) { {translate('onboarding.project.create')}
- {organizations.length > 0 && ( + {userOrganizations.length > 0 && ( <>
@@ -69,7 +66,7 @@ export function OnboardingModal(props: Props) {

{translate('onboarding.browse_your_organizations')}

- +
)} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx index 23ee2e84229..722c04598fb 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import { OnboardingModal, Props } from '../OnboardingModal'; import { click } from '../../../../helpers/testUtils'; -import { mockLoggedInUser, mockOrganization } from '../../../../helpers/testMocks'; +import { mockOrganization } from '../../../../helpers/testMocks'; it('renders correctly', () => { expect(shallowRender()).toMatchSnapshot(); @@ -41,22 +41,20 @@ it('should open project create page', () => { it('should display organization list if any', () => { const wrapper = shallowRender({ - currentUser: mockLoggedInUser({ personalOrganization: 'personal' }), userOrganizations: [ mockOrganization({ key: 'a', name: 'Arthur' }), - mockOrganization({ key: 'd', name: 'Daniel Inc' }), - mockOrganization({ key: 'personal', name: 'Personal' }) + mockOrganization({ key: 'b', name: 'Boston Co' }), + mockOrganization({ key: 'd', name: 'Daniel Inc' }) ] }); expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('OrganizationsShortList').prop('organizations')).toHaveLength(2); + expect(wrapper.find('OrganizationsShortList').prop('organizations')).toHaveLength(3); }); function shallowRender(props: Partial = {}) { return shallow( ( + WrappedComponent: React.ComponentType

, + hocName: string +) { const wrappedDisplayName = WrappedComponent.displayName || WrappedComponent.name || 'Component'; return `${hocName}(${wrappedDisplayName})`; } diff --git a/server/sonar-web/src/main/js/helpers/__tests__/almIntegrations-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/almIntegrations-test.ts index 212af84369f..8d36e055253 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/almIntegrations-test.ts +++ b/server/sonar-web/src/main/js/helpers/__tests__/almIntegrations-test.ts @@ -20,7 +20,6 @@ import { isBitbucket, isGithub, - isPersonal, isVSTS, sanitizeAlmId, getAlmMembersUrl, @@ -53,19 +52,6 @@ it('#isVSTS', () => { expect(isVSTS('github')).toBeFalsy(); }); -it('#isPersonal', () => { - const almOrg = { - almUrl: '', - key: 'foo', - name: 'Foo', - personal: true, - privateRepos: 0, - publicRepos: 3 - }; - expect(isPersonal(almOrg)).toBeTruthy(); - expect(isPersonal({ ...almOrg, personal: false })).toBeFalsy(); -}); - it('#sanitizeAlmId', () => { expect(sanitizeAlmId('bitbucketcloud')).toBe('bitbucket'); expect(sanitizeAlmId('bitbucket')).toBe('bitbucket'); diff --git a/server/sonar-web/src/main/js/helpers/almIntegrations.ts b/server/sonar-web/src/main/js/helpers/almIntegrations.ts index 16766f958c9..7c98feba474 100644 --- a/server/sonar-web/src/main/js/helpers/almIntegrations.ts +++ b/server/sonar-web/src/main/js/helpers/almIntegrations.ts @@ -53,10 +53,6 @@ export function isVSTS(almKey?: string): boolean { return almKey === 'microsoft'; } -export function isPersonal(organization?: T.AlmOrganization) { - return Boolean(organization && organization.personal); -} - export function sanitizeAlmId(almKey: string) { if (isBitbucket(almKey)) { return 'bitbucket'; diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts index 9fd2c05f8f9..7e9b7eb4d1e 100644 --- a/server/sonar-web/src/main/js/helpers/testMocks.ts +++ b/server/sonar-web/src/main/js/helpers/testMocks.ts @@ -43,7 +43,6 @@ export function mockAlmOrganization(overrides: Partial = {}): description: 'description-foo', key: 'foo', name: 'foo', - personal: false, privateRepos: 0, publicRepos: 3, url: 'http://example.com/foo', diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 3a940ac84fe..f70d466e866 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2882,7 +2882,6 @@ onboarding.import_organization.choose_organization_button.github=Choose an organ onboarding.import_organization.choose_the_organization_button.bitbucket=Choose the team on Bitbucket onboarding.import_organization.choose_the_organization_button.github=Choose the organization on GitHub onboarding.import_organization.installing=Finalize installation of the {0} application... -onboarding.import_organization.personal.page.header=Bind to your personal organization onboarding.import_organization.personal.import_org_details=Import personal organization details onboarding.import_organization.private.disabled=Selecting private repository is not available yet and will come soon. Meanwhile, you need to create the project manually. onboarding.import_organization.import_from_x=Import from {0}