Skip to main content
Glama

@arizeai/phoenix-mcp

Official
by Arize-ai
ProjectPage.tsx8.25 kB
import { startTransition, Suspense, useCallback, useEffect, useMemo, } from "react"; import { graphql, useLazyLoadQuery, useQueryLoader } from "react-relay"; import { Outlet, useNavigate, useParams } from "react-router"; import { css } from "@emotion/react"; import { Flex, LazyTabPanel, Loading, Tab, TabList, Tabs, } from "@phoenix/components"; import { ConnectedTimeRangeSelector, useTimeRange, } from "@phoenix/components/datetime"; import { useProjectContext } from "@phoenix/contexts/ProjectContext"; import { StreamStateProvider } from "@phoenix/contexts/StreamStateContext"; import { useProjectRootPath } from "@phoenix/hooks/useProjectRootPath"; import { ProjectPageQueriesProjectConfigQuery as ProjectPageProjectConfigQueryType } from "./__generated__/ProjectPageQueriesProjectConfigQuery.graphql"; import { ProjectPageQueriesSessionsQuery as ProjectPageSessionsQueryType } from "./__generated__/ProjectPageQueriesSessionsQuery.graphql"; import { ProjectPageQueriesSpansQuery as ProjectPageSpansQueryType } from "./__generated__/ProjectPageQueriesSpansQuery.graphql"; import { ProjectPageQueriesTracesQuery as ProjectPageTracesQueryType } from "./__generated__/ProjectPageQueriesTracesQuery.graphql"; import { ProjectPageQuery as ProjectPageQueryType } from "./__generated__/ProjectPageQuery.graphql"; import { ProjectPageHeader } from "./ProjectPageHeader"; import { ProjectPageQueriesProjectConfigQuery, ProjectPageQueriesSessionsQuery, ProjectPageQueriesSpansQuery, ProjectPageQueriesTracesQuery, ProjectPageQueryReferenceContext, } from "./ProjectPageQueries"; import { StreamToggle } from "./StreamToggle"; const mainCSS = css` flex: 1 1 auto; display: flex; flex-direction: column; overflow: hidden; .ac-tabs { flex: 1 1 auto; overflow: hidden; display: flex; flex-direction: column; div[role="tablist"] { flex: none; } .ac-tabs__pane-container { flex: 1 1 auto; display: flex; flex-direction: column; overflow: hidden; div[role="tabpanel"]:not([hidden]) { flex: 1 1 auto; display: flex; flex-direction: column; overflow: hidden; } } } `; export function ProjectPage() { const { projectId } = useParams(); const { timeRange } = useTimeRange(); return ( <Suspense fallback={<Loading />}> <ProjectPageContent projectId={projectId as string} timeRange={timeRange} /> </Suspense> ); } const TABS = ["spans", "traces", "sessions", "config", "metrics"] as const; /** * Type guard for the tab path in the URL */ const isTab = (tab: string): tab is (typeof TABS)[number] => { return TABS.includes(tab as (typeof TABS)[number]); }; const TAB_INDEX_MAP: Record<(typeof TABS)[number], number> = { spans: 0, traces: 1, sessions: 2, metrics: 3, config: 4, }; export function ProjectPageContent({ projectId, timeRange, }: { projectId: string; timeRange: OpenTimeRange; }) { const treatOrphansAsRoots = useProjectContext( (state) => state.treatOrphansAsRoots ); const timeRangeVariable = useMemo(() => { return { start: timeRange?.start?.toISOString(), end: timeRange?.end?.toISOString(), }; }, [timeRange]); const navigate = useNavigate(); const { rootPath, tab } = useProjectRootPath(); const data = useLazyLoadQuery<ProjectPageQueryType>( graphql` query ProjectPageQuery($id: ID!, $timeRange: TimeRange!) { project: node(id: $id) { ...ProjectPageHeader_stats ...StreamToggle_data } } `, { id: projectId as string, timeRange: timeRangeVariable, }, { fetchPolicy: "store-and-network", fetchKey: `${projectId}-${timeRangeVariable.start}-${timeRangeVariable.end}`, } ); const [tracesQueryReference, loadTracesQuery, disposeTracesQuery] = useQueryLoader<ProjectPageTracesQueryType>(ProjectPageQueriesTracesQuery); const [spansQueryReference, loadSpansQuery, disposeSpansQuery] = useQueryLoader<ProjectPageSpansQueryType>(ProjectPageQueriesSpansQuery); const [sessionsQueryReference, loadSessionsQuery, disposeSessionsQuery] = useQueryLoader<ProjectPageSessionsQueryType>( ProjectPageQueriesSessionsQuery ); const [ projectConfigQueryReference, loadProjectConfigQuery, disposeProjectConfigQuery, ] = useQueryLoader<ProjectPageProjectConfigQueryType>( ProjectPageQueriesProjectConfigQuery ); const tabIndex = isTab(tab) ? TAB_INDEX_MAP[tab] : 0; useEffect(() => { if (tabIndex === TAB_INDEX_MAP.spans) { loadSpansQuery({ id: projectId as string, timeRange: timeRangeVariable, orphanSpanAsRootSpan: treatOrphansAsRoots, }); } else if (tabIndex === TAB_INDEX_MAP.traces) { loadTracesQuery({ id: projectId as string, timeRange: timeRangeVariable, }); } else if (tabIndex === TAB_INDEX_MAP.sessions) { loadSessionsQuery({ id: projectId as string, timeRange: timeRangeVariable, }); } else if (tabIndex === TAB_INDEX_MAP.config) { loadProjectConfigQuery({ id: projectId as string, }); } return () => { disposeSpansQuery(); disposeSessionsQuery(); disposeTracesQuery(); disposeProjectConfigQuery(); }; }, [ loadTracesQuery, projectId, timeRangeVariable, tabIndex, disposeSpansQuery, disposeSessionsQuery, disposeTracesQuery, loadSpansQuery, loadSessionsQuery, loadProjectConfigQuery, disposeProjectConfigQuery, treatOrphansAsRoots, ]); const onTabChange = useCallback( (index: number) => { startTransition(() => { if (index === 1) { // navigate to the traces tab navigate(`${rootPath}/traces`); } else if (index === 2) { // navigate to the sessions tab navigate(`${rootPath}/sessions`); } else if (index === 3) { // navigate to the metrics tab navigate(`${rootPath}/metrics`); } else if (index === 4) { // navigate to the config tab navigate(`${rootPath}/config`); } else { // navigate to the spans tab navigate(`${rootPath}/spans`); } }); }, [navigate, rootPath] ); return ( <StreamStateProvider> <main css={mainCSS}> <ProjectPageHeader project={data.project} extra={ <Flex direction="row" alignItems="center" gap="size-100"> <StreamToggle project={data.project} /> <ConnectedTimeRangeSelector /> </Flex> } /> <ProjectPageQueryReferenceContext.Provider value={{ spansQueryReference: spansQueryReference ?? null, sessionsQueryReference: sessionsQueryReference ?? null, tracesQueryReference: tracesQueryReference ?? null, projectConfigQueryReference: projectConfigQueryReference ?? null, }} > <Tabs onSelectionChange={(key) => { if (typeof key === "string" && isTab(key)) { onTabChange(TAB_INDEX_MAP[key]); } }} selectedKey={tab} > <TabList> <Tab id="spans">Spans</Tab> <Tab id="traces">Traces</Tab> <Tab id="sessions">Sessions</Tab> <Tab id="metrics">Metrics</Tab> <Tab id="config">Config</Tab> </TabList> <LazyTabPanel padded={false} id="spans"> <Outlet /> </LazyTabPanel> <LazyTabPanel padded={false} id="traces"> <Outlet /> </LazyTabPanel> <LazyTabPanel padded={false} id="sessions"> <Outlet /> </LazyTabPanel> <LazyTabPanel padded={false} id="metrics"> <Outlet /> </LazyTabPanel> <LazyTabPanel padded={false} id="config"> <Outlet /> </LazyTabPanel> </Tabs> </ProjectPageQueryReferenceContext.Provider> </main> </StreamStateProvider> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Arize-ai/phoenix'

If you have feedback or need assistance with the MCP directory API, please join our Discord server