@lmzhen/dsh-evolution-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 +164 -55
- package/lib/types/panels/history/client/Workbench.d.ts +3 -6
- package/lib/types/panels/history/client/WorkbenchStore.d.ts +16 -0
- package/lib/types/panels/settings/generated-about.d.ts +1 -1
- package/lib/types/panels/settings/messages.d.ts +3 -0
- package/lib/types/panels/settings/seam.d.ts +3 -1
- package/package.json +4 -4
package/lib/client.js
CHANGED
|
@@ -858,6 +858,7 @@ window.__ModuleLoader__.load({
|
|
|
858
858
|
resetTo: "复位为 {value}",
|
|
859
859
|
saved: "已保存。",
|
|
860
860
|
saveReadbackFailed: "写入已被接受,但回读失败;点刷新重读后再确认。",
|
|
861
|
+
readbackStale: "显示的是最后一次成功读取的值;当前回读失败,刷新后可能变化。",
|
|
861
862
|
saveConflict: "这个值没有被接受:设置已被其他页面修改。请重读后再保存。",
|
|
862
863
|
resetDone: "已恢复默认值。",
|
|
863
864
|
refused: "这个值没有被接受(界面上保持原样)。想看原因:在对话里让它说明。",
|
|
@@ -926,6 +927,8 @@ window.__ModuleLoader__.load({
|
|
|
926
927
|
diagStatusUnknown: "未知",
|
|
927
928
|
diagRemedy: "建议:",
|
|
928
929
|
diagNoRows: "没有可显示的运行状态",
|
|
930
|
+
diagPurpose: "用途:检查插件挂载、平台服务和数据面是否正常,不修改任何状态。",
|
|
931
|
+
diagFooter: "诊断 schema v{version} · 生成于 {at}",
|
|
929
932
|
stateLoading: "正在读取…",
|
|
930
933
|
failureUnauthorized: "需要登录:重新打开这个页面完成登录后再试。",
|
|
931
934
|
failureForbidden: "平台拒绝了这个请求(身份不是 owner)。",
|
|
@@ -963,6 +966,7 @@ window.__ModuleLoader__.load({
|
|
|
963
966
|
resetTo: "Restores {value}",
|
|
964
967
|
saved: "Saved.",
|
|
965
968
|
saveReadbackFailed: "The write was accepted, but reading it back failed; refresh and confirm.",
|
|
969
|
+
readbackStale: "Showing the last successfully read values; the current re-read failed and may change after refresh.",
|
|
966
970
|
saveConflict: "The value was not accepted: settings changed in another page. Re-read before saving again.",
|
|
967
971
|
resetDone: "Default restored.",
|
|
968
972
|
refused: "The value was not accepted (the page keeps what you see). For the reason, ask in the conversation.",
|
|
@@ -1031,6 +1035,8 @@ window.__ModuleLoader__.load({
|
|
|
1031
1035
|
diagStatusUnknown: "unknown",
|
|
1032
1036
|
diagRemedy: "Suggested: ",
|
|
1033
1037
|
diagNoRows: "no runtime status to show",
|
|
1038
|
+
diagPurpose: "Purpose: check plugin mounting, platform services and data planes; nothing is changed.",
|
|
1039
|
+
diagFooter: "diagnostics schema v{version} · generated {at}",
|
|
1034
1040
|
stateLoading: "reading…",
|
|
1035
1041
|
failureUnauthorized: "Sign-in is required: reopen this page and sign in, then retry.",
|
|
1036
1042
|
failureForbidden: "The platform refused this request (not the owner principal).",
|
|
@@ -1426,7 +1432,11 @@ window.__ModuleLoader__.load({
|
|
|
1426
1432
|
onClick: () => {
|
|
1427
1433
|
setOpen(!open);
|
|
1428
1434
|
}
|
|
1429
|
-
}, (0, react.createElement)("span", { className: "evolution-param-card-title" }, title), changed === 0 ? null : (0, react.createElement)("span", { className: "evolution-param-count" }, t("changed", { n: changed })), (0, react.createElement)("span", { className: "evolution-param-chevron" }, open ? "▲" : "▼")), open ? (0, react.createElement)("div", { className: "evolution-param-body" }, hintKey === void 0 ? null : (0, react.createElement)("p", { className: "evolution-param-note" }, t(hintKey)),
|
|
1435
|
+
}, (0, react.createElement)("span", { className: "evolution-param-card-title" }, title), changed === 0 ? null : (0, react.createElement)("span", { className: "evolution-param-count" }, t("changed", { n: changed })), (0, react.createElement)("span", { className: "evolution-param-chevron" }, open ? "▲" : "▼")), open ? (0, react.createElement)("div", { className: "evolution-param-body" }, hintKey === void 0 ? null : (0, react.createElement)("p", { className: "evolution-param-note" }, t(hintKey)), snapshot.stale === true ? (0, react.createElement)("p", {
|
|
1436
|
+
className: "evolution-param-note",
|
|
1437
|
+
role: "status",
|
|
1438
|
+
"data-role": "stale-note"
|
|
1439
|
+
}, t("readbackStale")) : null, disabled ? (0, react.createElement)("p", {
|
|
1430
1440
|
className: "evolution-param-note",
|
|
1431
1441
|
role: "status"
|
|
1432
1442
|
}, t("readonly")) : null, fields.length === 0 ? (0, react.createElement)("p", {
|
|
@@ -1677,34 +1687,51 @@ window.__ModuleLoader__.load({
|
|
|
1677
1687
|
...EMPTY,
|
|
1678
1688
|
reason: "seat-missing"
|
|
1679
1689
|
};
|
|
1690
|
+
let lastReady;
|
|
1691
|
+
let generation = 0;
|
|
1680
1692
|
const listeners = /* @__PURE__ */ new Set();
|
|
1681
|
-
let
|
|
1682
|
-
let listening = false;
|
|
1693
|
+
let remoteOff;
|
|
1683
1694
|
const notify = () => {
|
|
1684
1695
|
for (const listener of listeners) listener();
|
|
1685
1696
|
};
|
|
1686
|
-
const
|
|
1687
|
-
|
|
1697
|
+
const absorb = (next) => {
|
|
1698
|
+
if (next.status === "ready") {
|
|
1699
|
+
lastReady = next;
|
|
1700
|
+
snapshot = next;
|
|
1701
|
+
} else if (lastReady !== void 0) snapshot = {
|
|
1702
|
+
...lastReady,
|
|
1703
|
+
stale: true,
|
|
1704
|
+
reason: next.reason ?? "readback-failed"
|
|
1705
|
+
};
|
|
1706
|
+
else snapshot = next;
|
|
1688
1707
|
notify();
|
|
1689
1708
|
};
|
|
1690
|
-
const
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
if (
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1709
|
+
const refresh = async () => {
|
|
1710
|
+
const ticket = ++generation;
|
|
1711
|
+
const next = await describe(namespace);
|
|
1712
|
+
if (ticket !== generation) return;
|
|
1713
|
+
absorb(next);
|
|
1714
|
+
};
|
|
1715
|
+
const remote = () => ctx.get?.("remote");
|
|
1716
|
+
const stopRemote = () => {
|
|
1717
|
+
remoteOff?.();
|
|
1718
|
+
remoteOff = void 0;
|
|
1719
|
+
};
|
|
1720
|
+
const startRemote = () => {
|
|
1721
|
+
if (remoteOff !== void 0) return;
|
|
1722
|
+
remoteOff = remote()?.$on?.("settings/document-updated", (changed) => {
|
|
1723
|
+
if (changed === namespace) refresh();
|
|
1724
|
+
});
|
|
1700
1725
|
};
|
|
1701
1726
|
const form = {
|
|
1702
1727
|
getSnapshot: () => snapshot,
|
|
1703
1728
|
subscribe: (listener) => {
|
|
1704
1729
|
listeners.add(listener);
|
|
1705
|
-
|
|
1730
|
+
startRemote();
|
|
1731
|
+
refresh();
|
|
1706
1732
|
return () => {
|
|
1707
1733
|
listeners.delete(listener);
|
|
1734
|
+
if (listeners.size === 0) stopRemote();
|
|
1708
1735
|
};
|
|
1709
1736
|
},
|
|
1710
1737
|
set: async (field, value) => await form.mutate([{
|
|
@@ -1718,35 +1745,39 @@ window.__ModuleLoader__.load({
|
|
|
1718
1745
|
}]),
|
|
1719
1746
|
mutate: async (ops, expectedRevision) => {
|
|
1720
1747
|
const outcome = await write(namespace, ops, expectedRevision ?? snapshot.revision);
|
|
1721
|
-
if (outcome.snapshot !== void 0)
|
|
1722
|
-
|
|
1723
|
-
notify();
|
|
1724
|
-
} else await refresh();
|
|
1748
|
+
if (outcome.snapshot !== void 0) absorb(outcome.snapshot);
|
|
1749
|
+
else await refresh();
|
|
1725
1750
|
return outcome.ok;
|
|
1751
|
+
},
|
|
1752
|
+
refresh,
|
|
1753
|
+
dispose: () => {
|
|
1754
|
+
stopRemote();
|
|
1755
|
+
listeners.clear();
|
|
1726
1756
|
}
|
|
1727
1757
|
};
|
|
1728
1758
|
return form;
|
|
1729
1759
|
}
|
|
1730
1760
|
/**
|
|
1731
|
-
* Build one
|
|
1732
|
-
*
|
|
1733
|
-
*
|
|
1761
|
+
* Build one seat per client registration; every form's remote listener is released by
|
|
1762
|
+
* the caller's effect. No module-level WeakMap: a replaced registration must not share
|
|
1763
|
+
* a dead seat with the previous one.
|
|
1734
1764
|
*/
|
|
1735
|
-
const seats = /* @__PURE__ */ new WeakMap();
|
|
1736
1765
|
function createSettingsSeat(ctx) {
|
|
1737
|
-
const cached = seats.get(ctx);
|
|
1738
|
-
if (cached !== void 0) return cached;
|
|
1739
1766
|
const forms = /* @__PURE__ */ new Map();
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
form
|
|
1744
|
-
|
|
1767
|
+
return {
|
|
1768
|
+
get(namespace) {
|
|
1769
|
+
let form = forms.get(namespace);
|
|
1770
|
+
if (form === void 0) {
|
|
1771
|
+
form = createForm(namespace, ctx);
|
|
1772
|
+
forms.set(namespace, form);
|
|
1773
|
+
}
|
|
1774
|
+
return form;
|
|
1775
|
+
},
|
|
1776
|
+
dispose: () => {
|
|
1777
|
+
for (const form of forms.values()) form.dispose?.();
|
|
1778
|
+
forms.clear();
|
|
1745
1779
|
}
|
|
1746
|
-
|
|
1747
|
-
} };
|
|
1748
|
-
seats.set(ctx, seat);
|
|
1749
|
-
return seat;
|
|
1780
|
+
};
|
|
1750
1781
|
}
|
|
1751
1782
|
//#endregion
|
|
1752
1783
|
//#region ../evolution-client-kit/src/action.ts
|
|
@@ -1848,7 +1879,8 @@ window.__ModuleLoader__.load({
|
|
|
1848
1879
|
user: snapshot.user,
|
|
1849
1880
|
writable: snapshot.writable,
|
|
1850
1881
|
base: isRecord(snapshot.base) ? snapshot.base : void 0,
|
|
1851
|
-
...snapshot.status === "unavailable" ? { reason: snapshot.reason ?? "not-served" } : {}
|
|
1882
|
+
...snapshot.status === "unavailable" ? { reason: snapshot.reason ?? "not-served" } : {},
|
|
1883
|
+
...snapshot.stale === true ? { stale: true } : {}
|
|
1852
1884
|
};
|
|
1853
1885
|
}
|
|
1854
1886
|
/**
|
|
@@ -1958,7 +1990,6 @@ window.__ModuleLoader__.load({
|
|
|
1958
1990
|
readback: "failed",
|
|
1959
1991
|
kind: "transport"
|
|
1960
1992
|
};
|
|
1961
|
-
const before = seat.getSnapshot().revision;
|
|
1962
1993
|
let written = false;
|
|
1963
1994
|
try {
|
|
1964
1995
|
written = await seat.mutate(ops);
|
|
@@ -1970,12 +2001,15 @@ window.__ModuleLoader__.load({
|
|
|
1970
2001
|
failure
|
|
1971
2002
|
};
|
|
1972
2003
|
}
|
|
1973
|
-
const snapshot = seat.getSnapshot();
|
|
1974
2004
|
if (!written) return {
|
|
1975
2005
|
written: false,
|
|
1976
2006
|
readback: "failed",
|
|
1977
2007
|
kind: "conflict"
|
|
1978
2008
|
};
|
|
2009
|
+
try {
|
|
2010
|
+
await seat.refresh?.();
|
|
2011
|
+
} catch {}
|
|
2012
|
+
const snapshot = seat.getSnapshot();
|
|
1979
2013
|
if (snapshot.status !== "ready") return {
|
|
1980
2014
|
written: true,
|
|
1981
2015
|
readback: "failed",
|
|
@@ -1983,7 +2017,8 @@ window.__ModuleLoader__.load({
|
|
|
1983
2017
|
};
|
|
1984
2018
|
return {
|
|
1985
2019
|
written: true,
|
|
1986
|
-
readback: snapshot.
|
|
2020
|
+
readback: snapshot.stale === true ? "failed" : "ok",
|
|
2021
|
+
...snapshot.stale === true ? { kind: "transport" } : {}
|
|
1987
2022
|
};
|
|
1988
2023
|
};
|
|
1989
2024
|
return {
|
|
@@ -2586,6 +2621,8 @@ window.__ModuleLoader__.load({
|
|
|
2586
2621
|
* read, because a half-list would read as a complete window.
|
|
2587
2622
|
*/
|
|
2588
2623
|
const readTicket = (0, react.useRef)(0);
|
|
2624
|
+
const previewTicket = (0, react.useRef)(0);
|
|
2625
|
+
const actionTickets = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
2589
2626
|
const load = async () => {
|
|
2590
2627
|
apply(loading);
|
|
2591
2628
|
const ticket = readTicket.current + 1;
|
|
@@ -2613,9 +2650,13 @@ window.__ModuleLoader__.load({
|
|
|
2613
2650
|
};
|
|
2614
2651
|
}, []);
|
|
2615
2652
|
const decide = (id, action) => {
|
|
2653
|
+
if (latest.current.busy.includes(id)) return;
|
|
2654
|
+
const ticket = (actionTickets.current.get(id) ?? 0) + 1;
|
|
2655
|
+
actionTickets.current.set(id, ticket);
|
|
2616
2656
|
apply((current) => beginAction(current, id));
|
|
2617
2657
|
(async () => {
|
|
2618
2658
|
const answer = action === "approve" ? await api.approve(id) : action === "reject" ? await api.reject(id) : await api.release(id);
|
|
2659
|
+
if (actionTickets.current.get(id) !== ticket) return;
|
|
2619
2660
|
if (!answer.ok) {
|
|
2620
2661
|
apply((current) => noticed(endAction(current, id), failureText(answer.failure, translate)));
|
|
2621
2662
|
return;
|
|
@@ -2631,7 +2672,9 @@ window.__ModuleLoader__.load({
|
|
|
2631
2672
|
};
|
|
2632
2673
|
/** Ask the host what this record would store; the answer lands only if the row is still open. */
|
|
2633
2674
|
const loadPreview = async (id) => {
|
|
2675
|
+
const ticket = ++previewTicket.current;
|
|
2634
2676
|
const answer = await api.preview(id);
|
|
2677
|
+
if (ticket !== previewTicket.current || latest.current.open !== id) return;
|
|
2635
2678
|
const view = answer.ok ? answer.data.available ? {
|
|
2636
2679
|
kind: "ready",
|
|
2637
2680
|
answer: answer.data
|
|
@@ -2685,7 +2728,13 @@ window.__ModuleLoader__.load({
|
|
|
2685
2728
|
}, t("approvalDiffCut"))] : []
|
|
2686
2729
|
];
|
|
2687
2730
|
const lines = [];
|
|
2731
|
+
const multiHunk = view.answer.hunks.length > 1 || view.answer.hunks.some((hunk) => hunk.path !== view.answer.path);
|
|
2688
2732
|
for (const [hunkIndex, hunk] of view.answer.hunks.entries()) {
|
|
2733
|
+
if (multiHunk) lines.push((0, react.createElement)("div", {
|
|
2734
|
+
key: "hunk-" + String(hunkIndex),
|
|
2735
|
+
className: "evolution-param-hunk-path",
|
|
2736
|
+
"data-role": "hunk-path"
|
|
2737
|
+
}, hunk.path));
|
|
2689
2738
|
for (const [index, line] of hunk.oldText.split("\n").entries()) {
|
|
2690
2739
|
if (hunk.oldText === "" && line === "") continue;
|
|
2691
2740
|
lines.push((0, react.createElement)("div", {
|
|
@@ -4038,7 +4087,16 @@ window.__ModuleLoader__.load({
|
|
|
4038
4087
|
onClick: refresh,
|
|
4039
4088
|
disabled: refreshing,
|
|
4040
4089
|
"data-action": "diag-refresh"
|
|
4041
|
-
}, t(refreshing ? "diagRefreshing" : "diagRefresh"))), runtime(view), view.runtime.length === 0 ? (0, react.createElement)("p", { className: "evolution-param-note" }, t("diagNoRows")) : null)
|
|
4090
|
+
}, t(refreshing ? "diagRefreshing" : "diagRefresh"))), runtime(view), view.runtime.length === 0 ? (0, react.createElement)("p", { className: "evolution-param-note" }, t("diagNoRows")) : null, (0, react.createElement)("p", {
|
|
4091
|
+
className: "evolution-param-note",
|
|
4092
|
+
"data-role": "diag-purpose"
|
|
4093
|
+
}, t("diagPurpose")), (0, react.createElement)("p", {
|
|
4094
|
+
className: "evolution-param-hint",
|
|
4095
|
+
"data-role": "diag-footer"
|
|
4096
|
+
}, t("diagFooter", {
|
|
4097
|
+
version: String(view.schemaVersion),
|
|
4098
|
+
at: new Date(view.generatedAt).toLocaleString()
|
|
4099
|
+
})));
|
|
4042
4100
|
};
|
|
4043
4101
|
return (0, react.createElement)("section", {
|
|
4044
4102
|
className: "evolution-param-card",
|
|
@@ -4061,16 +4119,23 @@ window.__ModuleLoader__.load({
|
|
|
4061
4119
|
* @returns the page surface.
|
|
4062
4120
|
*/
|
|
4063
4121
|
function WorkbenchPage(props) {
|
|
4064
|
-
const
|
|
4065
|
-
const
|
|
4066
|
-
const
|
|
4122
|
+
const state = (0, react.useSyncExternalStore)(props.store.subscribe, props.store.getState, props.store.getState);
|
|
4123
|
+
const view = state.view;
|
|
4124
|
+
const selectedSkill = state.selectedSkill;
|
|
4125
|
+
const focusRevision = state.focusRevision;
|
|
4067
4126
|
const openHistory = (skill) => {
|
|
4068
|
-
|
|
4069
|
-
setView("history");
|
|
4070
|
-
setFocusRevision((value) => value + 1);
|
|
4127
|
+
props.store.openHistory(skill);
|
|
4071
4128
|
};
|
|
4072
4129
|
const hasMerge = props.hasView?.("merge") ?? true;
|
|
4073
4130
|
const hasHealth = props.hasView?.("health") ?? true;
|
|
4131
|
+
(0, react.useEffect)(() => {
|
|
4132
|
+
if (view === "merge" && !hasMerge || view === "health" && !hasHealth) props.store.setView("history");
|
|
4133
|
+
}, [
|
|
4134
|
+
view,
|
|
4135
|
+
hasMerge,
|
|
4136
|
+
hasHealth,
|
|
4137
|
+
props.store
|
|
4138
|
+
]);
|
|
4074
4139
|
const viewOrder = [
|
|
4075
4140
|
"history",
|
|
4076
4141
|
"pending",
|
|
@@ -4084,7 +4149,7 @@ window.__ModuleLoader__.load({
|
|
|
4084
4149
|
event.preventDefault();
|
|
4085
4150
|
const index = viewOrder.indexOf(current);
|
|
4086
4151
|
const next = event.key === "Home" ? viewOrder[0] : event.key === "End" ? viewOrder[viewOrder.length - 1] : viewOrder[(index + delta + viewOrder.length) % viewOrder.length];
|
|
4087
|
-
setView(next);
|
|
4152
|
+
props.store.setView(next);
|
|
4088
4153
|
requestAnimationFrame(() => {
|
|
4089
4154
|
document.getElementById("evo-workbench-tab-" + next)?.focus();
|
|
4090
4155
|
});
|
|
@@ -4105,7 +4170,7 @@ window.__ModuleLoader__.load({
|
|
|
4105
4170
|
"aria-controls": "evo-workbench-panel",
|
|
4106
4171
|
"data-active": view === "history" ? "true" : void 0,
|
|
4107
4172
|
onClick: () => {
|
|
4108
|
-
setView("history");
|
|
4173
|
+
props.store.setView("history");
|
|
4109
4174
|
},
|
|
4110
4175
|
onKeyDown: (event) => {
|
|
4111
4176
|
onTabKey(event, "history");
|
|
@@ -4119,7 +4184,7 @@ window.__ModuleLoader__.load({
|
|
|
4119
4184
|
"aria-controls": "evo-workbench-panel",
|
|
4120
4185
|
"data-active": view === "pending" ? "true" : void 0,
|
|
4121
4186
|
onClick: () => {
|
|
4122
|
-
setView("pending");
|
|
4187
|
+
props.store.setView("pending");
|
|
4123
4188
|
},
|
|
4124
4189
|
onKeyDown: (event) => {
|
|
4125
4190
|
onTabKey(event, "pending");
|
|
@@ -4133,7 +4198,7 @@ window.__ModuleLoader__.load({
|
|
|
4133
4198
|
"aria-controls": "evo-workbench-panel",
|
|
4134
4199
|
"data-active": view === "merge" ? "true" : void 0,
|
|
4135
4200
|
onClick: () => {
|
|
4136
|
-
setView("merge");
|
|
4201
|
+
props.store.setView("merge");
|
|
4137
4202
|
},
|
|
4138
4203
|
onKeyDown: (event) => {
|
|
4139
4204
|
onTabKey(event, "merge");
|
|
@@ -4147,7 +4212,7 @@ window.__ModuleLoader__.load({
|
|
|
4147
4212
|
"aria-controls": "evo-workbench-panel",
|
|
4148
4213
|
"data-active": view === "health" ? "true" : void 0,
|
|
4149
4214
|
onClick: () => {
|
|
4150
|
-
setView("health");
|
|
4215
|
+
props.store.setView("health");
|
|
4151
4216
|
},
|
|
4152
4217
|
onKeyDown: (event) => {
|
|
4153
4218
|
onTabKey(event, "health");
|
|
@@ -4161,7 +4226,7 @@ window.__ModuleLoader__.load({
|
|
|
4161
4226
|
"aria-controls": "evo-workbench-panel",
|
|
4162
4227
|
"data-active": view === "diagnostics" ? "true" : void 0,
|
|
4163
4228
|
onClick: () => {
|
|
4164
|
-
setView("diagnostics");
|
|
4229
|
+
props.store.setView("diagnostics");
|
|
4165
4230
|
},
|
|
4166
4231
|
onKeyDown: (event) => {
|
|
4167
4232
|
onTabKey(event, "diagnostics");
|
|
@@ -4211,12 +4276,51 @@ window.__ModuleLoader__.load({
|
|
|
4211
4276
|
".evo-workbench-title{margin:0;font-size:var(--evo-type-lg);font-weight:600;line-height:var(--evo-leading-base)}",
|
|
4212
4277
|
".evo-workbench-body{display:flex;flex:1;min-height:0;min-width:0;overflow:hidden}",
|
|
4213
4278
|
".evo-workbench-body>.evolution-param-card{flex:1;min-width:0;overflow:auto}",
|
|
4214
|
-
".evo-workbench-nav{display:flex;width:100%;align-items:center;gap:var(--evo-space-8);padding:var(--evo-space-6) var(--evo-space-12);border:0;border-radius:var(--evo-radius-control);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:var(--evo-type-sm);text-align:left;cursor:pointer}",
|
|
4215
|
-
".evo-workbench-nav:hover,.evo-workbench-nav[data-active=\"true\"]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}",
|
|
4216
|
-
".evo-workbench-nav:focus-visible{outline:var(--evo-focus-ring);outline-offset:var(--evo-focus-offset)}",
|
|
4217
4279
|
"@media (max-width:720px){.evo-workbench-head{flex-wrap:wrap}.evo-workbench-tabs{flex-wrap:wrap}}"
|
|
4218
4280
|
].join("");
|
|
4219
4281
|
//#endregion
|
|
4282
|
+
//#region src/panels/history/client/WorkbenchStore.ts
|
|
4283
|
+
function createWorkbenchStore(initial = {
|
|
4284
|
+
view: "history",
|
|
4285
|
+
focusRevision: 0
|
|
4286
|
+
}) {
|
|
4287
|
+
let state = initial;
|
|
4288
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4289
|
+
const emit = (next) => {
|
|
4290
|
+
state = next;
|
|
4291
|
+
for (const listener of listeners) listener();
|
|
4292
|
+
};
|
|
4293
|
+
return {
|
|
4294
|
+
getState: () => state,
|
|
4295
|
+
subscribe(listener) {
|
|
4296
|
+
listeners.add(listener);
|
|
4297
|
+
return () => {
|
|
4298
|
+
listeners.delete(listener);
|
|
4299
|
+
};
|
|
4300
|
+
},
|
|
4301
|
+
setView(view) {
|
|
4302
|
+
if (state.view !== view) emit({
|
|
4303
|
+
...state,
|
|
4304
|
+
view
|
|
4305
|
+
});
|
|
4306
|
+
},
|
|
4307
|
+
openHistory(skill) {
|
|
4308
|
+
emit({
|
|
4309
|
+
view: "history",
|
|
4310
|
+
...skill === void 0 ? {} : { selectedSkill: skill },
|
|
4311
|
+
focusRevision: state.focusRevision + 1
|
|
4312
|
+
});
|
|
4313
|
+
},
|
|
4314
|
+
clearSelection() {
|
|
4315
|
+
const { selectedSkill: _selected, ...rest } = state;
|
|
4316
|
+
emit({
|
|
4317
|
+
...rest,
|
|
4318
|
+
focusRevision: state.focusRevision + 1
|
|
4319
|
+
});
|
|
4320
|
+
}
|
|
4321
|
+
};
|
|
4322
|
+
}
|
|
4323
|
+
//#endregion
|
|
4220
4324
|
//#region src/panels/history/client/index.ts
|
|
4221
4325
|
/**
|
|
4222
4326
|
* Register the locale namespace, the workbench main occupant and its sidebar row.
|
|
@@ -4225,6 +4329,9 @@ window.__ModuleLoader__.load({
|
|
|
4225
4329
|
function apply$1(ctx) {
|
|
4226
4330
|
const api = createSkillHistoryApi();
|
|
4227
4331
|
const settingsSeat = createSettingsSeat(ctx);
|
|
4332
|
+
ctx.effect(() => () => {
|
|
4333
|
+
settingsSeat.dispose?.();
|
|
4334
|
+
}, "evolution-ui: settings seat");
|
|
4228
4335
|
let approvalConfirmMode = "ask";
|
|
4229
4336
|
const approvalForm = settingsSeat.get("evolution-approval");
|
|
4230
4337
|
const stopApprovalWatch = approvalForm?.subscribe(() => {
|
|
@@ -4273,6 +4380,7 @@ window.__ModuleLoader__.load({
|
|
|
4273
4380
|
api: createDiagnosticsApi((input, init) => fetch(input, init)),
|
|
4274
4381
|
fallback: FALLBACKS.diagnostics
|
|
4275
4382
|
});
|
|
4383
|
+
const workbenchStore = createWorkbenchStore();
|
|
4276
4384
|
registerSidebarPanel(ctx, {
|
|
4277
4385
|
id: WORKBENCH_ID,
|
|
4278
4386
|
order: 35,
|
|
@@ -4289,6 +4397,7 @@ window.__ModuleLoader__.load({
|
|
|
4289
4397
|
component: WorkbenchPage,
|
|
4290
4398
|
body: (t) => ({
|
|
4291
4399
|
t,
|
|
4400
|
+
store: workbenchStore,
|
|
4292
4401
|
history: historyFace(t),
|
|
4293
4402
|
pending: pendingFace(),
|
|
4294
4403
|
diagnostics: diagnosticsFace(),
|
|
@@ -7,23 +7,20 @@ import { type ReactNode } from 'react';
|
|
|
7
7
|
import { type PanelFace } from './Panel.ts';
|
|
8
8
|
import { type PendingCardFace } from '../../settings/PendingCard.ts';
|
|
9
9
|
import { type DiagnosticsCardFace } from '../../settings/DiagnosticsCard.ts';
|
|
10
|
+
import type { WorkbenchStore } from './WorkbenchStore.ts';
|
|
10
11
|
/** Stable page id used by the sidebar row, the page slot key, and navigation params. */
|
|
11
12
|
export declare const WORKBENCH_ID = "evolution.workbench";
|
|
12
13
|
/** Injected face: copy plus the history view's data callbacks. */
|
|
13
14
|
export interface WorkbenchFace {
|
|
14
15
|
readonly t: (key: string) => string;
|
|
16
|
+
readonly store: WorkbenchStore;
|
|
15
17
|
readonly history: PanelFace;
|
|
16
18
|
readonly pending: PendingCardFace;
|
|
17
19
|
readonly diagnostics: DiagnosticsCardFace;
|
|
18
20
|
/** Whether a feature view is actually mounted (health is disabled by default). */
|
|
19
21
|
readonly hasView?: (view: 'merge' | 'health') => boolean;
|
|
20
22
|
}
|
|
21
|
-
|
|
22
|
-
export type WorkbenchView = 'history' | 'pending' | 'merge' | 'health' | 'diagnostics';
|
|
23
|
-
/** Sidebar row injected face. */
|
|
24
|
-
export interface WorkbenchNavFace {
|
|
25
|
-
readonly t: (key: string) => string;
|
|
26
|
-
}
|
|
23
|
+
export type { WorkbenchView } from './WorkbenchStore.ts';
|
|
27
24
|
/**
|
|
28
25
|
* Render the workbench page. The platform keeps it mounted; this component only
|
|
29
26
|
* consumes a new explicit revision exactly once.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Registration-owned workbench navigation state. No module-level singleton. */
|
|
2
|
+
export type WorkbenchView = 'history' | 'pending' | 'merge' | 'health' | 'diagnostics';
|
|
3
|
+
export interface WorkbenchState {
|
|
4
|
+
readonly view: WorkbenchView;
|
|
5
|
+
readonly selectedSkill?: string;
|
|
6
|
+
readonly focusRevision: number;
|
|
7
|
+
}
|
|
8
|
+
export interface WorkbenchStore {
|
|
9
|
+
getState(): WorkbenchState;
|
|
10
|
+
subscribe(listener: () => void): () => void;
|
|
11
|
+
setView(view: WorkbenchView): void;
|
|
12
|
+
openHistory(skill?: string): void;
|
|
13
|
+
clearSelection(): void;
|
|
14
|
+
}
|
|
15
|
+
export declare function createWorkbenchStore(initial?: WorkbenchState): WorkbenchStore;
|
|
16
|
+
//# sourceMappingURL=WorkbenchStore.d.ts.map
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* description, so the settings surface can state both without a hand-written copy.
|
|
6
6
|
*/
|
|
7
7
|
/** The family version this surface belongs to. */
|
|
8
|
-
export declare const FAMILY_VERSION = "0.
|
|
8
|
+
export declare const FAMILY_VERSION = "0.34.0";
|
|
9
9
|
/** What this surface is for, in one line. */
|
|
10
10
|
export declare const PACKAGE_PURPOSE = "Web UI umbrella for the evolution family: settings and skill-history panels";
|
|
11
11
|
//# sourceMappingURL=generated-about.d.ts.map
|
|
@@ -40,6 +40,7 @@ export declare const zh: {
|
|
|
40
40
|
readonly resetTo: "复位为 {value}";
|
|
41
41
|
readonly saved: "已保存。";
|
|
42
42
|
readonly saveReadbackFailed: "写入已被接受,但回读失败;点刷新重读后再确认。";
|
|
43
|
+
readonly readbackStale: "显示的是最后一次成功读取的值;当前回读失败,刷新后可能变化。";
|
|
43
44
|
readonly saveConflict: "这个值没有被接受:设置已被其他页面修改。请重读后再保存。";
|
|
44
45
|
readonly resetDone: "已恢复默认值。";
|
|
45
46
|
readonly refused: "这个值没有被接受(界面上保持原样)。想看原因:在对话里让它说明。";
|
|
@@ -108,6 +109,8 @@ export declare const zh: {
|
|
|
108
109
|
readonly diagStatusUnknown: "未知";
|
|
109
110
|
readonly diagRemedy: "建议:";
|
|
110
111
|
readonly diagNoRows: "没有可显示的运行状态";
|
|
112
|
+
readonly diagPurpose: "用途:检查插件挂载、平台服务和数据面是否正常,不修改任何状态。";
|
|
113
|
+
readonly diagFooter: "诊断 schema v{version} · 生成于 {at}";
|
|
111
114
|
readonly stateLoading: "正在读取…";
|
|
112
115
|
readonly failureUnauthorized: "需要登录:重新打开这个页面完成登录后再试。";
|
|
113
116
|
readonly failureForbidden: "平台拒绝了这个请求(身份不是 owner)。";
|
|
@@ -45,7 +45,9 @@ export interface ParamSectionSnapshot {
|
|
|
45
45
|
* all, or the seat is there and serves no such row. The two read differently to the
|
|
46
46
|
* operator (one is the UI's own gap, the other is a row that is not composed).
|
|
47
47
|
*/
|
|
48
|
-
reason?: 'seat-missing' | 'not-served' | 'projection-failed';
|
|
48
|
+
reason?: 'seat-missing' | 'not-served' | 'projection-failed' | 'readback-failed';
|
|
49
|
+
/** Last-known values are still shown; the row could not be re-read. */
|
|
50
|
+
stale?: boolean;
|
|
49
51
|
}
|
|
50
52
|
/** The reactive source the renderer binds to a `use<Name>` seat. */
|
|
51
53
|
export interface ParamSectionSource {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-ui",
|
|
3
3
|
"description": "Web UI umbrella for the evolution family: settings and skill-history panels (community build)",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.34.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"react": "^18.2.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@lmzhen/dsh-evolution-client-kit": "^0.
|
|
49
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
50
|
-
"@lmzhen/dsh-evolution-curator": "^0.
|
|
48
|
+
"@lmzhen/dsh-evolution-client-kit": "^0.34.0",
|
|
49
|
+
"@lmzhen/dsh-evolution-core": "^0.34.0",
|
|
50
|
+
"@lmzhen/dsh-evolution-curator": "^0.34.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/react": "~18.3.1",
|