diff --git a/web/package-lock.json b/web/package-lock.json index 65421945f..ed605f52f 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -30,6 +30,7 @@ "@tailwindcss/line-clamp": "^0.4.4", "@tanstack/react-query": "^5.40.0", "@tanstack/react-query-devtools": "^5.51.5", + "@tanstack/react-table": "^8.20.5", "@uiw/react-markdown-preview": "^5.1.3", "ahooks": "^3.7.10", "antd": "^5.12.7", @@ -5609,6 +5610,37 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tanstack/react-table": { + "version": "8.20.5", + "resolved": "https://registry.npmmirror.com/@tanstack/react-table/-/react-table-8.20.5.tgz", + "integrity": "sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==", + "dependencies": { + "@tanstack/table-core": "8.20.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.20.5", + "resolved": "https://registry.npmmirror.com/@tanstack/table-core/-/table-core-8.20.5.tgz", + "integrity": "sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@testing-library/dom": { "version": "10.1.0", "resolved": "https://registry.npmmirror.com/@testing-library/dom/-/dom-10.1.0.tgz", diff --git a/web/package.json b/web/package.json index 3a226d97f..74932c240 100644 --- a/web/package.json +++ b/web/package.json @@ -41,6 +41,7 @@ "@tailwindcss/line-clamp": "^0.4.4", "@tanstack/react-query": "^5.40.0", "@tanstack/react-query-devtools": "^5.51.5", + "@tanstack/react-table": "^8.20.5", "@uiw/react-markdown-preview": "^5.1.3", "ahooks": "^3.7.10", "antd": "^5.12.7", diff --git a/web/src/components/list-filter-bar.tsx b/web/src/components/list-filter-bar.tsx new file mode 100644 index 000000000..a6949098c --- /dev/null +++ b/web/src/components/list-filter-bar.tsx @@ -0,0 +1,25 @@ +import { Filter, Search } from 'lucide-react'; +import { PropsWithChildren } from 'react'; +import { Button } from './ui/button'; + +interface IProps { + title: string; +} + +export default function ListFilterBar({ + title, + children, +}: PropsWithChildren) { + return ( +
+ {title} +
+ + + +
+
+ ); +} diff --git a/web/src/interfaces/database/document.ts b/web/src/interfaces/database/document.ts index 7b1bce95e..81f3968de 100644 --- a/web/src/interfaces/database/document.ts +++ b/web/src/interfaces/database/document.ts @@ -11,7 +11,7 @@ export interface IDocumentInfo { name: string; parser_config: IParserConfig; parser_id: string; - process_begin_at: null; + process_begin_at?: string; process_duation: number; progress: number; progress_msg: string; @@ -27,11 +27,11 @@ export interface IDocumentInfo { } export interface IParserConfig { - delimiter: string; - html4excel: boolean; - layout_recognize: boolean; + delimiter?: string; + html4excel?: boolean; + layout_recognize?: boolean; pages: any[]; - raptor: Raptor; + raptor?: Raptor; } interface Raptor { diff --git a/web/src/pages/dataset/dataset/dataset-table.tsx b/web/src/pages/dataset/dataset/dataset-table.tsx new file mode 100644 index 000000000..bc9dd9501 --- /dev/null +++ b/web/src/pages/dataset/dataset/dataset-table.tsx @@ -0,0 +1,268 @@ +'use client'; + +import { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from '@tanstack/react-table'; +import { ArrowUpDown, MoreHorizontal } from 'lucide-react'; +import * as React from 'react'; + +import { Button } from '@/components/ui/button'; +import { Checkbox } from '@/components/ui/checkbox'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table'; +import { RunningStatus } from '@/constants/knowledge'; +import { IDocumentInfo } from '@/interfaces/database/document'; + +const data: IDocumentInfo[] = [ + { + chunk_num: 1, + create_date: 'Thu, 28 Nov 2024 17:10:22 GMT', + create_time: 1732785022792, + created_by: 'b0975cb4bc3111ee9b830aef05f5e94f', + id: '990cb30ead6811efb9b9fa163e197198', + kb_id: '25a8cfbe9cd411efbc12fa163e197198', + location: 'mian.jpg', + name: 'mian.jpg', + parser_config: { + pages: [[1, 1000000]], + }, + parser_id: 'picture', + process_begin_at: 'Thu, 28 Nov 2024 17:10:25 GMT', + process_duation: 8.46185, + progress: 1, + progress_msg: + '\nTask has been received.\nPage(1~100000001): Finish OCR: (用小麦粉\n金\nONGXI ...)\nPage(1~100000001): OCR results is too long to use CV LLM.\nPage(1~100000001): Finished slicing files (1 chunks in 0.34s). Start to embedding the content.\nPage(1~100000001): Finished embedding (in 0.35s)! Start to build index!\nPage(1~100000001): Indexing elapsed in 0.02s.\nPage(1~100000001): Done!', + run: RunningStatus.RUNNING, + size: 19692, + source_type: 'local', + status: '1', + thumbnail: + '/v1/document/image/25a8cfbe9cd411efbc12fa163e197198-thumbnail_990cb30ead6811efb9b9fa163e197198.png', + token_num: 115, + type: 'visual', + update_date: 'Thu, 28 Nov 2024 17:10:33 GMT', + update_time: 1732785033462, + }, +]; + +export const columns: ColumnDef[] = [ + { + id: 'select', + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!value)} + aria-label="Select row" + /> + ), + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: 'status', + header: 'Status', + cell: ({ row }) => ( +
{row.getValue('status')}
+ ), + }, + { + accessorKey: 'email', + header: ({ column }) => { + return ( + + ); + }, + cell: ({ row }) =>
{row.getValue('email')}
, + }, + { + accessorKey: 'amount', + header: () =>
Amount
, + cell: ({ row }) => { + const amount = parseFloat(row.getValue('amount')); + + // Format the amount as a dollar amount + const formatted = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD', + }).format(amount); + + return
{formatted}
; + }, + }, + { + id: 'actions', + enableHiding: false, + cell: ({ row }) => { + const payment = row.original; + + return ( + + + + + + Actions + navigator.clipboard.writeText(payment.id)} + > + Copy payment ID + + + View customer + View payment details + + + ); + }, + }, +]; + +export function DatasetTable() { + const [sorting, setSorting] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState( + [], + ); + const [columnVisibility, setColumnVisibility] = + React.useState({}); + const [rowSelection, setRowSelection] = React.useState({}); + + const table = useReactTable({ + data, + columns, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }); + + return ( +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext(), + )} + + ); + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext(), + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+
+ {table.getFilteredSelectedRowModel().rows.length} of{' '} + {table.getFilteredRowModel().rows.length} row(s) selected. +
+
+ + +
+
+
+ ); +} diff --git a/web/src/pages/dataset/dataset/index.tsx b/web/src/pages/dataset/dataset/index.tsx index 914ef81d3..d9d4e356b 100644 --- a/web/src/pages/dataset/dataset/index.tsx +++ b/web/src/pages/dataset/dataset/index.tsx @@ -1,3 +1,15 @@ +import ListFilterBar from '@/components/list-filter-bar'; +import { Upload } from 'lucide-react'; +import { DatasetTable } from './dataset-table'; + export default function Dataset() { - return
Outset
; + return ( +
+ + + Upload file + + +
+ ); } diff --git a/web/src/pages/dataset/index.tsx b/web/src/pages/dataset/index.tsx index bd4ab0cc9..7090b049b 100644 --- a/web/src/pages/dataset/index.tsx +++ b/web/src/pages/dataset/index.tsx @@ -5,7 +5,7 @@ export default function DatasetWrapper() { return (
-
+
diff --git a/web/src/pages/datasets/index.tsx b/web/src/pages/datasets/index.tsx index 558243aea..2e6d188f8 100644 --- a/web/src/pages/datasets/index.tsx +++ b/web/src/pages/datasets/index.tsx @@ -1,12 +1,7 @@ +import ListFilterBar from '@/components/list-filter-bar'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; -import { - ChevronRight, - Filter, - MoreHorizontal, - Plus, - Search, -} from 'lucide-react'; +import { ChevronRight, MoreHorizontal, Plus } from 'lucide-react'; const datasets = [ { @@ -86,17 +81,10 @@ const datasets = [ export default function Datasets() { return (
-
- Datasets -
- - - -
-
+ + + Create dataset +
{datasets.map((dataset) => (