dsh-ds-balance 2.1.0 → 2.1.1
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/README.md +1 -1
- package/README_en.md +1 -1
- package/lib/client.js +74 -46
- package/lib/types/client/locales.d.ts +1 -0
- package/lib/types/client/sidebar/BalancePopover.d.ts +16 -3
- package/lib/types/client/sidebar/SidebarBalance.d.ts +6 -4
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
| 界面 | 一句话 | 你会用它来 |
|
|
41
41
|
|---|---|---|
|
|
42
42
|
| 侧栏圆环 | 常驻左边栏底部的状态环 + 名称,**展开态悬浮条目就报出余额金额**,**环里填了多少 = 余额离该币种预警线还有多远** | 扫一眼就知道还剩多少、离预警线多远 |
|
|
43
|
-
| 余额浮层 | 点条目展开:总额、赠送 /
|
|
43
|
+
| 余额浮层 | 点条目展开:总额、赠送 / 充值拆分、数据新鲜度、手动刷新(带冷却);**右上角图标跳到本插件的配置格**(宿主没有那条跨插件深链服务时退回 Plugins 列表,悬浮文字同步改口径) | 核对具体数字,以及数据是几分钟前的 |
|
|
44
44
|
| 设置卡片 | 连接 / 展示 / 阈值 / 刷新四组,**默认四组全收起**,点组头逐组展开 | 换端点、换币种、调预警线、调节奏 |
|
|
45
45
|
|
|
46
46
|
三种界面的分工是死的:**圆环回答「大概还剩多少」,浮层回答「具体是多少」,卡片回答「怎么算」。**
|
package/README_en.md
CHANGED
|
@@ -40,7 +40,7 @@ The balance needs somewhere to live that does not take up room. A permanent stat
|
|
|
40
40
|
| Surface | One line | Use it for |
|
|
41
41
|
|---|---|---|
|
|
42
42
|
| Sidebar ring | A status ring plus label at the bottom of the sidebar; **in the expanded state, hovering the entry reports the balance amount**, and **how full it is = how far the balance is from that currency's warning line** | Seeing at a glance how much is left and how close it is to the warning line |
|
|
43
|
-
| Balance popover | Click the entry: total, granted / topped-up split, data freshness, manual refresh (with cooldown); **an icon at its top right
|
|
43
|
+
| Balance popover | Click the entry: total, granted / topped-up split, data freshness, manual refresh (with cooldown); **an icon at its top right opens this plugin's configuration page** (on a host without that cross-plugin deep link it falls back to the Plugins list, and its tooltip says so) | Checking the exact figures, and how many minutes old they are |
|
|
44
44
|
| Settings card | Connection / Display / Thresholds / Refresh, **all collapsed by default**, expand a group from its header | Changing the endpoint, the currency, the warning lines, the cadence |
|
|
45
45
|
|
|
46
46
|
The division of labour is fixed: **the ring answers "roughly how much is left", the popover answers "exactly how much", and the card answers "how is that computed".**
|
package/lib/client.js
CHANGED
|
@@ -56,7 +56,10 @@ var zh = {
|
|
|
56
56
|
"popover.cooldown": "{value} \u79D2\u540E\u53EF\u518D\u6B21\u5237\u65B0",
|
|
57
57
|
"popover.mismatch": "\u672A\u627E\u5230 {wanted} \u4F59\u989D\uFF0C\u5F53\u524D\u663E\u793A {shown}",
|
|
58
58
|
"popover.action.useShown": "\u6539\u7528 {shown}",
|
|
59
|
+
// 右上角图标的两档措辞。落点由**宿主能力**决定(跨插件深链服务在不在),
|
|
60
|
+
// 措辞就跟着落点分档:一句含糊的话盖不住两种落点。见 BalancePopover 的 PluginsAction。
|
|
59
61
|
"popover.action.openPlugins": "\u6253\u5F00\u63D2\u4EF6\u9875",
|
|
62
|
+
"popover.action.openPluginConfig": "\u6253\u5F00\u63D2\u4EF6\u914D\u7F6E\u9875",
|
|
60
63
|
"state.unavailable": "\u8D26\u6237\u4E0D\u53EF\u7528",
|
|
61
64
|
"state.stale": "\u6570\u636E\u5DF2\u8FC7\u671F",
|
|
62
65
|
"state.error": "\u8BFB\u53D6\u5931\u8D25",
|
|
@@ -137,6 +140,7 @@ var en = {
|
|
|
137
140
|
"popover.mismatch": "No {wanted} balance found; showing {shown}",
|
|
138
141
|
"popover.action.useShown": "Use {shown}",
|
|
139
142
|
"popover.action.openPlugins": "Open the Plugins page",
|
|
143
|
+
"popover.action.openPluginConfig": "Open the plugin configuration page",
|
|
140
144
|
"state.unavailable": "Account unavailable",
|
|
141
145
|
"state.stale": "Data is stale",
|
|
142
146
|
"state.error": "Failed to load",
|
|
@@ -1544,7 +1548,7 @@ function BalancePopover(props) {
|
|
|
1544
1548
|
onRefresh,
|
|
1545
1549
|
onUseShown,
|
|
1546
1550
|
useShownDisabled,
|
|
1547
|
-
|
|
1551
|
+
pluginsAction
|
|
1548
1552
|
} = props;
|
|
1549
1553
|
const shown = selection.shown;
|
|
1550
1554
|
const totalText = shown === null ? BALANCE_PLACEHOLDER : formatMoney(shown.total, shown.currency);
|
|
@@ -1559,6 +1563,7 @@ function BalancePopover(props) {
|
|
|
1559
1563
|
if (refreshing) statusText = t("popover.refreshing");
|
|
1560
1564
|
else if (cooling) statusText = interpolate(t("popover.cooldown"), { value: String(cooldownSeconds) });
|
|
1561
1565
|
const refreshLabel = t("sidebar.aria.refresh");
|
|
1566
|
+
const pluginsLabel = t(pluginsAction?.reachesConfig === true ? "popover.action.openPluginConfig" : "popover.action.openPlugins");
|
|
1562
1567
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1563
1568
|
"section",
|
|
1564
1569
|
{
|
|
@@ -1582,13 +1587,13 @@ function BalancePopover(props) {
|
|
|
1582
1587
|
]
|
|
1583
1588
|
}
|
|
1584
1589
|
),
|
|
1585
|
-
|
|
1590
|
+
pluginsAction === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Tooltip, { label: pluginsLabel, side: "top", delayMs: 500, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1586
1591
|
"button",
|
|
1587
1592
|
{
|
|
1588
1593
|
type: "button",
|
|
1589
1594
|
className: BalancePopover_default.iconButton,
|
|
1590
|
-
"aria-label":
|
|
1591
|
-
onClick:
|
|
1595
|
+
"aria-label": pluginsLabel,
|
|
1596
|
+
onClick: pluginsAction.open,
|
|
1592
1597
|
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.IconPluginPinwheelOutlineRegular, { size: 16 })
|
|
1593
1598
|
}
|
|
1594
1599
|
) })
|
|
@@ -1728,18 +1733,18 @@ function useConfigSlotState(probe) {
|
|
|
1728
1733
|
return state;
|
|
1729
1734
|
}
|
|
1730
1735
|
function usePluginsNavigation(navigation) {
|
|
1731
|
-
const [
|
|
1736
|
+
const [action, setAction] = (0, import_react5.useState)(() => navigation?.getSnapshot());
|
|
1732
1737
|
(0, import_react5.useEffect)(() => {
|
|
1733
1738
|
if (navigation === void 0) {
|
|
1734
|
-
|
|
1739
|
+
setAction(void 0);
|
|
1735
1740
|
return;
|
|
1736
1741
|
}
|
|
1737
|
-
|
|
1742
|
+
setAction(navigation.getSnapshot());
|
|
1738
1743
|
return navigation.subscribe(() => {
|
|
1739
|
-
|
|
1744
|
+
setAction(navigation.getSnapshot());
|
|
1740
1745
|
});
|
|
1741
1746
|
}, [navigation]);
|
|
1742
|
-
return
|
|
1747
|
+
return action;
|
|
1743
1748
|
}
|
|
1744
1749
|
function stateLabelKey(response, selection) {
|
|
1745
1750
|
if (response.state === "error") return response.error?.code === "NO_KEY" ? "state.noKey" : "state.error";
|
|
@@ -1893,11 +1898,17 @@ function SidebarBalance({
|
|
|
1893
1898
|
if (current === null) return;
|
|
1894
1899
|
void onSelectCurrency(current.currency);
|
|
1895
1900
|
}, [selection, onSelectCurrency]);
|
|
1896
|
-
const
|
|
1897
|
-
const
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
+
const pluginsAction = usePluginsNavigation(pluginsNavigation);
|
|
1902
|
+
const popoverPluginsAction = (0, import_react5.useMemo)(
|
|
1903
|
+
() => pluginsAction === void 0 ? void 0 : {
|
|
1904
|
+
reachesConfig: pluginsAction.reachesConfig,
|
|
1905
|
+
open: () => {
|
|
1906
|
+
closeNow();
|
|
1907
|
+
pluginsAction.open();
|
|
1908
|
+
}
|
|
1909
|
+
},
|
|
1910
|
+
[closeNow, pluginsAction]
|
|
1911
|
+
);
|
|
1901
1912
|
const configSlotState = useConfigSlotState(configSlotProbe);
|
|
1902
1913
|
const shown = selection.shown;
|
|
1903
1914
|
const ring = ringSpecFor(response.severity);
|
|
@@ -1966,7 +1977,7 @@ function SidebarBalance({
|
|
|
1966
1977
|
onRefresh: handleRefresh,
|
|
1967
1978
|
onUseShown: handleUseShown,
|
|
1968
1979
|
useShownDisabled: !config.writable,
|
|
1969
|
-
|
|
1980
|
+
pluginsAction: popoverPluginsAction
|
|
1970
1981
|
}
|
|
1971
1982
|
),
|
|
1972
1983
|
document.body
|
|
@@ -2063,25 +2074,59 @@ function SettingsSeatComponent(props) {
|
|
|
2063
2074
|
}
|
|
2064
2075
|
var PLUGINS_PANEL_ID = "plugins";
|
|
2065
2076
|
function createPluginsNavigation() {
|
|
2066
|
-
let
|
|
2077
|
+
let selectPanel;
|
|
2078
|
+
let openBundle;
|
|
2079
|
+
let snapshot;
|
|
2067
2080
|
const listeners2 = /* @__PURE__ */ new Set();
|
|
2068
|
-
const
|
|
2069
|
-
if (
|
|
2070
|
-
|
|
2081
|
+
const open = () => {
|
|
2082
|
+
if (openBundle !== void 0) {
|
|
2083
|
+
try {
|
|
2084
|
+
openBundle(BUNDLE_CONFIG_KEY);
|
|
2085
|
+
return;
|
|
2086
|
+
} catch (error) {
|
|
2087
|
+
console.warn("[WARN] ds-balance: cannot open the bundle config page", error);
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
try {
|
|
2091
|
+
selectPanel?.();
|
|
2092
|
+
} catch (error) {
|
|
2093
|
+
console.warn("[WARN] ds-balance: cannot switch to the plugins panel", error);
|
|
2094
|
+
}
|
|
2095
|
+
};
|
|
2096
|
+
const publish = () => {
|
|
2097
|
+
const reachesConfig = openBundle !== void 0;
|
|
2098
|
+
const next = selectPanel === void 0 ? void 0 : { open, reachesConfig };
|
|
2099
|
+
const unchanged = next === void 0 ? snapshot === void 0 : snapshot !== void 0 && snapshot.reachesConfig === reachesConfig;
|
|
2100
|
+
if (unchanged) return;
|
|
2101
|
+
snapshot = next;
|
|
2071
2102
|
for (const listener of [...listeners2]) listener();
|
|
2072
2103
|
};
|
|
2073
2104
|
return {
|
|
2074
|
-
getSnapshot: () =>
|
|
2105
|
+
getSnapshot: () => snapshot,
|
|
2075
2106
|
subscribe: (listener) => {
|
|
2076
2107
|
listeners2.add(listener);
|
|
2077
2108
|
return () => {
|
|
2078
2109
|
listeners2.delete(listener);
|
|
2079
2110
|
};
|
|
2080
2111
|
},
|
|
2081
|
-
|
|
2082
|
-
|
|
2112
|
+
attachPanel: (callback) => {
|
|
2113
|
+
selectPanel = callback;
|
|
2114
|
+
publish();
|
|
2083
2115
|
return () => {
|
|
2084
|
-
if (
|
|
2116
|
+
if (selectPanel === callback) {
|
|
2117
|
+
selectPanel = void 0;
|
|
2118
|
+
publish();
|
|
2119
|
+
}
|
|
2120
|
+
};
|
|
2121
|
+
},
|
|
2122
|
+
attachDeepLink: (callback) => {
|
|
2123
|
+
openBundle = callback;
|
|
2124
|
+
publish();
|
|
2125
|
+
return () => {
|
|
2126
|
+
if (openBundle === callback) {
|
|
2127
|
+
openBundle = void 0;
|
|
2128
|
+
publish();
|
|
2129
|
+
}
|
|
2085
2130
|
};
|
|
2086
2131
|
}
|
|
2087
2132
|
};
|
|
@@ -2091,21 +2136,13 @@ function apply(ctx) {
|
|
|
2091
2136
|
const configSlotProbe = createConfigSlotProbe();
|
|
2092
2137
|
ctx.effect(() => () => configSlotProbe.dispose(), "ds-balance: config slot probe");
|
|
2093
2138
|
const pluginsNavigation = createPluginsNavigation();
|
|
2094
|
-
let openBundlePanel;
|
|
2095
2139
|
ctx.inject(["pluginNavigation"], (navCtx) => {
|
|
2096
2140
|
const face = navCtx["pluginNavigation"];
|
|
2097
2141
|
if (typeof face !== "object" || face === null) return;
|
|
2098
2142
|
const candidate = face["openBundle"];
|
|
2099
2143
|
if (typeof candidate !== "function") return;
|
|
2100
2144
|
const openBundle = candidate.bind(face);
|
|
2101
|
-
navCtx.effect(() =>
|
|
2102
|
-
openBundlePanel = (packageName) => {
|
|
2103
|
-
openBundle(packageName);
|
|
2104
|
-
};
|
|
2105
|
-
return () => {
|
|
2106
|
-
openBundlePanel = void 0;
|
|
2107
|
-
};
|
|
2108
|
-
}, "ds-balance: bundle config deep link");
|
|
2145
|
+
navCtx.effect(() => pluginsNavigation.attachDeepLink(openBundle), "ds-balance: bundle config deep link");
|
|
2109
2146
|
});
|
|
2110
2147
|
ctx.inject(["layout"], (layoutCtx) => {
|
|
2111
2148
|
if (!("layout" in layoutCtx)) return;
|
|
@@ -2113,21 +2150,12 @@ function apply(ctx) {
|
|
|
2113
2150
|
if (typeof face !== "object" || face === null) return;
|
|
2114
2151
|
if (!("selectPanel" in face) || typeof face.selectPanel !== "function") return;
|
|
2115
2152
|
const selectPanel = face.selectPanel.bind(face);
|
|
2116
|
-
layoutCtx.effect(
|
|
2117
|
-
|
|
2118
|
-
try {
|
|
2119
|
-
openBundlePanel(BUNDLE_CONFIG_KEY);
|
|
2120
|
-
return;
|
|
2121
|
-
} catch (error) {
|
|
2122
|
-
console.warn("[WARN] ds-balance: cannot open the bundle config page", error);
|
|
2123
|
-
}
|
|
2124
|
-
}
|
|
2125
|
-
try {
|
|
2153
|
+
layoutCtx.effect(
|
|
2154
|
+
() => pluginsNavigation.attachPanel(() => {
|
|
2126
2155
|
selectPanel(PLUGINS_PANEL_ID);
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
}), "ds-balance: plugins panel navigation");
|
|
2156
|
+
}),
|
|
2157
|
+
"ds-balance: plugins panel navigation"
|
|
2158
|
+
);
|
|
2131
2159
|
});
|
|
2132
2160
|
ctx.inject(["configForms"], (configCtx) => {
|
|
2133
2161
|
configSlotProbe.markDeclared();
|
|
@@ -22,6 +22,7 @@ export declare const zh: {
|
|
|
22
22
|
readonly 'popover.mismatch': "未找到 {wanted} 余额,当前显示 {shown}";
|
|
23
23
|
readonly 'popover.action.useShown': "改用 {shown}";
|
|
24
24
|
readonly 'popover.action.openPlugins': "打开插件页";
|
|
25
|
+
readonly 'popover.action.openPluginConfig': "打开插件配置页";
|
|
25
26
|
readonly 'state.unavailable': "账户不可用";
|
|
26
27
|
readonly 'state.stale': "数据已过期";
|
|
27
28
|
readonly 'state.error': "读取失败";
|
|
@@ -46,10 +46,23 @@ export interface BalancePopoverProps {
|
|
|
46
46
|
*/
|
|
47
47
|
useShownDisabled?: boolean;
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
49
|
+
* 右上角图标:点下去做什么、落到哪里。宿主没提供 layout 服务时给 undefined ——
|
|
50
|
+
* 这时那个按钮**不渲染**:不留按不动的死按钮。
|
|
51
51
|
*/
|
|
52
|
-
|
|
52
|
+
pluginsAction?: PluginsAction;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 浮层右上角图标点下去会发生什么。
|
|
56
|
+
*
|
|
57
|
+
* 落点由**宿主能力**决定:宿主提供跨插件深链服务时直达本插件的配置格,
|
|
58
|
+
* 服务缺席时只能到 Plugins 列表。所以措辞跟着落点分档 ——
|
|
59
|
+
* 「打开插件配置页」与「打开插件页」各说自己那一件事,不许用一句含糊的话盖住两种落点。
|
|
60
|
+
*/
|
|
61
|
+
export interface PluginsAction {
|
|
62
|
+
/** 执行跳转;「先关浮层」由父组件包在里面。 */
|
|
63
|
+
open: () => void;
|
|
64
|
+
/** 落点是不是本插件的配置格。 */
|
|
65
|
+
reachesConfig: boolean;
|
|
53
66
|
}
|
|
54
67
|
/**
|
|
55
68
|
* 渲染余额浮层。
|
|
@@ -13,14 +13,16 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { type LocaleKey } from '../locales.ts';
|
|
15
15
|
import { type ConfigSlotProbe } from '../config-slot.ts';
|
|
16
|
+
import { type PluginsAction } from './BalancePopover.tsx';
|
|
16
17
|
/**
|
|
17
|
-
*
|
|
18
|
+
* 「打开本插件配置」这个**可选**入口。宿主没提供 layout 服务时整条链不存在,
|
|
18
19
|
* 浮层右上角的图标因此不渲染 —— 不留按不动的死按钮。
|
|
19
20
|
* 形态与 `configSlotProbe` 一样是个可订阅的小对象:服务可能晚到,图标要能自己出现、也能自己消失。
|
|
21
|
+
* 快照里带**落点**(见 BalancePopover 的 PluginsAction):深链服务在不在,措辞跟着分档。
|
|
20
22
|
*/
|
|
21
23
|
export interface PluginsNavigation {
|
|
22
|
-
/**
|
|
23
|
-
getSnapshot: () =>
|
|
24
|
+
/** 当前可用的动作与落点;宿主没有 layout 服务时是 undefined。 */
|
|
25
|
+
getSnapshot: () => PluginsAction | undefined;
|
|
24
26
|
/**
|
|
25
27
|
* 订阅它的出现与消失。
|
|
26
28
|
* @param listener - 变化回调。
|
|
@@ -41,7 +43,7 @@ export interface SidebarBalanceProps {
|
|
|
41
43
|
*/
|
|
42
44
|
configSlotProbe: ConfigSlotProbe;
|
|
43
45
|
/**
|
|
44
|
-
*
|
|
46
|
+
* 「打开本插件配置」的可选入口:有它才渲染浮层右上角那个图标按钮。
|
|
45
47
|
* 宿主缺 layout 服务时整条链不存在,图标就不出现。
|
|
46
48
|
*/
|
|
47
49
|
pluginsNavigation?: PluginsNavigation;
|
package/lib/version.d.ts
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
/** 线上 schema 版本。响应里逐条回传,消费方据此判断兼容性。 */
|
|
9
9
|
export declare const SCHEMA_VERSION = 1;
|
|
10
10
|
/** 插件版本。与 `package.json` 的 `version` 一致(有测试兜底)。 */
|
|
11
|
-
export declare const PLUGIN_VERSION = "2.1.
|
|
11
|
+
export declare const PLUGIN_VERSION = "2.1.1";
|
|
12
12
|
//# sourceMappingURL=version.d.ts.map
|
package/lib/version.js
CHANGED
package/package.json
CHANGED