From 2c50441433b83cf7793d84adf16e3593d62b0bd7 Mon Sep 17 00:00:00 2001 From: Mikyo King Date: Mon, 14 Oct 2024 11:39:49 -0600 Subject: [PATCH] feat(playground): playground layout (#4978) * playground layout * WIP * final changes * fix styles * final fix * cleanup the store * Update app/src/components/resize/styles.tsx --- app/package.json | 2 +- app/pnpm-lock.yaml | 10 +- app/src/pages/playground/Playground.tsx | 163 +++++++++++++++--- .../PlaygroundCredentialsDropdown.tsx | 75 ++++---- .../pages/playground/PlaygroundInstance.tsx | 60 ------- app/src/pages/playground/PlaygroundTools.tsx | 26 --- .../__tests__/playgroundUtils.test.ts | 3 - app/src/store/playground/playgroundStore.tsx | 2 +- app/src/store/playground/types.ts | 5 +- 9 files changed, 188 insertions(+), 158 deletions(-) delete mode 100644 app/src/pages/playground/PlaygroundInstance.tsx delete mode 100644 app/src/pages/playground/PlaygroundTools.tsx diff --git a/app/package.json b/app/package.json index c2ca08266c..1cb7645a2f 100644 --- a/app/package.json +++ b/app/package.json @@ -6,7 +6,7 @@ "license": "None", "private": true, "dependencies": { - "@arizeai/components": "^1.8.3", + "@arizeai/components": "^1.8.4", "@arizeai/openinference-semantic-conventions": "^0.10.0", "@arizeai/point-cloud": "^3.0.6", "@codemirror/autocomplete": "6.12.0", diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml index e1115998d7..f31c4990ba 100644 --- a/app/pnpm-lock.yaml +++ b/app/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: .: dependencies: '@arizeai/components': - specifier: ^1.8.3 - version: 1.8.3(@types/react@18.3.10)(eslint@8.57.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^1.8.4 + version: 1.8.4(@types/react@18.3.10)(eslint@8.57.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@arizeai/openinference-semantic-conventions': specifier: ^0.10.0 version: 0.10.0 @@ -274,8 +274,8 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@arizeai/components@1.8.3': - resolution: {integrity: sha512-U+EV8+GDm0yLNh+xXcEiKY4v7cJgepHMVLRD9pmtYYYdCgiBOLZ7TNQv6gxcRRvlxuqUgLIcP//nwY/roI6MdQ==} + '@arizeai/components@1.8.4': + resolution: {integrity: sha512-pq7J01TPXpLRJJjRZSWpZX4XtlO/41zKEZv1l7un8Nv6Ol4RG7mf5i4h+QMDUmg5m2JXVNAb8GaRLRqESFM5tA==} engines: {node: '>=14'} peerDependencies: react: '>=18' @@ -3804,7 +3804,7 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@arizeai/components@1.8.3(@types/react@18.3.10)(eslint@8.57.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@arizeai/components@1.8.4(@types/react@18.3.10)(eslint@8.57.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@emotion/react': 11.11.4(@types/react@18.3.10)(react@18.3.1) '@react-aria/breadcrumbs': 3.5.13(react@18.3.1) diff --git a/app/src/pages/playground/Playground.tsx b/app/src/pages/playground/Playground.tsx index f25d6548e7..e15fe4f220 100644 --- a/app/src/pages/playground/Playground.tsx +++ b/app/src/pages/playground/Playground.tsx @@ -1,7 +1,17 @@ -import React, { Fragment } from "react"; +import React from "react"; import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; +import { css } from "@emotion/react"; -import { Button, Flex, Heading, Icon, Icons, View } from "@arizeai/components"; +import { + Accordion, + AccordionItem, + Button, + Flex, + Heading, + Icon, + Icons, + View, +} from "@arizeai/components"; import { resizeHandleCSS } from "@phoenix/components/resize"; import { @@ -13,8 +23,9 @@ import { InitialPlaygroundState } from "@phoenix/store"; import { NUM_MAX_PLAYGROUND_INSTANCES } from "./constants"; import { PlaygroundCredentialsDropdown } from "./PlaygroundCredentialsDropdown"; import { PlaygroundInputTypeTypeRadioGroup } from "./PlaygroundInputModeRadioGroup"; -import { PlaygroundInstance } from "./PlaygroundInstance"; +import { PlaygroundOutput } from "./PlaygroundOutput"; import { PlaygroundRunButton } from "./PlaygroundRunButton"; +import { PlaygroundTemplate } from "./PlaygroundTemplate"; export function Playground(props: InitialPlaygroundState) { return ( @@ -35,12 +46,11 @@ export function Playground(props: InitialPlaygroundState) { - - + ); @@ -50,35 +60,132 @@ function AddPromptButton() { const addInstance = usePlaygroundContext((state) => state.addInstance); const numInstances = usePlaygroundContext((state) => state.instances.length); return ( - + + ); } -function PlaygroundInstances() { +const playgroundPromptPanelContentCSS = css` + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + .ac-accordion { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + flex: 1 1 auto; + .ac-accordion-item { + height: 100%; + overflow: hidden; + flex: 1 1 auto; + .ac-accordion-itemContent { + height: 100%; + overflow: hidden; + flex: 1 1 auto; + & > * { + height: 100%; + flex: 1 1 auto; + overflow: auto; + box-sizing: border-box; + // Fix padding issue with flexbox + padding-bottom: 57px !important; + } + } + } + } +`; + +const playgroundInputOutputPanelContentCSS = css` + display: flex; + flex-direction: column; + height: 100%; + overflow: auto; +`; + +function PlaygroundContent() { const instances = usePlaygroundContext((state) => state.instances); + const numInstances = instances.length; + const isSingleInstance = numInstances === 1; + return ( - - - {instances.map((instance, i) => ( - - {i !== 0 && } - - - - - ))} - - + + +
+ + } + > + + + {instances.map((instance, i) => ( +
+ +
+ ))} +
+
+
+
+
+
+ + +
+ + + Inputs go here + + + + + {instances.map((instance, i) => ( + + + + ))} + + + + +
+
+
); } diff --git a/app/src/pages/playground/PlaygroundCredentialsDropdown.tsx b/app/src/pages/playground/PlaygroundCredentialsDropdown.tsx index 4023bed5b0..3887c19ed5 100644 --- a/app/src/pages/playground/PlaygroundCredentialsDropdown.tsx +++ b/app/src/pages/playground/PlaygroundCredentialsDropdown.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { css } from "@emotion/react"; import { DropdownButton, @@ -32,38 +33,46 @@ export function PlaygroundCredentialsDropdown() { const setCredential = useCredentialsContext((state) => state.setCredential); const credentials = useCredentialsContext((state) => state); return ( - - API Keys - - - - - API Keys - - - API keys are stored in your browser and used to communicate with - their respective API's. - -
- {currentProviders.map((provider) => { - const credentialKey = ProviderToCredentialKeyMap[provider]; - return ( - { - setCredential({ credential: credentialKey, value }); - }} - value={credentials[credentialKey]} - /> - ); - })} - -
-
-
-
+
+ + API Keys + + + + + API Keys + + + API keys are stored in your browser and used to communicate with + their respective API's. + +
+ {currentProviders.map((provider) => { + const credentialKey = ProviderToCredentialKeyMap[provider]; + return ( + { + setCredential({ credential: credentialKey, value }); + }} + value={credentials[credentialKey]} + /> + ); + })} + +
+
+
+
+
); } diff --git a/app/src/pages/playground/PlaygroundInstance.tsx b/app/src/pages/playground/PlaygroundInstance.tsx deleted file mode 100644 index 8e6bf27de8..0000000000 --- a/app/src/pages/playground/PlaygroundInstance.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import React, { PropsWithChildren } from "react"; -import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; -import { css } from "@emotion/react"; - -import { - compactResizeHandleCSS, - resizeHandleCSS, -} from "@phoenix/components/resize"; -import { usePlaygroundContext } from "@phoenix/contexts/PlaygroundContext"; - -import { PlaygroundInput } from "./PlaygroundInput"; -import { PlaygroundOutput } from "./PlaygroundOutput"; -import { PlaygroundTemplate } from "./PlaygroundTemplate"; -import { PlaygroundTools } from "./PlaygroundTools"; -import { PlaygroundInstanceProps } from "./types"; - -export function PlaygroundInstance(props: PlaygroundInstanceProps) { - const numInstances = usePlaygroundContext((state) => state.instances.length); - const isSingleInstance = numInstances == 1; - return ( - - - - - - - - - - - - - - - - ); -} - -const PanelContent = (props: PropsWithChildren) => ( -
-
- {props.children} -
-
-); diff --git a/app/src/pages/playground/PlaygroundTools.tsx b/app/src/pages/playground/PlaygroundTools.tsx deleted file mode 100644 index 805f4e1823..0000000000 --- a/app/src/pages/playground/PlaygroundTools.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react"; - -import { Card } from "@arizeai/components"; - -import { usePlaygroundContext } from "@phoenix/contexts/PlaygroundContext"; - -import { TitleWithAlphabeticIndex } from "./TitleWithAlphabeticIndex"; -import { PlaygroundInstanceProps } from "./types"; - -interface PlaygroundToolsProps extends PlaygroundInstanceProps {} -export function PlaygroundTools(props: PlaygroundToolsProps) { - const index = usePlaygroundContext((state) => - state.instances.findIndex( - (instance) => instance.id === props.playgroundInstanceId - ) - ); - return ( - } - collapsible - variant="compact" - > - Tools go here - - ); -} diff --git a/app/src/pages/playground/__tests__/playgroundUtils.test.ts b/app/src/pages/playground/__tests__/playgroundUtils.test.ts index cd012c62f8..0f36ba1090 100644 --- a/app/src/pages/playground/__tests__/playgroundUtils.test.ts +++ b/app/src/pages/playground/__tests__/playgroundUtils.test.ts @@ -22,9 +22,6 @@ const expectedPlaygroundInstanceWithIO: PlaygroundInstance = { id: 0, activeRunId: null, isRunning: false, - input: { - variables: {}, - }, model: { provider: "OPENAI", modelName: "gpt-4o", diff --git a/app/src/store/playground/playgroundStore.tsx b/app/src/store/playground/playgroundStore.tsx index fe3a1292c8..7011dc41c0 100644 --- a/app/src/store/playground/playgroundStore.tsx +++ b/app/src/store/playground/playgroundStore.tsx @@ -71,7 +71,6 @@ export function createPlaygroundInstance(): PlaygroundInstance { template: generateChatCompletionTemplate(), model: { provider: "OPENAI", modelName: "gpt-4o" }, tools: {}, - input: { variables: {} }, output: undefined, activeRunId: null, isRunning: false, @@ -84,6 +83,7 @@ export const createPlaygroundStore = ( const playgroundStore: StateCreator = (set, get) => ({ operationType: "chat", inputMode: "manual", + input: { variables: {} }, setInputMode: (inputMode: PlaygroundInputMode) => set({ inputMode }), instances: [createPlaygroundInstance()], setOperationType: (operationType: GenAIOperationType) => { diff --git a/app/src/store/playground/types.ts b/app/src/store/playground/types.ts index 043007f485..1b36d2f5be 100644 --- a/app/src/store/playground/types.ts +++ b/app/src/store/playground/types.ts @@ -70,7 +70,6 @@ export interface PlaygroundInstance { id: number; template: PlaygroundTemplate; tools: unknown; - input: PlaygroundInput; model: ModelConfig; output: ChatMessage[] | undefined | string; activeRunId: number | null; @@ -102,6 +101,10 @@ export interface PlaygroundProps { * @default "manual" */ inputMode: PlaygroundInputMode; + /** + * The input to all the playground instances + */ + input: PlaygroundInput; /** * The current playground instances(s) * Defaults to a single instance until a second instance is added