mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-11 01:41:26 +08:00
170 lines
4.5 KiB
TypeScript
170 lines
4.5 KiB
TypeScript
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipTrigger,
|
|
} from '@/components/ui/tooltip';
|
|
import { formatDate } from '@/utils/date';
|
|
import { ElementType, ReactNode, useRef, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
interface IProps {
|
|
data: {
|
|
name: string;
|
|
description?: string;
|
|
avatar?: string;
|
|
update_time?: string | number;
|
|
release_time?: number;
|
|
};
|
|
onClick?: () => void;
|
|
moreDropdown: React.ReactNode;
|
|
sharedBadge?: ReactNode;
|
|
icon?: React.ReactNode;
|
|
testId?: string;
|
|
showReleaseTime?: boolean;
|
|
extra?: ReactNode;
|
|
}
|
|
|
|
function Time({ time }: { time: string | number | undefined }) {
|
|
return <p className="text-sm truncate">{formatDate(time)}</p>;
|
|
}
|
|
|
|
function TruncatedText({
|
|
as: Tag = 'div',
|
|
className,
|
|
children,
|
|
tooltip,
|
|
testId,
|
|
}: {
|
|
as?: ElementType;
|
|
className?: string;
|
|
children?: ReactNode;
|
|
tooltip?: ReactNode;
|
|
testId?: string;
|
|
}) {
|
|
const ref = useRef<HTMLElement>(null);
|
|
const [open, setOpen] = useState(false);
|
|
|
|
if (tooltip == null) {
|
|
return (
|
|
<Tag ref={ref} className={className} data-testid={testId}>
|
|
{children}
|
|
</Tag>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Tooltip
|
|
open={open}
|
|
onOpenChange={(next) => {
|
|
const el = ref.current;
|
|
setOpen(next && el !== null && el.scrollWidth > el.clientWidth);
|
|
}}
|
|
>
|
|
<TooltipTrigger asChild>
|
|
<Tag ref={ref} className={className} data-testid={testId} tabIndex={0}>
|
|
{children}
|
|
</Tag>
|
|
</TooltipTrigger>
|
|
<TooltipContent>{tooltip}</TooltipContent>
|
|
</Tooltip>
|
|
);
|
|
}
|
|
|
|
export function HomeCard({
|
|
data,
|
|
onClick,
|
|
moreDropdown,
|
|
sharedBadge,
|
|
icon,
|
|
testId,
|
|
showReleaseTime = false,
|
|
extra,
|
|
}: IProps) {
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<Card
|
|
as="article"
|
|
data-testid={testId}
|
|
data-agent-name={data.name}
|
|
onClick={() => {
|
|
// navigateToSearch(data?.id);
|
|
onClick?.();
|
|
}}
|
|
tabIndex={0}
|
|
className="px-2.5 py-4 flex gap-2 items-start group h-full w-full hover:shadow-md"
|
|
>
|
|
<div>
|
|
<RAGFlowAvatar
|
|
className="w-[32px] h-[32px]"
|
|
avatar={data.avatar}
|
|
name={data.name}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex-1 w-0">
|
|
<CardHeader
|
|
as="header"
|
|
className="p-0 flex-1 flex flex-row items-center gap-2 space-y-0"
|
|
>
|
|
<CardTitle className="flex-1 inline-flex w-0 me-auto">
|
|
<TruncatedText
|
|
as="h3"
|
|
className="flex-1 truncate text-base font-bold leading-snug"
|
|
testId="agent-name"
|
|
tooltip={data.name}
|
|
>
|
|
{data.name}
|
|
</TruncatedText>
|
|
|
|
{icon}
|
|
</CardTitle>
|
|
|
|
<div>{moreDropdown}</div>
|
|
</CardHeader>
|
|
|
|
<CardContent className="p-0">
|
|
<div className="flex flex-col justify-between gap-1 flex-1 h-full w-[calc(100%-50px)]">
|
|
<section className="flex justify-between"></section>
|
|
|
|
<section className="flex flex-col gap-1 mt-1">
|
|
<TruncatedText
|
|
className="whitespace-nowrap overflow-hidden text-ellipsis"
|
|
tooltip={data.description}
|
|
>
|
|
{data.description}
|
|
</TruncatedText>
|
|
{extra}
|
|
<div className="flex justify-between items-center min-w-0">
|
|
{showReleaseTime ? (
|
|
<section className="text-sm text-text-secondary space-y-1 min-w-0">
|
|
<div className="flex items-center gap-2 min-w-0">
|
|
<span className="whitespace-nowrap">
|
|
{t('flow.lastSavedAt')}:
|
|
</span>
|
|
<Time time={data.update_time}></Time>
|
|
</div>
|
|
{data.release_time && (
|
|
<div className="flex items-center gap-2 min-w-0">
|
|
<span className="whitespace-nowrap">
|
|
{t('flow.publishedAt')}:
|
|
</span>
|
|
<Time time={data.release_time}></Time>
|
|
</div>
|
|
)}
|
|
</section>
|
|
) : (
|
|
<Time time={data.update_time}></Time>
|
|
)}
|
|
{sharedBadge}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</CardContent>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|