Refactor menu building code to support sub-menus of any depth

This commit is contained in:
Aditya Toshniwal
2024-11-14 13:36:42 +05:30
parent 64399901ad
commit 00d3aaa1fd
14 changed files with 261 additions and 237 deletions

View File

@@ -67,7 +67,7 @@ export default function AppMenuBar() {
pgAdmin.Browser.Events.on('pgadmin:enable-disable-menu-items', _.debounce(()=>{
forceUpdate();
}, 100));
pgAdmin.Browser.Events.on('pgadmin:refresh-menu-item', _.debounce(()=>{
pgAdmin.Browser.Events.on('pgadmin:refresh-app-menu', _.debounce(()=>{
forceUpdate();
}, 100));
}, []);
@@ -95,6 +95,18 @@ export default function AppMenuBar() {
const userMenuInfo = pgAdmin.Browser.utils.userMenuInfo;
const getPgMenu = (menu)=>{
return menu.getMenuItems()?.map((menuItem, i)=>{
const submenus = menuItem.getMenuItems();
if(submenus) {
return <PgSubMenu key={menuItem.label} label={menuItem.label}>
{getPgMenu(menuItem)}
</PgSubMenu>;
}
return getPgMenuItem(menuItem, i);
});
};
return (
<StyledBox data-test="app-menu-bar">
<div className='AppMenuBar-logo' />
@@ -106,17 +118,7 @@ export default function AppMenuBar() {
label={menu.label}
key={menu.name}
>
{menu.getMenuItems().map((menuItem, i)=>{
const submenus = menuItem.getMenuItems();
if(submenus) {
return <PgSubMenu key={menuItem.label} label={menuItem.label}>
{submenus.map((submenuItem, si)=>{
return getPgMenuItem(submenuItem, si);
})}
</PgSubMenu>;
}
return getPgMenuItem(menuItem, i);
})}
{getPgMenu(menu)}
</PgMenu>
);
})}

View File

@@ -10,17 +10,18 @@ import _ from 'lodash';
import gettext from 'sources/gettext';
export default class Menu {
constructor(name, label, id, index, addSepratior) {
constructor(name, label, id, index, addSeprator, hasDynamicMenuItems) {
this.label = label;
this.name = name;
this.id = id;
this.index = index || 1;
this.menuItems = [];
this.addSepratior = addSepratior || false;
this.addSeprator = addSeprator || false;
this.hasDynamicMenuItems = hasDynamicMenuItems;
}
static create(name, label, id, index, addSepratior) {
let menuObj = new Menu(name, label, id, index, addSepratior);
static create(name, label, id, index, addSeprator, hasDynamicMenuItems) {
let menuObj = new Menu(name, label, id, index, addSeprator, hasDynamicMenuItems);
return menuObj;
}
@@ -30,7 +31,7 @@ export default class Menu {
label: this.label,
name: this.name,
index: this.index,
addSepratior: this.addSepratior,
addSeprator: this.addSeprator,
};
}
@@ -41,13 +42,10 @@ export default class Menu {
this.menuItems.splice(index, 0, menuItem);
} else {
this.menuItems.push(menuItem);
Menu.sortMenus(this.menuItems);
}
} else {
throw new Error(gettext('Invalid MenuItem instance'));
}
}
addMenuItems(menuItems) {
@@ -59,7 +57,6 @@ export default class Menu {
item.menu_items.forEach((i)=> {
i.parentMenu = item;
});
Menu.sortMenus(item.menu_items);
}
} else {
let subItems = Object.values(item);
@@ -88,16 +85,16 @@ export default class Menu {
setMenuItems(menuItems) {
this.menuItems = menuItems;
Menu.sortMenus(this.menuItems);
}
this.menuItems.forEach((item)=> {
if(item?.menu_items?.length > 0) {
Menu.sortMenus(item.menu_items);
}
});
clearMenuItems() {
this.menuItems = [];
}
static sortMenus(menuItems) {
if(!menuItems || menuItems.length <=0) {
return;
}
// Sort by alphanumeric ordered first
menuItems.sort(function (a, b) {
return a.label.localeCompare(b.label);
@@ -107,6 +104,10 @@ export default class Menu {
menuItems.sort(function (a, b) {
return a.priority - b.priority;
});
menuItems.forEach((mi)=>{
Menu.sortMenus(mi.getMenuItems());
});
}
getMenuItems() {
@@ -117,9 +118,9 @@ export default class Menu {
export class MenuItem {
constructor(options, onDisableChange) {
let menu_opts = [
let allowedOptions = [
'name', 'label', 'priority', 'module', 'callback', 'data', 'enable',
'category', 'target', 'url', 'node',
'category', 'target', 'url', 'node', 'single',
'checked', 'below', 'menu_items', 'is_checkbox', 'action', 'applies', 'is_native_only', 'type',
];
let defaults = {
@@ -127,7 +128,7 @@ export class MenuItem {
target: '_self',
enable: true,
};
_.extend(this, defaults, _.pick(options, menu_opts));
_.extend(this, defaults, _.pick(options, allowedOptions));
if (!this.callback) {
this.callback = (item) => {
if (item.url != '#') {
@@ -159,6 +160,11 @@ export class MenuItem {
this.checked = isChecked;
}
addMenuItems(items) {
this.menu_items = this.menu_items ?? [];
this.menu_items = this.menu_items.concat(items);
}
getMenuItems() {
return this.menu_items;
}