### What problem does this PR solve? Feat: Preview the file #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.19.0
| @@ -1,4 +1,5 @@ | |||
| import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; | |||
| import NewDocumentLink from '@/components/new-document-link'; | |||
| import { Button } from '@/components/ui/button'; | |||
| import { | |||
| DropdownMenu, | |||
| @@ -9,8 +10,12 @@ import { | |||
| } from '@/components/ui/dropdown-menu'; | |||
| import { useDownloadFile } from '@/hooks/file-manager-hooks'; | |||
| import { IFile } from '@/interfaces/database/file-manager'; | |||
| import { | |||
| getExtension, | |||
| isSupportedPreviewDocumentType, | |||
| } from '@/utils/document-util'; | |||
| import { CellContext } from '@tanstack/react-table'; | |||
| import { EllipsisVertical, Link2, Trash2 } from 'lucide-react'; | |||
| import { EllipsisVertical, Eye, Link2, Trash2 } from 'lucide-react'; | |||
| import { useCallback } from 'react'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { | |||
| @@ -18,6 +23,7 @@ import { | |||
| UseRenameCurrentFileReturnType, | |||
| } from './hooks'; | |||
| import { UseMoveDocumentShowType } from './use-move-file'; | |||
| import { isFolderType } from './util'; | |||
| type IProps = Pick<CellContext<IFile, unknown>, 'row'> & | |||
| Pick<UseHandleConnectToKnowledgeReturnType, 'showConnectToKnowledgeModal'> & | |||
| @@ -34,6 +40,8 @@ export function ActionCell({ | |||
| const record = row.original; | |||
| const documentId = record.id; | |||
| const { downloadFile } = useDownloadFile(); | |||
| const isFolder = isFolderType(record.type); | |||
| const extension = getExtension(record.name); | |||
| const handleShowConnectToKnowledgeModal = useCallback(() => { | |||
| showConnectToKnowledgeModal(record); | |||
| @@ -57,20 +65,31 @@ export function ActionCell({ | |||
| return ( | |||
| <section className="flex gap-4 items-center"> | |||
| <Button | |||
| variant="secondary" | |||
| variant="ghost" | |||
| size={'icon'} | |||
| onClick={handleShowConnectToKnowledgeModal} | |||
| > | |||
| <Link2 /> | |||
| </Button> | |||
| <ConfirmDeleteDialog> | |||
| <Button variant="secondary" size={'icon'}> | |||
| <Button variant="ghost" size={'icon'}> | |||
| <Trash2 /> | |||
| </Button> | |||
| </ConfirmDeleteDialog> | |||
| {isSupportedPreviewDocumentType(extension) && ( | |||
| <NewDocumentLink | |||
| documentId={documentId} | |||
| documentName={record.name} | |||
| color="black" | |||
| > | |||
| <Button variant={'ghost'} size={'icon'}> | |||
| <Eye /> | |||
| </Button> | |||
| </NewDocumentLink> | |||
| )} | |||
| <DropdownMenu> | |||
| <DropdownMenuTrigger asChild> | |||
| <Button variant="secondary" size={'icon'}> | |||
| <Button variant="ghost" size={'icon'}> | |||
| <EllipsisVertical /> | |||
| </Button> | |||
| </DropdownMenuTrigger> | |||
| @@ -83,9 +102,11 @@ export function ActionCell({ | |||
| {t('common.rename')} | |||
| </DropdownMenuItem> | |||
| <DropdownMenuSeparator /> | |||
| <DropdownMenuItem onClick={onDownloadDocument}> | |||
| {t('common.download')} | |||
| </DropdownMenuItem> | |||
| {isFolder || ( | |||
| <DropdownMenuItem onClick={onDownloadDocument}> | |||
| {t('common.download')} | |||
| </DropdownMenuItem> | |||
| )} | |||
| </DropdownMenuContent> | |||
| </DropdownMenu> | |||
| </section> | |||
| @@ -17,7 +17,6 @@ import * as React from 'react'; | |||
| import { RenameDialog } from '@/components/rename-dialog'; | |||
| import SvgIcon from '@/components/svg-icon'; | |||
| import { TableEmpty, TableSkeleton } from '@/components/table-skeleton'; | |||
| import { Badge } from '@/components/ui/badge'; | |||
| import { Button } from '@/components/ui/button'; | |||
| import { Checkbox } from '@/components/ui/checkbox'; | |||
| import { | |||
| @@ -44,9 +43,11 @@ import { useMemo } from 'react'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { ActionCell } from './action-cell'; | |||
| import { useHandleConnectToKnowledge, useRenameCurrentFile } from './hooks'; | |||
| import { KnowledgeCell } from './knowledge-cell'; | |||
| import { LinkToDatasetDialog } from './link-to-dataset-dialog'; | |||
| import { UseMoveDocumentShowType } from './use-move-file'; | |||
| import { useNavigateToOtherFolder } from './use-navigate-to-folder'; | |||
| import { isFolderType } from './util'; | |||
| type FilesTableProps = Pick< | |||
| ReturnType<typeof useFetchFileList>, | |||
| @@ -133,7 +134,7 @@ export function FilesTable({ | |||
| const name: string = row.getValue('name'); | |||
| const type = row.original.type; | |||
| const id = row.original.id; | |||
| const isFolder = type === 'folder'; | |||
| const isFolder = isFolderType(type); | |||
| const handleNameClick = () => { | |||
| if (isFolder) { | |||
| @@ -204,24 +205,8 @@ export function FilesTable({ | |||
| accessorKey: 'kbs_info', | |||
| header: t('knowledgeBase'), | |||
| cell: ({ row }) => { | |||
| const value = row.getValue('kbs_info'); | |||
| return Array.isArray(value) ? ( | |||
| <section className="flex gap-2 items-center"> | |||
| {value?.slice(0, 2).map((x) => ( | |||
| <Badge key={x.kb_id} className="" variant={'tertiary'}> | |||
| {x.kb_name} | |||
| </Badge> | |||
| ))} | |||
| {value.length > 2 && ( | |||
| <Button variant={'icon'} size={'auto'}> | |||
| +{value.length - 2} | |||
| </Button> | |||
| )} | |||
| </section> | |||
| ) : ( | |||
| '' | |||
| ); | |||
| const value: IFile['kbs_info'] = row.getValue('kbs_info'); | |||
| return <KnowledgeCell value={value}></KnowledgeCell>; | |||
| }, | |||
| }, | |||
| { | |||
| @@ -0,0 +1,41 @@ | |||
| import { Badge } from '@/components/ui/badge'; | |||
| import { Button } from '@/components/ui/button'; | |||
| import { | |||
| HoverCard, | |||
| HoverCardContent, | |||
| HoverCardTrigger, | |||
| } from '@/components/ui/hover-card'; | |||
| import { IFile } from '@/interfaces/database/file-manager'; | |||
| import { useCallback } from 'react'; | |||
| export function KnowledgeCell({ value }: { value: IFile['kbs_info'] }) { | |||
| const renderBadges = useCallback((list: IFile['kbs_info'] = []) => { | |||
| return list.map((x) => ( | |||
| <Badge key={x.kb_id} className="" variant={'tertiary'}> | |||
| {x.kb_name} | |||
| </Badge> | |||
| )); | |||
| }, []); | |||
| return Array.isArray(value) ? ( | |||
| <section className="flex gap-2 items-center"> | |||
| {renderBadges(value?.slice(0, 2))} | |||
| {value.length > 2 && ( | |||
| <HoverCard> | |||
| <HoverCardTrigger> | |||
| <Button variant={'icon'} size={'auto'}> | |||
| +{value.length - 2} | |||
| </Button> | |||
| </HoverCardTrigger> | |||
| <HoverCardContent className="flex gap-2 flex-wrap"> | |||
| {renderBadges(value)} | |||
| </HoverCardContent> | |||
| </HoverCard> | |||
| )} | |||
| </section> | |||
| ) : ( | |||
| '' | |||
| ); | |||
| } | |||
| @@ -0,0 +1,3 @@ | |||
| export function isFolderType(type: string) { | |||
| return type === 'folder'; | |||
| } | |||