diff --git a/.gitignore b/.gitignore index 614da9b..4ce5750 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ dist/ downloads/ eggs/ .eggs/ -#lib/ +lib/ lib64/ parts/ sdist/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c34cc6f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[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 cdba36e..02b9e79 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 8953a08..4fda10c 100644 --- a/deploy/dev/instance_b/nginx-b.dev.conf +++ b/deploy/dev/instance_b/nginx-b.dev.conf @@ -1,10 +1,3 @@ -# 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 fb16084..1def462 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 700e20c..04adb81 100644 --- a/docs/implementation.md +++ b/docs/implementation.md @@ -229,9 +229,6 @@ 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. @@ -274,10 +271,3 @@ 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 new file mode 160000 index 0000000..21bf28a --- /dev/null +++ b/frontend/extras @@ -0,0 +1 @@ +Subproject commit 21bf28a8b6293872f5f7a42c9ca0bc12ede5aaae diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0a7dc29..9a3cb1d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -887,6 +887,9 @@ "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 1fac118..bff1287 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,6 +17,7 @@ "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 17b5ad0..3ffe9a7 100644 --- a/frontend/src/components/BaseLayout.vue +++ b/frontend/src/components/BaseLayout.vue @@ -9,7 +9,7 @@