diff --git a/app/src/App.tsx b/app/src/App.tsx index db2c6a07e9..8b93838225 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -56,7 +56,7 @@ export function AppRoot() { - + diff --git a/app/src/Routes.tsx b/app/src/Routes.tsx index 6874bda984..5af9c14863 100644 --- a/app/src/Routes.tsx +++ b/app/src/Routes.tsx @@ -2,16 +2,26 @@ import React from "react"; import { Route, createRoutesFromElements, RouterProvider } from "react-router"; import { Home, Embedding, embeddingLoader, Layout } from "./pages"; import { createBrowserRouter } from "react-router-dom"; +import { EmbeddingLoaderQuery$data } from "./pages/__generated__/EmbeddingLoaderQuery.graphql"; const router = createBrowserRouter( createRoutesFromElements( - }> + } handle={{ crumb: () => "Home" }}> } /> - } - loader={embeddingLoader} - /> + + } + loader={embeddingLoader} + handle={{ + // `crumb` is your own abstraction, we decided + // to make this one a function so we can pass + // the data from the loader to it so that our + // breadcrumb is made up of dynamic content + crumb: (data: EmbeddingLoaderQuery$data) => data.embedding.name, + }} + /> + ) ); diff --git a/app/src/components/nav/NavBreadcrumb.tsx b/app/src/components/nav/NavBreadcrumb.tsx new file mode 100644 index 0000000000..f64d19dc06 --- /dev/null +++ b/app/src/components/nav/NavBreadcrumb.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import { Breadcrumbs, Item } from "@arizeai/components"; +import { useMatches, useNavigate } from "react-router"; + +export type CrumbFn = (data: unknown) => string; +type Matches = ReturnType; +type Match = Matches[number]; +type RouteMatchWithCrumb = Match & { + handle: { + crumb: CrumbFn; + }; +}; + +function isRouteMatchWithCrumb(match: Match): match is RouteMatchWithCrumb { + return ( + typeof match.handle == "object" && + // eslint-disable-next-line @typescript-eslint/no-explicit-any + typeof (match.handle as any)?.crumb === "function" + ); +} + +export function NavBreadcrumb() { + const navigate = useNavigate(); + const matches = useMatches(); + // Get rid of any matches that don't have handle and crumb + const matchesWithCrumb = matches.filter(isRouteMatchWithCrumb); + + console.dir(matchesWithCrumb); + return ( + { + // Action here is the index of the breadcrumb + navigate(matchesWithCrumb[Number(index)].pathname); + }} + > + {matchesWithCrumb.map((match, index) => ( + {match.handle.crumb(match.data)} + ))} + + ); +} diff --git a/app/src/components/nav/Navbar.tsx b/app/src/components/nav/Navbar.tsx index d70b945096..545ee4c30c 100644 --- a/app/src/components/nav/Navbar.tsx +++ b/app/src/components/nav/Navbar.tsx @@ -9,6 +9,7 @@ const navCSS = (theme: Theme) => css` display: flex; flex-direction: row; justify-content: space-between; + align-items: center; `; const brandCSS = (theme: Theme) => @@ -16,8 +17,6 @@ const brandCSS = (theme: Theme) => color: ${theme.textColors.white90}; font-size: ${theme.typography.sizes.large.fontSize}px; text-decoration: none; - display: flex; - flex-direction: row; svg { margin-right: ${theme.spacing.margin8}px; } @@ -25,8 +24,8 @@ const brandCSS = (theme: Theme) => const BrandSVG = () => ( - Phoenix ); } diff --git a/app/src/components/nav/index.tsx b/app/src/components/nav/index.tsx index 21348000eb..f3fdb60b97 100644 --- a/app/src/components/nav/index.tsx +++ b/app/src/components/nav/index.tsx @@ -1 +1,2 @@ export * from "./Navbar"; +export * from "./NavBreadcrumb"; diff --git a/app/src/pages/Embedding.tsx b/app/src/pages/Embedding.tsx index ea4e44c435..9749599183 100644 --- a/app/src/pages/Embedding.tsx +++ b/app/src/pages/Embedding.tsx @@ -1,19 +1,13 @@ import React from "react"; import { fetchQuery, graphql } from "react-relay"; -import { LoaderFunctionArgs, useLoaderData, useNavigate } from "react-router"; +import { LoaderFunctionArgs } from "react-router"; import RelayEnvironment from "../RelayEnvironment"; -import { - EmbeddingLoaderQuery, - EmbeddingLoaderQuery$data, -} from "./__generated__/EmbeddingLoaderQuery.graphql"; -import { Breadcrumbs, Item } from "@arizeai/components"; +import { EmbeddingLoaderQuery } from "./__generated__/EmbeddingLoaderQuery.graphql"; import { css } from "@emotion/react"; import { DriftPointCloud } from "../components/canvas"; import { data as primaryData } from "../data/umapData"; export function Embedding() { - const navigate = useNavigate(); - const data = useLoaderData() as EmbeddingLoaderQuery$data; return (
css` @@ -25,17 +19,6 @@ export function Embedding() { } `} > - { - if (action === "model") { - navigate("/"); - } - }} - > - Model - Embeddings - {data.embedding.name} -
css` margin: ${theme.spacing.margin8}px; - nav { - margin-bottom: ${theme.spacing.margin8}px; - } ` } > - - Model - Overview - +