mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor(#168): make project card be clickable everywhere
This commit is contained in:
@@ -76,8 +76,8 @@ export const ShowProjects = () => {
|
|||||||
project?.compose.length;
|
project?.compose.length;
|
||||||
return (
|
return (
|
||||||
<div key={project.projectId} className="w-full lg:max-w-md">
|
<div key={project.projectId} className="w-full lg:max-w-md">
|
||||||
<Card className="group relative w-full bg-transparent transition-colors hover:bg-card">
|
<Link href={`/dashboard/project/${project.projectId}`}>
|
||||||
<Link href={`/dashboard/project/${project.projectId}`}>
|
<Card className="group relative w-full bg-transparent transition-colors hover:bg-card">
|
||||||
<Button
|
<Button
|
||||||
className="absolute -right-3 -top-3 size-9 translate-y-1 rounded-full p-0 opacity-0 transition-all duration-200 group-hover:translate-y-0 group-hover:opacity-100"
|
className="absolute -right-3 -top-3 size-9 translate-y-1 rounded-full p-0 opacity-0 transition-all duration-200 group-hover:translate-y-0 group-hover:opacity-100"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -85,113 +85,122 @@ export const ShowProjects = () => {
|
|||||||
>
|
>
|
||||||
<ExternalLinkIcon className="size-3.5" />
|
<ExternalLinkIcon className="size-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
<CardHeader>
|
||||||
<CardHeader>
|
<CardTitle className="flex items-center justify-between gap-2">
|
||||||
<CardTitle className="flex items-center justify-between gap-2">
|
<span className="flex flex-col gap-1.5">
|
||||||
<span className="flex flex-col gap-1.5">
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex items-center gap-2">
|
<BookIcon className="size-4 text-muted-foreground" />
|
||||||
<BookIcon className="size-4 text-muted-foreground" />
|
<span className="text-base font-medium leading-none">
|
||||||
<Link
|
{project.name}
|
||||||
className="text-base font-medium leading-none"
|
</span>
|
||||||
href={`/dashboard/project/${project.projectId}`}
|
</div>
|
||||||
>
|
|
||||||
{project.name}
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span className="text-sm font-medium text-muted-foreground">
|
<span className="text-sm font-medium text-muted-foreground">
|
||||||
{project.description}
|
{project.description}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
<div className="flex self-start space-x-1">
|
||||||
<div className="flex self-start space-x-1">
|
<DropdownMenu>
|
||||||
<DropdownMenu>
|
<DropdownMenuTrigger asChild>
|
||||||
<DropdownMenuTrigger asChild>
|
<Button
|
||||||
<Button variant="ghost" size="icon" className="px-2">
|
variant="ghost"
|
||||||
<MoreHorizontalIcon className="size-5" />
|
size="icon"
|
||||||
</Button>
|
className="px-2"
|
||||||
</DropdownMenuTrigger>
|
>
|
||||||
<DropdownMenuContent className="w-[200px] space-y-2">
|
<MoreHorizontalIcon className="size-5" />
|
||||||
<DropdownMenuLabel className="font-normal">
|
</Button>
|
||||||
Actions
|
</DropdownMenuTrigger>
|
||||||
</DropdownMenuLabel>
|
<DropdownMenuContent className="w-[200px] space-y-2">
|
||||||
|
<DropdownMenuLabel className="font-normal">
|
||||||
|
Actions
|
||||||
|
</DropdownMenuLabel>
|
||||||
|
|
||||||
<UpdateProject projectId={project.projectId} />
|
<div onClick={(e) => e.stopPropagation()}>
|
||||||
|
<UpdateProject projectId={project.projectId} />
|
||||||
|
</div>
|
||||||
|
|
||||||
{(auth?.rol === "admin" ||
|
<div onClick={(e) => e.stopPropagation()}>
|
||||||
user?.canDeleteProjects) && (
|
{(auth?.rol === "admin" ||
|
||||||
<AlertDialog>
|
user?.canDeleteProjects) && (
|
||||||
<AlertDialogTrigger className="w-full">
|
<AlertDialog>
|
||||||
<DropdownMenuItem
|
<AlertDialogTrigger className="w-full">
|
||||||
className="w-full cursor-pointer space-x-3"
|
<DropdownMenuItem
|
||||||
onSelect={(e) => e.preventDefault()}
|
className="w-full cursor-pointer space-x-3"
|
||||||
>
|
onSelect={(e) => e.preventDefault()}
|
||||||
<TrashIcon className="size-4" />
|
>
|
||||||
<span>Delete</span>
|
<TrashIcon className="size-4" />
|
||||||
</DropdownMenuItem>
|
<span>Delete</span>
|
||||||
</AlertDialogTrigger>
|
</DropdownMenuItem>
|
||||||
<AlertDialogContent>
|
</AlertDialogTrigger>
|
||||||
<AlertDialogHeader>
|
<AlertDialogContent>
|
||||||
<AlertDialogTitle>
|
<AlertDialogHeader>
|
||||||
Are you sure to delete this project?
|
<AlertDialogTitle>
|
||||||
</AlertDialogTitle>
|
Are you sure to delete this project?
|
||||||
{!emptyServices ? (
|
</AlertDialogTitle>
|
||||||
<div className="flex flex-row gap-4 rounded-lg bg-yellow-50 p-2 dark:bg-yellow-950">
|
{!emptyServices ? (
|
||||||
<AlertTriangle className="text-yellow-600 dark:text-yellow-400" />
|
<div className="flex flex-row gap-4 rounded-lg bg-yellow-50 p-2 dark:bg-yellow-950">
|
||||||
<span className="text-sm text-yellow-600 dark:text-yellow-400">
|
<AlertTriangle className="text-yellow-600 dark:text-yellow-400" />
|
||||||
You have active services, please delete
|
<span className="text-sm text-yellow-600 dark:text-yellow-400">
|
||||||
them first
|
You have active services, please
|
||||||
</span>
|
delete them first
|
||||||
</div>
|
</span>
|
||||||
) : (
|
</div>
|
||||||
<AlertDialogDescription>
|
) : (
|
||||||
This action cannot be undone
|
<AlertDialogDescription>
|
||||||
</AlertDialogDescription>
|
This action cannot be undone
|
||||||
)}
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
)}
|
||||||
<AlertDialogFooter>
|
</AlertDialogHeader>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogFooter>
|
||||||
<AlertDialogAction
|
<AlertDialogCancel>
|
||||||
disabled={!emptyServices}
|
Cancel
|
||||||
onClick={async () => {
|
</AlertDialogCancel>
|
||||||
await mutateAsync({
|
<AlertDialogAction
|
||||||
projectId: project.projectId,
|
disabled={!emptyServices}
|
||||||
})
|
onClick={async () => {
|
||||||
.then(() => {
|
await mutateAsync({
|
||||||
toast.success(
|
projectId: project.projectId,
|
||||||
"Project delete succesfully",
|
})
|
||||||
);
|
.then(() => {
|
||||||
})
|
toast.success(
|
||||||
.catch(() => {
|
"Project delete succesfully",
|
||||||
toast.error(
|
);
|
||||||
"Error to delete this project",
|
})
|
||||||
);
|
.catch(() => {
|
||||||
})
|
toast.error(
|
||||||
.finally(() => {
|
"Error to delete this project",
|
||||||
utils.project.all.invalidate();
|
);
|
||||||
});
|
})
|
||||||
}}
|
.finally(() => {
|
||||||
>
|
utils.project.all.invalidate();
|
||||||
Delete
|
});
|
||||||
</AlertDialogAction>
|
}}
|
||||||
</AlertDialogFooter>
|
>
|
||||||
</AlertDialogContent>
|
Delete
|
||||||
</AlertDialog>
|
</AlertDialogAction>
|
||||||
)}
|
</AlertDialogFooter>
|
||||||
</DropdownMenuContent>
|
</AlertDialogContent>
|
||||||
</DropdownMenu>
|
</AlertDialog>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardFooter className="pt-4">
|
||||||
|
<div className="space-y-1 text-sm flex flex-row justify-between max-sm:flex-wrap w-full gap-2 sm:gap-4">
|
||||||
|
<DateTooltip date={project.createdAt}>
|
||||||
|
Created
|
||||||
|
</DateTooltip>
|
||||||
|
<span>
|
||||||
|
{totalServices}{" "}
|
||||||
|
{totalServices === 1 ? "service" : "services"}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</CardTitle>
|
</CardFooter>
|
||||||
</CardHeader>
|
</Card>
|
||||||
<CardFooter className="pt-4">
|
</Link>
|
||||||
<div className="space-y-1 text-sm flex flex-row justify-between max-sm:flex-wrap w-full gap-2 sm:gap-4">
|
|
||||||
<DateTooltip date={project.createdAt}>Created</DateTooltip>
|
|
||||||
<span>
|
|
||||||
{totalServices}{" "}
|
|
||||||
{totalServices === 1 ? "service" : "services"}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</CardFooter>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
Reference in New Issue
Block a user