diff --git a/ui/admin/app/components/tools/ToolCatalog.tsx b/ui/admin/app/components/tools/ToolCatalog.tsx index 60eeecab2..b85b29ae2 100644 --- a/ui/admin/app/components/tools/ToolCatalog.tsx +++ b/ui/admin/app/components/tools/ToolCatalog.tsx @@ -1,19 +1,15 @@ import { AlertTriangleIcon, PlusIcon } from "lucide-react"; -import { useCallback } from "react"; import useSWR from "swr"; -import { ToolReference } from "~/lib/model/toolReferences"; import { ToolReferenceService } from "~/lib/service/api/toolreferenceService"; import { cn } from "~/lib/utils"; -import { ToolCategoryHeader } from "~/components/tools/ToolCategoryHeader"; -import { ToolItem } from "~/components/tools/ToolItem"; +import { ToolCatalogGroup } from "~/components/tools/ToolCatalogGroup"; import { LoadingSpinner } from "~/components/ui/LoadingSpinner"; import { Button } from "~/components/ui/button"; import { Command, CommandEmpty, - CommandGroup, CommandInput, CommandList, } from "~/components/ui/command"; @@ -45,34 +41,6 @@ export function ToolCatalog({ { fallbackData: {} } ); - const handleSelect = useCallback( - (toolId: string) => { - if (!tools.includes(toolId)) { - onUpdateTools([...tools, toolId]); - } - }, - [tools, onUpdateTools] - ); - - const handleSelectBundle = useCallback( - (bundleToolId: string, categoryTools: ToolReference[]) => { - if (tools.includes(bundleToolId)) { - onUpdateTools(tools.filter((tool) => tool !== bundleToolId)); - return; - } - - const toolsToRemove = new Set(categoryTools.map((tool) => tool.id)); - - const newTools = [ - ...tools.filter((tool) => !toolsToRemove.has(tool)), - bundleToolId, - ]; - - onUpdateTools(newTools); - }, - [tools, onUpdateTools] - ); - if (isLoading) return ; return ( @@ -98,39 +66,17 @@ export function ToolCatalog({

No results found. -

+ {" "} {Object.entries(toolCategories).map( ([category, categoryTools]) => ( - - } - > - {categoryTools.tools.map((categoryTool) => ( - - handleSelect(categoryTool.id) - } - /> - ))} - + category={category} + tools={categoryTools} + selectedTools={tools} + onUpdateTools={onUpdateTools} + /> ) )} diff --git a/ui/admin/app/components/tools/ToolCatalogGroup.tsx b/ui/admin/app/components/tools/ToolCatalogGroup.tsx new file mode 100644 index 000000000..28676cba6 --- /dev/null +++ b/ui/admin/app/components/tools/ToolCatalogGroup.tsx @@ -0,0 +1,91 @@ +import { useState } from "react"; + +import { ToolCategory } from "~/lib/service/api/toolreferenceService"; +import { cn } from "~/lib/utils"; + +import { ToolItem } from "~/components/tools/ToolItem"; +import { CommandGroup } from "~/components/ui/command"; + +export function ToolCatalogGroup({ + category, + tools, + selectedTools, + onUpdateTools, +}: { + category: string; + tools: ToolCategory; + selectedTools: string[]; + onUpdateTools: (tools: string[]) => void; +}) { + const handleSelect = (toolId: string) => { + if (selectedTools.includes(toolId)) { + onUpdateTools(selectedTools.filter((tool) => tool !== toolId)); + } + + const newTools = selectedTools + .filter((tool) => tool !== tools.bundleTool?.id) + .concat(toolId); + + onUpdateTools(newTools); + }; + + const handleSelectBundle = (bundleToolId: string) => { + if (selectedTools.includes(bundleToolId)) { + onUpdateTools( + selectedTools.filter((tool) => tool !== bundleToolId) + ); + return; + } + + const toolsToRemove = new Set(tools.tools.map((tool) => tool.id)); + + const newTools = [ + ...selectedTools.filter((tool) => !toolsToRemove.has(tool)), + bundleToolId, + ]; + + onUpdateTools(newTools); + }; + + const [expanded, setExpanded] = useState(() => { + const set = new Set(tools.tools.map((tool) => tool.id)); + return selectedTools.some((tool) => set.has(tool)); + }); + + return ( + + {tools.bundleTool && ( + handleSelectBundle(tools.bundleTool!.id)} + expanded={expanded} + onExpand={setExpanded} + isBundle + /> + )} + + {(expanded || !tools.bundleTool) && + tools.tools.map((categoryTool) => ( + handleSelect(categoryTool.id)} + /> + ))} + + ); +} diff --git a/ui/admin/app/components/tools/ToolCategoryHeader.tsx b/ui/admin/app/components/tools/ToolCategoryHeader.tsx deleted file mode 100644 index f6b97a4d2..000000000 --- a/ui/admin/app/components/tools/ToolCategoryHeader.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { CheckIcon } from "lucide-react"; - -import { ToolReference } from "~/lib/model/toolReferences"; -import { ToolCategory } from "~/lib/service/api/toolreferenceService"; - -import { ToolTooltip } from "~/components/tools/ToolTooltip"; -import { Switch } from "~/components/ui/switch"; - -type ToolCategoryHeaderProps = { - category: string; - categoryTools: ToolCategory; - tools: string[]; - onSelectBundle: ( - bundleToolId: string, - categoryTools: ToolReference[] - ) => void; -}; - -export function ToolCategoryHeader({ - category, - categoryTools, - tools, - onSelectBundle, -}: ToolCategoryHeaderProps) { - return ( -
- {!categoryTools.bundleTool ? ( - {category} - ) : ( - <> - - {category} - {tools.includes(categoryTools.bundleTool!.id) && ( - - )} - - -
- - onSelectBundle( - categoryTools.bundleTool!.id, - categoryTools.tools - ) - } - /> -
-
- - )} -
- ); -} diff --git a/ui/admin/app/components/tools/ToolItem.tsx b/ui/admin/app/components/tools/ToolItem.tsx index 23572c0e7..17d5af904 100644 --- a/ui/admin/app/components/tools/ToolItem.tsx +++ b/ui/admin/app/components/tools/ToolItem.tsx @@ -1,7 +1,10 @@ import { ToolReference } from "~/lib/model/toolReferences"; +import { cn } from "~/lib/utils"; import { ToolIcon } from "~/components/tools/ToolIcon"; import { ToolTooltip } from "~/components/tools/ToolTooltip"; +import { Button } from "~/components/ui/button"; +import { Checkbox } from "~/components/ui/checkbox"; import { CommandItem } from "~/components/ui/command"; type ToolItemProps = { @@ -9,6 +12,10 @@ type ToolItemProps = { isSelected: boolean; isBundleSelected: boolean; onSelect: () => void; + expanded?: boolean; + onExpand?: (expanded: boolean) => void; + className?: string; + isBundle?: boolean; }; export function ToolItem({ @@ -16,29 +23,63 @@ export function ToolItem({ isSelected, isBundleSelected, onSelect, + expanded, + onExpand, + className, + isBundle, }: ToolItemProps) { return ( - - - {tool.name} - +
+ + + + + + {tool.name} + + + + {isBundle && ( + + )} +
); diff --git a/ui/admin/app/components/ui/button.tsx b/ui/admin/app/components/ui/button.tsx index bd455b296..868574e1d 100644 --- a/ui/admin/app/components/ui/button.tsx +++ b/ui/admin/app/components/ui/button.tsx @@ -26,6 +26,8 @@ const buttonVariants = cva( }, size: { none: "", + link: "p-0", + "link-sm": "p-0 text-xs", default: "h-9 px-4 py-2", badge: "text-xs py-0.5 px-2", sm: "h-8 px-3 text-xs", diff --git a/ui/admin/app/lib/service/api/toolreferenceService.ts b/ui/admin/app/lib/service/api/toolreferenceService.ts index 5605786ac..590711cff 100644 --- a/ui/admin/app/lib/service/api/toolreferenceService.ts +++ b/ui/admin/app/lib/service/api/toolreferenceService.ts @@ -47,7 +47,7 @@ async function getToolReferencesCategoryMap(type?: ToolReferenceType) { }; } - if (toolReference.metadata?.bundle) { + if (toolReference.metadata?.bundle === "true") { result[category].bundleTool = toolReference; } else { result[category].tools.push(toolReference);