Added skip diagnostics
X-Lovable-Edit-ID: edt-f62beb1b-ada6-4d4f-b7b9-e60c91317d0c Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
@@ -499,6 +499,7 @@ interface ImportResult {
|
||||
inserted: number;
|
||||
skipped: number;
|
||||
errors: string[];
|
||||
skipReasons?: Record<string, number>;
|
||||
}
|
||||
|
||||
function ImportPage() {
|
||||
@@ -582,6 +583,11 @@ function ImportPage() {
|
||||
const mapped: Row[] = [];
|
||||
let skipped = 0;
|
||||
const errors: string[] = [];
|
||||
const skipReasons: Record<string, number> = {};
|
||||
const bumpSkip = (reason: string) => {
|
||||
skipped++;
|
||||
skipReasons[reason] = (skipReasons[reason] ?? 0) + 1;
|
||||
};
|
||||
|
||||
for (const raw of rawRows) {
|
||||
const row: Row = {};
|
||||
@@ -598,7 +604,19 @@ function ImportPage() {
|
||||
|
||||
// transform
|
||||
const transformed = cfg.transform ? cfg.transform(row, ctx) : row;
|
||||
if (!transformed) { skipped++; continue; }
|
||||
if (!transformed) {
|
||||
// Diagnose common transform-rejection reasons for clearer feedback
|
||||
if (cfg.table === "homeowners" && !row.client_id && !row._clientext && !row._clientname) {
|
||||
bumpSkip("no client match (missing companyid/company)");
|
||||
} else if (cfg.table === "homeowners" && (row._clientext || row._clientname) && !row.client_id) {
|
||||
bumpSkip("client not found in existing clients (import companies first)");
|
||||
} else if ((cfg.table === "cases" || cfg.table === "invoices") && !row.client_id) {
|
||||
bumpSkip("client not found");
|
||||
} else {
|
||||
bumpSkip("rejected by transform");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// archived → archived_at (only on tables that support it)
|
||||
if ("_archived" in transformed) {
|
||||
@@ -611,7 +629,7 @@ function ImportPage() {
|
||||
|
||||
// required check
|
||||
const missing = cfg.required.find((k) => !transformed[k] && transformed[k] !== 0);
|
||||
if (missing) { skipped++; continue; }
|
||||
if (missing) { bumpSkip(`missing required: ${missing}`); continue; }
|
||||
|
||||
// attach created_by where not present
|
||||
if (!transformed.created_by && !["time_entries", "expenses", "comments"].includes(cfg.table)) {
|
||||
@@ -621,7 +639,7 @@ function ImportPage() {
|
||||
}
|
||||
|
||||
if (mapped.length === 0) {
|
||||
setResults((r) => ({ ...r, [cfg.key]: { total: rawRows.length, inserted: 0, skipped, errors: ["No valid rows after mapping. Check headers/required fields."] } }));
|
||||
setResults((r) => ({ ...r, [cfg.key]: { total: rawRows.length, inserted: 0, skipped, errors: ["No valid rows after mapping. Check headers/required fields."], skipReasons } }));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -663,7 +681,7 @@ function ImportPage() {
|
||||
|
||||
if (cfg.postInsert) cfg.postInsert(inserted_rows, ctx);
|
||||
|
||||
const summary = { total: rawRows.length, inserted, skipped, errors };
|
||||
const summary = { total: rawRows.length, inserted, skipped, errors, skipReasons };
|
||||
setResults((r) => ({ ...r, [cfg.key]: summary }));
|
||||
if (errors.length === 0) toast.success(`${cfg.label}: ${inserted} imported`);
|
||||
else toast.error(`${cfg.label}: ${errors.length} batch error(s)`);
|
||||
@@ -733,9 +751,16 @@ function ImportPage() {
|
||||
</Badge>
|
||||
)}
|
||||
{r.skipped > 0 && (
|
||||
<span className="text-muted-foreground">{r.skipped} skipped (missing required fields)</span>
|
||||
<span className="text-muted-foreground">{r.skipped} skipped</span>
|
||||
)}
|
||||
</div>
|
||||
{r.skipReasons && Object.keys(r.skipReasons).length > 0 && (
|
||||
<div className="mt-2 text-xs text-muted-foreground space-y-0.5">
|
||||
{Object.entries(r.skipReasons).map(([reason, count]) => (
|
||||
<div key={reason}>• {count} × {reason}</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{r.errors.length > 0 && (
|
||||
<div className="mt-2 text-xs text-destructive space-y-1">
|
||||
{r.errors.slice(0, 3).map((e, i) => <div key={i}>• {e}</div>)}
|
||||
|
||||
Reference in New Issue
Block a user