mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-09 15:35:39 +02:00
fix(queue): persist clear plate state across page refresh (#410)
After clicking "Clear Plate & Start Next", refreshing the page showed the button again because the frontend determined the state purely from the printer's FINISH/FAILED status. The backend already tracked a plate_cleared flag in memory but never exposed it to the frontend. - Add plate_cleared field to PrinterStatus schema and API response - Pass plateCleared prop to PrinterQueueWidget - Skip clear plate UI when plate is already acknowledged - Add 2 tests for plateCleared=true behavior
This commit is contained in:
@@ -71,6 +71,7 @@ All notable changes to Bambuddy will be documented in this file.
|
||||
### New Features
|
||||
- **External Links: Open in New Tab** ([#338](https://github.com/maziggy/bambuddy/issues/338)) — External sidebar links can now optionally open in a new browser tab instead of an iframe. Sites behind reverse proxies (Traefik, nginx) that send `X-Frame-Options: SAMEORIGIN` or CSP `frame-ancestors` headers block iframe embedding, causing "refused to connect" errors. A new "Open in new tab" toggle in the add/edit link modal lets users choose per-link. Keyboard shortcuts (number keys) also respect the setting. Defaults to iframe (existing behavior) for backward compatibility.
|
||||
- **Print Queue: Clear Plate Confirmation** — When a print finishes or fails and more items are queued, the printer card now shows a "Clear Plate & Start Next" button. The scheduler no longer auto-starts the next print while the printer is in FINISH or FAILED state — the user must confirm the build plate has been cleared first. This prevents prints from starting on a dirty plate. The button respects the `printers:control` permission and is available in all supported languages (en/de/ja).
|
||||
- **Clear Plate State Persists Across Page Refresh** ([#410](https://github.com/maziggy/bambuddy/issues/410)) — After clicking "Clear Plate & Start Next", refreshing the page showed the Clear Plate button again because the frontend determined the state purely from the printer's FINISH/FAILED status. The `plate_cleared` flag is now included in the printer status API response, so the widget correctly shows the passive queue link instead of the Clear Plate button after acknowledgment — even after a page refresh.
|
||||
|
||||
### Improved
|
||||
- **Skip Objects: Confirmation Dialog** ([#346](https://github.com/maziggy/bambuddy/issues/346)) — Added a warning confirmation modal before skipping an object during a print. Shows the object name and warns the action is irreversible. Prevents accidentally skipping the wrong object. Translated in all 4 locales (en, de, ja, it).
|
||||
|
||||
@@ -466,6 +466,7 @@ async def get_printer_status(
|
||||
big_fan2_speed=state.big_fan2_speed,
|
||||
heatbreak_fan_speed=state.heatbreak_fan_speed,
|
||||
firmware_version=state.firmware_version,
|
||||
plate_cleared=printer_manager.is_plate_cleared(printer_id),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -245,3 +245,5 @@ class PrinterStatus(BaseModel):
|
||||
heatbreak_fan_speed: int | None = None # Hotend heatbreak fan
|
||||
# Firmware version (from info.module[name="ota"].sw_ver)
|
||||
firmware_version: str | None = None
|
||||
# Queue: user has acknowledged plate is cleared for next queued print
|
||||
plate_cleared: bool = False
|
||||
|
||||
@@ -101,6 +101,28 @@ describe('PrinterQueueWidget - Clear Plate', () => {
|
||||
expect(link).toHaveAttribute('href', '/queue');
|
||||
});
|
||||
});
|
||||
|
||||
it('shows passive link when FINISH but plateCleared is true', async () => {
|
||||
render(<PrinterQueueWidget printerId={1} printerState="FINISH" plateCleared={true} />);
|
||||
|
||||
await waitFor(() => {
|
||||
const link = screen.getByRole('link');
|
||||
expect(link).toHaveAttribute('href', '/queue');
|
||||
});
|
||||
|
||||
expect(screen.queryByText('Clear Plate & Start Next')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows passive link when FAILED but plateCleared is true', async () => {
|
||||
render(<PrinterQueueWidget printerId={1} printerState="FAILED" plateCleared={true} />);
|
||||
|
||||
await waitFor(() => {
|
||||
const link = screen.getByRole('link');
|
||||
expect(link).toHaveAttribute('href', '/queue');
|
||||
});
|
||||
|
||||
expect(screen.queryByText('Clear Plate & Start Next')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('clear plate button shows queue info', () => {
|
||||
|
||||
@@ -250,6 +250,8 @@ export interface PrinterStatus {
|
||||
big_fan2_speed: number | null; // Chamber/exhaust fan
|
||||
heatbreak_fan_speed: number | null; // Hotend heatbreak fan
|
||||
firmware_version: string | null; // Firmware version from MQTT
|
||||
// Queue: user has acknowledged plate is cleared for next queued print
|
||||
plate_cleared: boolean;
|
||||
}
|
||||
|
||||
export interface PrinterCreate {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { parseUTCDate } from '../utils/date';
|
||||
interface PrinterQueueWidgetProps {
|
||||
printerId: number;
|
||||
printerState?: string | null;
|
||||
plateCleared?: boolean;
|
||||
}
|
||||
|
||||
function formatRelativeTime(dateString: string | null): string {
|
||||
@@ -26,7 +27,7 @@ function formatRelativeTime(dateString: string | null): string {
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
|
||||
export function PrinterQueueWidget({ printerId, printerState }: PrinterQueueWidgetProps) {
|
||||
export function PrinterQueueWidget({ printerId, printerState, plateCleared }: PrinterQueueWidgetProps) {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const { showToast } = useToast();
|
||||
@@ -56,7 +57,7 @@ export function PrinterQueueWidget({ printerId, printerState }: PrinterQueueWidg
|
||||
return null;
|
||||
}
|
||||
|
||||
const needsClearPlate = printerState === 'FINISH' || printerState === 'FAILED';
|
||||
const needsClearPlate = (printerState === 'FINISH' || printerState === 'FAILED') && !plateCleared;
|
||||
|
||||
if (needsClearPlate) {
|
||||
return (
|
||||
|
||||
@@ -2471,7 +2471,7 @@ function PrinterCard({
|
||||
</div>
|
||||
|
||||
{/* Queue Widget - always visible when there are pending items */}
|
||||
<PrinterQueueWidget printerId={printer.id} printerState={status.state} />
|
||||
<PrinterQueueWidget printerId={printer.id} printerState={status.state} plateCleared={status.plate_cleared} />
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -23,7 +23,7 @@
|
||||
|
||||
<!-- Splash screens for iOS -->
|
||||
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
|
||||
<script type="module" crossorigin src="/assets/index-NiP_88T6.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-D8lA4NE5.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DF7TfzH1.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user