Skip to content

Commit

Permalink
fix: Custom Tools & search tool dropdown fix (#1163)
Browse files Browse the repository at this point in the history
* fix: Custom Tools & search tool dropdown fix

* Update ToolCatalog.tsx

* fix: update expanded against searchFor
  • Loading branch information
ivyjeong13 authored Jan 9, 2025
1 parent 0e331e4 commit ec5b4eb
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 28 deletions.
76 changes: 62 additions & 14 deletions ui/admin/app/components/tools/ToolCatalog.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { AlertTriangleIcon, PlusIcon } from "lucide-react";
import { useMemo } from "react";
import { useMemo, useState } from "react";
import useSWR from "swr";

import { OAuthProvider } from "~/lib/model/oauthApps/oauth-helpers";
import { ToolReferenceService } from "~/lib/service/api/toolreferenceService";
import {
ToolCategory,
ToolReferenceService,
} from "~/lib/service/api/toolreferenceService";
import { cn } from "~/lib/utils";

import { ToolCatalogGroup } from "~/components/tools/ToolCatalogGroup";
Expand Down Expand Up @@ -43,6 +46,7 @@ export function ToolCatalog({
() => ToolReferenceService.getToolReferencesCategoryMap("tool"),
{ fallbackData: {} }
);
const [search, setSearch] = useState("");

const oauthApps = useOAuthAppList();
const configuredOauthApps = useMemo(() => {
Expand Down Expand Up @@ -79,43 +83,87 @@ export function ToolCatalog({

if (isLoading) return <LoadingSpinner />;

const results = search.length
? filterToolCatalogBySearch(sortedValidCategories)
: sortedValidCategories;
return (
<Command
className={cn(
"border w-full h-full",
className,
invert ? "flex-col-reverse" : "flex-col"
)}
filter={(value, search, keywords) => {
return value.toLowerCase().includes(search.toLowerCase()) ||
keywords?.some((keyword) =>
keyword.toLowerCase().includes(search.toLowerCase())
)
? 1
: 0;
}}
shouldFilter={false}
>
<CommandInput placeholder="Search tools..." />
<CommandInput
placeholder="Search tools..."
value={search}
onValueChange={setSearch}
/>
<div className="border-t shadow-2xl" />
<CommandList className={cn("py-2 max-h-full", classNames?.list)}>
<CommandEmpty>
<h1 className="flex items-center justify-center">
<small className="flex items-center justify-center">
<AlertTriangleIcon className="w-4 h-4 mr-2" />
No results found.
</h1>{" "}
</small>
</CommandEmpty>
{sortedValidCategories.map(([category, categoryTools]) => (
{results.map(([category, categoryTools]) => (
<ToolCatalogGroup
key={category}
category={category}
tools={categoryTools}
selectedTools={tools}
onUpdateTools={onUpdateTools}
expandFor={search}
/>
))}
</CommandList>
</Command>
);

function filterToolCatalogBySearch(
toolCategories: [string, ToolCategory][]
) {
return toolCategories.reduce<[string, ToolCategory][]>(
(acc, [category, categoryData]) => {
const matchesSearch = (str: string) =>
str.toLowerCase().includes(search.toLowerCase());

// Check if category name matches
if (matchesSearch(category)) {
acc.push([category, categoryData]);
return acc;
}

// Check if bundle tool matches
if (
categoryData.bundleTool &&
matchesSearch(categoryData.bundleTool.name)
) {
acc.push([category, categoryData]);
return acc;
}

// Filter tools and only include category if it has matching tools
const filteredTools = categoryData.tools.filter(
(tool) =>
matchesSearch(tool.name ?? "") ||
matchesSearch(tool.description ?? "")
);

if (filteredTools.length > 0) {
acc.push([
category,
{ ...categoryData, tools: filteredTools },
]);
}

return acc;
},
[]
);
}
}

export function ToolCatalogDialog(props: ToolCatalogProps) {
Expand Down
15 changes: 14 additions & 1 deletion ui/admin/app/components/tools/ToolCatalogGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";

import { ToolCategory } from "~/lib/service/api/toolreferenceService";
import { cn } from "~/lib/utils";
Expand All @@ -11,11 +11,13 @@ export function ToolCatalogGroup({
tools,
selectedTools,
onUpdateTools,
expandFor,
}: {
category: string;
tools: ToolCategory;
selectedTools: string[];
onUpdateTools: (tools: string[]) => void;
expandFor?: string;
}) {
const handleSelect = (toolId: string) => {
if (selectedTools.includes(toolId)) {
Expand Down Expand Up @@ -52,6 +54,17 @@ export function ToolCatalogGroup({
return selectedTools.some((tool) => set.has(tool));
});

useEffect(() => {
const containsMatchingTool =
expandFor?.length &&
tools.tools.some(
(tool) =>
tool.description?.toLowerCase().includes(expandFor) ||
tool.name?.toLowerCase().includes(expandFor)
);
setExpanded(containsMatchingTool || false);
}, [expandFor, tools]);

return (
<CommandGroup
key={category}
Expand Down
5 changes: 0 additions & 5 deletions ui/admin/app/components/tools/ToolItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ export function ToolItem({
return (
<CommandItem
className={cn("cursor-pointer", className)}
keywords={[
tool.description || "",
tool.name || "",
tool.metadata?.category || "",
]}
onSelect={onSelect}
disabled={isBundleSelected}
>
Expand Down
12 changes: 6 additions & 6 deletions ui/admin/app/components/tools/toolGrid/ToolGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { useCallback, useEffect, useState } from "react";

import { ToolReference } from "~/lib/model/toolReferences";
import {
CustomToolsToolCategory,
ToolCategoryMap,
YourToolsToolCategory,
} from "~/lib/service/api/toolreferenceService";

import { CategoryHeader } from "~/components/tools/toolGrid/CategoryHeader";
Expand Down Expand Up @@ -61,17 +61,17 @@ export function ToolGrid({ toolCategories, filter, onDelete }: ToolGridProps) {
return <p>No tools found...</p>;
}

const yourToolsCategory = filteredResults[YourToolsToolCategory];
const customToolsCategory = filteredResults[CustomToolsToolCategory];
return (
<div className="space-y-8 pb-16">
{yourToolsCategory &&
{customToolsCategory &&
renderToolCategory(
YourToolsToolCategory,
yourToolsCategory.tools
CustomToolsToolCategory,
customToolsCategory.tools
)}
{Object.entries(filteredResults).map(
([category, { tools, bundleTool }]) => {
if (category === YourToolsToolCategory) return null;
if (category === CustomToolsToolCategory) return null;
return renderToolCategory(
category,
tools,
Expand Down
4 changes: 2 additions & 2 deletions ui/admin/app/lib/service/api/toolreferenceService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export type ToolCategory = {
tools: ToolReference[];
};
export const UncategorizedToolCategory = "Uncategorized";
export const YourToolsToolCategory = "Your Tools";
export const CustomToolsToolCategory = "Custom Tools";
export type ToolCategoryMap = Record<string, ToolCategory>;
async function getToolReferencesCategoryMap(type?: ToolReferenceType) {
const res = await request<{ items: ToolReference[] }>({
Expand All @@ -43,7 +43,7 @@ async function getToolReferencesCategoryMap(type?: ToolReferenceType) {
}

const category = !toolReference.builtin
? YourToolsToolCategory
? CustomToolsToolCategory
: toolReference.metadata?.category || UncategorizedToolCategory;

if (!result[category]) {
Expand Down

0 comments on commit ec5b4eb

Please sign in to comment.