mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-20 17:50:12 +02:00
feat(ams-backup): add status badge + toggle, fix prefer-lowest (#1766)
Two tightly-coupled deliverables in one drop -- a new AMS Filament Backup status/control surface, and the #1766 fix that depends on it. Added -- AMS Filament Backup status + control - Parse bit 18 of top-level print.cfg into PrinterState.ams_filament_backup on every push_status. Verified against OrcaSlicer source (DeviceManager.cpp:4961) and a live H2D ON/OFF capture. Tri-state (None = A1 family / pre-cfg push) preserves today's behaviour. - Hold-timer guard (3 s) prevents stale frames from flickering the badge back to the printer's old cfg after a user-initiated toggle. - POST /printers/{id}/ams-backup toggle, set_ams_filament_backup() client method calling _set_print_option("auto_switch_filament", enabled). - GET /printers/{id}/inventory-remain endpoint exposes the same map the dispatcher uses (internal and Spoolman modes both work uniformly). - Small icon badge in the printer card's "Filaments" section header (placement reads as printer-wide because the cfg bit is printer-wide, not per-AMS). Click to toggle, success toast. - 5 i18n keys x 11 locales for the badge UI. Fixed -- #1766: prefer_lowest didn't pick lowest, ignored backup state - Backend gate in _compute_ams_mapping_for_printer: coerce prefer_lowest to False when status.ams_filament_backup is False; log the skip. - New effectivePreferLowest(setting, backup) helper applied at every frontend sort entry point: single-printer PrintModal, multi-printer hook per-printer, PrinterSelector InlineMappingEditor, FilamentMapping standalone editor (the last had NO preferLowest awareness at all before this change). - New preferLowestSortKey(f, inventoryByTrayId) mirrors backend's two-tier key exactly, including the banding tie-break (regular AMS < AMS-HT < external) so the client-side pre-compute matches the dispatch-time pick. An earlier draft used a flat `amsId * 4 + trayId` priority which gave external slots (ams_id = -1) a NEGATIVE priority -- caught in code review before commit. - Settings -> Filament -> "Prefer lowest remaining filament" gets an explanatory note about the printer-side AMS Backup dependency, with i18n key in all 11 locales.
This commit is contained in:
@@ -11,6 +11,9 @@ import {
|
||||
import {
|
||||
normalizeColorForCompare,
|
||||
colorsAreSimilar,
|
||||
preferLowestSortKey,
|
||||
compareSortKeys,
|
||||
effectivePreferLowest,
|
||||
} from '../utils/amsHelpers';
|
||||
|
||||
/**
|
||||
@@ -58,6 +61,8 @@ export interface PrinterMappingResult {
|
||||
totalSlots: number;
|
||||
/** Per-printer config */
|
||||
config: PerPrinterConfig;
|
||||
/** Per-globalTrayId inventory grams remaining, for the lowest-remain sort (#1766) */
|
||||
inventoryByTrayId?: Map<number, number>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +95,7 @@ function computeMatchDetails(
|
||||
loadedFilaments: LoadedFilament[],
|
||||
manualMappings: Record<number, number>,
|
||||
preferLowest?: boolean,
|
||||
inventoryByTrayId?: Map<number, number>,
|
||||
): { exactMatches: number; typeOnlyMatches: number; missingTypes: number; totalSlots: number; status: PrinterMatchStatus } {
|
||||
if (!filamentReqs || filamentReqs.length === 0) {
|
||||
return { exactMatches: 0, typeOnlyMatches: 0, missingTypes: 0, totalSlots: 0, status: 'full' };
|
||||
@@ -135,11 +141,12 @@ function computeMatchDetails(
|
||||
}
|
||||
|
||||
if (preferLowest) {
|
||||
candidates = [...candidates].sort((a, b) => {
|
||||
const ra = a.remain >= 0 ? a.remain : 101;
|
||||
const rb = b.remain >= 0 ? b.remain : 101;
|
||||
return ra - rb;
|
||||
});
|
||||
candidates = [...candidates].sort((a, b) =>
|
||||
compareSortKeys(
|
||||
preferLowestSortKey(a, inventoryByTrayId),
|
||||
preferLowestSortKey(b, inventoryByTrayId),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const exactMatch = candidates.find(
|
||||
@@ -194,6 +201,7 @@ function computeMappingWithOverrides(
|
||||
printerStatus: PrinterStatus | undefined,
|
||||
manualMappings: Record<number, number>,
|
||||
preferLowest?: boolean,
|
||||
inventoryByTrayId?: Map<number, number>,
|
||||
): number[] | undefined {
|
||||
if (!filamentReqs?.filaments || filamentReqs.filaments.length === 0) return undefined;
|
||||
|
||||
@@ -222,11 +230,12 @@ function computeMappingWithOverrides(
|
||||
}
|
||||
|
||||
if (preferLowest) {
|
||||
candidates = [...candidates].sort((a, b) => {
|
||||
const ra = a.remain >= 0 ? a.remain : 101;
|
||||
const rb = b.remain >= 0 ? b.remain : 101;
|
||||
return ra - rb;
|
||||
});
|
||||
candidates = [...candidates].sort((a, b) =>
|
||||
compareSortKeys(
|
||||
preferLowestSortKey(a, inventoryByTrayId),
|
||||
preferLowestSortKey(b, inventoryByTrayId),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const exactMatch = candidates.find(
|
||||
@@ -290,6 +299,7 @@ export function useMultiPrinterFilamentMapping(
|
||||
perPrinterConfigs: Record<number, PerPrinterConfig>,
|
||||
setPerPrinterConfigs: React.Dispatch<React.SetStateAction<Record<number, PerPrinterConfig>>>,
|
||||
preferLowest?: boolean,
|
||||
inventoryByTrayIdPerPrinter?: Map<number, Map<number, number>>,
|
||||
): UseMultiPrinterFilamentMappingResult {
|
||||
// Fetch printer status for all selected printers in parallel
|
||||
const statusQueries = useQueries({
|
||||
@@ -311,9 +321,14 @@ export function useMultiPrinterFilamentMapping(
|
||||
|
||||
const loadedFilaments = buildLoadedFilaments(printerStatus);
|
||||
const config = perPrinterConfigs[printerId] || DEFAULT_PRINTER_CONFIG;
|
||||
const inventoryByTrayId = inventoryByTrayIdPerPrinter?.get(printerId);
|
||||
// Per-printer gate (#1766): two printers in the same dispatch can have
|
||||
// different AMS Backup states; the sort must be skipped on the OFF ones
|
||||
// and kept on the ON ones. Computing inside the loop captures both.
|
||||
const printerPreferLowest = effectivePreferLowest(preferLowest, printerStatus?.ams_filament_backup);
|
||||
|
||||
// Compute auto mapping for this printer
|
||||
const autoMapping = computeAmsMapping(filamentReqs, printerStatus, preferLowest);
|
||||
const autoMapping = computeAmsMapping(filamentReqs, printerStatus, printerPreferLowest, inventoryByTrayId);
|
||||
|
||||
// Determine which mappings to use:
|
||||
// If printer has override (useDefault=false), use its custom mappings
|
||||
@@ -323,14 +338,15 @@ export function useMultiPrinterFilamentMapping(
|
||||
: defaultMappings;
|
||||
|
||||
// Compute final mapping with overrides
|
||||
const finalMapping = computeMappingWithOverrides(filamentReqs, printerStatus, effectiveMappings, preferLowest);
|
||||
const finalMapping = computeMappingWithOverrides(filamentReqs, printerStatus, effectiveMappings, printerPreferLowest, inventoryByTrayId);
|
||||
|
||||
// Compute match details
|
||||
const matchDetails = computeMatchDetails(
|
||||
filamentReqs?.filaments,
|
||||
loadedFilaments,
|
||||
effectiveMappings,
|
||||
preferLowest,
|
||||
printerPreferLowest,
|
||||
inventoryByTrayId,
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -347,9 +363,10 @@ export function useMultiPrinterFilamentMapping(
|
||||
missingTypes: matchDetails.missingTypes,
|
||||
totalSlots: matchDetails.totalSlots,
|
||||
config,
|
||||
inventoryByTrayId,
|
||||
};
|
||||
});
|
||||
}, [selectedPrinterIds, statusQueries, printers, filamentReqs, perPrinterConfigs, defaultMappings, preferLowest]);
|
||||
}, [selectedPrinterIds, statusQueries, printers, filamentReqs, perPrinterConfigs, defaultMappings, preferLowest, inventoryByTrayIdPerPrinter]);
|
||||
|
||||
const isLoading = statusQueries.some((q) => q.isLoading);
|
||||
|
||||
@@ -370,7 +387,12 @@ export function useMultiPrinterFilamentMapping(
|
||||
if (!result || !result.status || !filamentReqs?.filaments) return;
|
||||
|
||||
// Compute optimal mapping for this printer
|
||||
const autoMapping = computeAmsMapping(filamentReqs, result.status, preferLowest);
|
||||
const autoMapping = computeAmsMapping(
|
||||
filamentReqs,
|
||||
result.status,
|
||||
effectivePreferLowest(preferLowest, result.status?.ams_filament_backup),
|
||||
inventoryByTrayIdPerPrinter?.get(printerId),
|
||||
);
|
||||
if (!autoMapping) return;
|
||||
|
||||
// Convert autoMapping array to manualMappings record
|
||||
|
||||
Reference in New Issue
Block a user