Skip to content

Commit

Permalink
Restructure longhorn UI proxy link to contain dynamic namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
jordojordo committed Jan 22, 2024
1 parent 4cca5fa commit 11affd2
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 20 deletions.
1 change: 1 addition & 0 deletions shell/assets/translations/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3060,6 +3060,7 @@ longhorn:
label: 'Longhorn'
description: 'Manage storage system via UI'
na: Resource Unavailable
uiServiceUnavailable: The Longhorn UI service is not available or you do not have permission to access it.

neuvector:
overview:
Expand Down
90 changes: 90 additions & 0 deletions shell/pages/c/_cluster/longhorn/__tests__/longhorn.index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { shallowMount } from '@vue/test-utils';

import IconMessage from '@shell/components/IconMessage';
import LonghornOverview from '@shell/pages/c/_cluster/longhorn/index.vue';

const longhornFrontend = {
id: 'default/longhorn-frontend',
type: 'service',
apiVersion: 'v1',
kind: 'Service',
metadata: {
labels: { app: 'longhorn-ui' },
name: 'longhorn-frontend',
namespace: 'default',
}
};

describe('page: LonghornOverview', () => {
const commonMocks = {
$fetchState: { pending: false },
$store: {
dispatch: () => jest.fn,
getters: {
currentProduct: () => 'cluster',
'cluster/findAll': () => jest.fn(),
'cluster/schemaFor': () => jest.fn(),
'cluster/matching': () => jest.fn(),
'i18n/t': () => jest.fn(),
},
},
};

const createWrapper = (overrides?: any) => {
return shallowMount(LonghornOverview, {
mocks: commonMocks,
...overrides,
});
};

it('initializes externalLinks as an empty array', () => {
const wrapper = createWrapper({
stubs: {
IconMessage: { template: '<span />' },
LazyImage: { template: '<span />' },
}
});

expect(wrapper.vm.externalLinks).toStrictEqual([]);
});

it('populates externalLinks proxy link correctly when uiServices contain service', async() => {
const proxyUrl = `/k8s/clusters/_/api/v1/namespaces/${ longhornFrontend.metadata.namespace }/services/http:longhorn-frontend:80/proxy/`;

interface LinkConfig {
enabled: boolean;
iconSrc: string;
label: string;
description: string;
link: string;
}

const wrapper = createWrapper({
computed: {
currentCluster: () => ({ id: '_' }),
uiServices: () => [longhornFrontend]
},
stubs: {
Banner: { template: '<span />' },
LazyImage: { template: '<span />' },
}
});

await wrapper.vm.$nextTick();

const containsProxyUrl = wrapper.vm.externalLinks.find((link: LinkConfig) => link.link);

expect(containsProxyUrl).toBeTruthy();
expect(containsProxyUrl.link).toStrictEqual(proxyUrl);
});

it('displays IconMessage when externalLinks array is empty', () => {
const wrapper = createWrapper({ stubs: { LazyImage: { template: '<span />' } } });

expect(wrapper.vm.externalLinks).toStrictEqual([]);

const iconMessage = wrapper.findComponent(IconMessage);

expect(iconMessage.exists()).toBe(true);
});
});
73 changes: 53 additions & 20 deletions shell/pages/c/_cluster/longhorn/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,59 @@ import { mapGetters } from 'vuex';
import InstallRedirect from '@shell/utils/install-redirect';
import { SERVICE } from '@shell/config/types';
import { NAME, CHART_NAME } from '@shell/config/product/longhorn';
import IconMessage from '@shell/components/IconMessage';
import LazyImage from '@shell/components/LazyImage';
import Loading from '@shell/components/Loading';
export default {
components: { LazyImage },
components: {
IconMessage, LazyImage, Loading
},
middleware: InstallRedirect(NAME, CHART_NAME),
async fetch() {
if ( this.$store.getters['cluster/schemaFor'](SERVICE) ) {
await this.$store.dispatch('cluster/findAll', { type: SERVICE });
}
},
data() {
return {
externalLinks: [],
longhornImgSrc: require('~shell/assets/images/vendor/longhorn.svg'),
};
return { longhornImgSrc: require('~shell/assets/images/vendor/longhorn.svg') };
},
computed: { ...mapGetters(['currentCluster']) },
computed: {
...mapGetters(['currentCluster']),
mounted() {
this.externalLinks = [
{
enabled: true,
iconSrc: this.longhornImgSrc,
label: 'longhorn.overview.linkedList.longhorn.label',
description: 'longhorn.overview.linkedList.longhorn.description',
link: `/k8s/clusters/${ this.currentCluster.id }/api/v1/namespaces/longhorn-system/services/http:longhorn-frontend:80/proxy/`
},
];
},
externalLinks() {
if ( this.uiServices && this.uiServices.length === 1 && this.uiServices[0].metadata?.namespace ) {
return [
{
enabled: true,
iconSrc: this.longhornImgSrc,
label: 'longhorn.overview.linkedList.longhorn.label',
description: 'longhorn.overview.linkedList.longhorn.description',
link: `/k8s/clusters/${ this.currentCluster.id }/api/v1/namespaces/${ this.uiServices[0].metadata.namespace }/services/http:longhorn-frontend:80/proxy/`
},
];
}
return [];
},
methods: {}
uiServices() {
return this.$store.getters['cluster/matching'](SERVICE, 'app=longhorn-ui');
}
}
};
</script>
<template>
<section>
<Loading v-if="$fetchState.pending" />
<section v-else>
<header class="row">
<div class="col span-12">
<h1>
Expand All @@ -52,7 +69,10 @@ export default {
</div>
</div>
</header>
<div class="links">
<div
v-if="externalLinks && externalLinks.length"
class="links"
>
<div
v-for="fel in externalLinks"
:key="fel.label"
Expand All @@ -75,5 +95,18 @@ export default {
</a>
</div>
</div>
<IconMessage
v-else
class="mt-40 mb-20"
icon="icon-longhorn"
:vertical="true"
>
<template #message>
<p>
{{ t('longhorn.overview.linkedList.longhorn.uiServiceUnavailable') }}
</p>
</template>
</IconMessage>
</section>
</template>

0 comments on commit 11affd2

Please sign in to comment.