diff --git a/public/js/app.js b/public/js/app.js
index e3be841..44a1374 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -508,7 +508,13 @@ const App = {
/** Ensure lookup data is loaded (cached) */
async ensureLookups(forceRefresh = false) {
- if (this.lookupsLoaded && !forceRefresh) return;
+ if (this.lookupsLoaded && !forceRefresh) {
+ const freshConfig = await this.api('/api/config').catch(() => null);
+ if (freshConfig && this.lookups) {
+ this.lookups.config = freshConfig;
+ }
+ return;
+ }
// Check localStorage cache first if not forcing refresh
if (!forceRefresh) {
@@ -519,6 +525,10 @@ const App = {
if (!this.lookups.config || this.lookups.config.autoTimeMinHour === undefined || !this.lookups.customerUsers || !this.lookups.customer_users_version_1) {
throw new Error('Outdated config cache (missing autoTimeMinHour or customerUsers)');
}
+ const freshConfig = await this.api('/api/config').catch(() => null);
+ if (freshConfig) {
+ this.lookups.config = freshConfig;
+ }
this.lookupsLoaded = true;
return;
} catch (e) {
diff --git a/public/js/views/envConfig.js b/public/js/views/envConfig.js
index 835683d..5f1e641 100644
--- a/public/js/views/envConfig.js
+++ b/public/js/views/envConfig.js
@@ -125,6 +125,9 @@ const EnvConfigView = {
#${h.id}
+
${isCurrentVersion ? `
Attuale` : ''}
${formattedDate}
@@ -176,6 +179,11 @@ const EnvConfigView = {
this.currentContent = content;
this.history = res.history || [];
+ try {
+ await App.ensureLookups(true);
+ App.updateDailyTimer();
+ } catch (_) {}
+
// Re-render history panel
const historyListDiv = document.getElementById('env-history-list');
if (historyListDiv) {
@@ -237,6 +245,11 @@ const EnvConfigView = {
this.currentContent = res.content || record.content;
this.history = res.history || [];
+ try {
+ await App.ensureLookups(true);
+ App.updateDailyTimer();
+ } catch (_) {}
+
const editorTextarea = document.getElementById('env-editor-content');
if (editorTextarea) {
editorTextarea.value = this.currentContent;
@@ -254,6 +267,41 @@ const EnvConfigView = {
}
});
});
+
+ // Delete buttons
+ document.querySelectorAll('.env-history-delete-btn').forEach(btn => {
+ btn.addEventListener('click', async () => {
+ const id = parseInt(btn.dataset.id, 10);
+ const record = this.history.find(h => h.id === id);
+ if (!record) return;
+
+ const confirmed = await App.confirm(
+ `Eliminazione Versione #${record.id}`,
+ `Sei sicuro di voler eliminare permanentemente la versione #${record.id} dallo storico?`
+ );
+
+ if (!confirmed) return;
+
+ try {
+ btn.disabled = true;
+ const res = await App.api(`/api/config/env/history/${id}`, {
+ method: 'DELETE'
+ });
+
+ Toast.success(res.message || `Versione #${id} eliminata dallo storico!`);
+ this.history = res.history || [];
+
+ const historyListDiv = document.getElementById('env-history-list');
+ if (historyListDiv) {
+ historyListDiv.innerHTML = this.renderHistoryList();
+ this.bindHistoryEvents();
+ }
+ } catch (err) {
+ Toast.error('Errore durante l\'eliminazione dello storico: ' + err.message);
+ btn.disabled = false;
+ }
+ });
+ });
},
showPreviewModal(record) {
diff --git a/routes/config.js b/routes/config.js
index 2a81df7..49f88b7 100644
--- a/routes/config.js
+++ b/routes/config.js
@@ -67,6 +67,7 @@ router.post('/env', async (req, res) => {
// Write updated content to disk
fs.writeFileSync(envPath, content, 'utf8');
+ try { require('dotenv').config({ path: envPath, override: true }); } catch (_) {}
// Save snapshot in history table
const info = db.prepare(`
@@ -112,6 +113,7 @@ router.post('/env/restore/:history_id', async (req, res) => {
// Write snapshot content to disk
fs.writeFileSync(envPath, record.content, 'utf8');
+ try { require('dotenv').config({ path: envPath, override: true }); } catch (_) {}
// Insert new history record documenting the restore operation
const restoreNote = `Ripristinato alla versione #${record.id} del ${record.created_at}`;
@@ -144,4 +146,41 @@ router.post('/env/restore/:history_id', async (req, res) => {
}
});
+// DELETE /api/config/env/history/:id — Delete a specific .env history entry
+router.delete('/env/history/:id', async (req, res) => {
+ try {
+ const { id } = req.params;
+ const operatorId = parseInt(req.headers['x-agent-id'] || '1', 10);
+ const agentName = await resolveAgentName(operatorId);
+
+ const record = db.prepare('SELECT * FROM env_history WHERE id = ?').get(id);
+ if (!record) {
+ return res.status(404).json({ error: 'Versione di storico non trovata' });
+ }
+
+ db.prepare('DELETE FROM env_history WHERE id = ?').run(id);
+
+ logAttivita({
+ agente_id: operatorId,
+ agente_nome: agentName,
+ titolo_azione: 'Eliminazione Storico .env',
+ azione: { deleted_history_id: id },
+ esito: 'successo',
+ });
+
+ const history = db.prepare(`
+ SELECT * FROM env_history ORDER BY id DESC LIMIT 100
+ `).all();
+
+ res.json({
+ success: true,
+ message: `Versione #${id} dello storico eliminata con successo!`,
+ history,
+ });
+ } catch (err) {
+ console.error('Error deleting .env history entry:', err);
+ res.status(500).json({ error: 'Errore durante l\'eliminazione della versione dello storico', message: err.message });
+ }
+});
+
module.exports = router;
diff --git a/routes/lookups.js b/routes/lookups.js
index 1be8104..f79b01c 100644
--- a/routes/lookups.js
+++ b/routes/lookups.js
@@ -147,7 +147,7 @@ router.get('/config', async (req, res) => {
res.json({
defaultAgentLogin: process.env.OTRS_API_USER || '',
- dailyTargetTime: parseInt(process.env.DAILY_TARGET_TIME, 10) || 480,
+ dailyTargetTime: parseInt(process.env.DAILY_TARGET_TIME || process.env.daily_target_time || process.env.Daily_Target_Time, 10) || 480,
phraseThreshold: parseInt(process.env.PHRASE_THRESHOLD, 10) || 70,
autoTimeMinHour: process.env.AUTO_TIME_MIN_HOUR || '18:00',
helpdeskEmail: process.env.OTRS_MAIL_BCC || '',
diff --git a/routes/tickets.js b/routes/tickets.js
index 4f0c504..e5c04ba 100644
--- a/routes/tickets.js
+++ b/routes/tickets.js
@@ -2140,7 +2140,7 @@ router.get('/time-accounting/summary', async (req, res) => {
}
});
- const targetMinutes = parseInt(process.env.DAILY_TARGET_TIME, 10) || 480;
+ const targetMinutes = parseInt(process.env.DAILY_TARGET_TIME || process.env.daily_target_time || process.env.Daily_Target_Time, 10) || 480;
const workDaysRaw = process.env.WORK_DAYS || '1,2,3,4,5';
const workDays = workDaysRaw.split(',').map(x => parseInt(x.trim(), 10)).filter(x => !isNaN(x));
@@ -2265,7 +2265,7 @@ router.post('/auto-time', async (req, res) => {
await client.query('BEGIN');
// 1. Calculate remaining time
- const targetTime = parseInt(process.env.DAILY_TARGET_TIME, 10) || 480;
+ const targetTime = parseInt(process.env.DAILY_TARGET_TIME || process.env.daily_target_time || process.env.Daily_Target_Time, 10) || 480;
const timeTodayRes = await client.query(
`SELECT COALESCE(SUM(time_unit), 0) AS total_today
FROM time_accounting