diff --git a/src/components/shared/Dialogs/ComponentDetailsDialog.tsx b/src/components/shared/Dialogs/ComponentDetailsDialog.tsx
index a0588bad19..84ffb422f2 100644
--- a/src/components/shared/Dialogs/ComponentDetailsDialog.tsx
+++ b/src/components/shared/Dialogs/ComponentDetailsDialog.tsx
@@ -22,7 +22,6 @@ import { ComponentFavoriteToggle } from "../FavoriteComponentToggle";
import { InfoBox } from "../InfoBox";
import { PublishComponent } from "../ManageComponent/PublishComponent";
import { PublishedComponentDetails } from "../ManageComponent/PublishedComponentDetails";
-import { useFlagValue } from "../Settings/useFlags";
import { withSuspenseWrapper } from "../SuspenseWrapper";
import { TaskDetails, TaskImplementation, TaskIO } from "../TaskDetails";
import TaskActions from "../TaskDetails/Actions";
@@ -65,10 +64,6 @@ const ComponentDetailsDialogContentSkeleton = () => {
const ComponentDetailsDialogContent = withSuspenseWrapper(
({ component, displayName, readOnly }: ComponentDetailsProps) => {
- const remoteComponentLibrarySearchEnabled = useFlagValue(
- "remote-component-library-search",
- );
-
const componentRef = useHydrateComponentReference(component);
if (!componentRef) {
@@ -81,8 +76,7 @@ const ComponentDetailsDialogContent = withSuspenseWrapper(
const componentSpec = componentRef.spec;
- const hasPublishSection =
- remoteComponentLibrarySearchEnabled && component.owned;
+ const hasPublishSection = component.owned;
return (
<>
@@ -124,12 +118,10 @@ const ComponentDetailsDialogContent = withSuspenseWrapper(
- {remoteComponentLibrarySearchEnabled && (
-
- )}
+
{
const navigate = useNavigate();
- const isRemoteComponentLibrarySearchEnabled = useFlagValue(
- "remote-component-library-search",
- );
const inputAggregatorEnabled = useFlagValue("input-aggregator");
const { registerNode } = useNodesOverlay();
@@ -260,16 +257,12 @@ const TaskNodeCard = () => {
)}
- {isRemoteComponentLibrarySearchEnabled ? (
-
- {digestMarkup}
-
- ) : (
- digestMarkup
- )}
+
+ {digestMarkup}
+
{isSubgraphNode && subgraphExecutionStats && (
@@ -298,7 +291,7 @@ const TaskNodeCard = () => {
onBackgroundClick={handleOutputSectionClick}
/>
- {isRemoteComponentLibrarySearchEnabled && updateOverlayDialogOpen ? (
+ {updateOverlayDialogOpen ? (
{
- const isRemoteComponentLibrarySearchEnabled = useFlagValue(
- "remote-component-library-search",
- );
- const shouldShowOutdatedBadge =
- isRemoteComponentLibrarySearchEnabled && showOutdatedBadge;
-
const popoverRef = useRef(null);
// TODO: respect selected node as a starting point
@@ -252,7 +245,7 @@ const ComponentMarkup = ({
wrap="nowrap"
blockAlign="start"
>
- {shouldShowOutdatedBadge ? (
+ {showOutdatedBadge ? (
{
- const handleCheckboxChange = (filter: string, checked: boolean) => {
- if (checked) {
- onFiltersChange([...activeFilters, filter]);
- } else {
- onFiltersChange(activeFilters.filter((f) => f !== filter));
- }
- };
-
- return (
-
-
-
-
- {activeFilters.length > 0 && !disableCounter && (
-
- {activeFilters.length}
-
- )}
-
-
-
-
-
- Filter Search
-
-
- {availableFilters.map((filter) => {
- if (filter === ComponentSearchFilter.EXACTMATCH) return;
-
- return (
-
-
- handleCheckboxChange(filter, !!checked)
- }
- className="hover:cursor-pointer"
- />
-
-
- );
- })}
-
-
-
-
- handleCheckboxChange(
- ComponentSearchFilter.EXACTMATCH,
- !!checked,
- )
- }
- className="hover:cursor-pointer"
- />
-
-
-
-
-
- );
-};
-
-export default SearchFilter;
diff --git a/src/components/shared/ReactFlow/FlowSidebar/components/SearchInput.tsx b/src/components/shared/ReactFlow/FlowSidebar/components/SearchInput.tsx
deleted file mode 100644
index 7485b44099..0000000000
--- a/src/components/shared/ReactFlow/FlowSidebar/components/SearchInput.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Search } from "lucide-react";
-
-import { Input } from "@/components/ui/input";
-import { type SearchInputProps } from "@/types/componentLibrary";
-import { COMPONENT_SEARCH_FILTERS } from "@/utils/constants";
-
-import SearchFilter from "./SearchFilter";
-
-const SearchInput = ({
- value,
- activeFilters,
- onChange,
- onFiltersChange,
-}: SearchInputProps) => {
- return (
-
- );
-};
-
-export default SearchInput;
diff --git a/src/components/shared/ReactFlow/FlowSidebar/components/SearchResults.test.tsx b/src/components/shared/ReactFlow/FlowSidebar/components/SearchResults.test.tsx
deleted file mode 100644
index cfc1e00f1b..0000000000
--- a/src/components/shared/ReactFlow/FlowSidebar/components/SearchResults.test.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import { render, screen } from "@testing-library/react";
-import type { ReactNode } from "react";
-import { describe, expect, it, vi } from "vitest";
-
-import type { SearchResult } from "@/types/componentLibrary";
-import { ComponentSearchFilter } from "@/utils/constants";
-
-import SearchResults from "./SearchResults";
-
-vi.mock("@/components/shared/Dialogs", () => ({
- ComponentDetailsDialog: () => ,
-}));
-
-vi.mock("@/components/shared/FavoriteComponentToggle", () => ({
- ComponentFavoriteToggle: () => ,
-}));
-
-vi.mock(
- "@/components/shared/ManageComponent/hooks/useOutdatedComponents",
- () => ({
- useOutdatedComponents: () => ({ data: [] }),
- }),
-);
-
-vi.mock("@/components/shared/Settings/useFlags", () => ({
- useFlagValue: () => false,
-}));
-
-vi.mock("@/providers/ComponentLibraryProvider/ForcedSearchProvider", () => ({
- useForcedSearchContext: () => ({
- currentSearchFilter: {
- searchTerm: "scrape",
- filters: [ComponentSearchFilter.NAME],
- },
- }),
-}));
-
-vi.mock("../../NodesOverlay/NodesOverlayProvider", () => ({
- useNodesOverlay: () => ({
- notifyNode: vi.fn(),
- getNodeIdsByDigest: vi.fn(() => []),
- fitNodeIntoView: vi.fn(),
- }),
-}));
-
-vi.mock("./ComponentHoverPopover", () => ({
- ComponentHoverPopover: ({ children }: { children: ReactNode }) => (
- <>{children}>
- ),
-}));
-
-describe("SearchResults", () => {
- it("shows publisher metadata for v1 component search results", () => {
- const searchResult: SearchResult = {
- components: {
- standard: [
- {
- digest: "published-digest",
- name: "Scrape V2",
- published_by: "pipeline-components@shopify.com",
- },
- ],
- user: [],
- used: [],
- },
- };
-
- render(
- ,
- );
-
- expect(screen.getByText("Scrape V2")).toBeInTheDocument();
- expect(
- screen.getByText("Published by pipeline-components@shopify.com"),
- ).toBeInTheDocument();
- });
-
- it("shows digest metadata when a v1 component search result has no publisher", () => {
- const searchResult: SearchResult = {
- components: {
- standard: [
- {
- digest: "sha256:abc123",
- name: "Upload to GCS",
- },
- ],
- user: [],
- used: [],
- },
- };
-
- render(
- ,
- );
-
- expect(screen.getByText("Upload to GCS")).toBeInTheDocument();
- expect(screen.getByText("Digest sha256:abc123")).toBeInTheDocument();
- });
-});
diff --git a/src/components/shared/ReactFlow/FlowSidebar/components/SearchResults.tsx b/src/components/shared/ReactFlow/FlowSidebar/components/SearchResults.tsx
deleted file mode 100644
index fa696e8d84..0000000000
--- a/src/components/shared/ReactFlow/FlowSidebar/components/SearchResults.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import { useCallback } from "react";
-
-import { Button } from "@/components/ui/button";
-import { useForcedSearchContext } from "@/providers/ComponentLibraryProvider/ForcedSearchProvider";
-import type { SearchResult } from "@/types/componentLibrary";
-import { ComponentSearchFilter } from "@/utils/constants";
-
-import { ComponentMarkup } from "./ComponentItem";
-
-interface SearchResultsProps {
- searchResult: SearchResult;
- onFiltersChange: (filters: string[]) => void;
-}
-
-const SearchResults = ({
- searchResult,
- onFiltersChange,
-}: SearchResultsProps) => {
- const { currentSearchFilter } = useForcedSearchContext();
-
- const matchedComponents = searchResult.components.standard;
-
- const matchedUserComponents = searchResult.components.user;
-
- const handleNameFilterClick = useCallback(() => {
- if (!currentSearchFilter.filters.includes(ComponentSearchFilter.NAME)) {
- onFiltersChange([
- ...currentSearchFilter.filters,
- ComponentSearchFilter.NAME,
- ]);
- }
- }, [currentSearchFilter.filters, onFiltersChange]);
-
- const filtersWithoutExactMatch =
- currentSearchFilter.filters?.filter(
- (f) => f !== ComponentSearchFilter.EXACTMATCH,
- ) ?? [];
-
- const exactMatchFilter = currentSearchFilter.filters?.includes(
- ComponentSearchFilter.EXACTMATCH,
- );
-
- if (filtersWithoutExactMatch.length === 0) {
- return (
-
- No search filters set.{" "}
-
-
- );
- }
-
- const hasResults =
- matchedComponents.length > 0 || matchedUserComponents.length > 0;
- if (!hasResults) {
- return (
-
- No component {filtersWithoutExactMatch.join(" or ")}{" "}
- {exactMatchFilter ? "exactly matches" : "contains"} “
- {currentSearchFilter.searchTerm}
- ”
-
- );
- }
-
- const totalResults = matchedComponents.length + matchedUserComponents.length;
-
- return (
-
-
- Search Results ({totalResults})
-
-
- {matchedUserComponents.length > 0 && (
- <>
- {/* User component section header if both types exist */}
- {matchedComponents.length > 0 && (
-
- User Components
-
- )}
- {/* User component results */}
- {matchedUserComponents.map((component, index) => (
-
- ))}
- >
- )}
-
- {matchedComponents.length > 0 && (
- <>
- {/* Library component section header if both types exist */}
- {matchedUserComponents.length > 0 && (
-
- Library Components
-
- )}
- {/* Library component results */}
- {matchedComponents.map((component, index) => (
-
- ))}
- >
- )}
-
-
- );
-};
-
-export default SearchResults;
diff --git a/src/components/shared/ReactFlow/FlowSidebar/components/index.ts b/src/components/shared/ReactFlow/FlowSidebar/components/index.ts
index 8879d72e85..1417375cb6 100644
--- a/src/components/shared/ReactFlow/FlowSidebar/components/index.ts
+++ b/src/components/shared/ReactFlow/FlowSidebar/components/index.ts
@@ -1,5 +1,3 @@
export { default as FolderItem } from "./FolderItem";
export { default as ImportComponent } from "./ImportComponent";
export { EmptyState, ErrorState, LoadingState } from "./LibraryStates";
-export { default as SearchInput } from "./SearchInput";
-export { default as SearchResults } from "./SearchResults";
diff --git a/src/components/shared/ReactFlow/FlowSidebar/sections/GraphComponents.tsx b/src/components/shared/ReactFlow/FlowSidebar/sections/GraphComponents.tsx
index ff4287644e..914be2db9d 100644
--- a/src/components/shared/ReactFlow/FlowSidebar/sections/GraphComponents.tsx
+++ b/src/components/shared/ReactFlow/FlowSidebar/sections/GraphComponents.tsx
@@ -1,4 +1,4 @@
-import { type ChangeEvent, useCallback, useMemo } from "react";
+import { useMemo } from "react";
import { ManageLibrariesDialog } from "@/components/shared/GitHubLibrary/ManageLibrariesDialog";
import { useFlagValue } from "@/components/shared/Settings/useFlags";
@@ -7,7 +7,6 @@ import { BlockStack, InlineStack } from "@/components/ui/layout";
import { Separator } from "@/components/ui/separator";
import { Text } from "@/components/ui/typography";
import { useComponentLibrary } from "@/providers/ComponentLibraryProvider";
-import { useForcedSearchContext } from "@/providers/ComponentLibraryProvider/ForcedSearchProvider";
import type { UIComponentFolder } from "@/types/componentLibrary";
import {
@@ -16,8 +15,6 @@ import {
FolderItem,
ImportComponent,
LoadingState,
- SearchInput,
- SearchResults,
} from "../components";
import {
ComponentItemFromUrl,
@@ -39,9 +36,6 @@ interface GraphComponentsProps {
const GraphComponents = ({
showSectionHeader = false,
}: GraphComponentsProps) => {
- const remoteComponentLibrarySearchEnabled = useFlagValue(
- "remote-component-library-search",
- );
const githubComponentLibraryEnabled = useFlagValue(
"github-component-library",
);
@@ -49,7 +43,6 @@ const GraphComponents = ({
const { getComponentLibrary, existingComponentLibraries } =
useComponentLibrary();
- const { updateSearchFilter, currentSearchFilter } = useForcedSearchContext();
const {
componentLibrary,
usedComponentsFolder,
@@ -57,38 +50,13 @@ const GraphComponents = ({
favoritesFolder,
isLoading,
error,
- searchResult,
} = useComponentLibrary();
- const handleSearchChange = (e: ChangeEvent) => {
- updateSearchFilter({
- searchTerm: e.target.value,
- });
- };
-
- const handleFiltersChange = useCallback(
- (filters: string[]) => {
- updateSearchFilter({
- filters,
- });
- },
- [updateSearchFilter],
- );
-
const memoizedContent = useMemo(() => {
if (isLoading) return ;
if (error) return ;
if (!componentLibrary) return ;
- if (!remoteComponentLibrarySearchEnabled && searchResult) {
- return (
-
- );
- }
-
const hasUsedComponents =
usedComponentsFolder?.components &&
usedComponentsFolder.components.length > 0;
@@ -102,7 +70,7 @@ const GraphComponents = ({
return (
- {remoteComponentLibrarySearchEnabled && }
+
{memoizedContent}
- ) : (
- <>
-
-
- {memoizedContent}
- >
);
const content = (
diff --git a/src/flags.ts b/src/flags.ts
index 2d7a932197..48ed753f9d 100644
--- a/src/flags.ts
+++ b/src/flags.ts
@@ -1,13 +1,6 @@
import type { ConfigFlags } from "@/types/configuration";
export const ExistingFlags: ConfigFlags = {
- ["remote-component-library-search"]: {
- name: "Published Components Library",
- description: "Enable the Published Components Library feature.",
- default: true,
- category: "beta",
- },
-
["github-component-library"]: {
name: "GitHub Component Library",
description:
diff --git a/src/providers/AnalyticsProvider.test.tsx b/src/providers/AnalyticsProvider.test.tsx
index d1fe748dc7..56beb6a3fa 100644
--- a/src/providers/AnalyticsProvider.test.tsx
+++ b/src/providers/AnalyticsProvider.test.tsx
@@ -220,7 +220,7 @@ describe("AnalyticsProvider", () => {
it("includes resolved effective flag values in session.tab.start metadata", async () => {
mockGetUser.mockResolvedValue({ id: "user-1" });
mockIsFlagEnabled.mockImplementation(
- (key: string) => key === "remote-component-library-search",
+ (key: string) => key === "github-component-library",
);
const { events, cleanup } = captureEvents();
renderHook(() => useAnalytics(), { wrapper: makeWrapper() });
@@ -232,8 +232,8 @@ describe("AnalyticsProvider", () => {
const { flags } = events.find(
(e) => e.detail.actionType === "session.tab.start",
)!.detail.metadata as Record>;
- expect(flags["remote-component-library-search"]).toBe(true);
- expect(flags["github-component-library"]).toBe(false);
+ expect(flags["github-component-library"]).toBe(true);
+ expect(flags["input-aggregator"]).toBe(false);
cleanup();
});
diff --git a/src/providers/ComponentLibraryProvider/ComponentLibraryProvider.tsx b/src/providers/ComponentLibraryProvider/ComponentLibraryProvider.tsx
index 780ea0611d..b65872ed7e 100644
--- a/src/providers/ComponentLibraryProvider/ComponentLibraryProvider.tsx
+++ b/src/providers/ComponentLibraryProvider/ComponentLibraryProvider.tsx
@@ -64,7 +64,6 @@ import {
isFavoriteComponent,
populateComponentRefs,
} from "./componentLibrary";
-import { useForcedSearchContext } from "./ForcedSearchProvider";
import { createLibraryObject } from "./libraries/factory";
import { PublishedComponentsLibrary } from "./libraries/publishedComponentsLibrary";
import { ensureLibraryFactoriesRegistered } from "./libraries/setup";
@@ -81,7 +80,6 @@ type ComponentLibraryContextType = {
isLoading: boolean;
error: Error | null;
existingComponentLibraries: StoredLibrary[] | undefined;
- searchResult: SearchResult | null;
searchComponentLibrary: (
search: string,
@@ -171,7 +169,6 @@ export const ComponentLibraryProvider = ({
children: ReactNode;
}) => {
const { graphSpec } = useComponentSpec();
- const { currentSearchFilter } = useForcedSearchContext();
const queryClient = useQueryClient();
const { track } = useAnalytics();
@@ -588,23 +585,6 @@ export const ComponentLibraryProvider = ({
dispatchEvent(new CustomEvent("tangle.library.duplicateDialogClosed"));
}, []);
- const [searchResult, setSearchResult] = useState(null);
-
- useEffect(() => {
- let cancelled = false;
- searchComponentLibrary(
- currentSearchFilter.searchTerm,
- currentSearchFilter.filters,
- ).then((result) => {
- if (!cancelled) {
- setSearchResult(result);
- }
- });
- return () => {
- cancelled = true;
- };
- }, [currentSearchFilter, searchComponentLibrary]);
-
useEffect(() => {
if (!rawComponentLibrary) {
setComponentLibrary(undefined);
@@ -641,7 +621,6 @@ export const ComponentLibraryProvider = ({
favoritesFolder,
isLoading,
error,
- searchResult,
existingComponentLibraries,
searchComponentLibrary,
getComponentLibrary,
@@ -657,7 +636,6 @@ export const ComponentLibraryProvider = ({
favoritesFolder,
isLoading,
error,
- searchResult,
existingComponentLibraries,
searchComponentLibrary,
getComponentLibrary,
diff --git a/src/routes/v2/shared/nodes/TaskNode/TaskNode.tsx b/src/routes/v2/shared/nodes/TaskNode/TaskNode.tsx
index 88a3b8233c..257885e2c0 100644
--- a/src/routes/v2/shared/nodes/TaskNode/TaskNode.tsx
+++ b/src/routes/v2/shared/nodes/TaskNode/TaskNode.tsx
@@ -244,9 +244,6 @@ export const TaskNode = observer(function TaskNode({
const { getEdges, setEdges } = useReactFlow();
const showContent = useIsDetailedView();
const inputAggregatorEnabled = useFlagValue("input-aggregator");
- const publishedComponentBadgeEnabled = useFlagValue(
- "remote-component-library-search",
- );
const spec = useSpec();
const task = spec?.tasks.find((t) => t.$id === entityId);
@@ -333,9 +330,7 @@ export const TaskNode = observer(function TaskNode({
conditionReferenceLabel ??
describeConditionSource(task.isEnabled) ??
CONDITION_LITERAL_LABELS[toConditionLiteral(task.isEnabled)],
- componentRef: publishedComponentBadgeEnabled
- ? task.resolvedComponentRef
- : undefined,
+ componentRef: task.resolvedComponentRef,
publishedComponentBadgeReadOnly,
isAggregator,
outputType: resolveAggregatorOutputType(task),
diff --git a/src/types/componentLibrary.ts b/src/types/componentLibrary.ts
index 9e76651a29..64841f3730 100644
--- a/src/types/componentLibrary.ts
+++ b/src/types/componentLibrary.ts
@@ -1,4 +1,4 @@
-import type { ChangeEvent, ReactElement } from "react";
+import type { ReactElement } from "react";
import type { ComponentReference } from "@/utils/componentSpec";
@@ -24,20 +24,6 @@ export type UIComponentFolder = {
isUserFolder?: boolean;
};
-export type SearchInputProps = {
- value: string;
- activeFilters: string[];
- onChange: (e: ChangeEvent) => void;
- onFiltersChange: (filters: string[]) => void;
-};
-
-export type SearchFilterProps = {
- availableFilters: string[];
- activeFilters: string[];
- disableCounter?: boolean;
- onFiltersChange: (filters: string[]) => void;
-};
-
export type SearchResult = {
components: {
standard: ComponentReference[];
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index d2cbe36dac..c89110d9ef 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -69,8 +69,6 @@ export enum ComponentSearchFilter {
EXACTMATCH = "Exact Match",
}
-export const COMPONENT_SEARCH_FILTERS = Object.values(ComponentSearchFilter);
-
export const DEFAULT_FILTERS = [ComponentSearchFilter.NAME];
export const AUTOSAVE_DEBOUNCE_TIME_MS = 300;
diff --git a/tests/e2e/componentlib.spec.ts b/tests/e2e/componentlib.spec.ts
deleted file mode 100644
index 33153e44be..0000000000
--- a/tests/e2e/componentlib.spec.ts
+++ /dev/null
@@ -1,301 +0,0 @@
-import { expect, type Page, test } from "@playwright/test";
-
-import {
- assertSearchState,
- createNewPipeline,
- dropComponentFromLibraryOnCanvas,
- locateComponentInFolder,
- locateFlowCanvas,
- locateFolderByName,
- openComponentLibFolder,
- removeComponentFromCanvas,
- setBetaFlag,
-} from "./helpers";
-
-/**
- * Due to the time it takes to load the library, the tests are run in serial
- * and one page is used for all the tests.
- *
- * So every test must clean up after itself
- */
-test.describe.configure({ mode: "serial" });
-
-test.describe("Component Library", () => {
- let page: Page;
-
- test.beforeAll(async ({ browser }) => {
- page = await browser.newPage();
-
- await setBetaFlag(page, "remote-component-library-search", false);
- await createNewPipeline(page);
-
- await expect(page.locator("[data-testid='search-input']")).toBeVisible();
- await locateFolderByName(page, "Standard library");
- });
-
- test.afterAll(async () => {
- await page.close();
- });
-
- test("standard library successfully loads", async () => {
- await openComponentLibFolder(page, "Standard library");
-
- const standardLibraryFolders = [
- "Quick start",
- "Basics",
- "Datasets",
- "Data manipulation",
- "Upload/Download",
- "ML frameworks",
- "ML Metrics",
- "Converters",
- ];
-
- // expect to see all the folders
- for (const folder of standardLibraryFolders) {
- const folderContainer = await locateFolderByName(page, folder);
- await expect(folderContainer).toBeVisible();
- }
- });
-
- test("folder can be expanded and collapsed", async () => {
- // ensure no components are visible in the folder before it is expanded
- const inputsOutputsFolder = await locateFolderByName(
- page,
- "Inputs & Outputs",
- );
- await expect(inputsOutputsFolder.getByRole("button")).toHaveAttribute(
- "aria-expanded",
- "false",
- );
- const inputsOutputsFolderContent = inputsOutputsFolder.locator("li");
-
- (await inputsOutputsFolderContent.all()).forEach(async (component) => {
- await expect(component).toBeHidden();
- });
-
- // expand the folder
- await openComponentLibFolder(page, "Inputs & Outputs");
-
- await expect(inputsOutputsFolder.getByRole("button")).toHaveAttribute(
- "aria-expanded",
- "true",
- );
-
- // expect only two components in the folder
- const components = inputsOutputsFolder.locator("li");
- await expect(components).toHaveCount(2);
-
- await inputsOutputsFolder.getByRole("button").click();
-
- await expect(inputsOutputsFolder.getByRole("button")).toHaveAttribute(
- "aria-expanded",
- "false",
- );
- });
-
- test("user can navigate deep into the nested folders", async () => {
- // navigate to the nested folder
- await openComponentLibFolder(page, "Standard library");
-
- const topFolder = await openComponentLibFolder(page, "ML frameworks");
- const topFolderContent = topFolder.locator("[data-folder-name]");
- await expect(await topFolderContent).toHaveCount(6);
-
- const nestedFolder = await openComponentLibFolder(page, "XGBoost");
-
- const nestedFolderContent = nestedFolder.getByTestId("component-item");
- await expect(await nestedFolderContent).toHaveCount(4);
- });
-
- test("components can be added and removed from favorites folder", async () => {
- // add component to the favorites by clicking the star icon
- await openComponentLibFolder(page, "Standard library");
-
- const quickStartFolder = await openComponentLibFolder(page, "Quick start");
- const chicagoTaxiTripsDataset = await locateComponentInFolder(
- quickStartFolder,
- "Chicago Taxi Trips dataset",
- );
- await chicagoTaxiTripsDataset.getByTestId("favorite-star").click();
-
- // expect the component to be in the favorites folder
- const favoritesFolder = await openComponentLibFolder(
- page,
- "Favorite Components",
- );
- await expect(favoritesFolder.locator("li")).toHaveCount(1);
-
- // unstar the component
- await chicagoTaxiTripsDataset.getByTestId("favorite-star").click();
-
- await expect(favoritesFolder.locator("li")).toHaveCount(0);
- });
-
- test("component details can be opened as a dialog", async () => {
- await openComponentLibFolder(page, "Standard library");
- const quickStartFolder = await openComponentLibFolder(page, "Quick start");
- const chicagoTaxiTripsDataset = await locateComponentInFolder(
- quickStartFolder,
- "Chicago Taxi Trips dataset",
- );
-
- await chicagoTaxiTripsDataset.getByTestId("info-icon-button").click();
-
- const dialog = page.getByTestId("component-details-dialog");
- const dialogHeader = dialog.locator('[data-slot="dialog-header"]');
- await expect(dialogHeader).toBeVisible();
-
- await expect(dialogHeader).toHaveText("Chicago Taxi Trips dataset");
-
- await page.locator('button[data-slot="dialog-close"]').click();
-
- await expect(dialogHeader).toBeHidden();
- });
-
- test("components can be dragged to the canvas and appear in the used in pipeline folder", async () => {
- await openComponentLibFolder(page, "Standard library");
- await dropComponentFromLibraryOnCanvas(
- page,
- "Quick start",
- "Chicago Taxi Trips dataset",
- );
-
- const usedOnCanvasFolder = await openComponentLibFolder(
- page,
- "Used in Pipeline",
- );
- await expect(usedOnCanvasFolder.locator("li")).toHaveCount(1);
-
- // remove the component from the canvas
- await removeComponentFromCanvas(page, "Chicago Taxi Trips dataset");
- await expect(usedOnCanvasFolder.locator("li")).toHaveCount(0);
- });
-
- test("library can be searched", async () => {
- await page.getByTestId("search-input").fill("GCS");
-
- const searchResultsHeader = page.getByTestId("search-results-header");
- await expect(searchResultsHeader).toBeVisible();
- await expect(searchResultsHeader).toHaveText("Search Results (3)");
-
- const componentItem = page.getByTestId("component-item");
- await expect(componentItem).toHaveCount(3);
-
- await page.getByTestId("search-input").clear();
-
- await expect(searchResultsHeader).toBeHidden();
- });
-
- test("search results can be highlighted on input pin click", async () => {
- await openComponentLibFolder(page, "Standard library");
- await openComponentLibFolder(page, "Data manipulation");
- await openComponentLibFolder(page, "CSV");
-
- const node = await dropComponentFromLibraryOnCanvas(
- page,
- "CSV",
- "Select columns using Pandas on CSV data",
- );
- await expect(
- node,
- "Dropped component should be on the canvas before clicking its pin",
- ).toBeVisible();
-
- const inputHandle = page.getByTestId("input-handle-table");
- await expect(inputHandle).toBeVisible();
- await inputHandle.click();
-
- const outputConnection = page.getByTestId(
- "output-connection-transformed_table",
- );
- const inputConnection = page.getByTestId("input-connection-table");
- await expect(outputConnection).toHaveAttribute("data-highlighted", "true");
-
- // assert highlighting
- await expect(outputConnection).toHaveAttribute("data-highlighted", "true");
- await expect(inputConnection).toHaveAttribute("data-highlighted", "false");
- await expect(inputConnection).toHaveAttribute("data-selected", "true");
-
- await assertSearchState(page, {
- searchTerm: "CSV",
- searchFilterCount: "2",
- searchResultsCount: "*",
- });
-
- // reset highlighting after clicking on the canvas
- await locateFlowCanvas(page).click();
-
- // resets selection after clicking on the canvas
- await expect(inputConnection).toHaveAttribute("data-highlighted", "false");
- await expect(outputConnection).toHaveAttribute("data-highlighted", "false");
-
- // search should be reset
- await assertSearchState(page, {
- searchTerm: "",
- });
-
- // remove the component from the canvas
- await removeComponentFromCanvas(
- page,
- "Select columns using Pandas on CSV data",
- );
- });
-
- test("search results can be highlighted on output pin click", async () => {
- await openComponentLibFolder(page, "Standard library");
- await openComponentLibFolder(page, "Data manipulation");
- await openComponentLibFolder(page, "CSV");
-
- const node = await dropComponentFromLibraryOnCanvas(
- page,
- "CSV",
- "Select columns using Pandas on CSV data",
- );
- await expect(
- node,
- "Dropped component should be on the canvas before clicking its pin",
- ).toBeVisible();
-
- const outputHandle = page.getByTestId("output-handle-transformed_table");
- await expect(outputHandle).toBeVisible();
- await outputHandle.click();
-
- const outputConnection = page.getByTestId(
- "output-connection-transformed_table",
- );
- const inputConnection = page.getByTestId("input-connection-table");
- await expect(outputConnection).toHaveAttribute("data-selected", "true");
-
- // assert highlighting
- await expect(outputConnection).toHaveAttribute("data-highlighted", "false");
- await expect(outputConnection).toHaveAttribute("data-selected", "true");
- await expect(inputConnection).toHaveAttribute("data-highlighted", "true");
-
- // assert search inputs
- await assertSearchState(page, {
- searchTerm: "CSV",
- searchFilterCount: "2",
- // todo: this can be painful to maintain, find a better way to do this
- searchResultsCount: "*",
- });
-
- // reset highlighting after clicking on the canvas
- await locateFlowCanvas(page).click();
-
- // resets selection after clicking on the canvas
- await expect(inputConnection).toHaveAttribute("data-highlighted", "false");
- await expect(outputConnection).toHaveAttribute("data-selected", "false");
-
- // search should be reset
- await assertSearchState(page, {
- searchTerm: "",
- });
-
- // remove the component from the canvas
- await removeComponentFromCanvas(
- page,
- "Select columns using Pandas on CSV data",
- );
- });
-});
diff --git a/tests/e2e/helpers.ts b/tests/e2e/helpers.ts
index 66a25fc752..05fb4df550 100644
--- a/tests/e2e/helpers.ts
+++ b/tests/e2e/helpers.ts
@@ -310,12 +310,6 @@ async function navigateToSettings(
).toBeVisible();
}
-/**
- * Toggles a beta feature flag via the settings UI.
- * @param page - Playwright page object
- * @param flagKey - The flag key as defined in flags.ts (e.g. "remote-component-library-search")
- * @param enabled - Whether the flag should be enabled or disabled
- */
export async function setBetaFlag(
page: Page,
flagKey: string,
diff --git a/tests/e2e/published-componentlib.spec.ts b/tests/e2e/published-componentlib.spec.ts
index 26c3957ef2..3bf12003eb 100644
--- a/tests/e2e/published-componentlib.spec.ts
+++ b/tests/e2e/published-componentlib.spec.ts
@@ -10,7 +10,6 @@ import {
locateFolderByName,
openComponentLibFolder,
removeComponentFromCanvas,
- setBetaFlag,
} from "./helpers";
/**
@@ -28,8 +27,6 @@ test.describe("Published Component Library", () => {
page = await browser.newPage();
await createNewPipeline(page);
- await setBetaFlag(page, "remote-component-library-search", true);
- await page.goBack();
await expect(page.locator("[data-testid='search-input']")).toBeVisible();
});
@@ -59,6 +56,41 @@ test.describe("Published Component Library", () => {
}
});
+ test("folder can be expanded and collapsed", async () => {
+ const folder = await locateFolderByName(page, "Inputs & Outputs");
+ await expect(folder.getByRole("button")).toHaveAttribute(
+ "aria-expanded",
+ "false",
+ );
+
+ await openComponentLibFolder(page, "Inputs & Outputs");
+
+ await expect(folder.getByRole("button")).toHaveAttribute(
+ "aria-expanded",
+ "true",
+ );
+ await expect(folder.locator("li")).toHaveCount(2);
+
+ await folder.getByRole("button").click();
+ await expect(folder.getByRole("button")).toHaveAttribute(
+ "aria-expanded",
+ "false",
+ );
+ });
+
+ test("user can navigate nested folders", async () => {
+ await openComponentLibFolder(page, "Standard library");
+
+ const frameworksFolder = await openComponentLibFolder(
+ page,
+ "ML frameworks",
+ );
+ await expect(frameworksFolder.locator("[data-folder-name]")).toHaveCount(6);
+
+ const xgboostFolder = await openComponentLibFolder(page, "XGBoost");
+ await expect(xgboostFolder.getByTestId("component-item")).toHaveCount(4);
+ });
+
test("library can be searched", async () => {
// search for a component
await searchForComponent(page, "GCS");
diff --git a/tests/e2e/published-componentlifecycle.spec.ts b/tests/e2e/published-componentlifecycle.spec.ts
index 1ea2159cf1..df60ab6350 100644
--- a/tests/e2e/published-componentlifecycle.spec.ts
+++ b/tests/e2e/published-componentlifecycle.spec.ts
@@ -6,7 +6,6 @@ import {
locateComponentInFolder,
locateFolderByName,
openComponentLibFolder,
- setBetaFlag,
} from "./helpers";
/**
@@ -25,8 +24,6 @@ test.describe("Published Component Library - Lifecycle", () => {
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
- await setBetaFlag(page, "remote-component-library-search", true);
-
await createNewPipeline(page);
await expect(page.locator("[data-testid='search-input']")).toBeVisible();