From a2310aa02c0e1cb85432a3202307a1ae1c559454 Mon Sep 17 00:00:00 2001 From: Mohammed Razak Date: Sat, 20 Sep 2025 15:48:41 +0530 Subject: [PATCH 1/3] tool filtering - disable all - http method type --- .../src/pages/toolsets/ToolSelect.tsx | 84 ++++++++++++++----- 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/client/dashboard/src/pages/toolsets/ToolSelect.tsx b/client/dashboard/src/pages/toolsets/ToolSelect.tsx index a193113b5..cfc349d96 100644 --- a/client/dashboard/src/pages/toolsets/ToolSelect.tsx +++ b/client/dashboard/src/pages/toolsets/ToolSelect.tsx @@ -42,6 +42,8 @@ type ToggleableToolGroup = { key: string; defaultExpanded: boolean; toggleAll: () => void; + toggleEnableAll: () => void; + toggleDisableAll: () => void; tools: ToggleableTool[]; }; @@ -94,25 +96,33 @@ const groupColumnsToggleable: Column[] = [ width: "0.35fr", render: (row) => { const allEnabled = row.tools.every((t) => t.enabled); + const noneEnabled = row.tools.every((t) => !t.enabled); + + const onEnableAll = (e: React.MouseEvent) => { + e.stopPropagation(); + row.toggleEnableAll(); + }; + const onDisableAll = (e: React.MouseEvent) => { + e.stopPropagation(); + row.toggleDisableAll(); + }; return ( - + + Enable All + + + + ); }, }, @@ -194,6 +204,7 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { const [selectedTools, setSelectedTools] = useState([]); const [search, setSearch] = useState(""); const [tagFilters, setTagFilters] = useState([]); + const [methodFilters, setMethodFilters] = useState([]); const updateToolsetMutation = useUpdateToolsetMutation({ onSuccess: () => { @@ -252,6 +263,13 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { const groupedTools = useGroupedHttpTools(tools?.tools ?? []); + // build method filter options from available tools + const methodOptions = useMemo(() => { + const methods = new Set(); + groupedTools.forEach((g) => g.tools.forEach((t) => methods.add((t.httpMethod || "OTHER").toUpperCase()))); + return Array.from(methods).sort().map((m) => ({ label: m, value: m })); + }, [groupedTools]); + const tagFilterOptions = groupedTools.flatMap((group) => group.tools.flatMap((t) => t.tags.map((tag) => `${group.key}/${tag}`)) ); @@ -269,6 +287,17 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { /> ); + // method filter MultiSelect + const methodsFilter = ( + setMethodFilters(vals.map((v) => v.toUpperCase()))} + placeholder="Filter by method" + className="w-fit capitalize" + /> + ); + + // Compose filtering: tag, search, method, enabled/disabled const filteredGroups = useMemo(() => { const normalize = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, ""); const filteredGroups = groupedTools.map((g) => ({ @@ -280,6 +309,12 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { ) { return false; } + + if (methodFilters.length > 0) { + const method = (t.httpMethod || "").toUpperCase(); + if (!methodFilters.includes(method)) return false; + } + const tags = t.tags.join(","); return ( normalize(t.name).includes(normalize(search)) || @@ -287,15 +322,16 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { ); }), })); + return filteredGroups.filter((g) => g.tools.length > 0); - }, [tools, search, tagFilters]); + }, [tools, search, tagFilters, methodFilters, selectedTools]); const toolGroups = useMemo(() => { - const toggleAll = (tools: ToggleableTool[]) => { - setToolsEnabled( - tools.map((t) => t.canonicalName), - tools.some((t) => !t.enabled) // Disable iff all are already enabled - ); + const enableAll = (tools: ToggleableTool[]) => { + setToolsEnabled(tools.map((t) => t.canonicalName), true); + }; + const disableAll = (tools: ToggleableTool[]) => { + setToolsEnabled(tools.map((t) => t.canonicalName), false); }; const toolGroups = filteredGroups.map((group) => ({ @@ -310,7 +346,8 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { const toolGroupsFinal = toolGroups.map((group) => ({ ...group, - toggleAll: () => toggleAll(group.tools), + toggleEnableAll: () => enableAll(group.tools), + toggleDisableAll: () => disableAll(group.tools), defaultExpanded: toolGroups.length < 3 || group.tools.some((tool) => tool.enabled), })); @@ -338,6 +375,7 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { <> {tagsFilter} + {methodsFilter} Date: Sat, 20 Sep 2025 19:51:21 +0530 Subject: [PATCH 2/3] httpMethod none fallback -> other --- client/dashboard/src/pages/toolsets/ToolSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/dashboard/src/pages/toolsets/ToolSelect.tsx b/client/dashboard/src/pages/toolsets/ToolSelect.tsx index cfc349d96..d10b6070b 100644 --- a/client/dashboard/src/pages/toolsets/ToolSelect.tsx +++ b/client/dashboard/src/pages/toolsets/ToolSelect.tsx @@ -311,7 +311,7 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { } if (methodFilters.length > 0) { - const method = (t.httpMethod || "").toUpperCase(); + const method = (t.httpMethod || "OTHER").toUpperCase(); if (!methodFilters.includes(method)) return false; } From 98d239d62e0e4003a8bd813042e4b94f451ecb6c Mon Sep 17 00:00:00 2001 From: Mohammed Razak Date: Tue, 23 Sep 2025 07:15:54 +0530 Subject: [PATCH 3/3] enabled/disabled filter --- .../src/pages/toolsets/ToolSelect.tsx | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/client/dashboard/src/pages/toolsets/ToolSelect.tsx b/client/dashboard/src/pages/toolsets/ToolSelect.tsx index d10b6070b..bc72af2c7 100644 --- a/client/dashboard/src/pages/toolsets/ToolSelect.tsx +++ b/client/dashboard/src/pages/toolsets/ToolSelect.tsx @@ -205,6 +205,7 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { const [search, setSearch] = useState(""); const [tagFilters, setTagFilters] = useState([]); const [methodFilters, setMethodFilters] = useState([]); + const [enabledFilters, setEnabledFilters] = useState([]); const updateToolsetMutation = useUpdateToolsetMutation({ onSuccess: () => { @@ -263,12 +264,6 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { const groupedTools = useGroupedHttpTools(tools?.tools ?? []); - // build method filter options from available tools - const methodOptions = useMemo(() => { - const methods = new Set(); - groupedTools.forEach((g) => g.tools.forEach((t) => methods.add((t.httpMethod || "OTHER").toUpperCase()))); - return Array.from(methods).sort().map((m) => ({ label: m, value: m })); - }, [groupedTools]); const tagFilterOptions = groupedTools.flatMap((group) => group.tools.flatMap((t) => t.tags.map((tag) => `${group.key}/${tag}`)) @@ -287,7 +282,12 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { /> ); - // method filter MultiSelect + const methodOptions = useMemo(() => { + const methods = new Set(); + groupedTools.forEach((g) => g.tools.forEach((t) => methods.add((t.httpMethod || "OTHER").toUpperCase()))); + return Array.from(methods).sort().map((m) => ({ label: m, value: m })); + }, [groupedTools]); + const methodsFilter = ( ); + const enabledFilterItems = [ + { label: "Enabled", value: "ENABLED" }, + { label: "Disabled", value: "DISABLED" }, + ]; + + const enabledFilter = ( + + ) + // Compose filtering: tag, search, method, enabled/disabled const filteredGroups = useMemo(() => { const normalize = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, ""); @@ -310,11 +324,23 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { return false; } + // method filter if (methodFilters.length > 0) { const method = (t.httpMethod || "OTHER").toUpperCase(); if (!methodFilters.includes(method)) return false; } + // enabled/disabled filter + const isEnabled = selectedTools.includes(t.canonicalName); + const wantsEnabled = enabledFilters.includes("ENABLED"); + const wantsDisabled = enabledFilters.includes("DISABLED"); + + if (wantsEnabled && !wantsDisabled) { + if (!isEnabled) return false; + } else if (!wantsEnabled && wantsDisabled) { + if (isEnabled) return false; + } + const tags = t.tags.join(","); return ( normalize(t.name).includes(normalize(search)) || @@ -324,7 +350,7 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { })); return filteredGroups.filter((g) => g.tools.length > 0); - }, [tools, search, tagFilters, methodFilters, selectedTools]); + }, [tools, search, tagFilters, methodFilters, selectedTools, enabledFilters]); const toolGroups = useMemo(() => { const enableAll = (tools: ToggleableTool[]) => { @@ -376,6 +402,7 @@ export function ToolSelector({ toolsetSlug }: { toolsetSlug: string }) { {tagsFilter} {methodsFilter} + {enabledFilter}