dsh-ios-webview-app-control 0.2.1 → 0.2.2
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/CHANGELOG.md +5 -0
- package/lib/client.js +14 -2
- package/lib/runtime/environment-manager.mjs +9 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# 更新记录
|
|
2
2
|
|
|
3
|
+
## 0.2.2 — 2026-11-03
|
|
4
|
+
|
|
5
|
+
- 修复设置页环境面板在准备结束后仍挂着“步骤/字节数/进度条”的问题:只有准备进行中(busy)才输出并渲染过程信息,就绪、失败、取消后的公开状态不再保留 step/progress。
|
|
6
|
+
- 修复从插件列表启用后准备面板一直停留、要切换页面才消失的问题:环境达到 ready 时激活引导自动收起;失败、取消、未准备状态仍保留面板供操作。
|
|
7
|
+
|
|
3
8
|
## 0.2.1 — 2026-10-31
|
|
4
9
|
|
|
5
10
|
- README 按 npm 包页面的阅读顺序重组,补上 npm 安装方式和可直接跑的 CLI 示例,并把验证快照与安装要求的表述分开。
|
package/lib/client.js
CHANGED
|
@@ -108,6 +108,7 @@ window.__ModuleLoader__.load({
|
|
|
108
108
|
const [revision, setRevision] = React.useState(0);
|
|
109
109
|
const live = React.useRef(null);
|
|
110
110
|
const confirmedButton = React.useRef(null);
|
|
111
|
+
const dismissed = React.useRef(false);
|
|
111
112
|
const panelId = React.useId();
|
|
112
113
|
React.useEffect(() => {
|
|
113
114
|
const control = new AbortController();
|
|
@@ -135,6 +136,14 @@ window.__ModuleLoader__.load({
|
|
|
135
136
|
};
|
|
136
137
|
}, [revision]);
|
|
137
138
|
React.useEffect(() => { if (confirmCleanup) confirmedButton.current?.focus(); }, [confirmCleanup]);
|
|
139
|
+
// Activation guidance exists to get the environment ready, so it closes
|
|
140
|
+
// itself once preparation settles in a state that needs no action.
|
|
141
|
+
const settledReady = snapshot !== null && snapshot.phase === 'ready' && snapshot.busy !== true;
|
|
142
|
+
React.useEffect(() => {
|
|
143
|
+
if (!props.activation || !settledReady || dismissed.current) return;
|
|
144
|
+
dismissed.current = true;
|
|
145
|
+
if (typeof props.onDismiss === 'function') props.onDismiss();
|
|
146
|
+
}, [props.activation, settledReady, props.onDismiss]);
|
|
138
147
|
async function run(action) {
|
|
139
148
|
const control = live.current;
|
|
140
149
|
if (!control || control.signal.aborted || (working && !(action === 'cancel' && working === 'prepare'))) return;
|
|
@@ -158,7 +167,10 @@ window.__ModuleLoader__.load({
|
|
|
158
167
|
return h('div', { className: 'iosenv-row', key: label }, h('dt', null, label), h('dd', { className: mono ? 'iosenv-mono' : undefined }, value || t('missing')));
|
|
159
168
|
}
|
|
160
169
|
const busy = snapshot?.busy === true;
|
|
161
|
-
|
|
170
|
+
// Step and byte counts describe an in-flight preparation only; once it
|
|
171
|
+
// settles they must not read like a stalled download.
|
|
172
|
+
const progress = busy ? snapshot?.progress : null;
|
|
173
|
+
const step = busy ? snapshot?.step : null;
|
|
162
174
|
const total = progress?.totalBytes;
|
|
163
175
|
const progressText = progress ? t(total === undefined ? 'bytesUnknown' : 'bytes', { completed: progress.completedBytes, total }) : null;
|
|
164
176
|
const phase = snapshot?.phase;
|
|
@@ -175,7 +187,7 @@ window.__ModuleLoader__.load({
|
|
|
175
187
|
h('p', { className: 'iosenv-muted' }, t('intro')),
|
|
176
188
|
h('div', { className: 'iosenv-state', role: 'status', 'aria-live': 'polite' },
|
|
177
189
|
h('div', { className: 'iosenv-statehead' }, h('span', null, t('phase')), h('strong', { className: 'iosenv-phase' }, snapshot ? t(`phase.${phase}`) : t('loading'))),
|
|
178
|
-
|
|
190
|
+
step ? h('p', { className: 'iosenv-muted' }, `${t('step')}: ${step}`) : null,
|
|
179
191
|
progressText ? h('p', null, progressText) : null,
|
|
180
192
|
progress ? h('progress', { className: 'iosenv-progress', 'aria-label': t('progress'), ...(total > 0 ? { max: total, value: Math.min(progress.completedBytes, total) } : {}) }) : null,
|
|
181
193
|
phase === 'ready' ? h('p', { className: 'iosenv-muted' }, t('readyHint')) : null),
|
|
@@ -141,7 +141,15 @@ export class EnvironmentManager {
|
|
|
141
141
|
}
|
|
142
142
|
status() {
|
|
143
143
|
const state=clone(this.snapshot);
|
|
144
|
-
|
|
144
|
+
// Step and byte counters describe an in-flight preparation only. Once it
|
|
145
|
+
// settles they read like a stalled download, so a public status drops them.
|
|
146
|
+
if(BUSY_PHASES.has(state.phase)){
|
|
147
|
+
state.step=state.step||state.stage||state.phase;
|
|
148
|
+
state.progress=state.bytes.total>0?{completedBytes:state.bytes.downloaded,totalBytes:state.bytes.total}:null;
|
|
149
|
+
}else{
|
|
150
|
+
state.step='';
|
|
151
|
+
state.progress=null;
|
|
152
|
+
}
|
|
145
153
|
if(!state.python?.path||!state.python?.version||!['host','private'].includes(state.python?.source))state.python=null;
|
|
146
154
|
if(typeof state.pymobiledevice3!=='string')delete state.pymobiledevice3;
|
|
147
155
|
return state;
|