BUG-05: Speichern-Button weg, Save-Status-Indikator mit States
Der 'Speichern'-Button war redundant — debouncedSave() lief schon bei jedem Drop/Resize/Add/Delete. Klick auf den Button machte nur einen sofortigen POST statt 500ms-debounce. Verwirrend statt hilfreich. Fix: - Speichern-Button aus dem Toolbar entfernt. - Stattdessen: <div id='saveIndicator' data-state='idle'> mit .save-dot und .save-label — rechtsbündig im Toolbar (margin-left:auto). - States: idle | pending | saving | error (CSS-Data-Attr-basiert). - idle: grüner Punkt, 'Gespeichert' - pending: warn-gelber Punkt pulsiert, 'Ungespeichert…' (debouncedSave-Start) - saving: info-blauer Punkt pulsiert schneller, 'Speichern…' (saveLayout-Start) - error: alert-roter Punkt, 'Fehler: ...' (j.ok=false) - setSaveState(state, label?) als zentraler Helper. - saveLayout() macht jetzt success-toast weg — der Indicator reicht. - Fehlerfall: error-toast bleibt (kritisch, separat sichtbar). Vorteile: - Toolbar ist aufgeräumter, +Button ist eindeutig der primäre Action. - User sieht Save-Status ohne Klick auf irgendwas — visuelles Feedback für Auto-Save. - Fehler-State zeigt sofort 'Fehler: ...' mit Details. Beweis: tests/test_save_indicator.js (11/11 grün) 1. Speichern-Button entfernt 2. Save-Indicator #saveIndicator vorhanden 3. setSaveState() Funktion definiert 4. setSaveState setzt dataset.state 5. debouncedSave setzt pending-Status 6. saveLayout setzt saving am Anfang 7. saveLayout setzt idle bei Erfolg 8. saveLayout setzt error bei j.ok=false 9. CSS für alle 4 Indicator-States 10. Kein success-toast in saveLayout mehr 11. Save-Indicator rechtsbündig (margin-left:auto) Closes #7
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
// BUG-05 Test: Speichern-Button entfernt, Save-Indicator hinzugefügt.
|
||||
//
|
||||
// Erwartung:
|
||||
// 1) KEIN <button onclick="saveLayout()"> im Layout-Toolbar mehr
|
||||
// 2) NEUER #saveIndicator im Toolbar mit data-state="idle"
|
||||
// 3) setSaveState() existiert und akzeptiert (state, label?)
|
||||
// 4) setSaveState setzt el.dataset.state und label-Text
|
||||
// 5) debouncedSave setzt Status auf "pending" BEVOR es speichert
|
||||
// 6) saveLayout setzt Status auf "saving" am Anfang, "idle" am Ende (success)
|
||||
// 7) saveLayout setzt Status auf "error" bei j.ok=false
|
||||
// 8) CSS: .save-indicator[data-state="..."] für idle/pending/saving/error
|
||||
|
||||
const fs = require('fs');
|
||||
const html = fs.readFileSync('templates/index.html', 'utf8');
|
||||
const js = html.match(/<script>\s*\n([\s\S]*?)<\/script>/)[1];
|
||||
const css = html.match(/<style>([\s\S]*?)<\/style>/g).join('\n');
|
||||
|
||||
function check(name, fn) {
|
||||
const r = fn();
|
||||
console.log((r ? '✓' : '✗') + ' ' + name);
|
||||
if (!r) process.exitCode = 1;
|
||||
}
|
||||
|
||||
// 1) Kein Speichern-Button mehr
|
||||
check('Speichern-Button entfernt', () => {
|
||||
// Suchen wir den toolbar-Bereich
|
||||
const toolbarMatch = html.match(/<div class="layout-toolbar">([\s\S]*?)<\/div>\s*<div id="gridPreview"/);
|
||||
if (!toolbarMatch) return false; // Struktur geändert?
|
||||
return !/onclick="saveLayout\(\)"/.test(toolbarMatch[1]);
|
||||
});
|
||||
|
||||
// 2) Save-Indicator
|
||||
check('Save-Indicator #saveIndicator vorhanden', () =>
|
||||
/id="saveIndicator"/.test(html) && /data-state="idle"/.test(html));
|
||||
|
||||
// 3) setSaveState existiert
|
||||
check('setSaveState() Funktion definiert', () =>
|
||||
/function setSaveState\(/.test(js));
|
||||
|
||||
// 4) setSaveState setzt state und label
|
||||
check('setSaveState setzt dataset.state', () =>
|
||||
/setSaveState[\s\S]{0,300}dataset\.state/.test(js));
|
||||
|
||||
// 5) debouncedSave setzt pending
|
||||
check('debouncedSave setzt pending-Status', () =>
|
||||
/function debouncedSave\(\)\s*\{[^}]*setSaveState\(['"]pending['"]/.test(js));
|
||||
|
||||
// 6) saveLayout setzt saving→idle
|
||||
check('saveLayout setzt saving am Anfang', () =>
|
||||
/async function saveLayout\(\)[\s\S]{0,300}setSaveState\(['"]saving['"]/.test(js));
|
||||
|
||||
check('saveLayout setzt idle bei Erfolg', () =>
|
||||
/saveLayout[\s\S]{0,800}setSaveState\(['"]idle['"]/.test(js));
|
||||
|
||||
// 7) saveLayout setzt error bei Fehler
|
||||
check('saveLayout setzt error bei j.ok=false', () =>
|
||||
/!j\.ok[\s\S]{0,300}setSaveState\(['"]error['"]/.test(js));
|
||||
|
||||
// 8) CSS für alle States
|
||||
const cssStates = ['idle', 'pending', 'saving', 'error'].map(s =>
|
||||
new RegExp(`\\.save-indicator\\[data-state="${s}"\\]`));
|
||||
check('CSS für alle 4 Indicator-States', () =>
|
||||
cssStates.every(re => re.test(css)));
|
||||
|
||||
// 9) delete success-toast raus (Indicator reicht)
|
||||
check('Kein success-toast in saveLayout mehr', () =>
|
||||
!/function saveLayout[\s\S]{0,1000}toast\([^)]*['"]success['"][^)]*['"]Layout gespeichert['"]/.test(js));
|
||||
|
||||
// 10) margin-left:auto für rechtsbündige Position
|
||||
check('Save-Indicator rechtsbündig (margin-left:auto)', () =>
|
||||
/\.save-indicator\s*\{[^}]*margin-left:\s*auto/.test(css));
|
||||
|
||||
console.log('\n========');
|
||||
process.exit(process.exitCode || 0);
|
||||
Reference in New Issue
Block a user