From 5a6e3273d711a0b43473ff9c8f9911b4ea19dee6 Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Fri, 29 May 2026 13:25:04 +0200 Subject: [PATCH 01/71] fix(frontend): keep evaluator chain connected on app-revision change changePrimaryNode cleared all output connections when the primary app node was re-selected. Because the primary node is updated in place (its id is preserved), the app -> evaluator edge stayed valid, but clearing it orphaned the still-present evaluator node. connectDownstreamNode then no-ops on the existing evaluator, so the edge was never recreated and the evaluator silently stopped running after the first app-revision change. Preserve connections whose endpoints still reference existing nodes instead of clearing unconditionally. --- .../state/controllers/playgroundController.ts | 14 ++++- .../src/state/helpers/connectionGraph.ts | 25 +++++++++ .../tests/unit/connectionGraph.test.ts | 55 +++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 web/packages/agenta-playground/src/state/helpers/connectionGraph.ts create mode 100644 web/packages/agenta-playground/tests/unit/connectionGraph.test.ts diff --git a/web/packages/agenta-playground/src/state/controllers/playgroundController.ts b/web/packages/agenta-playground/src/state/controllers/playgroundController.ts index ce7046c782..6534407c81 100644 --- a/web/packages/agenta-playground/src/state/controllers/playgroundController.ts +++ b/web/packages/agenta-playground/src/state/controllers/playgroundController.ts @@ -78,6 +78,7 @@ import { newTestcaseCountAtom, newTestcaseDataHashAtom, } from "../execution/selectors" +import {pruneDanglingConnections} from "../helpers/connectionGraph" import {extractAndLoadChatMessagesAtom} from "../helpers/extractAndLoadChatMessages" import {normalizeTestcaseRowsForLoad} from "../helpers/testcaseRowNormalization" import type {EntitySelection, PlaygroundNode, RunnableType} from "../types" @@ -408,8 +409,17 @@ const changePrimaryNodeAtom = atom(null, (get, set, entity: EntitySelection) => label: entity.label, } - set(playgroundNodesAtom, [updatedNode, ...nodes.slice(1)]) - set(outputConnectionsAtom, []) + const nextNodes = [updatedNode, ...nodes.slice(1)] + set(playgroundNodesAtom, nextNodes) + + // Preserve downstream connections instead of clearing them. The primary + // node is updated in place, so its `id` is unchanged and any chain sourced + // from it (e.g. app → evaluator) stays valid. Clearing unconditionally + // orphaned the downstream evaluator on app-revision re-selection: + // connectDownstreamNode then no-ops because the evaluator node is still + // present, so the edge was never recreated and the evaluator silently + // stopped running. Only drop connections whose endpoints no longer exist. + set(outputConnectionsAtom, pruneDanglingConnections(get(outputConnectionsAtom), nextNodes)) // Update local testset name if not connected to a remote testset const currentTestset = get(connectedTestsetAtom) diff --git a/web/packages/agenta-playground/src/state/helpers/connectionGraph.ts b/web/packages/agenta-playground/src/state/helpers/connectionGraph.ts new file mode 100644 index 0000000000..ded7736f0a --- /dev/null +++ b/web/packages/agenta-playground/src/state/helpers/connectionGraph.ts @@ -0,0 +1,25 @@ +/** + * Connection graph helpers + * + * Pure functions for reasoning about the playground DAG's output connections. + */ + +import type {OutputConnection, PlaygroundNode} from "../types" + +/** + * Keep only connections whose source and target both reference existing nodes. + * + * Used when the primary node is swapped in place (its `id` is preserved), so + * downstream chains sourced from it stay valid and must not be wiped. Any + * connection pointing at a node that no longer exists is dropped. + */ +export function pruneDanglingConnections( + connections: OutputConnection[], + nodes: PlaygroundNode[], +): OutputConnection[] { + const nodeIds = new Set(nodes.map((node) => node.id)) + return connections.filter( + (connection) => + nodeIds.has(connection.sourceNodeId) && nodeIds.has(connection.targetNodeId), + ) +} diff --git a/web/packages/agenta-playground/tests/unit/connectionGraph.test.ts b/web/packages/agenta-playground/tests/unit/connectionGraph.test.ts new file mode 100644 index 0000000000..b26b50d4b9 --- /dev/null +++ b/web/packages/agenta-playground/tests/unit/connectionGraph.test.ts @@ -0,0 +1,55 @@ +import {describe, expect, it} from "vitest" + +import {pruneDanglingConnections} from "../../src/state/helpers/connectionGraph" +import type {OutputConnection, PlaygroundNode} from "../../src/state/types" + +function node(id: string, depth: number): PlaygroundNode { + return {id, entityType: "workflow", entityId: `entity-${id}`, label: id, depth} +} + +function connection(id: string, sourceNodeId: string, targetNodeId: string): OutputConnection { + return { + id, + sourceNodeId, + targetNodeId, + sourceOutputKey: "output", + inputMappings: [], + parallel: true, + } +} + +describe("pruneDanglingConnections", () => { + // Regression: changePrimaryNode swaps the primary node in place (same node + // id), so the app → evaluator edge must survive an app-revision change. + // Previously the controller cleared all connections here, orphaning the + // evaluator so it silently stopped running. + it("preserves the app → evaluator edge when the primary node is swapped in place", () => { + const nodes = [node("N0", 0), node("N1", 1)] + const connections = [connection("conn-1", "N0", "N1")] + + expect(pruneDanglingConnections(connections, nodes)).toEqual(connections) + }) + + it("drops connections whose source node no longer exists", () => { + const nodes = [node("N0", 0), node("N1", 1)] + const connections = [ + connection("conn-1", "N0", "N1"), + connection("conn-stale", "GONE", "N1"), + ] + + expect(pruneDanglingConnections(connections, nodes)).toEqual([ + connection("conn-1", "N0", "N1"), + ]) + }) + + it("drops connections whose target node no longer exists", () => { + const nodes = [node("N0", 0)] + const connections = [connection("conn-1", "N0", "N1")] + + expect(pruneDanglingConnections(connections, nodes)).toEqual([]) + }) + + it("returns an empty array when there are no connections", () => { + expect(pruneDanglingConnections([], [node("N0", 0)])).toEqual([]) + }) +}) From d4d1263ad2fc81fe45995fb320e2e0711e53c129 Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Fri, 29 May 2026 13:52:17 +0200 Subject: [PATCH 02/71] fix(frontend): split provider and models columns in custom providers table --- .../Secrets/SecretProviderTable/index.tsx | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/web/oss/src/components/pages/settings/Secrets/SecretProviderTable/index.tsx b/web/oss/src/components/pages/settings/Secrets/SecretProviderTable/index.tsx index 07fbc1422d..4cace211eb 100644 --- a/web/oss/src/components/pages/settings/Secrets/SecretProviderTable/index.tsx +++ b/web/oss/src/components/pages/settings/Secrets/SecretProviderTable/index.tsx @@ -80,9 +80,9 @@ const SecretProviderTable = ({type}: {type: "standard" | "custom"}) => { ...(isCustom ? [ { - title: "Model", - dataIndex: "model", - key: "model", + title: "Provider", + dataIndex: "provider", + key: "provider", onHeaderCell: () => ({ style: {minWidth: 160}, }), @@ -100,6 +100,36 @@ const SecretProviderTable = ({type}: {type: "standard" | "custom"}) => { ) }, }, + { + title: "Models", + dataIndex: "models", + key: "models", + onHeaderCell: () => ({ + style: {minWidth: 200}, + }), + render: (_: any, record: LlmProvider) => { + const models = record?.models ?? [] + + if (models.length === 0) { + return - + } + + return ( +
+ {models.map((model) => ( + + {model} + + ))} +
+ ) + }, + }, ] : []), { From 6c7f3e3bcb32d428d44579e03ab66e2af3ac3578 Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Fri, 29 May 2026 17:55:32 +0200 Subject: [PATCH 03/71] fix(frontend): mask provider API key/secret fields and disable browser autofill --- .../ConfigureProviderDrawer/assets/constants.ts | 4 ++++ .../ModelRegistry/assets/LabelInput/index.tsx | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/constants.ts b/web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/constants.ts index def625f5c9..6251c0b76c 100644 --- a/web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/constants.ts +++ b/web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/constants.ts @@ -23,6 +23,7 @@ export const PROVIDER_FIELDS: { note: "This secret will be encrypted in transit and at rest.", model: ["azure", "custom", ...STANDARD_PROVIDER_KINDS], required: false, + attributes: {kind: "text", type: "password"}, }, { key: "apiBaseUrl", @@ -76,6 +77,7 @@ export const PROVIDER_FIELDS: { note: "This secret will be encrypted in transit and at rest.", model: ["bedrock", "sagemaker"], required: false, + attributes: {kind: "text", type: "password"}, }, { key: "accessKey", @@ -84,6 +86,7 @@ export const PROVIDER_FIELDS: { note: "This secret will be encrypted in transit and at rest.", model: ["bedrock", "sagemaker"], required: false, + attributes: {kind: "text", type: "password"}, }, { key: "sessionToken", @@ -92,5 +95,6 @@ export const PROVIDER_FIELDS: { note: "This secret will be encrypted in transit and at rest.", model: [], required: false, + attributes: {kind: "text", type: "password"}, }, ] diff --git a/web/oss/src/components/ModelRegistry/assets/LabelInput/index.tsx b/web/oss/src/components/ModelRegistry/assets/LabelInput/index.tsx index 912f17bc2b..c5732c6c07 100644 --- a/web/oss/src/components/ModelRegistry/assets/LabelInput/index.tsx +++ b/web/oss/src/components/ModelRegistry/assets/LabelInput/index.tsx @@ -15,6 +15,7 @@ const LabelInput = ({ ...props }: LabelInputProps) => { const resolvedInputType = type ?? inputType + const isPassword = resolvedInputType === "password" return (
@@ -24,6 +25,8 @@ const LabelInput = ({ variant="borderless" className={clsx("px-0 rounded-none", className)} autoSize={{minRows: 1}} + spellCheck={false} + autoComplete="off" style={{ overflowY: "hidden", overflowX: "hidden", @@ -32,11 +35,21 @@ const LabelInput = ({ }} {...(props as TextAreaProps)} /> + ) : isPassword ? ( + ) : ( )} From 4f3186d596eff96ad62c7f665d366062a52daaee Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Fri, 29 May 2026 19:55:52 +0200 Subject: [PATCH 04/71] fix(frontend): rename settings sidebar item from Models to Providers & Models --- web/oss/src/components/Sidebar/SettingsSidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/oss/src/components/Sidebar/SettingsSidebar.tsx b/web/oss/src/components/Sidebar/SettingsSidebar.tsx index 364ba72c0d..1559145762 100644 --- a/web/oss/src/components/Sidebar/SettingsSidebar.tsx +++ b/web/oss/src/components/Sidebar/SettingsSidebar.tsx @@ -83,7 +83,7 @@ const SettingsSidebar: FC = ({lastPath}) => { : []), { key: "secrets", - title: "Models", + title: "Providers & Models", icon: , }, ...(canShowTools From 81e10cb2756e1761b4a6c44bade2823e095a3f15 Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Fri, 29 May 2026 20:11:15 +0200 Subject: [PATCH 05/71] fix(frontend): align settings page title and e2e helper to Providers & Models --- .../w/[workspace_id]/p/[project_id]/settings/index.tsx | 2 +- .../tests/fixtures/base.fixture/providerHelpers/index.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx b/web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx index e120a8d4e2..160faa318c 100644 --- a/web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx +++ b/web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx @@ -161,7 +161,7 @@ const Settings: React.FC = () => { ), } case "secrets": - return {content: , title: "Models"} + return {content: , title: "Providers & Models"} case "tools": return {content: , title: "Tools"} case "apiKeys": diff --git a/web/tests/tests/fixtures/base.fixture/providerHelpers/index.ts b/web/tests/tests/fixtures/base.fixture/providerHelpers/index.ts index 208f61bca1..a6eb960c71 100644 --- a/web/tests/tests/fixtures/base.fixture/providerHelpers/index.ts +++ b/web/tests/tests/fixtures/base.fixture/providerHelpers/index.ts @@ -137,7 +137,7 @@ async function waitForModelsPageReady(page: Page): Promise { const pathname = new URL(page.url()).pathname const hasScopedSettingsPath = /\/w\/[^/]+\/p\/[^/]+\/settings$/.test(pathname) const headingVisible = await page - .getByRole("heading", {name: "Models"}) + .getByRole("heading", {name: "Providers & Models"}) .isVisible() .catch(() => false) const sectionVisible = await customProvidersSection.isVisible().catch(() => false) @@ -181,7 +181,9 @@ async function navigateToModels(page: Page, uiHelpers: UIHelpers): Promise await page.goto(`${projectBasePath}/settings?tab=secrets`, {waitUntil: "domcontentloaded"}) await uiHelpers.expectPath("/settings") - await expect(page.getByRole("heading", {name: "Models"})).toBeVisible({timeout: 15000}) + await expect(page.getByRole("heading", {name: "Providers & Models"})).toBeVisible({ + timeout: 15000, + }) await expect(getCustomProvidersSection(page)).toBeVisible({timeout: 15000}) await waitForModelsPageReady(page) } From 1d4ae762de97ad0c96eb0f70103c535c28db43fe Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Fri, 29 May 2026 20:25:35 +0200 Subject: [PATCH 06/71] fix(frontend): align secrets breadcrumb label and use new-password autocomplete for API key --- .../src/components/ModelRegistry/assets/LabelInput/index.tsx | 2 +- .../pages/w/[workspace_id]/p/[project_id]/settings/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/oss/src/components/ModelRegistry/assets/LabelInput/index.tsx b/web/oss/src/components/ModelRegistry/assets/LabelInput/index.tsx index c5732c6c07..c64bbd6e9e 100644 --- a/web/oss/src/components/ModelRegistry/assets/LabelInput/index.tsx +++ b/web/oss/src/components/ModelRegistry/assets/LabelInput/index.tsx @@ -40,7 +40,7 @@ const LabelInput = ({ variant="borderless" className={clsx("px-0 rounded-none", className)} spellCheck={false} - autoComplete="off" + autoComplete="new-password" {...props} /> ) : ( diff --git a/web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx b/web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx index 160faa318c..e6a2e8dafb 100644 --- a/web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx +++ b/web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx @@ -113,7 +113,7 @@ const Settings: React.FC = () => { case "projects": return "Projects" case "secrets": - return "Models" + return "Providers & Models" case "tools": return "Tools" case "apiKeys": From 8bb3c72f2ce1bbec5164ee197e5870e4dd24ff9a Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Fri, 29 May 2026 22:44:42 +0200 Subject: [PATCH 07/71] [AGE-3790] fix(frontend): drop entity id from URL when switching projects Switching projects while on an entity-scoped page (evaluation, playground, testset) kept the old entity id in the URL. Since that entity does not exist in the target project, the user landed on an empty screen. Preserve only the top-level section segment on project switch and drop nested entity ids. All top-level sections have index pages, so the truncated path always resolves. Logic extracted to a pure helper with regression tests. --- .../Sidebar/components/ListOfProjects.tsx | 22 ++-- .../assets/projectSwitchHref.test.ts | 123 ++++++++++++++++++ .../components/assets/projectSwitchHref.ts | 34 +++++ 3 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 web/oss/src/components/Sidebar/components/assets/projectSwitchHref.test.ts create mode 100644 web/oss/src/components/Sidebar/components/assets/projectSwitchHref.ts diff --git a/web/oss/src/components/Sidebar/components/ListOfProjects.tsx b/web/oss/src/components/Sidebar/components/ListOfProjects.tsx index c57f519260..3e8c1f861c 100644 --- a/web/oss/src/components/Sidebar/components/ListOfProjects.tsx +++ b/web/oss/src/components/Sidebar/components/ListOfProjects.tsx @@ -26,6 +26,8 @@ import {cacheWorkspaceOrgPair} from "@/oss/state/org/selectors/org" import {cacheLastUsedProjectId, useProjectData} from "@/oss/state/project" import {settingsTabAtom} from "@/oss/state/settings" +import {buildProjectSwitchHref} from "./assets/projectSwitchHref" + interface ListOfProjectsProps { collapsed: boolean buttonProps?: ButtonProps @@ -261,19 +263,13 @@ const ListOfProjects = ({ cacheLastUsedProjectId(workspaceId, projectId) if (organizationId) cacheWorkspaceOrgPair(workspaceId, organizationId) - // Extract the current page path to preserve navigation context - const currentPathMatch = router.asPath.match(/\/p\/[^/]+\/(.*)/) - const currentPagePath = currentPathMatch?.[1]?.split("?")[0] ?? "apps" - - // Preserve query params for settings tab - const isOnSettingsPage = currentPagePath.startsWith("settings") - const currentTab = - (settingsTab && settingsTab !== "workspace" ? settingsTab : undefined) ?? - (router.query.tab as string | undefined) - const tabParam = - isOnSettingsPage && currentTab ? `?tab=${encodeURIComponent(currentTab)}` : "" - - const href = `/w/${encodeURIComponent(workspaceId)}/p/${encodeURIComponent(projectId)}/${currentPagePath}${tabParam}` + const href = buildProjectSwitchHref({ + workspaceId, + projectId, + currentAsPath: router.asPath, + settingsTab, + queryTab: router.query.tab as string | undefined, + }) void router.push(href) }, diff --git a/web/oss/src/components/Sidebar/components/assets/projectSwitchHref.test.ts b/web/oss/src/components/Sidebar/components/assets/projectSwitchHref.test.ts new file mode 100644 index 0000000000..11350555c2 --- /dev/null +++ b/web/oss/src/components/Sidebar/components/assets/projectSwitchHref.test.ts @@ -0,0 +1,123 @@ +/** + * Regression tests for AGE-3790: switching projects keeps evaluation/playground + * in the URL. + * + * Bug: navigating to a new project while on an evaluation or playground (or any + * entity-scoped page) kept the old project's entity ID in the URL. That entity + * doesn't exist in the target project, so the user landed on an empty screen. + * + * Fix: when switching projects, preserve only the top-level section and drop any + * nested entity IDs. The settings tab query param is the one exception that + * carries over, since tabs exist across all projects. + */ +import {describe, expect, it} from "vitest" + +import {buildProjectSwitchHref} from "./projectSwitchHref" + +const WS = "ws-1" +const NEW_PROJECT = "proj-new" + +describe("buildProjectSwitchHref", () => { + it("drops the evaluation id and lands on the evaluations list", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old/evaluations/results/eval-123", + }) + expect(href).toBe("/w/ws-1/p/proj-new/evaluations") + }) + + it("drops the single-model-test evaluation id", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old/evaluations/single_model_test/eval-123", + }) + expect(href).toBe("/w/ws-1/p/proj-new/evaluations") + }) + + it("drops the app id and any deep playground sub-route to the apps list", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old/apps/app-123/playground", + }) + expect(href).toBe("/w/ws-1/p/proj-new/apps") + }) + + it("drops the testset id and lands on the testsets list", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old/testsets/testset-123", + }) + expect(href).toBe("/w/ws-1/p/proj-new/testsets") + }) + + it("keeps the top-level playground section as-is", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old/playground", + }) + expect(href).toBe("/w/ws-1/p/proj-new/playground") + }) + + it("keeps the top-level observability section as-is", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old/observability", + }) + expect(href).toBe("/w/ws-1/p/proj-new/observability") + }) + + it("falls back to apps when there is no section in the path", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old", + }) + expect(href).toBe("/w/ws-1/p/proj-new/apps") + }) + + it("strips query params from non-settings pages", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old/evaluations/results/compare?evaluations=a,b", + }) + expect(href).toBe("/w/ws-1/p/proj-new/evaluations") + }) + + it("preserves the settings tab query param", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old/settings", + settingsTab: "apikeys", + }) + expect(href).toBe("/w/ws-1/p/proj-new/settings?tab=apikeys") + }) + + it("ignores the default 'workspace' settings tab and falls back to the query tab", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old/settings?tab=secrets", + settingsTab: "workspace", + queryTab: "secrets", + }) + expect(href).toBe("/w/ws-1/p/proj-new/settings?tab=secrets") + }) + + it("does not add a tab param for non-settings pages even if a tab is present", () => { + const href = buildProjectSwitchHref({ + workspaceId: WS, + projectId: NEW_PROJECT, + currentAsPath: "/w/ws-1/p/proj-old/apps/app-123/traces", + queryTab: "spans", + }) + expect(href).toBe("/w/ws-1/p/proj-new/apps") + }) +}) diff --git a/web/oss/src/components/Sidebar/components/assets/projectSwitchHref.ts b/web/oss/src/components/Sidebar/components/assets/projectSwitchHref.ts new file mode 100644 index 0000000000..55e2c09b21 --- /dev/null +++ b/web/oss/src/components/Sidebar/components/assets/projectSwitchHref.ts @@ -0,0 +1,34 @@ +interface BuildProjectSwitchHrefParams { + workspaceId: string + projectId: string + currentAsPath: string + settingsTab?: string + queryTab?: string +} + +/** + * Builds the target URL when switching to a different project. + * + * Only the top-level section (e.g. "apps", "evaluations") is preserved. Nested + * entity IDs — an evaluation, app, testset, etc. — belong to the previous + * project and don't exist in the target project, so keeping them in the URL + * would land the user on an empty screen. The settings tab query param is the + * one exception that carries over, since tabs exist across all projects. + */ +export function buildProjectSwitchHref({ + workspaceId, + projectId, + currentAsPath, + settingsTab, + queryTab, +}: BuildProjectSwitchHrefParams): string { + const currentPathMatch = currentAsPath.match(/\/p\/[^/]+\/([^/?#]+)/) + const currentPagePath = currentPathMatch?.[1] ?? "apps" + + const isOnSettingsPage = currentPagePath.startsWith("settings") + const currentTab = + (settingsTab && settingsTab !== "workspace" ? settingsTab : undefined) ?? queryTab + const tabParam = isOnSettingsPage && currentTab ? `?tab=${encodeURIComponent(currentTab)}` : "" + + return `/w/${encodeURIComponent(workspaceId)}/p/${encodeURIComponent(projectId)}/${currentPagePath}${tabParam}` +} From 9555c70ca09753b42acd786c0f03b4e9d35b6317 Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Fri, 29 May 2026 22:49:02 +0200 Subject: [PATCH 08/71] [AGE-3789] fix(frontend): show evaluator names not slugs in observability table The observability table's evaluator metric columns only carry a slug, but evaluatorReferenceAtomFamily resolved names solely through its id-based workflow-revision query. Slug-only callers fell through to a minimal reference that returned name=slug, leaking slugs into the table. Add a slug-resolution branch that matches the slug against the loaded app+evaluator union list (workflowsListQueryStateAtom) to surface the real name, deferring while the list loads. Mirrors appReferenceAtomFamily. --- .../References/atoms/entityReferences.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/web/oss/src/components/References/atoms/entityReferences.ts b/web/oss/src/components/References/atoms/entityReferences.ts index ec7ce2c1d6..1359db08d0 100644 --- a/web/oss/src/components/References/atoms/entityReferences.ts +++ b/web/oss/src/components/References/atoms/entityReferences.ts @@ -345,6 +345,42 @@ export const evaluatorReferenceAtomFamily = atomFamily( } } + // Slug-only resolution (e.g. the observability table's evaluator + // metric columns, which only carry a slug). The id query above + // never runs in that case, so match the slug against the already + // loaded app+evaluator union list to surface the real `name` + // instead of leaking the slug. Mirrors `appReferenceAtomFamily`. + if (slug) { + const listState = get(workflowsListQueryStateAtom) + const listMatch = listState.data.find((w) => w.slug === slug) + + if (listMatch) { + return { + data: { + id: listMatch.id ?? id ?? null, + slug: listMatch.slug ?? slug, + name: listMatch.name ?? listMatch.slug ?? slug, + metrics: extractMetricsFromWorkflow(listMatch), + }, + isPending: false, + isFetching: false, + isLoading: false, + isError: false, + } + } + + // List still loading — defer rather than flash the slug. + if (listState.isPending) { + return { + data: null, + isPending: true, + isFetching: true, + isLoading: true, + isError: false, + } + } + } + // Nothing found — return minimal reference return { data: { From 7da8c779791398273f92f6d72a5ed47bd615ec50 Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Sat, 30 May 2026 00:00:56 +0200 Subject: [PATCH 09/71] fix(frontend): align archived evaluators page layout with active page Render archived evaluators through the same single PageLayout as the active Evaluators page, with a Back arrow + title in the standard h-11 header row. Drops the ArchivedEntityLayout wrapper, which double-framed the page (extra p-4 + tall stacked Back/title/subtitle header) and pushed the table ~60-70px lower, causing a visible vertical shift when toggling between Evaluators and Archived. --- .../Evaluators/ArchivedEvaluatorsPage.tsx | 18 +------------- web/oss/src/components/Evaluators/index.tsx | 24 ++++++++++++++++--- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/web/oss/src/components/Evaluators/ArchivedEvaluatorsPage.tsx b/web/oss/src/components/Evaluators/ArchivedEvaluatorsPage.tsx index 501014225a..ceb80bb4c2 100644 --- a/web/oss/src/components/Evaluators/ArchivedEvaluatorsPage.tsx +++ b/web/oss/src/components/Evaluators/ArchivedEvaluatorsPage.tsx @@ -1,21 +1,5 @@ -import {useRouter} from "next/router" - -import ArchivedEntityLayout from "@/oss/components/ArchivedEntityLayout" -import useURL from "@/oss/hooks/useURL" - import EvaluatorsRegistry from "." export default function ArchivedEvaluatorsPage() { - const router = useRouter() - const {projectURL} = useURL() - - return ( - router.push(`${projectURL}/evaluators`)} - > - - - ) + return } diff --git a/web/oss/src/components/Evaluators/index.tsx b/web/oss/src/components/Evaluators/index.tsx index 85082983e4..ed318a1469 100644 --- a/web/oss/src/components/Evaluators/index.tsx +++ b/web/oss/src/components/Evaluators/index.tsx @@ -12,7 +12,7 @@ import {extractApiErrorMessage} from "@agenta/shared/utils" import {PageLayout} from "@agenta/ui" import {message} from "@agenta/ui/app-message" import {PlusOutlined} from "@ant-design/icons" -import {ChartDonutIcon, ListChecksIcon, Tray} from "@phosphor-icons/react" +import {ArrowLeft, ChartDonutIcon, ListChecksIcon, Tray} from "@phosphor-icons/react" import {Button, Input, Space} from "antd" import {useAtom, useAtomValue, useSetAtom} from "jotai" import {useRouter} from "next/router" @@ -426,6 +426,24 @@ const EvaluatorsRegistry = ({scope = "project", mode = "active"}: EvaluatorsRegi [searchTerm, setSearchTerm], ) + const archivedTitle = useMemo(() => { + if (!isArchived) return undefined + + return ( + + diff --git a/web/oss/src/components/DrillInView/DrillInBreadcrumb.tsx b/web/oss/src/components/DrillInView/DrillInBreadcrumb.tsx index 2c288876d7..36054740fa 100644 --- a/web/oss/src/components/DrillInView/DrillInBreadcrumb.tsx +++ b/web/oss/src/components/DrillInView/DrillInBreadcrumb.tsx @@ -104,7 +104,7 @@ const DrillInBreadcrumb = memo( ) return ( -
+
{/* Fixed prefix (span navigation) - doesn't scroll */} {prefix &&
{prefix}
} diff --git a/web/oss/src/components/DrillInView/DrillInContent.tsx b/web/oss/src/components/DrillInView/DrillInContent.tsx index 5b8e1178c0..b2f0978093 100644 --- a/web/oss/src/components/DrillInView/DrillInContent.tsx +++ b/web/oss/src/components/DrillInView/DrillInContent.tsx @@ -1288,7 +1288,7 @@ function renderFieldContent({ if (!editable) { // Read-only preview return ( -
+            
                 {stringValue}
             
) @@ -1340,7 +1340,7 @@ function renderFieldContent({ // Numbers and booleans stay as-is (no escaping needed) return ( -
+            
                 {rawValue}
             
) @@ -1392,8 +1392,8 @@ function renderFieldContent({ "[&.ant-input-number]:!rounded-lg", "[&.ant-input-number]:!min-h-[52px]", "[&.ant-input-number]:!px-[11px]", - "[&.ant-input-number-outlined]:!border-[#BDC7D1]", - "[&.ant-input-number-outlined]:hover:!border-[#394857]", + "[&.ant-input-number-outlined]:!border-[var(--ag-c-BDC7D1)]", + "[&.ant-input-number-outlined]:hover:!border-[var(--ag-c-394857)]", "[&_.ant-input-number-input]:!p-0", "[&_.ant-input-number-input]:!h-[50px]", "[&_.ant-input-number-input]:!text-xs", diff --git a/web/oss/src/components/DrillInView/DrillInFieldHeader.tsx b/web/oss/src/components/DrillInView/DrillInFieldHeader.tsx index 4c195798b8..427ea4f128 100644 --- a/web/oss/src/components/DrillInView/DrillInFieldHeader.tsx +++ b/web/oss/src/components/DrillInView/DrillInFieldHeader.tsx @@ -224,7 +224,9 @@ function ViewModeDropdown({ option.value === value ? "bg-[rgba(5,23,41,0.04)]" : "" }`} > - {option.label} + + {option.label} + {option.value === value ? ( default ) : null} @@ -243,7 +245,7 @@ function ViewModeDropdown({
diff --git a/web/oss/src/components/Playground/Components/Menus/SelectVariant/components/VariantGroupTitle.tsx b/web/oss/src/components/Playground/Components/Menus/SelectVariant/components/VariantGroupTitle.tsx index 9793f45925..ab1e780a9e 100644 --- a/web/oss/src/components/Playground/Components/Menus/SelectVariant/components/VariantGroupTitle.tsx +++ b/web/oss/src/components/Playground/Components/Menus/SelectVariant/components/VariantGroupTitle.tsx @@ -23,8 +23,8 @@ const VariantGroupTitle = ({parent, defaultNode}: VariantGroupTitleProps) => { return (
- - + + {defaultNode ?? parent.variantName ?? parent.name ?? "Local Drafts"}
diff --git a/web/oss/src/components/Playground/Components/PlaygroundPromptComparisonView/PromptComparisonVariantNavigation/index.tsx b/web/oss/src/components/Playground/Components/PlaygroundPromptComparisonView/PromptComparisonVariantNavigation/index.tsx index 16a2c84cef..31b681bc77 100644 --- a/web/oss/src/components/Playground/Components/PlaygroundPromptComparisonView/PromptComparisonVariantNavigation/index.tsx +++ b/web/oss/src/components/Playground/Components/PlaygroundPromptComparisonView/PromptComparisonVariantNavigation/index.tsx @@ -54,7 +54,7 @@ const PromptComparisonVariantNavigation = ({ return (
-
+
Variants
diff --git a/web/oss/src/components/Playground/Components/PlaygroundVariantConfigPrompt/assets/GatewayToolsPanel.tsx b/web/oss/src/components/Playground/Components/PlaygroundVariantConfigPrompt/assets/GatewayToolsPanel.tsx index 06900c8f05..63c58c794c 100644 --- a/web/oss/src/components/Playground/Components/PlaygroundVariantConfigPrompt/assets/GatewayToolsPanel.tsx +++ b/web/oss/src/components/Playground/Components/PlaygroundVariantConfigPrompt/assets/GatewayToolsPanel.tsx @@ -43,7 +43,7 @@ export default function GatewayToolsPanel({mountDrawers = false}: GatewayToolsPa
{/* Header */}
- + GATEWAY TOOLS
{hasWindowingMeta ? ( -
+
{samplingRate && samplingRate !== "—" ? ( Sampling: {samplingRate} ) : null} diff --git a/web/oss/src/components/ResultTag/assets/styles.ts b/web/oss/src/components/ResultTag/assets/styles.ts index 811b887fb8..604e79a2cb 100644 --- a/web/oss/src/components/ResultTag/assets/styles.ts +++ b/web/oss/src/components/ResultTag/assets/styles.ts @@ -10,7 +10,7 @@ export const useStyles = createUseStyles((theme: JSSTheme) => ({ padding: 0, cursor: "pointer", "& > span.value1": { - backgroundColor: "rgba(0, 0, 0, 0.02)", + backgroundColor: theme.colorFillQuaternary, flex: 1, padding: "0px 8px", borderRight: `1px solid ${theme.colorBorder}`, diff --git a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/Annotate/index.tsx b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/Annotate/index.tsx index 91b9d6323a..3dc9e13536 100644 --- a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/Annotate/index.tsx +++ b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/Annotate/index.tsx @@ -153,7 +153,7 @@ const Annotate = ({ {ann.meta?.name || ann.references?.evaluator?.slug} {ann.references?.evaluator?.slug} @@ -199,7 +199,7 @@ const Annotate = ({ {eva.name} {eva.slug} @@ -292,7 +292,7 @@ const Annotate = ({ className={clsx( "rounded-none", "[&_.ant-collapse-content-box]:!p-0", - "[&_.ant-collapse-content]:!bg-white [&_.ant-collapse-content]:p-3", + "[&_.ant-collapse-content]:!bg-[var(--ag-c-FFFFFF)] [&_.ant-collapse-content]:p-3", "[&_.playground-property-control]:!mb-0", "[&_.ant-slider]:!mb-0 [&_.ant-slider]:!mt-1", "[&_.ant-collapse-header-text]:w-[95%]", diff --git a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/CreateEvaluator/assets/CreateNewMetric/index.tsx b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/CreateEvaluator/assets/CreateNewMetric/index.tsx index 834df92aac..9767f74677 100644 --- a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/CreateEvaluator/assets/CreateNewMetric/index.tsx +++ b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/CreateEvaluator/assets/CreateNewMetric/index.tsx @@ -112,7 +112,7 @@ const CreateNewMetric = ({ ) return ( -
+
Feedback name @@ -275,7 +275,9 @@ const CreateNewMetric = ({
{fields.length === 0 ? ( - No options configured + + No options configured + ) : ( fields.map((fieldItem, index) => (
diff --git a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/SelectEvaluators/index.tsx b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/SelectEvaluators/index.tsx index 47a404a643..c21e5b63ed 100644 --- a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/SelectEvaluators/index.tsx +++ b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/SelectEvaluators/index.tsx @@ -47,7 +47,7 @@ const SelectEvaluators = ({ setSearch(e.target.value)} />
@@ -77,7 +77,7 @@ const SelectEvaluators = ({ )} > {evaluator.name} - Metric + Metric ))} diff --git a/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionContentSummary/index.tsx b/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionContentSummary/index.tsx index 049431f8e3..698d62bd31 100644 --- a/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionContentSummary/index.tsx +++ b/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionContentSummary/index.tsx @@ -41,7 +41,7 @@ const SessionContentSummary = () => {
{key.replace(/_/g, " ")}
-
+
{formatSummaryValue(key, value as number | string[])}
diff --git a/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionHeader/index.tsx b/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionHeader/index.tsx index 7434df34b9..b658f8ee1c 100644 --- a/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionHeader/index.tsx +++ b/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionHeader/index.tsx @@ -57,7 +57,7 @@ const SessionHeader = () => { Session - + # {sessionId || "-"} diff --git a/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionMessagePanel/index.tsx b/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionMessagePanel/index.tsx index d5f53ce61d..3fb46788e3 100644 --- a/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionMessagePanel/index.tsx +++ b/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionMessagePanel/index.tsx @@ -49,8 +49,8 @@ const SessionMessagePanel = ({ defaultActiveKey={[label]} className={clsx( "border border-solid border-colorBorder overflow-hidden", - "[&_.ant-collapse-header]:bg-[#05172905] [&_.ant-collapse-header]:border-0 [&_.ant-collapse-header]:border-b [&_.ant-collapse-header]:border-solid [&_.ant-collapse-header]:border-colorSplit", - "[&_.ant-collapse-body]:!bg-white [&_.ant-collapse-body]:!p-0", + "[&_.ant-collapse-header]:bg-[var(--ag-c-05172905)] [&_.ant-collapse-header]:border-0 [&_.ant-collapse-header]:border-b [&_.ant-collapse-header]:border-solid [&_.ant-collapse-header]:border-colorSplit", + "[&_.ant-collapse-body]:!bg-[var(--ag-c-FFFFFF)] [&_.ant-collapse-body]:!p-0", )} items={[ { @@ -64,7 +64,7 @@ const SessionMessagePanel = ({ tooltipProps={{placement: "top", arrow: true}} > # {trace?.span_id || "-"} @@ -85,7 +85,7 @@ const SessionMessagePanel = ({ ({ top: 48, right: 24, zIndex: 100, - background: "#fff", + background: theme.colorBgContainer, borderRadius: 6, boxShadow: "0 2px 8px rgba(0,0,0,0.15)", display: "flex", diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/AnnotationTabItem/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/AnnotationTabItem/index.tsx index dd21ce8356..e644787a97 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/AnnotationTabItem/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/AnnotationTabItem/index.tsx @@ -24,7 +24,7 @@ import {getAnnotationTableColumns} from "./assets/getAnnotationTableColumns" const useStyles = createUseStyles((theme: JSSTheme) => ({ expandableTable: { "& .ant-table-cell": { - backgroundColor: "#F5F7FA", + backgroundColor: theme.colorFillTertiary, }, }, table: { diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/LinkedSpansTabItem/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/LinkedSpansTabItem/index.tsx index 6ea5eed0a9..ea022853bd 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/LinkedSpansTabItem/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/LinkedSpansTabItem/index.tsx @@ -112,7 +112,7 @@ const LinkedSpansTabItem = ({isActive}: LinkedSpansTabItemProps) => { navigateToLink(record)} > # {shortId} diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/TraceTypeHeader/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/TraceTypeHeader/index.tsx index 76b03a4e69..96497607f1 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/TraceTypeHeader/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/TraceTypeHeader/index.tsx @@ -210,7 +210,7 @@ const TraceTypeHeader = ({ title="Copy span id" tooltipProps={{placement: "bottom", arrow: true}} > - + # {activeTrace?.span_id || "-"} diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/index.tsx index 83bceb8902..fdb171f90b 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/index.tsx @@ -148,7 +148,7 @@ const TraceContent = ({ onChange={setTab} items={items} className={clsx( - "flex flex-col h-full [&_.ant-tabs-nav]:!sticky [&_.ant-tabs-nav]:!top-0 [&_.ant-tabs-nav]:!z-10 [&_.ant-tabs-nav]:!bg-white", + "flex flex-col h-full [&_.ant-tabs-nav]:!sticky [&_.ant-tabs-nav]:!top-0 [&_.ant-tabs-nav]:!z-10 [&_.ant-tabs-nav]:!bg-[var(--ag-c-FFFFFF)]", classes.tabs, )} /> diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceHeader/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceHeader/index.tsx index 52fc518bfb..9071855464 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceHeader/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceHeader/index.tsx @@ -482,7 +482,7 @@ const TraceHeader = ({ Trace - + # {displayTraceId || "-"} diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceAnnotations/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceAnnotations/index.tsx index 102ec56327..923c50c3d6 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceAnnotations/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceAnnotations/index.tsx @@ -252,7 +252,7 @@ const TraceAnnotations = ({annotations = []}: TraceAnnotationsProps) => { className={clsx( "flex items-center flex-wrap gap-1 justify-between", "py-1 px-3 cursor-pointer", - "rounded-lg border border-[#BDC7D1] border-solid", + "rounded-lg border border-[var(--ag-c-BDC7D1)] border-solid", )} > diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceDetails/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceDetails/index.tsx index 95e1d7df62..7261855a34 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceDetails/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceDetails/index.tsx @@ -63,7 +63,7 @@ const TraceDetails = ({activeTrace}: {activeTrace: TraceSpanNode}) => { Latency {formattedLatency} @@ -78,11 +78,11 @@ const TraceDetails = ({activeTrace}: {activeTrace: TraceSpanNode}) => { Start - {traceStartTime}
} bordered={false} - className="bg-[#0517290F]" + className="bg-[var(--ag-c-0517290F)]" /> End {" "}- {traceEndTime} @@ -95,7 +95,7 @@ const TraceDetails = ({activeTrace}: {activeTrace: TraceSpanNode}) => { Tokens & Cost diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceLinkedSpans/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceLinkedSpans/index.tsx index 907d681bb5..85eb23cd1a 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceLinkedSpans/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceLinkedSpans/index.tsx @@ -50,7 +50,7 @@ const TraceLinkedSpans = () => { handleNavigate(link)} > {" "} diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceTree/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceTree/index.tsx index 27197b9265..3db023f041 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceTree/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceTree/index.tsx @@ -48,7 +48,7 @@ export const TreeContent = ({value, settings}: {value: TraceSpanNode; settings: diff --git a/web/oss/src/components/Sidebar/Sidebar.tsx b/web/oss/src/components/Sidebar/Sidebar.tsx index 8a4688eb96..fe4234a767 100644 --- a/web/oss/src/components/Sidebar/Sidebar.tsx +++ b/web/oss/src/components/Sidebar/Sidebar.tsx @@ -93,7 +93,7 @@ const Sidebar: React.FC<{showSettingsView?: boolean; lastPath?: string}> = ({
{organization.name} - {isDemo && demo} + {isDemo && demo}
), diff --git a/web/oss/src/components/Sidebar/components/ListOfProjects.tsx b/web/oss/src/components/Sidebar/components/ListOfProjects.tsx index c57f519260..778195ef3d 100644 --- a/web/oss/src/components/Sidebar/components/ListOfProjects.tsx +++ b/web/oss/src/components/Sidebar/components/ListOfProjects.tsx @@ -409,7 +409,7 @@ const ListOfProjects = ({
{proj.project_name} {proj.is_default_project && ( - default + default )}
), diff --git a/web/oss/src/components/Sidebar/components/WorkflowEntityCard.tsx b/web/oss/src/components/Sidebar/components/WorkflowEntityCard.tsx index e165f28ead..c98dcae204 100644 --- a/web/oss/src/components/Sidebar/components/WorkflowEntityCard.tsx +++ b/web/oss/src/components/Sidebar/components/WorkflowEntityCard.tsx @@ -96,7 +96,7 @@ const SWITCHER_MENU_CLASS = clsx( "[&_.ant-dropdown-menu-item-group-title]:sticky", "[&_.ant-dropdown-menu-item-group-title]:top-0", "[&_.ant-dropdown-menu-item-group-title]:z-10", - "[&_.ant-dropdown-menu-item-group-title]:bg-white", + "[&_.ant-dropdown-menu-item-group-title]:bg-[var(--ag-c-FFFFFF)]", ) /** @@ -248,7 +248,7 @@ const WorkflowEntityCard = memo(({collapsed}: WorkflowEntityCardProps) => { return (
diff --git a/web/oss/src/components/SidebarBanners/SidebarBanner.tsx b/web/oss/src/components/SidebarBanners/SidebarBanner.tsx index cb5b9b2a73..9ad5cf2a36 100644 --- a/web/oss/src/components/SidebarBanners/SidebarBanner.tsx +++ b/web/oss/src/components/SidebarBanners/SidebarBanner.tsx @@ -29,7 +29,7 @@ const SidebarBanner = ({banner, onDismiss}: SidebarBannerProps) => { // If custom content is provided, render it instead if (banner.customContent) { return ( -
+
{banner.dismissible && onDismiss && ( diff --git a/web/oss/src/components/TestsetsTable/components/TestsetsFiltersSummary.tsx b/web/oss/src/components/TestsetsTable/components/TestsetsFiltersSummary.tsx index f4f98bed5c..51e77ce0ce 100644 --- a/web/oss/src/components/TestsetsTable/components/TestsetsFiltersSummary.tsx +++ b/web/oss/src/components/TestsetsTable/components/TestsetsFiltersSummary.tsx @@ -48,22 +48,22 @@ const TestsetsFiltersSummary = ({tableMode = "active"}: TestsetsFiltersSummaryPr if (!summary.hasFilters) { return ( - + No filters applied ) } return ( -
+
{summary.dateCreated && ( - Date Created:{" "} + Date Created:{" "} {formatDateLabel(summary.dateCreated.from)} -{" "} {formatDateLabel(summary.dateCreated.to)} @@ -73,10 +73,12 @@ const TestsetsFiltersSummary = ({tableMode = "active"}: TestsetsFiltersSummaryPr - Date Modified:{" "} + + Date Modified: + {" "} {formatDateLabel(summary.dateModified.from)} -{" "} {formatDateLabel(summary.dateModified.to)} diff --git a/web/oss/src/components/pages/app-management/components/ApplicationManagementSection.tsx b/web/oss/src/components/pages/app-management/components/ApplicationManagementSection.tsx index 8a986aacbe..8fd5ea8c59 100644 --- a/web/oss/src/components/pages/app-management/components/ApplicationManagementSection.tsx +++ b/web/oss/src/components/pages/app-management/components/ApplicationManagementSection.tsx @@ -137,7 +137,7 @@ const ApplicationManagementSection = ({mode = "active"}: ApplicationManagementSe const emptyState = useMemo(() => { if (isArchived) { return ( -
+
) diff --git a/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/assets/components/WelcomeCard.tsx b/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/assets/components/WelcomeCard.tsx index 3c7d330ccf..76294fde89 100644 --- a/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/assets/components/WelcomeCard.tsx +++ b/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/assets/components/WelcomeCard.tsx @@ -17,13 +17,15 @@ const WelcomeCard = ({title, subtitle, onClick, hidden}: WelcomeCardProps) => {
{title} - {subtitle} + + {subtitle} +
diff --git a/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/assets/styles.ts b/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/assets/styles.ts index 2e1ef2d12b..6422eeedf8 100644 --- a/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/assets/styles.ts +++ b/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/assets/styles.ts @@ -11,15 +11,15 @@ export const useStyles = createUseStyles((theme: JSSTheme) => ({ flexDirection: "column", width: "100%", flex: 1, - border: "1px solid #EAEFF5", + border: `1px solid ${theme.colorBorderSecondary}`, borderRadius: "10px", - backgroundColor: "white", + backgroundColor: theme.colorBgContainer, boxShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.03), 0 1px 6px -1px rgba(0, 0, 0, 0.02), 0 2px 4px 0 rgba(0, 0, 0, 0.02)", cursor: "pointer", transition: "background-color 0.2s", "&:hover": { - backgroundColor: "#F9FAFB", + backgroundColor: theme.colorFillTertiary, }, }, })) diff --git a/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/index.tsx b/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/index.tsx index 2276563279..d6e36d995a 100644 --- a/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/index.tsx +++ b/web/oss/src/components/pages/app-management/components/WelcomeCardsSection/index.tsx @@ -106,7 +106,7 @@ const WelcomeCardsSection = ({onCreatePrompt, onSetupTracing}: WelcomeCardsSecti if (onboardingWidgetStatus === "completed" || welcomeCardsDismissed) return null return ( -
+
Welcome, @@ -117,7 +117,7 @@ const WelcomeCardsSection = ({onCreatePrompt, onSetupTracing}: WelcomeCardsSecti
diff --git a/web/oss/src/components/pages/app-management/modals/CreateAppStatusModal.tsx b/web/oss/src/components/pages/app-management/modals/CreateAppStatusModal.tsx index 25c9b9540b..f07c53ba84 100644 --- a/web/oss/src/components/pages/app-management/modals/CreateAppStatusModal.tsx +++ b/web/oss/src/components/pages/app-management/modals/CreateAppStatusModal.tsx @@ -25,7 +25,7 @@ const useStyles = createUseStyles((theme: JSSTheme) => ({ topContainer: { wdith: "100%", height: 200, - backgroundColor: "#F5F7FA", + backgroundColor: theme.colorFillTertiary, display: "flex", alignItems: "center", justifyContent: "center", diff --git a/web/oss/src/components/pages/app-management/modals/CustomAppCreationLoader.tsx b/web/oss/src/components/pages/app-management/modals/CustomAppCreationLoader.tsx index 7258e28cee..631501e500 100644 --- a/web/oss/src/components/pages/app-management/modals/CustomAppCreationLoader.tsx +++ b/web/oss/src/components/pages/app-management/modals/CustomAppCreationLoader.tsx @@ -7,7 +7,7 @@ const CustomAppCreationLoader = ({isFinish}: {isFinish: boolean}) => { viewBox="0 0 160 160" fill="none" xmlns="http://www.w3.org/2000/svg" - className={`${isFinish && "*:!stroke-[#36cfc9] *:!shadow-[0px_0px_10px_0px_#B2F8FF]"}`} + className={`${isFinish && "*:!stroke-[var(--ag-c-36CFC9)] *:!shadow-[0px_0px_10px_0px_#B2F8FF]"}`} > { Build Robust AI Applications - + Streamline the development of your LLM applications. Experiment, evaluate, and monitor AI applications faster and easier than ever before. Empower your team with seamless collaboration. diff --git a/web/oss/src/components/pages/evaluations/cellRenderers/cellRenderers.tsx b/web/oss/src/components/pages/evaluations/cellRenderers/cellRenderers.tsx index 9e2053e13f..65f2d7c731 100644 --- a/web/oss/src/components/pages/evaluations/cellRenderers/cellRenderers.tsx +++ b/web/oss/src/components/pages/evaluations/cellRenderers/cellRenderers.tsx @@ -62,11 +62,11 @@ const useStyles = createUseStyles((theme: JSSTheme) => ({ height: 3, aspectRatio: 1 / 1, borderRadius: "50%", - backgroundColor: "#8c8c8c", + backgroundColor: theme.colorTextQuaternary, marginTop: 2, }, date: { - color: "#8c8c8c", + color: theme.colorTextTertiary, }, longCell: { height: "100%", diff --git a/web/oss/src/components/pages/evaluations/onlineEvaluation/OnlineEvaluationDrawer.tsx b/web/oss/src/components/pages/evaluations/onlineEvaluation/OnlineEvaluationDrawer.tsx index c3703e0d29..8cd6cf5919 100644 --- a/web/oss/src/components/pages/evaluations/onlineEvaluation/OnlineEvaluationDrawer.tsx +++ b/web/oss/src/components/pages/evaluations/onlineEvaluation/OnlineEvaluationDrawer.tsx @@ -401,7 +401,7 @@ const OnlineEvaluationDrawer = ({open, onClose, onCreate}: OnlineEvaluationDrawe selectedEvaluatorConfig.name || selectedEvaluatorConfig?.slug || "Evaluator" return (
- {displayName} + {displayName} {summaryParts.join(" • ")} + return {summaryParts.join(" • ")} }, [filters.length, samplingRate]) const buildPanelHeader = (title: string, summary?: ReactNode) => (
- {title} + {title} {summary ?
{summary}
: null}
) diff --git a/web/oss/src/components/pages/evaluations/onlineEvaluation/assets/styles.ts b/web/oss/src/components/pages/evaluations/onlineEvaluation/assets/styles.ts index 3f90ba24dc..97025d4db6 100644 --- a/web/oss/src/components/pages/evaluations/onlineEvaluation/assets/styles.ts +++ b/web/oss/src/components/pages/evaluations/onlineEvaluation/assets/styles.ts @@ -21,7 +21,7 @@ export const useDrawerStyles = createUseStyles((theme: JSSTheme) => ({ border: "none !important", borderRadius: "10px !important", overflow: "hidden", - backgroundColor: "#FFFFFF", + backgroundColor: theme.colorBgContainer, boxShadow: "0 1px 2px rgba(15, 23, 42, 0.06)", }, "& .ant-collapse-item + .ant-collapse-item": { diff --git a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/EvaluatorDetailsPreview.tsx b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/EvaluatorDetailsPreview.tsx index 306fef4d44..7510db868a 100644 --- a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/EvaluatorDetailsPreview.tsx +++ b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/EvaluatorDetailsPreview.tsx @@ -26,11 +26,11 @@ const renderParameterValue = (param: ParameterPreviewItem) => { const isMultiline = displayValue.includes("\n") const baseContent = isMultiline ? ( -
+        
             {displayValue}
         
) : ( - {displayValue} + {displayValue} ) if (param.fullValue && param.fullValue !== displayValue) { @@ -100,7 +100,7 @@ const EvaluatorDetailsPreview = ({ {/* {details.parameters.length > 0 ? ( -
+                        
                             {JSON.stringify(details.parameterPayload, null, 2)}
                         
@@ -117,7 +117,9 @@ const EvaluatorDetailsPreview = ({ >
- {metric.name} + + {metric.name} + {renderOutputType(metric)} @@ -129,14 +131,19 @@ const EvaluatorDetailsPreview = ({ Optional )}
{metric.description ? ( -
{metric.description}
+
+ {metric.description} +
) : null}
diff --git a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/FiltersPreview.tsx b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/FiltersPreview.tsx index cde744ffec..a88444ae2e 100644 --- a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/FiltersPreview.tsx +++ b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/FiltersPreview.tsx @@ -128,15 +128,21 @@ const FiltersPreview = ({filtering, filters, className, compact}: FiltersPreview if (compact) { return ( -
+
{normalizedFilters.map((item) => (
- {item.fieldLabel}{" "} - {item.operatorLabel}{" "} - {item.valueLabel} + + {item.fieldLabel} + {" "} + {item.operatorLabel}{" "} + + {item.valueLabel} +
))}
@@ -146,9 +152,9 @@ const FiltersPreview = ({filtering, filters, className, compact}: FiltersPreview return (
- Field - Operator - Value + Field + Operator + Value
{normalizedFilters.map((item) => (
diff --git a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/PromptPreview.tsx b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/PromptPreview.tsx index 935981d776..e409bf5357 100644 --- a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/PromptPreview.tsx +++ b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/PromptPreview.tsx @@ -31,7 +31,7 @@ const PromptPreview = ({sections}: PromptPreviewProps) => {
{tagContent} {/* {secondaryLabel ? ( - + {secondaryLabel} ) : null} */} diff --git a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/QueryFiltersCell.tsx b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/QueryFiltersCell.tsx index 8b98017650..a4dd37799c 100644 --- a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/QueryFiltersCell.tsx +++ b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/QueryFiltersCell.tsx @@ -97,7 +97,7 @@ export default function QueryFiltersCell({record}: {record: RowRecord}) {
{hasMeta ? ( -
+
{historicalRangeLabel ? ( {historicalRangeLabel} ) : null} diff --git a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/QueryFiltersSummaryCard.tsx b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/QueryFiltersSummaryCard.tsx index 2a6bd1ca21..6ff1e13b50 100644 --- a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/QueryFiltersSummaryCard.tsx +++ b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/QueryFiltersSummaryCard.tsx @@ -70,20 +70,22 @@ const QueryFiltersSummaryCard = ({ return (
- + Query filters - {loading ? Loading… : null} + {loading ? ( + Loading… + ) : null}
{loading ? null : } {historicalLabel ? ( - {historicalLabel} + {historicalLabel} ) : null}
diff --git a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/ReadOnlyBox.tsx b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/ReadOnlyBox.tsx index 8223ed3faf..fa5f33bcb3 100644 --- a/web/oss/src/components/pages/evaluations/onlineEvaluation/components/ReadOnlyBox.tsx +++ b/web/oss/src/components/pages/evaluations/onlineEvaluation/components/ReadOnlyBox.tsx @@ -8,7 +8,7 @@ const ReadOnlyBox = ({children, className}: ReadOnlyBoxProps) => { return (
diff --git a/web/oss/src/components/pages/observability/assets/getObservabilityColumns.tsx b/web/oss/src/components/pages/observability/assets/getObservabilityColumns.tsx index 2d8c320150..ed0a53301d 100644 --- a/web/oss/src/components/pages/observability/assets/getObservabilityColumns.tsx +++ b/web/oss/src/components/pages/observability/assets/getObservabilityColumns.tsx @@ -63,7 +63,7 @@ export const getObservabilityColumns = ({evaluatorSlugs}: ObservabilityColumnsPr const shortId = spanId ? spanId.split("-")[0] : "-" return ( - + # {shortId} diff --git a/web/oss/src/components/pages/observability/components/SessionsTable/components/Cells/SessionIdCell.tsx b/web/oss/src/components/pages/observability/components/SessionsTable/components/Cells/SessionIdCell.tsx index c3cbfb6685..0fcd143913 100644 --- a/web/oss/src/components/pages/observability/components/SessionsTable/components/Cells/SessionIdCell.tsx +++ b/web/oss/src/components/pages/observability/components/SessionsTable/components/Cells/SessionIdCell.tsx @@ -4,7 +4,7 @@ import {Tag} from "antd" export const SessionIdCell = ({sessionId}: {sessionId: string}) => { return ( - + # {sessionId} diff --git a/web/oss/src/components/pages/overview/deployments/DeploymentDrawer/assets/LanguageCodeBlock.tsx b/web/oss/src/components/pages/overview/deployments/DeploymentDrawer/assets/LanguageCodeBlock.tsx index 878f36a438..a5253de0ba 100644 --- a/web/oss/src/components/pages/overview/deployments/DeploymentDrawer/assets/LanguageCodeBlock.tsx +++ b/web/oss/src/components/pages/overview/deployments/DeploymentDrawer/assets/LanguageCodeBlock.tsx @@ -45,7 +45,7 @@ const LanguageCodeBlock = ({
@@ -84,7 +84,7 @@ const LanguageCodeBlock = ({
diff --git a/web/oss/src/components/pages/overview/deployments/DeploymentDrawer/index.tsx b/web/oss/src/components/pages/overview/deployments/DeploymentDrawer/index.tsx index 7bfab04ef0..9e2d69fe5e 100644 --- a/web/oss/src/components/pages/overview/deployments/DeploymentDrawer/index.tsx +++ b/web/oss/src/components/pages/overview/deployments/DeploymentDrawer/index.tsx @@ -204,7 +204,7 @@ const DeploymentDrawer = ({ className={clsx([ "[&_.ant-tabs-nav]:sticky", "[&_.ant-tabs-nav]:-top-[25px]", - "[&_.ant-tabs-nav]:bg-white", + "[&_.ant-tabs-nav]:bg-[var(--ag-c-FFFFFF)]", "[&_.ant-tabs-nav]:z-[1]", ])} > diff --git a/web/oss/src/components/pages/prompts/hooks/usePromptsFolderTree.tsx b/web/oss/src/components/pages/prompts/hooks/usePromptsFolderTree.tsx index 0530efeacc..75562144b4 100644 --- a/web/oss/src/components/pages/prompts/hooks/usePromptsFolderTree.tsx +++ b/web/oss/src/components/pages/prompts/hooks/usePromptsFolderTree.tsx @@ -59,7 +59,7 @@ export const usePromptsFolderTree = ({ const hasChildren = (childNodes?.length ?? 0) > 0 const icon = isFolder ? ( - + ) : ( getAppTypeIcon(node.appType) ) diff --git a/web/oss/src/components/pages/settings/Projects/index.tsx b/web/oss/src/components/pages/settings/Projects/index.tsx index 0639e320a6..b16d913aad 100644 --- a/web/oss/src/components/pages/settings/Projects/index.tsx +++ b/web/oss/src/components/pages/settings/Projects/index.tsx @@ -182,7 +182,7 @@ const ProjectsSettings = () => {
{record.project_name} {record.is_default_project && ( - Default + Default )}
diff --git a/web/oss/src/components/pages/settings/Secrets/SecretProviderTable/index.tsx b/web/oss/src/components/pages/settings/Secrets/SecretProviderTable/index.tsx index ef5fd7ef2f..fb5d3e76aa 100644 --- a/web/oss/src/components/pages/settings/Secrets/SecretProviderTable/index.tsx +++ b/web/oss/src/components/pages/settings/Secrets/SecretProviderTable/index.tsx @@ -92,7 +92,7 @@ const SecretProviderTable = ({type}: {type: "standard" | "custom"}) => { {record?.provider} diff --git a/web/oss/src/components/pages/settings/Tools/components/GatewayToolsSection.tsx b/web/oss/src/components/pages/settings/Tools/components/GatewayToolsSection.tsx index 618a983b8d..ec512b1c92 100644 --- a/web/oss/src/components/pages/settings/Tools/components/GatewayToolsSection.tsx +++ b/web/oss/src/components/pages/settings/Tools/components/GatewayToolsSection.tsx @@ -178,7 +178,11 @@ export default function GatewayToolsSection() { style: {minWidth: 160}, }), render: (_, record) => ( - + {record.integration_key} ), diff --git a/web/oss/src/components/pages/settings/WorkspaceManage/Modals/InvitedUserLinkModal.tsx b/web/oss/src/components/pages/settings/WorkspaceManage/Modals/InvitedUserLinkModal.tsx index c1b24f5c7d..f09693ae92 100644 --- a/web/oss/src/components/pages/settings/WorkspaceManage/Modals/InvitedUserLinkModal.tsx +++ b/web/oss/src/components/pages/settings/WorkspaceManage/Modals/InvitedUserLinkModal.tsx @@ -56,7 +56,7 @@ const InvitedUserLinkModal = ({invitedUserData, ...props}: InvitedUserLinkModalP
-
+
Invited link
-
+
Password reset link diff --git a/web/oss/src/pages/_document.tsx b/web/oss/src/pages/_document.tsx index 9dbf4e2663..07e8fb1e55 100644 --- a/web/oss/src/pages/_document.tsx +++ b/web/oss/src/pages/_document.tsx @@ -1,10 +1,18 @@ import {Html, Head, Main, NextScript} from "next/document" import Script from "next/script" +// Runs synchronously before paint to apply the persisted theme, preventing a +// flash of the wrong theme on load. Mirrors ThemeContextProvider's resolution: +// stored "agenta-theme" (JSON-encoded by usehooks-ts), default light, "system" +// follows the OS preference. +const themeInitScript = `(function(){try{var r=localStorage.getItem('agenta-theme');var m=r?(r.charAt(0)==='"'?JSON.parse(r):r):'light';var d=m==='dark'||(m==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);if(d){document.documentElement.classList.add('dark');document.documentElement.style.colorScheme='dark';}}catch(e){}})();` + export default function Document() { return ( - + +