dsh-better-workspace 0.12.1 → 0.14.0
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/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/client.js +452 -45
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-better-workspace",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "侧边栏工作区两层层级树:工作区按磁盘目录嵌套(官方 workspace-tree 语义),名称中的 / 即虚拟分组(web/前端 · web/后端);添加工作区由官方目录流承载。Two-layer hierarchy tree for the DSH sidebar workspace list.",
|
|
6
6
|
"engines": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-better-workspace",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "侧边栏工作区两层层级树:磁盘目录嵌套(官方 workspace-tree 语义)+ 名称 / 虚拟分组,添加工作区走官方目录流。Two-layer workspace tree for the DSH sidebar: disk-path nesting plus \"/\"-name groups; add-workspace rides the official directory flow.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/src/client.js
CHANGED
|
@@ -40,6 +40,16 @@ window.__ModuleLoader__.load({
|
|
|
40
40
|
'empty': '暂无工作区',
|
|
41
41
|
'empty.search': '没有匹配的结果',
|
|
42
42
|
'session.new': '新会话',
|
|
43
|
+
'viewOptions.label': '视图选项',
|
|
44
|
+
'viewOptions.groupBy': '分组方式',
|
|
45
|
+
'viewOptions.byWorkspace': '按工作区',
|
|
46
|
+
'viewOptions.byWorkspaceTree': '按工作区树',
|
|
47
|
+
'viewOptions.flat': '单列表',
|
|
48
|
+
'viewOptions.orderBy': '排序方式',
|
|
49
|
+
'viewOptions.manualOrder': '手动排序',
|
|
50
|
+
'viewOptions.updatedOrder': '最近更新',
|
|
51
|
+
'viewOptions.sessionSlash': '会话按"/"分组',
|
|
52
|
+
'viewOptions.workspaceSlash': '工作区按"/"分组',
|
|
43
53
|
'group.ungrouped': '未分组',
|
|
44
54
|
'sessions.expand': '展开 {n} 个会话',
|
|
45
55
|
'sessions.collapse': '收起',
|
|
@@ -150,6 +160,16 @@ window.__ModuleLoader__.load({
|
|
|
150
160
|
'empty': 'No workspaces yet',
|
|
151
161
|
'empty.search': 'No matches',
|
|
152
162
|
'session.new': 'New session',
|
|
163
|
+
'viewOptions.label': 'View options',
|
|
164
|
+
'viewOptions.groupBy': 'Group by',
|
|
165
|
+
'viewOptions.byWorkspace': 'Workspaces',
|
|
166
|
+
'viewOptions.byWorkspaceTree': 'Workspace tree',
|
|
167
|
+
'viewOptions.flat': 'In one list',
|
|
168
|
+
'viewOptions.orderBy': 'Order by',
|
|
169
|
+
'viewOptions.manualOrder': 'Manual',
|
|
170
|
+
'viewOptions.updatedOrder': 'Last updated',
|
|
171
|
+
'viewOptions.sessionSlash': 'Group sessions by "/"',
|
|
172
|
+
'viewOptions.workspaceSlash': 'Group workspaces by "/"',
|
|
153
173
|
'group.ungrouped': 'Ungrouped',
|
|
154
174
|
'sessions.expand': 'Show {n} more sessions',
|
|
155
175
|
'sessions.collapse': 'Collapse',
|
|
@@ -268,6 +288,16 @@ window.__ModuleLoader__.load({
|
|
|
268
288
|
'empty': 'لا توجد مساحات عمل بعد',
|
|
269
289
|
'empty.search': 'لا توجد نتائج مطابقة',
|
|
270
290
|
'session.new': 'جلسة جديدة',
|
|
291
|
+
'viewOptions.label': 'خيارات العرض',
|
|
292
|
+
'viewOptions.groupBy': 'التجميع حسب',
|
|
293
|
+
'viewOptions.byWorkspace': 'مساحات العمل',
|
|
294
|
+
'viewOptions.byWorkspaceTree': 'شجرة مساحات العمل',
|
|
295
|
+
'viewOptions.flat': 'قائمة واحدة',
|
|
296
|
+
'viewOptions.orderBy': 'الترتيب حسب',
|
|
297
|
+
'viewOptions.manualOrder': 'يدوي',
|
|
298
|
+
'viewOptions.updatedOrder': 'آخر تحديث',
|
|
299
|
+
'viewOptions.sessionSlash': 'تجميع الجلسات حسب "/"',
|
|
300
|
+
'viewOptions.workspaceSlash': 'تجميع مساحات العمل حسب "/"',
|
|
271
301
|
'group.ungrouped': 'بلا مجموعة',
|
|
272
302
|
'sessions.expand': 'عرض {n} جلسات إضافية',
|
|
273
303
|
'sessions.collapse': 'طيّ',
|
|
@@ -378,6 +408,16 @@ window.__ModuleLoader__.load({
|
|
|
378
408
|
'empty': 'Noch keine Arbeitsbereiche',
|
|
379
409
|
'empty.search': 'Keine Treffer',
|
|
380
410
|
'session.new': 'Neue Sitzung',
|
|
411
|
+
'viewOptions.label': 'Ansichtsoptionen',
|
|
412
|
+
'viewOptions.groupBy': 'Gruppieren',
|
|
413
|
+
'viewOptions.byWorkspace': 'Arbeitsbereiche',
|
|
414
|
+
'viewOptions.byWorkspaceTree': 'Arbeitsbereichsbaum',
|
|
415
|
+
'viewOptions.flat': 'In einer Liste',
|
|
416
|
+
'viewOptions.orderBy': 'Sortieren',
|
|
417
|
+
'viewOptions.manualOrder': 'Manuell',
|
|
418
|
+
'viewOptions.updatedOrder': 'Zuletzt aktualisiert',
|
|
419
|
+
'viewOptions.sessionSlash': 'Sitzungen nach "/" gruppieren',
|
|
420
|
+
'viewOptions.workspaceSlash': 'Arbeitsbereiche nach "/" gruppieren',
|
|
381
421
|
'group.ungrouped': 'Ohne Gruppe',
|
|
382
422
|
'sessions.expand': '{n} Sitzungen einblenden',
|
|
383
423
|
'sessions.collapse': 'Einklappen',
|
|
@@ -488,6 +528,16 @@ window.__ModuleLoader__.load({
|
|
|
488
528
|
'empty': 'Aucun espace de travail',
|
|
489
529
|
'empty.search': 'Aucun résultat',
|
|
490
530
|
'session.new': 'Nouvelle session',
|
|
531
|
+
'viewOptions.label': 'Options d’affichage',
|
|
532
|
+
'viewOptions.groupBy': 'Regrouper par',
|
|
533
|
+
'viewOptions.byWorkspace': 'Espaces de travail',
|
|
534
|
+
'viewOptions.byWorkspaceTree': 'Arborescence des espaces',
|
|
535
|
+
'viewOptions.flat': 'En une liste',
|
|
536
|
+
'viewOptions.orderBy': 'Trier par',
|
|
537
|
+
'viewOptions.manualOrder': 'Manuel',
|
|
538
|
+
'viewOptions.updatedOrder': 'Dernière mise à jour',
|
|
539
|
+
'viewOptions.sessionSlash': 'Grouper les sessions par « / »',
|
|
540
|
+
'viewOptions.workspaceSlash': 'Grouper les espaces par « / »',
|
|
491
541
|
'group.ungrouped': 'Sans groupe',
|
|
492
542
|
'sessions.expand': 'Afficher {n} sessions',
|
|
493
543
|
'sessions.collapse': 'Réduire',
|
|
@@ -598,6 +648,16 @@ window.__ModuleLoader__.load({
|
|
|
598
648
|
'empty': 'अभी कोई कार्यस्थान नहीं',
|
|
599
649
|
'empty.search': 'कोई मेल खाता परिणाम नहीं',
|
|
600
650
|
'session.new': 'नया सत्र',
|
|
651
|
+
'viewOptions.label': 'दृश्य विकल्प',
|
|
652
|
+
'viewOptions.groupBy': 'समूहीकरण',
|
|
653
|
+
'viewOptions.byWorkspace': 'कार्यक्षेत्र अनुसार',
|
|
654
|
+
'viewOptions.byWorkspaceTree': 'कार्यक्षेत्र ट्री अनुसार',
|
|
655
|
+
'viewOptions.flat': 'एक सूची में',
|
|
656
|
+
'viewOptions.orderBy': 'क्रम',
|
|
657
|
+
'viewOptions.manualOrder': 'मैन्युअल',
|
|
658
|
+
'viewOptions.updatedOrder': 'हाल का अपडेट',
|
|
659
|
+
'viewOptions.sessionSlash': 'सत्रों को "/" से समूहित करें',
|
|
660
|
+
'viewOptions.workspaceSlash': 'कार्यक्षेत्रों को "/" से समूहित करें',
|
|
601
661
|
'group.ungrouped': 'बिना समूह',
|
|
602
662
|
'sessions.expand': '{n} सत्र दिखाएँ',
|
|
603
663
|
'sessions.collapse': 'समेटें',
|
|
@@ -708,6 +768,16 @@ window.__ModuleLoader__.load({
|
|
|
708
768
|
'empty': 'Belum ada ruang kerja',
|
|
709
769
|
'empty.search': 'Tidak ada hasil yang cocok',
|
|
710
770
|
'session.new': 'Sesi baru',
|
|
771
|
+
'viewOptions.label': 'Opsi tampilan',
|
|
772
|
+
'viewOptions.groupBy': 'Kelompokkan berdasarkan',
|
|
773
|
+
'viewOptions.byWorkspace': 'Ruang kerja',
|
|
774
|
+
'viewOptions.byWorkspaceTree': 'Pohon ruang kerja',
|
|
775
|
+
'viewOptions.flat': 'Satu daftar',
|
|
776
|
+
'viewOptions.orderBy': 'Urutkan',
|
|
777
|
+
'viewOptions.manualOrder': 'Manual',
|
|
778
|
+
'viewOptions.updatedOrder': 'Terakhir diperbarui',
|
|
779
|
+
'viewOptions.sessionSlash': 'Kelompokkan sesi per "/"',
|
|
780
|
+
'viewOptions.workspaceSlash': 'Kelompokkan ruang kerja per "/"',
|
|
711
781
|
'group.ungrouped': 'Tanpa grup',
|
|
712
782
|
'sessions.expand': 'Tampilkan {n} sesi',
|
|
713
783
|
'sessions.collapse': 'Ciutkan',
|
|
@@ -818,6 +888,16 @@ window.__ModuleLoader__.load({
|
|
|
818
888
|
'empty': 'Nessuna area di lavoro',
|
|
819
889
|
'empty.search': 'Nessun risultato',
|
|
820
890
|
'session.new': 'Nuova sessione',
|
|
891
|
+
'viewOptions.label': 'Opzioni vista',
|
|
892
|
+
'viewOptions.groupBy': 'Raggruppa per',
|
|
893
|
+
'viewOptions.byWorkspace': 'Aree di lavoro',
|
|
894
|
+
'viewOptions.byWorkspaceTree': 'Albero aree di lavoro',
|
|
895
|
+
'viewOptions.flat': 'In un elenco',
|
|
896
|
+
'viewOptions.orderBy': 'Ordina per',
|
|
897
|
+
'viewOptions.manualOrder': 'Manuale',
|
|
898
|
+
'viewOptions.updatedOrder': 'Ultimo aggiornamento',
|
|
899
|
+
'viewOptions.sessionSlash': 'Raggruppa sessioni per "/"',
|
|
900
|
+
'viewOptions.workspaceSlash': 'Raggruppa aree per "/"',
|
|
821
901
|
'group.ungrouped': 'Senza gruppo',
|
|
822
902
|
'sessions.expand': 'Mostra {n} sessioni',
|
|
823
903
|
'sessions.collapse': 'Comprimi',
|
|
@@ -928,6 +1008,16 @@ window.__ModuleLoader__.load({
|
|
|
928
1008
|
'empty': 'ワークスペースがありません',
|
|
929
1009
|
'empty.search': '一致する結果がありません',
|
|
930
1010
|
'session.new': '新しいセッション',
|
|
1011
|
+
'viewOptions.label': '表示オプション',
|
|
1012
|
+
'viewOptions.groupBy': 'グループ化',
|
|
1013
|
+
'viewOptions.byWorkspace': 'ワークスペースごと',
|
|
1014
|
+
'viewOptions.byWorkspaceTree': 'ワークスペースツリーごと',
|
|
1015
|
+
'viewOptions.flat': '1 つのリスト',
|
|
1016
|
+
'viewOptions.orderBy': '並べ替え',
|
|
1017
|
+
'viewOptions.manualOrder': '手動',
|
|
1018
|
+
'viewOptions.updatedOrder': '最近の更新',
|
|
1019
|
+
'viewOptions.sessionSlash': 'セッションを「/」でグループ化',
|
|
1020
|
+
'viewOptions.workspaceSlash': 'ワークスペースを「/」でグループ化',
|
|
931
1021
|
'group.ungrouped': '未分類',
|
|
932
1022
|
'sessions.expand': '{n} 件のセッションを展開',
|
|
933
1023
|
'sessions.collapse': '折りたたむ',
|
|
@@ -1038,6 +1128,16 @@ window.__ModuleLoader__.load({
|
|
|
1038
1128
|
'empty': '워크스페이스가 없습니다',
|
|
1039
1129
|
'empty.search': '일치하는 결과가 없습니다',
|
|
1040
1130
|
'session.new': '새 세션',
|
|
1131
|
+
'viewOptions.label': '보기 옵션',
|
|
1132
|
+
'viewOptions.groupBy': '그룹화',
|
|
1133
|
+
'viewOptions.byWorkspace': '작업 공간별',
|
|
1134
|
+
'viewOptions.byWorkspaceTree': '작업 공간 트리별',
|
|
1135
|
+
'viewOptions.flat': '하나의 목록',
|
|
1136
|
+
'viewOptions.orderBy': '정렬',
|
|
1137
|
+
'viewOptions.manualOrder': '수동',
|
|
1138
|
+
'viewOptions.updatedOrder': '최근 업데이트',
|
|
1139
|
+
'viewOptions.sessionSlash': '세션을 "/"로 그룹화',
|
|
1140
|
+
'viewOptions.workspaceSlash': '작업 공간을 "/"로 그룹화',
|
|
1041
1141
|
'group.ungrouped': '미분류',
|
|
1042
1142
|
'sessions.expand': '세션 {n}개 펼치기',
|
|
1043
1143
|
'sessions.collapse': '접기',
|
|
@@ -1148,6 +1248,16 @@ window.__ModuleLoader__.load({
|
|
|
1148
1248
|
'empty': 'Nog geen werkruimten',
|
|
1149
1249
|
'empty.search': 'Geen resultaten',
|
|
1150
1250
|
'session.new': 'Nieuwe sessie',
|
|
1251
|
+
'viewOptions.label': 'Weergaveopties',
|
|
1252
|
+
'viewOptions.groupBy': 'Groeperen op',
|
|
1253
|
+
'viewOptions.byWorkspace': 'Werkruimtes',
|
|
1254
|
+
'viewOptions.byWorkspaceTree': 'Werkruimteboom',
|
|
1255
|
+
'viewOptions.flat': 'In één lijst',
|
|
1256
|
+
'viewOptions.orderBy': 'Sorteren op',
|
|
1257
|
+
'viewOptions.manualOrder': 'Handmatig',
|
|
1258
|
+
'viewOptions.updatedOrder': 'Laatst bijgewerkt',
|
|
1259
|
+
'viewOptions.sessionSlash': 'Sessies groeperen op "/"',
|
|
1260
|
+
'viewOptions.workspaceSlash': 'Werkruimtes groeperen op "/"',
|
|
1151
1261
|
'group.ungrouped': 'Zonder groep',
|
|
1152
1262
|
'sessions.expand': '{n} sessies uitklappen',
|
|
1153
1263
|
'sessions.collapse': 'Inklappen',
|
|
@@ -1258,6 +1368,16 @@ window.__ModuleLoader__.load({
|
|
|
1258
1368
|
'empty': 'Brak obszarów roboczych',
|
|
1259
1369
|
'empty.search': 'Brak wyników',
|
|
1260
1370
|
'session.new': 'Nowa sesja',
|
|
1371
|
+
'viewOptions.label': 'Opcje widoku',
|
|
1372
|
+
'viewOptions.groupBy': 'Grupuj według',
|
|
1373
|
+
'viewOptions.byWorkspace': 'Obszary robocze',
|
|
1374
|
+
'viewOptions.byWorkspaceTree': 'Drzewo obszarów',
|
|
1375
|
+
'viewOptions.flat': 'Jedna lista',
|
|
1376
|
+
'viewOptions.orderBy': 'Sortuj według',
|
|
1377
|
+
'viewOptions.manualOrder': 'Ręcznie',
|
|
1378
|
+
'viewOptions.updatedOrder': 'Ostatnia aktualizacja',
|
|
1379
|
+
'viewOptions.sessionSlash': 'Grupuj sesje po "/"',
|
|
1380
|
+
'viewOptions.workspaceSlash': 'Grupuj obszary po "/"',
|
|
1261
1381
|
'group.ungrouped': 'Bez grupy',
|
|
1262
1382
|
'sessions.expand': 'Pokaż {n} sesji',
|
|
1263
1383
|
'sessions.collapse': 'Zwiń',
|
|
@@ -1368,6 +1488,16 @@ window.__ModuleLoader__.load({
|
|
|
1368
1488
|
'empty': 'Nenhum espaço de trabalho',
|
|
1369
1489
|
'empty.search': 'Nenhum resultado',
|
|
1370
1490
|
'session.new': 'Nova sessão',
|
|
1491
|
+
'viewOptions.label': 'Opções de vista',
|
|
1492
|
+
'viewOptions.groupBy': 'Agrupar por',
|
|
1493
|
+
'viewOptions.byWorkspace': 'Áreas de trabalho',
|
|
1494
|
+
'viewOptions.byWorkspaceTree': 'Árvore de áreas',
|
|
1495
|
+
'viewOptions.flat': 'Numa lista',
|
|
1496
|
+
'viewOptions.orderBy': 'Ordenar por',
|
|
1497
|
+
'viewOptions.manualOrder': 'Manual',
|
|
1498
|
+
'viewOptions.updatedOrder': 'Atualização recente',
|
|
1499
|
+
'viewOptions.sessionSlash': 'Agrupar sessões por "/"',
|
|
1500
|
+
'viewOptions.workspaceSlash': 'Agrupar áreas por "/"',
|
|
1371
1501
|
'group.ungrouped': 'Sem grupo',
|
|
1372
1502
|
'sessions.expand': 'Mostrar {n} sessões',
|
|
1373
1503
|
'sessions.collapse': 'Recolher',
|
|
@@ -1478,6 +1608,16 @@ window.__ModuleLoader__.load({
|
|
|
1478
1608
|
'empty': 'Рабочих областей пока нет',
|
|
1479
1609
|
'empty.search': 'Ничего не найдено',
|
|
1480
1610
|
'session.new': 'Новая сессия',
|
|
1611
|
+
'viewOptions.label': 'Параметры вида',
|
|
1612
|
+
'viewOptions.groupBy': 'Группировка',
|
|
1613
|
+
'viewOptions.byWorkspace': 'По рабочим областям',
|
|
1614
|
+
'viewOptions.byWorkspaceTree': 'По дереву областей',
|
|
1615
|
+
'viewOptions.flat': 'Одним списком',
|
|
1616
|
+
'viewOptions.orderBy': 'Сортировка',
|
|
1617
|
+
'viewOptions.manualOrder': 'Вручную',
|
|
1618
|
+
'viewOptions.updatedOrder': 'По обновлению',
|
|
1619
|
+
'viewOptions.sessionSlash': 'Группировать сессии по «/»',
|
|
1620
|
+
'viewOptions.workspaceSlash': 'Группировать области по «/»',
|
|
1481
1621
|
'group.ungrouped': 'Без группы',
|
|
1482
1622
|
'sessions.expand': 'Показать ещё {n} сессий',
|
|
1483
1623
|
'sessions.collapse': 'Свернуть',
|
|
@@ -1588,6 +1728,16 @@ window.__ModuleLoader__.load({
|
|
|
1588
1728
|
'empty': 'Inga arbetsytor ännu',
|
|
1589
1729
|
'empty.search': 'Inga träffar',
|
|
1590
1730
|
'session.new': 'Ny session',
|
|
1731
|
+
'viewOptions.label': 'Visningsalternativ',
|
|
1732
|
+
'viewOptions.groupBy': 'Gruppera efter',
|
|
1733
|
+
'viewOptions.byWorkspace': 'Arbetsytor',
|
|
1734
|
+
'viewOptions.byWorkspaceTree': 'Arbetsyta-träd',
|
|
1735
|
+
'viewOptions.flat': 'I en lista',
|
|
1736
|
+
'viewOptions.orderBy': 'Sortera efter',
|
|
1737
|
+
'viewOptions.manualOrder': 'Manuellt',
|
|
1738
|
+
'viewOptions.updatedOrder': 'Senast uppdaterad',
|
|
1739
|
+
'viewOptions.sessionSlash': 'Gruppera sessioner efter "/"',
|
|
1740
|
+
'viewOptions.workspaceSlash': 'Gruppera arbetsytor efter "/"',
|
|
1591
1741
|
'group.ungrouped': 'Utan grupp',
|
|
1592
1742
|
'sessions.expand': 'Visa {n} sessioner',
|
|
1593
1743
|
'sessions.collapse': 'Fäll ihop',
|
|
@@ -1698,6 +1848,16 @@ window.__ModuleLoader__.load({
|
|
|
1698
1848
|
'empty': 'ยังไม่มีพื้นที่ทำงาน',
|
|
1699
1849
|
'empty.search': 'ไม่พบผลลัพธ์ที่ตรงกัน',
|
|
1700
1850
|
'session.new': 'เซสชันใหม่',
|
|
1851
|
+
'viewOptions.label': 'ตัวเลือกมุมมอง',
|
|
1852
|
+
'viewOptions.groupBy': 'จัดกลุ่มตาม',
|
|
1853
|
+
'viewOptions.byWorkspace': 'ตามพื้นที่ทำงาน',
|
|
1854
|
+
'viewOptions.byWorkspaceTree': 'ตามแผนผังพื้นที่ทำงาน',
|
|
1855
|
+
'viewOptions.flat': 'รายการเดียว',
|
|
1856
|
+
'viewOptions.orderBy': 'เรียงตาม',
|
|
1857
|
+
'viewOptions.manualOrder': 'ด้วยตนเอง',
|
|
1858
|
+
'viewOptions.updatedOrder': 'อัปเดตล่าสุด',
|
|
1859
|
+
'viewOptions.sessionSlash': 'จัดกลุ่มเซสชันตาม "/"',
|
|
1860
|
+
'viewOptions.workspaceSlash': 'จัดกลุ่มพื้นที่ทำงานตาม "/"',
|
|
1701
1861
|
'group.ungrouped': 'ไม่มีกลุ่ม',
|
|
1702
1862
|
'sessions.expand': 'แสดงอีก {n} เซสชัน',
|
|
1703
1863
|
'sessions.collapse': 'ย่อ',
|
|
@@ -1808,6 +1968,16 @@ window.__ModuleLoader__.load({
|
|
|
1808
1968
|
'empty': 'Henüz çalışma alanı yok',
|
|
1809
1969
|
'empty.search': 'Eşleşen sonuç yok',
|
|
1810
1970
|
'session.new': 'Yeni oturum',
|
|
1971
|
+
'viewOptions.label': 'Görünüm seçenekleri',
|
|
1972
|
+
'viewOptions.groupBy': 'Gruplandır',
|
|
1973
|
+
'viewOptions.byWorkspace': 'Çalışma alanları',
|
|
1974
|
+
'viewOptions.byWorkspaceTree': 'Çalışma alanı ağacı',
|
|
1975
|
+
'viewOptions.flat': 'Tek liste',
|
|
1976
|
+
'viewOptions.orderBy': 'Sırala',
|
|
1977
|
+
'viewOptions.manualOrder': 'El ile',
|
|
1978
|
+
'viewOptions.updatedOrder': 'Son güncelleme',
|
|
1979
|
+
'viewOptions.sessionSlash': 'Oturumları "/" ile gruplandır',
|
|
1980
|
+
'viewOptions.workspaceSlash': 'Çalışma alanlarını "/" ile gruplandır',
|
|
1811
1981
|
'group.ungrouped': 'Grubusuz',
|
|
1812
1982
|
'sessions.expand': '{n} oturumu göster',
|
|
1813
1983
|
'sessions.collapse': 'Daralt',
|
|
@@ -1918,6 +2088,16 @@ window.__ModuleLoader__.load({
|
|
|
1918
2088
|
'empty': 'Chưa có không gian làm việc',
|
|
1919
2089
|
'empty.search': 'Không có kết quả phù hợp',
|
|
1920
2090
|
'session.new': 'Phiên mới',
|
|
2091
|
+
'viewOptions.label': 'Tùy chọn hiển thị',
|
|
2092
|
+
'viewOptions.groupBy': 'Nhóm theo',
|
|
2093
|
+
'viewOptions.byWorkspace': 'Theo khu vực làm việc',
|
|
2094
|
+
'viewOptions.byWorkspaceTree': 'Theo cây khu vực',
|
|
2095
|
+
'viewOptions.flat': 'Một danh sách',
|
|
2096
|
+
'viewOptions.orderBy': 'Sắp xếp theo',
|
|
2097
|
+
'viewOptions.manualOrder': 'Thủ công',
|
|
2098
|
+
'viewOptions.updatedOrder': 'Cập nhật gần đây',
|
|
2099
|
+
'viewOptions.sessionSlash': 'Nhóm phiên theo "/"',
|
|
2100
|
+
'viewOptions.workspaceSlash': 'Nhóm khu vực theo "/"',
|
|
1921
2101
|
'group.ungrouped': 'Chưa phân nhóm',
|
|
1922
2102
|
'sessions.expand': 'Hiện thêm {n} phiên',
|
|
1923
2103
|
'sessions.collapse': 'Thu gọn',
|
|
@@ -2028,6 +2208,16 @@ window.__ModuleLoader__.load({
|
|
|
2028
2208
|
'empty': '未有工作區',
|
|
2029
2209
|
'empty.search': '搵唔到符合嘅結果',
|
|
2030
2210
|
'session.new': '新對話',
|
|
2211
|
+
'viewOptions.label': '檢視選項',
|
|
2212
|
+
'viewOptions.groupBy': '分組方式',
|
|
2213
|
+
'viewOptions.byWorkspace': '按工作區',
|
|
2214
|
+
'viewOptions.byWorkspaceTree': '按工作區樹',
|
|
2215
|
+
'viewOptions.flat': '單一列表',
|
|
2216
|
+
'viewOptions.orderBy': '排序方式',
|
|
2217
|
+
'viewOptions.manualOrder': '手動排序',
|
|
2218
|
+
'viewOptions.updatedOrder': '最近更新',
|
|
2219
|
+
'viewOptions.sessionSlash': '對話按「/」分組',
|
|
2220
|
+
'viewOptions.workspaceSlash': '工作區按「/」分組',
|
|
2031
2221
|
'group.ungrouped': '未分組',
|
|
2032
2222
|
'sessions.expand': '展開 {n} 個對話',
|
|
2033
2223
|
'sessions.collapse': '收起',
|
|
@@ -2138,6 +2328,16 @@ window.__ModuleLoader__.load({
|
|
|
2138
2328
|
'empty': '未有工作區',
|
|
2139
2329
|
'empty.search': '搵唔到符合嘅結果',
|
|
2140
2330
|
'session.new': '新對話',
|
|
2331
|
+
'viewOptions.label': '檢視選項',
|
|
2332
|
+
'viewOptions.groupBy': '分組方式',
|
|
2333
|
+
'viewOptions.byWorkspace': '按工作區',
|
|
2334
|
+
'viewOptions.byWorkspaceTree': '按工作區樹',
|
|
2335
|
+
'viewOptions.flat': '單一列表',
|
|
2336
|
+
'viewOptions.orderBy': '排序方式',
|
|
2337
|
+
'viewOptions.manualOrder': '手動排序',
|
|
2338
|
+
'viewOptions.updatedOrder': '最近更新',
|
|
2339
|
+
'viewOptions.sessionSlash': '對話按「/」分組',
|
|
2340
|
+
'viewOptions.workspaceSlash': '工作區按「/」分組',
|
|
2141
2341
|
'group.ungrouped': '未分組',
|
|
2142
2342
|
'sessions.expand': '展開 {n} 個對話',
|
|
2143
2343
|
'sessions.collapse': '收起',
|
|
@@ -2248,6 +2448,16 @@ window.__ModuleLoader__.load({
|
|
|
2248
2448
|
'empty': '尚無工作區',
|
|
2249
2449
|
'empty.search': '沒有相符的結果',
|
|
2250
2450
|
'session.new': '新工作階段',
|
|
2451
|
+
'viewOptions.label': '檢視選項',
|
|
2452
|
+
'viewOptions.groupBy': '分組方式',
|
|
2453
|
+
'viewOptions.byWorkspace': '按工作區',
|
|
2454
|
+
'viewOptions.byWorkspaceTree': '按工作區樹',
|
|
2455
|
+
'viewOptions.flat': '單一列表',
|
|
2456
|
+
'viewOptions.orderBy': '排序方式',
|
|
2457
|
+
'viewOptions.manualOrder': '手動排序',
|
|
2458
|
+
'viewOptions.updatedOrder': '最近更新',
|
|
2459
|
+
'viewOptions.sessionSlash': '工作階段按「/」分組',
|
|
2460
|
+
'viewOptions.workspaceSlash': '工作區按「/」分組',
|
|
2251
2461
|
'group.ungrouped': '未分組',
|
|
2252
2462
|
'sessions.expand': '展開 {n} 個工作階段',
|
|
2253
2463
|
'sessions.collapse': '收合',
|
|
@@ -2495,6 +2705,21 @@ window.__ModuleLoader__.load({
|
|
|
2495
2705
|
&& !(archivedSet && archivedSet.has(summary.id))
|
|
2496
2706
|
&& (!summary.blank || summary.id === current)
|
|
2497
2707
|
|
|
2708
|
+
/**
|
|
2709
|
+
* dsh 0.1.6-alpha.2 dropped SessionListState.current: the "open" session
|
|
2710
|
+
* is now the one retained under the mainView source — navigation belongs
|
|
2711
|
+
* to the view owner (official ui-workspace tree.ts mainSessionId). The
|
|
2712
|
+
* old wire field is gone, so reading it yields a permanent undefined
|
|
2713
|
+
* (no current highlight, and blank rows would filter out everywhere).
|
|
2714
|
+
*/
|
|
2715
|
+
const mainSessionIdOf = (list) => {
|
|
2716
|
+
if (!list || !list.byId) return undefined
|
|
2717
|
+
for (const session of Object.values(list.byId)) {
|
|
2718
|
+
if (session && session.retainedBy && (session.retainedBy.mainView || 0) > 0) return session.id
|
|
2719
|
+
}
|
|
2720
|
+
return undefined
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2498
2723
|
/**
|
|
2499
2724
|
* Active-schedule marker, mirroring the official tree's
|
|
2500
2725
|
* hasActiveSchedule(): the list projection carries one entry per active
|
|
@@ -2548,9 +2773,15 @@ window.__ModuleLoader__.load({
|
|
|
2548
2773
|
* titles. Groups are virtual (projection of names). Rows keep the Host
|
|
2549
2774
|
* workspace.sessionIds (manual) order — drag-to-reorder must be visible.
|
|
2550
2775
|
*/
|
|
2551
|
-
function buildSessionTree(rows) {
|
|
2776
|
+
function buildSessionTree(rows, groupBySlash) {
|
|
2552
2777
|
const root = { path: '', name: '', groups: [], sessions: [] }
|
|
2553
2778
|
const byPath = new Map([['', root]])
|
|
2779
|
+
// Slash grouping OFF (v0.13 view option): every row lands at the
|
|
2780
|
+
// root level and keeps its FULL title as the leaf — no levels.
|
|
2781
|
+
if (groupBySlash === false) {
|
|
2782
|
+
for (const row of rows || []) root.sessions.push({ ...row, leaf: row.title })
|
|
2783
|
+
return root
|
|
2784
|
+
}
|
|
2554
2785
|
// SEGMENT-driven: paths arrive as already-split segment arrays (URL-aware
|
|
2555
2786
|
// splitTitleSegs can yield segments containing "//", e.g. the
|
|
2556
2787
|
// "scheme://host" authority segment) and are joined into the path KEY
|
|
@@ -2664,7 +2895,7 @@ window.__ModuleLoader__.load({
|
|
|
2664
2895
|
}
|
|
2665
2896
|
return map
|
|
2666
2897
|
}
|
|
2667
|
-
function buildTree(items) {
|
|
2898
|
+
function buildTree(items, groupBySlash) {
|
|
2668
2899
|
const list = items || []
|
|
2669
2900
|
const diskParentOf = diskParentMapOf(list)
|
|
2670
2901
|
const childrenOf = new Map()
|
|
@@ -2705,7 +2936,7 @@ window.__ModuleLoader__.load({
|
|
|
2705
2936
|
const folderPath = segs.slice(0, -1).join('/')
|
|
2706
2937
|
const leaf = segs.length > 0 ? segs[segs.length - 1] : (basename(workspace.path) || String(workspace.title || '') || String(workspace.workspaceId || ''))
|
|
2707
2938
|
const subList = childrenOf.get(workspace.workspaceId)
|
|
2708
|
-
|
|
2939
|
+
const entry = {
|
|
2709
2940
|
workspaceId: workspace.workspaceId,
|
|
2710
2941
|
title: String(workspace.title || ''),
|
|
2711
2942
|
path: String(workspace.path || ''),
|
|
@@ -2713,7 +2944,17 @@ window.__ModuleLoader__.load({
|
|
|
2713
2944
|
leaf,
|
|
2714
2945
|
folderPath,
|
|
2715
2946
|
sub: subList ? buildLevel(subList, (idPrefix !== '' ? idPrefix + '//' : '') + workspace.workspaceId) : null,
|
|
2716
|
-
}
|
|
2947
|
+
}
|
|
2948
|
+
// Slash grouping OFF (v0.13 view option): skip the name layer —
|
|
2949
|
+
// workspaces mount straight at their disk level; the DISK layer
|
|
2950
|
+
// is a filesystem fact and stays.
|
|
2951
|
+
if (groupBySlash === false) {
|
|
2952
|
+
entry.leaf = String(workspace.title || '') || leaf
|
|
2953
|
+
entry.folderPath = ''
|
|
2954
|
+
root.workspaces.push(entry)
|
|
2955
|
+
continue
|
|
2956
|
+
}
|
|
2957
|
+
ensure(segs.slice(0, -1)).workspaces.push(entry)
|
|
2717
2958
|
}
|
|
2718
2959
|
const sortRec = (node) => {
|
|
2719
2960
|
node.folders.sort((a, b) => a.name.localeCompare(b.name, 'zh'))
|
|
@@ -2951,7 +3192,7 @@ window.__ModuleLoader__.load({
|
|
|
2951
3192
|
/* ========================== view store =========================== */
|
|
2952
3193
|
|
|
2953
3194
|
const createViewStore = () => storeKit.defineStore({
|
|
2954
|
-
init: () => ({ expanded: {}, sessionsExpanded: {}, sessionGroups: {}, sessionOrder: {}, prefs: { compactChains: true }, styling: {} }),
|
|
3195
|
+
init: () => ({ expanded: {}, sessionsExpanded: {}, sessionGroups: {}, sessionOrder: {}, prefs: { compactChains: true }, styling: {}, groupBy: 'workspace-tree', orderBy: 'manual', sessionTitleSlash: true, workspaceTitleSlash: true }),
|
|
2955
3196
|
// NOTE: hydration REPLACES the state with the persisted whole value —
|
|
2956
3197
|
// init defaults never merge. Every action must tolerate a missing key
|
|
2957
3198
|
// (states persisted by older plugin versions lack sessionGroups), and
|
|
@@ -2994,6 +3235,14 @@ window.__ModuleLoader__.load({
|
|
|
2994
3235
|
if (!Array.isArray(order) || order.length === 0) delete d.sessionOrder[workspaceId]
|
|
2995
3236
|
else d.sessionOrder[workspaceId] = order.slice()
|
|
2996
3237
|
},
|
|
3238
|
+
// View options (v0.13): mirror the official browser's group/order
|
|
3239
|
+
// menu plus the two slash-grouping toggles. groupBy mirrors the
|
|
3240
|
+
// official literal set; the bw defaults keep the founding behaviour
|
|
3241
|
+
// (tree + both slash layers on + manual host order).
|
|
3242
|
+
setGroupBy: (d, value) => { d.groupBy = value },
|
|
3243
|
+
setOrderBy: (d, value) => { d.orderBy = value },
|
|
3244
|
+
setSessionTitleSlash: (d, value) => { d.sessionTitleSlash = value !== false },
|
|
3245
|
+
setWorkspaceTitleSlash: (d, value) => { d.workspaceTitleSlash = value !== false },
|
|
2997
3246
|
},
|
|
2998
3247
|
})
|
|
2999
3248
|
|
|
@@ -3951,6 +4200,60 @@ window.__ModuleLoader__.load({
|
|
|
3951
4200
|
)
|
|
3952
4201
|
}
|
|
3953
4202
|
|
|
4203
|
+
/* ------------------------- view options menu ---------------------- */
|
|
4204
|
+
|
|
4205
|
+
/**
|
|
4206
|
+
* View options (v0.13): mirrors the official browser's ViewOptionsMenu —
|
|
4207
|
+
* primitives Menu, label/separator/selectedIds structure, portal + dense
|
|
4208
|
+
* + end alignment. Group/order picks close the menu; the two slash
|
|
4209
|
+
* toggles flip in place (they ride selectedIds: present = on) and stay
|
|
4210
|
+
* open. Options that cannot affect the current mode render disabled:
|
|
4211
|
+
* slash toggles mean nothing in the flat list, and the WORKSPACE-name
|
|
4212
|
+
* toggle only shapes the tree mode (the flat workspace level has no
|
|
4213
|
+
* name layer). The primitives Menu is feature-probed like every
|
|
4214
|
+
* component — without it the button simply never renders.
|
|
4215
|
+
*/
|
|
4216
|
+
function ViewOptionsMenu({ groupBy, orderBy, sessionSlash, workspaceSlash, onPick, onToggle, t }) {
|
|
4217
|
+
const [open, setOpen] = React.useState(false)
|
|
4218
|
+
if (typeof ui.Menu !== 'function') return null
|
|
4219
|
+
return E(ui.Menu, {
|
|
4220
|
+
open,
|
|
4221
|
+
onClose: () => { setOpen(false) },
|
|
4222
|
+
items: [
|
|
4223
|
+
{ type: 'label', id: 'bw-group-by', text: t('viewOptions.groupBy') },
|
|
4224
|
+
{ id: 'workspace', label: t('viewOptions.byWorkspace') },
|
|
4225
|
+
{ id: 'workspace-tree', label: t('viewOptions.byWorkspaceTree') },
|
|
4226
|
+
{ id: 'flat', label: t('viewOptions.flat') },
|
|
4227
|
+
{ type: 'separator', id: 'bw-order-sep' },
|
|
4228
|
+
{ type: 'label', id: 'bw-order-by', text: t('viewOptions.orderBy') },
|
|
4229
|
+
{ id: 'manual', label: t('viewOptions.manualOrder') },
|
|
4230
|
+
{ id: 'updated', label: t('viewOptions.updatedOrder') },
|
|
4231
|
+
{ type: 'separator', id: 'bw-slash-sep' },
|
|
4232
|
+
{ id: 'session-slash', label: t('viewOptions.sessionSlash'), disabled: groupBy === 'flat' },
|
|
4233
|
+
{ id: 'workspace-slash', label: t('viewOptions.workspaceSlash'), disabled: groupBy !== 'workspace-tree' },
|
|
4234
|
+
],
|
|
4235
|
+
selectedIds: [groupBy, orderBy]
|
|
4236
|
+
.concat(sessionSlash ? ['session-slash'] : [])
|
|
4237
|
+
.concat(workspaceSlash ? ['workspace-slash'] : []),
|
|
4238
|
+
onSelect: (id) => {
|
|
4239
|
+
if (id === 'workspace' || id === 'workspace-tree' || id === 'flat') { onPick('groupBy', id); setOpen(false); return }
|
|
4240
|
+
if (id === 'manual' || id === 'updated') { onPick('orderBy', id); setOpen(false); return }
|
|
4241
|
+
if (id === 'session-slash') { onToggle('sessionTitleSlash', !sessionSlash); return }
|
|
4242
|
+
if (id === 'workspace-slash') { onToggle('workspaceTitleSlash', !workspaceSlash); return }
|
|
4243
|
+
},
|
|
4244
|
+
align: 'end',
|
|
4245
|
+
dense: true,
|
|
4246
|
+
portal: true,
|
|
4247
|
+
anchor: E('button', {
|
|
4248
|
+
type: 'button',
|
|
4249
|
+
className: 'bw-icon-btn',
|
|
4250
|
+
'aria-label': t('viewOptions.label'),
|
|
4251
|
+
title: t('viewOptions.label'),
|
|
4252
|
+
onClick: () => { setOpen(v => !v) },
|
|
4253
|
+
}, icon('IconPersonalizationOutline16')),
|
|
4254
|
+
})
|
|
4255
|
+
}
|
|
4256
|
+
|
|
3954
4257
|
/* --------------------- customization dialog ----------------------- */
|
|
3955
4258
|
|
|
3956
4259
|
const SWATCHES = ['', '#5b8def', '#3fb950', '#d29922', '#f85149', '#a371f7', '#39c5cf', '#ec6cb9', '#ff9f45', '#6e7681']
|
|
@@ -4423,6 +4726,7 @@ window.__ModuleLoader__.load({
|
|
|
4423
4726
|
insertWorkspaceBefore, insertSessionBefore,
|
|
4424
4727
|
useDirectoryFlow,
|
|
4425
4728
|
pickDirectory, listDirectory, createDirectory,
|
|
4729
|
+
officialT,
|
|
4426
4730
|
t,
|
|
4427
4731
|
} = props
|
|
4428
4732
|
|
|
@@ -4442,6 +4746,13 @@ window.__ModuleLoader__.load({
|
|
|
4442
4746
|
const prefsMap = useStore ? (useStore(s => s.prefs) || {}) : {}
|
|
4443
4747
|
const stylingMap = useStore ? (useStore(s => s.styling) || {}) : {}
|
|
4444
4748
|
const sessionOrderMap = useStore ? (useStore(s => s.sessionOrder) || {}) : {}
|
|
4749
|
+
// View options (v0.13). Selector reads take fallbacks: hydration
|
|
4750
|
+
// replaces the whole persisted value, so states written by older
|
|
4751
|
+
// plugin versions lack these keys (hard store discipline).
|
|
4752
|
+
const groupBy = useStore ? (useStore(s => s.groupBy) || 'workspace-tree') : 'workspace-tree'
|
|
4753
|
+
const orderBy = useStore ? (useStore(s => s.orderBy) || 'manual') : 'manual'
|
|
4754
|
+
const sessionSlash = useStore ? (useStore(s => s.sessionTitleSlash) !== false) : true
|
|
4755
|
+
const workspaceSlash = useStore ? (useStore(s => s.workspaceTitleSlash) !== false) : true
|
|
4445
4756
|
// Dual-write wrappers: every preference mutation lands in the local
|
|
4446
4757
|
// store (immediate echo + scope-less fallback) AND the host settings
|
|
4447
4758
|
// store (durable cross-device copy for the manual pull on the other
|
|
@@ -4451,6 +4762,8 @@ window.__ModuleLoader__.load({
|
|
|
4451
4762
|
const statusPulse = prefsMap.statusPulse !== false
|
|
4452
4763
|
const archivedSet = React.useMemo(() => new Set(archivedSessionIds), [archivedSessionIds])
|
|
4453
4764
|
const subCounts = React.useMemo(() => subagentRunningCounts(list ? list.byId : {}), [list ? list.byId : null])
|
|
4765
|
+
// Current session per the alpha.2 retention contract (see mainSessionIdOf).
|
|
4766
|
+
const currentId = React.useMemo(() => mainSessionIdOf(list), [list ? list.byId : null])
|
|
4454
4767
|
// Last-known real titles for the cold-restart fallback window (see
|
|
4455
4768
|
// the title-cache block). Read per render via getSnapshot: no
|
|
4456
4769
|
// subscription, because a cache write only happens when summary.title
|
|
@@ -4670,7 +4983,7 @@ window.__ModuleLoader__.load({
|
|
|
4670
4983
|
if (list && Array.isArray(list.ids)) {
|
|
4671
4984
|
for (const id of list.ids) {
|
|
4672
4985
|
const summary = list.byId[id]
|
|
4673
|
-
if (accounted.has(id) || !sessionVisible(summary,
|
|
4986
|
+
if (accounted.has(id) || !sessionVisible(summary, currentId, archivedSet)) continue
|
|
4674
4987
|
ungrouped.push({
|
|
4675
4988
|
id,
|
|
4676
4989
|
title: sessionTitleOf(summary, t, rememberedTitleOf(id)),
|
|
@@ -4696,10 +5009,10 @@ window.__ModuleLoader__.load({
|
|
|
4696
5009
|
// their drop targets live inside workspace rows, which compression merges.
|
|
4697
5010
|
const draggingWorkspace = drag !== null && drag.kind === 'workspace'
|
|
4698
5011
|
const tree = React.useMemo(() => {
|
|
4699
|
-
const built = buildTree(items)
|
|
5012
|
+
const built = buildTree(items, workspaceSlash)
|
|
4700
5013
|
if (!compactChains || draggingWorkspace) return built
|
|
4701
5014
|
return { ...built, folders: built.folders.map((f) => materializeChain(compressTree(f))), workspaces: built.workspaces }
|
|
4702
|
-
}, [items, compactChains, draggingWorkspace])
|
|
5015
|
+
}, [items, compactChains, draggingWorkspace, workspaceSlash])
|
|
4703
5016
|
// Disk-layer ancestry for drag semantics (same derivation as buildTree).
|
|
4704
5017
|
const diskParentMap = React.useMemo(() => diskParentMapOf(items), [items])
|
|
4705
5018
|
|
|
@@ -4714,7 +5027,7 @@ window.__ModuleLoader__.load({
|
|
|
4714
5027
|
const rows = []
|
|
4715
5028
|
for (const id of workspace.sessionIds || []) {
|
|
4716
5029
|
const summary = list && list.byId ? list.byId[id] : undefined
|
|
4717
|
-
if (!sessionVisible(summary,
|
|
5030
|
+
if (!sessionVisible(summary, currentId, archivedSet)) continue
|
|
4718
5031
|
rows.push({
|
|
4719
5032
|
id,
|
|
4720
5033
|
title: sessionTitleOf(summary, t, rememberedTitleOf(id)),
|
|
@@ -4733,6 +5046,21 @@ window.__ModuleLoader__.load({
|
|
|
4733
5046
|
// user dragged in, and is empty everywhere else — so a host that still
|
|
4734
5047
|
// exposes the action keeps its authoritative order untouched.
|
|
4735
5048
|
// Host order stays authoritative wherever the action exists.
|
|
5049
|
+
// Recency ordering (v0.13 view option, official orderBy semantics):
|
|
5050
|
+
// updatedAt descending with an id tie-break, and the CURRENT blank
|
|
5051
|
+
// session — the provisional New Session row — pinned on top. Purely
|
|
5052
|
+
// presentational: nothing is persisted, the host order is untouched,
|
|
5053
|
+
// and drag-to-reorder anchors are suppressed while active (an order
|
|
5054
|
+
// the very next render would re-sort is a lie).
|
|
5055
|
+
if (orderBy === 'updated') {
|
|
5056
|
+
const sorted = rows.slice().sort((a, b) => (b.updatedAt - a.updatedAt) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
|
|
5057
|
+
const pin = currentId !== undefined && sorted.find((row) => row.id === currentId && row.blank)
|
|
5058
|
+
if (pin) {
|
|
5059
|
+
const at = sorted.indexOf(pin)
|
|
5060
|
+
if (at > 0) { sorted.splice(at, 1); sorted.unshift(pin) }
|
|
5061
|
+
}
|
|
5062
|
+
return sorted
|
|
5063
|
+
}
|
|
4736
5064
|
const local = typeof insertSessionBefore === 'function' ? [] : sessionOrderOf(workspace.workspaceId)
|
|
4737
5065
|
if (local.length === 0) return rows
|
|
4738
5066
|
const remaining = new Map(rows.map((row) => [row.id, row]))
|
|
@@ -4791,7 +5119,7 @@ window.__ModuleLoader__.load({
|
|
|
4791
5119
|
// tree AND its disk-nested child levels.
|
|
4792
5120
|
const wsAllPulseOf = (workspace) => {
|
|
4793
5121
|
if (!statusPulse || searching) return null
|
|
4794
|
-
let best = nodePulseOf(buildSessionTree(sessionsOf(workspace)))
|
|
5122
|
+
let best = nodePulseOf(buildSessionTree(sessionsOf(workspace), sessionSlash))
|
|
4795
5123
|
if (workspace.sub) {
|
|
4796
5124
|
for (const folder of workspace.sub.folders) {
|
|
4797
5125
|
const s = folderPulseOf(folder)
|
|
@@ -4985,6 +5313,9 @@ window.__ModuleLoader__.load({
|
|
|
4985
5313
|
/* ---------------------- session drag & drop --------------------- */
|
|
4986
5314
|
|
|
4987
5315
|
const sessDropHalf = (sessionId) => {
|
|
5316
|
+
// Recency ordering is purely presentational: an anchor for a move
|
|
5317
|
+
// the very next render would re-sort is a lie — suppress it.
|
|
5318
|
+
if (orderBy === 'updated') return null
|
|
4988
5319
|
if (!dragMatches('session')) return null
|
|
4989
5320
|
const over = drag.over
|
|
4990
5321
|
return over && over.kind === 'session' && over.target === sessionId ? over.half : null
|
|
@@ -5104,7 +5435,7 @@ window.__ModuleLoader__.load({
|
|
|
5104
5435
|
if (name === target.name) { setDialog(null); return }
|
|
5105
5436
|
const workspace = (items || []).find(w => w.workspaceId === target.workspaceId)
|
|
5106
5437
|
if (!workspace) { setDialog(null); return }
|
|
5107
|
-
const node = findSessionGroup(buildSessionTree(sessionsOf(workspace)), target.path)
|
|
5438
|
+
const node = findSessionGroup(buildSessionTree(sessionsOf(workspace), sessionSlash), target.path)
|
|
5108
5439
|
if (!node) { setDialog(null); return }
|
|
5109
5440
|
const parentPath = target.path.includes('/') ? target.path.slice(0, target.path.lastIndexOf('/')) : ''
|
|
5110
5441
|
const nextPath = parentPath !== '' ? parentPath + '/' + name : name
|
|
@@ -5165,7 +5496,7 @@ window.__ModuleLoader__.load({
|
|
|
5165
5496
|
if (!searching && !sessionsOpenOf(workspace.workspaceId)) return []
|
|
5166
5497
|
const rows = sessionsOf(workspace)
|
|
5167
5498
|
if (rows.length === 0) return []
|
|
5168
|
-
return renderSessionNode(buildSessionTree(rows), workspace.workspaceId, depth)
|
|
5499
|
+
return renderSessionNode(buildSessionTree(rows, sessionSlash), workspace.workspaceId, depth)
|
|
5169
5500
|
}
|
|
5170
5501
|
const searchSessionNode = (node) => {
|
|
5171
5502
|
const groups = []
|
|
@@ -5208,7 +5539,7 @@ window.__ModuleLoader__.load({
|
|
|
5208
5539
|
key: session.id,
|
|
5209
5540
|
node: session,
|
|
5210
5541
|
depth,
|
|
5211
|
-
current:
|
|
5542
|
+
current: currentId === session.id,
|
|
5212
5543
|
now,
|
|
5213
5544
|
onOpen: (id) => open(id),
|
|
5214
5545
|
onContextMenu: (e) => openCtx('session', session, e),
|
|
@@ -5221,14 +5552,14 @@ window.__ModuleLoader__.load({
|
|
|
5221
5552
|
|
|
5222
5553
|
const renderWorkspaceEntry = (entry, depth, pulse) => {
|
|
5223
5554
|
const { workspace } = entry
|
|
5224
|
-
const count = countSessionTree(buildSessionTree(sessionsOf(workspace)))
|
|
5555
|
+
const count = countSessionTree(buildSessionTree(sessionsOf(workspace), sessionSlash))
|
|
5225
5556
|
const rows = [E(WorkspaceRow, {
|
|
5226
5557
|
key: 'ws-' + workspace.workspaceId,
|
|
5227
5558
|
workspace,
|
|
5228
5559
|
depth,
|
|
5229
5560
|
count,
|
|
5230
5561
|
sessionsOpen: searching ? true : sessionsOpenOf(workspace.workspaceId),
|
|
5231
|
-
currentInside: !!(
|
|
5562
|
+
currentInside: !!(currentId && (workspace.sessionIds || []).includes(currentId)),
|
|
5232
5563
|
onToggle: () => { if (!searching) actions.setSessionsExpanded(workspace.workspaceId, !sessionsOpenOf(workspace.workspaceId)) },
|
|
5233
5564
|
// Starting a session force-expands the workspace row: the user must
|
|
5234
5565
|
// SEE the new session appear, even if the row was collapsed.
|
|
@@ -5286,16 +5617,41 @@ window.__ModuleLoader__.load({
|
|
|
5286
5617
|
return rows
|
|
5287
5618
|
}
|
|
5288
5619
|
|
|
5620
|
+
// Single flat list (v0.13 groupBy:'flat', official FlatList semantics):
|
|
5621
|
+
// every visible session — each workspace's rows plus the ungrouped
|
|
5622
|
+
// account — as one depth-0 list. Rows keep their FULL title (no leaf
|
|
5623
|
+
// split, no levels), and render through the workspaceId-less path,
|
|
5624
|
+
// which carries no drag anchors by construction.
|
|
5625
|
+
const renderFlatRows = () => {
|
|
5626
|
+
const rows = []
|
|
5627
|
+
for (const workspace of items || []) rows.push(...sessionsOf(workspace))
|
|
5628
|
+
rows.push(...ungrouped)
|
|
5629
|
+
return rows.map((s) => renderSessionRow({ ...s, leaf: s.title }, 0, undefined))
|
|
5630
|
+
}
|
|
5631
|
+
const renderUngroupedBlock = () => {
|
|
5632
|
+
const rows = []
|
|
5633
|
+
if (ungrouped.length > 0) {
|
|
5634
|
+
rows.push(E('div', { key: 'ungrouped-label', className: 'bw-header-title', style: { padding: '10px 6px 2px' } }, t('group.ungrouped')))
|
|
5635
|
+
for (const s of ungrouped) rows.push(renderSessionRow(s, 0))
|
|
5636
|
+
}
|
|
5637
|
+
return rows
|
|
5638
|
+
}
|
|
5289
5639
|
let bodyRows = []
|
|
5290
5640
|
if (searching) {
|
|
5291
5641
|
for (const entry of searched) bodyRows.push(...renderWorkspaceEntry(entry, 0))
|
|
5642
|
+
} else if (groupBy === 'flat') {
|
|
5643
|
+
bodyRows.push(...renderFlatRows())
|
|
5644
|
+
} else if (groupBy === 'workspace') {
|
|
5645
|
+
// Official 'workspace' mode (v0.13): one level — every workspace at
|
|
5646
|
+
// the root, no name groups, no disk nesting, no chain compression.
|
|
5647
|
+
// Session rows keep the slash toggle; disk-nested children do not
|
|
5648
|
+
// recurse here because raw items carry no .sub level.
|
|
5649
|
+
for (const workspace of items || []) bodyRows.push(...renderWorkspaceEntry({ workspace }, 0, wsPulseOf(workspace)))
|
|
5650
|
+
bodyRows.push(...renderUngroupedBlock())
|
|
5292
5651
|
} else {
|
|
5293
5652
|
for (const folder of tree.folders) bodyRows.push(...renderPlainFolder(folder, 0))
|
|
5294
5653
|
for (const workspace of tree.workspaces) bodyRows.push(...renderWorkspaceEntry({ workspace }, 0, wsPulseOf(workspace)))
|
|
5295
|
-
|
|
5296
|
-
bodyRows.push(E('div', { key: 'ungrouped-label', className: 'bw-header-title', style: { padding: '10px 6px 2px' } }, t('group.ungrouped')))
|
|
5297
|
-
for (const s of ungrouped) bodyRows.push(renderSessionRow(s, 0))
|
|
5298
|
-
}
|
|
5654
|
+
bodyRows.push(...renderUngroupedBlock())
|
|
5299
5655
|
}
|
|
5300
5656
|
const isEmpty = bodyRows.length === 0
|
|
5301
5657
|
if (isEmpty) {
|
|
@@ -5304,30 +5660,42 @@ window.__ModuleLoader__.load({
|
|
|
5304
5660
|
|
|
5305
5661
|
/* ------------------------- context menu ------------------------ */
|
|
5306
5662
|
|
|
5307
|
-
|
|
5663
|
+
// Context-menu entries mirror the OFFICIAL row menus item-for-item
|
|
5664
|
+
// (ui-workspace Rows.tsx workspaceMenuItems / sessionMenuItems): same
|
|
5665
|
+
// ids, same icons, same danger semantics, and — through the official
|
|
5666
|
+
// 'workspace' dictionary — the same copy, so upstream rewording lands
|
|
5667
|
+
// here without a plugin release. What the official menus cannot
|
|
5668
|
+
// provide is the bw-only surface: name-group / session-group rename
|
|
5669
|
+
// and Customize appearance, appended after a separator.
|
|
5670
|
+
const ot = typeof officialT === 'function' ? officialT : null
|
|
5671
|
+
const menuEntries = () => {
|
|
5308
5672
|
if (ctx === null) return []
|
|
5673
|
+
const customizeEntry = { id: 'customize', label: t('custom.title'), icon: icon('IconPersonalizationOutline16', 16) }
|
|
5309
5674
|
if (ctx.kind === 'folder') return [
|
|
5310
|
-
{ id: 'rename-folder', label: t('menu.renameFolder') },
|
|
5311
|
-
{
|
|
5312
|
-
|
|
5675
|
+
{ id: 'rename-folder', label: t('menu.renameFolder'), icon: icon('IconEditOutline16', 16) },
|
|
5676
|
+
{ type: 'separator', id: 'bw-sep' },
|
|
5677
|
+
customizeEntry,
|
|
5313
5678
|
]
|
|
5314
5679
|
if (ctx.kind === 'workspace') return [
|
|
5315
|
-
{ id: 'rename', label: t('menu.rename') },
|
|
5316
|
-
{ id: 'delete', label: t('menu.delete'), danger: true },
|
|
5317
|
-
{
|
|
5318
|
-
|
|
5680
|
+
{ id: 'rename', label: ot ? ot('rename') : t('menu.rename'), icon: icon('IconEditOutline16', 16) },
|
|
5681
|
+
{ id: 'delete', label: ot ? ot('delete.workspace') : t('menu.delete'), icon: icon('IconTrashOutline16', 16), danger: true },
|
|
5682
|
+
{ type: 'separator', id: 'bw-sep' },
|
|
5683
|
+
customizeEntry,
|
|
5319
5684
|
]
|
|
5320
5685
|
if (ctx.kind === 'session') return [
|
|
5321
|
-
{ id: 'rename', label: t('menu.rename') },
|
|
5322
|
-
{ id: 'fork', label: t('menu.fork') },
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5686
|
+
{ id: 'rename', label: ot ? ot('rename') : t('menu.rename'), icon: icon('IconEditOutline16', 16) },
|
|
5687
|
+
{ id: 'fork', label: ot ? ot('menu.fork') : t('menu.fork'), icon: icon('IconBranchOutline16', 16) },
|
|
5688
|
+
// Official semantics (Rows.tsx): archive hides the row through the
|
|
5689
|
+
// registry-global archive set and never touches the session log —
|
|
5690
|
+
// deliberately NOT styled destructive.
|
|
5691
|
+
{ id: 'archive', label: ot ? ot('menu.archiveSession') : t('menu.archive'), icon: icon('IconArchiveOutline20', 16) },
|
|
5692
|
+
{ type: 'separator', id: 'bw-sep' },
|
|
5693
|
+
customizeEntry,
|
|
5326
5694
|
]
|
|
5327
5695
|
return [
|
|
5328
|
-
{ id: 'rename-sgroup', label: t('menu.renameSgroup') },
|
|
5329
|
-
{
|
|
5330
|
-
|
|
5696
|
+
{ id: 'rename-sgroup', label: t('menu.renameSgroup'), icon: icon('IconEditOutline16', 16) },
|
|
5697
|
+
{ type: 'separator', id: 'bw-sep' },
|
|
5698
|
+
customizeEntry,
|
|
5331
5699
|
]
|
|
5332
5700
|
}
|
|
5333
5701
|
const handleCtxPick = (id) => {
|
|
@@ -5453,6 +5821,15 @@ window.__ModuleLoader__.load({
|
|
|
5453
5821
|
onKeyDown: (e) => { if (e.key === 'Escape') { setQuery(''); setSearchOpen(false) } },
|
|
5454
5822
|
onBlur: () => { if (query === '') setSearchOpen(false) },
|
|
5455
5823
|
}) : null,
|
|
5824
|
+
E(ViewOptionsMenu, {
|
|
5825
|
+
groupBy,
|
|
5826
|
+
orderBy,
|
|
5827
|
+
sessionSlash,
|
|
5828
|
+
workspaceSlash,
|
|
5829
|
+
onPick: (kind, value) => { if (kind === 'groupBy') actions.setGroupBy(value); else actions.setOrderBy(value) },
|
|
5830
|
+
onToggle: (key, value) => { if (key === 'sessionTitleSlash') actions.setSessionTitleSlash(value); else actions.setWorkspaceTitleSlash(value) },
|
|
5831
|
+
t,
|
|
5832
|
+
}),
|
|
5456
5833
|
E('button', { type: 'button', className: 'bw-icon-btn', 'aria-label': t('search.placeholder'), onClick: () => setSearchOpen(v => !v) }, icon('IconSearchOutline16')),
|
|
5457
5834
|
flowAvailable ? E('button', { type: 'button', className: 'bw-icon-btn', 'aria-label': t('add'), onClick: () => setFlowOpen(true) }, icon('IconProjectAddOutline16')) : null,
|
|
5458
5835
|
),
|
|
@@ -5471,7 +5848,20 @@ window.__ModuleLoader__.load({
|
|
|
5471
5848
|
t,
|
|
5472
5849
|
}),
|
|
5473
5850
|
dialogElement,
|
|
5474
|
-
ctx !== null ? E(
|
|
5851
|
+
(ctx !== null && typeof ui.Menu === 'function') ? E(ui.Menu, {
|
|
5852
|
+
// Right-click opens the SAME menu surface the official ⋯ button
|
|
5853
|
+
// renders (primitives Menu, portal, dense): getAnchorRect feeds
|
|
5854
|
+
// the event coordinates as the anchor rect — portal mode positions
|
|
5855
|
+
// from it directly, no in-place wrapper needed.
|
|
5856
|
+
open: true,
|
|
5857
|
+
onClose: () => setCtx(null),
|
|
5858
|
+
items: menuEntries(),
|
|
5859
|
+
onSelect: handleCtxPick,
|
|
5860
|
+
align: 'start',
|
|
5861
|
+
dense: true,
|
|
5862
|
+
portal: true,
|
|
5863
|
+
getAnchorRect: () => new DOMRect(ctx.x, ctx.y, 0, 0),
|
|
5864
|
+
}) : (ctx !== null ? E('div', {
|
|
5475
5865
|
className: 'bw-ctx-overlay',
|
|
5476
5866
|
onMouseDown: () => setCtx(null),
|
|
5477
5867
|
onContextMenu: (e) => e.preventDefault(),
|
|
@@ -5482,7 +5872,7 @@ window.__ModuleLoader__.load({
|
|
|
5482
5872
|
onMouseDown: (e) => e.stopPropagation(),
|
|
5483
5873
|
onContextMenu: (e) => e.preventDefault(),
|
|
5484
5874
|
},
|
|
5485
|
-
|
|
5875
|
+
menuEntries().map((item, index) => item.type === 'separator'
|
|
5486
5876
|
? E('div', { key: 'sep-' + index, className: 'bw-ctx-sep' })
|
|
5487
5877
|
: E('button', {
|
|
5488
5878
|
key: item.id,
|
|
@@ -5492,7 +5882,7 @@ window.__ModuleLoader__.load({
|
|
|
5492
5882
|
}, item.label),
|
|
5493
5883
|
),
|
|
5494
5884
|
),
|
|
5495
|
-
) : null,
|
|
5885
|
+
) : null),
|
|
5496
5886
|
E(CustomizeDialog, {
|
|
5497
5887
|
open: customize !== null,
|
|
5498
5888
|
kind: customize ? customize.kind : undefined,
|
|
@@ -5555,6 +5945,14 @@ window.__ModuleLoader__.load({
|
|
|
5555
5945
|
// the handle before any flow can open.
|
|
5556
5946
|
pickerState.api = uiWorkspace
|
|
5557
5947
|
|
|
5948
|
+
// The OFFICIAL browser's own dictionary (NS 'workspace'), bound so the
|
|
5949
|
+
// context menu COPY follows upstream wording automatically — the menu
|
|
5950
|
+
// mirrors the official row menus item-for-item (Rows.tsx), and this
|
|
5951
|
+
// way upstream rewording lands here without a plugin release. Falls
|
|
5952
|
+
// back to this plugin's aligned dictionary when bind fails.
|
|
5953
|
+
let officialT = null
|
|
5954
|
+
try { officialT = ctx.locale.bind('workspace') } catch { officialT = null }
|
|
5955
|
+
|
|
5558
5956
|
if (ctx.locale && typeof ctx.locale.register === 'function') {
|
|
5559
5957
|
ctx.effect(() => {
|
|
5560
5958
|
try {
|
|
@@ -5571,22 +5969,31 @@ window.__ModuleLoader__.load({
|
|
|
5571
5969
|
if (!result || !result.ok) throw new Error(result && result.error ? result.error.message : 'session search failed')
|
|
5572
5970
|
return result.value
|
|
5573
5971
|
}
|
|
5972
|
+
// dsh 0.1.6-alpha.2 retention contract: rename borrows through
|
|
5973
|
+
// sessions.using with an explicit source — the old plain binding(id)
|
|
5974
|
+
// only ever saw already-retained sessions, so renaming a closed row
|
|
5975
|
+
// reported "unknown session". Fork and open go through the uiWorkspace
|
|
5976
|
+
// navigation service: ISessions no longer carries open() at all
|
|
5977
|
+
// (navigation belongs to the view owner, replaceMain).
|
|
5574
5978
|
const renameSession = async (sessionId, title) => {
|
|
5575
|
-
const
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5979
|
+
const result = await sessions.using(
|
|
5980
|
+
sessionId,
|
|
5981
|
+
{ source: 'workspaceOperation' },
|
|
5982
|
+
(reference) => reference.binding.session.rename(title),
|
|
5983
|
+
)
|
|
5579
5984
|
if (!result || !result.ok) throw new Error(result && result.error ? result.error.message : 'session rename failed')
|
|
5580
5985
|
}
|
|
5581
5986
|
const forkSession = (sessionId) => {
|
|
5582
|
-
|
|
5583
|
-
.then((childId) => sessions.open(childId))
|
|
5987
|
+
uiWorkspace.forkSession(sessionId)
|
|
5584
5988
|
.catch(() => { /* keep current selection */ })
|
|
5585
5989
|
}
|
|
5586
5990
|
|
|
5587
5991
|
const browserInjected = () => ({
|
|
5992
|
+
// Official 'workspace' dictionary translate (menu copy follows upstream);
|
|
5993
|
+
// null when the bind failed — the menu then uses the aligned bw copy.
|
|
5994
|
+
officialT,
|
|
5588
5995
|
startSession: (workspaceId) => { uiWorkspace.startSession(workspaceId) },
|
|
5589
|
-
open: (sessionId) => {
|
|
5996
|
+
open: (sessionId) => { uiWorkspace.openSession(sessionId) },
|
|
5590
5997
|
searchSessions,
|
|
5591
5998
|
searchResultLimit: sessions.searchResultLimit !== undefined ? sessions.searchResultLimit : 20,
|
|
5592
5999
|
renameSession,
|