- Refactored types in `Knowledge/types.ts` to introduce new interfaces for document handling. - Added `KnowledgeDocItem`, `KnowledgeDocsListResponse`, `KnowledgeDocsUploadInput`, `KnowledgeDocsUploadResponse`, and `KnowledgeDocsDeleteResponse` for better structure and clarity. - Updated `KnowledgeDocsApiClient` interface to include methods for listing, uploading, and deleting documents. fix: replace deprecated icons in AccountSettingsPanel and SettingMenu - Replaced `CheckCircleIcon` with `CheckCircle` from `lucide-react` in `AccountSettingsPanel.tsx`. - Updated `SettingMenu.tsx` to use `Settings` and `User` from `lucide-react` instead of custom icons. test: add tests for knowledge docs routes and KnowledgePage - Created `knowledge-docs-routes.test.ts` to test API routes for listing, uploading, and deleting knowledge documents. - Added `knowledge-page.test.tsx` to test the rendering and functionality of the KnowledgePage component, including document loading and deletion.
87 lines
2.6 KiB
TypeScript
87 lines
2.6 KiB
TypeScript
import type { HostApiContext } from '../context';
|
|
import type { NormalizedHostApiRequest } from '../route-utils';
|
|
import { fail, ok, parseJsonBody } from '../route-utils';
|
|
import {
|
|
deleteKnowledgeDoc,
|
|
listKnowledgeDocs,
|
|
uploadKnowledgeDoc,
|
|
isSafeKnowledgeDocName,
|
|
} from '../../utils/knowledge-docs';
|
|
|
|
function getDeleteTarget(request: NormalizedHostApiRequest): string | null {
|
|
const fromQuery = request.url.searchParams.get('name')?.trim() || '';
|
|
if (fromQuery) return fromQuery;
|
|
|
|
const body = request.body && typeof request.body === 'string'
|
|
? parseJsonBody<{ fileName?: string; name?: string }>(request.body)
|
|
: (request.body as { fileName?: string; name?: string } | null);
|
|
|
|
const candidate = String(body?.fileName || body?.name || '').trim();
|
|
return candidate || null;
|
|
}
|
|
|
|
export async function handleKnowledgeRoutes(
|
|
request: NormalizedHostApiRequest,
|
|
_ctx: HostApiContext,
|
|
) {
|
|
const { pathname, method } = request;
|
|
|
|
if (pathname === '/api/knowledge/docs' && method === 'GET') {
|
|
try {
|
|
return ok({
|
|
success: true,
|
|
files: await listKnowledgeDocs(),
|
|
});
|
|
} catch (error) {
|
|
return fail(500, error instanceof Error ? error.message : String(error));
|
|
}
|
|
}
|
|
|
|
if (pathname === '/api/knowledge/docs' && method === 'POST') {
|
|
try {
|
|
const body = parseJsonBody<{ base64?: string; fileName?: string }>(request.body);
|
|
const fileName = String(body?.fileName || '').trim();
|
|
const base64 = String(body?.base64 || '').trim();
|
|
|
|
if (!fileName) {
|
|
return fail(400, 'fileName is required');
|
|
}
|
|
if (!base64) {
|
|
return fail(400, 'base64 is required');
|
|
}
|
|
if (!isSafeKnowledgeDocName(fileName)) {
|
|
return fail(400, 'Invalid file name');
|
|
}
|
|
|
|
return ok({
|
|
success: true,
|
|
file: await uploadKnowledgeDoc({ fileName, base64 }),
|
|
});
|
|
} catch (error) {
|
|
return fail(500, error instanceof Error ? error.message : String(error));
|
|
}
|
|
}
|
|
|
|
if (method === 'DELETE' && (pathname === '/api/knowledge/docs' || pathname.startsWith('/api/knowledge/docs/'))) {
|
|
try {
|
|
const fileName = pathname.startsWith('/api/knowledge/docs/')
|
|
? decodeURIComponent(pathname.slice('/api/knowledge/docs/'.length))
|
|
: getDeleteTarget(request);
|
|
|
|
if (!fileName) {
|
|
return fail(400, 'fileName is required');
|
|
}
|
|
if (!isSafeKnowledgeDocName(fileName)) {
|
|
return fail(400, 'Invalid file name');
|
|
}
|
|
|
|
await deleteKnowledgeDoc(fileName);
|
|
return ok({ success: true });
|
|
} catch (error) {
|
|
return fail(500, error instanceof Error ? error.message : String(error));
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|