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 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';
31 const intlPrefix = 'settings.authentication.github.configuration.validation';
33 function ValidityIcon({ valid }: { valid: boolean }) {
34 const color = valid ? theme.colors.success500 : theme.colors.error500;
37 <CheckIcon fill={color} label={translate(`${intlPrefix}.details.valid_label`)} />
39 <ClearIcon fill={color} label={translate(`${intlPrefix}.details.invalid_label`)} />
44 isAutoProvisioning: boolean;
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`);
54 const applicationField = isAutoProvisioning ? 'autoProvisioning' : 'jit';
57 data?.application[applicationField].status === GitHubProvisioningStatus.Success;
61 setMessages([translate(`${intlPrefix}.loading`)]);
62 setAlertVariant('loading');
67 isValidApp && isAutoProvisioning && data
68 ? data.installations.filter(
69 (org) => org.autoProvisioning.status === GitHubProvisioningStatus.Error
73 if (isValidApp && invalidOrgs.length === 0) {
75 translateWithParameters(
76 `${intlPrefix}.valid${data.installations.length > 1 ? '.multiple_orgs' : ''}`,
78 ? translate('settings.authentication.github.form.provisioning_with_github_short')
79 : translate('settings.authentication.form.provisioning_at_login_short'),
80 data.installations.length
83 setAlertVariant('success');
86 translateWithParameters(
87 `${intlPrefix}.invalid`,
88 data?.application[applicationField].errorMessage ?? ''
90 ...invalidOrgs.map((org) =>
91 translateWithParameters(
92 `${intlPrefix}.invalid_org`,
94 org.autoProvisioning.errorMessage ?? ''
98 setAlertVariant('error');
100 }, [isFetching, isValidApp, isAutoProvisioning, applicationField, data]);
104 <Alert title={messages[0]} variant={alertVariant}>
105 <div className="sw-flex sw-justify-between sw-items-center">
107 {messages.map((msg) => (
108 <div key={msg}>{msg}</div>
112 <Button onClick={() => setOpenDetails(true)} disabled={isFetching} className="sw-mr-2">
113 {translate(`${intlPrefix}.details`)}
115 <Button onClick={() => refetch()} disabled={isFetching}>
116 {translate(`${intlPrefix}.test`)}
122 <Modal size="small" contentLabel={modalHeader} onRequestClose={() => setOpenDetails(false)}>
123 <header className="modal-head">
125 {modalHeader} <ValidityIcon valid={isValidApp} />
128 <div className="modal-body modal-container">
130 <Alert variant="error">{data?.application[applicationField].errorMessage}</Alert>
132 <ul className="sw-pl-5">
133 {data?.installations.map((inst) => (
134 <li key={inst.organization}>
137 !isAutoProvisioning ||
138 inst.autoProvisioning.status === GitHubProvisioningStatus.Success
141 <span className="sw-ml-2">{inst.organization}</span>
142 {isAutoProvisioning &&
143 inst.autoProvisioning.status === GitHubProvisioningStatus.Error && (
144 <span> - {inst.autoProvisioning.errorMessage}</span>
150 <footer className="modal-foot">
151 <Button onClick={() => setOpenDetails(false)}>{translate('close')}</Button>
159 export default GitHubConfigurationValidity;