Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
b16090b
fix(evaluators): show only detailed gallery description
rickarize Aug 25, 2026
f7538fc
feat(evaluators): add metadata badges to gallery cards
rickarize Aug 26, 2026
747fe6f
feat(evaluators): support custom label, variant, and gallery-item vis…
rickarize Aug 27, 2026
12f9ea7
feat(evaluators): replace scratch-start actions with unified Add Cust…
rickarize Aug 27, 2026
2e83790
feat(evaluators): add tooltip to gallery card evaluation-target badges
rickarize Aug 27, 2026
7a8a781
fix(ui): unify evaluator kind badge and fix Token line-height scaling
rickarize Aug 27, 2026
71cb6f8
feat(evaluators): double-click gallery template card to customize
rickarize Aug 27, 2026
f02854c
fix(ui): return to evaluator gallery after closing scratch-creation m…
rickarize Aug 27, 2026
7118e6d
fix(ui): clarify evaluator gallery and menu wording
rickarize Aug 27, 2026
8b8c4c7
feat(evaluators): add expandable prompt preview to gallery card details
rickarize Aug 27, 2026
9ded0c5
fix(ui): declutter evaluator empty state and surface gallery promo
rickarize Aug 27, 2026
f37374c
fix(ui): page evaluator gallery carousel by full groups
rickarize Aug 27, 2026
56846ba
fix(ui): flatten evaluator gallery into a single scrolling use-case s…
rickarize Aug 27, 2026
bd1d8dd
fix: preserve evaluator creation origin on cancel
yfrigui2 Aug 28, 2026
c955918
fix: synchronize evaluator gallery deep links
yfrigui2 Aug 28, 2026
c9c6636
fix: isolate evaluator carousel scrolling
yfrigui2 Aug 28, 2026
f4309fd
fix(evaluators): improve gallery collection behavior
yfrigui2 Aug 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions js/app/src/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ import {
LoggedOutPage,
LoginPage,
NewCodeProjectEvaluatorPage,
NewGalleryCodeProjectEvaluatorPage,
NewGalleryLlmFromTemplateProjectEvaluatorPage,
NewGalleryLlmProjectEvaluatorPage,
NewLlmProjectEvaluatorPage,
OAuth2ConsentPage,
PlaygroundPage,
Expand Down Expand Up @@ -562,40 +560,62 @@ export const appRouteObjects = createRoutesFromElements(
agentRoute: {
label: "Project Evaluator Gallery",
description:
"Browse evaluator templates and start a project evaluator from a template or from scratch.",
"Browse evaluator templates and create a project evaluator from a template, from scratch, or an existing evaluator.",
},
}}
>
<Route
path="new/template/:templateName"
element={<NewGalleryLlmFromTemplateProjectEvaluatorPage />}
handle={{
agentRoute: {
label: "New Project Evaluator From Gallery Template",
description:
"Create a project LLM evaluator seeded from the selected evaluator gallery template.",
},
}}
/>
<Route
path="new/llm"
element={<NewGalleryLlmProjectEvaluatorPage />}
element={<NewLlmProjectEvaluatorPage />}
handle={{
agentRoute: {
label: "New Project LLM Evaluator From Gallery",
description:
"Author a new LLM-as-a-judge evaluator from scratch while browsing the evaluator gallery.",
"Author a new LLM-as-a-judge evaluator for a project from scratch, started from the evaluator gallery.",
},
}}
/>
<Route
path="new/code"
element={<NewGalleryCodeProjectEvaluatorPage />}
element={<NewCodeProjectEvaluatorPage />}
handle={{
agentRoute: {
label: "New Project Code Evaluator From Gallery",
description:
"Author a new Python or TypeScript code evaluator from scratch while browsing the evaluator gallery.",
"Author a new Python or TypeScript code evaluator for a project from scratch, started from the evaluator gallery.",
},
}}
/>
<Route
path="new/template/:templateName"
element={<NewGalleryLlmFromTemplateProjectEvaluatorPage />}
path="new/copy/:evaluatorId"
element={<CopyLlmProjectEvaluatorPage />}
handle={{
agentRoute: {
label: "New Project Evaluator From Gallery Template",
label: "Copy LLM Evaluator Into Project From Gallery",
description:
"Create a project LLM evaluator seeded from the selected evaluator gallery template.",
"Create a project evaluator seeded from an existing LLM evaluator while browsing the evaluator gallery. The evaluatorId route param uses the GraphQL Evaluator.id Relay node ID of the evaluator being copied.",
},
}}
/>
<Route
path="new/attach/:evaluatorId"
element={<AttachCodeProjectEvaluatorPage />}
handle={{
agentRoute: {
label: "Attach Code Evaluator To Project From Gallery",
description:
"Attach an existing code evaluator to a project while browsing the evaluator gallery. The evaluatorId route param uses the GraphQL Evaluator.id Relay node ID of the evaluator being attached.",
},
}}
/>
Expand Down
4 changes: 4 additions & 0 deletions js/app/src/components/core/badge/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@ export interface BadgeProps extends StylableProps {
* @default 'wrap'
*/
overflowMode?: BadgeOverflowMode;
/**
* Native tooltip text shown on hover.
*/
title?: string;
}
6 changes: 5 additions & 1 deletion js/app/src/components/core/token/Token.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ const tokenBaseCSS = css`
visual's margin so the pill reads as one unit. */
gap: var(--global-dimension-size-50);
font-size: var(--global-dimension-font-size-75);
line-height: var(--global-line-height-s);
padding: 0 var(--global-dimension-size-100);
border-radius: var(--global-rounding-large);
border: 1px solid transparent;
Expand All @@ -72,17 +71,22 @@ const tokenBaseCSS = css`

&[data-size="S"] {
height: var(--global-dimension-size-200);
/* Match line-height to height (both 16px) — otherwise the 20px "S"
body line-height overflows this pill's shorter box. */
line-height: var(--global-line-height-xs);
}

&[data-size="M"] {
height: var(--global-dimension-size-250);
line-height: var(--global-line-height-s);
}

&[data-size="L"] {
height: var(--global-dimension-size-300);
/* The large token scales its typography up to body size so token-heavy
detail views stay readable; S and M keep the compact font. */
font-size: var(--global-dimension-font-size-100);
line-height: var(--global-line-height-m);
}

/* Center the leading visual and the remove button inside the pill's
Expand Down
45 changes: 35 additions & 10 deletions js/app/src/pages/project/evaluators/AddProjectEvaluatorMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,28 @@ import { Truncate } from "@phoenix/components/core/utility/Truncate";
import { View } from "@phoenix/components/core/view";
import type { projectEvaluatorOptionsQuery } from "@phoenix/pages/project/evaluators/__generated__/projectEvaluatorOptionsQuery.graphql";
import { projectEvaluatorOptionsQuery as projectEvaluatorOptionsQueryNode } from "@phoenix/pages/project/evaluators/projectEvaluatorOptions";
import { useProjectEvaluatorPaths } from "@phoenix/pages/project/evaluators/projectEvaluatorPaths";
import {
type ProjectEvaluatorCreationPaths,
useProjectEvaluatorPaths,
} from "@phoenix/pages/project/evaluators/projectEvaluatorPaths";

export const AddProjectEvaluatorMenu = ({
size,
buttonClassName,
buttonLabel = "Add evaluator",
shouldShowGalleryLink = true,
creationPaths,
...props
}: ProjectEvaluatorMenuTriggerProps) => {
return (
<ProjectEvaluatorMenu
size={size}
buttonLabel="Add evaluator"
buttonClassName={buttonClassName}
buttonLabel={buttonLabel}
buttonVariant="primary"
buttonLeadingVisual={<Icon svg={<Icons.Plus />} />}
shouldShowGalleryLink
shouldShowGalleryLink={shouldShowGalleryLink}
creationPaths={creationPaths}
{...props}
/>
);
Expand All @@ -59,14 +68,22 @@ export const BuildProjectEvaluatorMenu = ({

type ProjectEvaluatorMenuTriggerProps = {
size: ButtonProps["size"];
buttonClassName?: string;
buttonLabel?: string;
/** Hide the "Browse eval gallery" item, e.g. when already on the gallery page. */
shouldShowGalleryLink?: boolean;
/** The routes to use for every evaluator-creation action in this menu. */
creationPaths: ProjectEvaluatorCreationPaths;
} & Omit<MenuTriggerProps, "children">;

function ProjectEvaluatorMenu({
size,
buttonClassName,
buttonLabel,
buttonVariant,
buttonLeadingVisual,
shouldShowGalleryLink,
creationPaths,
...props
}: ProjectEvaluatorMenuTriggerProps & {
buttonLabel: string;
Expand All @@ -77,6 +94,7 @@ function ProjectEvaluatorMenu({
return (
<MenuTrigger {...props}>
<Button
className={buttonClassName}
variant={buttonVariant}
size={size}
leadingVisual={buttonLeadingVisual}
Expand All @@ -90,6 +108,7 @@ function ProjectEvaluatorMenu({
<ProjectEvaluatorMenuItems
menuLabel={buttonLabel}
shouldShowGalleryLink={shouldShowGalleryLink}
creationPaths={creationPaths}
/>
</Suspense>
</MenuContainer>
Expand All @@ -100,9 +119,11 @@ function ProjectEvaluatorMenu({
function ProjectEvaluatorMenuItems({
menuLabel,
shouldShowGalleryLink,
creationPaths,
}: {
menuLabel: string;
shouldShowGalleryLink: boolean;
creationPaths: ProjectEvaluatorCreationPaths;
}) {
const navigate = useNavigate();
const paths = useProjectEvaluatorPaths();
Expand All @@ -126,9 +147,9 @@ function ProjectEvaluatorMenuItems({
aria-label={menuLabel}
onAction={(action) => {
if (action === "createEvaluator") {
navigate(paths.newLlm);
navigate(creationPaths.newLlm);
} else if (action === "createCodeEvaluator") {
navigate(paths.newCode);
navigate(creationPaths.newCode);
}
}}
>
Expand All @@ -139,7 +160,7 @@ function ProjectEvaluatorMenuItems({
id="browseGallery"
href={galleryHref}
>
Browse the whole library
Browse eval gallery
</MenuItem>
</MenuSection>
) : null}
Expand All @@ -152,10 +173,12 @@ function ProjectEvaluatorMenuItems({
Create new LLM evaluator
</MenuItem>
<EvaluatorSubmenu
label="Copy existing LLM evaluator"
label="Duplicate existing LLM evaluator"
icon={<Icons.LLMOutput />}
evaluators={llmEvaluators}
onAction={(evaluatorId) => navigate(paths.copyLlm(evaluatorId))}
onAction={(evaluatorId) =>
navigate(creationPaths.copyLlm(evaluatorId))
}
/>
</MenuSection>
<MenuSection>
Expand All @@ -167,10 +190,12 @@ function ProjectEvaluatorMenuItems({
Create new code evaluator
</MenuItem>
<EvaluatorSubmenu
label="Attach existing code evaluator"
label="Use existing code evaluator"
icon={<Icons.Code />}
evaluators={codeEvaluators}
onAction={(evaluatorId) => navigate(paths.attachCode(evaluatorId))}
onAction={(evaluatorId) =>
navigate(creationPaths.attachCode(evaluatorId))
}
/>
</MenuSection>
</Menu>
Expand Down
54 changes: 54 additions & 0 deletions js/app/src/pages/project/evaluators/EvaluatorTemplateCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { css } from "@emotion/react";
import type { ReactNode, Ref } from "react";

import { ListBoxItem } from "@phoenix/components";
import { classNames } from "@phoenix/utils/classNames";

type EvaluatorTemplateCardProps = {
id: string;
textValue: string;
children: ReactNode;
ref?: Ref<HTMLDivElement>;
};

export function EvaluatorTemplateCard({
id,
textValue,
children,
ref,
}: EvaluatorTemplateCardProps) {
return (
<ListBoxItem
ref={ref}
css={evaluatorTemplateCardCSS}
id={id}
textValue={textValue}
className={classNames(
"react-aria-ListBoxItem",
"evaluator-template-card"
)}
>
{children}
</ListBoxItem>
);
}

const evaluatorTemplateCardCSS = css`
&& {
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: flex-start;
width: 100%;
height: auto;
min-height: var(--global-dimension-size-1400);
gap: var(--global-dimension-size-100);
margin: 0;
padding: var(--global-dimension-size-150);
text-align: left;
border: var(--global-border-size-thin) solid
var(--global-border-color-default);
border-radius: var(--global-rounding-small);
}
`;
Loading
Loading