diff --git a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java index 9f6c105de..bbf4eb178 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java @@ -70,14 +70,19 @@ public Object getApplicationsRoot() { @NotNull @Override - public Object @NotNull [] getChildElements(@NotNull Object element) { + public Object @NotNull [] getChildElements(@NotNull Object element) { try { if (element == this) { return new Object[]{root, registries}; } else if (element instanceof ApplicationsRootNode) { - return getCurrentNamespace((ApplicationsRootNode) element); + return new Object[] { + getCurrentNamespace((ApplicationsRootNode) element), + new HelmRepositoriesNode((ApplicationsRootNode) element) + }; } else if (element instanceof NamespaceNode) { return createNamespaceChildren((NamespaceNode) element); + } else if (element instanceof HelmRepositoriesNode) { + return createHelmRepositoriesChildren((HelmRepositoriesNode) element); } else if (element instanceof ComponentNode) { return createComponentChildren((ComponentNode) element); } else if (element instanceof DevfileRegistriesNode) { @@ -136,8 +141,9 @@ private Object[] createNamespaceChildren(@NotNull NamespaceNode namespaceNode) { return nodes.toArray(); } - private Object[] getCurrentNamespace(ApplicationsRootNode element) { - List namespaces = new ArrayList<>(); + @NotNull + private Object getCurrentNamespace(ApplicationsRootNode element) { + Object node; try { Odo odo = root.getOdo().getNow(null); if (odo == null) { @@ -146,20 +152,38 @@ private Object[] getCurrentNamespace(ApplicationsRootNode element) { boolean isAuthorized = odo.isAuthorized(); element.setLogged(isAuthorized); if (!isAuthorized) { - namespaces.add(new MessageNode<>(root, root, LOGIN)); + node = new MessageNode<>(root, root, LOGIN); } else { String namespace = odo.getCurrentNamespace(); if (namespace != null) { - namespaces.add(new NamespaceNode(element, namespace)); + node = new NamespaceNode(element, namespace); } else { - namespaces.add(new CreateNamespaceLinkNode(element)); + node = new CreateNamespaceLinkNode(element); } } } catch (Exception e) { - namespaces.add(createErrorNode(element, e)); + node = createErrorNode(element, e); element.setLogged(false); } - return namespaces.toArray(); + return node; + } + + private Object[] createHelmRepositoriesChildren(HelmRepositoriesNode parent) { + Helm helm = root.getHelm(true).getNow(null); + if (helm == null) { + return new Object[] { new MessageNode<>(root, parent, "Could not list repositories: Helm binary missing.") }; + } + try { + var repositories = helm.listRepos(); + if (repositories == null) { + return new Object[] { new MessageNode<>(root, parent, "Could not list repositories: no repositories defined.") }; + } + return repositories.stream() + .map(repository -> new HelmRepositoryNode(root, parent, repository)) + .toArray(); + } catch (IOException e) { + throw new RuntimeException(e); + } } private MessageNode createErrorNode(ParentableNode parent, Exception e) { diff --git a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/DescriptorFactory.java b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/DescriptorFactory.java index b161813a9..064896931 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/DescriptorFactory.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/DescriptorFactory.java @@ -14,6 +14,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; import com.redhat.devtools.intellij.common.tree.LabelAndIconDescriptor; +import org.jboss.tools.intellij.openshift.ui.SwingUtils; import org.jboss.tools.intellij.openshift.ui.helm.ChartIcons; import org.jboss.tools.intellij.openshift.utils.odo.Binding; import org.jboss.tools.intellij.openshift.utils.odo.Component; @@ -35,8 +36,11 @@ public class DescriptorFactory { private static final Icon COMPONENT_TYPE_ICON = IconLoader.findIcon("/images/component-type-light.png", ApplicationsTreeStructure.class); private static final Icon STARTER_ICON = IconLoader.findIcon("/images/start-project-light.png", ApplicationsTreeStructure.class); private static final Icon REGISTRY_ICON = IconLoader.findIcon("/images/registry.svg", ApplicationsTreeStructure.class); + private static final Icon HELM_REPOSITORY_ICON = IconLoader.findIcon("/images/helm/repo.svg", ApplicationsTreeStructure.class); - public static @NotNull NodeDescriptor create(@NotNull Object element, @Nullable NodeDescriptor parentDescriptor, @NotNull ApplicationsTreeStructure structure, @NotNull Project project) { + private static final int ICON_WIDTH = 15; + + public static @NotNull NodeDescriptor create(@NotNull Object element, @Nullable NodeDescriptor parentDescriptor, @NotNull ApplicationsTreeStructure structure, @NotNull Project project) { if (element == structure) { return new LabelAndIconDescriptor<>( project, @@ -157,7 +161,29 @@ public class DescriptorFactory { releaseNode, releaseNode::getName, () -> "Helm Release", - () -> ChartIcons.getIcon15x15(releaseNode.getRelease()), + () -> SwingUtils.scaleIcon(ICON_WIDTH, ChartIcons.getIcon(releaseNode.getRelease())), + parentDescriptor); + } else if (element instanceof HelmRepositoriesNode) { + HelmRepositoriesNode helmRepositoriesNode = (HelmRepositoriesNode) element; + return new ApplicationsTreeStructure.ProcessableDescriptor<>( + project, + helmRepositoriesNode, + helmRepositoriesNode::getName, + () -> "Repositories", + () -> SwingUtils.scaleIcon(ICON_WIDTH, ChartIcons.getHelmIcon()), + parentDescriptor); + } else if (element instanceof HelmRepositoryNode) { + HelmRepositoryNode helmRepositoryNode = (HelmRepositoryNode) element; + return new ApplicationsTreeStructure.ProcessableDescriptor<>( + project, + helmRepositoryNode, + helmRepositoryNode::getName, + () -> { + var repository = helmRepositoryNode.getRepository(); + return repository != null ? + repository.getUrl() : ""; + }, + () -> HELM_REPOSITORY_ICON, parentDescriptor); } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/HelmRepositoriesNode.java b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/HelmRepositoriesNode.java new file mode 100644 index 000000000..b21d88010 --- /dev/null +++ b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/HelmRepositoriesNode.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2024 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package org.jboss.tools.intellij.openshift.tree.application; + +public class HelmRepositoriesNode extends BaseNode { + public HelmRepositoriesNode(ApplicationsRootNode parent) { + super(parent, parent, "Helm"); + } +} diff --git a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/HelmRepositoryNode.java b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/HelmRepositoryNode.java new file mode 100644 index 000000000..51791bc8b --- /dev/null +++ b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/HelmRepositoryNode.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2024 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package org.jboss.tools.intellij.openshift.tree.application; + +import org.jboss.tools.intellij.openshift.utils.helm.Repository; + +public class HelmRepositoryNode extends BaseNode { + + private final Repository repository; + + public HelmRepositoryNode(ApplicationsRootNode root, HelmRepositoriesNode parent, Repository repository) { + super(root, parent, repository.getName()); + this.repository = repository; + } + + public Repository getRepository() { + return repository; + } +} diff --git a/src/main/java/org/jboss/tools/intellij/openshift/ui/SwingUtils.java b/src/main/java/org/jboss/tools/intellij/openshift/ui/SwingUtils.java index 55a1de004..81e228f37 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/ui/SwingUtils.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/ui/SwingUtils.java @@ -14,9 +14,11 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.wm.impl.IdeGlassPaneEx; import com.intellij.ui.JBColor; +import com.intellij.ui.SizedIcon; import com.intellij.ui.WindowMoveListener; import com.intellij.ui.WindowResizeListener; import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.scale.JBUIScale; import com.intellij.ui.table.JBTable; import com.intellij.util.containers.JBIterable; import com.intellij.util.ui.JBFont; @@ -26,6 +28,7 @@ import javax.swing.AbstractButton; import javax.swing.DefaultCellEditor; +import javax.swing.Icon; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; @@ -149,4 +152,10 @@ public static Point locationOrMouseLocation(Point location) { return location; } + public static Icon scaleIcon(int width, Icon icon) { + float scale = (float) width / icon.getIconWidth(); + SizedIcon scaled = JBUIScale.scaleIcon(new SizedIcon(icon, icon.getIconWidth(), icon.getIconHeight())); + return scaled.scale(scale); + } + } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/ui/helm/ChartIcons.java b/src/main/java/org/jboss/tools/intellij/openshift/ui/helm/ChartIcons.java index a058168a2..43afa2bbb 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/ui/helm/ChartIcons.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/ui/helm/ChartIcons.java @@ -11,8 +11,6 @@ package org.jboss.tools.intellij.openshift.ui.helm; import com.intellij.ui.IconManager; -import com.intellij.ui.SizedIcon; -import com.intellij.ui.scale.JBUIScale; import org.jboss.tools.intellij.openshift.utils.helm.ChartRelease; import javax.swing.Icon; @@ -26,28 +24,25 @@ public class ChartIcons { private static final Path BASE_PATH = Paths.get("images", "helm"); private static final String HELM_ICON = "helm.png"; - public static javax.swing.Icon getIcon(ChartVersions chart) { - return getIcon(chart.getName() + chart.getDescription()); + public static Icon getHelmIcon() { + return IconManager.getInstance().getIcon(BASE_PATH.resolve(HELM_ICON).toString(), ChartIcons.class); } - public static javax.swing.Icon getIcon(ChartRelease chart) { - return getIcon(chart.getChart()); + public static Icon getIcon(ChartVersions chart) { + return getIcon(chart.getName() + chart.getDescription()); } - public static javax.swing.Icon getIcon15x15(ChartRelease chart) { - Icon icon = getIcon(chart); - float scale = 15f / icon.getIconWidth(); - SizedIcon sized = JBUIScale.scaleIcon(new SizedIcon(icon, icon.getIconHeight(), icon.getIconHeight())); - return sized.scale(scale); + public static Icon getIcon(ChartRelease chart) { + return getIcon(chart.getChart()); } - private static javax.swing.Icon getIcon(String name) { + private static Icon getIcon(String name) { Optional found = Stream.of(IconExpression.values()) .filter((IconExpression available) -> available.isMatching(name)) .findFirst(); return found .map(iconExpression -> IconManager.getInstance().getIcon(iconExpression.filename, ChartIcons.class)) - .orElseGet(() -> IconManager.getInstance().getIcon(BASE_PATH.resolve(HELM_ICON).toString(), ChartIcons.class)); + .orElseGet(ChartIcons::getHelmIcon); } private enum IconExpression { @@ -88,5 +83,4 @@ public boolean isMatching(String chartText) { return chartText.toLowerCase().contains(substring.toLowerCase()); } } - } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/Helm.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/Helm.java index e07655da9..004a6bbe9 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/Helm.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/Helm.java @@ -17,6 +17,8 @@ public interface Helm { String addRepo(String name, String url) throws IOException; + List listRepos() throws IOException; + List search() throws IOException; List search(String regex) throws IOException; diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCli.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCli.java index 2f0e3ad79..03c7b856a 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCli.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCli.java @@ -57,6 +57,21 @@ public String addRepo(String name, String url) throws IOException { } } + @Override + public List listRepos() throws IOException { + ActionMessage telemetry = TelemetryService.instance().getBuilder().action( + TelemetryService.NAME_PREFIX_MISC + "helm-list repo"); + try { + LOGGER.info("Listing repos."); + String repos = execute(command, Collections.emptyMap(), "repo", "list", "-o=json"); + asyncSend(telemetry.success()); + return Serialization.json().readValue(repos, new TypeReference<>() {}); + } catch (IOException e) { + asyncSend(telemetry.error(e)); + throw e; + } + } + @Override public List search() throws IOException { ActionMessage telemetry = TelemetryService.instance().getBuilder().action( diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/Repository.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/Repository.java new file mode 100644 index 000000000..846cba9dd --- /dev/null +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/Repository.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2024 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package org.jboss.tools.intellij.openshift.utils.helm; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Repository { + + private String name; + private String url; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/src/main/resources/images/.DS_Store b/src/main/resources/images/.DS_Store deleted file mode 100644 index 18a94e928..000000000 Binary files a/src/main/resources/images/.DS_Store and /dev/null differ diff --git a/src/main/resources/images/helm/repo.svg b/src/main/resources/images/helm/repo.svg new file mode 100644 index 000000000..72fd4acd2 --- /dev/null +++ b/src/main/resources/images/helm/repo.svg @@ -0,0 +1 @@ + \ No newline at end of file