+++ /dev/null
-This project is private. Only the members of this organization are able to browse it and its source code.
-
----
-
-See also: [Organization Visibility](/organizations/organization-visibility/)
+++ /dev/null
-This project is public, which means anyone is able to browse its source code. Subscribe to a paid plan to get unlimited private projects in [Administration > Billing](/#sonarcloud#/organizations/#organization#/extension/billing/billing).
-
----
-
-See also: [Pricing](/sonarcloud-pricing/)
+++ /dev/null
-This project is public, which means anyone is able to browse its source code. Go to your project's [Administration > Permissions](/#sonarcloud#/project_roles?id=#projectKey#) to make it private.
-
----
-
-See also: [Organization Visibility](/organizations/organization-visibility/)
+++ /dev/null
-This project is public, which means anyone is able to browse its source code. Contact the project administrator to make it private.
-
----
-
-See also: [Organization Visibility](/organizations/organization-visibility/)
+++ /dev/null
-This project is public, which means anyone is able to browse its source code. Contact the organization administrator if you want to make it private.
-
----
-
-See also: [Pricing](/sonarcloud-pricing/)
+++ /dev/null
-/*
- * 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 { createContext } from 'react';
-
-export type OnboardingContextShape = (organization?: T.Organization) => void;
-
-export const OnboardingContext = createContext<OnboardingContextShape>(() => {});
<h3 className="spacer-right">{translate('project.info.description')}</h3>
{component.visibility && (
<PrivacyBadgeContainer
- organization={undefined}
qualifier={component.qualifier}
- tooltipProps={{ projectKey: component.key }}
visibility={component.visibility}
/>
)}
>
project.info.description
</h3>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
qualifier="TRK"
- tooltipProps={
- Object {
- "projectKey": "my-project",
- }
- }
visibility="private"
/>
</div>
>
project.info.description
</h3>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
qualifier="TRK"
- tooltipProps={
- Object {
- "projectKey": "my-project",
- }
- }
visibility="public"
/>
</div>
>
project.info.description
</h3>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
qualifier="TRK"
- tooltipProps={
- Object {
- "projectKey": "my-project",
- }
- }
visibility="public"
/>
</div>
>
project.info.description
</h3>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
qualifier="TRK"
- tooltipProps={
- Object {
- "projectKey": "my-project",
- }
- }
visibility="public"
/>
</div>
>
project.info.description
</h3>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
qualifier="TRK"
- tooltipProps={
- Object {
- "projectKey": "my-project",
- }
- }
visibility="public"
/>
</div>
import { setCurrentUserSetting } from '../../../../store/users';
import { rawSizes } from '../../../theme';
import EmbedDocsPopupHelper from '../../embed-docs-modal/EmbedDocsPopupHelper';
-import { OnboardingContext } from '../../OnboardingContext';
import Search from '../../search/Search';
import './GlobalNav.css';
import GlobalNavBranding, { SonarCloudNavBranding } from './GlobalNavBranding';
<EmbedDocsPopupHelper />
<Search appState={appState} currentUser={currentUser} />
{isLoggedIn(currentUser) && (
- <OnboardingContext.Consumer data-test="global-nav-plus">
- {openProjectOnboarding => (
- <GlobalNavPlus
- appState={appState}
- currentUser={currentUser}
- openProjectOnboarding={openProjectOnboarding}
- />
- )}
- </OnboardingContext.Consumer>
+ <GlobalNavPlus appState={appState} currentUser={currentUser} />
)}
<GlobalNavUserContainer appState={appState} currentUser={currentUser} />
</ul>
import { isSonarCloud } from '../../../../helpers/system';
import { getPortfolioAdminUrl, getPortfolioUrl } from '../../../../helpers/urls';
import { hasGlobalPermission } from '../../../../helpers/users';
-import { OnboardingContextShape } from '../../OnboardingContext';
interface Props {
appState: Pick<T.AppState, 'qualifiers'>;
currentUser: T.LoggedInUser;
- openProjectOnboarding: OnboardingContextShape;
}
interface State {
handleNewProjectClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
event.preventDefault();
- this.props.openProjectOnboarding();
+ this.props.router.push('/projects/create');
};
openCreatePortfolioForm = () => {
(fetchPrismicFeatureNews as jest.Mock).mockClear();
});
-it('should render for SonarQube', async () => {
+it('should render correctly', async () => {
(isSonarCloud as jest.Mock).mockImplementation(() => false);
const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
+ expect(wrapper).toMatchSnapshot('anonymous users');
wrapper.setProps({ currentUser: { isLoggedIn: true } });
- expect(wrapper.find('[data-test="global-nav-plus"]').exists()).toBe(true);
+ expect(wrapper).toMatchSnapshot('logged in users');
await waitAndUpdate(wrapper);
- expect(fetchPrismicRefs).not.toBeCalled();
-});
-
-it('should render for SonarCloud', () => {
- (isSonarCloud as jest.Mock).mockImplementation(() => true);
- const wrapper = shallowRender({ currentUser: { isLoggedIn: true } });
-
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.find('[data-test="global-nav-plus"]').exists()).toBe(true);
});
it('should render correctly if there are new features', async () => {
});
it('opens onboarding', () => {
- const openProjectOnboarding = jest.fn();
- const wrapper = getOverlayWrapper(getWrapper({ openProjectOnboarding }));
+ const push = jest.fn();
+ const wrapper = getOverlayWrapper(getWrapper({ router: mockRouter({ push }) }));
click(wrapper.find('.js-new-project'));
- expect(openProjectOnboarding).toBeCalled();
+ expect(push).toBeCalled();
});
it('should display create new project link when user has permission only', () => {
permissions: { global: globalPermissions || ['provisioning'] }
} as T.LoggedInUser
}
- openProjectOnboarding={jest.fn()}
router={mockRouter()}
{...props}
/>
}
}
/>
- <ContextConsumer
- data-test="global-nav-plus"
- >
- <Component />
- </ContextConsumer>
+ <GlobalNavPlus
+ appState={
+ Object {
+ "canAdmin": false,
+ "globalPages": Array [],
+ "organizationsEnabled": false,
+ "qualifiers": Array [],
+ }
+ }
+ currentUser={
+ Object {
+ "isLoggedIn": true,
+ }
+ }
+ />
<Connect(withRouter(GlobalNavUser))
appState={
Object {
</NavBar>
`;
-exports[`should render for SonarCloud 1`] = `
+exports[`should render correctly: anonymous users 1`] = `
<NavBar
className="navbar-global"
height={48}
id="global-navigation"
>
- <SonarCloudNavBranding />
+ <Connect(GlobalNavBranding) />
<GlobalNavMenu
accessToken="token"
appState={
}
currentUser={
Object {
- "isLoggedIn": true,
+ "isLoggedIn": false,
}
}
location={
<ul
className="global-navbar-menu global-navbar-menu-right"
>
- <GlobalNavExplore
- location={
- Object {
- "pathname": "",
- }
- }
- />
<EmbedDocsPopupHelper />
<withRouter(Search)
appState={
}
currentUser={
Object {
- "isLoggedIn": true,
+ "isLoggedIn": false,
}
}
/>
- <ContextConsumer
- data-test="global-nav-plus"
- >
- <Component />
- </ContextConsumer>
<Connect(withRouter(GlobalNavUser))
appState={
Object {
}
currentUser={
Object {
- "isLoggedIn": true,
+ "isLoggedIn": false,
}
}
/>
</NavBar>
`;
-exports[`should render for SonarQube 1`] = `
+exports[`should render correctly: logged in users 1`] = `
<NavBar
className="navbar-global"
height={48}
}
currentUser={
Object {
- "isLoggedIn": false,
+ "isLoggedIn": true,
}
}
location={
}
currentUser={
Object {
- "isLoggedIn": false,
+ "isLoggedIn": true,
+ }
+ }
+ />
+ <GlobalNavPlus
+ appState={
+ Object {
+ "canAdmin": false,
+ "globalPages": Array [],
+ "organizationsEnabled": false,
+ "qualifiers": Array [],
+ }
+ }
+ currentUser={
+ Object {
+ "isLoggedIn": true,
}
}
/>
}
currentUser={
Object {
- "isLoggedIn": false,
+ "isLoggedIn": true,
}
}
/>
import * as React from 'react';
import { Button } from 'sonar-ui-common/components/controls/buttons';
import OnboardingAddMembersIcon from 'sonar-ui-common/components/icons/OnboardingAddMembersIcon';
-import OnboardingProjectIcon from 'sonar-ui-common/components/icons/OnboardingProjectIcon';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { OnboardingContextShape } from '../../../app/components/OnboardingContext';
import { Router, withRouter } from '../../../components/hoc/withRouter';
import '../../tutorials/styles.css';
import './OrganizationEmpty.css';
interface Props {
- openProjectOnboarding: OnboardingContextShape;
organization: T.Organization;
router: Pick<Router, 'push'>;
}
export class OrganizationEmpty extends React.PureComponent<Props> {
- handleNewProjectClick = () => {
- this.props.openProjectOnboarding(this.props.organization);
- };
-
handleAddMembersClick = () => {
const { organization } = this.props;
this.props.router.push(`/organizations/${organization.key}/members`);
<div className="organization-empty">
<h3 className="text-center">{translate('onboarding.create_organization.ready')}</h3>
<div className="display-flex-space-around huge-spacer-top">
- <Button className="button-huge" onClick={this.handleNewProjectClick}>
- <OnboardingProjectIcon className="big-spacer-bottom" />
- <p className="medium spacer-top">{translate('provisioning.analyze_new_project')}</p>
- </Button>
{!memberSyncActivated && (
<Button className="button-huge" onClick={this.handleAddMembersClick}>
<OnboardingAddMembersIcon />
expect(shallowRender()).toMatchSnapshot();
});
-it('should create new project', () => {
- const openProjectOnboarding = jest.fn();
- const wrapper = shallowRender({ openProjectOnboarding });
-
- click(wrapper.find('Button').first());
- expect(openProjectOnboarding).toBeCalledWith({ key: 'foo', name: 'Foo' });
-});
-
it('should add members', () => {
const push = jest.fn();
const wrapper = shallowRender({ router: mockRouter({ push }) });
function shallowRender(props: Partial<OrganizationEmpty['props']> = {}) {
return shallow(
- <OrganizationEmpty
- openProjectOnboarding={jest.fn()}
- organization={organization}
- router={mockRouter()}
- {...props}
- />
+ <OrganizationEmpty organization={organization} router={mockRouter()} {...props} />
);
}
</h3>
<div
className="display-flex-space-around huge-spacer-top"
- >
- <Button
- className="button-huge"
- onClick={[Function]}
- >
- <OnboardingProjectIcon
- className="big-spacer-bottom"
- />
- <p
- className="medium spacer-top"
- >
- provisioning.analyze_new_project
- </p>
- </Button>
- </div>
+ />
</div>
`;
<div
className="display-flex-space-around huge-spacer-top"
>
- <Button
- className="button-huge"
- onClick={[Function]}
- >
- <OnboardingProjectIcon
- className="big-spacer-bottom"
- />
- <p
- className="medium spacer-top"
- >
- provisioning.analyze_new_project
- </p>
- </Button>
<Button
className="button-huge"
onClick={[Function]}
handleFavorite={this.handleFavorite}
isFavorite={this.props.isFavorite}
isFiltered={hasFilterParams(this.state.query)}
- organization={this.props.organization}
projects={this.state.projects}
query={this.state.query}
/>
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { WithRouterProps } from 'react-router';
import { Button } from 'sonar-ui-common/components/controls/buttons';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { OnboardingContextShape } from '../../../app/components/OnboardingContext';
-import { isSonarCloud } from '../../../helpers/system';
+import { withRouter } from '../../../components/hoc/withRouter';
import { hasGlobalPermission, isLoggedIn } from '../../../helpers/users';
-interface Props {
+export interface EmptyInstanceProps {
currentUser: T.CurrentUser;
- openProjectOnboarding: OnboardingContextShape;
- organization?: T.Organization;
+ router: WithRouterProps['router'];
}
-export default class EmptyInstance extends React.PureComponent<Props> {
- analyzeNewProject = () => {
- this.props.openProjectOnboarding(this.props.organization);
- };
+export function EmptyInstance(props: EmptyInstanceProps) {
+ const { currentUser, router } = props;
+ const showNewProjectButton =
+ isLoggedIn(currentUser) && hasGlobalPermission(currentUser, 'provisioning');
- render() {
- const { currentUser, organization } = this.props;
- const showNewProjectButton = isSonarCloud()
- ? organization && organization.actions && organization.actions.provision
- : isLoggedIn(currentUser) && hasGlobalPermission(currentUser, 'provisioning');
-
- return (
- <div className="projects-empty-list">
- <h3>
- {showNewProjectButton
- ? translate('projects.no_projects.empty_instance.new_project')
- : translate('projects.no_projects.empty_instance')}
- </h3>
- {showNewProjectButton && (
- <div>
- <p className="big-spacer-top">
- {translate('projects.no_projects.empty_instance.how_to_add_projects')}
- </p>
- <p className="big-spacer-top">
- <Button onClick={this.analyzeNewProject}>
- {translate('my_account.create_new.TRK')}
- </Button>
- </p>
- </div>
- )}
- </div>
- );
- }
+ return (
+ <div className="projects-empty-list">
+ <h3>
+ {showNewProjectButton
+ ? translate('projects.no_projects.empty_instance.new_project')
+ : translate('projects.no_projects.empty_instance')}
+ </h3>
+ {showNewProjectButton && (
+ <div>
+ <p className="big-spacer-top">
+ {translate('projects.no_projects.empty_instance.how_to_add_projects')}
+ </p>
+ <p className="big-spacer-top">
+ <Button
+ onClick={() => {
+ router.push('/projects/create');
+ }}>
+ {translate('my_account.create_new.TRK')}
+ </Button>
+ </p>
+ </div>
+ )}
+ </div>
+ );
}
+
+export default withRouter(EmptyInstance);
* 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 { connect } from 'react-redux';
import { Link } from 'react-router';
-import { Button } from 'sonar-ui-common/components/controls/buttons';
-import Dropdown from 'sonar-ui-common/components/controls/Dropdown';
-import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { OnboardingContextShape } from '../../../app/components/OnboardingContext';
-import OrganizationListItem from '../../../components/ui/OrganizationListItem';
-import { isSonarCloud } from '../../../helpers/system';
-import { getMyOrganizations, Store } from '../../../store/rootReducer';
-interface OwnProps {
- openProjectOnboarding: OnboardingContextShape;
-}
-
-interface StateProps {
- organizations: T.Organization[];
-}
-
-export function NoFavoriteProjects(props: StateProps & OwnProps) {
+export default function NoFavoriteProjects() {
return (
<div className="projects-empty-list">
<h3>{translate('projects.no_favorite_projects')}</h3>
- {isSonarCloud() ? (
- <div className="spacer-top">
- <p>{translate('projects.no_favorite_projects.how_to_add_projects')}</p>
- <div className="huge-spacer-top">
- <Button onClick={props.openProjectOnboarding}>
- {translate('provisioning.analyze_new_project')}
- </Button>
- {props.organizations.length > 0 && (
- <Dropdown
- className="display-inline-block big-spacer-left"
- overlay={
- <ul className="menu">
- {sortBy(props.organizations, org => org.name.toLowerCase()).map(
- organization => (
- <OrganizationListItem key={organization.key} organization={organization} />
- )
- )}
- </ul>
- }>
- <a className="button" href="#">
- {translate('projects.no_favorite_projects.favorite_projects_from_orgs')}
- <DropdownIcon className="little-spacer-left" />
- </a>
- </Dropdown>
- )}
-
- <Link className="button big-spacer-left" to="/explore/projects">
- {translate('projects.no_favorite_projects.favorite_public_projects')}
- </Link>
- </div>
- </div>
- ) : (
- <div>
- <p className="big-spacer-top">{translate('projects.no_favorite_projects.engagement')}</p>
- <p className="big-spacer-top">
- <Link className="button" to="/projects/all">
- {translate('projects.explore_projects')}
- </Link>
- </p>
- </div>
- )}
+ <div>
+ <p className="big-spacer-top">{translate('projects.no_favorite_projects.engagement')}</p>
+ <p className="big-spacer-top">
+ <Link className="button" to="/projects/all">
+ {translate('projects.explore_projects')}
+ </Link>
+ </p>
+ </div>
</div>
);
}
-
-const mapStateToProps = (state: Store): StateProps => ({
- organizations: getMyOrganizations(state)
-});
-
-export default connect(mapStateToProps)(NoFavoriteProjects);
import { Project } from '../types';
import { formatDuration } from '../utils';
import ProjectCardLeakMeasures from './ProjectCardLeakMeasures';
-import ProjectCardOrganizationContainer from './ProjectCardOrganizationContainer';
import ProjectCardOverallMeasures from './ProjectCardOverallMeasures';
import ProjectCardQualityGate from './ProjectCardQualityGate';
currentUser: T.CurrentUser;
handleFavorite: (component: string, isFavorite: boolean) => void;
height: number;
- organization: T.Organization | undefined;
project: Project;
type?: string;
}
}
function renderHeader(props: Props) {
- const { organization, project } = props;
+ const { project } = props;
const hasTags = project.tags.length > 0;
return (
<div className="project-card-header">
/>
)}
<h2 className="project-card-name">
- {!organization && <ProjectCardOrganizationContainer organization={project.organization} />}
<Link to={getProjectUrl(project.key)}>{project.name}</Link>
</h2>
{project.analysisDate && <ProjectCardQualityGate status={project.measures['alert_status']} />}
<div className="project-card-header-right">
<PrivacyBadgeContainer
className="spacer-left"
- organization={organization || project.organization}
qualifier={project.qualifier}
- tooltipProps={{ projectKey: project.key }}
visibility={project.visibility}
/>
import { List, ListRowProps } from 'react-virtualized/dist/commonjs/List';
import { WindowScroller } from 'react-virtualized/dist/commonjs/WindowScroller';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { OnboardingContext } from '../../../app/components/OnboardingContext';
import EmptySearch from '../../../components/common/EmptySearch';
import { Query } from '../query';
import { Project } from '../types';
handleFavorite: (component: string, isFavorite: boolean) => void;
isFavorite: boolean;
isFiltered: boolean;
- organization: T.Organization | undefined;
projects: Project[];
query: Query;
}
};
renderNoProjects() {
- const { currentUser, isFavorite, isFiltered, organization, query } = this.props;
+ const { currentUser, isFavorite, isFiltered, query } = this.props;
if (isFiltered) {
return isFavorite ? <EmptyFavoriteSearch query={query} /> : <EmptySearch />;
}
- return isFavorite ? (
- <OnboardingContext.Consumer>
- {openProjectOnboarding => (
- <NoFavoriteProjects openProjectOnboarding={openProjectOnboarding} />
- )}
- </OnboardingContext.Consumer>
- ) : (
- <OnboardingContext.Consumer>
- {openProjectOnboarding => (
- <EmptyInstance
- currentUser={currentUser}
- openProjectOnboarding={openProjectOnboarding}
- organization={organization}
- />
- )}
- </OnboardingContext.Consumer>
- );
+ return isFavorite ? <NoFavoriteProjects /> : <EmptyInstance currentUser={currentUser} />;
}
renderRow = ({ index, key, style }: ListRowProps) => {
handleFavorite={this.props.handleFavorite}
height={height}
key={project.key}
- organization={this.props.organization}
project={project}
type={this.props.cardType}
/>
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { isSonarCloud } from '../../../../helpers/system';
import EmptyInstance from '../EmptyInstance';
-jest.mock('../../../../helpers/system', () => ({
- isSonarCloud: jest.fn()
-}));
-
it('renders correctly for SQ', () => {
- (isSonarCloud as jest.Mock<any>).mockReturnValue(false);
- expect(
- shallow(
- <EmptyInstance
- currentUser={{ isLoggedIn: false }}
- openProjectOnboarding={jest.fn()}
- organization={undefined}
- />
- )
- ).toMatchSnapshot();
+ expect(shallow(<EmptyInstance currentUser={{ isLoggedIn: false }} />)).toMatchSnapshot();
expect(
shallow(
<EmptyInstance
currentUser={{ isLoggedIn: true, permissions: { global: ['provisioning'] } }}
- openProjectOnboarding={jest.fn()}
- organization={undefined}
- />
- )
- ).toMatchSnapshot();
-});
-
-it('renders correctly for SC', () => {
- (isSonarCloud as jest.Mock<any>).mockReturnValue(true);
- expect(
- shallow(
- <EmptyInstance
- currentUser={{ isLoggedIn: false }}
- openProjectOnboarding={jest.fn()}
- organization={{ key: 'foo', name: 'Foo' }}
- />
- )
- ).toMatchSnapshot();
- expect(
- shallow(
- <EmptyInstance
- currentUser={{ isLoggedIn: false }}
- openProjectOnboarding={jest.fn()}
- organization={{ actions: { provision: true }, key: 'foo', name: 'Foo' }}
/>
)
).toMatchSnapshot();
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { isSonarCloud } from '../../../../helpers/system';
-import { NoFavoriteProjects } from '../NoFavoriteProjects';
-
-jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
+import NoFavoriteProjects from '../NoFavoriteProjects';
it('renders', () => {
- (isSonarCloud as jest.Mock).mockImplementation(() => false);
- expect(
- shallow(<NoFavoriteProjects openProjectOnboarding={jest.fn()} organizations={[]} />)
- ).toMatchSnapshot();
-});
-
-it('renders for SonarCloud without organizations', () => {
- (isSonarCloud as jest.Mock).mockImplementation(() => true);
- expect(
- shallow(<NoFavoriteProjects openProjectOnboarding={jest.fn()} organizations={[]} />)
- ).toMatchSnapshot();
-});
-
-it('renders for SonarCloud with organizations', () => {
- (isSonarCloud as jest.Mock).mockImplementation(() => true);
- const organizations: T.Organization[] = [
- { actions: { admin: true }, key: 'org1', name: 'org1', projectVisibility: 'public' },
- { actions: { admin: false }, key: 'org2', name: 'org2', projectVisibility: 'public' }
- ];
- expect(
- shallow(<NoFavoriteProjects openProjectOnboarding={jest.fn()} organizations={organizations} />)
- ).toMatchSnapshot();
+ expect(shallow(<NoFavoriteProjects />)).toMatchSnapshot();
});
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import PrivacyBadgeContainer from '../../../../components/common/PrivacyBadgeContainer';
import { mockCurrentUser, mockLoggedInUser } from '../../../../helpers/testMocks';
import { ComponentQualifier } from '../../../../types/component';
import { Project } from '../../types';
const project: Project = { ...PROJECT, visibility: 'private' };
expect(
shallowRender(project)
- .find('Connect(PrivacyBadge)')
+ .find(PrivacyBadgeContainer)
.exists()
).toBe(true);
});
function shallowRender(project: Project, user: T.CurrentUser = USER_LOGGED_OUT) {
return shallow(
- <ProjectCard
- currentUser={user}
- handleFavorite={jest.fn()}
- height={100}
- organization={undefined}
- project={project}
- />
+ <ProjectCard currentUser={user} handleFavorite={jest.fn()} height={100} project={project} />
);
}
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`renders correctly for SC 1`] = `
-<div
- className="projects-empty-list"
->
- <h3>
- projects.no_projects.empty_instance
- </h3>
-</div>
-`;
-
-exports[`renders correctly for SC 2`] = `
-<div
- className="projects-empty-list"
->
- <h3>
- projects.no_projects.empty_instance.new_project
- </h3>
- <div>
- <p
- className="big-spacer-top"
- >
- projects.no_projects.empty_instance.how_to_add_projects
- </p>
- <p
- className="big-spacer-top"
- >
- <Button
- onClick={[Function]}
- >
- my_account.create_new.TRK
- </Button>
- </p>
- </div>
-</div>
-`;
-
exports[`renders correctly for SQ 1`] = `
-<div
- className="projects-empty-list"
->
- <h3>
- projects.no_projects.empty_instance
- </h3>
-</div>
+<EmptyInstance
+ currentUser={
+ Object {
+ "isLoggedIn": false,
+ }
+ }
+/>
`;
exports[`renders correctly for SQ 2`] = `
-<div
- className="projects-empty-list"
->
- <h3>
- projects.no_projects.empty_instance.new_project
- </h3>
- <div>
- <p
- className="big-spacer-top"
- >
- projects.no_projects.empty_instance.how_to_add_projects
- </p>
- <p
- className="big-spacer-top"
- >
- <Button
- onClick={[Function]}
- >
- my_account.create_new.TRK
- </Button>
- </p>
- </div>
-</div>
+<EmptyInstance
+ currentUser={
+ Object {
+ "isLoggedIn": true,
+ "permissions": Object {
+ "global": Array [
+ "provisioning",
+ ],
+ },
+ }
+ }
+/>
`;
</div>
</div>
`;
-
-exports[`renders for SonarCloud with organizations 1`] = `
-<div
- className="projects-empty-list"
->
- <h3>
- projects.no_favorite_projects
- </h3>
- <div
- className="spacer-top"
- >
- <p>
- projects.no_favorite_projects.how_to_add_projects
- </p>
- <div
- className="huge-spacer-top"
- >
- <Button
- onClick={[MockFunction]}
- >
- provisioning.analyze_new_project
- </Button>
- <Dropdown
- className="display-inline-block big-spacer-left"
- overlay={
- <ul
- className="menu"
- >
- <OrganizationListItem
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "org1",
- "name": "org1",
- "projectVisibility": "public",
- }
- }
- />
- <OrganizationListItem
- organization={
- Object {
- "actions": Object {
- "admin": false,
- },
- "key": "org2",
- "name": "org2",
- "projectVisibility": "public",
- }
- }
- />
- </ul>
- }
- >
- <a
- className="button"
- href="#"
- >
- projects.no_favorite_projects.favorite_projects_from_orgs
- <DropdownIcon
- className="little-spacer-left"
- />
- </a>
- </Dropdown>
- <Link
- className="button big-spacer-left"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/explore/projects"
- >
- projects.no_favorite_projects.favorite_public_projects
- </Link>
- </div>
- </div>
-</div>
-`;
-
-exports[`renders for SonarCloud without organizations 1`] = `
-<div
- className="projects-empty-list"
->
- <h3>
- projects.no_favorite_projects
- </h3>
- <div
- className="spacer-top"
- >
- <p>
- projects.no_favorite_projects.how_to_add_projects
- </p>
- <div
- className="huge-spacer-top"
- >
- <Button
- onClick={[MockFunction]}
- >
- provisioning.analyze_new_project
- </Button>
- <Link
- className="button big-spacer-left"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/explore/projects"
- >
- projects.no_favorite_projects.favorite_public_projects
- </Link>
- </div>
- </div>
-</div>
-`;
<h2
className="project-card-name"
>
- <Connect(ProjectCardOrganization)
- organization={
- Object {
- "key": "org",
- "name": "org",
- }
- }
- />
<Link
onlyActiveOnIndex={false}
style={Object {}}
<div
className="project-card-header-right"
>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
className="spacer-left"
- organization={
- Object {
- "key": "org",
- "name": "org",
- }
- }
qualifier="APP"
- tooltipProps={
- Object {
- "projectKey": "foo",
- }
- }
visibility="public"
/>
</div>
<h2
className="project-card-name"
>
- <Connect(ProjectCardOrganization)
- organization={
- Object {
- "key": "org",
- "name": "org",
- }
- }
- />
<Link
onlyActiveOnIndex={false}
style={Object {}}
<div
className="project-card-header-right"
>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
className="spacer-left"
- organization={
- Object {
- "key": "org",
- "name": "org",
- }
- }
qualifier="APP"
- tooltipProps={
- Object {
- "projectKey": "foo",
- }
- }
visibility="public"
/>
</div>
<h2
className="project-card-name"
>
- <Connect(ProjectCardOrganization)
- organization={
- Object {
- "key": "org",
- "name": "org",
- }
- }
- />
<Link
onlyActiveOnIndex={false}
style={Object {}}
<div
className="project-card-header-right"
>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
className="spacer-left"
- organization={
- Object {
- "key": "org",
- "name": "org",
- }
- }
qualifier="TRK"
- tooltipProps={
- Object {
- "projectKey": "foo",
- }
- }
visibility="public"
/>
</div>
<h2
className="project-card-name"
>
- <Connect(ProjectCardOrganization)
- organization={
- Object {
- "key": "org",
- "name": "org",
- }
- }
- />
<Link
onlyActiveOnIndex={false}
style={Object {}}
<div
className="project-card-header-right"
>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
className="spacer-left"
- organization={
- Object {
- "key": "org",
- "name": "org",
- }
- }
qualifier="TRK"
- tooltipProps={
- Object {
- "projectKey": "foo",
- }
- }
visibility="public"
/>
</div>
<h2
className="project-card-name"
>
- <Connect(ProjectCardOrganization)
- organization={
- Object {
- "key": "org",
- "name": "org",
- }
- }
- />
<Link
onlyActiveOnIndex={false}
style={Object {}}
<div
className="project-card-header-right"
>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
className="spacer-left"
- organization={
- Object {
- "key": "org",
- "name": "org",
- }
- }
qualifier="TRK"
- tooltipProps={
- Object {
- "projectKey": "foo",
- }
- }
visibility="public"
/>
</div>
<div
className="projects-list"
>
- <ContextConsumer>
- <Component />
- </ContextConsumer>
+ <withRouter(EmptyInstance)
+ currentUser={
+ Object {
+ "isLoggedIn": true,
+ }
+ }
+ />
</div>
`;
<div
className="projects-list"
>
- <ContextConsumer>
- <Component />
- </ContextConsumer>
+ <NoFavoriteProjects />
</div>
`;
</td>
<td className="thin nowrap">
- <PrivacyBadgeContainer
- organization={organization}
- qualifier={project.qualifier}
- tooltipProps={{ projectKey: project.key }}
- visibility={project.visibility}
- />
+ <PrivacyBadgeContainer qualifier={project.qualifier} visibility={project.visibility} />
</td>
<td className="nowrap hide-overflow project-row-text-cell">
<td
className="thin nowrap"
>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
qualifier="TRK"
- tooltipProps={
- Object {
- "projectKey": "project",
- }
- }
visibility="private"
/>
</td>
<td
className="thin nowrap"
>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
qualifier="VW"
- tooltipProps={
- Object {
- "projectKey": "project",
- }
- }
visibility="private"
/>
</td>
<td
className="thin nowrap"
>
- <Connect(PrivacyBadge)
+ <PrivacyBadgeContainer
qualifier="TRK"
- tooltipProps={
- Object {
- "projectKey": "project",
- }
- }
visibility="private"
/>
</td>
*/
import * as classNames from 'classnames';
import * as React from 'react';
-import { connect } from 'react-redux';
import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
-import VisibleIcon from 'sonar-ui-common/components/icons/VisibleIcon';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { colors } from '../../app/theme';
-import { isCurrentUserMemberOf, isPaidOrganization } from '../../helpers/organizations';
-import { isSonarCloud } from '../../helpers/system';
-import {
- getCurrentUser,
- getMyOrganizations,
- getOrganizationByKey,
- Store
-} from '../../store/rootReducer';
-import DocTooltip from '../docs/DocTooltip';
-interface StateToProps {
- currentUser: T.CurrentUser;
- organization?: T.Organization;
- userOrganizations: T.Organization[];
-}
-
-interface OwnProps {
+interface PrivacyBadgeContainerProps {
className?: string;
- organization: T.Organization | string | undefined;
qualifier: string;
- tooltipProps?: { projectKey: string };
visibility: T.Visibility;
}
-interface Props extends OwnProps, StateToProps {
- organization: T.Organization | undefined;
-}
-
-export function PrivacyBadge({
+export default function PrivacyBadgeContainer({
className,
- currentUser,
- organization,
qualifier,
- userOrganizations,
- tooltipProps,
visibility
-}: Props) {
- const onSonarCloud = isSonarCloud();
- if (
- visibility !== 'private' &&
- (!onSonarCloud || !isCurrentUserMemberOf(currentUser, organization, userOrganizations))
- ) {
+}: PrivacyBadgeContainerProps) {
+ if (visibility !== 'private') {
return null;
}
- let icon = null;
- if (isPaidOrganization(organization) && visibility === 'public') {
- icon = <VisibleIcon className="little-spacer-right" fill={colors.blue} />;
- }
-
- const badge = (
- <div
- className={classNames('badge', className, {
- 'badge-info': Boolean(icon)
- })}>
- {icon}
- {translate('visibility', visibility)}
- </div>
- );
-
- if (onSonarCloud && organization) {
- return (
- <DocTooltip
- className={className}
- doc={getDoc(visibility, icon, organization)}
- overlayProps={{ ...tooltipProps, organization: organization.key }}>
- {badge}
- </DocTooltip>
- );
- }
-
return (
<Tooltip overlay={translate('visibility', visibility, 'description', qualifier)}>
- {badge}
+ <div className={classNames('badge', className)}>{translate('visibility', visibility)}</div>
</Tooltip>
);
}
-
-const mapStateToProps = (state: Store, { organization }: OwnProps) => {
- if (typeof organization === 'string') {
- organization = getOrganizationByKey(state, organization);
- }
- return {
- currentUser: getCurrentUser(state),
- organization,
- userOrganizations: getMyOrganizations(state)
- };
-};
-
-export default connect(mapStateToProps)(PrivacyBadge);
-
-function getDoc(visibility: T.Visibility, icon: JSX.Element | null, organization: T.Organization) {
- let doc;
- const { actions = {} } = organization;
- if (visibility === 'private') {
- doc = import(/* webpackMode: "eager" */ 'Docs/tooltips/project/visibility-private.md');
- } else if (icon) {
- if (actions.admin) {
- doc = import(
- /* webpackMode: "eager" */ 'Docs/tooltips/project/visibility-public-paid-org-admin.md'
- );
- } else {
- doc = import(
- /* webpackMode: "eager" */ 'Docs/tooltips/project/visibility-public-paid-org.md'
- );
- }
- } else if (actions.admin) {
- doc = import(/* webpackMode: "eager" */ 'Docs/tooltips/project/visibility-public-admin.md');
- } else {
- doc = import(/* webpackMode: "eager" */ 'Docs/tooltips/project/visibility-public.md');
- }
- return doc;
-}
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { isSonarCloud } from '../../../helpers/system';
-import { PrivacyBadge } from '../PrivacyBadgeContainer';
-
-jest.mock('../../../helpers/system', () => ({ isSonarCloud: jest.fn().mockReturnValue(false) }));
-
-const organization: T.Organization = { key: 'foo', name: 'Foo' };
-const loggedInUser = { isLoggedIn: true, login: 'luke', name: 'Skywalker' };
+import { ComponentQualifier } from '../../../types/component';
+import PrivacyBadge from '../PrivacyBadgeContainer';
it('renders', () => {
expect(getWrapper()).toMatchSnapshot();
expect(getWrapper({ visibility: 'public' })).toMatchSnapshot();
});
-it('renders public', () => {
- (isSonarCloud as jest.Mock<any>).mockReturnValueOnce(true);
- expect(getWrapper({ visibility: 'public' })).toMatchSnapshot();
-});
-
-it('renders public with icon', () => {
- (isSonarCloud as jest.Mock<any>).mockReturnValueOnce(true);
- expect(
- getWrapper({
- organization: {
- ...organization,
- actions: { admin: true },
- subscription: 'PAID'
- },
- visibility: 'public'
- })
- ).toMatchSnapshot();
-});
-
function getWrapper(props = {}) {
return shallow(
- <PrivacyBadge
- currentUser={loggedInUser}
- organization={organization}
- qualifier="TRK"
- userOrganizations={[organization]}
- visibility="private"
- {...props}
- />
+ <PrivacyBadge qualifier={ComponentQualifier.Project} visibility="private" {...props} />
);
}
</div>
</Tooltip>
`;
-
-exports[`renders public 1`] = `
-<DocTooltip
- doc={Promise {}}
- overlayProps={
- Object {
- "organization": "foo",
- }
- }
->
- <div
- className="badge"
- >
- visibility.public
- </div>
-</DocTooltip>
-`;
-
-exports[`renders public with icon 1`] = `
-<DocTooltip
- doc={Promise {}}
- overlayProps={
- Object {
- "organization": "foo",
- }
- }
->
- <div
- className="badge badge-info"
- >
- <VisibleIcon
- className="little-spacer-right"
- fill="#4b9fd5"
- />
- visibility.public
- </div>
-</DocTooltip>
-`;