diff --git a/studio/src/components/dashboard/graph-command-group.tsx b/studio/src/components/dashboard/graph-command-group.tsx index e4fb695db1..f9c80215ef 100644 --- a/studio/src/components/dashboard/graph-command-group.tsx +++ b/studio/src/components/dashboard/graph-command-group.tsx @@ -67,6 +67,15 @@ interface GraphLinkProps { setNamespace(namespace: string): void; } +const defaultGraphTemplate = `/[organizationSlug]/[namespace]/graph/[slug]`; +const graphAreasWithParameters: readonly string[] = [ + 'change-log', + 'checks', + 'compositions', + 'feature-flags', + 'proposals' +]; + function GraphCommandItem({ name, namespace, @@ -82,16 +91,22 @@ function GraphCommandItem({ const pathname = useMemo( () => { - const segment = router.pathname.split('/')[3]?.toLowerCase(); + const segmentSplit = router.pathname.split('/'); + const segment = segmentSplit[3]?.toLowerCase(); if (isSubgraph) { return segment === 'subgraph' ? router.pathname : `/[organizationSlug]/[namespace]/subgraph/[subgraphSlug]`; } - return segment === 'graph' - ? router.pathname - : `/[organizationSlug]/[namespace]/graph/[slug]`; + if (segment !== 'graph') { + return defaultGraphTemplate; + } + + const areaSegment = segmentSplit[5]?.toLowerCase(); + return areaSegment && graphAreasWithParameters.includes(areaSegment) && segmentSplit.length > 5 + ? `${defaultGraphTemplate}/${areaSegment}` + : router.pathname; }, [router.pathname, isSubgraph], ); diff --git a/studio/src/components/dashboard/namespace-selector.tsx b/studio/src/components/dashboard/namespace-selector.tsx index c3cd42f794..b75149d1f1 100644 --- a/studio/src/components/dashboard/namespace-selector.tsx +++ b/studio/src/components/dashboard/namespace-selector.tsx @@ -6,8 +6,7 @@ import { useMemo, useState } from "react"; import Link from "next/link"; import { cn } from "@/lib/utils"; import * as React from "react"; -import { CheckIcon } from "@radix-ui/react-icons"; -import { CaretSortIcon } from "@radix-ui/react-icons"; +import { CheckIcon, CaretSortIcon } from "@radix-ui/react-icons"; import { docsBaseURL } from "@/lib/constants"; import { WorkspaceCommandWrapper } from "./workspace-command-wrapper" import { useCurrentOrganization } from "@/hooks/use-current-organization"; @@ -20,7 +19,7 @@ interface NamespaceSelectorProps { export function NamespaceSelector({ isViewingGraphOrSubgraph, truncateNamespace }: NamespaceSelectorProps) { const [filter, setFilter] = useState(''); const [isOpen, setOpen] = useState(false); - const { namespace, namespaceByName, setNamespace } = useWorkspace(); + const { isLoading, namespace, namespaceByName, setNamespace } = useWorkspace(); const router = useRouter(); const organizationSlug = useCurrentOrganization()?.slug; @@ -30,6 +29,22 @@ export function NamespaceSelector({ isViewingGraphOrSubgraph, truncateNamespace ); const namespaces = Array.from(namespaceByName.keys()); + if (isLoading) { + return ( + + + {namespace.name} + + + + ); + } return (
@@ -48,7 +63,6 @@ export function NamespaceSelector({ isViewingGraphOrSubgraph, truncateNamespace {namespace.name} )} - ([], { keys: ['name'], threshold: 0.3, }); + const fuse = new Fuse([], { keys: ['name'], threshold: 0.2, includeScore: true }); const searchResults: WorkspaceNamespace[] = []; for (const wns of Array.from(namespaceByName.values())) { - if (!wns.graphs?.length) { - // The namespace doesn't contain any federated graph, we don't need to perform the search here - continue; - } - // Determine whether the namespace contains the filter value - fuse.setCollection([wns]); - if (fuse.search(filterValue).length > 0) { + if (wns.name.toLowerCase().includes(filterValue)) { // The namespace contains the filter value, add it with all the graphs/subgraphs to the search results searchResults.push(wns); continue; } + if (!wns.graphs?.length) { + // The namespace doesn't contain any federated graph, we don't need to perform the search here + continue; + } + // We need to clone the namespace to avoid mutating the original object const clonedWns = wns.clone(); clonedWns.graphs = []; diff --git a/studio/src/components/dashboard/workspace-provider.tsx b/studio/src/components/dashboard/workspace-provider.tsx index ef7c6fc0ca..63d85937d5 100644 --- a/studio/src/components/dashboard/workspace-provider.tsx +++ b/studio/src/components/dashboard/workspace-provider.tsx @@ -59,12 +59,14 @@ export function WorkspaceProvider({ children }: React.PropsWithChildren) { // Memoize context components const currentNamespace= useMemo( - () => data?.namespaces.find((wns) => wns.name === namespace) ?? new WorkspaceNamespace({ - id: '', - name: DEFAULT_NAMESPACE_NAME, - graphs: [], - }), - [data?.namespaces, namespace], + () => isLoading + ? new WorkspaceNamespace({ id: '', name: namespace, graphs: [] }) + : data?.namespaces.find((wns) => wns.name === namespace) ?? new WorkspaceNamespace({ + id: '', + name: DEFAULT_NAMESPACE_NAME, + graphs: [], + }), + [isLoading, data?.namespaces, namespace], ); const namespaceByName = useMemo( diff --git a/studio/src/components/dashboard/workspace-selector.tsx b/studio/src/components/dashboard/workspace-selector.tsx index 59ccd46e30..a381231a58 100644 --- a/studio/src/components/dashboard/workspace-selector.tsx +++ b/studio/src/components/dashboard/workspace-selector.tsx @@ -39,7 +39,7 @@ export function WorkspaceSelector({ children, truncateNamespace = true }: Worksp const isViewingGraphOrSubgraph = !!activeGraph || !!activeSubgraph; return (
-
+
{breadcrumbs?.map((b, i) => ( diff --git a/studio/src/pages/[organizationSlug]/feature-flags/[featureFlagSlug]/index.tsx b/studio/src/pages/[organizationSlug]/feature-flags/[featureFlagSlug]/index.tsx index f7fc794ad1..04c0534662 100644 --- a/studio/src/pages/[organizationSlug]/feature-flags/[featureFlagSlug]/index.tsx +++ b/studio/src/pages/[organizationSlug]/feature-flags/[featureFlagSlug]/index.tsx @@ -11,6 +11,7 @@ import { Button } from "@/components/ui/button"; import Link from "next/link"; import { FeatureFlagDetails } from "@/components/feature-flag-details"; import { useWorkspace } from "@/hooks/use-workspace"; +import { NamespaceSelector } from "@/components/dashboard/namespace-selector"; import { useCurrentOrganization } from "@/hooks/use-current-organization"; const FeatureFlagDetailsPage: NextPageWithLayout = () => { @@ -89,8 +90,13 @@ FeatureFlagDetailsPage.getLayout = (page) => { undefined, undefined, [ - , - , + , + , + , ], true, );