@lmzhen/dsh-evolution-merge-ui 0.30.18 → 0.30.19
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/lib/client.js +1395 -373
- package/lib/types/client/MergeStore.d.ts +74 -0
- package/lib/types/client/Panel.d.ts +10 -14
- package/lib/types/client/api.d.ts +80 -20
- package/lib/types/client/fallbacks.d.ts +3 -0
- package/lib/types/client/index.d.ts +1 -4
- package/lib/types/client/seam.d.ts +20 -0
- package/lib/types/client/sorting.d.ts +25 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -7,10 +7,7 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let react = require("react");
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/client/api.ts
|
|
10
|
-
/**
|
|
11
|
-
* The two read routes this panel uses. Parses the frozen wireVersion=1 envelopes
|
|
12
|
-
* and maps them to the panel view types; the panel never sees a path or a raw host body.
|
|
13
|
-
*/
|
|
10
|
+
/** Read-only merge wire client. Classifies every failure and never writes. */
|
|
14
11
|
const HOST_ROUTES = {
|
|
15
12
|
approval: {
|
|
16
13
|
pending: "/api/dsh-evolution/approval/pending",
|
|
@@ -37,6 +34,38 @@ window.__ModuleLoader__.load({
|
|
|
37
34
|
},
|
|
38
35
|
diagnostics: { view: "/api/dsh-evolution/diagnostics" }
|
|
39
36
|
}.merge;
|
|
37
|
+
const isBlocked = (failure) => failure.kind === "blocked";
|
|
38
|
+
const asReadiness = (value) => {
|
|
39
|
+
const raw = typeof value === "object" && value !== null ? value : {};
|
|
40
|
+
const steps = Array.isArray(raw.steps) ? raw.steps.filter((step) => typeof step === "string") : void 0;
|
|
41
|
+
return {
|
|
42
|
+
...typeof raw.ok === "boolean" ? { ok: raw.ok } : {},
|
|
43
|
+
...typeof raw.code === "string" ? { code: raw.code } : {},
|
|
44
|
+
...typeof raw.message === "string" ? { message: raw.message } : {},
|
|
45
|
+
...steps === void 0 ? {} : { steps }
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
const asPlatformWrite = (value) => {
|
|
49
|
+
if (typeof value === "boolean") return {
|
|
50
|
+
enabled: value,
|
|
51
|
+
capability: true
|
|
52
|
+
};
|
|
53
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
54
|
+
const raw = value;
|
|
55
|
+
const enabled = typeof raw.enabled === "boolean" ? raw.enabled : typeof raw.value === "boolean" ? raw.value : void 0;
|
|
56
|
+
const capability = typeof raw.capability === "boolean" ? raw.capability : typeof raw.available === "boolean" ? raw.available : true;
|
|
57
|
+
return enabled === void 0 ? void 0 : {
|
|
58
|
+
enabled,
|
|
59
|
+
capability
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
const problem = (code, status, wireCode, message) => ({
|
|
63
|
+
kind: "problem",
|
|
64
|
+
code,
|
|
65
|
+
status,
|
|
66
|
+
...wireCode === void 0 ? {} : { wireCode },
|
|
67
|
+
...message === void 0 ? {} : { message }
|
|
68
|
+
});
|
|
40
69
|
async function requestWire(path) {
|
|
41
70
|
let response;
|
|
42
71
|
try {
|
|
@@ -44,39 +73,16 @@ window.__ModuleLoader__.load({
|
|
|
44
73
|
} catch {
|
|
45
74
|
return {
|
|
46
75
|
ok: false,
|
|
47
|
-
failure:
|
|
48
|
-
kind: "server",
|
|
49
|
-
status: 0
|
|
50
|
-
}
|
|
76
|
+
failure: problem("server", 0)
|
|
51
77
|
};
|
|
52
78
|
}
|
|
53
79
|
if (response.status === 401) return {
|
|
54
80
|
ok: false,
|
|
55
|
-
failure:
|
|
56
|
-
kind: "unauthenticated",
|
|
57
|
-
status: 401
|
|
58
|
-
}
|
|
81
|
+
failure: problem("unauthenticated", 401)
|
|
59
82
|
};
|
|
60
83
|
if (response.status === 403) return {
|
|
61
84
|
ok: false,
|
|
62
|
-
failure:
|
|
63
|
-
kind: "forbidden",
|
|
64
|
-
status: 403
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
if (response.status === 404) return {
|
|
68
|
-
ok: false,
|
|
69
|
-
failure: {
|
|
70
|
-
kind: "unmounted",
|
|
71
|
-
status: 404
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
if (!response.ok) return {
|
|
75
|
-
ok: false,
|
|
76
|
-
failure: {
|
|
77
|
-
kind: "server",
|
|
78
|
-
status: response.status
|
|
79
|
-
}
|
|
85
|
+
failure: problem("forbidden", 403)
|
|
80
86
|
};
|
|
81
87
|
let body;
|
|
82
88
|
try {
|
|
@@ -84,34 +90,64 @@ window.__ModuleLoader__.load({
|
|
|
84
90
|
} catch {
|
|
85
91
|
return {
|
|
86
92
|
ok: false,
|
|
87
|
-
failure:
|
|
88
|
-
kind: "server",
|
|
89
|
-
status: response.status
|
|
90
|
-
}
|
|
93
|
+
failure: problem("server", response.status)
|
|
91
94
|
};
|
|
92
95
|
}
|
|
93
96
|
const record = body;
|
|
94
|
-
|
|
97
|
+
const code = typeof record.code === "string" ? record.code : void 0;
|
|
98
|
+
const message = typeof record.message === "string" ? record.message : void 0;
|
|
99
|
+
if (code === "E-323" || message?.startsWith("E-323") === true) return {
|
|
95
100
|
ok: false,
|
|
96
|
-
failure:
|
|
97
|
-
kind: "server",
|
|
98
|
-
status: response.status
|
|
99
|
-
}
|
|
101
|
+
failure: problem("capability", response.status, code, message)
|
|
100
102
|
};
|
|
101
|
-
if (typeof record.
|
|
103
|
+
if (response.status === 503 && code === "merge-state-blocked" && typeof record.readiness === "object" && record.readiness !== null) return {
|
|
102
104
|
ok: false,
|
|
103
105
|
failure: {
|
|
104
|
-
kind: "
|
|
105
|
-
code
|
|
106
|
-
|
|
106
|
+
kind: "blocked",
|
|
107
|
+
code,
|
|
108
|
+
readiness: asReadiness(record.readiness)
|
|
107
109
|
}
|
|
108
110
|
};
|
|
111
|
+
if (response.status === 404) {
|
|
112
|
+
if (code === "E-325") return {
|
|
113
|
+
ok: false,
|
|
114
|
+
failure: problem("unmounted", 404, code, message)
|
|
115
|
+
};
|
|
116
|
+
if (code === "merge-body-missing" || code === "merge-body-not-found") return {
|
|
117
|
+
ok: false,
|
|
118
|
+
failure: problem("body-missing", 404, code, message)
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
failure: problem("unmounted", 404, code, message)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (response.status === 400 && code === "merge-bad-query") return {
|
|
126
|
+
ok: false,
|
|
127
|
+
failure: problem("bad-query", 400, code, message)
|
|
128
|
+
};
|
|
129
|
+
if (!response.ok) return {
|
|
130
|
+
ok: false,
|
|
131
|
+
failure: problem("server", response.status, code, message)
|
|
132
|
+
};
|
|
133
|
+
if (record.wireVersion !== 1) return {
|
|
134
|
+
ok: false,
|
|
135
|
+
failure: problem("wire-version", response.status, code, message)
|
|
136
|
+
};
|
|
137
|
+
if (code === "merge-body-missing" || code === "merge-body-not-found") return {
|
|
138
|
+
ok: false,
|
|
139
|
+
failure: problem("body-missing", response.status, code, message)
|
|
140
|
+
};
|
|
141
|
+
if (code !== void 0) return {
|
|
142
|
+
ok: false,
|
|
143
|
+
failure: problem("refused", response.status, code, message)
|
|
144
|
+
};
|
|
109
145
|
return {
|
|
110
146
|
ok: true,
|
|
111
147
|
payload: body
|
|
112
148
|
};
|
|
113
149
|
}
|
|
114
|
-
const
|
|
150
|
+
const toPlatformWrite = (facts) => asPlatformWrite(facts.approval.platformWrite ?? facts.platformWrite);
|
|
115
151
|
const toRun = (run) => ({
|
|
116
152
|
id: run.id,
|
|
117
153
|
state: run.state,
|
|
@@ -121,8 +157,47 @@ window.__ModuleLoader__.load({
|
|
|
121
157
|
done: run.progress.done,
|
|
122
158
|
total: run.progress.total
|
|
123
159
|
} },
|
|
124
|
-
startedAt: run.startedAt
|
|
160
|
+
startedAt: run.startedAt,
|
|
161
|
+
...run.endedAt === void 0 ? {} : { endedAt: run.endedAt },
|
|
162
|
+
...run.failure === void 0 ? {} : { failure: {
|
|
163
|
+
stage: run.failure.stage,
|
|
164
|
+
code: run.failure.code,
|
|
165
|
+
retryable: run.failure.retryable,
|
|
166
|
+
...run.failure.detail === void 0 ? {} : { detail: run.failure.detail }
|
|
167
|
+
} },
|
|
168
|
+
...run.parentRunId === void 0 ? {} : { parentRunId: run.parentRunId },
|
|
169
|
+
...run.currentPairKey === void 0 ? {} : { currentPairKey: run.currentPairKey },
|
|
170
|
+
...run.resultRef === void 0 ? {} : { resultRef: run.resultRef },
|
|
171
|
+
actions: (run.actions ?? []).map((action) => ({
|
|
172
|
+
id: action.id,
|
|
173
|
+
command: action.command,
|
|
174
|
+
confirm: action.confirm === true,
|
|
175
|
+
enabled: action.enabled !== false,
|
|
176
|
+
...action.disabledReason === void 0 ? {} : { disabledReason: action.disabledReason }
|
|
177
|
+
}))
|
|
125
178
|
});
|
|
179
|
+
const stageOf = (row) => {
|
|
180
|
+
const normalize = (raw) => {
|
|
181
|
+
if (typeof raw === "string") return raw === "reserved" || raw === "present" || raw === "expired" || raw === "lost" || raw === "absent" ? { state: raw } : void 0;
|
|
182
|
+
if (raw === void 0) return void 0;
|
|
183
|
+
if (raw.state === "reserved" || raw.state === "present" || raw.state === "expired" || raw.state === "lost" || raw.state === "absent") return {
|
|
184
|
+
state: raw.state,
|
|
185
|
+
...raw.expiresAt === void 0 ? {} : { expiresAt: raw.expiresAt }
|
|
186
|
+
};
|
|
187
|
+
if (raw.state === "kept") return {
|
|
188
|
+
state: "present",
|
|
189
|
+
...raw.expiresAt === void 0 ? {} : { expiresAt: raw.expiresAt }
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
const stage = normalize(row.stage);
|
|
193
|
+
const staging = normalize(row.staging);
|
|
194
|
+
if (stage === void 0) return staging;
|
|
195
|
+
const expiresAt = stage.expiresAt ?? (staging?.state === stage.state ? staging.expiresAt : void 0);
|
|
196
|
+
return expiresAt === void 0 ? stage : {
|
|
197
|
+
...stage,
|
|
198
|
+
expiresAt
|
|
199
|
+
};
|
|
200
|
+
};
|
|
126
201
|
const toRow = (row) => ({
|
|
127
202
|
id: row.id,
|
|
128
203
|
pairKey: row.id,
|
|
@@ -139,31 +214,31 @@ window.__ModuleLoader__.load({
|
|
|
139
214
|
...row.target.actual === void 0 ? {} : { targetActual: row.target.actual },
|
|
140
215
|
...row.target.created === void 0 ? {} : { targetCreated: row.target.created }
|
|
141
216
|
},
|
|
142
|
-
...row.staging?.state === void 0 ? {} : { stagingState: row.staging.state },
|
|
143
|
-
...row.verifySubState === void 0 ? {} : { verifySubState: row.verifySubState },
|
|
144
|
-
...row.skipKind === void 0 ? {} : { skipKind: row.skipKind },
|
|
145
|
-
...row.bodies === void 0 ? {} : { bodies: row.bodies.map((body) => ({
|
|
146
|
-
name: body.name,
|
|
147
|
-
side: body.side
|
|
148
|
-
})) },
|
|
149
217
|
...row.confidence === void 0 ? {} : { confidence: row.confidence },
|
|
150
|
-
...row.
|
|
151
|
-
|
|
152
|
-
row.summary.
|
|
153
|
-
row.summary.
|
|
154
|
-
|
|
155
|
-
].filter((value) => value !== null) },
|
|
218
|
+
...row.summary === void 0 ? {} : { summary: {
|
|
219
|
+
a: row.summary.a,
|
|
220
|
+
b: row.summary.b,
|
|
221
|
+
rationale: row.summary.rationale
|
|
222
|
+
} },
|
|
156
223
|
...row.reason === void 0 ? {} : { reason: row.reason },
|
|
157
|
-
...row.
|
|
224
|
+
...row.reasonCode === void 0 ? {} : { reasonCode: row.reasonCode },
|
|
225
|
+
...row.origin === void 0 ? {} : { origin: row.origin },
|
|
226
|
+
...row.attempts === void 0 ? {} : { attempts: row.attempts },
|
|
227
|
+
...row.expiresAt === void 0 ? {} : { stagingExpiresAt: row.expiresAt },
|
|
228
|
+
...row.expired === void 0 ? {} : { expired: row.expired.kind },
|
|
229
|
+
...stageOf(row) === void 0 ? {} : { stageView: stageOf(row) },
|
|
158
230
|
...row.failure === void 0 ? {} : { failure: {
|
|
159
231
|
stage: row.failure.stage,
|
|
160
232
|
code: row.failure.code,
|
|
161
233
|
message: row.failure.detail ?? row.failure.code,
|
|
162
234
|
retryable: row.failure.retryable
|
|
163
235
|
} },
|
|
164
|
-
...row.
|
|
165
|
-
...row.
|
|
166
|
-
...row.
|
|
236
|
+
...row.verifySubState === void 0 ? {} : { verifySubState: row.verifySubState },
|
|
237
|
+
...row.skipKind === void 0 ? {} : { skipKind: row.skipKind },
|
|
238
|
+
...row.bodies === void 0 ? {} : { bodies: row.bodies.map((body) => ({
|
|
239
|
+
name: body.name,
|
|
240
|
+
side: body.side
|
|
241
|
+
})) },
|
|
167
242
|
actions: row.actions.map((action) => ({
|
|
168
243
|
id: action.id,
|
|
169
244
|
command: action.command,
|
|
@@ -176,6 +251,7 @@ window.__ModuleLoader__.load({
|
|
|
176
251
|
const answer = await requestWire(HOST_ROUTES.view);
|
|
177
252
|
if (!answer.ok) return answer;
|
|
178
253
|
const facts = answer.payload;
|
|
254
|
+
const platformWrite = toPlatformWrite(facts);
|
|
179
255
|
return {
|
|
180
256
|
ok: true,
|
|
181
257
|
payload: {
|
|
@@ -195,7 +271,10 @@ window.__ModuleLoader__.load({
|
|
|
195
271
|
notes: [...facts.notes],
|
|
196
272
|
degraded: facts.degraded,
|
|
197
273
|
...facts.last === null && facts.active === null ? {} : { latestRun: toRun(facts.last ?? facts.active) },
|
|
198
|
-
approval:
|
|
274
|
+
approval: {
|
|
275
|
+
mergeApproval: facts.approval.mergeApproval,
|
|
276
|
+
...platformWrite === void 0 ? {} : { platformWrite }
|
|
277
|
+
}
|
|
199
278
|
}
|
|
200
279
|
};
|
|
201
280
|
}
|
|
@@ -204,30 +283,42 @@ window.__ModuleLoader__.load({
|
|
|
204
283
|
if (!answer.ok) return answer;
|
|
205
284
|
if (answer.payload.queue !== queue || answer.payload.expiredOnly !== expiredOnly) return {
|
|
206
285
|
ok: false,
|
|
207
|
-
failure:
|
|
208
|
-
kind: "server",
|
|
209
|
-
status: 200
|
|
210
|
-
}
|
|
286
|
+
failure: problem("server", 200)
|
|
211
287
|
};
|
|
212
288
|
return {
|
|
213
289
|
ok: true,
|
|
214
290
|
payload: {
|
|
215
291
|
queue: answer.payload.queue,
|
|
292
|
+
expiredOnly: answer.payload.expiredOnly,
|
|
216
293
|
items: answer.payload.rows.map(toRow),
|
|
294
|
+
counts: answer.payload.counts,
|
|
217
295
|
...answer.payload.nextCursor === void 0 ? {} : { nextCursor: answer.payload.nextCursor }
|
|
218
296
|
}
|
|
219
297
|
};
|
|
220
298
|
}
|
|
221
|
-
async function body(
|
|
222
|
-
const answer = await requestWire(HOST_ROUTES.body + "?
|
|
223
|
-
|
|
299
|
+
async function body(name, side) {
|
|
300
|
+
const answer = await requestWire(HOST_ROUTES.body + "?name=" + encodeURIComponent(name) + "&side=" + side);
|
|
301
|
+
if (!answer.ok) {
|
|
302
|
+
if (answer.failure.kind === "problem" && answer.failure.code === "bad-query" && (answer.failure.message ?? "").includes("multiple merge rows")) return {
|
|
303
|
+
ok: false,
|
|
304
|
+
failure: {
|
|
305
|
+
...answer.failure,
|
|
306
|
+
code: "body-ambiguous"
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
return answer;
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
224
312
|
ok: true,
|
|
225
313
|
payload: {
|
|
226
|
-
|
|
314
|
+
name: answer.payload.name,
|
|
315
|
+
side: answer.payload.side,
|
|
316
|
+
text: answer.payload.text,
|
|
227
317
|
markdown: answer.payload.markdown,
|
|
228
|
-
|
|
318
|
+
truncated: answer.payload.truncated,
|
|
319
|
+
totalBytes: answer.payload.totalBytes
|
|
229
320
|
}
|
|
230
|
-
}
|
|
321
|
+
};
|
|
231
322
|
}
|
|
232
323
|
async function history() {
|
|
233
324
|
const answer = await requestWire(HOST_ROUTES.history);
|
|
@@ -237,6 +328,7 @@ window.__ModuleLoader__.load({
|
|
|
237
328
|
name: item.name,
|
|
238
329
|
kind: item.kind,
|
|
239
330
|
reason: item.reason,
|
|
331
|
+
...item.reasonCode === void 0 ? {} : { reasonCode: item.reasonCode },
|
|
240
332
|
lastVersion: item.lastVersion,
|
|
241
333
|
archivedAt: new Date(item.archivedAt).toISOString(),
|
|
242
334
|
...item.sourceRunId === void 0 ? {} : { sourceRunId: item.sourceRunId }
|
|
@@ -266,6 +358,7 @@ window.__ModuleLoader__.load({
|
|
|
266
358
|
"tab.fuse": "待合并",
|
|
267
359
|
"tab.skipped": "无需合并",
|
|
268
360
|
"empty.verify": "没有待判断的对。",
|
|
361
|
+
"empty.scope": "这里只做两轮合成;机械追加属于 skill 管理,不进入合并队列。",
|
|
269
362
|
"empty.pending": "没有待批准的合并。",
|
|
270
363
|
"empty.fuse": "没有待合并的对。",
|
|
271
364
|
"empty.skipped": "没有标记为无需合并的对。",
|
|
@@ -275,11 +368,20 @@ window.__ModuleLoader__.load({
|
|
|
275
368
|
"approval.on": "审批开:合并前需人工批准。",
|
|
276
369
|
"approval.off": "审批关:合并自动执行。",
|
|
277
370
|
"failed": "读取失败,保留上次结果。",
|
|
371
|
+
"blocked.title": "合并状态未就绪",
|
|
372
|
+
"blocked.hint": "迁移/备份修复后刷新;面板不会自动降级。",
|
|
373
|
+
"blocked.doctor": "复制诊断命令",
|
|
374
|
+
"blocked.detail": "查看原始信息",
|
|
375
|
+
"blocked.reason.migration-blocked": "合并状态需要迁移,面板已暂停读取。",
|
|
376
|
+
"blocked.reason.needs-repair": "合并状态需要修复,面板已暂停读取。",
|
|
377
|
+
"blocked.reason.forward-only": "合并状态版本过新,当前面板暂不支持。",
|
|
378
|
+
"blocked.reason.unknown": "合并状态未就绪,面板已暂停读取。",
|
|
278
379
|
"stage.decide": "判定",
|
|
279
380
|
"stage.author": "合并",
|
|
280
381
|
"stage.validate": "检查",
|
|
281
382
|
"stage.commit": "提交",
|
|
282
383
|
"row.target": "目标",
|
|
384
|
+
"row.actualTarget": "实际目标",
|
|
283
385
|
"row.confidence": "置信度",
|
|
284
386
|
"row.attempts": "尝试",
|
|
285
387
|
"row.origin": "来源",
|
|
@@ -329,10 +431,14 @@ window.__ModuleLoader__.load({
|
|
|
329
431
|
"failureUnauthorized": "未登录",
|
|
330
432
|
"failureForbidden": "无权访问",
|
|
331
433
|
"failureUnmounted": "宿主未挂载",
|
|
434
|
+
"failureCapability": "子代理通道不可用",
|
|
435
|
+
"failureCapabilityHint": "先运行全局诊断,或复制下方命令继续处理。preset/host-only 形态没有面板时仍可用这些命令兜底。",
|
|
436
|
+
"failureBodyAmbiguous": "同名技能匹配到多行,无法确定读取哪一个;请用唯一名称或从具体行打开。",
|
|
332
437
|
"fallbackHint": "可复制命令见下方",
|
|
333
438
|
"body.missing": "正文不存在或不可读。",
|
|
334
439
|
"expired.target-taken": "目标已被占用",
|
|
335
440
|
"expired.source-changed": "源已变更",
|
|
441
|
+
"expired.source-gone": "源已缺失",
|
|
336
442
|
"expired.skipped-ttl": "跳过已到期",
|
|
337
443
|
"history.kind.merged": "已合并",
|
|
338
444
|
"history.kind.deleted": "已删除",
|
|
@@ -346,6 +452,89 @@ window.__ModuleLoader__.load({
|
|
|
346
452
|
"state.fuse": "待合并",
|
|
347
453
|
"state.skipped": "已跳过"
|
|
348
454
|
};
|
|
455
|
+
Object.assign(zh, {
|
|
456
|
+
"stage.screening": "筛选",
|
|
457
|
+
"stage.settle": "结算",
|
|
458
|
+
"stage.state.reserved": "已预留",
|
|
459
|
+
"stage.state.present": "已暂存",
|
|
460
|
+
"stage.state.expired": "已过期",
|
|
461
|
+
"stage.state.lost": "暂存丢失",
|
|
462
|
+
"stage.state.absent": "无暂存",
|
|
463
|
+
"origin.system": "系统",
|
|
464
|
+
"row.id": "编号",
|
|
465
|
+
"row.requestedTarget": "请求目标",
|
|
466
|
+
"row.stage": "合并暂存",
|
|
467
|
+
"row.summaryA": "摘要 A",
|
|
468
|
+
"row.summaryB": "摘要 B",
|
|
469
|
+
"row.rationale": "理由",
|
|
470
|
+
"row.notProvided": "未提供",
|
|
471
|
+
"row.fullId": "完整编号",
|
|
472
|
+
"row.actions": "操作",
|
|
473
|
+
"action.unavailable": "不可用",
|
|
474
|
+
"history.reason.target-taken": "目标已被占用",
|
|
475
|
+
"history.reason.source-changed": "源已变更",
|
|
476
|
+
"history.reason.skipped-ttl": "跳过已到期",
|
|
477
|
+
"history.reason.validation-failed": "检查失败",
|
|
478
|
+
"history.reason.merge-over-limit": "超过限制",
|
|
479
|
+
"history.reason.source-gone": "源已缺失",
|
|
480
|
+
"history.reason.merged": "已合并",
|
|
481
|
+
"history.reason.archived": "已归档",
|
|
482
|
+
"history.reason.unknown": "原因未提供",
|
|
483
|
+
"history.lastVersion": "最后版本",
|
|
484
|
+
"history.archivedAt": "归档时间",
|
|
485
|
+
"body.truncated": "正文过长,已截断。",
|
|
486
|
+
"body.empty": "正文为空。",
|
|
487
|
+
"body.totalBytes": "总字节",
|
|
488
|
+
"body.live": "当前版本",
|
|
489
|
+
"body.archive": "归档版本",
|
|
490
|
+
"failureWireVersion": "宿主返回了不兼容的数据版本,请升级页面。",
|
|
491
|
+
"failureBadQuery": "请求已失效,请刷新后重试。",
|
|
492
|
+
"failureBodyMissing": "正文不存在或不可读。",
|
|
493
|
+
"failureRefused": "宿主拒绝了这次读取。",
|
|
494
|
+
"failureDetails": "查看详情",
|
|
495
|
+
"failureFallback": "可复制命令见下方",
|
|
496
|
+
"settings.title": "审批设置",
|
|
497
|
+
"settings.hint": "两段审批分开显示;值来自宿主能力,不从另一项推导。",
|
|
498
|
+
"settings.mergeApproval": "合并审批",
|
|
499
|
+
"settings.platformWrite": "平台写入审批",
|
|
500
|
+
"settings.on": "开",
|
|
501
|
+
"settings.off": "关",
|
|
502
|
+
"settings.capabilityMissing": "宿主未提供该能力",
|
|
503
|
+
"settings.capabilityDisabled": "当前部署不可用",
|
|
504
|
+
"settings.readonly": "只读显示;修改请到平台设置页。",
|
|
505
|
+
"run.title": "运行",
|
|
506
|
+
"run.id": "运行编号",
|
|
507
|
+
"run.state": "状态",
|
|
508
|
+
"run.stage": "阶段",
|
|
509
|
+
"run.progress": "进度",
|
|
510
|
+
"run.endedAt": "结束时间",
|
|
511
|
+
"run.failure": "失败",
|
|
512
|
+
"run.currentPair": "当前对",
|
|
513
|
+
"run.parent": "父运行",
|
|
514
|
+
"run.report": "报告",
|
|
515
|
+
"run.noReport": "暂无报告",
|
|
516
|
+
"run.resultRef": "报告位置",
|
|
517
|
+
"run.actions": "运行操作",
|
|
518
|
+
"run.running": "运行中",
|
|
519
|
+
"run.ended": "已结束",
|
|
520
|
+
"run.cancelled": "已取消",
|
|
521
|
+
"run.failed": "失败",
|
|
522
|
+
"run.succeeded": "成功",
|
|
523
|
+
"run.awaiting": "等待审批",
|
|
524
|
+
"run.awaiting-approval": "等待审批",
|
|
525
|
+
"run.undone": "已撤销",
|
|
526
|
+
"run.superseded": "已失效",
|
|
527
|
+
"run.interrupted": "已中断",
|
|
528
|
+
"run.orphan": "孤立",
|
|
529
|
+
"error.title": "读取失败",
|
|
530
|
+
"error.retry": "重试",
|
|
531
|
+
"error.raw": "原始信息",
|
|
532
|
+
"doctor.open": "打开全局诊断",
|
|
533
|
+
"sort.updatedAt": "按更新时间",
|
|
534
|
+
"sort.score": "按分数",
|
|
535
|
+
"pin": "置顶",
|
|
536
|
+
"unpin": "取消置顶"
|
|
537
|
+
});
|
|
349
538
|
const en = {
|
|
350
539
|
"entry.label": "Skill merge",
|
|
351
540
|
"title": "Skill merge",
|
|
@@ -363,6 +552,7 @@ window.__ModuleLoader__.load({
|
|
|
363
552
|
"tab.fuse": "Ready to merge",
|
|
364
553
|
"tab.skipped": "Skipped",
|
|
365
554
|
"empty.verify": "No pairs to judge.",
|
|
555
|
+
"empty.scope": "This panel only performs two-round synthesis; mechanical append belongs to skill management and does not enter the merge queue.",
|
|
366
556
|
"empty.pending": "No pending merges.",
|
|
367
557
|
"empty.fuse": "No pairs ready to merge.",
|
|
368
558
|
"empty.skipped": "No pairs marked as not worth merging.",
|
|
@@ -372,11 +562,20 @@ window.__ModuleLoader__.load({
|
|
|
372
562
|
"approval.on": "Approval on: merges wait for a human.",
|
|
373
563
|
"approval.off": "Approval off: merges run automatically.",
|
|
374
564
|
"failed": "Read failed; keeping the last result.",
|
|
565
|
+
"blocked.title": "Merge state blocked",
|
|
566
|
+
"blocked.hint": "Fix the migration/backup, then refresh. The panel does not fall back automatically.",
|
|
567
|
+
"blocked.doctor": "Copy diagnostics command",
|
|
568
|
+
"blocked.detail": "Show host message",
|
|
569
|
+
"blocked.reason.migration-blocked": "Merge state needs migration; the panel is paused.",
|
|
570
|
+
"blocked.reason.needs-repair": "Merge state needs repair; the panel is paused.",
|
|
571
|
+
"blocked.reason.forward-only": "Merge state was written by a newer version; this panel cannot read it.",
|
|
572
|
+
"blocked.reason.unknown": "Merge state is not ready; the panel is paused.",
|
|
375
573
|
"stage.decide": "Decide",
|
|
376
574
|
"stage.author": "Author",
|
|
377
575
|
"stage.validate": "Validate",
|
|
378
576
|
"stage.commit": "Commit",
|
|
379
577
|
"row.target": "Target",
|
|
578
|
+
"row.actualTarget": "Actual target",
|
|
380
579
|
"row.confidence": "Confidence",
|
|
381
580
|
"row.attempts": "Attempts",
|
|
382
581
|
"row.origin": "Origin",
|
|
@@ -426,10 +625,14 @@ window.__ModuleLoader__.load({
|
|
|
426
625
|
"failureUnauthorized": "Not signed in",
|
|
427
626
|
"failureForbidden": "Forbidden",
|
|
428
627
|
"failureUnmounted": "Host not mounted",
|
|
628
|
+
"failureCapability": "Subagent channel unavailable",
|
|
629
|
+
"failureCapabilityHint": "Run global diagnostics first, or copy a command below to continue. The command fallback also covers preset/host-only shapes without a panel.",
|
|
630
|
+
"failureBodyAmbiguous": "The skill name matches multiple rows, so the body is ambiguous. Use a unique name or open it from a specific row.",
|
|
429
631
|
"fallbackHint": "Copy the command below",
|
|
430
632
|
"body.missing": "Body missing or unreadable.",
|
|
431
633
|
"expired.target-taken": "target taken",
|
|
432
634
|
"expired.source-changed": "source changed",
|
|
635
|
+
"expired.source-gone": "source gone",
|
|
433
636
|
"expired.skipped-ttl": "skip expired",
|
|
434
637
|
"history.kind.merged": "Merged",
|
|
435
638
|
"history.kind.deleted": "Deleted",
|
|
@@ -443,6 +646,117 @@ window.__ModuleLoader__.load({
|
|
|
443
646
|
"state.fuse": "Ready to merge",
|
|
444
647
|
"state.skipped": "Skipped"
|
|
445
648
|
};
|
|
649
|
+
Object.assign(en, {
|
|
650
|
+
"stage.screening": "Screen",
|
|
651
|
+
"stage.settle": "Settle",
|
|
652
|
+
"stage.state.reserved": "Reserved",
|
|
653
|
+
"stage.state.present": "Staged",
|
|
654
|
+
"stage.state.expired": "Expired",
|
|
655
|
+
"stage.state.lost": "Staging lost",
|
|
656
|
+
"stage.state.absent": "Not staged",
|
|
657
|
+
"origin.system": "System",
|
|
658
|
+
"row.id": "ID",
|
|
659
|
+
"row.requestedTarget": "Requested target",
|
|
660
|
+
"row.stage": "Merge staging",
|
|
661
|
+
"row.summaryA": "Summary A",
|
|
662
|
+
"row.summaryB": "Summary B",
|
|
663
|
+
"row.rationale": "Rationale",
|
|
664
|
+
"row.notProvided": "not provided",
|
|
665
|
+
"row.fullId": "Full ID",
|
|
666
|
+
"row.actions": "Actions",
|
|
667
|
+
"action.unavailable": "Unavailable",
|
|
668
|
+
"history.reason.target-taken": "target taken",
|
|
669
|
+
"history.reason.source-changed": "source changed",
|
|
670
|
+
"history.reason.skipped-ttl": "skip expired",
|
|
671
|
+
"history.reason.validation-failed": "validation failed",
|
|
672
|
+
"history.reason.merge-over-limit": "over limit",
|
|
673
|
+
"history.reason.source-gone": "source gone",
|
|
674
|
+
"history.reason.merged": "merged",
|
|
675
|
+
"history.reason.archived": "archived",
|
|
676
|
+
"history.reason.unknown": "reason not provided",
|
|
677
|
+
"history.lastVersion": "Last version",
|
|
678
|
+
"history.archivedAt": "Archived at",
|
|
679
|
+
"body.truncated": "Body is truncated.",
|
|
680
|
+
"body.empty": "Body is empty.",
|
|
681
|
+
"body.totalBytes": "Total bytes",
|
|
682
|
+
"body.live": "Live",
|
|
683
|
+
"body.archive": "Archive",
|
|
684
|
+
"failureWireVersion": "The host returned an incompatible data version; reload the page.",
|
|
685
|
+
"failureBadQuery": "This request is stale; refresh and retry.",
|
|
686
|
+
"failureBodyMissing": "Body missing or unreadable.",
|
|
687
|
+
"failureRefused": "The host refused this read.",
|
|
688
|
+
"failureDetails": "Show details",
|
|
689
|
+
"failureFallback": "Copy a command below",
|
|
690
|
+
"settings.title": "Approvals",
|
|
691
|
+
"settings.hint": "Two independent approval values; each comes from host capability, never derived from the other.",
|
|
692
|
+
"settings.mergeApproval": "Merge approval",
|
|
693
|
+
"settings.platformWrite": "Platform write approval",
|
|
694
|
+
"settings.on": "On",
|
|
695
|
+
"settings.off": "Off",
|
|
696
|
+
"settings.capabilityMissing": "Host did not provide this capability",
|
|
697
|
+
"settings.capabilityDisabled": "Not available in this deployment",
|
|
698
|
+
"settings.readonly": "Read-only here; edit in platform settings.",
|
|
699
|
+
"run.title": "Run",
|
|
700
|
+
"run.id": "Run ID",
|
|
701
|
+
"run.state": "State",
|
|
702
|
+
"run.stage": "Stage",
|
|
703
|
+
"run.progress": "Progress",
|
|
704
|
+
"run.endedAt": "Ended at",
|
|
705
|
+
"run.failure": "Failure",
|
|
706
|
+
"run.currentPair": "Current pair",
|
|
707
|
+
"run.parent": "Parent run",
|
|
708
|
+
"run.report": "Report",
|
|
709
|
+
"run.noReport": "No report yet",
|
|
710
|
+
"run.resultRef": "Report location",
|
|
711
|
+
"run.actions": "Run actions",
|
|
712
|
+
"run.running": "Running",
|
|
713
|
+
"run.ended": "Ended",
|
|
714
|
+
"run.cancelled": "Cancelled",
|
|
715
|
+
"run.failed": "Failed",
|
|
716
|
+
"run.succeeded": "Succeeded",
|
|
717
|
+
"run.awaiting": "Awaiting approval",
|
|
718
|
+
"run.awaiting-approval": "Awaiting approval",
|
|
719
|
+
"run.undone": "Undone",
|
|
720
|
+
"run.superseded": "Superseded",
|
|
721
|
+
"run.interrupted": "Interrupted",
|
|
722
|
+
"run.orphan": "Orphan",
|
|
723
|
+
"error.title": "Read failed",
|
|
724
|
+
"error.retry": "Retry",
|
|
725
|
+
"error.raw": "Raw message",
|
|
726
|
+
"doctor.open": "Open global diagnostics",
|
|
727
|
+
"sort.updatedAt": "Last updated",
|
|
728
|
+
"sort.score": "Score",
|
|
729
|
+
"pin": "Pin",
|
|
730
|
+
"unpin": "Unpin"
|
|
731
|
+
});
|
|
732
|
+
Object.assign(zh, {
|
|
733
|
+
"settings.saved": "已保存",
|
|
734
|
+
"settings.saveFailed": "保存失败",
|
|
735
|
+
"settings.openPlatform": "打开平台设置",
|
|
736
|
+
"settings.live": "可直接在此保存;platformWrite 能力来自宿主。"
|
|
737
|
+
});
|
|
738
|
+
Object.assign(en, {
|
|
739
|
+
"settings.saved": "Saved",
|
|
740
|
+
"settings.saveFailed": "Save failed",
|
|
741
|
+
"settings.openPlatform": "Open platform settings",
|
|
742
|
+
"settings.live": "Save directly here; platformWrite capability comes from the host."
|
|
743
|
+
});
|
|
744
|
+
Object.assign(zh, { "settings.platformWriteLinkHint": "此开关属于平台设置,这里只读;请到平台设置修改。" });
|
|
745
|
+
Object.assign(en, { "settings.platformWriteLinkHint": "This switch belongs to platform settings; this card is read-only. Change it in platform settings." });
|
|
746
|
+
Object.assign(zh, {
|
|
747
|
+
"sort.drag": "拖动排序",
|
|
748
|
+
"sort.menu": "行排序",
|
|
749
|
+
"sort.pinTop": "置顶",
|
|
750
|
+
"sort.pinBottom": "置底",
|
|
751
|
+
"sort.cancel": "取消"
|
|
752
|
+
});
|
|
753
|
+
Object.assign(en, {
|
|
754
|
+
"sort.drag": "Drag to reorder",
|
|
755
|
+
"sort.menu": "Row order",
|
|
756
|
+
"sort.pinTop": "Pin to top",
|
|
757
|
+
"sort.pinBottom": "Pin to bottom",
|
|
758
|
+
"sort.cancel": "Cancel"
|
|
759
|
+
});
|
|
446
760
|
//#endregion
|
|
447
761
|
//#region src/client/styles.ts
|
|
448
762
|
const CSS_TAG_ID = "evolution-merge-panel";
|
|
@@ -465,320 +779,1043 @@ window.__ModuleLoader__.load({
|
|
|
465
779
|
".evolution-merge-panel [data-role=\"failure\"] { display:flex; flex-direction:column; gap:var(--evo-space-6); }",
|
|
466
780
|
".evolution-merge-panel [data-role=\"failure\"] [data-tone=\"fail\"] { color:var(--dsw-alias-state-error-primary); }",
|
|
467
781
|
".evolution-merge-panel [data-role=\"fallback\"] { display:flex; gap:var(--evo-space-6); flex-wrap:wrap; }",
|
|
468
|
-
".evolution-merge-panel [data-role=\"overlay\"] { position:
|
|
782
|
+
".evolution-merge-panel [data-role=\"overlay\"] { position:fixed; z-index:60; top:8vh; left:50%; transform:translateX(-50%); width:min(820px, calc(100vw - 64px)); max-height:78vh; overflow:auto; display:flex; flex-direction:column; gap:var(--evo-space-8); padding:var(--evo-space-12); border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2); border-radius:var(--evo-radius-control); background:var(--dsw-alias-bg-layer-1); box-shadow:0 0 var(--evo-space-8) var(--dsw-alias-border-l2); }",
|
|
783
|
+
".evolution-merge-panel [data-role=\"overlay-head\"] { display:flex; align-items:center; justify-content:space-between; gap:var(--evo-space-8); }",
|
|
469
784
|
".evolution-merge-panel [data-role=\"overlay-title\"] { margin:0; font-size:var(--evo-type-lg); }",
|
|
470
785
|
".evolution-merge-panel [data-role=\"rows\"] { display:flex; flex-direction:column; gap:var(--evo-space-6); }",
|
|
471
|
-
".evolution-merge-panel [data-role=\"row\"] { display:grid; grid-template-columns:1fr auto; gap:var(--evo-space-8); padding:var(--evo-space-8); border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2); border-radius:var(--evo-radius-control); }",
|
|
786
|
+
".evolution-merge-panel [data-role=\"row\"] { display:grid; grid-template-columns:1fr auto; gap:var(--evo-space-8); padding:var(--evo-space-8); border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2); border-radius:var(--evo-radius-control); cursor:grab; }",
|
|
787
|
+
".evolution-merge-panel [data-role=\"row\"]:active { cursor:grabbing; }",
|
|
472
788
|
".evolution-merge-panel [data-role=\"row-label\"] { font-weight:600; }",
|
|
473
789
|
".evolution-merge-panel [data-role=\"row-meta\"] { color:var(--dsw-alias-label-tertiary); font-size:var(--evo-type-xs); }",
|
|
474
790
|
".evolution-merge-panel [data-role=\"note\"] { color:var(--dsw-alias-label-tertiary); font-size:var(--evo-type-xs); }",
|
|
791
|
+
".evolution-merge-panel [data-role=\"blocked\"] { display:flex; flex-direction:column; gap:var(--evo-space-8); padding:var(--evo-space-12); border:var(--evo-hairline-width) solid var(--dsw-alias-state-warning-primary); border-left-width:var(--evo-hairline-width); border-radius:var(--evo-radius-control); background:var(--dsw-alias-bg-layer-1); }",
|
|
792
|
+
".evolution-merge-panel [data-role=\"blocked-title\"] { margin:0; font-size:var(--evo-type-lg); font-weight:600; color:var(--dsw-alias-state-warning-primary); }",
|
|
793
|
+
".evolution-merge-panel [data-role=\"blocked-reason\"] { margin:0; white-space:pre-wrap; overflow-wrap:anywhere; }",
|
|
794
|
+
".evolution-merge-panel [data-role=\"blocked-hint\"] { margin:0; color:var(--dsw-alias-label-tertiary); font-size:var(--evo-type-xs); }",
|
|
795
|
+
".evolution-merge-panel [data-role=\"blocked-actions\"] { display:flex; gap:var(--evo-space-6); flex-wrap:wrap; }",
|
|
796
|
+
".evolution-merge-panel [data-role=\"content\"] { display:flex; flex-direction:column; gap:var(--evo-space-12); }",
|
|
797
|
+
".evolution-merge-panel [data-role=\"settings-card\"] { display:flex; flex-direction:column; gap:var(--evo-space-6); padding:var(--evo-space-10); border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2); border-radius:var(--evo-radius-control); background:var(--dsw-alias-bg-layer-1); }",
|
|
798
|
+
".evolution-merge-panel [data-role=\"settings-title\"] { margin:0; font-size:var(--evo-type-sm); }",
|
|
799
|
+
".evolution-merge-panel [data-role=\"settings-hint\"], .evolution-merge-panel [data-role=\"settings-readonly\"] { margin:0; color:var(--dsw-alias-label-tertiary); font-size:var(--evo-type-xs); }",
|
|
800
|
+
".evolution-merge-panel [data-role=\"settings-section\"] { display:grid; grid-template-columns:minmax(0,1fr) auto auto; align-items:center; column-gap:var(--evo-space-8); }",
|
|
801
|
+
".evolution-merge-panel [data-role=\"settings-section\"][data-disabled=\"true\"] { color:var(--dsw-alias-label-tertiary); }",
|
|
802
|
+
".evolution-merge-panel [data-role=\"settings-toggle\"] { margin:0; }",
|
|
803
|
+
".evolution-merge-panel [data-role=\"settings-value\"] { font-weight:600; min-width:2.5em; text-align:right; }",
|
|
804
|
+
".evolution-merge-panel [data-role=\"settings-note\"] { grid-column:1/-1; color:var(--dsw-alias-label-tertiary); font-size:var(--evo-type-xs); }",
|
|
805
|
+
".evolution-merge-panel [data-role=\"settings-link\"] { grid-column:1/-1; color:var(--dsw-alias-brand-primary); font-size:var(--evo-type-xs); }",
|
|
806
|
+
".evolution-merge-panel [data-role=\"run-strip\"] { display:flex; gap:var(--evo-space-8); flex-wrap:wrap; align-items:center; font-size:var(--evo-type-xs); }",
|
|
807
|
+
".evolution-merge-panel [data-role=\"run-failure\"] { color:var(--dsw-alias-state-error-primary); }",
|
|
808
|
+
".evolution-merge-panel [data-role=\"stage-badge\"] { display:inline-block; margin-top:var(--evo-space-4); padding:0 var(--evo-space-4); border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2); border-radius:var(--evo-radius-control); font-size:var(--evo-type-xs); }",
|
|
809
|
+
".evolution-merge-panel [data-role=\"stage-badge\"][data-tone=\"warn\"] { color:var(--dsw-alias-state-warning-primary); }",
|
|
810
|
+
".evolution-merge-panel [data-role=\"stage-badge\"][data-tone=\"fail\"] { color:var(--dsw-alias-state-error-primary); border-color:var(--dsw-alias-state-error-primary); }",
|
|
811
|
+
".evolution-merge-panel [data-role=\"row-id\"] { color:var(--dsw-alias-label-tertiary); font-size:var(--evo-type-xs); }",
|
|
812
|
+
".evolution-merge-panel [data-role=\"pending-summary\"] { display:flex; flex-direction:column; gap:var(--evo-space-4); margin-top:var(--evo-space-4); }",
|
|
813
|
+
".evolution-merge-panel [data-role=\"pending-summary-slot\"] { display:flex; gap:var(--evo-space-6); }",
|
|
814
|
+
".evolution-merge-panel [data-role=\"pending-summary-label\"] { color:var(--dsw-alias-label-tertiary); min-width:calc(var(--evo-space-16) * 2); }",
|
|
815
|
+
".evolution-merge-panel [data-role=\"body-text\"] { white-space:pre-wrap; overflow-wrap:anywhere; max-height:50vh; overflow:auto; }",
|
|
816
|
+
".evolution-merge-panel [data-role=\"overlay\"] { display:flex; flex-direction:column; gap:var(--evo-space-6); padding:var(--evo-space-10); border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2); border-radius:var(--evo-radius-control); }",
|
|
817
|
+
".evolution-merge-panel button:focus-visible, .evolution-merge-panel a:focus-visible { outline:2px solid var(--dsw-alias-brand-primary); outline-offset:2px; }",
|
|
818
|
+
".evolution-merge-panel [data-role=\"sort-menu\"] { position:fixed; z-index:70; display:flex; flex-direction:column; min-width:var(--evo-measure-read); padding:var(--evo-space-4); border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2); border-radius:var(--evo-radius-control); background:var(--dsw-alias-bg-layer-1); box-shadow:0 0 var(--evo-space-6) var(--dsw-alias-border-l2); }",
|
|
819
|
+
".evolution-merge-panel [data-role=\"sort-menu\"] button { text-align:left; }",
|
|
475
820
|
".evolution-merge-panel [data-role=\"refresh\"] { align-self:flex-start; }"
|
|
476
821
|
].join("\n");
|
|
477
822
|
//#endregion
|
|
478
|
-
//#region src/client/
|
|
479
|
-
/**
|
|
480
|
-
function
|
|
481
|
-
const
|
|
482
|
-
return
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
function
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
case "server": return failure.status === 0 ? t("failureServer") : t("failureServer") + " (HTTP " + String(failure.status) + ")";
|
|
494
|
-
case "refused": return failure.message;
|
|
823
|
+
//#region src/client/sorting.ts
|
|
824
|
+
/** Workspace scope for one tab. A missing panel workspace is the local scope. */
|
|
825
|
+
function resolveWorkspaceId(workspaceId) {
|
|
826
|
+
const value = workspaceId?.trim() ?? "";
|
|
827
|
+
return value === "" ? "local" : value;
|
|
828
|
+
}
|
|
829
|
+
/** Stable localStorage key for one workspace and queue. */
|
|
830
|
+
function rowOrderKey(workspaceId, queue) {
|
|
831
|
+
return "dsh-evolution-merge.row-order.v1:" + encodeURIComponent(resolveWorkspaceId(workspaceId)) + ":" + queue;
|
|
832
|
+
}
|
|
833
|
+
function defaultStorage() {
|
|
834
|
+
try {
|
|
835
|
+
return globalThis.localStorage;
|
|
836
|
+
} catch {
|
|
837
|
+
return;
|
|
495
838
|
}
|
|
496
839
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
840
|
+
function normalize(raw) {
|
|
841
|
+
if (raw === null) return [];
|
|
842
|
+
try {
|
|
843
|
+
const value = JSON.parse(raw);
|
|
844
|
+
if (!Array.isArray(value)) return [];
|
|
845
|
+
const ids = [];
|
|
846
|
+
const seen = /* @__PURE__ */ new Set();
|
|
847
|
+
for (const item of value) {
|
|
848
|
+
if (typeof item !== "string" || item === "" || seen.has(item)) continue;
|
|
849
|
+
seen.add(item);
|
|
850
|
+
ids.push(item);
|
|
851
|
+
}
|
|
852
|
+
return ids;
|
|
853
|
+
} catch {
|
|
854
|
+
return [];
|
|
855
|
+
}
|
|
505
856
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
857
|
+
/** One tab's persisted order; failures degrade to an empty (wire) order. */
|
|
858
|
+
function createRowOrderStore(storage = defaultStorage()) {
|
|
859
|
+
return {
|
|
860
|
+
read(workspaceId, queue) {
|
|
861
|
+
if (storage === void 0) return [];
|
|
862
|
+
try {
|
|
863
|
+
return normalize(storage.getItem(rowOrderKey(workspaceId, queue)));
|
|
864
|
+
} catch {
|
|
865
|
+
return [];
|
|
866
|
+
}
|
|
867
|
+
},
|
|
868
|
+
write(workspaceId, queue, ids) {
|
|
869
|
+
if (storage === void 0) return;
|
|
870
|
+
try {
|
|
871
|
+
storage.setItem(rowOrderKey(workspaceId, queue), JSON.stringify(ids));
|
|
872
|
+
} catch {}
|
|
873
|
+
}
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
/** Apply persisted ids first, then append unknown rows in their wire order. */
|
|
877
|
+
function orderRows(rows, order) {
|
|
878
|
+
if (order.length === 0) return rows;
|
|
879
|
+
const byId = new Map(rows.map((row) => [row.id, row]));
|
|
880
|
+
const out = [];
|
|
881
|
+
const seen = /* @__PURE__ */ new Set();
|
|
882
|
+
for (const id of order) {
|
|
883
|
+
const row = byId.get(id);
|
|
884
|
+
if (row === void 0 || seen.has(id)) continue;
|
|
885
|
+
seen.add(id);
|
|
886
|
+
out.push(row);
|
|
521
887
|
}
|
|
522
|
-
|
|
888
|
+
for (const row of rows) if (!seen.has(row.id)) out.push(row);
|
|
889
|
+
return out;
|
|
890
|
+
}
|
|
891
|
+
/** Move one visible row before another; unknown ids leave the order unchanged. */
|
|
892
|
+
function moveRow(order, fromId, beforeId) {
|
|
893
|
+
if (!order.includes(fromId)) return order;
|
|
894
|
+
const rest = order.filter((id) => id !== fromId);
|
|
895
|
+
if (beforeId === void 0) return [...rest, fromId];
|
|
896
|
+
const index = rest.indexOf(beforeId);
|
|
897
|
+
if (index < 0) return [...rest, fromId];
|
|
898
|
+
return [
|
|
899
|
+
...rest.slice(0, index),
|
|
900
|
+
fromId,
|
|
901
|
+
...rest.slice(index)
|
|
902
|
+
];
|
|
903
|
+
}
|
|
904
|
+
/** Pin one visible row to the top or bottom of the full visible order. */
|
|
905
|
+
function pinRow(order, id, edge) {
|
|
906
|
+
if (!order.includes(id)) return order;
|
|
907
|
+
const rest = order.filter((item) => item !== id);
|
|
908
|
+
return edge === "top" ? [id, ...rest] : [...rest, id];
|
|
909
|
+
}
|
|
910
|
+
//#endregion
|
|
911
|
+
//#region src/client/fallbacks.ts
|
|
912
|
+
/** Static command-face fallback for a Facts read failure; the API fallback is unavailable then. */
|
|
913
|
+
const FALLBACK_COMMANDS = [
|
|
914
|
+
"/evolution merge scan",
|
|
915
|
+
"/evolution merge pair <a> <b>",
|
|
916
|
+
"/evolution merge pending",
|
|
917
|
+
"/evolution merge pending --expired",
|
|
918
|
+
"/evolution merge skipped",
|
|
919
|
+
"/evolution merge candidates",
|
|
920
|
+
"/evolution merge status",
|
|
921
|
+
"/evolution merge report",
|
|
922
|
+
"/evolution doctor"
|
|
923
|
+
];
|
|
523
924
|
//#endregion
|
|
524
925
|
//#region src/client/Panel.ts
|
|
525
|
-
/**
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
926
|
+
/** Batch 4 merge panel: keyed read store, four tabs, local overlays, localized errors. */
|
|
927
|
+
async function saveSetting(form, field, value) {
|
|
928
|
+
try {
|
|
929
|
+
return await form.set(field, value);
|
|
930
|
+
} catch {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
529
934
|
const QUEUES = [
|
|
530
935
|
"verify",
|
|
531
936
|
"pending",
|
|
532
937
|
"fuse",
|
|
533
938
|
"skipped"
|
|
534
939
|
];
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
940
|
+
const DOCTOR_COMMAND = "/evolution doctor";
|
|
941
|
+
function problemKey(problem) {
|
|
942
|
+
switch (problem.code) {
|
|
943
|
+
case "unauthenticated": return "failureUnauthorized";
|
|
944
|
+
case "forbidden": return "failureForbidden";
|
|
945
|
+
case "unmounted": return "failureUnmounted";
|
|
946
|
+
case "capability": return "failureCapability";
|
|
947
|
+
case "body-ambiguous": return "failureBodyAmbiguous";
|
|
948
|
+
case "wire-version": return "failureWireVersion";
|
|
949
|
+
case "body-missing": return "failureBodyMissing";
|
|
950
|
+
case "bad-query": return "failureBadQuery";
|
|
951
|
+
case "refused": return "failureRefused";
|
|
952
|
+
case "server": return "failureServer";
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
function reasonText(t, reasonCode, fallback) {
|
|
956
|
+
if (reasonCode === void 0) return fallback;
|
|
957
|
+
const key = "history.reason." + reasonCode;
|
|
958
|
+
const text = t(key);
|
|
959
|
+
return text === key ? fallback : text;
|
|
960
|
+
}
|
|
961
|
+
function blockedReasonKey(failure) {
|
|
962
|
+
const code = failure.readiness.code ?? failure.code;
|
|
963
|
+
if (code.endsWith("needs-repair")) return "blocked.reason.needs-repair";
|
|
964
|
+
if (code.endsWith("forward-only")) return "blocked.reason.forward-only";
|
|
965
|
+
if (code.endsWith("migration-blocked")) return "blocked.reason.migration-blocked";
|
|
966
|
+
return "blocked.reason.unknown";
|
|
967
|
+
}
|
|
968
|
+
function failureNode(t, failure, fallback, copy) {
|
|
969
|
+
if (isBlocked(failure)) {
|
|
970
|
+
const raw = failure.readiness.message;
|
|
971
|
+
return (0, react.createElement)("div", {
|
|
972
|
+
"data-role": "blocked",
|
|
973
|
+
role: "alert",
|
|
974
|
+
"data-block-code": failure.code,
|
|
975
|
+
"data-readiness-code": failure.readiness.code ?? ""
|
|
976
|
+
}, (0, react.createElement)("h3", { "data-role": "blocked-title" }, t("blocked.title")), (0, react.createElement)("p", {
|
|
977
|
+
"data-role": "blocked-reason",
|
|
978
|
+
title: raw ?? t(blockedReasonKey(failure))
|
|
979
|
+
}, t(blockedReasonKey(failure))), (0, react.createElement)("p", { "data-role": "blocked-hint" }, t("blocked.hint")), raw === void 0 ? null : (0, react.createElement)("details", { "data-role": "blocked-detail" }, (0, react.createElement)("summary", null, t("blocked.detail")), (0, react.createElement)("p", { "data-role": "blocked-raw" }, raw)), (0, react.createElement)("div", { "data-role": "blocked-actions" }, (0, react.createElement)("button", {
|
|
980
|
+
type: "button",
|
|
981
|
+
"data-role": "doctor",
|
|
982
|
+
onClick: () => {
|
|
983
|
+
copy(DOCTOR_COMMAND);
|
|
984
|
+
}
|
|
985
|
+
}, t("blocked.doctor")), (0, react.createElement)("button", {
|
|
986
|
+
type: "button",
|
|
987
|
+
"data-role": "refresh",
|
|
988
|
+
onClick: () => {
|
|
989
|
+
window.dispatchEvent(new Event("evolution-merge:refresh"));
|
|
990
|
+
}
|
|
991
|
+
}, t("refresh"))));
|
|
992
|
+
}
|
|
993
|
+
const capability = failure.code === "capability";
|
|
994
|
+
return (0, react.createElement)("div", {
|
|
995
|
+
"data-role": capability ? "capability-failure" : "failure",
|
|
996
|
+
"data-error-code": failure.code,
|
|
997
|
+
"data-status": String(failure.status)
|
|
998
|
+
}, (0, react.createElement)("p", {
|
|
999
|
+
"data-role": "failure-title",
|
|
1000
|
+
title: failure.message
|
|
1001
|
+
}, t(problemKey(failure))), capability ? (0, react.createElement)("p", { "data-role": "capability-hint" }, t("failureCapabilityHint")) : null, failure.message === void 0 ? null : (0, react.createElement)("details", { "data-role": "failure-detail" }, (0, react.createElement)("summary", null, t("failureDetails")), (0, react.createElement)("p", { "data-role": "failure-raw" }, failure.message)), fallback.length === 0 ? null : (0, react.createElement)("div", { "data-role": "fallback" }, fallback.map((command) => (0, react.createElement)("button", {
|
|
1002
|
+
key: command,
|
|
1003
|
+
type: "button",
|
|
1004
|
+
"data-role": "fallback-command",
|
|
1005
|
+
onClick: () => {
|
|
1006
|
+
copy(command);
|
|
1007
|
+
}
|
|
1008
|
+
}, command))));
|
|
1009
|
+
}
|
|
1010
|
+
function summaryNode(row, t) {
|
|
1011
|
+
if (row.state !== "pending" || row.summary === void 0) return null;
|
|
1012
|
+
return (0, react.createElement)("div", { "data-role": "pending-summary" }, [
|
|
1013
|
+
["row.summaryA", row.summary.a],
|
|
1014
|
+
["row.summaryB", row.summary.b],
|
|
1015
|
+
["row.rationale", row.summary.rationale]
|
|
1016
|
+
].map(([label, value]) => (0, react.createElement)("div", {
|
|
1017
|
+
key: label,
|
|
1018
|
+
"data-role": "pending-summary-slot"
|
|
1019
|
+
}, (0, react.createElement)("span", { "data-role": "pending-summary-label" }, t(label)), (0, react.createElement)("span", { "data-role": "pending-summary-value" }, value === null || value === "" ? t("row.noSummary") : value))));
|
|
1020
|
+
}
|
|
1021
|
+
function stageNode(row, t) {
|
|
1022
|
+
const stage = row.stageView;
|
|
1023
|
+
if (stage === void 0) return null;
|
|
1024
|
+
const tone = stage.state === "lost" ? "fail" : stage.state === "expired" || stage.state === "reserved" ? "warn" : "neutral";
|
|
1025
|
+
const expiry = stage.expiresAt === void 0 ? "" : " · " + t("row.expires") + " " + new Date(stage.expiresAt).toLocaleString();
|
|
1026
|
+
return (0, react.createElement)("span", {
|
|
1027
|
+
"data-role": "stage-badge",
|
|
1028
|
+
"data-stage": stage.state,
|
|
1029
|
+
"data-tone": tone
|
|
1030
|
+
}, t("stage.state." + stage.state) + expiry);
|
|
1031
|
+
}
|
|
1032
|
+
function runNode(view, t, copy) {
|
|
1033
|
+
const run = view.latestRun;
|
|
1034
|
+
if (run === void 0) return null;
|
|
1035
|
+
const report = run.actions.find((action) => action.id === "report");
|
|
1036
|
+
const reportEnabled = report?.enabled === true;
|
|
1037
|
+
return (0, react.createElement)("div", {
|
|
1038
|
+
"data-role": "run-strip",
|
|
1039
|
+
"data-run-state": run.state
|
|
1040
|
+
}, (0, react.createElement)("span", {
|
|
1041
|
+
"data-role": "run-id",
|
|
1042
|
+
title: run.id
|
|
1043
|
+
}, t("run.id") + " " + run.id), (0, react.createElement)("span", { "data-role": "run-state" }, t("run.state") + " " + t("run." + run.state)), run.stage === void 0 ? null : (0, react.createElement)("span", { "data-role": "run-stage" }, t("stage." + run.stage)), run.progress === null || run.progress === void 0 ? null : (0, react.createElement)("span", { "data-role": "run-progress" }, t("run.progress") + " " + String(run.progress.done) + "/" + String(run.progress.total)), run.endedAt === void 0 ? null : (0, react.createElement)("span", { "data-role": "run-ended" }, t("run.endedAt") + " " + new Date(run.endedAt).toLocaleString()), run.failure === void 0 ? null : (0, react.createElement)("span", {
|
|
1044
|
+
"data-role": "run-failure",
|
|
1045
|
+
title: run.failure.detail
|
|
1046
|
+
}, t("run.failure") + " " + run.failure.code), run.currentPairKey === void 0 ? null : (0, react.createElement)("span", { "data-role": "run-current-pair" }, t("run.currentPair") + " " + run.currentPairKey), run.parentRunId === void 0 ? null : (0, react.createElement)("span", { "data-role": "run-parent" }, t("run.parent") + " " + run.parentRunId), run.resultRef === void 0 ? null : (0, react.createElement)("span", {
|
|
1047
|
+
"data-role": "run-result-ref",
|
|
1048
|
+
title: run.resultRef
|
|
1049
|
+
}, t("run.resultRef")), (0, react.createElement)("button", {
|
|
1050
|
+
type: "button",
|
|
1051
|
+
"data-role": "run-report",
|
|
1052
|
+
"data-action": "report",
|
|
1053
|
+
disabled: !reportEnabled,
|
|
1054
|
+
title: reportEnabled ? report?.command ?? t("run.report") : t("run.noReport"),
|
|
1055
|
+
onClick: () => {
|
|
1056
|
+
if (reportEnabled && report !== void 0) copy(report.command);
|
|
1057
|
+
}
|
|
1058
|
+
}, t("run.report")), ...run.actions.filter((action) => action.id !== "report").map((action) => (0, react.createElement)("button", {
|
|
1059
|
+
key: action.id,
|
|
1060
|
+
type: "button",
|
|
1061
|
+
"data-role": "run-action",
|
|
1062
|
+
"data-action": action.id,
|
|
1063
|
+
disabled: !action.enabled,
|
|
1064
|
+
title: action.disabledReason === void 0 ? action.command : t("disabled." + action.disabledReason),
|
|
1065
|
+
onClick: () => {
|
|
1066
|
+
if (action.enabled) copy(action.command);
|
|
1067
|
+
}
|
|
1068
|
+
}, t("action." + action.id))));
|
|
1069
|
+
}
|
|
1070
|
+
function ReadOnlySetting({ section, label, value, disabled, missing, note, link, t }) {
|
|
1071
|
+
const text = missing ? t("settings.capabilityMissing") : disabled ? t("settings.capabilityDisabled") : value === true ? t("settings.on") : t("settings.off");
|
|
1072
|
+
return (0, react.createElement)("div", {
|
|
1073
|
+
"data-role": "settings-section",
|
|
1074
|
+
"data-section": section,
|
|
1075
|
+
"data-disabled": missing || disabled ? "true" : "false"
|
|
1076
|
+
}, (0, react.createElement)("span", { "data-role": "settings-label" }, label), (0, react.createElement)("span", {
|
|
1077
|
+
"data-role": "settings-value",
|
|
1078
|
+
"data-value": missing ? "missing" : disabled ? "unavailable" : value === true ? "on" : "off"
|
|
1079
|
+
}, text), note === void 0 ? null : (0, react.createElement)("span", { "data-role": "settings-note" }, note), link === true ? (0, react.createElement)("a", {
|
|
1080
|
+
"data-role": "settings-link",
|
|
1081
|
+
href: "#/settings",
|
|
1082
|
+
onClick: () => {
|
|
1083
|
+
window.dispatchEvent(new KeyboardEvent("keydown", {
|
|
1084
|
+
key: ",",
|
|
1085
|
+
code: "Comma",
|
|
1086
|
+
ctrlKey: true,
|
|
1087
|
+
altKey: true,
|
|
1088
|
+
bubbles: true
|
|
1089
|
+
}));
|
|
1090
|
+
}
|
|
1091
|
+
}, t("settings.openPlatform")) : null);
|
|
1092
|
+
}
|
|
1093
|
+
function EditableSetting({ form, field, label, fallback, capability, t }) {
|
|
1094
|
+
const subscribe = (0, react.useCallback)((listener) => form.subscribe(listener), [form]);
|
|
1095
|
+
const readSnapshot = (0, react.useCallback)(() => form["getSnapshot"](), [form]);
|
|
1096
|
+
const snapshot = (0, react.useSyncExternalStore)(subscribe, readSnapshot, readSnapshot);
|
|
1097
|
+
const fieldPresent = snapshot.status !== "ready" || snapshot.value === void 0 || Object.prototype.hasOwnProperty.call(snapshot.value, field);
|
|
1098
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
1099
|
+
const [saved, setSaved] = (0, react.useState)(void 0);
|
|
1100
|
+
const value = snapshot.status === "ready" && typeof snapshot.value?.[field] === "boolean" ? snapshot.value[field] : fallback;
|
|
1101
|
+
const disabled = !capability || busy || snapshot.status !== "ready" || !snapshot.writable;
|
|
1102
|
+
const toggle = async () => {
|
|
1103
|
+
if (disabled) return;
|
|
1104
|
+
setBusy(true);
|
|
1105
|
+
setSaved(void 0);
|
|
1106
|
+
const ok = await saveSetting(form, field, !value);
|
|
1107
|
+
setBusy(false);
|
|
1108
|
+
setSaved(ok ? "saved" : "failed");
|
|
1109
|
+
};
|
|
1110
|
+
if (!fieldPresent) return (0, react.createElement)(ReadOnlySetting, {
|
|
1111
|
+
section: "platform-write",
|
|
1112
|
+
label,
|
|
1113
|
+
value: fallback,
|
|
1114
|
+
disabled: !capability,
|
|
1115
|
+
missing: false,
|
|
1116
|
+
note: t("settings.platformWriteLinkHint"),
|
|
1117
|
+
link: true,
|
|
1118
|
+
t
|
|
548
1119
|
});
|
|
1120
|
+
return (0, react.createElement)("div", {
|
|
1121
|
+
"data-role": "settings-section",
|
|
1122
|
+
"data-section": field === "mergeApproval" ? "merge-approval" : "platform-write",
|
|
1123
|
+
...disabled ? { "data-disabled": "true" } : {}
|
|
1124
|
+
}, (0, react.createElement)("label", { "data-role": "settings-label" }, label), (0, react.createElement)("input", {
|
|
1125
|
+
type: "checkbox",
|
|
1126
|
+
role: "switch",
|
|
1127
|
+
"data-role": "settings-toggle",
|
|
1128
|
+
"data-field": field,
|
|
1129
|
+
"data-value": value ? "on" : "off",
|
|
1130
|
+
checked: value,
|
|
1131
|
+
disabled,
|
|
1132
|
+
onChange: () => {
|
|
1133
|
+
toggle();
|
|
1134
|
+
}
|
|
1135
|
+
}), (0, react.createElement)("span", { "data-role": "settings-value" }, value ? t("settings.on") : t("settings.off")), ...saved === void 0 ? [] : [(0, react.createElement)("span", {
|
|
1136
|
+
"data-role": "settings-save-state",
|
|
1137
|
+
"data-save": saved
|
|
1138
|
+
}, t(saved === "saved" ? "settings.saved" : "settings.saveFailed"))]);
|
|
1139
|
+
}
|
|
1140
|
+
function SettingsCard({ view, settings, t }) {
|
|
1141
|
+
const platform = view.approval.platformWrite;
|
|
1142
|
+
const platformCapability = platform?.capability ?? settings?.platform !== void 0;
|
|
1143
|
+
const platformFallback = platform?.enabled ?? false;
|
|
1144
|
+
const mergeCapability = settings?.merge !== void 0;
|
|
1145
|
+
const mergeFallback = view.approval.mergeApproval;
|
|
1146
|
+
return (0, react.createElement)("div", { "data-role": "settings-card" }, (0, react.createElement)("h3", { "data-role": "settings-title" }, t("settings.title")), (0, react.createElement)("p", { "data-role": "settings-hint" }, t("settings.hint")), settings?.merge === void 0 ? (0, react.createElement)(ReadOnlySetting, {
|
|
1147
|
+
section: "merge-approval",
|
|
1148
|
+
label: t("settings.mergeApproval"),
|
|
1149
|
+
value: mergeFallback,
|
|
1150
|
+
disabled: false,
|
|
1151
|
+
missing: false,
|
|
1152
|
+
t
|
|
1153
|
+
}) : (0, react.createElement)(EditableSetting, {
|
|
1154
|
+
form: settings.merge,
|
|
1155
|
+
field: "mergeApproval",
|
|
1156
|
+
label: t("settings.mergeApproval"),
|
|
1157
|
+
fallback: mergeFallback,
|
|
1158
|
+
capability: mergeCapability,
|
|
1159
|
+
t
|
|
1160
|
+
}), settings?.platform === void 0 ? (0, react.createElement)(ReadOnlySetting, {
|
|
1161
|
+
section: "platform-write",
|
|
1162
|
+
label: t("settings.platformWrite"),
|
|
1163
|
+
value: platformFallback,
|
|
1164
|
+
disabled: platformCapability === false,
|
|
1165
|
+
missing: platform === void 0,
|
|
1166
|
+
note: t("settings.platformWriteLinkHint"),
|
|
1167
|
+
link: true,
|
|
1168
|
+
t
|
|
1169
|
+
}) : (0, react.createElement)(EditableSetting, {
|
|
1170
|
+
form: settings.platform,
|
|
1171
|
+
field: "enabled",
|
|
1172
|
+
label: t("settings.platformWrite"),
|
|
1173
|
+
fallback: platformFallback,
|
|
1174
|
+
capability: platformCapability,
|
|
1175
|
+
t
|
|
1176
|
+
}), settings?.merge === void 0 || settings?.platform === void 0 ? (0, react.createElement)("a", {
|
|
1177
|
+
"data-role": "settings-link",
|
|
1178
|
+
href: "#/settings"
|
|
1179
|
+
}, t("settings.openPlatform")) : null, (0, react.createElement)("p", { "data-role": "settings-readonly" }, settings?.merge === void 0 || settings?.platform === void 0 ? t("settings.readonly") : t("settings.live")));
|
|
1180
|
+
}
|
|
1181
|
+
function rowNode(row, store, t, copy, sort) {
|
|
1182
|
+
const facts = [
|
|
1183
|
+
row.target === void 0 ? void 0 : t("row.target") + " " + row.target,
|
|
1184
|
+
row.targetActual === void 0 ? void 0 : t("row.actualTarget") + " " + row.targetActual,
|
|
1185
|
+
row.verifySubState === void 0 ? void 0 : t("row.verify") + " " + t("verify." + row.verifySubState),
|
|
1186
|
+
row.origin === void 0 ? void 0 : t("row.origin") + " " + t("origin." + row.origin),
|
|
1187
|
+
row.attempts === void 0 ? void 0 : t("row.attempts") + " " + String(row.attempts),
|
|
1188
|
+
row.confidence === void 0 ? void 0 : t("row.confidence") + " " + row.confidence.toFixed(2),
|
|
1189
|
+
row.failure === void 0 ? void 0 : t("row.failure") + " " + row.failure.code + (row.failure.retryable ? "" : " · " + t("row.noRetry")),
|
|
1190
|
+
row.expired === void 0 ? void 0 : t("row.expired") + " " + t("expired." + row.expired),
|
|
1191
|
+
row.reasonCode === void 0 && row.reason === void 0 ? void 0 : t("row.reason") + " " + reasonText(t, row.reasonCode, row.reason ?? "")
|
|
1192
|
+
].filter((value) => value !== void 0).join(" · ");
|
|
1193
|
+
const actions = row.actions.map((action) => (0, react.createElement)("button", {
|
|
1194
|
+
key: action.id,
|
|
1195
|
+
type: "button",
|
|
1196
|
+
"data-role": "row-action",
|
|
1197
|
+
"data-action": action.id,
|
|
1198
|
+
...action.disabledReason === void 0 ? {} : { "data-disabled-reason": action.disabledReason },
|
|
1199
|
+
title: action.disabledReason === void 0 ? action.command : t("disabled." + action.disabledReason),
|
|
1200
|
+
disabled: !action.enabled,
|
|
1201
|
+
onClick: () => {
|
|
1202
|
+
if (!action.enabled) return;
|
|
1203
|
+
if (action.confirm && globalThis.confirm !== void 0 && !globalThis.confirm(t("action.confirm") + " " + (t("action." + action.id) || action.id))) return;
|
|
1204
|
+
copy(action.command);
|
|
1205
|
+
}
|
|
1206
|
+
}, t("action." + action.id)));
|
|
1207
|
+
return (0, react.createElement)("div", {
|
|
1208
|
+
key: row.id,
|
|
1209
|
+
"data-role": "row",
|
|
1210
|
+
"data-row-id": row.id,
|
|
1211
|
+
"data-row-state": row.state,
|
|
1212
|
+
"data-row-queue": row.queue,
|
|
1213
|
+
draggable: true,
|
|
1214
|
+
title: t("sort.drag"),
|
|
1215
|
+
onDragStart: (event) => {
|
|
1216
|
+
if (event.dataTransfer != null) {
|
|
1217
|
+
event.dataTransfer.setData("text/plain", row.id);
|
|
1218
|
+
event.dataTransfer.effectAllowed = "move";
|
|
1219
|
+
}
|
|
1220
|
+
sort.start(row.id);
|
|
1221
|
+
},
|
|
1222
|
+
onDragOver: (event) => {
|
|
1223
|
+
event.preventDefault();
|
|
1224
|
+
if (event.dataTransfer != null) event.dataTransfer.dropEffect = "move";
|
|
1225
|
+
sort.over(event);
|
|
1226
|
+
},
|
|
1227
|
+
onDrop: (event) => {
|
|
1228
|
+
event.preventDefault();
|
|
1229
|
+
sort.drop(row.id);
|
|
1230
|
+
},
|
|
1231
|
+
onDragEnd: () => {
|
|
1232
|
+
sort.end();
|
|
1233
|
+
},
|
|
1234
|
+
onContextMenu: (event) => {
|
|
1235
|
+
event.preventDefault();
|
|
1236
|
+
sort.menu(row.id, event.clientX, event.clientY);
|
|
1237
|
+
}
|
|
1238
|
+
}, (0, react.createElement)("div", null, (0, react.createElement)("div", { "data-role": "row-label" }, row.label), (0, react.createElement)("div", {
|
|
1239
|
+
"data-role": "row-id",
|
|
1240
|
+
title: row.id
|
|
1241
|
+
}, t("row.id") + " " + row.id), (0, react.createElement)("div", { "data-role": "row-meta" }, t("state." + row.state) + (row.stage === null ? "" : " · " + t("stage." + row.stage))), stageNode(row, t), summaryNode(row, t), facts === "" ? null : (0, react.createElement)("div", { "data-role": "row-facts" }, facts)), (0, react.createElement)("div", null, (0, react.createElement)("div", { "data-role": "row-meta" }, new Date(row.updatedAt).toLocaleString()), (0, react.createElement)("div", { "data-role": "row-actions" }, (() => {
|
|
1242
|
+
const bodyA = row.bodies?.find((body) => body.name === row.a);
|
|
1243
|
+
const bodyB = row.bodies?.find((body) => body.name === row.b);
|
|
1244
|
+
return [bodyA === void 0 ? null : (0, react.createElement)("button", {
|
|
1245
|
+
key: "a",
|
|
1246
|
+
type: "button",
|
|
1247
|
+
"data-role": "body-a",
|
|
1248
|
+
onClick: () => {
|
|
1249
|
+
store.openBody(bodyA.name, bodyA.side);
|
|
1250
|
+
}
|
|
1251
|
+
}, "A"), bodyB === void 0 ? null : (0, react.createElement)("button", {
|
|
1252
|
+
key: "b",
|
|
1253
|
+
type: "button",
|
|
1254
|
+
"data-role": "body-b",
|
|
1255
|
+
onClick: () => {
|
|
1256
|
+
store.openBody(bodyB.name, bodyB.side);
|
|
1257
|
+
}
|
|
1258
|
+
}, "B")];
|
|
1259
|
+
})(), actions)));
|
|
1260
|
+
}
|
|
1261
|
+
function bodyNode(overlay, t, onClose) {
|
|
1262
|
+
return (0, react.createElement)("section", {
|
|
1263
|
+
"data-role": "overlay",
|
|
1264
|
+
"data-overlay": "body",
|
|
1265
|
+
role: "dialog",
|
|
1266
|
+
"aria-modal": "true",
|
|
1267
|
+
"aria-label": t("overlay.body")
|
|
1268
|
+
}, (0, react.createElement)("div", { "data-role": "overlay-head" }, (0, react.createElement)("h3", { "data-role": "overlay-title" }, t("overlay.body") + " · " + overlay.name), (0, react.createElement)("button", {
|
|
1269
|
+
type: "button",
|
|
1270
|
+
"data-role": "overlay-close",
|
|
1271
|
+
onClick: onClose
|
|
1272
|
+
}, t("close"))), (0, react.createElement)("p", { "data-role": "overlay-meta" }, t("body." + overlay.side) + " · " + (overlay.status === "ready" ? t("body.totalBytes") + " " + String(overlay.body?.totalBytes ?? 0) : "")), overlay.status === "loading" ? (0, react.createElement)("p", { "data-role": "overlay-loading" }, t("loading")) : null, overlay.status === "error" && overlay.failure !== void 0 ? failureNode(t, overlay.failure, [], () => {}) : null, overlay.status === "ready" && overlay.body !== void 0 ? (0, react.createElement)("div", null, overlay.body.truncated ? (0, react.createElement)("p", { "data-role": "body-truncated" }, t("body.truncated")) : null, overlay.body.text === "" ? (0, react.createElement)("p", { "data-role": "body-empty" }, t("body.empty")) : (0, react.createElement)("pre", { "data-role": "body-text" }, overlay.body.text)) : null);
|
|
1273
|
+
}
|
|
1274
|
+
function historyNode(overlay, t, onClose) {
|
|
1275
|
+
return (0, react.createElement)("section", {
|
|
1276
|
+
"data-role": "overlay",
|
|
1277
|
+
"data-overlay": "history",
|
|
1278
|
+
role: "dialog",
|
|
1279
|
+
"aria-modal": "true",
|
|
1280
|
+
"aria-label": t("history")
|
|
1281
|
+
}, (0, react.createElement)("div", { "data-role": "overlay-head" }, (0, react.createElement)("h3", { "data-role": "overlay-title" }, t("history")), (0, react.createElement)("button", {
|
|
1282
|
+
type: "button",
|
|
1283
|
+
"data-role": "overlay-close",
|
|
1284
|
+
onClick: onClose
|
|
1285
|
+
}, t("close"))), overlay.status === "loading" ? (0, react.createElement)("p", { "data-role": "overlay-loading" }, t("loading")) : null, overlay.status === "error" && overlay.failure !== void 0 ? failureNode(t, overlay.failure, [], () => {}) : null, overlay.status === "ready" ? overlay.items === void 0 || overlay.items.length === 0 ? (0, react.createElement)("p", { "data-role": "history-empty" }, t("history.empty")) : (0, react.createElement)("ul", { "data-role": "history-list" }, overlay.items.map((item) => (0, react.createElement)("li", {
|
|
1286
|
+
key: item.name + ":" + item.archivedAt,
|
|
1287
|
+
"data-role": "history-item"
|
|
1288
|
+
}, item.name + " · " + (() => {
|
|
1289
|
+
const kind = t("history.kind." + item.kind);
|
|
1290
|
+
const reason = reasonText(t, item.reasonCode, item.reason);
|
|
1291
|
+
return kind === reason ? kind : kind + " · " + reason;
|
|
1292
|
+
})() + " · v" + String(item.lastVersion)))) : null);
|
|
549
1293
|
}
|
|
550
1294
|
function MergePanel(face) {
|
|
551
|
-
const t = face
|
|
552
|
-
const
|
|
553
|
-
const [tab, setTab] = (0, react.useState)("pending");
|
|
554
|
-
const [expiredOnly, setExpiredOnly] = (0, react.useState)(false);
|
|
555
|
-
const [rows, setRows] = (0, react.useState)(face.rows);
|
|
556
|
-
const [loading, setLoading] = (0, react.useState)(face.loadRows !== void 0 || face.loadView !== void 0);
|
|
557
|
-
const [failed, setFailed] = (0, react.useState)(void 0);
|
|
558
|
-
const [nextCursor, setNextCursor] = (0, react.useState)(void 0);
|
|
1295
|
+
const { store, t } = face;
|
|
1296
|
+
const snapshot = (0, react.useSyncExternalStore)(store.subscribe, store.read, store.read);
|
|
559
1297
|
const [copied, setCopied] = (0, react.useState)(void 0);
|
|
560
|
-
const [
|
|
561
|
-
const
|
|
562
|
-
const
|
|
1298
|
+
const [orders, setOrders] = (0, react.useState)({});
|
|
1299
|
+
const [dragId, setDragId] = (0, react.useState)(void 0);
|
|
1300
|
+
const [menu, setMenu] = (0, react.useState)(void 0);
|
|
1301
|
+
const workspaceId = resolveWorkspaceId(face.workspaceId);
|
|
1302
|
+
const orderStore = (0, react.useMemo)(() => createRowOrderStore(), []);
|
|
1303
|
+
const copy = (command) => {
|
|
563
1304
|
navigator.clipboard.writeText(command);
|
|
564
1305
|
setCopied(command);
|
|
565
1306
|
};
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
1307
|
+
const doctorCommand = face.doctorCommand ?? DOCTOR_COMMAND;
|
|
1308
|
+
(0, react.useEffect)(() => {
|
|
1309
|
+
store.start();
|
|
1310
|
+
return () => {
|
|
1311
|
+
store.dispose();
|
|
1312
|
+
};
|
|
1313
|
+
}, [store]);
|
|
1314
|
+
(0, react.useEffect)(() => {
|
|
1315
|
+
const onFocus = () => {
|
|
1316
|
+
store.refresh();
|
|
1317
|
+
};
|
|
1318
|
+
const onVisibility = () => {
|
|
1319
|
+
if (document.visibilityState === "visible") store.refresh();
|
|
1320
|
+
};
|
|
1321
|
+
const onRefresh = () => {
|
|
1322
|
+
store.refresh();
|
|
1323
|
+
};
|
|
1324
|
+
window.addEventListener("focus", onFocus);
|
|
1325
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
1326
|
+
window.addEventListener("evolution-merge:refresh", onRefresh);
|
|
1327
|
+
return () => {
|
|
1328
|
+
window.removeEventListener("focus", onFocus);
|
|
1329
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
1330
|
+
window.removeEventListener("evolution-merge:refresh", onRefresh);
|
|
1331
|
+
};
|
|
1332
|
+
}, [store]);
|
|
1333
|
+
const view = snapshot.view;
|
|
1334
|
+
const fallback = [...new Set([...view.commands, ...FALLBACK_COMMANDS])];
|
|
1335
|
+
const blocked = snapshot.viewState === "blocked" && snapshot.viewFailure !== void 0 ? snapshot.viewFailure : void 0;
|
|
1336
|
+
const viewFailure = snapshot.viewState === "error" ? snapshot.viewFailure : void 0;
|
|
1337
|
+
const queue = snapshot.current;
|
|
1338
|
+
const uiState = blocked !== void 0 ? "blocked" : viewFailure !== void 0 ? "error" : snapshot.viewState === "loading" ? "loading" : queue.status === "error" ? "error" : queue.status === "loading" ? "loading" : queue.status === "empty" ? "empty" : "ready";
|
|
1339
|
+
const orderKey = rowOrderKey(workspaceId, snapshot.queue);
|
|
1340
|
+
const visibleOrder = orders[orderKey] ?? orderStore.read(workspaceId, snapshot.queue);
|
|
1341
|
+
const visibleRows = orderRows(queue.rows, visibleOrder);
|
|
1342
|
+
const saveOrder = (ids) => {
|
|
1343
|
+
setOrders((previous) => ({
|
|
1344
|
+
...previous,
|
|
1345
|
+
[orderKey]: ids
|
|
1346
|
+
}));
|
|
1347
|
+
orderStore.write(workspaceId, snapshot.queue, ids);
|
|
603
1348
|
};
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
1349
|
+
const sortHandlers = {
|
|
1350
|
+
start: (id) => {
|
|
1351
|
+
setDragId(id);
|
|
1352
|
+
},
|
|
1353
|
+
over: () => {},
|
|
1354
|
+
end: () => {
|
|
1355
|
+
setDragId(void 0);
|
|
1356
|
+
},
|
|
1357
|
+
drop: (targetId) => {
|
|
1358
|
+
const fromId = dragId;
|
|
1359
|
+
setDragId(void 0);
|
|
1360
|
+
if (fromId === void 0 || fromId === targetId) return;
|
|
1361
|
+
saveOrder(moveRow(visibleRows.map((row) => row.id), fromId, targetId));
|
|
1362
|
+
},
|
|
1363
|
+
menu: (id, x, y) => {
|
|
1364
|
+
setMenu({
|
|
1365
|
+
id,
|
|
1366
|
+
x,
|
|
1367
|
+
y
|
|
620
1368
|
});
|
|
621
|
-
}
|
|
1369
|
+
}
|
|
622
1370
|
};
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
if (outcome.ok) {
|
|
628
|
-
setFailed(void 0);
|
|
629
|
-
setOverlay({
|
|
630
|
-
kind: "history",
|
|
631
|
-
items: outcome.payload.items
|
|
632
|
-
});
|
|
633
|
-
} else setFailed(outcome.failure);
|
|
634
|
-
}).catch(() => {
|
|
635
|
-
setFailed({
|
|
636
|
-
kind: "server",
|
|
637
|
-
status: 0
|
|
638
|
-
});
|
|
639
|
-
});
|
|
1371
|
+
const pinMenu = (edge) => {
|
|
1372
|
+
if (menu === void 0) return;
|
|
1373
|
+
saveOrder(pinRow(visibleRows.map((row) => row.id), menu.id, edge));
|
|
1374
|
+
setMenu(void 0);
|
|
640
1375
|
};
|
|
641
|
-
(0, react.useEffect)(() => {
|
|
642
|
-
loadView();
|
|
643
|
-
loadRows("pending");
|
|
644
|
-
}, [face]);
|
|
645
|
-
(0, react.useEffect)(() => {
|
|
646
|
-
if (tab !== "pending" && expiredOnly) setExpiredOnly(false);
|
|
647
|
-
setNextCursor(void 0);
|
|
648
|
-
loadRows(tab, void 0, tab === "pending" && expiredOnly);
|
|
649
|
-
}, [tab, expiredOnly]);
|
|
650
|
-
const counts = view.counts;
|
|
651
|
-
const latest = view.latestRun;
|
|
652
|
-
const runStrip = latest === void 0 ? null : (0, react.createElement)("div", { "data-role": "run-strip" }, (0, react.createElement)("span", { "data-role": "run-id" }, latest.id), (0, react.createElement)("span", { "data-role": "run-state" }, latest.state), latest.stage === void 0 ? null : (0, react.createElement)("span", { "data-role": "run-stage" }, t("stage." + latest.stage)), latest.progress === void 0 ? null : (0, react.createElement)("span", { "data-role": "run-progress" }, String(latest.progress.done) + "/" + String(latest.progress.total)));
|
|
653
1376
|
const tabs = (0, react.createElement)("div", {
|
|
654
1377
|
"data-role": "tabs",
|
|
655
1378
|
role: "tablist"
|
|
656
|
-
}, QUEUES.map((
|
|
657
|
-
key:
|
|
1379
|
+
}, QUEUES.map((item) => (0, react.createElement)("button", {
|
|
1380
|
+
key: item,
|
|
658
1381
|
type: "button",
|
|
659
1382
|
role: "tab",
|
|
660
|
-
"aria-selected":
|
|
1383
|
+
"aria-selected": snapshot.queue === item ? "true" : "false",
|
|
661
1384
|
"data-role": "tab",
|
|
662
|
-
"data-active":
|
|
1385
|
+
"data-active": snapshot.queue === item ? "true" : "false",
|
|
663
1386
|
onClick: () => {
|
|
664
|
-
|
|
1387
|
+
setMenu(void 0);
|
|
1388
|
+
store.select(item);
|
|
665
1389
|
}
|
|
666
|
-
}, t("tab." +
|
|
667
|
-
const expiredToggle =
|
|
1390
|
+
}, t("tab." + item) + " " + String(view.counts[item]))));
|
|
1391
|
+
const expiredToggle = snapshot.queue === "pending" ? (0, react.createElement)("button", {
|
|
668
1392
|
type: "button",
|
|
669
1393
|
role: "switch",
|
|
670
|
-
"aria-checked": expiredOnly ? "true" : "false",
|
|
1394
|
+
"aria-checked": snapshot.expiredOnly ? "true" : "false",
|
|
671
1395
|
"data-role": "expired-toggle",
|
|
672
|
-
"data-active": expiredOnly ? "true" : "false",
|
|
1396
|
+
"data-active": snapshot.expiredOnly ? "true" : "false",
|
|
673
1397
|
onClick: () => {
|
|
674
|
-
|
|
1398
|
+
store.toggleExpired();
|
|
675
1399
|
}
|
|
676
1400
|
}, t("tab.expired") + " " + String(view.expired)) : null;
|
|
677
|
-
const list =
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
"data-role": "row-action",
|
|
712
|
-
"data-action": action.id,
|
|
713
|
-
title: action.disabledReason === void 0 ? action.command : t("disabled." + action.disabledReason),
|
|
714
|
-
disabled: !action.enabled,
|
|
715
|
-
onClick: () => {
|
|
716
|
-
if (!action.enabled) return;
|
|
717
|
-
if (action.confirm && globalThis.confirm !== void 0 && !globalThis.confirm(t("action.confirm") + " " + t("action." + action.id))) return;
|
|
718
|
-
copyCommand(action.command);
|
|
719
|
-
}
|
|
720
|
-
}, t("action." + action.id))))));
|
|
721
|
-
}));
|
|
1401
|
+
const list = uiState === "ready" && queue.status === "ready" ? (0, react.createElement)("div", { "data-role": "rows" }, visibleRows.map((row) => rowNode(row, store, t, copy, sortHandlers))) : null;
|
|
1402
|
+
const empty = uiState === "empty" ? (0, react.createElement)("div", null, (0, react.createElement)("p", { "data-role": "note" }, t("empty." + snapshot.queue)), (0, react.createElement)("p", { "data-role": "empty-scope" }, t("empty.scope"))) : null;
|
|
1403
|
+
const activeFailure = viewFailure !== void 0 ? viewFailure : queue.status === "error" ? queue.failure : void 0;
|
|
1404
|
+
const overlay = snapshot.overlay;
|
|
1405
|
+
const menuNode = menu === void 0 ? null : (0, react.createElement)("div", {
|
|
1406
|
+
"data-role": "sort-menu",
|
|
1407
|
+
role: "menu",
|
|
1408
|
+
"aria-label": t("sort.menu"),
|
|
1409
|
+
style: {
|
|
1410
|
+
left: String(Math.min(menu.x, Math.max(0, (globalThis.innerWidth || 1440) - 180))) + "px",
|
|
1411
|
+
top: String(Math.min(menu.y, Math.max(0, (globalThis.innerHeight || 800) - 110))) + "px"
|
|
1412
|
+
}
|
|
1413
|
+
}, (0, react.createElement)("button", {
|
|
1414
|
+
type: "button",
|
|
1415
|
+
role: "menuitem",
|
|
1416
|
+
"data-role": "sort-pin-top",
|
|
1417
|
+
onClick: () => {
|
|
1418
|
+
pinMenu("top");
|
|
1419
|
+
}
|
|
1420
|
+
}, t("sort.pinTop")), (0, react.createElement)("button", {
|
|
1421
|
+
type: "button",
|
|
1422
|
+
role: "menuitem",
|
|
1423
|
+
"data-role": "sort-pin-bottom",
|
|
1424
|
+
onClick: () => {
|
|
1425
|
+
pinMenu("bottom");
|
|
1426
|
+
}
|
|
1427
|
+
}, t("sort.pinBottom")), (0, react.createElement)("button", {
|
|
1428
|
+
type: "button",
|
|
1429
|
+
role: "menuitem",
|
|
1430
|
+
"data-role": "sort-cancel",
|
|
1431
|
+
onClick: () => {
|
|
1432
|
+
setMenu(void 0);
|
|
1433
|
+
}
|
|
1434
|
+
}, t("sort.cancel")));
|
|
722
1435
|
return (0, react.createElement)("section", {
|
|
723
1436
|
className: CSS_TAG_ID,
|
|
724
|
-
"data-state":
|
|
725
|
-
}, (0, react.createElement)("h2", { "data-role": "title" }, t("title")), (0, react.createElement)("p", { "data-role": "hint" }, t("hint")), (0, react.createElement)("div", { "data-role": "start" }, (0, react.createElement)("button", {
|
|
1437
|
+
"data-state": uiState
|
|
1438
|
+
}, (0, react.createElement)("h2", { "data-role": "title" }, t("title")), (0, react.createElement)("p", { "data-role": "hint" }, t("hint")), blocked !== void 0 ? failureNode(t, blocked, fallback, copy) : (0, react.createElement)("div", { "data-role": "content" }, (0, react.createElement)("div", { "data-role": "start" }, (0, react.createElement)("button", {
|
|
726
1439
|
type: "button",
|
|
727
1440
|
"data-role": "start-scan",
|
|
728
1441
|
onClick: () => {
|
|
729
|
-
|
|
1442
|
+
copy(view.startCommands.scan);
|
|
730
1443
|
}
|
|
731
1444
|
}, t("start.scan")), (0, react.createElement)("button", {
|
|
732
1445
|
type: "button",
|
|
733
1446
|
"data-role": "start-pair",
|
|
734
1447
|
onClick: () => {
|
|
735
|
-
|
|
736
|
-
}
|
|
737
|
-
}, t("start.pair"))), view.degraded ? (0, react.createElement)("p", { "data-role": "degraded" }, t("degraded") + " " + view.notes.join(",")) : null, view.approval === void 0 ? null : (0, react.createElement)("p", { "data-role": "approval" }, t(view.approval ? "approval.on" : "approval.off")), runStrip, tabs, expiredToggle, loading ? (0, react.createElement)("p", { "data-role": "note" }, t("loading")) : null, failed === void 0 ? null : (0, react.createElement)("div", { "data-role": "failure" }, failure(t, failed), (0, react.createElement)("div", { "data-role": "fallback" }, view.commands.map((command) => (0, react.createElement)("button", {
|
|
738
|
-
key: command,
|
|
739
|
-
type: "button",
|
|
740
|
-
"data-role": "fallback-command",
|
|
741
|
-
onClick: () => {
|
|
742
|
-
copyCommand(command);
|
|
1448
|
+
copy(view.startCommands.pair);
|
|
743
1449
|
}
|
|
744
|
-
},
|
|
1450
|
+
}, t("start.pair"))), view.degraded ? (0, react.createElement)("p", { "data-role": "degraded" }, t("degraded") + " " + view.notes.join(",")) : null, (0, react.createElement)(SettingsCard, {
|
|
1451
|
+
view,
|
|
1452
|
+
settings: face.settings,
|
|
1453
|
+
t
|
|
1454
|
+
}), runNode(view, t, copy), tabs, expiredToggle, snapshot.viewState === "loading" || queue.status === "loading" ? (0, react.createElement)("p", { "data-role": "note" }, t("loading")) : null, activeFailure === void 0 ? null : failureNode(t, activeFailure, fallback, copy), copied === void 0 ? null : (0, react.createElement)("p", {
|
|
745
1455
|
"data-role": "copied",
|
|
746
1456
|
role: "status"
|
|
747
|
-
}, t("copied") + " " + copied), list, nextCursor === void 0 ? null : (0, react.createElement)("button", {
|
|
1457
|
+
}, t("copied") + " " + copied), list, empty, queue.nextCursor === void 0 || uiState !== "ready" ? null : (0, react.createElement)("button", {
|
|
748
1458
|
type: "button",
|
|
749
1459
|
"data-role": "load-more",
|
|
1460
|
+
disabled: queue.status === "loading",
|
|
750
1461
|
onClick: () => {
|
|
751
|
-
|
|
1462
|
+
store.loadMore();
|
|
752
1463
|
}
|
|
753
|
-
}, t("loadMore")),
|
|
1464
|
+
}, t("loadMore")), (0, react.createElement)("button", {
|
|
754
1465
|
type: "button",
|
|
755
1466
|
"data-role": "history",
|
|
756
|
-
onClick:
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
"aria-modal": "true",
|
|
761
|
-
"aria-label": overlay.kind === "body" ? t("overlay.body") : t("history")
|
|
762
|
-
}, (0, react.createElement)("h3", { "data-role": "overlay-title" }, overlay.kind === "body" ? t("overlay.body") : t("history")), (0, react.createElement)("button", {
|
|
1467
|
+
onClick: () => {
|
|
1468
|
+
store.openHistory();
|
|
1469
|
+
}
|
|
1470
|
+
}, t("history")), (0, react.createElement)("button", {
|
|
763
1471
|
type: "button",
|
|
764
|
-
"data-role": "
|
|
1472
|
+
"data-role": "doctor",
|
|
765
1473
|
onClick: () => {
|
|
766
|
-
|
|
1474
|
+
copy(doctorCommand);
|
|
767
1475
|
}
|
|
768
|
-
}, t("
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
})
|
|
1476
|
+
}, t("doctor.open")), overlay === void 0 ? null : overlay.kind === "body" ? bodyNode(overlay, t, () => {
|
|
1477
|
+
store.closeOverlay();
|
|
1478
|
+
}) : historyNode(overlay, t, () => {
|
|
1479
|
+
store.closeOverlay();
|
|
1480
|
+
}), (0, react.createElement)("button", {
|
|
773
1481
|
type: "button",
|
|
774
1482
|
"data-role": "refresh",
|
|
775
1483
|
onClick: () => {
|
|
776
|
-
|
|
777
|
-
loadRows(tab, void 0, tab === "pending" && expiredOnly);
|
|
1484
|
+
store.refresh();
|
|
778
1485
|
}
|
|
779
|
-
}, t("refresh")));
|
|
1486
|
+
}, t("refresh")), menuNode));
|
|
780
1487
|
}
|
|
781
1488
|
//#endregion
|
|
1489
|
+
//#region src/client/MergeStore.ts
|
|
1490
|
+
const emptyView = () => ({
|
|
1491
|
+
counts: {
|
|
1492
|
+
verify: 0,
|
|
1493
|
+
pending: 0,
|
|
1494
|
+
fuse: 0,
|
|
1495
|
+
skipped: 0
|
|
1496
|
+
},
|
|
1497
|
+
expired: 0,
|
|
1498
|
+
tabs: [
|
|
1499
|
+
{
|
|
1500
|
+
queue: "verify",
|
|
1501
|
+
count: 0
|
|
1502
|
+
},
|
|
1503
|
+
{
|
|
1504
|
+
queue: "pending",
|
|
1505
|
+
count: 0
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
queue: "fuse",
|
|
1509
|
+
count: 0
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
queue: "skipped",
|
|
1513
|
+
count: 0
|
|
1514
|
+
}
|
|
1515
|
+
],
|
|
1516
|
+
commands: [],
|
|
1517
|
+
startCommands: {
|
|
1518
|
+
scan: "/evolution merge scan",
|
|
1519
|
+
pair: "/evolution merge pair <a> <b>"
|
|
1520
|
+
},
|
|
1521
|
+
notes: [],
|
|
1522
|
+
degraded: false,
|
|
1523
|
+
approval: { mergeApproval: false }
|
|
1524
|
+
});
|
|
1525
|
+
const keyOf = (queue, expiredOnly) => queue + ":" + (expiredOnly ? "1" : "0");
|
|
1526
|
+
const loadingQueue = () => ({
|
|
1527
|
+
status: "loading",
|
|
1528
|
+
rows: []
|
|
1529
|
+
});
|
|
1530
|
+
var MergeStore = class {
|
|
1531
|
+
source;
|
|
1532
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1533
|
+
cache = /* @__PURE__ */ new Map();
|
|
1534
|
+
tokens = /* @__PURE__ */ new Map();
|
|
1535
|
+
viewToken = 0;
|
|
1536
|
+
overlayToken = 0;
|
|
1537
|
+
snapshot;
|
|
1538
|
+
started = false;
|
|
1539
|
+
disposed = false;
|
|
1540
|
+
constructor(source, initial = {}) {
|
|
1541
|
+
this.source = source;
|
|
1542
|
+
const queue = initial.queue ?? "pending";
|
|
1543
|
+
const expiredOnly = queue === "pending" ? initial.expiredOnly ?? false : false;
|
|
1544
|
+
const initialRows = initial.rows;
|
|
1545
|
+
const current = initialRows === void 0 ? loadingQueue() : {
|
|
1546
|
+
status: initialRows.length === 0 ? "empty" : "ready",
|
|
1547
|
+
rows: initialRows
|
|
1548
|
+
};
|
|
1549
|
+
if (initialRows !== void 0) this.cache.set(keyOf(queue, expiredOnly), current);
|
|
1550
|
+
this.snapshot = {
|
|
1551
|
+
view: initial.view ?? emptyView(),
|
|
1552
|
+
viewState: initial.view === void 0 ? "loading" : "ready",
|
|
1553
|
+
queue,
|
|
1554
|
+
expiredOnly,
|
|
1555
|
+
current
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
read = () => this.snapshot;
|
|
1559
|
+
subscribe = (listener) => {
|
|
1560
|
+
this.listeners.add(listener);
|
|
1561
|
+
return () => {
|
|
1562
|
+
this.listeners.delete(listener);
|
|
1563
|
+
};
|
|
1564
|
+
};
|
|
1565
|
+
emit() {
|
|
1566
|
+
if (this.disposed) return;
|
|
1567
|
+
for (const listener of this.listeners) listener();
|
|
1568
|
+
}
|
|
1569
|
+
set(next) {
|
|
1570
|
+
this.snapshot = next;
|
|
1571
|
+
this.emit();
|
|
1572
|
+
}
|
|
1573
|
+
isCurrent(queue, expiredOnly) {
|
|
1574
|
+
return this.snapshot.queue === queue && this.snapshot.expiredOnly === expiredOnly;
|
|
1575
|
+
}
|
|
1576
|
+
start() {
|
|
1577
|
+
if (this.started || this.disposed) return;
|
|
1578
|
+
this.started = true;
|
|
1579
|
+
this.loadView();
|
|
1580
|
+
this.loadQueue(this.snapshot.queue, this.snapshot.expiredOnly);
|
|
1581
|
+
}
|
|
1582
|
+
async loadView(showLoading = true) {
|
|
1583
|
+
const token = ++this.viewToken;
|
|
1584
|
+
if (showLoading) this.set({
|
|
1585
|
+
...this.snapshot,
|
|
1586
|
+
viewState: "loading",
|
|
1587
|
+
viewFailure: void 0
|
|
1588
|
+
});
|
|
1589
|
+
const outcome = await this.source.view();
|
|
1590
|
+
if (this.disposed || token !== this.viewToken) return;
|
|
1591
|
+
if (!outcome.ok) {
|
|
1592
|
+
if (outcome.failure.kind === "blocked") {
|
|
1593
|
+
this.set({
|
|
1594
|
+
...this.snapshot,
|
|
1595
|
+
viewState: "blocked",
|
|
1596
|
+
viewFailure: outcome.failure,
|
|
1597
|
+
current: {
|
|
1598
|
+
status: "idle",
|
|
1599
|
+
rows: []
|
|
1600
|
+
}
|
|
1601
|
+
});
|
|
1602
|
+
for (const key of this.cache.keys()) this.cache.set(key, {
|
|
1603
|
+
status: "idle",
|
|
1604
|
+
rows: []
|
|
1605
|
+
});
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1608
|
+
this.set({
|
|
1609
|
+
...this.snapshot,
|
|
1610
|
+
viewState: "error",
|
|
1611
|
+
viewFailure: outcome.failure
|
|
1612
|
+
});
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
this.set({
|
|
1616
|
+
...this.snapshot,
|
|
1617
|
+
view: outcome.payload,
|
|
1618
|
+
viewState: "ready",
|
|
1619
|
+
viewFailure: void 0
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
async loadQueue(queue, expiredOnly, cursor) {
|
|
1623
|
+
const key = keyOf(queue, expiredOnly);
|
|
1624
|
+
const token = (this.tokens.get(key) ?? 0) + 1;
|
|
1625
|
+
this.tokens.set(key, token);
|
|
1626
|
+
const previous = this.cache.get(key);
|
|
1627
|
+
const next = cursor === void 0 ? {
|
|
1628
|
+
status: "loading",
|
|
1629
|
+
rows: []
|
|
1630
|
+
} : {
|
|
1631
|
+
status: "loading",
|
|
1632
|
+
rows: previous?.rows ?? [],
|
|
1633
|
+
...previous?.nextCursor === void 0 ? {} : { nextCursor: previous.nextCursor }
|
|
1634
|
+
};
|
|
1635
|
+
this.cache.set(key, next);
|
|
1636
|
+
if (this.isCurrent(queue, expiredOnly)) this.set({
|
|
1637
|
+
...this.snapshot,
|
|
1638
|
+
current: next
|
|
1639
|
+
});
|
|
1640
|
+
const outcome = await this.source.rows(queue, cursor, queue === "pending" && expiredOnly);
|
|
1641
|
+
if (this.disposed || token !== this.tokens.get(key)) return;
|
|
1642
|
+
if (!outcome.ok) {
|
|
1643
|
+
if (outcome.failure.kind === "blocked") {
|
|
1644
|
+
this.set({
|
|
1645
|
+
...this.snapshot,
|
|
1646
|
+
viewState: "blocked",
|
|
1647
|
+
viewFailure: outcome.failure,
|
|
1648
|
+
current: {
|
|
1649
|
+
status: "idle",
|
|
1650
|
+
rows: []
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
return;
|
|
1654
|
+
}
|
|
1655
|
+
const failed = {
|
|
1656
|
+
status: "error",
|
|
1657
|
+
rows: [],
|
|
1658
|
+
failure: outcome.failure
|
|
1659
|
+
};
|
|
1660
|
+
this.cache.set(key, failed);
|
|
1661
|
+
if (this.isCurrent(queue, expiredOnly)) this.set({
|
|
1662
|
+
...this.snapshot,
|
|
1663
|
+
current: failed
|
|
1664
|
+
});
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
const items = cursor === void 0 ? outcome.payload.items : [...previous?.rows ?? [], ...outcome.payload.items];
|
|
1668
|
+
const ready = {
|
|
1669
|
+
status: items.length === 0 ? "empty" : "ready",
|
|
1670
|
+
rows: items,
|
|
1671
|
+
...outcome.payload.nextCursor === void 0 ? {} : { nextCursor: outcome.payload.nextCursor }
|
|
1672
|
+
};
|
|
1673
|
+
this.cache.set(key, ready);
|
|
1674
|
+
if (this.isCurrent(queue, expiredOnly)) this.set({
|
|
1675
|
+
...this.snapshot,
|
|
1676
|
+
current: ready,
|
|
1677
|
+
expiredOnly,
|
|
1678
|
+
queue
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
select(queue) {
|
|
1682
|
+
const expiredOnly = queue === "pending" ? this.snapshot.expiredOnly : false;
|
|
1683
|
+
if (queue === this.snapshot.queue && expiredOnly === this.snapshot.expiredOnly) return;
|
|
1684
|
+
const key = keyOf(queue, expiredOnly);
|
|
1685
|
+
const cached = this.cache.get(key);
|
|
1686
|
+
const current = cached ?? loadingQueue();
|
|
1687
|
+
this.set({
|
|
1688
|
+
...this.snapshot,
|
|
1689
|
+
queue,
|
|
1690
|
+
expiredOnly,
|
|
1691
|
+
current,
|
|
1692
|
+
overlay: void 0
|
|
1693
|
+
});
|
|
1694
|
+
if (cached === void 0) this.loadQueue(queue, expiredOnly);
|
|
1695
|
+
}
|
|
1696
|
+
toggleExpired() {
|
|
1697
|
+
if (this.snapshot.queue !== "pending") return;
|
|
1698
|
+
const expiredOnly = !this.snapshot.expiredOnly;
|
|
1699
|
+
const key = keyOf("pending", expiredOnly);
|
|
1700
|
+
const cached = this.cache.get(key);
|
|
1701
|
+
const current = cached ?? loadingQueue();
|
|
1702
|
+
this.set({
|
|
1703
|
+
...this.snapshot,
|
|
1704
|
+
expiredOnly,
|
|
1705
|
+
current,
|
|
1706
|
+
overlay: void 0
|
|
1707
|
+
});
|
|
1708
|
+
if (cached === void 0) this.loadQueue("pending", expiredOnly);
|
|
1709
|
+
}
|
|
1710
|
+
refresh() {
|
|
1711
|
+
if (this.disposed) return;
|
|
1712
|
+
this.loadView(true);
|
|
1713
|
+
this.loadQueue(this.snapshot.queue, this.snapshot.expiredOnly);
|
|
1714
|
+
}
|
|
1715
|
+
loadMore() {
|
|
1716
|
+
const current = this.snapshot.current;
|
|
1717
|
+
if (current.nextCursor === void 0 || current.status === "loading" || this.snapshot.viewState === "blocked") return;
|
|
1718
|
+
this.loadQueue(this.snapshot.queue, this.snapshot.expiredOnly, current.nextCursor);
|
|
1719
|
+
}
|
|
1720
|
+
async openBody(name, side) {
|
|
1721
|
+
const token = ++this.overlayToken;
|
|
1722
|
+
this.set({
|
|
1723
|
+
...this.snapshot,
|
|
1724
|
+
overlay: {
|
|
1725
|
+
kind: "body",
|
|
1726
|
+
name,
|
|
1727
|
+
side,
|
|
1728
|
+
status: "loading"
|
|
1729
|
+
}
|
|
1730
|
+
});
|
|
1731
|
+
const outcome = await this.source.body(name, side);
|
|
1732
|
+
if (this.disposed || token !== this.overlayToken) return;
|
|
1733
|
+
if (!outcome.ok) {
|
|
1734
|
+
if (outcome.failure.kind === "blocked") {
|
|
1735
|
+
this.set({
|
|
1736
|
+
...this.snapshot,
|
|
1737
|
+
viewState: "blocked",
|
|
1738
|
+
viewFailure: outcome.failure,
|
|
1739
|
+
overlay: void 0
|
|
1740
|
+
});
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
this.set({
|
|
1744
|
+
...this.snapshot,
|
|
1745
|
+
overlay: {
|
|
1746
|
+
kind: "body",
|
|
1747
|
+
name,
|
|
1748
|
+
side,
|
|
1749
|
+
status: "error",
|
|
1750
|
+
failure: outcome.failure
|
|
1751
|
+
}
|
|
1752
|
+
});
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
this.set({
|
|
1756
|
+
...this.snapshot,
|
|
1757
|
+
overlay: {
|
|
1758
|
+
kind: "body",
|
|
1759
|
+
name,
|
|
1760
|
+
side,
|
|
1761
|
+
status: "ready",
|
|
1762
|
+
body: outcome.payload
|
|
1763
|
+
}
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
async openHistory() {
|
|
1767
|
+
const token = ++this.overlayToken;
|
|
1768
|
+
this.set({
|
|
1769
|
+
...this.snapshot,
|
|
1770
|
+
overlay: {
|
|
1771
|
+
kind: "history",
|
|
1772
|
+
status: "loading"
|
|
1773
|
+
}
|
|
1774
|
+
});
|
|
1775
|
+
const outcome = await this.source.history();
|
|
1776
|
+
if (this.disposed || token !== this.overlayToken) return;
|
|
1777
|
+
if (!outcome.ok) {
|
|
1778
|
+
if (outcome.failure.kind === "blocked") {
|
|
1779
|
+
this.set({
|
|
1780
|
+
...this.snapshot,
|
|
1781
|
+
viewState: "blocked",
|
|
1782
|
+
viewFailure: outcome.failure,
|
|
1783
|
+
overlay: void 0
|
|
1784
|
+
});
|
|
1785
|
+
return;
|
|
1786
|
+
}
|
|
1787
|
+
this.set({
|
|
1788
|
+
...this.snapshot,
|
|
1789
|
+
overlay: {
|
|
1790
|
+
kind: "history",
|
|
1791
|
+
status: "error",
|
|
1792
|
+
failure: outcome.failure
|
|
1793
|
+
}
|
|
1794
|
+
});
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
this.set({
|
|
1798
|
+
...this.snapshot,
|
|
1799
|
+
overlay: {
|
|
1800
|
+
kind: "history",
|
|
1801
|
+
status: "ready",
|
|
1802
|
+
items: outcome.payload.items
|
|
1803
|
+
}
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
closeOverlay() {
|
|
1807
|
+
this.overlayToken += 1;
|
|
1808
|
+
this.set({
|
|
1809
|
+
...this.snapshot,
|
|
1810
|
+
overlay: void 0
|
|
1811
|
+
});
|
|
1812
|
+
}
|
|
1813
|
+
dispose() {
|
|
1814
|
+
this.disposed = true;
|
|
1815
|
+
this.listeners.clear();
|
|
1816
|
+
}
|
|
1817
|
+
};
|
|
1818
|
+
//#endregion
|
|
782
1819
|
//#region src/client/index.ts
|
|
783
1820
|
const inject = ["slots", "locale"];
|
|
784
1821
|
function PanelIcon(props = {}) {
|
|
@@ -795,51 +1832,19 @@ window.__ModuleLoader__.load({
|
|
|
795
1832
|
strokeLinejoin: "round"
|
|
796
1833
|
}, (0, react.createElement)("path", { d: "M3 4h10M3 8h6M3 12h8" }));
|
|
797
1834
|
}
|
|
798
|
-
function
|
|
799
|
-
return
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
},
|
|
812
|
-
{
|
|
813
|
-
queue: "pending",
|
|
814
|
-
count: 0
|
|
815
|
-
},
|
|
816
|
-
{
|
|
817
|
-
queue: "fuse",
|
|
818
|
-
count: 0
|
|
819
|
-
},
|
|
820
|
-
{
|
|
821
|
-
queue: "skipped",
|
|
822
|
-
count: 0
|
|
823
|
-
}
|
|
824
|
-
],
|
|
825
|
-
commands: [
|
|
826
|
-
"/evolution merge scan",
|
|
827
|
-
"/evolution merge pair <a> <b>",
|
|
828
|
-
"/evolution merge candidates",
|
|
829
|
-
"/evolution merge pending",
|
|
830
|
-
"/evolution merge resume",
|
|
831
|
-
"/evolution merge skipped",
|
|
832
|
-
"/evolution merge status",
|
|
833
|
-
"/evolution merge report",
|
|
834
|
-
"/evolution merge doctor"
|
|
835
|
-
],
|
|
836
|
-
startCommands: {
|
|
837
|
-
scan: "/evolution merge scan",
|
|
838
|
-
pair: "/evolution merge pair <a> <b>"
|
|
839
|
-
},
|
|
840
|
-
notes: [],
|
|
841
|
-
degraded: false
|
|
842
|
-
};
|
|
1835
|
+
function interpolate(text, values) {
|
|
1836
|
+
if (values === void 0) return text;
|
|
1837
|
+
return text.replace(/\{(\w+)\}/g, (_match, key) => String(values[key] ?? ""));
|
|
1838
|
+
}
|
|
1839
|
+
/** Best-effort panel workspace; the merge panel itself is not workspace-keyed. */
|
|
1840
|
+
function panelWorkspaceId(ctx) {
|
|
1841
|
+
const get = ctx.get;
|
|
1842
|
+
if (typeof get !== "function") return void 0;
|
|
1843
|
+
for (const name of ["workspace", "uiWorkspace"]) try {
|
|
1844
|
+
const seat = get.call(ctx, name);
|
|
1845
|
+
const id = seat?.workspaceId ?? seat?.currentWorkspaceId;
|
|
1846
|
+
if (typeof id === "string" && id.trim() !== "") return id;
|
|
1847
|
+
} catch {}
|
|
843
1848
|
}
|
|
844
1849
|
function apply(ctx) {
|
|
845
1850
|
const seam = ctx;
|
|
@@ -867,14 +1872,15 @@ window.__ModuleLoader__.load({
|
|
|
867
1872
|
tag.remove();
|
|
868
1873
|
};
|
|
869
1874
|
}, "evolution-merge-ui: styles");
|
|
870
|
-
const t = (key) => {
|
|
1875
|
+
const t = (key, values) => {
|
|
871
1876
|
const fallback = zh[key] ?? key;
|
|
872
|
-
|
|
873
|
-
try {
|
|
874
|
-
|
|
1877
|
+
let text = fallback;
|
|
1878
|
+
if (registered) try {
|
|
1879
|
+
text = seam.locale.bind(NS)(key);
|
|
875
1880
|
} catch {
|
|
876
|
-
|
|
1881
|
+
text = fallback;
|
|
877
1882
|
}
|
|
1883
|
+
return interpolate(text, values);
|
|
878
1884
|
};
|
|
879
1885
|
const label = () => t("entry.label");
|
|
880
1886
|
seam.slots.inject("sidebar.panellist", function* () {
|
|
@@ -887,15 +1893,31 @@ window.__ModuleLoader__.load({
|
|
|
887
1893
|
yield seam.slots.register({
|
|
888
1894
|
name: "main",
|
|
889
1895
|
key: PANEL_ID,
|
|
890
|
-
inject: () =>
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1896
|
+
inject: () => {
|
|
1897
|
+
const source = {
|
|
1898
|
+
view,
|
|
1899
|
+
rows,
|
|
1900
|
+
body,
|
|
1901
|
+
history
|
|
1902
|
+
};
|
|
1903
|
+
let seat;
|
|
1904
|
+
try {
|
|
1905
|
+
seat = ctx.get?.("configForms");
|
|
1906
|
+
} catch {
|
|
1907
|
+
seat = void 0;
|
|
1908
|
+
}
|
|
1909
|
+
const workspaceId = panelWorkspaceId(ctx);
|
|
1910
|
+
return {
|
|
1911
|
+
store: new MergeStore(source),
|
|
1912
|
+
t,
|
|
1913
|
+
doctorCommand: "/evolution doctor",
|
|
1914
|
+
settings: { ...seat === void 0 ? {} : {
|
|
1915
|
+
merge: seat.get("evolution-merge"),
|
|
1916
|
+
platform: seat.get("evolution-approval")
|
|
1917
|
+
} },
|
|
1918
|
+
...workspaceId === void 0 ? {} : { workspaceId }
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
899
1921
|
}, MergePanel);
|
|
900
1922
|
});
|
|
901
1923
|
}
|