3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 import { FlagMessage, InputField, Note, SubHeading, Switch } from 'design-system';
21 import * as React from 'react';
22 import { FormattedMessage } from 'react-intl';
23 import withAvailableFeatures, {
24 WithAvailableFeaturesProps,
25 } from '../../../../app/components/available-features/withAvailableFeatures';
26 import DocLink from '../../../../components/common/DocLink';
27 import MandatoryFieldMarker from '../../../../components/ui/MandatoryFieldMarker';
28 import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
29 import { translate } from '../../../../helpers/l10n';
30 import { convertGithubApiUrlToLink, stripTrailingSlash } from '../../../../helpers/urls';
34 ProjectAlmBindingResponse,
35 } from '../../../../types/alm-settings';
36 import { Feature } from '../../../../types/features';
37 import { Dict } from '../../../../types/types';
39 export interface AlmSpecificFormProps extends WithAvailableFeaturesProps {
41 instances: AlmSettingsInstance[];
42 formData: Omit<ProjectAlmBindingResponse, 'alm'>;
43 onFieldChange: (id: keyof ProjectAlmBindingResponse, value: string | boolean) => void;
46 interface LabelProps {
51 interface CommonFieldProps extends LabelProps {
53 helpParams?: Dict<string | JSX.Element>;
54 helpExample?: JSX.Element;
55 onFieldChange: (id: keyof ProjectAlmBindingResponse, value: string | boolean) => void;
56 propKey: keyof ProjectAlmBindingResponse;
59 function renderFieldWrapper(
60 label: React.ReactNode,
61 input: React.ReactNode,
62 help?: React.ReactNode,
65 <div className="sw-p-6 sw-flex sw-gap-12">
66 <div className="sw-w-abs-300">
67 <SubHeading>{label}</SubHeading>
68 {help && <div className="markdown">{help}</div>}
70 <div className="sw-flex-1">{input}</div>
75 function renderHelp({ help, helpExample, helpParams = {}, id }: CommonFieldProps) {
80 defaultMessage={translate('settings.pr_decoration.binding.form', id, 'help')}
81 id={`settings.pr_decoration.binding.form.${id}.help`}
85 <div className="sw-mt-2 sw-whitespace-nowrap">
86 {translate('example')}: <em>{helpExample}</em>
94 function renderLabel(props: LabelProps) {
95 const { optional, id } = props;
99 {translate('settings.pr_decoration.binding.form', id)}
100 {!optional && <MandatoryFieldMarker />}
106 function renderBooleanField(
107 props: Omit<CommonFieldProps, 'optional'> & {
109 inputExtra?: React.ReactNode;
112 const { id, value, onFieldChange, propKey, inputExtra } = props;
114 const label = translate('settings.pr_decoration.binding.form', id);
116 return renderFieldWrapper(
117 renderLabel({ ...props, optional: true }),
118 <div className="sw-flex sw-items-start">
121 labels={{ on: label, off: label }}
122 onChange={(v) => onFieldChange(propKey, v)}
125 {value == null && <Note className="sw-ml-2">{translate('settings.not_set')}</Note>}
132 function renderField(
133 props: CommonFieldProps & {
137 const { id, propKey, value, onFieldChange } = props;
138 return renderFieldWrapper(
144 onChange={(e) => onFieldChange(propKey, e.currentTarget.value)}
153 export function AlmSpecificForm(props: AlmSpecificFormProps) {
157 formData: { repository, slug, summaryCommentEnabled, monorepo },
160 let formFields: JSX.Element;
161 const instance = instances.find((i) => i.alm === alm);
169 helpExample: <strong>My Project</strong>,
171 onFieldChange: props.onFieldChange,
178 helpExample: <strong>My Repository</strong>,
179 id: 'azure.repository',
180 onFieldChange: props.onFieldChange,
181 propKey: 'repository',
182 value: repository || '',
187 case AlmKeys.BitbucketServer:
195 ? `${stripTrailingSlash(instance.url)}/projects/`
196 : 'https://bb.company.com/projects/'}
197 <strong>{'MY_PROJECT_KEY'}</strong>
198 {'/repos/my-repository-slug/browse'}
201 id: 'bitbucket.repository',
202 onFieldChange: props.onFieldChange,
203 propKey: 'repository',
204 value: repository || '',
212 ? `${stripTrailingSlash(instance.url)}/projects/MY_PROJECT_KEY/repos/`
213 : 'https://bb.company.com/projects/MY_PROJECT_KEY/repos/'}
214 <strong>{'my-repository-slug'}</strong>
218 id: 'bitbucket.slug',
219 onFieldChange: props.onFieldChange,
226 case AlmKeys.BitbucketCloud:
233 {'https://bitbucket.org/my-workspace/'}
234 <strong>{'my-repository-slug'}</strong>
237 id: 'bitbucketcloud.repository',
238 onFieldChange: props.onFieldChange,
239 propKey: 'repository',
240 value: repository || '',
253 ? `${stripTrailingSlash(convertGithubApiUrlToLink(instance.url))}/`
254 : 'https://github.com/'}
255 <strong>{'sonarsource/sonarqube'}</strong>
258 id: 'github.repository',
259 onFieldChange: props.onFieldChange,
260 propKey: 'repository',
261 value: repository || '',
264 {renderBooleanField({
266 id: 'github.summary_comment_setting',
267 onFieldChange: props.onFieldChange,
268 propKey: 'summaryCommentEnabled',
269 value: summaryCommentEnabled === undefined ? true : summaryCommentEnabled,
279 helpExample: <strong>123456</strong>,
280 id: 'gitlab.repository',
281 onFieldChange: props.onFieldChange,
282 propKey: 'repository',
283 value: repository || '',
290 const monorepoEnabled = props.hasFeature(Feature.MonoRepositoryPullRequestDecoration);
300 <DocLink to={ALM_DOCUMENTATION_PATHS[alm]}>{translate('learn_more')}</DocLink>
304 onFieldChange: props.onFieldChange,
307 inputExtra: monorepo && (
308 <FlagMessage className="sw-ml-2" variant="warning">
309 {translate('settings.pr_decoration.binding.form.monorepo.warning')}
317 export default withAvailableFeatures(AlmSpecificForm);