Add attachments to service, maintenance, fuel and parts records
Documents already carried a single optional file: upload, download, detach,
access-checked on every request and proxied through this server, so PocketBase's
files are never public URLs. Service records, workshop visits, refills and
catalog parts all want the same thing — a receipt, an invoice, a photo of the
box — so extend it to them.
Rather than copy the document handlers four more times, lift them into one
shared layer. Every attachable collection has a car relation and a file field,
which is what lets a single set of handlers authorize and serve all of them. An
upload finishes by delegating to the collection's own GET handler, so the
response carries the full record — derived fields and all — exactly as a re-read
would. The web side gets the same treatment: one picker component and one
upload-after-save helper behind all five forms. Net effect is five features for
about the cost of the one that was already there.
Alongside:
- parts gain a notes field
- Reminders moves behind Parts catalog in the car detail tabs
- the changed-part labels spell out in full ("Oil & Oil filter" rather than
"Oil & filter"), and the form and table now agree
The PocketBase schema must be migrated before the new attachments work:
scripts/setup-pocketbase.mjs adds the file fields and parts.notes. It is
additive and safe to re-run.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e64c89a564
commit
07192f1238
+28
-8
@@ -88,6 +88,25 @@ async function requestBlob(path) {
|
||||
return { blob: await res.blob(), filename };
|
||||
}
|
||||
|
||||
// Attachments. Every record that can carry a file — documents, service records,
|
||||
// workshop visits, refills, catalog parts — exposes the same three endpoints
|
||||
// under its own path, so they are built from one place rather than spelled out
|
||||
// five times.
|
||||
//
|
||||
// The file is proxied by the API (PocketBase's files aren't public), so it needs
|
||||
// the auth header — hence a multipart POST and a Blob fetch rather than a plain
|
||||
// <a href>. Uploading addresses a record that must already exist; see
|
||||
// applyAttachment in lib/attachment.js for the order the forms use.
|
||||
const attachment = (path) => ({
|
||||
upload: (id, file) => {
|
||||
const form = new FormData();
|
||||
form.append("file", file);
|
||||
return requestForm(`${path}/${id}/file`, { method: "POST", body: form });
|
||||
},
|
||||
download: (id) => requestBlob(`${path}/${id}/file`),
|
||||
remove: (id) => request(`${path}/${id}/file`, { method: "DELETE" }),
|
||||
});
|
||||
|
||||
export const api = {
|
||||
// Auth
|
||||
login: (email, password) =>
|
||||
@@ -145,15 +164,16 @@ export const api = {
|
||||
updateDocument: (id, body) =>
|
||||
request(`/car-documents/${id}`, { method: "PATCH", body: JSON.stringify(body) }),
|
||||
deleteDocument: (id) => request(`/car-documents/${id}`, { method: "DELETE" }),
|
||||
// The attachment is proxied by the API (PocketBase files aren't public), so it
|
||||
// needs the auth header — hence a Blob fetch rather than a plain link.
|
||||
uploadDocumentFile: (id, file) => {
|
||||
const form = new FormData();
|
||||
form.append("file", file);
|
||||
return requestForm(`/car-documents/${id}/file`, { method: "POST", body: form });
|
||||
|
||||
// Attachments, one per record. Keyed by the same names CarDetail uses for its
|
||||
// tabs so a table row can reach for the right one generically.
|
||||
files: {
|
||||
documents: attachment("/car-documents"),
|
||||
services: attachment("/service-records"),
|
||||
maintenance: attachment("/maintenance"),
|
||||
fuel: attachment("/fuel-entries"),
|
||||
parts: attachment("/parts"),
|
||||
},
|
||||
getDocumentFileBlob: (id) => requestBlob(`/car-documents/${id}/file`),
|
||||
deleteDocumentFile: (id) => request(`/car-documents/${id}/file`, { method: "DELETE" }),
|
||||
|
||||
// Reminders. The list mixes stored reminders with read-only ones derived from
|
||||
// documents and service records (flagged `auto`; their ids start with "auto:").
|
||||
|
||||
Reference in New Issue
Block a user