From a4b255b3f7da6beab13baa563fe23907f1ffc95a Mon Sep 17 00:00:00 2001 From: mbeaulne Date: Wed, 27 May 2026 16:21:34 -0400 Subject: [PATCH] Add Components V2 route shell --- src/flags.ts | 8 +++ .../Dashboard/DashboardComponentsV2View.tsx | 49 +++++++++++++++++++ src/routes/Dashboard/DashboardLayout.tsx | 23 ++++++++- src/routes/Settings/SettingsLayout.tsx | 14 +++++- src/routes/router.ts | 29 +++++++++++ 5 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 src/routes/Dashboard/DashboardComponentsV2View.tsx diff --git a/src/flags.ts b/src/flags.ts index c09acca71..46150c548 100644 --- a/src/flags.ts +++ b/src/flags.ts @@ -54,4 +54,12 @@ export const ExistingFlags: ConfigFlags = { default: true, category: "beta", }, + + ["component-search-v2"]: { + name: "Component Search V2", + description: + "Show the experimental Components V2 page that searches across standard, published, registered, and user component sources, with optional AI rerank.", + default: false, + category: "beta", + }, }; diff --git a/src/routes/Dashboard/DashboardComponentsV2View.tsx b/src/routes/Dashboard/DashboardComponentsV2View.tsx new file mode 100644 index 000000000..0d46bbea0 --- /dev/null +++ b/src/routes/Dashboard/DashboardComponentsV2View.tsx @@ -0,0 +1,49 @@ +import { type ChangeEvent, useState } from "react"; + +import { Input } from "@/components/ui/input"; +import { BlockStack } from "@/components/ui/layout"; +import { Heading, Paragraph } from "@/components/ui/typography"; +import { TOP_NAV_HEIGHT } from "@/utils/constants"; + +/** + * Experimental Components V2 route shell. Search data sources and result + * ranking land in the follow-up PRs in this stack. + */ +export const DashboardComponentsV2View = () => { + const [query, setQuery] = useState(""); + + const handleQueryChange = (event: ChangeEvent) => { + setQuery(event.target.value); + }; + + return ( +
+
+ + + Components V2 + + Search across component sources from one experimental dashboard. + + + + +
+
+ + Component results will appear here. + +
+
+ ); +}; diff --git a/src/routes/Dashboard/DashboardLayout.tsx b/src/routes/Dashboard/DashboardLayout.tsx index 969056410..fee815210 100644 --- a/src/routes/Dashboard/DashboardLayout.tsx +++ b/src/routes/Dashboard/DashboardLayout.tsx @@ -2,6 +2,7 @@ import { Link, Outlet } from "@tanstack/react-router"; import { isAuthorizationRequired } from "@/components/shared/Authentication/helpers"; import { TopBarAuthentication } from "@/components/shared/Authentication/TopBarAuthentication"; +import { useFlagValue } from "@/components/shared/Settings/useFlags"; import { Icon, type IconName } from "@/components/ui/icon"; import { BlockStack, InlineStack } from "@/components/ui/layout"; import { Link as UILink } from "@/components/ui/link"; @@ -24,7 +25,7 @@ interface SidebarItem { exact?: boolean; } -const SIDEBAR_ITEMS: SidebarItem[] = [ +const BASE_SIDEBAR_ITEMS: SidebarItem[] = [ { to: "/", label: "My Dashboard", icon: "LayoutDashboard", exact: true }, { to: "/pipelines", label: "My Pipelines", icon: "GitBranch" }, { to: "/runs", label: "All Runs", icon: "Play" }, @@ -33,6 +34,12 @@ const SIDEBAR_ITEMS: SidebarItem[] = [ { to: "/recently-viewed", label: "Recently Viewed", icon: "Clock" }, ]; +const COMPONENTS_V2_ITEM: SidebarItem = { + to: "/components-v2", + label: "Components V2", + icon: "PackageSearch", +}; + const navItemClass = (isActive: boolean) => cn( "w-full px-3 py-2 rounded-md text-sm cursor-pointer hover:bg-accent", @@ -41,6 +48,18 @@ const navItemClass = (isActive: boolean) => export function DashboardLayout() { const requiresAuthorization = isAuthorizationRequired(); + const isComponentsV2Enabled = useFlagValue("component-search-v2"); + + // Insert the Components V2 entry directly after "Components" when the + // beta flag is on. Keeps the nav order intuitive without touching the + // base list. + const sidebarItems = isComponentsV2Enabled + ? [ + ...BASE_SIDEBAR_ITEMS.slice(0, 4), + COMPONENTS_V2_ITEM, + ...BASE_SIDEBAR_ITEMS.slice(4), + ] + : BASE_SIDEBAR_ITEMS; return (
- {SIDEBAR_ITEMS.map((item) => ( + {sidebarItems.map((item) => ( { router.history.back(); @@ -76,7 +88,7 @@ export function SettingsLayout() { gap="1" className="w-48 shrink-0 border-r border-border pr-4" > - {SIDEBAR_ITEMS.map((item) => ( + {sidebarItems.map((item) => ( dashboardRoute, + path: "/components-v2", + component: DashboardComponentsV2View, + beforeLoad: () => { + if (!isFlagEnabled("component-search-v2")) { + throw redirect({ to: APP_ROUTES.DASHBOARD_COMPONENTS }); + } + }, +}); + const dashboardFavoritesRoute = createRoute({ getParentRoute: () => dashboardRoute, path: "/favorites", @@ -178,6 +194,17 @@ const settingsBetaFeaturesRoute = createRoute({ component: BetaFeaturesSettings, }); +const settingsAgentRoute = createRoute({ + getParentRoute: () => settingsLayoutRoute, + path: "/agent", + component: AgentSettings, + beforeLoad: () => { + if (!isFlagEnabled("component-search-v2")) { + throw redirect({ to: APP_ROUTES.SETTINGS_BACKEND }); + } + }, +}); + const settingsSecretsRoute = createRoute({ getParentRoute: () => settingsLayoutRoute, path: "/secrets", @@ -253,6 +280,7 @@ const settingsRouteTree = settingsLayoutRoute.addChildren([ settingsBackendRoute, settingsPreferencesRoute, settingsBetaFeaturesRoute, + settingsAgentRoute, secretsRouteTree, ]); @@ -297,6 +325,7 @@ const dashboardRouteTree = dashboardRoute.addChildren([ dashboardRunsRoute, dashboardPipelinesRoute, dashboardComponentsRoute, + dashboardComponentsV2Route, dashboardFavoritesRoute, dashboardRecentlyViewedRoute, ]);