Skip to content

[JEWEL-845] Add Context Menu to External Links #3107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

DanielSouzaBertoldi
Copy link
Collaborator

@DanielSouzaBertoldi DanielSouzaBertoldi commented Jun 27, 2025

Context

Important

For the popup to render correctly outside the row bounds in the SwingComparisonTabPanel we need #3105 merged, however it's not a prerequesite for us to open this PR.

Currently, our ExternalLink implementation doesn't show a context menu with the default action group from IntelliJ BrowserLink component (see screenshot below). This PR makes the necessary changes to show such context menu for external links only.

image

Main Changes

  • Created a LabelProvider interface which both IDE and standalone versions will implement to return the action action label.
  • Created a BridgeUriHandler class which implements UriHandler since in IDE we need to call IntelliJ's BrowserUtil.browse() function.
  • Created a new ExternalLink overload where clicking the element automatically opens the given link and also displays a ContextMenu. It also has a new parameter link which users can use to specify the actual link from the text.
  • This PR also fixes a weird visual bug in the Links row in SwingComparisonPanel.

Evidences

Right clicking external link

IDE Stand-alone
Screen.Recording.2025-07-07.at.10.39.49.mov
Screen.Recording.2025-07-07.at.10.37.43.mov

Using a valid browser link

IDE Stand-alone
Screen.Recording.2025-07-07.at.10.57.03.mov
Screen.Recording.2025-07-07.at.10.42.26.mov

Using an empty string

IDE Stand-alone
Screen.Recording.2025-07-07.at.10.59.07.mov
Screen.Recording.2025-07-07.at.11.00.07.mov

Release notes

New features

  • ExternalLink component now displays a context menu with two default options when right-clicking the link: open in browser and copy link address

@DanielSouzaBertoldi DanielSouzaBertoldi force-pushed the dsb/JEWEL-845 branch 2 times, most recently from 5f30676 to 4fdae8a Compare July 7, 2025 14:10
@@ -119,7 +119,7 @@ public class ContextSubmenu(label: String, public val submenu: () -> List<Contex

public class ContextMenuItemOption(
public val icon: IconKey? = null,
public val actionType: ContextMenuItemOptionAction,
public val actionType: ContextMenuItemOptionAction? = null,
Copy link
Collaborator Author

@DanielSouzaBertoldi DanielSouzaBertoldi Jul 7, 2025

Choose a reason for hiding this comment

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

The actionType parameter (which is used to map to a shortcut hint) should've been optional, my bad. You can have an item with an icon but no shortcut or vice versa.

@@ -167,7 +167,9 @@ public fun MenuContent(
val selectableItems = remember(items) { items.filterIsInstance<MenuSelectableItem>() }

val anyItemHasIcon = remember { selectableItems.any { it.iconKey != null } }
val anyItemHasKeybinding = remember { selectableItems.any { it.keybinding != null || it.itemOptionAction != null } }
val anyItemHasKeybinding = remember {
selectableItems.any { it.keybinding?.isNotEmpty() == true || it.itemOptionAction != null }
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Another minor mistake from the previous PR: the keybinding parameter will always be an empty set. So we shouldn't check if it's null, but if it's not empty.

Comment on lines 6 to 13
public class IntUiStringProvider : StringProvider {
override fun fetchStringFromKey(key: String): String =
when (key) {
"action.text.open.link.in.browser" -> "Open Link in Browser"
"action.text.copy.link.address" -> "Copy Link Address"
else -> ""
}
}
Copy link
Collaborator Author

@DanielSouzaBertoldi DanielSouzaBertoldi Jul 7, 2025

Choose a reason for hiding this comment

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

Ideally we should have a more robust architecture to map an label key to its actual string representation, but that's outside the scope of this PR.

If this approach is fine for everybody, I'll create an issue in our board about improving this.

@DanielSouzaBertoldi DanielSouzaBertoldi marked this pull request as ready for review July 7, 2025 14:15
@rock3r
Copy link
Collaborator

rock3r commented Jul 7, 2025

@DanielSouzaBertoldi please add release notes... and check if there are conflicts — GitHub seems very confused :D

image

import org.jetbrains.jewel.foundation.InternalJewelApi

@InternalJewelApi
public interface StringProvider {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add KDoc. Also, I'd name this something like MessageResourceResolver as it seems to be what it does in the IDE version, but am open to alternatives.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Honestly I'm kinda bad in coming up with names but I like your suggestion, it's way more specific and direct. @faogustavo what do you think?

[JEWEL-845] Add Context Menu to External Links

Updating branch now that JetBrains#3091 merged

update api dumps

applying pr suggestions

reran apichecktest

add KDoc to MessageResourceResolver

add KDoc to MessageResourceResolver

undo sample xml run config
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants