From 44d80f00a28a8d5722f34877969bffdf2cd145b5 Mon Sep 17 00:00:00 2001 From: Taksh Patel <84769392+TakshPatel5821@users.noreply.github.com> Date: Wed, 5 Aug 2026 16:45:10 -0500 Subject: [PATCH] Add AddOrRemoveAllButton to BundleSearchResult Adds a bulk add/remove button to bundle search results, matching the pattern used for individual vertex/edge results and the top-level "add all" button. Fixes #1221. --- .../SearchSidebar/BundleSearchResult.tsx | 87 ++++++++++++++++++- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/packages/graph-explorer/src/modules/SearchSidebar/BundleSearchResult.tsx b/packages/graph-explorer/src/modules/SearchSidebar/BundleSearchResult.tsx index 16a72415e..67d25ebc7 100644 --- a/packages/graph-explorer/src/modules/SearchSidebar/BundleSearchResult.tsx +++ b/packages/graph-explorer/src/modules/SearchSidebar/BundleSearchResult.tsx @@ -1,18 +1,29 @@ -import { BracketsIcon } from "lucide-react"; +import { useAtomValue } from "jotai"; +import { BracketsIcon, MinusCircleIcon, PlusCircleIcon } from "lucide-react"; import { + Button, + type ButtonProps, CollapsibleContent, SearchResultCollapsible, SearchResultCollapsibleTrigger, SearchResultSubtitle, SearchResultSymbol, SearchResultTitle, + Spinner, + stopPropagation, } from "@/components"; import { + getAllGraphableEntities, getDisplayValueForBundle, type PatchedResultBundle, } from "@/connector/entities"; -import { useTextTransform } from "@/hooks"; +import { edgesAtom, nodesAtom } from "@/core"; +import { + useAddToGraphMutation, + useRemoveFromGraph, + useTextTransform, +} from "@/hooks"; import { createEntityKey, EntitySearchResult } from "./EntitySearchResult"; @@ -33,10 +44,11 @@ export function BundleSearchResult({ -
+
{title && {title}} {subtitle}
+
    @@ -50,3 +62,72 @@ export function BundleSearchResult({ ); } + +/** + * Adds or removes all the graphable entities (vertices and edges) contained + * within a bundle, including nested bundles. + * + * - Hidden entirely when the bundle contains no graphable entities. + * - Shows an add button when any entity in the bundle is missing from the + * graph. Clicking it adds the remaining entities (already-added ones are + * left untouched). + * - Shows a remove button once every entity in the bundle has been added. + * Clicking it removes all of them from the graph. + */ +function AddOrRemoveAllButton({ + bundle, + ...props +}: ButtonProps & { bundle: PatchedResultBundle }) { + const graphableEntities = getAllGraphableEntities(bundle.values); + const vertexIds = graphableEntities.vertices.map(vertex => vertex.id); + const edgeIds = graphableEntities.edges.map(edge => edge.id); + + const nodesInGraph = useAtomValue(nodesAtom); + const edgesInGraph = useAtomValue(edgesAtom); + + const mutation = useAddToGraphMutation(); + const removeFromGraph = useRemoveFromGraph(); + + const hasGraphableEntities = vertexIds.length + edgeIds.length > 0; + if (!hasGraphableEntities) { + return null; + } + + const allAdded = + vertexIds.every(id => nodesInGraph.has(id)) && + edgeIds.every(id => edgesInGraph.has(id)); + + if (allAdded) { + const removeAllFromGraph = () => + removeFromGraph({ vertices: vertexIds, edges: edgeIds }); + + return ( + + ); + } + + const addAllToGraph = () => mutation.mutate(graphableEntities); + + return ( + + ); +}