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.

CreateProjectModeSelection.tsx 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2022 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 classNames from 'classnames';
  21. import * as React from 'react';
  22. import withAppStateContext from '../../../app/components/app-state/withAppStateContext';
  23. import ChevronsIcon from '../../../components/icons/ChevronsIcon';
  24. import { translate, translateWithParameters } from '../../../helpers/l10n';
  25. import { getBaseUrl } from '../../../helpers/system';
  26. import { AlmKeys } from '../../../types/alm-settings';
  27. import { AppState } from '../../../types/appstate';
  28. import { CreateProjectModes } from './types';
  29. export interface CreateProjectModeSelectionProps {
  30. almCounts: {
  31. [k in AlmKeys]: number;
  32. };
  33. appState: AppState;
  34. loadingBindings: boolean;
  35. onSelectMode: (mode: CreateProjectModes) => void;
  36. onConfigMode: (mode: AlmKeys) => void;
  37. }
  38. const DEFAULT_ICON_SIZE = 50;
  39. function renderAlmOption(
  40. props: CreateProjectModeSelectionProps,
  41. alm: AlmKeys.Azure | AlmKeys.BitbucketServer | AlmKeys.GitHub | AlmKeys.GitLab,
  42. mode: CreateProjectModes,
  43. last = false
  44. ) {
  45. const {
  46. almCounts,
  47. appState: { canAdmin },
  48. loadingBindings
  49. } = props;
  50. const hasBitbucketCloudConf = almCounts[AlmKeys.BitbucketCloud] > 0;
  51. const isBitbucketOption = alm === AlmKeys.BitbucketServer;
  52. const count = isBitbucketOption
  53. ? almCounts[AlmKeys.BitbucketServer] + almCounts[AlmKeys.BitbucketCloud]
  54. : almCounts[alm];
  55. const hasConfig = count > 0;
  56. const hasTooManyConfig = count > 1;
  57. const disabled = loadingBindings || hasTooManyConfig || (!hasConfig && !canAdmin);
  58. const onClick = () => {
  59. if (hasTooManyConfig || (!hasConfig && !canAdmin)) {
  60. return null;
  61. }
  62. if (!hasConfig && canAdmin) {
  63. return props.onConfigMode(alm);
  64. }
  65. return props.onSelectMode(
  66. isBitbucketOption && hasBitbucketCloudConf ? CreateProjectModes.BitbucketCloud : mode
  67. );
  68. };
  69. let errorMessage = '';
  70. if (hasTooManyConfig) {
  71. errorMessage = translateWithParameters(
  72. 'onboarding.create_project.too_many_alm_instances_X',
  73. translate('alm', alm)
  74. );
  75. } else if (!hasConfig) {
  76. errorMessage = canAdmin
  77. ? translate('onboarding.create_project.alm_not_configured.admin')
  78. : translate('onboarding.create_project.alm_not_configured');
  79. }
  80. return (
  81. <div className="display-flex-column">
  82. <button
  83. className={classNames(
  84. 'button button-huge display-flex-column create-project-mode-type-alm',
  85. { disabled, 'big-spacer-right': !last }
  86. )}
  87. disabled={disabled}
  88. onClick={onClick}
  89. type="button">
  90. <img
  91. alt="" // Should be ignored by screen readers
  92. height={DEFAULT_ICON_SIZE}
  93. src={`${getBaseUrl()}/images/alm/${alm}.svg`}
  94. />
  95. <div className="medium big-spacer-top abs-height-50 display-flex-center">
  96. {translate('onboarding.create_project.select_method', alm)}
  97. </div>
  98. {loadingBindings && (
  99. <span>
  100. {translate('onboarding.create_project.check_alm_supported')}
  101. <i className="little-spacer-left spinner" />
  102. </span>
  103. )}
  104. {!loadingBindings && errorMessage && (
  105. <p className="text-muted small spacer-top" style={{ lineHeight: 1.5 }}>
  106. {errorMessage}
  107. </p>
  108. )}
  109. </button>
  110. </div>
  111. );
  112. }
  113. export function CreateProjectModeSelection(props: CreateProjectModeSelectionProps) {
  114. const {
  115. appState: { canAdmin },
  116. almCounts
  117. } = props;
  118. const almTotalCount = Object.values(almCounts).reduce((prev, cur) => prev + cur);
  119. return (
  120. <>
  121. <h1 className="huge-spacer-top huge-spacer-bottom">
  122. {translate('onboarding.create_project.select_method')}
  123. </h1>
  124. <p>{translate('onboarding.create_project.select_method.devops_platform')}</p>
  125. {almTotalCount === 0 && canAdmin && (
  126. <p className="spacer-top">
  127. {translate('onboarding.create_project.select_method.no_alm_yet.admin')}
  128. </p>
  129. )}
  130. <div className="big-spacer-top huge-spacer-bottom display-flex-center">
  131. {renderAlmOption(props, AlmKeys.Azure, CreateProjectModes.AzureDevOps)}
  132. {renderAlmOption(props, AlmKeys.BitbucketServer, CreateProjectModes.BitbucketServer)}
  133. {renderAlmOption(props, AlmKeys.GitHub, CreateProjectModes.GitHub)}
  134. {renderAlmOption(props, AlmKeys.GitLab, CreateProjectModes.GitLab, true)}
  135. </div>
  136. <p className="big-spacer-bottom">
  137. {translate('onboarding.create_project.select_method.manually')}
  138. </p>
  139. <button
  140. className="button button-huge display-flex-column create-project-mode-type-manual"
  141. onClick={() => props.onSelectMode(CreateProjectModes.Manual)}
  142. type="button">
  143. <ChevronsIcon size={DEFAULT_ICON_SIZE} />
  144. <div className="medium big-spacer-top">
  145. {translate('onboarding.create_project.select_method.manual')}
  146. </div>
  147. </button>
  148. </>
  149. );
  150. }
  151. export default withAppStateContext(CreateProjectModeSelection);