feat: prepare Zhinian desktop pilot
This commit is contained in:
@@ -4,11 +4,13 @@ import {
|
||||
FolderUp,
|
||||
Search,
|
||||
ShieldCheck,
|
||||
Trash2,
|
||||
UploadCloud,
|
||||
} from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { ConfirmDialog } from '@/components/ui/confirm-dialog';
|
||||
import { toast } from 'sonner';
|
||||
import { invokeIpc, toUserMessage } from '@/lib/api-client';
|
||||
import { hostApiFetch } from '@/lib/host-api';
|
||||
@@ -82,6 +84,8 @@ export function Knowledge() {
|
||||
const [files, setFiles] = useState<KnowledgeFile[]>([]);
|
||||
const [query, setQuery] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [fileToDelete, setFileToDelete] = useState<KnowledgeFile | null>(null);
|
||||
const [deletingId, setDeletingId] = useState<string | null>(null);
|
||||
const config = useYinianStore((state) => state.config);
|
||||
const workspaceId = config?.hotel.id ?? 'default';
|
||||
|
||||
@@ -142,9 +146,27 @@ export function Knowledge() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (!fileToDelete) return;
|
||||
setDeletingId(fileToDelete.id);
|
||||
try {
|
||||
await hostApiFetch<{ success: boolean }>(
|
||||
`/api/knowledge/files/${encodeURIComponent(fileToDelete.id)}?workspaceId=${encodeURIComponent(workspaceId)}`,
|
||||
{ method: 'DELETE' },
|
||||
);
|
||||
setFiles((current) => current.filter((file) => file.id !== fileToDelete.id));
|
||||
toast.success(t('knowledge.toast.deleted'));
|
||||
setFileToDelete(null);
|
||||
} catch (error) {
|
||||
toast.error(t('knowledge.toast.deleteFailed', { message: toUserMessage(error) }));
|
||||
} finally {
|
||||
setDeletingId(null);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<YinianPageShell data-testid="knowledge-page">
|
||||
<YinianPageHeader>
|
||||
<YinianPageHeader className="yinian-visual-band rounded-lg border border-[#D5E8F3]/75 p-5">
|
||||
<div>
|
||||
<h1 className="text-3xl font-semibold tracking-normal text-slate-950 dark:text-slate-50">
|
||||
{t('knowledge.title')}
|
||||
@@ -205,10 +227,10 @@ export function Knowledge() {
|
||||
</div>
|
||||
</YinianEmptyState>
|
||||
) : (
|
||||
<div className="mt-4 divide-y divide-slate-200 dark:divide-white/10">
|
||||
<div className="mt-4 grid gap-2">
|
||||
{visibleFiles.map((file) => (
|
||||
<div key={file.id} className="flex items-center gap-3 py-3">
|
||||
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-slate-100 text-[#1E3A8A] dark:bg-slate-900 dark:text-blue-100">
|
||||
<div key={file.id} className="flex items-center gap-3 rounded-lg border border-slate-200/70 bg-white px-3 py-3 dark:border-white/10 dark:bg-white/5">
|
||||
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-[#D5E8F3]/80 bg-[#EAF5FA] text-[#075985] dark:border-white/10 dark:bg-white/10 dark:text-blue-100">
|
||||
<FileText className="h-4 w-4" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
@@ -221,11 +243,32 @@ export function Knowledge() {
|
||||
</div>
|
||||
</div>
|
||||
<Badge variant="success" className="shrink-0">{t('knowledge.backedUp')}</Badge>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 shrink-0 text-muted-foreground hover:bg-red-50 hover:text-red-600 dark:hover:bg-red-950/30"
|
||||
title={t('knowledge.delete')}
|
||||
disabled={deletingId === file.id}
|
||||
onClick={() => setFileToDelete(file)}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</YinianPanel>
|
||||
<ConfirmDialog
|
||||
open={!!fileToDelete}
|
||||
title={t('knowledge.delete')}
|
||||
message={t('knowledge.deleteConfirm', { name: fileToDelete?.name })}
|
||||
confirmLabel={t('knowledge.delete')}
|
||||
cancelLabel={t('common:actions.cancel')}
|
||||
variant="destructive"
|
||||
onConfirm={() => void handleDelete()}
|
||||
onCancel={() => setFileToDelete(null)}
|
||||
/>
|
||||
</YinianPageShell>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user