@lmzhen/dsh-evolution-ui 0.33.0 → 0.35.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 +230 -78
- 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/history/client/chrome.d.ts +1 -1
- package/lib/types/panels/settings/generated-about.d.ts +1 -1
- package/lib/types/panels/settings/messages.d.ts +5 -2
- package/lib/types/panels/settings/seam.d.ts +3 -1
- package/package.json +4 -4
package/lib/client.js
CHANGED
|
@@ -841,12 +841,12 @@ window.__ModuleLoader__.load({
|
|
|
841
841
|
projectionFailed: "这一块读设置时出错,已记入日志;其它参数不受影响",
|
|
842
842
|
readonly: "本次会话不允许写入设置(临时运行模式)",
|
|
843
843
|
apply: "保存",
|
|
844
|
-
reset: "
|
|
844
|
+
reset: "复位",
|
|
845
845
|
empty: "这里没有可改项",
|
|
846
846
|
changed: "{n} 项已覆盖",
|
|
847
847
|
discard: "放弃修改",
|
|
848
848
|
saving: "保存中…",
|
|
849
|
-
resetting: "
|
|
849
|
+
resetting: "复位中…",
|
|
850
850
|
writeTargetHost: "保存去向:宿主配置(对所有会话生效)",
|
|
851
851
|
invalidNumber: "需要一个数字",
|
|
852
852
|
invalidSelect: "不在允许的取值里",
|
|
@@ -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)。",
|
|
@@ -946,7 +949,7 @@ window.__ModuleLoader__.load({
|
|
|
946
949
|
projectionFailed: "reading this row failed and the error is in the log; the other parameters are unaffected",
|
|
947
950
|
readonly: "settings cannot be written in this session (temporary mode)",
|
|
948
951
|
apply: "Save",
|
|
949
|
-
reset: "Reset
|
|
952
|
+
reset: "Reset",
|
|
950
953
|
empty: "nothing to change here",
|
|
951
954
|
changed: "{n} overridden",
|
|
952
955
|
discard: "Discard",
|
|
@@ -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).",
|
|
@@ -1264,10 +1270,12 @@ window.__ModuleLoader__.load({
|
|
|
1264
1270
|
type: "button",
|
|
1265
1271
|
className: "evolution-param-button",
|
|
1266
1272
|
disabled: props.disabled || props.clearing,
|
|
1273
|
+
"data-role": "reset",
|
|
1274
|
+
title: props.resetTo === null ? void 0 : t("resetTo", { value: props.resetTo }),
|
|
1267
1275
|
onClick: () => {
|
|
1268
1276
|
props.onClear(field.id);
|
|
1269
1277
|
}
|
|
1270
|
-
}, props.clearing ? t("resetting") : t("reset"))
|
|
1278
|
+
}, props.clearing ? t("resetting") : t("reset"))) : null);
|
|
1271
1279
|
}
|
|
1272
1280
|
/**
|
|
1273
1281
|
* Render one row's card body from a supplied snapshot.
|
|
@@ -1426,7 +1434,11 @@ window.__ModuleLoader__.load({
|
|
|
1426
1434
|
onClick: () => {
|
|
1427
1435
|
setOpen(!open);
|
|
1428
1436
|
}
|
|
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)),
|
|
1437
|
+
}, (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", {
|
|
1438
|
+
className: "evolution-param-note",
|
|
1439
|
+
role: "status",
|
|
1440
|
+
"data-role": "stale-note"
|
|
1441
|
+
}, t("readbackStale")) : null, disabled ? (0, react.createElement)("p", {
|
|
1430
1442
|
className: "evolution-param-note",
|
|
1431
1443
|
role: "status"
|
|
1432
1444
|
}, t("readonly")) : null, fields.length === 0 ? (0, react.createElement)("p", {
|
|
@@ -1677,34 +1689,51 @@ window.__ModuleLoader__.load({
|
|
|
1677
1689
|
...EMPTY,
|
|
1678
1690
|
reason: "seat-missing"
|
|
1679
1691
|
};
|
|
1692
|
+
let lastReady;
|
|
1693
|
+
let generation = 0;
|
|
1680
1694
|
const listeners = /* @__PURE__ */ new Set();
|
|
1681
|
-
let
|
|
1682
|
-
let listening = false;
|
|
1695
|
+
let remoteOff;
|
|
1683
1696
|
const notify = () => {
|
|
1684
1697
|
for (const listener of listeners) listener();
|
|
1685
1698
|
};
|
|
1686
|
-
const
|
|
1687
|
-
|
|
1699
|
+
const absorb = (next) => {
|
|
1700
|
+
if (next.status === "ready") {
|
|
1701
|
+
lastReady = next;
|
|
1702
|
+
snapshot = next;
|
|
1703
|
+
} else if (lastReady !== void 0) snapshot = {
|
|
1704
|
+
...lastReady,
|
|
1705
|
+
stale: true,
|
|
1706
|
+
reason: next.reason ?? "readback-failed"
|
|
1707
|
+
};
|
|
1708
|
+
else snapshot = next;
|
|
1688
1709
|
notify();
|
|
1689
1710
|
};
|
|
1690
|
-
const
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
if (
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1711
|
+
const refresh = async () => {
|
|
1712
|
+
const ticket = ++generation;
|
|
1713
|
+
const next = await describe(namespace);
|
|
1714
|
+
if (ticket !== generation) return;
|
|
1715
|
+
absorb(next);
|
|
1716
|
+
};
|
|
1717
|
+
const remote = () => ctx.get?.("remote");
|
|
1718
|
+
const stopRemote = () => {
|
|
1719
|
+
remoteOff?.();
|
|
1720
|
+
remoteOff = void 0;
|
|
1721
|
+
};
|
|
1722
|
+
const startRemote = () => {
|
|
1723
|
+
if (remoteOff !== void 0) return;
|
|
1724
|
+
remoteOff = remote()?.$on?.("settings/document-updated", (changed) => {
|
|
1725
|
+
if (changed === namespace) refresh();
|
|
1726
|
+
});
|
|
1700
1727
|
};
|
|
1701
1728
|
const form = {
|
|
1702
1729
|
getSnapshot: () => snapshot,
|
|
1703
1730
|
subscribe: (listener) => {
|
|
1704
1731
|
listeners.add(listener);
|
|
1705
|
-
|
|
1732
|
+
startRemote();
|
|
1733
|
+
refresh();
|
|
1706
1734
|
return () => {
|
|
1707
1735
|
listeners.delete(listener);
|
|
1736
|
+
if (listeners.size === 0) stopRemote();
|
|
1708
1737
|
};
|
|
1709
1738
|
},
|
|
1710
1739
|
set: async (field, value) => await form.mutate([{
|
|
@@ -1718,37 +1747,63 @@ window.__ModuleLoader__.load({
|
|
|
1718
1747
|
}]),
|
|
1719
1748
|
mutate: async (ops, expectedRevision) => {
|
|
1720
1749
|
const outcome = await write(namespace, ops, expectedRevision ?? snapshot.revision);
|
|
1721
|
-
if (outcome.snapshot !== void 0)
|
|
1722
|
-
|
|
1723
|
-
notify();
|
|
1724
|
-
} else await refresh();
|
|
1750
|
+
if (outcome.snapshot !== void 0) absorb(outcome.snapshot);
|
|
1751
|
+
else await refresh();
|
|
1725
1752
|
return outcome.ok;
|
|
1753
|
+
},
|
|
1754
|
+
refresh,
|
|
1755
|
+
dispose: () => {
|
|
1756
|
+
stopRemote();
|
|
1757
|
+
listeners.clear();
|
|
1726
1758
|
}
|
|
1727
1759
|
};
|
|
1728
1760
|
return form;
|
|
1729
1761
|
}
|
|
1730
1762
|
/**
|
|
1731
|
-
* Build one
|
|
1732
|
-
*
|
|
1733
|
-
*
|
|
1763
|
+
* Build one seat per client registration; every form's remote listener is released by
|
|
1764
|
+
* the caller's effect. No module-level WeakMap: a replaced registration must not share
|
|
1765
|
+
* a dead seat with the previous one.
|
|
1734
1766
|
*/
|
|
1735
|
-
const seats = /* @__PURE__ */ new WeakMap();
|
|
1736
1767
|
function createSettingsSeat(ctx) {
|
|
1737
|
-
const cached = seats.get(ctx);
|
|
1738
|
-
if (cached !== void 0) return cached;
|
|
1739
1768
|
const forms = /* @__PURE__ */ new Map();
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
form
|
|
1744
|
-
|
|
1769
|
+
return {
|
|
1770
|
+
get(namespace) {
|
|
1771
|
+
let form = forms.get(namespace);
|
|
1772
|
+
if (form === void 0) {
|
|
1773
|
+
form = createForm(namespace, ctx);
|
|
1774
|
+
forms.set(namespace, form);
|
|
1775
|
+
}
|
|
1776
|
+
return form;
|
|
1777
|
+
},
|
|
1778
|
+
dispose: () => {
|
|
1779
|
+
for (const form of forms.values()) form.dispose?.();
|
|
1780
|
+
forms.clear();
|
|
1745
1781
|
}
|
|
1746
|
-
|
|
1747
|
-
} };
|
|
1748
|
-
seats.set(ctx, seat);
|
|
1749
|
-
return seat;
|
|
1782
|
+
};
|
|
1750
1783
|
}
|
|
1751
1784
|
//#endregion
|
|
1785
|
+
//#region ../evolution-client-kit/src/format.ts
|
|
1786
|
+
/**
|
|
1787
|
+
* Format an ISO string, epoch milliseconds, or null as local wall time.
|
|
1788
|
+
* Invalid values return null; callers decide how to say "unknown".
|
|
1789
|
+
* @param value - ISO string, epoch ms, or null.
|
|
1790
|
+
* @param options - seconds on/off; defaults to on.
|
|
1791
|
+
* @returns the formatted local time, or null when the value is absent/invalid.
|
|
1792
|
+
*/
|
|
1793
|
+
function formatLocalDateTime(value, options = {}) {
|
|
1794
|
+
if (value === null || value === void 0) return null;
|
|
1795
|
+
const ms = typeof value === "number" ? value : Date.parse(value);
|
|
1796
|
+
if (!Number.isFinite(ms)) return null;
|
|
1797
|
+
const date = new Date(ms);
|
|
1798
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
1799
|
+
const pad = (part) => String(part).padStart(2, "0");
|
|
1800
|
+
const head = String(date.getFullYear()) + "-" + pad(date.getMonth() + 1) + "-" + pad(date.getDate()) + " " + pad(date.getHours()) + ":" + pad(date.getMinutes());
|
|
1801
|
+
return options.seconds === false ? head : head + ":" + pad(date.getSeconds());
|
|
1802
|
+
}
|
|
1803
|
+
//#endregion
|
|
1804
|
+
//#region ../evolution-client-kit/src/notice.ts
|
|
1805
|
+
/** One inline state notice: semantic tone plus text, no surface-specific styling. */
|
|
1806
|
+
//#endregion
|
|
1752
1807
|
//#region ../evolution-client-kit/src/action.ts
|
|
1753
1808
|
/**
|
|
1754
1809
|
* Command-only actions. Approval decisions are a separate host API and must never
|
|
@@ -1848,7 +1903,8 @@ window.__ModuleLoader__.load({
|
|
|
1848
1903
|
user: snapshot.user,
|
|
1849
1904
|
writable: snapshot.writable,
|
|
1850
1905
|
base: isRecord(snapshot.base) ? snapshot.base : void 0,
|
|
1851
|
-
...snapshot.status === "unavailable" ? { reason: snapshot.reason ?? "not-served" } : {}
|
|
1906
|
+
...snapshot.status === "unavailable" ? { reason: snapshot.reason ?? "not-served" } : {},
|
|
1907
|
+
...snapshot.stale === true ? { stale: true } : {}
|
|
1852
1908
|
};
|
|
1853
1909
|
}
|
|
1854
1910
|
/**
|
|
@@ -1958,7 +2014,6 @@ window.__ModuleLoader__.load({
|
|
|
1958
2014
|
readback: "failed",
|
|
1959
2015
|
kind: "transport"
|
|
1960
2016
|
};
|
|
1961
|
-
const before = seat.getSnapshot().revision;
|
|
1962
2017
|
let written = false;
|
|
1963
2018
|
try {
|
|
1964
2019
|
written = await seat.mutate(ops);
|
|
@@ -1970,12 +2025,15 @@ window.__ModuleLoader__.load({
|
|
|
1970
2025
|
failure
|
|
1971
2026
|
};
|
|
1972
2027
|
}
|
|
1973
|
-
const snapshot = seat.getSnapshot();
|
|
1974
2028
|
if (!written) return {
|
|
1975
2029
|
written: false,
|
|
1976
2030
|
readback: "failed",
|
|
1977
2031
|
kind: "conflict"
|
|
1978
2032
|
};
|
|
2033
|
+
try {
|
|
2034
|
+
await seat.refresh?.();
|
|
2035
|
+
} catch {}
|
|
2036
|
+
const snapshot = seat.getSnapshot();
|
|
1979
2037
|
if (snapshot.status !== "ready") return {
|
|
1980
2038
|
written: true,
|
|
1981
2039
|
readback: "failed",
|
|
@@ -1983,7 +2041,8 @@ window.__ModuleLoader__.load({
|
|
|
1983
2041
|
};
|
|
1984
2042
|
return {
|
|
1985
2043
|
written: true,
|
|
1986
|
-
readback: snapshot.
|
|
2044
|
+
readback: snapshot.stale === true ? "failed" : "ok",
|
|
2045
|
+
...snapshot.stale === true ? { kind: "transport" } : {}
|
|
1987
2046
|
};
|
|
1988
2047
|
};
|
|
1989
2048
|
return {
|
|
@@ -2586,6 +2645,8 @@ window.__ModuleLoader__.load({
|
|
|
2586
2645
|
* read, because a half-list would read as a complete window.
|
|
2587
2646
|
*/
|
|
2588
2647
|
const readTicket = (0, react.useRef)(0);
|
|
2648
|
+
const previewTicket = (0, react.useRef)(0);
|
|
2649
|
+
const actionTickets = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
2589
2650
|
const load = async () => {
|
|
2590
2651
|
apply(loading);
|
|
2591
2652
|
const ticket = readTicket.current + 1;
|
|
@@ -2613,9 +2674,13 @@ window.__ModuleLoader__.load({
|
|
|
2613
2674
|
};
|
|
2614
2675
|
}, []);
|
|
2615
2676
|
const decide = (id, action) => {
|
|
2677
|
+
if (latest.current.busy.includes(id)) return;
|
|
2678
|
+
const ticket = (actionTickets.current.get(id) ?? 0) + 1;
|
|
2679
|
+
actionTickets.current.set(id, ticket);
|
|
2616
2680
|
apply((current) => beginAction(current, id));
|
|
2617
2681
|
(async () => {
|
|
2618
2682
|
const answer = action === "approve" ? await api.approve(id) : action === "reject" ? await api.reject(id) : await api.release(id);
|
|
2683
|
+
if (actionTickets.current.get(id) !== ticket) return;
|
|
2619
2684
|
if (!answer.ok) {
|
|
2620
2685
|
apply((current) => noticed(endAction(current, id), failureText(answer.failure, translate)));
|
|
2621
2686
|
return;
|
|
@@ -2631,7 +2696,9 @@ window.__ModuleLoader__.load({
|
|
|
2631
2696
|
};
|
|
2632
2697
|
/** Ask the host what this record would store; the answer lands only if the row is still open. */
|
|
2633
2698
|
const loadPreview = async (id) => {
|
|
2699
|
+
const ticket = ++previewTicket.current;
|
|
2634
2700
|
const answer = await api.preview(id);
|
|
2701
|
+
if (ticket !== previewTicket.current || latest.current.open !== id) return;
|
|
2635
2702
|
const view = answer.ok ? answer.data.available ? {
|
|
2636
2703
|
kind: "ready",
|
|
2637
2704
|
answer: answer.data
|
|
@@ -2685,7 +2752,13 @@ window.__ModuleLoader__.load({
|
|
|
2685
2752
|
}, t("approvalDiffCut"))] : []
|
|
2686
2753
|
];
|
|
2687
2754
|
const lines = [];
|
|
2755
|
+
const multiHunk = view.answer.hunks.length > 1 || view.answer.hunks.some((hunk) => hunk.path !== view.answer.path);
|
|
2688
2756
|
for (const [hunkIndex, hunk] of view.answer.hunks.entries()) {
|
|
2757
|
+
if (multiHunk) lines.push((0, react.createElement)("div", {
|
|
2758
|
+
key: "hunk-" + String(hunkIndex),
|
|
2759
|
+
className: "evolution-param-hunk-path",
|
|
2760
|
+
"data-role": "hunk-path"
|
|
2761
|
+
}, hunk.path));
|
|
2689
2762
|
for (const [index, line] of hunk.oldText.split("\n").entries()) {
|
|
2690
2763
|
if (hunk.oldText === "" && line === "") continue;
|
|
2691
2764
|
lines.push((0, react.createElement)("div", {
|
|
@@ -2854,6 +2927,7 @@ window.__ModuleLoader__.load({
|
|
|
2854
2927
|
const zh = {
|
|
2855
2928
|
"entry.label": "技能历史",
|
|
2856
2929
|
title: "技能历史",
|
|
2930
|
+
bodyTitle: "正文版本",
|
|
2857
2931
|
"workbench.history": "技能历史",
|
|
2858
2932
|
"workbench.pending": "待批",
|
|
2859
2933
|
"workbench.merge": "合并",
|
|
@@ -2883,6 +2957,7 @@ window.__ModuleLoader__.load({
|
|
|
2883
2957
|
"failure.server": "读取失败,可以重试。",
|
|
2884
2958
|
"fallback.hint": "可以改用命令:{command}",
|
|
2885
2959
|
"undo.confirm": "确认回退(会写入一版,可再回退)",
|
|
2960
|
+
"undo.confirmUnit": "确认回退整个跨技能写入单元(会写入一版,可再回退)",
|
|
2886
2961
|
"undo.no": "取消",
|
|
2887
2962
|
current: "当前",
|
|
2888
2963
|
"versions.count": "{n} 个版本",
|
|
@@ -2923,6 +2998,7 @@ window.__ModuleLoader__.load({
|
|
|
2923
2998
|
"action.archive": "归档",
|
|
2924
2999
|
"action.archive.note": "这一版存的是被归档的正文",
|
|
2925
3000
|
"action.consolidate": "合并",
|
|
3001
|
+
"action.merge": "合并",
|
|
2926
3002
|
"action.restructure": "结构调整",
|
|
2927
3003
|
"action.extract": "跨技能提取",
|
|
2928
3004
|
"action.support-write": "写入附带文件",
|
|
@@ -2946,6 +3022,7 @@ window.__ModuleLoader__.load({
|
|
|
2946
3022
|
const en = {
|
|
2947
3023
|
"entry.label": "Skill history",
|
|
2948
3024
|
title: "Skill history",
|
|
3025
|
+
bodyTitle: "Body versions",
|
|
2949
3026
|
"workbench.history": "Skill history",
|
|
2950
3027
|
"workbench.pending": "Pending",
|
|
2951
3028
|
"workbench.merge": "Merge",
|
|
@@ -2975,6 +3052,7 @@ window.__ModuleLoader__.load({
|
|
|
2975
3052
|
"failure.server": "The read failed; you can retry.",
|
|
2976
3053
|
"fallback.hint": "Command fallback: {command}",
|
|
2977
3054
|
"undo.confirm": "Confirm restore (writes a new version; can be undone)",
|
|
3055
|
+
"undo.confirmUnit": "Confirm restoring the whole cross-skill unit (writes a new version; can be undone)",
|
|
2978
3056
|
"undo.no": "Cancel",
|
|
2979
3057
|
current: "Current",
|
|
2980
3058
|
"versions.count": "{n} versions",
|
|
@@ -3015,6 +3093,7 @@ window.__ModuleLoader__.load({
|
|
|
3015
3093
|
"action.archive": "archived",
|
|
3016
3094
|
"action.archive.note": "this version holds the archived body",
|
|
3017
3095
|
"action.consolidate": "merged",
|
|
3096
|
+
"action.merge": "merged",
|
|
3018
3097
|
"action.restructure": "restructured",
|
|
3019
3098
|
"action.extract": "extracted across skills",
|
|
3020
3099
|
"action.support-write": "support file written",
|
|
@@ -3081,6 +3160,7 @@ window.__ModuleLoader__.load({
|
|
|
3081
3160
|
".evo-hist-skill[aria-current=\"true\"]{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);font-weight:500}",
|
|
3082
3161
|
".evo-hist-cell-line{display:flex;align-items:baseline;gap:var(--evo-space-6);min-width:0}",
|
|
3083
3162
|
".evo-hist-cell-meta{margin-top:var(--evo-space-2)}",
|
|
3163
|
+
".evo-hist-skill-description{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin-top:var(--evo-space-2);color:var(--dsw-alias-label-tertiary)}",
|
|
3084
3164
|
".evo-hist-cell{min-width:0;font-variant-numeric:tabular-nums}",
|
|
3085
3165
|
".evo-hist-slot-lead{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
3086
3166
|
".evo-hist-slot-meta{flex:none;white-space:nowrap}",
|
|
@@ -3124,7 +3204,7 @@ window.__ModuleLoader__.load({
|
|
|
3124
3204
|
".evo-doc-tag{position:absolute;left:var(--evo-space-8);top:var(--evo-space-8);color:var(--dsw-alias-label-tertiary)}",
|
|
3125
3205
|
".evo-doc-line-add{color:var(--evo-tone-success)}",
|
|
3126
3206
|
".evo-doc-line-del{color:var(--evo-tone-danger)}",
|
|
3127
|
-
"@media (max-width:
|
|
3207
|
+
"@media (max-width:900px){.evo-hist-root{flex-direction:column}.evo-hist-aside{flex:0 0 auto;width:100%;max-height:42%;border-right:0;border-bottom:var(--evo-hairline-width) solid var(--dsw-alias-border-l2)}.evo-hist-row{max-width:none}}"
|
|
3128
3208
|
].join("\n");
|
|
3129
3209
|
//#endregion
|
|
3130
3210
|
//#region src/panels/history/client/atoms.ts
|
|
@@ -3232,11 +3312,7 @@ window.__ModuleLoader__.load({
|
|
|
3232
3312
|
*/
|
|
3233
3313
|
/** The local time an ISO timestamp names, as the operator's own clock shows it. */
|
|
3234
3314
|
function localTime(at) {
|
|
3235
|
-
|
|
3236
|
-
if (Number.isNaN(parsed)) return at;
|
|
3237
|
-
const date = new Date(parsed);
|
|
3238
|
-
const pad = (value) => String(value).padStart(2, "0");
|
|
3239
|
-
return String(date.getFullYear()) + "-" + pad(date.getMonth() + 1) + "-" + pad(date.getDate()) + " " + pad(date.getHours()) + ":" + pad(date.getMinutes());
|
|
3315
|
+
return formatLocalDateTime(at, { seconds: false }) ?? at;
|
|
3240
3316
|
}
|
|
3241
3317
|
/** The text one cell shows, resolved through the seat. */
|
|
3242
3318
|
function cellText(copy, cell) {
|
|
@@ -3285,7 +3361,11 @@ window.__ModuleLoader__.load({
|
|
|
3285
3361
|
className: "evo-hist-skill",
|
|
3286
3362
|
"aria-current": selected ? "true" : void 0,
|
|
3287
3363
|
onClick: onOpen
|
|
3288
|
-
}, cellLine(row.cells.title, copy, "evo-hist-cell-line"),
|
|
3364
|
+
}, cellLine(row.cells.title, copy, "evo-hist-cell-line"), (() => {
|
|
3365
|
+
const description = row.cells.meta.filter((cell) => cell.key === "description");
|
|
3366
|
+
const facts = row.cells.meta.filter((cell) => cell.key !== "description");
|
|
3367
|
+
return [description.length === 0 ? null : cellLine(description, copy, "evo-hist-cell-line evo-hist-skill-description"), facts.length === 0 ? null : cellLine(facts, copy, "evo-hist-cell-line evo-hist-cell-meta")];
|
|
3368
|
+
})());
|
|
3289
3369
|
}
|
|
3290
3370
|
/**
|
|
3291
3371
|
* One version row: what happened, when, how big — then the controls, then whatever is expanded.
|
|
@@ -3313,7 +3393,7 @@ window.__ModuleLoader__.load({
|
|
|
3313
3393
|
key: "undo",
|
|
3314
3394
|
tone: confirming ? "primary" : "quiet",
|
|
3315
3395
|
onClick: onRestore,
|
|
3316
|
-
children: confirming ? copy.t("undo.confirm") : copy.t("undo")
|
|
3396
|
+
children: confirming ? copy.t(row.unitId === void 0 ? "undo.confirm" : "undo.confirmUnit") : copy.t("undo")
|
|
3317
3397
|
}));
|
|
3318
3398
|
}
|
|
3319
3399
|
if (row.undoable === true || row.charsDelta !== void 0) actions.push(button({
|
|
@@ -3373,8 +3453,8 @@ window.__ModuleLoader__.load({
|
|
|
3373
3453
|
});
|
|
3374
3454
|
}
|
|
3375
3455
|
/** The pane's heading and its one control. */
|
|
3376
|
-
function panelHead(copy, onRefresh) {
|
|
3377
|
-
return (0, react.createElement)("div", { className: "evo-hist-head" }, (0, react.createElement)("h2", { className: "evo-hist-title" }, copy.t("title")), button({
|
|
3456
|
+
function panelHead(copy, onRefresh, title) {
|
|
3457
|
+
return (0, react.createElement)("div", { className: "evo-hist-head" }, (0, react.createElement)("h2", { className: "evo-hist-title" }, title ?? copy.t("title")), button({
|
|
3378
3458
|
key: "refresh",
|
|
3379
3459
|
title: copy.t("refresh"),
|
|
3380
3460
|
onClick: onRefresh,
|
|
@@ -3900,7 +3980,7 @@ window.__ModuleLoader__.load({
|
|
|
3900
3980
|
};
|
|
3901
3981
|
return (0, react.createElement)("div", { className: "evo-hist-root" }, (0, react.createElement)("aside", { className: "evo-hist-aside" }, searchField(face, query, setQuery), (0, react.createElement)("div", { className: "evo-hist-list" }, skills.length === 0 ? emptyState(face.t(skillsLoaded ? "empty.skills" : "loading")) : visible.length === 0 ? emptyState(face.t("search.none")) : visible.map((skill) => skillLine(face, skill, skill.name === selected, () => {
|
|
3902
3982
|
open(skill.name);
|
|
3903
|
-
})))), (0, react.createElement)("div", { className: "evo-hist-main" }, panelHead(face, refresh), notice(noteText, noteError), failure === void 0 ? null : (0, react.createElement)("div", { className: "evo-hist-failure" }, failureBlock(face.t, failure)), selected === void 0 ? [emptyState(face.t(skills.length === 0 ? skillsLoaded ? "empty.skills" : "loading" : "empty.pick"), "empty"), (0, react.createElement)("p", {
|
|
3983
|
+
})))), (0, react.createElement)("div", { className: "evo-hist-main" }, panelHead(face, refresh, selected ?? face.t("bodyTitle")), notice(noteText, noteError), failure === void 0 ? null : (0, react.createElement)("div", { className: "evo-hist-failure" }, failureBlock(face.t, failure)), selected === void 0 ? [emptyState(face.t(skills.length === 0 ? skillsLoaded ? "empty.skills" : "loading" : "empty.pick"), "empty"), (0, react.createElement)("p", {
|
|
3904
3984
|
key: "hint",
|
|
3905
3985
|
className: "evo-hist-hint"
|
|
3906
3986
|
}, face.t("hint"))] : loaded ? null : emptyState(versionsFailed === void 0 ? face.t("loading") : `${face.t("empty.versions.failed")} — ${versionsFailed}`), loaded ? (0, react.createElement)("div", null, group(face.t("group.content"), payload.content, void 0), group(face.t("group.support"), payload.support, face.t("group.support.note")), payload.content.length === 0 && payload.support.length === 0 ? (0, react.createElement)("p", { className: "evo-hist-hint" }, face.t("empty.versions")) : null) : null));
|
|
@@ -3980,19 +4060,26 @@ window.__ModuleLoader__.load({
|
|
|
3980
4060
|
const translate = (key, values) => t(key, values);
|
|
3981
4061
|
const [state, setState] = (0, react.useState)({ phase: "loading" });
|
|
3982
4062
|
const [refreshing, setRefreshing] = (0, react.useState)(false);
|
|
4063
|
+
const [refreshFailure, setRefreshFailure] = (0, react.useState)(void 0);
|
|
3983
4064
|
const [open, setOpen] = (0, react.useState)(false);
|
|
3984
4065
|
const ticket = (0, react.useRef)(0);
|
|
3985
4066
|
const read = (keepView) => {
|
|
3986
4067
|
const current = ticket.current + 1;
|
|
3987
4068
|
ticket.current = current;
|
|
3988
|
-
if (keepView)
|
|
3989
|
-
|
|
4069
|
+
if (keepView) {
|
|
4070
|
+
setRefreshing(true);
|
|
4071
|
+
setRefreshFailure(void 0);
|
|
4072
|
+
} else setState({ phase: "loading" });
|
|
3990
4073
|
api.view().then((answer) => {
|
|
3991
4074
|
if (ticket.current !== current) return;
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
4075
|
+
if (answer.ok) {
|
|
4076
|
+
setState({
|
|
4077
|
+
phase: "ready",
|
|
4078
|
+
view: answer.data
|
|
4079
|
+
});
|
|
4080
|
+
setRefreshFailure(void 0);
|
|
4081
|
+
} else if (keepView) setRefreshFailure(answer.failure);
|
|
4082
|
+
else setState({
|
|
3996
4083
|
phase: "failed",
|
|
3997
4084
|
failure: answer.failure
|
|
3998
4085
|
});
|
|
@@ -4007,6 +4094,7 @@ window.__ModuleLoader__.load({
|
|
|
4007
4094
|
read(true);
|
|
4008
4095
|
};
|
|
4009
4096
|
const summary = state.phase === "ready" ? summaryOf(state.view.runtime) : void 0;
|
|
4097
|
+
const focusRow = summary === void 0 || summary.status === "ok" || state.phase !== "ready" ? void 0 : state.view.runtime.find((row) => row.status === summary.status);
|
|
4010
4098
|
const header = (0, react.createElement)("button", {
|
|
4011
4099
|
type: "button",
|
|
4012
4100
|
className: "evolution-param-head",
|
|
@@ -4017,7 +4105,7 @@ window.__ModuleLoader__.load({
|
|
|
4017
4105
|
}, (0, react.createElement)("span", { className: "evolution-param-card-title" }, t("diagTitle")), summary === void 0 ? null : (0, react.createElement)("span", {
|
|
4018
4106
|
className: "evo-diag-badge",
|
|
4019
4107
|
"data-status": summary.status
|
|
4020
|
-
}, t(SUMMARY_KEYS[summary.status], summary.count === 0 ? void 0 : { n: summary.count })), (0, react.createElement)("span", { className: "evolution-param-chevron" }, open ? "▲" : "▼"));
|
|
4108
|
+
}, t(SUMMARY_KEYS[summary.status], summary.count === 0 ? void 0 : { n: summary.count })), focusRow === void 0 ? null : (0, react.createElement)("span", { "data-role": "diag-focus" }, focusRow.label), (0, react.createElement)("span", { className: "evolution-param-chevron" }, open ? "▲" : "▼"));
|
|
4021
4109
|
const runtime = (view) => view.runtime.length === 0 ? null : (0, react.createElement)("div", {}, (0, react.createElement)("h3", { className: "evolution-param-group" }, t("diagRuntimeTitle")), (0, react.createElement)("div", { className: "evo-diag-list" }, ...view.runtime.map((row) => (0, react.createElement)("div", {
|
|
4022
4110
|
key: "runtime-" + row.key,
|
|
4023
4111
|
className: "evo-diag-item",
|
|
@@ -4032,13 +4120,26 @@ window.__ModuleLoader__.load({
|
|
|
4032
4120
|
fallback: props.fallback
|
|
4033
4121
|
});
|
|
4034
4122
|
const view = state.view;
|
|
4035
|
-
return (0, react.createElement)("div", {}, (0, react.createElement)("p", { className: "evolution-param-note" }, t("diagSubtitle")),
|
|
4123
|
+
return (0, react.createElement)("div", {}, (0, react.createElement)("p", { className: "evolution-param-note" }, t("diagSubtitle")), refreshFailure === void 0 ? null : FailureBlock({
|
|
4124
|
+
failure: refreshFailure,
|
|
4125
|
+
t: translate,
|
|
4126
|
+
fallback: props.fallback
|
|
4127
|
+
}), (0, react.createElement)("div", { className: "evolution-param-actions" }, (0, react.createElement)("button", {
|
|
4036
4128
|
type: "button",
|
|
4037
4129
|
className: "evolution-param-button",
|
|
4038
4130
|
onClick: refresh,
|
|
4039
4131
|
disabled: refreshing,
|
|
4040
4132
|
"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)
|
|
4133
|
+
}, 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", {
|
|
4134
|
+
className: "evolution-param-note",
|
|
4135
|
+
"data-role": "diag-purpose"
|
|
4136
|
+
}, t("diagPurpose")), (0, react.createElement)("p", {
|
|
4137
|
+
className: "evolution-param-hint",
|
|
4138
|
+
"data-role": "diag-footer"
|
|
4139
|
+
}, t("diagFooter", {
|
|
4140
|
+
version: String(view.schemaVersion),
|
|
4141
|
+
at: new Date(view.generatedAt).toLocaleString()
|
|
4142
|
+
})));
|
|
4042
4143
|
};
|
|
4043
4144
|
return (0, react.createElement)("section", {
|
|
4044
4145
|
className: "evolution-param-card",
|
|
@@ -4061,16 +4162,23 @@ window.__ModuleLoader__.load({
|
|
|
4061
4162
|
* @returns the page surface.
|
|
4062
4163
|
*/
|
|
4063
4164
|
function WorkbenchPage(props) {
|
|
4064
|
-
const
|
|
4065
|
-
const
|
|
4066
|
-
const
|
|
4165
|
+
const state = (0, react.useSyncExternalStore)(props.store.subscribe, props.store.getState, props.store.getState);
|
|
4166
|
+
const view = state.view;
|
|
4167
|
+
const selectedSkill = state.selectedSkill;
|
|
4168
|
+
const focusRevision = state.focusRevision;
|
|
4067
4169
|
const openHistory = (skill) => {
|
|
4068
|
-
|
|
4069
|
-
setView("history");
|
|
4070
|
-
setFocusRevision((value) => value + 1);
|
|
4170
|
+
props.store.openHistory(skill);
|
|
4071
4171
|
};
|
|
4072
4172
|
const hasMerge = props.hasView?.("merge") ?? true;
|
|
4073
4173
|
const hasHealth = props.hasView?.("health") ?? true;
|
|
4174
|
+
(0, react.useEffect)(() => {
|
|
4175
|
+
if (view === "merge" && !hasMerge || view === "health" && !hasHealth) props.store.setView("history");
|
|
4176
|
+
}, [
|
|
4177
|
+
view,
|
|
4178
|
+
hasMerge,
|
|
4179
|
+
hasHealth,
|
|
4180
|
+
props.store
|
|
4181
|
+
]);
|
|
4074
4182
|
const viewOrder = [
|
|
4075
4183
|
"history",
|
|
4076
4184
|
"pending",
|
|
@@ -4084,7 +4192,7 @@ window.__ModuleLoader__.load({
|
|
|
4084
4192
|
event.preventDefault();
|
|
4085
4193
|
const index = viewOrder.indexOf(current);
|
|
4086
4194
|
const next = event.key === "Home" ? viewOrder[0] : event.key === "End" ? viewOrder[viewOrder.length - 1] : viewOrder[(index + delta + viewOrder.length) % viewOrder.length];
|
|
4087
|
-
setView(next);
|
|
4195
|
+
props.store.setView(next);
|
|
4088
4196
|
requestAnimationFrame(() => {
|
|
4089
4197
|
document.getElementById("evo-workbench-tab-" + next)?.focus();
|
|
4090
4198
|
});
|
|
@@ -4105,7 +4213,7 @@ window.__ModuleLoader__.load({
|
|
|
4105
4213
|
"aria-controls": "evo-workbench-panel",
|
|
4106
4214
|
"data-active": view === "history" ? "true" : void 0,
|
|
4107
4215
|
onClick: () => {
|
|
4108
|
-
setView("history");
|
|
4216
|
+
props.store.setView("history");
|
|
4109
4217
|
},
|
|
4110
4218
|
onKeyDown: (event) => {
|
|
4111
4219
|
onTabKey(event, "history");
|
|
@@ -4119,7 +4227,7 @@ window.__ModuleLoader__.load({
|
|
|
4119
4227
|
"aria-controls": "evo-workbench-panel",
|
|
4120
4228
|
"data-active": view === "pending" ? "true" : void 0,
|
|
4121
4229
|
onClick: () => {
|
|
4122
|
-
setView("pending");
|
|
4230
|
+
props.store.setView("pending");
|
|
4123
4231
|
},
|
|
4124
4232
|
onKeyDown: (event) => {
|
|
4125
4233
|
onTabKey(event, "pending");
|
|
@@ -4133,7 +4241,7 @@ window.__ModuleLoader__.load({
|
|
|
4133
4241
|
"aria-controls": "evo-workbench-panel",
|
|
4134
4242
|
"data-active": view === "merge" ? "true" : void 0,
|
|
4135
4243
|
onClick: () => {
|
|
4136
|
-
setView("merge");
|
|
4244
|
+
props.store.setView("merge");
|
|
4137
4245
|
},
|
|
4138
4246
|
onKeyDown: (event) => {
|
|
4139
4247
|
onTabKey(event, "merge");
|
|
@@ -4147,7 +4255,7 @@ window.__ModuleLoader__.load({
|
|
|
4147
4255
|
"aria-controls": "evo-workbench-panel",
|
|
4148
4256
|
"data-active": view === "health" ? "true" : void 0,
|
|
4149
4257
|
onClick: () => {
|
|
4150
|
-
setView("health");
|
|
4258
|
+
props.store.setView("health");
|
|
4151
4259
|
},
|
|
4152
4260
|
onKeyDown: (event) => {
|
|
4153
4261
|
onTabKey(event, "health");
|
|
@@ -4161,7 +4269,7 @@ window.__ModuleLoader__.load({
|
|
|
4161
4269
|
"aria-controls": "evo-workbench-panel",
|
|
4162
4270
|
"data-active": view === "diagnostics" ? "true" : void 0,
|
|
4163
4271
|
onClick: () => {
|
|
4164
|
-
setView("diagnostics");
|
|
4272
|
+
props.store.setView("diagnostics");
|
|
4165
4273
|
},
|
|
4166
4274
|
onKeyDown: (event) => {
|
|
4167
4275
|
onTabKey(event, "diagnostics");
|
|
@@ -4211,12 +4319,51 @@ window.__ModuleLoader__.load({
|
|
|
4211
4319
|
".evo-workbench-title{margin:0;font-size:var(--evo-type-lg);font-weight:600;line-height:var(--evo-leading-base)}",
|
|
4212
4320
|
".evo-workbench-body{display:flex;flex:1;min-height:0;min-width:0;overflow:hidden}",
|
|
4213
4321
|
".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
4322
|
"@media (max-width:720px){.evo-workbench-head{flex-wrap:wrap}.evo-workbench-tabs{flex-wrap:wrap}}"
|
|
4218
4323
|
].join("");
|
|
4219
4324
|
//#endregion
|
|
4325
|
+
//#region src/panels/history/client/WorkbenchStore.ts
|
|
4326
|
+
function createWorkbenchStore(initial = {
|
|
4327
|
+
view: "history",
|
|
4328
|
+
focusRevision: 0
|
|
4329
|
+
}) {
|
|
4330
|
+
let state = initial;
|
|
4331
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4332
|
+
const emit = (next) => {
|
|
4333
|
+
state = next;
|
|
4334
|
+
for (const listener of listeners) listener();
|
|
4335
|
+
};
|
|
4336
|
+
return {
|
|
4337
|
+
getState: () => state,
|
|
4338
|
+
subscribe(listener) {
|
|
4339
|
+
listeners.add(listener);
|
|
4340
|
+
return () => {
|
|
4341
|
+
listeners.delete(listener);
|
|
4342
|
+
};
|
|
4343
|
+
},
|
|
4344
|
+
setView(view) {
|
|
4345
|
+
if (state.view !== view) emit({
|
|
4346
|
+
...state,
|
|
4347
|
+
view
|
|
4348
|
+
});
|
|
4349
|
+
},
|
|
4350
|
+
openHistory(skill) {
|
|
4351
|
+
emit({
|
|
4352
|
+
view: "history",
|
|
4353
|
+
...skill === void 0 ? {} : { selectedSkill: skill },
|
|
4354
|
+
focusRevision: state.focusRevision + 1
|
|
4355
|
+
});
|
|
4356
|
+
},
|
|
4357
|
+
clearSelection() {
|
|
4358
|
+
const { selectedSkill: _selected, ...rest } = state;
|
|
4359
|
+
emit({
|
|
4360
|
+
...rest,
|
|
4361
|
+
focusRevision: state.focusRevision + 1
|
|
4362
|
+
});
|
|
4363
|
+
}
|
|
4364
|
+
};
|
|
4365
|
+
}
|
|
4366
|
+
//#endregion
|
|
4220
4367
|
//#region src/panels/history/client/index.ts
|
|
4221
4368
|
/**
|
|
4222
4369
|
* Register the locale namespace, the workbench main occupant and its sidebar row.
|
|
@@ -4225,6 +4372,9 @@ window.__ModuleLoader__.load({
|
|
|
4225
4372
|
function apply$1(ctx) {
|
|
4226
4373
|
const api = createSkillHistoryApi();
|
|
4227
4374
|
const settingsSeat = createSettingsSeat(ctx);
|
|
4375
|
+
ctx.effect(() => () => {
|
|
4376
|
+
settingsSeat.dispose?.();
|
|
4377
|
+
}, "evolution-ui: settings seat");
|
|
4228
4378
|
let approvalConfirmMode = "ask";
|
|
4229
4379
|
const approvalForm = settingsSeat.get("evolution-approval");
|
|
4230
4380
|
const stopApprovalWatch = approvalForm?.subscribe(() => {
|
|
@@ -4273,6 +4423,7 @@ window.__ModuleLoader__.load({
|
|
|
4273
4423
|
api: createDiagnosticsApi((input, init) => fetch(input, init)),
|
|
4274
4424
|
fallback: FALLBACKS.diagnostics
|
|
4275
4425
|
});
|
|
4426
|
+
const workbenchStore = createWorkbenchStore();
|
|
4276
4427
|
registerSidebarPanel(ctx, {
|
|
4277
4428
|
id: WORKBENCH_ID,
|
|
4278
4429
|
order: 35,
|
|
@@ -4289,6 +4440,7 @@ window.__ModuleLoader__.load({
|
|
|
4289
4440
|
component: WorkbenchPage,
|
|
4290
4441
|
body: (t) => ({
|
|
4291
4442
|
t,
|
|
4443
|
+
store: workbenchStore,
|
|
4292
4444
|
history: historyFace(t),
|
|
4293
4445
|
pending: pendingFace(),
|
|
4294
4446
|
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
|
|
@@ -72,5 +72,5 @@ export declare function emptyState(text: string, key?: string): ReactNode;
|
|
|
72
72
|
/** One notice about what just happened. */
|
|
73
73
|
export declare function notice(text: string | undefined, error: boolean): ReactNode;
|
|
74
74
|
/** The pane's heading and its one control. */
|
|
75
|
-
export declare function panelHead(copy: Copy, onRefresh: () => void): ReactNode;
|
|
75
|
+
export declare function panelHead(copy: Copy, onRefresh: () => void, title?: string): ReactNode;
|
|
76
76
|
//# sourceMappingURL=chrome.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.35.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
|
|
@@ -23,12 +23,12 @@ export declare const zh: {
|
|
|
23
23
|
readonly projectionFailed: "这一块读设置时出错,已记入日志;其它参数不受影响";
|
|
24
24
|
readonly readonly: "本次会话不允许写入设置(临时运行模式)";
|
|
25
25
|
readonly apply: "保存";
|
|
26
|
-
readonly reset: "
|
|
26
|
+
readonly reset: "复位";
|
|
27
27
|
readonly empty: "这里没有可改项";
|
|
28
28
|
readonly changed: "{n} 项已覆盖";
|
|
29
29
|
readonly discard: "放弃修改";
|
|
30
30
|
readonly saving: "保存中…";
|
|
31
|
-
readonly resetting: "
|
|
31
|
+
readonly resetting: "复位中…";
|
|
32
32
|
readonly writeTargetHost: "保存去向:宿主配置(对所有会话生效)";
|
|
33
33
|
readonly invalidNumber: "需要一个数字";
|
|
34
34
|
readonly invalidSelect: "不在允许的取值里";
|
|
@@ -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.35.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.35.0",
|
|
49
|
+
"@lmzhen/dsh-evolution-core": "^0.35.0",
|
|
50
|
+
"@lmzhen/dsh-evolution-curator": "^0.35.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/react": "~18.3.1",
|