##// END OF EJS Templates
Pluggable admin menu (patch #2031 by Yuki Sonoda with slight changes)....
Jean-Philippe Lang -
r2020:d7718470785c
parent child
Show More
@@ -1,41 +1,47
1 1 <h2><%=l(:label_administration)%></h2>
2 2
3 3 <%= render :partial => 'no_data' if @no_configuration_data %>
4 4
5 5 <p class="icon22 icon22-projects">
6 6 <%= link_to l(:label_project_plural), :controller => 'admin', :action => 'projects' %> |
7 7 <%= link_to l(:label_new), :controller => 'projects', :action => 'add' %>
8 8 </p>
9 9
10 10 <p class="icon22 icon22-users">
11 11 <%= link_to l(:label_user_plural), :controller => 'users' %> |
12 12 <%= link_to l(:label_new), :controller => 'users', :action => 'add' %>
13 13 </p>
14 14
15 15 <p class="icon22 icon22-role">
16 16 <%= link_to l(:label_role_and_permissions), :controller => 'roles' %>
17 17 </p>
18 18
19 19 <p class="icon22 icon22-tracker">
20 20 <%= link_to l(:label_tracker_plural), :controller => 'trackers' %> |
21 21 <%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses' %> |
22 22 <%= link_to l(:label_workflow), :controller => 'workflows', :action => 'edit' %>
23 23 </p>
24 24
25 25 <p class="icon22 icon22-workflow">
26 26 <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields' %>
27 27 </p>
28 28
29 29 <p class="icon22 icon22-options">
30 30 <%= link_to l(:label_enumerations), :controller => 'enumerations' %>
31 31 </p>
32 32
33 33 <p class="icon22 icon22-settings">
34 34 <%= link_to l(:label_settings), :controller => 'settings' %>
35 35 </p>
36 36
37 <% menu_items_for(:admin_menu) do |item, caption, url, selected| -%>
38 <%= content_tag 'p',
39 link_to(h(caption), item.url, item.html_options),
40 :class => ["icon22", "icon22-#{item.name}"].join(' ') %>
41 <% end -%>
42
37 43 <p class="icon22 icon22-info">
38 44 <%= link_to l(:label_information_plural), :controller => 'admin', :action => 'info' %>
39 45 </p>
40 46
41 47 <% html_title(l(:label_administration)) -%>
@@ -1,159 +1,163
1 1 require 'redmine/access_control'
2 2 require 'redmine/menu_manager'
3 3 require 'redmine/activity'
4 4 require 'redmine/mime_type'
5 5 require 'redmine/core_ext'
6 6 require 'redmine/themes'
7 7 require 'redmine/hook'
8 8 require 'redmine/plugin'
9 9 require 'redmine/wiki_formatting'
10 10
11 11 begin
12 12 require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)
13 13 rescue LoadError
14 14 # RMagick is not available
15 15 end
16 16
17 17 REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar Git Filesystem )
18 18
19 19 # Permissions
20 20 Redmine::AccessControl.map do |map|
21 21 map.permission :view_project, {:projects => [:show, :activity]}, :public => true
22 22 map.permission :search_project, {:search => :index}, :public => true
23 23 map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member
24 24 map.permission :select_project_modules, {:projects => :modules}, :require => :member
25 25 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy]}, :require => :member
26 26 map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :destroy]}, :require => :member
27 27
28 28 map.project_module :issue_tracking do |map|
29 29 # Issue categories
30 30 map.permission :manage_categories, {:projects => [:settings, :add_issue_category], :issue_categories => [:edit, :destroy]}, :require => :member
31 31 # Issues
32 32 map.permission :view_issues, {:projects => [:changelog, :roadmap],
33 33 :issues => [:index, :changes, :show, :context_menu],
34 34 :versions => [:show, :status_by],
35 35 :queries => :index,
36 36 :reports => :issue_report}, :public => true
37 37 map.permission :add_issues, {:issues => :new}
38 38 map.permission :edit_issues, {:issues => [:edit, :reply, :bulk_edit, :destroy_attachment]}
39 39 map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
40 40 map.permission :add_issue_notes, {:issues => [:edit, :reply]}
41 41 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
42 42 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
43 43 map.permission :move_issues, {:issues => :move}, :require => :loggedin
44 44 map.permission :delete_issues, {:issues => :destroy}, :require => :member
45 45 # Queries
46 46 map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member
47 47 map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin
48 48 # Gantt & calendar
49 49 map.permission :view_gantt, :issues => :gantt
50 50 map.permission :view_calendar, :issues => :calendar
51 51 # Watchers
52 52 map.permission :view_issue_watchers, {}
53 53 map.permission :add_issue_watchers, {:watchers => :new}
54 54 end
55 55
56 56 map.project_module :time_tracking do |map|
57 57 map.permission :log_time, {:timelog => :edit}, :require => :loggedin
58 58 map.permission :view_time_entries, :timelog => [:details, :report]
59 59 map.permission :edit_time_entries, {:timelog => [:edit, :destroy]}, :require => :member
60 60 map.permission :edit_own_time_entries, {:timelog => [:edit, :destroy]}, :require => :loggedin
61 61 end
62 62
63 63 map.project_module :news do |map|
64 64 map.permission :manage_news, {:news => [:new, :edit, :destroy, :destroy_comment]}, :require => :member
65 65 map.permission :view_news, {:news => [:index, :show]}, :public => true
66 66 map.permission :comment_news, {:news => :add_comment}
67 67 end
68 68
69 69 map.project_module :documents do |map|
70 70 map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment, :destroy_attachment]}, :require => :loggedin
71 71 map.permission :view_documents, :documents => [:index, :show, :download]
72 72 end
73 73
74 74 map.project_module :files do |map|
75 75 map.permission :manage_files, {:projects => :add_file, :versions => :destroy_file}, :require => :loggedin
76 76 map.permission :view_files, :projects => :list_files, :versions => :download
77 77 end
78 78
79 79 map.project_module :wiki do |map|
80 80 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
81 81 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
82 82 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
83 83 map.permission :view_wiki_pages, :wiki => [:index, :special]
84 84 map.permission :view_wiki_edits, :wiki => [:history, :diff, :annotate]
85 85 map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment]
86 86 map.permission :delete_wiki_pages_attachments, :wiki => :destroy_attachment
87 87 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
88 88 end
89 89
90 90 map.project_module :repository do |map|
91 91 map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member
92 92 map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph]
93 93 map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
94 94 map.permission :commit_access, {}
95 95 end
96 96
97 97 map.project_module :boards do |map|
98 98 map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member
99 99 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
100 100 map.permission :add_messages, {:messages => [:new, :reply, :quote]}
101 101 map.permission :edit_messages, {:messages => :edit}, :require => :member
102 102 map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin
103 103 map.permission :delete_messages, {:messages => :destroy}, :require => :member
104 104 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
105 105 end
106 106 end
107 107
108 108 Redmine::MenuManager.map :top_menu do |menu|
109 109 menu.push :home, :home_path, :html => { :class => 'home' }
110 110 menu.push :my_page, { :controller => 'my', :action => 'page' }, :html => { :class => 'mypage' }, :if => Proc.new { User.current.logged? }
111 111 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural, :html => { :class => 'projects' }
112 112 menu.push :administration, { :controller => 'admin', :action => 'index' }, :html => { :class => 'admin' }, :if => Proc.new { User.current.admin? }, :last => true
113 113 menu.push :help, Redmine::Info.help_url, :html => { :class => 'help' }, :last => true
114 114 end
115 115
116 116 Redmine::MenuManager.map :account_menu do |menu|
117 117 menu.push :login, :signin_path, :html => { :class => 'login' }, :if => Proc.new { !User.current.logged? }
118 118 menu.push :register, { :controller => 'account', :action => 'register' }, :html => { :class => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
119 119 menu.push :my_account, { :controller => 'my', :action => 'account' }, :html => { :class => 'myaccount' }, :if => Proc.new { User.current.logged? }
120 120 menu.push :logout, :signout_path, :html => { :class => 'logout' }, :if => Proc.new { User.current.logged? }
121 121 end
122 122
123 123 Redmine::MenuManager.map :application_menu do |menu|
124 124 # Empty
125 125 end
126 126
127 Redmine::MenuManager.map :admin_menu do |menu|
128 # Empty
129 end
130
127 131 Redmine::MenuManager.map :project_menu do |menu|
128 132 menu.push :overview, { :controller => 'projects', :action => 'show' }
129 133 menu.push :activity, { :controller => 'projects', :action => 'activity' }
130 134 menu.push :roadmap, { :controller => 'projects', :action => 'roadmap' },
131 135 :if => Proc.new { |p| p.versions.any? }
132 136 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
133 137 menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new,
134 138 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
135 139 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
136 140 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
137 141 menu.push :wiki, { :controller => 'wiki', :action => 'index', :page => nil },
138 142 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
139 143 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
140 144 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
141 145 menu.push :files, { :controller => 'projects', :action => 'list_files' }, :caption => :label_attachment_plural
142 146 menu.push :repository, { :controller => 'repositories', :action => 'show' },
143 147 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
144 148 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
145 149 end
146 150
147 151 Redmine::Activity.map do |activity|
148 152 activity.register :issues, :class_name => %w(Issue Journal)
149 153 activity.register :changesets
150 154 activity.register :news
151 155 activity.register :documents, :class_name => %w(Document Attachment)
152 156 activity.register :files, :class_name => 'Attachment'
153 157 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
154 158 activity.register :messages, :default => false
155 159 end
156 160
157 161 Redmine::WikiFormatting.map do |format|
158 162 format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper
159 163 end
@@ -1,184 +1,196
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'gloc'
19 19
20 20 module Redmine
21 21 module MenuManager
22 22 module MenuController
23 23 def self.included(base)
24 24 base.extend(ClassMethods)
25 25 end
26 26
27 27 module ClassMethods
28 28 @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}}
29 29 mattr_accessor :menu_items
30 30
31 31 # Set the menu item name for a controller or specific actions
32 32 # Examples:
33 33 # * menu_item :tickets # => sets the menu name to :tickets for the whole controller
34 34 # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only
35 35 # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only
36 36 #
37 37 # The default menu item name for a controller is controller_name by default
38 38 # Eg. the default menu item name for ProjectsController is :projects
39 39 def menu_item(id, options = {})
40 40 if actions = options[:only]
41 41 actions = [] << actions unless actions.is_a?(Array)
42 42 actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id}
43 43 else
44 44 menu_items[controller_name.to_sym][:default] = id
45 45 end
46 46 end
47 47 end
48 48
49 49 def menu_items
50 50 self.class.menu_items
51 51 end
52 52
53 53 # Returns the menu item name according to the current action
54 54 def current_menu_item
55 55 menu_items[controller_name.to_sym][:actions][action_name.to_sym] ||
56 56 menu_items[controller_name.to_sym][:default]
57 57 end
58 58 end
59 59
60 60 module MenuHelper
61 61 # Returns the current menu item name
62 62 def current_menu_item
63 63 @controller.current_menu_item
64 64 end
65 65
66 66 # Renders the application main menu
67 67 def render_main_menu(project)
68 68 render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)
69 69 end
70 70
71 71 def render_menu(menu, project=nil)
72 72 links = []
73 menu_items_for(menu, project) do |item, caption, url, selected|
74 links << content_tag('li',
75 link_to(h(caption), url, (selected ? item.html_options.merge(:class => 'selected') : item.html_options)))
76 end
77 links.empty? ? nil : content_tag('ul', links.join("\n"))
78 end
79
80 def menu_items_for(menu, project=nil)
81 items = []
73 82 Redmine::MenuManager.allowed_items(menu, User.current, project).each do |item|
74 83 unless item.condition && !item.condition.call(project)
75 84 url = case item.url
76 85 when Hash
77 86 project.nil? ? item.url : {item.param => project}.merge(item.url)
78 87 when Symbol
79 88 send(item.url)
80 89 else
81 90 item.url
82 91 end
83 92 caption = item.caption(project)
84 93 caption = l(caption) if caption.is_a?(Symbol)
85 links << content_tag('li',
86 link_to(h(caption), url, (current_menu_item == item.name ? item.html_options.merge(:class => 'selected') : item.html_options)))
94 if block_given?
95 yield item, caption, url, (current_menu_item == item.name)
96 else
97 items << [item, caption, url, (current_menu_item == item.name)]
87 98 end
88 99 end
89 links.empty? ? nil : content_tag('ul', links.join("\n"))
100 end
101 return block_given? ? nil : items
90 102 end
91 103 end
92 104
93 105 class << self
94 106 def map(menu_name)
95 107 @items ||= {}
96 108 mapper = Mapper.new(menu_name.to_sym, @items)
97 109 if block_given?
98 110 yield mapper
99 111 else
100 112 mapper
101 113 end
102 114 end
103 115
104 116 def items(menu_name)
105 117 @items[menu_name.to_sym] || []
106 118 end
107 119
108 120 def allowed_items(menu_name, user, project)
109 121 project ? items(menu_name).select {|item| user && user.allowed_to?(item.url, project)} : items(menu_name)
110 122 end
111 123 end
112 124
113 125 class Mapper
114 126 def initialize(menu, items)
115 127 items[menu] ||= []
116 128 @menu = menu
117 129 @menu_items = items[menu]
118 130 end
119 131
120 132 @@last_items_count = Hash.new {|h,k| h[k] = 0}
121 133
122 134 # Adds an item at the end of the menu. Available options:
123 135 # * param: the parameter name that is used for the project id (default is :id)
124 136 # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true
125 137 # * caption that can be:
126 138 # * a localized string Symbol
127 139 # * a String
128 140 # * a Proc that can take the project as argument
129 141 # * before, after: specify where the menu item should be inserted (eg. :after => :activity)
130 142 # * last: menu item will stay at the end (eg. :last => true)
131 143 # * html_options: a hash of html options that are passed to link_to
132 144 def push(name, url, options={})
133 145 options = options.dup
134 146
135 147 # menu item position
136 148 if before = options.delete(:before)
137 149 position = @menu_items.collect(&:name).index(before)
138 150 elsif after = options.delete(:after)
139 151 position = @menu_items.collect(&:name).index(after)
140 152 position += 1 unless position.nil?
141 153 elsif options.delete(:last)
142 154 position = @menu_items.size
143 155 @@last_items_count[@menu] += 1
144 156 end
145 157 # default position
146 158 position ||= @menu_items.size - @@last_items_count[@menu]
147 159
148 160 @menu_items.insert(position, MenuItem.new(name, url, options))
149 161 end
150 162
151 163 # Removes a menu item
152 164 def delete(name)
153 165 @menu_items.delete_if {|i| i.name == name}
154 166 end
155 167 end
156 168
157 169 class MenuItem
158 170 include GLoc
159 171 attr_reader :name, :url, :param, :condition, :html_options
160 172
161 173 def initialize(name, url, options)
162 174 raise "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
163 175 raise "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
164 176 @name = name
165 177 @url = url
166 178 @condition = options[:if]
167 179 @param = options[:param] || :id
168 180 @caption = options[:caption]
169 181 @html_options = options[:html] || {}
170 182 end
171 183
172 184 def caption(project=nil)
173 185 if @caption.is_a?(Proc)
174 186 c = @caption.call(project).to_s
175 187 c = @name.to_s.humanize if c.blank?
176 188 c
177 189 else
178 190 # check if localized string exists on first render (after GLoc strings are loaded)
179 191 @caption_key ||= (@caption || (l_has_string?("label_#{@name}".to_sym) ? "label_#{@name}".to_sym : @name.to_s.humanize))
180 192 end
181 193 end
182 194 end
183 195 end
184 196 end
General Comments 0
You need to be logged in to leave comments. Login now