balibabu commited on
Commit
17b1039
·
1 Parent(s): 9753e7a

Feat: Add Dataset page #3221 (#3721)

Browse files

### What problem does this PR solve?

Feat: Add Dataset page #3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)

web/package-lock.json CHANGED
@@ -30,6 +30,7 @@
30
  "@tailwindcss/line-clamp": "^0.4.4",
31
  "@tanstack/react-query": "^5.40.0",
32
  "@tanstack/react-query-devtools": "^5.51.5",
 
33
  "@uiw/react-markdown-preview": "^5.1.3",
34
  "ahooks": "^3.7.10",
35
  "antd": "^5.12.7",
@@ -5609,6 +5610,37 @@
5609
  "url": "https://github.com/sponsors/tannerlinsley"
5610
  }
5611
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5612
  "node_modules/@testing-library/dom": {
5613
  "version": "10.1.0",
5614
  "resolved": "https://registry.npmmirror.com/@testing-library/dom/-/dom-10.1.0.tgz",
 
30
  "@tailwindcss/line-clamp": "^0.4.4",
31
  "@tanstack/react-query": "^5.40.0",
32
  "@tanstack/react-query-devtools": "^5.51.5",
33
+ "@tanstack/react-table": "^8.20.5",
34
  "@uiw/react-markdown-preview": "^5.1.3",
35
  "ahooks": "^3.7.10",
36
  "antd": "^5.12.7",
 
5610
  "url": "https://github.com/sponsors/tannerlinsley"
5611
  }
5612
  },
5613
+ "node_modules/@tanstack/react-table": {
5614
+ "version": "8.20.5",
5615
+ "resolved": "https://registry.npmmirror.com/@tanstack/react-table/-/react-table-8.20.5.tgz",
5616
+ "integrity": "sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==",
5617
+ "dependencies": {
5618
+ "@tanstack/table-core": "8.20.5"
5619
+ },
5620
+ "engines": {
5621
+ "node": ">=12"
5622
+ },
5623
+ "funding": {
5624
+ "type": "github",
5625
+ "url": "https://github.com/sponsors/tannerlinsley"
5626
+ },
5627
+ "peerDependencies": {
5628
+ "react": ">=16.8",
5629
+ "react-dom": ">=16.8"
5630
+ }
5631
+ },
5632
+ "node_modules/@tanstack/table-core": {
5633
+ "version": "8.20.5",
5634
+ "resolved": "https://registry.npmmirror.com/@tanstack/table-core/-/table-core-8.20.5.tgz",
5635
+ "integrity": "sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==",
5636
+ "engines": {
5637
+ "node": ">=12"
5638
+ },
5639
+ "funding": {
5640
+ "type": "github",
5641
+ "url": "https://github.com/sponsors/tannerlinsley"
5642
+ }
5643
+ },
5644
  "node_modules/@testing-library/dom": {
5645
  "version": "10.1.0",
5646
  "resolved": "https://registry.npmmirror.com/@testing-library/dom/-/dom-10.1.0.tgz",
web/package.json CHANGED
@@ -41,6 +41,7 @@
41
  "@tailwindcss/line-clamp": "^0.4.4",
42
  "@tanstack/react-query": "^5.40.0",
43
  "@tanstack/react-query-devtools": "^5.51.5",
 
44
  "@uiw/react-markdown-preview": "^5.1.3",
45
  "ahooks": "^3.7.10",
46
  "antd": "^5.12.7",
 
41
  "@tailwindcss/line-clamp": "^0.4.4",
42
  "@tanstack/react-query": "^5.40.0",
43
  "@tanstack/react-query-devtools": "^5.51.5",
44
+ "@tanstack/react-table": "^8.20.5",
45
  "@uiw/react-markdown-preview": "^5.1.3",
46
  "ahooks": "^3.7.10",
47
  "antd": "^5.12.7",
web/src/components/list-filter-bar.tsx ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Filter, Search } from 'lucide-react';
2
+ import { PropsWithChildren } from 'react';
3
+ import { Button } from './ui/button';
4
+
5
+ interface IProps {
6
+ title: string;
7
+ }
8
+
9
+ export default function ListFilterBar({
10
+ title,
11
+ children,
12
+ }: PropsWithChildren<IProps>) {
13
+ return (
14
+ <div className="flex justify-between mb-6">
15
+ <span className="text-3xl font-bold ">{title}</span>
16
+ <div className="flex gap-4 items-center">
17
+ <Filter className="size-5" />
18
+ <Search className="size-5" />
19
+ <Button variant={'tertiary'} size={'sm'}>
20
+ {children}
21
+ </Button>
22
+ </div>
23
+ </div>
24
+ );
25
+ }
web/src/interfaces/database/document.ts CHANGED
@@ -11,7 +11,7 @@ export interface IDocumentInfo {
11
  name: string;
12
  parser_config: IParserConfig;
13
  parser_id: string;
14
- process_begin_at: null;
15
  process_duation: number;
16
  progress: number;
17
  progress_msg: string;
@@ -27,11 +27,11 @@ export interface IDocumentInfo {
27
  }
28
 
29
  export interface IParserConfig {
30
- delimiter: string;
31
- html4excel: boolean;
32
- layout_recognize: boolean;
33
  pages: any[];
34
- raptor: Raptor;
35
  }
36
 
37
  interface Raptor {
 
11
  name: string;
12
  parser_config: IParserConfig;
13
  parser_id: string;
14
+ process_begin_at?: string;
15
  process_duation: number;
16
  progress: number;
17
  progress_msg: string;
 
27
  }
28
 
29
  export interface IParserConfig {
30
+ delimiter?: string;
31
+ html4excel?: boolean;
32
+ layout_recognize?: boolean;
33
  pages: any[];
34
+ raptor?: Raptor;
35
  }
36
 
37
  interface Raptor {
web/src/pages/dataset/dataset/dataset-table.tsx ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import {
4
+ ColumnDef,
5
+ ColumnFiltersState,
6
+ SortingState,
7
+ VisibilityState,
8
+ flexRender,
9
+ getCoreRowModel,
10
+ getFilteredRowModel,
11
+ getPaginationRowModel,
12
+ getSortedRowModel,
13
+ useReactTable,
14
+ } from '@tanstack/react-table';
15
+ import { ArrowUpDown, MoreHorizontal } from 'lucide-react';
16
+ import * as React from 'react';
17
+
18
+ import { Button } from '@/components/ui/button';
19
+ import { Checkbox } from '@/components/ui/checkbox';
20
+ import {
21
+ DropdownMenu,
22
+ DropdownMenuContent,
23
+ DropdownMenuItem,
24
+ DropdownMenuLabel,
25
+ DropdownMenuSeparator,
26
+ DropdownMenuTrigger,
27
+ } from '@/components/ui/dropdown-menu';
28
+ import {
29
+ Table,
30
+ TableBody,
31
+ TableCell,
32
+ TableHead,
33
+ TableHeader,
34
+ TableRow,
35
+ } from '@/components/ui/table';
36
+ import { RunningStatus } from '@/constants/knowledge';
37
+ import { IDocumentInfo } from '@/interfaces/database/document';
38
+
39
+ const data: IDocumentInfo[] = [
40
+ {
41
+ chunk_num: 1,
42
+ create_date: 'Thu, 28 Nov 2024 17:10:22 GMT',
43
+ create_time: 1732785022792,
44
+ created_by: 'b0975cb4bc3111ee9b830aef05f5e94f',
45
+ id: '990cb30ead6811efb9b9fa163e197198',
46
+ kb_id: '25a8cfbe9cd411efbc12fa163e197198',
47
+ location: 'mian.jpg',
48
+ name: 'mian.jpg',
49
+ parser_config: {
50
+ pages: [[1, 1000000]],
51
+ },
52
+ parser_id: 'picture',
53
+ process_begin_at: 'Thu, 28 Nov 2024 17:10:25 GMT',
54
+ process_duation: 8.46185,
55
+ progress: 1,
56
+ progress_msg:
57
+ '\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!',
58
+ run: RunningStatus.RUNNING,
59
+ size: 19692,
60
+ source_type: 'local',
61
+ status: '1',
62
+ thumbnail:
63
+ '/v1/document/image/25a8cfbe9cd411efbc12fa163e197198-thumbnail_990cb30ead6811efb9b9fa163e197198.png',
64
+ token_num: 115,
65
+ type: 'visual',
66
+ update_date: 'Thu, 28 Nov 2024 17:10:33 GMT',
67
+ update_time: 1732785033462,
68
+ },
69
+ ];
70
+
71
+ export const columns: ColumnDef<IDocumentInfo>[] = [
72
+ {
73
+ id: 'select',
74
+ header: ({ table }) => (
75
+ <Checkbox
76
+ checked={
77
+ table.getIsAllPageRowsSelected() ||
78
+ (table.getIsSomePageRowsSelected() && 'indeterminate')
79
+ }
80
+ onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
81
+ aria-label="Select all"
82
+ />
83
+ ),
84
+ cell: ({ row }) => (
85
+ <Checkbox
86
+ checked={row.getIsSelected()}
87
+ onCheckedChange={(value) => row.toggleSelected(!!value)}
88
+ aria-label="Select row"
89
+ />
90
+ ),
91
+ enableSorting: false,
92
+ enableHiding: false,
93
+ },
94
+ {
95
+ accessorKey: 'status',
96
+ header: 'Status',
97
+ cell: ({ row }) => (
98
+ <div className="capitalize">{row.getValue('status')}</div>
99
+ ),
100
+ },
101
+ {
102
+ accessorKey: 'email',
103
+ header: ({ column }) => {
104
+ return (
105
+ <Button
106
+ variant="ghost"
107
+ onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
108
+ >
109
+ Email
110
+ <ArrowUpDown />
111
+ </Button>
112
+ );
113
+ },
114
+ cell: ({ row }) => <div className="lowercase">{row.getValue('email')}</div>,
115
+ },
116
+ {
117
+ accessorKey: 'amount',
118
+ header: () => <div className="text-right">Amount</div>,
119
+ cell: ({ row }) => {
120
+ const amount = parseFloat(row.getValue('amount'));
121
+
122
+ // Format the amount as a dollar amount
123
+ const formatted = new Intl.NumberFormat('en-US', {
124
+ style: 'currency',
125
+ currency: 'USD',
126
+ }).format(amount);
127
+
128
+ return <div className="text-right font-medium">{formatted}</div>;
129
+ },
130
+ },
131
+ {
132
+ id: 'actions',
133
+ enableHiding: false,
134
+ cell: ({ row }) => {
135
+ const payment = row.original;
136
+
137
+ return (
138
+ <DropdownMenu>
139
+ <DropdownMenuTrigger asChild>
140
+ <Button variant="ghost" className="h-8 w-8 p-0">
141
+ <span className="sr-only">Open menu</span>
142
+ <MoreHorizontal />
143
+ </Button>
144
+ </DropdownMenuTrigger>
145
+ <DropdownMenuContent align="end">
146
+ <DropdownMenuLabel>Actions</DropdownMenuLabel>
147
+ <DropdownMenuItem
148
+ onClick={() => navigator.clipboard.writeText(payment.id)}
149
+ >
150
+ Copy payment ID
151
+ </DropdownMenuItem>
152
+ <DropdownMenuSeparator />
153
+ <DropdownMenuItem>View customer</DropdownMenuItem>
154
+ <DropdownMenuItem>View payment details</DropdownMenuItem>
155
+ </DropdownMenuContent>
156
+ </DropdownMenu>
157
+ );
158
+ },
159
+ },
160
+ ];
161
+
162
+ export function DatasetTable() {
163
+ const [sorting, setSorting] = React.useState<SortingState>([]);
164
+ const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
165
+ [],
166
+ );
167
+ const [columnVisibility, setColumnVisibility] =
168
+ React.useState<VisibilityState>({});
169
+ const [rowSelection, setRowSelection] = React.useState({});
170
+
171
+ const table = useReactTable({
172
+ data,
173
+ columns,
174
+ onSortingChange: setSorting,
175
+ onColumnFiltersChange: setColumnFilters,
176
+ getCoreRowModel: getCoreRowModel(),
177
+ getPaginationRowModel: getPaginationRowModel(),
178
+ getSortedRowModel: getSortedRowModel(),
179
+ getFilteredRowModel: getFilteredRowModel(),
180
+ onColumnVisibilityChange: setColumnVisibility,
181
+ onRowSelectionChange: setRowSelection,
182
+ state: {
183
+ sorting,
184
+ columnFilters,
185
+ columnVisibility,
186
+ rowSelection,
187
+ },
188
+ });
189
+
190
+ return (
191
+ <div className="w-full">
192
+ <div className="rounded-md border">
193
+ <Table>
194
+ <TableHeader>
195
+ {table.getHeaderGroups().map((headerGroup) => (
196
+ <TableRow key={headerGroup.id}>
197
+ {headerGroup.headers.map((header) => {
198
+ return (
199
+ <TableHead key={header.id}>
200
+ {header.isPlaceholder
201
+ ? null
202
+ : flexRender(
203
+ header.column.columnDef.header,
204
+ header.getContext(),
205
+ )}
206
+ </TableHead>
207
+ );
208
+ })}
209
+ </TableRow>
210
+ ))}
211
+ </TableHeader>
212
+ <TableBody>
213
+ {table.getRowModel().rows?.length ? (
214
+ table.getRowModel().rows.map((row) => (
215
+ <TableRow
216
+ key={row.id}
217
+ data-state={row.getIsSelected() && 'selected'}
218
+ >
219
+ {row.getVisibleCells().map((cell) => (
220
+ <TableCell key={cell.id}>
221
+ {flexRender(
222
+ cell.column.columnDef.cell,
223
+ cell.getContext(),
224
+ )}
225
+ </TableCell>
226
+ ))}
227
+ </TableRow>
228
+ ))
229
+ ) : (
230
+ <TableRow>
231
+ <TableCell
232
+ colSpan={columns.length}
233
+ className="h-24 text-center"
234
+ >
235
+ No results.
236
+ </TableCell>
237
+ </TableRow>
238
+ )}
239
+ </TableBody>
240
+ </Table>
241
+ </div>
242
+ <div className="flex items-center justify-end space-x-2 py-4">
243
+ <div className="flex-1 text-sm text-muted-foreground">
244
+ {table.getFilteredSelectedRowModel().rows.length} of{' '}
245
+ {table.getFilteredRowModel().rows.length} row(s) selected.
246
+ </div>
247
+ <div className="space-x-2">
248
+ <Button
249
+ variant="outline"
250
+ size="sm"
251
+ onClick={() => table.previousPage()}
252
+ disabled={!table.getCanPreviousPage()}
253
+ >
254
+ Previous
255
+ </Button>
256
+ <Button
257
+ variant="outline"
258
+ size="sm"
259
+ onClick={() => table.nextPage()}
260
+ disabled={!table.getCanNextPage()}
261
+ >
262
+ Next
263
+ </Button>
264
+ </div>
265
+ </div>
266
+ </div>
267
+ );
268
+ }
web/src/pages/dataset/dataset/index.tsx CHANGED
@@ -1,3 +1,15 @@
 
 
 
 
1
  export default function Dataset() {
2
- return <div>Outset</div>;
 
 
 
 
 
 
 
 
3
  }
 
1
+ import ListFilterBar from '@/components/list-filter-bar';
2
+ import { Upload } from 'lucide-react';
3
+ import { DatasetTable } from './dataset-table';
4
+
5
  export default function Dataset() {
6
+ return (
7
+ <section className="p-8 text-foreground">
8
+ <ListFilterBar title="Files">
9
+ <Upload />
10
+ Upload file
11
+ </ListFilterBar>
12
+ <DatasetTable></DatasetTable>
13
+ </section>
14
+ );
15
  }
web/src/pages/dataset/index.tsx CHANGED
@@ -5,7 +5,7 @@ export default function DatasetWrapper() {
5
  return (
6
  <div className="text-foreground flex">
7
  <SideBar></SideBar>
8
- <div className="p-6">
9
  <Outlet />
10
  </div>
11
  </div>
 
5
  return (
6
  <div className="text-foreground flex">
7
  <SideBar></SideBar>
8
+ <div className="flex-1">
9
  <Outlet />
10
  </div>
11
  </div>
web/src/pages/datasets/index.tsx CHANGED
@@ -1,12 +1,7 @@
 
1
  import { Button } from '@/components/ui/button';
2
  import { Card, CardContent } from '@/components/ui/card';
3
- import {
4
- ChevronRight,
5
- Filter,
6
- MoreHorizontal,
7
- Plus,
8
- Search,
9
- } from 'lucide-react';
10
 
11
  const datasets = [
12
  {
@@ -86,17 +81,10 @@ const datasets = [
86
  export default function Datasets() {
87
  return (
88
  <section className="p-8 text-foreground">
89
- <div className="flex justify-between mb-6">
90
- <span className="text-3xl font-bold ">Datasets</span>
91
- <div className="flex gap-4 items-center">
92
- <Filter className="size-5" />
93
- <Search className="size-5" />
94
- <Button variant={'tertiary'} size={'sm'}>
95
- <Plus className="mr-2 h-4 w-4" />
96
- Create dataset
97
- </Button>
98
- </div>
99
- </div>
100
  <div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-8">
101
  {datasets.map((dataset) => (
102
  <Card
 
1
+ import ListFilterBar from '@/components/list-filter-bar';
2
  import { Button } from '@/components/ui/button';
3
  import { Card, CardContent } from '@/components/ui/card';
4
+ import { ChevronRight, MoreHorizontal, Plus } from 'lucide-react';
 
 
 
 
 
 
5
 
6
  const datasets = [
7
  {
 
81
  export default function Datasets() {
82
  return (
83
  <section className="p-8 text-foreground">
84
+ <ListFilterBar title="Datasets">
85
+ <Plus className="mr-2 h-4 w-4" />
86
+ Create dataset
87
+ </ListFilterBar>
 
 
 
 
 
 
 
88
  <div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-8">
89
  {datasets.map((dataset) => (
90
  <Card