+++ /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 * as classNames from 'classnames';
-import { identity } from 'lodash';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { Link } from 'react-router';
-import Checkbox from 'sonar-ui-common/components/controls/Checkbox';
-import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
-import CheckIcon from 'sonar-ui-common/components/icons/CheckIcon';
-import LockIcon from 'sonar-ui-common/components/icons/LockIcon';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
-import { colors } from '../../../app/theme';
-import { getProjectUrl } from '../../../helpers/urls';
-
-interface Props {
- disabled: boolean;
- highlightUpgradeBox: (highlight: boolean) => void;
- identityProvider: T.IdentityProvider;
- repository: T.AlmRepository;
- selected: boolean;
- toggleRepository: (repository: T.AlmRepository) => void;
-}
-
-export default class AlmRepositoryItem extends React.PureComponent<Props> {
- handleMouseEnter = () => {
- this.props.highlightUpgradeBox(true);
- };
-
- handleMouseLeave = () => {
- this.props.highlightUpgradeBox(false);
- };
-
- handleToggle = () => {
- if (!this.props.disabled && !this.props.repository.linkedProjectKey) {
- this.props.toggleRepository(this.props.repository);
- }
- };
-
- render() {
- const { disabled, identityProvider, repository, selected } = this.props;
- const alreadyImported = Boolean(repository.linkedProjectKey);
- return (
- <Tooltip
- overlay={
- disabled
- ? translate('onboarding.create_project.subscribe_to_import_private_repositories')
- : undefined
- }>
- <li>
- <div
- className={classNames('create-project-repository', {
- disabled,
- imported: alreadyImported,
- selected
- })}
- onClick={this.handleToggle}
- onMouseEnter={disabled ? this.handleMouseEnter : undefined}
- onMouseLeave={disabled ? this.handleMouseLeave : undefined}
- role="listitem">
- <div className="flex-1 display-flex-center">
- {disabled ? (
- <LockIcon fill={colors.disableGrayText} />
- ) : (
- <Checkbox
- checked={selected || alreadyImported}
- disabled={disabled || alreadyImported}
- onCheck={identity}
- />
- )}
- <img
- alt={identityProvider.name}
- className={classNames('spacer-left', { 'icon-half-transparent': disabled })}
- height={14}
- src={`${getBaseUrl()}/images/sonarcloud/${identityProvider.key}.svg`}
- width={14}
- />
- <span className="spacer-left">{this.props.repository.label}</span>
- {repository.private && (
- <div className="badge spacer-left">{translate('visibility.private')}</div>
- )}
- </div>
-
- {repository.linkedProjectKey && (
- <span>
- <CheckIcon className="little-spacer-right" fill={colors.green} />
- <FormattedMessage
- defaultMessage={translate('onboarding.create_project.repository_imported')}
- id="onboarding.create_project.repository_imported"
- values={{
- link: (
- <Link to={getProjectUrl(repository.linkedProjectKey)}>
- {translate('onboarding.create_project.see_project')}
- </Link>
- )
- }}
- />
- </span>
- )}
- </div>
- </li>
- </Tooltip>
- );
- }
-}
+++ /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 * as React from 'react';
-import IdentityProviderLink from 'sonar-ui-common/components/controls/IdentityProviderLink';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { save } from 'sonar-ui-common/helpers/storage';
-import {
- ORGANIZATION_IMPORT_BINDING_IN_PROGRESS_TIMESTAMP,
- ORGANIZATION_IMPORT_REDIRECT_TO_PROJECT_TIMESTAMP
-} from '../organization/utils';
-import OrganizationInput from './OrganizationInput';
-import RemoteRepositories from './RemoteRepositories';
-
-interface Props {
- almApplication: T.AlmApplication;
- boundOrganizations: T.Organization[];
- onOrganizationUpgrade: () => void;
- onProjectCreate: (projectKeys: string[], organization: string) => void;
- organization?: string;
-}
-
-interface State {
- selectedOrganization: string;
-}
-
-export default class AutoProjectCreate extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- this.state = { selectedOrganization: this.getInitialSelectedOrganization(props) };
- }
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- getInitialSelectedOrganization(props: Props) {
- if (props.organization) {
- return props.organization;
- } else if (props.boundOrganizations.length === 1) {
- return props.boundOrganizations[0].key;
- } else {
- return '';
- }
- }
-
- handleInstallAppClick = () => {
- save(ORGANIZATION_IMPORT_BINDING_IN_PROGRESS_TIMESTAMP, Date.now().toString(10));
- save(ORGANIZATION_IMPORT_REDIRECT_TO_PROJECT_TIMESTAMP, Date.now().toString(10));
- };
-
- handleOrganizationSelect = ({ key }: T.Organization) => {
- this.setState({ selectedOrganization: key });
- };
-
- render() {
- const { almApplication, boundOrganizations, onProjectCreate } = this.props;
-
- if (boundOrganizations.length === 0) {
- return (
- <>
- <p className="spacer-bottom">
- {translate('onboarding.create_project.install_app_description', almApplication.key)}
- </p>
- <IdentityProviderLink
- backgroundColor={almApplication.backgroundColor}
- className="display-inline-block"
- iconPath={almApplication.iconPath}
- name={almApplication.name}
- onClick={this.handleInstallAppClick}
- small={true}
- url={almApplication.installationUrl}>
- {translate(
- 'onboarding.import_organization.choose_organization_button',
- almApplication.key
- )}
- </IdentityProviderLink>
- </>
- );
- }
-
- const { selectedOrganization } = this.state;
- const organization = boundOrganizations.find(o => o.key === selectedOrganization);
-
- return (
- <>
- <OrganizationInput
- autoImport={true}
- onChange={this.handleOrganizationSelect}
- organization={selectedOrganization}
- organizations={this.props.boundOrganizations}
- />
- {organization && (
- <RemoteRepositories
- almApplication={almApplication}
- onOrganizationUpgrade={this.props.onOrganizationUpgrade}
- onProjectCreate={onProjectCreate}
- organization={organization}
- />
- )}
- </>
- );
- }
-}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { Helmet } from 'react-helmet-async';
import { WithRouterProps } from 'react-router';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers/pages';
+import { getAlmSettings } from '../../../api/alm-settings';
import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget';
-import { isSonarCloud } from '../../../helpers/system';
-import CreateProjectPageSonarCloud from './CreateProjectPageSonarCloud';
-import CreateProjectPageSonarQube from './CreateProjectPageSonarQube';
-
-export default function CreateProjectPage(props: WithRouterProps) {
- return (
- <>
- <A11ySkipTarget anchor="create_project_main" />
- {isSonarCloud() ? (
- <CreateProjectPageSonarCloud {...props} />
- ) : (
- <CreateProjectPageSonarQube {...props} />
- )}
- </>
- );
+import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn';
+import { withAppState } from '../../../components/hoc/withAppState';
+import { getProjectUrl } from '../../../helpers/urls';
+import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings';
+import BitbucketProjectCreate from './BitbucketProjectCreate';
+import CreateProjectModeSelection from './CreateProjectModeSelection';
+import ManualProjectCreate from './ManualProjectCreate';
+import './style.css';
+import { CreateProjectModes } from './types';
+
+interface Props extends Pick<WithRouterProps, 'router' | 'location'> {
+ appState: Pick<T.AppState, 'branchesEnabled'>;
+ currentUser: T.LoggedInUser;
+}
+
+interface State {
+ bitbucketSettings: AlmSettingsInstance[];
+ loading: boolean;
+}
+
+export class CreateProjectPage extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = { bitbucketSettings: [], loading: false };
+
+ componentDidMount() {
+ const {
+ appState: { branchesEnabled },
+ location
+ } = this.props;
+ this.mounted = true;
+ if (branchesEnabled) {
+ this.fetchAlmBindings();
+ }
+
+ if (location.query?.mode || !branchesEnabled) {
+ addWhitePageClass();
+ }
+ }
+
+ componentDidUpdate(prevProps: Props) {
+ if (this.props.location.query?.mode && !prevProps.location.query?.mode) {
+ addWhitePageClass();
+ } else if (!this.props.location.query?.mode && prevProps.location.query?.mode) {
+ removeWhitePageClass();
+ }
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ removeWhitePageClass();
+ }
+
+ fetchAlmBindings = () => {
+ this.setState({ loading: true });
+ getAlmSettings()
+ .then(almSettings => {
+ if (this.mounted) {
+ this.setState({
+ bitbucketSettings: almSettings.filter(s => s.alm === AlmKeys.Bitbucket),
+ loading: false
+ });
+ }
+ })
+ .catch(() => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ });
+ };
+
+ handleProjectCreate = (projectKeys: string[]) => {
+ if (projectKeys.length === 1) {
+ this.props.router.push(getProjectUrl(projectKeys[0]));
+ }
+ };
+
+ handleModeSelect = (mode: CreateProjectModes) => {
+ const { router, location } = this.props;
+ router.push({
+ pathname: location.pathname,
+ query: { mode }
+ });
+ };
+
+ render() {
+ const {
+ appState: { branchesEnabled },
+ currentUser,
+ location
+ } = this.props;
+ const { bitbucketSettings, loading } = this.state;
+
+ const mode: CreateProjectModes | undefined = location.query?.mode;
+ const showManualForm = !branchesEnabled || mode === CreateProjectModes.Manual;
+ const showBBSForm = branchesEnabled && mode === CreateProjectModes.BitbucketServer;
+
+ return (
+ <>
+ <Helmet title={translate('my_account.create_new.TRK')} titleTemplate="%s" />
+ <A11ySkipTarget anchor="create_project_main" />
+ <div className="page page-limited huge-spacer-bottom position-relative" id="create-project">
+ {!showBBSForm && !showManualForm && (
+ <CreateProjectModeSelection
+ bbsBindingCount={bitbucketSettings.length}
+ loadingBindings={loading}
+ onSelectMode={this.handleModeSelect}
+ />
+ )}
+
+ {showManualForm && (
+ <ManualProjectCreate
+ branchesEnabled={branchesEnabled}
+ currentUser={currentUser}
+ onProjectCreate={this.handleProjectCreate}
+ />
+ )}
+
+ {showBBSForm && (
+ <BitbucketProjectCreate
+ bitbucketSettings={bitbucketSettings}
+ loadingBindings={loading}
+ location={location}
+ onProjectCreate={this.handleProjectCreate}
+ />
+ )}
+ </div>
+ </>
+ );
+ }
}
+
+export default whenLoggedIn(withAppState(CreateProjectPage));
+++ /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 * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import { connect } from 'react-redux';
-import { WithRouterProps } from 'react-router';
-import Tabs from 'sonar-ui-common/components/controls/Tabs';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers/pages';
-import { getAlmAppInfo } from '../../../api/alm-integration';
-import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn';
-import { withUserOrganizations } from '../../../components/hoc/withUserOrganizations';
-import { hasAdvancedALMIntegration } from '../../../helpers/almIntegrations';
-import { getOrganizationUrl, getProjectUrl } from '../../../helpers/urls';
-import { skipOnboarding } from '../../../store/users';
-import AutoProjectCreate from './AutoProjectCreate';
-import ManualProjectCreate from './ManualProjectCreate';
-import './style.css';
-
-interface Props {
- currentUser: T.LoggedInUser;
- fetchMyOrganizations: () => Promise<void>;
- skipOnboarding: () => void;
- userOrganizations: T.Organization[];
-}
-
-interface State {
- almApplication?: T.AlmApplication;
- loading: boolean;
-}
-
-type TabKeys = 'auto' | 'manual';
-
-interface LocationState {
- organization?: string;
- tab?: TabKeys;
-}
-
-export class CreateProjectPageSonarCloud extends React.PureComponent<
- Props & WithRouterProps,
- State
-> {
- mounted = false;
- state: State = { loading: true };
-
- componentDidMount() {
- this.mounted = true;
- if (hasAdvancedALMIntegration(this.props.currentUser)) {
- this.fetchAlmApplication();
- } else {
- this.setState({ loading: false });
- }
- addWhitePageClass();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- removeWhitePageClass();
- }
-
- handleProjectCreate = (projectKeys: string[], organization?: string) => {
- this.props.skipOnboarding();
- if (projectKeys.length > 1) {
- this.props.router.push({
- pathname: (organization ? getOrganizationUrl(organization) : '') + '/projects'
- });
- } else if (projectKeys.length === 1) {
- this.props.router.push(getProjectUrl(projectKeys[0]));
- }
- };
-
- fetchAlmApplication = () => {
- return getAlmAppInfo().then(
- ({ application }) => {
- if (this.mounted) {
- this.setState({ almApplication: application, loading: false });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- onTabChange = (tab: TabKeys) => {
- this.updateUrl({ tab });
- };
-
- updateUrl = (state: Partial<LocationState> = {}) => {
- this.props.router.replace({
- pathname: this.props.location.pathname,
- query: this.props.location.query,
- state: { ...(this.props.location.state || {}), ...state }
- });
- };
-
- render() {
- const { currentUser, location, userOrganizations } = this.props;
- const { almApplication, loading } = this.state;
- const state: LocationState = location.state || {};
- const header = translate('onboarding.create_project.header');
- const showManualTab = state.tab === 'manual';
-
- return (
- <>
- <Helmet title={header} titleTemplate="%s" />
- <div className="page page-limited huge-spacer-top huge-spacer-bottom">
- <header className="page-header huge-spacer-bottom">
- <h1 className="page-title huge">
- <strong>{header}</strong>
- </h1>
- </header>
- {loading ? (
- <DeferredSpinner />
- ) : (
- <>
- {almApplication && (
- <Tabs<TabKeys>
- onChange={this.onTabChange}
- selected={state.tab || 'auto'}
- tabs={[
- {
- key: 'auto',
- node: translate('onboarding.create_project.select_repositories')
- },
- { key: 'manual', node: translate('onboarding.create_project.setup_manually') }
- ]}
- />
- )}
-
- {showManualTab || !almApplication ? (
- <ManualProjectCreate
- currentUser={currentUser}
- fetchMyOrganizations={this.props.fetchMyOrganizations}
- onProjectCreate={this.handleProjectCreate}
- organization={state.organization}
- userOrganizations={userOrganizations.filter(
- ({ actions = {} }) => actions.provision
- )}
- />
- ) : (
- <AutoProjectCreate
- almApplication={almApplication}
- boundOrganizations={userOrganizations.filter(
- ({ alm, actions = {} }) => alm && actions.provision
- )}
- onOrganizationUpgrade={this.props.fetchMyOrganizations}
- onProjectCreate={this.handleProjectCreate}
- organization={state.organization}
- />
- )}
- </>
- )}
- </div>
- </>
- );
- }
-}
-
-const mapDispatchToProps = { skipOnboarding };
-
-export default whenLoggedIn(
- withUserOrganizations(connect(null, mapDispatchToProps)(CreateProjectPageSonarCloud))
-);
+++ /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 * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import { WithRouterProps } from 'react-router';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers/pages';
-import { getAlmSettings } from '../../../api/alm-settings';
-import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn';
-import { withAppState } from '../../../components/hoc/withAppState';
-import { getProjectUrl } from '../../../helpers/urls';
-import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings';
-import BitbucketProjectCreate from './BitbucketProjectCreate';
-import CreateProjectModeSelection from './CreateProjectModeSelection';
-import ManualProjectCreate from './ManualProjectCreate';
-import './style.css';
-import { CreateProjectModes } from './types';
-
-interface Props extends Pick<WithRouterProps, 'router' | 'location'> {
- appState: Pick<T.AppState, 'branchesEnabled'>;
- currentUser: T.LoggedInUser;
-}
-
-interface State {
- bitbucketSettings: AlmSettingsInstance[];
- loading: boolean;
-}
-
-export class CreateProjectPageSonarQube extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { bitbucketSettings: [], loading: false };
-
- componentDidMount() {
- const {
- appState: { branchesEnabled },
- location
- } = this.props;
- this.mounted = true;
- if (branchesEnabled) {
- this.fetchAlmBindings();
- }
-
- if (location.query?.mode || !branchesEnabled) {
- addWhitePageClass();
- }
- }
-
- componentDidUpdate(prevProps: Props) {
- if (this.props.location.query?.mode && !prevProps.location.query?.mode) {
- addWhitePageClass();
- } else if (!this.props.location.query?.mode && prevProps.location.query?.mode) {
- removeWhitePageClass();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- removeWhitePageClass();
- }
-
- fetchAlmBindings = () => {
- this.setState({ loading: true });
- getAlmSettings()
- .then(almSettings => {
- if (this.mounted) {
- this.setState({
- bitbucketSettings: almSettings.filter(s => s.alm === AlmKeys.Bitbucket),
- loading: false
- });
- }
- })
- .catch(() => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- });
- };
-
- handleProjectCreate = (projectKeys: string[]) => {
- if (projectKeys.length === 1) {
- this.props.router.push(getProjectUrl(projectKeys[0]));
- }
- };
-
- handleModeSelect = (mode: CreateProjectModes) => {
- const { router, location } = this.props;
- router.push({
- pathname: location.pathname,
- query: { mode }
- });
- };
-
- render() {
- const {
- appState: { branchesEnabled },
- currentUser,
- location
- } = this.props;
- const { bitbucketSettings, loading } = this.state;
-
- const mode: CreateProjectModes | undefined = location.query?.mode;
- const showManualForm = !branchesEnabled || mode === CreateProjectModes.Manual;
- const showBBSForm = branchesEnabled && mode === CreateProjectModes.BitbucketServer;
-
- return (
- <>
- <Helmet title={translate('my_account.create_new.TRK')} titleTemplate="%s" />
- <div className="page page-limited huge-spacer-bottom position-relative" id="create-project">
- {!showBBSForm && !showManualForm && (
- <CreateProjectModeSelection
- bbsBindingCount={bitbucketSettings.length}
- loadingBindings={loading}
- onSelectMode={this.handleModeSelect}
- />
- )}
-
- {showManualForm && (
- <ManualProjectCreate
- branchesEnabled={branchesEnabled}
- currentUser={currentUser}
- onProjectCreate={this.handleProjectCreate}
- />
- )}
-
- {showBBSForm && (
- <BitbucketProjectCreate
- bitbucketSettings={bitbucketSettings}
- loadingBindings={loading}
- location={location}
- onProjectCreate={this.handleProjectCreate}
- />
- )}
- </div>
- </>
- );
- }
-}
-
-export default whenLoggedIn(withAppState(CreateProjectPageSonarQube));
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { createProject, doesComponentExists } from '../../../api/components';
-import { isSonarCloud } from '../../../helpers/system';
-import UpgradeOrganizationBox from '../components/UpgradeOrganizationBox';
import CreateProjectPageHeader from './CreateProjectPageHeader';
import './ManualProjectCreate.css';
-import OrganizationInput from './OrganizationInput';
interface Props {
branchesEnabled?: boolean;
currentUser: T.LoggedInUser;
- fetchMyOrganizations?: () => Promise<void>;
onProjectCreate: (projectKeys: string[]) => void;
- organization?: string;
- userOrganizations?: T.Organization[];
}
interface State {
projectNameError?: string;
projectKey: string;
projectKeyError?: string;
- selectedOrganization?: T.Organization;
- selectedVisibility?: T.Visibility;
submitting: boolean;
touched: boolean;
validating: boolean;
projectKey: '',
projectName: '',
projectNameChanged: false,
- selectedOrganization: this.getInitialSelectedOrganization(props),
submitting: false,
touched: false,
validating: false
});
};
- canChoosePrivate = (selectedOrganization: T.Organization | undefined) => {
- return Boolean(selectedOrganization && selectedOrganization.subscription === 'PAID');
- };
-
canSubmit(state: State): state is ValidState {
- const {
- projectKey,
- projectKeyError,
- projectName,
- projectNameError,
- selectedOrganization
- } = state;
+ const { projectKey, projectKeyError, projectName, projectNameError } = state;
return Boolean(
projectKeyError === undefined &&
projectNameError === undefined &&
projectKey.length > 0 &&
- projectName.length > 0 &&
- (!isSonarCloud() || selectedOrganization)
+ projectName.length > 0
);
}
- getInitialSelectedOrganization = (props: Props) => {
- if (props.organization) {
- return this.getOrganization(props.organization);
- } else if (props.userOrganizations && props.userOrganizations.length === 1) {
- return props.userOrganizations[0];
- } else {
- return undefined;
- }
- };
-
- getOrganization = (organizationKey: string) => {
- return (
- this.props.userOrganizations &&
- this.props.userOrganizations.find(({ key }: T.Organization) => key === organizationKey)
- );
- };
-
handleFormSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const { state } = this;
this.setState({ submitting: true });
createProject({
project: state.projectKey,
- name: (state.projectName || state.projectKey).trim(),
- organization: state.selectedOrganization && state.selectedOrganization.key,
- visibility: this.state.selectedVisibility
+ name: (state.projectName || state.projectKey).trim()
}).then(
({ project }) => this.props.onProjectCreate([project.key]),
() => {
}
};
- handleOrganizationSelect = ({ key }: T.Organization) => {
- const selectedOrganization = this.getOrganization(key);
- let { selectedVisibility } = this.state;
-
- if (selectedVisibility === undefined) {
- selectedVisibility = this.canChoosePrivate(selectedOrganization) ? 'private' : 'public';
- }
-
- this.setState({
- selectedOrganization,
- selectedVisibility
- });
- };
-
- handleOrganizationUpgrade = () => {
- this.props.fetchMyOrganizations!().then(
- () => {
- this.setState(prevState => {
- if (prevState.selectedOrganization) {
- const selectedOrganization = this.getOrganization(prevState.selectedOrganization.key);
- return {
- selectedOrganization
- };
- }
- return null;
- });
- },
- () => {}
- );
- };
-
handleProjectKeyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const projectKey = event.currentTarget.value || '';
const projectKeyError = this.validateKey(projectKey);
});
};
- handleVisibilityChange = (selectedVisibility: T.Visibility) => {
- this.setState({ selectedVisibility });
- };
-
validateKey = (projectKey: string) => {
return projectKey.length > 400 || !/^[\w-.:]*[a-zA-Z]+[\w-.:]*$/.test(projectKey)
? translate('onboarding.create_project.project_key.error')
projectKeyError,
projectName,
projectNameError,
- selectedOrganization,
submitting,
touched,
validating
const projectKeyIsValid = touched && !validating && projectKeyError === undefined;
const projectNameIsInvalid = touched && projectNameError !== undefined;
const projectNameIsValid = touched && projectNameError === undefined;
- const canChoosePrivate = this.canChoosePrivate(selectedOrganization);
return (
<>
title={translate('onboarding.create_project.setup_manually')}
/>
- <div className="create-project">
+ <div className="create-project-manual">
<div className="flex-1 huge-spacer-right">
<form className="manual-project-create" onSubmit={this.handleFormSubmit}>
- {isSonarCloud() && this.props.userOrganizations && (
- <OrganizationInput
- onChange={this.handleOrganizationSelect}
- organization={selectedOrganization ? selectedOrganization.key : ''}
- organizations={this.props.userOrganizations}
- />
- )}
-
<ValidationInput
className="form-field"
description={translate('onboarding.create_project.project_key.description')}
<DeferredSpinner className="spacer-left" loading={submitting} />
</form>
</div>
-
- {isSonarCloud() && selectedOrganization && (
- <div className="create-project-side-sticky">
- <UpgradeOrganizationBox
- className={classNames('animated', { open: !canChoosePrivate })}
- onOrganizationUpgrade={this.handleOrganizationUpgrade}
- organization={selectedOrganization}
- />
- </div>
- )}
</div>
</>
);
+++ /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 * as React from 'react';
-import { withRouter, WithRouterProps } from 'react-router';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { save } from 'sonar-ui-common/helpers/storage';
-import OrganizationSelect from '../components/OrganizationSelect';
-import { ORGANIZATION_IMPORT_REDIRECT_TO_PROJECT_TIMESTAMP } from '../organization/utils';
-
-interface Props {
- autoImport?: boolean;
- onChange: (organization: T.Organization) => void;
- organization: string;
- organizations: T.Organization[];
-}
-
-export class OrganizationInput extends React.PureComponent<Props & WithRouterProps> {
- handleLinkClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- event.stopPropagation();
- save(ORGANIZATION_IMPORT_REDIRECT_TO_PROJECT_TIMESTAMP, Date.now().toString(10));
- this.props.router.push({
- pathname: '/create-organization',
- state: { tab: this.props.autoImport ? 'auto' : 'manual' }
- });
- };
-
- render() {
- const { autoImport, onChange, organization, organizations } = this.props;
- return (
- <div className="form-field spacer-bottom">
- <label htmlFor="select-organization">
- <span className="text-middle">
- <strong>{translate('onboarding.create_project.organization')}</strong>
- <em className="mandatory">*</em>
- </span>
- </label>
- <OrganizationSelect
- hideIcons={!autoImport}
- onChange={onChange}
- organization={organization}
- organizations={organizations}
- />
- <a className="big-spacer-left js-new-org" href="#" onClick={this.handleLinkClick}>
- {autoImport
- ? translate('onboarding.create_project.import_new_org')
- : translate('onboarding.create_project.create_new_org')}
- </a>
- </div>
- );
- }
-}
-
-export default withRouter(OrganizationInput);
+++ /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 * as classNames from 'classnames';
-import { keyBy } from 'lodash';
-import * as React from 'react';
-import Checkbox from 'sonar-ui-common/components/controls/Checkbox';
-import SearchBox from 'sonar-ui-common/components/controls/SearchBox';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { isDefined } from 'sonar-ui-common/helpers/types';
-import { getRepositories } from '../../../api/alm-integration';
-import { isPaidOrganization } from '../../../helpers/organizations';
-import UpgradeOrganizationBox from '../components/UpgradeOrganizationBox';
-import AlmRepositoryItem from './AlmRepositoryItem';
-import SetupProjectBox from './SetupProjectBox';
-
-interface Props {
- almApplication: T.AlmApplication;
- onOrganizationUpgrade: () => void;
- onProjectCreate: (projectKeys: string[], organization: string) => void;
- organization: T.Organization;
-}
-
-type SelectedRepositories = T.Dict<T.AlmRepository | undefined>;
-
-interface State {
- checkAllRepositories: boolean;
- highlight: boolean;
- loading: boolean;
- repositories: T.AlmRepository[];
- search: string;
- selectedRepositories: SelectedRepositories;
- successfullyUpgraded: boolean;
-}
-
-export default class RemoteRepositories extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {
- checkAllRepositories: false,
- highlight: false,
- loading: true,
- repositories: [],
- search: '',
- selectedRepositories: {},
- successfullyUpgraded: false
- };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchRepositories();
- }
-
- componentDidUpdate(prevProps: Props) {
- if (prevProps.organization.key !== this.props.organization.key) {
- this.setState({ loading: true, selectedRepositories: {} });
- this.fetchRepositories();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchRepositories = () => {
- const { organization } = this.props;
- return getRepositories({ organization: organization.key }).then(
- ({ repositories }) => {
- if (this.mounted) {
- this.setState({ loading: false, repositories });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- filterBySearch = (search: String) => (repo: T.AlmRepository) => {
- return repo.label.toLowerCase().includes(search.toLowerCase());
- };
-
- handleHighlightUpgradeBox = (highlight: boolean) => {
- this.setState({ highlight });
- };
-
- handleOrganizationUpgrade = () => {
- this.props.onOrganizationUpgrade();
- if (this.mounted) {
- this.setState({ successfullyUpgraded: true });
- }
- };
-
- handleProvisionFail = () => {
- return this.fetchRepositories().then(() => {
- if (this.mounted) {
- this.setState(({ repositories, selectedRepositories }) => {
- const updateSelectedRepositories: SelectedRepositories = {};
- Object.keys(selectedRepositories).forEach(installationKey => {
- const newRepository = repositories.find(r => r.installationKey === installationKey);
- if (newRepository && !newRepository.linkedProjectKey) {
- updateSelectedRepositories[newRepository.installationKey] = newRepository;
- }
- });
- return { selectedRepositories: updateSelectedRepositories };
- });
- }
- });
- };
-
- handleSearch = (search: string) => {
- this.setState({ search, checkAllRepositories: false, selectedRepositories: {} });
- };
-
- onCheckAllRepositories = () => {
- this.setState(({ checkAllRepositories, repositories, search }) => {
- const { organization } = this.props;
-
- const isPaidOrg = isPaidOrganization(organization);
- const filterByPlan = (repo: T.AlmRepository) => (isPaidOrg ? true : !repo.private);
- const filterByImportable = (repo: T.AlmRepository) => !repo.linkedProjectKey;
-
- const nextState = {
- selectedRepositories: {},
- checkAllRepositories: !checkAllRepositories
- };
-
- if (nextState.checkAllRepositories) {
- const validRepositories = repositories.filter(
- repo =>
- this.filterBySearch(search)(repo) && filterByPlan(repo) && filterByImportable(repo)
- );
- nextState.selectedRepositories = keyBy(validRepositories, 'installationKey');
- }
-
- return nextState;
- });
- };
-
- toggleRepository = (repository: T.AlmRepository) => {
- this.setState(({ selectedRepositories }) => ({
- selectedRepositories: {
- ...selectedRepositories,
- [repository.installationKey]: selectedRepositories[repository.installationKey]
- ? undefined
- : repository
- }
- }));
- };
-
- render() {
- const { highlight, loading, repositories, search, selectedRepositories } = this.state;
- const { almApplication, organization } = this.props;
- const isPaidOrg = isPaidOrganization(organization);
- const hasPrivateRepositories = repositories.some(repository => Boolean(repository.private));
- const showSearchBox = repositories.length > 5;
- const showCheckAll = repositories.length > 1;
- const showUpgradebox =
- !isPaidOrg && hasPrivateRepositories && organization.actions && organization.actions.admin;
- const filteredRepositories = repositories.filter(this.filterBySearch(search));
-
- return (
- <div className="create-project">
- <div className="flex-1 huge-spacer-right">
- <div className="spacer-bottom create-project-actions">
- <div>
- {showCheckAll && (
- <Checkbox
- checked={this.state.checkAllRepositories}
- disabled={filteredRepositories.length === 0}
- onCheck={this.onCheckAllRepositories}>
- {translate('onboarding.create_project.select_all_repositories')}
- </Checkbox>
- )}
- </div>
- {showSearchBox && (
- <SearchBox
- minLength={1}
- onChange={this.handleSearch}
- placeholder={translate('search.search_for_repositories')}
- value={this.state.search}
- />
- )}
- </div>
-
- {this.state.successfullyUpgraded && (
- <Alert variant="success">
- {translateWithParameters(
- 'onboarding.create_project.subscribtion_success_x',
- organization.name
- )}
- </Alert>
- )}
- <DeferredSpinner loading={loading}>
- <ul>
- {filteredRepositories.length === 0 && (
- <li className="big-spacer-top note">
- {showUpgradebox
- ? translateWithParameters('no_results_for_x', search)
- : translate('onboarding.create_project.no_repositories')}
- </li>
- )}
- {filteredRepositories.map(repo => (
- <AlmRepositoryItem
- disabled={Boolean(repo.private && !isPaidOrg)}
- highlightUpgradeBox={this.handleHighlightUpgradeBox}
- identityProvider={almApplication}
- key={repo.installationKey}
- repository={repo}
- selected={Boolean(selectedRepositories[repo.installationKey])}
- toggleRepository={this.toggleRepository}
- />
- ))}
- </ul>
- </DeferredSpinner>
- </div>
- {organization && (
- <div className={classNames({ 'create-project-side-with-search': showSearchBox })}>
- <div className="create-project-side-sticky">
- <SetupProjectBox
- onProjectCreate={this.props.onProjectCreate}
- onProvisionFail={this.handleProvisionFail}
- organization={organization}
- selectedRepositories={Object.keys(selectedRepositories)
- .map(r => selectedRepositories[r])
- .filter(isDefined)}
- />
- {showUpgradebox && (
- <UpgradeOrganizationBox
- className={classNames({ highlight })}
- onOrganizationUpgrade={this.handleOrganizationUpgrade}
- organization={organization}
- />
- )}
- </div>
- </div>
- )}
- </div>
- );
- }
-}
+++ /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 * as classNames from 'classnames';
-import { partition } from 'lodash';
-import * as React from 'react';
-import { SubmitButton } from 'sonar-ui-common/components/controls/buttons';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { provisionProject } from '../../../api/alm-integration';
-
-interface Props {
- onProjectCreate: (projectKeys: string[], organization: string) => void;
- onProvisionFail: () => Promise<void>;
- organization: T.Organization;
- selectedRepositories: T.AlmRepository[];
-}
-
-interface State {
- submitting: boolean;
-}
-
-export default class SetupProjectBox extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { submitting: false };
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- canSubmit = () => {
- return !this.state.submitting && this.props.selectedRepositories.length > 0;
- };
-
- handleFormSubmit = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
-
- if (this.canSubmit()) {
- const { selectedRepositories } = this.props;
- this.setState({ submitting: true });
- provisionProject({
- installationKeys: selectedRepositories.map(repo => repo.installationKey),
- organization: this.props.organization.key
- }).then(
- ({ projects }) =>
- this.props.onProjectCreate(
- projects.map(project => project.projectKey),
- this.props.organization.key
- ),
- this.handleProvisionFail
- );
- }
- };
-
- handleProvisionFail = () => {
- return this.props.onProvisionFail().then(() => {
- if (this.mounted) {
- this.setState({ submitting: false });
- }
- });
- };
-
- render() {
- const { selectedRepositories } = this.props;
- const hasSelectedRepositories = selectedRepositories.length > 0;
- const [privateRepos = [], publicRepos = []] = partition(
- selectedRepositories,
- repo => repo.private
- );
- return (
- <form
- className={classNames('create-project-setup boxed-group', {
- open: hasSelectedRepositories
- })}
- onSubmit={this.handleFormSubmit}>
- <div className="boxed-group-header">
- <h2 className="spacer-top">
- {selectedRepositories.length > 1
- ? translateWithParameters(
- 'onboarding.create_project.x_repositories_selected',
- selectedRepositories.length
- )
- : translate('onboarding.create_project.1_repository_selected')}
- </h2>
- </div>
- <div className="boxed-group-inner">
- <div className="flex-1">
- {publicRepos.length === 1 && (
- <p>{translate('onboarding.create_project.1_repository_created_as_public')}</p>
- )}
- {publicRepos.length > 1 && (
- <p>
- {translateWithParameters(
- 'onboarding.create_project.x_repository_created_as_public',
- publicRepos.length
- )}
- </p>
- )}
- {privateRepos.length === 1 && (
- <p>{translate('onboarding.create_project.1_repository_created_as_private')}</p>
- )}
- {privateRepos.length > 1 && (
- <p>
- {translateWithParameters(
- 'onboarding.create_project.x_repository_created_as_private',
- privateRepos.length
- )}
- </p>
- )}
- </div>
- <div>
- <SubmitButton className="button-large" disabled={this.state.submitting}>
- {translate('set_up')}
- </SubmitButton>
- <DeferredSpinner className="spacer-left" loading={this.state.submitting} />
- </div>
- </div>
- </form>
- );
- }
-}
+++ /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 { shallow } from 'enzyme';
-import * as React from 'react';
-import AlmRepositoryItem from '../AlmRepositoryItem';
-
-const identityProviders = {
- backgroundColor: 'blue',
- iconPath: 'icon/path',
- key: 'foo',
- name: 'Foo Provider'
-};
-
-const repositories = [
- {
- label: 'Cool Project',
- installationKey: 'github/cool',
- linkedProjectKey: 'proj_cool',
- linkedProjectName: 'Proj Cool'
- },
- {
- label: 'Awesome Project',
- installationKey: 'github/awesome'
- }
-];
-
-it('should render correctly', () => {
- expect(getWrapper()).toMatchSnapshot();
-});
-
-it('should render selected', () => {
- expect(getWrapper({ selected: true })).toMatchSnapshot();
-});
-
-it('should render imported', () => {
- expect(getWrapper({ repository: repositories[0] })).toMatchSnapshot();
-});
-
-it('should render disabed', () => {
- expect(getWrapper({ disabled: true, repository: repositories[1] })).toMatchSnapshot();
-});
-
-it('should render private repositories', () => {
- expect(getWrapper({ repository: { ...repositories[1], private: true } })).toMatchSnapshot();
-});
-
-function getWrapper(props = {}) {
- return shallow(
- <AlmRepositoryItem
- disabled={false}
- highlightUpgradeBox={jest.fn()}
- identityProvider={identityProviders}
- repository={repositories[1]}
- selected={false}
- toggleRepository={jest.fn()}
- {...props}
- />
- );
-}
+++ /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 { shallow } from 'enzyme';
-import * as React from 'react';
-import {
- mockOrganizationWithAdminActions,
- mockOrganizationWithAlm
-} from '../../../../helpers/testMocks';
-import AutoProjectCreate from '../AutoProjectCreate';
-
-const almApplication = {
- backgroundColor: 'blue',
- iconPath: 'icon/path',
- installationUrl: 'https://alm.installation.url',
- key: 'github',
- name: 'GitHub'
-};
-
-const boundOrganizations: T.Organization[] = [
- mockOrganizationWithAdminActions(mockOrganizationWithAlm({ subscription: 'FREE' })),
- mockOrganizationWithAlm({ key: 'bar', name: 'Bar', subscription: 'FREE' })
-];
-
-it('should display the provider app install button', () => {
- expect(shallowRender({ boundOrganizations: [] })).toMatchSnapshot();
-});
-
-it('should display the bound organizations dropdown with the remote repositories', () => {
- expect(shallowRender({ organization: 'foo' })).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<AutoProjectCreate['props']> = {}) {
- return shallow(
- <AutoProjectCreate
- almApplication={almApplication}
- boundOrganizations={boundOrganizations}
- onOrganizationUpgrade={jest.fn()}
- onProjectCreate={jest.fn()}
- organization=""
- {...props}
- />
- );
-}
* 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 { isSonarCloud } from '../../../../helpers/system';
-import { mockLocation, mockRouter } from '../../../../helpers/testMocks';
-import CreateProjectPage from '../CreateProjectPage';
+import { addWhitePageClass } from 'sonar-ui-common/helpers/pages';
+import { getAlmSettings } from '../../../../api/alm-settings';
+import { mockLocation, mockLoggedInUser, mockRouter } from '../../../../helpers/testMocks';
+import { AlmKeys } from '../../../../types/alm-settings';
+import { CreateProjectPage } from '../CreateProjectPage';
+import { CreateProjectModes } from '../types';
+
+jest.mock('../../../../api/alm-settings', () => ({
+ getAlmSettings: jest.fn().mockResolvedValue([{ alm: AlmKeys.Bitbucket, key: 'foo' }])
+}));
-jest.mock('../../../../helpers/system', () => ({
- isSonarCloud: jest.fn().mockReturnValue(false)
+jest.mock('sonar-ui-common/helpers/pages', () => ({
+ addWhitePageClass: jest.fn(),
+ removeWhitePageClass: jest.fn()
}));
-it('should render correctly for SonarQube', () => {
- const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
+beforeEach(jest.clearAllMocks);
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(getAlmSettings).toBeCalled();
+});
+
+it('should render correctly if no branch support', () => {
+ expect(shallowRender({ appState: { branchesEnabled: false } })).toMatchSnapshot();
+ expect(getAlmSettings).not.toBeCalled();
});
-it('should render correctly for SonarCloud', () => {
- (isSonarCloud as jest.Mock).mockReturnValue(true);
- const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
+it('should render correctly if the manual method is selected', () => {
+ const push = jest.fn();
+ const location = { query: { mode: CreateProjectModes.Manual } };
+ const wrapper = shallowRender({ router: mockRouter({ push }) });
+
+ wrapper.instance().handleModeSelect(CreateProjectModes.Manual);
+ expect(push).toBeCalledWith(expect.objectContaining(location));
+
+ expect(wrapper.setProps({ location: mockLocation(location) })).toMatchSnapshot();
+ expect(addWhitePageClass).toBeCalled();
+});
+
+it('should render correctly if the BBS method is selected', () => {
+ const push = jest.fn();
+ const location = { query: { mode: CreateProjectModes.BitbucketServer } };
+ const wrapper = shallowRender({ router: mockRouter({ push }) });
+
+ wrapper.instance().handleModeSelect(CreateProjectModes.BitbucketServer);
+ expect(push).toBeCalledWith(expect.objectContaining(location));
+
+ expect(wrapper.setProps({ location: mockLocation(location) })).toMatchSnapshot();
+ expect(addWhitePageClass).toBeCalled();
});
-function shallowRender(props = {}) {
- return shallow(
+function shallowRender(props: Partial<CreateProjectPage['props']> = {}) {
+ return shallow<CreateProjectPage>(
<CreateProjectPage
+ appState={{ branchesEnabled: true }}
+ currentUser={mockLoggedInUser()}
location={mockLocation()}
- params={{}}
router={mockRouter()}
- routes={[]}
{...props}
/>
);
+++ /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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { getAlmAppInfo } from '../../../../api/alm-integration';
-import {
- mockOrganizationWithAdminActions,
- mockOrganizationWithAlm,
- mockRouter
-} from '../../../../helpers/testMocks';
-import { CreateProjectPageSonarCloud } from '../CreateProjectPageSonarCloud';
-
-jest.mock('../../../../api/alm-integration', () => ({
- getAlmAppInfo: jest.fn().mockResolvedValue({
- application: {
- backgroundColor: 'blue',
- iconPath: 'icon/path',
- installationUrl: 'https://alm.installation.url',
- key: 'github',
- name: 'GitHub'
- }
- })
-}));
-
-const user: T.LoggedInUser = {
- externalProvider: 'github',
- groups: [],
- isLoggedIn: true,
- login: 'foo',
- name: 'Foo',
- scmAccounts: []
-};
-
-beforeEach(() => {
- (getAlmAppInfo as jest.Mock<any>).mockClear();
-});
-
-it('should render correctly', async () => {
- const wrapper = getWrapper();
- expect(wrapper).toMatchSnapshot();
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should render with Custom creation only', () => {
- expect(getWrapper({ currentUser: { ...user, externalProvider: 'microsoft' } })).toMatchSnapshot();
-});
-
-it('should switch tabs', async () => {
- const replace = jest.fn();
- const wrapper = getWrapper({ router: { replace } });
- replace.mockImplementation(location => {
- wrapper.setProps({ location }).update();
- });
-
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-
- wrapper.find('Tabs').prop<Function>('onChange')('manual');
- expect(wrapper.find('ManualProjectCreate').exists()).toBe(true);
- wrapper.find('Tabs').prop<Function>('onChange')('auto');
- expect(wrapper.find('AutoProjectCreate').exists()).toBe(true);
-});
-
-function getWrapper(props = {}) {
- return shallow(
- <CreateProjectPageSonarCloud
- addGlobalErrorMessage={jest.fn()}
- currentUser={user}
- // @ts-ignore avoid passing everything from WithRouterProps
- location={{}}
- router={mockRouter()}
- skipOnboarding={jest.fn()}
- userOrganizations={[
- mockOrganizationWithAdminActions({}, { admin: false, provision: true }),
- mockOrganizationWithAdminActions(mockOrganizationWithAlm({ key: 'bar', name: 'Bar' }), {
- admin: false,
- provision: true
- }),
- mockOrganizationWithAdminActions(
- { key: 'baz', name: 'Baz' },
- { admin: false, provision: false }
- )
- ]}
- {...props}
- />
- );
-}
+++ /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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { addWhitePageClass } from 'sonar-ui-common/helpers/pages';
-import { getAlmSettings } from '../../../../api/alm-settings';
-import { mockLocation, mockLoggedInUser, mockRouter } from '../../../../helpers/testMocks';
-import { AlmKeys } from '../../../../types/alm-settings';
-import { CreateProjectPageSonarQube } from '../CreateProjectPageSonarQube';
-import { CreateProjectModes } from '../types';
-
-jest.mock('../../../../api/alm-settings', () => ({
- getAlmSettings: jest.fn().mockResolvedValue([{ alm: AlmKeys.Bitbucket, key: 'foo' }])
-}));
-
-jest.mock('sonar-ui-common/helpers/pages', () => ({
- addWhitePageClass: jest.fn(),
- removeWhitePageClass: jest.fn()
-}));
-
-beforeEach(jest.clearAllMocks);
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
- expect(getAlmSettings).toBeCalled();
-});
-
-it('should render correctly if no branch support', () => {
- expect(shallowRender({ appState: { branchesEnabled: false } })).toMatchSnapshot();
- expect(getAlmSettings).not.toBeCalled();
-});
-
-it('should render correctly if the manual method is selected', () => {
- const push = jest.fn();
- const location = { query: { mode: CreateProjectModes.Manual } };
- const wrapper = shallowRender({ router: mockRouter({ push }) });
-
- wrapper.instance().handleModeSelect(CreateProjectModes.Manual);
- expect(push).toBeCalledWith(expect.objectContaining(location));
-
- expect(wrapper.setProps({ location: mockLocation(location) })).toMatchSnapshot();
- expect(addWhitePageClass).toBeCalled();
-});
-
-it('should render correctly if the BBS method is selected', () => {
- const push = jest.fn();
- const location = { query: { mode: CreateProjectModes.BitbucketServer } };
- const wrapper = shallowRender({ router: mockRouter({ push }) });
-
- wrapper.instance().handleModeSelect(CreateProjectModes.BitbucketServer);
- expect(push).toBeCalledWith(expect.objectContaining(location));
-
- expect(wrapper.setProps({ location: mockLocation(location) })).toMatchSnapshot();
- expect(addWhitePageClass).toBeCalled();
-});
-
-function shallowRender(props: Partial<CreateProjectPageSonarQube['props']> = {}) {
- return shallow<CreateProjectPageSonarQube>(
- <CreateProjectPageSonarQube
- appState={{ branchesEnabled: true }}
- currentUser={mockLoggedInUser()}
- location={mockLocation()}
- router={mockRouter()}
- {...props}
- />
- );
-}
expect(shallowRender()).toMatchSnapshot();
});
-it('should correctly create a public project', async () => {
+it('should correctly create a project', async () => {
const onProjectCreate = jest.fn();
const wrapper = shallowRender({ onProjectCreate });
- wrapper.find('withRouter(OrganizationInput)').prop<Function>('onChange')({ key: 'foo' });
change(wrapper.find('input#project-key'), 'bar');
change(wrapper.find('input#project-name'), 'Bar');
submit(wrapper.find('form'));
expect(createProject).toBeCalledWith({
project: 'bar',
- name: 'Bar',
- organization: 'foo',
- visibility: 'public'
- });
-
- await waitAndUpdate(wrapper);
- expect(onProjectCreate).toBeCalledWith(['bar']);
-});
-
-it('should correctly create a private project', async () => {
- const onProjectCreate = jest.fn();
- const wrapper = shallowRender({ onProjectCreate });
- wrapper.find('withRouter(OrganizationInput)').prop<Function>('onChange')({ key: 'bar' });
-
- change(wrapper.find('input#project-key'), 'bar');
- change(wrapper.find('input#project-name'), 'Bar');
-
- submit(wrapper.find('form'));
- expect(createProject).toBeCalledWith({
- project: 'bar',
- name: 'Bar',
- organization: 'bar',
- visibility: 'private'
+ name: 'Bar'
});
await waitAndUpdate(wrapper);
return shallow<ManualProjectCreate>(
<ManualProjectCreate
currentUser={{ groups: [], isLoggedIn: true, login: 'foo', name: 'Foo', scmAccounts: [] }}
- fetchMyOrganizations={jest.fn()}
onProjectCreate={jest.fn()}
- userOrganizations={[
- { key: 'foo', name: 'Foo' },
- { key: 'bar', name: 'Bar', subscription: 'PAID' }
- ]}
{...props}
/>
);
+++ /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 { shallow } from 'enzyme';
-import * as React from 'react';
-import {
- mockOrganization,
- mockOrganizationWithAlm,
- mockRouter
-} from '../../../../helpers/testMocks';
-import { OrganizationInput } from '../OrganizationInput';
-
-const organizations = [mockOrganization(), mockOrganizationWithAlm({ key: 'bar', name: 'Bar' })];
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
- expect(
- shallowRender({ autoImport: true })
- .find('.js-new-org')
- .contains('onboarding.create_project.import_new_org')
- ).toBe(true);
-});
-
-function shallowRender(props: Partial<OrganizationInput['props']> = {}) {
- return shallow(
- // @ts-ignore avoid passing everything from WithRouterProps
- <OrganizationInput
- onChange={jest.fn()}
- organization="bar"
- organizations={organizations}
- router={mockRouter()}
- {...props}
- />
- );
-}
+++ /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 { shallow } from 'enzyme';
-import { times } from 'lodash';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { getRepositories } from '../../../../api/alm-integration';
-import {
- mockOrganizationWithAdminActions,
- mockOrganizationWithAlm
-} from '../../../../helpers/testMocks';
-import RemoteRepositories from '../RemoteRepositories';
-
-jest.mock('../../../../api/alm-integration', () => ({
- getRepositories: jest.fn().mockResolvedValue({
- repositories: [
- {
- label: 'Cool Project',
- installationKey: 'github/cool'
- },
- { label: 'Awesome Project', installationKey: 'github/awesome' }
- ]
- })
-}));
-
-const almApplication = {
- backgroundColor: 'blue',
- iconPath: 'icon/path',
- installationUrl: 'https://alm.installation.url',
- key: 'github',
- name: 'GitHub'
-};
-
-const organization: T.Organization = mockOrganizationWithAlm({ subscription: 'FREE' });
-
-beforeEach(() => {
- (getRepositories as jest.Mock<any>).mockClear();
-});
-
-it('should display the list of repositories', async () => {
- const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(getRepositories).toHaveBeenCalledWith({ organization: 'foo' });
-});
-
-it('should display the organization upgrade box', async () => {
- (getRepositories as jest.Mock<any>).mockResolvedValueOnce({
- repositories: [{ label: 'Foo Project', installationKey: 'github/foo', private: true }]
- });
- const wrapper = shallowRender({ organization: { ...organization, actions: { admin: true } } });
- await waitAndUpdate(wrapper);
- expect(wrapper.find('UpgradeOrganizationBox')).toMatchSnapshot();
- wrapper.find('UpgradeOrganizationBox').prop<Function>('onOrganizationUpgrade')();
- expect(wrapper.find('Alert[variant="success"]').exists()).toBe(true);
-});
-
-it('should not display the organization upgrade box', () => {
- (getRepositories as jest.Mock<any>).mockResolvedValueOnce({
- repositories: [{ label: 'Bar Project', installationKey: 'github/bar', private: true }]
- });
- const wrapper = shallowRender({
- organization: mockOrganizationWithAdminActions(
- mockOrganizationWithAlm({ subscription: 'PAID' })
- )
- });
-
- expect(wrapper.find('UpgradeOrganizationBox').exists()).toBe(false);
-});
-
-it('should display a search box to filter repositories', async () => {
- (getRepositories as jest.Mock<any>).mockResolvedValueOnce({
- repositories: times(6, i => ({ label: `Project ${i}`, installationKey: `key-${i}` }))
- });
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
-
- expect(wrapper.find('SearchBox').exists()).toBe(true);
- expect(wrapper.find('AlmRepositoryItem')).toHaveLength(6);
- wrapper.find('SearchBox').prop<Function>('onChange')('3');
- expect(wrapper.find('AlmRepositoryItem')).toHaveLength(1);
-});
-
-it('should allow to select all repositories', async () => {
- (getRepositories as jest.Mock<any>).mockResolvedValueOnce({
- repositories: times(6, i => ({ label: `Project ${i}`, installationKey: `key-${i}` }))
- });
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
-
- expect(wrapper.find('Checkbox')).toHaveLength(1);
- expect(wrapper.state('checkAllRepositories')).toBe(false);
- expect(wrapper.state('selectedRepositories')).toEqual({});
-});
-
-it('should select all repositories', async () => {
- (getRepositories as jest.Mock<any>).mockResolvedValueOnce({
- repositories: [
- { label: 'Project 1', installationKey: 'key-1' },
- { label: 'Project 2', installationKey: 'key-2', linkedProjectKey: 'key-2' }
- ]
- });
-
- const wrapper = shallowRender();
- const instance = wrapper.instance() as RemoteRepositories;
- await waitAndUpdate(wrapper);
-
- instance.onCheckAllRepositories();
- await waitAndUpdate(wrapper);
-
- expect(wrapper.state('checkAllRepositories')).toBe(true);
- expect(wrapper.state('selectedRepositories')).toMatchSnapshot();
-
- instance.onCheckAllRepositories();
- await waitAndUpdate(wrapper);
-
- expect(wrapper.state('checkAllRepositories')).toBe(false);
- expect(wrapper.state('selectedRepositories')).toEqual({});
-});
-
-function shallowRender(props: Partial<RemoteRepositories['props']> = {}) {
- return shallow(
- <RemoteRepositories
- almApplication={almApplication}
- onOrganizationUpgrade={jest.fn()}
- onProjectCreate={jest.fn()}
- organization={organization}
- {...props}
- />
- );
-}
+++ /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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { submit, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { provisionProject } from '../../../../api/alm-integration';
-import { mockOrganizationWithAlm } from '../../../../helpers/testMocks';
-import SetupProjectBox from '../SetupProjectBox';
-
-jest.mock('../../../../api/alm-integration', () => ({
- provisionProject: jest
- .fn()
- .mockResolvedValue({ projects: [{ projectKey: 'awesome' }, { projectKey: 'foo' }] })
-}));
-
-it('should correctly create projects', async () => {
- const onProjectCreate = jest.fn();
- const wrapper = shallowRender({ onProjectCreate });
-
- expect(wrapper).toMatchSnapshot();
- submit(wrapper.find('form'));
- expect(provisionProject).toBeCalledWith({
- installationKeys: ['github/awesome', 'github/foo'],
- organization: 'foo'
- });
-
- await waitAndUpdate(wrapper);
- expect(onProjectCreate).toBeCalledWith(['awesome', 'foo'], 'foo');
-});
-
-function shallowRender(props: Partial<SetupProjectBox['props']> = {}) {
- return shallow(
- <SetupProjectBox
- onProjectCreate={jest.fn()}
- onProvisionFail={jest.fn()}
- organization={mockOrganizationWithAlm({ subscription: 'FREE' })}
- selectedRepositories={[
- { label: 'Awesome Project', installationKey: 'github/awesome' },
- { label: 'Foo', installationKey: 'github/foo', private: true }
- ]}
- {...props}
- />
- );
-}
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Tooltip>
- <li>
- <div
- className="create-project-repository"
- onClick={[Function]}
- role="listitem"
- >
- <div
- className="flex-1 display-flex-center"
- >
- <Checkbox
- checked={false}
- disabled={false}
- onCheck={[Function]}
- thirdState={false}
- />
- <img
- alt="Foo Provider"
- className="spacer-left"
- height={14}
- src="/images/sonarcloud/foo.svg"
- width={14}
- />
- <span
- className="spacer-left"
- >
- Awesome Project
- </span>
- </div>
- </div>
- </li>
-</Tooltip>
-`;
-
-exports[`should render disabed 1`] = `
-<Tooltip
- overlay="onboarding.create_project.subscribe_to_import_private_repositories"
->
- <li>
- <div
- className="create-project-repository disabled"
- onClick={[Function]}
- onMouseEnter={[Function]}
- onMouseLeave={[Function]}
- role="listitem"
- >
- <div
- className="flex-1 display-flex-center"
- >
- <LockIcon
- fill="#bbb"
- />
- <img
- alt="Foo Provider"
- className="spacer-left icon-half-transparent"
- height={14}
- src="/images/sonarcloud/foo.svg"
- width={14}
- />
- <span
- className="spacer-left"
- >
- Awesome Project
- </span>
- </div>
- </div>
- </li>
-</Tooltip>
-`;
-
-exports[`should render imported 1`] = `
-<Tooltip>
- <li>
- <div
- className="create-project-repository imported"
- onClick={[Function]}
- role="listitem"
- >
- <div
- className="flex-1 display-flex-center"
- >
- <Checkbox
- checked={true}
- disabled={true}
- onCheck={[Function]}
- thirdState={false}
- />
- <img
- alt="Foo Provider"
- className="spacer-left"
- height={14}
- src="/images/sonarcloud/foo.svg"
- width={14}
- />
- <span
- className="spacer-left"
- >
- Cool Project
- </span>
- </div>
- <span>
- <CheckIcon
- className="little-spacer-right"
- fill="#00aa00"
- />
- <FormattedMessage
- defaultMessage="onboarding.create_project.repository_imported"
- id="onboarding.create_project.repository_imported"
- values={
- Object {
- "link": <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/dashboard",
- "query": Object {
- "branch": undefined,
- "id": "proj_cool",
- },
- }
- }
- >
- onboarding.create_project.see_project
- </Link>,
- }
- }
- />
- </span>
- </div>
- </li>
-</Tooltip>
-`;
-
-exports[`should render private repositories 1`] = `
-<Tooltip>
- <li>
- <div
- className="create-project-repository"
- onClick={[Function]}
- role="listitem"
- >
- <div
- className="flex-1 display-flex-center"
- >
- <Checkbox
- checked={false}
- disabled={false}
- onCheck={[Function]}
- thirdState={false}
- />
- <img
- alt="Foo Provider"
- className="spacer-left"
- height={14}
- src="/images/sonarcloud/foo.svg"
- width={14}
- />
- <span
- className="spacer-left"
- >
- Awesome Project
- </span>
- <div
- className="badge spacer-left"
- >
- visibility.private
- </div>
- </div>
- </div>
- </li>
-</Tooltip>
-`;
-
-exports[`should render selected 1`] = `
-<Tooltip>
- <li>
- <div
- className="create-project-repository selected"
- onClick={[Function]}
- role="listitem"
- >
- <div
- className="flex-1 display-flex-center"
- >
- <Checkbox
- checked={true}
- disabled={false}
- onCheck={[Function]}
- thirdState={false}
- />
- <img
- alt="Foo Provider"
- className="spacer-left"
- height={14}
- src="/images/sonarcloud/foo.svg"
- width={14}
- />
- <span
- className="spacer-left"
- >
- Awesome Project
- </span>
- </div>
- </div>
- </li>
-</Tooltip>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display the bound organizations dropdown with the remote repositories 1`] = `
-<Fragment>
- <withRouter(OrganizationInput)
- autoImport={true}
- onChange={[Function]}
- organization="foo"
- organizations={
- Array [
- Object {
- "actions": Object {
- "admin": true,
- },
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "foo",
- "name": "Foo",
- "subscription": "FREE",
- },
- Object {
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "bar",
- "name": "Bar",
- "subscription": "FREE",
- },
- ]
- }
- />
- <RemoteRepositories
- almApplication={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "installationUrl": "https://alm.installation.url",
- "key": "github",
- "name": "GitHub",
- }
- }
- onOrganizationUpgrade={[MockFunction]}
- onProjectCreate={[MockFunction]}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "foo",
- "name": "Foo",
- "subscription": "FREE",
- }
- }
- />
-</Fragment>
-`;
-
-exports[`should display the provider app install button 1`] = `
-<Fragment>
- <p
- className="spacer-bottom"
- >
- onboarding.create_project.install_app_description.github
- </p>
- <IdentityProviderLink
- backgroundColor="blue"
- className="display-inline-block"
- iconPath="icon/path"
- name="GitHub"
- onClick={[Function]}
- small={true}
- url="https://alm.installation.url"
- >
- onboarding.import_organization.choose_organization_button.github
- </IdentityProviderLink>
-</Fragment>
-`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render correctly for SonarCloud 1`] = `
+exports[`should render correctly 1`] = `
<Fragment>
+ <Helmet
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="my_account.create_new.TRK"
+ titleTemplate="%s"
+ />
<A11ySkipTarget
anchor="create_project_main"
/>
- <Connect(withCurrentUser(whenLoggedIn(Connect(withUserOrganizations(Connect(CreateProjectPageSonarCloud))))))
- location={
- Object {
- "action": "PUSH",
- "hash": "",
- "key": "key",
- "pathname": "/path",
- "query": Object {},
- "search": "",
- "state": Object {},
- }
- }
- params={Object {}}
- router={
- Object {
- "createHref": [MockFunction],
- "createPath": [MockFunction],
- "go": [MockFunction],
- "goBack": [MockFunction],
- "goForward": [MockFunction],
- "isActive": [MockFunction],
- "push": [MockFunction],
- "replace": [MockFunction],
- "setRouteLeaveHook": [MockFunction],
- }
- }
- routes={Array []}
- />
+ <div
+ className="page page-limited huge-spacer-bottom position-relative"
+ id="create-project"
+ >
+ <CreateProjectModeSelection
+ bbsBindingCount={0}
+ loadingBindings={true}
+ onSelectMode={[Function]}
+ />
+ </div>
</Fragment>
`;
-exports[`should render correctly for SonarQube 1`] = `
+exports[`should render correctly if no branch support 1`] = `
<Fragment>
+ <Helmet
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="my_account.create_new.TRK"
+ titleTemplate="%s"
+ />
<A11ySkipTarget
anchor="create_project_main"
/>
- <Connect(withCurrentUser(whenLoggedIn(Connect(withAppState(CreateProjectPageSonarQube)))))
- location={
- Object {
- "action": "PUSH",
- "hash": "",
- "key": "key",
- "pathname": "/path",
- "query": Object {},
- "search": "",
- "state": Object {},
+ <div
+ className="page page-limited huge-spacer-bottom position-relative"
+ id="create-project"
+ >
+ <ManualProjectCreate
+ branchesEnabled={false}
+ currentUser={
+ Object {
+ "groups": Array [],
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ "scmAccounts": Array [],
+ }
}
- }
- params={Object {}}
- router={
- Object {
- "createHref": [MockFunction],
- "createPath": [MockFunction],
- "go": [MockFunction],
- "goBack": [MockFunction],
- "goForward": [MockFunction],
- "isActive": [MockFunction],
- "push": [MockFunction],
- "replace": [MockFunction],
- "setRouteLeaveHook": [MockFunction],
+ onProjectCreate={[Function]}
+ />
+ </div>
+</Fragment>
+`;
+
+exports[`should render correctly if the BBS method is selected 1`] = `
+<Fragment>
+ <Helmet
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="my_account.create_new.TRK"
+ titleTemplate="%s"
+ />
+ <A11ySkipTarget
+ anchor="create_project_main"
+ />
+ <div
+ className="page page-limited huge-spacer-bottom position-relative"
+ id="create-project"
+ >
+ <Connect(BitbucketProjectCreate)
+ bitbucketSettings={Array []}
+ loadingBindings={true}
+ location={
+ Object {
+ "action": "PUSH",
+ "hash": "",
+ "key": "key",
+ "pathname": "/path",
+ "query": Object {
+ "mode": "bbs",
+ },
+ "search": "",
+ "state": Object {},
+ }
}
- }
- routes={Array []}
+ onProjectCreate={[Function]}
+ />
+ </div>
+</Fragment>
+`;
+
+exports[`should render correctly if the manual method is selected 1`] = `
+<Fragment>
+ <Helmet
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="my_account.create_new.TRK"
+ titleTemplate="%s"
/>
+ <A11ySkipTarget
+ anchor="create_project_main"
+ />
+ <div
+ className="page page-limited huge-spacer-bottom position-relative"
+ id="create-project"
+ >
+ <ManualProjectCreate
+ branchesEnabled={true}
+ currentUser={
+ Object {
+ "groups": Array [],
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ "scmAccounts": Array [],
+ }
+ }
+ onProjectCreate={[Function]}
+ />
+ </div>
</Fragment>
`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Fragment>
- <Helmet
- defer={true}
- encodeSpecialCharacters={true}
- title="onboarding.create_project.header"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-top huge-spacer-bottom"
- >
- <header
- className="page-header huge-spacer-bottom"
- >
- <h1
- className="page-title huge"
- >
- <strong>
- onboarding.create_project.header
- </strong>
- </h1>
- </header>
- <DeferredSpinner
- timeout={100}
- />
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly 2`] = `
-<Fragment>
- <Helmet
- defer={true}
- encodeSpecialCharacters={true}
- title="onboarding.create_project.header"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-top huge-spacer-bottom"
- >
- <header
- className="page-header huge-spacer-bottom"
- >
- <h1
- className="page-title huge"
- >
- <strong>
- onboarding.create_project.header
- </strong>
- </h1>
- </header>
- <Tabs
- onChange={[Function]}
- selected="auto"
- tabs={
- Array [
- Object {
- "key": "auto",
- "node": "onboarding.create_project.select_repositories",
- },
- Object {
- "key": "manual",
- "node": "onboarding.create_project.setup_manually",
- },
- ]
- }
- />
- <AutoProjectCreate
- almApplication={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "installationUrl": "https://alm.installation.url",
- "key": "github",
- "name": "GitHub",
- }
- }
- boundOrganizations={
- Array [
- Object {
- "actions": Object {
- "admin": false,
- "provision": true,
- },
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "bar",
- "name": "Bar",
- },
- ]
- }
- onProjectCreate={[Function]}
- />
- </div>
-</Fragment>
-`;
-
-exports[`should render with Custom creation only 1`] = `
-<Fragment>
- <Helmet
- defer={true}
- encodeSpecialCharacters={true}
- title="onboarding.create_project.header"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-top huge-spacer-bottom"
- >
- <header
- className="page-header huge-spacer-bottom"
- >
- <h1
- className="page-title huge"
- >
- <strong>
- onboarding.create_project.header
- </strong>
- </h1>
- </header>
- <ManualProjectCreate
- currentUser={
- Object {
- "externalProvider": "microsoft",
- "groups": Array [],
- "isLoggedIn": true,
- "login": "foo",
- "name": "Foo",
- "scmAccounts": Array [],
- }
- }
- onProjectCreate={[Function]}
- userOrganizations={
- Array [
- Object {
- "actions": Object {
- "admin": false,
- "provision": true,
- },
- "key": "foo",
- "name": "Foo",
- },
- Object {
- "actions": Object {
- "admin": false,
- "provision": true,
- },
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "bar",
- "name": "Bar",
- },
- ]
- }
- />
- </div>
-</Fragment>
-`;
-
-exports[`should switch tabs 1`] = `
-<Fragment>
- <Helmet
- defer={true}
- encodeSpecialCharacters={true}
- title="onboarding.create_project.header"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-top huge-spacer-bottom"
- >
- <header
- className="page-header huge-spacer-bottom"
- >
- <h1
- className="page-title huge"
- >
- <strong>
- onboarding.create_project.header
- </strong>
- </h1>
- </header>
- <Tabs
- onChange={[Function]}
- selected="auto"
- tabs={
- Array [
- Object {
- "key": "auto",
- "node": "onboarding.create_project.select_repositories",
- },
- Object {
- "key": "manual",
- "node": "onboarding.create_project.setup_manually",
- },
- ]
- }
- />
- <AutoProjectCreate
- almApplication={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "installationUrl": "https://alm.installation.url",
- "key": "github",
- "name": "GitHub",
- }
- }
- boundOrganizations={
- Array [
- Object {
- "actions": Object {
- "admin": false,
- "provision": true,
- },
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "bar",
- "name": "Bar",
- },
- ]
- }
- onProjectCreate={[Function]}
- />
- </div>
-</Fragment>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Fragment>
- <Helmet
- defer={true}
- encodeSpecialCharacters={true}
- title="my_account.create_new.TRK"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-bottom position-relative"
- id="create-project"
- >
- <CreateProjectModeSelection
- bbsBindingCount={0}
- loadingBindings={true}
- onSelectMode={[Function]}
- />
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly if no branch support 1`] = `
-<Fragment>
- <Helmet
- defer={true}
- encodeSpecialCharacters={true}
- title="my_account.create_new.TRK"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-bottom position-relative"
- id="create-project"
- >
- <ManualProjectCreate
- branchesEnabled={false}
- currentUser={
- Object {
- "groups": Array [],
- "isLoggedIn": true,
- "login": "luke",
- "name": "Skywalker",
- "scmAccounts": Array [],
- }
- }
- onProjectCreate={[Function]}
- />
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly if the BBS method is selected 1`] = `
-<Fragment>
- <Helmet
- defer={true}
- encodeSpecialCharacters={true}
- title="my_account.create_new.TRK"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-bottom position-relative"
- id="create-project"
- >
- <Connect(BitbucketProjectCreate)
- bitbucketSettings={Array []}
- loadingBindings={true}
- location={
- Object {
- "action": "PUSH",
- "hash": "",
- "key": "key",
- "pathname": "/path",
- "query": Object {
- "mode": "bbs",
- },
- "search": "",
- "state": Object {},
- }
- }
- onProjectCreate={[Function]}
- />
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly if the manual method is selected 1`] = `
-<Fragment>
- <Helmet
- defer={true}
- encodeSpecialCharacters={true}
- title="my_account.create_new.TRK"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-bottom position-relative"
- id="create-project"
- >
- <ManualProjectCreate
- branchesEnabled={true}
- currentUser={
- Object {
- "groups": Array [],
- "isLoggedIn": true,
- "login": "luke",
- "name": "Skywalker",
- "scmAccounts": Array [],
- }
- }
- onProjectCreate={[Function]}
- />
- </div>
-</Fragment>
-`;
title="onboarding.create_project.setup_manually"
/>
<div
- className="create-project"
+ className="create-project-manual"
>
<div
className="flex-1 huge-spacer-right"
className="manual-project-create"
onSubmit={[Function]}
>
- <withRouter(OrganizationInput)
- onChange={[Function]}
- organization=""
- organizations={
- Array [
- Object {
- "key": "foo",
- "name": "Foo",
- },
- Object {
- "key": "bar",
- "name": "Bar",
- "subscription": "PAID",
- },
- ]
- }
- />
<ValidationInput
className="form-field"
description="onboarding.create_project.project_key.description"
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
- className="form-field spacer-bottom"
->
- <label
- htmlFor="select-organization"
- >
- <span
- className="text-middle"
- >
- <strong>
- onboarding.create_project.organization
- </strong>
- <em
- className="mandatory"
- >
- *
- </em>
- </span>
- </label>
- <OrganizationSelect
- hideIcons={true}
- onChange={[MockFunction]}
- organization="bar"
- organizations={
- Array [
- Object {
- "key": "foo",
- "name": "Foo",
- },
- Object {
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "bar",
- "name": "Bar",
- },
- ]
- }
- />
- <a
- className="big-spacer-left js-new-org"
- href="#"
- onClick={[Function]}
- >
- onboarding.create_project.create_new_org
- </a>
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display the list of repositories 1`] = `
-<div
- className="create-project"
->
- <div
- className="flex-1 huge-spacer-right"
- >
- <div
- className="spacer-bottom create-project-actions"
- >
- <div />
- </div>
- <DeferredSpinner
- loading={true}
- timeout={100}
- >
- <ul>
- <li
- className="big-spacer-top note"
- >
- onboarding.create_project.no_repositories
- </li>
- </ul>
- </DeferredSpinner>
- </div>
- <div
- className=""
- >
- <div
- className="create-project-side-sticky"
- >
- <SetupProjectBox
- onProjectCreate={[MockFunction]}
- onProvisionFail={[Function]}
- organization={
- Object {
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "foo",
- "name": "Foo",
- "subscription": "FREE",
- }
- }
- selectedRepositories={Array []}
- />
- </div>
- </div>
-</div>
-`;
-
-exports[`should display the list of repositories 2`] = `
-<div
- className="create-project"
->
- <div
- className="flex-1 huge-spacer-right"
- >
- <div
- className="spacer-bottom create-project-actions"
- >
- <div>
- <Checkbox
- checked={false}
- disabled={false}
- onCheck={[Function]}
- thirdState={false}
- >
- onboarding.create_project.select_all_repositories
- </Checkbox>
- </div>
- </div>
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <ul>
- <AlmRepositoryItem
- disabled={false}
- highlightUpgradeBox={[Function]}
- identityProvider={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "installationUrl": "https://alm.installation.url",
- "key": "github",
- "name": "GitHub",
- }
- }
- key="github/cool"
- repository={
- Object {
- "installationKey": "github/cool",
- "label": "Cool Project",
- }
- }
- selected={false}
- toggleRepository={[Function]}
- />
- <AlmRepositoryItem
- disabled={false}
- highlightUpgradeBox={[Function]}
- identityProvider={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "installationUrl": "https://alm.installation.url",
- "key": "github",
- "name": "GitHub",
- }
- }
- key="github/awesome"
- repository={
- Object {
- "installationKey": "github/awesome",
- "label": "Awesome Project",
- }
- }
- selected={false}
- toggleRepository={[Function]}
- />
- </ul>
- </DeferredSpinner>
- </div>
- <div
- className=""
- >
- <div
- className="create-project-side-sticky"
- >
- <SetupProjectBox
- onProjectCreate={[MockFunction]}
- onProvisionFail={[Function]}
- organization={
- Object {
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "foo",
- "name": "Foo",
- "subscription": "FREE",
- }
- }
- selectedRepositories={Array []}
- />
- </div>
- </div>
-</div>
-`;
-
-exports[`should display the organization upgrade box 1`] = `
-<UpgradeOrganizationBox
- className=""
- onOrganizationUpgrade={[Function]}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "foo",
- "name": "Foo",
- "subscription": "FREE",
- }
- }
-/>
-`;
-
-exports[`should select all repositories 1`] = `
-Object {
- "key-1": Object {
- "installationKey": "key-1",
- "label": "Project 1",
- },
-}
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should correctly create projects 1`] = `
-<form
- className="create-project-setup boxed-group open"
- onSubmit={[Function]}
->
- <div
- className="boxed-group-header"
- >
- <h2
- className="spacer-top"
- >
- onboarding.create_project.x_repositories_selected.2
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- >
- <div
- className="flex-1"
- >
- <p>
- onboarding.create_project.1_repository_created_as_public
- </p>
- <p>
- onboarding.create_project.1_repository_created_as_private
- </p>
- </div>
- <div>
- <SubmitButton
- className="button-large"
- disabled={false}
- >
- set_up
- </SubmitButton>
- <DeferredSpinner
- className="spacer-left"
- loading={false}
- timeout={100}
- />
- </div>
- </div>
-</form>
-`;
z-index: var(--pageMainZIndex);
}
-.create-project {
- display: flex !important;
- justify-content: space-between;
-}
-
-.create-project-repository {
- display: flex;
- align-items: center;
- min-width: 500px;
- height: 40px;
- border: 1px solid var(--barBorderColor);
- padding: var(--gridSize) calc(var(--gridSize) * 2);
- margin-bottom: calc(var(--gridSize));
- box-sizing: border-box;
- cursor: pointer;
- transition: all 0.3s ease;
-}
-
-.create-project-repository.disabled {
- background-color: var(--disableGrayBg);
- border-color: var(--disableGrayBorder);
- cursor: default;
-}
-
-.create-project-repository.imported {
- cursor: default;
-}
-
-.create-project-repository.selected {
- background-color: var(--lightBlue);
- border-color: var(--darkBlue);
-}
-
-.create-project-repository:not(.imported):not(.disabled):hover,
-.create-project-repository:not(.imported):not(.disabled):focus,
-.create-project-repository:not(.imported):not(.disabled):active {
- border-color: var(--blue);
- box-shadow: none;
-}
-
-.create-project-side-with-search {
- margin-top: calc(4 * var(--gridSize));
-}
-
-.create-project-side-sticky {
- position: sticky;
- top: 68px;
-}
-
-.create-project-setup {
- display: flex;
- overflow: hidden;
- opacity: 0;
- flex-direction: column;
- height: 0;
- width: 450px;
- margin-bottom: 0;
- color: #fff;
- background-color: var(--sonarcloudBlue900);
- border: none;
- border-radius: 3px;
- transition: height 0.5s ease, opacity 0.4s ease-out, margin-bottom 0.5s ease-in;
-}
-
-.create-project-setup.open {
- opacity: 1;
- height: 160px;
- margin-bottom: calc(2.5 * var(--gridSize));
-}
-
-.create-project-setup h2 {
- color: #fff;
- font-weight: 700;
- font-size: var(--bigFontSize);
-}
-
-.create-project-setup .boxed-group-inner {
- display: flex;
- flex-direction: column;
- flex-grow: 1;
-}
-
-.create-project-setup .button {
- border-color: var(--sonarcloudBlue500);
- background-color: var(--sonarcloudBlue500);
- color: #fff;
- transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
-}
-
-.create-project-setup .button:hover,
-.create-project-setup .button:focus {
- border-color: var(--sonarcloudBlue600);
- background-color: var(--sonarcloudBlue600);
-}
-
-.create-project-actions {
- min-width: 500px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 8px 0 8px 16px;
- border-left: 1px solid transparent;
-}
-
-.create-project-actions .icon-checkbox {
- margin-right: 8px;
-}
-
.create-project-modes {
margin: 0 auto;
max-width: 500px;
}
+.create-project-manual {
+ display: flex !important;
+ justify-content: space-between;
+}
+
.create-project-import-bbs .open .boxed-group-header {
border-bottom: 1px solid var(--barBorderColor);
}