]> source.dussan.org Git - sonarqube.git/blob
b3e07c92cec574e292cc77e922ecd1eeadbde7d9
[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 React, { useEffect, useState } from 'react';
21 import theme from '../../../../app/theme';
22 import Modal from '../../../../components/controls/Modal';
23 import { Button } from '../../../../components/controls/buttons';
24 import CheckIcon from '../../../../components/icons/CheckIcon';
25 import ClearIcon from '../../../../components/icons/ClearIcon';
26 import { Alert, AlertVariant } from '../../../../components/ui/Alert';
27 import { translate, translateWithParameters } from '../../../../helpers/l10n';
28 import { GitHubProvisioningStatus } from '../../../../types/provisioning';
29 import { useCheckGitHubConfigQuery } from './queries/identity-provider';
30
31 const intlPrefix = 'settings.authentication.github.configuration.validation';
32
33 function ValidityIcon({ valid }: { valid: boolean }) {
34   const color = valid ? theme.colors.success500 : theme.colors.error500;
35
36   return valid ? (
37     <CheckIcon fill={color} label={translate(`${intlPrefix}.details.valid_label`)} />
38   ) : (
39     <ClearIcon fill={color} label={translate(`${intlPrefix}.details.invalid_label`)} />
40   );
41 }
42
43 interface Props {
44   isAutoProvisioning: boolean;
45 }
46
47 function GitHubConfigurationValidity({ isAutoProvisioning }: Props) {
48   const [openDetails, setOpenDetails] = useState(false);
49   const [messages, setMessages] = useState<string[]>([]);
50   const [alertVariant, setAlertVariant] = useState<AlertVariant>('loading');
51   const { data, isFetching, refetch } = useCheckGitHubConfigQuery();
52   const modalHeader = translate(`${intlPrefix}.details.title`);
53
54   const applicationField = isAutoProvisioning ? 'autoProvisioning' : 'jit';
55
56   const isValidApp =
57     data?.application[applicationField].status === GitHubProvisioningStatus.Success;
58
59   useEffect(() => {
60     if (isFetching) {
61       setMessages([translate(`${intlPrefix}.loading`)]);
62       setAlertVariant('loading');
63       return;
64     }
65
66     const invalidOrgs =
67       isValidApp && isAutoProvisioning && data
68         ? data.installations.filter(
69             (org) => org.autoProvisioning.status === GitHubProvisioningStatus.Error
70           )
71         : [];
72
73     if (isValidApp && invalidOrgs.length === 0) {
74       setMessages([
75         translateWithParameters(
76           `${intlPrefix}.valid${data.installations.length > 1 ? '.multiple_orgs' : ''}`,
77           isAutoProvisioning
78             ? translate('settings.authentication.github.form.provisioning_with_github_short')
79             : translate('settings.authentication.form.provisioning_at_login_short'),
80           data.installations.length
81         ),
82       ]);
83       setAlertVariant('success');
84     } else {
85       setMessages([
86         translateWithParameters(
87           `${intlPrefix}.invalid`,
88           data?.application[applicationField].errorMessage ?? ''
89         ),
90         ...invalidOrgs.map((org) =>
91           translateWithParameters(
92             `${intlPrefix}.invalid_org`,
93             org.organization,
94             org.autoProvisioning.errorMessage ?? ''
95           )
96         ),
97       ]);
98       setAlertVariant('error');
99     }
100   }, [isFetching, isValidApp, isAutoProvisioning, applicationField, data]);
101
102   return (
103     <>
104       <Alert title={messages[0]} variant={alertVariant}>
105         <div className="sw-flex sw-justify-between sw-items-center">
106           <div>
107             {messages.map((msg) => (
108               <div key={msg}>{msg}</div>
109             ))}
110           </div>
111           <div>
112             <Button onClick={() => setOpenDetails(true)} disabled={isFetching} className="sw-mr-2">
113               {translate(`${intlPrefix}.details`)}
114             </Button>
115             <Button onClick={() => refetch()} disabled={isFetching}>
116               {translate(`${intlPrefix}.test`)}
117             </Button>
118           </div>
119         </div>
120       </Alert>
121       {openDetails && (
122         <Modal size="small" contentLabel={modalHeader} onRequestClose={() => setOpenDetails(false)}>
123           <header className="modal-head">
124             <h2>
125               {modalHeader} <ValidityIcon valid={isValidApp} />
126             </h2>
127           </header>
128           <div className="modal-body modal-container">
129             {!isValidApp && (
130               <Alert variant="error">{data?.application[applicationField].errorMessage}</Alert>
131             )}
132             <ul className="sw-pl-5">
133               {data?.installations.map((inst) => (
134                 <li key={inst.organization}>
135                   <ValidityIcon
136                     valid={
137                       !isAutoProvisioning ||
138                       inst.autoProvisioning.status === GitHubProvisioningStatus.Success
139                     }
140                   />
141                   <span className="sw-ml-2">{inst.organization}</span>
142                   {isAutoProvisioning &&
143                     inst.autoProvisioning.status === GitHubProvisioningStatus.Error && (
144                       <span> - {inst.autoProvisioning.errorMessage}</span>
145                     )}
146                 </li>
147               ))}
148             </ul>
149           </div>
150           <footer className="modal-foot">
151             <Button onClick={() => setOpenDetails(false)}>{translate('close')}</Button>
152           </footer>
153         </Modal>
154       )}
155     </>
156   );
157 }
158
159 export default GitHubConfigurationValidity;