Remove CSV scripts from frontend
This commit is contained in:
@@ -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);
|
||||
// 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')}
|
||||
|
||||
Reference in New Issue
Block a user