diff --git a/PROJECT_MEMORY.md b/PROJECT_MEMORY.md index 4d38d29..6476b31 100644 --- a/PROJECT_MEMORY.md +++ b/PROJECT_MEMORY.md @@ -6,6 +6,7 @@ Multi-Hoster-Upload ist eine Electron-Desktopanwendung für Windows, die große ## Aktueller Zustand +- Log-Einstellungen nach `2.1.49`: Logpfad und Log-Datei-Modus teilen ein Beschriftungsraster; native Modusauswahl auf 240 px begrenzt, 40 px hoch, Pfeil mit 14 px Innenabstand. Hinweis unter dem Dropdown ohne zusätzliche Einrückung. Ordner-/Öffnen-Buttons bleiben neben dem Pfad; schmale Container wechseln auf gestapelte Felder. IDs, Optionen und Logfunktion unverändert. Electron-Regression mit tatsächlichem Template bei drei Breiten und Screenshotprüfung; noch kein Release. - Automatik-Abstand nach `2.1.49`: zusätzlicher 22-px-Unterabstand der Statuskarte vor dem neuen Formularcontainer entfernt. Abstand zur ersten Abschnittsüberschrift entspricht jetzt dem folgenden Abschnitt: jeweils 28 px. Electron-Regression misst beide Abstände bei 1000/760/360 px direkt am echten Template; gezielter Test und Lint erfolgreich. Entwicklerversion wird automatisch neu gestartet; noch kein Release. - Ordnerüberwachungstest nach `2.1.49`: IPC verwendet gespeicherte Ordnerregeln in einer isolierten FolderMonitor-Instanz statt der möglicherweise unkonfigurierten laufenden Überwachung. Funktioniert bei deaktivierter, aktiver und pausierter Überwachung; kein Watcher-/Timerstart, keine neuen Dateien/Statusereignisse am produktiven Monitor, keine Änderung seiner Generation oder Duplikatreservierungen. Fehlender Pfad, unerreichbarer Ordner und Scanfehler werden über feste, übersetzte Fehlermeldungen angezeigt; unbekannte Fehler bleiben bereinigt. Regressionen für die drei Betriebszustände, parallele Tests, Fehlerfälle und IPC-Verdrahtung ergänzt; Entwicklung automatisch neu gestartet. - Automatik-Einstellungen nach `2.1.49`: gemeinsames 210-px-Beschriftungsraster für Wiederholungen, Ordnerpfad, Queue-Limit, Abgleichintervall, Dateifilter und Verzögerung. Felder 40 px hoch, Zahlenfelder 120 px breit, Dropdowns auf passende Breiten begrenzt und Pfeile 14 px nach innen versetzt. Hinweise stehen unter ihrem jeweiligen Feld; Container-Abfragen schalten bei schmalem Inhalt auf einspaltige Darstellung. Ordnerüberwachungstest steht nach Verhalten/Hoster-Vorauswahl als Abschlussaktion. IDs und Speicherlogik unverändert. Electron-Regression mit echtem Template bei 1000/760/360 px, Screenshot visuell geprüft; noch kein Release. @@ -95,6 +96,7 @@ npm audit --omit=dev ## Zuletzt verifiziert +- Log-Layout: 47 Startup-/Electron- und Logmodus-Tests sowie Lint erfolgreich. Gemeinsame Feldkante, Feldhöhe, Dropdownbreite, Pfeil-Innenabstand, Hinweise und unveränderte Modusoptionen bei 1000/760/360 px geprüft. Entwicklerversion automatisch neu gestartet; nicht veröffentlicht. - Automatik-Abstand: alle 26 Startup-/Electron-Tests und Lint erfolgreich. Gleiche Abschnittsabstände von 28 px bei drei Breiten bestätigt; automatischer Entwicklungsneustart im Watcher-Log nachgewiesen. Kein Release. - Test bei deaktivierter Ordnerüberwachung: 844 Haupttests, 18 Servertests und Lint erfolgreich. Watcher-Neustart bestätigt. Read-only-Test bleibt unabhängig vom Produktivzustand, bekannte Fehler werden konkret angezeigt. Noch nicht veröffentlicht. - Automatik-Layout: 840 Haupttests, 18 Servertests und Lint erfolgreich. Feldhöhen, gemeinsame linke Kante, Label-/Hinweispositionen, Dropdownbreiten/Pfeilabstand und Abschlussposition der Testaktion über echte Electron-DOM-Messungen geprüft. Watcher-Neustart und sichtbare Entwicklungsinstanz bestätigt. Noch nicht veröffentlicht. diff --git a/renderer/app.js b/renderer/app.js index cdf8afd..35ca8f6 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -6505,20 +6505,28 @@ function renderSettings() { pages.logs.innerHTML = ` ${pageHeader('Logs & Support', 'Protokollierung verwalten, Log-Dateien öffnen und ein bereinigtes Support-Paket erstellen.')}
Log
-
- +
+
+ +
+
-
- +
+ +
+ + Pro Session = neue Datei bei jedem App-Start; nach komplettem Schließen + erneutem Öffnen beginnt eine neue Session. +
+
diff --git a/renderer/styles.css b/renderer/styles.css index bce6676..831481e 100644 --- a/renderer/styles.css +++ b/renderer/styles.css @@ -3926,25 +3926,6 @@ input[type="checkbox"] { background: #3c3b6e; } -.log-file-path-row { - display: flex !important; - align-items: center !important; - flex-wrap: wrap !important; - gap: 8px !important; -} - -.log-file-path-row > label { - min-width: 140px !important; - flex: 1 1 190px; -} - -.log-file-path-row > .key-input { - width: auto; - min-width: 180px !important; - max-width: 100%; - flex: 999 1 260px; -} - .log-file-path-row .btn { flex: 0 0 auto; white-space: nowrap; @@ -4953,7 +4934,8 @@ input[type="checkbox"] { grid-template-columns: minmax(0, 180px) minmax(0, 1fr); } -.automation-select-control { +.automation-select-control, +.settings-select-control { display: block; position: relative; width: 100%; @@ -4961,7 +4943,8 @@ input[type="checkbox"] { min-width: 0; } -.automation-select-control::after { +.automation-select-control::after, +.settings-select-control::after { content: ''; position: absolute; top: 50%; @@ -4974,7 +4957,8 @@ input[type="checkbox"] { pointer-events: none; } -.settings-subpage .automation-select-control > select { +.settings-subpage .automation-select-control > select, +.settings-subpage .settings-select-control > select { appearance: none; padding-right: 38px; user-select: none; @@ -5000,3 +4984,65 @@ input[type="checkbox"] { grid-template-columns: minmax(0, 1fr); } } + +.log-config-fields { + container: log-fields / inline-size; + min-width: 0; +} + +.settings-subpage .settings-row.log-config-row { + display: grid; + grid-template-columns: 210px minmax(0, 1fr); + align-items: start; + gap: 12px; +} + +.settings-subpage .settings-row.log-config-row > label { + min-width: 0; + padding-top: 9px; + line-height: 1.5; +} + +.log-path-controls { + display: grid; + grid-template-columns: minmax(0, 1fr) auto auto; + align-items: center; + gap: 8px; + min-width: 0; +} + +.log-mode-controls { + display: grid; + gap: 8px; + min-width: 0; +} + +.settings-subpage .log-config-fields :is(.key-input, .hs-input) { + min-width: 0; + max-width: none; + width: 100%; + min-height: 40px; + border-radius: 6px; +} + +@container log-fields (max-width: 620px) { + .settings-subpage .settings-row.log-config-row { + grid-template-columns: minmax(0, 1fr); + gap: 8px; + } + + .settings-subpage .settings-row.log-config-row > label { + padding-top: 0; + } +} + +@container log-fields (max-width: 380px) { + .log-path-controls { + grid-template-columns: auto auto; + justify-content: start; + } + + .log-path-controls > input { + grid-column: 1 / -1; + } +} diff --git a/tests/startup-renderer.test.js b/tests/startup-renderer.test.js index 818e798..89dc082 100644 --- a/tests/startup-renderer.test.js +++ b/tests/startup-renderer.test.js @@ -222,7 +222,7 @@ app.whenReady().then(async () => { assert.equal(data.ok, true); }); -test('automation fields share a responsive grid and leave hints below their controls', { skip: process.platform !== 'win32' }, t => { +test('automation and log fields share responsive grids and aligned hints', { skip: process.platform !== 'win32' }, t => { const root = path.resolve(__dirname, '..'); const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'mhu-automation-layout-')); t.after(() => fs.rmSync(directory, { recursive: true, force: true })); @@ -261,6 +261,23 @@ app.whenReady().then(async()=>{ for(const select of data.selects){assert.ok(select.width<=240);assert.equal(select.arrow,'14px')} if(process.env.MHU_AUTOMATION_SCREENSHOT && width===1000){await new Promise(resolve=>setTimeout(resolve,500));fs.writeFileSync(process.env.MHU_AUTOMATION_SCREENSHOT,(await wc.capturePage()).toPNG())} } + context.pages.logs={};context.window={}; + vm.runInNewContext(source.slice(source.indexOf('pages.logs.innerHTML ='),source.indexOf('pages.remote.innerHTML =')),context); + for(const width of [1000,760,360]){ + win.setContentSize(width,700); + await wc.loadURL('data:text/html;charset=utf-8,'+encodeURIComponent('
'+context.pages.logs.innerHTML+'
')); + const layout=await wc.executeJavaScript('(() => {const rect=e=>{const r=e.getBoundingClientRect();return {left:r.left,right:r.right,top:r.top,bottom:r.bottom,width:r.width,height:r.height}};const select=document.getElementById("logModeInput");return {input:rect(document.getElementById("logFilePathInput")),select:rect(select),hint:rect(document.querySelector(".log-mode-controls .hint")),arrow:getComputedStyle(select.parentElement,"::after").right,overflow:document.documentElement.scrollWidth>innerWidth,options:Array.from(select.options).map(o=>o.value)};})()'); + assert.equal(layout.input.left,layout.select.left); + assert.equal(layout.input.height,40); + assert.equal(layout.select.height,40); + assert.ok(layout.select.width<=240); + assert.equal(layout.hint.left,layout.select.left); + assert.ok(layout.hint.top>=layout.select.bottom+6); + assert.equal(layout.arrow,'14px'); + assert.equal(layout.overflow,false); + assert.deepEqual(layout.options,['single','daily','session']); + if(process.env.MHU_LOG_SCREENSHOT && width===1000){await new Promise(resolve=>setTimeout(resolve,500));fs.writeFileSync(process.env.MHU_LOG_SCREENSHOT,(await wc.capturePage()).toPNG())} + } win.destroy();fs.writeFileSync(process.env.MHU_AUTOMATION_RESULT,JSON.stringify({ok:true}));app.exit(0); }).catch(error=>{fs.writeFileSync(process.env.MHU_AUTOMATION_RESULT,JSON.stringify({error:error.stack}));app.exit(1)}); `);