Skip to content

Fix drag-and-drop and macOS sidecar startup#4636

Open
guitar24t wants to merge 2 commits into
balena-io:masterfrom
guitar24t:fix-drag-and-drop-macos-sidecar
Open

Fix drag-and-drop and macOS sidecar startup#4636
guitar24t wants to merge 2 commits into
balena-io:masterfrom
guitar24t:fix-drag-and-drop-macos-sidecar

Conversation

@guitar24t

Copy link
Copy Markdown

Summary

Restores drag-and-drop image loading and gets the flasher sidecar
running again on recent macOS (tested on macOS 26). Two user-visible
bugs were addressed, plus several smaller issues found while debugging.

Drag-and-drop

Previously, dragging an image onto the window opened a browser-style
download instead of loading the image, and dropping on certain spots
(notably the "Flash from file" button) silently did nothing.

  • lib/gui/app/app.ts — window-level dragenter/dragover/drop
    listeners (capture phase) that preventDefault() and force
    dataTransfer.dropEffect = 'copy'. This stops Chromium from
    navigating/downloading the dropped file, and the explicit
    dropEffect makes the drop event fire even over interactive
    <button> elements (Chromium otherwise defaults the effect to
    'none' there and suppresses the event).
  • lib/gui/etcher.tssetWindowOpenHandler denies renderer
    new-window opens and a will-download handler cancels unexpected
    downloads, as a safety net for the old fall-through behaviour.
  • source-selector.tsx — the dropped path is now resolved with
    webUtils.getPathForFile(); File.path was removed in Electron
    32+ and the app runs on Electron 37, so it was always empty.
  • source-selector.tsx — the drop is accepted anywhere on the
    window via a capture-phase window listener, plus a stable
    full-window overlay shown only during a drag. The overlay keeps the
    drop from landing on a button whose underlying DOM node is swapped
    out on hover (rendition ColouredButtonPlain), which was
    disrupting the drag and preventing the drop from registering.

macOS sidecar startup

After drag-and-drop worked, the flasher sidecar (etcher-util) failed
with requestMetadata is not a function. The root cause: the
pkg-built sidecar embedded Node 20.11.1, which segfaults on
macOS 26. Newer Node 20 builds segfault too; Node 22 runs cleanly.

  • forge.sidecar.ts — pin the pkg target to node22.22.2.
  • package.jsonoverrides bump @yao-pkg/pkg-fetch to
    ^3.5.33 (ships the Node 22 build) and node-abi to ^4.31.0
    (older versions do not recognise Electron 37).

Additional fixes in api.ts

Found while debugging the sidecar:

  • Parenthesise the ETCHER_SERVER_PORT fallback — operator
    precedence meant an explicit port env var was discarded and 3435
    was always used.
  • Remove the dead Windows env-reset block (it spawned a throwaway
    cmd subprocess that had no effect).
  • Wrap ws.on('message') in try/catch and stop throwing on an
    unknown message type, so a bad frame can't crash the connection.
  • Close the WebSocket and stop the heartbeat on connection error.
  • Show a clear "sidecar failed to start" error instead of calling an
    undefined requestMetadata.

Test plan

  • npm run make builds a macOS arm64 DMG
  • Sidecar binary starts and listens (no segfault) on macOS 26
  • Drop an image on the window background — loads instead of
    downloading
  • Drop on the "Flash from file" button, highlighted and not —
    loads
  • Verify Windows and Linux builds via CI
  • Verify an actual flash end-to-end

🤖 Generated with Claude Code

Dropping an image on the window opened a browser download instead of
loading it, and the flasher sidecar failed to start on macOS 26.

Drag-and-drop:
- Add window-level dragenter/dragover/drop handlers that
  preventDefault and force dataTransfer.dropEffect to 'copy', so
  Chromium stops navigating/downloading the dropped file and fires
  the drop event even over interactive <button> elements.
- Resolve the dropped path with webUtils.getPathForFile, since the
  File.path property was removed in Electron 32+.
- Accept a drop anywhere on the window via a capture-phase window
  listener plus a stable full-window overlay shown during a drag, so
  the drop target is not a button whose DOM node swaps on hover.
- Deny renderer-initiated new windows and downloads in the main
  process as a safety net.

macOS sidecar:
- Pin the pkg build target to node22.22.2; the bundled Node 20
  runtimes segfault on macOS 26.
- Override @yao-pkg/pkg-fetch to ^3.5.33 (ships the Node 22 build)
  and node-abi to ^4.31.0 (recognises Electron 37).

Additional api.ts fixes found while debugging:
- Parenthesise the ETCHER_SERVER_PORT fallback so an explicit port
  env var is honoured instead of always selecting 3435.
- Remove the dead Windows env-reset block.
- Guard ws.on('message') with try/catch and stop throwing on an
  unknown message type.
- Close the WebSocket and stop the heartbeat on connection error.
- Show a clear error when the sidecar never connects instead of
  calling an undefined requestMetadata.

Change-type: patch

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@flowzone-app

flowzone-app Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

A repository maintainer needs to approve these workflow run(s).

To approve, maintainers can either:

Submit an approval review on this pull request, OR

Submit a review comment starting with /deploy

Then re-run the failed job(s) via the Checks tab above.

Reviews must be on the specific commit SHA of the workflow run to be considered.

The sidecar is now built with Node 22 and local development commonly
runs on Node 24, so the previous Node 20-only range produced spurious
EBADENGINE warnings. Widen the range to >=20 <25 (Node 20, 22 and 24).

Change-type: patch

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@puhitaku

Copy link
Copy Markdown

+1
Broken DnD prevents me from upgrading from an ancient x86 build so please be merged soon ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants