Repository navigation
Prints: a 3D print library with folders and groups - #341
Merged
Merged
Conversation
Each file lives once, in a folder, and belongs to smart groups worked out
from its details (season and robot, subsystem, material, print status) and
to any collections the team makes, without copies. The explorer shows
folders and groups side by side; picks combine ("Intake + PETG + To print").
- Upload by button or drag and drop (STL, 3MF, STEP/STP, OBJ, G-code),
rename, move (drag or "Move to"), delete with confirmation, folder delete
that says how many files, single and ZIP downloads, search, list and grid
views, sorting by name, date or size.
- 3D preview for STL/3MF/OBJ with three.js (lazy), and browser-drawn
thumbnails on grid tiles; STEP and G-code show an icon.
- Details: who added it and when, size, notes, robot/season, the CAD part it
prints (its section is the subsystem and its quantity the copies needed),
material, status and copies printed, collections, history.
- Bytes on the VM's disk under PRINTS_DIR at random keys; per-file limit,
per-workspace quota checked inside the insert, and a free-disk reserve.
- manage_prints role permission (granted wherever manage_cad is); members
view and download. Every change goes to print_activity.
- fileControlKitPrint() files a Control Kit print under
"Season / Robot / Control Kit" for the import to call.
Collaborator
Author
|
@greptile review |
[Medium impact] The latest changes appear safe to merge. SummaryAdds a workspace print library with folders, groups, previews, downloads, permissions, and Control Kit imports. The latest changes address the two most recent review threads:
No new actionable issues were found in these changes.
|
…tions; workspace-bound writes; thumbnails in the quota - Bulk move keeps the destination's names taken, so a same-named file becomes "(2)". - Uploads, moves and new folders check the destination inside the write; a folder move re-checks that the new parent is not inside it in the same statement; a folder delete re-reads its subtree and stops when the confirmed file count changed meanwhile. - The page names its workspace on every write (X-CP-Prints-Team); a write after a workspace switch is refused, and a queued upload stops there or when the page closes. - Marking one file printed fills its copies printed, as the bulk action does. - Thumbnails count toward the workspace quota and the disk reserve. - ZIPs refuse more than 65,535 entries; New folder shows on phones; F2 and Delete work on grid folders.
Collaborator
Author
|
@greptile review |
…ords changes that happened
The zip Control Kit uploads after a send (contract v1.2 §6) is read after the answer: each STEP in its 3D_print folder is filed for the import's robot under "Season / Robot / Control Kit", named after its part from MANIFEST.txt and linked to the CAD part its file name carries. A re-send replaces Control Kit's file for the same part. CNC, 2D-cut and fabricate files stay only in the zip.
Collaborator
Author
|
@greptile review |
…any size by ticket; the copies stepper counts every click
Collaborator
Author
|
@greptile review |
…, one use; a waiting copies count never overrides Printed
Collaborator
Author
|
@greptile review |
Collaborator
Author
|
Production verification (merge commit 953128b):
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Prints: a 3D print library per workspace (Build → Prints,
/prints), shaped like a file explorer with grouping at its heart.React.lazy/import()exactly likeCadModelViewer. Grid tiles show a thumbnail the uploader's browser draws at upload (or the first time an editor opens the preview); STEP and G-code show an icon.manage_prints("Upload and organize 3D prints"). Migration 155 grants it to every role that already hasmanage_cad; new teams' Member and Verified Member roles get it; admins have*. Members without it view and download only (the UI is read-only for them; the server answers 403). Every route bindsauth.teamId; another workspace's ids are 404. Every change (upload, replace, rename, move, edit, status, collect/uncollect, delete, folder and collection create/rename/move/delete) is written toprint_activity.aria-pressed, the path bararia-current, and a polite live region announces counts and results. "Move to" is the non-drag way to move.scrollWidth - clientWidth = 0).Storage and limits
PRINTS_DIR(default<cwd>/.data/prints, so/opt/control-point/.data/printson the VM)..data/is already git-ignored and outside every statically served directory (notuploads/, whichexpress.staticserves publicly). Bytes are stored at random keys<team>/<32 hex>; names people type never become disk paths, and anything that isn't a key is refused before it reachespath.join. The deploy workflow only touches files in its manifest, so it never touches this directory. R2 is not used for prints..envchange needed for the defaults):PRINTS_MAX_FILE_MB= 100 MB per file (a large G-code; STL/3MF robot parts are usually far smaller).PRINTS_QUOTA_MB= 2 GB per workspace, enforced inside the INSERT itself so two uploads at once can't both pass.PRINTS_MIN_FREE_MB= 5 GB disk reserve: an upload that would leave less free space (checked withstatfsbefore and after the body arrives) gets 507 with a plain message.df -h /opt/control-pointand tune the three variables in/opt/control-point/.envif needed.Control Kit wiring
#340 (Control Kit downloads and part pictures, contract v1.2) merged while this PR was open; this branch merges it and wires Prints into it. When Control Kit uploads a send's STEP zip through
POST …/imports/:importId/files(stored as a CAD doc on the import's robot, unchanged),controlKitLink.tsnow also hands the zip toprints.fileControlKitStepZipafter answering (best effort, logged on failure; the dependency is the optionalfileStepZip, passed inserver.ts):3D_print/folder is filed under " / / Control Kit", linked to the robot. CNC, 2D-cut and fabricate files are not prints and stay only in the zip.MANIFEST.txt("Claw finger.step") and linked to the robot's CAD part whose identity the file name carries (Control Kit'sstepFileName:<name>__<partId>[__cfg<hash>].step, matched by part id and configuration hash; no link when none or several fit). So subsystem and copies needed follow the BOM.docs/control-kit-link.mdis not changed: the contract between the apps is the same; this is Control Point's own handling of a file it already receives.fileControlKitPrintandfilePrintremain exported for any other caller.Data
Migration
155-prints-library.sql(after #340's 154):print_folders,print_files,print_collections,print_collection_files,print_activity, plus themanage_printsgrant. New tables only.Tests
server/__tests__/prints.test.ts(real server): name and path validation and traversal (.., separators, reserved characters, a traversal name field, storage keys), per-file limit, quota (including after deletes), disk reserve (507), permissions (viewer vsmanage_printsvs admin) and cross-workspace 404s, folder uniqueness (case-insensitive), moving a folder into itself or a descendant, rename and move collisions, "(2)" on moves and uploads, folder delete asking with the count (and a stale count asking again) and removing bytes, collections without copies, bulk status and copies, CAD-derived subsystem and copies, downloads and ZIPs (entries verified by CRC), the activity record, andfileControlKitPrint(path, links, replace, unchanged, a person's file kept, errors).src/modern/__tests__/prints.test.tsx: folder view and path, combined groups with counts and chips, search, selection → mark printed, group "Download all", Move to picker, folder delete question with its count, drag onto a collection, Delete key, details from the CAD part, read-only view.npm run lintpasses. Related suites pass (publicRoutes,teamModules,modern,sidebarFooter,controlKitLink, CAD).pitDisplay.test.tsxtimes out the same way onmainon this machine.Screenshots
Local production build (
npm run build,NODE_ENV=production) against a throwaway SQLite file with fixture data (team "Fixture Robotics", generated STL/OBJ/STEP/G-code files uploaded through the page, so thumbnails are the real browser-drawn ones). Captured with Playwright at 1x, dark theme. No production account or data was used.A folder, list view:

A subsystem group, and three groups combined:


Grid with thumbnails (STEP and G-code show icons):

A collection with a selection, ready to mark printed or failed:

Details, with the subsystem and copies taken from the linked CAD part:

3D preview:

Deleting a folder that holds files:

Phone (390 px): folder, folders-and-groups sheet, and a combined group in grid view:



Not verified