set users on resource working

This commit is contained in:
Milo Schwartz
2024-11-15 23:38:08 -05:00
parent 9f87b8d271
commit b1e53ed8d7
16 changed files with 414 additions and 118 deletions

View File

@@ -100,7 +100,7 @@ export default function AccessControlsPage() {
if (res && res.status === 200) {
toast({
variant: "default",
title: "User invited",
title: "User saved",
description: "The user has been updated.",
});
}

View File

@@ -8,9 +8,12 @@ import { useOrgContext } from "@app/hooks/useOrgContext";
import { useResourceContext } from "@app/hooks/useResourceContext";
import { AxiosResponse } from "axios";
import { formatAxiosError } from "@app/lib/utils";
import { ListResourceRolesResponse } from "@server/routers/resource";
import {
ListResourceRolesResponse,
ListResourceUsersResponse,
} from "@server/routers/resource";
import { Button } from "@app/components/ui/button";
import { set, z } from "zod";
import { z } from "zod";
import { Tag } from "emblor";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
@@ -25,6 +28,7 @@ import {
} from "@app/components/ui/form";
import { TagInput } from "emblor";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { ListUsersResponse } from "@server/routers/user";
const FormSchema = z.object({
roles: z.array(
@@ -33,6 +37,12 @@ const FormSchema = z.object({
text: z.string(),
})
),
users: z.array(
z.object({
id: z.string(),
text: z.string(),
})
),
});
export default function ResourceAuthenticationPage() {
@@ -43,13 +53,22 @@ export default function ResourceAuthenticationPage() {
const [allRoles, setAllRoles] = useState<{ id: string; text: string }[]>(
[]
);
const [activeTagIndex, setActiveTagIndex] = useState<number | null>(null);
const [allUsers, setAllUsers] = useState<{ id: string; text: string }[]>(
[]
);
const [activeRolesTagIndex, setActiveRolesTagIndex] = useState<
number | null
>(null);
const [activeUsersTagIndex, setActiveUsersTagIndex] = useState<
number | null
>(null);
const [loading, setLoading] = useState(false);
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: { roles: [] },
defaultValues: { roles: [], users: [] },
});
useEffect(() => {
@@ -103,6 +122,53 @@ export default function ResourceAuthenticationPage() {
),
});
});
api.get<AxiosResponse<ListUsersResponse>>(
`/org/${org?.org.orgId}/users`
)
.then((res) => {
setAllUsers(
res.data.data.users.map((user) => ({
id: user.id.toString(),
text: user.email,
}))
);
})
.catch((e) => {
console.error(e);
toast({
variant: "destructive",
title: "Failed to fetch users",
description: formatAxiosError(
e,
"An error occurred while fetching the users"
),
});
});
api.get<AxiosResponse<ListResourceUsersResponse>>(
`/resource/${resource.resourceId}/users`
)
.then((res) => {
form.setValue(
"users",
res.data.data.users.map((i) => ({
id: i.userId.toString(),
text: i.email,
}))
);
})
.catch((e) => {
console.error(e);
toast({
variant: "destructive",
title: "Failed to fetch users",
description: formatAxiosError(
e,
"An error occurred while fetching the users"
),
});
});
}, []);
async function onSubmit(data: z.infer<typeof FormSchema>) {
@@ -112,9 +178,13 @@ export default function ResourceAuthenticationPage() {
roleIds: data.roles.map((i) => parseInt(i.id)),
});
await api.post(`/resource/${resource.resourceId}/users`, {
userIds: data.users.map((i) => i.id),
});
toast({
title: "Roles set",
description: "Roles set for resource successfully",
title: "Saved successfully",
description: "Authentication settings have been saved",
});
} catch (e) {
console.error(e);
@@ -154,8 +224,10 @@ export default function ResourceAuthenticationPage() {
<FormControl>
<TagInput
{...field}
activeTagIndex={activeTagIndex}
setActiveTagIndex={setActiveTagIndex}
activeTagIndex={activeRolesTagIndex}
setActiveTagIndex={
setActiveRolesTagIndex
}
placeholder="Enter a role"
tags={form.getValues().roles}
setTags={(newRoles) => {
@@ -175,9 +247,9 @@ export default function ResourceAuthenticationPage() {
tag: {
body: "bg-muted hover:bg-accent text-foreground p-2",
},
input: "border-none bg-transparent text-inherit placeholder:text-inherit shadow-none"
input: "border-none bg-transparent text-inherit placeholder:text-inherit shadow-none",
inlineTagsContainer: "bg-transparent",
}}
inputFieldPosition={"top"}
/>
</FormControl>
<FormDescription>
@@ -189,6 +261,53 @@ export default function ResourceAuthenticationPage() {
</FormItem>
)}
/>
<FormField
control={form.control}
name="users"
render={({ field }) => (
<FormItem className="flex flex-col items-start">
<FormLabel>Users</FormLabel>
<FormControl>
<TagInput
{...field}
activeTagIndex={activeUsersTagIndex}
setActiveTagIndex={
setActiveUsersTagIndex
}
placeholder="Enter a user"
tags={form.getValues().users}
setTags={(newUsers) => {
form.setValue(
"users",
newUsers as [Tag, ...Tag[]]
);
}}
enableAutocomplete={true}
autocompleteOptions={allUsers}
allowDuplicates={false}
restrictTagsToAutocompleteOptions={
true
}
sortTags={true}
styleClasses={{
tag: {
body: "bg-muted hover:bg-accent text-foreground p-2",
},
input: "border-none bg-transparent text-inherit placeholder:text-inherit shadow-none",
inlineTagsContainer: "bg-transparent",
}}
/>
</FormControl>
<FormDescription>
Users added here will be able to access
this resource. A user will always have
access to a resource if they have a role
that has access to it.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button
type="submit"
loading={loading}

View File

@@ -73,6 +73,8 @@ export default function LoginForm({ redirect }: LoginFormProps) {
if (res && res.status === 200) {
setError(null);
console.log(res)
if (res.data?.data?.emailVerificationRequired) {
if (redirect) {
router.push(`/auth/verify-email?redirect=${redirect}`);
@@ -106,7 +108,7 @@ export default function LoginForm({ redirect }: LoginFormProps) {
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-4"
className="space-y-6"
>
<FormField
control={form.control}

View File

@@ -111,7 +111,7 @@ export default function SignupForm({ redirect }: SignupFormProps) {
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-4"
className="space-y-6"
>
<FormField
control={form.control}

View File

@@ -134,7 +134,7 @@ export default function VerifyEmailForm({
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-4"
className="space-y-6"
>
<FormField
control={form.control}