feat(fe): complete kb ui

This commit is contained in:
Junyan Qin
2025-07-12 18:00:54 +08:00
parent 1ef0193028
commit a10e61735d
7 changed files with 339 additions and 8 deletions

View File

@@ -4,20 +4,31 @@ import { KnowledgeBaseFile } from '@/app/infra/entities/api';
import { columns, DocumentFile } from './documents/columns';
import { DataTable } from './documents/data-table';
import FileUploadZone from './FileUploadZone';
import { toast } from 'sonner';
import { useTranslation } from 'react-i18next';
export default function KBDoc({ kbId }: { kbId: string }) {
const [documentsList, setDocumentsList] = useState<DocumentFile[]>([]);
const { t } = useTranslation();
useEffect(() => {
getDocumentsList();
}, []);
const intervalId = setInterval(() => {
getDocumentsList();
}, 5000);
return () => {
clearInterval(intervalId);
};
}, [kbId]);
async function getDocumentsList() {
const resp = await httpClient.getKnowledgeBaseFiles(kbId);
setDocumentsList(
resp.files.map((file: KnowledgeBaseFile) => {
return {
id: file.file_id,
id: file.id,
name: file.file_name,
status: file.status,
};
@@ -35,6 +46,19 @@ export default function KBDoc({ kbId }: { kbId: string }) {
console.error('Upload failed:', error);
};
const handleDelete = (id: string) => {
httpClient
.deleteKnowledgeBaseFile(kbId, id)
.then(() => {
getDocumentsList();
toast.success(t('knowledge.documentsTab.fileDeleteSuccess'));
})
.catch((error) => {
console.error('Delete failed:', error);
toast.error(t('knowledge.documentsTab.fileDeleteFailed'));
});
};
return (
<div className="container mx-auto py-2">
<FileUploadZone
@@ -42,7 +66,7 @@ export default function KBDoc({ kbId }: { kbId: string }) {
onUploadSuccess={handleUploadSuccess}
onUploadError={handleUploadError}
/>
<DataTable columns={columns()} data={documentsList} />
<DataTable columns={columns(handleDelete)} data={documentsList} />
</div>
);
}

View File

@@ -1,6 +1,16 @@
'use client';
import { ColumnDef } from '@tanstack/react-table';
import { MoreHorizontal } from 'lucide-react';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { useTranslation } from 'react-i18next';
export type DocumentFile = {
@@ -9,7 +19,9 @@ export type DocumentFile = {
status: string;
};
export const columns = (): ColumnDef<DocumentFile>[] => {
export const columns = (
onDelete: (id: string) => void,
): ColumnDef<DocumentFile>[] => {
const { t } = useTranslation();
return [
{
@@ -20,5 +32,33 @@ export const columns = (): ColumnDef<DocumentFile>[] => {
accessorKey: 'status',
header: t('knowledge.documentsTab.status'),
},
{
id: 'actions',
cell: ({ row }) => {
const document = row.original;
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">
{t('knowledge.documentsTab.actions')}
</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>
{t('knowledge.documentsTab.actions')}
</DropdownMenuLabel>
<DropdownMenuItem onClick={() => onDelete(document.id)}>
{t('knowledge.documentsTab.delete')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
},
},
];
};

View File

@@ -155,7 +155,7 @@ export interface ApiRespKnowledgeBaseFiles {
}
export interface KnowledgeBaseFile {
file_id: string;
id: string;
file_name: string;
status: string;
}

View File

@@ -463,9 +463,7 @@ class HttpClient {
uuid: string,
file_id: string,
): Promise<object> {
return this.post(`/api/v1/knowledge/bases/${uuid}/files`, {
file_id,
});
return this.delete(`/api/v1/knowledge/bases/${uuid}/files/${file_id}`);
}
public getKnowledgeBaseFiles(
@@ -474,6 +472,13 @@ class HttpClient {
return this.get(`/api/v1/knowledge/bases/${uuid}/files`);
}
public deleteKnowledgeBaseFile(
uuid: string,
file_id: string,
): Promise<object> {
return this.delete(`/api/v1/knowledge/bases/${uuid}/files/${file_id}`);
}
// ============ Plugins API ============
public getPlugins(): Promise<ApiRespPlugins> {
return this.get('/api/v1/plugins');