]> source.dussan.org Git - sonarqube.git/blob
db66a5ebe05bf85a72353d462955c04b87efc919
[sonarqube.git] /
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 React from 'react';
21 import { FormattedMessage } from 'react-intl';
22 import { Link } from 'react-router';
23 import { Alert } from '../../../../components/ui/Alert';
24 import MandatoryFieldMarker from '../../../../components/ui/MandatoryFieldMarker';
25 import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
26 import { translate } from '../../../../helpers/l10n';
27 import { convertGithubApiUrlToLink, stripTrailingSlash } from '../../../../helpers/urls';
28 import {
29   AlmKeys,
30   AlmSettingsInstance,
31   ProjectAlmBindingResponse
32 } from '../../../../types/alm-settings';
33 import InputForBoolean from '../inputs/InputForBoolean';
34
35 export interface AlmSpecificFormProps {
36   alm: AlmKeys;
37   instances: AlmSettingsInstance[];
38   formData: T.Omit<ProjectAlmBindingResponse, 'alm'>;
39   onFieldChange: (id: keyof ProjectAlmBindingResponse, value: string | boolean) => void;
40   monorepoEnabled: boolean;
41 }
42
43 interface LabelProps {
44   id: string;
45   optional?: boolean;
46 }
47
48 interface CommonFieldProps extends LabelProps {
49   help?: boolean;
50   helpParams?: T.Dict<string | JSX.Element>;
51   helpExample?: JSX.Element;
52   onFieldChange: (id: keyof ProjectAlmBindingResponse, value: string | boolean) => void;
53   propKey: keyof ProjectAlmBindingResponse;
54 }
55
56 function renderFieldWrapper(
57   label: React.ReactNode,
58   input: React.ReactNode,
59   help?: React.ReactNode
60 ) {
61   return (
62     <div className="settings-definition">
63       <div className="settings-definition-left">
64         {label}
65         {help && <div className="markdown small spacer-top">{help}</div>}
66       </div>
67       <div className="settings-definition-right padded-top">{input}</div>
68     </div>
69   );
70 }
71
72 function renderHelp({ help, helpExample, helpParams, id }: CommonFieldProps) {
73   return (
74     help && (
75       <>
76         <FormattedMessage
77           defaultMessage={translate('settings.pr_decoration.binding.form', id, 'help')}
78           id={`settings.pr_decoration.binding.form.${id}.help`}
79           values={helpParams}
80         />
81         {helpExample && (
82           <div className="spacer-top nowrap">
83             {translate('example')}: <em>{helpExample}</em>
84           </div>
85         )}
86       </>
87     )
88   );
89 }
90
91 function renderLabel(props: LabelProps) {
92   const { optional, id } = props;
93   return (
94     <label className="h3" htmlFor={id}>
95       {translate('settings.pr_decoration.binding.form', id)}
96       {!optional && <MandatoryFieldMarker />}
97     </label>
98   );
99 }
100
101 function renderBooleanField(
102   props: Omit<CommonFieldProps, 'optional'> & {
103     value: boolean;
104     inputExtra?: React.ReactNode;
105   }
106 ) {
107   const { id, value, onFieldChange, propKey, inputExtra } = props;
108   return renderFieldWrapper(
109     renderLabel({ ...props, optional: true }),
110     <div className="display-flex-center big-spacer-top">
111       <InputForBoolean
112         isDefault={true}
113         name={id}
114         onChange={v => onFieldChange(propKey, v)}
115         value={value}
116       />
117       {inputExtra}
118     </div>,
119     renderHelp(props)
120   );
121 }
122
123 function renderField(
124   props: CommonFieldProps & {
125     value: string;
126   }
127 ) {
128   const { id, propKey, value, onFieldChange } = props;
129   return renderFieldWrapper(
130     renderLabel(props),
131     <input
132       className="input-super-large big-spacer-top"
133       id={id}
134       maxLength={256}
135       name={id}
136       onChange={e => onFieldChange(propKey, e.currentTarget.value)}
137       type="text"
138       value={value}
139     />,
140     renderHelp(props)
141   );
142 }
143
144 export default function AlmSpecificForm(props: AlmSpecificFormProps) {
145   const {
146     alm,
147     instances,
148     formData: { repository, slug, summaryCommentEnabled, monorepo },
149     monorepoEnabled
150   } = props;
151
152   let formFields: JSX.Element;
153   const instance = instances.find(i => i.alm === alm);
154
155   switch (alm) {
156     case AlmKeys.Azure:
157       formFields = (
158         <>
159           {renderField({
160             help: true,
161             helpExample: <strong>My Project</strong>,
162             id: 'azure.project',
163             onFieldChange: props.onFieldChange,
164             propKey: 'slug',
165             value: slug || ''
166           })}
167           {renderField({
168             help: true,
169             helpExample: <strong>My Repository</strong>,
170             id: 'azure.repository',
171             onFieldChange: props.onFieldChange,
172             propKey: 'repository',
173             value: repository || ''
174           })}
175         </>
176       );
177       break;
178     case AlmKeys.BitbucketServer:
179       formFields = (
180         <>
181           {renderField({
182             help: true,
183             helpExample: (
184               <>
185                 {instance?.url
186                   ? `${stripTrailingSlash(instance.url)}/projects/`
187                   : 'https://bb.company.com/projects/'}
188                 <strong>{'MY_PROJECT_KEY'}</strong>
189                 {'/repos/my-repository-slug/browse'}
190               </>
191             ),
192             id: 'bitbucket.repository',
193             onFieldChange: props.onFieldChange,
194             propKey: 'repository',
195             value: repository || ''
196           })}
197           {renderField({
198             help: true,
199             helpExample: (
200               <>
201                 {instance?.url
202                   ? `${stripTrailingSlash(instance.url)}/projects/MY_PROJECT_KEY/repos/`
203                   : 'https://bb.company.com/projects/MY_PROJECT_KEY/repos/'}
204                 <strong>{'my-repository-slug'}</strong>
205                 {'/browse'}
206               </>
207             ),
208             id: 'bitbucket.slug',
209             onFieldChange: props.onFieldChange,
210             propKey: 'slug',
211             value: slug || ''
212           })}
213         </>
214       );
215       break;
216     case AlmKeys.BitbucketCloud:
217       formFields = (
218         <>
219           {renderField({
220             help: true,
221             helpExample: (
222               <>
223                 {'https://bitbucket.org/my-workspace/'}
224                 <strong>{'my-repository-slug'}</strong>
225               </>
226             ),
227             id: 'bitbucketcloud.repository',
228             onFieldChange: props.onFieldChange,
229             propKey: 'repository',
230             value: repository || ''
231           })}
232         </>
233       );
234       break;
235     case AlmKeys.GitHub:
236       formFields = (
237         <>
238           {renderField({
239             help: true,
240             helpExample: (
241               <>
242                 {instance?.url
243                   ? `${stripTrailingSlash(convertGithubApiUrlToLink(instance.url))}/`
244                   : 'https://github.com/'}
245                 <strong>{'sonarsource/sonarqube'}</strong>
246               </>
247             ),
248             id: 'github.repository',
249             onFieldChange: props.onFieldChange,
250             propKey: 'repository',
251             value: repository || ''
252           })}
253           {renderBooleanField({
254             help: true,
255             id: 'github.summary_comment_setting',
256             onFieldChange: props.onFieldChange,
257             propKey: 'summaryCommentEnabled',
258             value: summaryCommentEnabled === undefined ? true : summaryCommentEnabled
259           })}
260         </>
261       );
262       break;
263     case AlmKeys.GitLab:
264       formFields = (
265         <>
266           {renderField({
267             help: true,
268             helpExample: <strong>123456</strong>,
269             id: 'gitlab.repository',
270             onFieldChange: props.onFieldChange,
271             propKey: 'repository',
272             value: repository || ''
273           })}
274         </>
275       );
276       break;
277   }
278
279   return (
280     <>
281       {formFields}
282       {monorepoEnabled &&
283         renderBooleanField({
284           help: true,
285           helpParams: {
286             doc_link: (
287               <Link to={ALM_DOCUMENTATION_PATHS[alm]} target="_blank">
288                 {translate('learn_more')}
289               </Link>
290             )
291           },
292           id: 'monorepo',
293           onFieldChange: props.onFieldChange,
294           propKey: 'monorepo',
295           value: monorepo,
296           inputExtra: monorepo && (
297             <Alert className="no-margin-bottom spacer-left" variant="warning" display="inline">
298               {translate('settings.pr_decoration.binding.form.monorepo.warning')}
299             </Alert>
300           )
301         })}
302     </>
303   );
304 }