mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
import {PageParams} from "@/types/next";
|
||||||
|
|
||||||
|
import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||||
|
import {requiredCurrentUser} from "@/auth/current-user";
|
||||||
|
import {prisma} from "@/prisma";
|
||||||
|
import {AdminTabs} from "@/components/wrappers/Dashboard/admin/admin-tabs";
|
||||||
|
|
||||||
|
|
||||||
|
export default async function RoutePage(props: PageParams<{}>) {
|
||||||
|
|
||||||
|
|
||||||
|
const user = await requiredCurrentUser()
|
||||||
|
|
||||||
|
const users = await prisma.user.findMany({
|
||||||
|
where: {
|
||||||
|
// id: {
|
||||||
|
// not: user.id
|
||||||
|
// },
|
||||||
|
deleted: {not: true},
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(users)
|
||||||
|
|
||||||
|
const settings = await prisma.settings.findUnique({
|
||||||
|
where: {
|
||||||
|
name: "system"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page>
|
||||||
|
<PageHeader>
|
||||||
|
<PageTitle>
|
||||||
|
Administration Panel
|
||||||
|
</PageTitle>
|
||||||
|
</PageHeader>
|
||||||
|
<PageContent className="mt-10">
|
||||||
|
<AdminTabs settings={settings} currentUser={user} users={users}/>
|
||||||
|
|
||||||
|
</PageContent>
|
||||||
|
</Page>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -8,12 +8,18 @@ import {SettingsTabs} from "@/components/wrappers/Dashboard/Settings/SettingsTab
|
|||||||
export default async function RoutePage(props: PageParams<{}>) {
|
export default async function RoutePage(props: PageParams<{}>) {
|
||||||
const user = await requiredCurrentUser()
|
const user = await requiredCurrentUser()
|
||||||
|
|
||||||
|
const defaultOrganization = await prisma.organization.findUnique({
|
||||||
|
where: {slug: "default"},
|
||||||
|
});
|
||||||
|
|
||||||
const users = await prisma.user.findMany({
|
const users = await prisma.user.findMany({
|
||||||
where:{
|
where: {
|
||||||
id: {
|
organizations: {
|
||||||
not: user.id
|
some: {
|
||||||
|
organizationId: defaultOrganization.id
|
||||||
|
},
|
||||||
},
|
},
|
||||||
deleted: { not: true },
|
deleted: {not: true},
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -21,7 +27,7 @@ export default async function RoutePage(props: PageParams<{}>) {
|
|||||||
console.log(users)
|
console.log(users)
|
||||||
|
|
||||||
const settings = await prisma.settings.findUnique({
|
const settings = await prisma.settings.findUnique({
|
||||||
where:{
|
where: {
|
||||||
name: "system"
|
name: "system"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -34,10 +40,10 @@ export default async function RoutePage(props: PageParams<{}>) {
|
|||||||
</PageTitle>
|
</PageTitle>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<PageDescription>
|
<PageDescription>
|
||||||
Manage your Portabase settings
|
Manage your organization settings.
|
||||||
</PageDescription>
|
</PageDescription>
|
||||||
<PageContent>
|
<PageContent>
|
||||||
<SettingsTabs settings={settings} users={users}/>
|
<SettingsTabs settings={settings} currentUser={user} users={users}/>
|
||||||
</PageContent>
|
</PageContent>
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {PropsWithChildren} from "react";
|
|||||||
import {DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger} from "@/components/ui/dropdown-menu";
|
import {DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger} from "@/components/ui/dropdown-menu";
|
||||||
import {signOutAction} from "@/features/auth/auth.action";
|
import {signOutAction} from "@/features/auth/auth.action";
|
||||||
import {redirect} from "next/navigation";
|
import {redirect} from "next/navigation";
|
||||||
|
import {CircleUser, LogOut, ShieldHalf} from "lucide-react";
|
||||||
|
|
||||||
export type LoggedInDropdownProps = PropsWithChildren<{}>
|
export type LoggedInDropdownProps = PropsWithChildren<{}>
|
||||||
|
|
||||||
@@ -21,15 +22,29 @@ export const LoggedInDropdown = (props: LoggedInDropdownProps) => {
|
|||||||
<DropdownMenuItem onClick={() => {
|
<DropdownMenuItem onClick={() => {
|
||||||
redirect("/dashboard/profile")
|
redirect("/dashboard/profile")
|
||||||
}}>
|
}}>
|
||||||
<span>Account</span>
|
<div className="flex justify-start items-center gap-2">
|
||||||
|
<CircleUser size={16}/>
|
||||||
|
<span>Account</span>
|
||||||
|
</div>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem onClick={() => {
|
||||||
|
redirect("/dashboard/admin")
|
||||||
|
}}>
|
||||||
|
<div className="flex justify-start items-center gap-2">
|
||||||
|
<ShieldHalf size={16}/>
|
||||||
|
<span>Administration Panel</span>
|
||||||
|
</div>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={() => {
|
<DropdownMenuItem onClick={() => {
|
||||||
signOutAction()
|
signOutAction()
|
||||||
}}>
|
}}>
|
||||||
<span>Sign out</span>
|
<div className="flex justify-start items-center gap-2">
|
||||||
|
<LogOut size={16}/>
|
||||||
|
<span>Log out</span>
|
||||||
|
</div>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+1
-1
@@ -3,7 +3,7 @@ import {userAction} from "@/safe-actions";
|
|||||||
import {prisma} from "@/prisma";
|
import {prisma} from "@/prisma";
|
||||||
import {z} from "zod";
|
import {z} from "zod";
|
||||||
import {v4 as uuidv4} from "uuid";
|
import {v4 as uuidv4} from "uuid";
|
||||||
import {EmailFormSchema} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/EmailForm/email-form.schema";
|
import {EmailFormSchema} from "@/components/wrappers/Dashboard/admin/AdminEmailTab/EmailForm/email-form.schema";
|
||||||
|
|
||||||
|
|
||||||
export const deleteUserAction = userAction
|
export const deleteUserAction = userAction
|
||||||
|
|||||||
@@ -1,50 +1,54 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs";
|
import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs";
|
||||||
import {DataTableWithPagination} from "@/components/wrappers/table/data-table-with-pagination";
|
import {DataTableWithPagination} from "@/components/wrappers/table/data-table-with-pagination";
|
||||||
import {usersColumns} from "@/components/wrappers/Dashboard/Settings/SettingsUsersTab/columns-users";
|
import {usersColumns} from "@/components/wrappers/Dashboard/Settings/SettingsUsersTab/columns-users";
|
||||||
import {User, Settings} from "@prisma/client";
|
import {User, Settings} from "@prisma/client";
|
||||||
import {backupColumns} from "@/features/backup/columns";
|
import {backupColumns} from "@/features/backup/columns";
|
||||||
import {SettingsEmailTab} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/SettingsEmailTab";
|
import {SettingsEmailTab} from "@/components/wrappers/Dashboard/admin/AdminEmailTab/SettingsEmailTab";
|
||||||
import {SettingsStorageTab} from "@/components/wrappers/Dashboard/Settings/SettingsStorageTab/SettingsStorageTab";
|
import {SettingsStorageTab} from "@/components/wrappers/Dashboard/admin/AdminStorageTab/SettingsStorageTab";
|
||||||
import {SettingsUsersTab} from "@/components/wrappers/Dashboard/Settings/SettingsUsersTab/SettingsUsersTab";
|
import {SettingsUsersTab} from "@/components/wrappers/Dashboard/Settings/SettingsUsersTab/SettingsUsersTab";
|
||||||
|
|
||||||
|
|
||||||
export type SettingsTabsProps = {
|
export type SettingsTabsProps = {
|
||||||
|
currentUser: User;
|
||||||
users: User[];
|
users: User[];
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SettingsTabs = (props: SettingsTabsProps) => {
|
export const SettingsTabs = (props: SettingsTabsProps) => {
|
||||||
|
|
||||||
return(
|
const {currentUser, users} = props;
|
||||||
|
|
||||||
<Tabs defaultValue="informations" >
|
return (
|
||||||
<TabsList className="w-full">
|
|
||||||
<TabsTrigger className="w-full " value="informations">Info</TabsTrigger>
|
// <Tabs defaultValue="informations" >
|
||||||
<TabsTrigger className="w-full " value="users">Users</TabsTrigger>
|
// <TabsList className="w-full">
|
||||||
<TabsTrigger className="w-full " value="email">Email</TabsTrigger>
|
// <TabsTrigger className="w-full " value="informations">Info</TabsTrigger>
|
||||||
<TabsTrigger className="w-full " value="storage">Storage</TabsTrigger>
|
// <TabsTrigger className="w-full " value="users">Users</TabsTrigger>
|
||||||
</TabsList>
|
// <TabsTrigger className="w-full " value="email">Email</TabsTrigger>
|
||||||
<TabsContent value="informations">
|
// <TabsTrigger className="w-full " value="storage">Storage</TabsTrigger>
|
||||||
<div className="flex flex-1 flex-col gap-4 py-4">
|
// </TabsList>
|
||||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
// <TabsContent value="informations">
|
||||||
<div className="aspect-video rounded-xl bg-muted/50"/>
|
// <div className="flex flex-1 flex-col gap-4 py-4">
|
||||||
<div className="aspect-video rounded-xl bg-muted/50"/>
|
// <div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||||
<div className="aspect-video rounded-xl bg-muted/50"/>
|
// <div className="aspect-video rounded-xl bg-muted/50"/>
|
||||||
</div>
|
// <div className="aspect-video rounded-xl bg-muted/50"/>
|
||||||
<div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min"/>
|
// <div className="aspect-video rounded-xl bg-muted/50"/>
|
||||||
</div>
|
// </div>
|
||||||
</TabsContent>
|
// <div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min"/>
|
||||||
<TabsContent value="users" >
|
// </div>
|
||||||
<SettingsUsersTab users={props.users}/>
|
// </TabsContent>
|
||||||
</TabsContent>
|
// <TabsContent value="users" >
|
||||||
<TabsContent value="email">
|
<SettingsUsersTab currentUser={currentUser} users={users}/>
|
||||||
<SettingsEmailTab settings={props.settings}/>
|
// </TabsContent>
|
||||||
</TabsContent>
|
// <TabsContent value="email">
|
||||||
<TabsContent value="storage">
|
// <SettingsEmailTab settings={props.settings}/>
|
||||||
<SettingsStorageTab settings={props.settings}/>
|
// </TabsContent>
|
||||||
</TabsContent>
|
// <TabsContent value="storage">
|
||||||
</Tabs>
|
// <SettingsStorageTab settings={props.settings}/>
|
||||||
|
// </TabsContent>
|
||||||
|
// </Tabs>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,30 @@
|
|||||||
|
import {User} from "@prisma/client";
|
||||||
import {DataTableWithPagination} from "@/components/wrappers/table/data-table-with-pagination";
|
import {DataTableWithPagination} from "@/components/wrappers/table/data-table-with-pagination";
|
||||||
import {usersColumns} from "@/components/wrappers/Dashboard/Settings/SettingsUsersTab/columns-users";
|
import {usersColumns} from "@/components/wrappers/Dashboard/Settings/SettingsUsersTab/columns-users";
|
||||||
import {User} from "@prisma/client";
|
import {UsersDataTable} from "@/components/wrappers/Dashboard/admin/admin-user-table";
|
||||||
|
|
||||||
|
|
||||||
export type SettingsUsersTabProps = {
|
export type SettingsUsersTabProps = {
|
||||||
|
currentUser: User;
|
||||||
users: User[]
|
users: User[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SettingsUsersTab = (props: SettingsUsersTabProps) => {
|
export const SettingsUsersTab = (props: SettingsUsersTabProps) => {
|
||||||
return (
|
|
||||||
|
|
||||||
|
const {currentUser, users} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
<div className="flex flex-col h-full py-4">
|
<div className="flex flex-col h-full py-4">
|
||||||
<div className="flex gap-4 h-fit justify-between">
|
<div className="flex gap-4 h-fit justify-between">
|
||||||
<h1>List of Portabase users</h1>
|
<h1>List of organization's users</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
<DataTableWithPagination columns={usersColumns} data={props.users}/>
|
<DataTableWithPagination
|
||||||
|
columns={usersColumns}
|
||||||
|
data={users}
|
||||||
|
DataTable={UsersDataTable}
|
||||||
|
dataTableProps={{currentUser}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -56,13 +56,16 @@ export const SidebarMenuCustom = (props: SidebarMenuCustomProps) => {
|
|||||||
setActiveItem(title);
|
setActiveItem(title);
|
||||||
console.log(title)
|
console.log(title)
|
||||||
}
|
}
|
||||||
return(
|
return (
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<SidebarMenuItem key={item.title}>
|
<SidebarMenuItem key={item.title}>
|
||||||
<SidebarMenuButton asChild >
|
<SidebarMenuButton asChild>
|
||||||
<Link
|
<Link
|
||||||
className={cn(buttonVariants({size: "lg", variant: activeItem === item.title ? "secondary" : 'ghost'}), "justify-start p-0")}
|
className={cn(buttonVariants({
|
||||||
|
size: "lg",
|
||||||
|
variant: activeItem === item.title ? "secondary" : 'ghost'
|
||||||
|
}), "justify-start p-0")}
|
||||||
href={`${BASE_URL}/${item.url}`}
|
href={`${BASE_URL}/${item.url}`}
|
||||||
onClick={() => handleItemClick(item.title)}
|
onClick={() => handleItemClick(item.title)}
|
||||||
>
|
>
|
||||||
@@ -70,9 +73,47 @@ export const SidebarMenuCustom = (props: SidebarMenuCustomProps) => {
|
|||||||
<span>{item.title}</span>
|
<span>{item.title}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
<SidebarMenuAction className={`peer-data-[active=true]/menu-button:opacity-100 ${activeItem === item.title ? 'active' : ''}`}/>
|
<SidebarMenuAction
|
||||||
|
className={`peer-data-[active=true]/menu-button:opacity-100 ${activeItem === item.title ? 'active' : ''}`}/>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
))}
|
))}
|
||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// export type SidebarMenuItemCustomProps = {
|
||||||
|
// title: string
|
||||||
|
// url: string
|
||||||
|
// icon: Element
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// export const SidebarMenuItemCustom = (props: SidebarMenuItemCustomProps) => {
|
||||||
|
//
|
||||||
|
// const {title, url, icon} = props;
|
||||||
|
//
|
||||||
|
// const BASE_URL = "/dashboard";
|
||||||
|
// const pathname = usePathname();
|
||||||
|
//
|
||||||
|
// const [activeItem, setActiveItem] = useState(title);
|
||||||
|
//
|
||||||
|
// return (
|
||||||
|
// <SidebarMenuItem key={title}>
|
||||||
|
// <SidebarMenuButton asChild>
|
||||||
|
// <Link
|
||||||
|
// className={cn(buttonVariants({
|
||||||
|
// size: "lg",
|
||||||
|
// variant: activeItem === title ? "secondary" : 'ghost'
|
||||||
|
// }), "justify-start p-0")}
|
||||||
|
// href={`${BASE_URL}/${url}`}
|
||||||
|
// onClick={() => handleItemClick(item.title)}
|
||||||
|
// >
|
||||||
|
// <icon/>
|
||||||
|
// <span>{title}</span>
|
||||||
|
// </Link>
|
||||||
|
// </SidebarMenuButton>
|
||||||
|
// <SidebarMenuAction
|
||||||
|
// className={`peer-data-[active=true]/menu-button:opacity-100 ${activeItem === title ? 'active' : ''}`}/>
|
||||||
|
// </SidebarMenuItem>
|
||||||
|
// )
|
||||||
|
// }
|
||||||
+2
-2
@@ -13,12 +13,12 @@ import {TooltipProvider} from "@/components/ui/tooltip";
|
|||||||
import {
|
import {
|
||||||
EmailFormSchema,
|
EmailFormSchema,
|
||||||
EmailFormType
|
EmailFormType
|
||||||
} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/EmailForm/email-form.schema";
|
} from "@/components/wrappers/Dashboard/admin/AdminEmailTab/EmailForm/email-form.schema";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import {PasswordInput} from "@/components/wrappers/Auth/PaswordInput/password-input";
|
import {PasswordInput} from "@/components/wrappers/Auth/PaswordInput/password-input";
|
||||||
import {
|
import {
|
||||||
updateEmailSettingsAction
|
updateEmailSettingsAction
|
||||||
} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/EmailForm/email-form.action";
|
} from "@/components/wrappers/Dashboard/admin/AdminEmailTab/EmailForm/email-form.action";
|
||||||
import {toast} from "sonner";
|
import {toast} from "sonner";
|
||||||
import {useRouter} from "next/navigation";
|
import {useRouter} from "next/navigation";
|
||||||
|
|
||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
import {userAction} from "@/safe-actions";
|
import {userAction} from "@/safe-actions";
|
||||||
import {z} from "zod";
|
import {z} from "zod";
|
||||||
import {prisma} from "@/prisma";
|
import {prisma} from "@/prisma";
|
||||||
import {EmailFormSchema} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/EmailForm/email-form.schema";
|
import {EmailFormSchema} from "@/components/wrappers/Dashboard/admin/AdminEmailTab/EmailForm/email-form.schema";
|
||||||
|
|
||||||
|
|
||||||
export const updateEmailSettingsAction = userAction
|
export const updateEmailSettingsAction = userAction
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import {EmailForm} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/EmailForm/EmailForm";
|
import {EmailForm} from "@/components/wrappers/Dashboard/admin/AdminEmailTab/EmailForm/EmailForm";
|
||||||
import {Settings} from "@prisma/client";
|
import {Settings} from "@prisma/client";
|
||||||
import {Send} from "lucide-react";
|
import {Send} from "lucide-react";
|
||||||
import {ButtonWithLoading} from "@/components/wrappers/Button/ButtonWithLoading/ButtonWithLoading";
|
import {ButtonWithLoading} from "@/components/wrappers/Button/ButtonWithLoading/ButtonWithLoading";
|
||||||
+2
-2
@@ -2,7 +2,7 @@ import {Alert, AlertDescription, AlertTitle} from "@/components/ui/alert";
|
|||||||
import {Info, Send, ShieldCheck} from "lucide-react";
|
import {Info, Send, ShieldCheck} from "lucide-react";
|
||||||
import {Switch} from "@/components/ui/switch";
|
import {Switch} from "@/components/ui/switch";
|
||||||
import {Label} from "@/components/ui/label";
|
import {Label} from "@/components/ui/label";
|
||||||
import {StorageS3Form} from "@/components/wrappers/Dashboard/Settings/SettingsStorageTab/StorageS3Form/StorageS3Form";
|
import {StorageS3Form} from "@/components/wrappers/Dashboard/admin/AdminStorageTab/StorageS3Form/StorageS3Form";
|
||||||
import {useState} from "react";
|
import {useState} from "react";
|
||||||
import {Settings} from "@prisma/client";
|
import {Settings} from "@prisma/client";
|
||||||
import {ButtonWithLoading} from "@/components/wrappers/Button/ButtonWithLoading/ButtonWithLoading";
|
import {ButtonWithLoading} from "@/components/wrappers/Button/ButtonWithLoading/ButtonWithLoading";
|
||||||
@@ -13,7 +13,7 @@ import {updateUserAction} from "@/components/wrappers/Dashboard/Profile/UserForm
|
|||||||
import {useRouter} from "next/navigation";
|
import {useRouter} from "next/navigation";
|
||||||
import {
|
import {
|
||||||
updateStorageSettingsAction
|
updateStorageSettingsAction
|
||||||
} from "@/components/wrappers/Dashboard/Settings/SettingsStorageTab/StorageS3Form/s3-form.action";
|
} from "@/components/wrappers/Dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.action";
|
||||||
|
|
||||||
|
|
||||||
export type SettingsStorageTabProps = {
|
export type SettingsStorageTabProps = {
|
||||||
+2
-2
@@ -13,12 +13,12 @@ import {TooltipProvider} from "@/components/ui/tooltip";
|
|||||||
import {
|
import {
|
||||||
S3FormSchema,
|
S3FormSchema,
|
||||||
S3FormType
|
S3FormType
|
||||||
} from "@/components/wrappers/Dashboard/Settings/SettingsStorageTab/StorageS3Form/s3-form.schema";
|
} from "@/components/wrappers/Dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.schema";
|
||||||
import {useRouter} from "next/navigation";
|
import {useRouter} from "next/navigation";
|
||||||
import {toast} from "sonner";
|
import {toast} from "sonner";
|
||||||
import {
|
import {
|
||||||
updateS3SettingsAction
|
updateS3SettingsAction
|
||||||
} from "@/components/wrappers/Dashboard/Settings/SettingsStorageTab/StorageS3Form/s3-form.action";
|
} from "@/components/wrappers/Dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.action";
|
||||||
|
|
||||||
export type S3FormProps = {
|
export type S3FormProps = {
|
||||||
defaultValues?: S3FormType;
|
defaultValues?: S3FormType;
|
||||||
+1
-1
@@ -5,7 +5,7 @@ import {prisma} from "@/prisma";
|
|||||||
import {
|
import {
|
||||||
S3FormSchema,
|
S3FormSchema,
|
||||||
StorageSwitchSchema
|
StorageSwitchSchema
|
||||||
} from "@/components/wrappers/Dashboard/Settings/SettingsStorageTab/StorageS3Form/s3-form.schema";
|
} from "@/components/wrappers/Dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.schema";
|
||||||
|
|
||||||
|
|
||||||
export const updateS3SettingsAction = userAction
|
export const updateS3SettingsAction = userAction
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import {User, Settings} from "@prisma/client";
|
||||||
|
import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs";
|
||||||
|
import {SettingsEmailTab} from "@/components/wrappers/Dashboard/admin/AdminEmailTab/SettingsEmailTab";
|
||||||
|
import {SettingsStorageTab} from "@/components/wrappers/Dashboard/admin/AdminStorageTab/SettingsStorageTab";
|
||||||
|
import {AdminUsersTable} from "@/components/wrappers/Dashboard/admin/admin-user-table";
|
||||||
|
|
||||||
|
|
||||||
|
export type AdminTabsProps = {
|
||||||
|
currentUser: User;
|
||||||
|
users: User[];
|
||||||
|
settings: Settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AdminTabs = (props: AdminTabsProps) => {
|
||||||
|
|
||||||
|
const {currentUser, users, settings} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Tabs defaultValue="users">
|
||||||
|
|
||||||
|
<TabsList className="w-full">
|
||||||
|
<TabsTrigger className="w-full " value="users">Users</TabsTrigger>
|
||||||
|
<TabsTrigger className="w-full " value="email">Email</TabsTrigger>
|
||||||
|
<TabsTrigger className="w-full " value="storage">Storage</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="users">
|
||||||
|
<AdminUsersTable currentUser={currentUser} users={users}/>
|
||||||
|
</TabsContent>
|
||||||
|
<TabsContent value="email">
|
||||||
|
<SettingsEmailTab settings={settings}/>
|
||||||
|
</TabsContent>
|
||||||
|
<TabsContent value="storage">
|
||||||
|
<SettingsStorageTab settings={settings}/>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import {flexRender, Row, RowData} from "@tanstack/react-table";
|
||||||
|
|
||||||
|
import {User} from "@prisma/client";
|
||||||
|
import {DataTableWithPagination} from "@/components/wrappers/table/data-table-with-pagination";
|
||||||
|
import {usersColumns} from "@/components/wrappers/Dashboard/Settings/SettingsUsersTab/columns-users";
|
||||||
|
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
import {cn} from "@/lib/utils";
|
||||||
|
|
||||||
|
export type AdminUsersTableProps = {
|
||||||
|
currentUser: User;
|
||||||
|
users: User[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AdminUsersTable = (props: AdminUsersTableProps) => {
|
||||||
|
|
||||||
|
const {currentUser, users} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col h-full py-4">
|
||||||
|
<div className="flex gap-4 h-fit justify-between">
|
||||||
|
<h1>List of Portabase's users</h1>
|
||||||
|
</div>
|
||||||
|
<div className="mt-5">
|
||||||
|
<DataTableWithPagination
|
||||||
|
columns={usersColumns}
|
||||||
|
data={users}
|
||||||
|
DataTable={UsersDataTable}
|
||||||
|
dataTableProps={{currentUser}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type usersDataTableProps = {
|
||||||
|
currentUser: User;
|
||||||
|
table: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UsersDataTable = ({currentUser, table}: usersDataTableProps) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rounded-md border w-full ">
|
||||||
|
<Table className="w-full">
|
||||||
|
<TableHeader>
|
||||||
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
|
<TableRow key={headerGroup.id}>
|
||||||
|
{headerGroup.headers.map((header) => {
|
||||||
|
return (
|
||||||
|
<TableHead key={header.id}>
|
||||||
|
{header.isPlaceholder
|
||||||
|
? null
|
||||||
|
: flexRender(
|
||||||
|
header.column.columnDef.header,
|
||||||
|
header.getContext()
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{table.getRowModel().rows?.length ? (
|
||||||
|
table.getRowModel().rows.map((row: Row<User>) => (
|
||||||
|
<TableRow
|
||||||
|
className={cn(row.original.id === currentUser.id ? "bg-gray-200 pointer-events-none" : "")}
|
||||||
|
key={row.id}
|
||||||
|
data-state={row.getIsSelected() && "selected"}
|
||||||
|
>
|
||||||
|
{row.getVisibleCells().map((cell) => (
|
||||||
|
<TableCell key={cell.id}>
|
||||||
|
{flexRender(
|
||||||
|
cell.column.columnDef.cell,
|
||||||
|
cell.getContext(),
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))) : (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={table.getAllColumns().length} className="h-24 text-center">
|
||||||
|
No results.
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ import {useState} from "react";
|
|||||||
import {useMutation} from "@tanstack/react-query";
|
import {useMutation} from "@tanstack/react-query";
|
||||||
import {
|
import {
|
||||||
updateStorageSettingsAction
|
updateStorageSettingsAction
|
||||||
} from "@/components/wrappers/Dashboard/Settings/SettingsStorageTab/StorageS3Form/s3-form.action";
|
} from "@/components/wrappers/Dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.action";
|
||||||
import {toast} from "sonner";
|
import {toast} from "sonner";
|
||||||
import {useRouter} from "next/navigation";
|
import {useRouter} from "next/navigation";
|
||||||
import {Database} from "@prisma/client";
|
import {Database} from "@prisma/client";
|
||||||
|
|||||||
@@ -5,16 +5,21 @@ import {useState} from "react";
|
|||||||
import {
|
import {
|
||||||
ColumnDef, getCoreRowModel, getPaginationRowModel, getSortedRowModel, SortingState, useReactTable
|
ColumnDef, getCoreRowModel, getPaginationRowModel, getSortedRowModel, SortingState, useReactTable
|
||||||
} from "@tanstack/react-table"
|
} from "@tanstack/react-table"
|
||||||
import {DataTable} from "@/components/wrappers/table/data-table";
|
import {DataTable as BaseDataTable} from "@/components/wrappers/table/data-table";
|
||||||
import {TablePagination} from "@/components/wrappers/table/table-pagination";
|
import {TablePagination} from "@/components/wrappers/table/table-pagination";
|
||||||
|
|
||||||
interface DataTableProps<TData, TValue> {
|
interface DataTableProps<TData, TValue> {
|
||||||
columns: ColumnDef<TData, TValue>[]
|
columns: ColumnDef<TData, TValue>[]
|
||||||
data: TData[]
|
data: TData[]
|
||||||
extendedProps?: any
|
extendedProps?: any
|
||||||
|
DataTable?: any
|
||||||
|
dataTableProps?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DataTableWithPagination<TData, TValue>({columns, data, extendedProps}: DataTableProps<TData, TValue>) {
|
export function DataTableWithPagination<TData, TValue>(props: DataTableProps<TData, TValue>) {
|
||||||
|
|
||||||
|
const {columns, data, extendedProps, DataTable = BaseDataTable, dataTableProps} = props;
|
||||||
|
|
||||||
|
|
||||||
const [sorting, setSorting] = useState<SortingState>([])
|
const [sorting, setSorting] = useState<SortingState>([])
|
||||||
|
|
||||||
@@ -35,7 +40,7 @@ export function DataTableWithPagination<TData, TValue>({columns, data, extendedP
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col justify-between h-full">
|
<div className="flex flex-col justify-between h-full">
|
||||||
<DataTable table={table} />
|
<DataTable table={table} {...dataTableProps}/>
|
||||||
<TablePagination table={table} pageSizeOptions={[5, 10, 20, 50, 100]}/>
|
<TablePagination table={table} pageSizeOptions={[5, 10, 20, 50, 100]}/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
import {flexRender} from "@tanstack/react-table";
|
import {flexRender, Row, RowData} from "@tanstack/react-table";
|
||||||
|
import {cn} from "@/lib/utils";
|
||||||
|
|
||||||
export type dataTableProps = {
|
export type dataTableProps = {
|
||||||
table: any,
|
table: any,
|
||||||
@@ -30,21 +31,25 @@ export const DataTable = ({table}: dataTableProps) => {
|
|||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{table.getRowModel().rows?.length ? (
|
{table.getRowModel().rows?.length ? (
|
||||||
table.getRowModel().rows.map((row) => (
|
table.getRowModel().rows.map((row: Row<RowData>) => {
|
||||||
<TableRow
|
console.log("row.original",row.original.id)
|
||||||
key={row.id}
|
return(
|
||||||
data-state={row.getIsSelected() && "selected"}
|
<TableRow
|
||||||
>
|
className={cn(row.original ?? "bg-gray-200 pointer-events-none")}
|
||||||
{row.getVisibleCells().map((cell) => (
|
key={row.id}
|
||||||
<TableCell key={cell.id}>
|
data-state={row.getIsSelected() && "selected"}
|
||||||
{flexRender(
|
>
|
||||||
cell.column.columnDef.cell,
|
{row.getVisibleCells().map((cell) => (
|
||||||
cell.getContext(),
|
<TableCell key={cell.id}>
|
||||||
)}
|
{flexRender(
|
||||||
</TableCell>
|
cell.column.columnDef.cell,
|
||||||
))}
|
cell.getContext(),
|
||||||
</TableRow>
|
)}
|
||||||
))
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
})
|
||||||
) : (
|
) : (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={table.getAllColumns().length} className="h-24 text-center">
|
<TableCell colSpan={table.getAllColumns().length} className="h-24 text-center">
|
||||||
|
|||||||
Reference in New Issue
Block a user