intermittent commit
This commit is contained in:
@@ -4,7 +4,6 @@ type XlsxWorkbookSheet = {
|
||||
data: unknown[][];
|
||||
};
|
||||
type XlsxWorkbookReader = (input: ArrayBuffer) => Promise<XlsxWorkbookSheet[]>;
|
||||
type RawXlsxWorkbookReader = (input: unknown) => Promise<XlsxWorkbookSheet[]>;
|
||||
|
||||
export type ImportFieldDefinition = {
|
||||
name: string;
|
||||
@@ -16,7 +15,11 @@ export type ImportFieldDefinition = {
|
||||
|
||||
export type ImportAttachmentBasePath = {
|
||||
id?: string;
|
||||
name?: string;
|
||||
path?: string;
|
||||
source?: string;
|
||||
allow_individual?: boolean;
|
||||
unsent_warning?: boolean;
|
||||
};
|
||||
|
||||
export type RecipientImportMode = "append" | "replace";
|
||||
@@ -29,7 +32,7 @@ export type CsvParseOptions = {
|
||||
quoted: boolean;
|
||||
};
|
||||
|
||||
export type RecipientImportSourceType = "csv" | "xlsx" | "text";
|
||||
export type RecipientImportSourceType = "csv" | "xlsx" | "text" | "addresses";
|
||||
|
||||
export type RecipientColumnKind = "ignore" | "id" | "active" | "name" | "from" | "to" | "cc" | "bcc" | "reply_to" | "field" | "new_field" | "attachment_pattern";
|
||||
|
||||
@@ -99,6 +102,10 @@ export type RecipientImportProvenance = {
|
||||
imported_at: string;
|
||||
mode: RecipientImportMode;
|
||||
source_type: RecipientImportSourceType;
|
||||
source_id?: string | null;
|
||||
source_label?: string | null;
|
||||
source_revision?: string | null;
|
||||
source_provenance?: Record<string, unknown>;
|
||||
filename?: string | null;
|
||||
sheet_name?: string | null;
|
||||
encoding?: string | null;
|
||||
@@ -211,15 +218,6 @@ async function loadXlsxWorkbookReader(): Promise<XlsxWorkbookReader> {
|
||||
const module = await import("read-excel-file/browser");
|
||||
return module.default as XlsxWorkbookReader;
|
||||
}
|
||||
const globals = globalThis as typeof globalThis & {
|
||||
Buffer?: { from(input: ArrayBuffer): unknown };
|
||||
process?: { versions?: { node?: string } };
|
||||
};
|
||||
if (globals.process?.versions?.node && globals.Buffer?.from) {
|
||||
const dynamicImport = new Function("specifier", "return import(specifier)") as (specifier: string) => Promise<{ default: RawXlsxWorkbookReader }>;
|
||||
const module = await dynamicImport("read-excel-file/node");
|
||||
return (input: ArrayBuffer) => module.default(globals.Buffer!.from(input));
|
||||
}
|
||||
const module = await import("read-excel-file/universal");
|
||||
return module.default as XlsxWorkbookReader;
|
||||
}
|
||||
@@ -463,6 +461,37 @@ options: MaterializeImportOptions)
|
||||
};
|
||||
}
|
||||
|
||||
export function materializeRecipientImportWithAttachmentDefaults(
|
||||
draft: Record<string, unknown>,
|
||||
preview: RecipientImportPreview,
|
||||
options: MaterializeImportOptions)
|
||||
: Record<string, unknown> {
|
||||
const needsAttachmentSource = importedRowsNeedAttachmentSource(preview);
|
||||
const currentAttachments = asRecord(draft.attachments);
|
||||
let nextBasePaths = normalizeImportAttachmentBasePaths(currentAttachments.base_paths, currentAttachments, true);
|
||||
let attachmentBasePath: ImportAttachmentBasePath | null = null;
|
||||
|
||||
if (needsAttachmentSource) {
|
||||
if (nextBasePaths.length === 0) {
|
||||
nextBasePaths = [{ id: "base-path-campaign", name: "Campaign files", path: ".", allow_individual: true, unsent_warning: false }];
|
||||
}
|
||||
const selectedIndex = Math.max(0, nextBasePaths.findIndex((basePath) => basePath.allow_individual));
|
||||
nextBasePaths = nextBasePaths.map((basePath, index) => index === selectedIndex ? { ...basePath, allow_individual: true } : basePath);
|
||||
attachmentBasePath = options.attachmentBasePath ?? nextBasePaths[selectedIndex] ?? null;
|
||||
}
|
||||
|
||||
const importedDraft = materializeRecipientImport(draft, preview, { ...options, attachmentBasePath });
|
||||
if (!needsAttachmentSource) return importedDraft;
|
||||
return {
|
||||
...importedDraft,
|
||||
attachments: {
|
||||
...asRecord(importedDraft.attachments),
|
||||
base_paths: nextBasePaths,
|
||||
base_path: nextBasePaths[0]?.path || "."
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createRecipientImportProvenance(input: {
|
||||
preview: RecipientImportPreview;
|
||||
mappings: RecipientColumnMapping[];
|
||||
@@ -513,6 +542,27 @@ export function importedRowsNeedAttachmentSource(preview: RecipientImportPreview
|
||||
return preview.rows.some((row) => row.issues.length === 0 && row.patterns.length > 0);
|
||||
}
|
||||
|
||||
function normalizeImportAttachmentBasePaths(value: unknown, attachments: ImportRecord, fallbackAllowIndividual = false): ImportAttachmentBasePath[] {
|
||||
if (Array.isArray(value) && value.length > 0) {
|
||||
return value.filter(isRecord).map((basePath, index) => ({
|
||||
id: getText(basePath, "id", `base-path-${index + 1}`),
|
||||
name: getText(basePath, "name", `Base path ${index + 1}`),
|
||||
source: getText(basePath, "source"),
|
||||
path: getText(basePath, "path", index === 0 ? getText(attachments, "base_path", ".") : "."),
|
||||
allow_individual: getBool(basePath, "allow_individual"),
|
||||
unsent_warning: getBool(basePath, "unsent_warning")
|
||||
}));
|
||||
}
|
||||
|
||||
return [{
|
||||
id: "base-path-campaign",
|
||||
name: "Campaign files",
|
||||
path: getText(attachments, "base_path", "."),
|
||||
allow_individual: getBool(attachments, "allow_individual", fallbackAllowIndividual),
|
||||
unsent_warning: false
|
||||
}];
|
||||
}
|
||||
|
||||
function importedRowToEntry(row: ImportedRecipientRow, attachmentBasePath?: ImportAttachmentBasePath | null): Record<string, unknown> {
|
||||
return {
|
||||
id: row.id,
|
||||
@@ -815,6 +865,14 @@ function getText(record: ImportRecord, key: string, fallback = ""): string {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function getBool(record: ImportRecord, key: string, fallback = false): boolean {
|
||||
const value = record[key];
|
||||
if (typeof value === "boolean") return value;
|
||||
if (typeof value === "string") return ["1", "true", "yes", "on"].includes(value.toLowerCase());
|
||||
if (typeof value === "number") return value !== 0;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function humanizeFieldName(value: string): string {
|
||||
return value.replace(/[_-]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user