mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-06-04 11:24:00 +08:00
Feat: Adjust the operation cell of the table on the file management page and dataset page #3221. (#7526)
### What problem does this PR solve? Feat: Adjust the operation cell of the table on the file management page and dataset page #3221. ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
9d3dd13fef
commit
1657755b5d
11
web/package-lock.json
generated
11
web/package-lock.json
generated
@ -64,7 +64,7 @@
|
|||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"lexical": "^0.23.1",
|
"lexical": "^0.23.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lucide-react": "^0.454.0",
|
"lucide-react": "^0.508.0",
|
||||||
"mammoth": "^1.7.2",
|
"mammoth": "^1.7.2",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"openai-speech-stream-player": "^1.0.8",
|
"openai-speech-stream-player": "^1.0.8",
|
||||||
@ -22959,11 +22959,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lucide-react": {
|
"node_modules/lucide-react": {
|
||||||
"version": "0.454.0",
|
"version": "0.508.0",
|
||||||
"resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-0.454.0.tgz",
|
"resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-0.508.0.tgz",
|
||||||
"integrity": "sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==",
|
"integrity": "sha512-gcP16PnexqtOFrTtv98kVsGzTfnbPekzZiQfByi2S89xfk7E/4uKE1USZqccIp58v42LqkO7MuwpCqshwSrJCg==",
|
||||||
|
"license": "ISC",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
|
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lz-string": {
|
"node_modules/lz-string": {
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"lexical": "^0.23.1",
|
"lexical": "^0.23.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lucide-react": "^0.454.0",
|
"lucide-react": "^0.508.0",
|
||||||
"mammoth": "^1.7.2",
|
"mammoth": "^1.7.2",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"openai-speech-stream-player": "^1.0.8",
|
"openai-speech-stream-player": "^1.0.8",
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,8 +1,10 @@
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { BrushCleaning } from 'lucide-react';
|
||||||
import { ReactNode, useCallback } from 'react';
|
import { ReactNode, useCallback } from 'react';
|
||||||
import { ConfirmDeleteDialog } from './confirm-delete-dialog';
|
import { ConfirmDeleteDialog } from './confirm-delete-dialog';
|
||||||
|
import { Separator } from './ui/separator';
|
||||||
|
|
||||||
export type BulkOperateItemType = {
|
export type BulkOperateItemType = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -11,16 +13,21 @@ export type BulkOperateItemType = {
|
|||||||
onClick(): void;
|
onClick(): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type BulkOperateBarProps = { list: BulkOperateItemType[] };
|
type BulkOperateBarProps = { list: BulkOperateItemType[]; count: number };
|
||||||
|
|
||||||
export function BulkOperateBar({ list }: BulkOperateBarProps) {
|
export function BulkOperateBar({ list, count }: BulkOperateBarProps) {
|
||||||
const isDeleteItem = useCallback((id: string) => {
|
const isDeleteItem = useCallback((id: string) => {
|
||||||
return id === 'delete';
|
return id === 'delete';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="mb-4">
|
<Card className="mb-4">
|
||||||
<CardContent className="p-1">
|
<CardContent className="p-1 pl-5 flex items-center gap-6">
|
||||||
|
<section className="text-text-sub-title-invert flex items-center gap-2">
|
||||||
|
<span>Selected: {count} Files</span>
|
||||||
|
<BrushCleaning className="size-3" />
|
||||||
|
</section>
|
||||||
|
<Separator orientation={'vertical'} className="h-3"></Separator>
|
||||||
<ul className="flex gap-2">
|
<ul className="flex gap-2">
|
||||||
{list.map((x) => (
|
{list.map((x) => (
|
||||||
<li
|
<li
|
||||||
|
@ -22,7 +22,7 @@ export function FileIcon({
|
|||||||
return (
|
return (
|
||||||
<span className={cn('size-4', className)}>
|
<span className={cn('size-4', className)}>
|
||||||
<IconFont
|
<IconFont
|
||||||
name={isFolder ? 'file' : FileIconMap[getExtension(name)]}
|
name={isFolder ? 'file-sub' : FileIconMap[getExtension(name)]}
|
||||||
></IconFont>
|
></IconFont>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
@ -11,6 +11,7 @@ interface IProps extends React.PropsWithChildren {
|
|||||||
documentName: string;
|
documentName: string;
|
||||||
documentId?: string;
|
documentId?: string;
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NewDocumentLink = ({
|
const NewDocumentLink = ({
|
||||||
@ -21,6 +22,7 @@ const NewDocumentLink = ({
|
|||||||
documentId,
|
documentId,
|
||||||
documentName,
|
documentName,
|
||||||
prefix = 'file',
|
prefix = 'file',
|
||||||
|
className,
|
||||||
}: IProps) => {
|
}: IProps) => {
|
||||||
let nextLink = link;
|
let nextLink = link;
|
||||||
const extension = getExtension(documentName);
|
const extension = getExtension(documentName);
|
||||||
@ -38,7 +40,8 @@ const NewDocumentLink = ({
|
|||||||
}
|
}
|
||||||
href={nextLink}
|
href={nextLink}
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
style={{ color, wordBreak: 'break-all' }}
|
style={{ color: className ? '' : color, wordBreak: 'break-all' }}
|
||||||
|
className={className}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
|
@ -11,7 +11,7 @@ const badgeVariants = cva(
|
|||||||
default:
|
default:
|
||||||
'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
|
'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
|
||||||
secondary:
|
secondary:
|
||||||
'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
'border-transparent bg-background-card text-text-sub-title-invert hover:bg-secondary/80 rounded-md',
|
||||||
destructive:
|
destructive:
|
||||||
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
|
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
|
||||||
outline: 'text-foreground',
|
outline: 'text-foreground',
|
||||||
|
@ -4,9 +4,14 @@ import { cn } from '@/lib/utils';
|
|||||||
|
|
||||||
const Table = React.forwardRef<
|
const Table = React.forwardRef<
|
||||||
HTMLTableElement,
|
HTMLTableElement,
|
||||||
React.HTMLAttributes<HTMLTableElement>
|
React.HTMLAttributes<HTMLTableElement> & { rootClassName?: string }
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, rootClassName, ...props }, ref) => (
|
||||||
<div className="relative w-full overflow-auto rounded-2xl bg-background-card">
|
<div
|
||||||
|
className={cn(
|
||||||
|
'relative w-full overflow-auto rounded-2xl bg-background-card',
|
||||||
|
rootClassName,
|
||||||
|
)}
|
||||||
|
>
|
||||||
<table
|
<table
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn('w-full caption-bottom text-sm ', className)}
|
className={cn('w-full caption-bottom text-sm ', className)}
|
||||||
@ -20,7 +25,11 @@ const TableHeader = React.forwardRef<
|
|||||||
HTMLTableSectionElement,
|
HTMLTableSectionElement,
|
||||||
React.HTMLAttributes<HTMLTableSectionElement>
|
React.HTMLAttributes<HTMLTableSectionElement>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
|
<thead
|
||||||
|
ref={ref}
|
||||||
|
className={cn('[&_tr]:border-b top-0 sticky', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
));
|
));
|
||||||
TableHeader.displayName = 'TableHeader';
|
TableHeader.displayName = 'TableHeader';
|
||||||
|
|
||||||
|
@ -9,11 +9,16 @@ export function useRowSelection() {
|
|||||||
setRowSelection({});
|
setRowSelection({});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const selectedCount = useMemo(() => {
|
||||||
|
return Object.keys(rowSelection).length;
|
||||||
|
}, [rowSelection]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
rowSelection,
|
rowSelection,
|
||||||
setRowSelection,
|
setRowSelection,
|
||||||
rowSelectionIsEmpty: isEmpty(rowSelection),
|
rowSelectionIsEmpty: isEmpty(rowSelection),
|
||||||
clearRowSelection,
|
clearRowSelection,
|
||||||
|
selectedCount,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ export const useFetchDocumentList = () => {
|
|||||||
filterValue,
|
filterValue,
|
||||||
],
|
],
|
||||||
initialData: { docs: [], total: 0 },
|
initialData: { docs: [], total: 0 },
|
||||||
refetchInterval: 15000,
|
// refetchInterval: 15000,
|
||||||
enabled: !!knowledgeId || !!id,
|
enabled: !!knowledgeId || !!id,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const ret = await listDocument(
|
const ret = await listDocument(
|
||||||
|
@ -11,7 +11,7 @@ import { IDocumentInfo } from '@/interfaces/database/document';
|
|||||||
import { formatFileSize } from '@/utils/common-util';
|
import { formatFileSize } from '@/utils/common-util';
|
||||||
import { formatDate } from '@/utils/date';
|
import { formatDate } from '@/utils/date';
|
||||||
import { downloadDocument } from '@/utils/file-util';
|
import { downloadDocument } from '@/utils/file-util';
|
||||||
import { ArrowDownToLine, Pencil, ScrollText, Trash2 } from 'lucide-react';
|
import { ArrowDownToLine, FolderPen, ScrollText, Trash2 } from 'lucide-react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { UseRenameDocumentShowType } from './use-rename-document';
|
import { UseRenameDocumentShowType } from './use-rename-document';
|
||||||
import { isParserRunning } from './utils';
|
import { isParserRunning } from './utils';
|
||||||
@ -50,10 +50,18 @@ export function DatasetActionCell({
|
|||||||
}, [record, showRenameModal]);
|
}, [record, showRenameModal]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="flex gap-4 items-center">
|
<section className="flex gap-4 items-center text-text-sub-title-invert">
|
||||||
|
<Button
|
||||||
|
variant={'ghost'}
|
||||||
|
size={'sm'}
|
||||||
|
disabled={isRunning}
|
||||||
|
onClick={handleRename}
|
||||||
|
>
|
||||||
|
<FolderPen />
|
||||||
|
</Button>
|
||||||
<HoverCard>
|
<HoverCard>
|
||||||
<HoverCardTrigger>
|
<HoverCardTrigger>
|
||||||
<Button variant="ghost" size={'icon'} disabled={isRunning}>
|
<Button variant="ghost" disabled={isRunning} size={'sm'}>
|
||||||
<ScrollText />
|
<ScrollText />
|
||||||
</Button>
|
</Button>
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
@ -77,27 +85,20 @@ export function DatasetActionCell({
|
|||||||
</ul>
|
</ul>
|
||||||
</HoverCardContent>
|
</HoverCardContent>
|
||||||
</HoverCard>
|
</HoverCard>
|
||||||
<Button
|
|
||||||
variant={'ghost'}
|
|
||||||
size={'icon'}
|
|
||||||
disabled={isRunning}
|
|
||||||
onClick={handleRename}
|
|
||||||
>
|
|
||||||
<Pencil />
|
|
||||||
</Button>
|
|
||||||
{isVirtualDocument || (
|
{isVirtualDocument || (
|
||||||
<Button
|
<Button
|
||||||
variant={'ghost'}
|
variant={'ghost'}
|
||||||
size={'icon'}
|
|
||||||
onClick={onDownloadDocument}
|
onClick={onDownloadDocument}
|
||||||
disabled={isRunning}
|
disabled={isRunning}
|
||||||
|
size={'sm'}
|
||||||
>
|
>
|
||||||
<ArrowDownToLine />
|
<ArrowDownToLine />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<ConfirmDeleteDialog onOk={handleRemove}>
|
<ConfirmDeleteDialog onOk={handleRemove}>
|
||||||
<Button variant={'ghost'} size={'icon'} disabled={isRunning}>
|
<Button variant={'ghost'} size={'sm'} disabled={isRunning}>
|
||||||
<Trash2 className="text-text-delete-red" />
|
<Trash2 />
|
||||||
</Button>
|
</Button>
|
||||||
</ConfirmDeleteDialog>
|
</ConfirmDeleteDialog>
|
||||||
</section>
|
</section>
|
||||||
|
@ -119,7 +119,7 @@ export function DatasetTable({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Table>
|
<Table rootClassName="max-h-[82vh]">
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
<TableRow key={headerGroup.id}>
|
<TableRow key={headerGroup.id}>
|
||||||
@ -164,11 +164,7 @@ export function DatasetTable({
|
|||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
<div className="flex items-center justify-end space-x-2 py-4">
|
<div className="flex items-center justify-end py-4">
|
||||||
<div className="flex-1 text-sm text-muted-foreground">
|
|
||||||
{table.getFilteredSelectedRowModel().rows.length} of{' '}
|
|
||||||
{pagination?.total} row(s) selected.
|
|
||||||
</div>
|
|
||||||
<div className="space-x-2">
|
<div className="space-x-2">
|
||||||
<RAGFlowPagination
|
<RAGFlowPagination
|
||||||
{...pick(pagination, 'current', 'pageSize')}
|
{...pick(pagination, 'current', 'pageSize')}
|
||||||
|
@ -50,7 +50,7 @@ export default function Dataset() {
|
|||||||
showCreateModal,
|
showCreateModal,
|
||||||
} = useCreateEmptyDocument();
|
} = useCreateEmptyDocument();
|
||||||
|
|
||||||
const { rowSelection, rowSelectionIsEmpty, setRowSelection } =
|
const { rowSelection, rowSelectionIsEmpty, setRowSelection, selectedCount } =
|
||||||
useRowSelection();
|
useRowSelection();
|
||||||
|
|
||||||
const { list } = useBulkOperateDataset({
|
const { list } = useBulkOperateDataset({
|
||||||
@ -68,6 +68,15 @@ export default function Dataset() {
|
|||||||
value={filterValue}
|
value={filterValue}
|
||||||
onChange={handleFilterSubmit}
|
onChange={handleFilterSubmit}
|
||||||
filters={filters}
|
filters={filters}
|
||||||
|
leftPanel={
|
||||||
|
<div className="items-start">
|
||||||
|
<div className="pb-1">Dataset</div>
|
||||||
|
<div className="text-text-sub-title-invert text-sm">
|
||||||
|
Please wait for your files to finish parsing before starting an
|
||||||
|
AI-powered chat.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
@ -87,7 +96,9 @@ export default function Dataset() {
|
|||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</ListFilterBar>
|
</ListFilterBar>
|
||||||
{rowSelectionIsEmpty || <BulkOperateBar list={list}></BulkOperateBar>}
|
{rowSelectionIsEmpty || (
|
||||||
|
<BulkOperateBar list={list} count={selectedCount}></BulkOperateBar>
|
||||||
|
)}
|
||||||
<DatasetTable
|
<DatasetTable
|
||||||
documents={documents}
|
documents={documents}
|
||||||
pagination={pagination}
|
pagination={pagination}
|
||||||
|
@ -56,10 +56,10 @@ export function ParsingStatusCell({
|
|||||||
}, [record, showSetMetaModal]);
|
}, [record, showSetMetaModal]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="flex gap-2 items-center ">
|
<section className="flex gap-2 items-center">
|
||||||
<div>
|
<div className="w-28 flex items-center justify-between">
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button variant={'ghost'} size={'sm'}>
|
<Button variant={'ghost'} size={'sm'}>
|
||||||
{parser_id}
|
{parser_id}
|
||||||
</Button>
|
</Button>
|
||||||
@ -73,8 +73,7 @@ export function ParsingStatusCell({
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
<Separator orientation="vertical" className="h-2.5" />
|
||||||
<Separator orientation="vertical" />
|
|
||||||
</div>
|
</div>
|
||||||
<ConfirmDeleteDialog
|
<ConfirmDeleteDialog
|
||||||
title={t(`knowledgeDetails.redo`, { chunkNum: chunk_num })}
|
title={t(`knowledgeDetails.redo`, { chunkNum: chunk_num })}
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||||
import NewDocumentLink from '@/components/new-document-link';
|
import NewDocumentLink from '@/components/new-document-link';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
|
||||||
DropdownMenu,
|
|
||||||
DropdownMenuContent,
|
|
||||||
DropdownMenuItem,
|
|
||||||
DropdownMenuSeparator,
|
|
||||||
DropdownMenuTrigger,
|
|
||||||
} from '@/components/ui/dropdown-menu';
|
|
||||||
import { useDownloadFile } from '@/hooks/file-manager-hooks';
|
import { useDownloadFile } from '@/hooks/file-manager-hooks';
|
||||||
import { IFile } from '@/interfaces/database/file-manager';
|
import { IFile } from '@/interfaces/database/file-manager';
|
||||||
import {
|
import {
|
||||||
@ -15,9 +8,15 @@ import {
|
|||||||
isSupportedPreviewDocumentType,
|
isSupportedPreviewDocumentType,
|
||||||
} from '@/utils/document-util';
|
} from '@/utils/document-util';
|
||||||
import { CellContext } from '@tanstack/react-table';
|
import { CellContext } from '@tanstack/react-table';
|
||||||
import { EllipsisVertical, Eye, Link2, Trash2 } from 'lucide-react';
|
import {
|
||||||
|
ArrowDownToLine,
|
||||||
|
Eye,
|
||||||
|
FolderInput,
|
||||||
|
FolderPen,
|
||||||
|
Link2,
|
||||||
|
Trash2,
|
||||||
|
} from 'lucide-react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import {
|
import {
|
||||||
UseHandleConnectToKnowledgeReturnType,
|
UseHandleConnectToKnowledgeReturnType,
|
||||||
UseRenameCurrentFileReturnType,
|
UseRenameCurrentFileReturnType,
|
||||||
@ -36,7 +35,6 @@ export function ActionCell({
|
|||||||
showFileRenameModal,
|
showFileRenameModal,
|
||||||
showMoveFileModal,
|
showMoveFileModal,
|
||||||
}: IProps) {
|
}: IProps) {
|
||||||
const { t } = useTranslation();
|
|
||||||
const record = row.original;
|
const record = row.original;
|
||||||
const documentId = record.id;
|
const documentId = record.id;
|
||||||
const { downloadFile } = useDownloadFile();
|
const { downloadFile } = useDownloadFile();
|
||||||
@ -63,33 +61,43 @@ export function ActionCell({
|
|||||||
}, [record, showMoveFileModal]);
|
}, [record, showMoveFileModal]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="flex gap-4 items-center">
|
<section className="flex gap-4 items-center text-text-sub-title-invert">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size={'icon'}
|
size={'sm'}
|
||||||
onClick={handleShowConnectToKnowledgeModal}
|
onClick={handleShowConnectToKnowledgeModal}
|
||||||
>
|
>
|
||||||
<Link2 />
|
<Link2 />
|
||||||
</Button>
|
</Button>
|
||||||
<ConfirmDeleteDialog>
|
<Button variant="ghost" size={'sm'} onClick={handleShowMoveFileModal}>
|
||||||
<Button variant="ghost" size={'icon'}>
|
<FolderInput />
|
||||||
<Trash2 className="text-text-delete-red" />
|
</Button>
|
||||||
|
|
||||||
|
<Button variant="ghost" size={'sm'} onClick={handleShowFileRenameModal}>
|
||||||
|
<FolderPen />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{isFolder || (
|
||||||
|
<Button variant={'ghost'} size={'sm'} onClick={onDownloadDocument}>
|
||||||
|
<ArrowDownToLine />
|
||||||
</Button>
|
</Button>
|
||||||
</ConfirmDeleteDialog>
|
)}
|
||||||
|
|
||||||
{isSupportedPreviewDocumentType(extension) && (
|
{isSupportedPreviewDocumentType(extension) && (
|
||||||
<NewDocumentLink
|
<NewDocumentLink
|
||||||
documentId={documentId}
|
documentId={documentId}
|
||||||
documentName={record.name}
|
documentName={record.name}
|
||||||
color="black"
|
className="text-text-sub-title-invert"
|
||||||
>
|
>
|
||||||
<Button variant={'ghost'} size={'icon'}>
|
<Button variant={'ghost'} size={'sm'}>
|
||||||
<Eye />
|
<Eye />
|
||||||
</Button>
|
</Button>
|
||||||
</NewDocumentLink>
|
</NewDocumentLink>
|
||||||
)}
|
)}
|
||||||
<DropdownMenu>
|
|
||||||
|
{/* <DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button variant="ghost" size={'icon'}>
|
<Button variant="ghost" size={'sm'}>
|
||||||
<EllipsisVertical />
|
<EllipsisVertical />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
@ -108,7 +116,12 @@ export function ActionCell({
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu> */}
|
||||||
|
<ConfirmDeleteDialog>
|
||||||
|
<Button variant="ghost" size={'sm'}>
|
||||||
|
<Trash2 />
|
||||||
|
</Button>
|
||||||
|
</ConfirmDeleteDialog>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -304,12 +304,7 @@ export function FilesTable({
|
|||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
<div className="flex items-center justify-end space-x-2 py-4">
|
<div className="flex items-center justify-end py-4">
|
||||||
<div className="flex-1 text-sm text-muted-foreground">
|
|
||||||
{table.getFilteredSelectedRowModel().rows.length} of {total} row(s)
|
|
||||||
selected.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-x-2">
|
<div className="space-x-2">
|
||||||
<RAGFlowPagination
|
<RAGFlowPagination
|
||||||
{...pick(pagination, 'current', 'pageSize')}
|
{...pick(pagination, 'current', 'pageSize')}
|
||||||
|
@ -20,6 +20,7 @@ import { MoveDialog } from './move-dialog';
|
|||||||
import { useBulkOperateFile } from './use-bulk-operate-file';
|
import { useBulkOperateFile } from './use-bulk-operate-file';
|
||||||
import { useHandleCreateFolder } from './use-create-folder';
|
import { useHandleCreateFolder } from './use-create-folder';
|
||||||
import { useHandleMoveFile } from './use-move-file';
|
import { useHandleMoveFile } from './use-move-file';
|
||||||
|
import { useSelectBreadcrumbItems } from './use-navigate-to-folder';
|
||||||
import { useHandleUploadFile } from './use-upload-file';
|
import { useHandleUploadFile } from './use-upload-file';
|
||||||
|
|
||||||
export default function Files() {
|
export default function Files() {
|
||||||
@ -55,6 +56,7 @@ export default function Files() {
|
|||||||
setRowSelection,
|
setRowSelection,
|
||||||
rowSelectionIsEmpty,
|
rowSelectionIsEmpty,
|
||||||
clearRowSelection,
|
clearRowSelection,
|
||||||
|
selectedCount,
|
||||||
} = useRowSelection();
|
} = useRowSelection();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -72,9 +74,11 @@ export default function Files() {
|
|||||||
setRowSelection,
|
setRowSelection,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const breadcrumbItems = useSelectBreadcrumbItems();
|
||||||
|
|
||||||
const leftPanel = (
|
const leftPanel = (
|
||||||
<div>
|
<div>
|
||||||
<FileBreadcrumb></FileBreadcrumb>
|
{breadcrumbItems.length > 0 ? <FileBreadcrumb></FileBreadcrumb> : 'File'}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -85,6 +89,7 @@ export default function Files() {
|
|||||||
searchString={searchString}
|
searchString={searchString}
|
||||||
onSearchChange={handleInputChange}
|
onSearchChange={handleInputChange}
|
||||||
showFilter={false}
|
showFilter={false}
|
||||||
|
icon={'file'}
|
||||||
>
|
>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
@ -104,7 +109,9 @@ export default function Files() {
|
|||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</ListFilterBar>
|
</ListFilterBar>
|
||||||
{!rowSelectionIsEmpty && <BulkOperateBar list={list}></BulkOperateBar>}
|
{!rowSelectionIsEmpty && (
|
||||||
|
<BulkOperateBar list={list} count={selectedCount}></BulkOperateBar>
|
||||||
|
)}
|
||||||
<FilesTable
|
<FilesTable
|
||||||
files={files}
|
files={files}
|
||||||
total={total}
|
total={total}
|
||||||
|
@ -7,12 +7,13 @@ import {
|
|||||||
HoverCardTrigger,
|
HoverCardTrigger,
|
||||||
} from '@/components/ui/hover-card';
|
} from '@/components/ui/hover-card';
|
||||||
import { IFile } from '@/interfaces/database/file-manager';
|
import { IFile } from '@/interfaces/database/file-manager';
|
||||||
|
import { Ellipsis } from 'lucide-react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
export function KnowledgeCell({ value }: { value: IFile['kbs_info'] }) {
|
export function KnowledgeCell({ value }: { value: IFile['kbs_info'] }) {
|
||||||
const renderBadges = useCallback((list: IFile['kbs_info'] = []) => {
|
const renderBadges = useCallback((list: IFile['kbs_info'] = []) => {
|
||||||
return list.map((x) => (
|
return list.map((x) => (
|
||||||
<Badge key={x.kb_id} className="" variant={'tertiary'}>
|
<Badge key={x.kb_id} variant={'secondary'}>
|
||||||
{x.kb_name}
|
{x.kb_name}
|
||||||
</Badge>
|
</Badge>
|
||||||
));
|
));
|
||||||
@ -25,8 +26,8 @@ export function KnowledgeCell({ value }: { value: IFile['kbs_info'] }) {
|
|||||||
{value.length > 2 && (
|
{value.length > 2 && (
|
||||||
<HoverCard>
|
<HoverCard>
|
||||||
<HoverCardTrigger>
|
<HoverCardTrigger>
|
||||||
<Button variant={'icon'} size={'auto'}>
|
<Button variant={'ghost'} size={'sm'}>
|
||||||
+{value.length - 2}
|
<Ellipsis />
|
||||||
</Button>
|
</Button>
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
<HoverCardContent className="flex gap-2 flex-wrap">
|
<HoverCardContent className="flex gap-2 flex-wrap">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user