mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-24 19:56:45 +08:00
fix: search filter for agent component (#11939)
* Fix search filter for agent component * refactor and add tests
This commit is contained in:
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -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 };
|
||||
}
|
||||
@ -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}
|
||||
|
||||
Reference in New Issue
Block a user