fix: search filter for agent component (#11939)

* Fix search filter for agent component

* refactor and add tests
This commit is contained in:
Jordan Frazier
2026-02-27 12:30:39 -05:00
committed by GitHub
parent ae00c03154
commit 37a31a0bf9
3 changed files with 260 additions and 14 deletions

View File

@ -0,0 +1,201 @@
import {
computeSectionVisibility,
type SectionVisibilityInput,
} from "../compute-section-visibility";
describe("computeSectionVisibility", () => {
const baseInput: SectionVisibilityInput = {
enableNewSidebar: true,
activeSection: "components",
hasSearchInput: false,
hasCoreComponents: true,
hasMcpComponents: false,
hasBundleItems: false,
};
describe("Components tab (no search)", () => {
it("should show components when on components tab with core components", () => {
const result = computeSectionVisibility(baseInput);
expect(result.showComponents).toBe(true);
expect(result.showMcp).toBe(false);
expect(result.showBundles).toBe(false);
expect(result.isMcpTabActive).toBe(false);
});
it("should not show components when on components tab without core components", () => {
const result = computeSectionVisibility({
...baseInput,
hasCoreComponents: false,
});
expect(result.showComponents).toBe(false);
});
});
describe("MCP tab (no search)", () => {
it("should show MCP and hide components when on MCP tab", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "mcp",
});
expect(result.showMcp).toBe(true);
expect(result.isMcpTabActive).toBe(true);
});
it("should not show bundles when on MCP tab without search", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "mcp",
hasBundleItems: true,
});
expect(result.showBundles).toBe(false);
});
});
describe("Bundles tab (no search)", () => {
it("should show bundles when on bundles tab with bundle items", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "bundles",
hasBundleItems: true,
});
expect(result.showBundles).toBe(true);
expect(result.showComponents).toBe(false);
expect(result.showMcp).toBe(false);
});
});
describe("Search active", () => {
it("should show components during search when core components match", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "search",
hasSearchInput: true,
hasCoreComponents: true,
});
expect(result.showComponents).toBe(true);
expect(result.isMcpTabActive).toBe(false);
});
it("should show MCP during search when MCP components match", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "search",
hasSearchInput: true,
hasMcpComponents: true,
});
expect(result.showMcp).toBe(true);
expect(result.isMcpTabActive).toBe(false);
});
it("should show bundles during search when bundle items match", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "search",
hasSearchInput: true,
hasBundleItems: true,
});
expect(result.showBundles).toBe(true);
});
// Regression: searching for "Agent" with MCP servers configured should
// show both core components AND MCP results, not hide core components.
// See: https://github.com/langflow-ai/langflow/pull/11513
it("should show BOTH components and MCP when search matches both", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "search",
hasSearchInput: true,
hasCoreComponents: true,
hasMcpComponents: true,
});
expect(result.showComponents).toBe(true);
expect(result.showMcp).toBe(true);
expect(result.isMcpTabActive).toBe(false);
});
it("should show all sections when search matches everything", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "search",
hasSearchInput: true,
hasCoreComponents: true,
hasMcpComponents: true,
hasBundleItems: true,
});
expect(result.showComponents).toBe(true);
expect(result.showMcp).toBe(true);
expect(result.showBundles).toBe(true);
expect(result.isMcpTabActive).toBe(false);
});
it("should not show components during search when no core components match", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "search",
hasSearchInput: true,
hasCoreComponents: false,
hasMcpComponents: true,
});
expect(result.showComponents).toBe(false);
expect(result.showMcp).toBe(true);
});
});
describe("isMcpTabActive", () => {
it("should be true only when on MCP tab with new sidebar enabled", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "mcp",
});
expect(result.isMcpTabActive).toBe(true);
});
it("should be false when searching even if MCP has results", () => {
const result = computeSectionVisibility({
...baseInput,
activeSection: "search",
hasSearchInput: true,
hasMcpComponents: true,
});
expect(result.isMcpTabActive).toBe(false);
});
it("should be false when new sidebar is disabled", () => {
const result = computeSectionVisibility({
...baseInput,
enableNewSidebar: false,
activeSection: "mcp",
});
expect(result.isMcpTabActive).toBe(false);
});
});
describe("Legacy sidebar (ENABLE_NEW_SIDEBAR=false)", () => {
it("should always show components and bundles", () => {
const result = computeSectionVisibility({
...baseInput,
enableNewSidebar: false,
hasCoreComponents: false,
hasBundleItems: false,
});
expect(result.showComponents).toBe(true);
expect(result.showBundles).toBe(true);
expect(result.showMcp).toBe(false);
});
});
});

View File

@ -0,0 +1,48 @@
export interface SectionVisibilityInput {
enableNewSidebar: boolean;
activeSection: string;
hasSearchInput: boolean;
hasCoreComponents: boolean;
hasMcpComponents: boolean;
hasBundleItems: boolean;
}
export interface SectionVisibilityOutput {
showComponents: boolean;
showBundles: boolean;
showMcp: boolean;
isMcpTabActive: boolean;
}
export function computeSectionVisibility(
input: SectionVisibilityInput,
): SectionVisibilityOutput {
const {
enableNewSidebar,
activeSection,
hasSearchInput,
hasCoreComponents,
hasMcpComponents,
hasBundleItems,
} = input;
const showComponents =
(enableNewSidebar &&
hasCoreComponents &&
(activeSection === "components" || activeSection === "search")) ||
(hasSearchInput && hasCoreComponents && enableNewSidebar) ||
!enableNewSidebar;
const showBundles =
(hasBundleItems && enableNewSidebar && activeSection === "bundles") ||
(hasSearchInput && hasBundleItems && enableNewSidebar) ||
!enableNewSidebar;
const showMcp =
(enableNewSidebar && activeSection === "mcp") ||
(hasSearchInput && hasMcpComponents && enableNewSidebar);
const isMcpTabActive = enableNewSidebar && activeSection === "mcp";
return { showComponents, showBundles, showMcp, isMcpTabActive };
}

View File

@ -51,6 +51,7 @@ import { applyComponentFilter } from "./helpers/apply-component-filter";
import { applyEdgeFilter } from "./helpers/apply-edge-filter";
import { applyLegacyFilter } from "./helpers/apply-legacy-filter";
import { combinedResultsFn } from "./helpers/combined-results";
import { computeSectionVisibility } from "./helpers/compute-section-visibility";
import { filteredDataFn } from "./helpers/filtered-data";
import { normalizeString } from "./helpers/normalize-string";
import sensitiveSort from "./helpers/sensitive-sort";
@ -582,19 +583,15 @@ export function FlowSidebarComponent({ isLoading }: FlowSidebarComponentProps) {
filterType !== undefined ||
getFilterComponent !== "";
const showComponents =
(ENABLE_NEW_SIDEBAR &&
hasCoreComponents &&
(activeSection === "components" || activeSection === "search")) ||
(hasSearchInput && hasCoreComponents && ENABLE_NEW_SIDEBAR) ||
!ENABLE_NEW_SIDEBAR;
const showBundles =
(hasBundleItems && ENABLE_NEW_SIDEBAR && activeSection === "bundles") ||
(hasSearchInput && hasBundleItems && ENABLE_NEW_SIDEBAR) ||
!ENABLE_NEW_SIDEBAR;
const showMcp =
(ENABLE_NEW_SIDEBAR && activeSection === "mcp") ||
(hasSearchInput && hasMcpComponents && ENABLE_NEW_SIDEBAR);
const { showComponents, showBundles, showMcp, isMcpTabActive } =
computeSectionVisibility({
enableNewSidebar: ENABLE_NEW_SIDEBAR,
activeSection,
hasSearchInput,
hasCoreComponents,
hasMcpComponents,
hasBundleItems,
});
const [category, component] = getFilterComponent?.split(".") ?? ["", ""];
@ -668,7 +665,7 @@ export function FlowSidebarComponent({ isLoading }: FlowSidebarComponentProps) {
<>
{hasResults ? (
<>
{showComponents && !showMcp && (
{showComponents && !isMcpTabActive && (
<CategoryGroup
dataFilter={dataFilter}
sortedCategories={sortedCategories}