diff --git a/main.js b/main.js index 2af64b7..6bfff93 100644 --- a/main.js +++ b/main.js @@ -1,9 +1,10 @@ -const { app, BrowserWindow, dialog, ipcMain } = require('electron'); +const { app, BrowserWindow, dialog, ipcMain, shell } = require('electron'); const path = require('path'); const fs = require('fs-extra'); const { processFolder } = require('./services/folderProcessor'); const { processZip } = require('./services/zipProcessor'); +const { resolveUnroutedDir, listUnroutedFiles } = require('./services/unrouted'); const CAD_EXTENSIONS = ['prt', 'asm', 'dwr']; const DEFAULT_DESTINATION = './output/cad'; @@ -168,3 +169,16 @@ ipcMain.handle('update-destination', async (_event, payload) => { await persistDestination(config.destination); return { destination: config.destination }; }); + +ipcMain.handle('open-unrouted-folder', async () => { + const unroutedDir = await resolveUnroutedDir(); + const openResult = await shell.openPath(unroutedDir); + + if (openResult) { + throw new Error(`Impossibile aprire la cartella: ${openResult}`); + } + + return { path: unroutedDir }; +}); + +ipcMain.handle('list-unrouted-files', async () => listUnroutedFiles()); diff --git a/preload.js b/preload.js index e69c810..8729748 100644 --- a/preload.js +++ b/preload.js @@ -8,4 +8,6 @@ contextBridge.exposeInMainWorld('api', { getDestination: () => ipcRenderer.invoke('get-destination'), selectDestinationFolder: () => ipcRenderer.invoke('select-destination-folder'), updateDestination: (destination) => ipcRenderer.invoke('update-destination', { destination }), + openUnroutedFolder: () => ipcRenderer.invoke('open-unrouted-folder'), + listUnroutedFiles: () => ipcRenderer.invoke('list-unrouted-files'), }); diff --git a/renderer/index.html b/renderer/index.html index d4ce8c1..19ca720 100644 --- a/renderer/index.html +++ b/renderer/index.html @@ -161,6 +161,65 @@ color: var(--muted); } + .preview-overlay { + position: fixed; + inset: 0; + background: rgba(15, 23, 42, 0.55); + display: none; + align-items: center; + justify-content: center; + padding: 16px; + z-index: 20; + } + + .preview-overlay.visible { + display: flex; + } + + .preview-card { + width: min(900px, 100%); + max-height: 85vh; + background: #ffffff; + border: 1px solid var(--border); + border-radius: 12px; + padding: 14px; + display: flex; + flex-direction: column; + gap: 10px; + } + + .preview-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + } + + .preview-header h2 { + margin: 0; + font-size: 18px; + } + + .preview-meta { + font-size: 12px; + color: var(--muted); + word-break: break-all; + } + + .preview-list { + margin: 0; + background: #0f172a; + color: #e2e8f0; + border: 1px solid var(--border); + border-radius: 10px; + padding: 12px; + overflow: auto; + min-height: 220px; + max-height: 58vh; + font-size: 13px; + white-space: pre-wrap; + } + @media (max-width: 760px) { .rule-row { grid-template-columns: 1fr; @@ -200,11 +259,25 @@ +
+ +
Pronto.
+
+
+
+

Anteprima __NON_SMISTATI

+ +
+
+
Nessun dato.
+
+
+ diff --git a/renderer/renderer.js b/renderer/renderer.js index 6294442..4fc9fa7 100644 --- a/renderer/renderer.js +++ b/renderer/renderer.js @@ -5,7 +5,12 @@ const output = document.getElementById('output'); const destinationInput = document.getElementById('destinationInput'); const browseDestinationBtn = document.getElementById('browseDestinationBtn'); const saveDestinationBtn = document.getElementById('saveDestinationBtn'); +const openUnroutedBtn = document.getElementById('openUnroutedBtn'); const destinationStatus = document.getElementById('destinationStatus'); +const unroutedPreviewOverlay = document.getElementById('unroutedPreviewOverlay'); +const closeUnroutedPreviewBtn = document.getElementById('closeUnroutedPreviewBtn'); +const unroutedPreviewMeta = document.getElementById('unroutedPreviewMeta'); +const unroutedPreviewList = document.getElementById('unroutedPreviewList'); const defaultDropZoneText = 'Trascina qui una cartella o un file .zip'; let isProcessing = false; @@ -18,6 +23,31 @@ function setDestinationLoading(isLoading) { destinationInput.disabled = isLoading; browseDestinationBtn.disabled = isLoading; saveDestinationBtn.disabled = isLoading; + openUnroutedBtn.disabled = isLoading; +} + +function formatBytes(bytes) { + const value = Number(bytes || 0); + if (value < 1024) return `${value} B`; + if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`; + if (value < 1024 * 1024 * 1024) return `${(value / (1024 * 1024)).toFixed(1)} MB`; + return `${(value / (1024 * 1024 * 1024)).toFixed(1)} GB`; +} + +function showUnroutedPreview(payload) { + const files = payload?.files || []; + const directory = payload?.directory || ''; + const lines = files.length + ? files.map((file) => `- ${file.relativePath} | ${formatBytes(file.size)}`).join('\n') + : 'Nessun file presente in __NON_SMISTATI.'; + + unroutedPreviewMeta.textContent = `cartella: ${directory} | file totali: ${files.length}`; + unroutedPreviewList.textContent = lines; + unroutedPreviewOverlay.classList.add('visible'); +} + +function hideUnroutedPreview() { + unroutedPreviewOverlay.classList.remove('visible'); } function renderResult(title, result) { @@ -166,6 +196,34 @@ saveDestinationBtn.addEventListener('click', async () => { } }); +openUnroutedBtn.addEventListener('click', async () => { + try { + setDestinationLoading(true); + destinationStatus.textContent = 'Caricamento anteprima non smistati...'; + + const result = await window.api.listUnroutedFiles(); + showUnroutedPreview(result); + destinationStatus.textContent = `Anteprima caricata (${result.files?.length || 0} file).`; + } catch (error) { + destinationStatus.textContent = `Errore: ${error.message}`; + } finally { + setDestinationLoading(false); + } +}); + +closeUnroutedPreviewBtn.addEventListener('click', hideUnroutedPreview); +unroutedPreviewOverlay.addEventListener('click', (event) => { + if (event.target === unroutedPreviewOverlay) { + hideUnroutedPreview(); + } +}); + +window.addEventListener('keydown', (event) => { + if (event.key === 'Escape' && unroutedPreviewOverlay.classList.contains('visible')) { + hideUnroutedPreview(); + } +}); + async function initConfigUI() { try { const destinationResult = await window.api.getDestination(); diff --git a/services/unrouted.js b/services/unrouted.js index b8b558e..cab4645 100644 --- a/services/unrouted.js +++ b/services/unrouted.js @@ -46,8 +46,58 @@ async function getUnroutedTarget(fileName) { }; } +async function listFilesRecursively(rootDir) { + const files = []; + + async function walk(currentDir) { + let entries; + try { + entries = await fs.readdir(currentDir, { withFileTypes: true }); + } catch { + return; + } + + for (const entry of entries) { + const fullPath = path.join(currentDir, entry.name); + + if (entry.isDirectory()) { + await walk(fullPath); + continue; + } + + if (!entry.isFile()) { + continue; + } + + const stats = await fs.stat(fullPath).catch(() => null); + if (!stats) { + continue; + } + + files.push({ + name: entry.name, + relativePath: path.relative(rootDir, fullPath), + size: stats.size, + updatedAt: stats.mtime.toISOString(), + }); + } + } + + await walk(rootDir); + files.sort((a, b) => a.relativePath.localeCompare(b.relativePath, 'it')); + return files; +} + +async function listUnroutedFiles() { + const directory = await resolveUnroutedDir(); + const files = await listFilesRecursively(directory); + return { directory, files }; +} + module.exports = { getUnroutedTarget, + resolveUnroutedDir, + listUnroutedFiles, PRIMARY_UNROUTED_DIR, HOME_UNROUTED_DIR, };