Add database cleanup feature to empty all sensor tables
Added a "Danger Zone" section on the database page that allows users to empty all sensor data tables while preserving configuration and timestamp tables. The feature includes: - New Python script (sqlite/empty_sensor_tables.py) to safely empty sensor tables - Backend endpoint in launcher.php (empty_sensor_tables) - Frontend UI with red warning card and confirmation dialog - Detailed feedback showing deleted record counts per table - i18n support for French and English Tables emptied: data_NPM, data_NPM_5channels, data_BME280, data_envea, data_WIND, data_MPPT, data_NOISE, modem_status Tables preserved: timestamp_table, config_table, envea_sondes_table, config_scripts_table 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -108,6 +108,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-5">
|
||||
<div class="card text-white bg-danger">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title" data-i18n="database.dangerZone">Zone dangereuse</h5>
|
||||
<p class="card-text" data-i18n="database.dangerWarning">Attention: Cette action est irréversible!</p>
|
||||
<button class="btn btn-dark" onclick="emptySensorTables()" data-i18n="database.emptyAllTables">Vider toutes les tables de capteurs</button>
|
||||
<small class="d-block mt-2" data-i18n="database.emptyTablesNote">Note: Les tables de configuration et horodatage seront préservées.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<div class="row mt-2">
|
||||
@@ -441,6 +452,74 @@ function downloadCSV(response, table) {
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
|
||||
// Function to empty all sensor tables
|
||||
function emptySensorTables() {
|
||||
// Show confirmation dialog
|
||||
const confirmed = confirm(
|
||||
"WARNING: This will permanently delete ALL sensor data from the database!\n\n" +
|
||||
"The following tables will be emptied:\n" +
|
||||
"- data_NPM\n" +
|
||||
"- data_NPM_5channels\n" +
|
||||
"- data_BME280\n" +
|
||||
"- data_envea\n" +
|
||||
"- data_WIND\n" +
|
||||
"- data_MPPT\n" +
|
||||
"- data_NOISE\n\n" +
|
||||
"Configuration and timestamp tables will be preserved.\n\n" +
|
||||
"Are you absolutely sure you want to continue?"
|
||||
);
|
||||
|
||||
if (!confirmed) {
|
||||
console.log("Empty sensor tables operation cancelled by user");
|
||||
return;
|
||||
}
|
||||
|
||||
// Show loading message
|
||||
const tableDataDiv = document.getElementById("table_data");
|
||||
tableDataDiv.innerHTML = '<div class="alert alert-info">Emptying sensor tables... Please wait...</div>';
|
||||
|
||||
// Make AJAX request to empty tables
|
||||
$.ajax({
|
||||
url: 'launcher.php?type=empty_sensor_tables',
|
||||
dataType: 'json',
|
||||
method: 'GET',
|
||||
success: function(response) {
|
||||
console.log("Empty sensor tables response:", response);
|
||||
|
||||
if (response.success) {
|
||||
// Show success message
|
||||
let message = '<div class="alert alert-success">';
|
||||
message += '<h5>Success!</h5>';
|
||||
message += '<p>' + response.message + '</p>';
|
||||
|
||||
if (response.tables_processed && response.tables_processed.length > 0) {
|
||||
message += '<p><strong>Tables emptied:</strong></p><ul>';
|
||||
response.tables_processed.forEach(table => {
|
||||
message += `<li>${table.name}: ${table.deleted} records deleted</li>`;
|
||||
});
|
||||
message += '</ul>';
|
||||
}
|
||||
|
||||
message += '</div>';
|
||||
tableDataDiv.innerHTML = message;
|
||||
} else {
|
||||
// Show error message
|
||||
tableDataDiv.innerHTML = `<div class="alert alert-danger">
|
||||
<h5>Error!</h5>
|
||||
<p>${response.message || response.error || 'Unknown error occurred'}</p>
|
||||
</div>`;
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('AJAX request failed:', status, error);
|
||||
tableDataDiv.innerHTML = `<div class="alert alert-danger">
|
||||
<h5>Error!</h5>
|
||||
<p>Failed to empty sensor tables: ${error}</p>
|
||||
</div>`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -88,7 +88,11 @@
|
||||
"timestampTable": "Timestamp Table",
|
||||
"downloadData": "Download Data",
|
||||
"startDate": "Start date:",
|
||||
"endDate": "End date:"
|
||||
"endDate": "End date:",
|
||||
"dangerZone": "Danger Zone",
|
||||
"dangerWarning": "Warning: This action is irreversible!",
|
||||
"emptyAllTables": "Empty all sensor tables",
|
||||
"emptyTablesNote": "Note: Configuration and timestamp tables will be preserved."
|
||||
},
|
||||
"logs": {
|
||||
"title": "The Log",
|
||||
|
||||
@@ -88,7 +88,11 @@
|
||||
"timestampTable": "Timestamp Table",
|
||||
"downloadData": "Télécharger les données",
|
||||
"startDate": "Date de début:",
|
||||
"endDate": "Date de fin:"
|
||||
"endDate": "Date de fin:",
|
||||
"dangerZone": "Zone dangereuse",
|
||||
"dangerWarning": "Attention: Cette action est irréversible!",
|
||||
"emptyAllTables": "Vider toutes les tables de capteurs",
|
||||
"emptyTablesNote": "Note: Les tables de configuration et horodatage seront préservées."
|
||||
},
|
||||
"logs": {
|
||||
"title": "Le journal",
|
||||
|
||||
@@ -1270,13 +1270,68 @@ if ($type == "toggle_systemd_service") {
|
||||
}
|
||||
}
|
||||
|
||||
// Empty all sensor tables (preserve config and timestamp tables)
|
||||
if ($type == "empty_sensor_tables") {
|
||||
try {
|
||||
// Execute the empty sensor tables script
|
||||
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/empty_sensor_tables.py 2>&1';
|
||||
$output = shell_exec($command);
|
||||
|
||||
// Try to extract JSON result from output
|
||||
$json_start = strpos($output, '[JSON_RESULT]');
|
||||
if ($json_start !== false) {
|
||||
$json_data = substr($output, $json_start + strlen('[JSON_RESULT]'));
|
||||
$json_data = trim($json_data);
|
||||
|
||||
// Find the first { and last }
|
||||
$first_brace = strpos($json_data, '{');
|
||||
$last_brace = strrpos($json_data, '}');
|
||||
|
||||
if ($first_brace !== false && $last_brace !== false) {
|
||||
$json_data = substr($json_data, $first_brace, $last_brace - $first_brace + 1);
|
||||
$result = json_decode($json_data, true);
|
||||
|
||||
if ($result !== null) {
|
||||
echo json_encode($result);
|
||||
} else {
|
||||
// JSON decode failed, return raw output
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Tables emptied',
|
||||
'output' => $output
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Tables emptied',
|
||||
'output' => $output
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
// No JSON marker found, return raw output
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Tables emptied',
|
||||
'output' => $output
|
||||
]);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Script execution failed: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
_____ ____ _ _ _
|
||||
| ____|_ ____ _____ __ _ | _ \ ___| |_ ___ ___| |_(_) ___ _ __
|
||||
| _| | '_ \ \ / / _ \/ _` | | | | |/ _ \ __/ _ \/ __| __| |/ _ \| '_ \
|
||||
_____ ____ _ _ _
|
||||
| ____|_ ____ _____ __ _ | _ \ ___| |_ ___ ___| |_(_) ___ _ __
|
||||
| _| | '_ \ \ / / _ \/ _` | | | | |/ _ \ __/ _ \/ __| __| |/ _ \| '_ \
|
||||
| |___| | | \ V / __/ (_| | | |_| | __/ || __/ (__| |_| | (_) | | | |
|
||||
|_____|_| |_|\_/ \___|\__,_| |____/ \___|\__\___|\___|\__|_|\___/|_| |_|
|
||||
|
||||
|
||||
*/
|
||||
|
||||
// Detect Envea devices on specified port
|
||||
|
||||
Reference in New Issue
Block a user