dsh-group-status 0.2.2 → 0.3.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 +53 -0
- package/README.en.md +36 -18
- package/README.md +39 -19
- package/lib/client.js +659 -300
- package/lib/client.js.map +1 -1
- package/lib/index.js +22 -9
- package/lib/types/client/BadgeSettingsCard.d.ts +24 -0
- package/lib/types/client/BadgeSettingsCard.d.ts.map +1 -0
- package/lib/types/client/BadgeSettingsCard.js +73 -0
- package/lib/types/client/BadgeSettingsCard.js.map +1 -0
- package/lib/types/client/badge-field.d.ts +44 -0
- package/lib/types/client/badge-field.d.ts.map +1 -0
- package/lib/types/client/badge-field.js +77 -0
- package/lib/types/client/badge-field.js.map +1 -0
- package/lib/types/client/badge-labels.d.ts +92 -0
- package/lib/types/client/badge-labels.d.ts.map +1 -0
- package/lib/types/client/badge-labels.js +150 -0
- package/lib/types/client/badge-labels.js.map +1 -0
- package/lib/types/client/badge-settings.d.ts +31 -3
- package/lib/types/client/badge-settings.d.ts.map +1 -1
- package/lib/types/client/badge-settings.js +50 -6
- package/lib/types/client/badge-settings.js.map +1 -1
- package/lib/types/client/facet-store.d.ts +46 -0
- package/lib/types/client/facet-store.d.ts.map +1 -0
- package/lib/types/client/facet-store.js +123 -0
- package/lib/types/client/facet-store.js.map +1 -0
- package/lib/types/client/facet-visibility.d.ts +17 -0
- package/lib/types/client/facet-visibility.d.ts.map +1 -0
- package/lib/types/client/facet-visibility.js +18 -0
- package/lib/types/client/facet-visibility.js.map +1 -0
- package/lib/types/client/facets.d.ts +265 -0
- package/lib/types/client/facets.d.ts.map +1 -0
- package/lib/types/client/facets.js +209 -0
- package/lib/types/client/facets.js.map +1 -0
- package/lib/types/client/group-status.d.ts +97 -45
- package/lib/types/client/group-status.d.ts.map +1 -1
- package/lib/types/client/group-status.js +148 -85
- package/lib/types/client/group-status.js.map +1 -1
- package/lib/types/client/index.d.ts +25 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +59 -1
- package/lib/types/client/index.js.map +1 -1
- package/lib/types/client/legacy/bridge.d.ts +30 -0
- package/lib/types/client/legacy/bridge.d.ts.map +1 -0
- package/lib/types/client/legacy/bridge.js +58 -0
- package/lib/types/client/legacy/bridge.js.map +1 -0
- package/lib/types/client/legacy/register-legacy-facets.d.ts +14 -0
- package/lib/types/client/legacy/register-legacy-facets.d.ts.map +1 -0
- package/lib/types/client/legacy/register-legacy-facets.js +77 -0
- package/lib/types/client/legacy/register-legacy-facets.js.map +1 -0
- package/lib/types/client/legacy/schedule.d.ts +49 -0
- package/lib/types/client/legacy/schedule.d.ts.map +1 -0
- package/lib/types/client/legacy/schedule.js +73 -0
- package/lib/types/client/legacy/schedule.js.map +1 -0
- package/lib/types/client/legacy/store-source.d.ts +78 -0
- package/lib/types/client/legacy/store-source.d.ts.map +1 -0
- package/lib/types/client/legacy/store-source.js +82 -0
- package/lib/types/client/legacy/store-source.js.map +1 -0
- package/lib/types/client/legacy/waiting-review.d.ts +85 -0
- package/lib/types/client/legacy/waiting-review.d.ts.map +1 -0
- package/lib/types/client/legacy/waiting-review.js +179 -0
- package/lib/types/client/legacy/waiting-review.js.map +1 -0
- package/lib/types/client/locales.d.ts +46 -4
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +46 -4
- package/lib/types/client/locales.js.map +1 -1
- package/lib/types/client/rows/GroupBadge.d.ts +19 -25
- package/lib/types/client/rows/GroupBadge.d.ts.map +1 -1
- package/lib/types/client/rows/GroupBadge.js +45 -106
- package/lib/types/client/rows/GroupBadge.js.map +1 -1
- package/lib/types/client/rows/Rows.d.ts +7 -3
- package/lib/types/client/rows/Rows.d.ts.map +1 -1
- package/lib/types/client/rows/Rows.js +6 -6
- package/lib/types/client/rows/Rows.js.map +1 -1
- package/lib/types/client/rows/WorkspaceBrowser.d.ts.map +1 -1
- package/lib/types/client/rows/WorkspaceBrowser.js +21 -21
- package/lib/types/client/rows/WorkspaceBrowser.js.map +1 -1
- package/lib/types/client/tree.d.ts +2 -5
- package/lib/types/client/tree.d.ts.map +1 -1
- package/lib/types/client/tree.js +0 -5
- package/lib/types/client/tree.js.map +1 -1
- package/lib/types/index.d.ts +31 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +13 -1
- package/lib/types/index.js.map +1 -1
- package/package.json +1 -5
|
@@ -16,23 +16,67 @@
|
|
|
16
16
|
* 引用——每次都构造新对象会让选择器的 `Object.is` 比较永不成立,触发
|
|
17
17
|
* 「Maximum update depth exceeded」死循环(React #185),折叠行徽标会整块崩掉。
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* 设置面缺席或未就绪时,回落到**默认全部显示**,与 `Config` 各字段的 schema 默认值同源:
|
|
20
|
+
* 读不到配置不是「关掉」。
|
|
21
21
|
*/
|
|
22
22
|
/** Loader 条目 id —— 设置页的寻址键,也是宿主 `describe()` 的 ns。 */
|
|
23
23
|
export const ENTRY_ID = 'dsh-group-status';
|
|
24
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* 一个 facet 是否被设置关掉。
|
|
26
|
+
*
|
|
27
|
+
* - 没有 `settingKey` → 始终参与(缺省是"显示",与其余开关的默认值同源)。
|
|
28
|
+
* - 声明了但不是布尔开关键 → 同样按显示处理:拼错的键不该让一个状态整块消失。
|
|
29
|
+
*/
|
|
30
|
+
export function facetVisibleBySettings(settings, settingKey) {
|
|
31
|
+
if (settingKey === undefined)
|
|
32
|
+
return true;
|
|
33
|
+
const value = settings[settingKey];
|
|
34
|
+
return typeof value === 'boolean' ? value : true;
|
|
35
|
+
}
|
|
36
|
+
/** 默认值:与 `Config` 各字段的 schema 默认同源(全部显示,数字阈值 2 即 count=1 时省略)。 */
|
|
25
37
|
export const DEFAULT_BADGE_SETTINGS = Object.freeze({
|
|
26
38
|
showCompletedInBadge: true,
|
|
39
|
+
showRunningInBadge: true,
|
|
40
|
+
showPendingInBadge: true,
|
|
41
|
+
showScheduledInBadge: true,
|
|
42
|
+
showWaitingReviewInBadge: true,
|
|
43
|
+
showHoverDetails: true,
|
|
44
|
+
countThreshold: 2,
|
|
27
45
|
});
|
|
28
|
-
/**
|
|
46
|
+
/** 两个设置对象是否逐字段相等(用于发布前比较,避免无谓通知)。 */
|
|
47
|
+
function settingsEqual(a, b) {
|
|
48
|
+
return (a.showCompletedInBadge === b.showCompletedInBadge &&
|
|
49
|
+
a.showRunningInBadge === b.showRunningInBadge &&
|
|
50
|
+
a.showPendingInBadge === b.showPendingInBadge &&
|
|
51
|
+
a.showScheduledInBadge === b.showScheduledInBadge &&
|
|
52
|
+
a.showWaitingReviewInBadge === b.showWaitingReviewInBadge &&
|
|
53
|
+
a.showHoverDetails === b.showHoverDetails &&
|
|
54
|
+
a.countThreshold === b.countThreshold);
|
|
55
|
+
}
|
|
56
|
+
/** 从原始快照派生:只有**显式 false** 才隐藏,缺失/非法一律显示(countThreshold 默认 2)。 */
|
|
29
57
|
function resolveFromSnapshot(snap) {
|
|
30
58
|
if (snap === undefined || snap.status !== 'ready')
|
|
31
59
|
return DEFAULT_BADGE_SETTINGS;
|
|
32
60
|
const value = snap.value;
|
|
33
61
|
if (value === undefined || value === null || typeof value !== 'object')
|
|
34
62
|
return DEFAULT_BADGE_SETTINGS;
|
|
35
|
-
|
|
63
|
+
const getBool = (field, def) => {
|
|
64
|
+
const v = value[field];
|
|
65
|
+
return typeof v === 'boolean' ? v : def;
|
|
66
|
+
};
|
|
67
|
+
const getNumber = (field, def) => {
|
|
68
|
+
const v = value[field];
|
|
69
|
+
return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? Math.floor(v) : def;
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
showCompletedInBadge: getBool('showCompletedInBadge', true),
|
|
73
|
+
showRunningInBadge: getBool('showRunningInBadge', true),
|
|
74
|
+
showPendingInBadge: getBool('showPendingInBadge', true),
|
|
75
|
+
showScheduledInBadge: getBool('showScheduledInBadge', true),
|
|
76
|
+
showWaitingReviewInBadge: getBool('showWaitingReviewInBadge', true),
|
|
77
|
+
showHoverDetails: getBool('showHoverDetails', true),
|
|
78
|
+
countThreshold: getNumber('countThreshold', 2),
|
|
79
|
+
};
|
|
36
80
|
}
|
|
37
81
|
/**
|
|
38
82
|
* 建一个恒在、取值稳定的徽标设置源。
|
|
@@ -61,7 +105,7 @@ export function createBadgeSettingsSource() {
|
|
|
61
105
|
seenSet = true;
|
|
62
106
|
const next = resolveFromSnapshot(snapshot);
|
|
63
107
|
// 取值没变就不替换引用、不通知:宿主为无关字段替换快照时不该惊动折叠行。
|
|
64
|
-
if (next
|
|
108
|
+
if (settingsEqual(next, resolved))
|
|
65
109
|
return;
|
|
66
110
|
resolved = next;
|
|
67
111
|
for (const listener of [...listeners])
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"badge-settings.js","sourceRoot":"","sources":["../../../src/client/badge-settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,sDAAsD;AACtD,MAAM,CAAC,MAAM,QAAQ,GAAG,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"badge-settings.js","sourceRoot":"","sources":["../../../src/client/badge-settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* facet 的**消费侧**:把「登记表面 + 每个 facet 自己的外部存储」压成一份 React 可订阅的
|
|
3
|
+
* 单一存储。
|
|
4
|
+
*
|
|
5
|
+
* ## 为什么必须是一个存储,而不是逐个 hook
|
|
6
|
+
*
|
|
7
|
+
* 见 `./facets.ts` 的文件头:hook 数量在同一个组件里必须逐次渲染恒定,而 facet 是运行
|
|
8
|
+
* 时注册/注销的。所以这里只暴露一个**版本号**(数字,引用天然稳定)给
|
|
9
|
+
* `useSyncExternalStore`,实际的快照读取与折叠都发生在渲染期。
|
|
10
|
+
*
|
|
11
|
+
* ## 快照读取为什么放在渲染期
|
|
12
|
+
*
|
|
13
|
+
* `getSnapshot` 必须返回稳定引用,而「每个 facet 的快照」是一个对象图:为它造一个
|
|
14
|
+
* 缓存就需要判定失效,而判定失效又要读快照本身。改成「版本号变 → 重新渲染 → 现读现折」
|
|
15
|
+
* 之后,缓存问题消失,代价是一次 O(facet × 组内会话) 的纯计算,量级与原有实现相同。
|
|
16
|
+
*
|
|
17
|
+
* @module dsh-group-status/client/facet-store
|
|
18
|
+
*/
|
|
19
|
+
import { type FacetRegistry, type RegisteredFacet } from './facets.ts';
|
|
20
|
+
/** {@link createFacetStore} 的产物。 */
|
|
21
|
+
export interface FacetStore {
|
|
22
|
+
/** 订阅「快照可能变了」或「登记面变了」。 */
|
|
23
|
+
subscribe(listener: () => void): () => void;
|
|
24
|
+
/** 单调递增的版本号;引用天然稳定,可直接作为 `useSyncExternalStore` 的快照。 */
|
|
25
|
+
getVersion(): number;
|
|
26
|
+
/** 服务端渲染快照:与 {@link getVersion} 同型,避免 hydration 不一致。 */
|
|
27
|
+
getServerVersion(): number;
|
|
28
|
+
/** 当前登记项(已排序)。 */
|
|
29
|
+
list(): readonly RegisteredFacet[];
|
|
30
|
+
/** 释放所有对 facet 存储的订阅(宿主卸载本插件时调用)。 */
|
|
31
|
+
dispose(): void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 创建 facet 存储。
|
|
35
|
+
*
|
|
36
|
+
* 对登记面做一次订阅,并在登记变化时**重新接线**各 facet 的 `subscribe`:provider 热替换
|
|
37
|
+
* 实现(同 id 再注册)或运行中启用/停用插件,都只会走到这里一次,不会留下野订阅。
|
|
38
|
+
*
|
|
39
|
+
* @param source - 登记表面;缺省用模块级单例,测试传入自建实例以隔离。
|
|
40
|
+
*/
|
|
41
|
+
export declare function createFacetStore(source?: FacetRegistry): FacetStore;
|
|
42
|
+
/** 取(并首次创建)单例存储。 */
|
|
43
|
+
export declare function facetStore(): FacetStore;
|
|
44
|
+
/** 释放单例存储(插件卸载时调用;下次 {@link facetStore} 会重建)。 */
|
|
45
|
+
export declare function disposeFacetStore(): void;
|
|
46
|
+
//# sourceMappingURL=facet-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facet-store.d.ts","sourceRoot":"","sources":["../../../src/client/facet-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAA2B,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AAQ/F,oCAAoC;AACpC,MAAM,WAAW,UAAU;IACzB,0BAA0B;IAC1B,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;IAC3C,wDAAwD;IACxD,UAAU,IAAI,MAAM,CAAA;IACpB,wDAAwD;IACxD,gBAAgB,IAAI,MAAM,CAAA;IAC1B,kBAAkB;IAClB,IAAI,IAAI,SAAS,eAAe,EAAE,CAAA;IAClC,qCAAqC;IACrC,OAAO,IAAI,IAAI,CAAA;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,aAAwB,GAAG,UAAU,CAqE7E;AAWD,oBAAoB;AACpB,wBAAgB,UAAU,IAAI,UAAU,CAGvC;AAED,iDAAiD;AACjD,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* facet 的**消费侧**:把「登记表面 + 每个 facet 自己的外部存储」压成一份 React 可订阅的
|
|
3
|
+
* 单一存储。
|
|
4
|
+
*
|
|
5
|
+
* ## 为什么必须是一个存储,而不是逐个 hook
|
|
6
|
+
*
|
|
7
|
+
* 见 `./facets.ts` 的文件头:hook 数量在同一个组件里必须逐次渲染恒定,而 facet 是运行
|
|
8
|
+
* 时注册/注销的。所以这里只暴露一个**版本号**(数字,引用天然稳定)给
|
|
9
|
+
* `useSyncExternalStore`,实际的快照读取与折叠都发生在渲染期。
|
|
10
|
+
*
|
|
11
|
+
* ## 快照读取为什么放在渲染期
|
|
12
|
+
*
|
|
13
|
+
* `getSnapshot` 必须返回稳定引用,而「每个 facet 的快照」是一个对象图:为它造一个
|
|
14
|
+
* 缓存就需要判定失效,而判定失效又要读快照本身。改成「版本号变 → 重新渲染 → 现读现折」
|
|
15
|
+
* 之后,缓存问题消失,代价是一次 O(facet × 组内会话) 的纯计算,量级与原有实现相同。
|
|
16
|
+
*
|
|
17
|
+
* @module dsh-group-status/client/facet-store
|
|
18
|
+
*/
|
|
19
|
+
import { registry } from "./facets.js";
|
|
20
|
+
/**
|
|
21
|
+
* 创建 facet 存储。
|
|
22
|
+
*
|
|
23
|
+
* 对登记面做一次订阅,并在登记变化时**重新接线**各 facet 的 `subscribe`:provider 热替换
|
|
24
|
+
* 实现(同 id 再注册)或运行中启用/停用插件,都只会走到这里一次,不会留下野订阅。
|
|
25
|
+
*
|
|
26
|
+
* @param source - 登记表面;缺省用模块级单例,测试传入自建实例以隔离。
|
|
27
|
+
*/
|
|
28
|
+
export function createFacetStore(source = registry) {
|
|
29
|
+
const listeners = new Set();
|
|
30
|
+
const links = new Map();
|
|
31
|
+
let version = 0;
|
|
32
|
+
let disposed = false;
|
|
33
|
+
/** 任一来源变化都要让消费方重新渲染,因此统一 bump。 */
|
|
34
|
+
const bump = () => {
|
|
35
|
+
if (disposed)
|
|
36
|
+
return;
|
|
37
|
+
version += 1;
|
|
38
|
+
for (const listener of [...listeners]) {
|
|
39
|
+
try {
|
|
40
|
+
listener();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
/* 单个订阅者异常不影响其余订阅者 */
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
/** 把 links 对齐到当前登记项:新增接线、移除退订、替换重接。 */
|
|
48
|
+
const rewire = () => {
|
|
49
|
+
if (disposed)
|
|
50
|
+
return;
|
|
51
|
+
const current = new Map(source.list().map((entry) => [entry.facet.id, entry.facet]));
|
|
52
|
+
for (const [id, link] of [...links]) {
|
|
53
|
+
if (current.get(id) === link.facet)
|
|
54
|
+
continue;
|
|
55
|
+
try {
|
|
56
|
+
link.unsubscribe();
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
/* 退订失败不影响其它 facet 的接线 */
|
|
60
|
+
}
|
|
61
|
+
links.delete(id);
|
|
62
|
+
}
|
|
63
|
+
for (const [id, facet] of current) {
|
|
64
|
+
if (links.has(id))
|
|
65
|
+
continue;
|
|
66
|
+
links.set(id, { facet, unsubscribe: facet.subscribe(bump) });
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const unsubscribeRegistry = source.subscribe(() => {
|
|
70
|
+
rewire();
|
|
71
|
+
bump();
|
|
72
|
+
});
|
|
73
|
+
rewire();
|
|
74
|
+
return {
|
|
75
|
+
subscribe: (listener) => {
|
|
76
|
+
listeners.add(listener);
|
|
77
|
+
return () => {
|
|
78
|
+
listeners.delete(listener);
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
getVersion: () => version,
|
|
82
|
+
getServerVersion: () => 0,
|
|
83
|
+
list: () => source.list(),
|
|
84
|
+
dispose: () => {
|
|
85
|
+
if (disposed)
|
|
86
|
+
return;
|
|
87
|
+
disposed = true;
|
|
88
|
+
for (const link of links.values()) {
|
|
89
|
+
try {
|
|
90
|
+
link.unsubscribe();
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
/* 释放阶段忽略单个退订异常 */
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
links.clear();
|
|
97
|
+
unsubscribeRegistry();
|
|
98
|
+
listeners.clear();
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 生产用的单例存储:消费侧(`WorkspaceBrowser`)订阅它,
|
|
104
|
+
* `apply` 的 effect 结束时用 {@link disposeFacetStore} 释放全部接线。
|
|
105
|
+
*
|
|
106
|
+
* 单例而非每次渲染新建,是因为它持有**对每个 facet 存储的订阅**;随渲染重建会把
|
|
107
|
+
* provider 的 store 拖进无谓的退订/重订,也让"快照在两个文件夹行之间读数不同"成为可能。
|
|
108
|
+
*/
|
|
109
|
+
let singleton;
|
|
110
|
+
/** 取(并首次创建)单例存储。 */
|
|
111
|
+
export function facetStore() {
|
|
112
|
+
if (singleton === undefined)
|
|
113
|
+
singleton = createFacetStore();
|
|
114
|
+
return singleton;
|
|
115
|
+
}
|
|
116
|
+
/** 释放单例存储(插件卸载时调用;下次 {@link facetStore} 会重建)。 */
|
|
117
|
+
export function disposeFacetStore() {
|
|
118
|
+
if (singleton === undefined)
|
|
119
|
+
return;
|
|
120
|
+
singleton.dispose();
|
|
121
|
+
singleton = undefined;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=facet-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facet-store.js","sourceRoot":"","sources":["../../../src/client/facet-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 按用户设置筛掉不参与折叠的状态来源。
|
|
3
|
+
*
|
|
4
|
+
* 单独成文是因为它属于**徽标自身**的可见性规则,而不是某个来源的适配:来源只在
|
|
5
|
+
* `facet.settingKey` 上声明"我受哪个开关管",开关的语义与过滤时机归本插件。
|
|
6
|
+
*
|
|
7
|
+
* 过滤发生在**折叠之前**而不是渲染阶段:徽标数字、图标、`aria-label`、悬停明细与
|
|
8
|
+
* "要不要画徽标"因此天然同源。放到渲染阶段会出现"label 里有、计数里没有",而那正是
|
|
9
|
+
* 徽标最容易被怀疑撒谎的地方。
|
|
10
|
+
*
|
|
11
|
+
* @module dsh-group-status/client/facet-visibility
|
|
12
|
+
*/
|
|
13
|
+
import { type ResolvedBadgeSettings } from './badge-settings.ts';
|
|
14
|
+
import type { RegisteredFacet } from './facets.ts';
|
|
15
|
+
/** 筛出设置允许显示的登记项;顺序保持登记面的顺序(已按 `order` 排好)。 */
|
|
16
|
+
export declare function visibleFacets(entries: readonly RegisteredFacet[], settings: ResolvedBadgeSettings): RegisteredFacet[];
|
|
17
|
+
//# sourceMappingURL=facet-visibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facet-visibility.d.ts","sourceRoot":"","sources":["../../../src/client/facet-visibility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAA0B,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AACxF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,8CAA8C;AAC9C,wBAAgB,aAAa,CAC3B,OAAO,EAAE,SAAS,eAAe,EAAE,EACnC,QAAQ,EAAE,qBAAqB,GAC9B,eAAe,EAAE,CAEnB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 按用户设置筛掉不参与折叠的状态来源。
|
|
3
|
+
*
|
|
4
|
+
* 单独成文是因为它属于**徽标自身**的可见性规则,而不是某个来源的适配:来源只在
|
|
5
|
+
* `facet.settingKey` 上声明"我受哪个开关管",开关的语义与过滤时机归本插件。
|
|
6
|
+
*
|
|
7
|
+
* 过滤发生在**折叠之前**而不是渲染阶段:徽标数字、图标、`aria-label`、悬停明细与
|
|
8
|
+
* "要不要画徽标"因此天然同源。放到渲染阶段会出现"label 里有、计数里没有",而那正是
|
|
9
|
+
* 徽标最容易被怀疑撒谎的地方。
|
|
10
|
+
*
|
|
11
|
+
* @module dsh-group-status/client/facet-visibility
|
|
12
|
+
*/
|
|
13
|
+
import { facetVisibleBySettings } from "./badge-settings.js";
|
|
14
|
+
/** 筛出设置允许显示的登记项;顺序保持登记面的顺序(已按 `order` 排好)。 */
|
|
15
|
+
export function visibleFacets(entries, settings) {
|
|
16
|
+
return entries.filter(entry => facetVisibleBySettings(settings, entry.facet.settingKey));
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=facet-visibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facet-visibility.js","sourceRoot":"","sources":["../../../src/client/facet-visibility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,sBAAsB,EAA8B,MAAM,qBAAqB,CAAA;AAGxF,8CAA8C;AAC9C,MAAM,UAAU,aAAa,CAC3B,OAAmC,EACnC,QAA+B;IAE/B,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAA;AAC1F,CAAC"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 分组状态 **facet 协议**:本插件对外提供的唯一接入面。
|
|
3
|
+
*
|
|
4
|
+
* ## 为什么是这个方向
|
|
5
|
+
*
|
|
6
|
+
* 折叠分组的徽标要把「组内有没有别的插件的状态」折成一个数字。此前是**本插件逐家
|
|
7
|
+
* 适配**:`require('dsh-later/client')`、`require('dsh-gitea-dispatch/client')`,再把
|
|
8
|
+
* 各家的字段翻成自己的类型。那个方向的代价已经实测过一次:提供方把 `deadline` /
|
|
9
|
+
* `waitMaxSec` / `prNumber` 发出来了,本插件的接收类型只声明了两个字段,于是信息
|
|
10
|
+
* **静默丢失**(编译不报错、运行不报错、测试不报错,见 CHANGELOG 0.2.3「适配只做了一半」)。
|
|
11
|
+
*
|
|
12
|
+
* 现在方向反过来:**状态的所有者把自己的事实注册进来**,本插件只认协议形状。
|
|
13
|
+
* 新增一个状态源,本插件一行都不改。
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* // provider 侧(在自己的 apply 里)
|
|
17
|
+
* const groupStatus = require('dsh-group-status/client')
|
|
18
|
+
* groupStatus?.registerGroupStatusFacet?.({
|
|
19
|
+
* protocol: 1,
|
|
20
|
+
* id: 'my-plugin.review',
|
|
21
|
+
* subscribe: store.subscribe,
|
|
22
|
+
* getSnapshot: store.getSnapshot,
|
|
23
|
+
* fold: (snapshot, sessionIds, now) => ({ count, tone, pulse, data }),
|
|
24
|
+
* merge: (a, b) => ({ ... }),
|
|
25
|
+
* label: (fold, now) => '等待评审(剩 3分钟) · #15',
|
|
26
|
+
* renderIcon: (fold) => h('svg', …),
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* ## 为什么用 `subscribe` / `getSnapshot` 而不是 React hook
|
|
31
|
+
*
|
|
32
|
+
* 上一版让每家导出一个 hook,本插件在同一个组件里 `useXxxHook?.()` 调。两条都不成立:
|
|
33
|
+
*
|
|
34
|
+
* 1. **hook 数量必须逐次渲染恒定**,而 facet 是运行时注册/注销的:注册面一变,同一个
|
|
35
|
+
* 组件的 hook 调用序列就变了,React 直接抛 "Rendered more hooks than during the
|
|
36
|
+
* previous render"。
|
|
37
|
+
* 2. 本插件因此必须知道"有几个 facet、各叫什么"——正是想消掉的那个耦合。
|
|
38
|
+
*
|
|
39
|
+
* `subscribe` / `getSnapshot` 是同一份能力的非 React 形态(宿主
|
|
40
|
+
* `useSyncExternalStore` 的外部存储面),一个通用订阅器就能覆盖任意多个 facet。
|
|
41
|
+
*
|
|
42
|
+
* ## 为什么 `fold` 返回 `data`,而不是返回可渲染文本
|
|
43
|
+
*
|
|
44
|
+
* 多层文件夹要把同一个 facet 在子树各层的折叠结果**再合并**一次。文本合并不了
|
|
45
|
+
* (「剩 3分钟」和「剩 5分钟」拼起来不是答案),结构化 `data` 能合并——合并规则归
|
|
46
|
+
* facet 自己({@link GroupStatusFacet.merge}),渲染时刻再由
|
|
47
|
+
* {@link GroupStatusFacet.label} 现算文案。本插件全程不解释 `data`。
|
|
48
|
+
*
|
|
49
|
+
* ## 兼容性
|
|
50
|
+
*
|
|
51
|
+
* 协议带 `protocol` 版本号。本插件只接受
|
|
52
|
+
* {@link GROUP_STATUS_FACET_PROTOCOL_VERSION} 的 facet,其它版本**拒绝注册**并在
|
|
53
|
+
* console 点名(静默忽略会让"我注册了为什么没显示"变成不可诊断的问题)。
|
|
54
|
+
*
|
|
55
|
+
* @module dsh-group-status/client/facets
|
|
56
|
+
*/
|
|
57
|
+
import type { ReactNode } from 'react';
|
|
58
|
+
/** 本协议文件的协议版本。provider 必须原样填这个常量。 */
|
|
59
|
+
export declare const GROUP_STATUS_FACET_PROTOCOL_VERSION = 1;
|
|
60
|
+
/** 徽标可用的三档语义色(本插件的色板;provider 选档,不选具体颜色)。 */
|
|
61
|
+
export type FacetTone = 'info' | 'warn' | 'error';
|
|
62
|
+
/** tone 之间的优先级(越大越紧急),用于多层合并时取更高档。 */
|
|
63
|
+
export declare const FACET_TONE_RANK: Readonly<Record<FacetTone, number>>;
|
|
64
|
+
/**
|
|
65
|
+
* 一个 facet 在**一组会话**上折出来的事实。
|
|
66
|
+
*
|
|
67
|
+
* 字段是本插件与 provider 之间唯一的运行时契约:`count` 进徽标数字,`tone` 选色,
|
|
68
|
+
* `pulse` 决定要不要脉冲,`data` 归 provider 自用(本插件从不读它)。
|
|
69
|
+
*/
|
|
70
|
+
export interface FacetFold<Data = unknown> {
|
|
71
|
+
/**
|
|
72
|
+
* 贡献给徽标数字的条数。`0` 表示这个来源此刻不参与徽标(本插件会跳过它,
|
|
73
|
+
* 不画图标、不进文案)。
|
|
74
|
+
*/
|
|
75
|
+
count: number;
|
|
76
|
+
/** 语义色档。 */
|
|
77
|
+
tone: FacetTone;
|
|
78
|
+
/** 是否脉冲。紧迫感由状态所有者判定,不由徽标反推。 */
|
|
79
|
+
pulse: boolean;
|
|
80
|
+
/** 合并与文案所需的原始事实,形状由 facet 自定。 */
|
|
81
|
+
data?: Data;
|
|
82
|
+
}
|
|
83
|
+
/** {@link GroupStatusFacet.label} / {@link GroupStatusFacet.renderIcon} 的渲染上下文。 */
|
|
84
|
+
export interface FacetRenderContext {
|
|
85
|
+
/** 渲染时刻(epoch ms)。用于把 `data` 里的截止时刻换算成「还剩多久」。 */
|
|
86
|
+
now: number;
|
|
87
|
+
/**
|
|
88
|
+
* 侧栏行的翻译位(本插件的 `workspace` 命名空间)。
|
|
89
|
+
*
|
|
90
|
+
* ⚠️ 这是**便利项,不是义务**:provider 若有自己的 locale 命名空间,应当闭包自己
|
|
91
|
+
* 的翻译函数、忽略这里。这个字段是为**代管方**(`origin: 'legacy'`)复用本插件的行
|
|
92
|
+
* 文案而存在的;内置适配器已删除(迁移史见 `docs/facet-protocol.md`),字段保留给下一次代管。
|
|
93
|
+
*/
|
|
94
|
+
t: (key: string, options?: Record<string, string | number>) => string;
|
|
95
|
+
}
|
|
96
|
+
/** 一个注册进来的状态源。 */
|
|
97
|
+
export interface GroupStatusFacet<Input = unknown, Data = unknown> {
|
|
98
|
+
/** 必须是 {@link GROUP_STATUS_FACET_PROTOCOL_VERSION}。 */
|
|
99
|
+
readonly protocol: number;
|
|
100
|
+
/**
|
|
101
|
+
* 全局唯一 id,建议 `'<包名>.<状态名>'`(如 `'dsh-gitea-dispatch.waiting-review'`)。
|
|
102
|
+
* 它同时是 React key、重复注册的判据,以及本插件设置项的挂钩键({@link settingKey})。
|
|
103
|
+
*/
|
|
104
|
+
readonly id: string;
|
|
105
|
+
/**
|
|
106
|
+
* 外部存储订阅面(宿主 `useSyncExternalStore` 的第一参数)。
|
|
107
|
+
*
|
|
108
|
+
* 必须在快照可能变化时被调用,并且**允许多个订阅者**;返回退订函数。
|
|
109
|
+
*/
|
|
110
|
+
subscribe(listener: () => void): () => void;
|
|
111
|
+
/** 当前快照;还没拿到数据时返回 `undefined`(本插件会把该 facet 当作无贡献)。 */
|
|
112
|
+
getSnapshot(): Input | undefined;
|
|
113
|
+
/**
|
|
114
|
+
* 把快照折成这一组会话上的事实。
|
|
115
|
+
*
|
|
116
|
+
* 纯函数要求:同样的 `(snapshot, sessionIds, now)` 必须给出等价的折果——
|
|
117
|
+
* 它在每次渲染里被调用,不该有副作用。
|
|
118
|
+
* @param snapshot - {@link getSnapshot} 的结果。
|
|
119
|
+
* @param sessionIds - 组内会话 id(含前缀形态;口径归 provider 判定)。
|
|
120
|
+
* @param now - 本次折叠的时刻(epoch ms)。
|
|
121
|
+
*/
|
|
122
|
+
fold(snapshot: Input | undefined, sessionIds: readonly string[], now: number): FacetFold<Data>;
|
|
123
|
+
/**
|
|
124
|
+
* 合并同一 facet 在子树各层的折果(多层文件夹)。
|
|
125
|
+
*
|
|
126
|
+
* 缺省实现按 `count` 相加、`tone` 取更紧急的一档、`pulse` 取或;facet 若需要
|
|
127
|
+
* 合并自己的 `data`(例如 PR 号并集、最早截止时刻)就必须覆盖它。
|
|
128
|
+
*/
|
|
129
|
+
merge?(a: FacetFold<Data>, b: FacetFold<Data>): FacetFold<Data>;
|
|
130
|
+
/**
|
|
131
|
+
* 徽标 `aria-label` / `title` 与悬停明细里的那句话。
|
|
132
|
+
*
|
|
133
|
+
* 由 provider 自己本地化(用它自己的 locale 命名空间);本插件不参与措辞。
|
|
134
|
+
* 返回空串视为「这个 facet 没有可显示文案」,只保留数字贡献。
|
|
135
|
+
*/
|
|
136
|
+
label?(fold: FacetFold<Data>, context: FacetRenderContext): string;
|
|
137
|
+
/**
|
|
138
|
+
* 图标。provider 交出**已含配色**的 React 元素(它最懂自己的状态该怎么画,
|
|
139
|
+
* 包括"超时该静止还是该闪"这类视觉语义)。
|
|
140
|
+
*
|
|
141
|
+
* 不提供时,本插件退回一个按 `tone` 取色的通用点。
|
|
142
|
+
*/
|
|
143
|
+
renderIcon?(fold: FacetFold<Data>, context: FacetRenderContext): ReactNode;
|
|
144
|
+
/**
|
|
145
|
+
* 受本插件哪个设置项开关控制(如 `'showWaitingReviewInBadge'`)。
|
|
146
|
+
*
|
|
147
|
+
* 省略 = 不受开关控制,始终参与。开关的**语义**(关掉意味着什么)由本插件判定,
|
|
148
|
+
* provider 只声明挂钩键。
|
|
149
|
+
*/
|
|
150
|
+
settingKey?: string;
|
|
151
|
+
/**
|
|
152
|
+
* 渲染顺序(升序)。**缺省排在所有声明过 `order` 的来源之后**,彼此按注册先后,
|
|
153
|
+
* 这样新接入的陌生来源不会插到既有状态前面抢视觉位置。
|
|
154
|
+
*/
|
|
155
|
+
order?: number;
|
|
156
|
+
/**
|
|
157
|
+
* 来源标记。**provider 不用填**(缺省即 `provider`)。
|
|
158
|
+
*
|
|
159
|
+
* 代管某个来源的一方显式写 `'legacy'`,用它声明「我是在替状态所有者代管」,从而在
|
|
160
|
+
* 对方接入同名 facet 时自动让位。本插件目前不代管任何来源,这条规则为**下一次**迁移
|
|
161
|
+
* 保留。见 {@link FACET_ORIGIN_RANK}。
|
|
162
|
+
*/
|
|
163
|
+
origin?: FacetOrigin;
|
|
164
|
+
}
|
|
165
|
+
/** 协议来源:`provider` = 状态所有者自己注册;`legacy` = 替状态所有者代管的注册方(本插件目前不代管任何来源)。 */
|
|
166
|
+
export type FacetOrigin = 'provider' | 'legacy';
|
|
167
|
+
/**
|
|
168
|
+
* 同 id 冲突时**由来源决胜,与注册顺序无关**。
|
|
169
|
+
*
|
|
170
|
+
* 宿主不保证插件 apply 的先后。过渡期内"本插件代 provider 写的适配器"与"provider
|
|
171
|
+
* 自己注册的 facet"会撞同一个 id:若靠顺序决胜,同一份部署今天显示、明天不显示。
|
|
172
|
+
* `provider` 恒胜 `legacy`:所有者一接入,代管方立刻让位,且不重复计数。迁移因此
|
|
173
|
+
* 不需要协商发布顺序。
|
|
174
|
+
*/
|
|
175
|
+
export declare const FACET_ORIGIN_RANK: Readonly<Record<FacetOrigin, number>>;
|
|
176
|
+
/** 一个 facet 的来源;缺省按 `provider`(最保守的假设:别人主动注册就是所有者)。 */
|
|
177
|
+
export declare function facetOrigin(facet: {
|
|
178
|
+
readonly origin?: FacetOrigin;
|
|
179
|
+
}): FacetOrigin;
|
|
180
|
+
/** 任意来源的 facet / 折果:聚合与渲染侧使用的**非泛型**形态。
|
|
181
|
+
*
|
|
182
|
+
* 协议对 provider 是泛型的(它能拿到自己的 `data` 类型),但登记面、折果表、渲染层
|
|
183
|
+
* 都不关心 `data` 是什么,所以内部一律用这两个别名。方法用**方法语法**声明,于是
|
|
184
|
+
* 具体 facet 的 `fold` / `merge` 在这些位置上是可赋值的(双变),不需要 `as never`。
|
|
185
|
+
*/
|
|
186
|
+
export type AnyFacet = GroupStatusFacet<unknown, unknown>;
|
|
187
|
+
export type AnyFacetFold = FacetFold<unknown>;
|
|
188
|
+
/** 一个已登记 facet 及其排序位。 */
|
|
189
|
+
export interface RegisteredFacet {
|
|
190
|
+
facet: AnyFacet;
|
|
191
|
+
/** 注册序号,作为 `order` 相同时的稳定 tie-break。 */
|
|
192
|
+
sequence: number;
|
|
193
|
+
}
|
|
194
|
+
/** {@link registerGroupStatusFacet} 的失败原因。 */
|
|
195
|
+
export type FacetRejection = 'not-an-object' | 'protocol-mismatch' | 'missing-id' | 'missing-methods'
|
|
196
|
+
/** 同 id 上已有更高来源的登记(过渡期适配器被状态所有者顶掉) */
|
|
197
|
+
| 'superseded';
|
|
198
|
+
/** 注册结果:成功带 `id`,失败带原因(且**不**静默丢弃)。 */
|
|
199
|
+
export type FacetRegistration = {
|
|
200
|
+
ok: true;
|
|
201
|
+
id: string;
|
|
202
|
+
} | {
|
|
203
|
+
ok: false;
|
|
204
|
+
id: string;
|
|
205
|
+
reason: FacetRejection;
|
|
206
|
+
};
|
|
207
|
+
/** 退订/注销函数。 */
|
|
208
|
+
export type Unregister = () => void;
|
|
209
|
+
/**
|
|
210
|
+
* 检查一个 facet 是否符合协议 v1。
|
|
211
|
+
* @returns 拒绝原因;`undefined` 表示可用。
|
|
212
|
+
*/
|
|
213
|
+
export declare function facetRejection(facet: unknown): FacetRejection | undefined;
|
|
214
|
+
/**
|
|
215
|
+
* 缺省折果合并:数量相加、色档取更紧急的一档、脉冲取或。
|
|
216
|
+
*
|
|
217
|
+
* ⚠️ 它**不**合并 `data`(本插件不知道 `data` 是什么)。需要合并原始事实的 facet
|
|
218
|
+
* 必须自己实现 {@link GroupStatusFacet.merge}。
|
|
219
|
+
*/
|
|
220
|
+
export declare function defaultMergeFold(a: AnyFacetFold, b: AnyFacetFold): AnyFacetFold;
|
|
221
|
+
/**
|
|
222
|
+
* 登记表面:一个可订阅的 facet 列表。
|
|
223
|
+
*
|
|
224
|
+
* 用闭包工厂里的**模块级单例**,于是 provider 与本插件拿到的是同一张表:模块表行
|
|
225
|
+
* 只在首次 `require` 时 materialize,之后所有调用方共享同一实例。
|
|
226
|
+
*/
|
|
227
|
+
export interface FacetRegistry {
|
|
228
|
+
/**
|
|
229
|
+
* 登记一个 facet。
|
|
230
|
+
*
|
|
231
|
+
* 同 id 已存在时按**来源**决胜({@link FACET_ORIGIN_RANK}):更高来源保持原位,
|
|
232
|
+
* 同来源或更高者覆盖。返回失败而不静默丢弃,调用方能在 console 里查到原因。
|
|
233
|
+
*/
|
|
234
|
+
register(facet: AnyFacet): FacetRegistration;
|
|
235
|
+
/**
|
|
236
|
+
* 摘掉一个登记项。
|
|
237
|
+
*
|
|
238
|
+
* 给了 `facet` 时只摘"**当前登记的还是它**"的那一份:同 id 已被后来的实现替换后,
|
|
239
|
+
* 旧 provider 的 dispose 不该把新登记摘掉。
|
|
240
|
+
* @returns 是否真的摘掉了。
|
|
241
|
+
*/
|
|
242
|
+
remove(id: string, facet?: AnyFacet): boolean;
|
|
243
|
+
/** 当前登记项,按 `order` 再按注册先后排序。 */
|
|
244
|
+
list(): readonly RegisteredFacet[];
|
|
245
|
+
/** 订阅登记面变化(注册/注销时触发)。 */
|
|
246
|
+
subscribe(listener: () => void): () => void;
|
|
247
|
+
}
|
|
248
|
+
/** 创建一张登记表面(测试用;生产走模块级单例 {@link registry})。 */
|
|
249
|
+
export declare function createFacetRegistry(): FacetRegistry;
|
|
250
|
+
/**
|
|
251
|
+
* 生产用的模块级单例登记表面。
|
|
252
|
+
*
|
|
253
|
+
* 与 {@link createFacetRegistry} 分开,是为了让测试能对着一张干净的表断言协议行为,
|
|
254
|
+
* 而不会被别的用例或别的插件登记的 facet 污染。
|
|
255
|
+
*/
|
|
256
|
+
export declare const registry: FacetRegistry;
|
|
257
|
+
/**
|
|
258
|
+
* 本插件 client 入口对外的登记函数(provider 侧唯一需要认识的符号)。
|
|
259
|
+
*
|
|
260
|
+
* @param facet - 待登记的 facet。
|
|
261
|
+
* @returns 注销函数;**注册失败时返回一个空操作**,同时把原因写进 console——
|
|
262
|
+
* 返回值形状保持稳定,provider 的 dispose 路径不必区分成败。
|
|
263
|
+
*/
|
|
264
|
+
export declare function registerGroupStatusFacet(facet: AnyFacet): Unregister;
|
|
265
|
+
//# sourceMappingURL=facets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facets.d.ts","sourceRoot":"","sources":["../../../src/client/facets.ts"],"names":[],"mappings":"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"}
|