Improved version management banner for local and imported clusters (#14328)

This commit is contained in:
Evgeniya Vashkevich 2025-05-22 13:02:47 -07:00 committed by GitHub
parent 4289fe1ca8
commit f5305ed0d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 332 additions and 23 deletions

View File

@ -19,6 +19,10 @@ export default class CreateEditViewPo extends ComponentPo {
return new AsyncButtonPo(this.self().find('.cru-resource-footer .role-primary')).click();
}
cancel() {
return new AsyncButtonPo(this.self().find('.cru-resource-footer .role-secondary')).click();
}
saveAndWait() {
return new AsyncButtonPo(this.self().find('.cru-resource-footer .role-primary')).action('Save', 'Saved');
}

View File

@ -4,21 +4,22 @@ import ResourceDetailPo from '@/cypress/e2e/po/edit/resource-detail.po';
import NameNsDescription from '@/cypress/e2e/po/components/name-ns-description.po';
import LabeledInputPo from '@/cypress/e2e/po/components/labeled-input.po';
import CheckboxInputPo from '@/cypress/e2e/po/components/checkbox-input.po';
import RadioGroupInputPo from '@/cypress/e2e/po/components/radio-group-input.po';
/**
* Edit page for imported cluster
*/
export default class ClusterManagerEditImportedPagePo extends PagePo {
private static createPath(clusterId: string, clusterName: string) {
return `/c/${ clusterId }/manager/provisioning.cattle.io.cluster/fleet-default/${ clusterName }`;
private static createPath(clusterId: string, ns: string, clusterName: string) {
return `/c/${ clusterId }/manager/provisioning.cattle.io.cluster/${ ns }/${ clusterName }`;
}
static goTo(clusterId: string, clusterName: string ): Cypress.Chainable<Cypress.AUTWindow> {
return super.goTo(ClusterManagerEditImportedPagePo.createPath(clusterId, clusterName));
static goTo(clusterId: string, ns: string, clusterName: string ): Cypress.Chainable<Cypress.AUTWindow> {
return super.goTo(ClusterManagerEditImportedPagePo.createPath(clusterId, ns, clusterName));
}
constructor(clusterId = '_', clusterName: string) {
super(ClusterManagerEditImportedPagePo.createPath(clusterId, clusterName));
constructor(clusterId = '_', ns = 'fleet-default', clusterName: string) {
super(ClusterManagerEditImportedPagePo.createPath(clusterId, ns, clusterName));
}
nameNsDescription() {
@ -37,6 +38,26 @@ export default class ClusterManagerEditImportedPagePo extends PagePo {
return this.accordion(index, label).click();
}
versionManagementBanner() {
return this.self().find('[data-testid="version-management-banner"]');
}
versionManagementRadioButton(): RadioGroupInputPo {
return new RadioGroupInputPo('[data-testid="imported-version-management-radio"]');
}
enableVersionManagement() {
return this.versionManagementRadioButton().set(1);
}
disableVersionManagement() {
return this.versionManagementRadioButton().set(2);
}
defaultVersionManagement() {
return this.versionManagementRadioButton().set(0);
}
privateRegistryCheckbox() {
return new CheckboxInputPo('[data-testid="private-registry-enable-checkbox"]');
}
@ -56,4 +77,8 @@ export default class ClusterManagerEditImportedPagePo extends PagePo {
save() {
return this.resourceDetail().createEditView().save();
}
cancel() {
return this.resourceDetail().createEditView().cancel();
}
}

View File

@ -11,4 +11,8 @@ export default class ClusterManagerImportGenericPagePo extends ClusterManagerImp
networkingAccordion() {
return this.self().find('[data-testid="networking-accordion"]');
}
versionManagementBanner() {
return this.self().find('[data-testid="version-management-banner"]');
}
}

View File

@ -620,6 +620,9 @@ describe('Cluster Manager', { testIsolation: 'off', tags: ['@manager', '@adminUs
importClusterPage.nameNsDescription().name().checkVisible();
importClusterPage.nameNsDescription().name().set(importGenericName);
// Issue #13614: Imported Cluster Version Mgmt: Conditionally show warning message
importClusterPage.versionManagementBanner().should('exist').and('be.visible');
importClusterPage.create();
cy.wait('@importRequest').then((intercept) => {
@ -664,7 +667,7 @@ describe('Cluster Manager', { testIsolation: 'off', tags: ['@manager', '@adminUs
});
it('can edit imported cluster and see changes afterwards', () => {
const editImportedClusterPage = new ClusterManagerEditImportedPagePo(undefined, importedClusterName);
const editImportedClusterPage = new ClusterManagerEditImportedPagePo(undefined, 'fleet-default', importedClusterName);
cy.intercept('GET', '/v1-rke2-release/releases').as('getRke2Releases');
clusterList.goTo();
@ -684,6 +687,13 @@ describe('Cluster Manager', { testIsolation: 'off', tags: ['@manager', '@adminUs
// Issue #10432: Edit Cluster screen falsely gives impression imported cluster's name and description can be edited
editImportedClusterPage.nameNsDescription().name().expectToBeDisabled();
// Issue #13614: Imported Cluster Version Mgmt: Conditionally show warning message
editImportedClusterPage.versionManagementBanner().should('not.exist');
editImportedClusterPage.enableVersionManagement();
editImportedClusterPage.versionManagementBanner().should('exist').and('be.visible');
editImportedClusterPage.defaultVersionManagement();
editImportedClusterPage.toggleAccordion(5, 'Networking');
editImportedClusterPage.ace().enable();
editImportedClusterPage.ace().enterFdqn(fqdn);
@ -799,14 +809,48 @@ describe('Cluster Manager', { testIsolation: 'off', tags: ['@manager', '@adminUs
});
});
it(`can navigate to local cluster's explore product`, () => {
const clusterName = 'local';
const clusterDashboard = new ClusterDashboardPagePo(clusterName);
describe('Local', { tags: ['@jenkins', '@localCluster'] }, () => {
it(`can open edit for local cluster`, () => {
const editLocalClusterPage = new ClusterManagerEditImportedPagePo(undefined, 'fleet-local', 'local');
clusterList.goTo();
clusterList.list().explore(clusterName).click();
cy.intercept('GET', '/v1-rke2-release/releases').as('getRke2Releases');
clusterList.goTo();
clusterList.list().actionMenu('local').getMenuItem('Edit Config').click();
editLocalClusterPage.waitForPage('mode=edit');
clusterDashboard.waitForPage(undefined, 'cluster-events');
editLocalClusterPage.nameNsDescription().name().value().should('eq', 'local' );
// check accordions are properly displayed
editLocalClusterPage.accordion(2, 'Basics').should('be.visible');
editLocalClusterPage.accordion(3, 'Member Roles').scrollIntoView().should('be.visible');
editLocalClusterPage.accordion(4, 'Labels and Annotations').scrollIntoView().should('be.visible');
editLocalClusterPage.accordion(5, 'Networking').scrollIntoView().should('be.visible');
editLocalClusterPage.accordion(6, 'Registries').scrollIntoView().should('be.visible');
editLocalClusterPage.accordion(7, 'Advanced').scrollIntoView().should('be.visible');
// Issue #13614: Imported Cluster Version Mgmt: Conditionally show warning message
editLocalClusterPage.versionManagementBanner().should('not.exist');
editLocalClusterPage.enableVersionManagement();
editLocalClusterPage.versionManagementBanner().should('exist').and('be.visible');
editLocalClusterPage.versionManagementBanner().should('not.contain.text', 'This change will trigger cluster agent redeployment.');
editLocalClusterPage.disableVersionManagement();
editLocalClusterPage.versionManagementBanner().should('exist').and('be.visible');
editLocalClusterPage.versionManagementBanner().should('not.contain.text', 'This change will trigger cluster agent redeployment.');
editLocalClusterPage.cancel();
// We should be taken back to the list page if the save was successful
clusterList.waitForPage();
});
it(`can navigate to local cluster's explore product`, () => {
const clusterName = 'local';
const clusterDashboard = new ClusterDashboardPagePo(clusterName);
clusterList.goTo();
clusterList.list().explore(clusterName).click();
clusterDashboard.waitForPage(undefined, 'cluster-events');
});
});
it('can download YAML via bulk actions', () => {

View File

@ -78,6 +78,10 @@ export default defineComponent({
type: String,
required: true
},
isLocal: {
type: Boolean,
default: false
},
rules: {
default: () => ({
workerConcurrency: [],
@ -172,6 +176,7 @@ export default defineComponent({
:global-setting="versionManagementGlobalSetting"
:mode="mode"
:old-value="versionManagementOld"
:is-local="isLocal"
@version-management-changed="$emit('version-management-changed', $event)"
/>
<div

View File

@ -454,6 +454,7 @@ export default defineComponent({
:default-version="defaultVersion"
:loading-versions="loadingVersions"
:show-version-management="!isRKE1"
:is-local="isLocal"
:version-management-global-setting="versionManagementGlobalSetting"
:version-management="versionManagement"
:version-management-old="versionManagementOld"

View File

@ -28,11 +28,14 @@ export default defineComponent({
type: String,
required: true
},
isLocal: {
type: Boolean,
default: false
}
},
computed: {
...mapGetters({ t: 'i18n/t', features: 'features/get' }),
...mapGetters({ t: 'i18n/t' }),
isEdit() {
return this.mode === _EDIT;
},
@ -56,13 +59,26 @@ export default defineComponent({
return this.t('imported.basics.versionManagement.banner.create.nonDefault');
}
} else {
if (this.oldValue === VERSION_MANAGEMENT_DEFAULT) {
return this.value === this.globalSetting ? this.t('imported.basics.versionManagement.banner.edit.defaultToNonDefault', {}, true) : `${ this.t('imported.basics.versionManagement.banner.edit.different') } ${ this.t('imported.basics.versionManagement.banner.edit.defaultToNonDefault', {}, true ) }`;
if (this.value === this.oldValue) {
return '';
}
if ( this.isLocal) {
if ( this.oldValue === VERSION_MANAGEMENT_DEFAULT) {
return this.t('imported.basics.versionManagement.banner.edit.defaultToNonDefault', {}, true);
} else if (this.value === VERSION_MANAGEMENT_DEFAULT) {
return this.t('imported.basics.versionManagement.banner.edit.nonDefaultToDefault', {}, true);
}
return '';
} else {
if (this.value === VERSION_MANAGEMENT_DEFAULT) {
return this.oldValue === this.globalSetting ? this.t('imported.basics.versionManagement.banner.edit.nonDefaultToDefault', {}, true) : `${ this.t('imported.basics.versionManagement.banner.edit.different') } ${ this.t('imported.basics.versionManagement.banner.edit.nonDefaultToDefault', {}, true ) }`;
if (this.oldValue === VERSION_MANAGEMENT_DEFAULT) {
return this.value === `${ this.globalSetting }` ? this.t('imported.basics.versionManagement.banner.edit.defaultToNonDefault', {}, true) : `${ this.t('imported.basics.versionManagement.banner.edit.different') } ${ this.t('imported.basics.versionManagement.banner.edit.defaultToNonDefault', {}, true ) }`;
} else {
return this.t('imported.basics.versionManagement.banner.edit.different');
if (this.value === VERSION_MANAGEMENT_DEFAULT) {
return this.oldValue === `${ this.globalSetting }` ? this.t('imported.basics.versionManagement.banner.edit.nonDefaultToDefault', {}, true) : `${ this.t('imported.basics.versionManagement.banner.edit.different') } ${ this.t('imported.basics.versionManagement.banner.edit.nonDefaultToDefault', {}, true ) }`;
} else {
return this.t('imported.basics.versionManagement.banner.edit.different');
}
}
}
}
@ -80,6 +96,12 @@ export default defineComponent({
}
return !this.globalSetting ? this.t('imported.basics.versionManagement.summary.canEnable', {}, true) : '';
},
showVersionManagementBanner() {
const valueChanged = this.isEdit && this.value !== this.oldValue;
const localChangedInvolvingDefault = valueChanged && this.isLocal && (this.oldValue === VERSION_MANAGEMENT_DEFAULT || this.value === VERSION_MANAGEMENT_DEFAULT);
return this.isCreate || localChangedInvolvingDefault || (!this.isLocal && valueChanged);
}
}
});
@ -89,8 +111,9 @@ export default defineComponent({
<t k="imported.basics.versionManagement.title" />
</h3>
<Banner
v-if="!(isEdit && value === oldValue)"
v-if="showVersionManagementBanner"
color="info"
data-testid="version-management-banner"
>
{{ versionManagementInfo }}
</Banner>

View File

@ -0,0 +1,203 @@
import { shallowMount } from '@vue/test-utils';
import VersionManagement from '@pkg/imported/components/VersionManagement.vue';
import { _EDIT, _CREATE } from '@shell/config/query-params';
const mockedStore = () => {
return {
getters: {
'i18n/t': (text: string) => {
return `${ text }`;
},
},
};
};
const mockedRoute = { query: {} };
const requiredSetup = () => {
return {
global: {
mocks: {
$store: mockedStore(),
$route: mockedRoute,
$fetchState: {},
}
}
};
};
describe('version management component', () => {
it.each([
[{
oldValue: 'system-default', globalSetting: true, value: 'system-default'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.create.default' }],
[{
oldValue: 'system-default', globalSetting: true, value: 'true'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.create.nonDefault' }],
[{
oldValue: 'system-default', globalSetting: true, value: 'false'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.create.nonDefault' }],
[{
oldValue: 'system-default', globalSetting: false, value: 'system-default'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.create.default' }],
[{
oldValue: 'system-default', globalSetting: false, value: 'true'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.create.nonDefault' }],
[{
oldValue: 'system-default', globalSetting: false, value: 'false'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.create.nonDefault' }]
])('on import of a new cluster, should display correct warning depending on the selection', (config, expected) => {
const wrapper = shallowMount(VersionManagement, {
...requiredSetup(),
propsData: {
...config, isLocal: true, mode: _CREATE
}
});
const banner = wrapper.find('[data-testid="version-management-banner"]');
expect(banner.exists()).toBe(expected.shouldExist);
expect(wrapper.vm.versionManagementInfo).toBe(expected.value);
});
it.each([
[{
oldValue: 'system-default', globalSetting: true, value: 'system-default'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'system-default', globalSetting: true, value: 'true'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.defaultToNonDefault' }],
[{
oldValue: 'system-default', globalSetting: true, value: 'false'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.different imported.basics.versionManagement.banner.edit.defaultToNonDefault' }],
[{
oldValue: 'system-default', globalSetting: false, value: 'system-default'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'system-default', globalSetting: false, value: 'true'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.different imported.basics.versionManagement.banner.edit.defaultToNonDefault' }],
[{
oldValue: 'system-default', globalSetting: false, value: 'false'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.defaultToNonDefault' }],
[{
oldValue: 'true', globalSetting: true, value: 'system-default'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.nonDefaultToDefault' }],
[{
oldValue: 'true', globalSetting: true, value: 'true'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'true', globalSetting: true, value: 'false'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.different' }],
[{
oldValue: 'true', globalSetting: false, value: 'system-default'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.different imported.basics.versionManagement.banner.edit.nonDefaultToDefault' }],
[{
oldValue: 'true', globalSetting: false, value: 'true'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'true', globalSetting: false, value: 'false'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.different' }],
[{
oldValue: 'false', globalSetting: true, value: 'system-default'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.different imported.basics.versionManagement.banner.edit.nonDefaultToDefault' }],
[{
oldValue: 'false', globalSetting: true, value: 'true'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.different' }],
[{
oldValue: 'false', globalSetting: true, value: 'false'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'false', globalSetting: false, value: 'system-default'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.nonDefaultToDefault' }],
[{
oldValue: 'false', globalSetting: false, value: 'true'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.different' }],
[{
oldValue: 'false', globalSetting: false, value: 'false'
}, { shouldExist: false, value: '' }],
])('on edit of imported, should display correct warning depending on the selection', (config, expected) => {
const wrapper = shallowMount(VersionManagement, {
...requiredSetup(),
propsData: {
...config, isLocal: false, mode: _EDIT
}
});
const banner = wrapper.find('[data-testid="version-management-banner"]');
expect(banner.exists()).toBe(expected.shouldExist);
expect(wrapper.vm.versionManagementInfo).toBe(expected.value);
});
it.each([
[{
oldValue: 'system-default', globalSetting: true, value: 'system-default'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'system-default', globalSetting: true, value: 'true'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.defaultToNonDefault' }],
[{
oldValue: 'system-default', globalSetting: true, value: 'false'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.defaultToNonDefault' }],
[{
oldValue: 'system-default', globalSetting: false, value: 'system-default'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'system-default', globalSetting: false, value: 'true'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.defaultToNonDefault' }],
[{
oldValue: 'system-default', globalSetting: false, value: 'false'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.defaultToNonDefault' }],
[{
oldValue: 'true', globalSetting: true, value: 'system-default'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.nonDefaultToDefault' }],
[{
oldValue: 'true', globalSetting: true, value: 'true'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'true', globalSetting: true, value: 'false'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'true', globalSetting: false, value: 'system-default'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.nonDefaultToDefault' }],
[{
oldValue: 'true', globalSetting: false, value: 'true'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'true', globalSetting: false, value: 'false'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'false', globalSetting: true, value: 'system-default'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.nonDefaultToDefault' }],
[{
oldValue: 'false', globalSetting: true, value: 'true'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'false', globalSetting: true, value: 'false'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'false', globalSetting: false, value: 'system-default'
}, { shouldExist: true, value: 'imported.basics.versionManagement.banner.edit.nonDefaultToDefault' }],
[{
oldValue: 'false', globalSetting: false, value: 'true'
}, { shouldExist: false, value: '' }],
[{
oldValue: 'false', globalSetting: false, value: 'false'
}, { shouldExist: false, value: '' }],
])('on edit of local, should display correct warning depending on the selection', (config, expected) => {
const wrapper = shallowMount(VersionManagement, {
...requiredSetup(),
propsData: {
...config, isLocal: true, mode: _EDIT
}
});
const banner = wrapper.find('[data-testid="version-management-banner"]');
expect(banner.exists()).toBe(expected.shouldExist);
expect(wrapper.vm.versionManagementInfo).toBe(expected.value);
});
});

View File

@ -689,7 +689,7 @@ export default {
<template v-if="subType">
<!-- allow extensions to provide their own cluster provisioning form -->
<component
:is="selectedSubType.component"
:is="selectedSubType?.component"
v-if="selectedSubType && selectedSubType.component"
v-model:value="localValue"
:initial-value="initialValue"
@ -706,7 +706,7 @@ export default {
:live-value="liveValue"
:mode="mode"
:provider="subType"
:provider-config="selectedSubType.providerConfig"
:provider-config="selectedSubType?.providerConfig"
@update:value="$emit('input', $event)"
/>
</template>