diff options
Diffstat (limited to 'server/sonar-web/src')
89 files changed, 102 insertions, 2368 deletions
diff --git a/server/sonar-web/src/main/js/api/components.ts b/server/sonar-web/src/main/js/api/components.ts index 18401c85430..f0daad39faa 100644 --- a/server/sonar-web/src/main/js/api/components.ts +++ b/server/sonar-web/src/main/js/api/components.ts @@ -189,7 +189,6 @@ export function getMyProjects(data: { } export interface Component { - organization: string; id: string; key: string; name: string; @@ -212,7 +211,6 @@ export function searchProjects( ): Promise<{ components: Component[]; facets: Facet[]; - organizations: Array<{ key: string; name: string }>; paging: T.Paging; }> { const url = '/api/components/search_projects'; @@ -232,7 +230,6 @@ export function changeKey(data: { from: string; to: string }) { } export interface SuggestionsResponse { - organizations: Array<{ key: string; name: string }>; projects: Array<{ key: string; name: string }>; results: Array<{ items: Array<{ @@ -241,7 +238,6 @@ export interface SuggestionsResponse { key: string; match: string; name: string; - organization: string; project: string; }>; more: number; diff --git a/server/sonar-web/src/main/js/api/issues.ts b/server/sonar-web/src/main/js/api/issues.ts index bb3a396e702..afd7e315a39 100644 --- a/server/sonar-web/src/main/js/api/issues.ts +++ b/server/sonar-web/src/main/js/api/issues.ts @@ -75,7 +75,6 @@ export function getFacet( } export function searchIssueTags(data: { - organization?: string; project?: string; ps?: number; q?: string; @@ -136,7 +135,6 @@ export function bulkChangeIssues(issueKeys: string[], query: RequestData): Promi } export function searchIssueAuthors(data: { - organization?: string; project?: string; ps?: number; q?: string; diff --git a/server/sonar-web/src/main/js/api/organizations.ts b/server/sonar-web/src/main/js/api/organizations.ts deleted file mode 100644 index dd38f41fa6c..00000000000 --- a/server/sonar-web/src/main/js/api/organizations.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { getJSON } from 'sonar-ui-common/helpers/request'; -import throwGlobalError from '../app/utils/throwGlobalError'; - -export function getOrganizations(data: { - organizations?: string; - member?: boolean; -}): Promise<{ - organizations: T.Organization[]; - paging: T.Paging; -}> { - return getJSON('/api/organizations/search', data).catch(throwGlobalError); -} - -export function getOrganization(key: string): Promise<T.Organization | undefined> { - return getJSON('/api/organizations/search', { organizations: key }).then( - r => r.organizations.find((o: T.Organization) => o.key === key), - throwGlobalError - ); -} diff --git a/server/sonar-web/src/main/js/api/quality-profiles.ts b/server/sonar-web/src/main/js/api/quality-profiles.ts index fcd82b61b5a..967addb717f 100644 --- a/server/sonar-web/src/main/js/api/quality-profiles.ts +++ b/server/sonar-web/src/main/js/api/quality-profiles.ts @@ -229,7 +229,6 @@ export function dissociateProject({ language, name: qualityProfile }: Profile, p export interface SearchUsersGroupsParameters { language: string; - organization?: string; qualityProfile: string; q?: string; selected?: 'all' | 'selected' | 'deselected'; @@ -272,7 +271,6 @@ export function removeUser(parameters: AddRemoveUserParameters): Promise<void | export interface AddRemoveGroupParameters { group: string; language: string; - organization?: string; qualityProfile: string; } diff --git a/server/sonar-web/src/main/js/api/rules.ts b/server/sonar-web/src/main/js/api/rules.ts index 7a02fbe6885..4b6c3087857 100644 --- a/server/sonar-web/src/main/js/api/rules.ts +++ b/server/sonar-web/src/main/js/api/rules.ts @@ -25,10 +25,7 @@ export function getRulesApp(): Promise<GetRulesAppResponse> { return getJSON('/api/rules/app').catch(throwGlobalError); } -export function searchRules(data: { - organization?: string; - [x: string]: any; -}): Promise<SearchRulesResponse> { +export function searchRules(data: { [x: string]: any }): Promise<SearchRulesResponse> { return getJSON('/api/rules/search', data).catch(throwGlobalError); } @@ -73,7 +70,7 @@ export function createRule(data: { ); } -export function deleteRule(parameters: { key: string; organization?: string }) { +export function deleteRule(parameters: { key: string }) { return post('/api/rules/delete', parameters).catch(throwGlobalError); } diff --git a/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx b/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx deleted file mode 100644 index 39affc6e1c0..00000000000 --- a/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { connect } from 'react-redux'; -import { fetchOrganization } from '../../../store/rootActions'; -import { getOrganizationByKey, Store } from '../../../store/rootReducer'; -import NotFound from '../NotFound'; -import Extension from './Extension'; - -interface StateToProps { - organization?: T.Organization; -} - -interface DispatchProps { - fetchOrganization: (organizationKey: string) => void; -} - -interface OwnProps { - location: {}; - params: { - extensionKey: string; - organizationKey: string; - pluginKey: string; - }; -} - -type Props = OwnProps & StateToProps & DispatchProps; - -class OrganizationPageExtension extends React.PureComponent<Props> { - refreshOrganization = () => { - return this.props.organization && this.props.fetchOrganization(this.props.organization.key); - }; - - render() { - const { extensionKey, pluginKey } = this.props.params; - const { organization } = this.props; - - if (!organization) { - return null; - } - - const { actions = {} } = organization; - let { pages = [] } = organization; - if (actions.admin && organization.adminPages) { - pages = pages.concat(organization.adminPages); - } - - const extension = pages.find(p => p.key === `${pluginKey}/${extensionKey}`); - return extension ? ( - <Extension - extension={extension} - options={{ organization, refreshOrganization: this.refreshOrganization }} - /> - ) : ( - <NotFound withContainer={false} /> - ); - } -} - -const mapStateToProps = (state: Store, ownProps: OwnProps) => ({ - organization: getOrganizationByKey(state, ownProps.params.organizationKey) -}); - -const mapDispatchToProps = { fetchOrganization }; - -export default connect(mapStateToProps, mapDispatchToProps)(OrganizationPageExtension); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx index 3d502b1aca0..e44b628aafd 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx @@ -21,213 +21,47 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent'; import NavBar from 'sonar-ui-common/components/ui/NavBar'; -import { parseDate } from 'sonar-ui-common/helpers/dates'; -import { - fetchPrismicFeatureNews, - fetchPrismicRefs, - PrismicFeatureNews -} from '../../../../api/news'; -import { isSonarCloud } from '../../../../helpers/system'; import { isLoggedIn } from '../../../../helpers/users'; -import { - getAppState, - getCurrentUser, - getCurrentUserSetting, - getGlobalSettingValue, - Store -} from '../../../../store/rootReducer'; -import { setCurrentUserSetting } from '../../../../store/users'; +import { getAppState, getCurrentUser, Store } from '../../../../store/rootReducer'; import { rawSizes } from '../../../theme'; import EmbedDocsPopupHelper from '../../embed-docs-modal/EmbedDocsPopupHelper'; import Search from '../../search/Search'; import './GlobalNav.css'; -import GlobalNavBranding, { SonarCloudNavBranding } from './GlobalNavBranding'; +import GlobalNavBranding from './GlobalNavBranding'; import GlobalNavMenu from './GlobalNavMenu'; -import GlobalNavUserContainer from './GlobalNavUserContainer'; +import GlobalNavUser from './GlobalNavUser'; const GlobalNavPlus = lazyLoadComponent(() => import('./GlobalNavPlus'), 'GlobalNavPlus'); -const NotificationsSidebar = lazyLoadComponent( - () => import('../../notifications/NotificationsSidebar'), - 'NotificationsSidebar' -); -const NavLatestNotification = lazyLoadComponent( - () => import('../../notifications/NavLatestNotification'), - 'NavLatestNotification' -); -interface Props { - accessToken?: string; - appState: Pick<T.AppState, 'canAdmin' | 'globalPages' | 'organizationsEnabled' | 'qualifiers'>; +export interface GlobalNavProps { + appState: Pick<T.AppState, 'canAdmin' | 'globalPages' | 'qualifiers'>; currentUser: T.CurrentUser; location: { pathname: string }; - notificationsLastReadDate?: Date; - notificationsOptOut?: boolean; - setCurrentUserSetting: (setting: T.CurrentUserSetting) => void; } -interface State { - notificationSidebar?: boolean; - loadingNews: boolean; - loadingMoreNews: boolean; - news: PrismicFeatureNews[]; - newsPaging?: T.Paging; - newsRef?: string; -} - -const PAGE_SIZE = 5; - -export class GlobalNav extends React.PureComponent<Props, State> { - mounted = false; - state: State = { - loadingNews: false, - loadingMoreNews: false, - news: [], - notificationSidebar: false - }; - - componentDidMount() { - this.mounted = true; - if (isSonarCloud()) { - this.fetchFeatureNews(); - } - } - - componentWillUnmount() { - this.mounted = false; - } - - fetchFeatureNews = () => { - const { accessToken } = this.props; - if (accessToken) { - this.setState({ loadingNews: true }); - fetchPrismicRefs() - .then(({ ref }) => { - if (this.mounted) { - this.setState({ newsRef: ref }); - } - return ref; - }) - .then(ref => fetchPrismicFeatureNews({ accessToken, ref, ps: PAGE_SIZE })) - .then( - ({ news, paging }) => { - if (this.mounted) { - this.setState({ - loadingNews: false, - news, - newsPaging: paging - }); - } - }, - () => { - if (this.mounted) { - this.setState({ loadingNews: false }); - } - } - ); - } - }; - - fetchMoreFeatureNews = () => { - const { accessToken } = this.props; - const { newsPaging, newsRef } = this.state; - if (accessToken && newsPaging && newsRef) { - this.setState({ loadingMoreNews: true }); - fetchPrismicFeatureNews({ - accessToken, - ref: newsRef, - p: newsPaging.pageIndex + 1, - ps: PAGE_SIZE - }).then( - ({ news, paging }) => { - if (this.mounted) { - this.setState(state => ({ - loadingMoreNews: false, - news: [...state.news, ...news], - newsPaging: paging - })); - } - }, - () => { - if (this.mounted) { - this.setState({ loadingMoreNews: false }); - } - } - ); - } - }; - - handleOpenNotificationSidebar = () => { - this.setState({ notificationSidebar: true }); - this.fetchFeatureNews(); - }; - - handleCloseNotificationSidebar = () => { - this.setState({ notificationSidebar: false }); - const lastNews = this.state.news[0]; - const readDate = lastNews ? parseDate(lastNews.publicationDate).getTime() : Date.now(); - this.props.setCurrentUserSetting({ key: 'notifications.readDate', value: readDate.toString() }); - }; - - render() { - const { appState, currentUser } = this.props; - const { news } = this.state; - return ( - <NavBar className="navbar-global" height={rawSizes.globalNavHeightRaw} id="global-navigation"> - {isSonarCloud() ? <SonarCloudNavBranding /> : <GlobalNavBranding />} - - <GlobalNavMenu {...this.props} /> - - <ul className="global-navbar-menu global-navbar-menu-right"> - {isSonarCloud() && isLoggedIn(currentUser) && news.length > 0 && ( - <NavLatestNotification - lastNews={news[0]} - notificationsLastReadDate={this.props.notificationsLastReadDate} - notificationsOptOut={this.props.notificationsOptOut} - onClick={this.handleOpenNotificationSidebar} - setCurrentUserSetting={this.props.setCurrentUserSetting} - /> - )} - <EmbedDocsPopupHelper /> - <Search appState={appState} currentUser={currentUser} /> - {isLoggedIn(currentUser) && ( - <GlobalNavPlus appState={appState} currentUser={currentUser} /> - )} - <GlobalNavUserContainer appState={appState} currentUser={currentUser} /> - </ul> - {isSonarCloud() && isLoggedIn(currentUser) && this.state.notificationSidebar && ( - <NotificationsSidebar - fetchMoreFeatureNews={this.fetchMoreFeatureNews} - loading={this.state.loadingNews} - loadingMore={this.state.loadingMoreNews} - news={news} - notificationsLastReadDate={this.props.notificationsLastReadDate} - onClose={this.handleCloseNotificationSidebar} - paging={this.state.newsPaging} - /> - )} - </NavBar> - ); - } +export function GlobalNav(props: GlobalNavProps) { + const { appState, currentUser, location } = props; + return ( + <NavBar className="navbar-global" height={rawSizes.globalNavHeightRaw} id="global-navigation"> + <GlobalNavBranding /> + + <GlobalNavMenu appState={appState} currentUser={currentUser} location={location} /> + + <ul className="global-navbar-menu global-navbar-menu-right"> + <EmbedDocsPopupHelper /> + <Search currentUser={currentUser} /> + {isLoggedIn(currentUser) && <GlobalNavPlus appState={appState} currentUser={currentUser} />} + <GlobalNavUser currentUser={currentUser} /> + </ul> + </NavBar> + ); } const mapStateToProps = (state: Store) => { - const accessToken = getGlobalSettingValue(state, 'sonar.prismic.accessToken'); - const notificationsLastReadDate = getCurrentUserSetting(state, 'notifications.readDate'); - const notificationsOptOut = getCurrentUserSetting(state, 'notifications.optOut') === 'true'; - return { currentUser: getCurrentUser(state), - appState: getAppState(state), - accessToken: accessToken && accessToken.value, - notificationsLastReadDate: notificationsLastReadDate - ? parseDate(Number(notificationsLastReadDate)) - : undefined, - notificationsOptOut + appState: getAppState(state) }; }; -const mapDispatchToProps = { - setCurrentUserSetting -}; - -export default connect(mapStateToProps, mapDispatchToProps)(GlobalNav); +export default connect(mapStateToProps)(GlobalNav); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx index f384811b69e..386ffa1b77e 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx @@ -28,7 +28,7 @@ import { getQualityGatesUrl } from '../../../../helpers/urls'; import { ComponentQualifier } from '../../../../types/component'; interface Props { - appState: Pick<T.AppState, 'canAdmin' | 'globalPages' | 'organizationsEnabled' | 'qualifiers'>; + appState: Pick<T.AppState, 'canAdmin' | 'globalPages' | 'qualifiers'>; currentUser: T.CurrentUser; location: { pathname: string }; } @@ -156,16 +156,15 @@ export default class GlobalNavMenu extends React.PureComponent<Props> { const governanceInstalled = this.props.appState.qualifiers.includes( ComponentQualifier.Portfolio ); - const { organizationsEnabled } = this.props.appState; return ( <ul className="global-navbar-menu"> {this.renderProjects()} {governanceInstalled && this.renderPortfolios()} {this.renderIssuesLink()} - {!organizationsEnabled && this.renderRulesLink()} - {!organizationsEnabled && this.renderProfilesLink()} - {!organizationsEnabled && this.renderQualityGatesLink()} + {this.renderRulesLink()} + {this.renderProfilesLink()} + {this.renderQualityGatesLink()} {this.renderAdministrationLink()} {this.renderMore()} </ul> diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx index dfd43b4a876..c54ad724b51 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx @@ -17,7 +17,6 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { sortBy } from 'lodash'; import * as React from 'react'; import { Link } from 'react-router'; import Dropdown from 'sonar-ui-common/components/controls/Dropdown'; @@ -25,14 +24,11 @@ import { translate } from 'sonar-ui-common/helpers/l10n'; import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; import { Router, withRouter } from '../../../../components/hoc/withRouter'; import Avatar from '../../../../components/ui/Avatar'; -import OrganizationListItem from '../../../../components/ui/OrganizationListItem'; import { isLoggedIn } from '../../../../helpers/users'; import { rawSizes } from '../../../theme'; interface Props { - appState: { organizationsEnabled?: boolean }; currentUser: T.CurrentUser; - organizations: T.Organization[]; router: Pick<Router, 'push'>; } @@ -55,9 +51,7 @@ export class GlobalNavUser extends React.PureComponent<Props> { }; renderAuthenticated() { - const { organizations } = this.props; const currentUser = this.props.currentUser as T.LoggedInUser; - const hasOrganizations = this.props.appState.organizationsEnabled && organizations.length > 0; return ( <Dropdown className="js-user-authenticated" @@ -79,17 +73,6 @@ export class GlobalNavUser extends React.PureComponent<Props> { <li> <Link to="/account">{translate('my_account.page')}</Link> </li> - {hasOrganizations && <li className="divider" role="separator" />} - {hasOrganizations && ( - <li> - <Link to="/account/organizations">{translate('my_organizations')}</Link> - </li> - )} - {hasOrganizations && - sortBy(organizations, org => org.name.toLowerCase()).map(organization => ( - <OrganizationListItem key={organization.key} organization={organization} /> - ))} - {hasOrganizations && <li className="divider" role="separator" />} <li> <a href="#" onClick={this.handleLogout}> {translate('layout.logout')} diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx deleted file mode 100644 index 29d1b0be12f..00000000000 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { connect } from 'react-redux'; -import { getMyOrganizations, Store } from '../../../../store/rootReducer'; -import GlobalNavUser from './GlobalNavUser'; - -interface StateProps { - organizations: T.Organization[]; -} - -const mapStateToProps = (state: Store): StateProps => ({ - organizations: getMyOrganizations(state) -}); - -export default connect(mapStateToProps)(GlobalNavUser); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx index fe1f064d71d..f8db7ea5536 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx @@ -19,71 +19,21 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { click, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; -import { - fetchPrismicFeatureNews, - fetchPrismicRefs, - PrismicFeatureNews -} from '../../../../../api/news'; -import { isSonarCloud } from '../../../../../helpers/system'; -import { GlobalNav } from '../GlobalNav'; - -jest.mock('../../../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); +import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; +import { GlobalNav, GlobalNavProps } from '../GlobalNav'; // Solve redux warning issue "No reducer provided for key": // https://stackoverflow.com/questions/43375079/redux-warning-only-appearing-in-tests jest.mock('../../../../../store/rootReducer'); -jest.mock('../../../../../api/news', () => { - const prismicResult: PrismicFeatureNews[] = [ - { - notification: '10 Java rules, Github checks, Security Hotspots, BitBucket branch decoration', - publicationDate: '2018-04-06', - features: [ - { - categories: [{ color: '#ff0000', name: 'Java' }], - description: '10 new Java rules' - } - ] - }, - { - notification: 'Some other notification', - publicationDate: '2018-04-05', - features: [ - { - categories: [{ color: '#0000ff', name: 'BitBucket' }], - description: 'BitBucket branch decoration', - readMore: 'http://example.com' - } - ] - } - ]; - - return { - fetchPrismicRefs: jest.fn().mockResolvedValue({ ref: 'master-ref' }), - fetchPrismicFeatureNews: jest.fn().mockResolvedValue({ - news: prismicResult, - paging: { pageIndex: 1, pageSize: 10, total: 2 } - }) - }; -}); - -const appState: GlobalNav['props']['appState'] = { +const appState: GlobalNavProps['appState'] = { globalPages: [], canAdmin: false, - organizationsEnabled: false, qualifiers: [] }; const location = { pathname: '' }; -beforeEach(() => { - (fetchPrismicRefs as jest.Mock).mockClear(); - (fetchPrismicFeatureNews as jest.Mock).mockClear(); -}); - it('should render correctly', async () => { - (isSonarCloud as jest.Mock).mockImplementation(() => false); - const wrapper = shallowRender(); expect(wrapper).toMatchSnapshot('anonymous users'); @@ -93,28 +43,12 @@ it('should render correctly', async () => { await waitAndUpdate(wrapper); }); -it('should render correctly if there are new features', async () => { - (isSonarCloud as jest.Mock).mockImplementation(() => true); - const wrapper = shallowRender(); - wrapper.setProps({ currentUser: { isLoggedIn: true } }); - - await waitAndUpdate(wrapper); - expect(fetchPrismicRefs).toHaveBeenCalled(); - expect(fetchPrismicFeatureNews).toHaveBeenCalled(); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('NavLatestNotification').exists()).toBe(true); - click(wrapper.find('NavLatestNotification')); - expect(wrapper.find('NotificationsSidebar').exists()).toBe(true); -}); - -function shallowRender(props: Partial<GlobalNav['props']> = {}) { +function shallowRender(props: Partial<GlobalNavProps> = {}) { return shallow( <GlobalNav - accessToken="token" appState={appState} currentUser={{ isLoggedIn: false }} location={location} - setCurrentUserSetting={jest.fn()} {...props} /> ); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx index bc7245b1f17..03af0f9429d 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx @@ -19,64 +19,21 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; +import { mockCurrentUser, mockLoggedInUser, mockRouter } from '../../../../../helpers/testMocks'; import { GlobalNavUser } from '../GlobalNavUser'; -const currentUser = { avatar: 'abcd1234', isLoggedIn: true, name: 'foo', email: 'foo@bar.baz' }; -const organizations: T.Organization[] = [ - { key: 'myorg', name: 'MyOrg', projectVisibility: 'public' }, - { key: 'foo', name: 'Foo', projectVisibility: 'public' }, - { key: 'bar', name: 'bar', projectVisibility: 'public' } -]; -const appState = { organizationsEnabled: true }; - it('should render the right interface for anonymous user', () => { - const currentUser = { isLoggedIn: false }; - const wrapper = shallow( - <GlobalNavUser - appState={appState} - currentUser={currentUser} - organizations={[]} - router={{ push: jest.fn() }} - /> - ); - expect(wrapper).toMatchSnapshot(); + expect(shallowRender({ currentUser: mockCurrentUser() })).toMatchSnapshot(); }); it('should render the right interface for logged in user', () => { - const wrapper = shallow( - <GlobalNavUser - appState={appState} - currentUser={currentUser} - organizations={[]} - router={{ push: jest.fn() }} - /> - ); + const wrapper = shallowRender(); wrapper.setState({ open: true }); expect(wrapper.find('Dropdown')).toMatchSnapshot(); }); -it('should render user organizations', () => { - const wrapper = shallow( - <GlobalNavUser - appState={appState} - currentUser={currentUser} - organizations={organizations} - router={{ push: jest.fn() }} - /> +function shallowRender(overrides: Partial<GlobalNavUser['props']> = {}) { + return shallow<GlobalNavUser>( + <GlobalNavUser currentUser={mockLoggedInUser()} router={mockRouter()} {...overrides} /> ); - wrapper.setState({ open: true }); - expect(wrapper.find('Dropdown')).toMatchSnapshot(); -}); - -it('should not render user organizations when they are not activated', () => { - const wrapper = shallow( - <GlobalNavUser - appState={{ organizationsEnabled: false }} - currentUser={currentUser} - organizations={organizations} - router={{ push: jest.fn() }} - /> - ); - wrapper.setState({ open: true }); - expect(wrapper.find('Dropdown')).toMatchSnapshot(); -}); +} diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNav-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNav-test.tsx.snap index f5ddebb16d6..df3ede93b16 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNav-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNav-test.tsx.snap @@ -1,108 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should render correctly if there are new features 1`] = ` -<NavBar - className="navbar-global" - height={48} - id="global-navigation" -> - <SonarCloudNavBranding /> - <GlobalNavMenu - accessToken="token" - appState={ - Object { - "canAdmin": false, - "globalPages": Array [], - "organizationsEnabled": false, - "qualifiers": Array [], - } - } - currentUser={ - Object { - "isLoggedIn": true, - } - } - location={ - Object { - "pathname": "", - } - } - setCurrentUserSetting={[MockFunction]} - /> - <ul - className="global-navbar-menu global-navbar-menu-right" - > - <NavLatestNotification - lastNews={ - Object { - "features": Array [ - Object { - "categories": Array [ - Object { - "color": "#ff0000", - "name": "Java", - }, - ], - "description": "10 new Java rules", - }, - ], - "notification": "10 Java rules, Github checks, Security Hotspots, BitBucket branch decoration", - "publicationDate": "2018-04-06", - } - } - onClick={[Function]} - setCurrentUserSetting={[MockFunction]} - /> - <EmbedDocsPopupHelper /> - <withRouter(Search) - appState={ - Object { - "canAdmin": false, - "globalPages": Array [], - "organizationsEnabled": false, - "qualifiers": Array [], - } - } - currentUser={ - Object { - "isLoggedIn": true, - } - } - /> - <GlobalNavPlus - appState={ - Object { - "canAdmin": false, - "globalPages": Array [], - "organizationsEnabled": false, - "qualifiers": Array [], - } - } - currentUser={ - Object { - "isLoggedIn": true, - } - } - /> - <Connect(withRouter(GlobalNavUser)) - appState={ - Object { - "canAdmin": false, - "globalPages": Array [], - "organizationsEnabled": false, - "qualifiers": Array [], - } - } - currentUser={ - Object { - "isLoggedIn": true, - } - } - /> - </ul> -</NavBar> -`; - exports[`should render correctly: anonymous users 1`] = ` <NavBar className="navbar-global" @@ -111,12 +8,10 @@ exports[`should render correctly: anonymous users 1`] = ` > <Connect(GlobalNavBranding) /> <GlobalNavMenu - accessToken="token" appState={ Object { "canAdmin": false, "globalPages": Array [], - "organizationsEnabled": false, "qualifiers": Array [], } } @@ -130,36 +25,19 @@ exports[`should render correctly: anonymous users 1`] = ` "pathname": "", } } - setCurrentUserSetting={[MockFunction]} /> <ul className="global-navbar-menu global-navbar-menu-right" > <EmbedDocsPopupHelper /> <withRouter(Search) - appState={ - Object { - "canAdmin": false, - "globalPages": Array [], - "organizationsEnabled": false, - "qualifiers": Array [], - } - } currentUser={ Object { "isLoggedIn": false, } } /> - <Connect(withRouter(GlobalNavUser)) - appState={ - Object { - "canAdmin": false, - "globalPages": Array [], - "organizationsEnabled": false, - "qualifiers": Array [], - } - } + <withRouter(GlobalNavUser) currentUser={ Object { "isLoggedIn": false, @@ -178,12 +56,10 @@ exports[`should render correctly: logged in users 1`] = ` > <Connect(GlobalNavBranding) /> <GlobalNavMenu - accessToken="token" appState={ Object { "canAdmin": false, "globalPages": Array [], - "organizationsEnabled": false, "qualifiers": Array [], } } @@ -197,21 +73,12 @@ exports[`should render correctly: logged in users 1`] = ` "pathname": "", } } - setCurrentUserSetting={[MockFunction]} /> <ul className="global-navbar-menu global-navbar-menu-right" > <EmbedDocsPopupHelper /> <withRouter(Search) - appState={ - Object { - "canAdmin": false, - "globalPages": Array [], - "organizationsEnabled": false, - "qualifiers": Array [], - } - } currentUser={ Object { "isLoggedIn": true, @@ -223,7 +90,6 @@ exports[`should render correctly: logged in users 1`] = ` Object { "canAdmin": false, "globalPages": Array [], - "organizationsEnabled": false, "qualifiers": Array [], } } @@ -233,15 +99,7 @@ exports[`should render correctly: logged in users 1`] = ` } } /> - <Connect(withRouter(GlobalNavUser)) - appState={ - Object { - "canAdmin": false, - "globalPages": Array [], - "organizationsEnabled": false, - "qualifiers": Array [], - } - } + <withRouter(GlobalNavUser) currentUser={ Object { "isLoggedIn": true, diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap index 8b49b3f0961..b509fb25cd2 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap @@ -1,68 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should not render user organizations when they are not activated 1`] = ` -<Dropdown - className="js-user-authenticated" - overlay={ - <ul - className="menu" - > - <li - className="menu-item" - > - <div - className="text-ellipsis text-muted" - title="foo" - > - <strong> - foo - </strong> - </div> - <div - className="little-spacer-top text-ellipsis text-muted" - title="foo@bar.baz" - > - foo@bar.baz - </div> - </li> - <li - className="divider" - /> - <li> - <Link - onlyActiveOnIndex={false} - style={Object {}} - to="/account" - > - my_account.page - </Link> - </li> - <li> - <a - href="#" - onClick={[Function]} - > - layout.logout - </a> - </li> - </ul> - } - tagName="li" -> - <a - className="dropdown-toggle navbar-avatar" - href="#" - title="foo" - > - <Connect(Avatar) - hash="abcd1234" - name="foo" - size={32} - /> - </a> -</Dropdown> -`; - exports[`should render the right interface for anonymous user 1`] = ` <li> <a @@ -87,18 +24,12 @@ exports[`should render the right interface for logged in user 1`] = ` > <div className="text-ellipsis text-muted" - title="foo" + title="Skywalker" > <strong> - foo + Skywalker </strong> </div> - <div - className="little-spacer-top text-ellipsis text-muted" - title="foo@bar.baz" - > - foo@bar.baz - </div> </li> <li className="divider" @@ -127,118 +58,10 @@ exports[`should render the right interface for logged in user 1`] = ` <a className="dropdown-toggle navbar-avatar" href="#" - title="foo" - > - <Connect(Avatar) - hash="abcd1234" - name="foo" - size={32} - /> - </a> -</Dropdown> -`; - -exports[`should render user organizations 1`] = ` -<Dropdown - className="js-user-authenticated" - overlay={ - <ul - className="menu" - > - <li - className="menu-item" - > - <div - className="text-ellipsis text-muted" - title="foo" - > - <strong> - foo - </strong> - </div> - <div - className="little-spacer-top text-ellipsis text-muted" - title="foo@bar.baz" - > - foo@bar.baz - </div> - </li> - <li - className="divider" - /> - <li> - <Link - onlyActiveOnIndex={false} - style={Object {}} - to="/account" - > - my_account.page - </Link> - </li> - <li - className="divider" - role="separator" - /> - <li> - <Link - onlyActiveOnIndex={false} - style={Object {}} - to="/account/organizations" - > - my_organizations - </Link> - </li> - <OrganizationListItem - organization={ - Object { - "key": "bar", - "name": "bar", - "projectVisibility": "public", - } - } - /> - <OrganizationListItem - organization={ - Object { - "key": "foo", - "name": "Foo", - "projectVisibility": "public", - } - } - /> - <OrganizationListItem - organization={ - Object { - "key": "myorg", - "name": "MyOrg", - "projectVisibility": "public", - } - } - /> - <li - className="divider" - role="separator" - /> - <li> - <a - href="#" - onClick={[Function]} - > - layout.logout - </a> - </li> - </ul> - } - tagName="li" -> - <a - className="dropdown-toggle navbar-avatar" - href="#" - title="foo" + title="Skywalker" > <Connect(Avatar) - hash="abcd1234" - name="foo" + name="Skywalker" size={32} /> </a> diff --git a/server/sonar-web/src/main/js/app/components/search/Search.tsx b/server/sonar-web/src/main/js/app/components/search/Search.tsx index f9ab024bf7b..5ec5b52ff5e 100644 --- a/server/sonar-web/src/main/js/app/components/search/Search.tsx +++ b/server/sonar-web/src/main/js/app/components/search/Search.tsx @@ -41,7 +41,6 @@ const SearchResults = lazyLoadComponent(() => import('./SearchResults')); const SearchResult = lazyLoadComponent(() => import('./SearchResult')); interface OwnProps { - appState: Pick<T.AppState, 'organizationsEnabled'>; currentUser: T.CurrentUser; } @@ -52,7 +51,6 @@ interface State { loadingMore?: string; more: More; open: boolean; - organizations: T.Dict<{ name: string }>; projects: T.Dict<{ name: string }>; query: string; results: Results; @@ -74,7 +72,6 @@ export class Search extends React.PureComponent<Props, State> { loading: false, more: {}, open: false, - organizations: {}, projects: {}, query: '', results: {}, @@ -142,7 +139,6 @@ export class Search extends React.PureComponent<Props, State> { this.setState({ more: {}, open: false, - organizations: {}, projects: {}, query: '', results: {}, @@ -187,7 +183,6 @@ export class Search extends React.PureComponent<Props, State> { this.setState(state => ({ loading: false, more, - organizations: { ...state.organizations, ...keyBy(response.organizations, 'key') }, projects: { ...state.projects, ...keyBy(response.projects, 'key') }, results, selected: list.length > 0 ? list[0] : undefined, @@ -216,7 +211,6 @@ export class Search extends React.PureComponent<Props, State> { loading: false, loadingMore: undefined, more: { ...state.more, [qualifier]: 0 }, - organizations: { ...state.organizations, ...keyBy(response.organizations, 'key') }, projects: { ...state.projects, ...keyBy(response.projects, 'key') }, results: { ...state.results, @@ -326,13 +320,11 @@ export class Search extends React.PureComponent<Props, State> { renderResult = (component: ComponentResult) => ( <SearchResult - appState={this.props.appState} component={component} innerRef={this.innerRef} key={component.key} onClose={this.closeSearch} onSelect={this.handleSelect} - organizations={this.state.organizations} projects={this.state.projects} selected={this.state.selected === component.key} /> diff --git a/server/sonar-web/src/main/js/app/components/search/SearchResult.tsx b/server/sonar-web/src/main/js/app/components/search/SearchResult.tsx index a2d703e86a8..7832947cc20 100644 --- a/server/sonar-web/src/main/js/app/components/search/SearchResult.tsx +++ b/server/sonar-web/src/main/js/app/components/search/SearchResult.tsx @@ -28,12 +28,10 @@ import { getComponentOverviewUrl } from '../../../helpers/urls'; import { ComponentResult } from './utils'; interface Props { - appState: Pick<T.AppState, 'organizationsEnabled'>; component: ComponentResult; innerRef: (componentKey: string, node: HTMLElement | null) => void; onClose: () => void; onSelect: (componentKey: string) => void; - organizations: T.Dict<{ name: string }>; projects: T.Dict<{ name: string }>; selected: boolean; } diff --git a/server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx b/server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx index 8786dcaaac5..71aa6e34631 100644 --- a/server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx +++ b/server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx @@ -103,11 +103,7 @@ it('shows warning about short input', () => { function shallowRender(props: Partial<Search['props']> = {}) { return shallow<Search>( // @ts-ignore - <Search - appState={{ organizationsEnabled: false }} - currentUser={{ isLoggedIn: false }} - {...props} - /> + <Search currentUser={{ isLoggedIn: false }} {...props} /> ); } diff --git a/server/sonar-web/src/main/js/app/components/search/__tests__/SearchResult-test.tsx b/server/sonar-web/src/main/js/app/components/search/__tests__/SearchResult-test.tsx index 4d33b5b23d7..a6e2ebf61da 100644 --- a/server/sonar-web/src/main/js/app/components/search/__tests__/SearchResult-test.tsx +++ b/server/sonar-web/src/main/js/app/components/search/__tests__/SearchResult-test.tsx @@ -35,8 +35,7 @@ it('renders match', () => { key: 'foo', name: 'foo', match: 'f<mark>o</mark>o', - qualifier: 'TRK', - organization: 'bar' + qualifier: 'TRK' }; const wrapper = shallowRender({ component }); expect(wrapper).toMatchSnapshot(); @@ -47,8 +46,7 @@ it('renders favorite', () => { isFavorite: true, key: 'foo', name: 'foo', - qualifier: 'TRK', - organization: 'bar' + qualifier: 'TRK' }; const wrapper = shallowRender({ component }); expect(wrapper).toMatchSnapshot(); @@ -59,8 +57,7 @@ it('renders recently browsed', () => { isRecentlyBrowsed: true, key: 'foo', name: 'foo', - qualifier: 'TRK', - organization: 'bar' + qualifier: 'TRK' }; const wrapper = shallowRender({ component }); expect(wrapper).toMatchSnapshot(); @@ -96,12 +93,10 @@ it('shows tooltip after delay', () => { function shallowRender(props: Partial<SearchResult['props']> = {}) { return shallow( <SearchResult - appState={{ organizationsEnabled: false }} - component={{ key: 'foo', name: 'foo', qualifier: 'TRK', organization: 'bar' }} + component={{ key: 'foo', name: 'foo', qualifier: 'TRK' }} innerRef={jest.fn()} onClose={jest.fn()} onSelect={jest.fn()} - organizations={{ bar: { name: 'bar' } }} projects={{ foo: { name: 'foo' } }} selected={false} {...props} diff --git a/server/sonar-web/src/main/js/app/components/search/utils.ts b/server/sonar-web/src/main/js/app/components/search/utils.ts index 2a577efa990..cc847ebb1a9 100644 --- a/server/sonar-web/src/main/js/app/components/search/utils.ts +++ b/server/sonar-web/src/main/js/app/components/search/utils.ts @@ -39,7 +39,6 @@ export interface ComponentResult { key: string; match?: string; name: string; - organization?: string; project?: string; qualifier: string; } diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx b/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx index 0ab48488566..45176f84086 100644 --- a/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx +++ b/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx @@ -48,7 +48,6 @@ import AboutStandards from './AboutStandards'; import EntryIssueTypes from './EntryIssueTypes'; interface Props { - appState: Pick<T.AppState, 'defaultOrganization' | 'organizationsEnabled'>; currentUser: T.CurrentUser; customText?: string; fetchAboutPageSettings: () => Promise<void>; diff --git a/server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx b/server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx index a1393845948..70854f1d2a2 100644 --- a/server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx +++ b/server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx @@ -23,7 +23,7 @@ import { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; import { searchProjects } from '../../../../api/components'; import { getFacet } from '../../../../api/issues'; -import { mockAppState, mockCurrentUser, mockLocation } from '../../../../helpers/testMocks'; +import { mockCurrentUser, mockLocation } from '../../../../helpers/testMocks'; import { AboutApp } from '../AboutApp'; import EntryIssueTypes from '../EntryIssueTypes'; @@ -88,7 +88,6 @@ it('should not display issues if the WS return an http error', async () => { function shallowRender(props: Partial<AboutApp['props']> = {}) { return shallow( <AboutApp - appState={mockAppState()} currentUser={mockCurrentUser()} customText="Lorem ipsum" fetchAboutPageSettings={jest.fn().mockResolvedValue('')} diff --git a/server/sonar-web/src/main/js/apps/account/components/Account.tsx b/server/sonar-web/src/main/js/apps/account/components/Account.tsx index ec8613cba29..8b05c31de02 100644 --- a/server/sonar-web/src/main/js/apps/account/components/Account.tsx +++ b/server/sonar-web/src/main/js/apps/account/components/Account.tsx @@ -19,19 +19,17 @@ */ import * as React from 'react'; import { Helmet } from 'react-helmet-async'; -import { connect } from 'react-redux'; import handleRequiredAuthentication from 'sonar-ui-common/helpers/handleRequiredAuthentication'; import { translate } from 'sonar-ui-common/helpers/l10n'; import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget'; import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; -import { areThereCustomOrganizations, getCurrentUser, Store } from '../../../store/rootReducer'; +import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import '../account.css'; import Nav from './Nav'; import UserCard from './UserCard'; interface Props { currentUser: T.CurrentUser; - customOrganizations?: boolean; } export class Account extends React.PureComponent<Props> { @@ -57,7 +55,7 @@ export class Account extends React.PureComponent<Props> { <header className="account-header"> <div className="account-container clearfix"> <UserCard user={currentUser as T.LoggedInUser} /> - <Nav customOrganizations={this.props.customOrganizations} /> + <Nav /> </div> </header> @@ -67,9 +65,4 @@ export class Account extends React.PureComponent<Props> { } } -const mapStateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state), - customOrganizations: areThereCustomOrganizations(state) -}); - -export default connect(mapStateToProps)(Account); +export default withCurrentUser(Account); diff --git a/server/sonar-web/src/main/js/apps/account/components/Nav.tsx b/server/sonar-web/src/main/js/apps/account/components/Nav.tsx index 8a50c6604d1..216fe6d40b6 100644 --- a/server/sonar-web/src/main/js/apps/account/components/Nav.tsx +++ b/server/sonar-web/src/main/js/apps/account/components/Nav.tsx @@ -22,11 +22,7 @@ import { IndexLink, Link } from 'react-router'; import NavBarTabs from 'sonar-ui-common/components/ui/NavBarTabs'; import { translate } from 'sonar-ui-common/helpers/l10n'; -interface Props { - customOrganizations?: boolean; -} - -export default function Nav({ customOrganizations }: Props) { +export default function Nav() { return ( <nav className="account-nav"> <NavBarTabs> @@ -45,20 +41,11 @@ export default function Nav({ customOrganizations }: Props) { {translate('my_account.notifications')} </Link> </li> - {!customOrganizations && ( - <li> - <Link activeClassName="active" to="/account/projects/"> - {translate('my_account.projects')} - </Link> - </li> - )} - {customOrganizations && ( - <li> - <Link activeClassName="active" to="/account/organizations"> - {translate('my_account.organizations')} - </Link> - </li> - )} + <li> + <Link activeClassName="active" to="/account/projects/"> + {translate('my_account.projects')} + </Link> + </li> </NavBarTabs> </nav> ); diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx index 0d6b60b7b5b..3aa693e2b8e 100644 --- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx @@ -25,7 +25,6 @@ import ProjectModal from '../ProjectModal'; jest.mock('../../../../api/components', () => ({ getSuggestions: jest.fn().mockResolvedValue({ - organizations: [{ key: 'org', name: 'Org' }], results: [ { q: 'TRK', @@ -63,7 +62,6 @@ it('should return an empty list when I search non-existent elements', async () = { q: 'TRK', items: [], more: 0 }, { q: 'UTS', items: [], more: 0 } ], - organizations: [], projects: [] }); diff --git a/server/sonar-web/src/main/js/apps/account/organizations/OrganizationCard.tsx b/server/sonar-web/src/main/js/apps/account/organizations/OrganizationCard.tsx deleted file mode 100644 index bffd7e73f41..00000000000 --- a/server/sonar-web/src/main/js/apps/account/organizations/OrganizationCard.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { translate } from 'sonar-ui-common/helpers/l10n'; -import OrganizationAvatar from '../../../components/common/OrganizationAvatar'; -import OrganizationLink from '../../../components/ui/OrganizationLink'; - -interface Props { - organization: T.Organization; -} - -export default function OrganizationCard({ organization }: Props) { - const { actions = {} } = organization; - return ( - <div className="account-project-card clearfix"> - <aside className="account-project-side note"> - <strong>{translate('organization.key')}:</strong> {organization.key} - </aside> - - <h3 className="account-project-name"> - <OrganizationAvatar organization={organization} /> - <OrganizationLink className="spacer-left text-middle" organization={organization}> - {organization.name} - </OrganizationLink> - {actions.admin && <span className="badge spacer-left">{translate('admin')}</span>} - </h3> - - {!!organization.description && ( - <div className="markdown spacer-top">{organization.description}</div> - )} - - {!!organization.url && ( - <div className="markdown spacer-top"> - <a href={organization.url} rel="nofollow" title={organization.url}> - {organization.url} - </a> - </div> - )} - </div> - ); -} diff --git a/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx b/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx deleted file mode 100644 index de478c1e1ba..00000000000 --- a/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { sortBy } from 'lodash'; -import * as React from 'react'; -import { translate } from 'sonar-ui-common/helpers/l10n'; -import OrganizationCard from './OrganizationCard'; - -interface Props { - organizations: T.Organization[]; -} - -export default function OrganizationsList({ organizations }: Props) { - if (organizations.length === 0) { - return <div>{translate('my_account.organizations.no_results')}</div>; - } - - return ( - <ul className="account-projects-list"> - {sortBy(organizations, organization => organization.name.toLocaleLowerCase()).map( - organization => ( - <li key={organization.key}> - <OrganizationCard organization={organization} /> - </li> - ) - )} - </ul> - ); -} diff --git a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx deleted file mode 100644 index 7aff55375e5..00000000000 --- a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { Helmet } from 'react-helmet-async'; -import { connect } from 'react-redux'; -import { Link } from 'react-router'; -import { translate } from 'sonar-ui-common/helpers/l10n'; -import { - getAppState, - getGlobalSettingValue, - getMyOrganizations, - Store -} from '../../../store/rootReducer'; -import { fetchIfAnyoneCanCreateOrganizations } from './actions'; -import OrganizationsList from './OrganizationsList'; - -interface StateProps { - anyoneCanCreate: boolean; - canAdmin?: boolean; - organizations: T.Organization[]; -} - -interface DispatchProps { - fetchIfAnyoneCanCreateOrganizations: () => Promise<void>; -} - -interface Props extends StateProps, DispatchProps {} - -interface State { - loading: boolean; -} - -class UserOrganizations extends React.PureComponent<Props, State> { - mounted = false; - state: State = { loading: true }; - - componentDidMount() { - this.mounted = true; - this.props.fetchIfAnyoneCanCreateOrganizations().then(this.stopLoading, this.stopLoading); - } - - componentWillUnmount() { - this.mounted = false; - } - - stopLoading = () => { - if (this.mounted) { - this.setState({ loading: false }); - } - }; - - render() { - const { anyoneCanCreate } = this.props; - const canCreateOrganizations = !this.state.loading && (anyoneCanCreate || this.props.canAdmin); - - return ( - <div className="account-body account-container"> - <Helmet title={translate('my_account.organizations')} /> - - <div className="boxed-group"> - {canCreateOrganizations && ( - <div className="clearfix"> - <div className="boxed-group-actions"> - <Link className="button" to="/create-organization"> - {translate('create')} - </Link> - </div> - </div> - )} - <div className="boxed-group-inner"> - {this.state.loading ? ( - <i className="spinner" /> - ) : ( - <OrganizationsList organizations={this.props.organizations} /> - )} - </div> - </div> - </div> - ); - } -} - -const mapStateToProps = (state: Store): StateProps => { - const anyoneCanCreate = getGlobalSettingValue(state, 'sonar.organizations.anyoneCanCreate'); - return { - anyoneCanCreate: Boolean(anyoneCanCreate && anyoneCanCreate.value === 'true'), - canAdmin: getAppState(state).canAdmin, - organizations: getMyOrganizations(state) - }; -}; - -const mapDispatchToProps = { - fetchIfAnyoneCanCreateOrganizations: fetchIfAnyoneCanCreateOrganizations as any -} as DispatchProps; - -export default connect(mapStateToProps, mapDispatchToProps)(UserOrganizations); diff --git a/server/sonar-web/src/main/js/apps/account/organizations/actions.ts b/server/sonar-web/src/main/js/apps/account/organizations/actions.ts deleted file mode 100644 index 92b23db379f..00000000000 --- a/server/sonar-web/src/main/js/apps/account/organizations/actions.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { Dispatch } from 'redux'; -import { getOrganizations } from '../../../api/organizations'; -import { getValues } from '../../../api/settings'; -import { receiveMyOrganizations } from '../../../store/organizations'; -import { receiveValues } from '../../settings/store/values'; - -export const fetchMyOrganizations = () => (dispatch: Dispatch) => { - return getOrganizations({ member: true }).then(({ organizations }) => { - return dispatch(receiveMyOrganizations(organizations)); - }); -}; - -export const fetchIfAnyoneCanCreateOrganizations = () => (dispatch: Dispatch) => { - return getValues({ keys: 'sonar.organizations.anyoneCanCreate' }).then(values => { - dispatch(receiveValues(values)); - }); -}; diff --git a/server/sonar-web/src/main/js/apps/account/routes.ts b/server/sonar-web/src/main/js/apps/account/routes.ts index 8fc8ed5cefd..96b3cd230f6 100644 --- a/server/sonar-web/src/main/js/apps/account/routes.ts +++ b/server/sonar-web/src/main/js/apps/account/routes.ts @@ -37,10 +37,6 @@ const routes = [ { path: 'notifications', component: lazyLoadComponent(() => import('./notifications/Notifications')) - }, - { - path: 'organizations', - component: lazyLoadComponent(() => import('./organizations/UserOrganizations')) } ] } diff --git a/server/sonar-web/src/main/js/apps/code/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/code/components/__tests__/App-test.tsx index 9035233ffcc..ecc223a8f01 100644 --- a/server/sonar-web/src/main/js/apps/code/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/code/components/__tests__/App-test.tsx @@ -95,7 +95,6 @@ function shallowRender(props: Partial<App['props']> = {}) { breadcrumbs: [], name: 'foo', key: 'foo', - organization: 'foo', qualifier: 'FOO' }} fetchBranchStatus={jest.fn()} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumb-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumb-test.tsx index 1dc2b2a2750..34629a898f3 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumb-test.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumb-test.tsx @@ -29,7 +29,6 @@ it('should show the last element without clickable link', () => { component={{ key: 'foo', name: 'Foo', - organization: 'foo', qualifier: 'TRK' }} handleSelect={() => {}} @@ -47,7 +46,6 @@ it('should correctly show a middle element', () => { component={{ key: 'foo', name: 'Foo', - organization: 'foo', qualifier: 'TRK' }} handleSelect={() => {}} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumbs-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumbs-test.tsx index 3f5e37381c9..219cf9faae5 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumbs-test.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumbs-test.tsx @@ -34,14 +34,12 @@ jest.mock('../../../../api/components', () => ({ const componentFoo = { key: 'foo', name: 'Foo', - organization: 'bar', qualifier: 'TRK' }; const componentBar = { key: 'bar', name: 'Bar', - organization: 'bar', qualifier: 'TRK' }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/Breadcrumbs-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/Breadcrumbs-test.tsx.snap index 9e4fbb301a8..d950fb2a883 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/Breadcrumbs-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/Breadcrumbs-test.tsx.snap @@ -7,7 +7,6 @@ exports[`should display correctly for the list view 1`] = ` Object { "key": "bar", "name": "Bar", - "organization": "bar", "qualifier": "TRK", } } @@ -16,7 +15,6 @@ exports[`should display correctly for the list view 1`] = ` Object { "key": "foo", "name": "Foo", - "organization": "bar", "qualifier": "TRK", } } @@ -29,7 +27,6 @@ Object { Object { "key": "foo", "name": "Foo", - "organization": "bar", "qualifier": "TRK", }, ], diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/ComponentList-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/ComponentList-test.tsx index 497e2192fbc..1ffe0989345 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/ComponentList-test.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/ComponentList-test.tsx @@ -26,7 +26,6 @@ const COMPONENTS = [ key: 'foo', measures: [], name: 'Foo', - organization: 'foo', qualifier: 'TRK' } ]; diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/FilesView-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/FilesView-test.tsx index 26743fb65e7..eb951b8787f 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/FilesView-test.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/FilesView-test.tsx @@ -26,7 +26,6 @@ const COMPONENTS = [ key: 'foo', measures: [], name: 'Foo', - organization: 'foo', qualifier: 'TRK' } ]; @@ -46,7 +45,6 @@ it('should render with best values hidden', () => { key: 'bar', measures: [{ bestValue: true, metric: { key: 'coverage' } }], name: 'Bar', - organization: 'foo', qualifier: 'TRK' } ] @@ -70,7 +68,6 @@ function getWrapper(props = {}) { key: 'parent', measures: [], name: 'Parent', - organization: 'foo', qualifier: 'TRK' }} view="tree" diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/ComponentList-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/ComponentList-test.tsx.snap index c16ae7b6dff..eee4db08dc2 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/ComponentList-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/ComponentList-test.tsx.snap @@ -11,7 +11,6 @@ exports[`should renders correctly 1`] = ` "key": "foo", "measures": Array [], "name": "Foo", - "organization": "foo", "qualifier": "TRK", } } @@ -32,7 +31,6 @@ exports[`should renders correctly 1`] = ` "key": "foo", "measures": Array [], "name": "Foo", - "organization": "foo", "qualifier": "TRK", } } @@ -91,7 +89,6 @@ exports[`should renders with multiple measures 1`] = ` "key": "foo", "measures": Array [], "name": "Foo", - "organization": "foo", "qualifier": "TRK", } } @@ -127,7 +124,6 @@ exports[`should renders with multiple measures 1`] = ` "key": "foo", "measures": Array [], "name": "Foo", - "organization": "foo", "qualifier": "TRK", } } diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/FilesView-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/FilesView-test.tsx.snap index 6111aec51f6..edf84eb575e 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/FilesView-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/FilesView-test.tsx.snap @@ -9,7 +9,6 @@ exports[`should render with best values hidden 1`] = ` "key": "foo", "measures": Array [], "name": "Foo", - "organization": "foo", "qualifier": "TRK", }, ] @@ -38,7 +37,6 @@ exports[`should render with best values hidden 1`] = ` "key": "parent", "measures": Array [], "name": "Parent", - "organization": "foo", "qualifier": "TRK", } } @@ -72,7 +70,6 @@ exports[`should renders correctly 1`] = ` "key": "foo", "measures": Array [], "name": "Foo", - "organization": "foo", "qualifier": "TRK", }, ] @@ -101,7 +98,6 @@ exports[`should renders correctly 1`] = ` "key": "parent", "measures": Array [], "name": "Parent", - "organization": "foo", "qualifier": "TRK", } } diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/App-test.tsx index c05cc288f50..2b327cae7ea 100644 --- a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/App-test.tsx @@ -29,7 +29,7 @@ jest.mock('../../../../api/permissions', () => ({ { id: '1', name: 'Default template', - description: 'Default permission template of organization test', + description: 'Default permission template', createdAt: '2019-02-07T17:23:26+0100', updatedAt: '2019-02-07T17:23:26+0100', permissions: [ diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/App-test.tsx.snap index 0c79d187b7b..d755aea61e5 100644 --- a/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/App-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/App-test.tsx.snap @@ -42,7 +42,7 @@ exports[`should render correctly 2`] = ` "defaultFor": Array [ "TRK", ], - "description": "Default permission template of organization test", + "description": "Default permission template", "id": "1", "name": "Default template", "permissions": Array [ diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.tsx b/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.tsx index ac153dcd69f..1c474cdb2fa 100644 --- a/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.tsx @@ -45,7 +45,6 @@ interface OwnProps { onLoadMore: () => void; onFilter: (filter: string) => void; onSearch: (query: string) => void; - organization?: T.Organization; query: string; revokePermissionFromGroup: (groupName: string, permission: string) => Promise<void>; revokePermissionFromUser: (login: string, permission: string) => Promise<void>; @@ -77,7 +76,7 @@ export class AllHoldersList extends React.PureComponent<Props> { render() { const { appState, filter, groups, groupsPaging, users, usersPaging } = this.props; - const l10nPrefix = this.props.organization ? 'organizations_permissions' : 'global_permissions'; + const l10nPrefix = 'global_permissions'; const hasPortfoliosEnabled = appState.qualifiers.includes(ComponentQualifier.Portfolio); const hasApplicationsEnabled = appState.qualifiers.includes(ComponentQualifier.Application); diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx index 7b7189ec18f..9ed5b5da893 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx @@ -29,7 +29,6 @@ import { applyTemplateToProject, getPermissionTemplates } from '../../../../api/ interface Props { onApply?: () => void; onClose: () => void; - organization?: string; project: { key: string; name: string }; } @@ -71,7 +70,6 @@ export default class ApplyTemplate extends React.PureComponent<Props, State> { handleSubmit = () => { if (this.state.permissionTemplate) { return applyTemplateToProject({ - organization: this.props.organization, projectKey: this.props.project.key, templateId: this.state.permissionTemplate }).then(() => { 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 64c1e76cd4b..4bdf603fc1a 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 @@ -89,7 +89,6 @@ export default class PageHeader extends React.PureComponent<Props, State> { <ApplyTemplate onApply={this.props.loadHolders} onClose={this.handleApplyTemplateClose} - organization={component.organization} project={component} /> )} diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx index 28432a0976b..9d097921506 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx @@ -45,7 +45,7 @@ jest.mock('../../../../../api/permissions', () => ({ it('render correctly', async () => { const wrapper = shallow( - <ApplyTemplate onClose={jest.fn()} organization="foo" project={{ key: 'foo', name: 'Foo' }} /> + <ApplyTemplate onClose={jest.fn()} project={{ key: 'foo', name: 'Foo' }} /> ); expect(wrapper).toMatchSnapshot(); await waitAndUpdate(wrapper); diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/ChangeDefaultVisibilityForm.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/ChangeDefaultVisibilityForm.tsx index b9545f8f0a7..b94e49a5863 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/ChangeDefaultVisibilityForm.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/ChangeDefaultVisibilityForm.tsx @@ -53,7 +53,7 @@ export default class ChangeDefaultVisibilityForm extends React.PureComponent<Pro return ( <Modal contentLabel="modal form" onRequestClose={this.props.onClose}> <header className="modal-head"> - <h2>{translate('organization.change_visibility_form.header')}</h2> + <h2>{translate('settings.projects.change_visibility_form.header')}</h2> </header> <div className="modal-body"> @@ -74,13 +74,13 @@ export default class ChangeDefaultVisibilityForm extends React.PureComponent<Pro ))} <Alert variant="warning"> - {translate('organization.change_visibility_form.warning')} + {translate('settings.projects.change_visibility_form.warning')} </Alert> </div> <footer className="modal-foot"> <Button className="js-confirm" onClick={this.handleConfirmClick}> - {translate('organization.change_visibility_form.submit')} + {translate('settings.projects.change_visibility_form.submit')} </Button> <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}> {translate('cancel')} diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx index b43023411fb..653016002ac 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx @@ -55,7 +55,7 @@ export default class Header extends React.PureComponent<Props, State> { <div className="page-actions"> <span className="big-spacer-right"> <span className="text-middle"> - {translate('organization.default_visibility_of_new_projects')}{' '} + {translate('settings.projects.default_visibility_of_new_projects')}{' '} <strong> {defaultProjectVisibility ? translate('visibility', defaultProjectVisibility) : '—'} </strong> diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeDefaultVisibilityForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeDefaultVisibilityForm-test.tsx.snap index d735f686fb6..d8aaee95d7d 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeDefaultVisibilityForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeDefaultVisibilityForm-test.tsx.snap @@ -9,7 +9,7 @@ exports[`changes visibility 1`] = ` className="modal-head" > <h2> - organization.change_visibility_form.header + settings.projects.change_visibility_form.header </h2> </header> <div @@ -56,7 +56,7 @@ exports[`changes visibility 1`] = ` <Alert variant="warning" > - organization.change_visibility_form.warning + settings.projects.change_visibility_form.warning </Alert> </div> <footer @@ -66,7 +66,7 @@ exports[`changes visibility 1`] = ` className="js-confirm" onClick={[Function]} > - organization.change_visibility_form.submit + settings.projects.change_visibility_form.submit </Button> <ResetButtonLink className="js-modal-close" @@ -87,7 +87,7 @@ exports[`changes visibility 2`] = ` className="modal-head" > <h2> - organization.change_visibility_form.header + settings.projects.change_visibility_form.header </h2> </header> <div @@ -134,7 +134,7 @@ exports[`changes visibility 2`] = ` <Alert variant="warning" > - organization.change_visibility_form.warning + settings.projects.change_visibility_form.warning </Alert> </div> <footer @@ -144,7 +144,7 @@ exports[`changes visibility 2`] = ` className="js-confirm" onClick={[Function]} > - organization.change_visibility_form.submit + settings.projects.change_visibility_form.submit </Button> <ResetButtonLink className="js-modal-close" diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap index fc41e3dd39c..d55cfa0344d 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap @@ -26,7 +26,7 @@ exports[`renders: default 1`] = ` <span className="text-middle" > - organization.default_visibility_of_new_projects + settings.projects.default_visibility_of_new_projects <strong> visibility.public @@ -70,7 +70,7 @@ exports[`renders: undefined visibility 1`] = ` <span className="text-middle" > - organization.default_visibility_of_new_projects + settings.projects.default_visibility_of_new_projects <strong> — diff --git a/server/sonar-web/src/main/js/apps/users/UsersApp.tsx b/server/sonar-web/src/main/js/apps/users/UsersApp.tsx index a06ce473b52..8fef62fab34 100644 --- a/server/sonar-web/src/main/js/apps/users/UsersApp.tsx +++ b/server/sonar-web/src/main/js/apps/users/UsersApp.tsx @@ -23,6 +23,7 @@ import ListFooter from 'sonar-ui-common/components/controls/ListFooter'; import { translate } from 'sonar-ui-common/helpers/l10n'; import { getIdentityProviders, searchUsers } from '../../api/users'; import Suggestions from '../../app/components/embed-docs-modal/Suggestions'; +import { withCurrentUser } from '../../components/hoc/withCurrentUser'; import { Location, Router, withRouter } from '../../components/hoc/withRouter'; import Header from './Header'; import Search from './Search'; @@ -32,7 +33,6 @@ import { parseQuery, Query, serializeQuery } from './utils'; interface Props { currentUser: { isLoggedIn: boolean; login?: string }; location: Pick<Location, 'query'>; - organizationsEnabled?: boolean; router: Pick<Router, 'push'>; } @@ -70,14 +70,11 @@ export class UsersApp extends React.PureComponent<Props, State> { }; fetchIdentityProviders = () => - getIdentityProviders().then( - ({ identityProviders }) => { - if (this.mounted) { - this.setState({ identityProviders }); - } - }, - () => {} - ); + getIdentityProviders().then(({ identityProviders }) => { + if (this.mounted) { + this.setState({ identityProviders }); + } + }); fetchUsers = ({ location } = this.props) => { this.setState({ loading: true }); @@ -127,7 +124,6 @@ export class UsersApp extends React.PureComponent<Props, State> { currentUser={this.props.currentUser} identityProviders={this.state.identityProviders} onUpdateUsers={this.fetchUsers} - organizationsEnabled={this.props.organizationsEnabled} updateTokensCount={this.updateTokensCount} users={users} /> @@ -144,4 +140,4 @@ export class UsersApp extends React.PureComponent<Props, State> { } } -export default withRouter(UsersApp); +export default withRouter(withCurrentUser(UsersApp)); diff --git a/server/sonar-web/src/main/js/apps/users/UsersAppContainer.tsx b/server/sonar-web/src/main/js/apps/users/UsersAppContainer.tsx deleted file mode 100644 index 712b3b53a71..00000000000 --- a/server/sonar-web/src/main/js/apps/users/UsersAppContainer.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { connect } from 'react-redux'; -import { areThereCustomOrganizations, getCurrentUser, Store } from '../../store/rootReducer'; -import UsersApp from './UsersApp'; - -const mapStateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state), - organizationsEnabled: areThereCustomOrganizations(state) -}); - -export default connect(mapStateToProps)(UsersApp); diff --git a/server/sonar-web/src/main/js/apps/users/UsersList.tsx b/server/sonar-web/src/main/js/apps/users/UsersList.tsx index 38e5a2f8503..ef6a3a1d128 100644 --- a/server/sonar-web/src/main/js/apps/users/UsersList.tsx +++ b/server/sonar-web/src/main/js/apps/users/UsersList.tsx @@ -25,7 +25,6 @@ interface Props { currentUser: { isLoggedIn: boolean; login?: string }; identityProviders: T.IdentityProvider[]; onUpdateUsers: () => void; - organizationsEnabled?: boolean; updateTokensCount: (login: string, tokensCount: number) => void; users: T.User[]; } @@ -34,7 +33,6 @@ export default function UsersList({ currentUser, identityProviders, onUpdateUsers, - organizationsEnabled, updateTokensCount, users }: Props) { @@ -47,7 +45,7 @@ export default function UsersList({ <th className="nowrap" /> <th className="nowrap">{translate('my_profile.scm_accounts')}</th> <th className="nowrap">{translate('users.last_connection')}</th> - {!organizationsEnabled && <th className="nowrap">{translate('my_profile.groups')}</th>} + <th className="nowrap">{translate('my_profile.groups')}</th> <th className="nowrap">{translate('users.tokens')}</th> <th className="nowrap"> </th> </tr> @@ -61,7 +59,6 @@ export default function UsersList({ isCurrentUser={currentUser.isLoggedIn && currentUser.login === user.login} key={user.login} onUpdateUsers={onUpdateUsers} - organizationsEnabled={organizationsEnabled} updateTokensCount={updateTokensCount} user={user} /> diff --git a/server/sonar-web/src/main/js/apps/users/__tests__/UsersApp-test.tsx b/server/sonar-web/src/main/js/apps/users/__tests__/UsersApp-test.tsx index 64c8de620e8..3ea963be984 100644 --- a/server/sonar-web/src/main/js/apps/users/__tests__/UsersApp-test.tsx +++ b/server/sonar-web/src/main/js/apps/users/__tests__/UsersApp-test.tsx @@ -81,7 +81,6 @@ function getWrapper(props: Partial<UsersApp['props']> = {}) { <UsersApp currentUser={currentUser} location={location} - organizationsEnabled={true} router={{ push: jest.fn() }} {...props} /> diff --git a/server/sonar-web/src/main/js/apps/users/__tests__/UsersList-test.tsx b/server/sonar-web/src/main/js/apps/users/__tests__/UsersList-test.tsx index 8988e85959d..d67777120d9 100644 --- a/server/sonar-web/src/main/js/apps/users/__tests__/UsersList-test.tsx +++ b/server/sonar-web/src/main/js/apps/users/__tests__/UsersList-test.tsx @@ -42,13 +42,6 @@ it('should render correctly', () => { expect(getWrapper()).toMatchSnapshot(); }); -it('should show a group column', () => { - const wrapper = getWrapper({ organizationsEnabled: false }); - expect(wrapper.find('th').filterWhere(elem => elem.text() === 'my_profile.groups')).toHaveLength( - 1 - ); -}); - function getWrapper(props = {}) { return shallow( <UsersList @@ -62,7 +55,6 @@ function getWrapper(props = {}) { } ]} onUpdateUsers={jest.fn()} - organizationsEnabled={true} updateTokensCount={jest.fn()} users={users} {...props} diff --git a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersApp-test.tsx.snap b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersApp-test.tsx.snap index 3f747643705..27ebfe51e3f 100644 --- a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersApp-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersApp-test.tsx.snap @@ -34,7 +34,6 @@ exports[`should render correctly 1`] = ` } identityProviders={Array []} onUpdateUsers={[Function]} - organizationsEnabled={true} updateTokensCount={[Function]} users={Array []} /> @@ -84,7 +83,6 @@ exports[`should render correctly 2`] = ` ] } onUpdateUsers={[Function]} - organizationsEnabled={true} updateTokensCount={[Function]} users={ Array [ diff --git a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList-test.tsx.snap b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList-test.tsx.snap index f91c28ee600..739952fb5a9 100644 --- a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList-test.tsx.snap @@ -27,6 +27,11 @@ exports[`should render correctly 1`] = ` <th className="nowrap" > + my_profile.groups + </th> + <th + className="nowrap" + > users.tokens </th> <th @@ -41,7 +46,6 @@ exports[`should render correctly 1`] = ` isCurrentUser={true} key="luke" onUpdateUsers={[MockFunction]} - organizationsEnabled={true} updateTokensCount={[MockFunction]} user={ Object { @@ -57,7 +61,6 @@ exports[`should render correctly 1`] = ` isCurrentUser={false} key="obi" onUpdateUsers={[MockFunction]} - organizationsEnabled={true} updateTokensCount={[MockFunction]} user={ Object { diff --git a/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx b/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx index 53c06adc190..b6b3554313d 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx @@ -33,7 +33,6 @@ interface Props { identityProvider?: T.IdentityProvider; isCurrentUser: boolean; onUpdateUsers: () => void; - organizationsEnabled?: boolean; updateTokensCount: (login: string, tokensCount: number) => void; user: T.User; } @@ -49,7 +48,7 @@ export default class UserListItem extends React.PureComponent<Props, State> { handleCloseTokensForm = () => this.setState({ openTokenForm: false }); render() { - const { identityProvider, onUpdateUsers, organizationsEnabled, user } = this.props; + const { identityProvider, onUpdateUsers, user } = this.props; return ( <tr> @@ -63,11 +62,9 @@ export default class UserListItem extends React.PureComponent<Props, State> { <td className="thin nowrap text-middle"> <DateFromNow date={user.lastConnectionDate} hourPrecision={true} /> </td> - {!organizationsEnabled && ( - <td className="thin nowrap text-middle"> - <UserGroups groups={user.groups || []} onUpdateUsers={onUpdateUsers} user={user} /> - </td> - )} + <td className="thin nowrap text-middle"> + <UserGroups groups={user.groups || []} onUpdateUsers={onUpdateUsers} user={user} /> + </td> <td className="thin nowrap text-middle"> {user.tokensCount} <ButtonIcon diff --git a/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItem-test.tsx b/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItem-test.tsx index 273a495be88..6420c815508 100644 --- a/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItem-test.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItem-test.tsx @@ -42,14 +42,6 @@ it('should render correctly without last connection date', () => { expect(shallowRender({})).toMatchSnapshot(); }); -it('should display a change password button', () => { - expect( - shallowRender({ organizationsEnabled: true }) - .find('UserGroups') - .exists() - ).toBe(false); -}); - it('should open the correct forms', () => { const wrapper = shallowRender(); click(wrapper.find('.js-user-tokens')); @@ -61,7 +53,6 @@ function shallowRender(props: Partial<UserListItem['props']> = {}) { <UserListItem isCurrentUser={false} onUpdateUsers={jest.fn()} - organizationsEnabled={false} updateTokensCount={jest.fn()} user={user} {...props} diff --git a/server/sonar-web/src/main/js/apps/users/routes.ts b/server/sonar-web/src/main/js/apps/users/routes.ts index 4df2cd1dab3..2e82da0f3ad 100644 --- a/server/sonar-web/src/main/js/apps/users/routes.ts +++ b/server/sonar-web/src/main/js/apps/users/routes.ts @@ -21,7 +21,7 @@ import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent' const routes = [ { - indexRoute: { component: lazyLoadComponent(() => import('./UsersAppContainer')) } + indexRoute: { component: lazyLoadComponent(() => import('./UsersApp')) } } ]; diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/App-test.tsx index 97196d6cd41..f4eb83fe97b 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/App-test.tsx @@ -43,7 +43,7 @@ jest.mock('../../../../api/webhooks', () => ({ updateWebhook: jest.fn(() => Promise.resolve()) })); -const component = { key: 'bar', organization: 'foo', qualifier: 'TRK' }; +const component = { key: 'bar', qualifier: 'TRK' }; beforeEach(() => { (createWebhook as jest.Mock<any>).mockClear(); diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap index 2e6635c4494..4723e8ebc88 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap +++ b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap @@ -20,7 +20,6 @@ Array [ "componentKey": "foo.java", "componentLongName": "Foo.java", "componentName": "foo.java", - "componentOrganization": "default-organization", "componentPath": "/foo.java", "componentQualifier": "FIL", "creationDate": "2016-08-15T15:25:38+0200", @@ -30,13 +29,11 @@ Array [ "key": "AWaqVGl3tut9VbnJvk6M", "line": 62, "message": "Make sure this file handling is safe here.", - "organization": "default-organization", "project": "org.sonarsource.java:java", "projectEnabled": true, "projectKey": "org.sonarsource.java:java", "projectLongName": "SonarJava", "projectName": "SonarJava", - "projectOrganization": "default-organization", "projectQualifier": "TRK", "rule": "squid:S4797", "ruleKey": "squid:S4797", diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/loadIssues-test.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/loadIssues-test.ts index 615c412bbb0..5fd05665671 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/loadIssues-test.ts +++ b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/loadIssues-test.ts @@ -46,13 +46,11 @@ jest.mock('../../../../api/issues', () => ({ creationDate: '2016-08-15T15:25:38+0200', updateDate: '2018-10-25T10:23:08+0200', type: 'SECURITY_HOTSPOT', - organization: 'default-organization', fromHotspot: true } ], components: [ { - organization: 'default-organization', key: 'org.sonarsource.java:java', enabled: true, qualifier: 'TRK', @@ -60,7 +58,6 @@ jest.mock('../../../../api/issues', () => ({ longName: 'SonarJava' }, { - organization: 'default-organization', key: 'foo.java', enabled: true, qualifier: 'FIL', diff --git a/server/sonar-web/src/main/js/components/common/OrganizationAvatar.css b/server/sonar-web/src/main/js/components/common/OrganizationAvatar.css deleted file mode 100644 index e700d7beaf1..00000000000 --- a/server/sonar-web/src/main/js/components/common/OrganizationAvatar.css +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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. - */ -.navbar-context-avatar { - display: inline-flex; - vertical-align: top; - justify-content: center; - align-items: center; - width: calc(4 * var(--gridSize)); - height: calc(4 * var(--gridSize)); - border: 1px solid var(--barBorderColor); -} - -.navbar-context-avatar.no-border { - border: none; -} - -.navbar-context-avatar.is-small { - width: calc(2 * var(--gridSize)); - height: calc(2 * var(--gridSize)); -} - -.navbar-context-avatar img { - vertical-align: top; - max-width: 100%; - max-height: 100%; -} - -.navbar-context-avatar img, -.navbar-context-avatar svg { - transform: none; -} diff --git a/server/sonar-web/src/main/js/components/common/OrganizationAvatar.tsx b/server/sonar-web/src/main/js/components/common/OrganizationAvatar.tsx deleted file mode 100644 index 24edae59bf9..00000000000 --- a/server/sonar-web/src/main/js/components/common/OrganizationAvatar.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 classNames from 'classnames'; -import * as React from 'react'; -import GenericAvatar from 'sonar-ui-common/components/ui/GenericAvatar'; -import './OrganizationAvatar.css'; - -interface Props { - className?: string; - organization: Pick<T.OrganizationBase, 'avatar' | 'name'>; - small?: boolean; -} - -interface State { - imgLoadError: boolean; -} - -export default class OrganizationAvatar extends React.PureComponent<Props, State> { - state = { imgLoadError: false }; - - handleImgError = () => { - this.setState({ imgLoadError: true }); - }; - - render() { - const { className, organization, small } = this.props; - const { imgLoadError } = this.state; - return ( - <div - className={classNames( - 'navbar-context-avatar', - 'rounded', - { 'no-border': !organization.avatar, 'is-small': small }, - className - )}> - {organization.avatar && !imgLoadError ? ( - <img - alt={organization.name} - className="rounded" - onError={this.handleImgError} - src={organization.avatar} - /> - ) : ( - <GenericAvatar name={organization.name} size={small ? 15 : 30} /> - )} - </div> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx index ca7cc933a6e..b13b3741c3b 100644 --- a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx +++ b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx @@ -99,7 +99,6 @@ function isSameHomePage(a: T.HomePage, b: T.HomePage) { return ( a.type === b.type && (a as any).branch === (b as any).branch && - (a as any).component === (b as any).component && - (a as any).organization === (b as any).organization + (a as any).component === (b as any).component ); } diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/__snapshots__/withNotifications-test.tsx.snap b/server/sonar-web/src/main/js/components/hoc/__tests__/__snapshots__/withNotifications-test.tsx.snap index 4af5332cd6c..0307ad1d8ac 100644 --- a/server/sonar-web/src/main/js/components/hoc/__tests__/__snapshots__/withNotifications-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/hoc/__tests__/__snapshots__/withNotifications-test.tsx.snap @@ -20,21 +20,18 @@ exports[`should fetch notifications and render 1`] = ` Array [ Object { "channel": "channel1", - "organization": "org", "project": "foo", "projectName": "Foo", "type": "type-global", }, Object { "channel": "channel1", - "organization": "org", "project": "bar", "projectName": "Bar", "type": "type-common", }, Object { "channel": "channel2", - "organization": "org", "project": "qux", "projectName": "Qux", "type": "type-common", diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/withNotifications-test.tsx b/server/sonar-web/src/main/js/components/hoc/__tests__/withNotifications-test.tsx index 7b5d0f79d22..0062f7108aa 100644 --- a/server/sonar-web/src/main/js/components/hoc/__tests__/withNotifications-test.tsx +++ b/server/sonar-web/src/main/js/components/hoc/__tests__/withNotifications-test.tsx @@ -34,22 +34,19 @@ jest.mock('../../../api/notifications', () => ({ channel: 'channel1', type: 'type-global', project: 'foo', - projectName: 'Foo', - organization: 'org' + projectName: 'Foo' }, { channel: 'channel1', type: 'type-common', project: 'bar', - projectName: 'Bar', - organization: 'org' + projectName: 'Bar' }, { channel: 'channel2', type: 'type-common', project: 'qux', - projectName: 'Qux', - organization: 'org' + projectName: 'Qux' } ], perProjectTypes: ['type-common'] diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/withUserOrganizations-test.tsx b/server/sonar-web/src/main/js/components/hoc/__tests__/withUserOrganizations-test.tsx deleted file mode 100644 index 3644742c9df..00000000000 --- a/server/sonar-web/src/main/js/components/hoc/__tests__/withUserOrganizations-test.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import { mockStore } from '../../../helpers/testMocks'; -import { withUserOrganizations } from '../withUserOrganizations'; - -jest.mock('../../../api/organizations', () => ({ getOrganizations: jest.fn() })); - -class X extends React.Component<{ - fetchMyOrganizations: () => Promise<void>; - userOrganizations: T.Organization[]; -}> { - render() { - return <div />; - } -} - -const UnderTest = withUserOrganizations(X); - -it('should pass user organizations and logged in user', () => { - const org = { key: 'my-org', name: 'My Organization' }; - const wrapper = shallow(<UnderTest />, { - context: { - store: mockStore({ - organizations: { byKey: { 'my-org': org }, my: ['my-org'] } - }) - }, - disableLifecycleMethods: true - }); - const wrappedComponent = wrapper.dive(); - expect(wrappedComponent.type()).toBe(X); - expect(wrappedComponent.prop('userOrganizations')).toEqual([org]); -}); diff --git a/server/sonar-web/src/main/js/components/hoc/withUserOrganizations.tsx b/server/sonar-web/src/main/js/components/hoc/withUserOrganizations.tsx deleted file mode 100644 index a97150a3c3c..00000000000 --- a/server/sonar-web/src/main/js/components/hoc/withUserOrganizations.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { connect } from 'react-redux'; -import { fetchMyOrganizations } from '../../apps/account/organizations/actions'; -import { getMyOrganizations, Store } from '../../store/rootReducer'; -import { getWrappedDisplayName } from './utils'; - -interface OwnProps { - fetchMyOrganizations: () => Promise<void>; - userOrganizations: T.Organization[]; -} - -export function withUserOrganizations<P>( - WrappedComponent: React.ComponentType<P & Partial<OwnProps>> -) { - class Wrapper extends React.Component<P & OwnProps> { - static displayName = getWrappedDisplayName(WrappedComponent, 'withUserOrganizations'); - - componentDidMount() { - this.props.fetchMyOrganizations(); - } - - render() { - return <WrappedComponent {...this.props} />; - } - } - - const mapDispatchToProps = { fetchMyOrganizations: fetchMyOrganizations as any }; - - function mapStateToProps(state: Store) { - return { userOrganizations: getMyOrganizations(state) }; - } - - return connect(mapStateToProps, mapDispatchToProps)(Wrapper); -} diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.tsx b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.tsx index 266b3ffa80a..5c17e9cb35f 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.tsx +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import { click } from 'sonar-ui-common/helpers/testUtils'; import IssueTags from '../IssueTags'; -const issue = { key: 'issuekey', projectOrganization: 'foo', tags: ['mytag', 'test'] }; +const issue = { key: 'issuekey', tags: ['mytag', 'test'] }; it('should render without the action when the correct rights are missing', () => { expect(shallowRender({ canSetTags: false, issue: { ...issue, tags: [] } })).toMatchSnapshot(); diff --git a/server/sonar-web/src/main/js/components/shared/Organization.tsx b/server/sonar-web/src/main/js/components/shared/Organization.tsx deleted file mode 100644 index ecef76e7b39..00000000000 --- a/server/sonar-web/src/main/js/components/shared/Organization.tsx +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { connect } from 'react-redux'; -import { areThereCustomOrganizations, getOrganizationByKey, Store } from '../../store/rootReducer'; -import OrganizationLink from '../ui/OrganizationLink'; - -interface OwnProps { - organizationKey: string; -} - -interface Props { - link?: boolean; - linkClassName?: string; - organization: { key: string; name: string } | null; - shouldBeDisplayed?: boolean; -} - -function Organization(props: Props) { - const { link = true, organization, shouldBeDisplayed } = props; - - if (!shouldBeDisplayed || !organization) { - return null; - } - - return ( - <span> - {link ? ( - <OrganizationLink className={props.linkClassName} organization={organization}> - {organization.name} - </OrganizationLink> - ) : ( - organization.name - )} - <span className="slash-separator" /> - </span> - ); -} - -const mapStateToProps = (state: Store, ownProps: OwnProps) => ({ - organization: getOrganizationByKey(state, ownProps.organizationKey), - shouldBeDisplayed: areThereCustomOrganizations(state) -}); - -export default connect(mapStateToProps)(Organization); - -export const UnconnectedOrganization = Organization; diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/Organization-test.tsx b/server/sonar-web/src/main/js/components/shared/__tests__/Organization-test.tsx deleted file mode 100644 index 71f36b1b0eb..00000000000 --- a/server/sonar-web/src/main/js/components/shared/__tests__/Organization-test.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import { UnconnectedOrganization } from '../Organization'; - -const organization = { key: 'foo', name: 'foo' }; - -it('should match snapshot', () => { - expect( - shallow(<UnconnectedOrganization organization={organization} shouldBeDisplayed={true} />) - ).toMatchSnapshot(); -}); - -it('should not be displayed', () => { - expect( - shallow( - <UnconnectedOrganization organization={organization} shouldBeDisplayed={false} /> - ).type() - ).toBeNull(); - - expect( - shallow(<UnconnectedOrganization organization={null} shouldBeDisplayed={true} />).type() - ).toBeNull(); -}); diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/Organization-test.tsx.snap b/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/Organization-test.tsx.snap deleted file mode 100644 index 4f12a56b205..00000000000 --- a/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/Organization-test.tsx.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot 1`] = ` -<span> - <OrganizationLink - organization={ - Object { - "key": "foo", - "name": "foo", - } - } - > - foo - </OrganizationLink> - <span - className="slash-separator" - /> -</span> -`; diff --git a/server/sonar-web/src/main/js/components/ui/OrganizationLink.tsx b/server/sonar-web/src/main/js/components/ui/OrganizationLink.tsx deleted file mode 100644 index b025726c8e2..00000000000 --- a/server/sonar-web/src/main/js/components/ui/OrganizationLink.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { Link } from 'react-router'; - -interface Props { - children?: React.ReactNode; - organization: { key: string }; - [x: string]: any; -} - -export default function OrganizationLink(props: Props) { - const { children, organization, ...other } = props; - - return ( - <Link to={`/organizations/${organization.key}`} {...other}> - {children} - </Link> - ); -} diff --git a/server/sonar-web/src/main/js/components/ui/OrganizationListItem.tsx b/server/sonar-web/src/main/js/components/ui/OrganizationListItem.tsx deleted file mode 100644 index be71639b095..00000000000 --- a/server/sonar-web/src/main/js/components/ui/OrganizationListItem.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { translate } from 'sonar-ui-common/helpers/l10n'; -import OrganizationAvatar from '../common/OrganizationAvatar'; -import OrganizationLink from './OrganizationLink'; - -interface Props { - organization: T.Organization; -} - -export default function OrganizationListItem({ organization }: Props) { - const { actions = {} } = organization; - return ( - <li> - <OrganizationLink className="display-flex-center" organization={organization}> - <div> - <OrganizationAvatar organization={organization} small={true} /> - <span className="spacer-left">{organization.name}</span> - </div> - {actions.admin && <span className="badge spacer-left">{translate('admin')}</span>} - </OrganizationLink> - </li> - ); -} diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/OrganizationLink-test.tsx b/server/sonar-web/src/main/js/components/ui/__tests__/OrganizationLink-test.tsx deleted file mode 100644 index eb64d8ea210..00000000000 --- a/server/sonar-web/src/main/js/components/ui/__tests__/OrganizationLink-test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import OrganizationLink from '../OrganizationLink'; - -it('renders', () => { - expect(shallow(<OrganizationLink organization={{ key: 'org' }} />)).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/OrganizationListItem-test.tsx b/server/sonar-web/src/main/js/components/ui/__tests__/OrganizationListItem-test.tsx deleted file mode 100644 index 93e2e9e2f62..00000000000 --- a/server/sonar-web/src/main/js/components/ui/__tests__/OrganizationListItem-test.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { shallow } from 'enzyme'; -import * as React from 'react'; -import OrganizationListItem from '../OrganizationListItem'; - -it('renders', () => { - expect( - shallow( - <OrganizationListItem - organization={{ - actions: { admin: true }, - key: 'org', - name: 'org', - projectVisibility: 'public' - }} - /> - ) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationLink-test.tsx.snap b/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationLink-test.tsx.snap deleted file mode 100644 index 147ffccb64f..00000000000 --- a/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationLink-test.tsx.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<Link - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/org" -/> -`; diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationListItem-test.tsx.snap b/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationListItem-test.tsx.snap deleted file mode 100644 index a2f7dde9ca0..00000000000 --- a/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationListItem-test.tsx.snap +++ /dev/null @@ -1,45 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<li> - <OrganizationLink - className="display-flex-center" - organization={ - Object { - "actions": Object { - "admin": true, - }, - "key": "org", - "name": "org", - "projectVisibility": "public", - } - } - > - <div> - <OrganizationAvatar - organization={ - Object { - "actions": Object { - "admin": true, - }, - "key": "org", - "name": "org", - "projectVisibility": "public", - } - } - small={true} - /> - <span - className="spacer-left" - > - org - </span> - </div> - <span - className="badge spacer-left" - > - admin - </span> - </OrganizationLink> -</li> -`; diff --git a/server/sonar-web/src/main/js/helpers/__tests__/organizations-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/organizations-test.ts deleted file mode 100644 index b95574c53a0..00000000000 --- a/server/sonar-web/src/main/js/helpers/__tests__/organizations-test.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { hasPrivateAccess, isCurrentUserMemberOf } from '../organizations'; - -const org: T.Organization = { key: 'foo', name: 'Foo', subscription: 'PAID' }; -const adminOrg = { actions: { admin: true }, key: 'bar', name: 'Bar' }; -const randomOrg = { key: 'bar', name: 'Bar' }; - -const loggedIn = { - isLoggedIn: true, - login: 'luke', - name: 'Skywalker' -}; -const loggedOut = { isLoggedIn: false }; - -describe('isCurrentUserMemberOf', () => { - it('should be a member', () => { - expect(isCurrentUserMemberOf(loggedIn, adminOrg, [])).toBe(true); - expect(isCurrentUserMemberOf(loggedIn, org, [org])).toBe(true); - }); - - it('should not be a member', () => { - expect(isCurrentUserMemberOf(loggedIn, undefined, [])).toBe(false); - expect(isCurrentUserMemberOf(loggedIn, org, [])).toBe(false); - expect(isCurrentUserMemberOf(loggedIn, org, [randomOrg])).toBe(false); - expect(isCurrentUserMemberOf(loggedOut, org, [org])).toBe(false); - }); -}); - -describe('hasPrivateAccess', () => { - it('should have access', () => { - expect(hasPrivateAccess(loggedIn, randomOrg, [])).toBe(true); - expect(hasPrivateAccess(loggedIn, org, [org])).toBe(true); - }); - - it('should not have access', () => { - expect(hasPrivateAccess(loggedIn, org, [])).toBe(false); - }); -}); diff --git a/server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts index 48ae3ccba71..cd1d4088874 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts +++ b/server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts @@ -118,7 +118,7 @@ describe('#getComponentDrilldownUrl', () => { }); describe('#getQualityGate(s)Url', () => { - it('should take organization key into account', () => { + it('should work as expected', () => { expect(getQualityGatesUrl()).toEqual({ pathname: '/quality_gates' }); expect(getQualityGateUrl('bar')).toEqual({ pathname: '/quality_gates/show/bar' }); }); diff --git a/server/sonar-web/src/main/js/helpers/organizations.ts b/server/sonar-web/src/main/js/helpers/organizations.ts deleted file mode 100644 index 7c5ad587526..00000000000 --- a/server/sonar-web/src/main/js/helpers/organizations.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { isLoggedIn } from './users'; - -export function isPaidOrganization(organization: T.Organization | undefined): boolean { - return Boolean(organization && organization.subscription === 'PAID'); -} - -export function hasPrivateAccess( - currentUser: T.CurrentUser, - organization: T.Organization | undefined, - userOrganizations: T.Organization[] -): boolean { - return ( - !isPaidOrganization(organization) || - isCurrentUserMemberOf(currentUser, organization, userOrganizations) - ); -} - -export function isCurrentUserMemberOf( - currentUser: T.CurrentUser, - organization: T.Organization | undefined, - userOrganizations: T.Organization[] -): boolean { - return Boolean( - organization && - isLoggedIn(currentUser) && - ((organization.actions && organization.actions.admin) || - userOrganizations.some(org => org.key === organization.key)) - ); -} diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts index 63857857911..955df227d5e 100644 --- a/server/sonar-web/src/main/js/helpers/testMocks.ts +++ b/server/sonar-web/src/main/js/helpers/testMocks.ts @@ -36,21 +36,6 @@ export function mockAlmApplication(overrides: Partial<T.AlmApplication> = {}): T }; } -export function mockAlmOrganization(overrides: Partial<T.AlmOrganization> = {}): T.AlmOrganization { - return { - avatar: 'http://example.com/avatar', - almUrl: 'https://github.com/foo', - description: 'description-foo', - key: 'foo', - name: 'foo', - personal: false, - privateRepos: 0, - publicRepos: 3, - url: 'http://example.com/foo', - ...overrides - }; -} - export function mockAnalysis(overrides: Partial<T.Analysis> = {}): T.Analysis { return { date: '2017-03-01T09:36:01+0100', @@ -99,7 +84,6 @@ export function mockAnalysisEvent(overrides: Partial<T.AnalysisEvent> = {}): T.A export function mockAppState(overrides: Partial<T.AppState> = {}): T.AppState { return { - defaultOrganization: 'foo', edition: 'community', productionDatabase: true, qualifiers: ['TRK'], @@ -492,33 +476,6 @@ export function mockMeasureEnhanced(overrides: Partial<T.MeasureEnhanced> = {}): }; } -export function mockOrganization(overrides: Partial<T.Organization> = {}): T.Organization { - return { key: 'foo', name: 'Foo', ...overrides }; -} - -export function mockOrganizationWithAdminActions( - overrides: Partial<T.Organization> = {}, - actionsOverrides: Partial<T.Organization['actions']> = {} -) { - return mockOrganization({ actions: { admin: true, ...actionsOverrides }, ...overrides }); -} - -export function mockOrganizationWithAlm( - overrides: Partial<T.Organization> = {}, - almOverrides: Partial<T.Organization['alm']> = {} -): T.Organization { - return mockOrganization({ - alm: { - key: 'github', - membersSync: false, - personal: false, - url: 'https://github.com/foo', - ...almOverrides - }, - ...overrides - }); -} - export function mockPeriod(overrides: Partial<T.Period> = {}): T.Period { return { date: '2019-04-23T02:12:32+0100', diff --git a/server/sonar-web/src/main/js/helpers/urls.ts b/server/sonar-web/src/main/js/helpers/urls.ts index 1efdf8946aa..f3b7227e2ee 100644 --- a/server/sonar-web/src/main/js/helpers/urls.ts +++ b/server/sonar-web/src/main/js/helpers/urls.ts @@ -255,10 +255,6 @@ export function getCodeUrl( }; } -export function getOrganizationUrl(organization: string) { - return `/organizations/${organization}`; -} - export function getHomePageUrl(homepage: T.HomePage) { switch (homepage.type) { case 'APPLICATION': @@ -269,8 +265,6 @@ export function getHomePageUrl(homepage: T.HomePage) { return homepage.branch ? getBranchUrl(homepage.component, homepage.branch) : getProjectUrl(homepage.component); - case 'ORGANIZATION': - return getOrganizationUrl(homepage.organization); case 'PORTFOLIO': return getPortfolioUrl(homepage.component); case 'PORTFOLIOS': diff --git a/server/sonar-web/src/main/js/store/__tests__/__snapshots__/organizations-test.ts.snap b/server/sonar-web/src/main/js/store/__tests__/__snapshots__/organizations-test.ts.snap deleted file mode 100644 index 4ac73b4597f..00000000000 --- a/server/sonar-web/src/main/js/store/__tests__/__snapshots__/organizations-test.ts.snap +++ /dev/null @@ -1,101 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Reducer should create organization 1`] = ` -Object { - "byKey": Object { - "foo": Object { - "actions": Object { - "admin": true, - }, - "key": "foo", - "name": "foo", - }, - }, - "my": Array [ - "foo", - ], -} -`; - -exports[`Reducer should delete organization 1`] = ` -Object { - "byKey": Object {}, - "my": Array [], -} -`; - -exports[`Reducer should have initial state 1`] = ` -Object { - "byKey": Object {}, - "my": Array [], -} -`; - -exports[`Reducer should receive my organizations 1`] = ` -Object { - "byKey": Object { - "bar": Object { - "key": "bar", - "name": "Bar", - }, - "foo": Object { - "key": "foo", - "name": "Foo", - }, - }, - "my": Array [ - "foo", - "bar", - ], -} -`; - -exports[`Reducer should receive organizations 1`] = ` -Object { - "byKey": Object { - "bar": Object { - "key": "bar", - "name": "Bar", - }, - "foo": Object { - "key": "foo", - "name": "Foo", - }, - }, - "my": Array [], -} -`; - -exports[`Reducer should receive organizations 2`] = ` -Object { - "byKey": Object { - "bar": Object { - "key": "bar", - "name": "Bar", - }, - "foo": Object { - "key": "foo", - "name": "Qwe", - }, - }, - "my": Array [], -} -`; - -exports[`Reducer should update organization 1`] = ` -Object { - "byKey": Object { - "foo": Object { - "actions": Object { - "admin": true, - }, - "description": "description", - "key": "foo", - "name": "bar", - }, - }, - "my": Array [ - "foo", - ], -} -`; diff --git a/server/sonar-web/src/main/js/store/__tests__/organizations-test.ts b/server/sonar-web/src/main/js/store/__tests__/organizations-test.ts deleted file mode 100644 index 1ce00ff7a54..00000000000 --- a/server/sonar-web/src/main/js/store/__tests__/organizations-test.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 reducer, { - areThereCustomOrganizations, - createOrganization, - deleteOrganization, - getMyOrganizations, - getOrganizationByKey, - receiveMyOrganizations, - receiveOrganizations, - State, - updateOrganization -} from '../organizations'; - -const state0: State = { byKey: {}, my: [] }; - -describe('Reducer', () => { - it('should have initial state', () => { - // @ts-ignore `undefined` is passed when the redux store is created, - // however should not be allowed by typings - expect(reducer(undefined, {})).toMatchSnapshot(); - }); - - it('should receive organizations', () => { - const state1 = reducer( - state0, - receiveOrganizations([ - { key: 'foo', name: 'Foo' }, - { key: 'bar', name: 'Bar' } - ]) - ); - expect(state1).toMatchSnapshot(); - - const state2 = reducer(state1, receiveOrganizations([{ key: 'foo', name: 'Qwe' }])); - expect(state2).toMatchSnapshot(); - }); - - it('should receive my organizations', () => { - const state1 = reducer( - state0, - receiveMyOrganizations([ - { key: 'foo', name: 'Foo' }, - { key: 'bar', name: 'Bar' } - ]) - ); - expect(state1).toMatchSnapshot(); - }); - - it('should create organization', () => { - const state1 = reducer(state0, createOrganization({ key: 'foo', name: 'foo' })); - expect(state1).toMatchSnapshot(); - }); - - it('should update organization', () => { - const state1 = reducer(state0, createOrganization({ key: 'foo', name: 'foo' })); - const state2 = reducer( - state1, - updateOrganization('foo', { name: 'bar', description: 'description' }) - ); - expect(state2).toMatchSnapshot(); - }); - - it('should delete organization', () => { - const state1 = reducer(state0, createOrganization({ key: 'foo', name: 'foo' })); - const state2 = reducer(state1, deleteOrganization('foo')); - expect(state2).toMatchSnapshot(); - }); -}); - -describe('Selectors', () => { - it('getOrganizationByKey', () => { - const foo = { key: 'foo', name: 'Foo' }; - const state = { ...state0, byKey: { foo } }; - expect(getOrganizationByKey(state, 'foo')).toBe(foo); - expect(getOrganizationByKey(state, 'bar')).toBeUndefined(); - }); - - it('getMyOrganizations', () => { - expect(getMyOrganizations(state0)).toEqual([]); - - const foo = { key: 'foo', name: 'Foo' }; - expect(getMyOrganizations({ ...state0, byKey: { foo }, my: ['foo'] })).toEqual([foo]); - }); - - it('areThereCustomOrganizations', () => { - const foo = { key: 'foo', name: 'Foo' }; - const bar = { key: 'bar', name: 'Bar' }; - expect(areThereCustomOrganizations({ ...state0, byKey: {} })).toBe(false); - expect(areThereCustomOrganizations({ ...state0, byKey: { foo } })).toBe(false); - expect(areThereCustomOrganizations({ ...state0, byKey: { foo, bar } })).toBe(true); - }); -}); diff --git a/server/sonar-web/src/main/js/store/appState.ts b/server/sonar-web/src/main/js/store/appState.ts index 057049ae185..2fcffb33649 100644 --- a/server/sonar-web/src/main/js/store/appState.ts +++ b/server/sonar-web/src/main/js/store/appState.ts @@ -45,9 +45,7 @@ export function requireAuthorization() { const defaultValue: T.AppState = { authenticationError: false, authorizationError: false, - defaultOrganization: '', edition: undefined, - organizationsEnabled: false, productionDatabase: true, qualifiers: [], settings: {}, diff --git a/server/sonar-web/src/main/js/store/organizations.ts b/server/sonar-web/src/main/js/store/organizations.ts deleted file mode 100644 index 95cdffe8c3e..00000000000 --- a/server/sonar-web/src/main/js/store/organizations.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { omit, uniq, without } from 'lodash'; -import { combineReducers } from 'redux'; -import { ActionType } from './utils/actions'; - -type ReceiveOrganizationsAction = - | ActionType<typeof receiveOrganizations, 'RECEIVE_ORGANIZATIONS'> - | ActionType<typeof receiveMyOrganizations, 'RECEIVE_MY_ORGANIZATIONS'>; - -type Action = - | ReceiveOrganizationsAction - | ActionType<typeof createOrganization, 'CREATE_ORGANIZATION'> - | ActionType<typeof updateOrganization, 'UPDATE_ORGANIZATION'> - | ActionType<typeof deleteOrganization, 'DELETE_ORGANIZATION'>; - -export interface State { - byKey: T.Dict<T.Organization>; - my: string[]; -} - -export function receiveOrganizations(organizations: T.Organization[]) { - return { type: 'RECEIVE_ORGANIZATIONS', organizations }; -} - -export function receiveMyOrganizations(organizations: T.Organization[]) { - return { type: 'RECEIVE_MY_ORGANIZATIONS', organizations }; -} - -export function createOrganization(organization: T.Organization) { - return { type: 'CREATE_ORGANIZATION', organization }; -} - -export function updateOrganization(key: string, changes: T.OrganizationBase) { - return { type: 'UPDATE_ORGANIZATION', key, changes }; -} - -export function deleteOrganization(key: string) { - return { type: 'DELETE_ORGANIZATION', key }; -} - -function onReceiveOrganizations(state: State['byKey'], action: ReceiveOrganizationsAction) { - const nextState = { ...state }; - action.organizations.forEach(organization => { - nextState[organization.key] = { ...state[organization.key], ...organization }; - }); - return nextState; -} - -function byKey(state: State['byKey'] = {}, action: Action): State['byKey'] { - switch (action.type) { - case 'RECEIVE_ORGANIZATIONS': - case 'RECEIVE_MY_ORGANIZATIONS': - return onReceiveOrganizations(state, action); - case 'CREATE_ORGANIZATION': - return { - ...state, - [action.organization.key]: { - ...action.organization, - actions: { ...(action.organization.actions || {}), admin: true } - } - }; - case 'UPDATE_ORGANIZATION': - return { - ...state, - [action.key]: { - ...state[action.key], - key: action.key, - ...action.changes - } - }; - case 'DELETE_ORGANIZATION': - return omit(state, action.key); - default: - return state; - } -} - -function my(state: State['my'] = [], action: Action): State['my'] { - switch (action.type) { - case 'RECEIVE_MY_ORGANIZATIONS': - return uniq([...state, ...action.organizations.map(o => o.key)]); - case 'CREATE_ORGANIZATION': - return uniq([...state, action.organization.key]); - case 'DELETE_ORGANIZATION': - return without(state, action.key); - default: - return state; - } -} - -export default combineReducers({ byKey, my }); - -export function getOrganizationByKey(state: State, key: string) { - return state.byKey[key]; -} - -export function getMyOrganizations(state: State) { - return state.my.map(key => getOrganizationByKey(state, key)); -} - -export function areThereCustomOrganizations(state: State) { - return Object.keys(state.byKey).length > 1; -} diff --git a/server/sonar-web/src/main/js/store/rootActions.ts b/server/sonar-web/src/main/js/store/rootActions.ts index 70d9b2a4911..ee475999f51 100644 --- a/server/sonar-web/src/main/js/store/rootActions.ts +++ b/server/sonar-web/src/main/js/store/rootActions.ts @@ -22,7 +22,6 @@ import { Dispatch } from 'redux'; import * as auth from '../api/auth'; import { getLanguages } from '../api/languages'; import { getAllMetrics } from '../api/metrics'; -import { getOrganization } from '../api/organizations'; import { getQualityGateProjectStatus } from '../api/quality-gates'; import { getBranchLikeQuery } from '../helpers/branch-like'; import { extractStatusConditionsFromProjectStatus } from '../helpers/qualityGates'; @@ -32,7 +31,6 @@ import { registerBranchStatusAction } from './branches'; import { addGlobalErrorMessage } from './globalMessages'; import { receiveLanguages } from './languages'; import { receiveMetrics } from './metrics'; -import { receiveOrganizations } from './organizations'; export function fetchLanguages() { return (dispatch: Dispatch) => { @@ -56,13 +54,6 @@ export function fetchMetrics() { }; } -export const fetchOrganization = (key: string) => async (dispatch: Dispatch) => { - const organization = await getOrganization(key); - if (organization) { - dispatch(receiveOrganizations([organization])); - } -}; - export function fetchBranchStatus(branchLike: BranchLike, projectKey: string) { return (dispatch: Dispatch<any>) => { getQualityGateProjectStatus({ projectKey, ...getBranchLikeQuery(branchLike) }).then( diff --git a/server/sonar-web/src/main/js/store/rootReducer.ts b/server/sonar-web/src/main/js/store/rootReducer.ts index 557a956aa2c..fb6d3873614 100644 --- a/server/sonar-web/src/main/js/store/rootReducer.ts +++ b/server/sonar-web/src/main/js/store/rootReducer.ts @@ -25,7 +25,6 @@ import branches, * as fromBranches from './branches'; import globalMessages, * as fromGlobalMessages from './globalMessages'; import languages, * as fromLanguages from './languages'; import metrics, * as fromMetrics from './metrics'; -import organizations, * as fromOrganizations from './organizations'; import users, * as fromUsers from './users'; export type Store = { @@ -34,7 +33,6 @@ export type Store = { globalMessages: fromGlobalMessages.State; languages: T.Languages; metrics: fromMetrics.State; - organizations: fromOrganizations.State; users: fromUsers.State; // apps @@ -47,7 +45,6 @@ export default combineReducers<Store>({ globalMessages, languages, metrics, - organizations, users, // apps @@ -86,18 +83,6 @@ export function getMetricByKey(state: Store, key: string) { return fromMetrics.getMetricByKey(state.metrics, key); } -export function getOrganizationByKey(state: Store, key: string) { - return fromOrganizations.getOrganizationByKey(state.organizations, key); -} - -export function getMyOrganizations(state: Store) { - return fromOrganizations.getMyOrganizations(state.organizations); -} - -export function areThereCustomOrganizations(state: Store) { - return getAppState(state).organizationsEnabled; -} - export function getGlobalSettingValue(state: Store, key: string) { return fromSettingsApp.getValue(state.settingsApp, key); } diff --git a/server/sonar-web/src/main/js/types/types.d.ts b/server/sonar-web/src/main/js/types/types.d.ts index 57075e79735..7c1966ccfed 100644 --- a/server/sonar-web/src/main/js/types/types.d.ts +++ b/server/sonar-web/src/main/js/types/types.d.ts @@ -30,14 +30,6 @@ declare namespace T { installationUrl: string; } - export interface AlmOrganization extends OrganizationBase { - almUrl: string; - key: string; - personal: boolean; - privateRepos: number; - publicRepos: number; - } - export interface AlmRepository { label: string; installationKey: string; @@ -96,12 +88,10 @@ declare namespace T { authorizationError?: boolean; branchesEnabled?: boolean; canAdmin?: boolean; - defaultOrganization: string; edition: 'community' | 'developer' | 'enterprise' | 'datacenter' | undefined; globalPages?: Extension[]; multipleAlmEnabled?: boolean; needIssueSync?: boolean; - organizationsEnabled?: boolean; productionDatabase: boolean; qualifiers: string[]; settings: T.Dict<string>; @@ -167,7 +157,6 @@ declare namespace T { key: string; match?: string; name: string; - organization?: string; path?: string; project?: string; qualifier: string; @@ -295,7 +284,6 @@ declare namespace T { | { type: 'ISSUES' } | { type: 'MY_ISSUES' } | { type: 'MY_PROJECTS' } - | { type: 'ORGANIZATION'; organization: string } | { type: 'PORTFOLIO'; component: string } | { type: 'PORTFOLIOS' } | { type: 'PROJECT'; branch: string | undefined; component: string } @@ -306,7 +294,6 @@ declare namespace T { | 'ISSUES' | 'MY_ISSUES' | 'MY_PROJECTS' - | 'ORGANIZATION' | 'PORTFOLIO' | 'PORTFOLIOS' | 'PROJECT' @@ -403,7 +390,6 @@ declare namespace T { export interface LightComponent { key: string; - organization?: string; qualifier: string; } @@ -434,7 +420,6 @@ declare namespace T { homepage?: HomePage; isLoggedIn: true; local?: boolean; - personalOrganization?: string; scmAccounts: string[]; settings?: CurrentUserSetting[]; } @@ -518,39 +503,6 @@ declare namespace T { projectName: string; } - export interface OrganizationActions { - admin?: boolean; - delete?: boolean; - provision?: boolean; - executeAnalysis?: boolean; - } - - export interface Organization extends OrganizationBase { - actions?: OrganizationActions; - alm?: { key: string; membersSync: boolean; personal: boolean; url: string }; - adminPages?: Extension[]; - canUpdateProjectsVisibilityToPrivate?: boolean; - isDefault?: boolean; - key: string; - pages?: Extension[]; - projectVisibility?: Visibility; - subscription?: OrganizationSubscription; - } - - export interface OrganizationBase { - avatar?: string; - description?: string; - key?: string; - name: string; - url?: string; - } - - export interface OrganizationMember extends UserActive { - groupCount?: number; - } - - export type OrganizationSubscription = 'FREE' | 'PAID' | 'SONARQUBE'; - export interface Paging { pageIndex: number; pageSize: number; |