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 { 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';
33 export interface QualityGatePermissionsAddModalRendererProps {
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;
42 export default function QualityGatePermissionsAddModalRenderer(
43 props: QualityGatePermissionsAddModalRendererProps
45 const { selection, submitting } = props;
47 const header = translate('quality_gates.permissions.grant');
49 const noResultsText = translate('no_results');
52 <Modal contentLabel={header} onRequestClose={props.onClose}>
53 <header className="modal-head">
56 <form onSubmit={props.onSubmit}>
57 <div className="modal-body">
58 <div className="modal-field">
59 <label>{translate('quality_gates.permissions.search')}</label>
65 noOptionsMessage={() => noResultsText}
66 onChange={props.onSelection}
67 loadOptions={props.handleSearch}
68 getOptionValue={(opt) => (isUser(opt) ? opt.login : opt.name)}
71 Option: optionRenderer,
72 SingleValue: singleValueRenderer,
73 Control: controlRenderer,
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>
88 export function customOptions(option: OptionWithValue) {
90 <span className="display-flex-center" data-testid="qg-add-permission-option">
92 <Avatar hash={option.avatar} name={option.name} size={16} />
94 <GroupIcon size={16} />
96 <strong className="spacer-left">{option.name}</strong>
97 {isUser(option) && <span className="note little-spacer-left">{option.login}</span>}
102 function optionRenderer(props: OptionProps<OptionWithValue, false>) {
103 return <components.Option {...props}>{customOptions(props.data)}</components.Option>;
106 function singleValueRenderer(props: SingleValueProps<OptionWithValue>) {
107 return <components.SingleValue {...props}>{customOptions(props.data)}</components.SingleValue>;
110 function controlRenderer(props: ControlProps<OptionWithValue, false>) {
112 <components.Control {...omit(props, ['children'])} className="abs-height-100">
114 </components.Control>