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.

ProjectBaselineSelector.tsx 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 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 * as classNames from 'classnames';
  21. import * as React from 'react';
  22. import { ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons';
  23. import Radio from 'sonar-ui-common/components/controls/Radio';
  24. import { Alert } from 'sonar-ui-common/components/ui/Alert';
  25. import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
  26. import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
  27. import { Branch } from '../../../types/branch-like';
  28. import { validateSetting } from '../utils';
  29. import BaselineSettingAnalysis from './BaselineSettingAnalysis';
  30. import BaselineSettingDays from './BaselineSettingDays';
  31. import BaselineSettingPreviousVersion from './BaselineSettingPreviousVersion';
  32. import BaselineSettingReferenceBranch from './BaselineSettingReferenceBranch';
  33. import BranchAnalysisList from './BranchAnalysisList';
  34. export interface ProjectBaselineSelectorProps {
  35. analysis?: string;
  36. branchList: Branch[];
  37. branchesEnabled?: boolean;
  38. component: string;
  39. currentSetting?: T.NewCodePeriodSettingType;
  40. currentSettingValue?: string;
  41. days: string;
  42. generalSetting: T.NewCodePeriod;
  43. onCancel: () => void;
  44. onSelectAnalysis: (analysis: T.ParsedAnalysis) => void;
  45. onSelectDays: (value: string) => void;
  46. onSelectReferenceBranch: (value: string) => void;
  47. onSelectSetting: (value?: T.NewCodePeriodSettingType) => void;
  48. onSubmit: (e: React.SyntheticEvent<HTMLFormElement>) => void;
  49. onToggleSpecificSetting: (selection: boolean) => void;
  50. referenceBranch?: string;
  51. saving: boolean;
  52. selected?: T.NewCodePeriodSettingType;
  53. overrideGeneralSetting: boolean;
  54. }
  55. function renderGeneralSetting(generalSetting: T.NewCodePeriod) {
  56. let setting: string;
  57. let description: string;
  58. if (generalSetting.type === 'NUMBER_OF_DAYS') {
  59. setting = `${translate('baseline.number_days')} (${translateWithParameters(
  60. 'duration.days',
  61. generalSetting.value || '?'
  62. )})`;
  63. description = translate('baseline.number_days.description');
  64. } else {
  65. setting = translate('baseline.previous_version');
  66. description = translate('baseline.previous_version.description');
  67. }
  68. return (
  69. <div className="general-setting">
  70. <strong>{setting}</strong>: {description}
  71. </div>
  72. );
  73. }
  74. function branchToOption(b: Branch) {
  75. return { value: b.name, isMain: b.isMain };
  76. }
  77. export default function ProjectBaselineSelector(props: ProjectBaselineSelectorProps) {
  78. const {
  79. analysis,
  80. branchList,
  81. branchesEnabled,
  82. component,
  83. currentSetting,
  84. currentSettingValue,
  85. days,
  86. generalSetting,
  87. overrideGeneralSetting,
  88. referenceBranch,
  89. saving,
  90. selected
  91. } = props;
  92. const { isChanged, isValid } = validateSetting({
  93. analysis,
  94. currentSetting,
  95. currentSettingValue,
  96. days,
  97. overrideGeneralSetting,
  98. referenceBranch,
  99. selected
  100. });
  101. return (
  102. <form className="project-baseline-selector" onSubmit={props.onSubmit}>
  103. <div className="big-spacer-top spacer-bottom" role="radiogroup">
  104. <Radio
  105. checked={!overrideGeneralSetting}
  106. className="big-spacer-bottom"
  107. onCheck={() => props.onToggleSpecificSetting(false)}
  108. value="general">
  109. {translate('project_baseline.general_setting')}
  110. </Radio>
  111. <div className="big-spacer-left">{renderGeneralSetting(generalSetting)}</div>
  112. <Radio
  113. checked={overrideGeneralSetting}
  114. className="huge-spacer-top"
  115. onCheck={() => props.onToggleSpecificSetting(true)}
  116. value="specific">
  117. {translate('project_baseline.specific_setting')}
  118. </Radio>
  119. </div>
  120. <div className="big-spacer-left big-spacer-right project-baseline-setting">
  121. <div className="display-flex-row big-spacer-bottom" role="radiogroup">
  122. <BaselineSettingPreviousVersion
  123. disabled={!overrideGeneralSetting}
  124. onSelect={props.onSelectSetting}
  125. selected={overrideGeneralSetting && selected === 'PREVIOUS_VERSION'}
  126. />
  127. <BaselineSettingDays
  128. days={days}
  129. disabled={!overrideGeneralSetting}
  130. isChanged={isChanged}
  131. isValid={isValid}
  132. onChangeDays={props.onSelectDays}
  133. onSelect={props.onSelectSetting}
  134. selected={overrideGeneralSetting && selected === 'NUMBER_OF_DAYS'}
  135. />
  136. {branchesEnabled ? (
  137. <BaselineSettingReferenceBranch
  138. branchList={branchList.map(branchToOption)}
  139. disabled={!overrideGeneralSetting}
  140. onChangeReferenceBranch={props.onSelectReferenceBranch}
  141. onSelect={props.onSelectSetting}
  142. referenceBranch={referenceBranch || ''}
  143. selected={overrideGeneralSetting && selected === 'REFERENCE_BRANCH'}
  144. settingLevel="project"
  145. />
  146. ) : (
  147. <BaselineSettingAnalysis
  148. disabled={!overrideGeneralSetting}
  149. onSelect={props.onSelectSetting}
  150. selected={overrideGeneralSetting && selected === 'SPECIFIC_ANALYSIS'}
  151. />
  152. )}
  153. </div>
  154. {selected === 'SPECIFIC_ANALYSIS' && (
  155. <BranchAnalysisList
  156. analysis={analysis || ''}
  157. branch="master"
  158. component={component}
  159. onSelectAnalysis={props.onSelectAnalysis}
  160. />
  161. )}
  162. </div>
  163. <div className={classNames('big-spacer-top', { invisible: !isChanged })}>
  164. <Alert variant="info" className="spacer-bottom">
  165. {translate('baseline.next_analysis_notice')}
  166. </Alert>
  167. <DeferredSpinner className="spacer-right" loading={saving} />
  168. <SubmitButton disabled={saving || !isValid || !isChanged}>{translate('save')}</SubmitButton>
  169. <ResetButtonLink className="spacer-left" onClick={props.onCancel}>
  170. {translate('cancel')}
  171. </ResetButtonLink>
  172. </div>
  173. </form>
  174. );
  175. }