@lmzhen/dsh-evolution-merge-ui 0.33.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js
CHANGED
|
@@ -163,34 +163,51 @@ window.__ModuleLoader__.load({
|
|
|
163
163
|
...EMPTY,
|
|
164
164
|
reason: "seat-missing"
|
|
165
165
|
};
|
|
166
|
+
let lastReady;
|
|
167
|
+
let generation = 0;
|
|
166
168
|
const listeners = /* @__PURE__ */ new Set();
|
|
167
|
-
let
|
|
168
|
-
let listening = false;
|
|
169
|
+
let remoteOff;
|
|
169
170
|
const notify = () => {
|
|
170
171
|
for (const listener of listeners) listener();
|
|
171
172
|
};
|
|
172
|
-
const
|
|
173
|
-
|
|
173
|
+
const absorb = (next) => {
|
|
174
|
+
if (next.status === "ready") {
|
|
175
|
+
lastReady = next;
|
|
176
|
+
snapshot = next;
|
|
177
|
+
} else if (lastReady !== void 0) snapshot = {
|
|
178
|
+
...lastReady,
|
|
179
|
+
stale: true,
|
|
180
|
+
reason: next.reason ?? "readback-failed"
|
|
181
|
+
};
|
|
182
|
+
else snapshot = next;
|
|
174
183
|
notify();
|
|
175
184
|
};
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
185
|
+
const refresh = async () => {
|
|
186
|
+
const ticket = ++generation;
|
|
187
|
+
const next = await describe(namespace);
|
|
188
|
+
if (ticket !== generation) return;
|
|
189
|
+
absorb(next);
|
|
190
|
+
};
|
|
191
|
+
const remote = () => ctx.get?.("remote");
|
|
192
|
+
const stopRemote = () => {
|
|
193
|
+
remoteOff?.();
|
|
194
|
+
remoteOff = void 0;
|
|
195
|
+
};
|
|
196
|
+
const startRemote = () => {
|
|
197
|
+
if (remoteOff !== void 0) return;
|
|
198
|
+
remoteOff = remote()?.$on?.("settings/document-updated", (changed) => {
|
|
199
|
+
if (changed === namespace) refresh();
|
|
200
|
+
});
|
|
186
201
|
};
|
|
187
202
|
const form = {
|
|
188
203
|
getSnapshot: () => snapshot,
|
|
189
204
|
subscribe: (listener) => {
|
|
190
205
|
listeners.add(listener);
|
|
191
|
-
|
|
206
|
+
startRemote();
|
|
207
|
+
refresh();
|
|
192
208
|
return () => {
|
|
193
209
|
listeners.delete(listener);
|
|
210
|
+
if (listeners.size === 0) stopRemote();
|
|
194
211
|
};
|
|
195
212
|
},
|
|
196
213
|
set: async (field, value) => await form.mutate([{
|
|
@@ -204,35 +221,39 @@ window.__ModuleLoader__.load({
|
|
|
204
221
|
}]),
|
|
205
222
|
mutate: async (ops, expectedRevision) => {
|
|
206
223
|
const outcome = await write(namespace, ops, expectedRevision ?? snapshot.revision);
|
|
207
|
-
if (outcome.snapshot !== void 0)
|
|
208
|
-
|
|
209
|
-
notify();
|
|
210
|
-
} else await refresh();
|
|
224
|
+
if (outcome.snapshot !== void 0) absorb(outcome.snapshot);
|
|
225
|
+
else await refresh();
|
|
211
226
|
return outcome.ok;
|
|
227
|
+
},
|
|
228
|
+
refresh,
|
|
229
|
+
dispose: () => {
|
|
230
|
+
stopRemote();
|
|
231
|
+
listeners.clear();
|
|
212
232
|
}
|
|
213
233
|
};
|
|
214
234
|
return form;
|
|
215
235
|
}
|
|
216
236
|
/**
|
|
217
|
-
* Build one
|
|
218
|
-
*
|
|
219
|
-
*
|
|
237
|
+
* Build one seat per client registration; every form's remote listener is released by
|
|
238
|
+
* the caller's effect. No module-level WeakMap: a replaced registration must not share
|
|
239
|
+
* a dead seat with the previous one.
|
|
220
240
|
*/
|
|
221
|
-
const seats = /* @__PURE__ */ new WeakMap();
|
|
222
241
|
function createSettingsSeat(ctx) {
|
|
223
|
-
const cached = seats.get(ctx);
|
|
224
|
-
if (cached !== void 0) return cached;
|
|
225
242
|
const forms = /* @__PURE__ */ new Map();
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
form
|
|
230
|
-
|
|
243
|
+
return {
|
|
244
|
+
get(namespace) {
|
|
245
|
+
let form = forms.get(namespace);
|
|
246
|
+
if (form === void 0) {
|
|
247
|
+
form = createForm(namespace, ctx);
|
|
248
|
+
forms.set(namespace, form);
|
|
249
|
+
}
|
|
250
|
+
return form;
|
|
251
|
+
},
|
|
252
|
+
dispose: () => {
|
|
253
|
+
for (const form of forms.values()) form.dispose?.();
|
|
254
|
+
forms.clear();
|
|
231
255
|
}
|
|
232
|
-
|
|
233
|
-
} };
|
|
234
|
-
seats.set(ctx, seat);
|
|
235
|
-
return seat;
|
|
256
|
+
};
|
|
236
257
|
}
|
|
237
258
|
//#endregion
|
|
238
259
|
//#region ../evolution-client-kit/src/workspace.ts
|
|
@@ -491,7 +512,8 @@ window.__ModuleLoader__.load({
|
|
|
491
512
|
startCommands: facts.startCommands,
|
|
492
513
|
notes: [...facts.notes],
|
|
493
514
|
degraded: facts.degraded,
|
|
494
|
-
...facts.active === null
|
|
515
|
+
...facts.active === null ? {} : { activeRun: toRun(facts.active) },
|
|
516
|
+
...facts.last === null ? {} : { lastRun: toRun(facts.last) },
|
|
495
517
|
approval: {
|
|
496
518
|
mergeApproval: facts.approval.mergeApproval,
|
|
497
519
|
...platformWrite === void 0 ? {} : { platformWrite }
|
|
@@ -518,9 +540,14 @@ window.__ModuleLoader__.load({
|
|
|
518
540
|
};
|
|
519
541
|
}
|
|
520
542
|
async function body(name, side, rowId) {
|
|
521
|
-
const
|
|
543
|
+
const query = new URLSearchParams({
|
|
544
|
+
name,
|
|
545
|
+
side
|
|
546
|
+
});
|
|
547
|
+
if (rowId !== void 0) query.set("id", rowId);
|
|
548
|
+
const answer = await requestWire(HOST_ROUTES.body + "?" + query.toString());
|
|
522
549
|
if (!answer.ok) {
|
|
523
|
-
if (answer.failure.kind === "problem" && answer.failure.code === "bad-query" && (answer.failure.message ?? "").includes("
|
|
550
|
+
if (answer.failure.kind === "problem" && answer.failure.code === "bad-query" && (answer.failure.message ?? "").includes("ambiguous")) return {
|
|
524
551
|
ok: false,
|
|
525
552
|
failure: {
|
|
526
553
|
...answer.failure,
|
|
@@ -541,6 +568,56 @@ window.__ModuleLoader__.load({
|
|
|
541
568
|
}
|
|
542
569
|
};
|
|
543
570
|
}
|
|
571
|
+
async function decide(rowId, verb, sessionId) {
|
|
572
|
+
const path = HOST_ROUTES.body.replace(/body$/, "decision");
|
|
573
|
+
let response;
|
|
574
|
+
try {
|
|
575
|
+
response = await fetch(path, {
|
|
576
|
+
method: "POST",
|
|
577
|
+
headers: {
|
|
578
|
+
accept: "application/json",
|
|
579
|
+
"content-type": "application/json"
|
|
580
|
+
},
|
|
581
|
+
body: JSON.stringify({
|
|
582
|
+
rowId,
|
|
583
|
+
verb,
|
|
584
|
+
sessionId
|
|
585
|
+
})
|
|
586
|
+
});
|
|
587
|
+
} catch {
|
|
588
|
+
return {
|
|
589
|
+
ok: false,
|
|
590
|
+
failure: problem("server", 0)
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
let body;
|
|
594
|
+
try {
|
|
595
|
+
body = await response.json();
|
|
596
|
+
} catch {
|
|
597
|
+
return {
|
|
598
|
+
ok: false,
|
|
599
|
+
failure: problem("server", response.status)
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
if (typeof body !== "object" || body === null) return {
|
|
603
|
+
ok: false,
|
|
604
|
+
failure: problem("server", response.status)
|
|
605
|
+
};
|
|
606
|
+
const record = body;
|
|
607
|
+
if (record.wireVersion !== 1 || typeof record.ok !== "boolean" || typeof record.message !== "string") return {
|
|
608
|
+
ok: false,
|
|
609
|
+
failure: problem("wire-version", response.status)
|
|
610
|
+
};
|
|
611
|
+
return {
|
|
612
|
+
ok: true,
|
|
613
|
+
payload: {
|
|
614
|
+
ok: record.ok,
|
|
615
|
+
message: record.message,
|
|
616
|
+
...typeof record.code === "string" ? { code: record.code } : {},
|
|
617
|
+
...typeof record.runId === "string" ? { runId: record.runId } : {}
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
}
|
|
544
621
|
async function history() {
|
|
545
622
|
const answer = await requestWire(HOST_ROUTES.history);
|
|
546
623
|
return answer.ok ? {
|
|
@@ -634,6 +711,8 @@ window.__ModuleLoader__.load({
|
|
|
634
711
|
"skipKind.forced": "强制",
|
|
635
712
|
"action.approve": "复制批准",
|
|
636
713
|
"action.reject": "复制拒绝",
|
|
714
|
+
"decision.approve": "批准",
|
|
715
|
+
"decision.reject": "拒绝",
|
|
637
716
|
"action.retry-candidates": "复制重试候选",
|
|
638
717
|
"action.retry-resume": "重试续跑",
|
|
639
718
|
"action.discard": "复制丢弃",
|
|
@@ -708,7 +787,6 @@ window.__ModuleLoader__.load({
|
|
|
708
787
|
"history.reason.archived": "已归档",
|
|
709
788
|
"history.reason.unknown": "原因未提供",
|
|
710
789
|
"history.lastVersion": "最后版本",
|
|
711
|
-
"history.archivedAt": "归档时间",
|
|
712
790
|
"body.truncated": "正文过长,已截断。",
|
|
713
791
|
"body.empty": "正文为空。",
|
|
714
792
|
"body.totalBytes": "总字节",
|
|
@@ -729,7 +807,6 @@ window.__ModuleLoader__.load({
|
|
|
729
807
|
"settings.capabilityMissing": "宿主未提供该能力",
|
|
730
808
|
"settings.capabilityDisabled": "当前部署不可用",
|
|
731
809
|
"settings.readonly": "只读显示;修改请到平台设置页。",
|
|
732
|
-
"settings.mergeApprovalPath": "设置 → 插件 → 自进化 → 技能自动合并",
|
|
733
810
|
"run.title": "运行",
|
|
734
811
|
"run.id": "运行编号",
|
|
735
812
|
"run.state": "状态",
|
|
@@ -836,6 +913,8 @@ window.__ModuleLoader__.load({
|
|
|
836
913
|
"skipKind.forced": "forced",
|
|
837
914
|
"action.approve": "Copy approve",
|
|
838
915
|
"action.reject": "Copy reject",
|
|
916
|
+
"decision.approve": "Approve",
|
|
917
|
+
"decision.reject": "Reject",
|
|
839
918
|
"action.retry-candidates": "Copy retry candidates",
|
|
840
919
|
"action.retry-resume": "Retry resume",
|
|
841
920
|
"action.discard": "Copy discard",
|
|
@@ -910,7 +989,6 @@ window.__ModuleLoader__.load({
|
|
|
910
989
|
"history.reason.archived": "archived",
|
|
911
990
|
"history.reason.unknown": "reason not provided",
|
|
912
991
|
"history.lastVersion": "Last version",
|
|
913
|
-
"history.archivedAt": "Archived at",
|
|
914
992
|
"body.truncated": "Body is truncated.",
|
|
915
993
|
"body.empty": "Body is empty.",
|
|
916
994
|
"body.totalBytes": "Total bytes",
|
|
@@ -931,7 +1009,6 @@ window.__ModuleLoader__.load({
|
|
|
931
1009
|
"settings.capabilityMissing": "Host did not provide this capability",
|
|
932
1010
|
"settings.capabilityDisabled": "Not available in this deployment",
|
|
933
1011
|
"settings.readonly": "Read-only here; edit in platform settings.",
|
|
934
|
-
"settings.mergeApprovalPath": "Settings → Plugins → Evolution → Skill auto-merge",
|
|
935
1012
|
"run.title": "Run",
|
|
936
1013
|
"run.id": "Run ID",
|
|
937
1014
|
"run.state": "State",
|
|
@@ -970,14 +1047,14 @@ window.__ModuleLoader__.load({
|
|
|
970
1047
|
"settings.saved": "已保存",
|
|
971
1048
|
"settings.saveFailed": "保存失败",
|
|
972
1049
|
"settings.openPlatform": "打开平台设置",
|
|
973
|
-
"settings.openPlatformPath": "设置 → 内置插件 →
|
|
1050
|
+
"settings.openPlatformPath": "设置 → 内置插件 → 自进化 → 技能自动合并",
|
|
974
1051
|
"settings.live": "可直接在此保存;platformWrite 能力来自宿主。"
|
|
975
1052
|
});
|
|
976
1053
|
Object.assign(en, {
|
|
977
1054
|
"settings.saved": "Saved",
|
|
978
1055
|
"settings.saveFailed": "Save failed",
|
|
979
1056
|
"settings.openPlatform": "Open platform settings",
|
|
980
|
-
"settings.openPlatformPath": "Settings → Built-in plugins →
|
|
1057
|
+
"settings.openPlatformPath": "Settings → Built-in plugins → Evolution → Skill auto-merge",
|
|
981
1058
|
"settings.live": "Save directly here; platformWrite capability comes from the host."
|
|
982
1059
|
});
|
|
983
1060
|
Object.assign(zh, { "settings.platformWriteLinkHint": "此开关属于平台设置,这里只读;请到平台设置修改。" });
|
|
@@ -1146,9 +1223,9 @@ window.__ModuleLoader__.load({
|
|
|
1146
1223
|
const value = workspaceId?.trim() ?? "";
|
|
1147
1224
|
return value === "" ? "local" : value;
|
|
1148
1225
|
}
|
|
1149
|
-
/** Stable localStorage key for one workspace and
|
|
1150
|
-
function rowOrderKey(workspaceId, queue) {
|
|
1151
|
-
return "dsh-evolution-merge.row-order.v1:" + encodeURIComponent(resolveWorkspaceId(workspaceId)) + ":" + queue;
|
|
1226
|
+
/** Stable localStorage key for one workspace, queue and expired filter. */
|
|
1227
|
+
function rowOrderKey(workspaceId, queue, expiredOnly = false) {
|
|
1228
|
+
return "dsh-evolution-merge.row-order.v1:" + encodeURIComponent(resolveWorkspaceId(workspaceId)) + ":" + queue + (expiredOnly ? ":expired" : ":live");
|
|
1152
1229
|
}
|
|
1153
1230
|
function defaultStorage() {
|
|
1154
1231
|
try {
|
|
@@ -1177,18 +1254,18 @@ window.__ModuleLoader__.load({
|
|
|
1177
1254
|
/** One tab's persisted order; failures degrade to an empty (wire) order. */
|
|
1178
1255
|
function createRowOrderStore(storage = defaultStorage()) {
|
|
1179
1256
|
return {
|
|
1180
|
-
read(workspaceId, queue) {
|
|
1257
|
+
read(workspaceId, queue, expiredOnly = false) {
|
|
1181
1258
|
if (storage === void 0) return [];
|
|
1182
1259
|
try {
|
|
1183
|
-
return normalize(storage.getItem(rowOrderKey(workspaceId, queue)));
|
|
1260
|
+
return normalize(storage.getItem(rowOrderKey(workspaceId, queue, expiredOnly)));
|
|
1184
1261
|
} catch {
|
|
1185
1262
|
return [];
|
|
1186
1263
|
}
|
|
1187
1264
|
},
|
|
1188
|
-
write(workspaceId, queue, ids) {
|
|
1265
|
+
write(workspaceId, queue, ids, expiredOnly = false) {
|
|
1189
1266
|
if (storage === void 0) return;
|
|
1190
1267
|
try {
|
|
1191
|
-
storage.setItem(rowOrderKey(workspaceId, queue), JSON.stringify(ids));
|
|
1268
|
+
storage.setItem(rowOrderKey(workspaceId, queue, expiredOnly), JSON.stringify(ids));
|
|
1192
1269
|
} catch {}
|
|
1193
1270
|
}
|
|
1194
1271
|
};
|
|
@@ -1343,8 +1420,12 @@ window.__ModuleLoader__.load({
|
|
|
1343
1420
|
}, t("stage.state." + stage.state) + expiry);
|
|
1344
1421
|
}
|
|
1345
1422
|
function runNode(view, t, copy) {
|
|
1346
|
-
const
|
|
1347
|
-
|
|
1423
|
+
const active = view.activeRun;
|
|
1424
|
+
const last = view.lastRun;
|
|
1425
|
+
if (active === void 0 && last === void 0) return null;
|
|
1426
|
+
return (0, react.createElement)("div", { "data-role": "run-strips" }, active === void 0 ? null : runStrip(active, t, copy, "active"), last === void 0 ? null : runStrip(last, t, copy, "last"));
|
|
1427
|
+
}
|
|
1428
|
+
function runStrip(run, t, copy, role) {
|
|
1348
1429
|
const report = run.actions.find((action) => action.id === "report");
|
|
1349
1430
|
const reportEnabled = report?.enabled === true;
|
|
1350
1431
|
const internals = [
|
|
@@ -1382,6 +1463,7 @@ window.__ModuleLoader__.load({
|
|
|
1382
1463
|
];
|
|
1383
1464
|
return (0, react.createElement)("div", {
|
|
1384
1465
|
"data-role": "run-strip",
|
|
1466
|
+
"data-run-role": role,
|
|
1385
1467
|
"data-run-state": run.state
|
|
1386
1468
|
}, (0, react.createElement)("span", { "data-role": "run-state" }, t("run.state") + " " + t("run." + run.state)), 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)), (0, react.createElement)("button", {
|
|
1387
1469
|
type: "button",
|
|
@@ -1420,14 +1502,12 @@ window.__ModuleLoader__.load({
|
|
|
1420
1502
|
const platformCapability = platform?.capability === true;
|
|
1421
1503
|
const platformFallback = platform?.enabled ?? false;
|
|
1422
1504
|
const mergeFallback = view.approval.mergeApproval;
|
|
1423
|
-
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")), (0, react.createElement)(ReadOnlySetting, {
|
|
1505
|
+
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")), (0, react.createElement)("p", { "data-role": "settings-path" }, t("settings.openPlatformPath")), (0, react.createElement)(ReadOnlySetting, {
|
|
1424
1506
|
section: "merge-approval",
|
|
1425
1507
|
label: t("settings.mergeApproval"),
|
|
1426
1508
|
value: mergeFallback,
|
|
1427
1509
|
disabled: false,
|
|
1428
1510
|
missing: false,
|
|
1429
|
-
note: t("settings.mergeApprovalPath"),
|
|
1430
|
-
link: true,
|
|
1431
1511
|
t
|
|
1432
1512
|
}), (0, react.createElement)(ReadOnlySetting, {
|
|
1433
1513
|
section: "platform-write",
|
|
@@ -1436,11 +1516,10 @@ window.__ModuleLoader__.load({
|
|
|
1436
1516
|
disabled: platformCapability === false,
|
|
1437
1517
|
missing: platform === void 0,
|
|
1438
1518
|
note: t("settings.platformWriteLinkHint"),
|
|
1439
|
-
link: true,
|
|
1440
1519
|
t
|
|
1441
1520
|
}), (0, react.createElement)("p", { "data-role": "settings-readonly" }, t("settings.readonly")));
|
|
1442
1521
|
}
|
|
1443
|
-
function rowNode(row, t, copy, sort, openBody) {
|
|
1522
|
+
function rowNode(row, t, copy, sort, openBody, onDecide, busy) {
|
|
1444
1523
|
const first = [
|
|
1445
1524
|
row.target === void 0 ? void 0 : t("row.target") + " " + row.target,
|
|
1446
1525
|
row.failure === void 0 ? void 0 : t("row.failure") + " " + row.failure.code + (row.failure.retryable ? "" : " · " + t("row.noRetry")),
|
|
@@ -1455,19 +1534,35 @@ window.__ModuleLoader__.load({
|
|
|
1455
1534
|
row.attempts === void 0 ? void 0 : t("row.attempts") + " " + String(row.attempts),
|
|
1456
1535
|
row.confidence === void 0 ? void 0 : t("row.confidence") + " " + row.confidence.toFixed(2)
|
|
1457
1536
|
].filter((value) => value !== void 0).join(" · ");
|
|
1458
|
-
const actions = row.actions.
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1537
|
+
const actions = row.actions.flatMap((action) => {
|
|
1538
|
+
const decision = (action.id === "approve" || action.id === "reject") && onDecide !== void 0;
|
|
1539
|
+
const primary = (0, react.createElement)("button", {
|
|
1540
|
+
key: action.id,
|
|
1541
|
+
type: "button",
|
|
1542
|
+
"data-role": decision ? "row-decision" : "row-action",
|
|
1543
|
+
"data-action": action.id,
|
|
1544
|
+
...action.disabledReason === void 0 ? {} : { "data-disabled-reason": action.disabledReason },
|
|
1545
|
+
title: action.command,
|
|
1546
|
+
disabled: !action.enabled || busy,
|
|
1547
|
+
onClick: () => {
|
|
1548
|
+
if (!action.enabled || busy) return;
|
|
1549
|
+
if (decision) onDecide(row.id, action.id);
|
|
1550
|
+
else copy(action.command);
|
|
1551
|
+
}
|
|
1552
|
+
}, decision ? t("decision." + action.id) : t("action." + action.id));
|
|
1553
|
+
if (!decision) return [primary];
|
|
1554
|
+
return [primary, (0, react.createElement)("button", {
|
|
1555
|
+
key: action.id + "-copy",
|
|
1556
|
+
type: "button",
|
|
1557
|
+
"data-role": "row-copy",
|
|
1558
|
+
"data-action": action.id + "-copy",
|
|
1559
|
+
title: action.command,
|
|
1560
|
+
disabled: busy,
|
|
1561
|
+
onClick: () => {
|
|
1562
|
+
if (!busy) copy(action.command);
|
|
1563
|
+
}
|
|
1564
|
+
}, t("row.copy"))];
|
|
1565
|
+
});
|
|
1471
1566
|
return (0, react.createElement)("div", {
|
|
1472
1567
|
key: row.id,
|
|
1473
1568
|
"data-role": "row",
|
|
@@ -1507,7 +1602,16 @@ window.__ModuleLoader__.load({
|
|
|
1507
1602
|
event.preventDefault();
|
|
1508
1603
|
sort.menu(row.id, event.clientX, event.clientY);
|
|
1509
1604
|
}
|
|
1510
|
-
}, (0, react.createElement)("div", null, (0, react.createElement)("div", { "data-role": "row-label" }, row.label), (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), first === "" ? null : (0, react.createElement)("div", { "data-role": "row-facts" }, first), (0, react.createElement)("details", { "data-role": "row-details" }, (0, react.createElement)("summary", null, t("row.details")), (0, react.createElement)("p", null, details))), (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" }, ((
|
|
1605
|
+
}, (0, react.createElement)("div", null, (0, react.createElement)("div", { "data-role": "row-label" }, row.label), (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), first === "" ? null : (0, react.createElement)("div", { "data-role": "row-facts" }, first), (0, react.createElement)("details", { "data-role": "row-details" }, (0, react.createElement)("summary", null, t("row.details")), (0, react.createElement)("p", null, details))), (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" }, (0, react.createElement)("button", {
|
|
1606
|
+
type: "button",
|
|
1607
|
+
"data-role": "row-sort",
|
|
1608
|
+
"aria-haspopup": "menu",
|
|
1609
|
+
title: t("sort.menu"),
|
|
1610
|
+
onClick: (event) => {
|
|
1611
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
1612
|
+
sort.menu(row.id, rect.left, rect.bottom);
|
|
1613
|
+
}
|
|
1614
|
+
}, t("sort.menu")), (() => {
|
|
1511
1615
|
const bodyA = row.bodies?.find((body) => body.name === row.a);
|
|
1512
1616
|
const bodyB = row.bodies?.find((body) => body.name === row.b);
|
|
1513
1617
|
return [bodyA === void 0 ? null : (0, react.createElement)("button", {
|
|
@@ -1624,6 +1728,8 @@ window.__ModuleLoader__.load({
|
|
|
1624
1728
|
const [copyState, setCopyState] = (0, react.useState)({ kind: "idle" });
|
|
1625
1729
|
const [orders, setOrders] = (0, react.useState)({});
|
|
1626
1730
|
const [dragId, setDragId] = (0, react.useState)(void 0);
|
|
1731
|
+
const [deciding, setDeciding] = (0, react.useState)(void 0);
|
|
1732
|
+
const [decisionNotice, setDecisionNotice] = (0, react.useState)(void 0);
|
|
1627
1733
|
const [menu, setMenu] = (0, react.useState)(void 0);
|
|
1628
1734
|
const returnFocus = (0, react.useRef)(null);
|
|
1629
1735
|
const captureFocus = () => {
|
|
@@ -1645,6 +1751,27 @@ window.__ModuleLoader__.load({
|
|
|
1645
1751
|
};
|
|
1646
1752
|
const workspaceId = resolveWorkspaceId(face.workspaceId);
|
|
1647
1753
|
const orderStore = (0, react.useMemo)(() => createRowOrderStore(), []);
|
|
1754
|
+
const decideRow = (rowId, verb) => {
|
|
1755
|
+
if (face.decide === void 0) return;
|
|
1756
|
+
setDeciding(rowId);
|
|
1757
|
+
(async () => {
|
|
1758
|
+
try {
|
|
1759
|
+
setDecisionNotice({
|
|
1760
|
+
rowId,
|
|
1761
|
+
...await face.decide(rowId, verb)
|
|
1762
|
+
});
|
|
1763
|
+
store.refresh();
|
|
1764
|
+
} catch (error) {
|
|
1765
|
+
setDecisionNotice({
|
|
1766
|
+
rowId,
|
|
1767
|
+
ok: false,
|
|
1768
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1769
|
+
});
|
|
1770
|
+
} finally {
|
|
1771
|
+
setDeciding(void 0);
|
|
1772
|
+
}
|
|
1773
|
+
})();
|
|
1774
|
+
};
|
|
1648
1775
|
const copy = (command) => {
|
|
1649
1776
|
(async () => {
|
|
1650
1777
|
try {
|
|
@@ -1694,15 +1821,15 @@ window.__ModuleLoader__.load({
|
|
|
1694
1821
|
const viewFailure = snapshot.viewState === "error" ? snapshot.viewFailure : void 0;
|
|
1695
1822
|
const queue = snapshot.current;
|
|
1696
1823
|
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";
|
|
1697
|
-
const orderKey = rowOrderKey(workspaceId, snapshot.queue);
|
|
1698
|
-
const visibleOrder = orders[orderKey] ?? orderStore.read(workspaceId, snapshot.queue);
|
|
1824
|
+
const orderKey = rowOrderKey(workspaceId, snapshot.queue, snapshot.expiredOnly);
|
|
1825
|
+
const visibleOrder = orders[orderKey] ?? orderStore.read(workspaceId, snapshot.queue, snapshot.expiredOnly);
|
|
1699
1826
|
const visibleRows = orderRows(queue.rows, visibleOrder);
|
|
1700
1827
|
const saveOrder = (ids) => {
|
|
1701
1828
|
setOrders((previous) => ({
|
|
1702
1829
|
...previous,
|
|
1703
1830
|
[orderKey]: ids
|
|
1704
1831
|
}));
|
|
1705
|
-
orderStore.write(workspaceId, snapshot.queue, ids);
|
|
1832
|
+
orderStore.write(workspaceId, snapshot.queue, ids, snapshot.expiredOnly);
|
|
1706
1833
|
};
|
|
1707
1834
|
const sortHandlers = {
|
|
1708
1835
|
start: (id) => {
|
|
@@ -1774,11 +1901,15 @@ window.__ModuleLoader__.load({
|
|
|
1774
1901
|
store.toggleExpired();
|
|
1775
1902
|
}
|
|
1776
1903
|
}, t("tab.expired") + " " + String(view.expired)) : null;
|
|
1904
|
+
const notice = decisionNotice === void 0 ? null : (0, react.createElement)("p", {
|
|
1905
|
+
"data-role": "decision-notice",
|
|
1906
|
+
"data-ok": decisionNotice.ok ? "true" : "false"
|
|
1907
|
+
}, decisionNotice.message);
|
|
1777
1908
|
const list = uiState === "ready" && queue.status === "ready" ? (0, react.createElement)("div", {
|
|
1778
1909
|
"data-role": "rows",
|
|
1779
1910
|
id: "merge-rows",
|
|
1780
1911
|
role: "tabpanel"
|
|
1781
|
-
}, visibleRows.map((row) => rowNode(row, t, copy, sortHandlers, openBody))) : null;
|
|
1912
|
+
}, visibleRows.map((row) => rowNode(row, t, copy, sortHandlers, openBody, face.decide === void 0 ? void 0 : decideRow, deciding === row.id))) : null;
|
|
1782
1913
|
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;
|
|
1783
1914
|
const staleViewFailure = snapshot.viewState === "ready" ? snapshot.viewFailure : void 0;
|
|
1784
1915
|
const activeFailure = viewFailure !== void 0 ? viewFailure : staleViewFailure !== void 0 ? staleViewFailure : queue.status === "error" ? queue.failure : void 0;
|
|
@@ -1868,7 +1999,7 @@ window.__ModuleLoader__.load({
|
|
|
1868
1999
|
}, t("copied") + " " + (copyState.text ?? "")) : (0, react.createElement)("p", {
|
|
1869
2000
|
"data-role": "copy-failed",
|
|
1870
2001
|
role: "alert"
|
|
1871
|
-
}, t("copyFailed")), list, empty, queue.nextCursor === void 0 || uiState !== "ready" ? null : (0, react.createElement)("button", {
|
|
2002
|
+
}, t("copyFailed")), notice, list, empty, queue.nextCursor === void 0 || uiState !== "ready" ? null : (0, react.createElement)("button", {
|
|
1872
2003
|
type: "button",
|
|
1873
2004
|
"data-role": "load-more",
|
|
1874
2005
|
disabled: queue.status === "loading",
|
|
@@ -2253,8 +2384,19 @@ window.__ModuleLoader__.load({
|
|
|
2253
2384
|
}
|
|
2254
2385
|
};
|
|
2255
2386
|
//#endregion
|
|
2387
|
+
//#region src/client/session.ts
|
|
2388
|
+
function currentSessionId(ctx) {
|
|
2389
|
+
const byId = ctx.sessions?.list?.getSnapshot?.().byId;
|
|
2390
|
+
if (byId === void 0) return void 0;
|
|
2391
|
+
return Object.values(byId).find((session) => (session.retainedBy?.mainView ?? 0) > 0)?.id;
|
|
2392
|
+
}
|
|
2393
|
+
//#endregion
|
|
2256
2394
|
//#region src/client/index.ts
|
|
2257
|
-
const inject = [
|
|
2395
|
+
const inject = [
|
|
2396
|
+
"slots",
|
|
2397
|
+
"sessions",
|
|
2398
|
+
"locale"
|
|
2399
|
+
];
|
|
2258
2400
|
/** The view component receives the workbench's activeView marker alongside its face. */
|
|
2259
2401
|
function MergeView(props) {
|
|
2260
2402
|
return props.activeView === "merge" ? MergePanel(props) : null;
|
|
@@ -2264,6 +2406,10 @@ window.__ModuleLoader__.load({
|
|
|
2264
2406
|
* @param ctx - the client context.
|
|
2265
2407
|
*/
|
|
2266
2408
|
function apply(ctx) {
|
|
2409
|
+
const seat = createSettingsSeat(ctx);
|
|
2410
|
+
ctx.effect(() => () => {
|
|
2411
|
+
seat.dispose?.();
|
|
2412
|
+
}, "evolution-merge-ui: settings seat");
|
|
2267
2413
|
registerWorkbenchView(ctx, {
|
|
2268
2414
|
id: PANEL_ID,
|
|
2269
2415
|
order: 45,
|
|
@@ -2284,7 +2430,6 @@ window.__ModuleLoader__.load({
|
|
|
2284
2430
|
body,
|
|
2285
2431
|
history
|
|
2286
2432
|
};
|
|
2287
|
-
const seat = createSettingsSeat(ctx);
|
|
2288
2433
|
const workspaceId = panelWorkspaceId(ctx);
|
|
2289
2434
|
return {
|
|
2290
2435
|
store: new MergeStore(source),
|
|
@@ -2294,6 +2439,20 @@ window.__ModuleLoader__.load({
|
|
|
2294
2439
|
...seat.get("evolution-merge") === void 0 ? {} : { merge: seat.get("evolution-merge") },
|
|
2295
2440
|
...seat.get("evolution-approval") === void 0 ? {} : { platform: seat.get("evolution-approval") }
|
|
2296
2441
|
},
|
|
2442
|
+
decide: async (rowId, verb) => {
|
|
2443
|
+
const sessionId = currentSessionId(ctx);
|
|
2444
|
+
if (sessionId === void 0) return {
|
|
2445
|
+
ok: false,
|
|
2446
|
+
message: "没有当前会话;请打开会话后重试"
|
|
2447
|
+
};
|
|
2448
|
+
const result = await decide(rowId, verb, sessionId);
|
|
2449
|
+
if (result.ok) return result.payload;
|
|
2450
|
+
const failure = result.failure;
|
|
2451
|
+
return {
|
|
2452
|
+
ok: false,
|
|
2453
|
+
message: "message" in failure && typeof failure.message === "string" ? failure.message : "审批请求失败"
|
|
2454
|
+
};
|
|
2455
|
+
},
|
|
2297
2456
|
...workspaceId === void 0 ? {} : { workspaceId }
|
|
2298
2457
|
};
|
|
2299
2458
|
}
|
|
@@ -9,6 +9,10 @@ export interface MergeFace {
|
|
|
9
9
|
doctorCommand?: string;
|
|
10
10
|
settings?: SettingsFace;
|
|
11
11
|
workspaceId?: string;
|
|
12
|
+
decide?: (rowId: string, verb: 'approve' | 'reject') => Promise<{
|
|
13
|
+
ok: boolean;
|
|
14
|
+
message: string;
|
|
15
|
+
}>;
|
|
12
16
|
}
|
|
13
17
|
export declare function MergePanel(face: MergeFace): ReactNode;
|
|
14
18
|
//# sourceMappingURL=Panel.d.ts.map
|
|
@@ -65,7 +65,8 @@ export interface MergeViewPayload {
|
|
|
65
65
|
};
|
|
66
66
|
notes: string[];
|
|
67
67
|
degraded: boolean;
|
|
68
|
-
|
|
68
|
+
activeRun?: MergeRunView;
|
|
69
|
+
lastRun?: MergeRunView;
|
|
69
70
|
approval: MergeApproval;
|
|
70
71
|
}
|
|
71
72
|
export interface RowActionView {
|
|
@@ -177,6 +178,13 @@ export declare const isBlocked: (failure: MergeFailure) => failure is MergeBlock
|
|
|
177
178
|
export declare function view(): Promise<MergeOutcome<MergeViewPayload>>;
|
|
178
179
|
export declare function rows(queue: MergeQueue, cursor?: string, expiredOnly?: boolean): Promise<MergeOutcome<QueuePage>>;
|
|
179
180
|
export declare function body(name: string, side: 'live' | 'archive', rowId?: string): Promise<MergeOutcome<MergeBody>>;
|
|
181
|
+
export interface MergeDecisionOutcome {
|
|
182
|
+
readonly ok: boolean;
|
|
183
|
+
readonly message: string;
|
|
184
|
+
readonly code?: string;
|
|
185
|
+
readonly runId?: string;
|
|
186
|
+
}
|
|
187
|
+
export declare function decide(rowId: string, verb: 'approve' | 'reject', sessionId: string): Promise<MergeOutcome<MergeDecisionOutcome>>;
|
|
180
188
|
export declare function history(): Promise<MergeOutcome<{
|
|
181
189
|
items: MergeHistoryItem[];
|
|
182
190
|
}>>;
|
|
@@ -7,12 +7,12 @@ export interface StorageLike {
|
|
|
7
7
|
export type RowOrderEdge = 'top' | 'bottom';
|
|
8
8
|
/** Workspace scope for one tab. A missing panel workspace is the local scope. */
|
|
9
9
|
export declare function resolveWorkspaceId(workspaceId: string | null | undefined): string;
|
|
10
|
-
/** Stable localStorage key for one workspace and
|
|
11
|
-
export declare function rowOrderKey(workspaceId: string | null | undefined, queue: MergeQueue): string;
|
|
10
|
+
/** Stable localStorage key for one workspace, queue and expired filter. */
|
|
11
|
+
export declare function rowOrderKey(workspaceId: string | null | undefined, queue: MergeQueue, expiredOnly?: boolean): string;
|
|
12
12
|
/** One tab's persisted order; failures degrade to an empty (wire) order. */
|
|
13
13
|
export declare function createRowOrderStore(storage?: StorageLike | undefined): {
|
|
14
|
-
read(workspaceId: string | null | undefined, queue: MergeQueue): readonly string[];
|
|
15
|
-
write(workspaceId: string | null | undefined, queue: MergeQueue, ids: readonly string[]): void;
|
|
14
|
+
read(workspaceId: string | null | undefined, queue: MergeQueue, expiredOnly?: boolean): readonly string[];
|
|
15
|
+
write(workspaceId: string | null | undefined, queue: MergeQueue, ids: readonly string[], expiredOnly?: boolean): void;
|
|
16
16
|
};
|
|
17
17
|
/** Apply persisted ids first, then append unknown rows in their wire order. */
|
|
18
18
|
export declare function orderRows<T extends {
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
]
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.34.0",
|
|
15
15
|
"publishConfig": {
|
|
16
16
|
"access": "public"
|
|
17
17
|
},
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"react-dom": "^18.2.0"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@lmzhen/dsh-evolution-client-kit": "^0.
|
|
54
|
+
"@lmzhen/dsh-evolution-client-kit": "^0.34.0"
|
|
55
55
|
},
|
|
56
56
|
"engines": {
|
|
57
57
|
"dsh": ">=0.2.1-rc.2 <0.2.2-0"
|