claude-code-templates 1.24.16 → 1.24.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/analytics-web/chats_mobile.html +1466 -21
- package/src/chats-mobile.js +258 -0
|
@@ -183,6 +183,554 @@
|
|
|
183
183
|
color: var(--text-secondary);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
/* Advanced Search Panel - Telegram Style */
|
|
187
|
+
.search-panel-overlay {
|
|
188
|
+
position: fixed;
|
|
189
|
+
top: 0;
|
|
190
|
+
left: 0;
|
|
191
|
+
right: 0;
|
|
192
|
+
bottom: 0;
|
|
193
|
+
background: rgba(0, 0, 0, 0.5);
|
|
194
|
+
z-index: 1000;
|
|
195
|
+
display: none;
|
|
196
|
+
animation: fadeIn 0.2s ease;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.search-panel-overlay.active {
|
|
200
|
+
display: flex;
|
|
201
|
+
align-items: flex-start;
|
|
202
|
+
justify-content: center;
|
|
203
|
+
padding-top: 10vh;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
@keyframes fadeIn {
|
|
207
|
+
from { opacity: 0; }
|
|
208
|
+
to { opacity: 1; }
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.search-panel {
|
|
212
|
+
background: var(--bg-secondary);
|
|
213
|
+
border-radius: 12px;
|
|
214
|
+
width: 90%;
|
|
215
|
+
max-width: 600px;
|
|
216
|
+
max-height: 80vh;
|
|
217
|
+
overflow-y: auto;
|
|
218
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
219
|
+
animation: slideDown 0.3s ease;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@keyframes slideDown {
|
|
223
|
+
from {
|
|
224
|
+
opacity: 0;
|
|
225
|
+
transform: translateY(-20px);
|
|
226
|
+
}
|
|
227
|
+
to {
|
|
228
|
+
opacity: 1;
|
|
229
|
+
transform: translateY(0);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.search-panel-header {
|
|
234
|
+
padding: 20px;
|
|
235
|
+
border-bottom: 1px solid var(--border-primary);
|
|
236
|
+
display: flex;
|
|
237
|
+
align-items: center;
|
|
238
|
+
justify-content: space-between;
|
|
239
|
+
position: sticky;
|
|
240
|
+
top: 0;
|
|
241
|
+
background: var(--bg-secondary);
|
|
242
|
+
z-index: 10;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.search-panel-title {
|
|
246
|
+
font-size: 1.25rem;
|
|
247
|
+
font-weight: 600;
|
|
248
|
+
color: var(--text-primary);
|
|
249
|
+
display: flex;
|
|
250
|
+
align-items: center;
|
|
251
|
+
gap: 10px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.search-panel-close {
|
|
255
|
+
background: none;
|
|
256
|
+
border: none;
|
|
257
|
+
color: var(--text-secondary);
|
|
258
|
+
font-size: 1.5rem;
|
|
259
|
+
cursor: pointer;
|
|
260
|
+
padding: 4px 8px;
|
|
261
|
+
border-radius: 4px;
|
|
262
|
+
transition: all 0.2s ease;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.search-panel-close:hover {
|
|
266
|
+
background: var(--bg-tertiary);
|
|
267
|
+
color: var(--text-primary);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.search-panel-body {
|
|
271
|
+
padding: 20px;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.search-filter-group {
|
|
275
|
+
margin-bottom: 24px;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.search-filter-label {
|
|
279
|
+
display: block;
|
|
280
|
+
color: var(--text-secondary);
|
|
281
|
+
font-size: 0.875rem;
|
|
282
|
+
font-weight: 500;
|
|
283
|
+
margin-bottom: 8px;
|
|
284
|
+
text-transform: uppercase;
|
|
285
|
+
letter-spacing: 0.5px;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.search-filter-input {
|
|
289
|
+
width: 100%;
|
|
290
|
+
padding: 12px 16px;
|
|
291
|
+
background: var(--bg-tertiary);
|
|
292
|
+
border: 1px solid var(--border-primary);
|
|
293
|
+
border-radius: 8px;
|
|
294
|
+
color: var(--text-primary);
|
|
295
|
+
font-size: 1rem;
|
|
296
|
+
outline: none;
|
|
297
|
+
transition: all 0.2s ease;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.search-filter-input:focus {
|
|
301
|
+
border-color: var(--terminal-orange);
|
|
302
|
+
background: var(--bg-primary);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.search-filter-input::placeholder {
|
|
306
|
+
color: var(--text-secondary);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.search-filter-date-range {
|
|
310
|
+
display: grid;
|
|
311
|
+
grid-template-columns: 1fr 1fr;
|
|
312
|
+
gap: 12px;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.search-filter-date-wrapper {
|
|
316
|
+
display: flex;
|
|
317
|
+
flex-direction: column;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.search-filter-date-label {
|
|
321
|
+
font-size: 0.75rem;
|
|
322
|
+
color: var(--text-secondary);
|
|
323
|
+
margin-bottom: 4px;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.search-panel-actions {
|
|
327
|
+
padding: 16px 20px;
|
|
328
|
+
border-top: 1px solid var(--border-primary);
|
|
329
|
+
display: flex;
|
|
330
|
+
gap: 12px;
|
|
331
|
+
position: sticky;
|
|
332
|
+
bottom: 0;
|
|
333
|
+
background: var(--bg-secondary);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.search-btn {
|
|
337
|
+
flex: 1;
|
|
338
|
+
padding: 14px 24px;
|
|
339
|
+
border: none;
|
|
340
|
+
border-radius: 8px;
|
|
341
|
+
font-size: 1rem;
|
|
342
|
+
font-weight: 600;
|
|
343
|
+
cursor: pointer;
|
|
344
|
+
transition: all 0.2s ease;
|
|
345
|
+
text-transform: uppercase;
|
|
346
|
+
letter-spacing: 0.5px;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.search-btn-primary {
|
|
350
|
+
background: var(--terminal-orange);
|
|
351
|
+
color: white;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.search-btn-primary:hover {
|
|
355
|
+
background: var(--terminal-orange-hover);
|
|
356
|
+
transform: translateY(-1px);
|
|
357
|
+
box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.search-btn-secondary {
|
|
361
|
+
background: var(--bg-tertiary);
|
|
362
|
+
color: var(--text-primary);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.search-btn-secondary:hover {
|
|
366
|
+
background: var(--border-secondary);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.search-btn:active {
|
|
370
|
+
transform: translateY(0);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.search-filter-icon {
|
|
374
|
+
display: inline-block;
|
|
375
|
+
margin-right: 6px;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.advanced-search-toggle {
|
|
379
|
+
background: var(--bg-tertiary);
|
|
380
|
+
border: 1px solid var(--border-primary);
|
|
381
|
+
color: var(--terminal-orange);
|
|
382
|
+
padding: 8px 12px;
|
|
383
|
+
border-radius: 20px;
|
|
384
|
+
cursor: pointer;
|
|
385
|
+
font-size: 0.875rem;
|
|
386
|
+
margin-left: 8px;
|
|
387
|
+
transition: all 0.2s ease;
|
|
388
|
+
display: inline-flex;
|
|
389
|
+
align-items: center;
|
|
390
|
+
gap: 6px;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.advanced-search-toggle:hover {
|
|
394
|
+
background: var(--terminal-orange);
|
|
395
|
+
color: white;
|
|
396
|
+
border-color: var(--terminal-orange);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.search-results-info {
|
|
400
|
+
background: var(--bg-tertiary);
|
|
401
|
+
border-radius: 8px;
|
|
402
|
+
padding: 12px 16px;
|
|
403
|
+
margin-bottom: 16px;
|
|
404
|
+
color: var(--text-secondary);
|
|
405
|
+
font-size: 0.875rem;
|
|
406
|
+
display: none;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.search-results-info.active {
|
|
410
|
+
display: block;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.search-results-count {
|
|
414
|
+
color: var(--terminal-orange);
|
|
415
|
+
font-weight: 600;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.clear-filters-btn {
|
|
419
|
+
background: none;
|
|
420
|
+
border: none;
|
|
421
|
+
color: var(--terminal-orange);
|
|
422
|
+
cursor: pointer;
|
|
423
|
+
font-size: 0.875rem;
|
|
424
|
+
text-decoration: underline;
|
|
425
|
+
padding: 0;
|
|
426
|
+
margin-left: 8px;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.clear-filters-btn:hover {
|
|
430
|
+
color: var(--terminal-orange-hover);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.filter-tag {
|
|
434
|
+
display: inline-flex;
|
|
435
|
+
align-items: center;
|
|
436
|
+
gap: 6px;
|
|
437
|
+
background: var(--bg-primary);
|
|
438
|
+
border: 1px solid var(--border-secondary);
|
|
439
|
+
border-radius: 12px;
|
|
440
|
+
padding: 4px 10px;
|
|
441
|
+
font-size: 0.75rem;
|
|
442
|
+
color: var(--text-primary);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.filter-tag-icon {
|
|
446
|
+
font-size: 0.7rem;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.filter-tag-label {
|
|
450
|
+
color: var(--text-secondary);
|
|
451
|
+
margin-right: 2px;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.filter-tag-value {
|
|
455
|
+
color: var(--terminal-orange);
|
|
456
|
+
font-weight: 500;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* Folder Browser */
|
|
460
|
+
.folder-browser-wrapper {
|
|
461
|
+
position: relative;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.folder-browser-toggle {
|
|
465
|
+
position: absolute;
|
|
466
|
+
right: 12px;
|
|
467
|
+
top: 50%;
|
|
468
|
+
transform: translateY(-50%);
|
|
469
|
+
background: var(--terminal-orange);
|
|
470
|
+
border: none;
|
|
471
|
+
color: white;
|
|
472
|
+
padding: 6px 12px;
|
|
473
|
+
border-radius: 6px;
|
|
474
|
+
cursor: pointer;
|
|
475
|
+
font-size: 0.875rem;
|
|
476
|
+
transition: all 0.2s ease;
|
|
477
|
+
z-index: 1;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.folder-browser-toggle:hover {
|
|
481
|
+
background: var(--terminal-orange-hover);
|
|
482
|
+
transform: translateY(-50%) scale(1.05);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.folder-browser-dropdown {
|
|
486
|
+
position: absolute;
|
|
487
|
+
top: calc(100% + 8px);
|
|
488
|
+
left: 0;
|
|
489
|
+
right: 0;
|
|
490
|
+
background: var(--bg-primary);
|
|
491
|
+
border: 1px solid var(--border-secondary);
|
|
492
|
+
border-radius: 8px;
|
|
493
|
+
max-height: 300px;
|
|
494
|
+
overflow-y: auto;
|
|
495
|
+
z-index: 100;
|
|
496
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
|
497
|
+
display: none;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.folder-browser-dropdown.active {
|
|
501
|
+
display: block;
|
|
502
|
+
animation: slideDown 0.2s ease;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.folder-browser-header {
|
|
506
|
+
padding: 12px 16px;
|
|
507
|
+
background: var(--bg-secondary);
|
|
508
|
+
border-bottom: 1px solid var(--border-primary);
|
|
509
|
+
position: sticky;
|
|
510
|
+
top: 0;
|
|
511
|
+
z-index: 10;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.folder-browser-search {
|
|
515
|
+
width: 100%;
|
|
516
|
+
padding: 8px 12px;
|
|
517
|
+
background: var(--bg-tertiary);
|
|
518
|
+
border: 1px solid var(--border-primary);
|
|
519
|
+
border-radius: 6px;
|
|
520
|
+
color: var(--text-primary);
|
|
521
|
+
font-size: 0.875rem;
|
|
522
|
+
outline: none;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.folder-browser-search:focus {
|
|
526
|
+
border-color: var(--terminal-orange);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.folder-browser-list {
|
|
530
|
+
padding: 4px 0;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.folder-item {
|
|
534
|
+
padding: 12px 16px;
|
|
535
|
+
cursor: pointer;
|
|
536
|
+
transition: background 0.2s ease;
|
|
537
|
+
display: flex;
|
|
538
|
+
align-items: center;
|
|
539
|
+
gap: 10px;
|
|
540
|
+
border-bottom: 1px solid var(--border-primary);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.folder-item:last-child {
|
|
544
|
+
border-bottom: none;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.folder-item:hover {
|
|
548
|
+
background: var(--bg-tertiary);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
.folder-item.selected {
|
|
552
|
+
background: var(--terminal-orange);
|
|
553
|
+
color: white;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.folder-icon {
|
|
557
|
+
font-size: 1.2rem;
|
|
558
|
+
flex-shrink: 0;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
.folder-path {
|
|
562
|
+
flex: 1;
|
|
563
|
+
font-size: 0.875rem;
|
|
564
|
+
overflow: hidden;
|
|
565
|
+
text-overflow: ellipsis;
|
|
566
|
+
white-space: nowrap;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.folder-item.selected .folder-path {
|
|
570
|
+
color: white;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.folder-count {
|
|
574
|
+
font-size: 0.75rem;
|
|
575
|
+
color: var(--text-secondary);
|
|
576
|
+
background: var(--bg-tertiary);
|
|
577
|
+
padding: 2px 8px;
|
|
578
|
+
border-radius: 10px;
|
|
579
|
+
flex-shrink: 0;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.folder-item.selected .folder-count {
|
|
583
|
+
background: rgba(255, 255, 255, 0.2);
|
|
584
|
+
color: white;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
.folder-browser-empty {
|
|
588
|
+
padding: 24px 16px;
|
|
589
|
+
text-align: center;
|
|
590
|
+
color: var(--text-secondary);
|
|
591
|
+
font-size: 0.875rem;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/* In-Conversation Search */
|
|
595
|
+
.chat-search-bar {
|
|
596
|
+
display: none;
|
|
597
|
+
background: var(--bg-secondary);
|
|
598
|
+
border-bottom: 1px solid var(--border-primary);
|
|
599
|
+
padding: 12px 16px;
|
|
600
|
+
align-items: center;
|
|
601
|
+
gap: 12px;
|
|
602
|
+
animation: slideDown 0.2s ease;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
.chat-search-bar.active {
|
|
606
|
+
display: flex;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
.chat-search-input-wrapper {
|
|
610
|
+
flex: 1;
|
|
611
|
+
position: relative;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.chat-search-input {
|
|
615
|
+
width: 100%;
|
|
616
|
+
padding: 8px 12px;
|
|
617
|
+
background: var(--bg-tertiary);
|
|
618
|
+
border: 1px solid var(--border-primary);
|
|
619
|
+
border-radius: 6px;
|
|
620
|
+
color: var(--text-primary);
|
|
621
|
+
font-size: 0.875rem;
|
|
622
|
+
outline: none;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.chat-search-input:focus {
|
|
626
|
+
border-color: var(--terminal-orange);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.chat-search-controls {
|
|
630
|
+
display: flex;
|
|
631
|
+
align-items: center;
|
|
632
|
+
gap: 8px;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
.chat-search-counter {
|
|
636
|
+
font-size: 0.875rem;
|
|
637
|
+
color: var(--text-secondary);
|
|
638
|
+
white-space: nowrap;
|
|
639
|
+
min-width: 60px;
|
|
640
|
+
text-align: center;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.chat-search-counter.has-results {
|
|
644
|
+
color: var(--terminal-orange);
|
|
645
|
+
font-weight: 500;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
.chat-search-nav-btn {
|
|
649
|
+
background: var(--bg-tertiary);
|
|
650
|
+
border: 1px solid var(--border-primary);
|
|
651
|
+
color: var(--text-primary);
|
|
652
|
+
padding: 6px 10px;
|
|
653
|
+
border-radius: 4px;
|
|
654
|
+
cursor: pointer;
|
|
655
|
+
font-size: 1rem;
|
|
656
|
+
transition: all 0.2s ease;
|
|
657
|
+
display: flex;
|
|
658
|
+
align-items: center;
|
|
659
|
+
justify-content: center;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.chat-search-nav-btn:hover:not(:disabled) {
|
|
663
|
+
background: var(--terminal-orange);
|
|
664
|
+
border-color: var(--terminal-orange);
|
|
665
|
+
color: white;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.chat-search-nav-btn:disabled {
|
|
669
|
+
opacity: 0.3;
|
|
670
|
+
cursor: not-allowed;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
.chat-search-close-btn {
|
|
674
|
+
background: none;
|
|
675
|
+
border: none;
|
|
676
|
+
color: var(--text-secondary);
|
|
677
|
+
padding: 4px 8px;
|
|
678
|
+
border-radius: 4px;
|
|
679
|
+
cursor: pointer;
|
|
680
|
+
font-size: 1.2rem;
|
|
681
|
+
transition: all 0.2s ease;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.chat-search-close-btn:hover {
|
|
685
|
+
background: var(--bg-tertiary);
|
|
686
|
+
color: var(--text-primary);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/* Message highlight */
|
|
690
|
+
.message-highlight {
|
|
691
|
+
background: var(--terminal-orange);
|
|
692
|
+
color: white;
|
|
693
|
+
padding: 2px 4px;
|
|
694
|
+
border-radius: 3px;
|
|
695
|
+
font-weight: 500;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.message-current-highlight {
|
|
699
|
+
background: #ffaa00;
|
|
700
|
+
color: white;
|
|
701
|
+
padding: 2px 4px;
|
|
702
|
+
border-radius: 3px;
|
|
703
|
+
font-weight: 600;
|
|
704
|
+
box-shadow: 0 0 8px rgba(255, 170, 0, 0.6);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/* Search toggle button in header */
|
|
708
|
+
.search-toggle-btn {
|
|
709
|
+
background: var(--bg-tertiary);
|
|
710
|
+
border: 1px solid var(--border-primary);
|
|
711
|
+
color: var(--terminal-orange);
|
|
712
|
+
padding: 6px 12px;
|
|
713
|
+
border-radius: 6px;
|
|
714
|
+
cursor: pointer;
|
|
715
|
+
font-size: 0.875rem;
|
|
716
|
+
transition: all 0.2s ease;
|
|
717
|
+
display: flex;
|
|
718
|
+
align-items: center;
|
|
719
|
+
gap: 6px;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.search-toggle-btn:hover {
|
|
723
|
+
background: var(--terminal-orange);
|
|
724
|
+
color: white;
|
|
725
|
+
border-color: var(--terminal-orange);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.search-toggle-btn.active {
|
|
729
|
+
background: var(--terminal-orange);
|
|
730
|
+
color: white;
|
|
731
|
+
border-color: var(--terminal-orange);
|
|
732
|
+
}
|
|
733
|
+
|
|
186
734
|
/* Conversations list */
|
|
187
735
|
.conversations-list {
|
|
188
736
|
flex: 1;
|
|
@@ -1195,12 +1743,30 @@
|
|
|
1195
1743
|
|
|
1196
1744
|
<!-- Search -->
|
|
1197
1745
|
<div class="chat-search">
|
|
1198
|
-
<
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1746
|
+
<div style="display: flex; align-items: center;">
|
|
1747
|
+
<input
|
|
1748
|
+
type="text"
|
|
1749
|
+
class="search-input"
|
|
1750
|
+
placeholder="Search conversations..."
|
|
1751
|
+
id="searchInput"
|
|
1752
|
+
style="flex: 1;"
|
|
1753
|
+
/>
|
|
1754
|
+
<button class="advanced-search-toggle" id="advancedSearchToggle">
|
|
1755
|
+
<span>🔍</span>
|
|
1756
|
+
<span>Advanced</span>
|
|
1757
|
+
</button>
|
|
1758
|
+
</div>
|
|
1759
|
+
|
|
1760
|
+
<!-- Search Results Info -->
|
|
1761
|
+
<div class="search-results-info" id="searchResultsInfo">
|
|
1762
|
+
<div style="display: flex; flex-direction: column; gap: 8px;">
|
|
1763
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
1764
|
+
<span>Found <span class="search-results-count" id="searchResultsCount">0</span> conversations</span>
|
|
1765
|
+
<button class="clear-filters-btn" id="clearFiltersBtn">Clear filters</button>
|
|
1766
|
+
</div>
|
|
1767
|
+
<div id="appliedFilters" style="display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px;"></div>
|
|
1768
|
+
</div>
|
|
1769
|
+
</div>
|
|
1204
1770
|
</div>
|
|
1205
1771
|
|
|
1206
1772
|
<!-- Conversations List -->
|
|
@@ -1209,6 +1775,127 @@
|
|
|
1209
1775
|
</div>
|
|
1210
1776
|
</div>
|
|
1211
1777
|
|
|
1778
|
+
<!-- Advanced Search Panel Overlay -->
|
|
1779
|
+
<div class="search-panel-overlay" id="searchPanelOverlay">
|
|
1780
|
+
<div class="search-panel">
|
|
1781
|
+
<!-- Panel Header -->
|
|
1782
|
+
<div class="search-panel-header">
|
|
1783
|
+
<h3 class="search-panel-title">
|
|
1784
|
+
<span class="search-filter-icon">🔍</span>
|
|
1785
|
+
Advanced Search
|
|
1786
|
+
</h3>
|
|
1787
|
+
<button class="search-panel-close" id="searchPanelClose">✕</button>
|
|
1788
|
+
</div>
|
|
1789
|
+
|
|
1790
|
+
<!-- Panel Body -->
|
|
1791
|
+
<div class="search-panel-body">
|
|
1792
|
+
<!-- Quick Search -->
|
|
1793
|
+
<div class="search-filter-group">
|
|
1794
|
+
<label class="search-filter-label">
|
|
1795
|
+
<span class="search-filter-icon">💬</span>
|
|
1796
|
+
Quick Search
|
|
1797
|
+
</label>
|
|
1798
|
+
<input
|
|
1799
|
+
type="text"
|
|
1800
|
+
class="search-filter-input"
|
|
1801
|
+
placeholder="Search by conversation ID or filename..."
|
|
1802
|
+
id="filterQuery"
|
|
1803
|
+
/>
|
|
1804
|
+
</div>
|
|
1805
|
+
|
|
1806
|
+
<!-- Working Directory Filter -->
|
|
1807
|
+
<div class="search-filter-group">
|
|
1808
|
+
<label class="search-filter-label">
|
|
1809
|
+
<span class="search-filter-icon">📁</span>
|
|
1810
|
+
Working Directory
|
|
1811
|
+
</label>
|
|
1812
|
+
<div class="folder-browser-wrapper">
|
|
1813
|
+
<input
|
|
1814
|
+
type="text"
|
|
1815
|
+
class="search-filter-input"
|
|
1816
|
+
placeholder="e.g., /Users/name/Projects/MyProject"
|
|
1817
|
+
id="filterWorkingDirectory"
|
|
1818
|
+
style="padding-right: 100px;"
|
|
1819
|
+
/>
|
|
1820
|
+
<button class="folder-browser-toggle" id="folderBrowserToggle">
|
|
1821
|
+
📂 Browse
|
|
1822
|
+
</button>
|
|
1823
|
+
|
|
1824
|
+
<!-- Folder Browser Dropdown -->
|
|
1825
|
+
<div class="folder-browser-dropdown" id="folderBrowserDropdown">
|
|
1826
|
+
<div class="folder-browser-header">
|
|
1827
|
+
<input
|
|
1828
|
+
type="text"
|
|
1829
|
+
class="folder-browser-search"
|
|
1830
|
+
placeholder="Filter directories..."
|
|
1831
|
+
id="folderBrowserSearch"
|
|
1832
|
+
/>
|
|
1833
|
+
</div>
|
|
1834
|
+
<div class="folder-browser-list" id="folderBrowserList">
|
|
1835
|
+
<div class="folder-browser-empty">
|
|
1836
|
+
Loading directories...
|
|
1837
|
+
</div>
|
|
1838
|
+
</div>
|
|
1839
|
+
</div>
|
|
1840
|
+
</div>
|
|
1841
|
+
</div>
|
|
1842
|
+
|
|
1843
|
+
<!-- Date Range Filter -->
|
|
1844
|
+
<div class="search-filter-group">
|
|
1845
|
+
<label class="search-filter-label">
|
|
1846
|
+
<span class="search-filter-icon">📅</span>
|
|
1847
|
+
Date Range
|
|
1848
|
+
</label>
|
|
1849
|
+
<div class="search-filter-date-range">
|
|
1850
|
+
<div class="search-filter-date-wrapper">
|
|
1851
|
+
<span class="search-filter-date-label">From</span>
|
|
1852
|
+
<input
|
|
1853
|
+
type="date"
|
|
1854
|
+
class="search-filter-input"
|
|
1855
|
+
id="filterDateFrom"
|
|
1856
|
+
/>
|
|
1857
|
+
</div>
|
|
1858
|
+
<div class="search-filter-date-wrapper">
|
|
1859
|
+
<span class="search-filter-date-label">To</span>
|
|
1860
|
+
<input
|
|
1861
|
+
type="date"
|
|
1862
|
+
class="search-filter-input"
|
|
1863
|
+
id="filterDateTo"
|
|
1864
|
+
/>
|
|
1865
|
+
</div>
|
|
1866
|
+
</div>
|
|
1867
|
+
</div>
|
|
1868
|
+
|
|
1869
|
+
<!-- Content Search -->
|
|
1870
|
+
<div class="search-filter-group">
|
|
1871
|
+
<label class="search-filter-label">
|
|
1872
|
+
<span class="search-filter-icon">🔎</span>
|
|
1873
|
+
Search in Messages
|
|
1874
|
+
</label>
|
|
1875
|
+
<input
|
|
1876
|
+
type="text"
|
|
1877
|
+
class="search-filter-input"
|
|
1878
|
+
placeholder="Search within conversation content..."
|
|
1879
|
+
id="filterContentSearch"
|
|
1880
|
+
/>
|
|
1881
|
+
<small style="color: var(--text-secondary); font-size: 0.75rem; margin-top: 4px; display: block;">
|
|
1882
|
+
⚠️ This may take longer for large conversations
|
|
1883
|
+
</small>
|
|
1884
|
+
</div>
|
|
1885
|
+
</div>
|
|
1886
|
+
|
|
1887
|
+
<!-- Panel Actions -->
|
|
1888
|
+
<div class="search-panel-actions">
|
|
1889
|
+
<button class="search-btn search-btn-secondary" id="searchPanelReset">
|
|
1890
|
+
Reset
|
|
1891
|
+
</button>
|
|
1892
|
+
<button class="search-btn search-btn-primary" id="searchPanelApply">
|
|
1893
|
+
Search
|
|
1894
|
+
</button>
|
|
1895
|
+
</div>
|
|
1896
|
+
</div>
|
|
1897
|
+
</div>
|
|
1898
|
+
|
|
1212
1899
|
<!-- Chat View -->
|
|
1213
1900
|
<div class="chat-view" id="chatView">
|
|
1214
1901
|
<div class="chat-view-header">
|
|
@@ -1227,6 +1914,10 @@
|
|
|
1227
1914
|
</button>
|
|
1228
1915
|
</div>
|
|
1229
1916
|
<div class="header-right">
|
|
1917
|
+
<button class="search-toggle-btn" id="chatSearchToggle">
|
|
1918
|
+
<span>🔍</span>
|
|
1919
|
+
<span>Search</span>
|
|
1920
|
+
</button>
|
|
1230
1921
|
<div class="tools-toggle" id="toolsToggle">
|
|
1231
1922
|
<span class="tools-toggle-label" onclick="document.getElementById('showToolsSwitch').click()">Show Tools</span>
|
|
1232
1923
|
<label class="toggle-switch">
|
|
@@ -1236,6 +1927,31 @@
|
|
|
1236
1927
|
</div>
|
|
1237
1928
|
</div>
|
|
1238
1929
|
</div>
|
|
1930
|
+
|
|
1931
|
+
<!-- In-Conversation Search Bar -->
|
|
1932
|
+
<div class="chat-search-bar" id="chatSearchBar">
|
|
1933
|
+
<div class="chat-search-input-wrapper">
|
|
1934
|
+
<input
|
|
1935
|
+
type="text"
|
|
1936
|
+
class="chat-search-input"
|
|
1937
|
+
placeholder="Search in this conversation..."
|
|
1938
|
+
id="chatSearchInput"
|
|
1939
|
+
/>
|
|
1940
|
+
</div>
|
|
1941
|
+
<div class="chat-search-controls">
|
|
1942
|
+
<span class="chat-search-counter" id="chatSearchCounter">0/0</span>
|
|
1943
|
+
<button class="chat-search-nav-btn" id="chatSearchPrev" title="Previous match (↑)">
|
|
1944
|
+
↑
|
|
1945
|
+
</button>
|
|
1946
|
+
<button class="chat-search-nav-btn" id="chatSearchNext" title="Next match (↓)">
|
|
1947
|
+
↓
|
|
1948
|
+
</button>
|
|
1949
|
+
<button class="chat-search-close-btn" id="chatSearchClose">
|
|
1950
|
+
✕
|
|
1951
|
+
</button>
|
|
1952
|
+
</div>
|
|
1953
|
+
</div>
|
|
1954
|
+
|
|
1239
1955
|
<div class="chat-messages" id="chatMessages">
|
|
1240
1956
|
<div class="no-conversations">
|
|
1241
1957
|
<div class="no-conversations-icon">💬</div>
|
|
@@ -1340,6 +2056,109 @@
|
|
|
1340
2056
|
this.filterConversations(e.target.value);
|
|
1341
2057
|
});
|
|
1342
2058
|
|
|
2059
|
+
// Advanced search toggle
|
|
2060
|
+
document.getElementById('advancedSearchToggle').addEventListener('click', () => {
|
|
2061
|
+
this.openAdvancedSearch();
|
|
2062
|
+
});
|
|
2063
|
+
|
|
2064
|
+
// Advanced search panel close
|
|
2065
|
+
document.getElementById('searchPanelClose').addEventListener('click', () => {
|
|
2066
|
+
this.closeAdvancedSearch();
|
|
2067
|
+
});
|
|
2068
|
+
|
|
2069
|
+
// Close panel on overlay click
|
|
2070
|
+
document.getElementById('searchPanelOverlay').addEventListener('click', (e) => {
|
|
2071
|
+
if (e.target.id === 'searchPanelOverlay') {
|
|
2072
|
+
this.closeAdvancedSearch();
|
|
2073
|
+
}
|
|
2074
|
+
});
|
|
2075
|
+
|
|
2076
|
+
// Advanced search apply
|
|
2077
|
+
document.getElementById('searchPanelApply').addEventListener('click', () => {
|
|
2078
|
+
this.applyAdvancedSearch();
|
|
2079
|
+
});
|
|
2080
|
+
|
|
2081
|
+
// Advanced search reset
|
|
2082
|
+
document.getElementById('searchPanelReset').addEventListener('click', () => {
|
|
2083
|
+
this.resetAdvancedSearch();
|
|
2084
|
+
});
|
|
2085
|
+
|
|
2086
|
+
// Clear filters button
|
|
2087
|
+
document.getElementById('clearFiltersBtn').addEventListener('click', () => {
|
|
2088
|
+
this.clearAllFilters();
|
|
2089
|
+
});
|
|
2090
|
+
|
|
2091
|
+
// Folder browser toggle
|
|
2092
|
+
document.getElementById('folderBrowserToggle').addEventListener('click', (e) => {
|
|
2093
|
+
e.preventDefault();
|
|
2094
|
+
e.stopPropagation();
|
|
2095
|
+
this.toggleFolderBrowser();
|
|
2096
|
+
});
|
|
2097
|
+
|
|
2098
|
+
// Folder browser search
|
|
2099
|
+
document.getElementById('folderBrowserSearch').addEventListener('input', (e) => {
|
|
2100
|
+
this.filterFolderBrowserList(e.target.value);
|
|
2101
|
+
});
|
|
2102
|
+
|
|
2103
|
+
// Close folder browser when clicking outside
|
|
2104
|
+
document.addEventListener('click', (e) => {
|
|
2105
|
+
const dropdown = document.getElementById('folderBrowserDropdown');
|
|
2106
|
+
const toggle = document.getElementById('folderBrowserToggle');
|
|
2107
|
+
const wrapper = document.querySelector('.folder-browser-wrapper');
|
|
2108
|
+
|
|
2109
|
+
if (dropdown.classList.contains('active') &&
|
|
2110
|
+
!wrapper.contains(e.target)) {
|
|
2111
|
+
dropdown.classList.remove('active');
|
|
2112
|
+
}
|
|
2113
|
+
});
|
|
2114
|
+
|
|
2115
|
+
// In-conversation search toggle
|
|
2116
|
+
document.getElementById('chatSearchToggle').addEventListener('click', () => {
|
|
2117
|
+
this.toggleChatSearch();
|
|
2118
|
+
});
|
|
2119
|
+
|
|
2120
|
+
// In-conversation search input (only search with 3+ characters)
|
|
2121
|
+
document.getElementById('chatSearchInput').addEventListener('input', (e) => {
|
|
2122
|
+
const query = e.target.value.trim();
|
|
2123
|
+
if (query.length >= 3) {
|
|
2124
|
+
this.performChatSearch(query);
|
|
2125
|
+
} else if (query.length === 0) {
|
|
2126
|
+
// Clear search when input is empty
|
|
2127
|
+
this.clearChatSearch();
|
|
2128
|
+
} else {
|
|
2129
|
+
// Show message that minimum 3 characters are required
|
|
2130
|
+
this.updateSearchCounter(0, 0, true);
|
|
2131
|
+
}
|
|
2132
|
+
});
|
|
2133
|
+
|
|
2134
|
+
// In-conversation search navigation
|
|
2135
|
+
document.getElementById('chatSearchPrev').addEventListener('click', () => {
|
|
2136
|
+
this.navigateSearchResults('prev');
|
|
2137
|
+
});
|
|
2138
|
+
|
|
2139
|
+
document.getElementById('chatSearchNext').addEventListener('click', () => {
|
|
2140
|
+
this.navigateSearchResults('next');
|
|
2141
|
+
});
|
|
2142
|
+
|
|
2143
|
+
// In-conversation search close
|
|
2144
|
+
document.getElementById('chatSearchClose').addEventListener('click', () => {
|
|
2145
|
+
this.closeChatSearch();
|
|
2146
|
+
});
|
|
2147
|
+
|
|
2148
|
+
// Keyboard shortcuts for search
|
|
2149
|
+
document.getElementById('chatSearchInput').addEventListener('keydown', (e) => {
|
|
2150
|
+
if (e.key === 'Enter') {
|
|
2151
|
+
e.preventDefault();
|
|
2152
|
+
if (e.shiftKey) {
|
|
2153
|
+
this.navigateSearchResults('prev');
|
|
2154
|
+
} else {
|
|
2155
|
+
this.navigateSearchResults('next');
|
|
2156
|
+
}
|
|
2157
|
+
} else if (e.key === 'Escape') {
|
|
2158
|
+
this.closeChatSearch();
|
|
2159
|
+
}
|
|
2160
|
+
});
|
|
2161
|
+
|
|
1343
2162
|
// Show Tools toggle functionality
|
|
1344
2163
|
const showToolsSwitch = document.getElementById('showToolsSwitch');
|
|
1345
2164
|
showToolsSwitch.addEventListener('change', (e) => {
|
|
@@ -1717,22 +2536,26 @@
|
|
|
1717
2536
|
const scrollHeight = chatMessages.scrollHeight;
|
|
1718
2537
|
|
|
1719
2538
|
// Prepend new messages
|
|
1720
|
-
|
|
2539
|
+
// Calculate message indices (considering we're prepending older messages)
|
|
2540
|
+
const startIndex = this.messagesPagination.currentPage * this.messagesPagination.limit;
|
|
2541
|
+
const newMessagesHTML = messages.map((msg, idx) =>
|
|
2542
|
+
this.renderMessage(msg, startIndex + idx)
|
|
2543
|
+
).join('');
|
|
1721
2544
|
existingMessagesDiv.innerHTML = newMessagesHTML + existingMessagesDiv.innerHTML;
|
|
1722
|
-
|
|
2545
|
+
|
|
1723
2546
|
// Restore scroll position (account for new content)
|
|
1724
2547
|
const newScrollHeight = chatMessages.scrollHeight;
|
|
1725
2548
|
const scrollDiff = newScrollHeight - scrollHeight;
|
|
1726
2549
|
chatMessages.scrollTop = scrollTop + scrollDiff;
|
|
1727
|
-
|
|
2550
|
+
|
|
1728
2551
|
} else {
|
|
1729
2552
|
// Normal render (initial load or replace all)
|
|
1730
2553
|
const messageHTML = `
|
|
1731
2554
|
<div class="messages-list">
|
|
1732
|
-
${messages.map(msg => this.renderMessage(msg)).join('')}
|
|
2555
|
+
${messages.map((msg, idx) => this.renderMessage(msg, idx)).join('')}
|
|
1733
2556
|
</div>
|
|
1734
2557
|
`;
|
|
1735
|
-
|
|
2558
|
+
|
|
1736
2559
|
chatMessages.innerHTML = messageHTML;
|
|
1737
2560
|
}
|
|
1738
2561
|
}
|
|
@@ -1800,17 +2623,17 @@
|
|
|
1800
2623
|
chatMessages.addEventListener('scroll', this.messagesScrollListener);
|
|
1801
2624
|
}
|
|
1802
2625
|
|
|
1803
|
-
renderMessage(message) {
|
|
2626
|
+
renderMessage(message, messageIndex) {
|
|
1804
2627
|
const timestamp = this.formatRelativeTime(new Date(message.timestamp));
|
|
1805
2628
|
const fullTimestamp = new Date(message.timestamp).toLocaleString();
|
|
1806
2629
|
const isUser = message.role === 'user' && !message.isCompactSummary;
|
|
1807
|
-
|
|
2630
|
+
|
|
1808
2631
|
// Detect if message contains tools (either in content or as correlated toolResults)
|
|
1809
|
-
const hasToolsInContent = Array.isArray(message.content) &&
|
|
2632
|
+
const hasToolsInContent = Array.isArray(message.content) &&
|
|
1810
2633
|
message.content.some(block => block.type === 'tool_use');
|
|
1811
2634
|
const hasCorrelatedTools = message.toolResults && message.toolResults.length > 0;
|
|
1812
2635
|
const hasTools = hasToolsInContent || hasCorrelatedTools;
|
|
1813
|
-
|
|
2636
|
+
|
|
1814
2637
|
// Debug logging for tool detection
|
|
1815
2638
|
if (hasTools) {
|
|
1816
2639
|
console.log('🔧 Rendering message with tools', {
|
|
@@ -1823,16 +2646,19 @@
|
|
|
1823
2646
|
willHaveHasToolsClass: !isUser && hasTools
|
|
1824
2647
|
});
|
|
1825
2648
|
}
|
|
1826
|
-
|
|
1827
|
-
const toolCount = hasToolsInContent ?
|
|
2649
|
+
|
|
2650
|
+
const toolCount = hasToolsInContent ?
|
|
1828
2651
|
message.content.filter(block => block.type === 'tool_use').length :
|
|
1829
2652
|
(hasCorrelatedTools ? message.toolResults.length : 0);
|
|
1830
|
-
|
|
2653
|
+
|
|
1831
2654
|
// Add has-tools class to assistant messages that contain tools
|
|
1832
2655
|
const hasToolsClass = (!isUser && hasTools) ? ' has-tools' : '';
|
|
1833
|
-
|
|
2656
|
+
|
|
2657
|
+
// Add message index for search functionality
|
|
2658
|
+
const messageIndexAttr = messageIndex !== undefined ? ` data-message-index="${messageIndex}"` : '';
|
|
2659
|
+
|
|
1834
2660
|
return `
|
|
1835
|
-
<div class="message message-${isUser ? 'user' : 'assistant'}${hasToolsClass}" data-message-id="${message.id || ''}">
|
|
2661
|
+
<div class="message message-${isUser ? 'user' : 'assistant'}${hasToolsClass}" data-message-id="${message.id || ''}"${messageIndexAttr}>
|
|
1836
2662
|
<div class="message-bubble">
|
|
1837
2663
|
<div class="message-content">
|
|
1838
2664
|
${this.formatMessageContent(message.content, message)}
|
|
@@ -2200,7 +3026,7 @@
|
|
|
2200
3026
|
filterConversations(searchTerm) {
|
|
2201
3027
|
const items = document.querySelectorAll('.conversation-item');
|
|
2202
3028
|
const term = searchTerm.toLowerCase();
|
|
2203
|
-
|
|
3029
|
+
|
|
2204
3030
|
items.forEach(item => {
|
|
2205
3031
|
const name = item.querySelector('.conversation-name').textContent.toLowerCase();
|
|
2206
3032
|
const preview = item.querySelector('.conversation-preview').textContent.toLowerCase();
|
|
@@ -2209,6 +3035,625 @@
|
|
|
2209
3035
|
});
|
|
2210
3036
|
}
|
|
2211
3037
|
|
|
3038
|
+
// Advanced Search Methods
|
|
3039
|
+
openAdvancedSearch() {
|
|
3040
|
+
const overlay = document.getElementById('searchPanelOverlay');
|
|
3041
|
+
overlay.classList.add('active');
|
|
3042
|
+
document.body.style.overflow = 'hidden'; // Prevent background scrolling
|
|
3043
|
+
}
|
|
3044
|
+
|
|
3045
|
+
closeAdvancedSearch() {
|
|
3046
|
+
const overlay = document.getElementById('searchPanelOverlay');
|
|
3047
|
+
overlay.classList.remove('active');
|
|
3048
|
+
document.body.style.overflow = ''; // Restore scrolling
|
|
3049
|
+
}
|
|
3050
|
+
|
|
3051
|
+
async applyAdvancedSearch() {
|
|
3052
|
+
const conversationsList = document.getElementById('conversationsList');
|
|
3053
|
+
const searchResultsInfo = document.getElementById('searchResultsInfo');
|
|
3054
|
+
const searchResultsCount = document.getElementById('searchResultsCount');
|
|
3055
|
+
const appliedFiltersContainer = document.getElementById('appliedFilters');
|
|
3056
|
+
|
|
3057
|
+
try {
|
|
3058
|
+
// Show loading state
|
|
3059
|
+
conversationsList.innerHTML = '<div class="loading-spinner" style="margin: 40px auto;"></div>';
|
|
3060
|
+
|
|
3061
|
+
// Get filter values
|
|
3062
|
+
const filters = {
|
|
3063
|
+
query: document.getElementById('filterQuery').value.trim(),
|
|
3064
|
+
workingDirectory: document.getElementById('filterWorkingDirectory').value.trim(),
|
|
3065
|
+
dateFrom: document.getElementById('filterDateFrom').value,
|
|
3066
|
+
dateTo: document.getElementById('filterDateTo').value,
|
|
3067
|
+
contentSearch: document.getElementById('filterContentSearch').value.trim()
|
|
3068
|
+
};
|
|
3069
|
+
|
|
3070
|
+
// Call the search API
|
|
3071
|
+
const response = await fetch('/api/search', {
|
|
3072
|
+
method: 'POST',
|
|
3073
|
+
headers: {
|
|
3074
|
+
'Content-Type': 'application/json'
|
|
3075
|
+
},
|
|
3076
|
+
body: JSON.stringify(filters)
|
|
3077
|
+
});
|
|
3078
|
+
|
|
3079
|
+
if (!response.ok) {
|
|
3080
|
+
throw new Error(`Search failed: ${response.status}`);
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
const data = await response.json();
|
|
3084
|
+
|
|
3085
|
+
// Update conversations with search results
|
|
3086
|
+
this.conversations = data.results || [];
|
|
3087
|
+
|
|
3088
|
+
// Get conversation states for the results
|
|
3089
|
+
const statesResponse = await fetch('/api/conversation-state');
|
|
3090
|
+
let states = {};
|
|
3091
|
+
if (statesResponse.ok) {
|
|
3092
|
+
const statesData = await statesResponse.json();
|
|
3093
|
+
states = statesData.activeStates || {};
|
|
3094
|
+
}
|
|
3095
|
+
|
|
3096
|
+
// Render search results
|
|
3097
|
+
this.renderConversations(this.conversations, states);
|
|
3098
|
+
|
|
3099
|
+
// Show search results info with applied filters
|
|
3100
|
+
searchResultsCount.textContent = data.count;
|
|
3101
|
+
this.renderAppliedFilters(filters, appliedFiltersContainer);
|
|
3102
|
+
searchResultsInfo.classList.add('active');
|
|
3103
|
+
|
|
3104
|
+
// Close the search panel
|
|
3105
|
+
this.closeAdvancedSearch();
|
|
3106
|
+
|
|
3107
|
+
console.log('🔍 Search completed:', data.count, 'results found');
|
|
3108
|
+
} catch (error) {
|
|
3109
|
+
console.error('Error performing advanced search:', error);
|
|
3110
|
+
conversationsList.innerHTML = `
|
|
3111
|
+
<div class="no-conversations">
|
|
3112
|
+
<div class="no-conversations-icon">⚠️</div>
|
|
3113
|
+
<h3>Search Error</h3>
|
|
3114
|
+
<p>${error.message}</p>
|
|
3115
|
+
<button onclick="location.reload()" style="margin-top: 12px; padding: 8px 16px; background: var(--text-accent); color: white; border: none; border-radius: 4px; cursor: pointer;">Retry</button>
|
|
3116
|
+
</div>
|
|
3117
|
+
`;
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
renderAppliedFilters(filters, container) {
|
|
3122
|
+
container.innerHTML = '';
|
|
3123
|
+
|
|
3124
|
+
const filterTags = [];
|
|
3125
|
+
|
|
3126
|
+
// Quick search filter
|
|
3127
|
+
if (filters.query) {
|
|
3128
|
+
filterTags.push({
|
|
3129
|
+
icon: '💬',
|
|
3130
|
+
label: 'Search',
|
|
3131
|
+
value: filters.query
|
|
3132
|
+
});
|
|
3133
|
+
}
|
|
3134
|
+
|
|
3135
|
+
// Working directory filter
|
|
3136
|
+
if (filters.workingDirectory) {
|
|
3137
|
+
// Shorten the path for display
|
|
3138
|
+
const shortPath = filters.workingDirectory.length > 30
|
|
3139
|
+
? '...' + filters.workingDirectory.slice(-30)
|
|
3140
|
+
: filters.workingDirectory;
|
|
3141
|
+
filterTags.push({
|
|
3142
|
+
icon: '📁',
|
|
3143
|
+
label: 'Directory',
|
|
3144
|
+
value: shortPath
|
|
3145
|
+
});
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
// Date range filter
|
|
3149
|
+
if (filters.dateFrom || filters.dateTo) {
|
|
3150
|
+
let dateValue = '';
|
|
3151
|
+
if (filters.dateFrom && filters.dateTo) {
|
|
3152
|
+
dateValue = `${this.formatDate(filters.dateFrom)} → ${this.formatDate(filters.dateTo)}`;
|
|
3153
|
+
} else if (filters.dateFrom) {
|
|
3154
|
+
dateValue = `From ${this.formatDate(filters.dateFrom)}`;
|
|
3155
|
+
} else if (filters.dateTo) {
|
|
3156
|
+
dateValue = `Until ${this.formatDate(filters.dateTo)}`;
|
|
3157
|
+
}
|
|
3158
|
+
filterTags.push({
|
|
3159
|
+
icon: '📅',
|
|
3160
|
+
label: 'Date',
|
|
3161
|
+
value: dateValue
|
|
3162
|
+
});
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
// Content search filter
|
|
3166
|
+
if (filters.contentSearch) {
|
|
3167
|
+
filterTags.push({
|
|
3168
|
+
icon: '🔎',
|
|
3169
|
+
label: 'Content',
|
|
3170
|
+
value: filters.contentSearch
|
|
3171
|
+
});
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
// Render filter tags
|
|
3175
|
+
filterTags.forEach(tag => {
|
|
3176
|
+
const tagElement = document.createElement('div');
|
|
3177
|
+
tagElement.className = 'filter-tag';
|
|
3178
|
+
tagElement.innerHTML = `
|
|
3179
|
+
<span class="filter-tag-icon">${tag.icon}</span>
|
|
3180
|
+
<span class="filter-tag-label">${tag.label}:</span>
|
|
3181
|
+
<span class="filter-tag-value">${tag.value}</span>
|
|
3182
|
+
`;
|
|
3183
|
+
container.appendChild(tagElement);
|
|
3184
|
+
});
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
formatDate(dateString) {
|
|
3188
|
+
const date = new Date(dateString);
|
|
3189
|
+
const options = { month: 'short', day: 'numeric', year: 'numeric' };
|
|
3190
|
+
return date.toLocaleDateString('en-US', options);
|
|
3191
|
+
}
|
|
3192
|
+
|
|
3193
|
+
// Folder Browser Methods
|
|
3194
|
+
async toggleFolderBrowser() {
|
|
3195
|
+
const dropdown = document.getElementById('folderBrowserDropdown');
|
|
3196
|
+
const isActive = dropdown.classList.contains('active');
|
|
3197
|
+
|
|
3198
|
+
if (isActive) {
|
|
3199
|
+
dropdown.classList.remove('active');
|
|
3200
|
+
} else {
|
|
3201
|
+
// Load directories if not loaded yet
|
|
3202
|
+
if (!this.directories) {
|
|
3203
|
+
await this.loadDirectories();
|
|
3204
|
+
}
|
|
3205
|
+
dropdown.classList.add('active');
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
async loadDirectories() {
|
|
3210
|
+
const listContainer = document.getElementById('folderBrowserList');
|
|
3211
|
+
|
|
3212
|
+
try {
|
|
3213
|
+
listContainer.innerHTML = '<div class="folder-browser-empty">Loading directories...</div>';
|
|
3214
|
+
|
|
3215
|
+
const response = await fetch('/api/directories');
|
|
3216
|
+
if (!response.ok) {
|
|
3217
|
+
throw new Error('Failed to load directories');
|
|
3218
|
+
}
|
|
3219
|
+
|
|
3220
|
+
const data = await response.json();
|
|
3221
|
+
this.directories = data.directories || [];
|
|
3222
|
+
|
|
3223
|
+
// Count conversations per directory
|
|
3224
|
+
this.directoryCounts = {};
|
|
3225
|
+
this.conversations.forEach(conv => {
|
|
3226
|
+
if (conv.project) {
|
|
3227
|
+
this.directoryCounts[conv.project] = (this.directoryCounts[conv.project] || 0) + 1;
|
|
3228
|
+
}
|
|
3229
|
+
});
|
|
3230
|
+
|
|
3231
|
+
this.renderFolderBrowserList(this.directories);
|
|
3232
|
+
} catch (error) {
|
|
3233
|
+
console.error('Error loading directories:', error);
|
|
3234
|
+
listContainer.innerHTML = '<div class="folder-browser-empty">Error loading directories</div>';
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3238
|
+
renderFolderBrowserList(directories) {
|
|
3239
|
+
const listContainer = document.getElementById('folderBrowserList');
|
|
3240
|
+
const currentValue = document.getElementById('filterWorkingDirectory').value;
|
|
3241
|
+
|
|
3242
|
+
if (directories.length === 0) {
|
|
3243
|
+
listContainer.innerHTML = '<div class="folder-browser-empty">No directories found</div>';
|
|
3244
|
+
return;
|
|
3245
|
+
}
|
|
3246
|
+
|
|
3247
|
+
listContainer.innerHTML = directories.map(dir => {
|
|
3248
|
+
const count = this.directoryCounts[dir] || 0;
|
|
3249
|
+
const isSelected = dir === currentValue;
|
|
3250
|
+
|
|
3251
|
+
return `
|
|
3252
|
+
<div class="folder-item ${isSelected ? 'selected' : ''}" data-path="${this.escapeHtml(dir)}">
|
|
3253
|
+
<span class="folder-icon">📁</span>
|
|
3254
|
+
<span class="folder-path" title="${this.escapeHtml(dir)}">${this.escapeHtml(dir)}</span>
|
|
3255
|
+
<span class="folder-count">${count}</span>
|
|
3256
|
+
</div>
|
|
3257
|
+
`;
|
|
3258
|
+
}).join('');
|
|
3259
|
+
|
|
3260
|
+
// Add click handlers to folder items
|
|
3261
|
+
listContainer.querySelectorAll('.folder-item').forEach(item => {
|
|
3262
|
+
item.addEventListener('click', () => {
|
|
3263
|
+
const path = item.getAttribute('data-path');
|
|
3264
|
+
this.selectDirectory(path);
|
|
3265
|
+
});
|
|
3266
|
+
});
|
|
3267
|
+
}
|
|
3268
|
+
|
|
3269
|
+
selectDirectory(path) {
|
|
3270
|
+
const input = document.getElementById('filterWorkingDirectory');
|
|
3271
|
+
const dropdown = document.getElementById('folderBrowserDropdown');
|
|
3272
|
+
|
|
3273
|
+
input.value = path;
|
|
3274
|
+
dropdown.classList.remove('active');
|
|
3275
|
+
|
|
3276
|
+
// Update UI to show selected folder
|
|
3277
|
+
this.renderFolderBrowserList(this.directories);
|
|
3278
|
+
}
|
|
3279
|
+
|
|
3280
|
+
filterFolderBrowserList(searchTerm) {
|
|
3281
|
+
if (!this.directories) return;
|
|
3282
|
+
|
|
3283
|
+
const term = searchTerm.toLowerCase();
|
|
3284
|
+
const filtered = this.directories.filter(dir =>
|
|
3285
|
+
dir.toLowerCase().includes(term)
|
|
3286
|
+
);
|
|
3287
|
+
|
|
3288
|
+
this.renderFolderBrowserList(filtered);
|
|
3289
|
+
}
|
|
3290
|
+
|
|
3291
|
+
escapeHtml(text) {
|
|
3292
|
+
const div = document.createElement('div');
|
|
3293
|
+
div.textContent = text;
|
|
3294
|
+
return div.innerHTML;
|
|
3295
|
+
}
|
|
3296
|
+
|
|
3297
|
+
// In-Conversation Search Methods
|
|
3298
|
+
toggleChatSearch() {
|
|
3299
|
+
const searchBar = document.getElementById('chatSearchBar');
|
|
3300
|
+
const toggle = document.getElementById('chatSearchToggle');
|
|
3301
|
+
const isActive = searchBar.classList.contains('active');
|
|
3302
|
+
|
|
3303
|
+
if (isActive) {
|
|
3304
|
+
this.closeChatSearch();
|
|
3305
|
+
} else {
|
|
3306
|
+
searchBar.classList.add('active');
|
|
3307
|
+
toggle.classList.add('active');
|
|
3308
|
+
document.getElementById('chatSearchInput').focus();
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
|
|
3312
|
+
closeChatSearch() {
|
|
3313
|
+
const searchBar = document.getElementById('chatSearchBar');
|
|
3314
|
+
const toggle = document.getElementById('chatSearchToggle');
|
|
3315
|
+
const input = document.getElementById('chatSearchInput');
|
|
3316
|
+
|
|
3317
|
+
searchBar.classList.remove('active');
|
|
3318
|
+
toggle.classList.remove('active');
|
|
3319
|
+
input.value = '';
|
|
3320
|
+
|
|
3321
|
+
// Clear search state
|
|
3322
|
+
this.chatSearchMatches = [];
|
|
3323
|
+
this.chatSearchCurrentIndex = -1;
|
|
3324
|
+
this.updateSearchCounter();
|
|
3325
|
+
this.clearSearchHighlights();
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3328
|
+
clearChatSearch() {
|
|
3329
|
+
// Clear search results but keep search bar open
|
|
3330
|
+
this.chatSearchMatches = [];
|
|
3331
|
+
this.chatSearchCurrentIndex = -1;
|
|
3332
|
+
this.updateSearchCounter();
|
|
3333
|
+
this.clearSearchHighlights();
|
|
3334
|
+
}
|
|
3335
|
+
|
|
3336
|
+
async performChatSearch(query) {
|
|
3337
|
+
if (!this.selectedConversationId || !query || query.trim().length === 0) {
|
|
3338
|
+
this.chatSearchMatches = [];
|
|
3339
|
+
this.chatSearchCurrentIndex = -1;
|
|
3340
|
+
this.updateSearchCounter();
|
|
3341
|
+
this.clearSearchHighlights();
|
|
3342
|
+
return;
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
try {
|
|
3346
|
+
const response = await fetch(`/api/conversations/${this.selectedConversationId}/search`, {
|
|
3347
|
+
method: 'POST',
|
|
3348
|
+
headers: {
|
|
3349
|
+
'Content-Type': 'application/json'
|
|
3350
|
+
},
|
|
3351
|
+
body: JSON.stringify({ query: query.trim() })
|
|
3352
|
+
});
|
|
3353
|
+
|
|
3354
|
+
if (!response.ok) {
|
|
3355
|
+
throw new Error('Search failed');
|
|
3356
|
+
}
|
|
3357
|
+
|
|
3358
|
+
const data = await response.json();
|
|
3359
|
+
this.chatSearchMatches = data.matches || [];
|
|
3360
|
+
this.chatSearchCurrentIndex = this.chatSearchMatches.length > 0 ? 0 : -1;
|
|
3361
|
+
|
|
3362
|
+
console.log('🔍 Search results:', {
|
|
3363
|
+
query: query,
|
|
3364
|
+
totalMatches: this.chatSearchMatches.length,
|
|
3365
|
+
matches: this.chatSearchMatches
|
|
3366
|
+
});
|
|
3367
|
+
|
|
3368
|
+
this.updateSearchCounter();
|
|
3369
|
+
this.highlightSearchResults(query);
|
|
3370
|
+
|
|
3371
|
+
// Navigate to first match
|
|
3372
|
+
if (this.chatSearchMatches.length > 0) {
|
|
3373
|
+
await this.scrollToSearchMatch(0);
|
|
3374
|
+
}
|
|
3375
|
+
} catch (error) {
|
|
3376
|
+
console.error('Error searching in conversation:', error);
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3379
|
+
|
|
3380
|
+
async navigateSearchResults(direction) {
|
|
3381
|
+
if (this.chatSearchMatches.length === 0) return;
|
|
3382
|
+
|
|
3383
|
+
if (direction === 'next') {
|
|
3384
|
+
this.chatSearchCurrentIndex = (this.chatSearchCurrentIndex + 1) % this.chatSearchMatches.length;
|
|
3385
|
+
} else {
|
|
3386
|
+
this.chatSearchCurrentIndex = (this.chatSearchCurrentIndex - 1 + this.chatSearchMatches.length) % this.chatSearchMatches.length;
|
|
3387
|
+
}
|
|
3388
|
+
|
|
3389
|
+
this.updateSearchCounter();
|
|
3390
|
+
await this.scrollToSearchMatch(this.chatSearchCurrentIndex);
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
async scrollToSearchMatch(index) {
|
|
3394
|
+
if (index < 0 || index >= this.chatSearchMatches.length) return;
|
|
3395
|
+
|
|
3396
|
+
const match = this.chatSearchMatches[index];
|
|
3397
|
+
const messageId = match.messageId;
|
|
3398
|
+
const messageIndex = match.messageIndex;
|
|
3399
|
+
|
|
3400
|
+
// Try to find the message by ID first (more reliable)
|
|
3401
|
+
let messageElement = document.querySelector(`[data-message-id="${messageId}"]`);
|
|
3402
|
+
|
|
3403
|
+
// Fallback to index if ID doesn't work
|
|
3404
|
+
if (!messageElement) {
|
|
3405
|
+
messageElement = document.querySelector(`[data-message-index="${messageIndex}"]`);
|
|
3406
|
+
}
|
|
3407
|
+
|
|
3408
|
+
if (messageElement) {
|
|
3409
|
+
// Message is already in DOM, just scroll to it
|
|
3410
|
+
this.scrollToMessage(messageElement);
|
|
3411
|
+
this.highlightCurrentMatchById(messageId);
|
|
3412
|
+
} else {
|
|
3413
|
+
// Message not loaded yet - need to load more messages
|
|
3414
|
+
// This handles the infinite scroll case
|
|
3415
|
+
await this.loadMessageById(messageId, messageIndex);
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
|
|
3419
|
+
async loadMessageById(messageId, messageIndex) {
|
|
3420
|
+
// Keep loading more messages until we find the target message by ID
|
|
3421
|
+
let attempts = 0;
|
|
3422
|
+
const maxAttempts = 10; // Prevent infinite loops
|
|
3423
|
+
|
|
3424
|
+
while (attempts < maxAttempts) {
|
|
3425
|
+
// Try to find by ID first
|
|
3426
|
+
let messageElement = document.querySelector(`[data-message-id="${messageId}"]`);
|
|
3427
|
+
|
|
3428
|
+
if (messageElement) {
|
|
3429
|
+
// Found the message!
|
|
3430
|
+
this.scrollToMessage(messageElement);
|
|
3431
|
+
this.highlightCurrentMatchById(messageId);
|
|
3432
|
+
return;
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3435
|
+
// Try to load more messages
|
|
3436
|
+
if (this.messagesPagination.hasMore && !this.messagesPagination.isLoading) {
|
|
3437
|
+
console.log(`🔄 Loading more messages to find message ${messageId}...`);
|
|
3438
|
+
await this.loadMoreMessages(this.selectedConversationId, false);
|
|
3439
|
+
attempts++;
|
|
3440
|
+
|
|
3441
|
+
// Wait a bit for messages to render
|
|
3442
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
3443
|
+
} else {
|
|
3444
|
+
// No more messages to load or already loading
|
|
3445
|
+
console.warn('Could not find message with ID', messageId, 'after', attempts, 'attempts');
|
|
3446
|
+
break;
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
|
|
3451
|
+
scrollToMessage(messageElement) {
|
|
3452
|
+
if (!messageElement) {
|
|
3453
|
+
console.warn('No message element to scroll to');
|
|
3454
|
+
return;
|
|
3455
|
+
}
|
|
3456
|
+
|
|
3457
|
+
const messagesContainer = document.getElementById('chatMessages');
|
|
3458
|
+
if (!messagesContainer) return;
|
|
3459
|
+
|
|
3460
|
+
// Get the absolute position of the message within the scrollable container
|
|
3461
|
+
const containerTop = messagesContainer.getBoundingClientRect().top;
|
|
3462
|
+
const messageTop = messageElement.getBoundingClientRect().top;
|
|
3463
|
+
const containerHeight = messagesContainer.clientHeight;
|
|
3464
|
+
const messageHeight = messageElement.offsetHeight;
|
|
3465
|
+
|
|
3466
|
+
// Calculate the current scroll position
|
|
3467
|
+
const currentScroll = messagesContainer.scrollTop;
|
|
3468
|
+
|
|
3469
|
+
// Calculate the offset from the top of the container
|
|
3470
|
+
const messageOffsetFromTop = messageTop - containerTop;
|
|
3471
|
+
|
|
3472
|
+
// Calculate target scroll position to center the message
|
|
3473
|
+
// We want the message to be in the middle of the visible area
|
|
3474
|
+
const targetScroll = currentScroll + messageOffsetFromTop - (containerHeight / 2) + (messageHeight / 2);
|
|
3475
|
+
|
|
3476
|
+
// Scroll to the target position
|
|
3477
|
+
messagesContainer.scrollTo({
|
|
3478
|
+
top: Math.max(0, targetScroll), // Don't scroll to negative values
|
|
3479
|
+
behavior: 'smooth'
|
|
3480
|
+
});
|
|
3481
|
+
|
|
3482
|
+
// Add a brief highlight animation to make it more visible
|
|
3483
|
+
messageElement.style.transition = 'background-color 0.3s ease';
|
|
3484
|
+
const originalBg = messageElement.style.backgroundColor;
|
|
3485
|
+
messageElement.style.backgroundColor = 'rgba(255, 107, 53, 0.1)';
|
|
3486
|
+
|
|
3487
|
+
setTimeout(() => {
|
|
3488
|
+
messageElement.style.backgroundColor = originalBg;
|
|
3489
|
+
setTimeout(() => {
|
|
3490
|
+
messageElement.style.transition = '';
|
|
3491
|
+
}, 300);
|
|
3492
|
+
}, 600);
|
|
3493
|
+
}
|
|
3494
|
+
|
|
3495
|
+
highlightSearchResults(query) {
|
|
3496
|
+
this.clearSearchHighlights();
|
|
3497
|
+
const searchTerm = query.toLowerCase();
|
|
3498
|
+
const messageElements = document.querySelectorAll('.message-content');
|
|
3499
|
+
|
|
3500
|
+
messageElements.forEach(element => {
|
|
3501
|
+
const text = element.textContent;
|
|
3502
|
+
if (text.toLowerCase().includes(searchTerm)) {
|
|
3503
|
+
const highlightedHTML = this.highlightText(element.innerHTML, query);
|
|
3504
|
+
element.innerHTML = highlightedHTML;
|
|
3505
|
+
}
|
|
3506
|
+
});
|
|
3507
|
+
}
|
|
3508
|
+
|
|
3509
|
+
highlightText(html, searchTerm) {
|
|
3510
|
+
const text = document.createElement('div');
|
|
3511
|
+
text.innerHTML = html;
|
|
3512
|
+
const textContent = text.textContent;
|
|
3513
|
+
|
|
3514
|
+
if (!textContent.toLowerCase().includes(searchTerm.toLowerCase())) {
|
|
3515
|
+
return html;
|
|
3516
|
+
}
|
|
3517
|
+
|
|
3518
|
+
// Use regex to find all occurrences (case-insensitive)
|
|
3519
|
+
const regex = new RegExp(`(${this.escapeRegex(searchTerm)})`, 'gi');
|
|
3520
|
+
const newHTML = textContent.replace(regex, '<span class="message-highlight">$1</span>');
|
|
3521
|
+
|
|
3522
|
+
return newHTML;
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3525
|
+
highlightCurrentMatch(messageIndex) {
|
|
3526
|
+
// Remove previous current highlight
|
|
3527
|
+
document.querySelectorAll('.message-current-highlight').forEach(el => {
|
|
3528
|
+
el.classList.remove('message-current-highlight');
|
|
3529
|
+
el.classList.add('message-highlight');
|
|
3530
|
+
});
|
|
3531
|
+
|
|
3532
|
+
// Add current highlight to the current match
|
|
3533
|
+
const messageElement = document.querySelector(`[data-message-index="${messageIndex}"]`);
|
|
3534
|
+
if (messageElement) {
|
|
3535
|
+
const firstHighlight = messageElement.querySelector('.message-highlight');
|
|
3536
|
+
if (firstHighlight) {
|
|
3537
|
+
firstHighlight.classList.remove('message-highlight');
|
|
3538
|
+
firstHighlight.classList.add('message-current-highlight');
|
|
3539
|
+
|
|
3540
|
+
// Scroll the highlight into view within the message
|
|
3541
|
+
// This ensures the actual highlighted text is visible
|
|
3542
|
+
setTimeout(() => {
|
|
3543
|
+
firstHighlight.scrollIntoView({
|
|
3544
|
+
behavior: 'smooth',
|
|
3545
|
+
block: 'center',
|
|
3546
|
+
inline: 'nearest'
|
|
3547
|
+
});
|
|
3548
|
+
}, 100);
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
}
|
|
3552
|
+
|
|
3553
|
+
highlightCurrentMatchById(messageId) {
|
|
3554
|
+
// Remove previous current highlight
|
|
3555
|
+
document.querySelectorAll('.message-current-highlight').forEach(el => {
|
|
3556
|
+
el.classList.remove('message-current-highlight');
|
|
3557
|
+
el.classList.add('message-highlight');
|
|
3558
|
+
});
|
|
3559
|
+
|
|
3560
|
+
// Add current highlight to the current match (find by message ID)
|
|
3561
|
+
const messageElement = document.querySelector(`[data-message-id="${messageId}"]`);
|
|
3562
|
+
if (messageElement) {
|
|
3563
|
+
const firstHighlight = messageElement.querySelector('.message-highlight');
|
|
3564
|
+
if (firstHighlight) {
|
|
3565
|
+
firstHighlight.classList.remove('message-highlight');
|
|
3566
|
+
firstHighlight.classList.add('message-current-highlight');
|
|
3567
|
+
|
|
3568
|
+
// Scroll the highlight into view within the message
|
|
3569
|
+
// This ensures the actual highlighted text is visible
|
|
3570
|
+
setTimeout(() => {
|
|
3571
|
+
firstHighlight.scrollIntoView({
|
|
3572
|
+
behavior: 'smooth',
|
|
3573
|
+
block: 'center',
|
|
3574
|
+
inline: 'nearest'
|
|
3575
|
+
});
|
|
3576
|
+
}, 100);
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
|
|
3581
|
+
clearSearchHighlights() {
|
|
3582
|
+
document.querySelectorAll('.message-highlight, .message-current-highlight').forEach(el => {
|
|
3583
|
+
const parent = el.parentNode;
|
|
3584
|
+
parent.replaceChild(document.createTextNode(el.textContent), el);
|
|
3585
|
+
parent.normalize(); // Merge adjacent text nodes
|
|
3586
|
+
});
|
|
3587
|
+
}
|
|
3588
|
+
|
|
3589
|
+
updateSearchCounter(currentIndex = null, totalMatches = null, showMinCharsMessage = false) {
|
|
3590
|
+
const counter = document.getElementById('chatSearchCounter');
|
|
3591
|
+
const prevBtn = document.getElementById('chatSearchPrev');
|
|
3592
|
+
const nextBtn = document.getElementById('chatSearchNext');
|
|
3593
|
+
|
|
3594
|
+
// Use provided values or fall back to instance values
|
|
3595
|
+
const current = currentIndex !== null ? currentIndex : this.chatSearchCurrentIndex;
|
|
3596
|
+
const total = totalMatches !== null ? totalMatches : this.chatSearchMatches.length;
|
|
3597
|
+
|
|
3598
|
+
console.log('📊 Updating counter:', {
|
|
3599
|
+
currentIndex: current,
|
|
3600
|
+
totalMatches: total,
|
|
3601
|
+
showMinCharsMessage: showMinCharsMessage
|
|
3602
|
+
});
|
|
3603
|
+
|
|
3604
|
+
if (showMinCharsMessage) {
|
|
3605
|
+
counter.textContent = 'Min 3 chars';
|
|
3606
|
+
counter.classList.remove('has-results');
|
|
3607
|
+
prevBtn.disabled = true;
|
|
3608
|
+
nextBtn.disabled = true;
|
|
3609
|
+
} else if (total === 0) {
|
|
3610
|
+
counter.textContent = '0/0';
|
|
3611
|
+
counter.classList.remove('has-results');
|
|
3612
|
+
prevBtn.disabled = true;
|
|
3613
|
+
nextBtn.disabled = true;
|
|
3614
|
+
} else {
|
|
3615
|
+
counter.textContent = `${current + 1}/${total}`;
|
|
3616
|
+
counter.classList.add('has-results');
|
|
3617
|
+
prevBtn.disabled = false;
|
|
3618
|
+
nextBtn.disabled = false;
|
|
3619
|
+
}
|
|
3620
|
+
}
|
|
3621
|
+
|
|
3622
|
+
async getTotalMessageCount(conversationId) {
|
|
3623
|
+
const conversation = this.conversations.find(c => c.id === conversationId);
|
|
3624
|
+
return conversation ? conversation.messageCount : 0;
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
escapeRegex(string) {
|
|
3628
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3631
|
+
resetAdvancedSearch() {
|
|
3632
|
+
// Clear all filter inputs
|
|
3633
|
+
document.getElementById('filterQuery').value = '';
|
|
3634
|
+
document.getElementById('filterWorkingDirectory').value = '';
|
|
3635
|
+
document.getElementById('filterDateFrom').value = '';
|
|
3636
|
+
document.getElementById('filterDateTo').value = '';
|
|
3637
|
+
document.getElementById('filterContentSearch').value = '';
|
|
3638
|
+
}
|
|
3639
|
+
|
|
3640
|
+
async clearAllFilters() {
|
|
3641
|
+
const searchResultsInfo = document.getElementById('searchResultsInfo');
|
|
3642
|
+
const searchInput = document.getElementById('searchInput');
|
|
3643
|
+
|
|
3644
|
+
// Clear simple search
|
|
3645
|
+
searchInput.value = '';
|
|
3646
|
+
|
|
3647
|
+
// Clear advanced search filters
|
|
3648
|
+
this.resetAdvancedSearch();
|
|
3649
|
+
|
|
3650
|
+
// Hide search results info
|
|
3651
|
+
searchResultsInfo.classList.remove('active');
|
|
3652
|
+
|
|
3653
|
+
// Reload all conversations
|
|
3654
|
+
await this.loadConversations();
|
|
3655
|
+
}
|
|
3656
|
+
|
|
2212
3657
|
getStateLabel(state) {
|
|
2213
3658
|
// Handle all possible states from StateCalculator with icons
|
|
2214
3659
|
const stateLabels = {
|