import Link from "@mui/material/Link"; import MenuItem from "@mui/material/MenuItem"; import TextField from "@mui/material/TextField"; import { hasApiFieldErrors, isApiError } from "api/errors"; import type * as TypesGen from "api/typesGenerated"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Button } from "components/Button/Button"; import { FormFooter } from "components/Form/Form"; import { FullPageForm } from "components/FullPageForm/FullPageForm"; import { OrganizationAutocomplete } from "components/OrganizationAutocomplete/OrganizationAutocomplete"; import { PasswordField } from "components/PasswordField/PasswordField"; import { Spinner } from "components/Spinner/Spinner"; import { Stack } from "components/Stack/Stack"; import { useFormik } from "formik"; import type { FC } from "react"; import { displayNameValidator, getFormHelpers, nameValidator, onChangeTrimmed, } from "utils/formUtils"; import * as Yup from "yup"; import { Language } from "./Language"; export const authMethodLanguage = { password: { displayName: "Password", description: "Use an email address and password to login", }, oidc: { displayName: "OpenID Connect", description: "Use an OpenID Connect provider for authentication", }, github: { displayName: "Github", description: "Use Github OAuth for authentication", }, none: { displayName: "None", description: ( <> Disable authentication for this user (See the{" "} documentation {" "} for more details) ), }, }; const validationSchema = Yup.object({ email: Yup.string() .trim() .email(Language.emailInvalid) .required(Language.emailRequired), password: Yup.string().when("login_type", { is: "password", then: (schema) => schema.required(Language.passwordRequired), otherwise: (schema) => schema, }), username: nameValidator(Language.usernameLabel), name: displayNameValidator(Language.nameLabel), login_type: Yup.string().oneOf(Object.keys(authMethodLanguage)), }); type CreateUserFormData = { readonly username: string; readonly name: string; readonly email: string; readonly organization: string; readonly login_type: TypesGen.LoginType; readonly password: string; }; export interface CreateUserFormProps { error?: unknown; isLoading: boolean; onSubmit: (user: CreateUserFormData) => void; onCancel: () => void; authMethods?: TypesGen.AuthMethods; showOrganizations: boolean; } export const CreateUserForm: FC< React.PropsWithChildren > = ({ error, isLoading, onSubmit, onCancel, showOrganizations, authMethods, }) => { const form = useFormik({ initialValues: { email: "", password: "", username: "", name: "", // If organizations aren't enabled, use the fallback ID to add the user to // the default organization. organization: showOrganizations ? "" : "00000000-0000-0000-0000-000000000000", login_type: "", }, validationSchema, onSubmit, }); const getFieldHelpers = getFormHelpers(form, error); const methods = [ authMethods?.password.enabled && "password", authMethods?.oidc.enabled && "oidc", authMethods?.github.enabled && "github", "none", ].filter(Boolean) as Array; return ( {isApiError(error) && !hasApiFieldErrors(error) && ( )}
{showOrganizations && ( { void form.setFieldValue("organization", newValue?.id ?? ""); }} check={{ object: { resource_type: "organization_member" }, action: "create", }} /> )} { if (e.target.value !== "password") { await form.setFieldValue("password", ""); } await form.setFieldValue("login_type", e.target.value); }} SelectProps={{ renderValue: (selected: unknown) => authMethodLanguage[selected as keyof typeof authMethodLanguage] ?.displayName ?? "", }} > {methods.map((value) => { const language = authMethodLanguage[value]; return ( {language.displayName} ({ fontSize: 14, color: theme.palette.text.secondary, wordWrap: "normal", whiteSpace: "break-spaces", })} > {language.description} ); })}
); };