Role Based Menu Navigation - Bug

Hello everybody,
I'm using this resource: Role Based Menu Navigation

I found a bug in the resource and I don't know how to fix it, so I hope you can help me.

When you add a view you can set the "Required Roles" property.

So now this is the procedure to make the bug happens:

  1. Add roles to the view
  2. Submit
  3. Remove all the roles to the view
  4. Submit
  5. At this moment the page return this error:
Traceback (most recent call last): File "<transform>", line 53, in transform File "<transform>", line 34, in buildInstance File "<transform>", line 34, in buildInstance File "<transform>", line 7, in buildInstance TypeError: object of type 'bool' has no len()

And the only way to fix this error is to find in the "menu tree" that specific page where the requiredRoles has become a bool and convert to an array

Thank you for the help

2 Likes

You should report this to resource's author.

The resource is quite old, i doubt it's gonna get updated.
But still worth a try,
Could also show us the code that addes the role, maybe its an easy fix

I've already tried to concact the author for another question but without any answer.

Yes, that was my idea, maybe someone can fix it. I will try to understand the code and I will post it.

Thank you all for the help.

With more things going to text on 8.3, maybe it would be time to consider some sort of source control functionality for the Ignition Exchange. Then others can submit pull requests to fix bugs or add features to existing Exchange resources.

1 Like

The author of this ressource doesn't work anymore at IA so i don't know if she keep it updated. I use that ressource in our standard project. I will check if we made any update to it but will not be before this weekend.

Don't worry, in fact, thank you for your availability. I find this resource very useful, although I would like to be able to make a few more modifications, such as being able to choose from different icons (currently, it seems there are only the default ones). I would have also added the icons from Bootstrap as I already have in the designer, but I'm not sure how to add them in the resource. Another idea that comes to mind could be to make it possible to grant access (and visibility) only to specific users rather than by role.

This resource is so useful that it would be a shame not to continue with the updates.

Thanks again

(post deleted by author)

I tested the issue with the help of GPT, and here’s what I found:

The error appears in this part of the original code:

The code where the error appears is this:


	def buildInstance(item, options, instances, depth, length, index):
		isChild = True
		selectedValues = []
		subInstances = []
		for roles in range(len(item['requiredRoles'])):
			for opt in range(len(options)):
				if item['requiredRoles'][roles] == options[opt]['label']:
					selectedValues.append(options[opt]['value'])
		if len(item['items']) > 0:
			isChild = False	
			
		#dict matches the view params of Menu Items	
		dict =	{
					"viewName": item['label']['text'], 
					"target": item['target'],
					"dropdownItems": options, 
					"selectedValues": selectedValues,
					"isChild": isChild, 
					"length":length,
					"index":index,
					"depth": depth,
					"tagPath":item['path'],
					"iconPath":item['label']['icon']['path'],
					"requiredRoles": item['requiredRoles']
				}
		instances.append(dict)
					
		if len(item['items']) > 0:
			length = len(item['items'])	
			for j in range(len(item['items'])):
				index = j
				buildInstance(item['items'][j], options, instances, depth+1, length, index)
				

		
	instances = [] 
	items = value
	rolesDict = {}
	roles = system.user.getRoles("default") #get all possible roles from user source
	options= [] #rolesDict will be appended to this to fill in the dropdown options
	depth = 0 
	
	#create dropdown items object
	for r in range(len(roles)):
		rolesDict = {"value":r, "label":roles[r]}
		options.append(rolesDict.copy())
		
	length = len(items)
	for i in range(len(items)):
		index = i
		buildInstance(items[i], options, instances, depth, length, index)
	return instances

The error appears in this part of the original code:

for roles in range(len(item['requiredRoles'])):

The issue is that when you delete all the rolesitem['requiredRoles'] is not an array but a boolean (False ). To handle this, I updated the code as follows:

requiredRoles = item.get('requiredRoles', [])
if isinstance(requiredRoles, bool):
    requiredRoles = []  

Here’s the final code I tried, and it seems to work:

		
	def buildInstance(item, options, instances, depth, length, index):
	    isChild = True
	    selectedValues = []
	    subInstances = []
	    
	    requiredRoles = item.get('requiredRoles', [])
	    if isinstance(requiredRoles, bool):
	        requiredRoles = []  
	
	    for roles in range(len(requiredRoles)):
	        for opt in range(len(options)):
	            if requiredRoles[roles] == options[opt]['label']:
	                selectedValues.append(options[opt]['value'])
	    if len(item['items']) > 0:
	        isChild = False	
	
	    #dict matches the view params of Menu Items	
	    dict = {
	        "viewName": item['label']['text'], 
	        "target": item['target'],
	        "dropdownItems": options, 
	        "selectedValues": selectedValues,
	        "isChild": isChild, 
	        "length": length,
	        "index": index,
	        "depth": depth,
	        "tagPath": item['path'],
	        "iconPath": item['label']['icon']['path'],
	        "requiredRoles": requiredRoles
	    }
	    instances.append(dict)
						
	    if len(item['items']) > 0:
	        length = len(item['items'])	
	        for j in range(len(item['items'])):
	            index = j
	            buildInstance(item['items'][j], options, instances, depth + 1, length, index)
	
	instances = [] 
	items = value
	rolesDict = {}
	roles = system.user.getRoles("default")  # get all possible roles from user source
	options = []  # rolesDict will be appended to this to fill in the dropdown options
	depth = 0 
	
	#create dropdown items object
	for r in range(len(roles)):
	    rolesDict = {"value": r, "label": roles[r]}
	    options.append(rolesDict.copy())
	
	length = len(items)
	for i in range(len(items)):
	    index = i
	    buildInstance(items[i], options, instances, depth, length, index)
	
	return instances
return instances

Please give me your feedback about this.

Thank you