diff --git a/uiserver/src/components/ViewManager.js b/uiserver/src/components/ViewManager.js index 103fad0..0c7691d 100644 --- a/uiserver/src/components/ViewManager.js +++ b/uiserver/src/components/ViewManager.js @@ -558,9 +558,7 @@ class ViewManager extends Component { ); })} - - 📊 Current outputs: {Object.entries(this.state.outputValues).filter(([k, v]) => v > 0).map(([k, v]) => `${k}=${v}`).join(', ') || 'all off'} - + )} diff --git a/uiserver/webpack.config.js b/uiserver/webpack.config.js index bf6f918..a352323 100644 --- a/uiserver/webpack.config.js +++ b/uiserver/webpack.config.js @@ -18,6 +18,29 @@ let db; try { db = new Database(dbPath); console.log(`[UI Server] Connected to database at ${dbPath}`); + + // Create changelog table + db.exec(` + CREATE TABLE IF NOT EXISTS changelog ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + date TEXT NOT NULL, + user TEXT, + text TEXT NOT NULL + ) + `); + + // Helper to insert changelog entry + global.insertChangelog = (user, text) => { + try { + if (!db) return; + const stmt = db.prepare('INSERT INTO changelog (date, user, text) VALUES (?, ?, ?)'); + stmt.run(new Date().toISOString(), user || 'system', text); + console.log(`[Changelog] ${user || 'system'}: ${text}`); + } catch (err) { + console.error('[Changelog] Error inserting entry:', err.message); + } + }; + } catch (err) { console.error(`[UI Server] Failed to connect to database at ${dbPath}:`, err.message); } @@ -655,6 +678,7 @@ module.exports = { try { const stmt = db.prepare('INSERT INTO views (name, config, created_by) VALUES (?, ?, ?)'); const info = stmt.run(name, JSON.stringify(config), req.user.id); + global.insertChangelog(req.user.username, `Created view "${name}"`); res.json({ id: info.lastInsertRowid, name, config }); } catch (err) { res.status(500).json({ error: err.message }); @@ -698,8 +722,11 @@ module.exports = { app.delete('/api/views/:id', requireAdmin, (req, res) => { try { const stmt = db.prepare('DELETE FROM views WHERE id = ?'); + // Get name before delete for logging + const viewName = db.prepare('SELECT name FROM views WHERE id = ?').get(req.params.id)?.name || 'Unknown View'; const info = stmt.run(req.params.id); if (info.changes > 0) { + global.insertChangelog(req.user.username, `Deleted view "${viewName}" (ID: ${req.params.id})`); res.json({ success: true }); } else { res.status(404).json({ error: 'View not found' }); @@ -716,6 +743,7 @@ module.exports = { const stmt = db.prepare('UPDATE views SET name = ?, config = ? WHERE id = ?'); const info = stmt.run(name, JSON.stringify(config), req.params.id); if (info.changes > 0) { + global.insertChangelog(req.user.username, `Updated view "${name}" (ID: ${req.params.id})`); res.json({ id: req.params.id, name, config }); } else { res.status(404).json({ error: 'View not found' }); @@ -871,6 +899,7 @@ module.exports = { req.user?.id || null ); runRules(); // Trigger rules immediately + global.insertChangelog(req.user?.username || 'admin', `Created rule "${name}"`); res.json({ id: info.lastInsertRowid, name, type, enabled, conditions, action }); } catch (err) { res.status(500).json({ error: err.message }); @@ -895,6 +924,7 @@ module.exports = { ); if (info.changes > 0) { runRules(); // Trigger rules immediately + global.insertChangelog(req.user?.username || 'admin', `Updated rule "${name}" (ID: ${req.params.id})`); res.json({ id: req.params.id, name, type, enabled, conditions, action }); } else { res.status(404).json({ error: 'Rule not found' }); @@ -908,9 +938,12 @@ module.exports = { app.delete('/api/rules/:id', requireAdmin, (req, res) => { try { const stmt = db.prepare('DELETE FROM rules WHERE id = ?'); + // Get name before delete + const ruleName = db.prepare('SELECT name FROM rules WHERE id = ?').get(req.params.id)?.name || 'Unknown Rule'; const info = stmt.run(req.params.id); if (info.changes > 0) { runRules(); // Trigger rules immediately + global.insertChangelog(req.user?.username || 'admin', `Deleted rule "${ruleName}" (ID: ${req.params.id})`); res.json({ success: true }); } else { res.status(404).json({ error: 'Rule not found' }); diff --git a/verify_changelog.js b/verify_changelog.js new file mode 100644 index 0000000..4ff793d --- /dev/null +++ b/verify_changelog.js @@ -0,0 +1,48 @@ +const Database = require('better-sqlite3'); +const path = require('path'); + +const dbPath = path.resolve(__dirname, 'server/data/sensors.db'); +console.log(`Connecting to database at ${dbPath}`); +const db = new Database(dbPath); + +// 1. Verify Table Creation +console.log('Creating changelog table...'); +try { + db.exec(` + CREATE TABLE IF NOT EXISTS changelog ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + date TEXT NOT NULL, + user TEXT, + text TEXT NOT NULL + ) + `); + console.log('PASS: Table creation successful (or already exists)'); +} catch (err) { + console.error('FAIL: Table creation failed:', err.message); + process.exit(1); +} + +// 2. Verify Insert +console.log('Inserting test entry...'); +try { + const stmt = db.prepare('INSERT INTO changelog (date, user, text) VALUES (?, ?, ?)'); + const info = stmt.run(new Date().toISOString(), 'test_user', 'Test changelog entry'); + console.log(`PASS: Insert successful, ID: ${info.lastInsertRowid}`); +} catch (err) { + console.error('FAIL: Insert failed:', err.message); + process.exit(1); +} + +// 3. Verify Read +console.log('Reading entries...'); +try { + const rows = db.prepare('SELECT * FROM changelog ORDER BY id DESC LIMIT 5').all(); + console.table(rows); + if (rows.length > 0 && rows[0].user === 'test_user') { + console.log('PASS: Read verification successful'); + } else { + console.error('FAIL: Read verification failed or data mismatch'); + } +} catch (err) { + console.error('FAIL: Read failed:', err.message); +}