dsh-better-workspace 0.15.0 → 0.15.1
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 +138 -18
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-better-workspace",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.1",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "侧边栏工作区树:按官方磁盘目录嵌套(官方 workspace-tree 语义),可选按名称中的 / 分组(默认关闭,设置里开启);添加工作区由官方目录流承载。Workspace tree for the DSH sidebar workspace list, nested by official disk folders with optional \"/\"-name grouping.",
|
|
6
6
|
"engines": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-better-workspace",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.1",
|
|
4
4
|
"description": "侧边栏工作区树:按官方磁盘目录嵌套(官方 workspace-tree 语义),可选按名称中的 / 分组(默认关闭,设置里开启);添加工作区走官方目录流。Workspace tree for the DSH sidebar: disk-path nesting (official workspace-tree semantics), with optional \"/\"-name grouping (off by default); add-workspace rides the official directory flow.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/src/client.js
CHANGED
|
@@ -152,6 +152,7 @@ window.__ModuleLoader__.load({
|
|
|
152
152
|
'folder.rename.hint': '重命名会同步更新组内所有工作区名称',
|
|
153
153
|
'folder.error.empty': '分组路径不能为空',
|
|
154
154
|
'group.move.title': '移动到分组',
|
|
155
|
+
'group.pick': '选择已有分组',
|
|
155
156
|
'group.new': '新建分组',
|
|
156
157
|
}
|
|
157
158
|
|
|
@@ -276,6 +277,7 @@ window.__ModuleLoader__.load({
|
|
|
276
277
|
'folder.rename.hint': 'Renaming updates every workspace title inside the folder',
|
|
277
278
|
'folder.error.empty': 'Folder path must not be empty',
|
|
278
279
|
'group.move.title': 'Move to group',
|
|
280
|
+
'group.pick': 'Pick an existing group',
|
|
279
281
|
'group.new': 'New group',
|
|
280
282
|
}
|
|
281
283
|
|
|
@@ -408,6 +410,7 @@ window.__ModuleLoader__.load({
|
|
|
408
410
|
'folder.rename.hint': 'تحديث الاسم يعيد تسمية كل مساحات العمل داخل المجموعة',
|
|
409
411
|
'folder.error.empty': 'لا يمكن أن يكون مسار المجموعة فارغاً',
|
|
410
412
|
'group.move.title': 'نقل إلى مجموعة',
|
|
413
|
+
'group.pick': 'اختر مجموعة موجودة',
|
|
411
414
|
'group.new': 'مجموعة جديدة',
|
|
412
415
|
},
|
|
413
416
|
/* locale: de */
|
|
@@ -532,6 +535,7 @@ window.__ModuleLoader__.load({
|
|
|
532
535
|
'folder.rename.hint': 'Umbenennen aktualisiert alle Arbeitsbereichsnamen im Ordner',
|
|
533
536
|
'folder.error.empty': 'Der Ordnerpfad darf nicht leer sein',
|
|
534
537
|
'group.move.title': 'In Gruppe verschieben',
|
|
538
|
+
'group.pick': 'Vorhandene Gruppe wählen',
|
|
535
539
|
'group.new': 'Neue Gruppe',
|
|
536
540
|
},
|
|
537
541
|
/* locale: fr */
|
|
@@ -656,6 +660,7 @@ window.__ModuleLoader__.load({
|
|
|
656
660
|
'folder.rename.hint': 'Le renommage met à jour tous les espaces de travail du dossier',
|
|
657
661
|
'folder.error.empty': 'Le chemin du dossier ne doit pas être vide',
|
|
658
662
|
'group.move.title': 'Déplacer vers le groupe',
|
|
663
|
+
'group.pick': 'Choisir un groupe existant',
|
|
659
664
|
'group.new': 'Nouveau groupe',
|
|
660
665
|
},
|
|
661
666
|
/* locale: hi */
|
|
@@ -780,6 +785,7 @@ window.__ModuleLoader__.load({
|
|
|
780
785
|
'folder.rename.hint': 'नाम बदलने पर समूह के सभी कार्यस्थानों के नाम भी बदल जाते हैं',
|
|
781
786
|
'folder.error.empty': 'समूह पथ खाली नहीं हो सकता',
|
|
782
787
|
'group.move.title': 'समूह में ले जाएँ',
|
|
788
|
+
'group.pick': 'मौजूदा समूह चुनें',
|
|
783
789
|
'group.new': 'नया समूह',
|
|
784
790
|
},
|
|
785
791
|
/* locale: id */
|
|
@@ -904,6 +910,7 @@ window.__ModuleLoader__.load({
|
|
|
904
910
|
'folder.rename.hint': 'Mengganti nama akan memperbarui semua ruang kerja di folder',
|
|
905
911
|
'folder.error.empty': 'Jalur folder tidak boleh kosong',
|
|
906
912
|
'group.move.title': 'Pindahkan ke grup',
|
|
913
|
+
'group.pick': 'Pilih grup yang ada',
|
|
907
914
|
'group.new': 'Grup baru',
|
|
908
915
|
},
|
|
909
916
|
/* locale: it */
|
|
@@ -1028,6 +1035,7 @@ window.__ModuleLoader__.load({
|
|
|
1028
1035
|
'folder.rename.hint': 'La rinomina aggiorna tutte le aree di lavoro nella cartella',
|
|
1029
1036
|
'folder.error.empty': 'Il percorso della cartella non può essere vuoto',
|
|
1030
1037
|
'group.move.title': 'Sposta nel gruppo',
|
|
1038
|
+
'group.pick': 'Scegli un gruppo esistente',
|
|
1031
1039
|
'group.new': 'Nuovo gruppo',
|
|
1032
1040
|
},
|
|
1033
1041
|
/* locale: ja */
|
|
@@ -1152,6 +1160,7 @@ window.__ModuleLoader__.load({
|
|
|
1152
1160
|
'folder.rename.hint': '名前を変更すると,フォルダー内のすべてのワークスペース名も更新されます',
|
|
1153
1161
|
'folder.error.empty': 'フォルダーのパスを入力してください',
|
|
1154
1162
|
'group.move.title': 'グループに移動',
|
|
1163
|
+
'group.pick': '既存のグループを選択',
|
|
1155
1164
|
'group.new': '新しいグループ',
|
|
1156
1165
|
},
|
|
1157
1166
|
/* locale: ko */
|
|
@@ -1276,6 +1285,7 @@ window.__ModuleLoader__.load({
|
|
|
1276
1285
|
'folder.rename.hint': '이름을 바꾸면 폴더 안 모든 워크스페이스 이름도 함께 바뀝니다',
|
|
1277
1286
|
'folder.error.empty': '폴더 경로를 입력해야 합니다',
|
|
1278
1287
|
'group.move.title': '그룹으로 이동',
|
|
1288
|
+
'group.pick': '기존 그룹 선택',
|
|
1279
1289
|
'group.new': '새 그룹',
|
|
1280
1290
|
},
|
|
1281
1291
|
/* locale: nl */
|
|
@@ -1400,6 +1410,7 @@ window.__ModuleLoader__.load({
|
|
|
1400
1410
|
'folder.rename.hint': 'Naam wijzigen werkt alle werkruimtenamen in de map bij',
|
|
1401
1411
|
'folder.error.empty': 'Het mappad mag niet leeg zijn',
|
|
1402
1412
|
'group.move.title': 'Naar groep verplaatsen',
|
|
1413
|
+
'group.pick': 'Bestaande groep kiezen',
|
|
1403
1414
|
'group.new': 'Nieuwe groep',
|
|
1404
1415
|
},
|
|
1405
1416
|
/* locale: pl */
|
|
@@ -1524,6 +1535,7 @@ window.__ModuleLoader__.load({
|
|
|
1524
1535
|
'folder.rename.hint': 'Zmiana nazwy zaktualizuje wszystkie obszary robocze w folderze',
|
|
1525
1536
|
'folder.error.empty': 'Ścieżka folderu nie może być pusta',
|
|
1526
1537
|
'group.move.title': 'Przenieś do grupy',
|
|
1538
|
+
'group.pick': 'Wybierz istniejącą grupę',
|
|
1527
1539
|
'group.new': 'Nowa grupa',
|
|
1528
1540
|
},
|
|
1529
1541
|
/* locale: pt */
|
|
@@ -1648,6 +1660,7 @@ window.__ModuleLoader__.load({
|
|
|
1648
1660
|
'folder.rename.hint': 'Renomear atualiza todos os espaços de trabalho da pasta',
|
|
1649
1661
|
'folder.error.empty': 'O caminho da pasta não pode ficar vazio',
|
|
1650
1662
|
'group.move.title': 'Mover para o grupo',
|
|
1663
|
+
'group.pick': 'Escolher um grupo existente',
|
|
1651
1664
|
'group.new': 'Novo grupo',
|
|
1652
1665
|
},
|
|
1653
1666
|
/* locale: ru */
|
|
@@ -1772,6 +1785,7 @@ window.__ModuleLoader__.load({
|
|
|
1772
1785
|
'folder.rename.hint': 'Переименование обновит все рабочие области в папке',
|
|
1773
1786
|
'folder.error.empty': 'Путь папки не может быть пустым',
|
|
1774
1787
|
'group.move.title': 'Переместить в группу',
|
|
1788
|
+
'group.pick': 'Выбрать существующую группу',
|
|
1775
1789
|
'group.new': 'Новая группа',
|
|
1776
1790
|
},
|
|
1777
1791
|
/* locale: sv */
|
|
@@ -1896,6 +1910,7 @@ window.__ModuleLoader__.load({
|
|
|
1896
1910
|
'folder.rename.hint': 'Namnbytet uppdaterar alla arbetsytor i mappen',
|
|
1897
1911
|
'folder.error.empty': 'Mappsökvägen får inte vara tom',
|
|
1898
1912
|
'group.move.title': 'Flytta till grupp',
|
|
1913
|
+
'group.pick': 'Välj en befintlig grupp',
|
|
1899
1914
|
'group.new': 'Ny grupp',
|
|
1900
1915
|
},
|
|
1901
1916
|
/* locale: th */
|
|
@@ -2020,6 +2035,7 @@ window.__ModuleLoader__.load({
|
|
|
2020
2035
|
'folder.rename.hint': 'การเปลี่ยนชื่อจะอัปเดตพื้นที่ทำงานทั้งหมดในกลุ่ม',
|
|
2021
2036
|
'folder.error.empty': 'เส้นทางกลุ่มต้องไม่ว่าง',
|
|
2022
2037
|
'group.move.title': 'ย้ายไปยังกลุ่ม',
|
|
2038
|
+
'group.pick': 'เลือกกลุ่มที่มีอยู่',
|
|
2023
2039
|
'group.new': 'กลุ่มใหม่',
|
|
2024
2040
|
},
|
|
2025
2041
|
/* locale: tr */
|
|
@@ -2144,6 +2160,7 @@ window.__ModuleLoader__.load({
|
|
|
2144
2160
|
'folder.rename.hint': 'Yeniden adlandırma klasördeki tüm çalışma alanlarını günceller',
|
|
2145
2161
|
'folder.error.empty': 'Klasör yolu boş olamaz',
|
|
2146
2162
|
'group.move.title': 'Gruba taşı',
|
|
2163
|
+
'group.pick': 'Mevcut bir grup seç',
|
|
2147
2164
|
'group.new': 'Yeni grup',
|
|
2148
2165
|
},
|
|
2149
2166
|
/* locale: vi */
|
|
@@ -2268,6 +2285,7 @@ window.__ModuleLoader__.load({
|
|
|
2268
2285
|
'folder.rename.hint': 'Đổi tên sẽ cập nhật mọi không gian làm việc trong nhóm',
|
|
2269
2286
|
'folder.error.empty': 'Đường dẫn nhóm không được để trống',
|
|
2270
2287
|
'group.move.title': 'Chuyển vào nhóm',
|
|
2288
|
+
'group.pick': 'Chọn một nhóm có sẵn',
|
|
2271
2289
|
'group.new': 'Nhóm mới',
|
|
2272
2290
|
},
|
|
2273
2291
|
/* locale: zh-HK */
|
|
@@ -2392,6 +2410,7 @@ window.__ModuleLoader__.load({
|
|
|
2392
2410
|
'folder.rename.hint': '重新命名會同步更新組內所有工作區名稱',
|
|
2393
2411
|
'folder.error.empty': '分組路徑唔可以係空',
|
|
2394
2412
|
'group.move.title': '移動到分組',
|
|
2413
|
+
'group.pick': '選擇已有分組',
|
|
2395
2414
|
'group.new': '新增分組',
|
|
2396
2415
|
},
|
|
2397
2416
|
/* locale: zh-MO */
|
|
@@ -2516,6 +2535,7 @@ window.__ModuleLoader__.load({
|
|
|
2516
2535
|
'folder.rename.hint': '重新命名會同步更新組內所有工作區名稱',
|
|
2517
2536
|
'folder.error.empty': '分組路徑唔可以係空',
|
|
2518
2537
|
'group.move.title': '移動到分組',
|
|
2538
|
+
'group.pick': '選擇已有分組',
|
|
2519
2539
|
'group.new': '新增分組',
|
|
2520
2540
|
},
|
|
2521
2541
|
/* locale: zh-TW */
|
|
@@ -2640,6 +2660,7 @@ window.__ModuleLoader__.load({
|
|
|
2640
2660
|
'folder.rename.hint': '重新命名會同步更新群組內所有工作區名稱',
|
|
2641
2661
|
'folder.error.empty': '群組路徑不能為空',
|
|
2642
2662
|
'group.move.title': '移動到分組',
|
|
2663
|
+
'group.pick': '選擇現有群組',
|
|
2643
2664
|
'group.new': '新增分組',
|
|
2644
2665
|
},
|
|
2645
2666
|
}
|
|
@@ -2986,6 +3007,23 @@ window.__ModuleLoader__.load({
|
|
|
2986
3007
|
}
|
|
2987
3008
|
return map
|
|
2988
3009
|
}
|
|
3010
|
+
/**
|
|
3011
|
+
* The row entry the official 'workspace' grouping mode renders.
|
|
3012
|
+
*
|
|
3013
|
+
* A raw WorkspaceView carries no `leaf`, and WorkspaceRow renders exactly
|
|
3014
|
+
* that field as its label (the tree path fills it while building) — so
|
|
3015
|
+
* handing the raw item to renderWorkspaceEntry, as v0.13 did, drew every
|
|
3016
|
+
* row with its icon and sessions but NO NAME AT ALL. Reported 2026-09-19.
|
|
3017
|
+
*
|
|
3018
|
+
* The label is the FULL title: this mode renders no name groups, so a "/"
|
|
3019
|
+
* has nothing to group into and must stay in the text.
|
|
3020
|
+
*/
|
|
3021
|
+
const flatWorkspaceEntry = (workspace) => ({
|
|
3022
|
+
...workspace,
|
|
3023
|
+
leaf: String(workspace.title || '') || basename(workspace.path) || String(workspace.workspaceId || ''),
|
|
3024
|
+
folderPath: '',
|
|
3025
|
+
})
|
|
3026
|
+
|
|
2989
3027
|
function buildTree(items, groupBySlash) {
|
|
2990
3028
|
const list = items || []
|
|
2991
3029
|
const diskParentOf = diskParentMapOf(list)
|
|
@@ -3127,6 +3165,18 @@ window.__ModuleLoader__.load({
|
|
|
3127
3165
|
'.bw-input{width:100%;box-sizing:border-box;height:26px;background:var(--dsw-alias-bg-layer-2,rgba(127,127,127,.1));border:1px solid var(--dsw-alias-border-l1,rgba(127,127,127,.25));border-radius:6px;color:inherit;padding:0 8px;font-size:12px;outline:none;font-family:inherit}',
|
|
3128
3166
|
'.bw-input:focus{border-color:var(--dsw-alias-brand-primary,#5b8def)}',
|
|
3129
3167
|
'.bw-input::placeholder{color:var(--dsw-alias-label-quaternary,#8a8a8a)}',
|
|
3168
|
+
// Dropdown triggers (MenuPicker): the same surface as .bw-input so a
|
|
3169
|
+
// picker and a text field read as one family.
|
|
3170
|
+
'.bw-select{display:flex;align-items:center;gap:6px;width:100%;box-sizing:border-box;height:26px;padding:0 8px;background:var(--dsw-alias-bg-layer-2,rgba(127,127,127,.1));border:1px solid var(--dsw-alias-border-l1,rgba(127,127,127,.25));border-radius:6px;color:inherit;font-size:12px;font-family:inherit;cursor:pointer;text-align:left}',
|
|
3171
|
+
'.bw-select:hover{border-color:var(--dsw-alias-brand-primary,#5b8def)}',
|
|
3172
|
+
'.bw-select-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',
|
|
3173
|
+
'.bw-select-chevron{flex:none;display:inline-flex;align-items:center;color:var(--dsw-alias-label-quaternary,#8a8a8a);font-size:10px;line-height:1}',
|
|
3174
|
+
'.bw-select-icon{width:26px;flex:none;justify-content:center;padding:0}',
|
|
3175
|
+
'.bw-combo{display:flex;align-items:center;gap:6px}',
|
|
3176
|
+
// The Menu root is a <span>; these make it fill the field, or sit inline
|
|
3177
|
+
// as the chevron-only button beside an input.
|
|
3178
|
+
'.bw-menu-block{display:block;width:100%}',
|
|
3179
|
+
'.bw-menu-inline{display:inline-block;width:auto;flex:none}',
|
|
3130
3180
|
'.bw-tree{flex:1;overflow-y:auto;overflow-x:hidden;padding:2px 6px 12px;min-height:0}',
|
|
3131
3181
|
'.bw-row{display:flex;align-items:center;gap:6px;min-height:28px;padding:0 6px;border-radius:6px;cursor:pointer;user-select:none;font-size:13px;color:var(--dsw-alias-label-primary,#e6e6e6);position:relative}',
|
|
3132
3182
|
'.bw-drop-before::after{content:"";position:absolute;left:8px;right:8px;top:-1px;height:2px;border-radius:1px;background:var(--dsw-alias-brand-primary,#5b8def);pointer-events:none}',
|
|
@@ -3610,6 +3660,52 @@ window.__ModuleLoader__.load({
|
|
|
3610
3660
|
}, E('div', { className: 'bw-modal-body' }, E('div', { className: 'bw-hint' }, body)), StyleNode())
|
|
3611
3661
|
}
|
|
3612
3662
|
|
|
3663
|
+
/**
|
|
3664
|
+
* One picker over the official primitives Menu, used wherever this plugin
|
|
3665
|
+
* would otherwise reach for a native <select> / <datalist>.
|
|
3666
|
+
*
|
|
3667
|
+
* WHY NOT NATIVE: the OS draws a native select's popup itself, so over this
|
|
3668
|
+
* plugin's translucent panel it comes back as a light system list that
|
|
3669
|
+
* ignores the theme entirely. dsh-ide-git hit the same defect twice and
|
|
3670
|
+
* replaced its selects with a button-over-menu for exactly that reason (see
|
|
3671
|
+
* the RepoSelect / FilterSelect notes there) — but it had to lay that menu
|
|
3672
|
+
* out INSIDE the panel, because dsh-better-sidebar declares
|
|
3673
|
+
* `contain: layout` and would strand a portal off-screen. This plugin sits
|
|
3674
|
+
* in a native DSH sidebar slot with no such constraint, so it can use the
|
|
3675
|
+
* real primitives Menu: official look and keyboard model, portal above the
|
|
3676
|
+
* modal (z-index 1100 vs 1000), and its own scrolling list — which the
|
|
3677
|
+
* workspace x session target list needs.
|
|
3678
|
+
*
|
|
3679
|
+
* Degradation: callers keep a native control for hosts whose primitives
|
|
3680
|
+
* have no Menu, so picking never becomes impossible.
|
|
3681
|
+
*/
|
|
3682
|
+
function MenuPicker({ options, value, onPick, placeholder, chevronOnly, title, t }) {
|
|
3683
|
+
const [open, setOpen] = React.useState(false)
|
|
3684
|
+
const list = Array.isArray(options) ? options : []
|
|
3685
|
+
let current = null
|
|
3686
|
+
for (const option of list) { if (String(option.value) === String(value)) { current = option; break } }
|
|
3687
|
+
const chevron = icon('IconChevronDownOutline14', 14)
|
|
3688
|
+
return E(ui.Menu, {
|
|
3689
|
+
open,
|
|
3690
|
+
onClose: () => { setOpen(false) },
|
|
3691
|
+
items: list.map((option) => ({ id: String(option.value), label: String(option.label) })),
|
|
3692
|
+
selectedId: current === null ? undefined : String(current.value),
|
|
3693
|
+
onSelect: (id) => { setOpen(false); onPick(id) },
|
|
3694
|
+
align: 'start',
|
|
3695
|
+
dense: true,
|
|
3696
|
+
portal: true,
|
|
3697
|
+
className: cls('bw-menu-block', chevronOnly && 'bw-menu-inline'),
|
|
3698
|
+
anchor: E('button', {
|
|
3699
|
+
type: 'button',
|
|
3700
|
+
className: cls('bw-select', chevronOnly && 'bw-select-icon'),
|
|
3701
|
+
title: title === undefined ? undefined : title,
|
|
3702
|
+
onClick: () => setOpen(v => !v),
|
|
3703
|
+
},
|
|
3704
|
+
chevronOnly ? null : E('span', { className: 'bw-select-label' }, current === null ? (placeholder || '') : String(current.label)),
|
|
3705
|
+
E('span', { className: 'bw-select-chevron' }, chevron || '\u25be')),
|
|
3706
|
+
})
|
|
3707
|
+
}
|
|
3708
|
+
|
|
3613
3709
|
/**
|
|
3614
3710
|
* "Move to group…": the discoverable front door for the name-projection
|
|
3615
3711
|
* grouping this plugin has always had (no empty groups — moving an entry
|
|
@@ -3617,8 +3713,9 @@ window.__ModuleLoader__.load({
|
|
|
3617
3713
|
* - a free target (the header "New group" button, or a row drop on it)
|
|
3618
3714
|
* locks the entry and only asks for the group name;
|
|
3619
3715
|
* - the picker shape (header button click) asks which entry first.
|
|
3620
|
-
*
|
|
3621
|
-
*
|
|
3716
|
+
* Both dropdowns are MenuPicker (see its note): a native select's popup and
|
|
3717
|
+
* a native datalist's suggestions are drawn by the OS and ignore the panel
|
|
3718
|
+
* theme, which is exactly what users reported here.
|
|
3622
3719
|
*/
|
|
3623
3720
|
function GroupDialog({ title, hint, initial, targets, groupPaths, onConfirm, onClose, t }) {
|
|
3624
3721
|
const hasTargets = Array.isArray(targets) && targets.length > 0
|
|
@@ -3628,6 +3725,7 @@ window.__ModuleLoader__.load({
|
|
|
3628
3725
|
React.useEffect(() => { if (inputRef.current) { inputRef.current.focus(); inputRef.current.select() } }, [])
|
|
3629
3726
|
const commit = () => onConfirm(hasTargets ? targetValue : undefined, value)
|
|
3630
3727
|
const hintList = Array.isArray(groupPaths) ? groupPaths.filter((p) => p !== '') : []
|
|
3728
|
+
const menuReady = typeof ui.Menu === 'function'
|
|
3631
3729
|
return E(ui.Modal, {
|
|
3632
3730
|
open: true,
|
|
3633
3731
|
onClose,
|
|
@@ -3641,24 +3739,42 @@ window.__ModuleLoader__.load({
|
|
|
3641
3739
|
E('div', { className: 'bw-modal-body' },
|
|
3642
3740
|
hasTargets
|
|
3643
3741
|
? E('div', { className: 'bw-field' },
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3742
|
+
menuReady
|
|
3743
|
+
? E(MenuPicker, {
|
|
3744
|
+
options: targets.map((item) => ({ value: item.value, label: item.label })),
|
|
3745
|
+
value: targetValue,
|
|
3746
|
+
onPick: setTargetValue,
|
|
3747
|
+
t,
|
|
3748
|
+
})
|
|
3749
|
+
: E('select', {
|
|
3750
|
+
className: 'bw-input',
|
|
3751
|
+
defaultValue: targets[0].value,
|
|
3752
|
+
onChange: (e) => setTargetValue(e.target.value),
|
|
3753
|
+
}, targets.map((item) => E('option', { key: String(item.value), value: String(item.value) }, item.label))),
|
|
3649
3754
|
)
|
|
3650
3755
|
: null,
|
|
3651
3756
|
E('div', { className: 'bw-field' },
|
|
3652
|
-
E('
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3757
|
+
E('div', { className: 'bw-combo' },
|
|
3758
|
+
E('input', {
|
|
3759
|
+
ref: inputRef,
|
|
3760
|
+
className: 'bw-input',
|
|
3761
|
+
value,
|
|
3762
|
+
onChange: (e) => setValue(e.target.value),
|
|
3763
|
+
onKeyDown: (e) => { if (e.key === 'Enter') commit() },
|
|
3764
|
+
}),
|
|
3765
|
+
// The old datalist's suggestions, as a real menu: one chevron
|
|
3766
|
+
// button beside the field. Typing a brand-new group name still
|
|
3767
|
+
// works exactly as before.
|
|
3768
|
+
(menuReady && hintList.length > 0)
|
|
3769
|
+
? E(MenuPicker, {
|
|
3770
|
+
options: hintList.map((path) => ({ value: path, label: path })),
|
|
3771
|
+
value,
|
|
3772
|
+
onPick: setValue,
|
|
3773
|
+
chevronOnly: true,
|
|
3774
|
+
title: t('group.pick'),
|
|
3775
|
+
t,
|
|
3776
|
+
})
|
|
3777
|
+
: null,
|
|
3662
3778
|
),
|
|
3663
3779
|
hint ? E('div', { className: 'bw-hint' }, hint) : null,
|
|
3664
3780
|
),
|
|
@@ -6023,7 +6139,11 @@ window.__ModuleLoader__.load({
|
|
|
6023
6139
|
// the root, no name groups, no disk nesting, no chain compression.
|
|
6024
6140
|
// Session rows keep the slash toggle; disk-nested children do not
|
|
6025
6141
|
// recurse here because raw items carry no .sub level.
|
|
6026
|
-
|
|
6142
|
+
// flatWorkspaceEntry, never the raw item: see its note — the raw one
|
|
6143
|
+
// has no `leaf` and the row would render nameless.
|
|
6144
|
+
for (const workspace of items || []) {
|
|
6145
|
+
bodyRows.push(...renderWorkspaceEntry({ workspace: flatWorkspaceEntry(workspace) }, 0, wsPulseOf(workspace)))
|
|
6146
|
+
}
|
|
6027
6147
|
bodyRows.push(...renderUngroupedBlock())
|
|
6028
6148
|
} else {
|
|
6029
6149
|
for (const folder of tree.folders) bodyRows.push(...renderPlainFolder(folder, 0))
|