Prefill file fields with their file_name joined from CiviCRM

CiviCRM APIv4 file custom fields return a bare file id by default; an
extra '.file_name' join is required to get the human-readable filename.
Both the form prefill walk (lib/prefill.ts) and the report walk
(app/api/report/route.ts) now request '<civiField>.file_name' for every
file-type field alongside the primary value, and wrap the prefill into
a { id, file_name } object so downstream UI has both. Falls back to
file_name undefined when the join returns null (eg orphaned id).

The form's FilePriorIndicator already accepts the object shape, so it
now shows the filename inline. The report's FormattedValue gets a
matching case: renders the file_name string if present, falls back to
'Attachment #<id>' when only the id came through.
This commit is contained in:
Joel Brock
2026-05-19 15:51:35 -07:00
parent a8ed6073a9
commit 9209d6dc02
3 changed files with 50 additions and 5 deletions
+22 -3
View File
@@ -39,7 +39,19 @@ export async function loadPrefill(
activityTypeName = "Org Engagement Submission",
): Promise<PrefillResult> {
const civiSelected = fields.filter((f) => f.civiField);
const select = ["id", "activity_date_time", ...new Set(civiSelected.map((f) => f.civiField!))];
// CiviCRM File custom fields return a file id by default. To surface a
// human-readable filename in the prefill (so the prior-attachment
// indicator can show it), also request the joined `.file_name` for any
// file-type field.
const fileFieldRefs = new Set(
civiSelected.filter((f) => f.type === "file").map((f) => f.civiField!),
);
const selectSet = new Set<string>(["id", "activity_date_time"]);
for (const f of civiSelected) selectSet.add(f.civiField!);
for (const ref of fileFieldRefs) selectSet.add(`${ref}.file_name`);
const select = Array.from(selectSet);
const res = await civi<ActivityRow>("Activity", "get", {
select,
@@ -56,10 +68,17 @@ export async function loadPrefill(
for (const f of civiSelected) {
for (const row of rows) {
const v = row[f.civiField!];
if (v !== null && v !== undefined && v !== "") {
if (v === null || v === undefined || v === "") continue;
if (f.type === "file") {
const fname = row[`${f.civiField!}.file_name`];
out[f.name] = {
id: v,
file_name: typeof fname === "string" ? fname : undefined,
};
} else {
out[f.name] = v;
break;
}
break;
}
}