]> source.dussan.org Git - sonarqube.git/blob
e76452194c9a16872ce7346fc0c71009722884d2
[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 { Button, SubmitButton } from 'sonar-ui-common/components/controls/buttons';
24 import Select from 'sonar-ui-common/components/controls/Select';
25 import AlertSuccessIcon from 'sonar-ui-common/components/icons/AlertSuccessIcon';
26 import { Alert } from 'sonar-ui-common/components/ui/Alert';
27 import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
28 import { translate } from 'sonar-ui-common/helpers/l10n';
29 import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../../../types/alm-settings';
30 import AlmSpecificForm from './AlmSpecificForm';
31
32 export interface PRDecorationBindingRendererProps {
33   formData: T.Omit<ProjectAlmBindingResponse, 'alm'>;
34   instances: AlmSettingsInstance[];
35   isChanged: boolean;
36   isConfigured: boolean;
37   isValid: boolean;
38   loading: boolean;
39   onFieldChange: (id: keyof ProjectAlmBindingResponse, value: string | boolean) => void;
40   onReset: () => void;
41   onSubmit: () => void;
42   saving: boolean;
43   success: boolean;
44   monorepoEnabled: boolean;
45 }
46
47 function optionRenderer(instance: AlmSettingsInstance) {
48   return instance.url ? (
49     <>
50       <span>{instance.key} — </span>
51       <span className="text-muted">{instance.url}</span>
52     </>
53   ) : (
54     <span>{instance.key}</span>
55   );
56 }
57
58 export default function PRDecorationBindingRenderer(props: PRDecorationBindingRendererProps) {
59   const {
60     formData,
61     instances,
62     isChanged,
63     isConfigured,
64     isValid,
65     loading,
66     saving,
67     success,
68     monorepoEnabled
69   } = props;
70
71   if (loading) {
72     return <DeferredSpinner />;
73   }
74
75   if (instances.length < 1) {
76     return (
77       <div>
78         <Alert className="spacer-top huge-spacer-bottom" variant="info">
79           <FormattedMessage
80             defaultMessage={translate('settings.pr_decoration.binding.no_bindings')}
81             id="settings.pr_decoration.binding.no_bindings"
82             values={{
83               link: (
84                 <Link to="/documentation/analysis/pull-request/#pr-decoration">
85                   {translate('learn_more')}
86                 </Link>
87               )
88             }}
89           />
90         </Alert>
91       </div>
92     );
93   }
94
95   const selected = formData.key && instances.find(i => i.key === formData.key);
96   const alm = selected && selected.alm;
97
98   return (
99     <div>
100       <header className="page-header">
101         <h1 className="page-title">{translate('settings.pr_decoration.binding.title')}</h1>
102       </header>
103
104       <div className="markdown small spacer-top big-spacer-bottom">
105         {translate('settings.pr_decoration.binding.description')}
106       </div>
107
108       <form
109         onSubmit={(event: React.SyntheticEvent<HTMLFormElement>) => {
110           event.preventDefault();
111           props.onSubmit();
112         }}>
113         <div className="form-field">
114           <label htmlFor="name">
115             {translate('settings.pr_decoration.binding.form.name')}
116             <em className="mandatory spacer-right">*</em>
117           </label>
118           <Select
119             autosize={true}
120             className="abs-width-400"
121             clearable={false}
122             id="name"
123             menuContainerStyle={{
124               maxWidth: '210%' /* Allow double the width of the select */,
125               width: 'auto'
126             }}
127             onChange={(instance: AlmSettingsInstance) => props.onFieldChange('key', instance.key)}
128             optionRenderer={optionRenderer}
129             options={instances}
130             searchable={false}
131             value={formData.key}
132             valueKey="key"
133             valueRenderer={optionRenderer}
134           />
135         </div>
136
137         {alm && (
138           <AlmSpecificForm
139             alm={alm}
140             formData={formData}
141             onFieldChange={props.onFieldChange}
142             monorepoEnabled={monorepoEnabled}
143           />
144         )}
145
146         <div className="display-flex-center">
147           <DeferredSpinner className="spacer-right" loading={saving} />
148           {isChanged && (
149             <SubmitButton className="spacer-right button-success" disabled={saving || !isValid}>
150               <span data-test="project-settings__alm-save">{translate('save')}</span>
151             </SubmitButton>
152           )}
153           {isConfigured && (
154             <Button className="spacer-right" onClick={props.onReset}>
155               <span data-test="project-settings__alm-reset">{translate('reset_verb')}</span>
156             </Button>
157           )}
158           {!saving && success && (
159             <span className="text-success">
160               <AlertSuccessIcon className="spacer-right" />
161               {translate('settings.state.saved')}
162             </span>
163           )}
164         </div>
165       </form>
166     </div>
167   );
168 }