Skip to content

Commit 7c0fa05

Browse files
Merge pull request #8115 from microsoft/wangmi/dev.next
manage Azure Container Registries in services view.
2 parents 0ebecfd + c0847e2 commit 7c0fa05

File tree

20 files changed

+616
-20
lines changed

20 files changed

+616
-20
lines changed

PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-base/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pluginVersion=3.85.0-SNAPSHOT
22
intellijDisplayVersion=2023.3
3-
intellij_version=IU-LATEST-EAP-SNAPSHOT
3+
intellij_version=IU-2023.3.2
44
dep_plugins=org.intellij.scala:2023.3.3
55
patchPluginXmlSinceBuild=233.9102.97
66
needPatchVersion=true

PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-containerregistry/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
intellij {
2-
plugins = ['java', 'maven', 'maven-model', 'gradle', 'gradle-java', 'terminal']
2+
plugins = ['java', 'maven', 'maven-model', 'gradle', 'gradle-java', 'terminal', 'Docker']
33
}
44

55
repositories {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*/
5+
6+
package com.microsoft.azure.toolkit.intellij.containerregistry;
7+
8+
import com.intellij.docker.registry.DockerRegistryConfiguration;
9+
import com.intellij.docker.registry.DockerRegistryManager;
10+
import com.intellij.docker.view.registry.DockerRegistryServiceViewContributor;
11+
import com.intellij.docker.view.registry.node.DockerRegistryRoot;
12+
import com.intellij.execution.services.ServiceEventListener;
13+
import com.intellij.execution.services.ServiceViewContributor;
14+
import com.intellij.execution.services.ServiceViewManager;
15+
import com.intellij.openapi.actionSystem.AnActionEvent;
16+
import com.intellij.openapi.application.ApplicationManager;
17+
import com.intellij.openapi.project.Project;
18+
import com.intellij.openapi.ui.MessageDialogBuilder;
19+
import com.intellij.openapi.wm.ToolWindow;
20+
import com.intellij.openapi.wm.ToolWindowManager;
21+
import com.intellij.util.messages.MessageBus;
22+
import com.intellij.util.messages.MessageBusConnection;
23+
import com.microsoft.azure.toolkit.ide.common.IActionsContributor;
24+
import com.microsoft.azure.toolkit.ide.common.action.ResourceCommonActionsContributor;
25+
import com.microsoft.azure.toolkit.ide.containerregistry.ContainerRegistryActionsContributor;
26+
import com.microsoft.azure.toolkit.intellij.containerregistry.servicesview.AzureContainerRegistryProvider;
27+
import com.microsoft.azure.toolkit.lib.common.action.Action;
28+
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
29+
import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
30+
import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
31+
import com.microsoft.azure.toolkit.lib.common.messager.IAzureMessage;
32+
import com.microsoft.azure.toolkit.lib.common.model.AbstractAzResource;
33+
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
34+
import com.microsoft.azure.toolkit.lib.containerregistry.ContainerRegistry;
35+
import org.apache.commons.lang3.StringUtils;
36+
37+
import javax.annotation.Nonnull;
38+
import java.util.Objects;
39+
import java.util.Optional;
40+
import java.util.function.Predicate;
41+
42+
import static com.microsoft.azure.toolkit.intellij.containerregistry.servicesview.AzureContainerRegistryConfigurator.ENABLE_ADMIN_USER_DOC_LINK;
43+
44+
@SuppressWarnings("UnstableApiUsage")
45+
public class IntelliJContainerRegistryActionsContributorForDockerPlugin implements IActionsContributor {
46+
public static final String NULL_SERVICE_MESSAGE = "Failed to get Docker Registries root in \"Services\" view, please check whether \"Docker\" plugin is correctly installed.";
47+
48+
@Override
49+
public void registerHandlers(AzureActionManager am) {
50+
am.registerHandler(ResourceCommonActionsContributor.OPEN_IN_SERVICES_VIEW, (r, e) -> r instanceof ContainerRegistry,
51+
(AbstractAzResource<?, ?, ?> r, AnActionEvent e) -> {
52+
final ContainerRegistry registry = (ContainerRegistry) r;
53+
final AzureString msg = AzureString.format("<html><body>Admin user is not enabled for (%s), but it is required to login a Azure Container Registry. <b>Do you want to enable Admin user and then open it in \"services\" view?</b> <br>You can learn more about admin user <a href='" + ENABLE_ADMIN_USER_DOC_LINK + "'>here</a>.</body></html>", registry.getName());
54+
final IAzureMessage message = AzureMessager.getMessager().buildConfirmMessage(msg, "Enable Admin User");
55+
final boolean[] result = new boolean[1];
56+
if (!registry.isAdminUserEnabled()) {
57+
ApplicationManager.getApplication().invokeAndWait(() -> result[0] = MessageDialogBuilder.yesNo("Enable Admin User", message.getContent()).guessWindowAndAsk());
58+
if (result[0]) {
59+
final Action<ContainerRegistry> enableAdminUser = AzureActionManager.getInstance().getAction(ContainerRegistryActionsContributor.ENABLE_ADMIN_USER);
60+
enableAdminUser.handleSync(registry);
61+
}
62+
}
63+
if (registry.isAdminUserEnabled()) {
64+
AzureTaskManager.getInstance().runLater(() -> openRegistryInServicesView(registry, Objects.requireNonNull(e.getProject())));
65+
}
66+
}
67+
);
68+
}
69+
70+
private static void openRegistryInServicesView(@Nonnull final ContainerRegistry data, @Nonnull final Project project) {
71+
final ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Services");
72+
if (Objects.nonNull(toolWindow) && !toolWindow.isActive()) {
73+
toolWindow.activate(() -> openRegistryInServicesView(data, project));
74+
return;
75+
}
76+
final ServiceViewContributor<?> root = ServiceViewContributor.CONTRIBUTOR_EP_NAME.findExtension(DockerRegistryServiceViewContributor.class);
77+
if (Objects.isNull(root)) {
78+
final Action<String> installAction = AzureActionManager.getInstance().getAction(ResourceCommonActionsContributor.SEARCH_MARKETPLACE_PLUGIN).bind("Docker").withLabel("Install");
79+
AzureMessager.getMessager().warning(NULL_SERVICE_MESSAGE, installAction);
80+
return;
81+
}
82+
final ServiceViewContributor<?> registry = getRegistryService(data, project, root).orElse(null);
83+
if (Objects.nonNull(registry)) {
84+
focusInServicesView(registry, root, project);
85+
} else {
86+
addAndFocusInServicesView(data, root, project);
87+
}
88+
}
89+
90+
private static void addAndFocusInServicesView(@Nonnull final ContainerRegistry data, ServiceViewContributor<?> root, @Nonnull final Project project) {
91+
final DockerRegistryManager registryManager = DockerRegistryManager.getInstance();
92+
final Predicate<DockerRegistryConfiguration> exists = r -> r.getAddress().equals(data.getLoginServerUrl()) && r.getUsername().equalsIgnoreCase(data.getUserName());
93+
if (registryManager.getRegistries().stream().noneMatch(exists)) {
94+
final MessageBus messageBus = project.getMessageBus();
95+
final MessageBusConnection connect = messageBus.connect();
96+
connect.subscribe(ServiceEventListener.TOPIC, (ServiceEventListener) serviceEvent -> {
97+
final boolean isDockerRegistryEvent = serviceEvent.contributorClass == root.getClass();
98+
if (isDockerRegistryEvent) {
99+
getRegistryService(data, project, root).ifPresent(service -> {
100+
focusInServicesView(service, root, project);
101+
connect.disconnect();
102+
});
103+
}
104+
});
105+
AzureTaskManager.getInstance().runOnPooledThread(() -> {
106+
final DockerRegistryConfiguration config = new DockerRegistryConfiguration().withName(data.getName());
107+
config.setRegistryProviderId(AzureContainerRegistryProvider.ID);
108+
config.setAddress(data.getLoginServerUrl());
109+
config.setUsername(data.getUserName());
110+
config.setPasswordSafe(data.getPrimaryCredential());
111+
112+
registryManager.addRegistry(config);
113+
});
114+
}
115+
}
116+
117+
private static void focusInServicesView(@Nonnull final ServiceViewContributor<?> service,
118+
@Nonnull final ServiceViewContributor<?> contributor, final Project project) {
119+
ServiceViewManager.getInstance(project).select(service, contributor.getClass(), true, true);
120+
ServiceViewManager.getInstance(project).expand(service, contributor.getClass());
121+
}
122+
123+
private static Optional<DockerRegistryRoot> getRegistryService(final @Nonnull ContainerRegistry data, final @Nonnull Project project, final ServiceViewContributor<?> root) {
124+
return root.getServices(project).stream()
125+
.filter(c -> c instanceof DockerRegistryRoot)
126+
.map(c -> (DockerRegistryRoot) c)
127+
.filter(r -> StringUtils.equals(r.getConfiguration().getAddress(), data.getLoginServerUrl()) && StringUtils.equals(r.getConfiguration().getUsername(), data.getUserName()))
128+
.findFirst();
129+
}
130+
131+
}

PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-containerregistry/src/main/java/com/microsoft/azure/toolkit/intellij/containerregistry/component/AzureContainerRegistryComboBox.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,26 @@
66
package com.microsoft.azure.toolkit.intellij.containerregistry.component;
77

88

9+
import com.intellij.icons.AllIcons;
10+
import com.intellij.openapi.keymap.KeymapUtil;
11+
import com.intellij.ui.components.fields.ExtendableTextComponent;
12+
import com.microsoft.azure.toolkit.ide.common.action.ResourceCommonActionsContributor;
913
import com.microsoft.azure.toolkit.ide.common.icon.AzureIcons;
1014
import com.microsoft.azure.toolkit.intellij.common.AzureComboBox;
1115
import com.microsoft.azure.toolkit.intellij.common.IntelliJAzureIcons;
1216
import com.microsoft.azure.toolkit.lib.Azure;
1317
import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
18+
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
1419
import com.microsoft.azure.toolkit.lib.common.model.Subscription;
1520
import com.microsoft.azure.toolkit.lib.containerregistry.AzureContainerRegistry;
1621
import com.microsoft.azure.toolkit.lib.containerregistry.ContainerRegistry;
1722

1823
import javax.annotation.Nonnull;
1924
import javax.annotation.Nullable;
2025
import javax.swing.*;
26+
import java.awt.event.InputEvent;
27+
import java.awt.event.KeyEvent;
28+
import java.util.Collections;
2129
import java.util.List;
2230
import java.util.Objects;
2331
import java.util.Optional;
@@ -63,9 +71,25 @@ protected Icon getItemIcon(Object item) {
6371
@Nonnull
6472
@Override
6573
protected List<? extends ContainerRegistry> loadItems() throws Exception {
66-
final Stream<Subscription> subscriptionStream = Optional.ofNullable(subscription).map(Stream::of).orElseGet(()-> !listAllSubscription ? Stream.empty() :
67-
Azure.az(AzureAccount.class).account().getSelectedSubscriptions().stream());
74+
if (!Azure.az(AzureAccount.class).isLoggedIn()) {
75+
return Collections.emptyList();
76+
}
77+
final Stream<Subscription> subscriptionStream = Optional.ofNullable(subscription).map(Stream::of).orElseGet(() -> !listAllSubscription ? Stream.empty() :
78+
Azure.az(AzureAccount.class).account().getSelectedSubscriptions().stream());
6879
return subscriptionStream.map(s -> Azure.az(AzureContainerRegistry.class).registry(s.getId()))
69-
.flatMap(module -> module.list().stream()).collect(Collectors.toList());
80+
.flatMap(module -> module.list().stream()).collect(Collectors.toList());
81+
}
82+
83+
@Nonnull
84+
@Override
85+
protected List<ExtendableTextComponent.Extension> getExtensions() {
86+
final List<ExtendableTextComponent.Extension> extensions = super.getExtensions();
87+
final KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, InputEvent.ALT_DOWN_MASK);
88+
final String tooltip = String.format("Create Azure Container Registry in Azure Portal (%s)", KeymapUtil.getKeystrokeText(keyStroke));
89+
final ExtendableTextComponent.Extension addEx = ExtendableTextComponent.Extension.create(AllIcons.General.Add, tooltip,
90+
()-> AzureActionManager.getInstance().getAction(ResourceCommonActionsContributor.CREATE_IN_PORTAL).handle(Azure.az(AzureContainerRegistry.class)));
91+
this.registerShortcut(keyStroke, addEx);
92+
extensions.add(addEx);
93+
return extensions;
7094
}
7195
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*/
5+
6+
package com.microsoft.azure.toolkit.intellij.containerregistry.servicesview;
7+
8+
import com.intellij.docker.registry.DockerRegistryConfigurable;
9+
import com.intellij.docker.registry.DockerRegistryConfiguration;
10+
import com.intellij.docker.registry.DockerRegistryManager;
11+
import com.intellij.openapi.actionSystem.AnAction;
12+
import com.intellij.openapi.actionSystem.AnActionEvent;
13+
import com.intellij.openapi.options.ShowSettingsUtil;
14+
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
15+
import org.jetbrains.annotations.NotNull;
16+
17+
import java.util.function.Predicate;
18+
19+
public class AddContainerRegistryServiceAction extends AnAction {
20+
@Override
21+
@AzureOperation("user/acr.edit_acr_registry_in_services_view")
22+
public void actionPerformed(@NotNull final AnActionEvent e) {
23+
final DockerRegistryConfiguration registry = (new DockerRegistryConfiguration()).withName("New Azure Container Registry");
24+
registry.setRegistryProviderId(AzureContainerRegistryProvider.ID);
25+
final DockerRegistryConfigurable configurable = new DockerRegistryConfigurable(registry, null, false);
26+
if (ShowSettingsUtil.getInstance().editConfigurable(e.getProject(), configurable)) {
27+
final DockerRegistryManager registryManager = DockerRegistryManager.getInstance();
28+
final Predicate<DockerRegistryConfiguration> exists = r -> r.getAddress().equals(registry.getAddress()) && r.getUsername().equalsIgnoreCase(registry.getUsername());
29+
if (registryManager.getRegistries().stream().noneMatch(exists)) {
30+
registryManager.addRegistry(registry);
31+
}
32+
}
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.microsoft.azure.toolkit.intellij.containerregistry.servicesview.AzureContainerRegistryConfigurator">
3+
<grid id="27dc6" binding="contentPanel" layout-manager="GridLayoutManager" row-count="6" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
4+
<margin top="0" left="0" bottom="0" right="0"/>
5+
<constraints>
6+
<xy x="35" y="20" width="377" height="170"/>
7+
</constraints>
8+
<properties/>
9+
<border type="none"/>
10+
<children>
11+
<vspacer id="7877">
12+
<constraints>
13+
<grid row="5" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="1" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
14+
</constraints>
15+
</vspacer>
16+
<component id="af4b3" class="javax.swing.JLabel" binding="lblSubscription">
17+
<constraints>
18+
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
19+
</constraints>
20+
<properties>
21+
<horizontalTextPosition value="10"/>
22+
<text value="Subscription:"/>
23+
<toolTipText value="All resources in an Azure subscription are billed together."/>
24+
</properties>
25+
</component>
26+
<component id="3be99" class="com.microsoft.azure.toolkit.intellij.common.component.SubscriptionComboBox" binding="selectorSubscription">
27+
<constraints>
28+
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
29+
</constraints>
30+
<properties/>
31+
</component>
32+
<component id="ced48" class="javax.swing.JLabel" binding="lblRegistry">
33+
<constraints>
34+
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
35+
</constraints>
36+
<properties>
37+
<text value="Instance:"/>
38+
</properties>
39+
</component>
40+
<component id="355ab" class="com.microsoft.azure.toolkit.intellij.containerregistry.component.AzureContainerRegistryComboBox" binding="selectorRegistry" custom-create="true">
41+
<constraints>
42+
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
43+
</constraints>
44+
<properties/>
45+
</component>
46+
<component id="b6f53" class="com.intellij.ui.components.JBLabel" binding="notSignInLabel" custom-create="true">
47+
<constraints>
48+
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
49+
</constraints>
50+
<properties>
51+
<visible value="false"/>
52+
</properties>
53+
</component>
54+
<component id="f77e2" class="com.intellij.ui.components.JBLabel" binding="noRegistryLabel" custom-create="true">
55+
<constraints>
56+
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
57+
</constraints>
58+
<properties>
59+
<visible value="false"/>
60+
</properties>
61+
</component>
62+
<component id="17552" class="com.intellij.ui.components.JBLabel" binding="enableAdminLabel" custom-create="true">
63+
<constraints>
64+
<grid row="4" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
65+
</constraints>
66+
<properties>
67+
<visible value="false"/>
68+
</properties>
69+
</component>
70+
</children>
71+
</grid>
72+
</form>

0 commit comments

Comments
 (0)