mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 03:01:21 +02:00
[Fix]: Update location when linking/unlinking to/from Spoolman (#669)
* Enhance link spool functionality with additional printer and AMS details * Refactor linkSpool function to accept detailed context object for improved spooling integration * Enhance LinkSpoolModal to include amsName in props and linkSpool mutation for improved functionality * Add amsName prop to PrinterCard for enhanced spool linking functionality * Updates LinkSpoolModal test to work with recent spool location update changes * Adds clear_location to unlink testing * Refactor LinkSpoolRequest to remove ams_name and update location generation logic for improved clarity * Remove amsName from LinkSpoolModal and PrinterCard for cleaner API integration * Remove amsName from LinkSpoolModal test props and update linkSpool mock response for improved clarity
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""Spoolman integration API routes."""
|
||||
|
||||
import logging
|
||||
import json
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
@@ -669,6 +669,9 @@ class LinkSpoolRequest(BaseModel):
|
||||
spool_tag: str | None = None
|
||||
tray_uuid: str | None = None
|
||||
tag_uid: str | None = None
|
||||
printer_id: int | None = None
|
||||
ams_id: int | None = None
|
||||
tray_id: int | None = None
|
||||
|
||||
|
||||
@router.post("/spools/{spool_id}/link")
|
||||
@@ -708,12 +711,23 @@ async def link_spool(
|
||||
if set(spool_tag) == {"0"}:
|
||||
raise HTTPException(status_code=400, detail="Invalid spool tag format (all-zero tag is not linkable)")
|
||||
|
||||
spool_tag = spool_tag.upper()
|
||||
|
||||
# Build location like: "{Printer Name} - {AMS Name} {Slot Number}"
|
||||
location: str | None = None
|
||||
if request.printer_id is not None and request.ams_id is not None and request.tray_id is not None:
|
||||
printer_result = await db.execute(select(Printer).where(Printer.id == request.printer_id))
|
||||
printer = printer_result.scalar_one_or_none()
|
||||
if not printer:
|
||||
raise HTTPException(status_code=404, detail="Printer not found")
|
||||
|
||||
location = f"{printer.name} - {client.convert_ams_slot_to_location(request.ams_id, request.tray_id)}"
|
||||
|
||||
# Update spool with tag
|
||||
# Note: Spoolman extra field values must be valid JSON, so we encode the string
|
||||
import json
|
||||
|
||||
result = await client.update_spool(
|
||||
spool_id=spool_id,
|
||||
location=location,
|
||||
extra={"tag": json.dumps(spool_tag)},
|
||||
)
|
||||
|
||||
@@ -748,6 +762,7 @@ async def unlink_spool(
|
||||
|
||||
result = await client.update_spool(
|
||||
spool_id=spool_id,
|
||||
clear_location=True,
|
||||
extra={"tag": json.dumps("")},
|
||||
)
|
||||
|
||||
|
||||
@@ -479,6 +479,7 @@ class TestSpoolmanAPI:
|
||||
|
||||
mock_spoolman_client.update_spool.assert_called_once_with(
|
||||
spool_id=1,
|
||||
clear_location=True,
|
||||
extra={"tag": '""'},
|
||||
)
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ describe('LinkSpoolModal', () => {
|
||||
filament_material: 'PLA',
|
||||
filament_color_hex: 'FF0000',
|
||||
remaining_weight: 800,
|
||||
location: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
@@ -61,13 +62,14 @@ describe('LinkSpoolModal', () => {
|
||||
filament_material: 'PETG',
|
||||
filament_color_hex: '0000FF',
|
||||
remaining_weight: 500,
|
||||
location: null,
|
||||
},
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.mocked(api.getUnlinkedSpools).mockResolvedValue(mockSpools);
|
||||
vi.mocked(api.linkSpool).mockResolvedValue({});
|
||||
vi.mocked(api.linkSpool).mockResolvedValue({ success: true, message: 'ok' });
|
||||
});
|
||||
|
||||
describe('rendering', () => {
|
||||
@@ -125,7 +127,12 @@ describe('LinkSpoolModal', () => {
|
||||
fireEvent.click(screen.getByText(/Generic PLA Red/).closest('button')!);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(api.linkSpool).toHaveBeenCalledWith(1, 'A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4');
|
||||
expect(api.linkSpool).toHaveBeenCalledWith(1, {
|
||||
spoolTag: 'ABCD1234',
|
||||
printerId: 1,
|
||||
amsId: 0,
|
||||
trayId: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3527,10 +3527,23 @@ export const api = {
|
||||
request<UnlinkedSpool[]>('/spoolman/spools/unlinked'),
|
||||
getLinkedSpools: () =>
|
||||
request<LinkedSpoolsMap>('/spoolman/spools/linked'),
|
||||
linkSpool: (spoolId: number, spoolTag: string) =>
|
||||
linkSpool: (
|
||||
spoolId: number,
|
||||
context: {
|
||||
spoolTag: string;
|
||||
printerId: number;
|
||||
amsId: number;
|
||||
trayId: number;
|
||||
}
|
||||
) =>
|
||||
request<{ success: boolean; message: string }>(`/spoolman/spools/${spoolId}/link`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ spool_tag: spoolTag }),
|
||||
body: JSON.stringify({
|
||||
spool_tag: context.spoolTag,
|
||||
printer_id: context.printerId,
|
||||
ams_id: context.amsId,
|
||||
tray_id: context.trayId,
|
||||
}),
|
||||
}),
|
||||
unlinkSpool: (spoolId: number) =>
|
||||
request<{ success: boolean; message: string }>(`/spoolman/spools/${spoolId}/unlink`, {
|
||||
|
||||
@@ -46,7 +46,12 @@ export function LinkSpoolModal({ isOpen, onClose, tagUid, trayUuid, printerId, a
|
||||
|
||||
const linkMutation = useMutation({
|
||||
mutationFn: (spoolId: number) =>
|
||||
api.linkSpool(spoolId, spoolTag!),
|
||||
api.linkSpool(spoolId, {
|
||||
spoolTag: spoolTag!,
|
||||
printerId,
|
||||
amsId,
|
||||
trayId,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['unlinked-spools'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['linked-spools'] });
|
||||
|
||||
Reference in New Issue
Block a user