Fix frontend reset script and visual tweaks
This commit is contained in:
@@ -57,25 +57,36 @@ async function fullReset() {
|
|||||||
message: 'Step 1/3: Resetting database...'
|
message: 'Step 1/3: Resetting database...'
|
||||||
});
|
});
|
||||||
await runScript(path.join(__dirname, 'reset-db.js'));
|
await runScript(path.join(__dirname, 'reset-db.js'));
|
||||||
|
outputProgress({
|
||||||
|
status: 'complete',
|
||||||
|
operation: 'Database reset step complete',
|
||||||
|
message: 'Database reset finished, moving to import...'
|
||||||
|
});
|
||||||
|
|
||||||
// Step 2: Import from Production
|
// Step 2: Import from Production
|
||||||
outputProgress({
|
outputProgress({
|
||||||
operation: 'Database reset complete',
|
operation: 'Starting import',
|
||||||
message: 'Step 2/3: Importing from production...'
|
message: 'Step 2/3: Importing from production...'
|
||||||
});
|
});
|
||||||
await runScript(path.join(__dirname, 'import-from-prod.js'));
|
await runScript(path.join(__dirname, 'import-from-prod.js'));
|
||||||
|
outputProgress({
|
||||||
|
status: 'complete',
|
||||||
|
operation: 'Import step complete',
|
||||||
|
message: 'Import finished, moving to metrics calculation...'
|
||||||
|
});
|
||||||
|
|
||||||
// Step 3: Calculate Metrics
|
// Step 3: Calculate Metrics
|
||||||
outputProgress({
|
outputProgress({
|
||||||
operation: 'Import complete',
|
operation: 'Starting metrics calculation',
|
||||||
message: 'Step 3/3: Calculating metrics...'
|
message: 'Step 3/3: Calculating metrics...'
|
||||||
});
|
});
|
||||||
await runScript(path.join(__dirname, 'calculate-metrics.js'));
|
await runScript(path.join(__dirname, 'calculate-metrics.js'));
|
||||||
|
|
||||||
|
// Final completion message
|
||||||
outputProgress({
|
outputProgress({
|
||||||
status: 'complete',
|
status: 'complete',
|
||||||
operation: 'Full reset complete',
|
operation: 'Full reset complete',
|
||||||
message: 'Successfully completed database reset, import, and metrics calculation'
|
message: 'Successfully completed all steps: database reset, import, and metrics calculation'
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
outputProgress({
|
outputProgress({
|
||||||
|
|||||||
@@ -57,18 +57,29 @@ async function fullUpdate() {
|
|||||||
message: 'Step 1/2: Importing from production...'
|
message: 'Step 1/2: Importing from production...'
|
||||||
});
|
});
|
||||||
await runScript(path.join(__dirname, 'import-from-prod.js'));
|
await runScript(path.join(__dirname, 'import-from-prod.js'));
|
||||||
|
outputProgress({
|
||||||
|
status: 'complete',
|
||||||
|
operation: 'Import step complete',
|
||||||
|
message: 'Import finished, moving to metrics calculation...'
|
||||||
|
});
|
||||||
|
|
||||||
// Step 2: Calculate Metrics
|
// Step 2: Calculate Metrics
|
||||||
outputProgress({
|
outputProgress({
|
||||||
operation: 'Import complete',
|
operation: 'Starting metrics calculation',
|
||||||
message: 'Step 2/2: Calculating metrics...'
|
message: 'Step 2/2: Calculating metrics...'
|
||||||
});
|
});
|
||||||
await runScript(path.join(__dirname, 'calculate-metrics.js'));
|
await runScript(path.join(__dirname, 'calculate-metrics.js'));
|
||||||
|
outputProgress({
|
||||||
|
status: 'complete',
|
||||||
|
operation: 'Metrics step complete',
|
||||||
|
message: 'Metrics calculation finished'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Final completion message
|
||||||
outputProgress({
|
outputProgress({
|
||||||
status: 'complete',
|
status: 'complete',
|
||||||
operation: 'Full update complete',
|
operation: 'Full update complete',
|
||||||
message: 'Successfully completed import and metrics calculation'
|
message: 'Successfully completed all steps: import and metrics calculation'
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
outputProgress({
|
outputProgress({
|
||||||
|
|||||||
@@ -85,8 +85,41 @@ function runScript(scriptPath, type, clients) {
|
|||||||
child.stdout.on('data', (data) => {
|
child.stdout.on('data', (data) => {
|
||||||
const text = data.toString();
|
const text = data.toString();
|
||||||
output += text;
|
output += text;
|
||||||
// Send raw output directly
|
|
||||||
sendProgressToClients(clients, text);
|
// Split by lines to handle multiple JSON outputs
|
||||||
|
const lines = text.split('\n');
|
||||||
|
lines.filter(line => line.trim()).forEach(line => {
|
||||||
|
try {
|
||||||
|
// Try to parse as JSON but don't let it affect the display
|
||||||
|
const jsonData = JSON.parse(line);
|
||||||
|
// Only end the process if we get a final status
|
||||||
|
if (jsonData.status === 'complete' || jsonData.status === 'error' || jsonData.status === 'cancelled') {
|
||||||
|
if (jsonData.status === 'complete' && !jsonData.operation?.includes('complete')) {
|
||||||
|
// Don't close for intermediate completion messages
|
||||||
|
sendProgressToClients(clients, line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Close only on final completion/error/cancellation
|
||||||
|
switch (type) {
|
||||||
|
case 'update':
|
||||||
|
activeFullUpdate = null;
|
||||||
|
break;
|
||||||
|
case 'reset':
|
||||||
|
activeFullReset = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (jsonData.status === 'error') {
|
||||||
|
reject(new Error(jsonData.error || 'Unknown error'));
|
||||||
|
} else {
|
||||||
|
resolve({ output });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Not JSON, just display as is
|
||||||
|
}
|
||||||
|
// Always send the raw line
|
||||||
|
sendProgressToClients(clients, line);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
child.stderr.on('data', (data) => {
|
child.stderr.on('data', (data) => {
|
||||||
@@ -110,10 +143,8 @@ function runScript(scriptPath, type, clients) {
|
|||||||
const error = `Script ${scriptPath} exited with code ${code}`;
|
const error = `Script ${scriptPath} exited with code ${code}`;
|
||||||
sendProgressToClients(clients, error);
|
sendProgressToClients(clients, error);
|
||||||
reject(new Error(error));
|
reject(new Error(error));
|
||||||
} else {
|
|
||||||
sendProgressToClients(clients, `${type} completed successfully`);
|
|
||||||
resolve({ output });
|
|
||||||
}
|
}
|
||||||
|
// Don't resolve here - let the completion message from the script trigger the resolve
|
||||||
});
|
});
|
||||||
|
|
||||||
child.on('error', (err) => {
|
child.on('error', (err) => {
|
||||||
|
|||||||
@@ -181,25 +181,30 @@ export function DataManagement() {
|
|||||||
// Try to parse for status updates, but don't affect display
|
// Try to parse for status updates, but don't affect display
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
if (
|
if (data.status === 'complete' || data.status === 'error' || data.status === 'cancelled') {
|
||||||
data.status === "complete" ||
|
// Only close and reset state if this is the final completion message
|
||||||
data.status === "error" ||
|
if (data.operation === 'Full update complete' ||
|
||||||
data.status === "cancelled"
|
data.status === 'error' ||
|
||||||
) {
|
data.status === 'cancelled') {
|
||||||
source.close();
|
source.close();
|
||||||
setEventSource(null);
|
setEventSource(null);
|
||||||
setIsUpdating(false);
|
setIsUpdating(false);
|
||||||
|
|
||||||
if (data.status === "complete") {
|
if (data.status === 'complete') {
|
||||||
toast.success("Update completed successfully");
|
toast.success("Update completed successfully");
|
||||||
fetchHistory();
|
fetchHistory();
|
||||||
} else if (data.status === "error") {
|
} else if (data.status === 'error') {
|
||||||
toast.error(`Update failed: ${data.error || "Unknown error"}`);
|
toast.error(`Update failed: ${data.error || 'Unknown error'}`);
|
||||||
} else {
|
} else {
|
||||||
toast.warning("Update cancelled");
|
toast.warning("Update cancelled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// For intermediate completions, just show a toast
|
||||||
|
else if (data.status === 'complete') {
|
||||||
|
toast.success(data.message || "Step completed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Not JSON, just display as is
|
// Not JSON, just display as is
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -246,25 +251,30 @@ export function DataManagement() {
|
|||||||
// Try to parse for status updates, but don't affect display
|
// Try to parse for status updates, but don't affect display
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
if (
|
if (data.status === 'complete' || data.status === 'error' || data.status === 'cancelled') {
|
||||||
data.status === "complete" ||
|
// Only close and reset state if this is the final completion message
|
||||||
data.status === "error" ||
|
if (data.operation === 'Full reset complete' ||
|
||||||
data.status === "cancelled"
|
data.status === 'error' ||
|
||||||
) {
|
data.status === 'cancelled') {
|
||||||
source.close();
|
source.close();
|
||||||
setEventSource(null);
|
setEventSource(null);
|
||||||
setIsResetting(false);
|
setIsResetting(false);
|
||||||
|
|
||||||
if (data.status === "complete") {
|
if (data.status === 'complete') {
|
||||||
toast.success("Reset completed successfully");
|
toast.success("Reset completed successfully");
|
||||||
fetchHistory();
|
fetchHistory();
|
||||||
} else if (data.status === "error") {
|
} else if (data.status === 'error') {
|
||||||
toast.error(`Reset failed: ${data.error || "Unknown error"}`);
|
toast.error(`Reset failed: ${data.error || 'Unknown error'}`);
|
||||||
} else {
|
} else {
|
||||||
toast.warning("Reset cancelled");
|
toast.warning("Reset cancelled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
// For intermediate completions, just show a toast
|
||||||
|
else if (data.status === 'complete') {
|
||||||
|
toast.success(data.message || "Step completed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
// Not JSON, just display as is
|
// Not JSON, just display as is
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -511,17 +521,23 @@ export function DataManagement() {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="">
|
<div className="">
|
||||||
{tableStatus.map((table) => (
|
{tableStatus.length > 0 ? (
|
||||||
<div
|
tableStatus.map((table) => (
|
||||||
key={table.table_name}
|
<div
|
||||||
className="flex justify-between text-sm items-center py-2 border-b last:border-0"
|
key={table.table_name}
|
||||||
>
|
className="flex justify-between text-sm items-center py-2 border-b last:border-0"
|
||||||
<span className="font-medium">{table.table_name}</span>
|
>
|
||||||
<span className="text-sm text-gray-600">
|
<span className="font-medium">{table.table_name}</span>
|
||||||
{formatStatusTime(table.last_sync_timestamp)}
|
<span className="text-sm text-gray-600">
|
||||||
</span>
|
{formatStatusTime(table.last_sync_timestamp)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="text-sm text-muted-foreground py-4 text-center">
|
||||||
|
No imports have been performed yet.<br/>Run a full update or reset to import data.
|
||||||
</div>
|
</div>
|
||||||
))}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -532,17 +548,23 @@ export function DataManagement() {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="">
|
<div className="">
|
||||||
{moduleStatus.map((module) => (
|
{moduleStatus.length > 0 ? (
|
||||||
<div
|
moduleStatus.map((module) => (
|
||||||
key={module.module_name}
|
<div
|
||||||
className="flex justify-between text-sm items-center py-2 border-b last:border-0"
|
key={module.module_name}
|
||||||
>
|
className="flex justify-between text-sm items-center py-2 border-b last:border-0"
|
||||||
<span className="font-medium">{module.module_name}</span>
|
>
|
||||||
<span className="text-sm text-gray-600">
|
<span className="font-medium">{module.module_name}</span>
|
||||||
{formatStatusTime(module.last_calculation_timestamp)}
|
<span className="text-sm text-gray-600">
|
||||||
</span>
|
{formatStatusTime(module.last_calculation_timestamp)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="text-sm text-muted-foreground py-4 text-center">
|
||||||
|
No metrics have been calculated yet.<br/>Run a full update or reset to calculate metrics.
|
||||||
</div>
|
</div>
|
||||||
))}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
Reference in New Issue
Block a user