pinokiod 8.0.62 → 8.0.64
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/package.json
CHANGED
package/server/public/layout.js
CHANGED
|
@@ -853,6 +853,7 @@
|
|
|
853
853
|
<circle cx="10" cy="10" r="7.5"></circle>
|
|
854
854
|
<path d="m6.75 10.1 2.1 2.1 4.6-4.65"></path>
|
|
855
855
|
</svg>`;
|
|
856
|
+
const MIN_CHECKING_VISIBLE_MS = 500;
|
|
856
857
|
const COMPLETION_VISIBLE_MS = 4000;
|
|
857
858
|
|
|
858
859
|
let eventSource = null;
|
|
@@ -923,7 +924,9 @@
|
|
|
923
924
|
}
|
|
924
925
|
|
|
925
926
|
function scheduleCompletion(completion) {
|
|
926
|
-
if (completion.paused.size || completion.timer)
|
|
927
|
+
if (!completion.revealed || completion.paused.size || completion.timer) {
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
927
930
|
completion.startedAt = Date.now();
|
|
928
931
|
completion.timer = window.setTimeout(() => {
|
|
929
932
|
completion.timer = null;
|
|
@@ -932,7 +935,7 @@
|
|
|
932
935
|
}
|
|
933
936
|
|
|
934
937
|
function setCompletionPaused(completion, reason, paused) {
|
|
935
|
-
if (!completion) return;
|
|
938
|
+
if (!completion || !completion.revealed) return;
|
|
936
939
|
if (paused) {
|
|
937
940
|
if (completion.paused.has(reason)) return;
|
|
938
941
|
if (!completion.paused.size && completion.timer) {
|
|
@@ -1026,13 +1029,14 @@
|
|
|
1026
1029
|
controls,
|
|
1027
1030
|
currentState: null,
|
|
1028
1031
|
currentNoticeId: null,
|
|
1032
|
+
checkingShownAt: 0,
|
|
1029
1033
|
dismissPending: false,
|
|
1030
1034
|
pointerInside: false,
|
|
1031
1035
|
focusInside: false,
|
|
1032
1036
|
completion: null
|
|
1033
1037
|
};
|
|
1034
1038
|
close.addEventListener('click', async () => {
|
|
1035
|
-
if (card.
|
|
1039
|
+
if (card.completion) {
|
|
1036
1040
|
removeCard(app);
|
|
1037
1041
|
return;
|
|
1038
1042
|
}
|
|
@@ -1177,32 +1181,50 @@
|
|
|
1177
1181
|
appendMessage(card, displayState);
|
|
1178
1182
|
card.currentState = row.state;
|
|
1179
1183
|
card.currentNoticeId = row.notice_id || null;
|
|
1184
|
+
card.checkingShownAt = row.state === 'checking' ? Date.now() : 0;
|
|
1180
1185
|
card.dismissPending = false;
|
|
1181
1186
|
card.item.dataset.state = row.state;
|
|
1182
1187
|
renderControls(card, row);
|
|
1183
1188
|
return card;
|
|
1184
1189
|
}
|
|
1185
1190
|
|
|
1186
|
-
function
|
|
1187
|
-
const card = cards.get(app);
|
|
1188
|
-
if (!card || card.
|
|
1189
|
-
card.
|
|
1191
|
+
function revealCompletion(completion) {
|
|
1192
|
+
const card = cards.get(completion.app);
|
|
1193
|
+
if (!card || card.completion !== completion ||
|
|
1194
|
+
card.currentState !== 'checking' || card.dismissPending) return;
|
|
1195
|
+
completion.timer = null;
|
|
1196
|
+
completion.revealed = true;
|
|
1190
1197
|
appendMessage(card, 'complete');
|
|
1191
1198
|
card.currentState = 'complete';
|
|
1192
1199
|
card.currentNoticeId = null;
|
|
1193
1200
|
card.item.dataset.state = 'complete';
|
|
1194
1201
|
renderControls(card, { state: 'complete' });
|
|
1202
|
+
if (card.pointerInside) completion.paused.add('pointer');
|
|
1203
|
+
if (card.focusInside) completion.paused.add('focus');
|
|
1204
|
+
scheduleCompletion(completion);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
function startCompletion(app) {
|
|
1208
|
+
const card = cards.get(app);
|
|
1209
|
+
if (!card || card.currentState !== 'checking' ||
|
|
1210
|
+
card.dismissPending || card.completion) return false;
|
|
1195
1211
|
const completion = {
|
|
1196
1212
|
app,
|
|
1213
|
+
revealed: false,
|
|
1197
1214
|
timer: null,
|
|
1198
1215
|
remaining: COMPLETION_VISIBLE_MS,
|
|
1199
1216
|
startedAt: 0,
|
|
1200
1217
|
paused: new Set()
|
|
1201
1218
|
};
|
|
1202
|
-
if (card.pointerInside) completion.paused.add('pointer');
|
|
1203
|
-
if (card.focusInside) completion.paused.add('focus');
|
|
1204
1219
|
card.completion = completion;
|
|
1205
|
-
|
|
1220
|
+
const elapsed = Math.max(0, Date.now() - card.checkingShownAt);
|
|
1221
|
+
const delay = Math.max(0, MIN_CHECKING_VISIBLE_MS - elapsed);
|
|
1222
|
+
if (delay) {
|
|
1223
|
+
completion.timer = window.setTimeout(
|
|
1224
|
+
() => revealCompletion(completion), delay);
|
|
1225
|
+
} else {
|
|
1226
|
+
revealCompletion(completion);
|
|
1227
|
+
}
|
|
1206
1228
|
return true;
|
|
1207
1229
|
}
|
|
1208
1230
|
|
package/server/public/vault.js
CHANGED
|
@@ -2232,6 +2232,8 @@ const renderNormalOverview = () => {
|
|
|
2232
2232
|
const activeScan = scanActive(data.scan)
|
|
2233
2233
|
const scanning = scanMatchesContext(data.scan)
|
|
2234
2234
|
const busyElsewhere = activeScan && !scanning
|
|
2235
|
+
const actionableDuplicates = Math.max(0, Number(
|
|
2236
|
+
data.inventory && data.inventory.shareable_duplicates) || 0)
|
|
2235
2237
|
const metrics = el("vault-metrics")
|
|
2236
2238
|
const existingModeMenu = el("vault-auto-mode")
|
|
2237
2239
|
const modeMenuOpen = !!(existingModeMenu && existingModeMenu.open) ||
|
|
@@ -2313,7 +2315,8 @@ const renderNormalOverview = () => {
|
|
|
2313
2315
|
? `<i class="fa-solid fa-circle-notch fa-spin"></i>${esc(COPY.scanning)}`
|
|
2314
2316
|
: `<i class="fa-solid fa-rotate"></i>${esc(idleScanLabel)}`
|
|
2315
2317
|
const firstScan = !last && !activeScan
|
|
2316
|
-
|
|
2318
|
+
const scanIsPrimary = firstScan || (!activeScan && !actionableDuplicates)
|
|
2319
|
+
scanButton.classList.toggle("primary", scanIsPrimary)
|
|
2317
2320
|
scanButton.disabled = busyElsewhere || state.scanCancelRequested
|
|
2318
2321
|
if (state.automaticReviewRequested && !activeScan &&
|
|
2319
2322
|
!scanButton.disabled) {
|
package/server/views/layout.ejs
CHANGED
|
@@ -224,6 +224,11 @@
|
|
|
224
224
|
opacity: 0.58;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
.vault-auto-scan-message[data-current="true"] {
|
|
228
|
+
animation: vault-notice-message-enter 160ms
|
|
229
|
+
cubic-bezier(0.25, 1, 0.5, 1);
|
|
230
|
+
}
|
|
231
|
+
|
|
227
232
|
.vault-auto-scan-icon {
|
|
228
233
|
display: grid;
|
|
229
234
|
place-items: center;
|
|
@@ -374,6 +379,11 @@
|
|
|
374
379
|
to { transform: rotate(360deg); }
|
|
375
380
|
}
|
|
376
381
|
|
|
382
|
+
@keyframes vault-notice-message-enter {
|
|
383
|
+
from { opacity: 0; transform: translateY(2px); }
|
|
384
|
+
to { opacity: 1; transform: translateY(0); }
|
|
385
|
+
}
|
|
386
|
+
|
|
377
387
|
@media (pointer: coarse) {
|
|
378
388
|
.vault-auto-scan-controls { min-height: 44px; }
|
|
379
389
|
.vault-auto-scan-action {
|
|
@@ -386,6 +396,9 @@
|
|
|
386
396
|
.vault-auto-scan-row {
|
|
387
397
|
animation: none;
|
|
388
398
|
}
|
|
399
|
+
.vault-auto-scan-message[data-current="true"] {
|
|
400
|
+
animation: none;
|
|
401
|
+
}
|
|
389
402
|
.vault-auto-scan-message[data-current="true"][data-state="checking"]
|
|
390
403
|
.vault-auto-scan-icon {
|
|
391
404
|
animation-duration: 1800ms;
|
|
@@ -370,10 +370,21 @@ test("an empty automatic check briefly confirms completion", async () => {
|
|
|
370
370
|
})
|
|
371
371
|
const eventSources = []
|
|
372
372
|
const requests = []
|
|
373
|
+
const revealTimers = []
|
|
373
374
|
const completionTimers = []
|
|
374
375
|
const nativeSetTimeout = dom.window.setTimeout.bind(dom.window)
|
|
375
376
|
const nativeClearTimeout = dom.window.clearTimeout.bind(dom.window)
|
|
376
377
|
dom.window.setTimeout = (callback, delay, ...args) => {
|
|
378
|
+
if (delay <= 500 && delay > 400) {
|
|
379
|
+
const timer = {
|
|
380
|
+
callback,
|
|
381
|
+
delay,
|
|
382
|
+
cleared: false,
|
|
383
|
+
id: 9000 + revealTimers.length
|
|
384
|
+
}
|
|
385
|
+
revealTimers.push(timer)
|
|
386
|
+
return timer.id
|
|
387
|
+
}
|
|
377
388
|
if (delay <= 4000 && delay > 3500) {
|
|
378
389
|
const timer = {
|
|
379
390
|
callback,
|
|
@@ -387,7 +398,8 @@ test("an empty automatic check briefly confirms completion", async () => {
|
|
|
387
398
|
return nativeSetTimeout(callback, delay, ...args)
|
|
388
399
|
}
|
|
389
400
|
dom.window.clearTimeout = (id) => {
|
|
390
|
-
const timer = completionTimers
|
|
401
|
+
const timer = [...revealTimers, ...completionTimers]
|
|
402
|
+
.find((candidate) => candidate.id === id)
|
|
391
403
|
if (timer) {
|
|
392
404
|
timer.cleared = true
|
|
393
405
|
return
|
|
@@ -480,6 +492,20 @@ test("an empty automatic check briefly confirms completion", async () => {
|
|
|
480
492
|
}
|
|
481
493
|
})
|
|
482
494
|
|
|
495
|
+
const checking = [...tray.querySelectorAll(".vault-auto-scan-row")]
|
|
496
|
+
.find((card) => card.querySelector(
|
|
497
|
+
".vault-auto-scan-app").textContent === "ComfyUI")
|
|
498
|
+
assert.ok(checking)
|
|
499
|
+
assert.equal(checking.dataset.state, "checking")
|
|
500
|
+
assert.equal(checking.querySelectorAll(
|
|
501
|
+
".vault-auto-scan-message").length, 1)
|
|
502
|
+
assert.equal(tray.querySelector(
|
|
503
|
+
'.vault-auto-scan-row[data-state="complete"]'), null,
|
|
504
|
+
"the checking phase remains visible before an immediate result")
|
|
505
|
+
assert.equal(revealTimers.length, 1)
|
|
506
|
+
assert.ok(revealTimers[0].delay <= 500)
|
|
507
|
+
|
|
508
|
+
revealTimers[0].callback()
|
|
483
509
|
const completed = tray.querySelector(
|
|
484
510
|
'.vault-auto-scan-row[data-state="complete"]')
|
|
485
511
|
assert.ok(completed)
|
|
@@ -541,6 +567,7 @@ test("an empty automatic check briefly confirms completion", async () => {
|
|
|
541
567
|
})
|
|
542
568
|
const focusedClose = tray.querySelector(".vault-auto-scan-close")
|
|
543
569
|
focusedClose.focus()
|
|
570
|
+
const revealsBeforeFocusedCompletion = revealTimers.length
|
|
544
571
|
const timersBeforeFocusedCompletion = completionTimers.length
|
|
545
572
|
send({
|
|
546
573
|
enabled: true,
|
|
@@ -552,6 +579,10 @@ test("an empty automatic check briefly confirms completion", async () => {
|
|
|
552
579
|
}
|
|
553
580
|
})
|
|
554
581
|
assert.equal(tray.hidden, false)
|
|
582
|
+
assert.equal(revealTimers.length, revealsBeforeFocusedCompletion + 1)
|
|
583
|
+
assert.equal(completionTimers.length, timersBeforeFocusedCompletion,
|
|
584
|
+
"completion dismissal cannot start before its result is revealed")
|
|
585
|
+
revealTimers.at(-1).callback()
|
|
555
586
|
assert.equal(completionTimers.length, timersBeforeFocusedCompletion,
|
|
556
587
|
"completion does not start its timer while focus is already in the card")
|
|
557
588
|
focusedClose.dispatchEvent(new dom.window.FocusEvent("focusout", {
|
package/test/vault-ui.test.js
CHANGED
|
@@ -654,7 +654,7 @@ describe("Save Space interface", () => {
|
|
|
654
654
|
assert.match(document.getElementById("btn-scan").textContent,
|
|
655
655
|
/Scan again/)
|
|
656
656
|
assert.equal(document.getElementById("btn-scan").classList
|
|
657
|
-
.contains("primary"),
|
|
657
|
+
.contains("primary"), true)
|
|
658
658
|
assert.equal(document.querySelector("#vault-scan-size-menu > summary")
|
|
659
659
|
.classList.contains("primary"), false)
|
|
660
660
|
assert.match(document.getElementById("vault-scan-size-label").textContent,
|
|
@@ -751,6 +751,10 @@ describe("Save Space interface", () => {
|
|
|
751
751
|
/Cannot deduplicate\s*1/)
|
|
752
752
|
assert.match(document.querySelector("#vault-status-filter").textContent,
|
|
753
753
|
/Cannot deduplicate/)
|
|
754
|
+
assert.equal(document.getElementById("btn-review-metric").classList
|
|
755
|
+
.contains("primary"), true)
|
|
756
|
+
assert.equal(document.getElementById("btn-scan").classList
|
|
757
|
+
.contains("primary"), false)
|
|
754
758
|
|
|
755
759
|
document.querySelector('[data-view="duplicates"]').click()
|
|
756
760
|
await waitFor(() => document.querySelector(
|
|
@@ -759,7 +763,10 @@ describe("Save Space interface", () => {
|
|
|
759
763
|
/duplicate\.bin/)
|
|
760
764
|
assert.doesNotMatch(document.querySelector(".vault-table").textContent,
|
|
761
765
|
/blocked\.bin/)
|
|
762
|
-
assert.
|
|
766
|
+
assert.equal(document.querySelector("[data-deduplicate-all]")
|
|
767
|
+
.classList.contains("primary"), true)
|
|
768
|
+
assert.equal(document.getElementById("btn-scan").classList
|
|
769
|
+
.contains("primary"), false)
|
|
763
770
|
|
|
764
771
|
document.querySelector('[data-view="unavailable"]').click()
|
|
765
772
|
await waitFor(() => document.querySelector(
|
|
@@ -2221,6 +2228,37 @@ describe("Save Space interface", () => {
|
|
|
2221
2228
|
dom.window.close()
|
|
2222
2229
|
})
|
|
2223
2230
|
|
|
2231
|
+
test("a completed app workspace keeps Scan again primary", async () => {
|
|
2232
|
+
const { dom } = await makePage(fixture([]), {
|
|
2233
|
+
appMode: true,
|
|
2234
|
+
scopeId: "app:app"
|
|
2235
|
+
})
|
|
2236
|
+
const document = dom.window.document
|
|
2237
|
+
|
|
2238
|
+
assert.match(document.getElementById("btn-scan").textContent,
|
|
2239
|
+
/Scan again/)
|
|
2240
|
+
assert.equal(document.getElementById("btn-scan").classList
|
|
2241
|
+
.contains("primary"), true)
|
|
2242
|
+
|
|
2243
|
+
dom.window.close()
|
|
2244
|
+
})
|
|
2245
|
+
|
|
2246
|
+
test("an app with duplicates keeps Scan again secondary", async () => {
|
|
2247
|
+
const duplicate = item({ status: "duplicate", shareable: true })
|
|
2248
|
+
const { dom } = await makePage(fixture([duplicate]), {
|
|
2249
|
+
appMode: true,
|
|
2250
|
+
scopeId: "app:app"
|
|
2251
|
+
})
|
|
2252
|
+
const document = dom.window.document
|
|
2253
|
+
|
|
2254
|
+
assert.equal(document.getElementById("btn-review-metric").classList
|
|
2255
|
+
.contains("primary"), true)
|
|
2256
|
+
assert.equal(document.getElementById("btn-scan").classList
|
|
2257
|
+
.contains("primary"), false)
|
|
2258
|
+
|
|
2259
|
+
dom.window.close()
|
|
2260
|
+
})
|
|
2261
|
+
|
|
2224
2262
|
test("an app without a global baseline shows setup and opens global Disk Saver", async () => {
|
|
2225
2263
|
const status = fixture([], {
|
|
2226
2264
|
global_scan_ready: false,
|