Kaynağa Gözat

SONAR-13999 Drop frontend organizations leftovers

tags/8.7.0.41497
Jeremy Davis 3 yıl önce
ebeveyn
işleme
d83e1ab982
90 değiştirilmiş dosya ile 107 ekleme ve 2515 silme
  1. 0
    4
      server/sonar-web/src/main/js/api/components.ts
  2. 0
    2
      server/sonar-web/src/main/js/api/issues.ts
  3. 0
    38
      server/sonar-web/src/main/js/api/organizations.ts
  4. 0
    2
      server/sonar-web/src/main/js/api/quality-profiles.ts
  5. 2
    5
      server/sonar-web/src/main/js/api/rules.ts
  6. 0
    83
      server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx
  7. 23
    189
      server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx
  8. 4
    5
      server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx
  9. 0
    17
      server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx
  10. 0
    32
      server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx
  11. 4
    70
      server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx
  12. 7
    50
      server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx
  13. 2
    144
      server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNav-test.tsx.snap
  14. 4
    181
      server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap
  15. 0
    8
      server/sonar-web/src/main/js/app/components/search/Search.tsx
  16. 0
    2
      server/sonar-web/src/main/js/app/components/search/SearchResult.tsx
  17. 1
    5
      server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx
  18. 4
    9
      server/sonar-web/src/main/js/app/components/search/__tests__/SearchResult-test.tsx
  19. 0
    1
      server/sonar-web/src/main/js/app/components/search/utils.ts
  20. 0
    1
      server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx
  21. 1
    2
      server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx
  22. 3
    10
      server/sonar-web/src/main/js/apps/account/components/Account.tsx
  23. 6
    19
      server/sonar-web/src/main/js/apps/account/components/Nav.tsx
  24. 0
    2
      server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx
  25. 0
    58
      server/sonar-web/src/main/js/apps/account/organizations/OrganizationCard.tsx
  26. 0
    45
      server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx
  27. 0
    113
      server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
  28. 0
    36
      server/sonar-web/src/main/js/apps/account/organizations/actions.ts
  29. 0
    4
      server/sonar-web/src/main/js/apps/account/routes.ts
  30. 0
    1
      server/sonar-web/src/main/js/apps/code/components/__tests__/App-test.tsx
  31. 0
    2
      server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumb-test.tsx
  32. 0
    2
      server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumbs-test.tsx
  33. 0
    3
      server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/Breadcrumbs-test.tsx.snap
  34. 0
    1
      server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/ComponentList-test.tsx
  35. 0
    3
      server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/FilesView-test.tsx
  36. 0
    4
      server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/ComponentList-test.tsx.snap
  37. 0
    4
      server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/FilesView-test.tsx.snap
  38. 1
    1
      server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/App-test.tsx
  39. 1
    1
      server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/App-test.tsx.snap
  40. 1
    2
      server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.tsx
  41. 0
    2
      server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx
  42. 0
    1
      server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx
  43. 1
    1
      server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx
  44. 3
    3
      server/sonar-web/src/main/js/apps/projectsManagement/ChangeDefaultVisibilityForm.tsx
  45. 1
    1
      server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx
  46. 6
    6
      server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeDefaultVisibilityForm-test.tsx.snap
  47. 2
    2
      server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap
  48. 7
    11
      server/sonar-web/src/main/js/apps/users/UsersApp.tsx
  49. 0
    29
      server/sonar-web/src/main/js/apps/users/UsersAppContainer.tsx
  50. 1
    4
      server/sonar-web/src/main/js/apps/users/UsersList.tsx
  51. 0
    1
      server/sonar-web/src/main/js/apps/users/__tests__/UsersApp-test.tsx
  52. 0
    8
      server/sonar-web/src/main/js/apps/users/__tests__/UsersList-test.tsx
  53. 0
    2
      server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersApp-test.tsx.snap
  54. 5
    2
      server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList-test.tsx.snap
  55. 4
    7
      server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx
  56. 0
    9
      server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItem-test.tsx
  57. 1
    1
      server/sonar-web/src/main/js/apps/users/routes.ts
  58. 1
    1
      server/sonar-web/src/main/js/apps/webhooks/components/__tests__/App-test.tsx
  59. 0
    3
      server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap
  60. 0
    3
      server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/loadIssues-test.ts
  61. 0
    48
      server/sonar-web/src/main/js/components/common/OrganizationAvatar.css
  62. 0
    66
      server/sonar-web/src/main/js/components/common/OrganizationAvatar.tsx
  63. 1
    2
      server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx
  64. 0
    3
      server/sonar-web/src/main/js/components/hoc/__tests__/__snapshots__/withNotifications-test.tsx.snap
  65. 3
    6
      server/sonar-web/src/main/js/components/hoc/__tests__/withNotifications-test.tsx
  66. 0
    51
      server/sonar-web/src/main/js/components/hoc/__tests__/withUserOrganizations-test.tsx
  67. 0
    53
      server/sonar-web/src/main/js/components/hoc/withUserOrganizations.tsx
  68. 1
    1
      server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.tsx
  69. 0
    64
      server/sonar-web/src/main/js/components/shared/Organization.tsx
  70. 0
    42
      server/sonar-web/src/main/js/components/shared/__tests__/Organization-test.tsx
  71. 0
    19
      server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/Organization-test.tsx.snap
  72. 0
    37
      server/sonar-web/src/main/js/components/ui/OrganizationLink.tsx
  73. 0
    42
      server/sonar-web/src/main/js/components/ui/OrganizationListItem.tsx
  74. 0
    26
      server/sonar-web/src/main/js/components/ui/__tests__/OrganizationLink-test.tsx
  75. 0
    37
      server/sonar-web/src/main/js/components/ui/__tests__/OrganizationListItem-test.tsx
  76. 0
    9
      server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationLink-test.tsx.snap
  77. 0
    45
      server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationListItem-test.tsx.snap
  78. 0
    56
      server/sonar-web/src/main/js/helpers/__tests__/organizations-test.ts
  79. 1
    1
      server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts
  80. 0
    48
      server/sonar-web/src/main/js/helpers/organizations.ts
  81. 0
    43
      server/sonar-web/src/main/js/helpers/testMocks.ts
  82. 0
    6
      server/sonar-web/src/main/js/helpers/urls.ts
  83. 0
    101
      server/sonar-web/src/main/js/store/__tests__/__snapshots__/organizations-test.ts.snap
  84. 0
    109
      server/sonar-web/src/main/js/store/__tests__/organizations-test.ts
  85. 0
    2
      server/sonar-web/src/main/js/store/appState.ts
  86. 0
    121
      server/sonar-web/src/main/js/store/organizations.ts
  87. 0
    9
      server/sonar-web/src/main/js/store/rootActions.ts
  88. 0
    15
      server/sonar-web/src/main/js/store/rootReducer.ts
  89. 0
    48
      server/sonar-web/src/main/js/types/types.d.ts
  90. 5
    147
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 0
- 4
server/sonar-web/src/main/js/api/components.ts Dosyayı Görüntüle

@@ -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;

+ 0
- 2
server/sonar-web/src/main/js/api/issues.ts Dosyayı Görüntüle

@@ -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;

+ 0
- 38
server/sonar-web/src/main/js/api/organizations.ts Dosyayı Görüntüle

@@ -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
);
}

+ 0
- 2
server/sonar-web/src/main/js/api/quality-profiles.ts Dosyayı Görüntüle

@@ -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;
}


+ 2
- 5
server/sonar-web/src/main/js/api/rules.ts Dosyayı Görüntüle

@@ -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);
}


+ 0
- 83
server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx Dosyayı Görüntüle

@@ -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);

+ 23
- 189
server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx Dosyayı Görüntüle

@@ -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);

+ 4
- 5
server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx Dosyayı Görüntüle

@@ -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>

+ 0
- 17
server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx Dosyayı Görüntüle

@@ -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')}

+ 0
- 32
server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx Dosyayı Görüntüle

@@ -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);

+ 4
- 70
server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx Dosyayı Görüntüle

@@ -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}
/>
);

+ 7
- 50
server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx Dosyayı Görüntüle

@@ -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();
});
}

+ 2
- 144
server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNav-test.tsx.snap Dosyayı Görüntüle

@@ -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,

+ 4
- 181
server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap Dosyayı Görüntüle

@@ -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>

+ 0
- 8
server/sonar-web/src/main/js/app/components/search/Search.tsx Dosyayı Görüntüle

@@ -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}
/>

+ 0
- 2
server/sonar-web/src/main/js/app/components/search/SearchResult.tsx Dosyayı Görüntüle

@@ -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;
}

+ 1
- 5
server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx Dosyayı Görüntüle

@@ -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} />
);
}


+ 4
- 9
server/sonar-web/src/main/js/app/components/search/__tests__/SearchResult-test.tsx Dosyayı Görüntüle

@@ -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}

+ 0
- 1
server/sonar-web/src/main/js/app/components/search/utils.ts Dosyayı Görüntüle

@@ -39,7 +39,6 @@ export interface ComponentResult {
key: string;
match?: string;
name: string;
organization?: string;
project?: string;
qualifier: string;
}

+ 0
- 1
server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx Dosyayı Görüntüle

@@ -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>;

+ 1
- 2
server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx Dosyayı Görüntüle

@@ -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('')}

+ 3
- 10
server/sonar-web/src/main/js/apps/account/components/Account.tsx Dosyayı Görüntüle

@@ -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);

+ 6
- 19
server/sonar-web/src/main/js/apps/account/components/Nav.tsx Dosyayı Görüntüle

@@ -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>
);

+ 0
- 2
server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx Dosyayı Görüntüle

@@ -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: []
});


+ 0
- 58
server/sonar-web/src/main/js/apps/account/organizations/OrganizationCard.tsx Dosyayı Görüntüle

@@ -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>
);
}

+ 0
- 45
server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx Dosyayı Görüntüle

@@ -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>
);
}

+ 0
- 113
server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx Dosyayı Görüntüle

@@ -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);

+ 0
- 36
server/sonar-web/src/main/js/apps/account/organizations/actions.ts Dosyayı Görüntüle

@@ -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));
});
};

+ 0
- 4
server/sonar-web/src/main/js/apps/account/routes.ts Dosyayı Görüntüle

@@ -37,10 +37,6 @@ const routes = [
{
path: 'notifications',
component: lazyLoadComponent(() => import('./notifications/Notifications'))
},
{
path: 'organizations',
component: lazyLoadComponent(() => import('./organizations/UserOrganizations'))
}
]
}

+ 0
- 1
server/sonar-web/src/main/js/apps/code/components/__tests__/App-test.tsx Dosyayı Görüntüle

@@ -95,7 +95,6 @@ function shallowRender(props: Partial<App['props']> = {}) {
breadcrumbs: [],
name: 'foo',
key: 'foo',
organization: 'foo',
qualifier: 'FOO'
}}
fetchBranchStatus={jest.fn()}

+ 0
- 2
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumb-test.tsx Dosyayı Görüntüle

@@ -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={() => {}}

+ 0
- 2
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/Breadcrumbs-test.tsx Dosyayı Görüntüle

@@ -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'
};


+ 0
- 3
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/Breadcrumbs-test.tsx.snap Dosyayı Görüntüle

@@ -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",
},
],

+ 0
- 1
server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/ComponentList-test.tsx Dosyayı Görüntüle

@@ -26,7 +26,6 @@ const COMPONENTS = [
key: 'foo',
measures: [],
name: 'Foo',
organization: 'foo',
qualifier: 'TRK'
}
];

+ 0
- 3
server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/FilesView-test.tsx Dosyayı Görüntüle

@@ -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"

+ 0
- 4
server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/ComponentList-test.tsx.snap Dosyayı Görüntüle

@@ -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",
}
}

+ 0
- 4
server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/__snapshots__/FilesView-test.tsx.snap Dosyayı Görüntüle

@@ -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",
}
}

+ 1
- 1
server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/App-test.tsx Dosyayı Görüntüle

@@ -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: [

+ 1
- 1
server/sonar-web/src/main/js/apps/permission-templates/components/__tests__/__snapshots__/App-test.tsx.snap Dosyayı Görüntüle

@@ -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 [

+ 1
- 2
server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.tsx Dosyayı Görüntüle

@@ -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);

+ 0
- 2
server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx Dosyayı Görüntüle

@@ -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(() => {

+ 0
- 1
server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx Dosyayı Görüntüle

@@ -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}
/>
)}

+ 1
- 1
server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx Dosyayı Görüntüle

@@ -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);

+ 3
- 3
server/sonar-web/src/main/js/apps/projectsManagement/ChangeDefaultVisibilityForm.tsx Dosyayı Görüntüle

@@ -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')}

+ 1
- 1
server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx Dosyayı Görüntüle

@@ -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>

+ 6
- 6
server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeDefaultVisibilityForm-test.tsx.snap Dosyayı Görüntüle

@@ -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"

+ 2
- 2
server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap Dosyayı Görüntüle

@@ -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>

+ 7
- 11
server/sonar-web/src/main/js/apps/users/UsersApp.tsx Dosyayı Görüntüle

@@ -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));

+ 0
- 29
server/sonar-web/src/main/js/apps/users/UsersAppContainer.tsx Dosyayı Görüntüle

@@ -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);

+ 1
- 4
server/sonar-web/src/main/js/apps/users/UsersList.tsx Dosyayı Görüntüle

@@ -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">&nbsp;</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}
/>

+ 0
- 1
server/sonar-web/src/main/js/apps/users/__tests__/UsersApp-test.tsx Dosyayı Görüntüle

@@ -81,7 +81,6 @@ function getWrapper(props: Partial<UsersApp['props']> = {}) {
<UsersApp
currentUser={currentUser}
location={location}
organizationsEnabled={true}
router={{ push: jest.fn() }}
{...props}
/>

+ 0
- 8
server/sonar-web/src/main/js/apps/users/__tests__/UsersList-test.tsx Dosyayı Görüntüle

@@ -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}

+ 0
- 2
server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersApp-test.tsx.snap Dosyayı Görüntüle

@@ -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 [

+ 5
- 2
server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList-test.tsx.snap Dosyayı Görüntüle

@@ -24,6 +24,11 @@ exports[`should render correctly 1`] = `
>
users.last_connection
</th>
<th
className="nowrap"
>
my_profile.groups
</th>
<th
className="nowrap"
>
@@ -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 {

+ 4
- 7
server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx Dosyayı Görüntüle

@@ -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

+ 0
- 9
server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItem-test.tsx Dosyayı Görüntüle

@@ -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}

+ 1
- 1
server/sonar-web/src/main/js/apps/users/routes.ts Dosyayı Görüntüle

@@ -21,7 +21,7 @@ import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent'

const routes = [
{
indexRoute: { component: lazyLoadComponent(() => import('./UsersAppContainer')) }
indexRoute: { component: lazyLoadComponent(() => import('./UsersApp')) }
}
];


+ 1
- 1
server/sonar-web/src/main/js/apps/webhooks/components/__tests__/App-test.tsx Dosyayı Görüntüle

@@ -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();

+ 0
- 3
server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap Dosyayı Görüntüle

@@ -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",

+ 0
- 3
server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/loadIssues-test.ts Dosyayı Görüntüle

@@ -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',

+ 0
- 48
server/sonar-web/src/main/js/components/common/OrganizationAvatar.css Dosyayı Görüntüle

@@ -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;
}

+ 0
- 66
server/sonar-web/src/main/js/components/common/OrganizationAvatar.tsx Dosyayı Görüntüle

@@ -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>
);
}
}

+ 1
- 2
server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx Dosyayı Görüntüle

@@ -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
);
}

+ 0
- 3
server/sonar-web/src/main/js/components/hoc/__tests__/__snapshots__/withNotifications-test.tsx.snap Dosyayı Görüntüle

@@ -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",

+ 3
- 6
server/sonar-web/src/main/js/components/hoc/__tests__/withNotifications-test.tsx Dosyayı Görüntüle

@@ -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']

+ 0
- 51
server/sonar-web/src/main/js/components/hoc/__tests__/withUserOrganizations-test.tsx Dosyayı Görüntüle

@@ -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]);
});

+ 0
- 53
server/sonar-web/src/main/js/components/hoc/withUserOrganizations.tsx Dosyayı Görüntüle

@@ -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);
}

+ 1
- 1
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.tsx Dosyayı Görüntüle

@@ -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();

+ 0
- 64
server/sonar-web/src/main/js/components/shared/Organization.tsx Dosyayı Görüntüle

@@ -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;

+ 0
- 42
server/sonar-web/src/main/js/components/shared/__tests__/Organization-test.tsx Dosyayı Görüntüle

@@ -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();
});

+ 0
- 19
server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/Organization-test.tsx.snap Dosyayı Görüntüle

@@ -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>
`;

+ 0
- 37
server/sonar-web/src/main/js/components/ui/OrganizationLink.tsx Dosyayı Görüntüle

@@ -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>
);
}

+ 0
- 42
server/sonar-web/src/main/js/components/ui/OrganizationListItem.tsx Dosyayı Görüntüle

@@ -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>
);
}

+ 0
- 26
server/sonar-web/src/main/js/components/ui/__tests__/OrganizationLink-test.tsx Dosyayı Görüntüle

@@ -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();
});

+ 0
- 37
server/sonar-web/src/main/js/components/ui/__tests__/OrganizationListItem-test.tsx Dosyayı Görüntüle

@@ -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();
});

+ 0
- 9
server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationLink-test.tsx.snap Dosyayı Görüntüle

@@ -1,9 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders 1`] = `
<Link
onlyActiveOnIndex={false}
style={Object {}}
to="/organizations/org"
/>
`;

+ 0
- 45
server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationListItem-test.tsx.snap Dosyayı Görüntüle

@@ -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>
`;

+ 0
- 56
server/sonar-web/src/main/js/helpers/__tests__/organizations-test.ts Dosyayı Görüntüle

@@ -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);
});
});

+ 1
- 1
server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts Dosyayı Görüntüle

@@ -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' });
});

+ 0
- 48
server/sonar-web/src/main/js/helpers/organizations.ts Dosyayı Görüntüle

@@ -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))
);
}

+ 0
- 43
server/sonar-web/src/main/js/helpers/testMocks.ts Dosyayı Görüntüle

@@ -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',

+ 0
- 6
server/sonar-web/src/main/js/helpers/urls.ts Dosyayı Görüntüle

@@ -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':

+ 0
- 101
server/sonar-web/src/main/js/store/__tests__/__snapshots__/organizations-test.ts.snap Dosyayı Görüntüle

@@ -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",
],
}
`;

+ 0
- 109
server/sonar-web/src/main/js/store/__tests__/organizations-test.ts Dosyayı Görüntüle

@@ -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);
});
});

+ 0
- 2
server/sonar-web/src/main/js/store/appState.ts Dosyayı Görüntüle

@@ -45,9 +45,7 @@ export function requireAuthorization() {
const defaultValue: T.AppState = {
authenticationError: false,
authorizationError: false,
defaultOrganization: '',
edition: undefined,
organizationsEnabled: false,
productionDatabase: true,
qualifiers: [],
settings: {},

+ 0
- 121
server/sonar-web/src/main/js/store/organizations.ts Dosyayı Görüntüle

@@ -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;
}

+ 0
- 9
server/sonar-web/src/main/js/store/rootActions.ts Dosyayı Görüntüle

@@ -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(

+ 0
- 15
server/sonar-web/src/main/js/store/rootReducer.ts Dosyayı Görüntüle

@@ -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);
}

+ 0
- 48
server/sonar-web/src/main/js/types/types.d.ts Dosyayı Görüntüle

@@ -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;

+ 5
- 147
sonar-core/src/main/resources/org/sonar/l10n/core.properties Dosyayı Görüntüle

@@ -132,9 +132,6 @@ not_now=Not now
off=Off
on=On
or=Or
organization_key=Organization Key
organization.bitbucket=Bitbucket team
organization.github=GitHub organization
open=Open
optional=Optional
order=Order
@@ -262,7 +259,6 @@ logging_out=You're logging out, please wait...
manage=Manage
management=Management
more_information=More information
my_organizations=My Organizations
new_violations=New violations
new_window=New window
no_data=No data
@@ -1060,6 +1056,11 @@ settings.new_code_period.description2=This setting is the default for all projec

settings.languages.select_a_language_placeholder=Select a language

settings.projects.default_visibility_of_new_projects=Default visibility of new projects:
settings.projects.change_visibility_form.header=Set Default Visibility of New Projects
settings.projects.change_visibility_form.warning=This will not change the visibility of already existing projects.
settings.projects.change_visibility_form.submit=Change Default Visibility

settings.almintegration.title=Integration configurations
settings.almintegration.description=ALM integrations allow SonarQube to interact with your ALM. This enables things like authentication, or providing analysis details and a Quality Gate to your Pull Requests directly in your ALM provider's interface.
settings.almintegration.azure.info=Accounts that will be used to decorate Pull Requests need Code: Read & Write permission. {link}
@@ -1853,10 +1854,6 @@ my_account.projects.description=Those projects are the ones you are administerin
my_account.projects.no_results=You are not administering any project yet.
my_account.projects.analyzed_x=Analyzed {0}
my_account.projects.never_analyzed=Never analyzed
my_account.organizations=Organizations
my_account.organizations.description=Those organizations are the ones you are member of.
my_account.organizations.no_results=You are not a member of any organizations yet.
my_account.create_organization=Create Organization
my_account.search_project=Search Project
my_account.set_notifications_for=Search a project by name
my_account.set_notifications_for.title=Add a project
@@ -2413,9 +2410,7 @@ global_permissions.groups=Groups
global_permissions.administer=Administer
global_permissions.creator=Create
global_permissions.admin=Administer System
global_permissions.admin.sonarcloud=Administer Organization
global_permissions.admin.desc=Ability to perform all administration functions for the instance.
global_permissions.admin.desc.sonarcloud=Ability to perform all administration functions for the organization.
global_permissions.profileadmin=Quality Profiles
global_permissions.profileadmin.desc=Ability to perform any action on Quality Profiles.
global_permissions.gateadmin=Quality Gates
@@ -2432,23 +2427,6 @@ global_permissions.applicationcreator.desc=Ability to create an application.
global_permissions.portfoliocreator=Portfolios
global_permissions.portfoliocreator.desc=Ability to create a portfolio.

#------------------------------------------------------------------------------
#
# ORGANIZATIONS PERMISSIONS
#
#------------------------------------------------------------------------------

organizations_permissions.admin=Administer Organization
organizations_permissions.admin.desc=Ability to perform all administration functions for the organization.
organizations_permissions.profileadmin=Administer Quality Profiles
organizations_permissions.profileadmin.desc=Ability to perform any action on Quality Profiles.
organizations_permissions.gateadmin=Administer Quality Gates
organizations_permissions.gateadmin.desc=Ability to perform any action on quality gates.
organizations_permissions.scan=Execute Analysis
organizations_permissions.scan.desc=Ability to get all settings required to perform an analysis (including the secured settings like passwords) and to push analysis results to the {instance} server.
organizations_permissions.provisioning=Create Projects
organizations_permissions.provisioning.desc=Ability to initialize a project so its settings can be configured before the first analysis.

#------------------------------------------------------------------------------
#
# PROJECTS PERMISSIONS
@@ -3104,75 +3082,6 @@ about_page.scanners.gradle=SonarQube Scanner for Gradle
about_page.scanners.jenkins=SonarQube Scanner for Jenkins
about_page.scanners.ant=SonarQube Scanner for Ant


#------------------------------------------------------------------------------
#
# ORGANIZATIONS
#
#------------------------------------------------------------------------------
organization.avatar=Avatar
organization.avatar.description=Url of a small image that represents the organization (preferably 30px height).
organization.avatar.preview=Preview
organization.bind_to_x=Bind this organization to {0}
organization.go_to_settings_to_bind=Go to Organization Settings to bind it
organization.bound=This organization is bound.
organization.bound_to_x=This organization is bound to {0}
organization.not_bound_to_x=This organization is not bound to {0}
organization.created=Organization "{0}" has been created.
organization.delete=Delete Organization
organization.delete_x=Delete the "{0}" organization
organization.delete.description=Delete this organization from {instance}. All projects belonging to the organization will be deleted as well. The operation cannot be undone.
organization.delete.sonarcloud.paid_plan_info=Your current paid plan subscription will stop and you won't be charged anymore.
organization.delete.question=Are you sure you want to delete this organization?
organization.deleted=Organization has been deleted.
organization.deleted_x=Organization "{0}" has been deleted.
organization.description=Description
organization.description.description=Description of the organization.
organization.details=Organization details
organization.key=Key
organization.key.description=Key of the organization (up to 255 characters). All chars must be lower-case letters (a to z), digits or dash (but dash can neither be trailing nor heading). When not specified, the key is computed from the name.
organization.name=Name
organization.name.description=Name of the organization (up to 255 characters).
organization.see_on_x=See on {0}
organization.settings=Organization settings
organization.updated=Organization details have been updated.
organization.url=Url
organization.url.description=Url of the homepage of the organization.
organization.binding_with_x_easy_sync=Binding an organization from SonarCloud with {0} is an easy way to keep them synchronized.
organization.app_will_be_installed_on_x=To bind this organization to {0}, the SonarCloud application will be installed.
organization.members.page=Members
organization.members.page.description=Add users to the organization and grant them permissions to work on the projects. See {link} documentation.
organization.members.add=Add a member
organization.members.add.multiple=Add members
organization.members.x_groups={0} group(s)
organization.members.members=member(s)
organization.members.remove=Remove from organization's members
organization.members.remove_x=Are you sure you want to remove {0} from {1}'s members ?
organization.members.manage_groups=Manage groups
organization.members.members_groups={0}'s groups:
organization.members.manage_a_team=Manage a team
organization.members.add_to_members=Add to members
organization.members.config_synchro=Configure Synchronization
organization.members.auto_sync_with_x=Automatic sync with {0}
organization.members.auto_sync_members_from_org_x=Now your members can be automatically synchronized with your {0}.
organization.members.auto_sync_total_help.github=You might not see all members from your GitHub organization yet, as they need to connect to SonarCloud at least once to appear in this list.
organization.members.see_all_members_on_x=See all members on {0}
organization.members.management.title=Members Management
organization.members.management.description=Select your management mode for members of this organization.
organization.members.management.manual=Manual
organization.members.management.manual.add_members_manually=Admin add members manually from SonarCloud existing users
organization.members.management.automatic=Automatic sync with {0}
organization.members.management.automatic.synchronized_from_x=Members are synchronized automatically from your {0}
organization.members.management.automatic.members_changes_reflected.github=If you add or remove a member on GitHub, SonarCloud immediately reflects the changes
organization.members.management.automatic.warning_x=This will override your current Members, removing those that are not part of your {0}.
organization.members.management.choose_members_permissions=Admin manages permissions for each member in SonarCloud
organization.paid_plan.badge=Paid plan
organization.default_visibility_of_new_projects=Default visibility of new projects:
organization.change_visibility_form.header=Set Default Visibility of New Projects
organization.change_visibility_form.warning=This will not change the visibility of already existing projects.
organization.change_visibility_form.submit=Change Default Visibility
organization.bind.success=Organization bound successfully

#------------------------------------------------------------------------------
#
# EMBEDED DOCS
@@ -3319,57 +3228,6 @@ onboarding.create_project.gitlab.link=See on GitLab
onboarding.create_project.gitlab.search_prompt=Search for projects
onboarding.create_project.gitlab.set_up=Set up

onboarding.create_organization.page.header=Create Organization
onboarding.create_organization.page.description=An organization is a space where a team or a whole company can collaborate accross many projects.
onboarding.create_organization.organization_name=Key
onboarding.create_organization.organization_name.description=Up to 255 characters. All chars must be lower-case letters (a to z), digits or dash (but dash can neither be trailing nor heading). The display name can be specified in the additional info.
onboarding.create_organization.organization_name.error=The provided value doesn't match the expected format.
onboarding.create_organization.organization_name.taken=This name is already taken.
onboarding.create_organization.add_additional_info=Add additional info
onboarding.create_organization.hide_additional_info=Hide additional info
onboarding.create_organization.description=Description
onboarding.create_organization.description.error=The provided value doesn't match the expected format.
onboarding.create_organization.display_name=Display Name
onboarding.create_organization.display_name.description=Up to 255 characters
onboarding.create_organization.display_name.error=The provided value doesn't match the expected format.
onboarding.create_organization.avatar=Avatar
onboarding.create_organization.avatar.description=Url of a small image that represents the organization (preferably 30px height).
onboarding.create_organization.avatar.error=The value must be a valid url.
onboarding.create_organization.avatar.placeholder=Default avatar
onboarding.create_organization.url=URL
onboarding.create_organization.url.error=The value must be a valid url.
onboarding.create_organization.enter_org_details=Enter your organization details
onboarding.create_organization.create_manually=Create manually
onboarding.create_organization.enter_payment_details=Enter payment details
onboarding.create_organization.choose_plan=Choose a plan
onboarding.create_organization.enter_your_coupon=Enter your coupon
onboarding.create_organization.create_and_upgrade=Create Organization and Upgrade
onboarding.create_organization.ready=All set! Your organization is now ready to go
onboarding.import_organization.bind=Bind Organization
onboarding.import_organization.choose_unbound_installation_x=Choose one of your {0} that already have the SonarCloud application installed:
onboarding.import_organization.import=Import Organization
onboarding.import_organization.import_org_details=Import organization details
onboarding.import_organization.org_not_found=We were not able to find the requested organization, here are a few tips to help you troubleshoot the issue:
onboarding.import_organization.org_not_found.tips_1=You must be an administrator of the organization
onboarding.import_organization.org_not_found.tips_2=Try to uninstall and re-install the SonarCloud App (using the button bellow)
onboarding.import_organization.choose_organization=Choose an organization...
onboarding.import_organization.choose_organization_button.bitbucket=Choose a team on Bitbucket
onboarding.import_organization.choose_organization_button.github=Choose an organization on GitHub
onboarding.import_organization.choose_the_organization_button.bitbucket=Choose the team on Bitbucket
onboarding.import_organization.choose_the_organization_button.github=Choose the organization on GitHub
onboarding.import_organization.installing=Finalize installation of the {0} application...
onboarding.import_organization.personal.import_org_details=Import personal organization details
onboarding.import_organization.private.disabled=Selecting private repository is not available yet and will come soon. Meanwhile, you need to create the project manually.
onboarding.import_organization.import_from_x=Import from {0}
onboarding.import_organization.bind_existing=Bind to an existing SonarCloud organization
onboarding.import_organization.create_new=Create new SonarCloud organization from it
onboarding.import_organization.already_bound_x=Your organization {avatar} {name} is already bound to the SonarCloud organization {boundAvatar} {boundName}. Try again and choose a different organization.
onboarding.import_organization.members_sync_info_x=All members from your {0} {1} will be added to your SonarCloud organization. As they connect to SonarCloud with their {2} account, members will automatically have access to your SonarCloud organization and its projects.
onboarding.import_organization.bind_members_not_sync_info_x=We'll keep your members, groups and permissions as they are today on SonarCloud. To sync your members with your {0}, enable members sync in your Members tab.
onboarding.import_organization_x=Import {avatar} {name} into a SonarCloud organization
onboarding.import_personal_organization_x=Bind {avatar} {name} with your personal SonarCloud organization {personalAvatar} {personalName}
onboarding.binding_organization=Binding organization

onboarding.token.header=Provide a token
onboarding.token.text=The token is used to identify you when an analysis is performed. If it has been compromised, you can revoke it at any point of time in your {link}.
onboarding.token.text.user_account=user account

Loading…
İptal
Kaydet