Browse Source

improve spacing and column layout on mobile

Milo Schwartz 6 months ago
parent
commit
32ffb33d98

+ 5 - 3
src/api/index.ts

@@ -8,8 +8,9 @@ export function createApiClient({ env }: { env: env }): AxiosInstance {
         return apiInstance;
         return apiInstance;
     }
     }
 
 
-    if (apiInstance) {
-        return apiInstance
+    if (typeof window === "undefined") {
+        // @ts-ignore
+        return;
     }
     }
 
 
     let baseURL;
     let baseURL;
@@ -45,7 +46,8 @@ export const internal = axios.create({
     baseURL: `http://localhost:${process.env.SERVER_EXTERNAL_PORT}/api/v1`,
     baseURL: `http://localhost:${process.env.SERVER_EXTERNAL_PORT}/api/v1`,
     timeout: 10000,
     timeout: 10000,
     headers: {
     headers: {
-        "Content-Type": "application/json"
+        "Content-Type": "application/json",
+        "X-CSRF-Token": "x-csrf-protection"
     }
     }
 });
 });
 
 

+ 22 - 27
src/app/[orgId]/settings/access/roles/components/RolesTable.tsx

@@ -40,26 +40,6 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
     const { toast } = useToast();
     const { toast } = useToast();
 
 
     const columns: ColumnDef<RoleRow>[] = [
     const columns: ColumnDef<RoleRow>[] = [
-        {
-            accessorKey: "name",
-            header: ({ column }) => {
-                return (
-                    <Button
-                        variant="ghost"
-                        onClick={() =>
-                            column.toggleSorting(column.getIsSorted() === "asc")
-                        }
-                    >
-                        Name
-                        <ArrowUpDown className="ml-2 h-4 w-4" />
-                    </Button>
-                );
-            }
-        },
-        {
-            accessorKey: "description",
-            header: "Description"
-        },
         {
         {
             id: "actions",
             id: "actions",
             cell: ({ row }) => {
             cell: ({ row }) => {
@@ -67,14 +47,9 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
 
 
                 return (
                 return (
                     <>
                     <>
-                        <div className="flex items-center justify-end">
+                        <div>
                             {roleRow.isAdmin && (
                             {roleRow.isAdmin && (
-                                <Button
-                                    variant="ghost"
-                                    className="h-8 w-8 p-0 opacity-0 cursor-default"
-                                >
-                                    Placeholder
-                                </Button>
+                                <MoreHorizontal className="h-4 w-4 opacity-0" />
                             )}
                             )}
                             {!roleRow.isAdmin && (
                             {!roleRow.isAdmin && (
                                 <DropdownMenu>
                                 <DropdownMenu>
@@ -107,6 +82,26 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
                     </>
                     </>
                 );
                 );
             }
             }
+        },
+        {
+            accessorKey: "name",
+            header: ({ column }) => {
+                return (
+                    <Button
+                        variant="ghost"
+                        onClick={() =>
+                            column.toggleSorting(column.getIsSorted() === "asc")
+                        }
+                    >
+                        Name
+                        <ArrowUpDown className="ml-2 h-4 w-4" />
+                    </Button>
+                );
+            }
+        },
+        {
+            accessorKey: "description",
+            header: "Description"
         }
         }
     ];
     ];
 
 

+ 77 - 65
src/app/[orgId]/settings/access/users/components/UsersTable.tsx

@@ -50,6 +50,64 @@ export default function UsersTable({ users: u }: UsersTableProps) {
     const { toast } = useToast();
     const { toast } = useToast();
 
 
     const columns: ColumnDef<UserRow>[] = [
     const columns: ColumnDef<UserRow>[] = [
+        {
+            id: "dots",
+            cell: ({ row }) => {
+                const userRow = row.original;
+                return (
+                    <>
+                        <div>
+                            {userRow.isOwner && (
+                                <MoreHorizontal className="h-4 w-4 opacity-0" />
+                            )}
+                            {!userRow.isOwner && (
+                                <>
+                                    <DropdownMenu>
+                                        <DropdownMenuTrigger asChild>
+                                            <Button
+                                                variant="ghost"
+                                                className="h-8 w-8 p-0"
+                                            >
+                                                <span className="sr-only">
+                                                    Open menu
+                                                </span>
+                                                <MoreHorizontal className="h-4 w-4" />
+                                            </Button>
+                                        </DropdownMenuTrigger>
+                                        <DropdownMenuContent align="end">
+                                            <DropdownMenuItem>
+                                                <Link
+                                                    href={`/${org?.org.orgId}/settings/access/users/${userRow.id}`}
+                                                    className="block w-full"
+                                                >
+                                                    Manage User
+                                                </Link>
+                                            </DropdownMenuItem>
+                                            {userRow.email !== user?.email && (
+                                                <DropdownMenuItem
+                                                    onClick={() => {
+                                                        setIsDeleteModalOpen(
+                                                            true
+                                                        );
+                                                        setSelectedUser(
+                                                            userRow
+                                                        );
+                                                    }}
+                                                >
+                                                    <span className="text-red-500">
+                                                        Remove User
+                                                    </span>
+                                                </DropdownMenuItem>
+                                            )}
+                                        </DropdownMenuContent>
+                                    </DropdownMenu>
+                                </>
+                            )}
+                        </div>
+                    </>
+                );
+            }
+        },
         {
         {
             accessorKey: "email",
             accessorKey: "email",
             header: ({ column }) => {
             header: ({ column }) => {
@@ -114,73 +172,27 @@ export default function UsersTable({ users: u }: UsersTableProps) {
             id: "actions",
             id: "actions",
             cell: ({ row }) => {
             cell: ({ row }) => {
                 const userRow = row.original;
                 const userRow = row.original;
-
                 return (
                 return (
-                    <>
-                        <div className="flex items-center justify-end">
-                            {userRow.isOwner && (
-                                <Button
-                                    variant="ghost"
-                                    className="opacity-0 cursor-default"
-                                >
-                                    Placeholder
+                    <div className="flex items-center justify-end">
+                        {userRow.isOwner && (
+                            <Button
+                                variant="ghost"
+                                className="opacity-0 cursor-default"
+                            >
+                                Placeholder
+                            </Button>
+                        )}
+                        {!userRow.isOwner && (
+                            <Link
+                                href={`/${org?.org.orgId}/settings/access/users/${userRow.id}`}
+                            >
+                                <Button variant={"gray"} className="ml-2">
+                                    Manage
+                                    <ArrowRight className="ml-2 w-4 h-4" />
                                 </Button>
                                 </Button>
-                            )}
-                            {!userRow.isOwner && (
-                                <>
-                                    <DropdownMenu>
-                                        <DropdownMenuTrigger asChild>
-                                            <Button
-                                                variant="ghost"
-                                                className="h-8 w-8 p-0"
-                                            >
-                                                <span className="sr-only">
-                                                    Open menu
-                                                </span>
-                                                <MoreHorizontal className="h-4 w-4" />
-                                            </Button>
-                                        </DropdownMenuTrigger>
-                                        <DropdownMenuContent align="end">
-                                            <DropdownMenuItem>
-                                                <Link
-                                                    href={`/${org?.org.orgId}/settings/access/users/${userRow.id}`}
-                                                >
-                                                    Manage User
-                                                </Link>
-                                            </DropdownMenuItem>
-                                            {userRow.email !== user?.email && (
-                                                <DropdownMenuItem
-                                                    onClick={() => {
-                                                        setIsDeleteModalOpen(
-                                                            true
-                                                        );
-                                                        setSelectedUser(
-                                                            userRow
-                                                        );
-                                                    }}
-                                                >
-                                                    <span className="text-red-500">
-                                                        Remove User
-                                                    </span>
-                                                </DropdownMenuItem>
-                                            )}
-                                        </DropdownMenuContent>
-                                    </DropdownMenu>
-                                    <Link
-                                        href={`/${org?.org.orgId}/settings/access/users/${userRow.id}`}
-                                    >
-                                        <Button
-                                            variant={"gray"}
-                                            className="ml-2"
-                                        >
-                                            Manage
-                                            <ArrowRight className="ml-2 w-4 h-4" />
-                                        </Button>
-                                    </Link>
-                                </>
-                            )}
-                        </div>
-                    </>
+                            </Link>
+                        )}
+                    </div>
                 );
                 );
             }
             }
         }
         }

+ 1 - 1
src/app/[orgId]/settings/resources/[resourceId]/components/ResourceInfoBox.tsx

@@ -69,7 +69,7 @@ export default function ResourceInfoBox({}: ResourceInfoBoxType) {
                         )}
                         )}
                     </div>
                     </div>
 
 
-                    <div className="flex items-center space-x-2 bg-muted p-1 pl-3 rounded-md">
+                    <div className="flex items-center space-x-2 bg-muted p-1 pl-3 rounded-md lg:max-w-xl">
                         <LinkIcon className="h-4 w-4" />
                         <LinkIcon className="h-4 w-4" />
                         <a
                         <a
                             href={fullUrl}
                             href={fullUrl}

+ 63 - 58
src/app/[orgId]/settings/resources/[resourceId]/connectivity/page.tsx

@@ -9,7 +9,7 @@ import {
     SelectContent,
     SelectContent,
     SelectItem,
     SelectItem,
     SelectTrigger,
     SelectTrigger,
-    SelectValue,
+    SelectValue
 } from "@/components/ui/select";
 } from "@/components/ui/select";
 import { Switch } from "@/components/ui/switch";
 import { Switch } from "@/components/ui/switch";
 import { AxiosResponse } from "axios";
 import { AxiosResponse } from "axios";
@@ -24,7 +24,7 @@ import {
     FormField,
     FormField,
     FormItem,
     FormItem,
     FormLabel,
     FormLabel,
-    FormMessage,
+    FormMessage
 } from "@app/components/ui/form";
 } from "@app/components/ui/form";
 import { CreateTargetResponse } from "@server/routers/target";
 import { CreateTargetResponse } from "@server/routers/target";
 import {
 import {
@@ -34,7 +34,7 @@ import {
     getPaginationRowModel,
     getPaginationRowModel,
     getCoreRowModel,
     getCoreRowModel,
     useReactTable,
     useReactTable,
-    flexRender,
+    flexRender
 } from "@tanstack/react-table";
 } from "@tanstack/react-table";
 import {
 import {
     Table,
     Table,
@@ -42,7 +42,7 @@ import {
     TableCell,
     TableCell,
     TableHead,
     TableHead,
     TableHeader,
     TableHeader,
-    TableRow,
+    TableRow
 } from "@app/components/ui/table";
 } from "@app/components/ui/table";
 import { useToast } from "@app/hooks/useToast";
 import { useToast } from "@app/hooks/useToast";
 import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
 import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
@@ -59,9 +59,9 @@ const addTargetSchema = z.object({
     port: z
     port: z
         .string()
         .string()
         .refine((val) => !isNaN(Number(val)), {
         .refine((val) => !isNaN(Number(val)), {
-            message: "Port must be a number",
+            message: "Port must be a number"
         })
         })
-        .transform((val) => Number(val)),
+        .transform((val) => Number(val))
     // protocol: z.string(),
     // protocol: z.string(),
 });
 });
 
 
@@ -99,16 +99,16 @@ export default function ReverseProxyTargets(props: {
         defaultValues: {
         defaultValues: {
             ip: "",
             ip: "",
             method: "http",
             method: "http",
-            port: "80",
+            port: "80"
             // protocol: "TCP",
             // protocol: "TCP",
-        },
+        }
     });
     });
 
 
     useEffect(() => {
     useEffect(() => {
         const fetchTargets = async () => {
         const fetchTargets = async () => {
             try {
             try {
                 const res = await api.get<AxiosResponse<ListTargetsResponse>>(
                 const res = await api.get<AxiosResponse<ListTargetsResponse>>(
-                    `/resource/${params.resourceId}/targets`,
+                    `/resource/${params.resourceId}/targets`
                 );
                 );
 
 
                 if (res.status === 200) {
                 if (res.status === 200) {
@@ -121,8 +121,8 @@ export default function ReverseProxyTargets(props: {
                     title: "Failed to fetch targets",
                     title: "Failed to fetch targets",
                     description: formatAxiosError(
                     description: formatAxiosError(
                         err,
                         err,
-                        "An error occurred while fetching targets",
-                    ),
+                        "An error occurred while fetching targets"
+                    )
                 });
                 });
             } finally {
             } finally {
                 setPageLoading(false);
                 setPageLoading(false);
@@ -133,7 +133,7 @@ export default function ReverseProxyTargets(props: {
         const fetchSite = async () => {
         const fetchSite = async () => {
             try {
             try {
                 const res = await api.get<AxiosResponse<GetSiteResponse>>(
                 const res = await api.get<AxiosResponse<GetSiteResponse>>(
-                    `/site/${resource.siteId}`,
+                    `/site/${resource.siteId}`
                 );
                 );
 
 
                 if (res.status === 200) {
                 if (res.status === 200) {
@@ -146,27 +146,28 @@ export default function ReverseProxyTargets(props: {
                     title: "Failed to fetch resource",
                     title: "Failed to fetch resource",
                     description: formatAxiosError(
                     description: formatAxiosError(
                         err,
                         err,
-                        "An error occurred while fetching resource",
-                    ),
+                        "An error occurred while fetching resource"
+                    )
                 });
                 });
             }
             }
-        }
+        };
         fetchSite();
         fetchSite();
     }, []);
     }, []);
 
 
     async function addTarget(data: AddTargetFormValues) {
     async function addTarget(data: AddTargetFormValues) {
         // Check if target with same IP, port and method already exists
         // Check if target with same IP, port and method already exists
         const isDuplicate = targets.some(
         const isDuplicate = targets.some(
-            target => target.ip === data.ip &&
-                     target.port === data.port &&
-                     target.method === data.method
+            (target) =>
+                target.ip === data.ip &&
+                target.port === data.port &&
+                target.method === data.method
         );
         );
 
 
         if (isDuplicate) {
         if (isDuplicate) {
             toast({
             toast({
                 variant: "destructive",
                 variant: "destructive",
                 title: "Duplicate target",
                 title: "Duplicate target",
-                description: "A target with these settings already exists",
+                description: "A target with these settings already exists"
             });
             });
             return;
             return;
         }
         }
@@ -179,7 +180,7 @@ export default function ReverseProxyTargets(props: {
                 toast({
                 toast({
                     variant: "destructive",
                     variant: "destructive",
                     title: "Invalid target IP",
                     title: "Invalid target IP",
-                    description: "Target IP must be within the site subnet",
+                    description: "Target IP must be within the site subnet"
                 });
                 });
                 return;
                 return;
             }
             }
@@ -190,7 +191,7 @@ export default function ReverseProxyTargets(props: {
             enabled: true,
             enabled: true,
             targetId: new Date().getTime(),
             targetId: new Date().getTime(),
             new: true,
             new: true,
-            resourceId: resource.resourceId,
+            resourceId: resource.resourceId
         };
         };
 
 
         setTargets([...targets, newTarget]);
         setTargets([...targets, newTarget]);
@@ -199,7 +200,7 @@ export default function ReverseProxyTargets(props: {
 
 
     const removeTarget = (targetId: number) => {
     const removeTarget = (targetId: number) => {
         setTargets([
         setTargets([
-            ...targets.filter((target) => target.targetId !== targetId),
+            ...targets.filter((target) => target.targetId !== targetId)
         ]);
         ]);
 
 
         if (!targets.find((target) => target.targetId === targetId)?.new) {
         if (!targets.find((target) => target.targetId === targetId)?.new) {
@@ -212,8 +213,8 @@ export default function ReverseProxyTargets(props: {
             targets.map((target) =>
             targets.map((target) =>
                 target.targetId === targetId
                 target.targetId === targetId
                     ? { ...target, ...data, updated: true }
                     ? { ...target, ...data, updated: true }
-                    : target,
-            ),
+                    : target
+            )
         );
         );
     }
     }
 
 
@@ -222,7 +223,7 @@ export default function ReverseProxyTargets(props: {
             setLoading(true);
             setLoading(true);
 
 
             const res = await api.post(`/resource/${params.resourceId}`, {
             const res = await api.post(`/resource/${params.resourceId}`, {
-                ssl: sslEnabled,
+                ssl: sslEnabled
             });
             });
 
 
             updateResource({ ssl: sslEnabled });
             updateResource({ ssl: sslEnabled });
@@ -233,7 +234,7 @@ export default function ReverseProxyTargets(props: {
                     port: target.port,
                     port: target.port,
                     // protocol: target.protocol,
                     // protocol: target.protocol,
                     method: target.method,
                     method: target.method,
-                    enabled: target.enabled,
+                    enabled: target.enabled
                 };
                 };
 
 
                 if (target.new) {
                 if (target.new) {
@@ -244,7 +245,7 @@ export default function ReverseProxyTargets(props: {
                 } else if (target.updated) {
                 } else if (target.updated) {
                     const res = await api.post(
                     const res = await api.post(
                         `/target/${target.targetId}`,
                         `/target/${target.targetId}`,
-                        data,
+                        data
                     );
                     );
                 }
                 }
 
 
@@ -253,23 +254,23 @@ export default function ReverseProxyTargets(props: {
                         let res = {
                         let res = {
                             ...t,
                             ...t,
                             new: false,
                             new: false,
-                            updated: false,
+                            updated: false
                         };
                         };
                         return res;
                         return res;
-                    }),
+                    })
                 ]);
                 ]);
             }
             }
 
 
             for (const targetId of targetsToRemove) {
             for (const targetId of targetsToRemove) {
                 await api.delete(`/target/${targetId}`);
                 await api.delete(`/target/${targetId}`);
                 setTargets(
                 setTargets(
-                    targets.filter((target) => target.targetId !== targetId),
+                    targets.filter((target) => target.targetId !== targetId)
                 );
                 );
             }
             }
 
 
             toast({
             toast({
                 title: "Resource updated",
                 title: "Resource updated",
-                description: "Resource and targets updated successfully",
+                description: "Resource and targets updated successfully"
             });
             });
 
 
             setTargetsToRemove([]);
             setTargetsToRemove([]);
@@ -280,8 +281,8 @@ export default function ReverseProxyTargets(props: {
                 title: "Operation failed",
                 title: "Operation failed",
                 description: formatAxiosError(
                 description: formatAxiosError(
                     err,
                     err,
-                    "An error occurred during the save operation",
-                ),
+                    "An error occurred during the save operation"
+                )
             });
             });
         }
         }
 
 
@@ -299,13 +300,15 @@ export default function ReverseProxyTargets(props: {
                         updateTarget(row.original.targetId, { method: value })
                         updateTarget(row.original.targetId, { method: value })
                     }
                     }
                 >
                 >
-                    <SelectTrigger>{row.original.method}</SelectTrigger>
+                    <SelectTrigger className="min-w-[100px]">
+                        {row.original.method}
+                    </SelectTrigger>
                     <SelectContent>
                     <SelectContent>
                         <SelectItem value="http">http</SelectItem>
                         <SelectItem value="http">http</SelectItem>
                         <SelectItem value="https">https</SelectItem>
                         <SelectItem value="https">https</SelectItem>
                     </SelectContent>
                     </SelectContent>
                 </Select>
                 </Select>
-            ),
+            )
         },
         },
         {
         {
             accessorKey: "ip",
             accessorKey: "ip",
@@ -313,13 +316,14 @@ export default function ReverseProxyTargets(props: {
             cell: ({ row }) => (
             cell: ({ row }) => (
                 <Input
                 <Input
                     defaultValue={row.original.ip}
                     defaultValue={row.original.ip}
+                    className="min-w-[150px]"
                     onBlur={(e) =>
                     onBlur={(e) =>
                         updateTarget(row.original.targetId, {
                         updateTarget(row.original.targetId, {
-                            ip: e.target.value,
+                            ip: e.target.value
                         })
                         })
                     }
                     }
                 />
                 />
-            ),
+            )
         },
         },
         {
         {
             accessorKey: "port",
             accessorKey: "port",
@@ -328,13 +332,14 @@ export default function ReverseProxyTargets(props: {
                 <Input
                 <Input
                     type="number"
                     type="number"
                     defaultValue={row.original.port}
                     defaultValue={row.original.port}
+                    className="min-w-[100px]"
                     onBlur={(e) =>
                     onBlur={(e) =>
                         updateTarget(row.original.targetId, {
                         updateTarget(row.original.targetId, {
-                            port: parseInt(e.target.value, 10),
+                            port: parseInt(e.target.value, 10)
                         })
                         })
                     }
                     }
                 />
                 />
-            ),
+            )
         },
         },
         // {
         // {
         //     accessorKey: "protocol",
         //     accessorKey: "protocol",
@@ -364,7 +369,7 @@ export default function ReverseProxyTargets(props: {
                         updateTarget(row.original.targetId, { enabled: val })
                         updateTarget(row.original.targetId, { enabled: val })
                     }
                     }
                 />
                 />
-            ),
+            )
         },
         },
         {
         {
             id: "actions",
             id: "actions",
@@ -387,8 +392,8 @@ export default function ReverseProxyTargets(props: {
                         </Button>
                         </Button>
                     </div>
                     </div>
                 </>
                 </>
-            ),
-        },
+            )
+        }
     ];
     ];
 
 
     const table = useReactTable({
     const table = useReactTable({
@@ -397,7 +402,7 @@ export default function ReverseProxyTargets(props: {
         getCoreRowModel: getCoreRowModel(),
         getCoreRowModel: getCoreRowModel(),
         getPaginationRowModel: getPaginationRowModel(),
         getPaginationRowModel: getPaginationRowModel(),
         getSortedRowModel: getSortedRowModel(),
         getSortedRowModel: getSortedRowModel(),
-        getFilteredRowModel: getFilteredRowModel(),
+        getFilteredRowModel: getFilteredRowModel()
     });
     });
 
 
     if (pageLoading) {
     if (pageLoading) {
@@ -437,7 +442,7 @@ export default function ReverseProxyTargets(props: {
                         <Form {...addTargetForm}>
                         <Form {...addTargetForm}>
                             <form
                             <form
                                 onSubmit={addTargetForm.handleSubmit(
                                 onSubmit={addTargetForm.handleSubmit(
-                                    addTarget as any,
+                                    addTarget as any
                                 )}
                                 )}
                                 className="space-y-4"
                                 className="space-y-4"
                             >
                             >
@@ -452,11 +457,11 @@ export default function ReverseProxyTargets(props: {
                                                     <Select
                                                     <Select
                                                         {...field}
                                                         {...field}
                                                         onValueChange={(
                                                         onValueChange={(
-                                                            value,
+                                                            value
                                                         ) => {
                                                         ) => {
                                                             addTargetForm.setValue(
                                                             addTargetForm.setValue(
                                                                 "method",
                                                                 "method",
-                                                                value,
+                                                                value
                                                             );
                                                             );
                                                         }}
                                                         }}
                                                     >
                                                     >
@@ -585,10 +590,10 @@ export default function ReverseProxyTargets(props: {
                                                                           .column
                                                                           .column
                                                                           .columnDef
                                                                           .columnDef
                                                                           .header,
                                                                           .header,
-                                                                      header.getContext(),
+                                                                      header.getContext()
                                                                   )}
                                                                   )}
                                                         </TableHead>
                                                         </TableHead>
-                                                    ),
+                                                    )
                                                 )}
                                                 )}
                                             </TableRow>
                                             </TableRow>
                                         ))}
                                         ))}
@@ -607,7 +612,7 @@ export default function ReverseProxyTargets(props: {
                                                                 cell.column
                                                                 cell.column
                                                                     .columnDef
                                                                     .columnDef
                                                                     .cell,
                                                                     .cell,
-                                                                cell.getContext(),
+                                                                cell.getContext()
                                                             )}
                                                             )}
                                                         </TableCell>
                                                         </TableCell>
                                                     ))}
                                                     ))}
@@ -644,36 +649,36 @@ export default function ReverseProxyTargets(props: {
 
 
 function isIPInSubnet(subnet: string, ip: string): boolean {
 function isIPInSubnet(subnet: string, ip: string): boolean {
     // Split subnet into IP and mask parts
     // Split subnet into IP and mask parts
-    const [subnetIP, maskBits] = subnet.split('/');
+    const [subnetIP, maskBits] = subnet.split("/");
     const mask = parseInt(maskBits);
     const mask = parseInt(maskBits);
-    
+
     if (mask < 0 || mask > 32) {
     if (mask < 0 || mask > 32) {
-        throw new Error('Invalid subnet mask. Must be between 0 and 32.');
+        throw new Error("Invalid subnet mask. Must be between 0 and 32.");
     }
     }
 
 
     // Convert IP addresses to binary numbers
     // Convert IP addresses to binary numbers
     const subnetNum = ipToNumber(subnetIP);
     const subnetNum = ipToNumber(subnetIP);
     const ipNum = ipToNumber(ip);
     const ipNum = ipToNumber(ip);
-    
+
     // Calculate subnet mask
     // Calculate subnet mask
     const maskNum = mask === 32 ? -1 : ~((1 << (32 - mask)) - 1);
     const maskNum = mask === 32 ? -1 : ~((1 << (32 - mask)) - 1);
-    
+
     // Check if the IP is in the subnet
     // Check if the IP is in the subnet
     return (subnetNum & maskNum) === (ipNum & maskNum);
     return (subnetNum & maskNum) === (ipNum & maskNum);
 }
 }
 
 
 function ipToNumber(ip: string): number {
 function ipToNumber(ip: string): number {
     // Validate IP address format
     // Validate IP address format
-    const parts = ip.split('.');
+    const parts = ip.split(".");
     if (parts.length !== 4) {
     if (parts.length !== 4) {
-        throw new Error('Invalid IP address format');
+        throw new Error("Invalid IP address format");
     }
     }
-    
+
     // Convert IP octets to 32-bit number
     // Convert IP octets to 32-bit number
     return parts.reduce((num, octet) => {
     return parts.reduce((num, octet) => {
         const oct = parseInt(octet);
         const oct = parseInt(octet);
         if (isNaN(oct) || oct < 0 || oct > 255) {
         if (isNaN(oct) || oct < 0 || oct > 255) {
-            throw new Error('Invalid IP address octet');
+            throw new Error("Invalid IP address octet");
         }
         }
         return (num << 8) + oct;
         return (num << 8) + oct;
     }, 0);
     }, 0);

+ 1 - 1
src/app/[orgId]/settings/resources/[resourceId]/layout.tsx

@@ -123,7 +123,7 @@ export default async function ResourceLayout(props: ResourceLayoutProps) {
             <OrgProvider org={org}>
             <OrgProvider org={org}>
                 <ResourceProvider resource={resource} authInfo={authInfo}>
                 <ResourceProvider resource={resource} authInfo={authInfo}>
                     <SidebarSettings sidebarNavItems={sidebarNavItems}>
                     <SidebarSettings sidebarNavItems={sidebarNavItems}>
-                        <div className="mb-8 lg:max-w-2xl">
+                        <div className="mb-8">
                             <ResourceInfoBox />
                             <ResourceInfoBox />
                         </div>
                         </div>
                         {children}
                         {children}

+ 47 - 47
src/app/[orgId]/settings/resources/components/ResourcesTable.tsx

@@ -74,6 +74,43 @@ export default function SitesTable({ resources, orgId }: ResourcesTableProps) {
     };
     };
 
 
     const columns: ColumnDef<ResourceRow>[] = [
     const columns: ColumnDef<ResourceRow>[] = [
+        {
+            accessorKey: "dots",
+            header: "",
+            cell: ({ row }) => {
+                const resourceRow = row.original;
+                const router = useRouter();
+
+                return (
+                    <DropdownMenu>
+                        <DropdownMenuTrigger asChild>
+                            <Button variant="ghost" className="h-8 w-8 p-0">
+                                <span className="sr-only">Open menu</span>
+                                <MoreHorizontal className="h-4 w-4" />
+                            </Button>
+                        </DropdownMenuTrigger>
+                        <DropdownMenuContent align="end">
+                            <DropdownMenuItem>
+                                <Link
+                                    className="block w-full"
+                                    href={`/${resourceRow.orgId}/settings/resources/${resourceRow.id}`}
+                                >
+                                    View settings
+                                </Link>
+                            </DropdownMenuItem>
+                            <DropdownMenuItem
+                                onClick={() => {
+                                    setSelectedResource(resourceRow);
+                                    setIsDeleteModalOpen(true);
+                                }}
+                            >
+                                <span className="text-red-500">Delete</span>
+                            </DropdownMenuItem>
+                        </DropdownMenuContent>
+                    </DropdownMenu>
+                );
+            }
+        },
         {
         {
             accessorKey: "name",
             accessorKey: "name",
             header: ({ column }) => {
             header: ({ column }) => {
@@ -214,55 +251,18 @@ export default function SitesTable({ resources, orgId }: ResourcesTableProps) {
         {
         {
             id: "actions",
             id: "actions",
             cell: ({ row }) => {
             cell: ({ row }) => {
-                const router = useRouter();
-
                 const resourceRow = row.original;
                 const resourceRow = row.original;
-
                 return (
                 return (
-                    <>
-                        <div className="flex items-center justify-end">
-                            <DropdownMenu>
-                                <DropdownMenuTrigger asChild>
-                                    <Button
-                                        variant="ghost"
-                                        className="h-8 w-8 p-0"
-                                    >
-                                        <span className="sr-only">
-                                            Open menu
-                                        </span>
-                                        <MoreHorizontal className="h-4 w-4" />
-                                    </Button>
-                                </DropdownMenuTrigger>
-                                <DropdownMenuContent align="end">
-                                    <DropdownMenuItem>
-                                        <Link
-                                            href={`/${resourceRow.orgId}/settings/resources/${resourceRow.id}`}
-                                        >
-                                            View settings
-                                        </Link>
-                                    </DropdownMenuItem>
-                                    <DropdownMenuItem
-                                        onClick={() => {
-                                            setSelectedResource(resourceRow);
-                                            setIsDeleteModalOpen(true);
-                                        }}
-                                    >
-                                        <span className="text-red-500">
-                                            Delete
-                                        </span>
-                                    </DropdownMenuItem>
-                                </DropdownMenuContent>
-                            </DropdownMenu>
-                            <Link
-                                href={`/${resourceRow.orgId}/settings/resources/${resourceRow.id}`}
-                            >
-                                <Button variant={"gray"} className="ml-2">
-                                    Edit
-                                    <ArrowRight className="ml-2 w-4 h-4" />
-                                </Button>
-                            </Link>
-                        </div>
-                    </>
+                    <div className="flex items-center justify-end">
+                        <Link
+                            href={`/${resourceRow.orgId}/settings/resources/${resourceRow.id}`}
+                        >
+                            <Button variant={"gray"} className="ml-2">
+                                Edit
+                                <ArrowRight className="ml-2 w-4 h-4" />
+                            </Button>
+                        </Link>
+                    </div>
                 );
                 );
             }
             }
         }
         }

+ 11 - 11
src/app/[orgId]/settings/share-links/components/CreateShareLinkForm.tsx

@@ -63,7 +63,7 @@ import { Checkbox } from "@app/components/ui/checkbox";
 import { GenerateAccessTokenResponse } from "@server/routers/accessToken";
 import { GenerateAccessTokenResponse } from "@server/routers/accessToken";
 import { constructShareLink } from "@app/lib/shareLinks";
 import { constructShareLink } from "@app/lib/shareLinks";
 import { ShareLinkRow } from "./ShareLinksTable";
 import { ShareLinkRow } from "./ShareLinksTable";
-import { QRCodeSVG } from "qrcode.react";
+import { QRCodeCanvas, QRCodeSVG } from "qrcode.react";
 
 
 type FormProps = {
 type FormProps = {
     open: boolean;
     open: boolean;
@@ -449,23 +449,23 @@ export default function CreateShareLinkForm({
                             {link && (
                             {link && (
                                 <div className="max-w-md space-y-4">
                                 <div className="max-w-md space-y-4">
                                     <p>
                                     <p>
-                                        You will only be able to see this link once.
-                                        Make sure to copy it.
+                                        You will only be able to see this link
+                                        once. Make sure to copy it.
                                     </p>
                                     </p>
                                     <p>
                                     <p>
                                         Anyone with this link can access the
                                         Anyone with this link can access the
                                         resource. Share it with care.
                                         resource. Share it with care.
                                     </p>
                                     </p>
 
 
-                                    <div className="w-64 h-64 mx-auto flex items-center justify-center">
-                                        <QRCodeSVG
-                                            value={link}
-                                            size={256}
-                                        />
+                                    <div className="h-[250px] w-full mx-auto flex items-center justify-center">
+                                        <QRCodeCanvas value={link} size={200} />
                                     </div>
                                     </div>
 
 
                                     <div className="mx-auto">
                                     <div className="mx-auto">
-                                        <CopyTextBox text={link} wrapText={false} />
+                                        <CopyTextBox
+                                            text={link}
+                                            wrapText={false}
+                                        />
                                     </div>
                                     </div>
                                 </div>
                                 </div>
                             )}
                             )}
@@ -473,8 +473,8 @@ export default function CreateShareLinkForm({
                     </CredenzaBody>
                     </CredenzaBody>
                     <CredenzaFooter>
                     <CredenzaFooter>
                         <Button
                         <Button
-                            type="submit"
-                            form="share-link-form"
+                            type="button"
+                            onClick={form.handleSubmit(onSubmit)}
                             loading={loading}
                             loading={loading}
                             disabled={link !== null || loading}
                             disabled={link !== null || loading}
                         >
                         >

+ 42 - 42
src/app/[orgId]/settings/share-links/components/ShareLinksTable.tsx

@@ -86,6 +86,48 @@ export default function ShareLinksTable({
     }
     }
 
 
     const columns: ColumnDef<ShareLinkRow>[] = [
     const columns: ColumnDef<ShareLinkRow>[] = [
+        {
+            id: "actions",
+            cell: ({ row }) => {
+                const router = useRouter();
+
+                const resourceRow = row.original;
+
+                return (
+                    <>
+                        <div>
+                            <DropdownMenu>
+                                <DropdownMenuTrigger asChild>
+                                    <Button
+                                        variant="ghost"
+                                        className="h-8 w-8 p-0"
+                                    >
+                                        <span className="sr-only">
+                                            Open menu
+                                        </span>
+                                        <MoreHorizontal className="h-4 w-4" />
+                                    </Button>
+                                </DropdownMenuTrigger>
+                                <DropdownMenuContent align="end">
+                                    <DropdownMenuItem>
+                                        <button
+                                            onClick={() =>
+                                                deleteSharelink(
+                                                    resourceRow.accessTokenId
+                                                )
+                                            }
+                                            className="text-red-500"
+                                        >
+                                            Delete
+                                        </button>
+                                    </DropdownMenuItem>
+                                </DropdownMenuContent>
+                            </DropdownMenu>
+                        </div>
+                    </>
+                );
+            }
+        },
         {
         {
             accessorKey: "resourceName",
             accessorKey: "resourceName",
             header: ({ column }) => {
             header: ({ column }) => {
@@ -236,48 +278,6 @@ export default function ShareLinksTable({
                 }
                 }
                 return "Never";
                 return "Never";
             }
             }
-        },
-        {
-            id: "actions",
-            cell: ({ row }) => {
-                const router = useRouter();
-
-                const resourceRow = row.original;
-
-                return (
-                    <>
-                        <div className="flex items-center justify-end">
-                            <DropdownMenu>
-                                <DropdownMenuTrigger asChild>
-                                    <Button
-                                        variant="ghost"
-                                        className="h-8 w-8 p-0"
-                                    >
-                                        <span className="sr-only">
-                                            Open menu
-                                        </span>
-                                        <MoreHorizontal className="h-4 w-4" />
-                                    </Button>
-                                </DropdownMenuTrigger>
-                                <DropdownMenuContent align="end">
-                                    <DropdownMenuItem>
-                                        <button
-                                            onClick={() =>
-                                                deleteSharelink(
-                                                    resourceRow.accessTokenId
-                                                )
-                                            }
-                                            className="text-red-500"
-                                        >
-                                            Delete
-                                        </button>
-                                    </DropdownMenuItem>
-                                </DropdownMenuContent>
-                            </DropdownMenu>
-                        </div>
-                    </>
-                );
-            }
         }
         }
     ];
     ];
 
 

+ 73 - 63
src/app/[orgId]/settings/sites/components/SitesTable.tsx

@@ -71,10 +71,48 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
                 setIsDeleteModalOpen(false);
                 setIsDeleteModalOpen(false);
 
 
                 const newRows = rows.filter((row) => row.id !== siteId);
                 const newRows = rows.filter((row) => row.id !== siteId);
+
+                setRows(newRows);
             });
             });
     };
     };
 
 
     const columns: ColumnDef<SiteRow>[] = [
     const columns: ColumnDef<SiteRow>[] = [
+        {
+            id: "dots",
+            cell: ({ row }) => {
+                const siteRow = row.original;
+                const router = useRouter();
+
+                return (
+                    <DropdownMenu>
+                        <DropdownMenuTrigger asChild>
+                            <Button variant="ghost" className="h-8 w-8 p-0">
+                                <span className="sr-only">Open menu</span>
+                                <MoreHorizontal className="h-4 w-4" />
+                            </Button>
+                        </DropdownMenuTrigger>
+                        <DropdownMenuContent align="end">
+                            <DropdownMenuItem>
+                                <Link
+                                    className="block w-full"
+                                    href={`/${siteRow.orgId}/settings/sites/${siteRow.nice}`}
+                                >
+                                    View settings
+                                </Link>
+                            </DropdownMenuItem>
+                            <DropdownMenuItem
+                                onClick={() => {
+                                    setSelectedSite(siteRow);
+                                    setIsDeleteModalOpen(true);
+                                }}
+                            >
+                                <span className="text-red-500">Delete</span>
+                            </DropdownMenuItem>
+                        </DropdownMenuContent>
+                    </DropdownMenu>
+                );
+            }
+        },
         {
         {
             accessorKey: "name",
             accessorKey: "name",
             header: ({ column }) => {
             header: ({ column }) => {
@@ -91,6 +129,41 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
                 );
                 );
             }
             }
         },
         },
+        {
+            accessorKey: "online",
+            header: ({ column }) => {
+                return (
+                    <Button
+                        variant="ghost"
+                        onClick={() =>
+                            column.toggleSorting(column.getIsSorted() === "asc")
+                        }
+                    >
+                        Online
+                        <ArrowUpDown className="ml-2 h-4 w-4" />
+                    </Button>
+                );
+            },
+            cell: ({ row }) => {
+                const originalRow = row.original;
+
+                if (originalRow.online) {
+                    return (
+                        <span className="text-green-500 flex items-center space-x-2">
+                            <div className="w-2 h-2 bg-green-500 rounded-full"></div>
+                            <span>Online</span>
+                        </span>
+                    );
+                } else {
+                    return (
+                        <span className="text-neutral-500 flex items-center space-x-2">
+                            <div className="w-2 h-2 bg-gray-500 rounded-full"></div>
+                            <span>Offline</span>
+                        </span>
+                    );
+                }
+            }
+        },
         {
         {
             accessorKey: "nice",
             accessorKey: "nice",
             header: ({ column }) => {
             header: ({ column }) => {
@@ -174,75 +247,12 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
                 }
                 }
             }
             }
         },
         },
-        {
-            accessorKey: "online",
-            header: ({ column }) => {
-                return (
-                    <Button
-                        variant="ghost"
-                        onClick={() =>
-                            column.toggleSorting(column.getIsSorted() === "asc")
-                        }
-                    >
-                        Online
-                        <ArrowUpDown className="ml-2 h-4 w-4" />
-                    </Button>
-                );
-            },
-            cell: ({ row }) => {
-                const originalRow = row.original;
-
-                if (originalRow.online) {
-                    return (
-                        <span className="text-green-500 flex items-center space-x-2">
-                            <div className="w-2 h-2 bg-green-500 rounded-full"></div>
-                            <span>Online</span>
-                        </span>
-                    );
-                } else {
-                    return (
-                        <span className="text-gray-500 flex items-center space-x-2">
-                            <div className="w-2 h-2 bg-gray-500 rounded-full"></div>
-                            <span>Offline</span>
-                        </span>
-                    );
-                }
-            }
-        },
         {
         {
             id: "actions",
             id: "actions",
             cell: ({ row }) => {
             cell: ({ row }) => {
-                const router = useRouter();
-
                 const siteRow = row.original;
                 const siteRow = row.original;
-
                 return (
                 return (
                     <div className="flex items-center justify-end">
                     <div className="flex items-center justify-end">
-                        <DropdownMenu>
-                            <DropdownMenuTrigger asChild>
-                                <Button variant="ghost" className="h-8 w-8 p-0">
-                                    <span className="sr-only">Open menu</span>
-                                    <MoreHorizontal className="h-4 w-4" />
-                                </Button>
-                            </DropdownMenuTrigger>
-                            <DropdownMenuContent align="end">
-                                <DropdownMenuItem>
-                                    <Link
-                                        href={`/${siteRow.orgId}/settings/sites/${siteRow.nice}`}
-                                    >
-                                        View settings
-                                    </Link>
-                                </DropdownMenuItem>
-                                <DropdownMenuItem
-                                    onClick={() => {
-                                        setSelectedSite(siteRow);
-                                        setIsDeleteModalOpen(true);
-                                    }}
-                                >
-                                    <span className="text-red-500">Delete</span>
-                                </DropdownMenuItem>
-                            </DropdownMenuContent>
-                        </DropdownMenu>
                         <Link
                         <Link
                             href={`/${siteRow.orgId}/settings/sites/${siteRow.nice}`}
                             href={`/${siteRow.orgId}/settings/sites/${siteRow.nice}`}
                         >
                         >

+ 2 - 2
src/app/invite/InviteStatusCard.tsx

@@ -7,7 +7,7 @@ import {
     CardContent,
     CardContent,
     CardFooter,
     CardFooter,
     CardHeader,
     CardHeader,
-    CardTitle
+    CardTitle,
 } from "@app/components/ui/card";
 } from "@app/components/ui/card";
 import { useEnvContext } from "@app/hooks/useEnvContext";
 import { useEnvContext } from "@app/hooks/useEnvContext";
 import { XCircle } from "lucide-react";
 import { XCircle } from "lucide-react";
@@ -20,7 +20,7 @@ type InviteStatusCardProps = {
 
 
 export default function InviteStatusCard({
 export default function InviteStatusCard({
     type,
     type,
-    token
+    token,
 }: InviteStatusCardProps) {
 }: InviteStatusCardProps) {
     const router = useRouter();
     const router = useRouter();
 
 

+ 26 - 4
src/components/Credenza.tsx

@@ -12,7 +12,7 @@ import {
     DialogFooter,
     DialogFooter,
     DialogHeader,
     DialogHeader,
     DialogTitle,
     DialogTitle,
-    DialogTrigger,
+    DialogTrigger
 } from "@/components/ui/dialog";
 } from "@/components/ui/dialog";
 import {
 import {
     Drawer,
     Drawer,
@@ -22,7 +22,7 @@ import {
     DrawerFooter,
     DrawerFooter,
     DrawerHeader,
     DrawerHeader,
     DrawerTitle,
     DrawerTitle,
-    DrawerTrigger,
+    DrawerTrigger
 } from "@/components/ui/drawer";
 } from "@/components/ui/drawer";
 
 
 interface BaseProps {
 interface BaseProps {
@@ -43,6 +43,7 @@ const desktop = "(min-width: 768px)";
 
 
 const Credenza = ({ children, ...props }: RootCredenzaProps) => {
 const Credenza = ({ children, ...props }: RootCredenzaProps) => {
     const isDesktop = useMediaQuery(desktop);
     const isDesktop = useMediaQuery(desktop);
+    // const isDesktop = true;
     const Credenza = isDesktop ? Dialog : Drawer;
     const Credenza = isDesktop ? Dialog : Drawer;
 
 
     return <Credenza {...props}>{children}</Credenza>;
     return <Credenza {...props}>{children}</Credenza>;
@@ -50,6 +51,8 @@ const Credenza = ({ children, ...props }: RootCredenzaProps) => {
 
 
 const CredenzaTrigger = ({ className, children, ...props }: CredenzaProps) => {
 const CredenzaTrigger = ({ className, children, ...props }: CredenzaProps) => {
     const isDesktop = useMediaQuery(desktop);
     const isDesktop = useMediaQuery(desktop);
+    // const isDesktop = true;
+
     const CredenzaTrigger = isDesktop ? DialogTrigger : DrawerTrigger;
     const CredenzaTrigger = isDesktop ? DialogTrigger : DrawerTrigger;
 
 
     return (
     return (
@@ -61,10 +64,12 @@ const CredenzaTrigger = ({ className, children, ...props }: CredenzaProps) => {
 
 
 const CredenzaClose = ({ className, children, ...props }: CredenzaProps) => {
 const CredenzaClose = ({ className, children, ...props }: CredenzaProps) => {
     const isDesktop = useMediaQuery(desktop);
     const isDesktop = useMediaQuery(desktop);
+    // const isDesktop = true;
+
     const CredenzaClose = isDesktop ? DialogClose : DrawerClose;
     const CredenzaClose = isDesktop ? DialogClose : DrawerClose;
 
 
     return (
     return (
-        <CredenzaClose className={className} {...props}>
+        <CredenzaClose className={cn("mb-3 md:mb-0", className)} {...props}>
             {children}
             {children}
         </CredenzaClose>
         </CredenzaClose>
     );
     );
@@ -72,6 +77,8 @@ const CredenzaClose = ({ className, children, ...props }: CredenzaProps) => {
 
 
 const CredenzaContent = ({ className, children, ...props }: CredenzaProps) => {
 const CredenzaContent = ({ className, children, ...props }: CredenzaProps) => {
     const isDesktop = useMediaQuery(desktop);
     const isDesktop = useMediaQuery(desktop);
+    // const isDesktop = true;
+
     const CredenzaContent = isDesktop ? DialogContent : DrawerContent;
     const CredenzaContent = isDesktop ? DialogContent : DrawerContent;
 
 
     return (
     return (
@@ -87,6 +94,8 @@ const CredenzaDescription = ({
     ...props
     ...props
 }: CredenzaProps) => {
 }: CredenzaProps) => {
     const isDesktop = useMediaQuery(desktop);
     const isDesktop = useMediaQuery(desktop);
+    // const isDesktop = true;
+
     const CredenzaDescription = isDesktop
     const CredenzaDescription = isDesktop
         ? DialogDescription
         ? DialogDescription
         : DrawerDescription;
         : DrawerDescription;
@@ -100,6 +109,8 @@ const CredenzaDescription = ({
 
 
 const CredenzaHeader = ({ className, children, ...props }: CredenzaProps) => {
 const CredenzaHeader = ({ className, children, ...props }: CredenzaProps) => {
     const isDesktop = useMediaQuery(desktop);
     const isDesktop = useMediaQuery(desktop);
+    // const isDesktop = true;
+
     const CredenzaHeader = isDesktop ? DialogHeader : DrawerHeader;
     const CredenzaHeader = isDesktop ? DialogHeader : DrawerHeader;
 
 
     return (
     return (
@@ -111,6 +122,8 @@ const CredenzaHeader = ({ className, children, ...props }: CredenzaProps) => {
 
 
 const CredenzaTitle = ({ className, children, ...props }: CredenzaProps) => {
 const CredenzaTitle = ({ className, children, ...props }: CredenzaProps) => {
     const isDesktop = useMediaQuery(desktop);
     const isDesktop = useMediaQuery(desktop);
+    // const isDesktop = true;
+
     const CredenzaTitle = isDesktop ? DialogTitle : DrawerTitle;
     const CredenzaTitle = isDesktop ? DialogTitle : DrawerTitle;
 
 
     return (
     return (
@@ -126,10 +139,19 @@ const CredenzaBody = ({ className, children, ...props }: CredenzaProps) => {
             {children}
             {children}
         </div>
         </div>
     );
     );
+
+    //     return (
+    //     <div className={cn("px-0 mb-4", className)} {...props}>
+    //         {children}
+    //     </div>
+    // );
+
 };
 };
 
 
 const CredenzaFooter = ({ className, children, ...props }: CredenzaProps) => {
 const CredenzaFooter = ({ className, children, ...props }: CredenzaProps) => {
     const isDesktop = useMediaQuery(desktop);
     const isDesktop = useMediaQuery(desktop);
+    // const isDesktop = true;
+
     const CredenzaFooter = isDesktop ? DialogFooter : DrawerFooter;
     const CredenzaFooter = isDesktop ? DialogFooter : DrawerFooter;
 
 
     return (
     return (
@@ -148,5 +170,5 @@ export {
     CredenzaHeader,
     CredenzaHeader,
     CredenzaTitle,
     CredenzaTitle,
     CredenzaBody,
     CredenzaBody,
-    CredenzaFooter,
+    CredenzaFooter
 };
 };

+ 12 - 11
src/components/Enable2FaForm.tsx

@@ -38,7 +38,7 @@ import {
 import { useToast } from "@app/hooks/useToast";
 import { useToast } from "@app/hooks/useToast";
 import { formatAxiosError } from "@app/lib/utils";
 import { formatAxiosError } from "@app/lib/utils";
 import CopyTextBox from "@app/components/CopyTextBox";
 import CopyTextBox from "@app/components/CopyTextBox";
-import { QRCodeSVG } from "qrcode.react";
+import { QRCodeCanvas, QRCodeSVG } from "qrcode.react";
 import { useUserContext } from "@app/hooks/useUserContext";
 import { useUserContext } from "@app/hooks/useUserContext";
 
 
 const enableSchema = z.object({
 const enableSchema = z.object({
@@ -221,15 +221,10 @@ export default function Enable2FaForm({ open, setOpen }: Enable2FaProps) {
                                 Scan this QR code with your authenticator app or
                                 Scan this QR code with your authenticator app or
                                 enter the secret key manually:
                                 enter the secret key manually:
                             </p>
                             </p>
-                            <div className="w-64 h-64 mx-auto flex items-center justify-center">
-                                <QRCodeSVG value={secretUri} size={256} />
-                            </div>
-                            <div className="max-w-md mx-auto">
-                                <CopyTextBox
-                                    text={secretKey}
-                                    wrapText={false}
-                                />
+                            <div className="h-[250px] mx-auto flex items-center justify-center">
+                                <QRCodeCanvas value={secretUri} size={200} />
                             </div>
                             </div>
+                            <CopyTextBox text={secretKey} wrapText={false} />
 
 
                             <Form {...confirmForm}>
                             <Form {...confirmForm}>
                                 <form
                                 <form
@@ -288,10 +283,16 @@ export default function Enable2FaForm({ open, setOpen }: Enable2FaProps) {
                 <CredenzaFooter>
                 <CredenzaFooter>
                     {(step === 1 || step === 2) && (
                     {(step === 1 || step === 2) && (
                         <Button
                         <Button
-                            type="submit"
-                            form="form"
+                            type="button"
                             loading={loading}
                             loading={loading}
                             disabled={loading}
                             disabled={loading}
+                            onClick={() => {
+                                if (step === 1) {
+                                    enableForm.handleSubmit(request2fa)();
+                                } else {
+                                    confirmForm.handleSubmit(confirm2fa)();
+                                }
+                            }}
                         >
                         >
                             Submit
                             Submit
                         </Button>
                         </Button>

+ 2 - 2
src/components/SidebarSettings.tsx

@@ -21,9 +21,9 @@ export function SidebarSettings({
     limitWidth,
     limitWidth,
 }: SideBarSettingsProps) {
 }: SideBarSettingsProps) {
     return (
     return (
-        <div className="space-y-8 0 pb-16k">
+        <div className="space-y-8 pb-16k">
             <div className="flex flex-col space-y-8 lg:flex-row lg:space-x-32 lg:space-y-0">
             <div className="flex flex-col space-y-8 lg:flex-row lg:space-x-32 lg:space-y-0">
-                <aside className="-mx-4 lg:w-1/5">
+                <aside className="lg:w-1/5">
                     <SidebarNav items={sidebarNavItems} disabled={disabled} />
                     <SidebarNav items={sidebarNavItems} disabled={disabled} />
                 </aside>
                 </aside>
                 <div className={`flex-1 ${limitWidth ? "lg:max-w-2xl" : ""}`}>
                 <div className={`flex-1 ${limitWidth ? "lg:max-w-2xl" : ""}`}>

+ 10 - 3
src/components/sidebar-nav.tsx

@@ -1,6 +1,6 @@
 "use client";
 "use client";
 
 
-import React from "react";
+import React, { useEffect } from "react";
 import Link from "next/link";
 import Link from "next/link";
 import { useParams, usePathname, useRouter } from "next/navigation";
 import { useParams, usePathname, useRouter } from "next/navigation";
 import { cn } from "@/lib/utils";
 import { cn } from "@/lib/utils";
@@ -35,6 +35,12 @@ export function SidebarNav({
     const resourceId = params.resourceId as string;
     const resourceId = params.resourceId as string;
     const userId = params.userId as string;
     const userId = params.userId as string;
 
 
+    const [selectedValue, setSelectedValue] = React.useState<string>(getSelectedValue());
+
+    useEffect(() => {
+        setSelectedValue(getSelectedValue());
+    }, [usePathname()]);
+
     const router = useRouter();
     const router = useRouter();
 
 
     const handleSelectChange = (value: string) => {
     const handleSelectChange = (value: string) => {
@@ -58,9 +64,10 @@ export function SidebarNav({
 
 
     return (
     return (
         <div>
         <div>
-            <div className="block lg:hidden px-4">
+            <div className="block lg:hidden">
                 <Select
                 <Select
-                    defaultValue={getSelectedValue()}
+                    defaultValue={selectedValue}
+                    value={selectedValue}
                     onValueChange={handleSelectChange}
                     onValueChange={handleSelectChange}
                     disabled={disabled}
                     disabled={disabled}
                 >
                 >

+ 1 - 1
src/components/ui/command.tsx

@@ -46,7 +46,7 @@ const CommandInput = React.forwardRef<
     <CommandPrimitive.Input
     <CommandPrimitive.Input
       ref={ref}
       ref={ref}
       className={cn(
       className={cn(
-        "flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
+        "flex h-11 w-full rounded-md bg-transparent py-3 text-base md:text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
         className
         className
       )}
       )}
       {...props}
       {...props}

+ 1 - 1
src/components/ui/dialog.tsx

@@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef<
     <DialogPrimitive.Overlay
     <DialogPrimitive.Overlay
         ref={ref}
         ref={ref}
         className={cn(
         className={cn(
-            "fixed inset-0 z-50 bg-black/30  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
+            "fixed inset-0 z-50 bg-black/50  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
             className
             className
         )}
         )}
         {...props}
         {...props}

+ 1 - 1
src/components/ui/input-otp.tsx

@@ -41,7 +41,7 @@ const InputOTPSlot = React.forwardRef<
     <div
     <div
       ref={ref}
       ref={ref}
       className={cn(
       className={cn(
-        "relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
+        "relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-base md:text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
         isActive && "z-10 ring-2 ring-ring ring-offset-background",
         isActive && "z-10 ring-2 ring-ring ring-offset-background",
         className
         className
       )}
       )}

+ 2 - 2
src/components/ui/input.tsx

@@ -15,7 +15,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
                 <input
                 <input
                     type={showPassword ? "text" : "password"}
                     type={showPassword ? "text" : "password"}
                     className={cn(
                     className={cn(
-                        "flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
+                        "flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-base md:text-sm ring-offset-background file:border-0 file:bg-transparent file:text-base md:file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
                         className
                         className
                     )}
                     )}
                     ref={ref}
                     ref={ref}
@@ -39,7 +39,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
             <input
             <input
                 type={type}
                 type={type}
                 className={cn(
                 className={cn(
-                    "flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
+                    "flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-base md:text-sm ring-offset-background file:border-0 file:bg-transparent file:text-base md:file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
                     className
                     className
                 )}
                 )}
                 ref={ref}
                 ref={ref}

+ 1 - 1
src/components/ui/select.tsx

@@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
   <SelectPrimitive.Trigger
   <SelectPrimitive.Trigger
     ref={ref}
     ref={ref}
     className={cn(
     className={cn(
-      "flex h-9 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
+      "flex h-9 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-base md:text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
       className
       className
     )}
     )}
     {...props}
     {...props}