feat: make settings data imports visible in Import History

Create import_sources + imported_files tracking records when importing
transactions from Settings > Data Management, so imports appear in the
Import History panel and can be deleted like CSV imports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Le-King-Fu 2026-02-15 13:38:51 +00:00
parent 172be36f1d
commit e23e559ee3
2 changed files with 56 additions and 13 deletions

View file

@ -33,6 +33,7 @@ type ImportAction =
| { type: "NEEDS_PASSWORD"; filePath: string }
| {
type: "CONFIRMING";
filePath: string;
summary: ImportSummary;
data: ExportEnvelope["data"];
importType: ExportEnvelope["export_type"];
@ -61,6 +62,7 @@ function reducer(state: ImportState, action: ImportAction): ImportState {
return {
...state,
status: "confirming",
filePath: action.filePath,
summary: action.summary,
parsedData: action.data,
importType: action.importType,
@ -132,7 +134,7 @@ export function useDataImport() {
});
const { summary, data, importType } = parseContent(content, filePath);
dispatch({ type: "CONFIRMING", summary, data, importType });
dispatch({ type: "CONFIRMING", filePath, summary, data, importType });
} catch (e) {
dispatch({
type: "IMPORT_ERROR",
@ -152,7 +154,7 @@ export function useDataImport() {
});
const { summary, data, importType } = parseContent(content, state.filePath);
dispatch({ type: "CONFIRMING", summary, data, importType });
dispatch({ type: "CONFIRMING", filePath: state.filePath, summary, data, importType });
} catch (e) {
dispatch({
type: "IMPORT_ERROR",
@ -166,16 +168,17 @@ export function useDataImport() {
const executeImport = useCallback(async () => {
if (!state.parsedData || !state.importType) return;
dispatch({ type: "IMPORT_START" });
const filename = state.filePath?.split(/[/\\]/).pop() ?? "unknown";
try {
switch (state.importType) {
case "categories_only":
await importCategoriesOnly(state.parsedData);
break;
case "transactions_with_categories":
await importTransactionsWithCategories(state.parsedData);
await importTransactionsWithCategories(state.parsedData, filename);
break;
case "transactions_only":
await importTransactionsOnly(state.parsedData);
await importTransactionsOnly(state.parsedData, filename);
break;
}
dispatch({ type: "IMPORT_SUCCESS" });
@ -185,7 +188,7 @@ export function useDataImport() {
error: e instanceof Error ? e.message : String(e),
});
}
}, [state.parsedData, state.importType]);
}, [state.parsedData, state.importType, state.filePath]);
const reset = useCallback(() => dispatch({ type: "RESET" }), []);

View file

@ -254,13 +254,15 @@ export async function importCategoriesOnly(data: ExportEnvelope["data"]): Promis
}
export async function importTransactionsWithCategories(
data: ExportEnvelope["data"]
data: ExportEnvelope["data"],
filename: string
): Promise<void> {
const db = await getDb();
// Wipe everything
await db.execute("DELETE FROM transactions");
await db.execute("DELETE FROM imported_files");
await db.execute("DELETE FROM import_sources");
await db.execute("DELETE FROM keywords");
await db.execute("DELETE FROM suppliers");
await db.execute("DELETE FROM categories");
@ -308,12 +310,28 @@ export async function importTransactionsWithCategories(
}
}
// Re-insert transactions
// Create tracking records for import history
const sourceResult = await db.execute(
`INSERT INTO import_sources (name, description, date_format, delimiter, encoding, column_mapping, skip_lines)
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
["Data Import", "Imported from settings", "%Y-%m-%d", ",", "utf-8", "{}", 0]
);
const sourceId = sourceResult.lastInsertId;
const txCount = data.transactions?.length ?? 0;
const fileResult = await db.execute(
`INSERT INTO imported_files (source_id, filename, file_hash, row_count, status)
VALUES ($1, $2, $3, $4, $5)`,
[sourceId, filename, `data-import-${Date.now()}`, txCount, "completed"]
);
const fileId = fileResult.lastInsertId;
// Re-insert transactions linked to the import
if (data.transactions) {
for (const tx of data.transactions) {
await db.execute(
`INSERT INTO transactions (date, description, amount, category_id, original_description, notes, is_manually_categorized, is_split, parent_transaction_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
`INSERT INTO transactions (date, description, amount, category_id, original_description, notes, is_manually_categorized, is_split, parent_transaction_id, source_id, file_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
[
tx.date,
tx.description,
@ -324,6 +342,8 @@ export async function importTransactionsWithCategories(
tx.is_manually_categorized,
tx.is_split,
tx.parent_transaction_id,
sourceId,
fileId,
]
);
}
@ -331,20 +351,38 @@ export async function importTransactionsWithCategories(
}
export async function importTransactionsOnly(
data: ExportEnvelope["data"]
data: ExportEnvelope["data"],
filename: string
): Promise<void> {
const db = await getDb();
// Wipe transactions and import history
await db.execute("DELETE FROM transactions");
await db.execute("DELETE FROM imported_files");
await db.execute("DELETE FROM import_sources");
// Re-insert transactions
// Create tracking records for import history
const sourceResult = await db.execute(
`INSERT INTO import_sources (name, description, date_format, delimiter, encoding, column_mapping, skip_lines)
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
["Data Import", "Imported from settings", "%Y-%m-%d", ",", "utf-8", "{}", 0]
);
const sourceId = sourceResult.lastInsertId;
const txCount = data.transactions?.length ?? 0;
const fileResult = await db.execute(
`INSERT INTO imported_files (source_id, filename, file_hash, row_count, status)
VALUES ($1, $2, $3, $4, $5)`,
[sourceId, filename, `data-import-${Date.now()}`, txCount, "completed"]
);
const fileId = fileResult.lastInsertId;
// Re-insert transactions linked to the import
if (data.transactions) {
for (const tx of data.transactions) {
await db.execute(
`INSERT INTO transactions (date, description, amount, category_id, original_description, notes, is_manually_categorized, is_split, parent_transaction_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
`INSERT INTO transactions (date, description, amount, category_id, original_description, notes, is_manually_categorized, is_split, parent_transaction_id, source_id, file_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
[
tx.date,
tx.description,
@ -355,6 +393,8 @@ export async function importTransactionsOnly(
tx.is_manually_categorized,
tx.is_split,
tx.parent_transaction_id,
sourceId,
fileId,
]
);
}