Skip to content

Commit ae5e4ae

Browse files
author
Dylan Huang
committed
refactor Row component to replace MessageBubble with ChatInterface and simplify message display
1 parent 242a39e commit ae5e4ae

File tree

2 files changed

+144
-17
lines changed

2 files changed

+144
-17
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { useState, useRef, useEffect } from "react";
2+
import type { Message } from "../types/eval-protocol";
3+
import { MessageBubble } from "./MessageBubble";
4+
5+
interface ChatInterfaceProps {
6+
messages: Message[];
7+
}
8+
9+
export const ChatInterface = ({ messages }: ChatInterfaceProps) => {
10+
const [chatWidth, setChatWidth] = useState(600); // Default width in pixels
11+
const [chatHeight, setChatHeight] = useState(512); // Default height in pixels (32rem = 512px)
12+
const [isResizingWidth, setIsResizingWidth] = useState(false);
13+
const [isResizingHeight, setIsResizingHeight] = useState(false);
14+
const [initialWidth, setInitialWidth] = useState(0);
15+
const [initialHeight, setInitialHeight] = useState(0);
16+
const [initialMouseX, setInitialMouseX] = useState(0);
17+
const [initialMouseY, setInitialMouseY] = useState(0);
18+
const chatContainerRef = useRef<HTMLDivElement>(null);
19+
const resizeHandleRef = useRef<HTMLDivElement>(null);
20+
const heightResizeHandleRef = useRef<HTMLDivElement>(null);
21+
22+
// Handle horizontal resizing
23+
useEffect(() => {
24+
const handleMouseMove = (e: MouseEvent) => {
25+
if (isResizingWidth) {
26+
e.preventDefault();
27+
const deltaX = e.clientX - initialMouseX;
28+
const newWidth = initialWidth + deltaX;
29+
setChatWidth(Math.max(300, Math.min(1200, newWidth))); // Min 300px, max 1200px
30+
}
31+
};
32+
33+
const handleMouseUp = () => {
34+
setIsResizingWidth(false);
35+
};
36+
37+
if (isResizingWidth) {
38+
document.addEventListener("mousemove", handleMouseMove);
39+
document.addEventListener("mouseup", handleMouseUp);
40+
}
41+
42+
return () => {
43+
document.removeEventListener("mousemove", handleMouseMove);
44+
document.removeEventListener("mouseup", handleMouseUp);
45+
};
46+
}, [isResizingWidth, initialMouseX, initialWidth]);
47+
48+
// Handle vertical resizing
49+
useEffect(() => {
50+
const handleMouseMove = (e: MouseEvent) => {
51+
if (isResizingHeight) {
52+
e.preventDefault();
53+
const deltaY = e.clientY - initialMouseY;
54+
const newHeight = initialHeight + deltaY;
55+
setChatHeight(Math.max(200, Math.min(800, newHeight))); // Min 200px, max 800px
56+
}
57+
};
58+
59+
const handleMouseUp = () => {
60+
setIsResizingHeight(false);
61+
};
62+
63+
if (isResizingHeight) {
64+
document.addEventListener("mousemove", handleMouseMove);
65+
document.addEventListener("mouseup", handleMouseUp);
66+
}
67+
68+
return () => {
69+
document.removeEventListener("mousemove", handleMouseMove);
70+
document.removeEventListener("mouseup", handleMouseUp);
71+
};
72+
}, [isResizingHeight, initialMouseY, initialHeight]);
73+
74+
const startWidthResize = (e: React.MouseEvent) => {
75+
e.preventDefault();
76+
e.stopPropagation();
77+
setInitialMouseX(e.clientX);
78+
setInitialWidth(chatWidth);
79+
setIsResizingWidth(true);
80+
};
81+
82+
const startHeightResize = (e: React.MouseEvent) => {
83+
e.preventDefault();
84+
e.stopPropagation();
85+
setInitialMouseY(e.clientY);
86+
setInitialHeight(chatHeight);
87+
setIsResizingHeight(true);
88+
};
89+
90+
const startCornerResize = (e: React.MouseEvent) => {
91+
e.preventDefault();
92+
e.stopPropagation();
93+
setInitialMouseX(e.clientX);
94+
setInitialMouseY(e.clientY);
95+
setInitialWidth(chatWidth);
96+
setInitialHeight(chatHeight);
97+
setIsResizingWidth(true);
98+
setIsResizingHeight(true);
99+
};
100+
101+
return (
102+
<div
103+
ref={chatContainerRef}
104+
className="relative"
105+
style={{ width: `${chatWidth}px` }}
106+
>
107+
<div
108+
className="bg-white border border-gray-200 p-4 overflow-y-auto"
109+
style={{ height: `${chatHeight}px` }}
110+
>
111+
{messages.map((message, msgIndex) => (
112+
<MessageBubble key={msgIndex} message={message} />
113+
))}
114+
</div>
115+
116+
{/* Horizontal resize handle */}
117+
<div
118+
ref={resizeHandleRef}
119+
className="absolute top-0 right-0 w-1 h-full bg-gray-300 cursor-col-resize hover:bg-gray-400 transition-colors select-none"
120+
onMouseDown={startWidthResize}
121+
onDragStart={(e) => e.preventDefault()}
122+
/>
123+
124+
{/* Vertical resize handle */}
125+
<div
126+
ref={heightResizeHandleRef}
127+
className="absolute bottom-0 left-0 w-full h-1 bg-gray-300 cursor-row-resize hover:bg-gray-400 transition-colors select-none"
128+
onMouseDown={startHeightResize}
129+
onDragStart={(e) => e.preventDefault()}
130+
/>
131+
132+
{/* Corner resize handle */}
133+
<div
134+
className="absolute bottom-0 right-0 w-3 h-3 bg-gray-300 cursor-nw-resize hover:bg-gray-400 transition-colors select-none"
135+
onMouseDown={startCornerResize}
136+
onDragStart={(e) => e.preventDefault()}
137+
/>
138+
</div>
139+
);
140+
};

vite-app/src/components/Row.tsx

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { observer } from "mobx-react";
22
import { useState } from "react";
33
import type { EvaluationRow } from "../types/eval-protocol";
4-
import { MessageBubble } from "./MessageBubble";
4+
import { ChatInterface } from "./ChatInterface";
55
import { MetadataSection } from "./MetadataSection";
66

77
export const Row = observer(
@@ -52,23 +52,20 @@ export const Row = observer(
5252

5353
{/* Row ID */}
5454
<td className="px-3 py-3 text-xs">
55-
<span className="font-semibold text-gray-600">ID:</span>{" "}
5655
<span className="font-mono text-gray-900">
5756
{row.input_metadata.row_id}
5857
</span>
5958
</td>
6059

6160
{/* Model */}
6261
<td className="px-3 py-3 text-xs">
63-
<span className="font-semibold text-gray-600">Model:</span>{" "}
6462
<span className="text-gray-900">
6563
{row.input_metadata.completion_params?.model || "N/A"}
6664
</span>
6765
</td>
6866

6967
{/* Score */}
7068
<td className="px-3 py-3 text-xs">
71-
<span className="font-semibold text-gray-600">Score:</span>{" "}
7269
<span
7370
className={`font-mono ${
7471
row.evaluation_result?.score
@@ -86,7 +83,6 @@ export const Row = observer(
8683

8784
{/* Messages */}
8885
<td className="px-3 py-3 text-xs">
89-
<span className="font-semibold text-gray-600">Messages:</span>{" "}
9086
<span className="text-gray-900">{row.messages.length}</span>
9187
</td>
9288
</tr>
@@ -96,21 +92,12 @@ export const Row = observer(
9692
<tr>
9793
<td colSpan={5} className="p-0">
9894
<div className="p-4 bg-gray-50 border-t border-gray-200">
99-
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
95+
<div className="flex gap-6">
10096
{/* Left Column - Chat Interface */}
101-
<div className="lg:col-span-2">
102-
<h4 className="font-semibold text-sm text-gray-700 mb-2 pb-1">
103-
Conversation ({row.messages.length} messages)
104-
</h4>
105-
<div className="bg-white border border-gray-200 p-4 max-h-[32rem] overflow-y-auto">
106-
{row.messages.map((message, msgIndex) => (
107-
<MessageBubble key={msgIndex} message={message} />
108-
))}
109-
</div>
110-
</div>
97+
<ChatInterface messages={row.messages} />
11198

11299
{/* Right Column - Metadata */}
113-
<div className="space-y-3">
100+
<div className="flex-1 space-y-3 min-w-0">
114101
<h4 className="font-semibold text-sm text-gray-700 mb-2 pb-1">
115102
Metadata
116103
</h4>

0 commit comments

Comments
 (0)