diff --git a/.gitignore b/.gitignore index 4ce5750..614da9b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ dist/ downloads/ eggs/ .eggs/ -lib/ +#lib/ lib64/ parts/ sdist/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index c34cc6f..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "frontend/extras"] - path = frontend/extras - url = https://git.neulandlabor.de/j3d1/vue-extras.git diff --git a/deploy/dev/Dockerfile.frontend b/deploy/dev/Dockerfile.frontend index 02b9e79..cdba36e 100644 --- a/deploy/dev/Dockerfile.frontend +++ b/deploy/dev/Dockerfile.frontend @@ -9,7 +9,7 @@ RUN mkdir /git # A wildcard is used to ensure both package.json AND package-lock.json are copied COPY package.json ./ -COPY extras/ ./extras/ +#COPY extras/ ./extras/ RUN npm install CMD [ "npm", "run", "dev", "--", "--host"] diff --git a/deploy/dev/instance_b/nginx-b.dev.conf b/deploy/dev/instance_b/nginx-b.dev.conf index 4fda10c..8953a08 100644 --- a/deploy/dev/instance_b/nginx-b.dev.conf +++ b/deploy/dev/instance_b/nginx-b.dev.conf @@ -1,3 +1,10 @@ +# Worker stays unprivileged as the image's default "nginx" user, but gains the "root" group so +# it can read /var/www/userfiles - backend-b (running as root) writes those with +# FILE_UPLOAD_DIRECTORY_PERMISSIONS=0750, group-readable but not world-readable. Mirrors +# deploy/prod/playbook.yml's "Allow nginx to read backend user files" (www-data joins the +# backend's file-owning group instead of loosening the mode). +user nginx root; + events {} http { diff --git a/deploy/prod/Dockerfile.frontend b/deploy/prod/Dockerfile.frontend index 1def462..fb16084 100644 --- a/deploy/prod/Dockerfile.frontend +++ b/deploy/prod/Dockerfile.frontend @@ -15,7 +15,7 @@ ARG GIT_COMMIT=unknown ENV GIT_COMMIT=$GIT_COMMIT COPY package.json package-lock.json ./ -COPY extras/ ./extras/ +#COPY extras/ ./extras/ RUN npm ci COPY . . RUN npm run build diff --git a/docs/implementation.md b/docs/implementation.md index 04adb81..700e20c 100644 --- a/docs/implementation.md +++ b/docs/implementation.md @@ -229,6 +229,9 @@ In `FotoFirstBulkImportWorkflow.vue`, `photos`' durable state is the `WorkflowIn Once a photo finishes uploading, the gallery switches it to the server-fetched thumbnail by re-looking it up by hash rather than mutating the closed-over `photo` object from the upload closure - that reference predates the `this.photos.push()` call, so it's the raw object, not the reactive proxy Vue tracks, and writing to it wouldn't trigger a re-render. +### Bulk Label Print Workflow +`BulkLabelPrintWorkflow.vue` implements the `bulk-label-print` workflow: step 1 collects a kind/owner/id range plus a label layout (reusing `LabelLayoutPreview.vue` for the template grid, previewed against the range's first id); step 2 connects a printer (or falls back to PNG downloads, same device-chip/PNG-Export pattern as `Print.vue`) and, on start, sequentially renders and prints/downloads one label per id in the range via `label.js`'s `drawLabel`, logging each id's outcome. `MAX_RANGE_SIZE` caps a single run so a mistyped range can't queue an unbounded number of labels. + ### Foto First Bulk Import Workflow `FotoFirstBulkImportWorkflow2.vue` implements every step of the `foto-first-bulk-import` workflow (photo capture, image processing, item detail entry, import completion) in a single component. Keeping the whole workflow in one file avoids splitting closely related state (photos, processed images, completed items) across many small step components and their prop/emit boundaries. @@ -271,3 +274,10 @@ An inventory item's properties are encoded into the `properties` CSV cell as a c ### Print Link Shape `printLinkFor` in `Inventory.vue` and `StorageLocation.vue` (and the print buttons in `InventoryDetail.vue`/`StorageLocationDetail.vue`) all route to `Print.vue` with the same `{kind, userHandle, id}` query shape - the thing's raw identity - rather than any pre-built link. `kind` is one of `CONTENT_KINDS`' ids (`"item"`/`"storage-location"`, see Content Kinds Registry above); `label.js`'s `buildLabelFields` reads it generically since every kind's prefill now shares this one shape. That lets the print page derive every representation it needs (qualified handle, owner handle, URL, short link, …) itself, instead of being tied to whichever one the calling button happened to construct. Group-owned items have no individual owner handle - `short-id.js`'s `group_item` kind resolves them via `owner_group` instead (see `shortIdLink`) - so there's no `{userHandle, id}` to build yet; `Inventory.vue`'s `printLinkFor` returns `null` for them until group print support exists. Storage locations are always individually owned (see `StorageLocationViewSet.get_queryset`), so `StorageLocation.vue`'s version never has that fallback to make. + +## Categories + +### Category Tree Reconstruction From Flat Path Strings +`Category` (`backend/toolshed/models.py`) is a real parent/children tree (self-referencing FK), but `combined_info`'s `/api/v1/info/` response (`backend/toolshed/api/info.py`) flattens every category to `str(category)` - a `/`-joined ancestor path (`Category.__str__`) - with every ancestor and descendant listed as its own separate string, not nested. `Admin.vue`'s `categoryTree` computed rebuilds the hierarchy client-side by splitting each path on `/` and grouping nodes by shared prefixes, then renders it with `TreeView.vue` (`frontend/src/components/TreeView.vue`), a generic recursive collapsible tree component built for single-line slot content. + +`StorageLocation` (`backend/toolshed/models.py`) is the same self-referencing-FK shape, but its `StorageLocationSerializer` keeps `parent` as a real owner-scoped id rather than flattening it away, so `Admin.vue`'s `storageLocationTree` and `StorageLocation.vue`'s `locationTree` computeds group nodes by that id directly instead of parsing path strings - the same tree-from-flat-list pattern, one step simpler since the parent relation already survives serialization. diff --git a/frontend/extras b/frontend/extras deleted file mode 160000 index 21bf28a..0000000 --- a/frontend/extras +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 21bf28a8b6293872f5f7a42c9ca0bc12ede5aaae diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9a3cb1d..0a7dc29 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -887,9 +887,6 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "extras": { - "version": "file:extras" - }, "fast-diff": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index bff1287..1fac118 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,7 +17,6 @@ "vue-multiselect": "^2.1.7", "vue-router": "^4.1.6", "vuex": "^4.1.0", - "extras": "file:./extras", "jquery": "^3.6.0", "popper.js": "^1.16.1" }, diff --git a/frontend/src/components/BaseLayout.vue b/frontend/src/components/BaseLayout.vue index 3ffe9a7..17b5ad0 100644 --- a/frontend/src/components/BaseLayout.vue +++ b/frontend/src/components/BaseLayout.vue @@ -9,7 +9,7 @@