feat(ui): add screenshot button to action bar (#1394)#1434
Conversation
Adds a Screenshot button next to the existing Fullscreen button that captures the current WebRTC video frame to a PNG download at the native stream resolution. Filename format: 'JetKVM <W>x<H> <YYYY-MM-DD> at <HH.MM.SS>.png'. Closes jetkvm#1394
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f4b54f5. Configure here.
| document.body.appendChild(a); | ||
| a.click(); | ||
| a.remove(); | ||
| }, []); |
There was a problem hiding this comment.
Screenshot ignores user video display filter settings
Medium Severity
The takeScreenshot callback draws the raw video frame via ctx.drawImage but does not apply the user's videoSaturation, videoBrightness, or videoContrast CSS filters that are actively applied to the <video> element through videoStyle. When a user has adjusted these display settings, the downloaded screenshot will look different from what they see on screen. The canvas 2D context's filter property can replicate the same CSS filter string before drawing. The useCallback dependency array [] would also need to include those settings values.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit f4b54f5. Configure here.


Closes #1394.
Adds a "Screenshot" button next to the Fullscreen button on the action bar. Captures the current WebRTC
<video>frame via an offscreen canvas and downloads a PNG at the native stream resolution.Changes
ui/src/components/WebRTCVideo.tsx— newtakeScreenshotcallback, wired to the existingvideoElmref; guards against unready streams (videoWidth/videoHeight === 0).ui/src/components/ActionBar.tsx— newLuCamerabutton inside the existinglg:flexwrapper, positioned immediately before the FullscreenSplitButtonGroup.ui/localization/messages/*.json— newaction_bar_screenshotkey, machine-translated to every existing locale.Implementation notes
JetKVM <W>x<H> <YYYY-MM-DD> at <HH.MM.SS>.png, matching the reporter's proposal. Timestamp is built from localDatecomponents (nottoISOString()) so that a 6pm-local screenshot actually reads18.00.00instead of a UTC-shifted time that looks like a bug.LuCamerafromreact-icons/lu— no new dependency, visually consistent with the sibling icons (LuMaximize,LuSettings, etc.).WebRTCVideo.tsxand is passed down as a prop, mirroring the existingrequestFullscreenplumbing through the same component interface.lg:flexbreakpoint wrapper as Fullscreen. Happy to surface it on smaller breakpoints if preferred.<video>is fed by a local WebRTCMediaStream, socanvas.toDataURLis safe.Testing
npm run lint:only,npm run build:device,npm run i18n:validate, andnpm run i18n:find-unusedall pass locally.Note
Low Risk
Low risk UI-only change that captures a client-side video frame to a downloaded PNG; main risk is minor UX/browser compatibility around canvas capture and download behavior.
Overview
Adds a new Screenshot control to the KVM
Actionbar, wired fromWebRTCVideovia a newtakeScreenshotprop.The screenshot implementation captures the current WebRTC
<video>frame into an offscreen canvas and triggers a PNG download with a timestamped filename, with guards for uninitialized video dimensions.Updates i18n message catalogs to include the new
action_bar_screenshotlabel across locales (and fills in additional missing Welsh strings related to advanced reset/network time sync).Reviewed by Cursor Bugbot for commit f4b54f5. Bugbot is set up for automated code reviews on this repo. Configure here.