Add reset database script and frontend
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
125
inventory-server/scripts/reset-db.js
Normal file
125
inventory-server/scripts/reset-db.js
Normal file
@@ -0,0 +1,125 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const path = require('path');
|
||||
const dotenv = require('dotenv');
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
dotenv.config({ path: path.join(__dirname, '../.env') });
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
multipleStatements: true
|
||||
};
|
||||
|
||||
// Helper function to output progress in JSON format
|
||||
function outputProgress(data) {
|
||||
if (!data.status) {
|
||||
data = {
|
||||
status: 'running',
|
||||
...data
|
||||
};
|
||||
}
|
||||
console.log(JSON.stringify(data));
|
||||
}
|
||||
|
||||
async function resetDatabase() {
|
||||
outputProgress({
|
||||
operation: 'Starting database reset',
|
||||
message: 'Connecting to database...'
|
||||
});
|
||||
|
||||
const connection = await mysql.createConnection(dbConfig);
|
||||
|
||||
try {
|
||||
// Get list of all tables
|
||||
outputProgress({
|
||||
operation: 'Getting table list',
|
||||
message: 'Retrieving all table names...'
|
||||
});
|
||||
|
||||
const [tables] = await connection.query(
|
||||
'SELECT table_name FROM information_schema.tables WHERE table_schema = ?',
|
||||
[dbConfig.database]
|
||||
);
|
||||
|
||||
if (tables.length === 0) {
|
||||
outputProgress({
|
||||
operation: 'No tables found',
|
||||
message: 'Database is already empty'
|
||||
});
|
||||
} else {
|
||||
// Disable foreign key checks to allow dropping tables with dependencies
|
||||
await connection.query('SET FOREIGN_KEY_CHECKS = 0');
|
||||
|
||||
// Drop each table
|
||||
for (let i = 0; i < tables.length; i++) {
|
||||
const tableName = tables[i].TABLE_NAME;
|
||||
outputProgress({
|
||||
operation: 'Dropping tables',
|
||||
message: `Dropping table: ${tableName}`,
|
||||
current: i + 1,
|
||||
total: tables.length,
|
||||
percentage: (((i + 1) / tables.length) * 100).toFixed(1)
|
||||
});
|
||||
await connection.query(`DROP TABLE IF EXISTS \`${tableName}\``);
|
||||
}
|
||||
|
||||
// Re-enable foreign key checks
|
||||
await connection.query('SET FOREIGN_KEY_CHECKS = 1');
|
||||
}
|
||||
|
||||
// Run setup-db.js
|
||||
outputProgress({
|
||||
operation: 'Running database setup',
|
||||
message: 'Creating new tables...'
|
||||
});
|
||||
|
||||
const setupScript = path.join(__dirname, 'setup-db.js');
|
||||
const setupProcess = spawn('node', [setupScript]);
|
||||
|
||||
setupProcess.stdout.on('data', (data) => {
|
||||
const output = data.toString().trim();
|
||||
outputProgress({
|
||||
operation: 'Database setup',
|
||||
message: output
|
||||
});
|
||||
});
|
||||
|
||||
setupProcess.stderr.on('data', (data) => {
|
||||
const error = data.toString().trim();
|
||||
outputProgress({
|
||||
status: 'error',
|
||||
error
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
setupProcess.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(`Setup process exited with code ${code}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
outputProgress({
|
||||
status: 'complete',
|
||||
operation: 'Database reset complete',
|
||||
message: 'Database has been reset and tables recreated'
|
||||
});
|
||||
} catch (error) {
|
||||
outputProgress({
|
||||
status: 'error',
|
||||
error: error.message
|
||||
});
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
|
||||
// Run the reset
|
||||
resetDatabase();
|
||||
@@ -16,6 +16,7 @@ let importProgress = null;
|
||||
// SSE clients for progress updates
|
||||
const updateClients = new Set();
|
||||
const importClients = new Set();
|
||||
const resetClients = new Set();
|
||||
|
||||
// Helper to send progress to specific clients
|
||||
function sendProgressToClients(clients, progress) {
|
||||
@@ -85,6 +86,27 @@ router.get('/import/progress', (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/reset/progress', (req, res) => {
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive',
|
||||
'Access-Control-Allow-Origin': req.headers.origin || '*',
|
||||
'Access-Control-Allow-Credentials': 'true'
|
||||
});
|
||||
|
||||
// Send an initial message to test the connection
|
||||
res.write('data: {"status":"running","operation":"Initializing connection..."}\n\n');
|
||||
|
||||
// Add this client to the reset set
|
||||
resetClients.add(res);
|
||||
|
||||
// Remove client when connection closes
|
||||
req.on('close', () => {
|
||||
resetClients.delete(res);
|
||||
});
|
||||
});
|
||||
|
||||
// Debug endpoint to verify route registration
|
||||
router.get('/test', (req, res) => {
|
||||
console.log('CSV test endpoint hit');
|
||||
@@ -296,13 +318,26 @@ router.post('/cancel', (req, res) => {
|
||||
activeImport = null;
|
||||
importProgress = null;
|
||||
|
||||
// Notify all clients
|
||||
// Get the operation type from the request
|
||||
const { operation } = req.query;
|
||||
|
||||
// Send cancel message only to the appropriate client set
|
||||
const cancelMessage = {
|
||||
status: 'complete',
|
||||
operation: 'Operation cancelled'
|
||||
};
|
||||
sendProgressToClients(updateClients, cancelMessage);
|
||||
sendProgressToClients(importClients, cancelMessage);
|
||||
|
||||
switch (operation) {
|
||||
case 'update':
|
||||
sendProgressToClients(updateClients, cancelMessage);
|
||||
break;
|
||||
case 'import':
|
||||
sendProgressToClients(importClients, cancelMessage);
|
||||
break;
|
||||
case 'reset':
|
||||
sendProgressToClients(resetClients, cancelMessage);
|
||||
break;
|
||||
}
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
@@ -313,4 +348,90 @@ router.post('/cancel', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Route to reset database
|
||||
router.post('/reset', async (req, res) => {
|
||||
if (activeImport) {
|
||||
return res.status(409).json({ error: 'Import already in progress' });
|
||||
}
|
||||
|
||||
try {
|
||||
const scriptPath = path.join(__dirname, '..', '..', 'scripts', 'reset-db.js');
|
||||
|
||||
if (!require('fs').existsSync(scriptPath)) {
|
||||
return res.status(500).json({ error: 'Reset script not found' });
|
||||
}
|
||||
|
||||
activeImport = spawn('node', [scriptPath]);
|
||||
|
||||
activeImport.stdout.on('data', (data) => {
|
||||
const output = data.toString().trim();
|
||||
|
||||
try {
|
||||
// Try to parse as JSON
|
||||
const jsonData = JSON.parse(output);
|
||||
sendProgressToClients(resetClients, {
|
||||
status: 'running',
|
||||
...jsonData
|
||||
});
|
||||
} catch (e) {
|
||||
// If not JSON, send as plain progress
|
||||
sendProgressToClients(resetClients, {
|
||||
status: 'running',
|
||||
progress: output
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
activeImport.stderr.on('data', (data) => {
|
||||
const error = data.toString().trim();
|
||||
try {
|
||||
// Try to parse as JSON
|
||||
const jsonData = JSON.parse(error);
|
||||
sendProgressToClients(resetClients, {
|
||||
status: 'error',
|
||||
...jsonData
|
||||
});
|
||||
} catch {
|
||||
sendProgressToClients(resetClients, {
|
||||
status: 'error',
|
||||
error
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
activeImport.on('close', (code) => {
|
||||
// Don't treat cancellation (code 143/SIGTERM) as an error
|
||||
if (code === 0 || code === 143) {
|
||||
sendProgressToClients(resetClients, {
|
||||
status: 'complete',
|
||||
operation: code === 143 ? 'Operation cancelled' : 'Reset complete'
|
||||
});
|
||||
resolve();
|
||||
} else {
|
||||
const errorMsg = `Reset process exited with code ${code}`;
|
||||
sendProgressToClients(resetClients, {
|
||||
status: 'error',
|
||||
error: errorMsg
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
activeImport = null;
|
||||
importProgress = null;
|
||||
});
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Error resetting database:', error);
|
||||
activeImport = null;
|
||||
importProgress = null;
|
||||
sendProgressToClients(resetClients, {
|
||||
status: 'error',
|
||||
error: error.message
|
||||
});
|
||||
res.status(500).json({ error: 'Failed to reset database', details: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user