Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ui): Playground design tweaks (header, buttons) #3172

Merged
merged 15 commits into from
Dec 9, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,14 @@ export const ChatView = ({chat}: ChatViewProps) => {

return (
<div className="flex flex-col pb-32">
<span className="mb-[-16px] text-sm font-semibold text-moon-800">
Messages
</span>
<p className="mb-[8px] text-sm font-semibold text-moon-800">Messages</p>
<MessageList
messages={chat.request?.messages || []}
scrollLastMessage={scrollLastMessage}
/>
{chatResult?.choices && chatResult.choices.length > 0 && (
<>
<span className="-mb-16 mt-24 text-sm font-semibold text-moon-800">
<span className="mb-[8px] text-sm font-semibold text-moon-800">
Response
</span>
<div ref={outputRef}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export const MessagePanel = ({
}: MessagePanelProps) => {
const [isShowingMore, setIsShowingMore] = useState(false);
const [isOverflowing, setIsOverflowing] = useState(false);
const [isHovering, setIsHovering] = useState(false);
const [editorHeight, setEditorHeight] = useState<number | null>(
pendingToolResponseId ? 100 : null
);
Expand Down Expand Up @@ -62,126 +61,127 @@ export const MessagePanel = ({
: undefined;

return (
<div className={classNames('flex gap-8', {'mt-24': !isTool})}>
{!isNested && !isSystemPrompt && (
<div className="w-32 flex-shrink-0">
{!isUser && !isTool && (
<Callout
size="x-small"
icon="robot-service-member"
color="moon"
className="h-32 w-32"
/>
)}
</div>
)}
<div
className={classNames('group', {
'mb-[24px]': !isNested,
'mb-[0]': isNested,
})}>
<div className="flex gap-[16px]">
{!isNested && !isSystemPrompt && (
<div className="w-32 flex-shrink-0">
{!isUser && !isTool && (
<Callout
size="x-small"
icon="robot-service-member"
color="moon"
className="mt-[4px] h-32 w-32 bg-moon-100"
/>
)}
</div>
)}

<div
className={classNames('relative w-full overflow-visible', {
'rounded-lg': !isNested,
'border-t border-moon-250': isTool,
'bg-moon-100': isSystemPrompt || hasToolCalls,
'bg-cactus-300/[0.24]': isUser,
'max-w-full': !isUser,
'max-w-[768px]': isUser,
'ml-auto py-8': isUser,
'mr-auto pb-8 pt-4': !isUser,
'py-8': hasContent,
})}
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}>
<div>
{isSystemPrompt && (
<div className="flex justify-between px-16">
<div className="text-moon-500">
{message.role.charAt(0).toUpperCase() + message.role.slice(1)}
<div
className={classNames('relative w-full overflow-visible', {
'rounded-lg': !isNested,
'border-t border-moon-250': isTool,
'bg-moon-100': isSystemPrompt || hasToolCalls,
'bg-cactus-300/[0.24]': isUser,
'max-w-full': !isUser,
'max-w-[768px]': isUser,
'ml-auto': isUser,
'mr-auto': !isUser,
'py-[16px]': hasContent,
'pb-[4px] pt-[8px]': !isUser && !isTool && !isSystemPrompt,
})}>
<div>
{isSystemPrompt && (
<div className="flex justify-between px-[16px]">
<div className="text-sm text-moon-500">
{message.role.charAt(0).toUpperCase() + message.role.slice(1)}
</div>
</div>
</div>
)}
)}

{isTool && (
<div className={classNames('pb-8')}>
<div className="text-[14px] font-semibold text-moon-500">
Response
{isTool && (
<div className={classNames('pb-8')}>
<div className="text-[14px] font-semibold text-moon-500">
Response
</div>
</div>
)}

<div
ref={contentRef}
className={classNames('w-full overflow-y-hidden', {
'max-h-[400px]': !isShowingMore,
'max-h-full': isShowingMore,
})}>
{isPlayground && editorHeight ? (
<PlaygroundMessagePanelEditor
message={message}
index={index}
isChoice={isChoice ?? false}
editorHeight={editorHeight}
isNested={isNested ?? false}
pendingToolResponseId={pendingToolResponseId}
setEditorHeight={setEditorHeight}
/>
) : (
<>
{hasContent && (
<div
className={classNames(hasToolCalls ? 'pb-8' : '', {
'px-16': isSystemPrompt || isUser,
})}>
{_.isString(message.content) ? (
<MessagePanelPart
value={message.content}
isStructuredOutput={isStructuredOutput}
/>
) : (
message.content!.map((p, i) => (
<MessagePanelPart key={i} value={p} />
))
)}
</div>
)}
{hasToolCalls && (
<div
className={classNames({
'border-t border-moon-250 pt-8': hasContent,
})}>
<ToolCalls toolCalls={message.tool_calls!} />
</div>
)}
</>
)}
</div>
)}

<div
ref={contentRef}
className={classNames('w-full overflow-y-hidden', {
'max-h-[400px]': !isShowingMore,
'max-h-full': isShowingMore,
})}>
{isPlayground && editorHeight ? (
<PlaygroundMessagePanelEditor
message={message}
index={index}
isChoice={isChoice ?? false}
editorHeight={editorHeight}
isNested={isNested ?? false}
pendingToolResponseId={pendingToolResponseId}
setEditorHeight={setEditorHeight}
{isOverflowing && !editorHeight && (
<ShowMoreButton
isUser={isUser}
isShowingMore={isShowingMore}
setIsShowingMore={setIsShowingMore}
/>
) : (
<>
{hasContent && (
<div
className={classNames(hasToolCalls ? 'pb-8' : '', {
'px-16': isSystemPrompt || isUser,
})}>
{_.isString(message.content) ? (
<MessagePanelPart
value={message.content}
isStructuredOutput={isStructuredOutput}
/>
) : (
message.content!.map((p, i) => (
<MessagePanelPart key={i} value={p} />
))
)}
</div>
)}
{hasToolCalls && (
<div
className={classNames({
'border-t border-moon-250 pt-8': hasContent,
})}>
<ToolCalls toolCalls={message.tool_calls!} />
</div>
)}
</>
)}
</div>

{isOverflowing && !editorHeight && (
<ShowMoreButton
isUser={isUser}
isShowingMore={isShowingMore}
setIsShowingMore={setIsShowingMore}
/>
)}

{/* Playground buttons (retry, edit, delete) */}
{isPlayground && isHovering && !editorHeight && (
<div
className={classNames(
'absolute -bottom-[24px] right-[4px] flex w-full items-center justify-start',
isNested ? 'bottom-0' : 'bottom-[-32px]'
)}>
<PlaygroundMessagePanelButtons
index={message.original_index ?? index}
isChoice={isChoice ?? false}
isTool={isTool}
hasContent={hasContent}
contentRef={contentRef}
setEditorHeight={setEditorHeight}
responseIndexes={responseIndexes}
/>
</div>
)}
</div>
</div>

{/* Playground buttons (retry, edit, delete) - using group and group-hover to control opacity. */}
{isPlayground && !editorHeight ? (
<div className="flex w-full items-center justify-start opacity-0 group-hover:opacity-100">
<PlaygroundMessagePanelButtons
index={message.original_index ?? index}
isChoice={isChoice ?? false}
isTool={isTool}
hasContent={hasContent}
contentRef={contentRef}
setEditorHeight={setEditorHeight}
responseIndexes={responseIndexes}
/>
</div>
) : null}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const PlaygroundMessagePanelButtons: React.FC<
const {deleteMessage, deleteChoice, retry} = usePlaygroundContext();

return (
<div className="z-10 ml-auto flex gap-4 rounded-lg border border-moon-250 bg-white p-4">
<div className="ml-auto flex gap-4 rounded-lg pt-[8px]">
<Button
variant="quiet"
size="small"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,19 @@ export const PlaygroundMessagePanelEditor: React.FC<
};

return (
<div className={classNames('w-full pt-16', isNested ? 'px-2' : 'px-16')}>
<div
className={classNames(
'w-full pt-[6px]',
isNested ? 'px-[4px]' : 'px-[8px]'
)}>
<StyledTextArea
value={editedContent}
onChange={e => setEditedContent(e.target.value)}
autoGrow
maxHeight={160}
/>
<div className="z-100 mt-8 flex justify-end gap-8">
{/* 6px vs. 8px to make up for extra padding from textarea field */}
<div className="z-100 mt-[6px] flex justify-end gap-[8px]">
<Button variant="quiet" size="medium" onClick={handleCancel}>
Cancel
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,15 @@ export const PlaygroundChat = ({
}}>
<Box
sx={{
backgroundColor: 'white',
borderBottom: `1px solid ${MOON_200}`,
position: 'absolute',
top: '8px',
width: 'calc(100% - 32px)',
left: '16px',
right: '16px',
top: '0',
width: '100%',
paddingTop: '8px',
paddingBottom: '8px',
paddingLeft: '16px',
paddingRight: '16px',
zIndex: 10,
}}>
<PlaygroundChatTopBar
Expand All @@ -143,7 +147,7 @@ export const PlaygroundChat = ({
flexGrow: 1,
}}>
<Tailwind>
<div className=" mx-auto h-full min-w-[400px] max-w-[800px] pb-8">
<div className=" mx-auto mt-[32px] h-full min-w-[400px] max-w-[800px] pb-8">
{state.traceCall && (
<PlaygroundContext.Provider
value={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ export const PlaygroundChatTopBar: React.FC<PlaygroundChatTopBarProps> = ({
width: '100%',
display: 'flex',
justifyContent: 'space-between',
paddingBottom: '8px',
}}>
<Box
sx={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,18 +313,20 @@ const SimpleTabView: FC<{
height: '100%',
overflow: 'hidden',
}}>
<Box
sx={{
maxHeight: '50%',
flex: '0 0 auto',
width: '100%',
overflow: 'auto',
pt: 1,
px: 2,
alignContent: 'center',
}}>
{props.headerContent}
</Box>
{props.headerContent && (
<Box
sx={{
maxHeight: '50%',
flex: '0 0 auto',
width: '100%',
overflow: 'auto',
pt: 1,
px: 2,
alignContent: 'center',
}}>
{props.headerContent}
</Box>
)}
{(!props.hideTabsIfSingle || props.tabs.length > 1) && (
<Tabs.Root
style={{margin: '12px 16px 0 16px'}}
Expand Down
Loading