Cross-cutting · File upload, gallery & image modal
The shared upload and media-browsing layer behind store images, proposal images and audio, centre branding, app-button images, intranet files and CSV uploads — with type and size restrictions, aspect-ratio guidance, a gallery picker and a full-size image modal.
| Area | Cross-cutting |
| Routes | (used by most editors) |
| Centre modules | always available |
| Staff levels | as per the host screen |
| Models | intranet-file |
| UI label | error.file.type.not_allowed |
| Coverage | 5 use cases · 1 happy · 5 failure |
How it works
api-files.uploadFile(file, …) is the single upload entry point and returns a file_url that models store as a string rather than as a binary relationship, which is why the same component works for images, audio, PDFs and CSVs. Three shared error strings cover every caller (error.file.type.not_allowed, error.file.oversize, error.file.not_allowed), so a failed upload reads the same everywhere even though the limits differ by context — the proposal audio limit of 10 MB, for example, is only stated in its own message. enums/aspectRatio and enums/orientations drive the cropping guidance, and img-modal provides the zoom view.
Use cases
Why someone opens this (5)
- Uploading a store logo at the right aspect ratio.
- Attaching a hero image to a proposal, or picking one already uploaded from the gallery.
- Uploading a PDF to the intranet document library.
- Attaching an audio description to a proposal for accessibility.
- Uploading a CSV as part of an import.
Path map
flowchart LR F(["File upload, gallery and image modal"]):::feat F --> H1["Image uploaded and attached"]:::ok F -.-> X1["Disallowed file type"]:::bad F -.-> X2["File too large"]:::bad F -.-> X3["Upload rejected"]:::bad F -.-> X4["Required image left empty"]:::bad F -.-> X5["Orphaned uploads"]:::bad classDef feat fill:#8c5a3c,stroke:#8c5a3c,color:#ffffff,font-weight:bold classDef ok fill:#e3f1ea,stroke:#0d6b42,color:#0d4a2e classDef bad fill:#f7e6e2,stroke:#9a2d1c,color:#6e1f13
Happy paths
Image uploaded and attached
- User opens the file field in an editor and selects an image within the allowed types and size.
api-files.uploadFilestores it and returns the URL.- The URL is written to the model attribute and the thumbnail renders.
- The gallery can be used later to reuse the same asset.
Failure paths
Disallowed file type
Cause — Extension outside
enums/file-extensionsfor that field.What happens —
error.file.type.not_allowed.
File too large
Cause — Exceeds the context’s size limit.
What happens —
error.file.oversize; the proposal audio path has its own more specific message naming the 10 MB cap.
Upload rejected
Cause — Storage or API failure.
What happens —
error.file.not_allowed— a generic catch-all that does not distinguish a rejected file from a failed upload.
Required image left empty
Cause — A mandatory image field not filled.
What happens — Enforced by the host model (e.g.
error.commerce.imageUrl.required,required+proposal.app-image,error.mof.image.required).
Orphaned uploads
Cause — A file is uploaded but the form is then abandoned.
What happens — Not handled — the asset remains stored with no record referencing it.
QA checklist
Tick these off while regression-testing this feature. The boxes are plain Markdown, so progress is visible in git diffs.
- ✅ Image uploaded and attached
- ⛔ Disallowed file type
- ⛔ File too large
- ⛔ Upload rejected
- ⛔ Required image left empty
- ⛔ Orphaned uploads
Implementation
app/components/nf-file-manager.jsapp/components/nf-file-manager-single.jsapp/components/nf-file-loader.jsapp/components/nf-input-file.jsapp/components/file-gallery.jsapp/components/file-image.jsapp/components/file-size.jsapp/components/files-loader.jsapp/components/nf-img-modal.jsapp/services/api-files.jsapp/services/explore-files.jsapp/services/img-modal.jsapp/enums/file-extensions.jsapp/enums/file-type-assets.jsapp/enums/aspectRatio.js
Translation keys (6)
Key English error.file.type.not_allowedFile type not allowed error.file.oversizeFile exceeds the maximum file size error.file.not_allowedFile not allowed ImageImage new_folderNew folder folder.success-createdSuccess created
Related
- Same area — CSV import engine · Data export engine (email delivery) · Filter & segment builder component · Multi-language content authoring · Realtime updates (Pusher) · Role & module permission layer · Error presentation & API error mapping · Product analytics & error monitoring
- Shares data with — Files management
Generated from doc/feature-inventory.json · id xc-file-manager · commit 276788ca6