1
+ import React , { useState , useEffect , useRef , useMemo } from 'react' ;
1
2
import { useRecoilValue } from 'recoil' ;
3
+ import { Check , X } from 'lucide-react' ;
2
4
import { useParams } from 'react-router-dom' ;
3
- import React , { useState , useEffect , useRef , useMemo } from 'react' ;
4
-
5
5
import { Constants } from 'librechat-data-provider' ;
6
6
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query' ;
7
- import { Check , X } from 'lucide-react' ;
8
7
import type { MouseEvent , FocusEvent , KeyboardEvent } from 'react' ;
8
+ import type { TConversation } from 'librechat-data-provider' ;
9
9
import { useConversations , useNavigateToConvo , useMediaQuery } from '~/hooks' ;
10
10
import { useUpdateConversationMutation } from '~/data-provider' ;
11
11
import EndpointIcon from '~/components/Endpoints/EndpointIcon' ;
@@ -17,7 +17,19 @@ import store from '~/store';
17
17
18
18
type KeyEvent = KeyboardEvent < HTMLInputElement > ;
19
19
20
- export default function Conversation ( { conversation, retainView, toggleNav, isLatestConvo } ) {
20
+ type ConversationProps = {
21
+ conversation : TConversation ;
22
+ retainView : ( ) => void ;
23
+ toggleNav : ( ) => void ;
24
+ isLatestConvo : boolean ;
25
+ } ;
26
+
27
+ export default function Conversation ( {
28
+ conversation,
29
+ retainView,
30
+ toggleNav,
31
+ isLatestConvo,
32
+ } : ConversationProps ) {
21
33
const params = useParams ( ) ;
22
34
const currentConvoId = useMemo ( ( ) => params . conversationId , [ params . conversationId ] ) ;
23
35
const updateConvoMutation = useUpdateConversationMutation ( currentConvoId ?? '' ) ;
@@ -33,7 +45,7 @@ export default function Conversation({ conversation, retainView, toggleNav, isLa
33
45
const [ isPopoverActive , setIsPopoverActive ] = useState ( false ) ;
34
46
const isSmallScreen = useMediaQuery ( '(max-width: 768px)' ) ;
35
47
36
- const clickHandler = async ( event : React . MouseEvent < HTMLAnchorElement > ) => {
48
+ const clickHandler = async ( event : MouseEvent < HTMLAnchorElement > ) => {
37
49
if ( event . button === 0 && ( event . ctrlKey || event . metaKey ) ) {
38
50
toggleNav ( ) ;
39
51
return ;
@@ -47,12 +59,17 @@ export default function Conversation({ conversation, retainView, toggleNav, isLa
47
59
toggleNav ( ) ;
48
60
49
61
// set document title
50
- document . title = title ;
62
+ if ( typeof title === 'string' && title . length > 0 ) {
63
+ document . title = title ;
64
+ }
51
65
/* Note: Latest Message should not be reset if existing convo */
52
- navigateWithLastTools ( conversation , ! conversationId || conversationId === Constants . NEW_CONVO ) ;
66
+ navigateWithLastTools (
67
+ conversation ,
68
+ ! ( conversationId ?? '' ) || conversationId === Constants . NEW_CONVO ,
69
+ ) ;
53
70
} ;
54
71
55
- const renameHandler = ( e : MouseEvent < HTMLButtonElement > ) => {
72
+ const renameHandler : ( e : MouseEvent < HTMLButtonElement > ) => void = ( ) => {
56
73
setIsPopoverActive ( false ) ;
57
74
setTitleInput ( title ) ;
58
75
setRenaming ( true ) ;
@@ -70,8 +87,12 @@ export default function Conversation({ conversation, retainView, toggleNav, isLa
70
87
if ( titleInput === title ) {
71
88
return ;
72
89
}
90
+ if ( typeof conversationId !== 'string' || conversationId === '' ) {
91
+ return ;
92
+ }
93
+
73
94
updateConvoMutation . mutate (
74
- { conversationId, title : titleInput } ,
95
+ { conversationId, title : titleInput ?? '' } ,
75
96
{
76
97
onSuccess : ( ) => refreshConversations ( ) ,
77
98
onError : ( ) => {
@@ -101,14 +122,17 @@ export default function Conversation({ conversation, retainView, toggleNav, isLa
101
122
setRenaming ( false ) ;
102
123
} ;
103
124
104
- const isActiveConvo =
125
+ const isActiveConvo : boolean =
105
126
currentConvoId === conversationId ||
106
- ( isLatestConvo && currentConvoId === 'new' && activeConvos [ 0 ] && activeConvos [ 0 ] !== 'new' ) ;
127
+ ( isLatestConvo &&
128
+ currentConvoId === 'new' &&
129
+ activeConvos [ 0 ] != null &&
130
+ activeConvos [ 0 ] !== 'new' ) ;
107
131
108
132
return (
109
133
< div
110
134
className = { cn (
111
- 'group relative mt-2 flex h-9 items-center rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700' ,
135
+ 'group relative mt-2 flex h-9 w-full items-center rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700' ,
112
136
isActiveConvo ? 'bg-gray-200 dark:bg-gray-700' : '' ,
113
137
isSmallScreen ? 'h-12' : '' ,
114
138
) }
@@ -119,7 +143,7 @@ export default function Conversation({ conversation, retainView, toggleNav, isLa
119
143
ref = { inputRef }
120
144
type = "text"
121
145
className = "w-full rounded bg-transparent p-0.5 text-sm leading-tight outline-none"
122
- value = { titleInput }
146
+ value = { titleInput ?? '' }
123
147
onChange = { ( e ) => setTitleInput ( e . target . value ) }
124
148
onKeyDown = { handleKeyDown }
125
149
/>
@@ -141,24 +165,17 @@ export default function Conversation({ conversation, retainView, toggleNav, isLa
141
165
'flex grow cursor-pointer items-center gap-2 overflow-hidden whitespace-nowrap break-all rounded-lg px-2 py-2' ,
142
166
isActiveConvo ? 'bg-gray-200 dark:bg-gray-700' : '' ,
143
167
) }
144
- title = { title }
168
+ title = { title ?? '' }
145
169
>
146
170
< EndpointIcon
147
171
conversation = { conversation }
148
172
endpointsConfig = { endpointsConfig }
149
173
size = { 20 }
150
174
context = "menu-item"
151
175
/>
152
- { ! renaming && (
153
- < div className = "relative line-clamp-1 flex-1 grow overflow-hidden" > { title } </ div >
154
- ) }
176
+ < div className = "relative line-clamp-1 flex-1 grow overflow-hidden" > { title } </ div >
155
177
{ isActiveConvo ? (
156
- < div
157
- className = { cn (
158
- 'absolute bottom-0 right-0 top-0 w-20 rounded-r-lg bg-gradient-to-l' ,
159
- ! renaming ? 'from-gray-200 from-40% to-transparent dark:from-gray-700' : '' ,
160
- ) }
161
- />
178
+ < div className = "absolute bottom-0 right-0 top-0 w-20 rounded-r-lg bg-gradient-to-l" />
162
179
) : (
163
180
< div className = "absolute bottom-0 right-0 top-0 w-20 rounded-r-lg bg-gradient-to-l from-gray-50 from-0% to-transparent group-hover:from-gray-200 group-hover:from-40% dark:from-gray-850 dark:group-hover:from-gray-700" />
164
181
) }
@@ -167,7 +184,9 @@ export default function Conversation({ conversation, retainView, toggleNav, isLa
167
184
< div
168
185
className = { cn (
169
186
'mr-2' ,
170
- isPopoverActive || isActiveConvo ? 'flex' : 'hidden group-hover:flex' ,
187
+ isPopoverActive || isActiveConvo
188
+ ? 'flex'
189
+ : 'hidden group-focus-within:flex group-hover:flex' ,
171
190
) }
172
191
>
173
192
< ConvoOptions
0 commit comments