Remove CSV scripts from frontend

This commit is contained in:
2025-01-29 00:04:47 -05:00
parent d56f1e1437
commit b578549763

View File

@@ -43,27 +43,18 @@ interface ImportLimits {
}
export function DataManagement() {
const [isUpdating, setIsUpdating] = useState(false);
const [isImportingCSV, setIsImportingCSV] = useState(false);
const [isImportingProd, setIsImportingProd] = useState(false);
const [isResetting, setIsResetting] = useState(false);
const [updateProgress, setUpdateProgress] = useState<ImportProgress | null>(null);
const [importProgress, setImportProgress] = useState<ImportProgress | null>(null);
const [purchaseOrdersProgress, setPurchaseOrdersProgress] = useState<ImportProgress | null>(null);
const [resetProgress, setResetProgress] = useState<ImportProgress | null>(null);
const [eventSource, setEventSource] = useState<EventSource | null>(null);
const [] = useState<ImportLimits>({
products: 0,
orders: 0,
purchaseOrders: 0
});
const [isResettingMetrics, setIsResettingMetrics] = useState(false);
const [resetMetricsProgress, setResetMetricsProgress] = useState<ImportProgress | null>(null);
const [isCalculatingMetrics, setIsCalculatingMetrics] = useState(false);
const [metricsProgress, setMetricsProgress] = useState<ImportProgress | null>(null);
// Add states for completed operations
const [lastUpdateStatus, setLastUpdateStatus] = useState<ImportProgress | null>(null);
const [lastImportStatus, setLastImportStatus] = useState<ImportProgress | null>(null);
const [lastResetStatus, setLastResetStatus] = useState<ImportProgress | null>(null);
const [lastMetricsStatus, setLastMetricsStatus] = useState<ImportProgress | null>(null);
@@ -77,7 +68,7 @@ export function DataManagement() {
// Helper to check if any operation is running
const isAnyOperationRunning = () => {
return isUpdating || isImportingCSV || isImportingProd || isTestingConnection || isResetting || isCalculatingMetrics;
return isImportingProd || isTestingConnection || isResetting || isCalculatingMetrics || isResettingMetrics;
};
// Helper function to get progress bar color based on status
@@ -132,7 +123,7 @@ export function DataManagement() {
};
// Helper function to render progress
const renderProgress = (progress: any, operationType: 'update' | 'import' | 'reset' | 'reset-metrics' | 'calculate-metrics') => {
const renderProgress = (progress: any, operationType: 'import' | 'reset' | 'reset-metrics' | 'calculate-metrics') => {
if (!progress) return null;
const status = progress.status?.toLowerCase();
@@ -218,7 +209,7 @@ export function DataManagement() {
};
// Helper to connect to event source
const connectToEventSource = (type: 'update' | 'import' | 'reset' | 'reset-metrics' | 'calculate-metrics') => {
const connectToEventSource = (type: 'import' | 'reset' | 'reset-metrics' | 'calculate-metrics') => {
console.log(`Setting up EventSource for ${type}...`);
// Clean up existing connection first
@@ -257,8 +248,7 @@ export function DataManagement() {
// Try to reconnect via status check if the operation might still be running
if (
(type === 'calculate-metrics' && isCalculatingMetrics) ||
(type === 'import' && isImportingCSV) ||
(type === 'update' && isUpdating) ||
(type === 'import' && isImportingProd) ||
(type === 'reset' && isResetting) ||
(type === 'reset-metrics' && isResettingMetrics)
) {
@@ -295,7 +285,7 @@ export function DataManagement() {
};
const handleProgressUpdate = (
type: 'update' | 'import' | 'reset' | 'reset-metrics' | 'calculate-metrics',
type: 'import' | 'reset' | 'reset-metrics' | 'calculate-metrics',
progressData: any,
source: EventSource
) => {
@@ -342,7 +332,6 @@ export function DataManagement() {
if (!otherProgress || otherProgress.status === 'complete' || otherProgress.status === 'error' || otherProgress.status === 'cancelled') {
source.close();
setEventSource(null);
setIsImportingCSV(false);
setIsImportingProd(false);
// Show appropriate toast based on final status
@@ -374,12 +363,6 @@ export function DataManagement() {
let operationName;
switch (type) {
case 'update':
setProgress = setUpdateProgress;
setLastStatus = setLastUpdateStatus;
setIsRunning = setIsUpdating;
operationName = 'Update';
break;
case 'reset':
setProgress = setResetProgress;
setLastStatus = setLastResetStatus;
@@ -435,7 +418,7 @@ export function DataManagement() {
}
};
const handleCancel = async (operation: 'update' | 'import' | 'reset' | 'calculate-metrics') => {
const handleCancel = async (operation: 'import' | 'reset' | 'calculate-metrics') => {
try {
const response = await fetch(`${config.apiUrl}/csv/cancel?operation=${operation}`, {
method: 'POST',
@@ -448,13 +431,9 @@ export function DataManagement() {
// Reset the appropriate state
if (operation === 'import') {
setIsImportingCSV(false);
setIsImportingProd(false);
setImportProgress(null);
setPurchaseOrdersProgress(null);
} else if (operation === 'update') {
setIsUpdating(false);
setUpdateProgress(null);
}
// ... other operation states ...
} catch (error) {
@@ -511,7 +490,7 @@ export function DataManagement() {
if (operation.includes('import')) {
console.log('Import is running');
setIsImportingCSV(true);
setIsImportingProd(true);
if (operation.includes('purchase orders')) {
setPurchaseOrdersProgress(importData.progress || importData);
} else {
@@ -520,13 +499,6 @@ export function DataManagement() {
if (!eventSource) {
connectToEventSource('import');
}
} else if (operation.includes('update')) {
console.log('Update is running');
setIsUpdating(true);
setUpdateProgress(importData.progress || importData);
if (!eventSource) {
connectToEventSource('update');
}
} else if (operation.includes('reset')) {
if (operation.includes('metrics')) {
console.log('Reset metrics is running');
@@ -549,8 +521,6 @@ export function DataManagement() {
const operation = (importData.lastStatus?.operation || '').toLowerCase();
if (operation.includes('import')) {
setLastImportStatus(importData.lastStatus);
} else if (operation.includes('update')) {
setLastUpdateStatus(importData.lastStatus);
} else if (operation.includes('reset')) {
if (operation.includes('metrics')) {
setLastResetMetricsStatus(importData.lastStatus);
@@ -569,39 +539,30 @@ export function DataManagement() {
checkStatus();
}, []);
const handleUpdateCSV = async () => {
setIsUpdating(true);
setUpdateProgress({ status: 'running', operation: 'Starting CSV update' });
const handleTestConnection = async () => {
setIsTestingConnection(true);
try {
connectToEventSource('update');
const response = await fetch(`${config.apiUrl}/csv/update`, {
method: 'POST',
const response = await fetch(`${config.apiUrl}/test-prod-connection`, {
credentials: 'include'
});
if (!response.ok) {
const data = await response.json().catch(() => ({}));
if (data.error === 'Import already in progress') {
return;
}
throw new Error(data.error || `Failed to update CSV files: ${response.status} ${response.statusText}`);
const data = await response.json();
if (response.ok) {
toast.success(`Successfully connected to production database. Found ${data.productCount.toLocaleString()} products.`);
} else {
throw new Error(data.error || 'Failed to connect to production database');
}
} catch (error) {
if (eventSource) {
eventSource.close();
setEventSource(null);
}
setIsUpdating(false);
setUpdateProgress(null);
toast.error(`CSV update failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
toast.error(`Connection test failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
} finally {
setIsTestingConnection(false);
}
};
const handleImportCSV = async () => {
setIsImportingCSV(true);
setImportProgress({ status: 'running', operation: 'Starting CSV import' });
const handleImportFromProd = async () => {
setIsImportingProd(true);
setImportProgress({ status: 'running', operation: 'Starting import from production' });
try {
connectToEventSource('import');
@@ -620,20 +581,93 @@ export function DataManagement() {
}
// Start new import
const response = await fetch(`${config.apiUrl}/csv/import`, {
const response = await fetch(`${config.apiUrl}/csv/import-from-prod`, {
method: 'POST',
credentials: 'include'
}).catch(error => {
console.log('Import request error (may be timeout):', error);
return null;
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Failed to start CSV import');
// If we got no response but have progress, assume it's still running
if (!response && (importProgress?.current || purchaseOrdersProgress?.current)) {
console.log('No response but import appears to be running, continuing...');
return;
}
// If we got a response, check if it indicates an actual error
if (response) {
const data = await response.json().catch(() => null);
if (!response.ok && data?.error && !data.error.includes('already in progress')) {
throw new Error(data.error || 'Failed to start production import');
}
}
} catch (error) {
toast.error(`CSV import failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
setIsImportingCSV(false);
setImportProgress(null);
setPurchaseOrdersProgress(null);
// Only handle actual errors, not timeouts or connection issues
if (error instanceof Error && !error.message.includes('NetworkError') && !error.message.includes('Failed to fetch')) {
toast.error(`Production import failed: ${error.message}`);
setIsImportingProd(false);
setImportProgress(null);
setPurchaseOrdersProgress(null);
} else {
console.log('Ignoring network error, import may still be running:', error);
}
}
};
const handleCalculateMetrics = async () => {
setIsCalculatingMetrics(true);
setMetricsProgress({ status: 'running', operation: 'Starting metrics calculation' });
try {
connectToEventSource('calculate-metrics');
// First check if metrics calculation is already running
const statusResponse = await fetch(`${config.apiUrl}/csv/calculate-metrics/status`, {
credentials: 'include'
}).catch(() => null);
if (statusResponse) {
const statusData = await statusResponse.json().catch(() => null);
if (statusData?.active && statusData?.progress) {
console.log('Metrics calculation already running, connecting to existing process');
setMetricsProgress(statusData.progress);
return;
}
}
// Start new metrics calculation
const response = await fetch(`${config.apiUrl}/csv/calculate-metrics`, {
method: 'POST',
credentials: 'include'
}).catch(error => {
// Ignore network errors as the calculation might still be running
console.log('Metrics calculation request error (may be timeout):', error);
return null;
});
// If we got no response but have progress, assume it's still running
if (!response && metricsProgress?.current) {
console.log('No response but metrics calculation appears to be running, continuing...');
return;
}
// If we got a response, check if it indicates an actual error
if (response) {
const data = await response.json().catch(() => null);
if (!response.ok && data?.error && !data.error.includes('already in progress')) {
throw new Error(data.error || 'Failed to calculate metrics');
}
}
} catch (error) {
// Only handle actual errors, not timeouts or connection issues
if (error instanceof Error && !error.message.includes('NetworkError') && !error.message.includes('Failed to fetch')) {
toast.error(`Metrics calculation failed: ${error.message}`);
setIsCalculatingMetrics(false);
setMetricsProgress(null);
} else {
console.log('Ignoring network error, metrics calculation may still be running:', error);
}
}
};
@@ -726,138 +760,6 @@ export function DataManagement() {
}
};
const handleCalculateMetrics = async () => {
setIsCalculatingMetrics(true);
setMetricsProgress({ status: 'running', operation: 'Starting metrics calculation' });
try {
connectToEventSource('calculate-metrics');
// First check if metrics calculation is already running
const statusResponse = await fetch(`${config.apiUrl}/csv/calculate-metrics/status`, {
credentials: 'include'
}).catch(() => null);
if (statusResponse) {
const statusData = await statusResponse.json().catch(() => null);
if (statusData?.active && statusData?.progress) {
console.log('Metrics calculation already running, connecting to existing process');
setMetricsProgress(statusData.progress);
return;
}
}
// Start new metrics calculation
const response = await fetch(`${config.apiUrl}/csv/calculate-metrics`, {
method: 'POST',
credentials: 'include'
}).catch(error => {
// Ignore network errors as the calculation might still be running
console.log('Metrics calculation request error (may be timeout):', error);
return null;
});
// If we got no response but have progress, assume it's still running
if (!response && metricsProgress?.current) {
console.log('No response but metrics calculation appears to be running, continuing...');
return;
}
// If we got a response, check if it indicates an actual error
if (response) {
const data = await response.json().catch(() => null);
if (!response.ok && data?.error && !data.error.includes('already in progress')) {
throw new Error(data.error || 'Failed to calculate metrics');
}
}
} catch (error) {
// Only handle actual errors, not timeouts or connection issues
if (error instanceof Error && !error.message.includes('NetworkError') && !error.message.includes('Failed to fetch')) {
toast.error(`Metrics calculation failed: ${error.message}`);
setIsCalculatingMetrics(false);
setMetricsProgress(null);
} else {
console.log('Ignoring network error, metrics calculation may still be running:', error);
}
}
};
const handleTestConnection = async () => {
setIsTestingConnection(true);
try {
const response = await fetch(`${config.apiUrl}/test-prod-connection`, {
credentials: 'include'
});
const data = await response.json();
if (response.ok) {
toast.success(`Successfully connected to production database. Found ${data.productCount.toLocaleString()} products.`);
} else {
throw new Error(data.error || 'Failed to connect to production database');
}
} catch (error) {
toast.error(`Connection test failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
} finally {
setIsTestingConnection(false);
}
};
const handleImportFromProd = async () => {
setIsImportingProd(true);
setImportProgress({ status: 'running', operation: 'Starting import from production' });
try {
connectToEventSource('import');
// First check if import is already running
const statusResponse = await fetch(`${config.apiUrl}/csv/status`, {
credentials: 'include'
}).catch(() => null);
if (statusResponse) {
const statusData = await statusResponse.json().catch(() => null);
if (statusData?.active && statusData?.progress) {
console.log('Import already running, connecting to existing process');
return;
}
}
// Start new import
const response = await fetch(`${config.apiUrl}/csv/import-from-prod`, {
method: 'POST',
credentials: 'include'
}).catch(error => {
console.log('Import request error (may be timeout):', error);
return null;
});
// If we got no response but have progress, assume it's still running
if (!response && (importProgress?.current || purchaseOrdersProgress?.current)) {
console.log('No response but import appears to be running, continuing...');
return;
}
// If we got a response, check if it indicates an actual error
if (response) {
const data = await response.json().catch(() => null);
if (!response.ok && data?.error && !data.error.includes('already in progress')) {
throw new Error(data.error || 'Failed to start production import');
}
}
} catch (error) {
// Only handle actual errors, not timeouts or connection issues
if (error instanceof Error && !error.message.includes('NetworkError') && !error.message.includes('Failed to fetch')) {
toast.error(`Production import failed: ${error.message}`);
setIsImportingProd(false);
setImportProgress(null);
setPurchaseOrdersProgress(null);
} else {
console.log('Ignoring network error, import may still be running:', error);
}
}
};
return (
<div className="max-w-[400px] space-y-4">
{/* Test Production Connection Card */}
@@ -887,91 +789,33 @@ export function DataManagement() {
</CardContent>
</Card>
{/* Update CSV Card */}
<Card>
<CardHeader>
<CardTitle>Update CSV Files</CardTitle>
<CardDescription>Download the latest CSV data files</CardDescription>
</CardHeader>
<CardContent>
<div className="flex gap-2">
<Button
className="flex-1"
onClick={handleUpdateCSV}
disabled={isAnyOperationRunning()}
>
{isUpdating ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Updating CSV Files...
</>
) : (
<>
<RefreshCw className="mr-2 h-4 w-4" />
Update CSV Files
</>
)}
</Button>
{isUpdating && (
<Button
variant="destructive"
onClick={() => handleCancel('update')}
>
<X className="h-4 w-4" />
</Button>
)}
</div>
{(isUpdating || lastUpdateStatus) && renderProgress(updateProgress || lastUpdateStatus, 'update')}
</CardContent>
</Card>
{/* Import Data Card */}
<Card>
<CardHeader>
<CardTitle>Import Data</CardTitle>
<CardDescription>Import data from CSV files or production database</CardDescription>
<CardDescription>Import data from production database</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="flex gap-2">
<Button
className="flex-1 min-w-0"
onClick={handleImportCSV}
disabled={isAnyOperationRunning()}
>
{isImportingCSV ? (
<div className="flex items-center justify-center">
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
<span className="truncate">Importing CSV...</span>
</div>
) : (
<div className="flex items-center justify-center">
<Upload className="mr-2 h-4 w-4" />
<span>Import from CSV</span>
</div>
)}
</Button>
<Button
className="flex-1 min-w-0"
className="w-full"
onClick={handleImportFromProd}
disabled={isAnyOperationRunning()}
>
{isImportingProd ? (
<div className="flex items-center justify-center">
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
<span className="truncate">Importing Prod...</span>
<span className="truncate">Importing from Production...</span>
</div>
) : (
<div className="flex items-center justify-center">
<Database className="mr-2 h-4 w-4" />
<span>Import from Prod</span>
<span>Import from Production</span>
</div>
)}
</Button>
{(isImportingCSV || isImportingProd) && (
{isImportingProd && (
<Button
variant="destructive"
onClick={() => handleCancel('import')}
@@ -981,7 +825,7 @@ export function DataManagement() {
)}
</div>
{(isImportingCSV || isImportingProd || lastImportStatus) && (
{(isImportingProd || lastImportStatus) && (
<div className="space-y-4">
{renderProgress(importProgress || lastImportStatus, 'import')}
{renderProgress(purchaseOrdersProgress, 'import')}