Repository: argoproj/argo-cd
Pull request #4376 (2020-09-18 19:20:07)

feat: Add version information panel (#4312)
- Add new extended version info panel that pops up when the version is clicked in the navbar
- Refactor kustomize and helm versions to be more user-friendly (also affects argo CLI)

Signed-off-by: Tim Etchells <tetchell@redhat.com>

Checklist:

* [x] Either (a) I've created an [enhancement proposal](https://github.com/argoproj/argo-cd/issues/new/choose) and discussed it with the community, (b) this is a bug fix, or (c) this does not need to be in the release notes.
* [x] The title of the PR states what changed and the related issues number (used for the release note).
* [x] I've updated both the CLI and UI to expose my feature, or I plan to submit a second PR with them.
* [ ] Does this PR require documentation updates? 
 - Maybe
* [ ] I've updated documentation as required by this PR.
* [x] Optional. My organization is added to USERS.md.
* [x] I've signed the CLA and my build is green ([troubleshooting builds](https://argoproj.github.io/argo-cd/developer-guide/ci/)). 


codecov-commenter: # [Codecov](https://codecov.io/gh/argoproj/argo-cd/pull/4376?src=pr&el=h1) Report
> Merging [#4376](https://codecov.io/gh/argoproj/argo-cd/pull/4376?src=pr&el=desc) into [master](https://codecov.io/gh/argoproj/argo-cd/commit/28e60406a8195dace34df48261345ec3f965f108?el=desc) will **decrease** coverage by `0.01%`.
> The diff coverage is `42.85%`.

[![Impacted file tree graph](https://codecov.io/gh/argoproj/argo-cd/pull/4376/graphs/tree.svg?width=650&height=150&src=pr&token=kf5kwuegwE)](https://codecov.io/gh/argoproj/argo-cd/pull/4376?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #4376      +/-   ##
==========================================
- Coverage   41.16%   41.14%   -0.02%     
==========================================
  Files         122      122              
  Lines       16579    16596      +17     
==========================================
+ Hits         6824     6829       +5     
- Misses       8772     8781       +9     
- Partials      983      986       +3     
```


| [Impacted Files](https://codecov.io/gh/argoproj/argo-cd/pull/4376?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [util/kustomize/kustomize.go](https://codecov.io/gh/argoproj/argo-cd/pull/4376/diff?src=pr&el=tree#diff-dXRpbC9rdXN0b21pemUva3VzdG9taXplLmdv) | `61.20% <37.50%> (-4.82%)` | :arrow_down: |
| [util/helm/helm.go](https://codecov.io/gh/argoproj/argo-cd/pull/4376/diff?src=pr&el=tree#diff-dXRpbC9oZWxtL2hlbG0uZ28=) | `61.81% <60.00%> (-0.93%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/argoproj/argo-cd/pull/4376?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/argoproj/argo-cd/pull/4376?src=pr&el=footer). Last update [28e6040...04360d8](https://codecov.io/gh/argoproj/argo-cd/pull/4376?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

tetchel: new `argocd version` server output

```
argocd-server: v99.99.99+unknown
  BuildDate: 1970-01-01T00:00:00Z
  GitCommit:
  GitTreeState:
  GoVersion: go1.14.1
  Compiler: gc
  Platform: linux/amd64
  Ksonnet Version: v0.13.1
  Kustomize Version: v3.8.1 2020-07-16T00:58:46Z
  Helm Version: v3.3.1+g249e521
  Kubectl Version: v1.17.8
```
tetchel: demo:
![version-panel(1)](https://user-images.githubusercontent.com/8888438/93639638-58180a00-f9c7-11ea-8d7e-f2f17bd1ee7b.gif)

[version-panel.mov.zip](https://github.com/argoproj/argo-cd/files/5247852/version-panel.mov.zip)


tetchel: resolves https://github.com/argoproj/argo-cd/issues/4312
tetchel: I am totally new to Go and fairly new to React so please go ahead and nitpick if you'd like :)
rbreeze: Love the new panel. I found that after removing the CSS it still looks almost identical so I think it's best to leave it out if possible. I also inlined `VersionInfoButton` to keep down the amount of new code added, and I think the `VersionInfoPanel` file should live in the `shared` directory. 

LGTM, this is really useful.
tetchel: I can appreciate the desire to keep the code as simple as possible, but I wouldn't have added the styles if I didn't think those details mattered. 

Especially the styles on the `version-info-button` are important to allow a user to discover this panel; otherwise on mouse-over it looks like the tooltip is all you get. The `:hover` `pointer` and `underline` are what make it look clickable. 

The styles on the panel itself are definitely more subjective and I am OK without most of those, however I think the Copy button is a little cramped now and the icon could use some padding. 

![image](https://user-images.githubusercontent.com/8888438/94935756-6f60f800-049b-11eb-969e-4b5b20b34456.png)

The reason I set the `min-width` was because the text changes on the button when you click it, and I did not like the button changing widths on-click and then resetting.


Patch:
diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml
index 74dd05224..ab23e0960 100644
--- a/.github/workflows/ci-build.yaml
+++ b/.github/workflows/ci-build.yaml
@@ -326,7 +326,7 @@ jobs:
           git config --global user.email "john.doe@example.com"
       - name: Pull Docker image required for tests
         run: |
-          docker pull quay.io/dexidp/dex:v2.22.0
+          docker pull quay.io/dexidp/dex:v2.25.0
           docker pull argoproj/argo-cd-ci-builder:v1.0.0
           docker pull redis:5.0.8-alpine
       - name: Create target directory for binaries in the build-process
diff --git a/Procfile b/Procfile
index 09a1adc1c..a96ddd261 100644
--- a/Procfile
+++ b/Procfile
@@ -1,6 +1,6 @@
 controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} go run ./cmd/argocd-application-controller/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
 api-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} go run ./cmd/argocd-server/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --staticassets ui/dist/app"
-dex: sh -c "go run github.com/argoproj/argo-cd/cmd/argocd-util gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml quay.io/dexidp/dex:v2.22.0 serve /dex.yaml"
+dex: sh -c "go run github.com/argoproj/argo-cd/cmd/argocd-util gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml quay.io/dexidp/dex:v2.25.0 serve /dex.yaml"
 redis: docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} redis:5.0.8-alpine --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}
 repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} go run ./cmd/argocd-repo-server/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
 ui: sh -c 'cd ui && ${ARGOCD_E2E_YARN_CMD:-yarn} start'
diff --git a/USERS.md b/USERS.md
index 3563ba83e..575eab852 100644
--- a/USERS.md
+++ b/USERS.md
@@ -65,6 +65,7 @@ Currently, the following organizations are **officially** using Argo CD:
 1. [Swisscom](https://www.swisscom.ch)
 1. [Swissquote](https://github.com/swissquote)
 1. [Syncier](https://syncier.com/)
+1. [TableCheck](https://tablecheck.com/)
 1. [Tesla](https://tesla.com/)
 1. [ThousandEyes](https://www.thousandeyes.com/)
 1. [Ticketmaster](https://ticketmaster.com)
@@ -87,3 +88,5 @@ Currently, the following organizations are **officially** using Argo CD:
 1. [New Relic](https://newrelic.com/)
 1. [Sumo Logic](https://sumologic.com/)
 1. [Kinguin](https://www.kinguin.net/)
+1. [Speee](https://speee.jp/)
+1. [VISITS Technologies](https://visits.world/en)
diff --git a/controller/cache/info.go b/controller/cache/info.go
index 5bcf1375a..db7649e64 100644
--- a/controller/cache/info.go
+++ b/controller/cache/info.go
@@ -142,7 +142,7 @@ func populateIngressInfo(un *unstructured.Unstructured, res *ResourceInfo) {
 
 				subPath := ""
 				if nestedPath, ok, err := unstructured.NestedString(path, "path"); ok && err == nil {
-					subPath = nestedPath
+					subPath = strings.TrimSuffix(nestedPath, "*")
 				}
 				externalURL += subPath
 				urlsSet[externalURL] = true
diff --git a/docs/cli_installation.md b/docs/cli_installation.md
index 2d688b0f0..3ed832bda 100644
--- a/docs/cli_installation.md
+++ b/docs/cli_installation.md
@@ -53,3 +53,27 @@ chmod +x /usr/local/bin/argocd
 ```
 
 After finishing either of the instructions above, you should now be able to run `argocd` commands.
+
+
+## Windows
+
+### Download With Powershell: Invoke-WebRequest
+
+You can view the latest version of Argo CD at the link above or run the following command to grab the version:
+
+```powershell
+$version = (Invoke-RestMethod https://api.github.com/repos/argoproj/argo-cd/releases/latest).tag_name
+```
+
+Replace `$version` in the command below with the version of Argo CD you would like to download:
+
+```powershell
+$url = "https://github.com/argoproj/argo-cd/releases/download/" + $version + "/argocd-windows-amd64.exe"
+$output = "argocd.exe"
+
+Invoke-WebRequest -Uri $url -OutFile $output
+```
+Also please note you will probably need to move the file into your PATH.
+
+
+After finishing the instructions above, you should now be able to run `argocd` commands.
diff --git a/docs/developer-guide/dependencies.md b/docs/developer-guide/dependencies.md
new file mode 100644
index 000000000..374d85eed
--- /dev/null
+++ b/docs/developer-guide/dependencies.md
@@ -0,0 +1,33 @@
+# Managing Dependencies
+
+## GitOps Engine (`github.com/argoproj/gitops-engine`)
+
+### Repository
+
+https://github.com/argoproj/gitops-engine
+
+### Pulling changes from `gitops-engine` 
+
+After your GitOps Engine PR has been merged, ArgoCD needs to be updated to pull in the version of the GitOps engine that contains your change.  Here are the steps:
+
+* Retrieve the SHA hash for your commit. You will use this in the next step.
+* From the `argo-cd` folder, run the following command
+
+    `go get github.com/argoproj/gitops-engine@<git-commit-sha>`
+
+    If you get an error message `invalid version: unknown revision` then you got the wrong SHA hash
+
+* Run:
+
+    `go mod tidy`
+
+* The following files are changed:
+
+    - `go.mod`
+    - `go.sum`
+
+* Create an ArgoCD PR with a `refactor:` type in its title for the two file changes.
+
+### Tips:
+* See https://github.com/argoproj/argo-cd/pull/4434 as an example
+* The PR might require additional, dependent changes in ArgoCD that are directly impacted by the changes made in the engine.  
diff --git a/docs/index.md b/docs/index.md
index ca81014e1..b42bba85b 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -24,7 +24,7 @@ kubectl create namespace argocd
 kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
 ```
 
-Follow our [getting started guide](getting_started.md). Further user oriented [documentation](user_guide/)
+Follow our [getting started guide](getting_started.md). Further user oriented [documentation](user-guide/)
 is provided for additional features. If you are looking to upgrade ArgoCD, see the [upgrade guide](./operator-manual/upgrading/overview.md).
 Developer oriented [documentation](developer-guide/) is available for people interested in building third-party integrations.
 
diff --git a/docs/user-guide/compare-options.md b/docs/user-guide/compare-options.md
index 27024b261..1f4661028 100644
--- a/docs/user-guide/compare-options.md
+++ b/docs/user-guide/compare-options.md
@@ -4,7 +4,7 @@
 
 >v1.1
 
-You may wish to exclude resources from the app's overall sync status under certain circumstances. E.g. if they are generated by a tool. This can be done by adding this annotation:
+You may wish to exclude resources from the app's overall sync status under certain circumstances. E.g. if they are generated by a tool. This can be done by adding this annotation on the resource you wish to exclude:
 
 ```yaml
 metadata:
diff --git a/go.mod b/go.mod
index 8d62e0a47..156ac7994 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
 	github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect
 	github.com/alicebob/miniredis v2.5.0+incompatible
-	github.com/argoproj/gitops-engine v0.1.3-0.20200925215903-d25b8fd69f0d
+	github.com/argoproj/gitops-engine v0.1.3-0.20201003031953-3a3f6a33d7ee
 	github.com/argoproj/pkg v0.2.0
 	github.com/casbin/casbin v1.9.1
 	github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect
diff --git a/go.sum b/go.sum
index 6bd90ef61..71ce5199d 100644
--- a/go.sum
+++ b/go.sum
@@ -68,8 +68,8 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
-github.com/argoproj/gitops-engine v0.1.3-0.20200925215903-d25b8fd69f0d h1:uSKX9+3sVmo4DPwKsn8IdwAMxjkvqCpLN5FXG426vic=
-github.com/argoproj/gitops-engine v0.1.3-0.20200925215903-d25b8fd69f0d/go.mod h1:jeiFokbkgLXjvx3eXB0MddyxsmftWsFTY7paLH4ZqCg=
+github.com/argoproj/gitops-engine v0.1.3-0.20201003031953-3a3f6a33d7ee h1:L1n/Q1twmfqcMcBstONI4SIUOI7wu6cmYK4woxBvXIk=
+github.com/argoproj/gitops-engine v0.1.3-0.20201003031953-3a3f6a33d7ee/go.mod h1:jeiFokbkgLXjvx3eXB0MddyxsmftWsFTY7paLH4ZqCg=
 github.com/argoproj/pkg v0.2.0 h1:ETgC600kr8WcAi3MEVY5sA1H7H/u1/IysYOobwsZ8No=
 github.com/argoproj/pkg v0.2.0/go.mod h1:F4TZgInLUEjzsWFB/BTJBsewoEy0ucnKSq6vmQiD/yc=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
diff --git a/manifests/base/dex/argocd-dex-server-deployment.yaml b/manifests/base/dex/argocd-dex-server-deployment.yaml
index 7bf33be47..13b247f79 100644
--- a/manifests/base/dex/argocd-dex-server-deployment.yaml
+++ b/manifests/base/dex/argocd-dex-server-deployment.yaml
@@ -26,7 +26,7 @@ spec:
           name: static-files
       containers:
       - name: dex
-        image: quay.io/dexidp/dex:v2.22.0
+        image: quay.io/dexidp/dex:v2.25.0
         imagePullPolicy: Always
         command: [/shared/argocd-util, rundex]
         ports:
diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml
index 0117cd047..36b5aa539 100644
--- a/manifests/ha/install.yaml
+++ b/manifests/ha/install.yaml
@@ -2785,7 +2785,7 @@ spec:
       - command:
         - /shared/argocd-util
         - rundex
-        image: quay.io/dexidp/dex:v2.22.0
+        image: quay.io/dexidp/dex:v2.25.0
         imagePullPolicy: Always
         name: dex
         ports:
diff --git a/manifests/ha/namespace-install.yaml b/manifests/ha/namespace-install.yaml
index 270515d6d..a0b3a5f7a 100644
--- a/manifests/ha/namespace-install.yaml
+++ b/manifests/ha/namespace-install.yaml
@@ -2700,7 +2700,7 @@ spec:
       - command:
         - /shared/argocd-util
         - rundex
-        image: quay.io/dexidp/dex:v2.22.0
+        image: quay.io/dexidp/dex:v2.25.0
         imagePullPolicy: Always
         name: dex
         ports:
diff --git a/manifests/install.yaml b/manifests/install.yaml
index e7a8242b4..49a499ea6 100644
--- a/manifests/install.yaml
+++ b/manifests/install.yaml
@@ -2373,7 +2373,7 @@ spec:
       - command:
         - /shared/argocd-util
         - rundex
-        image: quay.io/dexidp/dex:v2.22.0
+        image: quay.io/dexidp/dex:v2.25.0
         imagePullPolicy: Always
         name: dex
         ports:
diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml
index 7b8a1b808..797732489 100644
--- a/manifests/namespace-install.yaml
+++ b/manifests/namespace-install.yaml
@@ -2288,7 +2288,7 @@ spec:
       - command:
         - /shared/argocd-util
         - rundex
-        image: quay.io/dexidp/dex:v2.22.0
+        image: quay.io/dexidp/dex:v2.25.0
         imagePullPolicy: Always
         name: dex
         ports:
diff --git a/mkdocs.yml b/mkdocs.yml
index b46d01df6..5bbd0a4c3 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -92,6 +92,7 @@ nav:
     - developer-guide/debugging-remote-environment.md
     - developer-guide/api-docs.md
     - developer-guide/test-e2e.md
+    - developer-guide/dependencies.md
     - developer-guide/ci.md
     - developer-guide/releasing.md
     - developer-guide/site.md
diff --git a/reposerver/server.go b/reposerver/server.go
index 27ebc03db..cc158827a 100644
--- a/reposerver/server.go
+++ b/reposerver/server.go
@@ -64,6 +64,8 @@ func NewServer(metricsServer *metrics.MetricsServer, cache *reposervercache.Cach
 			grpc.Creds(credentials.NewTLS(tlsConfig)),
 			grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptors...)),
 			grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(streamInterceptors...)),
+			grpc.MaxRecvMsgSize(apiclient.MaxGRPCMessageSize),
+			grpc.MaxSendMsgSize(apiclient.MaxGRPCMessageSize),
 		},
 	}, nil
 }
diff --git a/server/version/version.go b/server/version/version.go
index a151f23b1..806cfcbd4 100644
--- a/server/version/version.go
+++ b/server/version/version.go
@@ -34,16 +34,15 @@ func (s *Server) Version(context.Context, *empty.Empty) (*version.VersionMessage
 		}
 	}
 	if s.kustomizeVersion == "" {
-		kustomizeVersion, err := kustomize.Version()
+		kustomizeVersion, err := kustomize.Version(true)
 		if err == nil {
 			s.kustomizeVersion = kustomizeVersion
 		} else {
 			s.kustomizeVersion = err.Error()
 		}
-
 	}
 	if s.helmVersion == "" {
-		helmVersion, err := helm.Version()
+		helmVersion, err := helm.Version(true)
 		if err == nil {
 			s.helmVersion = helmVersion
 		} else {
diff --git a/ui/src/app/app.tsx b/ui/src/app/app.tsx
index 68b3ce44f..450627d16 100644
--- a/ui/src/app/app.tsx
+++ b/ui/src/app/app.tsx
@@ -9,6 +9,7 @@ import applications from './applications';
 import help from './help';
 import login from './login';
 import settings from './settings';
+import {VersionPanel} from './shared/components/version-info/version-info-panel';
 import {Provider} from './shared/context';
 import {services} from './shared/services';
 import requests from './shared/services/requests';
@@ -52,7 +53,7 @@ const navItems = [
     }
 ];
 
-const versionInfo = services.version.version();
+const versionLoader = services.version.version();
 
 async function isExpiredSSO() {
     try {
@@ -92,7 +93,7 @@ requests.onError.subscribe(async err => {
     }
 });
 
-export class App extends React.Component<{}, {popupProps: PopupProps; error: Error}> {
+export class App extends React.Component<{}, {popupProps: PopupProps; showVersionPanel: boolean; error: Error}> {
     public static childContextTypes = {
         history: PropTypes.object,
         apis: PropTypes.object
@@ -108,7 +109,7 @@ export class App extends React.Component<{}, {popupProps: PopupProps; error: Err
 
     constructor(props: {}) {
         super(props);
-        this.state = {popupProps: null, error: null};
+        this.state = {popupProps: null, error: null, showVersionPanel: false};
         this.popupManager = new PopupManager();
         this.notificationsManager = new NotificationsManager();
         this.navigationManager = new NavigationManager(history);
@@ -186,11 +187,15 @@ export class App extends React.Component<{}, {popupProps: PopupProps; error: Err
                                                     <Layout
                                                         navItems={navItems}
                                                         version={() => (
-                                                            <DataLoader load={() => versionInfo}>
-                                                                {msg => (
-                                                                    <Tooltip content={msg.Version}>
-                                                                        <span style={{whiteSpace: 'nowrap'}}>{msg.Version}</span>
-                                                                    </Tooltip>
+                                                            <DataLoader load={() => versionLoader}>
+                                                                {version => (
+                                                                    <React.Fragment>
+                                                                        <Tooltip content={version.Version}>
+                                                                            <a style={{color: 'white'}} onClick={() => this.setState({showVersionPanel: true})}>
+                                                                                {version.Version}
+                                                                            </a>
+                                                                        </Tooltip>
+                                                                    </React.Fragment>
                                                                 )}
                                                             </DataLoader>
                                                         )}>
@@ -219,6 +224,7 @@ export class App extends React.Component<{}, {popupProps: PopupProps; error: Err
                     </Provider>
                 </PageContext.Provider>
                 <Notifications notifications={this.notificationsManager.notifications} />
+                <VersionPanel version={versionLoader} isShown={this.state.showVersionPanel} onClose={() => this.setState({showVersionPanel: false})} />
             </React.Fragment>
         );
     }
diff --git a/ui/src/app/applications/components/application-details/application-details.scss b/ui/src/app/applications/components/application-details/application-details.scss
index bb9a77a61..1e478e338 100644
--- a/ui/src/app/applications/components/application-details/application-details.scss
+++ b/ui/src/app/applications/components/application-details/application-details.scss
@@ -71,6 +71,17 @@
         }
     }
 
+    &__resource-icon{
+        text-align: center;
+        position: absolute;
+        left: 0;
+        top: 10px;
+        width: 60px;
+        line-height: 1;
+        color: $argo-color-gray-5;
+        font-size: 0.8em;
+    }
+
     .application-resource-tree {
         margin: 0 auto;
     }
diff --git a/ui/src/app/applications/components/application-details/application-resource-list.tsx b/ui/src/app/applications/components/application-details/application-resource-list.tsx
index b0d3c469b..a5069ed3f 100644
--- a/ui/src/app/applications/components/application-details/application-resource-list.tsx
+++ b/ui/src/app/applications/components/application-details/application-resource-list.tsx
@@ -3,6 +3,7 @@ import * as React from 'react';
 
 import * as models from '../../../shared/models';
 import {ResourceIcon} from '../resource-icon';
+import {ResourceLabel} from '../resource-label';
 import {ComparisonStatusIcon, HealthStatusIcon, nodeKey} from '../utils';
 
 export const ApplicationResourceList = ({
@@ -30,7 +31,11 @@ export const ApplicationResourceList = ({
                 <div key={nodeKey(res)} className='argo-table-list__row' onClick={() => onNodeClick(nodeKey(res))}>
                     <div className='row'>
                         <div className='columns small-1 xxxlarge-1'>
-                            <ResourceIcon kind={res.kind} />
+                            <div className='application-details__resource-icon'>
+                                <ResourceIcon kind={res.kind} />
+                                <br />
+                                <div>{ResourceLabel({kind: res.kind})}</div>
+                            </div>
                         </div>
                         <div className='columns small-2 xxxlarge-2'>{res.name}</div>
                         <div className='columns small-3 xxxlarge-4'>{[res.group, res.kind].filter(item => !!item).join('/')}</div>
diff --git a/ui/src/app/shared/components/version-info/version-info-panel.tsx b/ui/src/app/shared/components/version-info/version-info-panel.tsx
new file mode 100644
index 000000000..757550e47
--- /dev/null
+++ b/ui/src/app/shared/components/version-info/version-info-panel.tsx
@@ -0,0 +1,111 @@
+import {DataLoader, SlidingPanel, Tooltip} from 'argo-ui';
+import * as React from 'react';
+import {VersionMessage} from '../../models';
+
+interface VersionPanelProps {
+    isShown: boolean;
+    onClose: () => void;
+    version: Promise<VersionMessage>;
+}
+
+type CopyState = 'success' | 'failed' | undefined;
+
+export class VersionPanel extends React.Component<VersionPanelProps, {copyState: CopyState}> {
+    private readonly header = 'Argo CD Server Version';
+
+    constructor(props: VersionPanelProps) {
+        super(props);
+        this.state = {copyState: undefined};
+    }
+
+    public render() {
+        return (
+            <DataLoader load={() => this.props.version}>
+                {version => {
+                    return (
+                        <SlidingPanel header={this.header} isShown={this.props.isShown} onClose={() => this.props.onClose()} hasCloseButton={true} isNarrow={true}>
+                            <div className='argo-table-list'>{this.buildVersionTable(version)}</div>
+                            <div>
+                                <Tooltip content='Copy all version info as JSON'>{this.getCopyButton(version)}</Tooltip>
+                            </div>
+                        </SlidingPanel>
+                    );
+                }}
+            </DataLoader>
+        );
+    }
+
+    /**
+     * Formats the version data and renders the table rows.
+     */
+    private buildVersionTable(version: VersionMessage): JSX.Element {
+        const formattedVersion = {
+            'Argo CD': version.Version,
+            'Build Date': version.BuildDate,
+            'Go': version.GoVersion,
+            'Compiler': version.Compiler,
+            'Platform': version.Platform,
+            'ksonnet': version.KsonnetVersion,
+            'kustomize': version.KustomizeVersion,
+            'Helm': version.HelmVersion,
+            'kubectl': version.KubectlVersion
+        };
+
+        return (
+            <React.Fragment>
+                {Object.entries(formattedVersion).map(([key, value]) => {
+                    return (
+                        <div className='argo-table-list__row' key={key}>
+                            <div className='row'>
+                                <div className='columns small-4' title={key}>
+                                    <strong>{key}</strong>
+                                </div>
+                                <div className='columns'>
+                                    <Tooltip content={value}>
+                                        <span>{value}</span>
+                                    </Tooltip>
+                                </div>
+                            </div>
+                        </div>
+                    );
+                })}
+            </React.Fragment>
+        );
+    }
+
+    private getCopyButton(version: VersionMessage): JSX.Element {
+        let img: string;
+        let text: string;
+        if (this.state.copyState === 'success') {
+            img = 'fa-check';
+            text = 'Copied';
+        } else if (this.state.copyState === 'failed') {
+            img = 'fa-times';
+            text = 'Copy Failed';
+        } else {
+            img = 'fa-copy';
+            text = 'Copy JSON';
+        }
+
+        return (
+            <button className='argo-button argo-button--base' style={{marginTop: '1em', minWidth: '18ch'}} onClick={() => this.onCopy(version)}>
+                <i className={'fa ' + img} />
+                &nbsp;&nbsp;{text}
+            </button>
+        );
+    }
+
+    private async onCopy(version: VersionMessage): Promise<void> {
+        const stringifiedVersion = JSON.stringify(version, undefined, 4);
+        try {
+            await navigator.clipboard.writeText(stringifiedVersion);
+            this.setState({copyState: 'success'});
+        } catch (err) {
+            this.setState({copyState: 'failed'});
+        }
+
+        setTimeout(() => {
+            this.setState({copyState: undefined});
+        }, 750);
+    }
+}
diff --git a/ui/src/app/shared/models.ts b/ui/src/app/shared/models.ts
index fbdd05983..a8c166d8d 100644
--- a/ui/src/app/shared/models.ts
+++ b/ui/src/app/shared/models.ts
@@ -697,6 +697,15 @@ export interface ApplicationSyncWindowState {
 
 export interface VersionMessage {
     Version: string;
+    BuildDate: string;
+    GoVersion: string;
+    Compiler: string;
+    Platform: string;
+    KsonnetVersion: string;
+    KustomizeVersion: string;
+    HelmVersion: string;
+    KubectlVersion: string;
+    JsonnetVersion: string;
 }
 
 export interface Token {
diff --git a/util/helm/helm.go b/util/helm/helm.go
index 67b662d3c..5f44e33df 100644
--- a/util/helm/helm.go
+++ b/util/helm/helm.go
@@ -86,8 +86,16 @@ func (h *helm) Dispose() {
 	h.cmd.Close()
 }
 
-func Version() (string, error) {
-	cmd := exec.Command("helm", "version", "--client")
+func Version(shortForm bool) (string, error) {
+	executable := "helm"
+	cmdArgs := []string{"version", "--client"}
+	if shortForm {
+		cmdArgs = append(cmdArgs, "--short")
+	}
+	cmd := exec.Command(executable, cmdArgs...)
+	// example version output:
+	// long: "version.BuildInfo{Version:\"v3.3.1\", GitCommit:\"249e5215cde0c3fa72e27eb7a30e8d55c9696144\", GitTreeState:\"clean\", GoVersion:\"go1.14.7\"}"
+	// short: "v3.3.1+g249e521"
 	version, err := executil.RunWithRedactor(cmd, redactor)
 	if err != nil {
 		return "", fmt.Errorf("could not get helm version: %s", err)
diff --git a/util/kustomize/kustomize.go b/util/kustomize/kustomize.go
index 862e8e8f2..057fcfb63 100644
--- a/util/kustomize/kustomize.go
+++ b/util/kustomize/kustomize.go
@@ -187,13 +187,35 @@ func IsKustomization(path string) bool {
 	return false
 }
 
-func Version() (string, error) {
-	cmd := exec.Command("kustomize", "version")
-	out, err := executil.Run(cmd)
+func Version(shortForm bool) (string, error) {
+	executable := "kustomize"
+	cmdArgs := []string{"version"}
+	if shortForm {
+		cmdArgs = append(cmdArgs, "--short")
+	}
+	cmd := exec.Command(executable, cmdArgs...)
+	// example version output:
+	// long: "{Version:kustomize/v3.8.1 GitCommit:0b359d0ef0272e6545eda0e99aacd63aef99c4d0 BuildDate:2020-07-16T00:58:46Z GoOs:linux GoArch:amd64}"
+	// short: "{kustomize/v3.8.1  2020-07-16T00:58:46Z  }"
+	version, err := executil.Run(cmd)
 	if err != nil {
 		return "", fmt.Errorf("could not get kustomize version: %s", err)
 	}
-	return strings.TrimSpace(out), nil
+	version = strings.TrimSpace(version)
+	if shortForm {
+		// trim the curly braces
+		version = strings.TrimPrefix(version, "{")
+		version = strings.TrimSuffix(version, "}")
+		version = strings.TrimSpace(version)
+
+		// remove double space in middle
+		version = strings.ReplaceAll(version, "  ", " ")
+
+		// remove extra 'kustomize/' before version
+		version = strings.TrimPrefix(version, "kustomize/")
+
+	}
+	return version, nil
 }
 
 func getImageParameters(objs []*unstructured.Unstructured) []Image {


Test patch:
diff --git a/controller/cache/info_test.go b/controller/cache/info_test.go
index b29c874bf..30e02dd7a 100644
--- a/controller/cache/info_test.go
+++ b/controller/cache/info_test.go
@@ -71,6 +71,37 @@ var (
       ingress:
       - ip: 107.178.210.11`)
 
+	testIngressWildCardPath = strToUnstructured(`
+  apiVersion: extensions/v1beta1
+  kind: Ingress
+  metadata:
+    name: helm-guestbook
+    namespace: default
+    uid: "4"
+  spec:
+    backend:
+      serviceName: not-found-service
+      servicePort: 443
+    rules:
+    - host: helm-guestbook.com
+      http:
+        paths:
+        - backend:
+            serviceName: helm-guestbook
+            servicePort: 443
+          path: /*
+        - backend:
+            serviceName: helm-guestbook
+            servicePort: https
+          path: /*
+    tls:
+    - host: helm-guestbook.com
+    secretName: my-tls-secret
+  status:
+    loadBalancer:
+      ingress:
+      - ip: 107.178.210.11`)
+
 	testIngressWithoutTls = strToUnstructured(`
   apiVersion: extensions/v1beta1
   kind: Ingress
@@ -159,6 +190,30 @@ func TestGetIngressInfo(t *testing.T) {
 	}, info.NetworkingInfo)
 }
 
+func TestGetIngressInfoWildCardPath(t *testing.T) {
+	info := &ResourceInfo{}
+	populateNodeInfo(testIngressWildCardPath, info)
+	assert.Equal(t, 0, len(info.Info))
+	sort.Slice(info.NetworkingInfo.TargetRefs, func(i, j int) bool {
+		return strings.Compare(info.NetworkingInfo.TargetRefs[j].Name, info.NetworkingInfo.TargetRefs[i].Name) < 0
+	})
+	assert.Equal(t, &v1alpha1.ResourceNetworkingInfo{
+		Ingress: []v1.LoadBalancerIngress{{IP: "107.178.210.11"}},
+		TargetRefs: []v1alpha1.ResourceRef{{
+			Namespace: "default",
+			Group:     "",
+			Kind:      kube.ServiceKind,
+			Name:      "not-found-service",
+		}, {
+			Namespace: "default",
+			Group:     "",
+			Kind:      kube.ServiceKind,
+			Name:      "helm-guestbook",
+		}},
+		ExternalURLs: []string{"https://helm-guestbook.com/"},
+	}, info.NetworkingInfo)
+}
+
 func TestGetIngressInfoWithoutTls(t *testing.T) {
 	info := &ResourceInfo{}
 	populateNodeInfo(testIngressWithoutTls, info)
diff --git a/test/container/Procfile b/test/container/Procfile
index 15be79365..4b15b28c8 100644
--- a/test/container/Procfile
+++ b/test/container/Procfile
@@ -1,6 +1,6 @@
 controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-application-controller/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
 api-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-server/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --staticassets ui/dist/app"
-dex: sh -c "test $ARGOCD_IN_CI = true && exit 0; go run github.com/argoproj/argo-cd/cmd/argocd-util gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml quay.io/dexidp/dex:v2.22.0 serve /dex.yaml"
+dex: sh -c "test $ARGOCD_IN_CI = true && exit 0; go run github.com/argoproj/argo-cd/cmd/argocd-util gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml quay.io/dexidp/dex:v2.25.0 serve /dex.yaml"
 redis: sh -c "/usr/local/bin/redis-server --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}"
 repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} go run ./cmd/argocd-repo-server/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
 ui: sh -c "test $ARGOCD_IN_CI = true && exit 0; cd ui && ARGOCD_E2E_YARN_HOST=0.0.0.0 ${ARGOCD_E2E_YARN_CMD:-yarn} start"
diff --git a/util/health/health_test.go b/util/health/health_test.go
index 221793ac3..4952bb009 100644
--- a/util/health/health_test.go
+++ b/util/health/health_test.go
@@ -111,7 +111,7 @@ func TestAppOfAppsHealth(t *testing.T) {
 		degradedAndHealthyLiveObjects := []*unstructured.Unstructured{degradedApp, healthyApp}
 		healthStatus, err := SetApplicationHealth(degradedAndHealthyStatuses, degradedAndHealthyLiveObjects, nil, noFilter)
 		assert.NoError(t, err)
-		assert.Equal(t, health.HealthStatusDegraded, healthStatus.Status)
+		assert.Equal(t, health.HealthStatusHealthy, healthStatus.Status)
 	}
 
 }
diff --git a/util/helm/helm_test.go b/util/helm/helm_test.go
index c31e67ca4..27a79aad1 100644
--- a/util/helm/helm_test.go
+++ b/util/helm/helm_test.go
@@ -165,7 +165,7 @@ func TestHelmArgCleaner(t *testing.T) {
 }
 
 func TestVersion(t *testing.T) {
-	ver, err := Version()
+	ver, err := Version(false)
 	assert.NoError(t, err)
 	assert.NotEmpty(t, ver)
 }
diff --git a/util/kustomize/kustomize_test.go b/util/kustomize/kustomize_test.go
index 9ad0c38ac..2996b2b7e 100644
--- a/util/kustomize/kustomize_test.go
+++ b/util/kustomize/kustomize_test.go
@@ -101,7 +101,7 @@ func TestParseKustomizeBuildOptions(t *testing.T) {
 }
 
 func TestVersion(t *testing.T) {
-	ver, err := Version()
+	ver, err := Version(false)
 	assert.NoError(t, err)
 	assert.NotEmpty(t, ver)
 }