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
75 lines
2.9 KiB
JavaScript
75 lines
2.9 KiB
JavaScript
// 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);
|