Phase 1: Workflows UI, Dedup/Merge UI, Import/Export UI, Print/PDF
- Workflows UI: full page with definitions/instances tabs, step editor, instance detail with approve/reject - Dedup/Merge UI: duplicate detection, side-by-side comparison, field-level merge dialog, merge history - Import/Export UI: import wizard (dry-run preview), export panel (CSV/XLSX), backend export route added - Print/PDF: PrintButton component, print.css, integrated in Contacts/Calendar/Reports/ContactDetail - Backend: GET /api/v1/export endpoint, export_companies_csv() service function - Routes: /workflows, /contacts/dedup, /import-export registered - Menu items: Workflows, Import/Export, Duplikate added to automation plugin manifest - IMPLEMENTATION_PLAN.md: audit-corrected plan for all 14 remaining features
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { apiClient } from './client';
|
||||
|
||||
// ─── Types ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface ImportResult {
|
||||
total?: number;
|
||||
created?: number;
|
||||
updated?: number;
|
||||
errors?: string[];
|
||||
warnings?: string[];
|
||||
rows?: Record<string, unknown>[];
|
||||
preview?: boolean;
|
||||
}
|
||||
|
||||
export type EntityType = 'companies' | 'contacts';
|
||||
export type ExportFormat = 'csv' | 'xlsx';
|
||||
|
||||
// ─── Import ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Import a CSV file. When dryRun is true, a preview is returned without
|
||||
* writing to the database.
|
||||
*/
|
||||
export async function importCsv(
|
||||
file: File,
|
||||
entityType: string,
|
||||
dryRun: boolean
|
||||
): Promise<ImportResult> {
|
||||
const url = dryRun ? '/import/preview' : '/import';
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('entity_type', entityType);
|
||||
|
||||
const response = await apiClient.post<ImportResult>(url, formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// ─── Export ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Export data as CSV or XLSX and trigger a browser download.
|
||||
*/
|
||||
export async function exportData(
|
||||
entityType: string,
|
||||
format: string
|
||||
): Promise<void> {
|
||||
const url = `/export?entity_type=${encodeURIComponent(entityType)}&format=${encodeURIComponent(format)}`;
|
||||
const response = await apiClient.get(url, { responseType: 'blob' });
|
||||
|
||||
const blob = new Blob([response.data], {
|
||||
type: format === 'xlsx'
|
||||
? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
: 'text/csv',
|
||||
});
|
||||
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = blobUrl;
|
||||
link.download = `${entityType}_export.${format}`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
}
|
||||
Reference in New Issue
Block a user