<StyledInputWrapper className="sw-flex sw-items-center">
{children ?? (
<input
- aria-label={searchInputAriaLabel}
+ aria-label={searchInputAriaLabel ?? placeholder}
autoComplete="off"
className={inputClassName}
maxLength={maxLength}
import { BitbucketCloudRepository } from '../../../../types/alm-integration';
import { AlmSettingsInstance } from '../../../../types/alm-settings';
import { Paging } from '../../../../types/types';
+import { BITBUCKET_CLOUD_PROJECTS_PAGESIZE } from '../constants';
import { CreateProjectApiCallback } from '../types';
import BitbucketCloudProjectCreateRenderer from './BitbucketCloudProjectCreateRender';
showPersonalAccessTokenForm: boolean;
}
-export const BITBUCKET_CLOUD_PROJECTS_PAGESIZE = 30;
export default class BitbucketCloudProjectCreate extends React.PureComponent<Props, State> {
mounted = false;
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { DeferredSpinner, LightPrimary, Title } from 'design-system';
import * as React from 'react';
import { translate } from '../../../../helpers/l10n';
-import { getBaseUrl } from '../../../../helpers/system';
import { BitbucketCloudRepository } from '../../../../types/alm-integration';
import { AlmKeys, AlmSettingsInstance } from '../../../../types/alm-settings';
import AlmSettingsInstanceDropdown from '../components/AlmSettingsInstanceDropdown';
-import CreateProjectPageHeader from '../components/CreateProjectPageHeader';
import PersonalAccessTokenForm from '../components/PersonalAccessTokenForm';
import WrongBindingCountAlert from '../components/WrongBindingCountAlert';
import BitbucketCloudSearchForm from './BitbucketCloudSearchForm';
return (
<>
- <CreateProjectPageHeader
- title={
- <span className="text-middle">
- <img
- alt="" // Should be ignored by screen readers
- className="spacer-right"
- height="24"
- src={`${getBaseUrl()}/images/alm/bitbucket.svg`}
- />
- {translate('onboarding.create_project.bitbucketcloud.title')}
- </span>
- }
- />
+ <header className="sw-mb-10">
+ <Title className="sw-mb-4">
+ {translate('onboarding.create_project.bitbucketcloud.title')}
+ </Title>
+ <LightPrimary className="sw-body-sm">
+ {translate('onboarding.create_project.bitbucketcloud.subtitle')}
+ </LightPrimary>
+ </header>
<AlmSettingsInstanceDropdown
almKey={AlmKeys.BitbucketCloud}
onChangeConfig={props.onSelectedAlmInstanceChange}
/>
- {loading && <i className="spinner" />}
+ <DeferredSpinner loading={loading} />
{!loading && !selectedAlmInstance && (
<WrongBindingCountAlert alm={AlmKeys.BitbucketCloud} canAdmin={!!canAdmin} />
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { FlagMessage, InputSearch, LightPrimary, Link } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
-import Link from '../../../../components/common/Link';
-import SearchBox from '../../../../components/controls/SearchBox';
-import Tooltip from '../../../../components/controls/Tooltip';
-import { Button } from '../../../../components/controls/buttons';
-import CheckIcon from '../../../../components/icons/CheckIcon';
-import QualifierIcon from '../../../../components/icons/QualifierIcon';
-import { Alert } from '../../../../components/ui/Alert';
-import DeferredSpinner from '../../../../components/ui/DeferredSpinner';
-import { translate, translateWithParameters } from '../../../../helpers/l10n';
-import { formatMeasure } from '../../../../helpers/measures';
-import { getProjectUrl, queryToSearch } from '../../../../helpers/urls';
+import ListFooter from '../../../../components/controls/ListFooter';
+import { translate } from '../../../../helpers/l10n';
+import { getBaseUrl } from '../../../../helpers/system';
+import { queryToSearch } from '../../../../helpers/urls';
import { BitbucketCloudRepository } from '../../../../types/alm-integration';
-import { ComponentQualifier } from '../../../../types/component';
-import { MetricType } from '../../../../types/metrics';
+import AlmRepoItem from '../components/AlmRepoItem';
+import { BITBUCKET_CLOUD_PROJECTS_PAGESIZE } from '../constants';
import { CreateProjectModes } from '../types';
export interface BitbucketCloudSearchFormProps {
if (repositories.length === 0 && searchQuery.length === 0 && !searching) {
return (
- <Alert className="spacer-top" variant="warning">
+ <FlagMessage className="sw-mt-2" variant="warning">
<FormattedMessage
defaultMessage={translate('onboarding.create_project.bitbucketcloud.no_projects')}
id="onboarding.create_project.bitbucketcloud.no_projects"
),
}}
/>
- </Alert>
+ </FlagMessage>
);
}
return (
- <div className="boxed-group big-padded create-project-import">
- <SearchBox
- className="spacer"
- loading={searching}
- minLength={3}
- onChange={props.onSearch}
- placeholder={translate('onboarding.create_project.search_prompt')}
- />
-
- <hr />
+ <div>
+ <div className="sw-flex sw-items-center sw-mb-6 sw-w-abs-400">
+ <InputSearch
+ clearIconAriaLabel={translate('clear')}
+ loading={searching}
+ minLength={3}
+ onChange={props.onSearch}
+ placeholder={translate('onboarding.create_project.search_prompt')}
+ size="full"
+ value={searchQuery}
+ />
+ </div>
{repositories.length === 0 ? (
- <div className="padded">{translate('no_results')}</div>
+ <div className="sw-py-6 sw-px-2">
+ <LightPrimary className="sw-body-sm">{translate('no_results')}</LightPrimary>
+ </div>
) : (
- <table className="data zebra zebra-hover">
- <tbody>
- {repositories.map((repository) => (
- <tr key={repository.uuid}>
- <td>
- <Tooltip overlay={repository.slug}>
- <strong className="project-name display-inline-block text-ellipsis">
- {repository.sqProjectKey ? (
- <Link to={getProjectUrl(repository.sqProjectKey)}>
- <QualifierIcon
- className="spacer-right"
- qualifier={ComponentQualifier.Project}
- />
- {repository.name}
- </Link>
- ) : (
- repository.name
- )}
- </strong>
- </Tooltip>
- <br />
- <Tooltip overlay={repository.projectKey}>
- <span className="text-muted project-path display-inline-block text-ellipsis">
- {repository.projectKey}
- </span>
- </Tooltip>
- </td>
- <td>
- <Link
- className="display-inline-flex-center big-spacer-right"
- to={getRepositoryUrl(repository.workspace, repository.slug)}
- target="_blank"
- >
- {translate('onboarding.create_project.bitbucketcloud.link')}
- </Link>
- </td>
- {repository.sqProjectKey ? (
- <td>
- <span className="display-flex-center display-flex-justify-end already-set-up">
- <CheckIcon className="little-spacer-right" size={12} />
- {translate('onboarding.create_project.repository_imported')}
- </span>
- </td>
- ) : (
- <td className="text-right">
- <Button
- onClick={() => {
- props.onImport(repository.slug);
- }}
- >
- {translate('onboarding.create_project.set_up')}
- </Button>
- </td>
- )}
- </tr>
- ))}
- </tbody>
- </table>
+ <div className="sw-flex sw-flex-col sw-gap-3">
+ {repositories.map((r) => (
+ <AlmRepoItem
+ key={r.uuid}
+ almKey={r.slug}
+ almUrl={getRepositoryUrl(r.workspace, r.slug)}
+ almUrlText={translate('onboarding.create_project.bitbucketcloud.link')}
+ almIconSrc={`${getBaseUrl()}/images/alm/bitbucket.svg`}
+ sqProjectKey={r.sqProjectKey}
+ onImport={props.onImport}
+ primaryTextNode={<span title={r.name}>{r.name}</span>}
+ secondaryTextNode={<span title={r.projectKey}>{r.projectKey}</span>}
+ />
+ ))}
+ </div>
)}
- <footer className="spacer-top note text-center">
- {isLastPage &&
- translateWithParameters(
- 'x_of_y_shown',
- formatMeasure(repositories.length, MetricType.Integer, null),
- formatMeasure(repositories.length, MetricType.Integer, null)
- )}
- {!isLastPage && (
- <Button
- className="spacer-left"
- disabled={loadingMore}
- data-test="show-more"
- onClick={props.onLoadMore}
- >
- {translate('show_more')}
- </Button>
- )}
- <DeferredSpinner
- className="text-bottom spacer-left position-absolute"
- loading={loadingMore}
- />
- </footer>
+
+ <ListFooter
+ className="sw-mb-10"
+ count={repositories.length}
+ // we don't know the total, so only provide when we've reached the last page
+ total={isLastPage ? repositories.length : undefined}
+ pageSize={BITBUCKET_CLOUD_PROJECTS_PAGESIZE}
+ loadMore={props.onLoadMore}
+ loading={loadingMore}
+ useMIUIButtons
+ />
</div>
);
}
<div className="sw-flex sw-items-center sw-mb-6">
<InputSearch
size="large"
+ loading={loadingRepositories}
onChange={props.onSearch}
placeholder={translate('onboarding.create_project.search_repositories')}
value={searchQuery}
clearIconAriaLabel={translate('clear')}
/>
- <DeferredSpinner loading={loadingRepositories} className="sw-ml-2" />
</div>
{repositories.length === 0 ? (
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { act, screen, within } from '@testing-library/react';
+import { act, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as React from 'react';
import { renderApp } from '../../../../helpers/testReactTestingUtils';
import { byLabelText, byRole, byText } from '../../../../helpers/testSelector';
import CreateProjectPage from '../CreateProjectPage';
+import { BITBUCKET_CLOUD_PROJECTS_PAGESIZE } from '../constants';
jest.mock('../../../../api/alm-integrations');
jest.mock('../../../../api/alm-settings');
projectItem = screen.getByRole('row', { name: /BitbucketCloud Repo 2/ });
const setupButton = within(projectItem).getByRole('button', {
- name: 'onboarding.create_project.set_up',
+ name: 'onboarding.create_project.import',
});
await user.click(setupButton);
expect(searchForBitbucketCloudRepositories).toHaveBeenLastCalledWith(
'conf-bitbucketcloud-2',
'',
- 30,
+ BITBUCKET_CLOUD_PROJECTS_PAGESIZE,
1
);
expect(searchForBitbucketCloudRepositories).toHaveBeenLastCalledWith(
'conf-bitbucketcloud-2',
'search',
- 30,
+ BITBUCKET_CLOUD_PROJECTS_PAGESIZE,
1
);
});
it('should have load more', async () => {
const user = userEvent.setup();
- almIntegrationHandler.createRandomBitbucketCloudProjectsWithLoadMore(2, 4);
+ almIntegrationHandler.createRandomBitbucketCloudProjectsWithLoadMore(
+ BITBUCKET_CLOUD_PROJECTS_PAGESIZE,
+ BITBUCKET_CLOUD_PROJECTS_PAGESIZE + 1
+ );
renderCreateProject();
expect(screen.getByText('onboarding.create_project.bitbucketcloud.title')).toBeInTheDocument();
await selectEvent.select(ui.instanceSelector.get(), [/conf-bitbucketcloud-2/]);
});
- const loadMore = screen.getByRole('button', { name: 'show_more' });
- expect(loadMore).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: 'show_more' })).toBeInTheDocument();
/*
* Next api call response will simulate reaching the last page so we can test the
* loadmore button disapperance.
*/
- almIntegrationHandler.createRandomBitbucketCloudProjectsWithLoadMore(4, 4);
- await user.click(loadMore);
+ almIntegrationHandler.createRandomBitbucketCloudProjectsWithLoadMore(
+ BITBUCKET_CLOUD_PROJECTS_PAGESIZE + 1,
+ BITBUCKET_CLOUD_PROJECTS_PAGESIZE + 1
+ );
+ await user.click(screen.getByRole('button', { name: 'show_more' }));
expect(searchForBitbucketCloudRepositories).toHaveBeenLastCalledWith(
'conf-bitbucketcloud-2',
'',
- 30,
+ BITBUCKET_CLOUD_PROJECTS_PAGESIZE,
2
);
- expect(loadMore).not.toBeInTheDocument();
+
+ await waitFor(() => {
+ expect(screen.queryByRole('button', { name: 'show_more' })).not.toBeInTheDocument();
+ });
});
function renderCreateProject() {
export const PROJECT_NAME_MAX_LEN = 255;
export const DEFAULT_BBS_PAGE_SIZE = 25;
+
+export const BITBUCKET_CLOUD_PROJECTS_PAGESIZE = 20;
onboarding.create_project.azure.no_repositories=Could not fetch repositories for this project. Contact your system administrator, or {link}.
onboarding.create_project.azure.no_results=No repositories match your search query.
onboarding.create_project.bitbucketcloud.title=Bitbucket Cloud project onboarding
+onboarding.create_project.bitbucketcloud.subtitle=Import projects from one of your Bitbucket Cloud workspaces
onboarding.create_project.bitbucketcloud.no_projects=No projects could be fetched from Bitbucket. Contact your system administrator, or {link}.
onboarding.create_project.bitbucketcloud.link=See on Bitbucket
onboarding.create_project.github.title=GitHub project onboarding