@@ -8,12 +8,14 @@ import {
8
8
import { EllipsisButton } from "./ellipsis-button" ;
9
9
import { ConversationCardContextMenu } from "./conversation-card-context-menu" ;
10
10
import { cn } from "#/utils/utils" ;
11
+ import { MetricsModal } from "../../shared/metrics-modal" ;
11
12
12
13
interface ConversationCardProps {
13
14
onClick ?: ( ) => void ;
14
15
onDelete ?: ( ) => void ;
15
16
onChangeTitle ?: ( title : string ) => void ;
16
17
onDownloadWorkspace ?: ( ) => void ;
18
+ onDisplayCost ?: ( ) => void ;
17
19
isActive ?: boolean ;
18
20
title : string ;
19
21
selectedRepository : string | null ;
@@ -27,6 +29,7 @@ export function ConversationCard({
27
29
onDelete,
28
30
onChangeTitle,
29
31
onDownloadWorkspace,
32
+ onDisplayCost,
30
33
isActive,
31
34
title,
32
35
selectedRepository,
@@ -36,6 +39,7 @@ export function ConversationCard({
36
39
} : ConversationCardProps ) {
37
40
const [ contextMenuVisible , setContextMenuVisible ] = React . useState ( false ) ;
38
41
const [ titleMode , setTitleMode ] = React . useState < "view" | "edit" > ( "view" ) ;
42
+ const [ metricsModalVisible , setMetricsModalVisible ] = React . useState ( false ) ;
39
43
const inputRef = React . useRef < HTMLInputElement > ( null ) ;
40
44
41
45
const handleBlur = ( ) => {
@@ -83,87 +87,101 @@ export function ConversationCard({
83
87
onDownloadWorkspace ?.( ) ;
84
88
} ;
85
89
90
+ const handleDisplayCost = ( event : React . MouseEvent < HTMLButtonElement > ) => {
91
+ event . stopPropagation ( ) ;
92
+ setMetricsModalVisible ( true ) ;
93
+ setContextMenuVisible ( false ) ;
94
+ } ;
95
+
86
96
React . useEffect ( ( ) => {
87
97
if ( titleMode === "edit" ) {
88
98
inputRef . current ?. focus ( ) ;
89
99
}
90
100
} , [ titleMode ] ) ;
91
101
92
- const hasContextMenu = ! ! ( onDelete || onChangeTitle || onDownloadWorkspace ) ;
102
+ const hasContextMenu = ! ! ( onDelete || onChangeTitle || onDownloadWorkspace || onDisplayCost ) ;
93
103
94
104
return (
95
- < div
96
- data-testid = "conversation-card"
97
- onClick = { onClick }
98
- className = { cn (
99
- "h-[100px] w-full px-[18px] py-4 border-b border-neutral-600 cursor-pointer" ,
100
- variant === "compact" &&
101
- "h-auto w-fit rounded-xl border border-[#525252]" ,
102
- ) }
103
- >
104
- < div className = "flex items-center justify-between w-full" >
105
- < div className = "flex items-center gap-2 flex-1 min-w-0 overflow-hidden mr-2" >
106
- { isActive && (
107
- < span className = "w-2 h-2 bg-blue-500 rounded-full flex-shrink-0" />
108
- ) }
109
- { titleMode === "edit" && (
110
- < input
111
- ref = { inputRef }
112
- data-testid = "conversation-card-title"
113
- onClick = { handleInputClick }
114
- onBlur = { handleBlur }
115
- onKeyUp = { handleKeyUp }
116
- type = "text"
117
- defaultValue = { title }
118
- className = "text-sm leading-6 font-semibold bg-transparent w-full"
119
- />
120
- ) }
121
- { titleMode === "view" && (
122
- < p
123
- data-testid = "conversation-card-title"
124
- className = "text-sm leading-6 font-semibold bg-transparent truncate overflow-hidden"
125
- title = { title }
126
- >
127
- { title }
128
- </ p >
129
- ) }
105
+ < >
106
+ < div
107
+ data-testid = "conversation-card"
108
+ onClick = { onClick }
109
+ className = { cn (
110
+ "h-[100px] w-full px-[18px] py-4 border-b border-neutral-600 cursor-pointer" ,
111
+ variant === "compact" &&
112
+ "h-auto w-fit rounded-xl border border-[#525252]" ,
113
+ ) }
114
+ >
115
+ < div className = "flex items-center justify-between w-full" >
116
+ < div className = "flex items-center gap-2 flex-1 min-w-0 overflow-hidden mr-2" >
117
+ { isActive && (
118
+ < span className = "w-2 h-2 bg-blue-500 rounded-full flex-shrink-0" />
119
+ ) }
120
+ { titleMode === "edit" && (
121
+ < input
122
+ ref = { inputRef }
123
+ data-testid = "conversation-card-title"
124
+ onClick = { handleInputClick }
125
+ onBlur = { handleBlur }
126
+ onKeyUp = { handleKeyUp }
127
+ type = "text"
128
+ defaultValue = { title }
129
+ className = "text-sm leading-6 font-semibold bg-transparent w-full"
130
+ />
131
+ ) }
132
+ { titleMode === "view" && (
133
+ < p
134
+ data-testid = "conversation-card-title"
135
+ className = "text-sm leading-6 font-semibold bg-transparent truncate overflow-hidden"
136
+ title = { title }
137
+ >
138
+ { title }
139
+ </ p >
140
+ ) }
141
+ </ div >
142
+
143
+ < div className = "flex items-center gap-2 relative" >
144
+ < ConversationStateIndicator status = { status } />
145
+ { hasContextMenu && (
146
+ < EllipsisButton
147
+ onClick = { ( event ) => {
148
+ event . preventDefault ( ) ;
149
+ event . stopPropagation ( ) ;
150
+ setContextMenuVisible ( ( prev ) => ! prev ) ;
151
+ } }
152
+ />
153
+ ) }
154
+ { contextMenuVisible && (
155
+ < ConversationCardContextMenu
156
+ onClose = { ( ) => setContextMenuVisible ( false ) }
157
+ onDelete = { onDelete && handleDelete }
158
+ onEdit = { onChangeTitle && handleEdit }
159
+ onDownload = { onDownloadWorkspace && handleDownload }
160
+ onDisplayCost = { handleDisplayCost }
161
+ position = { variant === "compact" ? "top" : "bottom" }
162
+ />
163
+ ) }
164
+ </ div >
130
165
</ div >
131
166
132
- < div className = "flex items-center gap-2 relative" >
133
- < ConversationStateIndicator status = { status } />
134
- { hasContextMenu && (
135
- < EllipsisButton
136
- onClick = { ( event ) => {
137
- event . preventDefault ( ) ;
138
- event . stopPropagation ( ) ;
139
- setContextMenuVisible ( ( prev ) => ! prev ) ;
140
- } }
141
- />
167
+ < div
168
+ className = { cn (
169
+ variant === "compact" && "flex items-center justify-between mt-1" ,
142
170
) }
143
- { contextMenuVisible && (
144
- < ConversationCardContextMenu
145
- onClose = { ( ) => setContextMenuVisible ( false ) }
146
- onDelete = { onDelete && handleDelete }
147
- onEdit = { onChangeTitle && handleEdit }
148
- onDownload = { onDownloadWorkspace && handleDownload }
149
- position = { variant === "compact" ? "top" : "bottom" }
150
- />
171
+ >
172
+ { selectedRepository && (
173
+ < ConversationRepoLink selectedRepository = { selectedRepository } />
151
174
) }
175
+ < p className = "text-xs text-neutral-400" >
176
+ < time > { formatTimeDelta ( new Date ( lastUpdatedAt ) ) } ago</ time >
177
+ </ p >
152
178
</ div >
153
179
</ div >
154
180
155
- < div
156
- className = { cn (
157
- variant === "compact" && "flex items-center justify-between mt-1" ,
158
- ) }
159
- >
160
- { selectedRepository && (
161
- < ConversationRepoLink selectedRepository = { selectedRepository } />
162
- ) }
163
- < p className = "text-xs text-neutral-400" >
164
- < time > { formatTimeDelta ( new Date ( lastUpdatedAt ) ) } ago</ time >
165
- </ p >
166
- </ div >
167
- </ div >
181
+ < MetricsModal
182
+ isOpen = { metricsModalVisible }
183
+ onClose = { ( ) => setMetricsModalVisible ( false ) }
184
+ />
185
+ </ >
168
186
) ;
169
187
}
0 commit comments