wiki-plugin-shoppe 0.0.32 → 0.0.34
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/client/shoppe.js +66 -10
- package/package.json +1 -1
- package/server/server.js +1061 -47
package/client/shoppe.js
CHANGED
|
@@ -44,6 +44,10 @@
|
|
|
44
44
|
.sw-status.success { background: #d1fae5; color: #065f46; display: block; }
|
|
45
45
|
.sw-status.error { background: #fee2e2; color: #991b1b; display: block; }
|
|
46
46
|
.sw-status code { background: rgba(0,0,0,0.08); border-radius: 4px; padding: 1px 5px; font-size: 12px; }
|
|
47
|
+
.sw-progress-bar-track { background: rgba(0,0,0,0.12); border-radius: 4px; height: 8px; margin: 8px 0; overflow: hidden; }
|
|
48
|
+
.sw-progress-bar-fill { height: 100%; background: #1a56db; border-radius: 4px; width: 0%; transition: width 0.25s ease; }
|
|
49
|
+
.sw-progress-meta { display: flex; justify-content: space-between; font-size: 12px; opacity: 0.75; }
|
|
50
|
+
.sw-progress-item { margin-top: 6px; font-size: 13px; font-style: italic; }
|
|
47
51
|
.sw-remove { display: block; width: 100%; margin-top: 24px; padding: 8px; background: none; border: 1px solid #e5e5ea; border-radius: 8px; font-size: 12px; color: #aaa; cursor: pointer; text-align: center; }
|
|
48
52
|
.sw-remove:hover { border-color: #cc0000; color: #cc0000; }
|
|
49
53
|
</style>
|
|
@@ -313,25 +317,72 @@
|
|
|
313
317
|
// ── Upload ──────────────────────────────────────────────────────────────────
|
|
314
318
|
|
|
315
319
|
async function uploadArchive(file, container) {
|
|
320
|
+
const statusEl = container.querySelector('#sw-upload-status');
|
|
321
|
+
|
|
322
|
+
// Step 1: POST the file, get a jobId back immediately.
|
|
316
323
|
showStatus(container, '#sw-upload-status', `⏳ Uploading <strong>${file.name}</strong>…`, 'info');
|
|
317
324
|
const form = new FormData();
|
|
318
325
|
form.append('archive', file);
|
|
326
|
+
let jobId;
|
|
319
327
|
try {
|
|
320
328
|
const resp = await fetch('/plugin/shoppe/upload', { method: 'POST', body: form });
|
|
321
329
|
const result = await resp.json();
|
|
322
|
-
if (!result.success) throw new Error(result.error || 'Upload failed');
|
|
330
|
+
if (!result.success || !result.jobId) throw new Error(result.error || 'Upload failed');
|
|
331
|
+
jobId = result.jobId;
|
|
332
|
+
} catch (err) {
|
|
333
|
+
showStatus(container, '#sw-upload-status', `❌ ${err.message}`, 'error');
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Step 2: Show progress UI and open SSE stream.
|
|
338
|
+
statusEl.className = 'sw-status info';
|
|
339
|
+
statusEl.style.display = 'block';
|
|
340
|
+
statusEl.innerHTML = `
|
|
341
|
+
<div id="sw-progress-title" style="font-weight:600;margin-bottom:6px;">⏳ Processing archive…</div>
|
|
342
|
+
<div class="sw-progress-bar-track"><div id="sw-progress-fill" class="sw-progress-bar-fill"></div></div>
|
|
343
|
+
<div class="sw-progress-meta">
|
|
344
|
+
<span id="sw-progress-count">0 / …</span>
|
|
345
|
+
<span id="sw-progress-pct">0%</span>
|
|
346
|
+
</div>
|
|
347
|
+
<div id="sw-progress-item" class="sw-progress-item"></div>
|
|
348
|
+
`;
|
|
349
|
+
|
|
350
|
+
const fillEl = statusEl.querySelector('#sw-progress-fill');
|
|
351
|
+
const countEl = statusEl.querySelector('#sw-progress-count');
|
|
352
|
+
const pctEl = statusEl.querySelector('#sw-progress-pct');
|
|
353
|
+
const itemEl = statusEl.querySelector('#sw-progress-item');
|
|
354
|
+
const titleEl = statusEl.querySelector('#sw-progress-title');
|
|
355
|
+
|
|
356
|
+
const es = new EventSource(`/plugin/shoppe/upload/progress/${jobId}`);
|
|
357
|
+
|
|
358
|
+
es.addEventListener('start', e => {
|
|
359
|
+
const { total, name } = JSON.parse(e.data);
|
|
360
|
+
titleEl.innerHTML = `⏳ Uploading <strong>${name}</strong> — ${total} item${total !== 1 ? 's' : ''}`;
|
|
361
|
+
countEl.textContent = `0 / ${total}`;
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
es.addEventListener('progress', e => {
|
|
365
|
+
const { current, total, label } = JSON.parse(e.data);
|
|
366
|
+
const pct = total > 0 ? Math.round(current / total * 100) : 0;
|
|
367
|
+
fillEl.style.width = pct + '%';
|
|
368
|
+
countEl.textContent = `${current} / ${total}`;
|
|
369
|
+
pctEl.textContent = pct + '%';
|
|
370
|
+
itemEl.textContent = label;
|
|
371
|
+
});
|
|
323
372
|
|
|
373
|
+
es.addEventListener('complete', e => {
|
|
374
|
+
es.close();
|
|
375
|
+
const result = JSON.parse(e.data);
|
|
324
376
|
const r = result.results;
|
|
325
377
|
const counts = [
|
|
326
|
-
r.books.length && `📚 ${r.books.length} book${r.books.length !== 1 ? 's' : ''}`,
|
|
327
|
-
r.music.length && `🎵 ${r.music.length} music item${r.music.length !== 1 ? 's' : ''}`,
|
|
328
|
-
r.posts.length && `📝 ${r.posts.length} post${r.posts.length !== 1 ? 's' : ''}`,
|
|
329
|
-
r.albums.length && `🖼️ ${r.albums.length} album${r.albums.length !== 1 ? 's' : ''}`,
|
|
330
|
-
r.products.length && `📦 ${r.products.length} product${r.products.length !== 1 ? 's' : ''}`,
|
|
378
|
+
r.books && r.books.length && `📚 ${r.books.length} book${r.books.length !== 1 ? 's' : ''}`,
|
|
379
|
+
r.music && r.music.length && `🎵 ${r.music.length} music item${r.music.length !== 1 ? 's' : ''}`,
|
|
380
|
+
r.posts && r.posts.length && `📝 ${r.posts.length} post${r.posts.length !== 1 ? 's' : ''}`,
|
|
381
|
+
r.albums && r.albums.length && `🖼️ ${r.albums.length} album${r.albums.length !== 1 ? 's' : ''}`,
|
|
382
|
+
r.products && r.products.length && `📦 ${r.products.length} product${r.products.length !== 1 ? 's' : ''}`,
|
|
331
383
|
r.appointments && r.appointments.length && `📅 ${r.appointments.length} appointment${r.appointments.length !== 1 ? 's' : ''}`,
|
|
332
384
|
r.subscriptions && r.subscriptions.length && `🎁 ${r.subscriptions.length} subscription tier${r.subscriptions.length !== 1 ? 's' : ''}`
|
|
333
385
|
].filter(Boolean).join(' · ') || 'no items found';
|
|
334
|
-
|
|
335
386
|
const warnings = (r.warnings && r.warnings.length > 0)
|
|
336
387
|
? `<br><br>⚠️ <strong>Warnings (${r.warnings.length}):</strong><br>${r.warnings.map(w => `• ${w}`).join('<br>')}`
|
|
337
388
|
: '';
|
|
@@ -340,9 +391,14 @@
|
|
|
340
391
|
<a href="/plugin/shoppe/${result.tenant.uuid}" target="_blank" class="sw-link" style="display:inline-block;margin-top:8px;">View your shoppe →</a>`,
|
|
341
392
|
'success');
|
|
342
393
|
loadDirectory(container);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
es.addEventListener('error', e => {
|
|
397
|
+
es.close();
|
|
398
|
+
let msg = 'Upload failed';
|
|
399
|
+
try { msg = JSON.parse(e.data).message; } catch (err) { /* use default */ }
|
|
400
|
+
showStatus(container, '#sw-upload-status', `❌ ${msg}`, 'error');
|
|
401
|
+
});
|
|
346
402
|
}
|
|
347
403
|
|
|
348
404
|
// ── Save URL (owner) ────────────────────────────────────────────────────────
|