Skip to content

Commit 45a274f

Browse files
committed
feat: add URL-based printer context selection
Select the active printer from ?ip= / ?serial= query params so the WebUI stays in sync when embedded in tools like OrcaSlicer's Device tab. Refs #16.
1 parent 6da3024 commit 45a274f

2 files changed

Lines changed: 52 additions & 0 deletions

File tree

src/webui/static/app.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
} from './features/authentication.js';
3535
import { initializeCamera } from './features/camera.js';
3636
import {
37+
applyUrlPrinterSelection,
3738
fetchPrinterContexts,
3839
getCurrentContextId,
3940
initializeContextSwitching,
@@ -460,6 +461,7 @@ async function handlePostLoginTasks(): Promise<void> {
460461
try {
461462
await loadPrinterFeatures();
462463
await fetchPrinterContexts();
464+
await applyUrlPrinterSelection();
463465
await loadSpoolmanConfig();
464466

465467
initializeCamera();

src/webui/static/features/context-switching.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,56 @@ export function updatePrinterSelector(contexts: PrinterContext[], activeContextI
126126
});
127127
}
128128

129+
/**
130+
* One-shot guard so URL-based selection only runs on the initial page load and
131+
* never re-fires on the context re-fetch that follows every manual switch.
132+
*/
133+
let hasAppliedUrlSelection = false;
134+
135+
/**
136+
* Selects a printer context from URL query parameters (e.g. `?ip=192.168.1.100`
137+
* or `?serial=ABCD1234`). Intended for embedding the WebUI in another tool
138+
* (such as OrcaSlicer's Device tab) so the displayed printer stays in sync with
139+
* the host application.
140+
*
141+
* Matches against connected context data (not the DOM selector), so it works
142+
* even when the printer selector is hidden in single-printer mode. Uses exact
143+
* matching to avoid `192.168.1.1` colliding with `192.168.1.10`. Runs at most
144+
* once per page load and no-ops when the target is already active.
145+
*/
146+
export async function applyUrlPrinterSelection(): Promise<void> {
147+
if (hasAppliedUrlSelection) {
148+
return;
149+
}
150+
hasAppliedUrlSelection = true;
151+
152+
const params = new URLSearchParams(window.location.search);
153+
const ip = params.get('ip')?.trim();
154+
const serial = params.get('serial')?.trim();
155+
if (!ip && !serial) {
156+
return;
157+
}
158+
159+
const match = Array.from(contextById.values()).find(
160+
(context) =>
161+
(ip !== undefined && ip !== '' && context.ipAddress === ip) ||
162+
(serial !== undefined &&
163+
serial !== '' &&
164+
context.serialNumber?.toLowerCase() === serial.toLowerCase())
165+
);
166+
167+
if (!match) {
168+
showToast(`No connected printer matches ${ip ?? serial}`, 'error');
169+
return;
170+
}
171+
172+
if (match.id === getCurrentContextId()) {
173+
return;
174+
}
175+
176+
await switchPrinterContext(match.id);
177+
}
178+
129179
export async function switchPrinterContext(contextId: string): Promise<void> {
130180
if (state.authRequired && !state.authToken) {
131181
showToast('Not authenticated', 'error');

0 commit comments

Comments
 (0)