@tablestore/tablestore-agent-cli 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dashboard-runtime/dashboard/.next/BUILD_ID +1 -1
- package/dist/dashboard-runtime/dashboard/.next/build-manifest.json +3 -3
- package/dist/dashboard-runtime/dashboard/.next/prerender-manifest.json +3 -3
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/[name]/documents/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/[name]/documents/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/[name]/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/[name]/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/[name]/qa/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/[name]/qa/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/[name]/retrieval/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/[name]/retrieval/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/[name]/settings/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/[name]/settings/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/create/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/knowledge-base/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/llm-providers/[id]/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/llm-providers/new/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/llm-providers/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/llm-providers/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/messages/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/messages/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/requests/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/requests/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/search/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/search/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/settings/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/settings/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/units/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/[store]/units/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/create/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/memory/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/projects/page.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/(dashboard)/projects/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_global-error.html +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_global-error.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_not-found.html +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_not-found.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/api/v1/knowledge-bases/[name]/documents/upload/route.js.nft.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/index.html +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/index.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/onboarding.html +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/onboarding.rsc +3 -3
- package/dist/dashboard-runtime/dashboard/.next/server/app/onboarding.segments/_full.segment.rsc +3 -3
- package/dist/dashboard-runtime/dashboard/.next/server/app/onboarding.segments/_head.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/onboarding.segments/_index.segment.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/onboarding.segments/_tree.segment.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/onboarding.segments/onboarding/__PAGE__.segment.rsc +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/app/onboarding.segments/onboarding.segment.rsc +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/0b1r_app_(dashboard)_knowledge-base_[name]_documents_documents-client_tsx_0g2uxmt._.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/[root-of-the-server]__09_30hi._.js +3 -0
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/[root-of-the-server]__0kaiok7._.js +3 -0
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/[root-of-the-server]__0l937k4._.js +3 -0
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_0-dlo4s._.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_01pp~xx._.js +3 -0
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/{_0476v7r._.js → _08j6p-z._.js} +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/{_0ct0n55._.js → _09eom0_._.js} +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/{_0mzxmfh._.js → _0f-may2._.js} +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_0fp_nnb._.js +3 -0
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_0l6jz-5._.js +3 -0
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/{_0fg6iap._.js → _0ntv66s._.js} +2 -2
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_0sc0tpz._.js +3 -0
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_0tyxwr3._.js +3 -0
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_0u9md36._.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/dashboard_src_065m1.j._.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/dashboard_src_app_(dashboard)_knowledge-base_[name]_layout-client_tsx_05momc5._.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/middleware-build-manifest.js +3 -3
- package/dist/dashboard-runtime/dashboard/.next/server/pages/404.html +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/pages/500.html +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/server-reference-manifest.js +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/server-reference-manifest.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0-xqk6wfme5fu.js +1 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/{0jeb9kxtd_jq..js → 00.fyg_t3xjc~.js} +1 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/01k-.wkndubwy.js +138 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/07r22x5uhjxjb.js +1 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0cbu3udngtx-v.js +4 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0h7d69g2fdgs6.js +138 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0iv0g360z0ja5.js +1 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0jf4ytf.izmzh.js +1 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/{17nx_vdk_qemm.js → 0m42mmyxmgn-i.js} +1 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0odz1whf-ozqn.css +1 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0ouxv_2qvf6.9.js +1 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0rbkgj._oqsb3.js +1 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0u6u.649ou67b.js +1 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0vf7~eysvh9bq.js +1 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/{09qsmnfvk8dm3.js → 0wmaq.ay~r2sn.js} +1 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/{0i5aqiffpm9jr.js → 0xb0_9t-vmo6e.js} +1 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0yp_2ea75d19v.js +1 -0
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/{0s3mvx9_dr13c.js → 11cizim1aug~b.js} +1 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/13-2ei295hl0-.js +1 -0
- package/dist/dashboard-runtime/dashboard/src/app/(dashboard)/knowledge-base/[name]/qa/page.tsx +23 -1
- package/dist/dashboard-runtime/dashboard/src/components/documents/doc-upload-dialog.tsx +370 -91
- package/dist/dashboard-runtime/dashboard/src/components/knowledge-base/kb-card.tsx +8 -5
- package/dist/dashboard-runtime/dashboard/src/components/knowledge-base/kb-header.tsx +18 -10
- package/dist/dashboard-runtime/dashboard/src/components/memory/memory-header.tsx +8 -12
- package/dist/dashboard-runtime/dashboard/src/components/qa/qa-chat-panel.tsx +45 -4
- package/dist/dashboard-runtime/dashboard/src/components/qa/qa-message.tsx +636 -36
- package/dist/dashboard-runtime/dashboard/src/components/shared/confirm-dialog.tsx +8 -1
- package/dist/dashboard-runtime/dashboard/src/components/shared/refresh-button.tsx +102 -86
- package/dist/dashboard-runtime/dashboard/src/hooks/use-qa-chat.ts +261 -58
- package/dist/dashboard-runtime/dashboard/src/lib/chat-message-ops.ts +76 -0
- package/dist/dashboard-runtime/dashboard/src/lib/dev-flags.ts +24 -0
- package/dist/dashboard-runtime/dashboard/src/types/llm-chat.ts +19 -0
- package/package.json +1 -1
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/[root-of-the-server]__0i0y9.r._.js +0 -3
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/[root-of-the-server]__0r_6wpx._.js +0 -3
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/[root-of-the-server]__0y8rrcu._.js +0 -3
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_02e0c00._.js +0 -3
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_0doczxg._.js +0 -3
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_0e9y.xc._.js +0 -3
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_0ti~om_._.js +0 -3
- package/dist/dashboard-runtime/dashboard/.next/server/chunks/ssr/_0~s~e-0._.js +0 -3
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/055_bo6_3nt-s.js +0 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/07l4dodn5t6l4.js +0 -4
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0a5ass8u78k90.js +0 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0j~63ld9lbb25.js +0 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0l6znnjqw.4yw.js +0 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0o-c2g8y5pw-c.js +0 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0o0i2ke2jbdvq.js +0 -138
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0u2lo2lzizxy_.js +0 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/0v.hno.6q74nn.css +0 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/100.ax5hitxko.js +0 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/14ti2gx~1fiub.js +0 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/14vqmdm7sosj2.js +0 -1
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/17h~onnkksf44.js +0 -138
- package/dist/dashboard-runtime/dashboard/.next/static/chunks/186jubvt5xyuj.js +0 -1
- /package/dist/dashboard-runtime/dashboard/.next/static/{wWmSSYUu4w4mIF1R_7UoM → BGnMIk4OPjFx_qvLFMTBc}/_buildManifest.js +0 -0
- /package/dist/dashboard-runtime/dashboard/.next/static/{wWmSSYUu4w4mIF1R_7UoM → BGnMIk4OPjFx_qvLFMTBc}/_clientMiddlewareManifest.js +0 -0
- /package/dist/dashboard-runtime/dashboard/.next/static/{wWmSSYUu4w4mIF1R_7UoM → BGnMIk4OPjFx_qvLFMTBc}/_ssgManifest.js +0 -0
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
|
|
25
25
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
26
26
|
import { useUploadDocuments } from "@/hooks/use-upload-documents";
|
|
27
|
+
import { cn } from "@/lib/utils";
|
|
27
28
|
import type { MetadataField } from "@/types/knowledge-base";
|
|
28
29
|
|
|
29
30
|
interface DocUploadDialogProps {
|
|
@@ -93,6 +94,107 @@ interface FolderFilterOptions {
|
|
|
93
94
|
recursive: boolean;
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Minimal subset of the FileSystemEntry API we rely on. Typescript ships
|
|
99
|
+
* loose types under DOM lib, but they don't reliably expose
|
|
100
|
+
* `createReader().readEntries(...)` — declare what we use.
|
|
101
|
+
*/
|
|
102
|
+
interface FsEntry {
|
|
103
|
+
isFile: boolean;
|
|
104
|
+
isDirectory: boolean;
|
|
105
|
+
name: string;
|
|
106
|
+
fullPath: string;
|
|
107
|
+
}
|
|
108
|
+
interface FsFileEntry extends FsEntry {
|
|
109
|
+
isFile: true;
|
|
110
|
+
file(success: (file: File) => void, error?: (e: Error) => void): void;
|
|
111
|
+
}
|
|
112
|
+
interface FsDirEntry extends FsEntry {
|
|
113
|
+
isDirectory: true;
|
|
114
|
+
createReader(): {
|
|
115
|
+
readEntries(success: (entries: FsEntry[]) => void, error?: (e: Error) => void): void;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Tag a File with a relative path so the rest of the pipeline (filter, list,
|
|
120
|
+
* display) can treat drag-dropped folder uploads identically to picker-based
|
|
121
|
+
* ones. `webkitRelativePath` is normally a read-only inherited getter, but
|
|
122
|
+
* defining a same-named own data property shadows it cleanly across browsers.
|
|
123
|
+
*/
|
|
124
|
+
function tagRelativePath(file: File, path: string): File {
|
|
125
|
+
try {
|
|
126
|
+
Object.defineProperty(file, "webkitRelativePath", {
|
|
127
|
+
value: path,
|
|
128
|
+
configurable: true,
|
|
129
|
+
writable: false,
|
|
130
|
+
});
|
|
131
|
+
} catch {
|
|
132
|
+
// Some engines may freeze the prototype shape; fall back to a parallel
|
|
133
|
+
// own property so filterFolderFiles' fallback (`|| file.name`) at least
|
|
134
|
+
// surfaces a reasonable label.
|
|
135
|
+
}
|
|
136
|
+
return file;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Recursively walk a FileSystemEntry tree and resolve a flat File[] with
|
|
140
|
+
* webkitRelativePath populated to the root-relative path. */
|
|
141
|
+
async function walkEntry(entry: FsEntry, parentPath = ""): Promise<File[]> {
|
|
142
|
+
if (entry.isFile) {
|
|
143
|
+
const fileEntry = entry as FsFileEntry;
|
|
144
|
+
return new Promise<File[]>((resolve) => {
|
|
145
|
+
fileEntry.file(
|
|
146
|
+
(file) => {
|
|
147
|
+
const relPath = parentPath ? `${parentPath}/${file.name}` : file.name;
|
|
148
|
+
resolve([tagRelativePath(file, relPath)]);
|
|
149
|
+
},
|
|
150
|
+
() => resolve([]),
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (entry.isDirectory) {
|
|
155
|
+
const dirEntry = entry as FsDirEntry;
|
|
156
|
+
const reader = dirEntry.createReader();
|
|
157
|
+
// readEntries returns at most ~100 entries per call; loop until empty.
|
|
158
|
+
const collected: FsEntry[] = [];
|
|
159
|
+
await new Promise<void>((resolve) => {
|
|
160
|
+
const readBatch = () => {
|
|
161
|
+
reader.readEntries(
|
|
162
|
+
(batch) => {
|
|
163
|
+
if (batch.length === 0) {
|
|
164
|
+
resolve();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
collected.push(...batch);
|
|
168
|
+
readBatch();
|
|
169
|
+
},
|
|
170
|
+
() => resolve(),
|
|
171
|
+
);
|
|
172
|
+
};
|
|
173
|
+
readBatch();
|
|
174
|
+
});
|
|
175
|
+
const here = parentPath ? `${parentPath}/${entry.name}` : entry.name;
|
|
176
|
+
const nested = await Promise.all(collected.map((child) => walkEntry(child, here)));
|
|
177
|
+
return nested.flat();
|
|
178
|
+
}
|
|
179
|
+
return [];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Pull entries off a DataTransferItemList. Items without `webkitGetAsEntry`
|
|
183
|
+
* (older browsers) silently fall back to whatever the dataTransfer.files
|
|
184
|
+
* list resolved to. */
|
|
185
|
+
function extractEntries(items: DataTransferItemList): FsEntry[] {
|
|
186
|
+
const out: FsEntry[] = [];
|
|
187
|
+
for (let i = 0; i < items.length; i++) {
|
|
188
|
+
const item = items[i];
|
|
189
|
+
if (item.kind !== "file") continue;
|
|
190
|
+
const entry = (item as DataTransferItem & {
|
|
191
|
+
webkitGetAsEntry?: () => FsEntry | null;
|
|
192
|
+
}).webkitGetAsEntry?.();
|
|
193
|
+
if (entry) out.push(entry);
|
|
194
|
+
}
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
|
|
96
198
|
/** Apply include / exclude / recursive filters to a batch of picked files. */
|
|
97
199
|
function filterFolderFiles(list: File[], opts: FolderFilterOptions): File[] {
|
|
98
200
|
const { include, exclude, recursive } = opts;
|
|
@@ -136,6 +238,7 @@ export function DocUploadDialog({
|
|
|
136
238
|
const [excludeInput, setExcludeInput] = useState("");
|
|
137
239
|
const [recursive, setRecursive] = useState(true);
|
|
138
240
|
const folderInputRef = useRef<HTMLInputElement | null>(null);
|
|
241
|
+
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
|
139
242
|
|
|
140
243
|
const hasSchemaFields = metadataFields && metadataFields.length > 0;
|
|
141
244
|
const uploadDocuments = useUploadDocuments();
|
|
@@ -157,6 +260,8 @@ export function DocUploadDialog({
|
|
|
157
260
|
|
|
158
261
|
const handleDragOver = useCallback((event: React.DragEvent) => {
|
|
159
262
|
event.preventDefault();
|
|
263
|
+
// `move` cursor confuses folder drops; `copy` reads as "I'll add this".
|
|
264
|
+
if (event.dataTransfer) event.dataTransfer.dropEffect = "copy";
|
|
160
265
|
setIsDragOver(true);
|
|
161
266
|
}, []);
|
|
162
267
|
|
|
@@ -164,11 +269,137 @@ export function DocUploadDialog({
|
|
|
164
269
|
setIsDragOver(false);
|
|
165
270
|
}, []);
|
|
166
271
|
|
|
167
|
-
|
|
272
|
+
/** Walk a list of FileSystemDirectoryEntry trees and store the resulting
|
|
273
|
+
* File[] in folderRaw. Shared between drag-drop and the toast action.
|
|
274
|
+
* Declared before handleDropFileMode so its callback identity is stable
|
|
275
|
+
* for that hook's dependency array. */
|
|
276
|
+
const importDirEntries = useCallback(async (dirs: FsEntry[]) => {
|
|
277
|
+
const all = await Promise.all(dirs.map((d) => walkEntry(d)));
|
|
278
|
+
const flat = all.flat();
|
|
279
|
+
if (flat.length > 0) {
|
|
280
|
+
setFolderRaw((prev) => [...prev, ...flat]);
|
|
281
|
+
}
|
|
282
|
+
}, []);
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* File-mode drop. Tolerates the user dragging folders by (a) silently
|
|
286
|
+
* extracting all leaf files from any dropped folder via webkitGetAsEntry
|
|
287
|
+
* and (b) hinting via toast that 「按文件夹」 mode supports filtering. The
|
|
288
|
+
* old behaviour of forwarding raw `dataTransfer.files` would have surfaced
|
|
289
|
+
* a 0-byte directory entry to the API and failed the upload.
|
|
290
|
+
*/
|
|
291
|
+
const handleDropFileMode = useCallback(async (event: React.DragEvent) => {
|
|
168
292
|
event.preventDefault();
|
|
169
293
|
setIsDragOver(false);
|
|
170
|
-
|
|
171
|
-
|
|
294
|
+
|
|
295
|
+
const entries = extractEntries(event.dataTransfer.items);
|
|
296
|
+
if (entries.length === 0) {
|
|
297
|
+
// Browser without webkitGetAsEntry — fall back to the file list. Any
|
|
298
|
+
// raw "directory" entry will show up as a zero-byte File with empty
|
|
299
|
+
// type, which we filter out below as a defensive measure.
|
|
300
|
+
const fallback = Array.from(event.dataTransfer.files).filter(
|
|
301
|
+
(f) => f.size > 0 || f.type !== "",
|
|
302
|
+
);
|
|
303
|
+
if (fallback.length > 0) {
|
|
304
|
+
setFiles((prev) => [...prev, ...fallback]);
|
|
305
|
+
}
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const fileEntries = entries.filter((e) => e.isFile);
|
|
310
|
+
const dirEntries = entries.filter((e) => e.isDirectory);
|
|
311
|
+
|
|
312
|
+
// Resolve File objects from the file entries directly (no recursion in
|
|
313
|
+
// file mode — the user explicitly chose 「按文件」).
|
|
314
|
+
const directFiles = (
|
|
315
|
+
await Promise.all(
|
|
316
|
+
fileEntries.map(
|
|
317
|
+
(e) =>
|
|
318
|
+
new Promise<File | null>((resolve) => {
|
|
319
|
+
(e as FsFileEntry).file(
|
|
320
|
+
(file) => resolve(file),
|
|
321
|
+
() => resolve(null),
|
|
322
|
+
);
|
|
323
|
+
}),
|
|
324
|
+
),
|
|
325
|
+
)
|
|
326
|
+
).filter((f): f is File => f !== null);
|
|
327
|
+
|
|
328
|
+
if (directFiles.length > 0) {
|
|
329
|
+
setFiles((prev) => [...prev, ...directFiles]);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (dirEntries.length > 0) {
|
|
333
|
+
const folderNames = dirEntries.map((d) => d.name).join("、");
|
|
334
|
+
toast.info(
|
|
335
|
+
directFiles.length > 0
|
|
336
|
+
? `已忽略 ${dirEntries.length} 个文件夹(${folderNames})`
|
|
337
|
+
: `检测到文件夹(${folderNames}),已自动切换到「按文件夹」模式`,
|
|
338
|
+
{
|
|
339
|
+
description: "可在「按文件夹」模式按后缀筛选并递归上传",
|
|
340
|
+
action: {
|
|
341
|
+
label: "切换至按文件夹",
|
|
342
|
+
onClick: () => {
|
|
343
|
+
setMode("folder");
|
|
344
|
+
// Auto-import the dropped folders so the user doesn't repeat
|
|
345
|
+
// the gesture.
|
|
346
|
+
void importDirEntries(dirEntries);
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
// Auto-switch and import when the user dropped only folders. They
|
|
353
|
+
// clearly intended a folder upload — don't make them click the toast.
|
|
354
|
+
if (directFiles.length === 0) {
|
|
355
|
+
setMode("folder");
|
|
356
|
+
await importDirEntries(dirEntries);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}, [importDirEntries]);
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Folder-mode drop. Walks any dropped FileSystemDirectoryEntry tree to
|
|
363
|
+
* produce a flat File[] with webkitRelativePath populated, so the existing
|
|
364
|
+
* include/exclude/recursive filter pipeline works identically to a folder
|
|
365
|
+
* picked through `<input webkitdirectory>`.
|
|
366
|
+
*/
|
|
367
|
+
const handleDropFolderMode = useCallback(async (event: React.DragEvent) => {
|
|
368
|
+
event.preventDefault();
|
|
369
|
+
setIsDragOver(false);
|
|
370
|
+
|
|
371
|
+
const entries = extractEntries(event.dataTransfer.items);
|
|
372
|
+
if (entries.length === 0) {
|
|
373
|
+
toast.error("当前浏览器不支持文件夹拖拽,请使用「选择文件夹」按钮");
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const dirs = entries.filter((e) => e.isDirectory);
|
|
378
|
+
const looseFiles = entries.filter((e) => e.isFile);
|
|
379
|
+
|
|
380
|
+
if (dirs.length === 0 && looseFiles.length > 0) {
|
|
381
|
+
toast.info("拖拽内容均为文件,已合并到当前列表(不会经过过滤)");
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const dirFiles = (await Promise.all(dirs.map((d) => walkEntry(d)))).flat();
|
|
385
|
+
const looseFileObjs = (
|
|
386
|
+
await Promise.all(
|
|
387
|
+
looseFiles.map(
|
|
388
|
+
(e) =>
|
|
389
|
+
new Promise<File | null>((resolve) => {
|
|
390
|
+
(e as FsFileEntry).file(
|
|
391
|
+
(file) => resolve(tagRelativePath(file, file.name)),
|
|
392
|
+
() => resolve(null),
|
|
393
|
+
);
|
|
394
|
+
}),
|
|
395
|
+
),
|
|
396
|
+
)
|
|
397
|
+
).filter((f): f is File => f !== null);
|
|
398
|
+
|
|
399
|
+
const merged = [...dirFiles, ...looseFileObjs];
|
|
400
|
+
if (merged.length > 0) {
|
|
401
|
+
setFolderRaw((prev) => [...prev, ...merged]);
|
|
402
|
+
}
|
|
172
403
|
}, []);
|
|
173
404
|
|
|
174
405
|
const handleFileSelect = useCallback(
|
|
@@ -311,75 +542,114 @@ export function DocUploadDialog({
|
|
|
311
542
|
<DialogHeader>
|
|
312
543
|
<DialogTitle>上传文档</DialogTitle>
|
|
313
544
|
<DialogDescription>
|
|
314
|
-
将文档上传到知识库 {knowledgeBaseName}
|
|
545
|
+
将文档上传到知识库 <span className="font-medium text-foreground">{knowledgeBaseName}</span>
|
|
315
546
|
</DialogDescription>
|
|
316
547
|
</DialogHeader>
|
|
317
548
|
|
|
318
549
|
<div className="space-y-4 min-w-0">
|
|
319
550
|
<Tabs value={mode} onValueChange={handleModeChange}>
|
|
320
551
|
<TabsList className="grid w-full grid-cols-2">
|
|
321
|
-
<TabsTrigger value="file"
|
|
322
|
-
|
|
552
|
+
<TabsTrigger value="file" className="gap-2">
|
|
553
|
+
<FileText className="h-3.5 w-3.5" />
|
|
554
|
+
按文件
|
|
555
|
+
</TabsTrigger>
|
|
556
|
+
<TabsTrigger value="folder" className="gap-2">
|
|
557
|
+
<FolderOpen className="h-3.5 w-3.5" />
|
|
558
|
+
按文件夹
|
|
559
|
+
</TabsTrigger>
|
|
323
560
|
</TabsList>
|
|
324
561
|
|
|
325
562
|
{/* ---- File mode ---- */}
|
|
326
563
|
<TabsContent value="file" className="space-y-3">
|
|
327
564
|
<div
|
|
328
|
-
className={
|
|
565
|
+
className={cn(
|
|
566
|
+
"relative flex h-36 flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed transition-colors",
|
|
329
567
|
isDragOver
|
|
330
568
|
? "border-[hsl(var(--primary))] bg-[hsl(var(--primary))]/5"
|
|
331
|
-
: "border-[hsl(var(--border))] hover:border-[hsl(var(--primary))]/50"
|
|
332
|
-
}
|
|
569
|
+
: "border-[hsl(var(--border))] bg-[hsl(var(--secondary))]/40 hover:border-[hsl(var(--primary))]/50 hover:bg-[hsl(var(--primary))]/[0.03]",
|
|
570
|
+
)}
|
|
333
571
|
onDragOver={handleDragOver}
|
|
334
572
|
onDragLeave={handleDragLeave}
|
|
335
|
-
onDrop={
|
|
573
|
+
onDrop={handleDropFileMode}
|
|
336
574
|
>
|
|
337
|
-
<Upload className="
|
|
575
|
+
<Upload className="h-7 w-7 text-[hsl(var(--muted-foreground))]" />
|
|
338
576
|
<p className="text-sm text-[hsl(var(--muted-foreground))]">
|
|
339
|
-
|
|
340
|
-
<label className="cursor-pointer text-[hsl(var(--primary))] hover:underline">
|
|
341
|
-
点击选择
|
|
342
|
-
<input
|
|
343
|
-
type="file"
|
|
344
|
-
multiple
|
|
345
|
-
className="hidden"
|
|
346
|
-
onChange={handleFileSelect}
|
|
347
|
-
/>
|
|
348
|
-
</label>
|
|
577
|
+
拖拽文件到此处
|
|
349
578
|
</p>
|
|
579
|
+
<Button
|
|
580
|
+
type="button"
|
|
581
|
+
variant="outline"
|
|
582
|
+
size="sm"
|
|
583
|
+
onClick={() => fileInputRef.current?.click()}
|
|
584
|
+
>
|
|
585
|
+
选择文件
|
|
586
|
+
</Button>
|
|
587
|
+
<input
|
|
588
|
+
ref={fileInputRef}
|
|
589
|
+
type="file"
|
|
590
|
+
multiple
|
|
591
|
+
className="hidden"
|
|
592
|
+
onChange={handleFileSelect}
|
|
593
|
+
/>
|
|
350
594
|
</div>
|
|
351
595
|
|
|
352
596
|
{files.length > 0 && (
|
|
353
|
-
<div className="space-y-2
|
|
354
|
-
|
|
355
|
-
<
|
|
356
|
-
|
|
357
|
-
className="
|
|
597
|
+
<div className="space-y-2">
|
|
598
|
+
<div className="flex items-center justify-between text-xs text-[hsl(var(--muted-foreground))]">
|
|
599
|
+
<span>
|
|
600
|
+
已选择{" "}
|
|
601
|
+
<span className="font-medium text-foreground">{files.length}</span>{" "}
|
|
602
|
+
个文件
|
|
603
|
+
</span>
|
|
604
|
+
<button
|
|
605
|
+
type="button"
|
|
606
|
+
className="hover:text-foreground transition-colors"
|
|
607
|
+
onClick={() => setFiles([])}
|
|
358
608
|
>
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
className="
|
|
367
|
-
onClick={() => removeFile(index)}
|
|
609
|
+
全部清除
|
|
610
|
+
</button>
|
|
611
|
+
</div>
|
|
612
|
+
<div className="max-h-32 overflow-y-auto space-y-1.5 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--secondary))]/30 p-1.5">
|
|
613
|
+
{files.map((file, index) => (
|
|
614
|
+
<div
|
|
615
|
+
key={`${file.name}-${index}`}
|
|
616
|
+
className="flex items-center justify-between rounded-md bg-[hsl(var(--background))] px-2.5 py-1.5 text-sm shadow-sm"
|
|
368
617
|
>
|
|
369
|
-
<
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
618
|
+
<div className="flex items-center gap-2 min-w-0">
|
|
619
|
+
<FileText className="h-3.5 w-3.5 shrink-0 text-[hsl(var(--muted-foreground))]" />
|
|
620
|
+
<span className="truncate">{file.name}</span>
|
|
621
|
+
</div>
|
|
622
|
+
<Button
|
|
623
|
+
variant="ghost"
|
|
624
|
+
size="icon"
|
|
625
|
+
className="h-6 w-6 shrink-0"
|
|
626
|
+
onClick={() => removeFile(index)}
|
|
627
|
+
>
|
|
628
|
+
<X className="h-3 w-3" />
|
|
629
|
+
</Button>
|
|
630
|
+
</div>
|
|
631
|
+
))}
|
|
632
|
+
</div>
|
|
373
633
|
</div>
|
|
374
634
|
)}
|
|
375
635
|
</TabsContent>
|
|
376
636
|
|
|
377
637
|
{/* ---- Folder mode ---- */}
|
|
378
638
|
<TabsContent value="folder" className="space-y-3">
|
|
379
|
-
<div
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
639
|
+
<div
|
|
640
|
+
className={cn(
|
|
641
|
+
"relative flex h-36 flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed transition-colors",
|
|
642
|
+
isDragOver
|
|
643
|
+
? "border-[hsl(var(--primary))] bg-[hsl(var(--primary))]/5"
|
|
644
|
+
: "border-[hsl(var(--border))] bg-[hsl(var(--secondary))]/40 hover:border-[hsl(var(--primary))]/50 hover:bg-[hsl(var(--primary))]/[0.03]",
|
|
645
|
+
)}
|
|
646
|
+
onDragOver={handleDragOver}
|
|
647
|
+
onDragLeave={handleDragLeave}
|
|
648
|
+
onDrop={handleDropFolderMode}
|
|
649
|
+
>
|
|
650
|
+
<FolderOpen className="h-7 w-7 text-[hsl(var(--muted-foreground))]" />
|
|
651
|
+
<p className="text-sm text-[hsl(var(--muted-foreground))]">
|
|
652
|
+
拖拽文件夹到此处,或选择
|
|
383
653
|
</p>
|
|
384
654
|
<Button
|
|
385
655
|
type="button"
|
|
@@ -404,59 +674,68 @@ export function DocUploadDialog({
|
|
|
404
674
|
/>
|
|
405
675
|
</div>
|
|
406
676
|
|
|
407
|
-
<div className="
|
|
408
|
-
<div className="
|
|
409
|
-
|
|
410
|
-
<
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
677
|
+
<div className="rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--secondary))]/30 p-3 space-y-3">
|
|
678
|
+
<div className="text-xs font-medium text-foreground">过滤选项</div>
|
|
679
|
+
<div className="grid grid-cols-2 gap-3">
|
|
680
|
+
<div className="space-y-1">
|
|
681
|
+
<Label className="text-xs text-muted-foreground">包含后缀</Label>
|
|
682
|
+
<Input
|
|
683
|
+
placeholder=".md, .pdf, .txt"
|
|
684
|
+
value={includeInput}
|
|
685
|
+
onChange={(e) => setIncludeInput(e.target.value)}
|
|
686
|
+
className="h-8 bg-background"
|
|
687
|
+
/>
|
|
688
|
+
</div>
|
|
689
|
+
<div className="space-y-1">
|
|
690
|
+
<Label className="text-xs text-muted-foreground">排除后缀</Label>
|
|
691
|
+
<Input
|
|
692
|
+
placeholder=".log, .tmp"
|
|
693
|
+
value={excludeInput}
|
|
694
|
+
onChange={(e) => setExcludeInput(e.target.value)}
|
|
695
|
+
className="h-8 bg-background"
|
|
696
|
+
/>
|
|
697
|
+
</div>
|
|
415
698
|
</div>
|
|
416
|
-
<
|
|
417
|
-
<
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
value={excludeInput}
|
|
421
|
-
onChange={(e) => setExcludeInput(e.target.value)}
|
|
699
|
+
<label className="flex cursor-pointer items-center gap-2 text-sm text-foreground">
|
|
700
|
+
<Checkbox
|
|
701
|
+
checked={recursive}
|
|
702
|
+
onCheckedChange={(v) => setRecursive(v === true)}
|
|
422
703
|
/>
|
|
423
|
-
|
|
704
|
+
递归包含子目录
|
|
705
|
+
</label>
|
|
424
706
|
</div>
|
|
425
707
|
|
|
426
|
-
<label className="flex items-center gap-2 text-sm text-[hsl(var(--muted-foreground))]">
|
|
427
|
-
<Checkbox
|
|
428
|
-
checked={recursive}
|
|
429
|
-
onCheckedChange={(v) => setRecursive(v === true)}
|
|
430
|
-
/>
|
|
431
|
-
递归包含子目录
|
|
432
|
-
</label>
|
|
433
|
-
|
|
434
708
|
{folderRaw.length > 0 && (
|
|
435
|
-
<div className="
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
709
|
+
<div className="space-y-2">
|
|
710
|
+
<div className="flex items-center justify-between text-xs text-[hsl(var(--muted-foreground))]">
|
|
711
|
+
<span>
|
|
712
|
+
已选择{" "}
|
|
713
|
+
<span className="font-medium text-foreground">{folderRaw.length}</span>{" "}
|
|
714
|
+
个文件,过滤后将上传{" "}
|
|
715
|
+
<span className="font-medium text-[hsl(var(--primary))]">
|
|
716
|
+
{folderFiltered.length}
|
|
717
|
+
</span>{" "}
|
|
718
|
+
个
|
|
719
|
+
</span>
|
|
720
|
+
</div>
|
|
721
|
+
{folderFiltered.length > 0 && (
|
|
722
|
+
<div className="max-h-32 overflow-y-auto overflow-x-hidden rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--secondary))]/30 p-1.5 min-w-0 space-y-1">
|
|
723
|
+
{folderFiltered.slice(0, 50).map((file, index) => (
|
|
724
|
+
<div
|
|
725
|
+
key={`${file.webkitRelativePath || file.name}-${index}`}
|
|
726
|
+
className="flex items-center gap-2 rounded-md bg-[hsl(var(--background))] px-2.5 py-1 text-xs shadow-sm min-w-0"
|
|
727
|
+
>
|
|
728
|
+
<FileText className="h-3 w-3 shrink-0 text-[hsl(var(--muted-foreground))]" />
|
|
729
|
+
<span className="truncate">
|
|
730
|
+
{file.webkitRelativePath || file.name}
|
|
731
|
+
</span>
|
|
732
|
+
</div>
|
|
733
|
+
))}
|
|
734
|
+
{folderFiltered.length > 50 && (
|
|
735
|
+
<div className="text-xs text-[hsl(var(--muted-foreground))] pt-1 px-2">
|
|
736
|
+
... 还有 {folderFiltered.length - 50} 个文件未展示
|
|
737
|
+
</div>
|
|
738
|
+
)}
|
|
460
739
|
</div>
|
|
461
740
|
)}
|
|
462
741
|
</div>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import Link from "next/link";
|
|
4
4
|
import { useRouter } from "next/navigation";
|
|
5
|
-
import { MoreHorizontal, Trash2, FileText, Search, Settings } from "lucide-react";
|
|
5
|
+
import { BookOpenText, MoreHorizontal, Trash2, FileText, Search, Settings } from "lucide-react";
|
|
6
6
|
// Note: router is still used for dropdown menu navigation items
|
|
7
7
|
import { CardContent, CardInteractive } from "@/components/ui/card";
|
|
8
8
|
import {
|
|
@@ -44,10 +44,13 @@ export function KBCard({ knowledgeBase, onDelete }: KBCardProps) {
|
|
|
44
44
|
className="group relative flex h-full cursor-pointer flex-col"
|
|
45
45
|
>
|
|
46
46
|
<CardContent className="flex flex-col flex-1 p-5">
|
|
47
|
-
<div className="flex items-start justify-between">
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
<div className="flex items-start justify-between gap-3">
|
|
48
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
49
|
+
<BookOpenText className="h-4 w-4 shrink-0 text-primary" />
|
|
50
|
+
<h3 className="truncate text-base font-semibold text-foreground">
|
|
51
|
+
{knowledgeBaseName}
|
|
52
|
+
</h3>
|
|
53
|
+
</div>
|
|
51
54
|
|
|
52
55
|
<div
|
|
53
56
|
className="opacity-0 transition-opacity duration-150 delay-75 group-hover:opacity-100 focus-within:opacity-100"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { Badge } from "@/components/ui/badge";
|
|
4
4
|
import { Button } from "@/components/ui/button";
|
|
5
|
-
import { Trash2 } from "lucide-react";
|
|
5
|
+
import { BookOpenText, Trash2 } from "lucide-react";
|
|
6
6
|
import { RelativeTime } from "@/components/shared/relative-time";
|
|
7
7
|
import { SubspaceSwitcher } from "@/components/knowledge-base/subspace-switcher";
|
|
8
8
|
import type { KnowledgeBase } from "@/types/knowledge-base";
|
|
@@ -24,13 +24,21 @@ export function KBHeader({ knowledgeBase, onDelete }: KBHeaderProps) {
|
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
26
|
<div className="space-y-4">
|
|
27
|
-
<div className="flex items-start justify-between">
|
|
28
|
-
<div className="space-y-
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
<div className="flex items-start justify-between gap-4">
|
|
28
|
+
<div className="min-w-0 space-y-2">
|
|
29
|
+
<div className="flex items-center gap-3">
|
|
30
|
+
<div className="rounded-lg bg-[hsl(var(--primary)/0.1)] p-2 text-primary">
|
|
31
|
+
<BookOpenText className="h-5 w-5" />
|
|
32
|
+
</div>
|
|
33
|
+
<h1 className="truncate font-display text-[32px] font-semibold leading-tight tracking-tight text-foreground">
|
|
34
|
+
{knowledgeBaseName}
|
|
35
|
+
</h1>
|
|
36
|
+
<Badge variant="secondary" className="border-0 bg-[hsl(var(--primary-50))] text-primary">
|
|
37
|
+
Knowledge Base
|
|
38
|
+
</Badge>
|
|
39
|
+
</div>
|
|
32
40
|
{description && (
|
|
33
|
-
<p className="text-sm text-muted-foreground
|
|
41
|
+
<p className="max-w-3xl text-sm text-muted-foreground">
|
|
34
42
|
{description}
|
|
35
43
|
</p>
|
|
36
44
|
)}
|
|
@@ -61,11 +69,11 @@ export function KBHeader({ knowledgeBase, onDelete }: KBHeaderProps) {
|
|
|
61
69
|
</div>
|
|
62
70
|
)}
|
|
63
71
|
|
|
64
|
-
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
|
72
|
+
<div className="flex flex-wrap items-center gap-x-4 gap-y-2 text-xs text-muted-foreground">
|
|
65
73
|
{subspace && (
|
|
66
74
|
<>
|
|
67
|
-
<span className="inline-flex items-center gap-1">
|
|
68
|
-
<span className="h-1.5 w-1.5 rounded-full bg-
|
|
75
|
+
<span className="inline-flex items-center gap-1.5">
|
|
76
|
+
<span className="h-1.5 w-1.5 rounded-full bg-emerald-500 shadow-[0_0_0_3px_rgb(16,185,129,0.15)]" />
|
|
69
77
|
已开启子空间隔离
|
|
70
78
|
</span>
|
|
71
79
|
<SubspaceSwitcher />
|