You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GitlabProjectCreate.tsx 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import { LabelValueSelectOption } from 'design-system';
  21. import React, { useCallback, useMemo } from 'react';
  22. import { getGitlabProjects } from '../../../../api/alm-integrations';
  23. import { useLocation } from '../../../../components/hoc/withRouter';
  24. import { GitlabProject } from '../../../../types/alm-integration';
  25. import { AlmKeys } from '../../../../types/alm-settings';
  26. import { DopSetting } from '../../../../types/dop-translation';
  27. import { ImportProjectParam } from '../CreateProjectPage';
  28. import { REPOSITORY_PAGE_SIZE } from '../constants';
  29. import MonorepoProjectCreate from '../monorepo/MonorepoProjectCreate';
  30. import { CreateProjectModes } from '../types';
  31. import { useProjectCreate } from '../useProjectCreate';
  32. import { useProjectRepositorySearch } from '../useProjectRepositorySearch';
  33. import GitlabPersonalAccessTokenForm from './GItlabPersonalAccessTokenForm';
  34. import GitlabProjectCreateRenderer from './GitlabProjectCreateRenderer';
  35. interface Props {
  36. isLoadingBindings: boolean;
  37. onProjectSetupDone: (importProjects: ImportProjectParam) => void;
  38. dopSettings: DopSetting[];
  39. }
  40. export default function GitlabProjectCreate(props: Readonly<Props>) {
  41. const { dopSettings, isLoadingBindings, onProjectSetupDone } = props;
  42. const {
  43. handlePersonalAccessTokenCreated,
  44. handleSelectRepository,
  45. isInitialized,
  46. isLoadingRepositories,
  47. isMonorepoSetup,
  48. onSelectedAlmInstanceChange,
  49. onSelectDopSetting,
  50. projectsPaging,
  51. repositories,
  52. resetPersonalAccessToken,
  53. searchQuery,
  54. selectedDopSetting,
  55. selectedRepository,
  56. setIsInitialized,
  57. setIsLoadingRepositories,
  58. setProjectsPaging,
  59. setRepositories,
  60. setResetPersonalAccessToken,
  61. setSearchQuery,
  62. setShowPersonalAccessTokenForm,
  63. showPersonalAccessTokenForm,
  64. } = useProjectCreate<GitlabProject, undefined>(
  65. AlmKeys.GitLab,
  66. dopSettings,
  67. ({ id }) => id,
  68. REPOSITORY_PAGE_SIZE,
  69. );
  70. const location = useLocation();
  71. const repositoryOptions = useMemo(() => {
  72. return repositories.map(transformToOption);
  73. }, [repositories]);
  74. const fetchRepositories = useCallback(
  75. (_orgKey?: string, query = '', pageIndex = 1, more = false) => {
  76. if (showPersonalAccessTokenForm || !selectedDopSetting) {
  77. return Promise.resolve();
  78. }
  79. setIsLoadingRepositories(true);
  80. // eslint-disable-next-line local-rules/no-api-imports
  81. return getGitlabProjects({
  82. almSetting: selectedDopSetting.key,
  83. page: pageIndex,
  84. pageSize: REPOSITORY_PAGE_SIZE,
  85. query,
  86. })
  87. .then((result) => {
  88. if (result?.projects) {
  89. setProjectsPaging(result.projectsPaging);
  90. setRepositories(
  91. more && repositories && repositories.length > 0
  92. ? [...repositories, ...result.projects]
  93. : result.projects,
  94. );
  95. setIsInitialized(true);
  96. }
  97. })
  98. .finally(() => {
  99. setIsLoadingRepositories(false);
  100. })
  101. .catch(() => {
  102. setResetPersonalAccessToken(true);
  103. setShowPersonalAccessTokenForm(true);
  104. setIsLoadingRepositories(false);
  105. });
  106. },
  107. [
  108. repositories,
  109. selectedDopSetting,
  110. setIsInitialized,
  111. setIsLoadingRepositories,
  112. setProjectsPaging,
  113. setRepositories,
  114. setResetPersonalAccessToken,
  115. setShowPersonalAccessTokenForm,
  116. showPersonalAccessTokenForm,
  117. ],
  118. );
  119. const handleImportRepository = useCallback(
  120. (repoKeys: string[]) => {
  121. if (selectedDopSetting && repoKeys.length > 0) {
  122. onProjectSetupDone({
  123. almSetting: selectedDopSetting.key,
  124. creationMode: CreateProjectModes.GitLab,
  125. monorepo: false,
  126. projects: repoKeys.map((repoKeys) => ({ gitlabProjectId: repoKeys })),
  127. });
  128. }
  129. },
  130. [onProjectSetupDone, selectedDopSetting],
  131. );
  132. const handleLoadMore = useCallback(() => {
  133. fetchRepositories(undefined, searchQuery, projectsPaging.pageIndex + 1, true);
  134. }, [fetchRepositories, projectsPaging, searchQuery]);
  135. const { onSearch } = useProjectRepositorySearch(
  136. AlmKeys.GitLab,
  137. fetchRepositories,
  138. isInitialized,
  139. selectedDopSetting,
  140. undefined,
  141. setSearchQuery,
  142. showPersonalAccessTokenForm,
  143. );
  144. return isMonorepoSetup ? (
  145. <MonorepoProjectCreate
  146. dopSettings={dopSettings}
  147. error={false}
  148. loadingBindings={isLoadingBindings}
  149. loadingOrganizations={false}
  150. loadingRepositories={isLoadingRepositories}
  151. onProjectSetupDone={onProjectSetupDone}
  152. onSearchRepositories={onSearch}
  153. onSelectDopSetting={onSelectDopSetting}
  154. onSelectRepository={handleSelectRepository}
  155. personalAccessTokenComponent={
  156. !isLoadingRepositories &&
  157. selectedDopSetting && (
  158. <GitlabPersonalAccessTokenForm
  159. almSetting={selectedDopSetting}
  160. resetPat={resetPersonalAccessToken}
  161. onPersonalAccessTokenCreated={handlePersonalAccessTokenCreated}
  162. />
  163. )
  164. }
  165. repositoryOptions={repositoryOptions}
  166. repositorySearchQuery={searchQuery}
  167. selectedDopSetting={selectedDopSetting}
  168. selectedRepository={selectedRepository ? transformToOption(selectedRepository) : undefined}
  169. showPersonalAccessToken={showPersonalAccessTokenForm || Boolean(location.query.resetPat)}
  170. />
  171. ) : (
  172. <GitlabProjectCreateRenderer
  173. almInstances={dopSettings.map((dopSetting) => ({
  174. alm: dopSetting.type,
  175. key: dopSetting.key,
  176. url: dopSetting.url,
  177. }))}
  178. loading={isLoadingRepositories || isLoadingBindings}
  179. onImport={handleImportRepository}
  180. onLoadMore={handleLoadMore}
  181. onPersonalAccessTokenCreated={handlePersonalAccessTokenCreated}
  182. onSearch={onSearch}
  183. onSelectedAlmInstanceChange={onSelectedAlmInstanceChange}
  184. projects={repositories}
  185. projectsPaging={projectsPaging}
  186. resetPat={resetPersonalAccessToken || Boolean(location.query.resetPat)}
  187. searchQuery={searchQuery}
  188. selectedAlmInstance={
  189. selectedDopSetting && {
  190. alm: selectedDopSetting.type,
  191. key: selectedDopSetting.key,
  192. url: selectedDopSetting.url,
  193. }
  194. }
  195. showPersonalAccessTokenForm={showPersonalAccessTokenForm || Boolean(location.query.resetPat)}
  196. />
  197. );
  198. }
  199. function transformToOption({ id, name }: GitlabProject): LabelValueSelectOption<string> {
  200. return { value: id, label: name };
  201. }