[katello-devel] New approach to navigation

Partha Aji paji at redhat.com
Fri Oct 7 18:06:55 UTC 2011


Recently I encountered a bug on some nav issues (https://bugzilla.redhat.com/show_bug.cgi?id=737207) with the subject "Navigation can lead to permission denied if user permissions do not allow access to tab's default url". So here is an example of bugs like this
"The user has permissions to read contents in an environment BUT has no permissions to access any providers". Now the nav system always has a default url pointing to providers index page causing "permission denied"  error when clicked on content management tab. So to solve this problem, looking at the existing navigation.rb we'd have had to do something like

top_level.item, :url=> (condition1)?url1:(condition2)?url2:(condition3)?url3:"", ....do |second_level|
  second_level.item {sub menu1 details}, :url => url1 ,:if => condition1
  second_level.item {sub menu2 details} ,:url => url2 , :if => condition2
  second_level.item {sub menu3details} ,:url => url3 , :if => condition3
end if condition1 || condition2
   
notice that for a successful menu item I'd have to repeat + evaluate  the same rules logic 3 times, once to set the top_level url, once to set the second level item and once evaluate if the top_level need to be shown. This can get quite unwieldy if we have more than 2 second and third level menu items. So looked up a bit on simple navigation and saw that I could dynamically provide a menu for simple nav to render. Based on this (with help from jsherrill/witlessb/inecas) I have hopefully improved the menu navigation implemented with my changes in katello git's navigation branch (http://git.fedorahosted.org/git/?p=katello.git;a=shortlog;h=refs/heads/navigation). 
The huge navigation file is now fragmented a little into smaller files under katello/src/lib/navigation  - main.rb, dashboard.rb, organization.rb, content_management.rb and so on  each representing a top level menu item. I have not tried to be clever, so hopefully its obvious enough. So here is a sample code for the content_management menu 

  def menu_contents
    {:key => :content,
     :name => N_("Content Management"),
      :url => :sub_level,
      :class=>'content',
      :items=> [ menu_providers  ]
    }
  end

Notice the construct that says :url => :sub_level in the menu_contents method which is responsible for returning the top level items (for now it only does providers, soon will be adding entries for promotion if this works out with every one). The :url => :sub_level tells it to fetch the url from the first item of the sub level (as in go through the menu items in as shown in the :items tag and get the first accessible one. ) Further down the path,

    def menu_providers

      {:key => :providers,
       :name =>N_("Providers"),
       :url => :sub_level,
       :options => {:highlights_on => /(\/organizations\/.*\/providers)|(\/providers\/.*\/(products|repos))/},
       :if => :sub_level,
       :items => [menu_redhat_providers, menu_custom_providers]
      }
    end


    def menu_redhat_providers
      {:key => :redhat_providers,
        :name =>N_("Red Hat"),
        :url => redhat_provider_providers_path,
        :if => lambda{current_organization && current_organization.readable?},
        :options => {:class=>"third_level"}
      }
    end


Notice the :if => sub_level. Same idea. So what this says is that the condition for its display are based of what the sub menu if conditions evaluate to. That is if the :items menu is empty (because of inaccessible sub menu items),  do not include the top level.

Please let me know if any of you have any reservations/questions on this. I'll probably push this master monday evening, if not..

Partha











More information about the katello-devel mailing list