Skip to content

Block context menu refactor#687

Merged
lawsie merged 9 commits into
flipcomputing:mainfrom
lawsie:block-context-menu-refactor
Jun 25, 2026
Merged

Block context menu refactor#687
lawsie merged 9 commits into
flipcomputing:mainfrom
lawsie:block-context-menu-refactor

Conversation

@lawsie

@lawsie lawsie commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Refactor the 'right click' and mobile context menus into a separate file, and enable what was previously the mobile context menu to appear in desktop view too for mouse users.

  • Clicking the same block toggles the menu closed or open so that it is easy to hide it
  • The eye button (focus on a mesh) now displays a panorama icon (see whole scene) if you try to click it again on the block for a mesh that is already being orbited.
image
  • I have deliberately NOT made this menu appear for keyboard navigation because all of the things in the menu already have keyboard shortcuts

AI usage

Claude Sonnet 4.6 and Opus 4.8 used interactively to find and make updates. Edits approved individually with modifications to approach.

Summary by CodeRabbit

  • New Features

    • Added a floating toolbar for quick block actions (duplicate, detach, comment, view in canvas, delete).
    • Introduced "Find in workspace" context menu option.
    • Implemented paste-at-pointer functionality for improved block placement.
    • Enhanced orbit view mode switching behavior for 3D canvas navigation.
  • Improvements

    • Optimized context menu organization and block operations.
    • Refined clipboard behavior for copy/paste workflows.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@lawsie, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 34 minutes and 2 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97bbaca4-f460-4bf9-b5ab-cb12571d7ec7

📥 Commits

Reviewing files that changed from the base of the PR and between 9b007f2 and 41b1120.

📒 Files selected for processing (2)
  • ui/contextmenu.js
  • ui/gizmos.js
📝 Walkthrough

Walkthrough

This PR moves Blockly context menu, clipboard, paste, and floating block toolbar logic into ui/contextmenu.js, initializes that module from workspace setup, and updates orbit-view state in ui/gizmos.js so toolbar canvas-view actions can track and switch the active target.

Changes

Blockly workspace UI behavior

Layer / File(s) Summary
Module wiring and menu actions
main/blocklyinit.js, ui/contextmenu.js
Workspace setup now calls initContextMenus(workspace), and the new module registers customized block and workspace context-menu items including detach, view in canvas, collapse/expand toggle, delete label changes, and find-in-workspace.
Clipboard overrides and pointer-aware paste
ui/contextmenu.js
The module adds block/workspace cut-copy-paste entries, patches copy behavior, tracks pointer and context-menu coordinates, and routes menu paste plus Ctrl/Cmd+V through pasteAsChildOrHere.
Floating toolbar and orbit-view integration
ui/contextmenu.js, main/blocklyinit.js, ui/gizmos.js
The floating selected-block toolbar is implemented in the new module with duplicate, detach, comment, canvas-view, and delete actions; the old inline toolbar code is removed; orbit-view globals now track the active block and allow retargeting without always exiting orbit mode.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • flipcomputing/flock#682: Also touches the tablet/mobile context menu and floating block toolbar behavior that is now centralized in ui/contextmenu.js.
  • flipcomputing/flock#683: Shares the floating toolbar and “View in canvas” behavior, including viewMeshWithCamera integration.
  • flipcomputing/flock#684: Also modifies Blockly paste behavior around workspace-level paste and pointer-based insertion.

Poem

🐇 I tucked the menus in a neater burrow,
and taught paste where the pointer will go.
A toolbar now hops by the chosen block,
with canvas-view peeking around the clock.
Snip, copy, detach—what a tidy warren glow!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: refactoring block context menu logic from blocklyinit.js into a separate ui/contextmenu.js module.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/contextmenu.js`:
- Around line 645-647: The pointerdown event listener is attached to
injectionDiv, but on mobile the blocklyinit.js shim stops propagation before the
event reaches injectionDiv, causing the toolbar scheduling to fail on first
selection. Move the addEventListener call from injectionDiv to document to
capture the pointerdown event before propagation is stopped, and update the
handler to check if any hidden toolbar exists on the currently selected block
and treat it as openable. Apply the same fix to the similar code block
referenced at lines 745-759.
- Around line 584-600: The translate() function returns the key string when a
translation is missing, so patterns like translate('duplicate_button') ||
'Duplicate' never reach the English fallback. Replace all toolbar button
aria-label assignments (duplicateBtn, deleteBtn, detachBtn, and others
referenced in lines 609-632 and 681-693) with a consistent translation pattern
that properly provides English fallbacks. Instead of using the || operator after
translate(), pass the English fallback text as a parameter to the translate
function or use an alternative pattern that actually falls back when
translations are missing, ensuring all toolbar labels use the same approach
throughout the file.
- Around line 168-170: The empty catch block in the registry.unregister call is
triggering ESLint no-empty and no-unused-vars errors. Fix this by adding an
eslint-disable comment above the try-catch statement to suppress both the
no-empty and no-unused-vars rules, or alternatively add a comment inside the
empty catch block such as // ignore error to satisfy the no-empty rule while
keeping the catch block empty.
- Around line 843-849: The delete flow in the context menu calls
`Blockly.Toast.show` unconditionally after `block.checkAndDelete()`, unlike the
rest of `ui/contextmenu.js` where `Blockly.Toast?.show` is used. Update the
delete handler to guard the toast invocation with optional chaining in the same
way as the other `Blockly.Toast` usages, keeping the `checkAndDelete()` behavior
unchanged and preventing runtime errors when Toast is unavailable.
- Around line 285-292: In the blockPaste context menu callback (lines 285-292),
replace the use of globally selected item with scope.block to ensure paste
attaches to the right-clicked block. Additionally, add a check to validate that
the selected item is actually a Block type before passing it to
pasteAsChildOrHere, since Blockly selectables can include workspace comments
which will crash when accessing inputList. Apply the same validation logic to
the keyboard paste handler in the mentioned section (lines 558-564) to prevent
passing non-block selectables to pasteAsChildOrHere.
- Around line 470-541: Strategies 1 and 4 in the block pasting logic are missing
occupancy checks before connecting pasted blocks. In strategy 1, before calling
targetBlock.nextConnection.connect(pb.previousConnection), verify that
targetBlock.nextConnection is free (either by checking
!targetBlock.nextConnection.targetBlock() or by disconnecting any existing
connection first). Similarly in strategy 4, before calling
targetBlock.previousConnection.connect(pb.nextConnection), verify that
targetBlock.previousConnection is free using the same pattern. Follow the
approach used in strategy 2b which explicitly calls disconnect() before
connecting to ensure existing chains are properly preserved when pasting onto
blocks in the middle of a stack.

In `@ui/gizmos.js`:
- Around line 467-471: The issue is that after calling
`restoreFreeCameraFromOrbit()`, the code unconditionally calls
`disconnectOrbitView()` even when the restore operation failed to deactivate the
orbit camera. When restoration fails and the orbit camera remains active,
calling `disconnectOrbitView()` clears the flag without actually disconnecting,
allowing a new orbit camera to be attached on top. The fix is to check if the
orbit camera is still active after attempting restoration, and if it is still
active, return without calling `disconnectOrbitView()` to prevent the
fall-through behavior that would attach another orbit camera on top of the
existing one. This applies to both the section at lines 467-471 and the similar
code at lines 690-694.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 661806ef-5553-480c-92e3-e139f5933ccd

📥 Commits

Reviewing files that changed from the base of the PR and between 2b7db78 and 9b007f2.

📒 Files selected for processing (3)
  • main/blocklyinit.js
  • ui/contextmenu.js
  • ui/gizmos.js

Comment thread ui/contextmenu.js Outdated
Comment thread ui/contextmenu.js Outdated
Comment thread ui/contextmenu.js
Comment thread ui/contextmenu.js Outdated
Comment thread ui/contextmenu.js Outdated
Comment thread ui/contextmenu.js
Comment thread ui/gizmos.js
@lawsie lawsie requested a review from tracygardner June 23, 2026 15:06
@lawsie lawsie mentioned this pull request Jun 23, 2026
7 tasks
@lawsie

lawsie commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

@tracygardner There is a regression bug where sometimes the context menu doesn't show up on a block. I haven't got time to fix it today and Claude is also down, but I've noted it for next time. I can also implement any design changes then once you've had chance to have a look.

@lawsie lawsie merged commit 371b430 into flipcomputing:main Jun 25, 2026
2 of 3 checks passed
@lawsie lawsie deleted the block-context-menu-refactor branch June 25, 2026 07:59
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.

1 participant