@makolabs/ripple
Version:
Simple Svelte 5 powered component library ✨
172 lines (171 loc) • 6.91 kB
JavaScript
/**
* Base storage adapter with common functionality
*/
export class BaseAdapter {
// Common implementation of import and getImportStatus
async import(file, options) {
try {
const endpoint = `/api/${this.getApiPath()}/import`;
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
key: file.key,
fileId: file.id, // For Google Drive
contentType: options.contentType,
fileFormat: options.fileFormat,
reference: options.reference || file.name,
insurer: options.contentType === 'insurer_statement' ? options.insurer : null
})
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Failed to import file');
}
const result = await response.json();
return {
success: true,
message: `File ${file.name} imported successfully`,
fileId: result.fileId || result.importResponse?.uuid,
status: 'pending',
progress: 10
};
}
catch (err) {
console.error(`Error importing ${this.getName()} file:`, err);
return {
success: false,
message: `Failed to import file from ${this.getName()}`,
error: err instanceof Error ? err.message : 'Unknown error'
};
}
}
async getImportStatus(importId, fileKey) {
try {
const response = await fetch(`/api/v1/uploads/${importId}`);
if (!response.ok) {
if (response.status === 404) {
throw new Error(`404: File ${importId} not found on server`);
}
throw new Error(`Failed to get file status: ${response.status} ${response.statusText}`);
}
const fileData = await response.json();
return {
fileId: importId,
status: fileData.processing_status,
progress: this.calculateProgress(fileData.processing_status, fileData.processed_rows, fileData.total_rows),
processedRows: fileData.processed_rows,
totalRows: fileData.total_rows,
detailedStatus: this.getDetailedStatus(fileData.processing_status),
error: fileData.error_details?.message,
created_at: fileData.created_at
};
}
catch (err) {
console.error('Error polling file status:', err);
throw err;
}
}
// Common implementation of batch import
async batchImport(files, options) {
// Process files sequentially
const individualResults = [];
for (const file of files) {
try {
const result = await this.import(file, options);
individualResults.push(result);
}
catch (err) {
individualResults.push({
success: false,
message: `Failed to import ${file.name}`,
error: err instanceof Error ? err.message : 'Unknown error',
fileId: file.id
});
}
}
// Count successes and failures
const succeeded = individualResults.filter(r => r.success).length;
const failed = individualResults.length - succeeded;
// Return batch import result
return {
success: failed === 0, // Overall success if all files succeeded
message: `Imported ${succeeded} of ${individualResults.length} files`,
summary: {
total: individualResults.length,
succeeded,
failed
},
results: individualResults.map(r => ({
key: r.fileId || '',
success: r.success,
fileId: r.fileId,
error: r.error
}))
};
}
// Set a flag to reopen the browser after authentication
setReopenFlag() {
// Default implementation does nothing
// Subclasses should override this method to implement storage-specific reopening flags
}
// Check if the browser should be reopened
shouldReopenBrowser() {
// Default implementation returns false
// Subclasses should override this method to check their specific reopening flags
return false;
}
// Clear the browser reopening flag
clearReopenFlag() {
// Default implementation does nothing
// Subclasses should override this method to clear their specific reopening flags
}
// Helper method to get detailed status
getDetailedStatus(status) {
const statusMap = {
'pending': 'Waiting to start',
'pending_import': 'Preparing import',
'initializing': 'Initializing import',
'pending_file_retrieval': 'Retrieving file',
'retrieving_file': 'Downloading file',
'file_retrieved': 'File downloaded',
'loading_file_contents_to_db': 'Loading data',
'file_contents_loaded': 'Data loaded',
'ready_to_process': 'Ready for processing',
'validating_source_file_rows': 'Validating file',
'converting_to_business_objects': 'Converting data',
'processing': 'Processing data',
'completed': 'Import completed',
'failed': 'Import failed',
'partially_processed': 'Partially processed'
};
return statusMap[status] || status;
}
// Helper method to calculate progress
calculateProgress(status, processedRows, totalRows) {
// If we have row counts, use them for more accurate progress
if (processedRows !== undefined && totalRows && totalRows > 0) {
return Math.min(95, Math.round((processedRows / totalRows) * 100));
}
// Otherwise, use status-based progress estimates
const progressMap = {
'pending': 5,
'pending_import': 10,
'initializing': 15,
'pending_file_retrieval': 20,
'retrieving_file': 30,
'file_retrieved': 40,
'loading_file_contents_to_db': 50,
'file_contents_loaded': 60,
'ready_to_process': 70,
'validating_source_file_rows': 80,
'converting_to_business_objects': 90,
'completed': 100,
'failed': 0,
'partially_processed': 95
};
return progressMap[status] || 50;
}
}