mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-08-16 12:49:14 +00:00
* fix: hide Virtul machine migration tabs if forklift addon is not enabled * fix: rename advanced to configurations * fix: fixed column width * refactor: review comment * revert: power on background color --------- (cherry picked from commit 41cf44d23131ce30762fd29fe38d833d22238398) Signed-off-by: Andy Lee <andy.lee@suse.com> Co-authored-by: Andy Lee <andy.lee@suse.com>
122 lines
4.3 KiB
JavaScript
122 lines
4.3 KiB
JavaScript
/**
|
|
* Dynamically toggles SideNav entries based on the enabled status of a specific Addon.
|
|
*
|
|
* @param {Object} store - The Vuex store instance.
|
|
* @param {String} productName - The product name (e.g. 'harvester').
|
|
* @param {Object} config - Configuration object.
|
|
* @param {String} config.addonName - The name of the addon to watch.
|
|
* @param {String} config.resourceType - The schema ID for addons.
|
|
* @param {String} config.navGroup - The group name in the side nav.
|
|
* @param {Array<String>} config.types - Array of Resource IDs to show/hide.
|
|
* @param {Boolean} [config.requireSchema=true] - When true, only types with an
|
|
* accessible schema are shown. Set false for schema-less virtual types.
|
|
*/
|
|
export function registerAddonSideNav(store, productName, {
|
|
addonName, resourceType, navGroup, types, requireSchema = true
|
|
}) {
|
|
if (typeof window === 'undefined') {
|
|
return;
|
|
}
|
|
|
|
// Forces the SideNav component to re-render by toggling a dummy user preference.
|
|
// Necessary because the menu component does not automatically detect
|
|
// changes to the allowed types list.
|
|
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);
|
|
};
|
|
|
|
const hasAccessibleSchema = (t) => {
|
|
try {
|
|
return !!store.getters[`${ productName }/schemaFor`]?.(t);
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const showTypes = (visibleTypes) => {
|
|
store.commit('type-map/basicType', {
|
|
product: productName,
|
|
group: navGroup,
|
|
types: visibleTypes
|
|
});
|
|
};
|
|
|
|
const hideTypes = () => {
|
|
const basicTypes = store.state['type-map'].basicTypes[productName];
|
|
|
|
if (basicTypes) {
|
|
types.forEach((t) => delete basicTypes[t]);
|
|
}
|
|
};
|
|
|
|
// Adds or removes the resource IDs from the product visibility whitelist.
|
|
const setMenuVisibility = (visible) => {
|
|
const accessibleTypes = visible ? (requireSchema ? types.filter(hasAccessibleSchema) : types) : [];
|
|
|
|
// Always clear first to remove any previously-registered types that are
|
|
// no longer accessible (e.g. partial permission changes like types=[A,B] where B is dropped).
|
|
hideTypes();
|
|
|
|
if (accessibleTypes.length > 0) {
|
|
showTypes(accessibleTypes);
|
|
}
|
|
|
|
kickSideNav();
|
|
};
|
|
|
|
// Start polling to check if the store is ready.
|
|
let attempts = 0;
|
|
const MAX_ATTEMPTS = 60;
|
|
|
|
const waitForStore = setInterval(() => {
|
|
attempts++;
|
|
|
|
try {
|
|
// Check if the Schema definitions are loaded.
|
|
const hasSchema = store.getters[`${ productName }/schemaFor`] &&
|
|
store.getters[`${ productName }/schemaFor`](resourceType);
|
|
|
|
// Check if the resource list data is fully loaded to prevent race conditions.
|
|
const hasData = store.getters[`${ productName }/haveAll`] &&
|
|
store.getters[`${ productName }/haveAll`](resourceType);
|
|
|
|
if (hasSchema && hasData) {
|
|
// Store is ready. Stop polling.
|
|
clearInterval(waitForStore);
|
|
|
|
// Watch the specific addon resource for changes to its enabled status.
|
|
store.watch(
|
|
(state, getters) => {
|
|
const addons = getters[`${ productName }/all`](resourceType);
|
|
const addon = addons.find((a) => a.metadata.name === addonName);
|
|
|
|
return addon?.spec?.enabled === true;
|
|
},
|
|
(isEnabled) => {
|
|
setMenuVisibility(isEnabled);
|
|
},
|
|
{ immediate: true, deep: true }
|
|
);
|
|
} else if (hasSchema && !hasData) {
|
|
// If the schema is ready but the data is missing, request the list from the API.
|
|
// Ensures the script does not wait indefinitely if the UI has not loaded the addons yet.
|
|
store.dispatch(`${ productName }/findAll`, { type: resourceType });
|
|
} else if (attempts >= MAX_ATTEMPTS) {
|
|
// Stop checking if the store does not load within the timeout limit.
|
|
clearInterval(waitForStore);
|
|
}
|
|
} catch (e) {
|
|
// Ignore errors if the store module is not yet registered and wait for the next attempt.
|
|
if (attempts >= MAX_ATTEMPTS) clearInterval(waitForStore);
|
|
}
|
|
}, 1000);
|
|
}
|