Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/dashboard/src/teams/sso/OIDCClientConfigModal.tsx
2501 views
1
/**
2
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import { CreateClientConfigResponse, OIDCClientConfig } from "@gitpod/public-api/lib/gitpod/experimental/v1/oidc_pb";
8
import { FC, useCallback, useReducer } from "react";
9
import { Button } from "@podkit/buttons/Button";
10
import Modal, { ModalBody, ModalFooter, ModalFooterAlert, ModalHeader } from "../../components/Modal";
11
import { ssoConfigReducer, isValid, useSaveSSOConfig, SSOConfigForm } from "./SSOConfigForm";
12
import Alert from "../../components/Alert";
13
import { LoadingButton } from "@podkit/buttons/LoadingButton";
14
15
type Props = {
16
clientConfig?: OIDCClientConfig;
17
onClose: () => void;
18
onSaved: (configId: string) => void;
19
};
20
21
export const OIDCClientConfigModal: FC<Props> = ({ clientConfig, onSaved, onClose }) => {
22
const isNew = !clientConfig;
23
24
const [ssoConfig, dispatch] = useReducer(ssoConfigReducer, {
25
id: clientConfig?.id ?? "",
26
issuer: clientConfig?.oidcConfig?.issuer ?? "",
27
clientId: clientConfig?.oauth2Config?.clientId ?? "",
28
clientSecret: clientConfig?.oauth2Config?.clientSecret ?? "",
29
celExpression: clientConfig?.oauth2Config?.celExpression ?? "",
30
usePKCE: clientConfig?.oauth2Config?.usePkce ?? false,
31
});
32
const configIsValid = isValid(ssoConfig);
33
34
const { save, isLoading, error } = useSaveSSOConfig();
35
36
const saveConfig = useCallback(async () => {
37
if (!isValid(ssoConfig) || isLoading) {
38
return;
39
}
40
41
try {
42
// Have to jump through some hoops to ensure we have a config id after create and update
43
let configId = ssoConfig.id;
44
45
const resp = await save(ssoConfig);
46
47
// Create response returns the new config, upate does not
48
if (resp.hasOwnProperty("config")) {
49
configId = (resp as CreateClientConfigResponse).config?.id;
50
}
51
52
// There should always be a configId, but just to type-guard
53
if (!!configId) {
54
onSaved(configId);
55
}
56
onClose();
57
} catch (error) {
58
console.error(error);
59
}
60
}, [isLoading, onClose, onSaved, save, ssoConfig]);
61
62
return (
63
<Modal visible onClose={onClose} onSubmit={saveConfig}>
64
<ModalHeader>
65
{isNew
66
? "New SSO Configuration"
67
: clientConfig?.active
68
? "View SSO Configuration"
69
: "Edit SSO Configuration"}
70
</ModalHeader>
71
<ModalBody>
72
{clientConfig?.active && (
73
<Alert type="message" className="mb-4">
74
This configuration is currently active for single sign-on (SSO). To make any modifications,
75
please create a new configuration. Once created, you can proceed to verify and activate it.
76
</Alert>
77
)}
78
<SSOConfigForm config={ssoConfig} onChange={dispatch} readOnly={clientConfig?.active === true} />
79
</ModalBody>
80
<ModalFooter alert={error ? <SaveErrorAlert error={error} /> : null}>
81
<Button variant="secondary" onClick={onClose}>
82
Cancel
83
</Button>
84
<LoadingButton
85
type="submit"
86
disabled={!configIsValid || clientConfig?.active === true}
87
loading={isLoading}
88
>
89
{isNew ? "Create" : "Save"}
90
</LoadingButton>
91
</ModalFooter>
92
</Modal>
93
);
94
};
95
96
type SaveErrorMessageProps = {
97
error?: Error;
98
};
99
const SaveErrorAlert: FC<SaveErrorMessageProps> = ({ error }) => {
100
const message = error?.message || "";
101
102
return (
103
<ModalFooterAlert type="danger">
104
<span>There was a problem saving your configuration.</span>
105
{message && <div className="leading-4 text-xs font-mono">{message}</div>}
106
</ModalFooterAlert>
107
);
108
};
109
110