Skip to content

Commit 955ffff

Browse files
authored
add select dataset files component (#94)
* feat: Refactor AddDataDialog and introduce DatasetFileTransfer component for improved file selection and management * feat: Refactor SynthesisTask and InstructionTemplate components for improved UI and functionality; integrate DatasetFileTransfer for file management * feat: Enhance CollectionTaskCreate form with additional fields for MYSQL configuration and prefix input
1 parent a07fba2 commit 955ffff

File tree

8 files changed

+749
-1258
lines changed

8 files changed

+749
-1258
lines changed

frontend/src/pages/KnowledgeBase/components/AddDataDialog.tsx

Lines changed: 210 additions & 671 deletions
Large diffs are not rendered by default.
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
import React, { useEffect } from "react";
2+
import { Input, Table } from "antd";
3+
import { RightOutlined } from "@ant-design/icons";
4+
import { mapDataset } from "@/pages/DataManagement/dataset.const";
5+
import {
6+
Dataset,
7+
DatasetFile,
8+
DatasetType,
9+
} from "@/pages/DataManagement/dataset.model";
10+
import {
11+
queryDatasetFilesUsingGet,
12+
queryDatasetsUsingGet,
13+
} from "@/pages/DataManagement/dataset.api";
14+
import { formatBytes } from "@/utils/unit";
15+
16+
interface DatasetFileTransferProps
17+
extends React.HTMLAttributes<HTMLDivElement> {
18+
open: boolean;
19+
selectedMap: Record<string, DatasetFile[]>;
20+
onSelectedChange: (filesMap: Record<string, DatasetFile[]>) => void;
21+
}
22+
23+
// Customize Table Transfer
24+
const DatasetFileTransfer: React.FC<DatasetFileTransferProps> = ({
25+
open,
26+
selectedMap,
27+
onSelectedChange,
28+
...props
29+
}) => {
30+
const [datasets, setDatasets] = React.useState<Dataset[]>([]);
31+
const [datasetSearch, setDatasetSearch] = React.useState<string>("");
32+
const [datasetPagination, setDatasetPagination] = React.useState<{
33+
current: number;
34+
pageSize: number;
35+
total: number;
36+
}>({ current: 1, pageSize: 1000, total: 0 });
37+
38+
const [expandedRowKeys, setExpandedRowKeys] = React.useState<React.Key[]>([]);
39+
40+
const [loadedFiles, setLoadedFiles] = React.useState<
41+
Record<string, DatasetFile[]>
42+
>({});
43+
const [filesSearch, setFilesSearch] = React.useState<string>("");
44+
const [filesPagination, setFilesPagination] = React.useState<{
45+
current: number;
46+
pageSize: number;
47+
total: number;
48+
}>({ current: 1, pageSize: 10, total: 0 });
49+
50+
const selectedFiles = React.useMemo(() => {
51+
const files: DatasetFile[] = [];
52+
Object.values(selectedMap).forEach((fileList) => {
53+
files.push(...fileList);
54+
});
55+
return files;
56+
}, [selectedMap]);
57+
58+
const fetchDatasets = async () => {
59+
const { data } = await queryDatasetsUsingGet({
60+
page: datasetPagination.current - 1,
61+
size: datasetPagination.pageSize,
62+
keyword: datasetSearch,
63+
type: DatasetType.TEXT,
64+
});
65+
setDatasets(data.content.map(mapDataset) || []);
66+
setDatasetPagination((prev) => ({
67+
...prev,
68+
total: data.totalElements,
69+
}));
70+
};
71+
72+
useEffect(() => {
73+
if (open) {
74+
fetchDatasets();
75+
}
76+
}, [open]);
77+
78+
const fetchFiles = async (dataset: Dataset) => {
79+
if (!dataset || loadedFiles[dataset.id]) return;
80+
const { data } = await queryDatasetFilesUsingGet(dataset.id, {
81+
page: filesPagination.current - 1,
82+
size: 1000,
83+
keyword: filesSearch,
84+
});
85+
setLoadedFiles((prev) => ({
86+
...prev,
87+
[dataset.id]: data.content,
88+
}));
89+
setFilesPagination((prev) => ({
90+
...prev,
91+
total: data.totalElements,
92+
}));
93+
return data.content;
94+
};
95+
96+
const onExpand = (expanded: boolean, record: Dataset) => {
97+
if (expanded) {
98+
fetchFiles(record);
99+
setExpandedRowKeys([...expandedRowKeys, record.id]);
100+
} else {
101+
setExpandedRowKeys(expandedRowKeys.filter((key) => key !== record.id));
102+
}
103+
};
104+
105+
const toggleSelectFile = (dataset: Dataset, record: DatasetFile) => {
106+
const datasetFiles = selectedMap[dataset.id] || [];
107+
const hasSelected = datasetFiles.find((file) => file.id === record.id);
108+
let files = [...datasetFiles];
109+
if (!hasSelected) {
110+
files.push(record);
111+
} else {
112+
files = datasetFiles.filter((file) => file.id !== record.id);
113+
}
114+
115+
const newMap = { ...selectedMap, [dataset.id]: files };
116+
if (files.length === 0) {
117+
delete newMap[dataset.id];
118+
}
119+
onSelectedChange(newMap);
120+
};
121+
122+
const datasetCols = [
123+
{
124+
title: "数据集名称",
125+
dataIndex: "name",
126+
key: "name",
127+
ellipsis: true,
128+
},
129+
{
130+
title: "文件数",
131+
dataIndex: "fileCount",
132+
key: "fileCount",
133+
ellipsis: true,
134+
},
135+
{
136+
title: "大小",
137+
dataIndex: "totalSize",
138+
key: "totalSize",
139+
ellipsis: true,
140+
render: formatBytes,
141+
},
142+
];
143+
144+
const fileCols = [
145+
{
146+
title: "文件名",
147+
dataIndex: "fileName",
148+
key: "fileName",
149+
ellipsis: true,
150+
},
151+
{
152+
title: "大小",
153+
dataIndex: "size",
154+
key: "size",
155+
ellipsis: true,
156+
render: formatBytes,
157+
},
158+
];
159+
return (
160+
<div className="grid grid-cols-25 gap-4 w-full" {...props}>
161+
<div className="border-card flex flex-col col-span-12">
162+
<div className="border-bottom p-2 font-bold">选择数据集文件</div>
163+
<div className="p-2">
164+
<Input
165+
placeholder="搜索数据集名称..."
166+
value={datasetSearch}
167+
onChange={(e) => setDatasetSearch(e.target.value)}
168+
/>
169+
</div>
170+
<Table
171+
scroll={{ y: 400 }}
172+
rowKey="id"
173+
size="small"
174+
onRow={(record: Dataset) => ({
175+
onClick: () => {
176+
const isExpanded = expandedRowKeys.includes(record.id);
177+
onExpand(!isExpanded, record);
178+
},
179+
})}
180+
dataSource={datasets}
181+
columns={datasetCols}
182+
pagination={datasetPagination}
183+
rowSelection={{
184+
type: "checkbox",
185+
selectedRowKeys: Object.keys(selectedMap),
186+
onSelect: async (record, isSelected) => {
187+
let files = [];
188+
if (!loadedFiles[record.id]) {
189+
files = await fetchFiles(record);
190+
} else {
191+
files = loadedFiles[record.id];
192+
}
193+
194+
const newMap = { ...selectedMap };
195+
if (isSelected) {
196+
newMap[record.id] = files;
197+
} else {
198+
delete newMap[record.id];
199+
}
200+
onSelectedChange(newMap);
201+
},
202+
}}
203+
expandable={{
204+
expandedRowKeys,
205+
onExpand,
206+
expandedRowRender: (dataset) => (
207+
<Table
208+
scroll={{ y: 400 }}
209+
rowKey="id"
210+
size="small"
211+
dataSource={loadedFiles[dataset.id] || []}
212+
columns={fileCols}
213+
pagination={filesPagination}
214+
onRow={(record: DatasetFile) => ({
215+
onClick: () => toggleSelectFile(dataset, record),
216+
})}
217+
rowSelection={{
218+
type: "checkbox",
219+
selectedRowKeys: Object.values(
220+
selectedMap[dataset.id] || {}
221+
).map((file) => file.id),
222+
onSelect: (record) => toggleSelectFile(dataset, record),
223+
}}
224+
/>
225+
),
226+
}}
227+
/>
228+
</div>
229+
<RightOutlined />
230+
<div className="border-card flex flex-col col-span-12">
231+
<div className="border-bottom p-2 font-bold">
232+
已选文件({selectedFiles.length}
233+
</div>
234+
<div className="p-2">
235+
<Input
236+
placeholder="搜索文件名称..."
237+
value={filesSearch}
238+
onChange={(e) => setFilesSearch(e.target.value)}
239+
/>
240+
</div>
241+
<Table
242+
size="small"
243+
scroll={{ y: 400 }}
244+
rowKey="id"
245+
dataSource={selectedFiles}
246+
columns={fileCols}
247+
/>
248+
</div>
249+
</div>
250+
);
251+
};
252+
253+
export default DatasetFileTransfer;

frontend/src/pages/KnowledgeBase/components/TableTransfer.tsx

Lines changed: 0 additions & 75 deletions
This file was deleted.

0 commit comments

Comments
 (0)