Best practices with Navigation Menu and permissions

  1. My goal: Add a module that contains a single navigation menu to apps to create the illusion of a single "Portal", which would navigate from app to app. The critical feature that I want is the ability to hide/show menu items based on your user's groups, which would mirror the apps that user has access. The point being that I do not want to show a menu item for an app you do not have access to.

  2. Issue: This proved to much more complex than I planned and I went through many iterations until I settled on a working but heavy solution.

a) The users object has access to the groups, but there is no way to get to the underlying apps. This can be done through the Retool API I think, but we do not have Enterprise, so that is not an option. For this reason, I ultimately settled on basically recreating the group/applications list in a Retool database table that has GROUP and APP as it's two fields. For new apps you now have to set the permission in Retool itself and add the necessary records to this table.

b) The navigation menu is not as robust as I needed. What I wanted to do is have a JS resource run on page load and query the DB and run through the navigation menu updating the hidden attribute of each menu item. However, you cannot programmatically change either the hidden or 'disabled` attributes. There are no .setHidden() or .setDisabled() methods exposed and the attribute itself is read-only. So I went with a function (meaning {{ }}) on each hidden attribute on each menu item (there are currently 47 menu items).

c) Menu Items on the Navigation Menu are not directly accessible, so you cannot reference the menu item you are on in the hidden attribute of the menu item. self references the Navigation Menu, not the menu item. And there is no index to the specific menu item. So I could not write a "copy and paste" function. Instead I had to write a function with hard-coded values for each menu item. The process is 'copy and paste' and then edit the hard-coded values. The function looks like this:
{{ !current_user.groups.map(group => group.name).some(g => fetchPermissionMap.data.find(p => p.app === "Driver Support Hub")?.roles.includes(g)) }}
which is pretty ugly but all you have to change is the name like 'Driver Support Hub'.

So, what should have been a small JS resource that made 1 call to the user's group's application list and a loop though that list that sets the Navigation Menu's item's hidden attribute turned into a huge effort that took a day to write, multiple dead-end development ideas, and a much more convoluted solution.

I am hoping I missed something and there is a better solution to this and I am looking for some best practices and other ideas.

A multi-page app doesn't solve my problem as I still need the DB to correlate the permissions and I would have the same access issues to the Navigation Menu. However, until very recently with multi-player, the biggest reason not to move to a multi-page app was the limitation that only one person could modify the app at a time safely and this app would be way to big for that.

  1. Additional info: (Cloud or Self-hosted, Screenshots) Self-hosted, Business Plan

Thanks,
Steve

Hey,

sounds like you've got a good idea of how you want to structure the app navigation and you've put that structure into your Retool DB already. That's more than half the battle, I think, and getting that data into your nav bar should be possible too.

At a high level view, what I'd expect your nav module to do is to run a select query from your DB and get all the apps that the currentUser has access to and return that to your nav module.
The navigation component would then be able to display only the apps that your user has been granted access too.
Now, while this is built-in to the higher Retool plans you need to construct that permissions logic yourself.

(I'm not sure which plan you have, but on Business or above you can set permission groups and have a resource query which returns you all the apps and folders the current user can access)

Can I ask how you've structured the user/group/app/permissions data at the moment?
I'm thinking that retrieving every possible item and then filtering them out in the UI isn't very fun or maintainable and should be driven by the data wherever possible.

Thanks for the feedback and especially on the User Actions resource. I did not know about that and it removed about 90% of the code and greatly simplified my life!

1 Like