@stofone/dsh-agent-roster 1.0.0 → 1.1.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/CHANGELOG.md +18 -0
- package/README.md +5 -0
- package/README.zh.md +4 -0
- package/client.js +71 -22
- package/locale/en.json +3 -1
- package/locale/zh.json +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,23 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.1.0] - 2026-11-03
|
|
8
|
+
|
|
9
|
+
### The library reads as spaces, not groups
|
|
10
|
+
|
|
11
|
+
1.0.0 made the space a real level in the format. The panel still showed collections as small labels, so the
|
|
12
|
+
level existed in the files and not on screen. Each group header is now the space itself: its id sits in the
|
|
13
|
+
same column as the roster ids (the register keeps one spine), the right side states two facts you can check
|
|
14
|
+
on the spot — how many rosters it holds, how many are already here — and one button pulls the whole space.
|
|
15
|
+
|
|
16
|
+
Rows also stopped lying about state. A roster that is already on this machine says so, and its action
|
|
17
|
+
becomes **Open** instead of **Pull**: the panel no longer offers to fetch something you already have. The
|
|
18
|
+
local group drops the per-row "local" label, because the group header already says it.
|
|
19
|
+
|
|
20
|
+
On a narrow panel the space header folds into two lines (id + action, then title + facts) instead of
|
|
21
|
+
squeezing a long space name into a vertical stack one character wide.
|
|
22
|
+
|
|
23
|
+
|
|
7
24
|
## [1.0.0] - 2026-11-03
|
|
8
25
|
|
|
9
26
|
### A space is the thing a repository holds
|
|
@@ -668,6 +685,7 @@ point is now one search field above the tabs.
|
|
|
668
685
|
[Unreleased]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.12.0...main
|
|
669
686
|
[0.13.1]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.13.0...v0.13.1
|
|
670
687
|
[1.0.0]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.13.1...v1.0.0
|
|
688
|
+
[1.1.0]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v1.0.0...v1.1.0
|
|
671
689
|
[0.13.0]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.12.0...v0.13.0
|
|
672
690
|
[0.12.0]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.11.1...v0.12.0
|
|
673
691
|
[0.11.1]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.11.0...v0.11.1
|
package/README.md
CHANGED
|
@@ -326,6 +326,11 @@ response, the tag strip summarises every tag in view with its count (multiple ta
|
|
|
326
326
|
segmented control switches between **by source** (this machine, then one group per collection) and **flat**
|
|
327
327
|
(one list, source named per row). Tag filtering is view state only; it never writes back to a file.
|
|
328
328
|
|
|
329
|
+
By source, each group's head **is the space**: its id sits in the same column as the roster ids, the
|
|
330
|
+
right side states two facts you can check on the spot — how many rosters it holds, how many are already
|
|
331
|
+
here — and carries one button that pulls the whole space. A roster that is already here says so in its row
|
|
332
|
+
and its button reads **Open**: the panel never asks you to pull something you already have.
|
|
333
|
+
|
|
329
334
|
Multiple words are AND, not OR: `data kubernetes` returns nothing rather than every roster that merely
|
|
330
335
|
mentions "data". Ranking is a pure function in `lib/search.js`, so it is unit-tested rather than eyeballed.
|
|
331
336
|
|
package/README.zh.md
CHANGED
|
@@ -323,6 +323,10 @@ node bin/cli.mjs compile --roster examples-orchestration/rosters/core-review \
|
|
|
323
323
|
多选是「且」;右侧可以在**按来源**(本机 + 每个 collection 各一组)与**平铺**(一份清单,来源写在行内)
|
|
324
324
|
之间切换。标签筛选只影响视图,不写回文件。
|
|
325
325
|
|
|
326
|
+
按来源时,每一组的头就是**空间**本身:等宽的空间 id 落在与档案 id 同一列,右侧写两件当场能核对的事实
|
|
327
|
+
——「几份 · 已装几份」——并带一个「拉取整个空间」按钮。已经在本机的那份,行内写「已在本机」,
|
|
328
|
+
按钮变成「打开」:面板不会让你去拉一份自己已经有的档案。窄屏上这个头折成两行,空间名不会被挤成竖排。
|
|
329
|
+
|
|
326
330
|
多个词是「且」不是「或」:`data kubernetes` 一条都不返,而不是把所有提到 data 的档案都堆上来。
|
|
327
331
|
排序是 `lib/search.js` 里的纯函数,所以它被单测钉住,而不是靠肉眼看着顺。
|
|
328
332
|
|
package/client.js
CHANGED
|
@@ -1373,14 +1373,19 @@ window.__ModuleLoader__.load({
|
|
|
1373
1373
|
map.set(key, {
|
|
1374
1374
|
key,
|
|
1375
1375
|
scope: entry.scope,
|
|
1376
|
-
|
|
1376
|
+
id: entry.scope === "local" ? t("catalog.local") : entry.collectionId ?? "",
|
|
1377
|
+
title: entry.scope === "local" ? "" : entry.collectionTitle ?? "",
|
|
1377
1378
|
entries: [],
|
|
1378
1379
|
});
|
|
1379
1380
|
}
|
|
1380
1381
|
map.get(key).entries.push(entry);
|
|
1381
1382
|
}
|
|
1382
|
-
|
|
1383
|
-
|
|
1383
|
+
// 空间头上只放两件能当场核对的事实:有几份、其中几份本机已经有。
|
|
1384
|
+
return [...map.values()].map((group) => ({
|
|
1385
|
+
...group,
|
|
1386
|
+
installed: group.entries.filter((entry) => installed.has(entry.rosterId)).length,
|
|
1387
|
+
}));
|
|
1388
|
+
}, [filtered, mode, installed, t]);
|
|
1384
1389
|
|
|
1385
1390
|
function toggleTag(tag) {
|
|
1386
1391
|
setSelected((current) => {
|
|
@@ -1419,15 +1424,16 @@ window.__ModuleLoader__.load({
|
|
|
1419
1424
|
{ className: "rstr-row-stats" },
|
|
1420
1425
|
h("span", { className: "rstr-stat" }, t("catalog.members", { count: String(entry.members ?? 0) })),
|
|
1421
1426
|
entry.scope === "remote" && installed.has(entry.rosterId)
|
|
1422
|
-
? h(
|
|
1427
|
+
? h("span", { className: "rstr-row-here" }, t("catalog.here"))
|
|
1423
1428
|
: null,
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1429
|
+
// 本机组里每行再写一次「本机」是废话:所在的分组头已经说了。
|
|
1430
|
+
entry.scope === "local"
|
|
1431
|
+
? null
|
|
1432
|
+
: h(
|
|
1433
|
+
"span",
|
|
1434
|
+
{ className: "rstr-stat" },
|
|
1435
|
+
t("catalog.remoteFrom", { collection: entry.collectionTitle ?? entry.collectionId ?? "" }),
|
|
1436
|
+
),
|
|
1431
1437
|
),
|
|
1432
1438
|
h(
|
|
1433
1439
|
"div",
|
|
@@ -1439,7 +1445,8 @@ window.__ModuleLoader__.load({
|
|
|
1439
1445
|
className: "rstr-btn rstr-btn-sm",
|
|
1440
1446
|
disabled: busy,
|
|
1441
1447
|
onClick: async () => {
|
|
1442
|
-
|
|
1448
|
+
// 已经在本机的那份,按钮就该是「打开」——不能让人去拉一份自己已经有的。
|
|
1449
|
+
if (entry.scope === "local" || installed.has(entry.rosterId)) {
|
|
1443
1450
|
onOpen(entry.rosterId);
|
|
1444
1451
|
return;
|
|
1445
1452
|
}
|
|
@@ -1452,7 +1459,7 @@ window.__ModuleLoader__.load({
|
|
|
1452
1459
|
}
|
|
1453
1460
|
},
|
|
1454
1461
|
},
|
|
1455
|
-
entry.scope === "local" ? t("catalog.open") : t("catalog.pull"),
|
|
1462
|
+
entry.scope === "local" || installed.has(entry.rosterId) ? t("catalog.open") : t("catalog.pull"),
|
|
1456
1463
|
),
|
|
1457
1464
|
),
|
|
1458
1465
|
),
|
|
@@ -1549,14 +1556,22 @@ window.__ModuleLoader__.load({
|
|
|
1549
1556
|
: groups.map((group) =>
|
|
1550
1557
|
h(
|
|
1551
1558
|
"div",
|
|
1552
|
-
{ key: group.key, className: "rstr-
|
|
1553
|
-
mode === "flat"
|
|
1559
|
+
{ key: group.key, className: "rstr-space" },
|
|
1560
|
+
mode === "flat"
|
|
1554
1561
|
? null
|
|
1555
1562
|
: h(
|
|
1556
1563
|
"div",
|
|
1557
|
-
{ className: "rstr-
|
|
1558
|
-
h("
|
|
1559
|
-
h("span", { className: "rstr-
|
|
1564
|
+
{ className: "rstr-space-head" },
|
|
1565
|
+
h("code", { className: "rstr-space-id", title: group.id }, group.id),
|
|
1566
|
+
h("span", { className: "rstr-space-title" }, group.title),
|
|
1567
|
+
h(
|
|
1568
|
+
"span",
|
|
1569
|
+
{ className: "rstr-space-facts" },
|
|
1570
|
+
t("catalog.facts", {
|
|
1571
|
+
count: String(group.entries.length),
|
|
1572
|
+
installed: String(group.installed),
|
|
1573
|
+
}),
|
|
1574
|
+
),
|
|
1560
1575
|
group.scope === "remote" && typeof onPullSpace === "function"
|
|
1561
1576
|
? h(
|
|
1562
1577
|
"button",
|
|
@@ -2735,13 +2750,37 @@ window.__ModuleLoader__.load({
|
|
|
2735
2750
|
}
|
|
2736
2751
|
.rstr-catalog .rstr-search { max-width: 560px; }
|
|
2737
2752
|
|
|
2738
|
-
.rstr-
|
|
2753
|
+
.rstr-space { display: flex; flex-direction: column; min-width: 0; }
|
|
2754
|
+
.rstr-space + .rstr-space { margin-top: 24px; }
|
|
2755
|
+
.rstr-space-head {
|
|
2756
|
+
display: grid;
|
|
2757
|
+
grid-template-columns: minmax(110px, 176px) minmax(0, 1fr) auto auto;
|
|
2758
|
+
align-items: baseline;
|
|
2759
|
+
gap: 8px 16px;
|
|
2760
|
+
padding: 16px 8px 6px 0;
|
|
2761
|
+
border-bottom: 1px solid var(--dsw-alias-border-l2);
|
|
2762
|
+
min-width: 0;
|
|
2763
|
+
}
|
|
2764
|
+
.rstr-space-id {
|
|
2765
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
2766
|
+
font-size: 13px;
|
|
2767
|
+
font-weight: 600;
|
|
2768
|
+
color: var(--dsw-alias-label-primary);
|
|
2769
|
+
overflow: hidden;
|
|
2770
|
+
text-overflow: ellipsis;
|
|
2771
|
+
white-space: nowrap;
|
|
2772
|
+
}
|
|
2773
|
+
.rstr-space-title { font-size: 13px; color: var(--dsw-alias-label-secondary); min-width: 0; }
|
|
2774
|
+
.rstr-space-facts {
|
|
2775
|
+
font-size: 11px;
|
|
2776
|
+
color: var(--dsw-alias-label-tertiary);
|
|
2777
|
+
font-variant-numeric: tabular-nums;
|
|
2778
|
+
white-space: nowrap;
|
|
2779
|
+
}
|
|
2780
|
+
.rstr-row-here { font-size: 11px; color: var(--dsw-alias-label-tertiary); }
|
|
2739
2781
|
|
|
2740
|
-
.rstr-group-head { display: flex; align-items: baseline; gap: 8px; padding: 10px 0 4px; border-bottom: 1px solid var(--dsw-alias-border-l2); }
|
|
2741
2782
|
|
|
2742
|
-
.rstr-group-title { font-size: 12px; font-weight: 600; letter-spacing: 0.02em; color: var(--dsw-alias-label-secondary); }
|
|
2743
2783
|
|
|
2744
|
-
.rstr-group-count { font-size: 11px; color: var(--dsw-alias-label-tertiary); font-variant-numeric: tabular-nums; }
|
|
2745
2784
|
|
|
2746
2785
|
.rstr-results { display: flex; flex-direction: column; min-width: 0; padding: 0 28px 28px; border-top: 1px solid var(--dsw-alias-border-l2); }
|
|
2747
2786
|
|
|
@@ -3080,6 +3119,16 @@ window.__ModuleLoader__.load({
|
|
|
3080
3119
|
.rstr-tag { border-left: none; border-bottom: 2px solid transparent; border-radius: 0; white-space: nowrap; }
|
|
3081
3120
|
.rstr-tag-on { border-left: none; border-bottom-color: var(--dsw-alias-state-business-primary); background: transparent; }
|
|
3082
3121
|
.rstr-tag-clear { margin-top: 0; flex: 0 0 auto; }
|
|
3122
|
+
/* 空间头:窄屏由一列 id/标题/事实/按钮的四列网格折成两行 */
|
|
3123
|
+
.rstr-space-head {
|
|
3124
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
3125
|
+
row-gap: 2px;
|
|
3126
|
+
padding-top: 14px;
|
|
3127
|
+
}
|
|
3128
|
+
.rstr-space-id { grid-area: 1 / 1; }
|
|
3129
|
+
.rstr-space-head > .rstr-btn { grid-area: 1 / 2; }
|
|
3130
|
+
.rstr-space-title { grid-area: 2 / 1; }
|
|
3131
|
+
.rstr-space-facts { grid-area: 2 / 2; text-align: right; }
|
|
3083
3132
|
.rstr-row-body { grid-template-columns: minmax(0, 1fr) auto; }
|
|
3084
3133
|
.rstr-row-id { grid-column: 1; }
|
|
3085
3134
|
.rstr-row-text { grid-column: 1; }
|
package/locale/en.json
CHANGED
|
@@ -320,6 +320,8 @@
|
|
|
320
320
|
"refresh": "Refresh",
|
|
321
321
|
"installed": "Installed",
|
|
322
322
|
"pullSpace": "Pull whole space",
|
|
323
|
-
"pulledSpace": "Space pulled: {files} files written, {skipped} skipped"
|
|
323
|
+
"pulledSpace": "Space pulled: {files} files written, {skipped} skipped",
|
|
324
|
+
"facts": "{count} rosters · {installed} here",
|
|
325
|
+
"here": "Already here"
|
|
324
326
|
}
|
|
325
327
|
}
|
package/locale/zh.json
CHANGED
|
@@ -320,6 +320,8 @@
|
|
|
320
320
|
"refresh": "刷新",
|
|
321
321
|
"installed": "已安装",
|
|
322
322
|
"pullSpace": "拉取整个空间",
|
|
323
|
-
"pulledSpace": "空间已拉取:写入 {files} 个文件,跳过 {skipped} 个"
|
|
323
|
+
"pulledSpace": "空间已拉取:写入 {files} 个文件,跳过 {skipped} 个",
|
|
324
|
+
"facts": "{count} 份 · 已装 {installed}",
|
|
325
|
+
"here": "已在本机"
|
|
324
326
|
}
|
|
325
327
|
}
|
package/package.json
CHANGED