@@ -151,7 +151,7 @@ export class ChatPanel extends SidePanel {
151
151
* @param model - the model of the chat widget
152
152
* @param name - the name of the chat.
153
153
*/
154
- addChat ( model : IChatModel , name : string ) : void {
154
+ addChat ( model : IChatModel , name : string , path : string ) : void {
155
155
// Collapse all chats
156
156
const content = this . content as AccordionPanel ;
157
157
for ( let i = 0 ; i < this . widgets . length ; i ++ ) {
@@ -168,22 +168,45 @@ export class ChatPanel extends SidePanel {
168
168
themeManager : this . _themeManager ,
169
169
autocompletionRegistry : this . _autocompletionRegistry
170
170
} ) ;
171
- this . addWidget ( new ChatSection ( { name, widget, commands : this . _commands } ) ) ;
171
+ this . addWidget (
172
+ new ChatSection ( { name, widget, commands : this . _commands , path } )
173
+ ) ;
172
174
}
173
175
176
+ /**
177
+ * Update the list of available chats in the root directory of the drive.
178
+ */
174
179
updateChatNames = async ( ) : Promise < void > => {
175
180
const extension = chatFileType . extensions [ 0 ] ;
176
181
this . _drive
177
182
. get ( '.' )
178
- . then ( model => {
179
- const chatsName = ( model . content as any [ ] )
183
+ . then ( contentModel => {
184
+ const chatsNames : { [ name : string ] : string } = { } ;
185
+ ( contentModel . content as any [ ] )
180
186
. filter ( f => f . type === 'file' && f . name . endsWith ( extension ) )
181
- . map ( f => PathExt . basename ( f . name , extension ) ) ;
182
- this . _chatNamesChanged . emit ( chatsName ) ;
187
+ . forEach (
188
+ f => ( chatsNames [ PathExt . basename ( f . name , extension ) ] = f . name )
189
+ ) ;
190
+
191
+ this . _chatNamesChanged . emit ( chatsNames ) ;
183
192
} )
184
193
. catch ( e => console . error ( 'Error getting the chat files from drive' , e ) ) ;
185
194
} ;
186
195
196
+ /**
197
+ * Open a chat if it exists in the side panel.
198
+ *
199
+ * @param path - the path of the chat.
200
+ * @returns a boolean, whether the chat existed in the side panel or not.
201
+ */
202
+ openIfExists ( path : string ) : boolean {
203
+ const index = this . _getChatIndex ( path ) ;
204
+ if ( index > - 1 ) {
205
+ this . _expandChat ( index ) ;
206
+ }
207
+ return index > - 1 ;
208
+ }
209
+
187
210
/**
188
211
* A message handler invoked on an `'after-show'` message.
189
212
*/
@@ -192,28 +215,41 @@ export class ChatPanel extends SidePanel {
192
215
this . _openChat . renderPromise ?. then ( ( ) => this . updateChatNames ( ) ) ;
193
216
}
194
217
218
+ /**
219
+ * Return the index of the chat in the list (-1 if not opened).
220
+ *
221
+ * @param name - the chat name.
222
+ */
223
+ private _getChatIndex ( path : string ) {
224
+ return this . widgets . findIndex ( w => ( w as ChatSection ) . path === path ) ;
225
+ }
226
+
227
+ /**
228
+ * Expand the chat from its index.
229
+ */
230
+ private _expandChat ( index : number ) : void {
231
+ if ( ! this . widgets [ index ] . isVisible ) {
232
+ ( this . content as AccordionPanel ) . expand ( index ) ;
233
+ }
234
+ }
235
+
195
236
/**
196
237
* Handle `change` events for the HTMLSelect component.
197
238
*/
198
239
private _chatSelected = (
199
240
event : React . ChangeEvent < HTMLSelectElement >
200
241
) : void => {
201
- const value = event . target . value ;
202
- if ( value === '-' ) {
242
+ const select = event . target ;
243
+ const path = select . value ;
244
+ const name = select . options [ select . selectedIndex ] . textContent ;
245
+ if ( name === '-' ) {
203
246
return ;
204
247
}
205
248
206
- const index = this . widgets . findIndex (
207
- w => ( w as ChatSection ) . name === value
208
- ) ;
209
- if ( index === - 1 ) {
210
- this . _commands . execute ( CommandIDs . openChat , {
211
- filepath : `${ value } ${ chatFileType . extensions [ 0 ] } ` ,
212
- inSidePanel : true
213
- } ) ;
214
- } else if ( ! this . widgets [ index ] . isVisible ) {
215
- ( this . content as AccordionPanel ) . expand ( index ) ;
216
- }
249
+ this . _commands . execute ( CommandIDs . openChat , {
250
+ filepath : path ,
251
+ inSidePanel : true
252
+ } ) ;
217
253
event . target . selectedIndex = 0 ;
218
254
} ;
219
255
@@ -232,7 +268,9 @@ export class ChatPanel extends SidePanel {
232
268
}
233
269
}
234
270
235
- private _chatNamesChanged = new Signal < this, string [ ] > ( this ) ;
271
+ private _chatNamesChanged = new Signal < this, { [ name : string ] : string } > (
272
+ this
273
+ ) ;
236
274
private _commands : CommandRegistry ;
237
275
private _config : IConfig = { } ;
238
276
private _drive : ICollaborativeDrive ;
@@ -269,8 +307,9 @@ class ChatSection extends PanelWithToolbar {
269
307
super ( options ) ;
270
308
this . addClass ( SECTION_CLASS ) ;
271
309
this . _name = options . name ;
310
+ this . _path = options . path ;
272
311
this . title . label = this . _name ;
273
- this . title . caption = this . _name ;
312
+ this . title . caption = this . _path ;
274
313
this . toolbar . addClass ( TOOLBAR_CLASS ) ;
275
314
276
315
this . _markAsRead = new ToolbarButton ( {
@@ -316,6 +355,13 @@ class ChatSection extends PanelWithToolbar {
316
355
options . widget . node . style . height = '100%' ;
317
356
}
318
357
358
+ /**
359
+ * The path of the chat.
360
+ */
361
+ get path ( ) : string {
362
+ return this . _path ;
363
+ }
364
+
319
365
/**
320
366
* The name of the chat.
321
367
*/
@@ -353,6 +399,7 @@ class ChatSection extends PanelWithToolbar {
353
399
354
400
private _name : string ;
355
401
private _markAsRead : ToolbarButton ;
402
+ private _path : string ;
356
403
}
357
404
358
405
/**
@@ -366,11 +413,12 @@ export namespace ChatSection {
366
413
commands : CommandRegistry ;
367
414
name : string ;
368
415
widget : ChatWidget ;
416
+ path : string ;
369
417
}
370
418
}
371
419
372
420
type ChatSelectProps = {
373
- chatNamesChanged : ISignal < ChatPanel , string [ ] > ;
421
+ chatNamesChanged : ISignal < ChatPanel , { [ name : string ] : string } > ;
374
422
handleChange : ( event : React . ChangeEvent < HTMLSelectElement > ) => void ;
375
423
} ;
376
424
@@ -381,7 +429,9 @@ function ChatSelect({
381
429
chatNamesChanged,
382
430
handleChange
383
431
} : ChatSelectProps ) : JSX . Element {
384
- const [ chatNames , setChatNames ] = useState < string [ ] > ( [ ] ) ;
432
+ // An object associating a chat name to its path. Both are purely indicative, the name
433
+ // is the section title and the path is used as caption.
434
+ const [ chatNames , setChatNames ] = useState < { [ name : string ] : string } > ( { } ) ;
385
435
386
436
// Update the chat list.
387
437
chatNamesChanged . connect ( ( _ , chatNames ) => {
@@ -391,8 +441,8 @@ function ChatSelect({
391
441
return (
392
442
< HTMLSelect onChange = { handleChange } >
393
443
< option value = "-" > Open a chat</ option >
394
- { chatNames . map ( name => (
395
- < option value = { name } > { name } </ option >
444
+ { Object . keys ( chatNames ) . map ( name => (
445
+ < option value = { chatNames [ name ] } > { name } </ option >
396
446
) ) }
397
447
</ HTMLSelect >
398
448
) ;
0 commit comments