diff --git a/frontend/js/i18n/de.js b/frontend/js/i18n/de.js index 8429af2..2fe1010 100644 --- a/frontend/js/i18n/de.js +++ b/frontend/js/i18n/de.js @@ -347,6 +347,9 @@ export default { 'device.assign.select_first': 'Erst etwas auswählen', 'device.assign.kiosk_widget_name': 'Kiosk: {name}', 'device.toast.screenshot_requested': 'Screenshot angefordert', + 'device.toast.screenshot_unsupported': 'Der Player dieses Displays unterstützt keine Screenshots', + 'device.toast.screenshot_offline': 'Display ist offline — Screenshot nicht angefordert', + 'device.toast.screenshot_failed': 'Screenshot-Anfrage fehlgeschlagen — keine Antwort vom Server', 'device.toast.renamed': 'Bildschirm umbenannt', 'device.toast.removing': 'Wird entfernt...', 'device.toast.removed': 'Bildschirm entfernt', diff --git a/frontend/js/i18n/en.js b/frontend/js/i18n/en.js index 821c15d..adcdaef 100644 --- a/frontend/js/i18n/en.js +++ b/frontend/js/i18n/en.js @@ -648,6 +648,9 @@ export default { 'device.assign.kiosk_widget_name': 'Kiosk: {name}', // Toasts 'device.toast.screenshot_requested': 'Screenshot requested', + 'device.toast.screenshot_unsupported': 'This display\'s player can\'t take screenshots', + 'device.toast.screenshot_offline': 'Display is offline — screenshot not requested', + 'device.toast.screenshot_failed': 'Screenshot request failed — no response from server', 'device.toast.renamed': 'Display renamed', 'device.toast.removing': 'Removing...', 'device.toast.removed': 'Display removed', diff --git a/frontend/js/i18n/es.js b/frontend/js/i18n/es.js index 9a6da03..ca1c47d 100644 --- a/frontend/js/i18n/es.js +++ b/frontend/js/i18n/es.js @@ -377,6 +377,9 @@ export default { 'device.assign.select_first': 'Primero selecciona algo', 'device.assign.kiosk_widget_name': 'Kiosco: {name}', 'device.toast.screenshot_requested': 'Captura solicitada', + 'device.toast.screenshot_unsupported': 'El reproductor de esta pantalla no admite capturas de pantalla', + 'device.toast.screenshot_offline': 'La pantalla está desconectada — captura no solicitada', + 'device.toast.screenshot_failed': 'La solicitud de captura falló — sin respuesta del servidor', 'device.toast.renamed': 'Pantalla renombrada', 'device.toast.removing': 'Eliminando...', 'device.toast.removed': 'Pantalla eliminada', diff --git a/frontend/js/i18n/fr.js b/frontend/js/i18n/fr.js index 438f36c..8acb3ec 100644 --- a/frontend/js/i18n/fr.js +++ b/frontend/js/i18n/fr.js @@ -347,6 +347,9 @@ export default { 'device.assign.select_first': 'Sélectionnez d\'abord un élément', 'device.assign.kiosk_widget_name': 'Kiosque : {name}', 'device.toast.screenshot_requested': 'Capture demandée', + 'device.toast.screenshot_unsupported': 'Le lecteur de cet écran ne prend pas en charge les captures d\'écran', + 'device.toast.screenshot_offline': 'Écran hors ligne — capture non demandée', + 'device.toast.screenshot_failed': 'Échec de la demande de capture — pas de réponse du serveur', 'device.toast.renamed': 'Écran renommé', 'device.toast.removing': 'Suppression...', 'device.toast.removed': 'Écran retiré', diff --git a/frontend/js/i18n/it.js b/frontend/js/i18n/it.js index 091c2d9..c5ad537 100644 --- a/frontend/js/i18n/it.js +++ b/frontend/js/i18n/it.js @@ -371,6 +371,9 @@ export default { 'device.assign.kiosk_widget_name': 'Chiosco: {name}', // Toasts 'device.toast.screenshot_requested': 'Richiesta screenshot inviata', + 'device.toast.screenshot_unsupported': 'Il player di questo schermo non supporta gli screenshot', + 'device.toast.screenshot_offline': 'Lo schermo è offline — screenshot non richiesto', + 'device.toast.screenshot_failed': 'Richiesta screenshot non riuscita — nessuna risposta dal server', 'device.toast.renamed': 'Schermo rinominato', 'device.toast.removing': 'Rimozione in corso...', 'device.toast.removed': 'Schermo rimosso', diff --git a/frontend/js/i18n/pt.js b/frontend/js/i18n/pt.js index e7a90d5..3dcd64a 100644 --- a/frontend/js/i18n/pt.js +++ b/frontend/js/i18n/pt.js @@ -347,6 +347,9 @@ export default { 'device.assign.select_first': 'Selecione algo primeiro', 'device.assign.kiosk_widget_name': 'Quiosque: {name}', 'device.toast.screenshot_requested': 'Captura solicitada', + 'device.toast.screenshot_unsupported': 'O player desta tela não suporta capturas de tela', + 'device.toast.screenshot_offline': 'A tela está offline — captura não solicitada', + 'device.toast.screenshot_failed': 'Falha na solicitação de captura — sem resposta do servidor', 'device.toast.renamed': 'Tela renomeada', 'device.toast.removing': 'Removendo...', 'device.toast.removed': 'Tela removida', diff --git a/frontend/js/socket.js b/frontend/js/socket.js index a1e5840..e5e2d20 100644 --- a/frontend/js/socket.js +++ b/frontend/js/socket.js @@ -112,9 +112,22 @@ function emit(event, data) { if (cbs) cbs.forEach(cb => cb(data)); } -export function requestScreenshot(deviceId) { +// Optional callback receives the server-side ack: { delivered, reason, capability }. +// reason is 'offline' (no live connection) or 'unsupported' (this player type can't +// take screenshots). Callers without a callback keep firing-and-forgetting — the +// dashboard grid and the device-detail 5s poll stay silent; only the explicit +// Screenshot button asks for the verdict. +export function requestScreenshot(deviceId, callback) { console.log('requestScreenshot:', deviceId, 'socket connected:', dashboardSocket?.connected); - if (dashboardSocket) dashboardSocket.emit('dashboard:request-screenshot', { device_id: deviceId }); + if (!dashboardSocket) return; + if (typeof callback === 'function') { + dashboardSocket.timeout(5000).emit('dashboard:request-screenshot', { device_id: deviceId }, (err, ack) => { + if (err) callback({ delivered: false, reason: 'no_ack' }); + else callback(ack || { delivered: false, reason: 'no_ack' }); + }); + } else { + dashboardSocket.emit('dashboard:request-screenshot', { device_id: deviceId }); + } } export function startRemote(deviceId) { diff --git a/frontend/js/views/device-detail.js b/frontend/js/views/device-detail.js index 32e6fba..7a26256 100644 --- a/frontend/js/views/device-detail.js +++ b/frontend/js/views/device-detail.js @@ -1084,10 +1084,16 @@ function setupActions(device) { document.getElementById('devicePreviewBtn')?.addEventListener('click', () => showDevicePreview(device)); - // Screenshot button + // Screenshot button — pass a callback so the server's verdict surfaces as a toast + // instead of the request silently going nowhere (offline device, or a player type + // that can't capture at all, e.g. BrightSign). document.getElementById('screenshotBtn')?.addEventListener('click', () => { - requestScreenshot(device.id); - showToast(t('device.toast.screenshot_requested'), 'info'); + requestScreenshot(device.id, (ack) => { + if (ack?.delivered) showToast(t('device.toast.screenshot_requested'), 'info'); + else if (ack?.reason === 'unsupported') showToast(t('device.toast.screenshot_unsupported'), 'warning'); + else if (ack?.reason === 'offline') showToast(t('device.toast.screenshot_offline'), 'warning'); + else showToast(t('device.toast.screenshot_failed'), 'error'); + }); }); // Rename