This commit is contained in:
@@ -6,6 +6,7 @@ Multi-Hoster-Upload ist eine Electron-Desktopanwendung für Windows, die große
|
|||||||
|
|
||||||
## Aktueller Zustand
|
## Aktueller Zustand
|
||||||
|
|
||||||
|
- Online-Backup-Seite nach `2.1.49`: drei klar abgegrenzte Bereiche in Reihenfolge „Schlüssel erstellen“, „Schlüssel importieren“, „Auf diesem Gerät erstellt“. Vorhandene IDs, Import-/Exportlogik, Statusmeldungen und Suchziele bleiben erhalten. Neue Überschriften auf Deutsch/Englisch; konsistente Karten ohne Akzentstreifen. Electron-Test nutzt jetzt das echte Seitenmarkup und prüft Modulzuordnung, Ausrichtung sowie Überlauf bei 1000/600/360 px. Lokale Entwicklerversion automatisch neu gestartet; breiter Screenshot visuell geprüft. Noch nicht veröffentlicht.
|
||||||
- Lokale Entwicklung auf Nutzerwunsch dauerhaft mit automatischem Neustart: `.artifacts/dev-watch.cjs` überwacht Main-/Preload-Dateien, `lib`, `renderer` und den lokalen Bootstrap `.artifacts/menu-test.cjs`. Start über `node .artifacts/dev-watch.cjs`; separater Fenstertitel „Multi-Hoster – Entwicklung (automatischer Neustart)“. Persistentes Testprofil unter `%LOCALAPPDATA%/Multi-Hoster-Upload-Development`, ohne automatische Accountchecks/Ordnerüberwachung/Remote-Steuerung initialisiert. Installierte Anwendung bleibt getrennt. Neustart durch CSS-Dateiänderung anhand gewechselter Electron-PID und erneut sichtbarem Fenster verifiziert. Bei weiteren Code-/UI-Änderungen diesen Watcher verwenden und den Neustart prüfen.
|
- Lokale Entwicklung auf Nutzerwunsch dauerhaft mit automatischem Neustart: `.artifacts/dev-watch.cjs` überwacht Main-/Preload-Dateien, `lib`, `renderer` und den lokalen Bootstrap `.artifacts/menu-test.cjs`. Start über `node .artifacts/dev-watch.cjs`; separater Fenstertitel „Multi-Hoster – Entwicklung (automatischer Neustart)“. Persistentes Testprofil unter `%LOCALAPPDATA%/Multi-Hoster-Upload-Development`, ohne automatische Accountchecks/Ordnerüberwachung/Remote-Steuerung initialisiert. Installierte Anwendung bleibt getrennt. Neustart durch CSS-Dateiänderung anhand gewechselter Electron-PID und erneut sichtbarem Fenster verifiziert. Bei weiteren Code-/UI-Änderungen diesen Watcher verwenden und den Neustart prüfen.
|
||||||
- Online-Backup-Gültigkeitsdauer nach `2.1.49`, noch nicht veröffentlicht: Auswahl und Erstellen-Button verwenden 40 px Höhe und 14 px Schrift; Label und Auswahl sind zur Importzeile ausgerichtet. Footer bricht bei Platzmangel um, auf schmalen Fenstern untereinander. Leere Statuszeile belegt keinen Platz; echte Meldungen bleiben sichtbar. Nativer Select und 14 px Pfeil-Innenabstand bleiben erhalten. Electron-Layoutregression bei 1000, 600 und 360 px; Screenshot der breiten Darstellung visuell geprüft.
|
- Online-Backup-Gültigkeitsdauer nach `2.1.49`, noch nicht veröffentlicht: Auswahl und Erstellen-Button verwenden 40 px Höhe und 14 px Schrift; Label und Auswahl sind zur Importzeile ausgerichtet. Footer bricht bei Platzmangel um, auf schmalen Fenstern untereinander. Leere Statuszeile belegt keinen Platz; echte Meldungen bleiben sichtbar. Nativer Select und 14 px Pfeil-Innenabstand bleiben erhalten. Electron-Layoutregression bei 1000, 600 und 360 px; Screenshot der breiten Darstellung visuell geprüft.
|
||||||
- Nach `2.1.49`, noch nicht veröffentlicht: Backup-Untermenü erhält eine durchgängige Hover-Fläche über den sichtbaren Abstand und 250 ms abbrechbare Schließverzögerung. Hover plus Klick bleibt offen, erneutes Betreten startet keine neue Öffnungsanimation; Tastaturfokus hält das Untermenü offen. Pfeil und Pfeiltasten folgen der linken Öffnungsrichtung, Escape schließt nur die aktuelle Untermenüebene. Fremde `animationend`-Ereignisse schließen kein übergeordnetes Panel mehr. Electron-Regression prüft DOM-Treffertests im Abstand, verzögerte Ein-/Austritte, Klick, Fokus und Escape bei 850 und 600 Pixel Fensterbreite. Kein Release beauftragt.
|
- Nach `2.1.49`, noch nicht veröffentlicht: Backup-Untermenü erhält eine durchgängige Hover-Fläche über den sichtbaren Abstand und 250 ms abbrechbare Schließverzögerung. Hover plus Klick bleibt offen, erneutes Betreten startet keine neue Öffnungsanimation; Tastaturfokus hält das Untermenü offen. Pfeil und Pfeiltasten folgen der linken Öffnungsrichtung, Escape schließt nur die aktuelle Untermenüebene. Fremde `animationend`-Ereignisse schließen kein übergeordnetes Panel mehr. Electron-Regression prüft DOM-Treffertests im Abstand, verzögerte Ein-/Austritte, Klick, Fokus und Escape bei 850 und 600 Pixel Fensterbreite. Kein Release beauftragt.
|
||||||
@@ -91,6 +92,7 @@ npm audit --omit=dev
|
|||||||
|
|
||||||
## Zuletzt verifiziert
|
## Zuletzt verifiziert
|
||||||
|
|
||||||
|
- Getrennte Online-Backup-Module: 839 Haupttests, 18 Servertests und Lint erfolgreich. Echtes Modulmarkup in Electron bei drei Fensterbreiten geprüft; Entwicklerversion nach Renderer-Änderung mit neuem Prozess sichtbar bestätigt. Noch kein Release.
|
||||||
- Gültigkeitsdauer-Layout: neue Electron-Regression erfolgreich, Screenshot visuell geprüft, Lint und 18 Servertests erfolgreich. Hauptlauf 838/839 erfolgreich: Menü-Fokustest reagierte einmal zu früh auf asynchronen Fokus. Test wartet jetzt begrenzt auf den tatsächlichen Fokus statt pauschal 240 ms; kompletter Wiederholungslauf der betroffenen Datei 25/25 erfolgreich. Kein Release erstellt.
|
- Gültigkeitsdauer-Layout: neue Electron-Regression erfolgreich, Screenshot visuell geprüft, Lint und 18 Servertests erfolgreich. Hauptlauf 838/839 erfolgreich: Menü-Fokustest reagierte einmal zu früh auf asynchronen Fokus. Test wartet jetzt begrenzt auf den tatsächlichen Fokus statt pauschal 240 ms; kompletter Wiederholungslauf der betroffenen Datei 25/25 erfolgreich. Kein Release erstellt.
|
||||||
- Backup-Untermenü nach `2.1.49`: 838 Haupttests, 18 Servertests und Lint erfolgreich. Gezielter Electron-Test nach abschließender Fokuskorrektur erneut erfolgreich; ein Mausklick auf den Trigger hält das Menü beim Verlassen nicht unbeabsichtigt offen. Änderungen noch nicht veröffentlicht.
|
- Backup-Untermenü nach `2.1.49`: 838 Haupttests, 18 Servertests und Lint erfolgreich. Gezielter Electron-Test nach abschließender Fokuskorrektur erneut erfolgreich; ein Mausklick auf den Trigger hält das Menü beim Verlassen nicht unbeabsichtigt offen. Änderungen noch nicht veröffentlicht.
|
||||||
- Release `2.1.49`: Titel, Tags, englischer GitHub- und deutscher Forgejo-Changelog, jeweils vier Assets und Update-Metadaten geprüft. Alle acht veröffentlichten Dateien erneut heruntergeladen und Größe sowie SHA-512 mit lokalen Dateien verglichen. Echter Updater erkennt `2.1.49` ausgehend von `2.1.48` und akzeptiert englische Hinweise sowie Forgejo-Manifest. Öffentlicher Quellcheck einschließlich Screenshots erfolgreich (164 Dateien). Keine produktive Serveränderung erforderlich.
|
- Release `2.1.49`: Titel, Tags, englischer GitHub- und deutscher Forgejo-Changelog, jeweils vier Assets und Update-Metadaten geprüft. Alle acht veröffentlichten Dateien erneut heruntergeladen und Größe sowie SHA-512 mit lokalen Dateien verglichen. Echter Updater erkennt `2.1.49` ausgehend von `2.1.48` und akzeptiert englische Hinweise sowie Forgejo-Manifest. Öffentlicher Quellcheck einschließlich Screenshots erfolgreich (164 Dateien). Keine produktive Serveränderung erforderlich.
|
||||||
|
|||||||
+21
-15
@@ -6609,21 +6609,8 @@ function renderSettings() {
|
|||||||
<h3 id="onlineBackupHeading">Verschlüsseltes Online-Backup</h3>
|
<h3 id="onlineBackupHeading">Verschlüsseltes Online-Backup</h3>
|
||||||
<p>Die Verschlüsselung findet ausschließlich auf diesem Gerät statt. Der Server speichert nur verschlüsselte Daten.</p>
|
<p>Die Verschlüsselung findet ausschließlich auf diesem Gerät statt. Der Server speichert nur verschlüsselte Daten.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="online-backup-key-row" data-settings-search-entry data-settings-search-section="Online-Backup">
|
<section class="online-backup-module" aria-labelledby="onlineBackupCreateHeading">
|
||||||
<label for="onlineBackupKeyInput">Schlüssel importieren</label>
|
<h4 id="onlineBackupCreateHeading">Schlüssel erstellen</h4>
|
||||||
<input type="password" class="key-input" id="onlineBackupKeyInput" maxlength="75" pattern="MHU2-[A-Za-z0-9_-]{70}" spellcheck="false" autocomplete="off" placeholder="MHU2-…">
|
|
||||||
<button class="btn btn-secondary" id="restoreOnlineBackupBtn" disabled>Importieren</button>
|
|
||||||
</div>
|
|
||||||
<p class="online-backup-warning">Behandle den Schlüssel wie ein Passwort. Wer ihn besitzt, kann die verschlüsselten Einstellungen entschlüsseln.</p>
|
|
||||||
<section class="online-backup-managed" aria-labelledby="managedOnlineBackupHeading" data-settings-search-entry data-settings-search-section="Online-Backup" data-settings-search-label="Online-Backups verwalten" data-settings-search-control="managedOnlineBackupHeading">
|
|
||||||
<h4 id="managedOnlineBackupHeading" tabindex="-1">Auf diesem Gerät erstellt</h4>
|
|
||||||
<div class="online-backup-managed-list" id="managedOnlineBackupList"></div>
|
|
||||||
<div class="online-backup-refresh-status" id="managedOnlineBackupRefreshStatus" role="status" hidden>
|
|
||||||
<span id="managedOnlineBackupRefreshMessage"></span>
|
|
||||||
<button class="btn btn-secondary" id="reloadManagedOnlineBackupsBtn" type="button">Erneut laden</button>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<div class="online-backup-status" id="onlineBackupStatus" role="status" aria-live="polite"></div>
|
|
||||||
<footer class="online-backup-footer" data-settings-search-entry data-settings-search-section="Online-Backup" data-settings-search-label="Neuen Schlüssel erzeugen">
|
<footer class="online-backup-footer" data-settings-search-entry data-settings-search-section="Online-Backup" data-settings-search-label="Neuen Schlüssel erzeugen">
|
||||||
<div class="online-backup-retention-field">
|
<div class="online-backup-retention-field">
|
||||||
<label for="onlineBackupRetentionSelect">Gültigkeitsdauer</label>
|
<label for="onlineBackupRetentionSelect">Gültigkeitsdauer</label>
|
||||||
@@ -6640,6 +6627,25 @@ function renderSettings() {
|
|||||||
<button class="btn btn-primary" id="createOnlineBackupBtn">Neuen Schlüssel erzeugen</button>
|
<button class="btn btn-primary" id="createOnlineBackupBtn">Neuen Schlüssel erzeugen</button>
|
||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
|
<section class="online-backup-module" aria-labelledby="onlineBackupImportHeading">
|
||||||
|
<h4 id="onlineBackupImportHeading">Schlüssel importieren</h4>
|
||||||
|
<div class="online-backup-key-row" data-settings-search-entry data-settings-search-section="Online-Backup" data-settings-search-label="Schlüssel importieren">
|
||||||
|
<label for="onlineBackupKeyInput">Online-Schlüssel</label>
|
||||||
|
<input type="password" class="key-input" id="onlineBackupKeyInput" maxlength="75" pattern="MHU2-[A-Za-z0-9_-]{70}" spellcheck="false" autocomplete="off" placeholder="MHU2-…">
|
||||||
|
<button class="btn btn-secondary" id="restoreOnlineBackupBtn" disabled>Importieren</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<p class="online-backup-warning">Behandle den Schlüssel wie ein Passwort. Wer ihn besitzt, kann die verschlüsselten Einstellungen entschlüsseln.</p>
|
||||||
|
<div class="online-backup-status" id="onlineBackupStatus" role="status" aria-live="polite"></div>
|
||||||
|
<section class="online-backup-module online-backup-managed" aria-labelledby="managedOnlineBackupHeading" data-settings-search-entry data-settings-search-section="Online-Backup" data-settings-search-label="Online-Backups verwalten" data-settings-search-control="managedOnlineBackupHeading">
|
||||||
|
<h4 id="managedOnlineBackupHeading" tabindex="-1">Auf diesem Gerät erstellt</h4>
|
||||||
|
<div class="online-backup-managed-list" id="managedOnlineBackupList"></div>
|
||||||
|
<div class="online-backup-refresh-status" id="managedOnlineBackupRefreshStatus" role="status" hidden>
|
||||||
|
<span id="managedOnlineBackupRefreshMessage"></span>
|
||||||
|
<button class="btn btn-secondary" id="reloadManagedOnlineBackupsBtn" type="button">Erneut laden</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
<div class="settings-section-label">Lokales Datei-Backup</div>
|
<div class="settings-section-label">Lokales Datei-Backup</div>
|
||||||
<div class="settings-row local-backup-password-row">
|
<div class="settings-row local-backup-password-row">
|
||||||
<div class="settings-copy">
|
<div class="settings-copy">
|
||||||
|
|||||||
@@ -380,6 +380,8 @@
|
|||||||
['Verschlüsseltes Online-Backup', 'Encrypted online backup'],
|
['Verschlüsseltes Online-Backup', 'Encrypted online backup'],
|
||||||
['Die Verschlüsselung findet ausschließlich auf diesem Gerät statt. Der Server speichert nur verschlüsselte Daten.', 'Encryption takes place only on this device. The server stores encrypted data only.'],
|
['Die Verschlüsselung findet ausschließlich auf diesem Gerät statt. Der Server speichert nur verschlüsselte Daten.', 'Encryption takes place only on this device. The server stores encrypted data only.'],
|
||||||
['Neuen Schlüssel erzeugen', 'Generate new key'],
|
['Neuen Schlüssel erzeugen', 'Generate new key'],
|
||||||
|
['Schlüssel erstellen', 'Create key'],
|
||||||
|
['Online-Schlüssel', 'Online key'],
|
||||||
['Gültigkeitsdauer', 'Validity period'],
|
['Gültigkeitsdauer', 'Validity period'],
|
||||||
['24 Stunden', '24 hours'],
|
['24 Stunden', '24 hours'],
|
||||||
['3 Tage', '3 days'],
|
['3 Tage', '3 days'],
|
||||||
|
|||||||
@@ -2250,6 +2250,22 @@ select.hs-input { max-width: none; width: auto; min-width: 140px; }
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.online-backup-module {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 16px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.online-backup-module h4 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
.online-backup-retention-field {
|
.online-backup-retention-field {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 150px minmax(210px, 300px);
|
grid-template-columns: 150px minmax(210px, 300px);
|
||||||
|
|||||||
@@ -180,12 +180,17 @@ app.whenReady().then(async () => {
|
|||||||
const root=process.env.MHU_RETENTION_ROOT;
|
const root=process.env.MHU_RETENTION_ROOT;
|
||||||
const css=fs.readFileSync(path.join(root,'renderer/styles.css'),'utf8');
|
const css=fs.readFileSync(path.join(root,'renderer/styles.css'),'utf8');
|
||||||
const source=fs.readFileSync(path.join(root,'renderer/app.js'),'utf8');
|
const source=fs.readFileSync(path.join(root,'renderer/app.js'),'utf8');
|
||||||
const footer=source.match(/<footer class="online-backup-footer"[\\s\\S]*?<\\/footer>/)[0];
|
const panel=source.slice(source.indexOf('<section class="online-backup-panel"'),source.indexOf('<div class="settings-section-label">Lokales Datei-Backup</div>'));
|
||||||
const win=new BrowserWindow({show:false,width:1000,height:500,webPreferences:{backgroundThrottling:false}});
|
const win=new BrowserWindow({show:false,width:1000,height:800,webPreferences:{backgroundThrottling:false}});
|
||||||
const wc=win.webContents;
|
const wc=win.webContents;
|
||||||
for(const width of [1000,600,360]) {
|
for(const width of [1000,600,360]) {
|
||||||
win.setContentSize(width,500);
|
win.setContentSize(width,800);
|
||||||
await wc.loadURL('data:text/html;charset=utf-8,'+encodeURIComponent('<style>'+css+'</style><main id="settings-view" style="display:block;padding:16px;width:100%"><section class="online-backup-panel"><h3>Verschlüsseltes Online-Backup</h3><div class="online-backup-key-row"><label>Schlüssel importieren</label><input class="key-input"><button class="btn btn-secondary">Importieren</button></div><div class="online-backup-status"></div>'+footer+'</section></main>'));
|
await wc.loadURL('data:text/html;charset=utf-8,'+encodeURIComponent('<style>'+css+'</style><main id="settings-view" style="display:block;padding:16px;width:100%">'+panel+'</main>'));
|
||||||
|
assert.deepEqual(await wc.executeJavaScript('Array.from(document.querySelectorAll(".online-backup-module")).map(module=>({heading:module.getAttribute("aria-labelledby"),create:!!module.querySelector("#createOnlineBackupBtn"),import:!!module.querySelector("#restoreOnlineBackupBtn"),manage:!!module.querySelector("#managedOnlineBackupList")}))'),[
|
||||||
|
{heading:'onlineBackupCreateHeading',create:true,import:false,manage:false},
|
||||||
|
{heading:'onlineBackupImportHeading',create:false,import:true,manage:false},
|
||||||
|
{heading:'managedOnlineBackupHeading',create:false,import:false,manage:true}
|
||||||
|
]);
|
||||||
const layout=await wc.executeJavaScript('(() => { const s=document.querySelector("select"), b=document.querySelector("footer button"), l=document.querySelector(".online-backup-retention-field label"), i=document.querySelector(".key-input"); const rect=e=>{const r=e.getBoundingClientRect();return {left:r.left,right:r.right,top:r.top,bottom:r.bottom,height:r.height}}; return {select:rect(s),button:rect(b),input:rect(i),labelFont:getComputedStyle(l).fontSize,selectFont:getComputedStyle(s).fontSize,buttonFont:getComputedStyle(b).fontSize,arrowRight:getComputedStyle(s.parentElement,"::after").right,empty:getComputedStyle(document.querySelector(".online-backup-status")).display,scroll:document.documentElement.scrollWidth,viewport:innerWidth}; })()');
|
const layout=await wc.executeJavaScript('(() => { const s=document.querySelector("select"), b=document.querySelector("footer button"), l=document.querySelector(".online-backup-retention-field label"), i=document.querySelector(".key-input"); const rect=e=>{const r=e.getBoundingClientRect();return {left:r.left,right:r.right,top:r.top,bottom:r.bottom,height:r.height}}; return {select:rect(s),button:rect(b),input:rect(i),labelFont:getComputedStyle(l).fontSize,selectFont:getComputedStyle(s).fontSize,buttonFont:getComputedStyle(b).fontSize,arrowRight:getComputedStyle(s.parentElement,"::after").right,empty:getComputedStyle(document.querySelector(".online-backup-status")).display,scroll:document.documentElement.scrollWidth,viewport:innerWidth}; })()');
|
||||||
assert.equal(layout.select.height,40);
|
assert.equal(layout.select.height,40);
|
||||||
assert.equal(layout.button.height,40);
|
assert.equal(layout.button.height,40);
|
||||||
|
|||||||
Reference in New Issue
Block a user