mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 03:01:21 +02:00
fix(printers): hide chamber fan badge on open-frame Bambu models
The Printers page rendered three fan widgets (part / aux / chamber)
for every printer unconditionally. Open-frame models (A1, A1 Mini,
A2L, P1P) have no chamber fan — the firmware reports big_fan2_speed
as 0, so the badge always rendered greyed-out and let users "set" a
fan speed on hardware that doesn't exist.
Adds MODELS_WITH_CHAMBER_FAN allowlist (X1C / X1 / X1E / X2D / P1S /
P2S / H2D / H2D Pro / H2C / H2S) near mapModelCode, and the chamber
entry is spread into fanItems only when the printer's model is in the
set. Open-frame printers now show two badges (part + aux), which
matches their actual hardware.
Allowlist not denylist: mirrors the file's existing classification
pattern (the enclosure-door badge gate uses the same shape), and the
failure mode is preferable — a missing badge on a real chambered
printer is obvious; a phantom badge on a future open-frame model
would look correct and silently lie.
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -243,6 +243,73 @@ describe('PrintersPage', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('fan badges', () => {
|
||||
// Chamber fan only exists on enclosed Bambu models. Open-frame printers
|
||||
// (A1, A1 Mini, A2L, P1P) have no chamber fan — the firmware reports
|
||||
// big_fan2_speed as 0 there and the widget would be dead UI.
|
||||
const statusWithFans = {
|
||||
...mockPrinterStatus,
|
||||
cooling_fan_speed: 53,
|
||||
big_fan1_speed: 53,
|
||||
big_fan2_speed: 53,
|
||||
};
|
||||
|
||||
const renderWithPrinter = (printer: typeof mockPrinters[number]) => {
|
||||
server.use(
|
||||
http.get('/api/v1/printers/', () => HttpResponse.json([printer])),
|
||||
http.get('/api/v1/printers/:id/status', () => HttpResponse.json(statusWithFans)),
|
||||
);
|
||||
render(<PrintersPage />);
|
||||
};
|
||||
|
||||
it('hides chamber fan badge on A1 Mini (open-frame, no chamber fan)', async () => {
|
||||
renderWithPrinter({ ...mockPrinters[0], model: 'A1 Mini' });
|
||||
|
||||
await waitFor(() => {
|
||||
// Part-cooling badge confirms the fan row rendered.
|
||||
expect(screen.getByTitle('Part Cooling Fan')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByTitle('Auxiliary Fan')).toBeInTheDocument();
|
||||
expect(screen.queryByTitle('Chamber Fan')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('hides chamber fan badge on A1 (open-frame)', async () => {
|
||||
renderWithPrinter({ ...mockPrinters[0], model: 'A1' });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTitle('Part Cooling Fan')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.queryByTitle('Chamber Fan')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('hides chamber fan badge on P1P (open-frame)', async () => {
|
||||
renderWithPrinter({ ...mockPrinters[0], model: 'P1P' });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTitle('Part Cooling Fan')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.queryByTitle('Chamber Fan')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows chamber fan badge on X1C (enclosed)', async () => {
|
||||
renderWithPrinter({ ...mockPrinters[0], model: 'X1C' });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTitle('Chamber Fan')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByTitle('Part Cooling Fan')).toBeInTheDocument();
|
||||
expect(screen.getByTitle('Auxiliary Fan')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows chamber fan badge on P1S (enclosed)', async () => {
|
||||
renderWithPrinter({ ...mockPrinters[0], model: 'P1S' });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTitle('Chamber Fan')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('empty state', () => {
|
||||
it('shows empty state when no printers', async () => {
|
||||
server.use(
|
||||
|
||||
@@ -1465,6 +1465,23 @@ function getStatusDisplay(state: string | null | undefined, stg_cur_name: string
|
||||
}
|
||||
}
|
||||
|
||||
// Bambu models that ship with an enclosure chamber fan (firmware field
|
||||
// `big_fan2_speed`). Open-frame models (A1 / A1 Mini / A2L / P1P) have no
|
||||
// chamber fan — `big_fan2_speed` is meaningless / always 0 there, so the
|
||||
// widget is hidden in fanItems instead of rendered greyed-out.
|
||||
const MODELS_WITH_CHAMBER_FAN: ReadonlySet<string> = new Set([
|
||||
'X1C',
|
||||
'X1',
|
||||
'X1E',
|
||||
'X2D',
|
||||
'P1S',
|
||||
'P2S',
|
||||
'H2D',
|
||||
'H2D Pro',
|
||||
'H2C',
|
||||
'H2S',
|
||||
]);
|
||||
|
||||
// Map SSDP model codes to display names
|
||||
function mapModelCode(ssdpModel: string | null): string {
|
||||
if (!ssdpModel) return '';
|
||||
@@ -3576,6 +3593,12 @@ function PrinterCard({
|
||||
const statusControlClass = `relative text-center px-2 py-1.5 bg-bambu-dark rounded-lg flex-1 flex flex-col justify-center items-center transition-colors ${
|
||||
canUseStatusControls ? 'cursor-pointer hover:bg-bambu-dark-tertiary' : 'cursor-default opacity-80'
|
||||
}`;
|
||||
// Chamber fan only exists on enclosed Bambu models. Open-frame
|
||||
// printers (A1, A1 Mini, A2L, P1P) have no chamber fan — showing
|
||||
// the widget there is at best dead UI and at worst suggests a
|
||||
// control that does nothing. Mirrors the enclosure-door badge
|
||||
// gate above.
|
||||
const hasChamberFan = MODELS_WITH_CHAMBER_FAN.has(printer.model ?? '');
|
||||
const fanItems = [
|
||||
{
|
||||
key: 'part',
|
||||
@@ -3591,13 +3614,17 @@ function PrinterCard({
|
||||
Icon: Wind,
|
||||
activeClass: 'text-blue-400',
|
||||
},
|
||||
{
|
||||
key: 'chamber',
|
||||
label: t('printers.fans.chamber'),
|
||||
value: status.big_fan2_speed ?? 0,
|
||||
Icon: AirVent,
|
||||
activeClass: 'text-green-400',
|
||||
},
|
||||
...(hasChamberFan
|
||||
? [
|
||||
{
|
||||
key: 'chamber',
|
||||
label: t('printers.fans.chamber'),
|
||||
value: status.big_fan2_speed ?? 0,
|
||||
Icon: AirVent,
|
||||
activeClass: 'text-green-400',
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user