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(true);
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.Failed
73 if (isValidApp && invalidOrgs.length === 0) {
75 translateWithParameters(
76 `${intlPrefix}.valid${data.installations.length === 1 ? '_one' : ''}`,
78 ? translate('settings.authentication.github.form.provisioning_with_github_short')
79 : translate('settings.authentication.form.provisioning_at_login_short'),
80 data.installations.length === 1
81 ? data.installations[0].organization
82 : data.installations.length
85 setAlertVariant('success');
88 translateWithParameters(
89 `${intlPrefix}.invalid`,
90 data?.application[applicationField].errorMessage ?? ''
92 ...invalidOrgs.map((org) =>
93 translateWithParameters(
94 `${intlPrefix}.invalid_org`,
96 org.autoProvisioning.errorMessage ?? ''
100 setAlertVariant('error');
102 }, [isFetching, isValidApp, isAutoProvisioning, applicationField, data]);
106 <Alert title={messages[0]} variant={alertVariant}>
107 <div className="sw-flex sw-justify-between sw-items-center">
109 {messages.map((msg) => (
110 <div key={msg}>{msg}</div>
114 <Button onClick={() => setOpenDetails(true)} disabled={isFetching} className="sw-mr-2">
115 {translate(`${intlPrefix}.details`)}
117 <Button onClick={() => refetch()} disabled={isFetching}>
118 {translate(`${intlPrefix}.test`)}
124 <Modal size="small" contentLabel={modalHeader} onRequestClose={() => setOpenDetails(false)}>
125 <header className="modal-head">
127 {modalHeader} <ValidityIcon valid={isValidApp} />
130 <div className="modal-body modal-container">
132 <Alert variant="error">{data?.application[applicationField].errorMessage}</Alert>
134 <ul className="sw-pl-5">
135 {data?.installations.map((inst) => (
136 <li key={inst.organization}>
139 !isAutoProvisioning ||
140 inst.autoProvisioning.status === GitHubProvisioningStatus.Success
143 <span className="sw-ml-2">{inst.organization}</span>
144 {isAutoProvisioning &&
145 inst.autoProvisioning.status === GitHubProvisioningStatus.Failed && (
146 <span> - {inst.autoProvisioning.errorMessage}</span>
152 <footer className="modal-foot">
153 <Button onClick={() => setOpenDetails(false)}>{translate('close')}</Button>
161 export default GitHubConfigurationValidity;