mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-18 21:47:39 +02:00
Feature: Scheduled drying (#2703)
* feat: add ScheduledDrying model for delayed drying runs (#2638) * Release the printer when a scheduled dry ends (#2638) _check_scheduled_dryings marks a printer as drying in _drying_in_progress, which is shared with auto-drying. Auto-drying prunes that map in _sync_drying_state(), but that call sits behind its enabled check, and this is the first writer that runs whether auto-drying is on or not. With it off -- the default -- nothing dropped the entry short of a print being dispatched to the same printer, so the next scheduled run parked on "already_drying" forever and queue_drying_block held that printer's prints too. A nightly off-peak dry with no printing in between is exactly the workflow this feature is for: night one worked, every night after it silently did not. The check now releases what it acquired, covering both a run that ends mid-pass and one cancelled through the route between passes. The retention prune ran on every pass. Issuing the DELETE is what opens a write transaction, this method is called every 3s while the queue dispatches, and rows only become prunable a week after they finish, so it is now gated to hourly on a monotonic stamp -- with the first pass after a restart still reaping whatever the dead process left behind. Both drying paths now pick the blocking dry_sf_reason through one rule. The immediate endpoint quoted whichever code the firmware listed first while the scheduler prioritised power over retract, so one blocked AMS read two ways depending on which button you pressed. drying_preflight.primary_reason_code holds the order and both call it, including the flame button's tooltip, which had no wording for filament at the outlet at all and sent those users to the generic "can't start drying right now". scheduled_drying joins the model list in init_db. The table was already created -- importing the package registers it -- but it was the only model relying on that indirection. Tests: the release (completion and route-cancel), the prune throttle, the shared reason rule, the tooltip priority, and four driving the real check_queue, which nothing covered before -- a pass with no rows still dispatching prints, a due row dispatching, and a failed row not stalling the queue behind it. Each one fails against the code it guards. --------- Co-authored-by: MartinNYHC <martin@bambuddy.cool> Co-authored-by: maziggy <mz@v8w.de>
This commit is contained in:
co-authored by
MartinNYHC
maziggy
parent
db94ea7971
commit
d37ce94f81
@@ -1,6 +1,20 @@
|
||||
export interface PopoverPosition {
|
||||
top: number;
|
||||
left: number;
|
||||
/** Which side of the trigger the popover landed on. */
|
||||
placement: 'below' | 'above';
|
||||
/**
|
||||
* Viewport y of the popover edge facing the trigger: the top edge for
|
||||
* 'below' (equals `top`), the bottom edge for 'above'. Anchoring an
|
||||
* 'above' popover by this edge (CSS `bottom`) lets late-appearing content
|
||||
* grow it upward, keeping it glued to the trigger.
|
||||
*/
|
||||
anchorY: number;
|
||||
/**
|
||||
* X-offset within the popover for an anchor arrow pointing at the
|
||||
* trigger's center, clamped inside the popover's rounded corners.
|
||||
*/
|
||||
arrowLeft: number;
|
||||
}
|
||||
|
||||
interface RectLike {
|
||||
@@ -38,10 +52,10 @@ export interface ComputePopoverPositionOpts {
|
||||
* Compute fixed-positioning coordinates for a popover anchored to a trigger.
|
||||
*
|
||||
* Default placement is BELOW the trigger, right-aligned to the trigger. Flips
|
||||
* to ABOVE the trigger when below would overflow the viewport (#1447 — the
|
||||
* AMS drying popover on the printer card sits at the bottom of the AMS row
|
||||
* and was rendering off the bottom of the viewport with the Start button
|
||||
* unreachable on smaller screens).
|
||||
* to ABOVE the trigger when below would overflow the viewport and above fits
|
||||
* (#1447: the AMS drying popover on the printer card sits at the bottom of
|
||||
* the AMS row and was rendering off the bottom of the viewport with the Start
|
||||
* button unreachable on smaller screens).
|
||||
*
|
||||
* Horizontal axis right-aligns to triggerRect.right and clamps to the
|
||||
* viewport with the configured margin so a trigger near the right edge
|
||||
@@ -72,15 +86,19 @@ export function computePopoverPosition(opts: ComputePopoverPositionOpts): Popove
|
||||
|
||||
// Vertical: prefer below, flip to above only when below overflows AND
|
||||
// above would actually fit. If neither fits (a popover taller than the
|
||||
// viewport), stay below — at least the top of the popover is visible
|
||||
// and the user can scroll inside it, which is better than flipping to a
|
||||
// top-clipped position where the action buttons might also be unreachable.
|
||||
// viewport), stay below: at least the top of the popover is visible and
|
||||
// the user can scroll to the rest, which beats flipping to a top-clipped
|
||||
// position where the action buttons might also be unreachable (#1447,
|
||||
// #1458, #1669). Callers that cap their own height still rely on this;
|
||||
// IndicatorControlPopover sets no maxHeight at all.
|
||||
let top = triggerRect.bottom + gap;
|
||||
let placement: PopoverPosition['placement'] = 'below';
|
||||
const wouldOverflowBottom = top + estimatedHeight > viewportHeight - margin;
|
||||
if (wouldOverflowBottom) {
|
||||
const aboveTop = triggerRect.top - gap - estimatedHeight;
|
||||
if (aboveTop >= margin) {
|
||||
top = aboveTop;
|
||||
placement = 'above';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,5 +113,9 @@ export function computePopoverPosition(opts: ComputePopoverPositionOpts): Popove
|
||||
left = Math.max(margin, viewportWidth - popoverWidth - margin);
|
||||
}
|
||||
|
||||
return { top, left };
|
||||
const anchorY = placement === 'above' ? triggerRect.top - gap : top;
|
||||
// Keep the arrow clear of the popover's rounded corners.
|
||||
const arrowLeft = Math.max(14, Math.min(popoverWidth - 14, triggerCenter - left));
|
||||
|
||||
return { top, left, placement, anchorY, arrowLeft };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user