]> source.dussan.org Git - sonarqube.git/blob
d881be0d2d846716a72a7e841a3612dd7f2de122
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 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 { InputSize, Select } from '@sonarsource/echoes-react';
21 import { FormField, InputField, TextError } from 'design-system/lib';
22 import { isEmpty, isUndefined } from 'lodash';
23 import React from 'react';
24 import isEmail from 'validator/lib/isEmail';
25 import { translate, translateWithParameters } from '../../../../helpers/l10n';
26
27 type InputType = 'email' | 'number' | 'password' | 'select' | 'text';
28
29 interface Props {
30   children?: (props: { onChange: (value: string) => void }) => React.ReactNode;
31   description: string;
32   id: string;
33   name: string;
34   onChange: (value: string) => void;
35   options?: string[];
36   required?: boolean;
37   type?: InputType;
38   value: string | undefined;
39 }
40
41 export function EmailNotificationFormField(props: Readonly<Props>) {
42   const { description, id, name, options, required, type = 'text', value } = props;
43
44   const [validationMessage, setValidationMessage] = React.useState<string>();
45
46   const handleCheck = (changedValue?: string) => {
47     if (isEmpty(changedValue) && required) {
48       setValidationMessage(translate('settings.state.value_cant_be_empty_no_default'));
49       return false;
50     }
51
52     if (type === 'email' && !isEmail(changedValue ?? '')) {
53       setValidationMessage(translate('email_notification.state.value_should_be_valid_email'));
54       return false;
55     }
56
57     setValidationMessage(undefined);
58     return true;
59   };
60
61   const onChange = (newValue: string) => {
62     handleCheck(newValue);
63     props.onChange(newValue);
64   };
65
66   const hasValidationMessage = !isUndefined(validationMessage);
67
68   return (
69     <FormField
70       className="sw-grid sw-grid-cols-2 sw-gap-x-4 sw-py-6 sw-px-4"
71       htmlFor={id}
72       label={translate(name)}
73       required={required}
74       requiredAriaLabel={translate('field_required')}
75     >
76       <div className="sw-row-span-2 sw-grid">
77         {type === 'select' ? (
78           <SelectInput
79             id={id}
80             name={name}
81             options={options ?? []}
82             onChange={onChange}
83             required={required}
84             value={value}
85           />
86         ) : (
87           <BasicInput
88             id={id}
89             name={name}
90             type={type}
91             onChange={onChange}
92             required={required}
93             value={value}
94           />
95         )}
96
97         {hasValidationMessage && (
98           <TextError
99             className="sw-mt-2"
100             text={translateWithParameters('settings.state.validation_failed', validationMessage)}
101           />
102         )}
103       </div>
104
105       <div className="sw-w-abs-300">
106         {!isUndefined(description) && <div className="markdown sw-mt-1">{description}</div>}
107       </div>
108     </FormField>
109   );
110 }
111
112 function BasicInput(
113   props: Readonly<{
114     id: string;
115     name: string;
116     onChange: (value: string) => void;
117     required?: boolean;
118     type: InputType;
119     value: string | undefined;
120   }>,
121 ) {
122   const { id, onChange, name, required, type, value } = props;
123
124   return (
125     <InputField
126       id={id}
127       min={type === 'number' ? 0 : undefined}
128       name={name}
129       onChange={(event) => onChange(event.target.value)}
130       required={required}
131       size="large"
132       step={type === 'number' ? 1 : undefined}
133       type={type}
134       value={value ?? ''}
135     />
136   );
137 }
138
139 function SelectInput(
140   props: Readonly<{
141     id: string;
142     name: string;
143     onChange: (value: string) => void;
144     options: string[];
145     required?: boolean;
146     value: string | undefined;
147   }>,
148 ) {
149   const { id, name, onChange, options, required, value } = props;
150
151   return (
152     <Select
153       data={options?.map((option) => ({ label: option, value: option })) ?? []}
154       id={id}
155       isNotClearable
156       isRequired={required}
157       name={name}
158       onChange={onChange}
159       size={InputSize.Large}
160       value={value}
161     />
162   );
163 }