Path: blob/main/components/dashboard/src/teams/sso/OIDCClientConfigModal.tsx
2501 views
/**1* Copyright (c) 2023 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import { CreateClientConfigResponse, OIDCClientConfig } from "@gitpod/public-api/lib/gitpod/experimental/v1/oidc_pb";7import { FC, useCallback, useReducer } from "react";8import { Button } from "@podkit/buttons/Button";9import Modal, { ModalBody, ModalFooter, ModalFooterAlert, ModalHeader } from "../../components/Modal";10import { ssoConfigReducer, isValid, useSaveSSOConfig, SSOConfigForm } from "./SSOConfigForm";11import Alert from "../../components/Alert";12import { LoadingButton } from "@podkit/buttons/LoadingButton";1314type Props = {15clientConfig?: OIDCClientConfig;16onClose: () => void;17onSaved: (configId: string) => void;18};1920export const OIDCClientConfigModal: FC<Props> = ({ clientConfig, onSaved, onClose }) => {21const isNew = !clientConfig;2223const [ssoConfig, dispatch] = useReducer(ssoConfigReducer, {24id: clientConfig?.id ?? "",25issuer: clientConfig?.oidcConfig?.issuer ?? "",26clientId: clientConfig?.oauth2Config?.clientId ?? "",27clientSecret: clientConfig?.oauth2Config?.clientSecret ?? "",28celExpression: clientConfig?.oauth2Config?.celExpression ?? "",29usePKCE: clientConfig?.oauth2Config?.usePkce ?? false,30});31const configIsValid = isValid(ssoConfig);3233const { save, isLoading, error } = useSaveSSOConfig();3435const saveConfig = useCallback(async () => {36if (!isValid(ssoConfig) || isLoading) {37return;38}3940try {41// Have to jump through some hoops to ensure we have a config id after create and update42let configId = ssoConfig.id;4344const resp = await save(ssoConfig);4546// Create response returns the new config, upate does not47if (resp.hasOwnProperty("config")) {48configId = (resp as CreateClientConfigResponse).config?.id;49}5051// There should always be a configId, but just to type-guard52if (!!configId) {53onSaved(configId);54}55onClose();56} catch (error) {57console.error(error);58}59}, [isLoading, onClose, onSaved, save, ssoConfig]);6061return (62<Modal visible onClose={onClose} onSubmit={saveConfig}>63<ModalHeader>64{isNew65? "New SSO Configuration"66: clientConfig?.active67? "View SSO Configuration"68: "Edit SSO Configuration"}69</ModalHeader>70<ModalBody>71{clientConfig?.active && (72<Alert type="message" className="mb-4">73This configuration is currently active for single sign-on (SSO). To make any modifications,74please create a new configuration. Once created, you can proceed to verify and activate it.75</Alert>76)}77<SSOConfigForm config={ssoConfig} onChange={dispatch} readOnly={clientConfig?.active === true} />78</ModalBody>79<ModalFooter alert={error ? <SaveErrorAlert error={error} /> : null}>80<Button variant="secondary" onClick={onClose}>81Cancel82</Button>83<LoadingButton84type="submit"85disabled={!configIsValid || clientConfig?.active === true}86loading={isLoading}87>88{isNew ? "Create" : "Save"}89</LoadingButton>90</ModalFooter>91</Modal>92);93};9495type SaveErrorMessageProps = {96error?: Error;97};98const SaveErrorAlert: FC<SaveErrorMessageProps> = ({ error }) => {99const message = error?.message || "";100101return (102<ModalFooterAlert type="danger">103<span>There was a problem saving your configuration.</span>104{message && <div className="leading-4 text-xs font-mono">{message}</div>}105</ModalFooterAlert>106);107};108109110