Skip to content

Commit fe9321f

Browse files
committed
Update uninstalling overlay
Signed-off-by: paulober <[email protected]>
1 parent a539eff commit fe9321f

File tree

2 files changed

+96
-10
lines changed

2 files changed

+96
-10
lines changed

src/utils/uninstallUtil.mts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { homedir } from "os";
99
import LastUsedDepsStore from "./lastUsedDeps.mjs";
1010
import { unknownErrorToString } from "./errorHelper.mjs";
1111
import Logger, { LoggerSource } from "../logger.mjs";
12+
import { getZephyrSDKVersion } from "./setupZephyr.mjs";
1213

1314
const SDK_ROOT = Uri.joinPath(Uri.file(homedir()), ".pico-sdk");
1415

@@ -70,6 +71,41 @@ export async function uninstallOne(
7071
return;
7172
}
7273

74+
if (depId === "zephyr") {
75+
const sdkVersion = await getZephyrSDKVersion(
76+
version?.startsWith("zephyr-") ? version.slice(7) : version
77+
);
78+
if (sdkVersion === undefined) {
79+
Logger.warn(
80+
LoggerSource.uninstallUtil,
81+
`Cannot uninstall zephyr ${version}: matching ` +
82+
"zephyr SDK version not found"
83+
);
84+
void window.showWarningMessage(
85+
`Cannot uninstall zephyr ${version}: matching ` +
86+
"zephyr SDK version not found"
87+
);
88+
89+
return;
90+
}
91+
92+
const sdkPath = Uri.joinPath(target, "..", "zephyr-sdk-" + sdkVersion);
93+
try {
94+
await workspace.fs.stat(sdkPath);
95+
await workspace.fs.delete(sdkPath, {
96+
recursive: true,
97+
useTrash: false,
98+
});
99+
} catch {
100+
// ignore errors; maybe it doesn't exist
101+
Logger.debug(
102+
LoggerSource.uninstallUtil,
103+
`Zephyr SDK ${sdkVersion} not found at ${sdkPath.fsPath}, ` +
104+
"not deleting or reporting error"
105+
);
106+
}
107+
}
108+
73109
// delete folder (prefer hard delete; fall back to trash if needed)
74110
try {
75111
await workspace.fs.delete(target, {

web/uninstaller/main.js

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
/* global acquireVsCodeApi */
22
"use strict";
33

4+
const OVERLAY_MIN_MS = 3000; // keep overlay visible at least this long
5+
let overlayShownAt = 0;
6+
let overlayTimerId = null
7+
48
const vscode = acquireVsCodeApi();
59

610
/** @typedef {{ id:string, depId:string, label:string, version:string, installedAt: string, lastUsed:string, path?:string }} Item */
@@ -12,6 +16,8 @@ let state = {
1216
filter: "",
1317
selected: new Set(), // of item.id
1418
uninstalling: false,
19+
overlayVisible: false,
20+
pendingRender: false,
1521
};
1622

1723
const $ = (sel, root = document) => /** @type {HTMLElement|null} */(root.querySelector(sel));
@@ -225,11 +231,15 @@ function renderList() {
225231
`;
226232
}
227233

228-
function renderOverlay() {
234+
function renderOverlay(visible = false) {
229235
return `
230-
<div id="overlay" class="fixed inset-0 hidden items-center justify-center z-50 bg-black/60 backdrop-blur-sm">
231-
<div class="flex flex-col items-center gap-4 p-8 rounded-2xl bg-white/90 dark:bg-zinc-900/90 border border-gray-200 dark:border-zinc-800">
232-
<div class="h-10 w-10 rounded-full border-4 border-gray-300 dark:border-zinc-700 border-t-transparent animate-spin"></div>
236+
<div id="overlay"
237+
class="fixed inset-0 ${visible ? '' : 'hidden'} z-50 grid place-items-center bg-black/60 backdrop-blur-sm">
238+
<div class="pointer-events-auto flex flex-col items-center gap-4 p-8 rounded-2xl
239+
bg-white/90 dark:bg-zinc-900/90 border border-gray-200 dark:border-zinc-800 shadow-lg"
240+
role="status" aria-live="polite">
241+
<div class="h-10 w-10 rounded-full border-4 border-gray-300 dark:border-zinc-700 border-t-transparent animate-spin"
242+
aria-hidden="true"></div>
233243
<div id="overlay-text" class="text-sm text-gray-700 dark:text-gray-200">Uninstalling…</div>
234244
</div>
235245
</div>`;
@@ -252,7 +262,7 @@ function renderFrame() {
252262
</div>
253263
</main>
254264
</div>
255-
${renderOverlay()}
265+
${renderOverlay(state.overlayVisible)}
256266
`;
257267
bindEvents();
258268
updateSelectAllCheckbox();
@@ -400,19 +410,51 @@ function beginUninstall(ids) {
400410
}
401411

402412
function showOverlay(text) {
413+
// reset any previous timer
414+
if (overlayTimerId) {
415+
clearTimeout(overlayTimerId);
416+
overlayTimerId = null;
417+
}
418+
419+
overlayShownAt = Date.now();
420+
state.overlayVisible = true;
403421
const ov = $("#overlay");
404422
if (!ov) return;
405-
$("#overlay-text").textContent = text || "Working…";
423+
const ovT = $("#overlay-text");
424+
if (!ovT) return;
425+
ovT.textContent = text || "Working…";
426+
406427
ov.classList.remove("hidden");
407428
// prevent interaction underneath
408429
document.body.style.pointerEvents = "none";
409430
ov.style.pointerEvents = "auto";
410431
}
411432

433+
function scheduleHideOverlay() {
434+
const now = Date.now();
435+
const remain = Math.max(OVERLAY_MIN_MS - (now - overlayShownAt), 0);
436+
console.debug(`scheduling overlay hide in ${remain}ms`);
437+
if (overlayTimerId) clearTimeout(overlayTimerId);
438+
439+
const finish = () => {
440+
hideOverlay();
441+
overlayTimerId = null;
442+
if (state.pendingRender) {
443+
state.pendingRender = false;
444+
update();
445+
}
446+
};
447+
448+
overlayTimerId = remain <= 0
449+
? setTimeout(() => requestAnimationFrame(finish), 0) // next frame
450+
: setTimeout(finish, remain);
451+
}
452+
412453
function hideOverlay() {
413454
const ov = $("#overlay");
414455
if (!ov) return;
415456
ov.classList.add("hidden");
457+
state.overlayVisible = false;
416458
document.body.style.pointerEvents = "";
417459
}
418460

@@ -453,13 +495,17 @@ window.addEventListener("message", (event) => {
453495
state.items = state.items.filter(i => !removedIds.has(i.id));
454496
for (const id of removedIds) state.selected.delete(id);
455497
state.uninstalling = false;
456-
hideOverlay();
457-
update();
498+
499+
//hideOverlay();
500+
// don't flicker: wait until min visible time has passed
501+
state.pendingRender = true;
502+
scheduleHideOverlay();
458503
break;
459504
}
460505
case "uninstall:error": {
461506
state.uninstalling = false;
462-
hideOverlay();
507+
//hideOverlay();
508+
scheduleHideOverlay();
463509
alert(msg.error || "Uninstall failed."); // simple; VS Code shows alerts fine
464510
break;
465511
}
@@ -469,7 +515,11 @@ window.addEventListener("message", (event) => {
469515
state.items = msg.items;
470516
// prune selection
471517
state.selected = new Set([...state.selected].filter(id => state.items.some(i => i.id === id)));
472-
update();
518+
if (state.overlayVisible) {
519+
state.pendingRender = true; // defer while overlay is up
520+
} else {
521+
update();
522+
}
473523
}
474524
break;
475525
}

0 commit comments

Comments
 (0)