Fix AMPP picker: text input, path-based queuing, worker path resolution
This commit is contained in:
parent
1be810be24
commit
e55555d2b7
3 changed files with 20 additions and 76 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { placeAssetInFolderById } = require("./ampp-folder-placer");
|
const { placeAssetInFolderById, getOrCreateFolderByPath } = require("./ampp-folder-placer");
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
// AMPP Placement Worker — lib/ampp-placement-worker.js
|
// AMPP Placement Worker — lib/ampp-placement-worker.js
|
||||||
|
|
@ -128,9 +128,14 @@ class AmppPlacementWorker {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[placement-worker] Placing '${placement.filename}' → folder ${placement.amppFolderId} (asset ${assetId})`);
|
let targetFolderId = placement.amppFolderId;
|
||||||
|
if (!targetFolderId && placement.amppFolderName) {
|
||||||
|
try { targetFolderId = await getOrCreateFolderByPath(this._getAmppBase(), placement.amppFolderName, token); }
|
||||||
|
catch(e) { placement.status='failed'; placement.error=e.message; changed=true; continue; }
|
||||||
|
}
|
||||||
|
console.log(`[placement-worker] Placing '${placement.filename}' → folder ${targetFolderId} (asset ${assetId})`);
|
||||||
try {
|
try {
|
||||||
await placeAssetInFolderById(this._getAmppBase(), assetId, placement.amppFolderId, token);
|
await placeAssetInFolderById(this._getAmppBase(), assetId, targetFolderId, token);
|
||||||
placement.status = "placed";
|
placement.status = "placed";
|
||||||
placement.assetId = assetId;
|
placement.assetId = assetId;
|
||||||
placement.placedAt = new Date().toISOString();
|
placement.placedAt = new Date().toISOString();
|
||||||
|
|
|
||||||
|
|
@ -485,17 +485,17 @@ body::before{content:'';position:fixed;inset:0;background:radial-gradient(ellips
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- AMPP DESTINATION FOLDER -->
|
||||||
<div style="margin-bottom:1.5rem" id="ampp-folder-section">
|
<div style="margin-bottom:1.5rem" id="ampp-folder-section">
|
||||||
<div class="section-title" style="display:flex;align-items:center;gap:.5rem">
|
<div class="section-title" style="display:flex;align-items:center;gap:.5rem">
|
||||||
AMPP Destination Folder
|
AMPP Destination Folder
|
||||||
<span id="ampp-folder-status" style="font-size:.7rem;font-weight:400;text-transform:none;letter-spacing:0;color:var(--text-dim)">— optional</span>
|
<span style="font-size:.7rem;font-weight:400;text-transform:none;letter-spacing:0;color:var(--text-dim)">— optional</span>
|
||||||
<button id="ampp-folder-refresh-btn" onclick="loadAmppFolders()" style="margin-left:auto;padding:.2rem .55rem;font-size:.72rem;background:transparent;border:1px solid var(--border);border-radius:6px;color:var(--text-secondary);cursor:pointer">↻ Refresh</button>
|
|
||||||
</div>
|
</div>
|
||||||
<input class="form-input" id="ampp-folder-search" placeholder="🔍 Search AMPP folders…" oninput="renderAmppFolderList()" style="margin-bottom:.4rem;font-size:.78rem;padding:.4rem .65rem"/>
|
<input class="form-input" id="ampp-folder-path-input"
|
||||||
<div class="folder-tree-box" id="ampp-folder-box" style="max-height:220px;overflow-y:auto">
|
placeholder="e.g. NEWS/PACKAGES (leave blank to skip)"
|
||||||
<div style="color:var(--text-dim);font-size:.8rem;padding:.75rem;text-align:center">Click ↻ Refresh to load AMPP folders</div>
|
oninput="updateAmppFolderFromInput(this.value)"
|
||||||
</div>
|
style="font-size:.82rem;margin-bottom:.35rem">
|
||||||
<div style="margin-top:.45rem;font-size:.73rem;color:var(--text-dim)">
|
<div style="font-size:.75rem;color:var(--text-dim)">
|
||||||
AMPP folder: <code id="ampp-folder-display" style="color:var(--blue-bright);font-family:'JetBrains Mono',monospace">(none — skip placement)</code>
|
AMPP folder: <code id="ampp-folder-display" style="color:var(--blue-bright);font-family:'JetBrains Mono',monospace">(none — skip placement)</code>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -879,7 +879,6 @@ function showApp() {
|
||||||
loadS3Config(); loadRelayConfig(); loadAmppConfig(); loadUsers(); loadShareLinks(); populateSlFolderSelect();
|
loadS3Config(); loadRelayConfig(); loadAmppConfig(); loadUsers(); loadShareLinks(); populateSlFolderSelect();
|
||||||
}
|
}
|
||||||
loadFolders();
|
loadFolders();
|
||||||
loadAmppFolders();
|
|
||||||
loadAmppJobs();
|
loadAmppJobs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1087,70 +1086,10 @@ async function deleteFolder(pathArr) {
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// AMPP FOLDER PICKER
|
// AMPP FOLDER PICKER
|
||||||
// ============================================================
|
// ============================================================
|
||||||
async function loadAmppFolders() {
|
function updateAmppFolderFromInput(val) {
|
||||||
const box = document.getElementById('ampp-folder-box');
|
selectedAmppFolderName = val.trim();
|
||||||
const statusEl = document.getElementById('ampp-folder-status');
|
selectedAmppFolderId = '';
|
||||||
if (!box) return;
|
var el = document.getElementById('ampp-folder-display');
|
||||||
box.innerHTML = '<div style="color:var(--text-dim);font-size:.8rem;padding:.75rem;text-align:center">Loading AMPP folders…</div>';
|
|
||||||
if (statusEl) statusEl.textContent = '— loading…';
|
|
||||||
try {
|
|
||||||
const d = await api('GET', '/api/ampp/folders/list');
|
|
||||||
if (!d.success) {
|
|
||||||
if (d.error && d.error.toLowerCase().includes('not configured')) {
|
|
||||||
box.innerHTML = '<div style="color:var(--text-dim);font-size:.8rem;padding:.75rem;text-align:center">AMPP not configured — set up in Admin → AMPP</div>';
|
|
||||||
if (statusEl) statusEl.textContent = '— not configured';
|
|
||||||
} else {
|
|
||||||
box.innerHTML = `<div style="color:var(--red,#e55);font-size:.8rem;padding:.75rem;text-align:center">Error: ${esc(d.error||'Failed to load folders')}</div>`;
|
|
||||||
if (statusEl) statusEl.textContent = '— error';
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
amppFolderCache = d.folders || [];
|
|
||||||
if (statusEl) statusEl.textContent = `— ${amppFolderCache.length} folder${amppFolderCache.length!==1?'s':''}`;
|
|
||||||
renderAmppFolderList();
|
|
||||||
} catch(e) {
|
|
||||||
box.innerHTML = `<div style="color:var(--red,#e55);font-size:.8rem;padding:.75rem;text-align:center">Error: ${esc(e.message)}</div>`;
|
|
||||||
if (statusEl) statusEl.textContent = '— error';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderAmppFolderList() {
|
|
||||||
const box = document.getElementById('ampp-folder-box');
|
|
||||||
if (!box) return;
|
|
||||||
box.innerHTML = '';
|
|
||||||
const searchEl = document.getElementById('ampp-folder-search');
|
|
||||||
const filter = (searchEl ? searchEl.value.trim().toLowerCase() : '');
|
|
||||||
const folders = amppFolderCache.filter(f => !filter || (f.path||f.name||'').toLowerCase().includes(filter));
|
|
||||||
|
|
||||||
// "None" row — always first
|
|
||||||
const noneRow = document.createElement('div');
|
|
||||||
noneRow.className = 'folder-tree-row' + (selectedAmppFolderId === '' ? ' active' : '');
|
|
||||||
noneRow.innerHTML = `<span class="ftr-icon">🚫</span><span class="ftr-name" style="font-style:italic;color:${selectedAmppFolderId===''?'':'var(--text-dim)'}">(no AMPP placement)</span>`;
|
|
||||||
noneRow.onclick = () => { selectedAmppFolderId = ''; selectedAmppFolderName = ''; updateAmppFolderDisplay(); renderAmppFolderList(); };
|
|
||||||
box.appendChild(noneRow);
|
|
||||||
|
|
||||||
if (!folders.length && amppFolderCache.length > 0) {
|
|
||||||
box.innerHTML += '<div style="color:var(--text-dim);font-size:.8rem;padding:.5rem .75rem">No folders match your search</div>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort by path/name
|
|
||||||
const sorted = [...folders].sort((a, b) => (a.path||a.name||'').localeCompare(b.path||b.name||''));
|
|
||||||
sorted.forEach(f => {
|
|
||||||
const id = f.id || f['folder:id'] || '';
|
|
||||||
const displayName = f.path || f.name || f['name:text'] || id;
|
|
||||||
const depth = (displayName.match(/\//g)||[]).length;
|
|
||||||
const row = document.createElement('div');
|
|
||||||
row.className = 'folder-tree-row' + (selectedAmppFolderId === id ? ' active' : '');
|
|
||||||
row.style.paddingLeft = (0.75 + depth * 1.0) + 'rem';
|
|
||||||
row.innerHTML = `<span class="ftr-icon">📁</span><span class="ftr-name">${esc(displayName)}</span>`;
|
|
||||||
row.onclick = () => { selectedAmppFolderId = id; selectedAmppFolderName = displayName; updateAmppFolderDisplay(); renderAmppFolderList(); };
|
|
||||||
box.appendChild(row);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateAmppFolderDisplay() {
|
|
||||||
const el = document.getElementById('ampp-folder-display');
|
|
||||||
if (el) el.textContent = selectedAmppFolderName || '(none — skip placement)';
|
if (el) el.textContent = selectedAmppFolderName || '(none — skip placement)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -625,7 +625,7 @@ app.post("/api/presigned/complete", requireAuth, (req, res) => {
|
||||||
saveData(db);
|
saveData(db);
|
||||||
}
|
}
|
||||||
// Record AMPP placement if a folder was selected
|
// Record AMPP placement if a folder was selected
|
||||||
if (amppFolderId && filename) {
|
if ((amppFolderId || amppFolderName) && filename) {
|
||||||
if (!db.pendingPlacements) db.pendingPlacements = [];
|
if (!db.pendingPlacements) db.pendingPlacements = [];
|
||||||
db.pendingPlacements.push({
|
db.pendingPlacements.push({
|
||||||
id: require("crypto").randomBytes(8).toString("hex"),
|
id: require("crypto").randomBytes(8).toString("hex"),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue