feat: add access/volume mode support and improvements for VM migration (#1074) (#1081)

* fix: VM migration tab not appear when first login



* feat: add access/ volume mode model



* feat: add selected all | clear all actions for selected VM



* fix: bugs in VM selection table



* refactor: copilot review



---------


(cherry picked from commit afe632b723)

Signed-off-by: Andy Lee <andy.lee@suse.com>
Co-authored-by: Andy Lee <andy.lee@suse.com>
This commit is contained in:
mergify[bot]
2026-08-03 13:33:26 +08:00
committed by GitHub
co-authored by Andy Lee
parent 080f9cdb29
commit d4562a91d1
8 changed files with 506 additions and 48 deletions
+21 -11
View File
@@ -24,13 +24,14 @@ export function registerAddonSideNav(store, productName, {
const kickSideNav = () => {
const TRIGGER = 'ui.refresh.trigger';
store.dispatch('type-map/addFavorite', TRIGGER);
// SideNav component seem to ignore rapid state changes.
// Wait 600ms to ensure the toggle event triggers a re-render.
setTimeout(() => {
store.dispatch('type-map/removeFavorite', TRIGGER);
}, 600);
// Toggle the trigger a few times so an early kick (fired before the SideNav
// has mounted on first login) is retried once the component is listening.
[0, 600, 1500].forEach((delay) => {
setTimeout(() => {
store.dispatch('type-map/addFavorite', TRIGGER);
setTimeout(() => store.dispatch('type-map/removeFavorite', TRIGGER), 300);
}, delay);
});
};
const hasAccessibleSchema = (t) => {
@@ -92,16 +93,25 @@ export function registerAddonSideNav(store, productName, {
// Store is ready. Stop polling.
clearInterval(waitForStore);
// Watch the specific addon resource for changes to its enabled status.
// Watch the addon's enabled status together with the schema availability
// of the gated types. Schemas (e.g. forklift CRDs) can load after the
// addon is already enabled, so the watcher must also re-run when they
// become accessible; otherwise the menu never updates until a refresh.
store.watch(
(state, getters) => {
const addons = getters[`${ productName }/all`](resourceType);
const addon = addons.find((a) => a.metadata.name === addonName);
const isEnabled = addon?.spec?.enabled === true;
return addon?.spec?.enabled === true;
const schemaReady = requireSchema ? types.every(hasAccessibleSchema) : true;
return `${ isEnabled }:${ schemaReady }`;
},
(isEnabled) => {
setMenuVisibility(isEnabled);
() => {
const addons = store.getters[`${ productName }/all`](resourceType);
const addon = addons.find((a) => a.metadata.name === addonName);
setMenuVisibility(addon?.spec?.enabled === true);
},
{ immediate: true, deep: true }
);
+17 -4
View File
@@ -73,8 +73,21 @@ export function buildNetworkMapEntries(entries = [], defaultNamespace) {
export function buildStorageMapEntries(entries = []) {
return entries
.filter((entry) => !!entry.target)
.map((entry) => ({
source: { name: entry.name, id: entry.id },
destination: { storageClass: entry.target },
}));
.map((entry) => {
const destination = { storageClass: entry.target };
if (entry.volumeMode) {
destination.volumeMode = entry.volumeMode;
}
// Forklift StorageMap destination expects a single `accessMode` value.
if (Array.isArray(entry.accessModes) && entry.accessModes.length) {
destination.accessMode = entry.accessModes[0];
}
return {
source: { name: entry.name, id: entry.id },
destination,
};
});
}