diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-lib/src/main/java/com/microsoft/azure/toolkit/intellij/common/TerminalUtils.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-lib/src/main/java/com/microsoft/azure/toolkit/intellij/common/TerminalUtils.java index b87227b19fc..3bfad8d0f8c 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-lib/src/main/java/com/microsoft/azure/toolkit/intellij/common/TerminalUtils.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-lib/src/main/java/com/microsoft/azure/toolkit/intellij/common/TerminalUtils.java @@ -78,6 +78,19 @@ public static TerminalWidget getOrCreateTerminalWidget(@Nonnull Project project, .orElseGet(() -> manager.createShellWidget(workingDirectory, terminalTabTitle, true, true)); } + @Nonnull + public static TerminalWidget getTerminalWidget(@Nonnull Project project, @Nullable Path workingDir, String terminalTabTitle) { + final TerminalToolWindowManager manager = TerminalToolWindowManager.getInstance(project); + final String workingDirectory = Optional.ofNullable(workingDir).map(Path::toString).orElse(null); + return manager.getTerminalWidgets().stream() + .filter(widget -> StringUtils.isBlank(terminalTabTitle) || + StringUtils.equals(widget.getTerminalTitle().buildTitle(), terminalTabTitle)) + .findFirst() + .orElseGet(() -> manager.createShellWidget(workingDirectory, terminalTabTitle, true, true)); + } + + + public static boolean hasRunningCommands(TerminalWidget widget) throws IllegalStateException { final TtyConnector connector = widget.getTtyConnector(); if (connector == null) { diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/AzureExplorer.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/AzureExplorer.java index 14817fc78d9..1b450e7ad6a 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/AzureExplorer.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/AzureExplorer.java @@ -50,10 +50,13 @@ import javax.annotation.Nonnull; import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import java.awt.event.MouseEvent; import java.util.Arrays; import java.util.Comparator; +import java.util.Enumeration; +import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -105,6 +108,28 @@ private AzureExplorer(Project project) { appGroupedResourcesRoot.clearChildren(); typeGroupedResourcesRoot.clearChildren(); })); + + AzureEventBus.on("azd.installed", new AzureEventBus.EventListener(e -> { + final DefaultTreeModel model = (DefaultTreeModel) this.getModel(); + final TreeNode root = (TreeNode) model.getRoot(); + if (root != null && root.children() != null) { + Iterator iterator = root.children().asIterator(); + while (iterator.hasNext()) { + final TreeNode childNode = (TreeNode) iterator.next(); + final Node childInnerNode = childNode.getInner(); + if (childInnerNode instanceof AzdNode) { + final AzdNode azdNode = (AzdNode) childInnerNode; + childNode.setAllowsChildren(true); + azdNode.clearClickHandlers(); + azdNode.withDescription(""); + azdNode.showAzdActions(); + azdNode.refreshView(); + childNode.updateChildren(true); + break; + } + } + } + })); } @Override diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdNode.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdNode.java index 7eb0269eef7..13f84818b68 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdNode.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdNode.java @@ -1,23 +1,35 @@ package com.microsoft.azure.toolkit.intellij.explorer.azd; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.intellij.notification.NotificationGroupManager; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.microsoft.azure.toolkit.ide.common.component.Node; import com.microsoft.azure.toolkit.ide.common.icon.AzureIcons; -import com.microsoft.azure.toolkit.intellij.common.TerminalUtils; +import com.microsoft.azure.toolkit.lib.common.event.AzureEventBus; +import org.apache.commons.lang3.SystemUtils; import java.io.BufferedReader; import java.io.InputStreamReader; -import java.util.Map; import java.util.stream.Collectors; +import static com.microsoft.azure.toolkit.intellij.explorer.azd.AzdUtils.executeInTerminal; + public final class AzdNode extends Node { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .setSerializationInclusion(JsonInclude.Include.NON_NULL); + private static final String WIN_REFRESH_PATH_COMMAND = "$env:PATH = [System.Environment]::GetEnvironmentVariable(\"PATH\",\"Machine\") + \";\" + [System.Environment]::GetEnvironmentVariable(\"PATH\",\"User\"); "; + private static final String LINUX_REFRESH_PATH_COMMAND = "source ~/.bashrc"; + private static final String MAC_REFRESH_PATH_COMMAND = "source ~/.zshrc"; + + private static final String WIN_AZD_INSTALL_COMMAND = "winget install microsoft.azd"; + private static final String LINUX_AZD_INSTALL_COMMAND = "curl -fsSL https://aka.ms/install-azd.sh | bash"; + private static final String MAC_AZD_INSTALL_COMMAND = "brew tap azure/azd && brew install azd"; private final Project project; @@ -25,70 +37,131 @@ public AzdNode(Project project) { super("Azure Developer (Preview)"); this.project = project; withIcon(AzureIcons.Common.SERVICES); - addChildren(); + initializeNode(); } - public void addChildren() { + public void initializeNode() { if (isAzdInstalled()) { AzdUtils.logTelemetryEvent("azd-installed"); - if (isAzdSignedIn()) { - AzdUtils.logTelemetryEvent("azd-signed-in"); - withDescription("Signed In"); - addChild(getCreateFromTemplatesNode()); - addChild(getInitializeFromSourceNode()); - addChild(getProvisionResourcesNode()); - addChild(getDeployToAzureNode()); - addChild(getProvisionAndDeployToAzureNode()); + showAzdActions(); + } else { + showNotInstalled(); + } + } + + private void showNotInstalled() { + AzdUtils.logTelemetryEvent("azd-not-installed"); + withDescription("Install azd"); + onClicked(e -> { + final String command; + if (SystemUtils.IS_OS_WINDOWS) { + command = WIN_AZD_INSTALL_COMMAND; + } else if (SystemUtils.IS_OS_LINUX) { + command = LINUX_AZD_INSTALL_COMMAND; } else { - AzdUtils.logTelemetryEvent("azd-not-signed-in"); - withDescription("Not Signed In"); - onClicked(e -> { - final ConfirmAndRunDialog confirmAndRunDialog = new ConfirmAndRunDialog(project, "Sign in", "Do you want to sign in to Azure Developer CLI (azd)?", "azd auth login"); - confirmAndRunDialog.setOkButtonText("Sign In"); - confirmAndRunDialog.show(); - }); + command = MAC_AZD_INSTALL_COMMAND; } - } else { - AzdUtils.logTelemetryEvent("azd-not-installed"); - withDescription("Install azd"); - onClicked(e -> { - final String command; - if (System.getProperties().getProperty("os.name").toLowerCase().contains("windows")) { - command = "winget install microsoft.azd"; - } else if (System.getProperties().getProperty("os.name").toLowerCase().contains("linux")) { - command = "curl -fsSL https://aka.ms/install-azd.sh | bash"; + + final ConfirmAndRunDialog installDialog = new ConfirmAndRunDialog(project, "Install azd"); + installDialog.setLabel("Do you want to install Azure Developer CLI (azd)?"); + installDialog.setOkButtonText("Install"); + installDialog.setEventName("install"); + installDialog.setOnOkAction(() -> { + installAzd(command); + }); + installDialog.show(); + }); + } + + private void installAzd(String command) { + ProgressManager.getInstance().run(new Task.Backgroundable(project, "Install azd", false) { + @Override + public void run(com.intellij.openapi.progress.ProgressIndicator indicator) { + indicator.setIndeterminate(true); + indicator.setText(getTitle() + "..."); + final int exitCode = runAsBackgroundTask(command); + if (exitCode == 0) { + AzureEventBus.emit("azd.installed"); + NotificationGroupManager.getInstance() + .getNotificationGroup("Azure Developer") + .createNotification("Installation of azd is successful.", NotificationType.INFORMATION) + .notify(project); + + if (SystemUtils.IS_OS_WINDOWS) { + executeInTerminal(project, WIN_REFRESH_PATH_COMMAND); + } else if (SystemUtils.IS_OS_LINUX) { + executeInTerminal(project, LINUX_REFRESH_PATH_COMMAND); + } else { + executeInTerminal(project, MAC_REFRESH_PATH_COMMAND); + } + indicator.stop(); } else { - command = "brew tap azure/azd && brew install azd"; + indicator.setText("Installation of azd failed."); + NotificationGroupManager.getInstance() + .getNotificationGroup("Azure Developer") + .createNotification("Installation of azd failed.", NotificationType.ERROR) + .notify(project); + indicator.stop(); } - final ConfirmAndRunDialog installDialog = new ConfirmAndRunDialog(project, "Install azd", "Do you want to install Azure Developer CLI (azd)?", command); - installDialog.setOkButtonText("Install"); - installDialog.show(); - }); - } + } + }); + } + + public void showAzdActions() { + AzdUtils.logTelemetryEvent("azd-signed-in"); + addChild(getCreateFromTemplatesNode()); + addChild(getInitializeFromSourceNode()); + addChild(getProvisionResourcesNode()); + addChild(getDeployToAzureNode()); + addChild(getProvisionAndDeployToAzureNode()); + } + + @Override + public synchronized void refreshView() { + super.refreshView(); + refreshChildrenLater(true); } private Node getProvisionAndDeployToAzureNode() { return new Node<>("Provision and Deploy") .withIcon(AzureIcons.Action.START) - .onClicked(e -> new ConfirmAndRunDialog(project, "Provision and deploy", "Do you want to provision and deploy to Azure?", "azd up").show()); + .onClicked(e -> { + new ConfirmAndRunDialog(project, "Provision and deploy") + .setLabel("Do you want to provision and deploy to Azure?") + .setOnOkAction(() -> executeInTerminal(project, "azd up")) + .setEventName("provision-and-deploy") + .show(); + }); } private Node getDeployToAzureNode() { return new Node<>("Deploy to Azure") .withIcon(AzureIcons.Action.DEPLOY) - .onClicked(e -> new ConfirmAndRunDialog(project, "Deploy to Azure", "Do you want to start deployment to Azure?", "azd deploy").show()); + .onClicked(e -> new ConfirmAndRunDialog(project, "Deploy to Azure") + .setLabel("Do you want to start deployment to Azure?") + .setOnOkAction(() -> executeInTerminal(project, "azd deploy")) + .setEventName("deploy-to-azure") + .show()); } private Node getProvisionResourcesNode() { return new Node<>("Provision resources") .withIcon(AzureIcons.Action.EXPORT) - .onClicked(e -> new ConfirmAndRunDialog(project, "Provision Resources", "Do you want to provision Azure resources?", "azd provision").show()); + .onClicked(e -> new ConfirmAndRunDialog(project, "Provision Resources") + .setLabel("Do you want to provision Azure resources?") + .setOnOkAction(() -> executeInTerminal(project, "azd provision")) + .setEventName("provision-resources") + .show()); } private Node getInitializeFromSourceNode() { return new Node<>("Initialize from source") .withIcon(AzureIcons.Action.EDIT) - .onClicked(e -> new ConfirmAndRunDialog(project, "Initialize from source", "Do you want to initialize using existing code?", "azd init").show()); + .onClicked(e -> new ConfirmAndRunDialog(project, "Initialize from source") + .setLabel("Do you want to initialize using existing code?") + .setOnOkAction(() -> executeInTerminal(project, "azd init")) + .setEventName("initialize-from-source") + .show()); } private Node getCreateFromTemplatesNode() { @@ -100,40 +173,16 @@ private Node getCreateFromTemplatesNode() { }); } - private static boolean isAzdInstalled() { - final String azdVersionJson = runCommand("azd version -o json"); - if (azdVersionJson != null && !azdVersionJson.isEmpty()) { - try { - final Map response = OBJECT_MAPPER.readValue(azdVersionJson, Map.class); - if (response.containsKey("azd")) { - return true; - } - } catch (JsonProcessingException e) { - } - } - return false; + public static boolean isAzdInstalled() { + return runAsBackgroundTask("azd version -o json") == 0; } - private static boolean isAzdSignedIn() { - final String loginStatusJson = runCommand("azd auth login --check-status -o json"); - if (loginStatusJson != null && !loginStatusJson.isEmpty()) { - try { - final Map response = OBJECT_MAPPER.readValue(loginStatusJson, Map.class); - if (response.containsKey("status") && "success".equals(response.get("status"))) { - return true; - } - } catch (JsonProcessingException e) { - } - } - return false; - } - - public static String runCommand(String command) { + private static int runAsBackgroundTask(String command) { try { final ProcessBuilder processBuilder = new ProcessBuilder(); // Detect OS and set the appropriate command - String os = System.getProperty("os.name").toLowerCase(); - if (os.contains("win")) { + final String os = System.getProperty("os.name").toLowerCase(); + if (SystemUtils.IS_OS_WINDOWS) { processBuilder.command("cmd", "/c", command); // Windows } else { processBuilder.command("bash", "-c", command); // Linux/Unix @@ -145,13 +194,10 @@ public static String runCommand(String command) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { String output = reader.lines().collect(Collectors.joining("\n")); int exitCode = process.waitFor(); - if (exitCode != 0) { - return null; - } - return output; + return exitCode; } } catch (Exception e) { - return null; // Handle error appropriately + return 1; // Handle error appropriately } } } diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdTemplatesDialog.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdTemplatesDialog.java index 6351ef39b39..967dd7cdea8 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdTemplatesDialog.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdTemplatesDialog.java @@ -20,7 +20,7 @@ public AzdTemplatesDialog(@Nullable Project project) { @Override protected @Nullable JComponent createCenterPanel() { - return new AzdTemplatesLibrary(project); + return new AzdTemplatesLibrary(project, this); } @Override diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdTemplatesLibrary.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdTemplatesLibrary.java index 307fe197233..7ea3339b627 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdTemplatesLibrary.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdTemplatesLibrary.java @@ -7,6 +7,7 @@ import com.intellij.icons.AllIcons; import com.intellij.ide.BrowserUtil; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.ui.HyperlinkLabel; import com.intellij.ui.ScrollPaneFactory; @@ -38,10 +39,12 @@ public class AzdTemplatesLibrary extends JPanel { private final Project project; private final List templates; private final List selectedFilters = new ArrayList<>(); + private final DialogWrapper dialogWrapper; - public AzdTemplatesLibrary(Project project) { + public AzdTemplatesLibrary(Project project, DialogWrapper dialogWrapper) { super(); this.project = project; + this.dialogWrapper = dialogWrapper; setLayout(new BorderLayout()); setBorder(JBUI.Borders.empty(10)); this.templates = readFromGitHub("https://raw.githubusercontent.com/Azure/awesome-azd/refs/heads/main/website/static/templates.json"); @@ -154,9 +157,17 @@ private void createTemplateTile(AzdTemplate item, JPanel tilesPanel) { return; } // Show confirmation dialog - ConfirmAndRunDialog createDialog = new ConfirmAndRunDialog(project, "Create from template", "Create a new project from the selected template?", command); - createDialog.setOkButtonText("Create"); + final ConfirmAndRunDialog createDialog = new ConfirmAndRunDialog(project, "Create from template") + .setLabel("Create a new project from the selected template?") + .setEventName("create-from-template") + .setOnOkAction(() -> { + dialogWrapper.close(DialogWrapper.OK_EXIT_CODE); + AzdUtils.executeInTerminal(project, command); + }) + .setOkButtonText("Create"); + createDialog.show(); + }); commandPanel.add(runButton); diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdUtils.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdUtils.java index 0e3f2fed338..1cb1aee2420 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdUtils.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/AzdUtils.java @@ -1,5 +1,9 @@ package com.microsoft.azure.toolkit.intellij.explorer.azd; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.terminal.ui.TerminalWidget; +import com.microsoft.azure.toolkit.intellij.common.TerminalUtils; import com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemeter; import com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemetry; @@ -22,4 +26,13 @@ public static void logTelemetryEvent(String eventName) { ); AzureTelemeter.log(AzureTelemetry.Type.INFO, properties); } + + public static void executeInTerminal(Project project, String command) { + final TerminalWidget azdTerminal = TerminalUtils.getTerminalWidget(project, null, "azd"); + if (TerminalUtils.hasRunningCommands(azdTerminal)) { + Messages.showErrorDialog(project, "Another command is already running. Please try again later.", "Error"); + } else { + TerminalUtils.executeInTerminal(azdTerminal, command); + } + } } diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/ConfirmAndRunDialog.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/ConfirmAndRunDialog.java index 32ee7229d2d..241b3979838 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/ConfirmAndRunDialog.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/java/com/microsoft/azure/toolkit/intellij/explorer/azd/ConfirmAndRunDialog.java @@ -2,38 +2,53 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.terminal.ui.TerminalWidget; -import com.microsoft.azure.toolkit.intellij.common.TerminalUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.util.Locale; import java.util.Objects; public class ConfirmAndRunDialog extends DialogWrapper { private final Project project; - private final String label; - private final String command; - private final String eventName; + private String label; + private String command; + private String eventName; + private Runnable onOkAction; - public ConfirmAndRunDialog(Project project, String title, String label, String command) { + public ConfirmAndRunDialog(Project project, String title) { super(true); this.project = project; + setSize(300, 150); setTitle(Objects.requireNonNull(title, "Title must not be null")); setOKButtonText("Run"); - this.label = label; - init(); - setSize(300, 150); - this.command = command; - this.eventName = title.toLowerCase(Locale.ROOT).replace(" ", "-"); - AzdUtils.logTelemetryEvent("azd-" + eventName); } - public void setOkButtonText(String okButtonText) { + public ConfirmAndRunDialog setLabel(String label) { + this.label = Objects.requireNonNull(label, "Label must not be null"); + return this; + } + + public ConfirmAndRunDialog setEventName(String eventName) { + this.eventName = Objects.requireNonNull(eventName, "Event name must not be null"); + return this; + } + + public ConfirmAndRunDialog setOnOkAction(Runnable onOkAction) { + this.onOkAction = onOkAction; + return this; + } + + public ConfirmAndRunDialog setOkButtonText(String okButtonText) { setOKButtonText(okButtonText); + return this; + } + + @Override + public void show() { + init(); + super.show(); } @Override @@ -54,8 +69,9 @@ public void setOkButtonText(String okButtonText) { protected void doOKAction() { AzdUtils.logTelemetryEvent("azd-" + eventName + "-ok"); super.doOKAction(); - final TerminalWidget azdTerminal = TerminalUtils.getOrCreateTerminalWidget(project, null, "azd"); - TerminalUtils.executeInTerminal(azdTerminal, command); + if(onOkAction != null) { + onOkAction.run(); + } } @Override diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/resources/META-INF/azure-intellij-plugin-service-explorer.xml b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/resources/META-INF/azure-intellij-plugin-service-explorer.xml index e340e904ca1..0c777df32df 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/resources/META-INF/azure-intellij-plugin-service-explorer.xml +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-service-explorer/src/main/resources/META-INF/azure-intellij-plugin-service-explorer.xml @@ -13,4 +13,8 @@ + + + + diff --git a/Utils/azure-toolkit-ide-libs/azure-toolkit-ide-common-lib/src/main/java/com/microsoft/azure/toolkit/ide/common/component/Node.java b/Utils/azure-toolkit-ide-libs/azure-toolkit-ide-common-lib/src/main/java/com/microsoft/azure/toolkit/ide/common/component/Node.java index ad6fe23c73e..bc4f8c88141 100644 --- a/Utils/azure-toolkit-ide-libs/azure-toolkit-ide-common-lib/src/main/java/com/microsoft/azure/toolkit/ide/common/component/Node.java +++ b/Utils/azure-toolkit-ide-libs/azure-toolkit-ide-common-lib/src/main/java/com/microsoft/azure/toolkit/ide/common/component/Node.java @@ -169,6 +169,14 @@ public Node onClicked(Action.Id actionId) { return this; } + public void clearClickHandlers() { + this.clickHandlers.clear(); + } + + public void clearDoubleClickHandlers() { + this.doubleClickHandlers.clear(); + } + public void click(final Object event) { if (!this.clickHandlers.isEmpty()) { this.clickHandlers.forEach(h -> h.accept(this.value, event));