From c59f6b5fca7d6a58ad396e4de2c8f3682c14717c Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Mon, 14 Sep 2026 16:29:14 -0400 Subject: [PATCH] =?UTF-8?q?fix(dragdrop):=20modale=20de=20s=C3=A9lection?= =?UTF-8?q?=20de=20vo=C3=BBte=20et=20sous-r=C3=A9pertoire=20align=C3=A9e?= =?UTF-8?q?=20avec=20le=20th=C3=A8me=20ObsiGate=20(#89)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/js/upload.js | 146 ++++++++++++++++++++++++++++----------- frontend/locales/en.json | 7 +- frontend/locales/fr.json | 7 +- 3 files changed, 114 insertions(+), 46 deletions(-) diff --git a/frontend/js/upload.js b/frontend/js/upload.js index 2236cf8..d7f39b4 100644 --- a/frontend/js/upload.js +++ b/frontend/js/upload.js @@ -181,22 +181,25 @@ export async function uploadBatch(vault, targetDir, items, options = {}) { export async function handleVaultDropUpload(vault, targetDir, items) { if (!items || !items.length) return; - // If target directory is not explicitly passed or if dropping on vault root, - // allow user to choose or confirm the target folder + let chosenVault = vault; let chosenTargetDir = targetDir || ''; + + // If target directory is not explicitly passed or if dropping from global overlay, + // allow user to choose or confirm the target vault and folder if (targetDir === undefined || targetDir === null) { const picked = await promptTargetFolder(vault, chosenTargetDir, items); if (picked === null) return; // User cancelled - chosenTargetDir = picked; + chosenVault = picked.vault || chosenVault; + chosenTargetDir = picked.targetDir || ''; } const fileCount = items.filter((x) => !x.isDir).length; - const destName = chosenTargetDir ? `${vault}/${chosenTargetDir}` : vault; + const destName = chosenTargetDir ? `${chosenVault}/${chosenTargetDir}` : chosenVault; showToast(`${t('upload.uploading', { count: fileCount }) || `Uploading ${fileCount} file(s) to ${destName}...`}`, 'info'); try { - const res = await uploadBatch(vault, chosenTargetDir, items); + const res = await uploadBatch(chosenVault, chosenTargetDir, items); if (res && res.success) { showToast(t('upload.success', { count: res.uploaded.length }) || `Imported ${res.uploaded.length} file(s) successfully`, 'success'); } else if (res && res.uploaded && res.uploaded.length > 0) { @@ -213,27 +216,57 @@ export async function handleVaultDropUpload(vault, targetDir, items) { } /** - * Display a folder picker modal for choosing the upload destination folder. + * Display a folder picker modal for choosing the upload destination vault and folder. * - * @param {string} vault - Vault name - * @param {string} currentDir - Initial folder path + * @param {string} initialVault - Default vault name + * @param {string} initialDir - Initial folder path * @param {Array} items - Items to upload - * @returns {Promise} Selected folder path (empty for root) or null if cancelled. + * @returns {Promise<{ vault: string, targetDir: string }|null>} Selected target or null if cancelled. */ -export async function promptTargetFolder(vault, currentDir = '', items = []) { - let folders = []; +export async function promptTargetFolder(initialVault, initialDir = '', items = []) { + let vaultsList = []; try { - const res = await api(`/api/vault/${encodeURIComponent(vault)}/paths?limit=5000`); - if (res && Array.isArray(res.paths)) { - folders = res.paths - .filter((p) => p.type === 'directory') - .map((p) => p.path) - .sort(); + const vRes = await api('/api/vaults'); + if (vRes && Array.isArray(vRes.vaults)) { + vaultsList = vRes.vaults; + } else if (Array.isArray(vRes)) { + vaultsList = vRes; } } catch (e) { - console.warn('Could not fetch vault directory paths:', e); + console.warn('Could not fetch vaults list:', e); } + // Fallback if vaults list API returns empty or fails + if (!vaultsList.length && initialVault) { + vaultsList = [{ name: initialVault }]; + } + + let selectedVault = initialVault || (vaultsList[0]?.name) || ''; + + // Cache folder list per vault + const vaultFoldersMap = {}; + + async function fetchFoldersForVault(v) { + if (vaultFoldersMap[v]) return vaultFoldersMap[v]; + try { + const res = await api(`/api/vault/${encodeURIComponent(v)}/paths?limit=5000`); + if (res && Array.isArray(res.paths)) { + vaultFoldersMap[v] = res.paths + .filter((p) => p.type === 'directory') + .map((p) => p.path) + .sort(); + } else { + vaultFoldersMap[v] = []; + } + } catch (e) { + console.warn(`Could not fetch directories for vault ${v}:`, e); + vaultFoldersMap[v] = []; + } + return vaultFoldersMap[v]; + } + + await fetchFoldersForVault(selectedVault); + return new Promise((resolve) => { const overlay = document.createElement('div'); overlay.className = 'obsigate-modal-overlay active'; @@ -242,38 +275,70 @@ export async function promptTargetFolder(vault, currentDir = '', items = []) { const fileCount = items.filter((x) => !x.isDir).length; const dirCount = items.filter((x) => x.isDir).length; - let optionsHtml = ``; - for (const folder of folders) { - const selected = folder === currentDir ? 'selected' : ''; - optionsHtml += ``; + function renderVaultOptions() { + return vaultsList.map((v) => { + const vName = typeof v === 'string' ? v : v.name; + const sel = vName === selectedVault ? 'selected' : ''; + return ``; + }).join(''); + } + + function renderFolderOptions(folders, curDir) { + let html = ``; + for (const folder of folders) { + const sel = folder === curDir ? 'selected' : ''; + html += ``; + } + return html; } overlay.innerHTML = ` -
-