Skip to content
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

feat: Add external link annotation support. #3487 #4380

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ const (
AnnotationValueManagedByArgoCD = "argocd.argoproj.io"
// ResourcesFinalizerName the finalizer value which we inject to finalize deletion of an application
ResourcesFinalizerName = "resources-finalizer.argocd.argoproj.io"

// AnnotationKeyLinkPrefix tells the UI to add an external link icon to the application node
// that links to the value given in the annotation.
// The annotation key must be followed by a unique identifier. Ex: link.argocd.argoproj.io/dashboard
// It's valid to have multiple annotions that match the prefix.
// Values can simply be a url or they can have
// an optional link title separated by a "|"
// Ex: "http://grafana.example.com/d/yu5UH4MMz/deployments"
// Ex: "Go to Dashboard|http://grafana.example.com/d/yu5UH4MMz/deployments"
AnnotationKeyLinkPrefix = "link.argocd.argoproj.io/"
)

// Environment variables for tuning and debugging Argo CD
Expand Down
17 changes: 16 additions & 1 deletion controller/cache/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cache

import (
"fmt"
"strings"

"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/argoproj/gitops-engine/pkg/utils/text"
Expand All @@ -10,6 +11,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
k8snode "k8s.io/kubernetes/pkg/util/node"

"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/util/resource"
)
Expand Down Expand Up @@ -37,6 +39,15 @@ func populateNodeInfo(un *unstructured.Unstructured, res *ResourceInfo) {
return
}
}

for k, v := range un.GetAnnotations() {
if strings.HasPrefix(k, common.AnnotationKeyLinkPrefix) {
if res.NetworkingInfo == nil {
res.NetworkingInfo = &v1alpha1.ResourceNetworkingInfo{}
}
res.NetworkingInfo.ExternalURLs = append(res.NetworkingInfo.ExternalURLs, v)
}
}
}

func getIngress(un *unstructured.Unstructured) []v1.LoadBalancerIngress {
Expand Down Expand Up @@ -142,7 +153,11 @@ func populateIngressInfo(un *unstructured.Unstructured, res *ResourceInfo) {
for target := range targetsMap {
targets = append(targets, target)
}
urls := make([]string, 0)

var urls []string
if res.NetworkingInfo != nil {
urls = res.NetworkingInfo.ExternalURLs
}
for url := range urlsSet {
urls = append(urls, url)
}
Expand Down
47 changes: 40 additions & 7 deletions ui/src/app/applications/components/application-urls.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,56 @@
import {DropDownMenu} from 'argo-ui';
import * as React from 'react';

class ExternalLink {
public title: string;
public ref: string;

constructor(url: string) {
const parts = url.split('|');
if (parts.length === 2) {
this.title = parts[0];
this.ref = parts[1];
} else {
this.title = url;
this.ref = url;
}
}
}

export const ApplicationURLs = ({urls}: {urls: string[]}) => {
(urls || []).sort();
const externalLinks: ExternalLink[] = [];
for (const url of urls || []) {
externalLinks.push(new ExternalLink(url));
}

// sorted alphabetically & links with titles first
externalLinks.sort((a, b) => {
if (a.title !== '' && b.title !== '') {
return a.title > b.title ? 1 : -1;
} else if (a.title === '') {
return 1;
} else if (b.title === '') {
return -1;
}
return a.ref > b.ref ? 1 : -1;
});

return (
((urls || []).length > 0 && (
((externalLinks || []).length > 0 && (
<span>
<a
title={externalLinks[0].title}
onClick={e => {
e.stopPropagation();
window.open(urls[0]);
window.open(externalLinks[0].ref);
}}>
<i className='fa fa-external-link-alt' />{' '}
{urls.length > 1 && (
{externalLinks.length > 1 && (
<DropDownMenu
anchor={() => <i className='fa fa-caret-down' />}
items={urls.map(item => ({
title: item,
action: () => window.open(item)
items={externalLinks.map(item => ({
title: item.title,
action: () => window.open(item.ref)
}))}
/>
)}
Expand Down