3 * Copyright (C) 2009-2024 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, RequiredIcon, 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 DocumentationLink from '../../../../components/common/DocumentationLink';
27 import { translate } from '../../../../helpers/l10n';
28 import { convertGithubApiUrlToLink, stripTrailingSlash } from '../../../../helpers/urls';
32 ProjectAlmBindingResponse,
33 } from '../../../../types/alm-settings';
34 import { Feature } from '../../../../types/features';
35 import { Dict } from '../../../../types/types';
37 export interface AlmSpecificFormProps extends WithAvailableFeaturesProps {
39 instances: AlmSettingsInstance[];
40 formData: Omit<ProjectAlmBindingResponse, 'alm'>;
41 onFieldChange: (id: keyof ProjectAlmBindingResponse, value: string | boolean) => void;
44 interface LabelProps {
49 interface CommonFieldProps extends LabelProps {
51 helpParams?: Dict<string | JSX.Element>;
52 helpExample?: JSX.Element;
53 onFieldChange: (id: keyof ProjectAlmBindingResponse, value: string | boolean) => void;
54 propKey: keyof ProjectAlmBindingResponse;
57 function renderFieldWrapper(
58 label: React.ReactNode,
59 input: React.ReactNode,
60 help?: React.ReactNode,
63 <div className="sw-p-6 sw-flex sw-gap-12">
64 <div className="sw-w-abs-300">
65 <SubHeading>{label}</SubHeading>
66 {help && <div className="markdown">{help}</div>}
68 <div className="sw-flex-1">{input}</div>
73 function renderHelp({ help, helpExample, helpParams = {}, id }: CommonFieldProps) {
78 defaultMessage={translate('settings.pr_decoration.binding.form', id, 'help')}
79 id={`settings.pr_decoration.binding.form.${id}.help`}
83 <div className="sw-mt-2 sw-whitespace-nowrap">
84 {translate('example')}: <em>{helpExample}</em>
92 function renderLabel(props: LabelProps) {
93 const { optional, id } = props;
96 {translate('settings.pr_decoration.binding.form', id)}
97 {!optional && <RequiredIcon />}
102 function renderBooleanField(
103 props: Omit<CommonFieldProps, 'optional'> & {
105 inputExtra?: React.ReactNode;
108 const { id, value, onFieldChange, propKey, inputExtra } = props;
110 const label = translate('settings.pr_decoration.binding.form', id);
112 return renderFieldWrapper(
113 renderLabel({ ...props, optional: true }),
114 <div className="sw-flex sw-items-start">
117 labels={{ on: label, off: label }}
118 onChange={(v) => onFieldChange(propKey, v)}
121 {value == null && <Note className="sw-ml-2">{translate('settings.not_set')}</Note>}
128 function renderField(
129 props: CommonFieldProps & {
133 const { id, propKey, value, onFieldChange } = props;
134 return renderFieldWrapper(
140 onChange={(e) => onFieldChange(propKey, e.currentTarget.value)}
149 export function AlmSpecificForm(props: AlmSpecificFormProps) {
153 formData: { repository, slug, summaryCommentEnabled, monorepo },
156 let formFields: JSX.Element;
157 const instance = instances.find((i) => i.alm === alm);
165 helpExample: <strong>My Project</strong>,
167 onFieldChange: props.onFieldChange,
174 helpExample: <strong>My Repository</strong>,
175 id: 'azure.repository',
176 onFieldChange: props.onFieldChange,
177 propKey: 'repository',
178 value: repository || '',
183 case AlmKeys.BitbucketServer:
191 ? `${stripTrailingSlash(instance.url)}/projects/`
192 : 'https://bb.company.com/projects/'}
193 <strong>{'MY_PROJECT_KEY'}</strong>
194 {'/repos/my-repository-slug/browse'}
197 id: 'bitbucket.repository',
198 onFieldChange: props.onFieldChange,
199 propKey: 'repository',
200 value: repository || '',
208 ? `${stripTrailingSlash(instance.url)}/projects/MY_PROJECT_KEY/repos/`
209 : 'https://bb.company.com/projects/MY_PROJECT_KEY/repos/'}
210 <strong>{'my-repository-slug'}</strong>
214 id: 'bitbucket.slug',
215 onFieldChange: props.onFieldChange,
222 case AlmKeys.BitbucketCloud:
229 {'https://bitbucket.org/my-workspace/'}
230 <strong>{'my-repository-slug'}</strong>
233 id: 'bitbucketcloud.repository',
234 onFieldChange: props.onFieldChange,
235 propKey: 'repository',
236 value: repository || '',
249 ? `${stripTrailingSlash(convertGithubApiUrlToLink(instance.url))}/`
250 : 'https://github.com/'}
251 <strong>{'sonarsource/sonarqube'}</strong>
254 id: 'github.repository',
255 onFieldChange: props.onFieldChange,
256 propKey: 'repository',
257 value: repository || '',
260 {renderBooleanField({
262 id: 'github.summary_comment_setting',
263 onFieldChange: props.onFieldChange,
264 propKey: 'summaryCommentEnabled',
265 value: summaryCommentEnabled === undefined ? true : summaryCommentEnabled,
275 helpExample: <strong>123456</strong>,
276 id: 'gitlab.repository',
277 onFieldChange: props.onFieldChange,
278 propKey: 'repository',
279 value: repository || '',
286 const monorepoEnabled = props.hasFeature(Feature.MonoRepositoryPullRequestDecoration);
296 <DocumentationLink to="/project-administration/monorepos/">
297 {translate('learn_more')}
302 onFieldChange: props.onFieldChange,
305 inputExtra: monorepo && (
306 <FlagMessage className="sw-ml-2" variant="warning">
307 {translate('settings.pr_decoration.binding.form.monorepo.warning')}
315 export default withAvailableFeatures(AlmSpecificForm);