]> source.dussan.org Git - sonarqube.git/blob
32cfa51a0c42938809c8c9032d48b7096e2eb160
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 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 { omit } from 'lodash';
21 import * as React from 'react';
22 import { components, ControlProps, OptionProps, SingleValueProps } from 'react-select';
23 import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
24 import Modal from '../../../components/controls/Modal';
25 import { SearchSelect } from '../../../components/controls/Select';
26 import GroupIcon from '../../../components/icons/GroupIcon';
27 import Avatar from '../../../components/ui/Avatar';
28 import { translate } from '../../../helpers/l10n';
29 import { Group, isUser } from '../../../types/quality-gates';
30 import { UserBase } from '../../../types/users';
31 import { OptionWithValue } from './QualityGatePermissionsAddModal';
32
33 export interface QualityGatePermissionsAddModalRendererProps {
34   onClose: () => void;
35   handleSearch: (q: string, resolve: (options: OptionWithValue[]) => void) => void;
36   onSelection: (selection: OptionWithValue) => void;
37   selection?: UserBase | Group;
38   onSubmit: (event: React.SyntheticEvent<HTMLFormElement>) => void;
39   submitting: boolean;
40 }
41
42 export default function QualityGatePermissionsAddModalRenderer(
43   props: QualityGatePermissionsAddModalRendererProps
44 ) {
45   const { selection, submitting } = props;
46
47   const header = translate('quality_gates.permissions.grant');
48
49   const noResultsText = translate('no_results');
50
51   return (
52     <Modal contentLabel={header} onRequestClose={props.onClose}>
53       <header className="modal-head">
54         <h2>{header}</h2>
55       </header>
56       <form onSubmit={props.onSubmit}>
57         <div className="modal-body">
58           <div className="modal-field">
59             <label>{translate('quality_gates.permissions.search')}</label>
60             <SearchSelect
61               autoFocus={true}
62               isClearable={false}
63               placeholder=""
64               defaultOptions={true}
65               noOptionsMessage={() => noResultsText}
66               onChange={props.onSelection}
67               loadOptions={props.handleSearch}
68               getOptionValue={(opt) => (isUser(opt) ? opt.login : opt.name)}
69               large={true}
70               components={{
71                 Option: optionRenderer,
72                 SingleValue: singleValueRenderer,
73                 Control: controlRenderer,
74               }}
75             />
76           </div>
77         </div>
78         <footer className="modal-foot">
79           {submitting && <i className="spinner spacer-right" />}
80           <SubmitButton disabled={!selection || submitting}>{translate('add_verb')}</SubmitButton>
81           <ResetButtonLink onClick={props.onClose}>{translate('cancel')}</ResetButtonLink>
82         </footer>
83       </form>
84     </Modal>
85   );
86 }
87
88 export function customOptions(option: OptionWithValue) {
89   return (
90     <span className="display-flex-center" data-testid="qg-add-permission-option">
91       {isUser(option) ? (
92         <Avatar hash={option.avatar} name={option.name} size={16} />
93       ) : (
94         <GroupIcon size={16} />
95       )}
96       <strong className="spacer-left">{option.name}</strong>
97       {isUser(option) && <span className="note little-spacer-left">{option.login}</span>}
98     </span>
99   );
100 }
101
102 function optionRenderer(props: OptionProps<OptionWithValue, false>) {
103   return <components.Option {...props}>{customOptions(props.data)}</components.Option>;
104 }
105
106 function singleValueRenderer(props: SingleValueProps<OptionWithValue>) {
107   return <components.SingleValue {...props}>{customOptions(props.data)}</components.SingleValue>;
108 }
109
110 function controlRenderer(props: ControlProps<OptionWithValue, false>) {
111   return (
112     <components.Control {...omit(props, ['children'])} className="abs-height-100">
113       {props.children}
114     </components.Control>
115   );
116 }