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
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/** 本协议文件的协议版本。provider 必须原样填这个常量。 */
|
|
2
|
+
export const GROUP_STATUS_FACET_PROTOCOL_VERSION = 1;
|
|
3
|
+
/** tone 之间的优先级(越大越紧急),用于多层合并时取更高档。 */
|
|
4
|
+
export const FACET_TONE_RANK = Object.freeze({
|
|
5
|
+
info: 0, warn: 1, error: 2,
|
|
6
|
+
});
|
|
7
|
+
/**
|
|
8
|
+
* 同 id 冲突时**由来源决胜,与注册顺序无关**。
|
|
9
|
+
*
|
|
10
|
+
* 宿主不保证插件 apply 的先后。过渡期内"本插件代 provider 写的适配器"与"provider
|
|
11
|
+
* 自己注册的 facet"会撞同一个 id:若靠顺序决胜,同一份部署今天显示、明天不显示。
|
|
12
|
+
* `provider` 恒胜 `legacy`:所有者一接入,代管方立刻让位,且不重复计数。迁移因此
|
|
13
|
+
* 不需要协商发布顺序。
|
|
14
|
+
*/
|
|
15
|
+
export const FACET_ORIGIN_RANK = Object.freeze({
|
|
16
|
+
legacy: 0, provider: 1,
|
|
17
|
+
});
|
|
18
|
+
/** 一个 facet 的来源;缺省按 `provider`(最保守的假设:别人主动注册就是所有者)。 */
|
|
19
|
+
export function facetOrigin(facet) {
|
|
20
|
+
return facet.origin === 'legacy' ? 'legacy' : 'provider';
|
|
21
|
+
}
|
|
22
|
+
// #25③:此处原有 `const TONE_ORDER = ['info','warn','error']`,与对外导出的
|
|
23
|
+
// `FACET_TONE_RANK` 是同一个事实的两份实现,且只有 `defaultMergeFold` 一个使用者。
|
|
24
|
+
// 现已统一到 `FACET_TONE_RANK`(见该函数),私有那份删除。
|
|
25
|
+
/**
|
|
26
|
+
* 检查一个 facet 是否符合协议 v1。
|
|
27
|
+
* @returns 拒绝原因;`undefined` 表示可用。
|
|
28
|
+
*/
|
|
29
|
+
export function facetRejection(facet) {
|
|
30
|
+
if (typeof facet !== 'object' || facet === null)
|
|
31
|
+
return 'not-an-object';
|
|
32
|
+
const candidate = facet;
|
|
33
|
+
if (candidate.protocol !== GROUP_STATUS_FACET_PROTOCOL_VERSION)
|
|
34
|
+
return 'protocol-mismatch';
|
|
35
|
+
if (typeof candidate.id !== 'string' || candidate.id === '')
|
|
36
|
+
return 'missing-id';
|
|
37
|
+
if (typeof candidate.subscribe !== 'function'
|
|
38
|
+
|| typeof candidate.getSnapshot !== 'function'
|
|
39
|
+
|| typeof candidate.fold !== 'function')
|
|
40
|
+
return 'missing-methods';
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 缺省折果合并:数量相加、色档取更紧急的一档、脉冲取或。
|
|
45
|
+
*
|
|
46
|
+
* ⚠️ 它**不**合并 `data`(本插件不知道 `data` 是什么)。需要合并原始事实的 facet
|
|
47
|
+
* 必须自己实现 {@link GroupStatusFacet.merge}。
|
|
48
|
+
*/
|
|
49
|
+
export function defaultMergeFold(a, b) {
|
|
50
|
+
// #25③:读对外导出的 `FACET_TONE_RANK`,不再另持一份私有 `TONE_ORDER`。两份表的顺序
|
|
51
|
+
// 逐项相同(`{info:0,warn:1,error:2}` 与 `['info','warn','error']` 的下标一致),所以对
|
|
52
|
+
// 合法色档这是**零行为变更**;收口的是「同一个事实两份实现」本身。
|
|
53
|
+
//
|
|
54
|
+
// ⚠️ `?? -1` **不是防御性冗余,是负载性的,别顺手删**。`facetRejection` 只校验
|
|
55
|
+
// protocol / id / 三个方法,**不校验 `fold()` 返回的 `tone`** —— 那是跨插件边界,坏
|
|
56
|
+
// provider 交回一个非法档位是真能到达这里的。旧的 `TONE_ORDER.indexOf(非法值)` 得到
|
|
57
|
+
// `-1`,于是另一侧的合法档位必胜(`2 > -1`);而 `FACET_TONE_RANK[非法值]` 得到
|
|
58
|
+
// `undefined`,任何比较都是 `false`,非法档位就会被**传播出去**。少了这个 `?? -1`,
|
|
59
|
+
// 本次重构会在坏输入下静默改变结果。
|
|
60
|
+
const toneA = FACET_TONE_RANK[a.tone] ?? -1;
|
|
61
|
+
const toneB = FACET_TONE_RANK[b.tone] ?? -1;
|
|
62
|
+
return {
|
|
63
|
+
count: a.count + b.count,
|
|
64
|
+
tone: toneB > toneA ? b.tone : a.tone,
|
|
65
|
+
pulse: a.pulse || b.pulse,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** 创建一张登记表面(测试用;生产走模块级单例 {@link registry})。 */
|
|
69
|
+
export function createFacetRegistry() {
|
|
70
|
+
const entries = new Map();
|
|
71
|
+
const listeners = new Set();
|
|
72
|
+
let sequence = 0;
|
|
73
|
+
let sorted = [];
|
|
74
|
+
const resort = () => {
|
|
75
|
+
sorted = [...entries.values()].sort((x, y) => {
|
|
76
|
+
// 排序键 = (有没有声明 order, order, 注册序号)。
|
|
77
|
+
// 没声明 order 的来源一律排在**所有声明过的之后**,彼此按注册先后:陌生新来者
|
|
78
|
+
// 不该插到既有状态前面抢视觉位置,而两两之间又没有可比的新排序键。
|
|
79
|
+
const declaredX = x.facet.order !== undefined;
|
|
80
|
+
const declaredY = y.facet.order !== undefined;
|
|
81
|
+
if (declaredX !== declaredY)
|
|
82
|
+
return declaredX ? -1 : 1;
|
|
83
|
+
if (declaredX && declaredY)
|
|
84
|
+
return x.facet.order - y.facet.order;
|
|
85
|
+
return x.sequence - y.sequence;
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
let notifying = false;
|
|
89
|
+
let pending = false;
|
|
90
|
+
/**
|
|
91
|
+
* 通知订阅者,并把**重入合并成一轮补跑**。
|
|
92
|
+
*
|
|
93
|
+
* 订阅者在自己的回调里登记/注销 facet 是完全合法的(消费方常在收到变更后立即
|
|
94
|
+
* 补登记一个派生来源)。直接递归会有两个问题:嵌套深度由订阅者数量决定(两个互相
|
|
95
|
+
* 触发的订阅者就是无界递归),而且中间那轮通知看到的登记面是**改到一半**的。
|
|
96
|
+
* 所以内层调用只置脏标志,外层跑完一轮后再补一轮,直到没有新的改动 —— 每个订阅者
|
|
97
|
+
* 都看得到最终状态,递归深度恒为 1。
|
|
98
|
+
*/
|
|
99
|
+
const notify = () => {
|
|
100
|
+
if (notifying) {
|
|
101
|
+
pending = true;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
notifying = true;
|
|
105
|
+
try {
|
|
106
|
+
do {
|
|
107
|
+
pending = false;
|
|
108
|
+
// 复制一份再遍历:订阅者可能在回调里退订自己。
|
|
109
|
+
for (const listener of [...listeners]) {
|
|
110
|
+
try {
|
|
111
|
+
listener();
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
/* 单个订阅者异常不影响其余订阅者 */
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} while (pending);
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
notifying = false;
|
|
121
|
+
pending = false;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
register: (facet) => {
|
|
126
|
+
const reason = facetRejection(facet);
|
|
127
|
+
const id = typeof facet?.id === 'string' ? facet.id : '';
|
|
128
|
+
if (reason !== undefined)
|
|
129
|
+
return { ok: false, id, reason };
|
|
130
|
+
const existing = entries.get(id);
|
|
131
|
+
const nextRank = FACET_ORIGIN_RANK[facetOrigin(facet)];
|
|
132
|
+
if (existing !== undefined && FACET_ORIGIN_RANK[facetOrigin(existing.facet)] > nextRank) {
|
|
133
|
+
// 同 id 上站着更高来源的登记(状态所有者已经自己接入),低的一边让位。
|
|
134
|
+
return { ok: false, id, reason: 'superseded' };
|
|
135
|
+
}
|
|
136
|
+
sequence += 1;
|
|
137
|
+
// 同来源重复登记直接覆盖:provider 热替换实现不必先注销再登记。
|
|
138
|
+
entries.set(id, { facet, sequence });
|
|
139
|
+
resort();
|
|
140
|
+
notify();
|
|
141
|
+
return { ok: true, id };
|
|
142
|
+
},
|
|
143
|
+
remove: (id, facet) => {
|
|
144
|
+
const current = entries.get(id);
|
|
145
|
+
if (current === undefined)
|
|
146
|
+
return false;
|
|
147
|
+
if (facet !== undefined && current.facet !== facet)
|
|
148
|
+
return false;
|
|
149
|
+
entries.delete(id);
|
|
150
|
+
resort();
|
|
151
|
+
notify();
|
|
152
|
+
return true;
|
|
153
|
+
},
|
|
154
|
+
list: () => sorted,
|
|
155
|
+
subscribe: (listener) => {
|
|
156
|
+
listeners.add(listener);
|
|
157
|
+
return () => {
|
|
158
|
+
listeners.delete(listener);
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 生产用的模块级单例登记表面。
|
|
165
|
+
*
|
|
166
|
+
* 与 {@link createFacetRegistry} 分开,是为了让测试能对着一张干净的表断言协议行为,
|
|
167
|
+
* 而不会被别的用例或别的插件登记的 facet 污染。
|
|
168
|
+
*/
|
|
169
|
+
export const registry = createFacetRegistry();
|
|
170
|
+
/**
|
|
171
|
+
* 本插件 client 入口对外的登记函数(provider 侧唯一需要认识的符号)。
|
|
172
|
+
*
|
|
173
|
+
* @param facet - 待登记的 facet。
|
|
174
|
+
* @returns 注销函数;**注册失败时返回一个空操作**,同时把原因写进 console——
|
|
175
|
+
* 返回值形状保持稳定,provider 的 dispose 路径不必区分成败。
|
|
176
|
+
*/
|
|
177
|
+
export function registerGroupStatusFacet(facet) {
|
|
178
|
+
const result = registry.register(facet);
|
|
179
|
+
if (!result.ok) {
|
|
180
|
+
// 过渡期适配器被状态所有者顶掉是**预期结果**,不是错误:报一条 warn 会让人以为
|
|
181
|
+
// 徽标坏了。除此之外的每一次失败都必须可见,否则"注册了却没显示"无从诊断。
|
|
182
|
+
if (!(result.reason === 'superseded' && facetOrigin(facet) === 'legacy'))
|
|
183
|
+
reportRejection(result);
|
|
184
|
+
return () => undefined;
|
|
185
|
+
}
|
|
186
|
+
// 只摘"还是自己"的那一份:同 id 已被后来的实现替换时,旧 dispose 不该动新登记。
|
|
187
|
+
return () => {
|
|
188
|
+
registry.remove(result.id, facet);
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 把注册失败写成一条可诊断的日志。
|
|
193
|
+
*
|
|
194
|
+
* 刻意不抛错:状态显示是增强功能,一个插件协议填错不该把宿主界面渲染打断;
|
|
195
|
+
* 但也不静默——"注册了却没显示"必须能查出原因。
|
|
196
|
+
*/
|
|
197
|
+
function reportRejection(rejection) {
|
|
198
|
+
const detail = rejection.reason === 'protocol-mismatch'
|
|
199
|
+
? `本插件只接受 protocol: ${GROUP_STATUS_FACET_PROTOCOL_VERSION}`
|
|
200
|
+
: rejection.reason === 'missing-methods'
|
|
201
|
+
? 'subscribe / getSnapshot / fold 三个方法必须齐备'
|
|
202
|
+
: rejection.reason === 'missing-id'
|
|
203
|
+
? "id 必须是非空字符串,建议 '<包名>.<状态名>'"
|
|
204
|
+
: rejection.reason === 'superseded'
|
|
205
|
+
? '同 id 上已有更高来源的登记;两个不同插件用了同一个 id,请各自换名'
|
|
206
|
+
: 'facet 必须是一个对象';
|
|
207
|
+
console.warn(`dsh-group-status: 拒绝登记状态 facet "${rejection.id}"(${rejection.reason}):${detail}`);
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=facets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facets.js","sourceRoot":"","sources":["../../../src/client/facets.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,30 +5,19 @@
|
|
|
5
5
|
* vendored file only needs one import line and one field assignment to wire
|
|
6
6
|
* the badge aggregation in. Everything fork-specific lives here.
|
|
7
7
|
*
|
|
8
|
+
* ## 本模块不认识任何具体状态源
|
|
9
|
+
*
|
|
10
|
+
* 它只统计宿主自己的行级事实(进行中 / 待审批 / 计划待审 / 等待回答 / 已完成 /
|
|
11
|
+
* 子智能体);外部状态一律经 `./facets.ts` 的协议折成 {@link FacetFold}。
|
|
12
|
+
*
|
|
13
|
+
* 这不是洁癖:此前这里为定时任务与等待评审各写了一组具名字段和一套查表,于是提供方
|
|
14
|
+
* 新增字段时本插件的本地类型一无所知,信息**静默丢失**(不报错、测试也不红,见
|
|
15
|
+
* CHANGELOG 0.2.3 第一条)。把语义留在拥有它的那一侧,这类漂移才结构上不可能发生。
|
|
16
|
+
*
|
|
8
17
|
* @module
|
|
9
18
|
*/
|
|
10
|
-
import type {
|
|
11
|
-
|
|
12
|
-
* One session's waiting-review fact, as published by dsh-gitea-dispatch's
|
|
13
|
-
* `useWaitingSummary()` (issue: dsh-gitea-dispatch#16).
|
|
14
|
-
*/
|
|
15
|
-
export interface WaitingReviewSummaryEntry {
|
|
16
|
-
readonly prNumber: number;
|
|
17
|
-
readonly state: 'waiting' | 'overdue';
|
|
18
|
-
}
|
|
19
|
-
/** Session id → that session's waiting-review fact (no entry = not waiting). */
|
|
20
|
-
export type WaitingReviewSummaryMap = ReadonlyMap<string, WaitingReviewSummaryEntry>;
|
|
21
|
-
/**
|
|
22
|
-
* One session's schedule fact, as published by dsh-later's `useScheduleSummary()`.
|
|
23
|
-
*/
|
|
24
|
-
export interface ScheduleSummaryEntry {
|
|
25
|
-
readonly count: number;
|
|
26
|
-
readonly pausedCount: number;
|
|
27
|
-
readonly nextAt?: number;
|
|
28
|
-
readonly state: 'scheduled' | 'urgent' | 'overdue';
|
|
29
|
-
}
|
|
30
|
-
/** Session id → that session's schedule fact (no entry = no scheduled tasks). */
|
|
31
|
-
export type ScheduleSummaryMap = ReadonlyMap<string, ScheduleSummaryEntry>;
|
|
19
|
+
import type { AnyFacet, AnyFacetFold, RegisteredFacet } from './facets.ts';
|
|
20
|
+
import type { GroupNode, SessionNode } from './tree.ts';
|
|
32
21
|
/**
|
|
33
22
|
* Aggregated live-session counts for one group, computed over all members so a
|
|
34
23
|
* folded folder row can hint at hidden activity.
|
|
@@ -46,33 +35,38 @@ export interface GroupLiveStatus {
|
|
|
46
35
|
done: number;
|
|
47
36
|
/** Running direct children across members. */
|
|
48
37
|
subagents: number;
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
38
|
+
/**
|
|
39
|
+
* 外部状态源的折果,按 facet id 索引,只含**有贡献**的来源(`count > 0`)。
|
|
40
|
+
*
|
|
41
|
+
* 这里刻意没有 `scheduled*` / `waitingReview*` 这类具名字段:徽标一旦为某个来源开
|
|
42
|
+
* 一个字段,就等于把别人家的语义焊进自己的类型,新增来源就得改本插件。
|
|
43
|
+
* `FacetFold.data` 的形状只有该来源自己读。
|
|
44
|
+
*/
|
|
45
|
+
facets: ReadonlyMap<string, FacetEntry>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 一个来源在**这一组**上的折果,连同它自己的 facet。
|
|
49
|
+
*
|
|
50
|
+
* 带上 facet 是为了让渲染(文案、图标、脉冲)与多层合并(`facet.merge`)都不必再回
|
|
51
|
+
* 登记面查表——也就不需要任何模块级状态。
|
|
52
|
+
*/
|
|
53
|
+
export interface FacetEntry {
|
|
54
|
+
facet: AnyFacet;
|
|
55
|
+
fold: AnyFacetFold;
|
|
59
56
|
}
|
|
60
57
|
/**
|
|
61
58
|
* Zero-valued sentinel for {@link GroupLiveStatus}.
|
|
62
59
|
*
|
|
63
|
-
* Used when a group
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* React selectors never trigger spurious re-renders on it.
|
|
60
|
+
* Used when a group has nothing to report. Kept as a frozen constant so the
|
|
61
|
+
* reference is stable across renders — `Object.is` comparisons in React selectors
|
|
62
|
+
* never trigger spurious re-renders on it.
|
|
67
63
|
*/
|
|
68
64
|
export declare const EMPTY_LIVE_STATUS: GroupLiveStatus;
|
|
69
65
|
/**
|
|
70
|
-
*
|
|
71
|
-
* highest-priority state (overdue > urgent > scheduled for schedule; overdue > waiting
|
|
72
|
-
* for waiting-review).
|
|
66
|
+
* 合并两份分组折果:本插件自己的计数相加,外部状态来源**按 facet 各自合并**。
|
|
73
67
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
68
|
+
* 用于多层聚合:折叠的父文件夹要覆盖整棵子树,而子树里每一层都已各自折过一遍。
|
|
69
|
+
* `FacetFold.data` 怎么合归该 facet 自己决定,本模块从不解释。
|
|
76
70
|
*/
|
|
77
71
|
export declare function mergeLiveStatus(a: GroupLiveStatus, b: GroupLiveStatus): GroupLiveStatus;
|
|
78
72
|
/**
|
|
@@ -80,10 +74,68 @@ export declare function mergeLiveStatus(a: GroupLiveStatus, b: GroupLiveStatus):
|
|
|
80
74
|
* hidden live sessions. Mirrors the session-row status priority (pending
|
|
81
75
|
* outranks running outranks completed) at the counting level; labels resolve with
|
|
82
76
|
* locale at render time.
|
|
77
|
+
*
|
|
83
78
|
* @param nodes - member rows of the group.
|
|
84
|
-
* @param sessionIds - the same members' Session ids (
|
|
85
|
-
* @param
|
|
86
|
-
* @param
|
|
79
|
+
* @param sessionIds - the same members' Session ids (facets address their own data by id).
|
|
80
|
+
* @param facets - the registered status sources to fold over this group.
|
|
81
|
+
* @param now - one clock reading for the whole pass, so sibling facets cannot disagree
|
|
82
|
+
* about which deadlines are still ahead.
|
|
83
|
+
*/
|
|
84
|
+
export declare function summarizeGroupStatus(nodes: readonly SessionNode[], sessionIds: readonly string[], facets?: readonly RegisteredFacet[], now?: number): GroupLiveStatus;
|
|
85
|
+
/**
|
|
86
|
+
* Measure each group's own members, as the input to {@link aggregateGroupStatuses}.
|
|
87
|
+
*
|
|
88
|
+
* Every group is measured, expanded ones included. A folder row shows no badge while
|
|
89
|
+
* it is expanded, but its sessions still need attention and a collapsed ancestor must
|
|
90
|
+
* keep counting them — so expansion is a rendering fact, never an input to the
|
|
91
|
+
* aggregation. Short-circuiting expanded groups to `EMPTY_LIVE_STATUS` (the shape this
|
|
92
|
+
* had before the tree-wide aggregator existed, harmless while nothing aggregated) makes
|
|
93
|
+
* every collapsed parent undercount by the size of its expanded descendants.
|
|
94
|
+
*
|
|
95
|
+
* @param groups - derived groups, each with its member rows already populated.
|
|
96
|
+
* @param facets - registered sources, already filtered by the visibility settings.
|
|
97
|
+
* @param now - one clock reading shared by every group in the pass.
|
|
98
|
+
*/
|
|
99
|
+
export declare function directStatusesForGroups(groups: readonly {
|
|
100
|
+
key: string;
|
|
101
|
+
sessions: readonly SessionNode[];
|
|
102
|
+
}[], facets?: readonly RegisteredFacet[], now?: number): Map<string, GroupLiveStatus>;
|
|
103
|
+
/**
|
|
104
|
+
* Fold every group's DIRECT status up the workspace tree, so a collapsed folder
|
|
105
|
+
* counts every descendant session. A group's own row shows no badge while it is
|
|
106
|
+
* expanded, but its sessions still need attention and its collapsed ancestor must
|
|
107
|
+
* keep counting them — so the walk never depends on a group's expanded state.
|
|
108
|
+
*
|
|
109
|
+
* @param direct - each group's own-member status, keyed by group key.
|
|
110
|
+
* @param childrenByParent - the rendered tree: parent key (`undefined` = roots) → children.
|
|
111
|
+
* @returns aggregated status per group key: own members plus the whole subtree.
|
|
112
|
+
*/
|
|
113
|
+
export declare function aggregateGroupStatuses(direct: ReadonlyMap<string, GroupLiveStatus>, childrenByParent: ReadonlyMap<string | undefined, readonly {
|
|
114
|
+
key: string;
|
|
115
|
+
}[]>): Map<string, GroupLiveStatus>;
|
|
116
|
+
/**
|
|
117
|
+
* A group row whose badge input is resolved: its own members plus its whole subtree.
|
|
118
|
+
*
|
|
119
|
+
* `GroupNode.liveStatus` is optional only because upstream never fills it — this
|
|
120
|
+
* package's aggregator is the sole producer. Typing a rendered row as
|
|
121
|
+
* `StatusedGroupNode` is what turns "a row that skipped the aggregator" into a compile
|
|
122
|
+
* error instead of a folder that silently lost its badge, which is how the PR #10
|
|
123
|
+
* regression reached main.
|
|
124
|
+
*/
|
|
125
|
+
export interface StatusedGroupNode extends GroupNode {
|
|
126
|
+
liveStatus: GroupLiveStatus;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Attach each group's subtree-wide status, in derivation order. This is the producer
|
|
130
|
+
* the sidebar renders from.
|
|
131
|
+
*
|
|
132
|
+
* Expanded groups carry their status too: their own row draws no badge (a decision
|
|
133
|
+
* inside `groupLiveBadge`), but a collapsed ancestor still has to count them, so
|
|
134
|
+
* expansion never suppresses the measurement.
|
|
135
|
+
*
|
|
136
|
+
* @param groups - derived rows, in the order they render.
|
|
137
|
+
* @param direct - each group's own-member status, from {@link directStatusesForGroups}.
|
|
138
|
+
* @param childrenByParent - the rendered tree: parent key (`undefined` = roots) → children.
|
|
87
139
|
*/
|
|
88
|
-
export declare function
|
|
140
|
+
export declare function withAggregatedStatus(groups: readonly GroupNode[], direct: ReadonlyMap<string, GroupLiveStatus>, childrenByParent: ReadonlyMap<string | undefined, readonly GroupNode[]>): StatusedGroupNode[];
|
|
89
141
|
//# sourceMappingURL=group-status.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group-status.d.ts","sourceRoot":"","sources":["../../../src/client/group-status.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"group-status.d.ts","sourceRoot":"","sources":["../../../src/client/group-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE1E,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAIvD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAA;IAChB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAA;IAChB,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAA;IACZ,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CACxC;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,QAAQ,CAAA;IACf,IAAI,EAAE,YAAY,CAAA;CACnB;AAKD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,eAGX,CAAA;AAErB;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,GAAG,eAAe,CAUvF;AAuBD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,MAAM,GAAE,SAAS,eAAe,EAAO,EACvC,GAAG,GAAE,MAAmB,GACvB,eAAe,CA6CjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAA;CAAE,EAAE,EACpE,MAAM,GAAE,SAAS,eAAe,EAAO,EACvC,GAAG,GAAE,MAAmB,GACvB,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAQ9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC5C,gBAAgB,EAAE,WAAW,CAAC,MAAM,GAAG,SAAS,EAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,GAC5E,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAwB9B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,UAAU,EAAE,eAAe,CAAA;CAC5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,SAAS,EAAE,EAC5B,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC5C,gBAAgB,EAAE,WAAW,CAAC,MAAM,GAAG,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC,GACtE,iBAAiB,EAAE,CAKrB"}
|