From 275daa79766931d3517edc9bbefffe08a39940c8 Mon Sep 17 00:00:00 2001 From: Liviu Costea Date: Sat, 25 Jul 2020 01:37:58 +0300 Subject: [PATCH] feat: Support applications with cluster name in the ui #1548 (#3944) * feat: Support applications with cluster name in the ui * Retrigger CI pipeline --- test/e2e/cluster_test.go | 5 ++-- .../application-create-panel.tsx | 1 + .../application-summary.tsx | 23 +++++++++++++------ .../applications-list/applications-tiles.tsx | 9 +++++++- .../cluster-details/cluster-details.tsx | 4 ++-- ui/src/app/shared/components/cluster.tsx | 10 ++++---- ui/src/app/shared/models.ts | 4 ++++ .../app/shared/services/clusters-service.ts | 10 ++++++-- util/db/cluster.go | 1 + util/db/cluster_test.go | 2 +- 10 files changed, 49 insertions(+), 20 deletions(-) diff --git a/test/e2e/cluster_test.go b/test/e2e/cluster_test.go index b9a4045968..a3475d56aa 100644 --- a/test/e2e/cluster_test.go +++ b/test/e2e/cluster_test.go @@ -13,14 +13,15 @@ import ( func TestClusterList(t *testing.T) { output := FailOnErr(RunCli("cluster", "list")).(string) - assert.Equal(t, fmt.Sprintf(`SERVER NAME VERSION STATUS MESSAGE -https://kubernetes.default.svc %v Successful `, GetVersions().ServerVersion), output) + assert.Equal(t, fmt.Sprintf(`SERVER NAME VERSION STATUS MESSAGE +https://kubernetes.default.svc in-cluster %v Successful `, GetVersions().ServerVersion), output) } func TestClusterGet(t *testing.T) { output := FailOnErr(RunCli("cluster", "get", "https://kubernetes.default.svc")).(string) assert.Contains(t, output, fmt.Sprintf(` +name: in-cluster server: https://kubernetes.default.svc serverVersion: "%v"`, GetVersions().ServerVersion)) diff --git a/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx b/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx index 04c16db507..42672480b0 100644 --- a/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx +++ b/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx @@ -28,6 +28,7 @@ const DEFAULT_APP: Partial = { }, spec: { destination: { + name: '', namespace: '', server: '' }, diff --git a/ui/src/app/applications/components/application-summary/application-summary.tsx b/ui/src/app/applications/components/application-summary/application-summary.tsx index 3df82b04ba..b380adc9ac 100644 --- a/ui/src/app/applications/components/application-summary/application-summary.tsx +++ b/ui/src/app/applications/components/application-summary/application-summary.tsx @@ -28,6 +28,8 @@ function swap(array: any[], a: number, b: number) { export const ApplicationSummary = (props: {app: models.Application; updateApp: (app: models.Application) => Promise}) => { const app = JSON.parse(JSON.stringify(props.app)) as models.Application; const isHelm = app.spec.source.hasOwnProperty('chart'); + const isDestName = app.spec.destination.server === undefined; + const fieldDest = isDestName ? 'spec.destination.name' : 'spec.destination.server'; const attributes = [ { @@ -59,18 +61,18 @@ export const ApplicationSummary = (props: {app: models.Application; updateApp: ( }, { title: 'CLUSTER', - view: , + view: , edit: (formApi: FormApi) => ( services.clusters.list().then(clusters => clusters.map(cluster => ({ title: clusterTitle(cluster), - value: cluster.server + value: isDestName ? cluster.name : cluster.server })) ) }> - {clusters => } + {clusters => } ) }, @@ -326,10 +328,17 @@ Default is 10.
({ - 'spec.project': !input.spec.project && 'Project name is required', - 'spec.destination.server': !input.spec.destination.server && 'Cluster is required' - })} + validate={input => + isDestName + ? { + 'spec.project': !input.spec.project && 'Project name is required', + 'spec.destination.name': !input.spec.destination.name && 'Cluster is required' + } + : { + 'spec.project': !input.spec.project && 'Project name is required', + 'spec.destination.server': !input.spec.destination.server && 'Cluster is required' + } + } values={app} title={app.metadata.name.toLocaleUpperCase()} items={attributes} diff --git a/ui/src/app/applications/components/applications-list/applications-tiles.tsx b/ui/src/app/applications/components/applications-list/applications-tiles.tsx index e1a874f8d6..cf9f36eff4 100644 --- a/ui/src/app/applications/components/applications-list/applications-tiles.tsx +++ b/ui/src/app/applications/components/applications-list/applications-tiles.tsx @@ -18,6 +18,13 @@ export interface ApplicationTilesProps { deleteApplication: (appName: string) => any; } +function getDestination(dest: models.ApplicationDestination) { + if (dest.server === undefined) { + return dest.name; + } + return dest.server; +} + export const ApplicationTiles = ({applications, syncApplication, refreshApplication, deleteApplication}: ApplicationTilesProps) => ( {ctx => ( @@ -102,7 +109,7 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat )}
Destination:
-
{app.spec.destination.server}
+
{getDestination(app.spec.destination)}
Namespace:
diff --git a/ui/src/app/settings/components/cluster-details/cluster-details.tsx b/ui/src/app/settings/components/cluster-details/cluster-details.tsx index b5c779aa9e..ba4da37fc5 100644 --- a/ui/src/app/settings/components/cluster-details/cluster-details.tsx +++ b/ui/src/app/settings/components/cluster-details/cluster-details.tsx @@ -24,7 +24,7 @@ export const ClusterDetails = (props: RouteComponentProps<{server: string}>) => const loaderRef = React.useRef(); const [updating, setUpdating] = React.useState(false); return ( - Observable.interval(1000).flatMap(() => Observable.fromPromise(services.clusters.get(url)))}> + Observable.interval(1000).flatMap(() => Observable.fromPromise(services.clusters.get(url, '')))}> {(cluster: Cluster) => ( ) => { - const item = await services.clusters.get(updated.server); + const item = await services.clusters.get(updated.server, ''); item.name = updated.name; item.namespaces = updated.namespaces; loaderRef.current.setData(await services.clusters.update(item)); diff --git a/ui/src/app/shared/components/cluster.tsx b/ui/src/app/shared/components/cluster.tsx index 70a0e977eb..c79bfa3da3 100644 --- a/ui/src/app/shared/components/cluster.tsx +++ b/ui/src/app/shared/components/cluster.tsx @@ -21,13 +21,13 @@ const clusterHTML = (cluster: models.Cluster, showUrl: boolean) => { ); }; -async function getCluster(clusters: Promise, server: string): Promise { +async function getCluster(clusters: Promise, server: string, name: string): Promise { let cluster: models.Cluster; if (clusters) { - cluster = await clusters.then(items => items.find(item => item.server === server)); + cluster = await clusters.then(items => items.find(item => item.server === server || item.name === name)); } else { try { - cluster = await services.clusters.get(server); + cluster = await services.clusters.get(server, name); } catch { cluster = null; } @@ -43,10 +43,10 @@ async function getCluster(clusters: Promise, server: string): export const ClusterCtx = React.createContext>>(null); -export const Cluster = (props: {server: string; showUrl?: boolean}) => ( +export const Cluster = (props: {server: string; name?: string; showUrl?: boolean}) => ( {clusters => ( - {props.server}} load={server => getCluster(clusters, server)}> + {props.server}} load={input => getCluster(clusters, input.server, input.name)}> {(cluster: models.Cluster) => clusterHTML(cluster, props.showUrl)} )} diff --git a/ui/src/app/shared/models.ts b/ui/src/app/shared/models.ts index 5e5ceda182..2a39459ec7 100644 --- a/ui/src/app/shared/models.ts +++ b/ui/src/app/shared/models.ts @@ -142,6 +142,10 @@ export interface ApplicationDestination { * Namespace overrides the environment namespace value in the ksonnet app.yaml */ namespace: string; + /** + * Name of the destination cluster which can be used instead of server (url) field + */ + name: string; } export interface OrphanedResource { diff --git a/ui/src/app/shared/services/clusters-service.ts b/ui/src/app/shared/services/clusters-service.ts index 7778cf83bd..31ab94ccb7 100644 --- a/ui/src/app/shared/services/clusters-service.ts +++ b/ui/src/app/shared/services/clusters-service.ts @@ -9,8 +9,14 @@ export class ClustersService { .then(list => list.items || []); } - public get(url: string): Promise { - return requests.get(`/clusters/${encodeURIComponent(url)}`).then(res => res.body as models.Cluster); + public get(url: string, name: string): Promise { + let queryName = ''; + if (url === undefined) { + url = ''; + queryName = `?name=${name}`; + } + const requestUrl = `/clusters/${encodeURIComponent(url)}` + queryName; + return requests.get(requestUrl).then(res => res.body as models.Cluster); } public update(cluster: models.Cluster): Promise { diff --git a/util/db/cluster.go b/util/db/cluster.go index 2c7a6dea51..200673e10e 100644 --- a/util/db/cluster.go +++ b/util/db/cluster.go @@ -29,6 +29,7 @@ import ( var ( localCluster = appv1.Cluster{ + Name: "in-cluster", Server: common.KubernetesInternalAPIServerAddr, ConnectionState: appv1.ConnectionState{Status: appv1.ConnectionStatusSuccessful}, } diff --git a/util/db/cluster_test.go b/util/db/cluster_test.go index ff28da2c85..bafb43ca9d 100644 --- a/util/db/cluster_test.go +++ b/util/db/cluster_test.go @@ -112,7 +112,7 @@ func TestWatchClusters_LocalClusterModifications(t *testing.T) { }, func(old *v1alpha1.Cluster, new *v1alpha1.Cluster) { assert.Equal(t, new.Server, common.KubernetesInternalAPIServerAddr) - assert.Equal(t, new.Name, "") + assert.Equal(t, new.Name, "in-cluster") }, }) }