Skip to content

Commit

Permalink
feat(client_bot_ui): beautify the Bot list UI (#229)
Browse files Browse the repository at this point in the history
  • Loading branch information
xingwanying authored Aug 19, 2024
2 parents 3918b4b + cc4864e commit 388cb89
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 30 deletions.
113 changes: 96 additions & 17 deletions client/app/factory/list/components/BotCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,16 @@ import {
Button,
Image,
useDisclosure,
Tooltip,
} from '@nextui-org/react';
import { useRouter } from 'next/navigation';
import { useBotDelete } from '@/app/hooks/useBot';
import { useBotDelete, useGetRagTask } from '@/app/hooks/useBot';
import CloudIcon from '@/public/icons/CloudIcon';
import MinusCircleIcon from '@/public/icons/MinusCircleIcon';
import { TaskStatus } from '@/types/task';
import ErrorBadgeIcon from '@/public/icons/ErrorBadgeIcon';
import CheckBadgeIcon from '@/public/icons/CheckBadgeIcon';
import LoadingIcon from '@/public/icons/LoadingIcon';

declare type Bot = Tables<'bots'>;

Expand All @@ -25,6 +32,7 @@ const BotCard = (props: { bot: Bot }) => {
const router = useRouter();
const [isHovered, setIsHovered] = useState(false);
const { deleteBot, isLoading, isSuccess } = useBotDelete();
const { data: taskInfo } = useGetRagTask(bot.id);

useEffect(() => {
if (isSuccess) {
Expand All @@ -35,40 +43,111 @@ const BotCard = (props: { bot: Bot }) => {
const onDelete = (id: string) => {
deleteBot(id);
};
const renderTaskStatusIcon = (status: TaskStatus) => {
if (status === TaskStatus.COMPLETED) {
return <CheckBadgeIcon />;
}
if (status === TaskStatus.ERROR) {
return <ErrorBadgeIcon />;
}
return (
<span className="animate-spinner-ease-spin">
<LoadingIcon />
</span>
);
};

return (
<>
<Card
className="border-none w-full bg-[#FFF] rounded-[16px] p-2 h-[384px]"
isPressable
isPressable={false}
shadow="none"
data-hover="true"
onPress={() => router.push(`/factory/edit/${bot.id}`)}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<CardBody className="overflow-visible flex-initial p-0">
<Image
shadow="none"
loading="eager"
radius="lg"
width="100%"
alt={bot.name!}
className="rounded-[8px] opacity-100 w-full object-cover h-[268px]"
src={bot.avatar!}
/>
<div className="z-10 opacity-0 rounded-[8px] hover:opacity-100 w-full h-full backdrop-blur-xl transition-all bg-gradient-to-b from-[rgba(255,255,255,0.65)] to-white absolute flex items-center justify-center">
<Image src="./images/chat.svg" />
<CardBody className="overflow-visible flex-initial p-0 flex-1">
<div
className="relative overflow-hidden w-full h-full bg-cover bg-center"
style={{ backgroundImage: `url(${bot.avatar})` }}
>
<div className="absolute inset-0 bg-white bg-opacity-50 backdrop-blur-[70px]"></div>
<div className="flex justify-center items-center h-full">
{isHovered ? (
<div className="flex items-center gap-10">
<Tooltip
showArrow
placement="top"
content="调试"
classNames={{
base: [
// arrow color
'before:bg-[#3F3F46] dark:before:bg-white',
],
content: [
'py-2 px-4 rounded-lg shadow-xl text-white',
'bg-[#3F3F46]',
],
}}
>
<Image
src="../images/debug.svg"
alt={'调试'}
onClick={() => router.push(`/factory/edit/${bot.id}`)}
className="z-10 cursor-pointer"
/>
</Tooltip>
<Tooltip
showArrow
placement="top"
content="更新知识库"
classNames={{
base: [
// arrow color
'before:bg-[#3F3F46] dark:before:bg-white',
],
content: [
'py-2 px-4 rounded-lg shadow-xl text-white',
'bg-[#3F3F46]',
],
}}
>
<Image
src="../images/refresh.svg"
alt={'更新知识'}
className="z-10 cursor-pointer"
/>
</Tooltip>
</div>
) : (
<Image
src={bot.avatar!}
shadow="none"
loading="eager"
alt={bot.name}
className="w-24 h-24"
/>
)}
</div>
</div>
</CardBody>
<CardFooter className="text-small justify-between flex-col flex-1 mt-4 p-0 px-3">
<CardFooter className="text-small justify-between flex-col mt-4 p-0 px-3 h-[84px]">
<div className="flex w-full text-small justify-between pb-2">
<span className="leading-8 h-8 font-semibold text-2xl whitespace-nowrap overflow-hidden text-ellipsis">
{bot.name}
</span>
<div className="flex items-center gap-2 shrink-0">
<div className="w-[32px] h-[32px] p-[7px] flex items-center rounded-[16px] bg-[#F4F4F5]">
{bot.public ? <CloudIcon /> : <MinusCircleIcon />}
</div>
<div className="w-[32px] h-[32px] p-[7px] flex items-center rounded-[16px] bg-[#F4F4F5]">
{renderTaskStatusIcon(taskInfo?.status as TaskStatus)}
</div>
</div>
</div>

<div className="flex-1 w-full border-zinc-100/50 text-left text-gray-400 font-[400] text-[14px] leading-[22px]">
<div className="flex-1 w-full border-zinc-100/50 text-left text-gray-400 font-[400] text-[14px] leading-[22px] ">
<p className="my-0 overflow-hidden text-ellipsis line-clamp-2">
{bot.description}
</p>
Expand Down
30 changes: 18 additions & 12 deletions client/components/BotCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,29 @@ const BotCard = (props: {
handleCardClick?.(bot?.id);
}}
>
<CardBody className="overflow-visible flex-initial p-0">
<Image
shadow="none"
loading="eager"
radius="lg"
width="100%"
alt={bot.name!}
className="rounded-[8px] opacity-100 w-full object-cover h-[268px]"
src={bot.avatar!}
/>
<CardBody className="overflow-visible flex-initial p-0 flex-1">
<div
className="z-10 opacity-0 rounded-[8px] hover:opacity-100 w-full h-full backdrop-blur-xl transition-all bg-gradient-to-b from-[rgba(255,255,255,0.65)] to-white absolute flex items-center justify-center"
className="relative overflow-hidden w-full h-full bg-cover bg-center"
style={{ backgroundImage: `url(${bot.avatar})` }}
>
<div className="absolute inset-0 bg-white bg-opacity-50 backdrop-blur-[70px]"></div>
<div className="flex justify-center items-center h-full">
<Image
shadow="none"
loading="eager"
radius="lg"
width="100px"
alt={bot.name!}
className="w-24 h-24"
src={bot.avatar!}
/>
</div>
</div>
<div className="z-10 opacity-0 rounded-[8px] hover:opacity-100 w-full h-full backdrop-blur-xl transition-all bg-gradient-to-b from-[rgba(255,255,255,0.65)] to-white absolute flex items-center justify-center">
<Image src="./images/chat.svg" />
</div>
</CardBody>
<CardFooter className="text-small justify-between flex-col flex-1 mt-4 p-0 px-3">
<CardFooter className="text-small justify-between flex-col mt-4 p-0 px-3 min-h-[84px]">
<div className="flex w-full text-small justify-between pb-2">
<span className="leading-8 h-8 font-semibold text-2xl whitespace-nowrap overflow-hidden text-ellipsis">
{bot.name}
Expand Down
17 changes: 17 additions & 0 deletions client/public/icons/CheckBadgeIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const CheckBadgeIcon = () => (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M13.1222 10.1218C13.882 9.71897 14.3996 8.91992 14.3996 7.99998C14.3996 7.08003 13.882 6.28098 13.1222 5.87814C13.3746 5.05599 13.1756 4.12498 12.5251 3.47447C11.8746 2.82397 10.9436 2.62495 10.1214 2.87741C9.7186 2.11756 8.91955 1.59998 7.99961 1.59998C7.07966 1.59998 6.28061 2.11757 5.87777 2.87743C5.05563 2.62498 4.12462 2.824 3.47413 3.4745C2.82363 4.125 2.62461 5.056 2.87705 5.87814C2.1172 6.28098 1.59961 7.08003 1.59961 7.99998C1.59961 8.91992 2.1172 9.71897 2.87705 10.1218C2.6246 10.944 2.82362 11.875 3.47412 12.5255C4.12462 13.176 5.05563 13.375 5.87778 13.1225C6.28062 13.8824 7.07967 14.4 7.99961 14.4C8.91956 14.4 9.71861 13.8824 10.1214 13.1225C10.9436 13.375 11.8746 13.1759 12.5251 12.5254C13.1756 11.875 13.3746 10.944 13.1222 10.1218ZM11.0849 6.55288C11.2798 6.28489 11.2205 5.90964 10.9525 5.71473C10.6845 5.51983 10.3093 5.57908 10.1144 5.84707L7.32736 9.6792L5.82387 8.17571C5.58956 7.9414 5.20966 7.9414 4.97535 8.17571C4.74103 8.41003 4.74103 8.78992 4.97535 9.02424L6.97535 11.0242C7.09942 11.1483 7.2716 11.2119 7.44654 11.1981C7.62148 11.1844 7.78164 11.0948 7.88485 10.9529L11.0849 6.55288Z"
fill="#6B7280"
/>
</svg>
);
export default CheckBadgeIcon;
14 changes: 14 additions & 0 deletions client/public/icons/CloudIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const CloudIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" width={16} height={16} fill="none">
<g fill="#F9FAFB" fillRule="evenodd" clipPath="url(#a)" clipRule="evenodd">
<path d="M3.685 10.375a.6.6 0 0 1-.108.842 1.996 1.996 0 0 0-.744 1.95 2.008 2.008 0 0 0 1.95-.744.6.6 0 1 1 .949.734 3.196 3.196 0 0 1-3.585 1.066.6.6 0 0 1-.37-.37 3.196 3.196 0 0 1 1.066-3.585.6.6 0 0 1 .842.107Z" />
<path d="M4.602 9.6A10.46 10.46 0 0 0 6.4 11.398V14.6a.6.6 0 0 0 .6.6 4 4 0 0 0 3.838-5.131 10.388 10.388 0 0 0 4.36-8.679.6.6 0 0 0-.588-.588 10.388 10.388 0 0 0-8.679 4.36A4 4 0 0 0 .8 9a.6.6 0 0 0 .6.6h3.202ZM10.4 7.2a1.6 1.6 0 1 0 0-3.2 1.6 1.6 0 0 0 0 3.2Z" />
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h16v16H0z" />
</clipPath>
</defs>
</svg>
);
export default CloudIcon;
17 changes: 17 additions & 0 deletions client/public/icons/ErrorBadgeIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const ErrorBadgeIcon = () => (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M14.3996 7.99998C14.3996 11.5346 11.5342 14.4 7.99961 14.4C4.46499 14.4 1.59961 11.5346 1.59961 7.99998C1.59961 4.46535 4.46499 1.59998 7.99961 1.59998C11.5342 1.59998 14.3996 4.46535 14.3996 7.99998ZM7.99961 3.99998C8.33098 3.99998 8.59961 4.2686 8.59961 4.59998V8.19998C8.59961 8.53135 8.33098 8.79998 7.99961 8.79998C7.66824 8.79998 7.39961 8.53135 7.39961 8.19998V4.59998C7.39961 4.2686 7.66824 3.99998 7.99961 3.99998ZM7.99961 12C8.44144 12 8.79961 11.6418 8.79961 11.2C8.79961 10.7581 8.44144 10.4 7.99961 10.4C7.55778 10.4 7.19961 10.7581 7.19961 11.2C7.19961 11.6418 7.55778 12 7.99961 12Z"
fill="#DC2626"
/>
</svg>
);
export default ErrorBadgeIcon;
18 changes: 18 additions & 0 deletions client/public/icons/LoadingIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const LoadingIcon = () => (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.8635 2.06246C7.68917 1.89168 6.49056 2.07296 5.41925 2.58338C4.34795 3.0938 3.45206 3.91044 2.84488 4.93003C2.23769 5.94962 1.94649 7.12636 2.00809 8.31145C2.06969 9.49654 2.48132 10.6367 3.19094 11.5879C3.90056 12.539 4.87628 13.2584 5.99474 13.655C7.11319 14.0516 8.32413 14.1076 9.47443 13.816C10.6247 13.5244 11.6627 12.8982 12.4571 12.0167C13.2516 11.1352 13.7668 10.0378 13.9375 8.8635"
stroke="#9CA3AF"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
export default LoadingIcon;
17 changes: 17 additions & 0 deletions client/public/icons/MinusCircleIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const MinusCircleIcon = () => (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M7.99961 14.4C11.5342 14.4 14.3996 11.5346 14.3996 7.99998C14.3996 4.46535 11.5342 1.59998 7.99961 1.59998C4.46499 1.59998 1.59961 4.46535 1.59961 7.99998C1.59961 11.5346 4.46499 14.4 7.99961 14.4ZM5.39961 7.39998C5.06824 7.39998 4.79961 7.6686 4.79961 7.99998C4.79961 8.33135 5.06824 8.59998 5.39961 8.59998H10.5996C10.931 8.59998 11.1996 8.33135 11.1996 7.99998C11.1996 7.6686 10.931 7.39998 10.5996 7.39998H5.39961Z"
fill="#9CA3AF"
/>
</svg>
);
export default MinusCircleIcon;
29 changes: 29 additions & 0 deletions client/public/images/debug.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions client/public/images/refresh.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion server/routers/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,3 @@ async def delete_bot(
return JSONResponse(content={"success": True})
except Exception as e:
return JSONResponse(content={"success": False, "errorMessage": str(e)}, status_code=500)

0 comments on commit 388cb89

Please sign in to comment.