From 77b643540e06c1ad935b0c93f991a78c67400be6 Mon Sep 17 00:00:00 2001 From: marcelofukumoto Date: Thu, 29 Oct 2026 16:00:00 +0000 Subject: [PATCH] fix: label the VPC group of subnets without a VPC as None (#1210) Kube-OVN sets a subnet's VPC (ovn-cluster when none is given), but a subnet it hasn't processed, such as one with an invalid provider, has none. The VPC page grouped those under "Virtual Private Cloud:" with an empty name, and its Create Subnet, Topology and actions buttons pointed at no VPC. Show None as the VPC name for that group and leave out its VPC buttons. Signed-off-by: Marcelo Fukumoto --- .../list/__tests__/kubeovn.io.vpc.test.js | 54 +++++++++++++++++++ pkg/harvester/list/kubeovn.io.vpc.vue | 8 ++- 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 pkg/harvester/list/__tests__/kubeovn.io.vpc.test.js diff --git a/pkg/harvester/list/__tests__/kubeovn.io.vpc.test.js b/pkg/harvester/list/__tests__/kubeovn.io.vpc.test.js new file mode 100644 index 00000000..380348c0 --- /dev/null +++ b/pkg/harvester/list/__tests__/kubeovn.io.vpc.test.js @@ -0,0 +1,54 @@ +import { mount } from '@vue/test-utils'; +import HarvesterVPC from '../kubeovn.io.vpc.vue'; + +// A table that renders the page's group header for each of the given groups +function resourceTable(groups) { + return { + data: () => ({ groups }), + template: '
', + }; +} + +function mountList(groups) { + return mount(HarvesterVPC, { + props: { schema: { id: 'kubeovn.io.vpc' } }, + data: () => ({ enabledKubeOvnAddon: true }), + global: { + stubs: { + ResourceTable: resourceTable(groups), + Masthead: true, + Loading: true, + 'router-link': { template: '' }, + }, + mocks: { + $fetchState: { pending: false }, + t: (key) => ({ 'harvester.vpc.label': 'Virtual Private Cloud', 'generic.none': 'None' }[key] || key), + $store: { + getters: { + currentProduct: { inStore: 'harvester' }, + 'harvester/all': () => [], + 'harvester/schemaFor': () => ({ collectionMethods: ['POST'] }), + }, + }, + }, + }, + }); +} + +describe('list: kubeovn.io.vpc', () => { + it('should label a group of subnets without a VPC as None and offer no VPC actions', () => { + const wrapper = mountList([{ key: '' }]); + const group = wrapper.find('.group'); + + expect(group.find('.group-tab').text()).toBe('Virtual Private Cloud: None'); + expect(group.find('.right').exists()).toBe(false); + }); + + it('should label a VPC group with its name and offer the VPC actions', () => { + const wrapper = mountList([{ key: 'ovn-cluster' }]); + const group = wrapper.find('.group'); + + expect(group.find('.group-tab').text()).toBe('Virtual Private Cloud: ovn-cluster'); + expect(group.findAll('.right a, .right button')).toHaveLength(3); + }); +}); diff --git a/pkg/harvester/list/kubeovn.io.vpc.vue b/pkg/harvester/list/kubeovn.io.vpc.vue index 254200c4..8fb94952 100644 --- a/pkg/harvester/list/kubeovn.io.vpc.vue +++ b/pkg/harvester/list/kubeovn.io.vpc.vue @@ -139,7 +139,8 @@ export default { }, methods: { groupLabel(group) { - return `${ this.t('harvester.vpc.label') }: ${ group.key }`; + // Kube-OVN sets a subnet's VPC (ovn-cluster when none is given), so an empty one is a subnet it hasn't processed + return `${ this.t('harvester.vpc.label') }: ${ group.key || this.t('generic.none') }`; }, slotName(vpc) { @@ -226,7 +227,10 @@ export default { {{ groupLabel(group) }} -
+