Updated CHANGELOG

This commit is contained in:
maziggy
2026-08-10 13:57:58 +02:00
parent f982da2a49
commit 07495c5ae5
+3
View File
@@ -5,6 +5,7 @@ All notable changes to Bambuddy will be documented in this file.
## [1.2.6b1] - Unreleased
### Added
- **The bed can be held warm between chamber-heated prints, and a heat-soak that already happened is not paid for twice (#2727, contributed by @ticfinack)** — Back-to-back prints in ASA, ABS, PA or PC each soaked the chamber from cold, even when the print that just finished had left it at temperature. The chamber cooled during the minutes a plate sat waiting to be cleared, and then the next job spent its full soak putting the heat back. Two settings under **Queue** address that. **Keep bed warm between prints** holds the bed hot while a printer sits in FINISH waiting for its plate to be cleared and the next queued item needs chamber heat — the bed is the chamber's heating element here rather than a print surface, so the hold runs at the new **Keep-warm bed temperature** (90 °C by default, which is also above the threshold the common aftermarket chamber heaters switch on at), raised to the print's own bed temperature whenever that is higher. It only engages for filament that actually wants a hot chamber, worked out from what is loaded in the AMS, so a PLA or PETG job is skipped without anyone configuring anything. Alongside it, Bambuddy now samples each printer's chamber temperature into a rolling two-hour history and credits time the chamber has already spent at temperature against the next print's soak, shortening or skipping it. That credit is deliberately hard to earn: it stops at the newest reading, at any gap in the samples, and at the end of the last real dip below target, and a history that has gone stale credits nothing at all — the chamber can cross the threshold unobserved, so the full soak runs instead. A dip only counts once it has lasted six minutes, because an enclosed chamber cannot lose and regain several degrees quickly — measured on an X1C, cooling from 55 °C to below 48 °C takes between 23 and 73 minutes — so a brief low reading is a door being opened, which is exactly what a plate swap does during the window this feature runs in. The hold needs plate-clear confirmation and preheat both switched on, all three re-checked on every pass so turning one off stops the hold rather than leaving it running somewhere the interface can no longer reach. It is bounded by **Stop keeping warm after** (120 minutes by default): when that elapses the bed is switched off and does not re-arm, so a plate nobody clears cannot leave a bed hot all weekend. The hold is also released when the item is deleted, the queue empties, or a gate is switched off part-way through, and never when the printer reports a bed target other than the one Bambuddy set — a temperature you changed by hand is left alone. Off by default. Covered by backend tests.
- **A slim user listing, so an API client can put names to the ids it already gets back (#1894, reported by @MorganMLGman)** — Archives, the queue and the statistics endpoints all report ownership as a numeric `created_by_id`, and statistics accept it as a filter, but there was no way for an API key to find out whose id was whose: the only user listing returns emails, roles, group membership and every account's full permission set, so it is administrative and rejects keys outright. Anyone building against the API was left parsing ids out of somewhere else, or doing without. `GET /users/slim` now answers with `id` and `username` and nothing else. It is covered by the **Read Status** scope, because a key holding that scope could already filter statistics by any `created_by_id` it cared to guess — what was missing was only the ability to address the filter, not permission to use it. The full listing stays admin-only, and for groups there is a matching **List User Names** permission that grants the narrow read without the broad one. If all you need is your own id, `GET /auth/me` now answers that on its own and no user listing is involved.
- **Cost centers, budgets and a print ledger, for installs where somebody has to be billed (#1448, contributor @behrinml, requested in #1065)** — A print farm shared by a lab, a makerspace or a department has always been able to see what a print cost, but not to say whose budget it came out of. Bambuddy now has an optional billing layer that answers that. **Settings → Workflow → Billing** turns it on; it is off by default and nothing about an existing install changes until it is switched on. A **cost center** is a budget somebody can print against — a team, a course, a customer, a grant. Every user gets a private one automatically, so a personal install is usable the moment billing is enabled, and shared centers are created and staffed by an administrator with per-member permission to print against them. Each center carries an optional total or monthly budget; a center with no budget is explicitly unlimited rather than blocked. When a print is queued against a budgeted center, its cost is **reserved** rather than merely predicted, so a queue of ten jobs cannot each pass a check the tenth would fail — the reservation is released if the print never happens. The monthly window is configurable: pick the day it resets and the timezone that day is measured in, since a team spread across timezones otherwise disagrees about which month a print landed in. The estimate itself is computed on the server. The figure shown in the print dialog is a display hint, and the browser cannot lower it: budget enforcement uses Bambuddy's own calculation from the file's filament and the printer's rates, whatever the client sends. Completed prints are charged from the archive's measured cost, and a print that is aborted part-way is charged for the filament it actually used rather than the whole job. Every charge, deposit, withdrawal and administrative adjustment lands in a ledger on the new **Finance** page, which appears in the sidebar only while billing is on. Each charge carries a per-dispatch identity that survives restarts and reprints, so a job cannot be billed twice, and a charge that fails is reported through the UI and any configured notification provider rather than quietly not happening. Balances and budgets deliberately mean different things: a balance records what somebody has spent, and only a cost center's budget can stop a print. Personal balances count unassigned charges and the user's own private center; a print billed to a shared center does not touch the personal one. Four permissions gate the whole thing — `cost_centers:read_own`, `read_all`, `modify` and `create` — with the default Administrators group holding all four. Separately switchable, and off by default, is a **printer kill switch** that stops any print that starts on a printer without going through Bambuddy, so a farm that bills its users cannot be bypassed by sending a job straight from Bambu Studio. It stops the print, says so on screen and notifies. It also declines to act whenever it cannot prove ownership — a restart mid-print, a job Bambuddy dispatched but has not finished recording — because stopping a print is irreversible and refusing to act costs only a log line.
- **Nest projects under a master project and see the whole programme in one place (#1264, reporter @enjoylifenow)** — A project has always been a flat thing: a build with fifty parts and a build with two got the same single row, and the only way to keep a large job legible was to split it into separate projects that then knew nothing about each other. Projects can now be nested. The project dialog has a **Parent project** picker, so an assembly can sit under the build it belongs to, at whatever depth suits the work; the picker leaves out the project itself and anything already beneath it, because nesting a project inside its own branch is a loop rather than a hierarchy. A project that has sub-projects gains a second card reporting the whole tree at once — print jobs, parts, time, filament and total cost, with progress measured against every target in the tree added together. That card is deliberately separate from the project's own figures, which keep meaning exactly what they meant before: what this project printed, not what its sub-projects did. Each sub-project listed underneath now carries its own branch's totals rather than only a percentage, so the rows add up to the card above them instead of contradicting it. On the Projects page a sub-project is drawn inside its parent's group rather than as another card somewhere in the grid, because two cards that belong together cannot show it while they sit columns apart, however they are captioned; the group is ruled in the parent's own colour and nests as deep as the projects do. A sub-project whose parent is hidden by the status filter stays where it is and says which project it belongs to instead. Two things that only became reachable once the interface could reach them were fixed along the way: a project could be moved under its own sub-project, which the API refused only when a project was made its own direct parent, and a percentage shown against a sub-project was measured differently from the same percentage on the page it linked to. Deleting a project in the middle of a tree now lifts its sub-projects up to its own parent instead of cutting them loose at the top level.
@@ -17,6 +18,7 @@ All notable changes to Bambuddy will be documented in this file.
- **The slice dialog can edit the full print-parameter set, not just pick a preset** — Slicing from Bambuddy meant taking a process preset exactly as it came. Anything beyond that — one more wall for a bracket, supports for a single overhang, slower outer walls on a part that keeps scarring — meant going back to Bambu Studio, editing there, and re-exporting. The slice dialog now has a **Process settings** section carrying the whole tree: the same pages, groups and ordering the desktop slicer shows under Print Settings, with the same labels, tooltips, ranges and defaults, because they are extracted from the slicer's own sources rather than hand-picked. The dialog itself widens to make room: on a reasonably sized screen it now uses two columns, with every "what am I slicing with" decision — pipeline, printer, process, filaments, bed type, layout passes — kept together on the left and the settings panel given a column of its own on the right, open and ready rather than folded away. Narrower screens keep the single column and the collapsed panel. The settings a source file's designer changed (#2622) now live in this panel too, marked *from file* against the options they belong to instead of in a separate list further up the dialog — so there is one place that shows what a slice will actually use. Machine-coupled ones stay flagged and unticked as before, anything the panel has no entry for is listed by name rather than quietly dropped, and typing your own value still wins. Switching on "Use the file's built-in settings" greys the panel out rather than removing it, so the dialog does not appear to lose a feature when that toggle is flipped — it stays visible, says why it is inactive, and applies nothing. Options that select *which* filament prints a feature — support base and interface, and the per-region pickers for walls, infill and surfaces — list the filaments you actually picked on the left rather than asking for a slot number, so "support interface" can be set to the PVA in slot 2 by name. Defaults and ranges are read out of the slicer's C++ initialisers, so a few arrived in source form — the whole Line width group showed "0." rather than "0" — and those are now cleaned as the data is generated instead of being papered over at display time. Every field starts from the values your picked process preset actually sets, fetched by flattening it through the slicer sidecar — the same resolver that does the slicing, so the numbers cannot disagree with what a slice produces. A field you never touch shows the preset's value, and reverting returns to it. Where those values cannot be read the panel falls back to the slicer's own defaults and says why — a sidecar older than the feature, one that did not answer, or none configured at all — rather than presenting the defaults as if they were your preset's. The first is much the most likely, because the sidecar image is pulled independently of your Bambuddy version, so that message names the fix outright: update the sidecar image. It behaves the way the desktop one does. **Simple / Advanced / Expert** matches the slicer's own visibility tiers, search reaches across every page at once, changed settings are marked and individually revertable, and settings the slicer itself disables in your current configuration are greyed out — infill options with infill at zero, ironing options with ironing off — because Bambuddy evaluates the slicer's own enable rules rather than approximating them. Where a rule cannot be decided with certainty the setting stays editable, on the grounds that a missing control looks like a bug while a redundant one is merely ignored. Edits apply to one slice, are not saved into a preset, and are written after the source file's support configuration and any carried designer settings, so an explicit choice is never silently overridden; an untouched panel produces exactly the request it did before. Parameter names and descriptions are in English even where the rest of Bambuddy is not — several hundred strings lifted verbatim from the slicer, which is a separate job from translating Bambuddy's own interface. The dialog's own wording is translated in all locales. Wiki updated, covered by backend and frontend tests.
### Changed
- **Preheat no longer gives up on a chamber-heated print whose file carries no bed temperature (#2727, contributed by @ticfinack)** — Preheat read its bed target out of the slicer metadata, and a file that carried none — common in OrcaSlicer's `gcode.3mf` exports — made it skip the whole stage and start the print against a cold chamber, which is the outcome preheat exists to prevent. Where the print needs chamber heat the bed is simply how that heat is produced, so those jobs now heat the bed to the **Keep-warm bed temperature** instead of bailing out. A bed temperature found in the file still wins, and a print with no chamber requirement still skips, so no bed temperature is invented for the print itself; preheat's target is transient either way, since the print's own G-code sets its bed at start. **If you have preheat enabled and your files carry no bed temperature, dispatch will now take noticeably longer than it used to** — those jobs previously skipped straight to the upload and will now wait for the chamber to converge and soak, up to twenty minutes at the default wait and soak settings. This applies only with preheat switched on, and the two settings that govern it are unchanged. In the same pass, preheat gained the soak-crediting described above: on a printer that reports its chamber temperature, a soak the chamber has demonstrably already served is shortened or skipped rather than repeated. Both apply wherever preheat runs, not only under the new keep-warm toggle.
- **The G-code preview is now the slicer's own renderer** — Sliced files previewed through an embedded copy of a third-party viewer, shown in an iframe. It drew each move as a screen-space line, so a print came out stringy and shimmered wherever layers crossed; it coloured by filament slot only; and being a separate app inside a frame, it could be neither themed nor translated, and needed its own machinery to detect a proxy refusing the embed. It has been replaced by Bambuddy's own viewer built on **libvgcode**, the renderer OrcaSlicer draws its own preview with, so extrusions are solid volumes that occlude one another and a print reads the way it does on the desktop. Colour by **filament** — the default, showing the print in the colours you actually assigned — or by **feature**, where walls, infill, supports, bridges and the prime tower each take the slicer's own colour, or by **layer height** or **line width** on a graduated scale. Every entry in the legend is a switch: click a filament or a feature to take it out of the view, which genuinely removes it rather than hiding it behind what it was covering, so you can look inside a part without its supports in the way. The layer slider has both ends, so a band of layers can be isolated rather than only a top capped, and travel moves can be shown. Reading the file needed real care: BambuStudio annotates its G-code quite differently from OrcaSlicer, and it emits a tenth of its moves as arcs — reading only the one dialect showed a 52-layer print as 23,165 layers in a single colour, and ignoring the arcs punched holes through every curved wall and tree support. Both are handled, along with the helical travel lifts that look like arcs but lay down nothing. Covered by frontend tests.
- **The 3D and G-code previews are rendered properly rather than sketched** — The model preview drew every surface with the same flat shading, so a print read as a coloured silhouette with no form, and it sat marooned in the middle of the frame with a screenful of empty space above it. The framing was the plainer bug: the camera distance came from a fixed multiple of the model's largest dimension, which takes no account of the camera's field of view or the shape of the panel it is drawn in, so a tall narrow preview was framed as though it were square. It is now solved against the model's bounding sphere and both fields of view, and fills the frame whatever the panel's proportions. The model itself is lit by a generated environment rather than two lamps and a wash of ambient light, which is what gives a curved surface a gradient across it instead of one flat tone, and it now casts a contact shadow so it looks like it is resting on the plate rather than pasted in front of it. The G-code preview drew each move as a two-pixel line, which is why a sliced model came out stringy and shimmered where layers crossed — a line has no thickness in the scene, so it cannot hide the layer behind it. Moves are now drawn as solid extrusions with real width and height, and the print occludes itself the way it does in a desktop slicer. The modal's second tab is gone: G-code already has its own full-page viewer, and a preview of a model is a different question from a preview of a print. Covered by frontend tests.
- **The slice dialog's process and filament lists now leave out presets that belong to another printer** — They were already sorted by compatibility, but a preset for a different Bambu model still appeared, demoted to an "Other printers" group at the bottom of the dropdown. With a large cloud filament library that group is most of the list, so the filtering was doing little for the thing it was meant to help: finding the profile you actually want. Those presets are now held back, with the label reporting how many ("3 hidden") next to a **Show all** link that brings them back for that one dropdown. Two things are never hidden. A preset with no detectable printer — a custom or renamed profile — stays in the list, because absence of evidence is not evidence of incompatibility and hiding those would make people's own imported profiles vanish. And whatever is currently selected stays visible even when the list is collapsed, so a deliberate cross-printer pick, or one restored from a pipeline, is never silently discarded by being dropped from the options. Re-slicing for another printer remains fully supported, so this is a default view rather than a restriction. Fixing this also corrected a screen-reader bug in those dropdowns: the controls sat inside the label wrapping the select, which handed them the entire label as their spoken name. A separate defect surfaced alongside it — the filter did nothing at all when the selected printer was a preset you had edited, because BambuStudio names those copies with a leading "# " and the matcher did not know to look past it. On such a printer every preset read as "compatibility unknown", and profiles listing their compatible printers by name could be ruled out against the very printer they were cloned from.
@@ -25,6 +27,7 @@ All notable changes to Bambuddy will be documented in this file.
- **Error and warning toasts now stay up twice as long** — Every pop-up notification disappeared after three seconds regardless of what it said. That is about right for "Settings saved", which confirms something you just did and is skimmed rather than read, but errors and warnings are a different kind of message: they carry a reason, often one relayed from the printer or the backend, and they run to a couple of lines. Three seconds was not long enough to finish reading one, and a missed error message is gone for good — there is no notification history to go back to. Errors and warnings now hold for six seconds. Success and informational toasts keep the three-second default, so the common case of clicking something and seeing it confirmed is unchanged, and the close button and the manual dismiss work exactly as before on all of them. The background print-dispatch toast is unaffected: it stays up while it has work in progress and clears itself shortly after the last job settles. Covered by frontend tests.
### Fixed
- **Cancelling or deleting a queued item did not stop the preheat already running for it (#2727, contributed by @ticfinack)** — The cancel and delete routes write the item's new status to the database, and nothing else. A dispatch that had already begun preheating was parked in a sleep waiting for the chamber to reach temperature, where it could not see that write — so the heaters kept running out the rest of the wait and soak for a print that was not going to happen, twenty minutes at the default settings and longer if those have been raised, and the printer stayed marked busy the whole time, holding up every other job queued behind it. Those routes now tell the scheduler directly and the waits are taken in slices, so a cancelled preheat is abandoned within seconds and the heaters are switched off on the way out. The same unwinding now covers every other way a dispatch can end without starting a print — a failed upload, an error mid-dispatch, a plate whose file has gone missing — each of which used to leave the bed and chamber heating with nothing to turn them off. What preheat set is recorded and reversed, and a bed the printer reports at some other target is left alone rather than switched off, on the grounds that it belongs to whoever set it. A cancellation that lands after the upload has begun still starts the print, as it always has. Covered by backend tests.
- **STEP files were offered for server-side slicing, which cannot work** — The **Slice** action appeared on `.step` / `.stp` files and the backend accepted the job, but neither slicer can load one from its command line: OrcaSlicer 2.4.2 and Bambu Studio 02.07.01.62 both answer `Unknown file format. Input file must have .stl, .obj, .amf(.xml) extension.` So the file was read, converted and uploaded, and the failure came back as "The input model file to the slicer can not be parsed" — which reads as a corrupt model rather than an unsupported format. The Slice button and the pipeline action no longer appear on STEP files, and the endpoint refuses one up front with a message that says to export it as STL or 3MF first. **Open in Slicer** is unchanged and still hands STEP to the desktop application, which opens it perfectly well — that was always the working path for these files.
- **A large model was refused with "Slicer CLI failed (500): File too large" and no way to find out what was too large (#2802, reported by @zevulos)** — Server-side slicing of a big multi-colour project failed on every attempt, and the message pointed at nothing. The slicer sidecar caps the size of the model it will accept; that cap was fixed at 100 MB, which real MakerWorld projects exceed. Worse than the limit was how it arrived: the sidecar's upload layer reports a size rejection as a kind of error its own handler does not recognise, so it fell through to a generic **HTTP 500** carrying the bare words "File too large". A 500 reads as a crash inside the slicer, and Bambuddy's one good explanation about request size was written for the HTTP 413 that a reverse proxy sends, so it never appeared. The reporter did the only reasonable thing with what they were shown: set `MAX_FILE_SIZE`, `BODY_PARSER_LIMIT` and `EXPRESS_PAYLOAD_LIMIT`, restart everything, stop nginx in case it was interfering, and move the whole installation from Windows to Docker — none of which the sidecar reads, on a proxy that was never in the path. The cap is now **512 MB** by default and settable with `MAX_MODEL_UPLOAD_MB` on the slicer-api service, and the sidecar answers an oversized upload with a 413 that names the limit and where it lives. Bambuddy recognises the rejection by what it says rather than by its status code, so an installation still running an older sidecar image gets the same explanation — including that the fix there is to update the image, since those have no setting to change. Two things followed from the same misreading: the failure was classed as a slicer crash, so every attempt retried the identical oversized upload "with embedded settings", spending a second 25-second conversion on a guaranteed-identical answer; and nothing anywhere recorded the size of what was being sent, so the support package from a slice that died on an upload cap looked exactly like one that died on a bad profile. Both are fixed — the retry is skipped, and each slice logs the model's size. Raising the cap also changed how the sidecar handles the upload: the model is streamed to disk instead of being held whole in memory, so a 512 MB project no longer costs half a gigabyte of RAM per concurrent slice on the small machines most likely to be running it. **This needs a sidecar update to take effect** — `cd slicer-api/ && docker compose pull && docker compose up -d`.
- **`/auth/me` described API keys as administrators they were never allowed to be (#1894, reported by @MorganMLGman)** — Asked to identify an API key, Bambuddy answered with a synthetic administrator: user id `0`, role `admin`, `is_admin: true`, and every permission in the system. None of that was true. An API key cannot reach an administrative route at all, whatever its scopes and whoever owns it, so a client that built its interface from this answer — which is exactly what a native app does — offered buttons that failed with a permission error the moment anyone pressed one, and still had no way to learn which user id its own prints were filed under. The endpoint now reports the key's **owner** as its identity, `is_admin: false`, and a permission list containing precisely what the key's scopes admit, so what a client is told matches what it will be allowed to do. Keys created before keys had owners have no identity to report and keep the old `id: 0` placeholder, but they no longer claim to be administrators either. Clients that branched on `is_admin` or `role` should branch on `permissions` instead.