feat: allow selecting the initial organization for new users (#16829)

This commit is contained in:
ケイラ
2025-03-07 08:42:10 -07:00
committed by GitHub
parent db064ed0f8
commit 32c36d5336
7 changed files with 151 additions and 77 deletions

View File

@ -7,10 +7,11 @@ 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 { type FormikContextType, useFormik } from "formik";
import { useFormik } from "formik";
import type { FC } from "react";
import {
displayNameValidator,
@ -52,14 +53,6 @@ export const authMethodLanguage = {
},
};
export interface CreateUserFormProps {
onSubmit: (user: TypesGen.CreateUserRequestWithOrgs) => void;
onCancel: () => void;
error?: unknown;
isLoading: boolean;
authMethods?: TypesGen.AuthMethods;
}
const validationSchema = Yup.object({
email: Yup.string()
.trim()
@ -75,27 +68,51 @@ const validationSchema = Yup.object({
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<CreateUserFormProps>
> = ({ onSubmit, onCancel, error, isLoading, authMethods }) => {
const form: FormikContextType<TypesGen.CreateUserRequestWithOrgs> =
useFormik<TypesGen.CreateUserRequestWithOrgs>({
initialValues: {
email: "",
password: "",
username: "",
name: "",
organization_ids: ["00000000-0000-0000-0000-000000000000"],
login_type: "",
user_status: null,
},
validationSchema,
onSubmit,
});
const getFieldHelpers = getFormHelpers<TypesGen.CreateUserRequestWithOrgs>(
form,
error,
);
> = ({
error,
isLoading,
onSubmit,
onCancel,
showOrganizations,
authMethods,
}) => {
const form = useFormik<CreateUserFormData>({
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",
@ -132,6 +149,20 @@ export const CreateUserForm: FC<
fullWidth
label={Language.emailLabel}
/>
{showOrganizations && (
<OrganizationAutocomplete
{...getFieldHelpers("organization")}
required
label="Organization"
onChange={(newValue) => {
void form.setFieldValue("organization", newValue?.id ?? "");
}}
check={{
object: { resource_type: "organization_member" },
action: "create",
}}
/>
)}
<TextField
{...getFieldHelpers("login_type", {
helperText: "Authentication method for this user",