diff --git a/studio/frontend/src/__tests__/knowledge-bases-tab.test.tsx b/studio/frontend/src/__tests__/knowledge-bases-tab.test.tsx index eb7c2f4de0..8a468bfd52 100644 --- a/studio/frontend/src/__tests__/knowledge-bases-tab.test.tsx +++ b/studio/frontend/src/__tests__/knowledge-bases-tab.test.tsx @@ -25,6 +25,11 @@ vi.mock("@/features/rag/components/kb-list", () => ({ KBList: () => React.createElement("div", { "data-testid": "kb-list" }), })); +vi.mock("@/features/rag/components/kb-create-dialog", () => ({ + KBCreateDialog: () => + React.createElement("div", { "data-testid": "kb-create-dialog" }), +})); + vi.mock("@/features/rag/components/kb-detail-panel", () => ({ KBDetailPanel: () => React.createElement("div", { "data-testid": "kb-detail-panel" }), diff --git a/studio/frontend/src/features/rag/components/kb-list.tsx b/studio/frontend/src/features/rag/components/kb-list.tsx index 684d747558..d53f87248e 100644 --- a/studio/frontend/src/features/rag/components/kb-list.tsx +++ b/studio/frontend/src/features/rag/components/kb-list.tsx @@ -4,12 +4,10 @@ import { Button } from "@/components/ui/button"; import { ScrollArea } from "@/components/ui/scroll-area"; import { cn } from "@/lib/utils"; -import { Add01Icon, Delete02Icon } from "@hugeicons/core-free-icons"; +import { Delete02Icon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; -import { useState } from "react"; import type { KnowledgeBase } from "../api/rag-api"; import { useKnowledgeBases } from "../hooks/use-knowledge-bases"; -import { KBCreateDialog } from "./kb-create-dialog"; export function KBList({ selectedId, @@ -19,25 +17,14 @@ export function KBList({ onSelect: (kb: KnowledgeBase | null) => void; }) { const { knowledgeBases, loading, error, deleteKB } = useKnowledgeBases(); - const [createOpen, setCreateOpen] = useState(false); return ( -
-
-

Knowledge bases

- -
- +
{error ?
{error}
: null} - + {/* Capped, content-sized list: stays short when empty (no oddly-tall + box) and scrolls internally once there are many bases. */} +
{knowledgeBases.length === 0 && !loading ? (
@@ -108,12 +95,6 @@ export function KBList({ })}
- - onSelect(kb)} - />
); } diff --git a/studio/frontend/src/features/settings/tabs/knowledge-bases-tab.tsx b/studio/frontend/src/features/settings/tabs/knowledge-bases-tab.tsx index d9c901b8d3..28a744dcbf 100644 --- a/studio/frontend/src/features/settings/tabs/knowledge-bases-tab.tsx +++ b/studio/frontend/src/features/settings/tabs/knowledge-bases-tab.tsx @@ -1,8 +1,10 @@ // SPDX-License-Identifier: AGPL-3.0-only // Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 +import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; import type { KnowledgeBase } from "@/features/rag/api/rag-api"; +import { KBCreateDialog } from "@/features/rag/components/kb-create-dialog"; import { KBDetailPanel } from "@/features/rag/components/kb-detail-panel"; import { KBList } from "@/features/rag/components/kb-list"; import { PreviewPanel } from "@/features/rag/components/preview-panel"; @@ -11,10 +13,17 @@ import { ThreadIndexList } from "@/features/rag/components/thread-index-list"; import { useResizablePanelWidth } from "@/features/rag/hooks/use-resizable-width"; import { usePreviewStore } from "@/features/rag/stores/preview-store"; import { cn } from "@/lib/utils"; +import { Add01Icon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; import { type CSSProperties, useState } from "react"; +// Height of the master-detail workspace shown once a knowledge base is +// selected. Only rendered then, so the section stays compact when empty. +const KB_WORKSPACE_HEIGHT = "h-[360px]"; + export function KnowledgeBasesTab() { const [selected, setSelected] = useState(null); + const [createOpen, setCreateOpen] = useState(false); const previewTarget = usePreviewStore((s) => s.target); const previewStatus = usePreviewStore((s) => s.status); const previewActive = @@ -46,76 +55,99 @@ export function KnowledgeBasesTab() {

- {/* Fixed-height workspace so the KB list / detail / preview have a - bounded area to scroll within; the rest of the tab flows and the - settings dialog body scrolls. A flex-1 fill here collapsed under the - tall thread-index + defaults sections below, overlapping them. */} -
-
- + +
+
+

Knowledge bases

+
- -
- {selected ? ( - - ) : ( -
- Select a knowledge base, or create a new one to get started. -
+

+ Select a knowledge base to manage its documents, or create a new one + to get started. +

+
- {previewActive ? ( - <> - -
- -
- - ) : null} + > +
+ setSelected(kb)} + />
+