##// END OF EJS Templates
Adds an admin layout that displays the admin menu in the sidebar....
Jean-Philippe Lang -
r3062:dfabadf4f7e0
parent child
Show More
@@ -0,0 +1,8
1 <% unless controller_name == 'admin' && action_name == 'index' %>
2 <% content_for :sidebar do %>
3 <h3><%=l(:label_administration)%></h3>
4 <%= render :partial => 'admin/menu' %>
5 <% end %>
6 <% end %>
7
8 <%= render :file => "layouts/base" %>
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
@@ -1,84 +1,86
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 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 class AdminController < ApplicationController
19 layout 'admin'
20
19 21 before_filter :require_admin
20 22
21 23 helper :sort
22 24 include SortHelper
23 25
24 26 def index
25 27 @no_configuration_data = Redmine::DefaultData::Loader::no_data?
26 28 end
27 29
28 30 def projects
29 31 @status = params[:status] ? params[:status].to_i : 1
30 32 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
31 33
32 34 unless params[:name].blank?
33 35 name = "%#{params[:name].strip.downcase}%"
34 36 c << ["LOWER(identifier) LIKE ? OR LOWER(name) LIKE ?", name, name]
35 37 end
36 38
37 39 @projects = Project.find :all, :order => 'lft',
38 40 :conditions => c.conditions
39 41
40 42 render :action => "projects", :layout => false if request.xhr?
41 43 end
42 44
43 45 def plugins
44 46 @plugins = Redmine::Plugin.all
45 47 end
46 48
47 49 # Loads the default configuration
48 50 # (roles, trackers, statuses, workflow, enumerations)
49 51 def default_configuration
50 52 if request.post?
51 53 begin
52 54 Redmine::DefaultData::Loader::load(params[:lang])
53 55 flash[:notice] = l(:notice_default_data_loaded)
54 56 rescue Exception => e
55 57 flash[:error] = l(:error_can_t_load_default_data, e.message)
56 58 end
57 59 end
58 60 redirect_to :action => 'index'
59 61 end
60 62
61 63 def test_email
62 64 raise_delivery_errors = ActionMailer::Base.raise_delivery_errors
63 65 # Force ActionMailer to raise delivery errors so we can catch it
64 66 ActionMailer::Base.raise_delivery_errors = true
65 67 begin
66 68 @test = Mailer.deliver_test(User.current)
67 69 flash[:notice] = l(:notice_email_sent, User.current.mail)
68 70 rescue Exception => e
69 71 flash[:error] = l(:notice_email_error, e.message)
70 72 end
71 73 ActionMailer::Base.raise_delivery_errors = raise_delivery_errors
72 74 redirect_to :controller => 'settings', :action => 'edit', :tab => 'notifications'
73 75 end
74 76
75 77 def info
76 78 @db_adapter_name = ActiveRecord::Base.connection.adapter_name
77 79 @flags = {
78 80 :default_admin_changed => User.find(:first, :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?,
79 81 :file_repository_writable => File.writable?(Attachment.storage_path),
80 82 :plugin_assets_writable => File.writable?(Engines.public_directory),
81 83 :rmagick_available => Object.const_defined?(:Magick)
82 84 }
83 85 end
84 86 end
@@ -1,276 +1,276
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 'uri'
19 19 require 'cgi'
20 20
21 21 class ApplicationController < ActionController::Base
22 22 include Redmine::I18n
23 23
24 24 layout 'base'
25 25
26 26 # Remove broken cookie after upgrade from 0.8.x (#4292)
27 27 # See https://rails.lighthouseapp.com/projects/8994/tickets/3360
28 28 # TODO: remove it when Rails is fixed
29 29 before_filter :delete_broken_cookies
30 30 def delete_broken_cookies
31 31 if cookies['_redmine_session'] && cookies['_redmine_session'] !~ /--/
32 32 cookies.delete '_redmine_session'
33 33 redirect_to home_path and return false
34 34 end
35 35 end
36 36
37 37 before_filter :user_setup, :check_if_login_required, :set_localization
38 38 filter_parameter_logging :password
39 39 protect_from_forgery
40 40
41 41 rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
42 42
43 43 include Redmine::Search::Controller
44 44 include Redmine::MenuManager::MenuController
45 45 helper Redmine::MenuManager::MenuHelper
46 46
47 47 REDMINE_SUPPORTED_SCM.each do |scm|
48 48 require_dependency "repository/#{scm.underscore}"
49 49 end
50 50
51 51 def user_setup
52 52 # Check the settings cache for each request
53 53 Setting.check_cache
54 54 # Find the current user
55 55 User.current = find_current_user
56 56 end
57 57
58 58 # Returns the current user or nil if no user is logged in
59 59 # and starts a session if needed
60 60 def find_current_user
61 61 if session[:user_id]
62 62 # existing session
63 63 (User.active.find(session[:user_id]) rescue nil)
64 64 elsif cookies[:autologin] && Setting.autologin?
65 65 # auto-login feature starts a new session
66 66 user = User.try_to_autologin(cookies[:autologin])
67 67 session[:user_id] = user.id if user
68 68 user
69 69 elsif params[:format] == 'atom' && params[:key] && accept_key_auth_actions.include?(params[:action])
70 70 # RSS key authentication does not start a session
71 71 User.find_by_rss_key(params[:key])
72 72 end
73 73 end
74 74
75 75 # Sets the logged in user
76 76 def logged_user=(user)
77 77 reset_session
78 78 if user && user.is_a?(User)
79 79 User.current = user
80 80 session[:user_id] = user.id
81 81 else
82 82 User.current = User.anonymous
83 83 end
84 84 end
85 85
86 86 # check if login is globally required to access the application
87 87 def check_if_login_required
88 88 # no check needed if user is already logged in
89 89 return true if User.current.logged?
90 90 require_login if Setting.login_required?
91 91 end
92 92
93 93 def set_localization
94 94 lang = nil
95 95 if User.current.logged?
96 96 lang = find_language(User.current.language)
97 97 end
98 98 if lang.nil? && request.env['HTTP_ACCEPT_LANGUAGE']
99 99 accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.downcase
100 100 if !accept_lang.blank?
101 101 lang = find_language(accept_lang) || find_language(accept_lang.split('-').first)
102 102 end
103 103 end
104 104 lang ||= Setting.default_language
105 105 set_language_if_valid(lang)
106 106 end
107 107
108 108 def require_login
109 109 if !User.current.logged?
110 110 # Extract only the basic url parameters on non-GET requests
111 111 if request.get?
112 112 url = url_for(params)
113 113 else
114 114 url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id])
115 115 end
116 116 redirect_to :controller => "account", :action => "login", :back_url => url
117 117 return false
118 118 end
119 119 true
120 120 end
121 121
122 122 def require_admin
123 123 return unless require_login
124 124 if !User.current.admin?
125 125 render_403
126 126 return false
127 127 end
128 128 true
129 129 end
130 130
131 131 def deny_access
132 132 User.current.logged? ? render_403 : require_login
133 133 end
134 134
135 135 # Authorize the user for the requested action
136 136 def authorize(ctrl = params[:controller], action = params[:action], global = false)
137 137 allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project, :global => global)
138 138 allowed ? true : deny_access
139 139 end
140 140
141 141 # Authorize the user for the requested action outside a project
142 142 def authorize_global(ctrl = params[:controller], action = params[:action], global = true)
143 143 authorize(ctrl, action, global)
144 144 end
145 145
146 146 # make sure that the user is a member of the project (or admin) if project is private
147 147 # used as a before_filter for actions that do not require any particular permission on the project
148 148 def check_project_privacy
149 149 if @project && @project.active?
150 150 if @project.is_public? || User.current.member_of?(@project) || User.current.admin?
151 151 true
152 152 else
153 153 User.current.logged? ? render_403 : require_login
154 154 end
155 155 else
156 156 @project = nil
157 157 render_404
158 158 false
159 159 end
160 160 end
161 161
162 162 def redirect_back_or_default(default)
163 163 back_url = CGI.unescape(params[:back_url].to_s)
164 164 if !back_url.blank?
165 165 begin
166 166 uri = URI.parse(back_url)
167 167 # do not redirect user to another host or to the login or register page
168 168 if (uri.relative? || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)})
169 169 redirect_to(back_url) and return
170 170 end
171 171 rescue URI::InvalidURIError
172 172 # redirect to default
173 173 end
174 174 end
175 175 redirect_to default
176 176 end
177 177
178 178 def render_403
179 179 @project = nil
180 render :template => "common/403", :layout => !request.xhr?, :status => 403
180 render :template => "common/403", :layout => (request.xhr? ? false : 'base'), :status => 403
181 181 return false
182 182 end
183 183
184 184 def render_404
185 185 render :template => "common/404", :layout => !request.xhr?, :status => 404
186 186 return false
187 187 end
188 188
189 189 def render_error(msg)
190 190 flash.now[:error] = msg
191 191 render :text => '', :layout => !request.xhr?, :status => 500
192 192 end
193 193
194 194 def invalid_authenticity_token
195 195 render_error "Invalid form authenticity token."
196 196 end
197 197
198 198 def render_feed(items, options={})
199 199 @items = items || []
200 200 @items.sort! {|x,y| y.event_datetime <=> x.event_datetime }
201 201 @items = @items.slice(0, Setting.feeds_limit.to_i)
202 202 @title = options[:title] || Setting.app_title
203 203 render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml'
204 204 end
205 205
206 206 def self.accept_key_auth(*actions)
207 207 actions = actions.flatten.map(&:to_s)
208 208 write_inheritable_attribute('accept_key_auth_actions', actions)
209 209 end
210 210
211 211 def accept_key_auth_actions
212 212 self.class.read_inheritable_attribute('accept_key_auth_actions') || []
213 213 end
214 214
215 215 # TODO: move to model
216 216 def attach_files(obj, attachments)
217 217 attached = []
218 218 unsaved = []
219 219 if attachments && attachments.is_a?(Hash)
220 220 attachments.each_value do |attachment|
221 221 file = attachment['file']
222 222 next unless file && file.size > 0
223 223 a = Attachment.create(:container => obj,
224 224 :file => file,
225 225 :description => attachment['description'].to_s.strip,
226 226 :author => User.current)
227 227 a.new_record? ? (unsaved << a) : (attached << a)
228 228 end
229 229 if unsaved.any?
230 230 flash[:warning] = l(:warning_attachments_not_saved, unsaved.size)
231 231 end
232 232 end
233 233 attached
234 234 end
235 235
236 236 # Returns the number of objects that should be displayed
237 237 # on the paginated list
238 238 def per_page_option
239 239 per_page = nil
240 240 if params[:per_page] && Setting.per_page_options_array.include?(params[:per_page].to_s.to_i)
241 241 per_page = params[:per_page].to_s.to_i
242 242 session[:per_page] = per_page
243 243 elsif session[:per_page]
244 244 per_page = session[:per_page]
245 245 else
246 246 per_page = Setting.per_page_options_array.first || 25
247 247 end
248 248 per_page
249 249 end
250 250
251 251 # qvalues http header parser
252 252 # code taken from webrick
253 253 def parse_qvalues(value)
254 254 tmp = []
255 255 if value
256 256 parts = value.split(/,\s*/)
257 257 parts.each {|part|
258 258 if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part)
259 259 val = m[1]
260 260 q = (m[2] or 1).to_f
261 261 tmp.push([val, q])
262 262 end
263 263 }
264 264 tmp = tmp.sort_by{|val, q| -q}
265 265 tmp.collect!{|val, q| val}
266 266 end
267 267 return tmp
268 268 rescue
269 269 nil
270 270 end
271 271
272 272 # Returns a string that can be used as filename value in Content-Disposition header
273 273 def filename_for_content_disposition(name)
274 274 request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(name) : name
275 275 end
276 276 end
@@ -1,82 +1,84
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 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 class AuthSourcesController < ApplicationController
19 layout 'admin'
20
19 21 before_filter :require_admin
20 22
21 23 def index
22 24 list
23 25 render :action => 'list' unless request.xhr?
24 26 end
25 27
26 28 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
27 29 verify :method => :post, :only => [ :destroy, :create, :update ],
28 30 :redirect_to => { :action => :list }
29 31
30 32 def list
31 33 @auth_source_pages, @auth_sources = paginate :auth_sources, :per_page => 10
32 34 render :action => "list", :layout => false if request.xhr?
33 35 end
34 36
35 37 def new
36 38 @auth_source = AuthSourceLdap.new
37 39 end
38 40
39 41 def create
40 42 @auth_source = AuthSourceLdap.new(params[:auth_source])
41 43 if @auth_source.save
42 44 flash[:notice] = l(:notice_successful_create)
43 45 redirect_to :action => 'list'
44 46 else
45 47 render :action => 'new'
46 48 end
47 49 end
48 50
49 51 def edit
50 52 @auth_source = AuthSource.find(params[:id])
51 53 end
52 54
53 55 def update
54 56 @auth_source = AuthSource.find(params[:id])
55 57 if @auth_source.update_attributes(params[:auth_source])
56 58 flash[:notice] = l(:notice_successful_update)
57 59 redirect_to :action => 'list'
58 60 else
59 61 render :action => 'edit'
60 62 end
61 63 end
62 64
63 65 def test_connection
64 66 @auth_method = AuthSource.find(params[:id])
65 67 begin
66 68 @auth_method.test_connection
67 69 flash[:notice] = l(:notice_successful_connection)
68 70 rescue => text
69 71 flash[:error] = "Unable to connect (#{text})"
70 72 end
71 73 redirect_to :action => 'list'
72 74 end
73 75
74 76 def destroy
75 77 @auth_source = AuthSource.find(params[:id])
76 78 unless @auth_source.users.find(:first)
77 79 @auth_source.destroy
78 80 flash[:notice] = l(:notice_successful_delete)
79 81 end
80 82 redirect_to :action => 'list'
81 83 end
82 84 end
@@ -1,60 +1,62
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2009 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 class CustomFieldsController < ApplicationController
19 layout 'admin'
20
19 21 before_filter :require_admin
20 22
21 23 def index
22 24 @custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name }
23 25 @tab = params[:tab] || 'IssueCustomField'
24 26 end
25 27
26 28 def new
27 29 @custom_field = begin
28 30 if params[:type].to_s.match(/.+CustomField$/)
29 31 params[:type].to_s.constantize.new(params[:custom_field])
30 32 end
31 33 rescue
32 34 end
33 35 redirect_to(:action => 'index') and return unless @custom_field.is_a?(CustomField)
34 36
35 37 if request.post? and @custom_field.save
36 38 flash[:notice] = l(:notice_successful_create)
37 39 call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field)
38 40 redirect_to :action => 'index', :tab => @custom_field.class.name
39 41 end
40 42 @trackers = Tracker.find(:all, :order => 'position')
41 43 end
42 44
43 45 def edit
44 46 @custom_field = CustomField.find(params[:id])
45 47 if request.post? and @custom_field.update_attributes(params[:custom_field])
46 48 flash[:notice] = l(:notice_successful_update)
47 49 call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field)
48 50 redirect_to :action => 'index', :tab => @custom_field.class.name
49 51 end
50 52 @trackers = Tracker.find(:all, :order => 'position')
51 53 end
52 54
53 55 def destroy
54 56 @custom_field = CustomField.find(params[:id]).destroy
55 57 redirect_to :action => 'index', :tab => @custom_field.class.name
56 58 rescue
57 59 flash[:error] = "Unable to delete custom field"
58 60 redirect_to :action => 'index'
59 61 end
60 62 end
@@ -1,87 +1,89
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 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 class EnumerationsController < ApplicationController
19 layout 'admin'
20
19 21 before_filter :require_admin
20 22
21 23 helper :custom_fields
22 24 include CustomFieldsHelper
23 25
24 26 def index
25 27 list
26 28 render :action => 'list'
27 29 end
28 30
29 31 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
30 32 verify :method => :post, :only => [ :destroy, :create, :update ],
31 33 :redirect_to => { :action => :list }
32 34
33 35 def list
34 36 end
35 37
36 38 def new
37 39 begin
38 40 @enumeration = params[:type].constantize.new
39 41 rescue NameError
40 42 @enumeration = Enumeration.new
41 43 end
42 44 end
43 45
44 46 def create
45 47 @enumeration = Enumeration.new(params[:enumeration])
46 48 @enumeration.type = params[:enumeration][:type]
47 49 if @enumeration.save
48 50 flash[:notice] = l(:notice_successful_create)
49 51 redirect_to :action => 'list', :type => @enumeration.type
50 52 else
51 53 render :action => 'new'
52 54 end
53 55 end
54 56
55 57 def edit
56 58 @enumeration = Enumeration.find(params[:id])
57 59 end
58 60
59 61 def update
60 62 @enumeration = Enumeration.find(params[:id])
61 63 @enumeration.type = params[:enumeration][:type] if params[:enumeration][:type]
62 64 if @enumeration.update_attributes(params[:enumeration])
63 65 flash[:notice] = l(:notice_successful_update)
64 66 redirect_to :action => 'list', :type => @enumeration.type
65 67 else
66 68 render :action => 'edit'
67 69 end
68 70 end
69 71
70 72 def destroy
71 73 @enumeration = Enumeration.find(params[:id])
72 74 if !@enumeration.in_use?
73 75 # No associated objects
74 76 @enumeration.destroy
75 77 redirect_to :action => 'index'
76 78 elsif params[:reassign_to_id]
77 79 if reassign_to = Enumeration.find_by_type_and_id(@enumeration.type, params[:reassign_to_id])
78 80 @enumeration.destroy(reassign_to)
79 81 redirect_to :action => 'index'
80 82 end
81 83 end
82 84 @enumerations = Enumeration.find(:all, :conditions => ['type = (?)', @enumeration.type]) - [@enumeration]
83 85 #rescue
84 86 # flash[:error] = 'Unable to delete enumeration'
85 87 # redirect_to :action => 'index'
86 88 end
87 89 end
@@ -1,162 +1,163
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2009 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 class GroupsController < ApplicationController
19 layout 'base'
19 layout 'admin'
20
20 21 before_filter :require_admin
21 22
22 23 helper :custom_fields
23 24
24 25 # GET /groups
25 26 # GET /groups.xml
26 27 def index
27 28 @groups = Group.find(:all, :order => 'lastname')
28 29
29 30 respond_to do |format|
30 31 format.html # index.html.erb
31 32 format.xml { render :xml => @groups }
32 33 end
33 34 end
34 35
35 36 # GET /groups/1
36 37 # GET /groups/1.xml
37 38 def show
38 39 @group = Group.find(params[:id])
39 40
40 41 respond_to do |format|
41 42 format.html # show.html.erb
42 43 format.xml { render :xml => @group }
43 44 end
44 45 end
45 46
46 47 # GET /groups/new
47 48 # GET /groups/new.xml
48 49 def new
49 50 @group = Group.new
50 51
51 52 respond_to do |format|
52 53 format.html # new.html.erb
53 54 format.xml { render :xml => @group }
54 55 end
55 56 end
56 57
57 58 # GET /groups/1/edit
58 59 def edit
59 60 @group = Group.find(params[:id])
60 61 end
61 62
62 63 # POST /groups
63 64 # POST /groups.xml
64 65 def create
65 66 @group = Group.new(params[:group])
66 67
67 68 respond_to do |format|
68 69 if @group.save
69 70 flash[:notice] = l(:notice_successful_create)
70 71 format.html { redirect_to(groups_path) }
71 72 format.xml { render :xml => @group, :status => :created, :location => @group }
72 73 else
73 74 format.html { render :action => "new" }
74 75 format.xml { render :xml => @group.errors, :status => :unprocessable_entity }
75 76 end
76 77 end
77 78 end
78 79
79 80 # PUT /groups/1
80 81 # PUT /groups/1.xml
81 82 def update
82 83 @group = Group.find(params[:id])
83 84
84 85 respond_to do |format|
85 86 if @group.update_attributes(params[:group])
86 87 flash[:notice] = l(:notice_successful_update)
87 88 format.html { redirect_to(groups_path) }
88 89 format.xml { head :ok }
89 90 else
90 91 format.html { render :action => "edit" }
91 92 format.xml { render :xml => @group.errors, :status => :unprocessable_entity }
92 93 end
93 94 end
94 95 end
95 96
96 97 # DELETE /groups/1
97 98 # DELETE /groups/1.xml
98 99 def destroy
99 100 @group = Group.find(params[:id])
100 101 @group.destroy
101 102
102 103 respond_to do |format|
103 104 format.html { redirect_to(groups_url) }
104 105 format.xml { head :ok }
105 106 end
106 107 end
107 108
108 109 def add_users
109 110 @group = Group.find(params[:id])
110 111 users = User.find_all_by_id(params[:user_ids])
111 112 @group.users << users if request.post?
112 113 respond_to do |format|
113 114 format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' }
114 115 format.js {
115 116 render(:update) {|page|
116 117 page.replace_html "tab-content-users", :partial => 'groups/users'
117 118 users.each {|user| page.visual_effect(:highlight, "user-#{user.id}") }
118 119 }
119 120 }
120 121 end
121 122 end
122 123
123 124 def remove_user
124 125 @group = Group.find(params[:id])
125 126 @group.users.delete(User.find(params[:user_id])) if request.post?
126 127 respond_to do |format|
127 128 format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' }
128 129 format.js { render(:update) {|page| page.replace_html "tab-content-users", :partial => 'groups/users'} }
129 130 end
130 131 end
131 132
132 133 def autocomplete_for_user
133 134 @group = Group.find(params[:id])
134 135 @users = User.active.like(params[:q]).find(:all, :limit => 100) - @group.users
135 136 render :layout => false
136 137 end
137 138
138 139 def edit_membership
139 140 @group = Group.find(params[:id])
140 141 @membership = params[:membership_id] ? Member.find(params[:membership_id]) : Member.new(:principal => @group)
141 142 @membership.attributes = params[:membership]
142 143 @membership.save if request.post?
143 144 respond_to do |format|
144 145 format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' }
145 146 format.js {
146 147 render(:update) {|page|
147 148 page.replace_html "tab-content-memberships", :partial => 'groups/memberships'
148 149 page.visual_effect(:highlight, "member-#{@membership.id}")
149 150 }
150 151 }
151 152 end
152 153 end
153 154
154 155 def destroy_membership
155 156 @group = Group.find(params[:id])
156 157 Member.find(params[:membership_id]).destroy if request.post?
157 158 respond_to do |format|
158 159 format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' }
159 160 format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'groups/memberships'} }
160 161 end
161 162 end
162 163 end
@@ -1,78 +1,80
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 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 class IssueStatusesController < ApplicationController
19 layout 'admin'
20
19 21 before_filter :require_admin
20 22
21 23 verify :method => :post, :only => [ :destroy, :create, :update, :move, :update_issue_done_ratio ],
22 24 :redirect_to => { :action => :list }
23 25
24 26 def index
25 27 list
26 28 render :action => 'list' unless request.xhr?
27 29 end
28 30
29 31 def list
30 32 @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position"
31 33 render :action => "list", :layout => false if request.xhr?
32 34 end
33 35
34 36 def new
35 37 @issue_status = IssueStatus.new
36 38 end
37 39
38 40 def create
39 41 @issue_status = IssueStatus.new(params[:issue_status])
40 42 if @issue_status.save
41 43 flash[:notice] = l(:notice_successful_create)
42 44 redirect_to :action => 'list'
43 45 else
44 46 render :action => 'new'
45 47 end
46 48 end
47 49
48 50 def edit
49 51 @issue_status = IssueStatus.find(params[:id])
50 52 end
51 53
52 54 def update
53 55 @issue_status = IssueStatus.find(params[:id])
54 56 if @issue_status.update_attributes(params[:issue_status])
55 57 flash[:notice] = l(:notice_successful_update)
56 58 redirect_to :action => 'list'
57 59 else
58 60 render :action => 'edit'
59 61 end
60 62 end
61 63
62 64 def destroy
63 65 IssueStatus.find(params[:id]).destroy
64 66 redirect_to :action => 'list'
65 67 rescue
66 68 flash[:error] = "Unable to delete issue status"
67 69 redirect_to :action => 'list'
68 70 end
69 71
70 72 def update_issue_done_ratio
71 73 if IssueStatus.update_issue_done_ratios
72 74 flash[:notice] = l(:notice_issue_done_ratios_updated)
73 75 else
74 76 flash[:error] = l(:error_issue_done_ratios_not_updated)
75 77 end
76 78 redirect_to :action => 'list'
77 79 end
78 80 end
@@ -1,79 +1,81
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 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 class RolesController < ApplicationController
19 layout 'admin'
20
19 21 before_filter :require_admin
20 22
21 23 verify :method => :post, :only => [ :destroy, :move ],
22 24 :redirect_to => { :action => :list }
23 25
24 26 def index
25 27 list
26 28 render :action => 'list' unless request.xhr?
27 29 end
28 30
29 31 def list
30 32 @role_pages, @roles = paginate :roles, :per_page => 25, :order => 'builtin, position'
31 33 render :action => "list", :layout => false if request.xhr?
32 34 end
33 35
34 36 def new
35 37 # Prefills the form with 'Non member' role permissions
36 38 @role = Role.new(params[:role] || {:permissions => Role.non_member.permissions})
37 39 if request.post? && @role.save
38 40 # workflow copy
39 41 if !params[:copy_workflow_from].blank? && (copy_from = Role.find_by_id(params[:copy_workflow_from]))
40 42 @role.workflows.copy(copy_from)
41 43 end
42 44 flash[:notice] = l(:notice_successful_create)
43 45 redirect_to :action => 'index'
44 46 end
45 47 @permissions = @role.setable_permissions
46 48 @roles = Role.find :all, :order => 'builtin, position'
47 49 end
48 50
49 51 def edit
50 52 @role = Role.find(params[:id])
51 53 if request.post? and @role.update_attributes(params[:role])
52 54 flash[:notice] = l(:notice_successful_update)
53 55 redirect_to :action => 'index'
54 56 end
55 57 @permissions = @role.setable_permissions
56 58 end
57 59
58 60 def destroy
59 61 @role = Role.find(params[:id])
60 62 @role.destroy
61 63 redirect_to :action => 'index'
62 64 rescue
63 65 flash[:error] = 'This role is in use and can not be deleted.'
64 66 redirect_to :action => 'index'
65 67 end
66 68
67 69 def report
68 70 @roles = Role.find(:all, :order => 'builtin, position')
69 71 @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? }
70 72 if request.post?
71 73 @roles.each do |role|
72 74 role.permissions = params[:permissions][role.id.to_s]
73 75 role.save
74 76 end
75 77 flash[:notice] = l(:notice_successful_update)
76 78 redirect_to :action => 'index'
77 79 end
78 80 end
79 81 end
@@ -1,59 +1,61
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 class SettingsController < ApplicationController
19 layout 'admin'
20
19 21 before_filter :require_admin
20 22
21 23 def index
22 24 edit
23 25 render :action => 'edit'
24 26 end
25 27
26 28 def edit
27 29 @notifiables = %w(issue_added issue_updated news_added document_added file_added message_posted wiki_content_added wiki_content_updated)
28 30 if request.post? && params[:settings] && params[:settings].is_a?(Hash)
29 31 settings = (params[:settings] || {}).dup.symbolize_keys
30 32 settings.each do |name, value|
31 33 # remove blank values in array settings
32 34 value.delete_if {|v| v.blank? } if value.is_a?(Array)
33 35 Setting[name] = value
34 36 end
35 37 flash[:notice] = l(:notice_successful_update)
36 38 redirect_to :action => 'edit', :tab => params[:tab]
37 39 return
38 40 end
39 41 @options = {}
40 42 @options[:user_format] = User::USER_FORMATS.keys.collect {|f| [User.current.name(f), f.to_s] }
41 43 @deliveries = ActionMailer::Base.perform_deliveries
42 44
43 45 @guessed_host_and_path = request.host_with_port.dup
44 46 @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank?
45 47 end
46 48
47 49 def plugin
48 50 @plugin = Redmine::Plugin.find(params[:id])
49 51 if request.post?
50 52 Setting["plugin_#{@plugin.id}"] = params[:settings]
51 53 flash[:notice] = l(:notice_successful_update)
52 54 redirect_to :action => 'plugin', :id => @plugin.id
53 55 end
54 56 @partial = @plugin.settings[:partial]
55 57 @settings = Setting["plugin_#{@plugin.id}"]
56 58 rescue Redmine::PluginNotFound
57 59 render_404
58 60 end
59 61 end
@@ -1,67 +1,69
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2009 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 class TrackersController < ApplicationController
19 layout 'admin'
20
19 21 before_filter :require_admin
20 22
21 23 def index
22 24 list
23 25 render :action => 'list' unless request.xhr?
24 26 end
25 27
26 28 verify :method => :post, :only => :destroy, :redirect_to => { :action => :list }
27 29
28 30 def list
29 31 @tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position'
30 32 render :action => "list", :layout => false if request.xhr?
31 33 end
32 34
33 35 def new
34 36 @tracker = Tracker.new(params[:tracker])
35 37 if request.post? and @tracker.save
36 38 # workflow copy
37 39 if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from]))
38 40 @tracker.workflows.copy(copy_from)
39 41 end
40 42 flash[:notice] = l(:notice_successful_create)
41 43 redirect_to :action => 'list'
42 44 return
43 45 end
44 46 @trackers = Tracker.find :all, :order => 'position'
45 47 @projects = Project.find(:all)
46 48 end
47 49
48 50 def edit
49 51 @tracker = Tracker.find(params[:id])
50 52 if request.post? and @tracker.update_attributes(params[:tracker])
51 53 flash[:notice] = l(:notice_successful_update)
52 54 redirect_to :action => 'list'
53 55 return
54 56 end
55 57 @projects = Project.find(:all)
56 58 end
57 59
58 60 def destroy
59 61 @tracker = Tracker.find(params[:id])
60 62 unless @tracker.issues.empty?
61 63 flash[:error] = "This tracker contains issues and can\'t be deleted."
62 64 else
63 65 @tracker.destroy
64 66 end
65 67 redirect_to :action => 'list'
66 68 end
67 69 end
@@ -1,140 +1,143
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2009 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 class UsersController < ApplicationController
19 layout 'admin'
20
19 21 before_filter :require_admin, :except => :show
20 22
21 23 helper :sort
22 24 include SortHelper
23 25 helper :custom_fields
24 26 include CustomFieldsHelper
25 27
26 28 def index
27 29 sort_init 'login', 'asc'
28 30 sort_update %w(login firstname lastname mail admin created_on last_login_on)
29 31
30 32 @status = params[:status] ? params[:status].to_i : 1
31 33 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
32 34
33 35 unless params[:name].blank?
34 36 name = "%#{params[:name].strip.downcase}%"
35 37 c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?", name, name, name, name]
36 38 end
37 39
38 40 @user_count = User.count(:conditions => c.conditions)
39 41 @user_pages = Paginator.new self, @user_count,
40 42 per_page_option,
41 43 params['page']
42 44 @users = User.find :all,:order => sort_clause,
43 45 :conditions => c.conditions,
44 46 :limit => @user_pages.items_per_page,
45 47 :offset => @user_pages.current.offset
46 48
47 49 render :layout => !request.xhr?
48 50 end
49 51
50 52 def show
51 53 @user = User.active.find(params[:id])
52 54 @custom_values = @user.custom_values
53 55
54 56 # show only public projects and private projects that the logged in user is also a member of
55 57 @memberships = @user.memberships.select do |membership|
56 58 membership.project.is_public? || (User.current.member_of?(membership.project))
57 59 end
58 60
59 61 events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
60 62 @events_by_day = events.group_by(&:event_date)
61 63
62 64 if @user != User.current && !User.current.admin? && @memberships.empty? && events.empty?
63 65 render_404 and return
64 66 end
67 render :layout => 'base'
65 68
66 69 rescue ActiveRecord::RecordNotFound
67 70 render_404
68 71 end
69 72
70 73 def add
71 74 if request.get?
72 75 @user = User.new(:language => Setting.default_language)
73 76 else
74 77 @user = User.new(params[:user])
75 78 @user.admin = params[:user][:admin] || false
76 79 @user.login = params[:user][:login]
77 80 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless @user.auth_source_id
78 81 if @user.save
79 82 Mailer.deliver_account_information(@user, params[:password]) if params[:send_information]
80 83 flash[:notice] = l(:notice_successful_create)
81 84 redirect_to :controller => 'users', :action => 'edit', :id => @user
82 85 end
83 86 end
84 87 @auth_sources = AuthSource.find(:all)
85 88 end
86 89
87 90 def edit
88 91 @user = User.find(params[:id])
89 92 if request.post?
90 93 @user.admin = params[:user][:admin] if params[:user][:admin]
91 94 @user.login = params[:user][:login] if params[:user][:login]
92 95 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless params[:password].nil? or params[:password].empty? or @user.auth_source_id
93 96 @user.group_ids = params[:user][:group_ids] if params[:user][:group_ids]
94 97 @user.attributes = params[:user]
95 98 # Was the account actived ? (do it before User#save clears the change)
96 99 was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
97 100 if @user.save
98 101 if was_activated
99 102 Mailer.deliver_account_activated(@user)
100 103 elsif @user.active? && params[:send_information] && !params[:password].blank? && @user.auth_source_id.nil?
101 104 Mailer.deliver_account_information(@user, params[:password])
102 105 end
103 106 flash[:notice] = l(:notice_successful_update)
104 107 redirect_to :back
105 108 end
106 109 end
107 110 @auth_sources = AuthSource.find(:all)
108 111 @membership ||= Member.new
109 112 rescue ::ActionController::RedirectBackError
110 113 redirect_to :controller => 'users', :action => 'edit', :id => @user
111 114 end
112 115
113 116 def edit_membership
114 117 @user = User.find(params[:id])
115 118 @membership = params[:membership_id] ? Member.find(params[:membership_id]) : Member.new(:principal => @user)
116 119 @membership.attributes = params[:membership]
117 120 @membership.save if request.post?
118 121 respond_to do |format|
119 122 format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
120 123 format.js {
121 124 render(:update) {|page|
122 125 page.replace_html "tab-content-memberships", :partial => 'users/memberships'
123 126 page.visual_effect(:highlight, "member-#{@membership.id}")
124 127 }
125 128 }
126 129 end
127 130 end
128 131
129 132 def destroy_membership
130 133 @user = User.find(params[:id])
131 134 @membership = Member.find(params[:membership_id])
132 135 if request.post? && @membership.deletable?
133 136 @membership.destroy
134 137 end
135 138 respond_to do |format|
136 139 format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
137 140 format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'users/memberships'} }
138 141 end
139 142 end
140 143 end
@@ -1,68 +1,70
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2008 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 class WorkflowsController < ApplicationController
19 layout 'admin'
20
19 21 before_filter :require_admin
20 22
21 23 def index
22 24 @workflow_counts = Workflow.count_by_tracker_and_role
23 25 end
24 26
25 27 def edit
26 28 @role = Role.find_by_id(params[:role_id])
27 29 @tracker = Tracker.find_by_id(params[:tracker_id])
28 30
29 31 if request.post?
30 32 Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id])
31 33 (params[:issue_status] || []).each { |old, news|
32 34 news.each { |new|
33 35 @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new)
34 36 }
35 37 }
36 38 if @role.save
37 39 flash[:notice] = l(:notice_successful_update)
38 40 redirect_to :action => 'edit', :role_id => @role, :tracker_id => @tracker
39 41 end
40 42 end
41 43 @roles = Role.find(:all, :order => 'builtin, position')
42 44 @trackers = Tracker.find(:all, :order => 'position')
43 45 @statuses = IssueStatus.find(:all, :order => 'position')
44 46 end
45 47
46 48 def copy
47 49 @trackers = Tracker.find(:all, :order => 'position')
48 50 @roles = Role.find(:all, :order => 'builtin, position')
49 51
50 52 @source_tracker = params[:source_tracker_id].blank? ? nil : Tracker.find_by_id(params[:source_tracker_id])
51 53 @source_role = params[:source_role_id].blank? ? nil : Role.find_by_id(params[:source_role_id])
52 54
53 55 @target_trackers = params[:target_tracker_ids].blank? ? nil : Tracker.find_all_by_id(params[:target_tracker_ids])
54 56 @target_roles = params[:target_role_ids].blank? ? nil : Role.find_all_by_id(params[:target_role_ids])
55 57
56 58 if request.post?
57 59 if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?)
58 60 flash.now[:error] = l(:error_workflow_copy_source)
59 61 elsif @target_trackers.nil? || @target_roles.nil?
60 62 flash.now[:error] = l(:error_workflow_copy_target)
61 63 else
62 64 Workflow.copy(@source_tracker, @source_role, @target_trackers, @target_roles)
63 65 flash[:notice] = l(:notice_successful_update)
64 66 redirect_to :action => 'copy', :source_tracker_id => @source_tracker, :source_role_id => @source_role
65 67 end
66 68 end
67 69 end
68 70 end
@@ -1,25 +1,19
1 <div id="menuAdmin" class="menu" onmouseover="menuMouseover(event)">
2 <a class="menuItem" href="#" onmouseover="menuItemMouseover(event,'menuProjects');" onclick="this.blur(); return false;"><span class="menuItemText"><%=l(:label_project_plural)%></span><span class="menuItemArrow">&#9654;</span></a>
3 <a class="menuItem" href="#" onmouseover="menuItemMouseover(event,'menuUsers');" onclick="this.blur(); return false;"><span class="menuItemText"><%=l(:label_user_plural)%></span><span class="menuItemArrow">&#9654;</span></a>
4 <%= link_to l(:label_role_and_permissions), {:controller => 'roles' }, :class => "menuItem" %>
5 <a class="menuItem" href="#" onmouseover="menuItemMouseover(event,'menuTrackers');" onclick="this.blur(); return false;"><span class="menuItemText"><%=l(:label_issue_tracking)%></span><span class="menuItemArrow">&#9654;</span></a>
6 <%= link_to l(:label_custom_field_plural), {:controller => 'custom_fields' }, :class => "menuItem" %>
7 <%= link_to l(:label_enumerations), {:controller => 'enumerations' }, :class => "menuItem" %>
8 <%= link_to l(:field_mail_notification), {:controller => 'admin', :action => 'mail_options' }, :class => "menuItem" %>
9 <%= link_to l(:label_authentication), {:controller => 'auth_sources' }, :class => "menuItem" %>
10 <%= link_to l(:label_settings), {:controller => 'settings' }, :class => "menuItem" %>
11 <%= link_to l(:label_information_plural), {:controller => 'admin', :action => 'info' }, :class => "menuItem" %>
12 </div>
13 <div id="menuTrackers" class="menu">
14 <%= link_to l(:label_tracker_plural), {:controller => 'trackers' }, :class => "menuItem" %>
15 <%= link_to l(:label_issue_status_plural), {:controller => 'issue_statuses' }, :class => "menuItem" %>
16 <%= link_to l(:label_workflow), {:controller => 'roles', :action => 'workflow' }, :class => "menuItem" %>
17 </div>
18 <div id="menuProjects" class="menu">
19 <%= link_to l(:button_list), {:controller => 'admin', :action => 'projects' }, :class => "menuItem" %>
20 <%= link_to l(:label_new), {:controller => 'projects', :action => 'add' }, :class => "menuItem" %>
21 </div>
22 <div id="menuUsers" class="menu">
23 <%= link_to l(:button_list), {:controller => 'users' }, :class => "menuItem" %>
24 <%= link_to l(:label_new), {:controller => 'users', :action => 'add' }, :class => "menuItem" %>
1 <div id="admin-menu">
2 <ul>
3 <li><%= link_to l(:label_project_plural), {:controller => 'admin', :action => 'projects'}, :class => 'projects' %></li>
4 <li><%= link_to l(:label_user_plural), {:controller => 'users'}, :class => 'users' %></li>
5 <li><%= link_to l(:label_group_plural), {:controller => 'groups'}, :class => 'groups' %></li>
6 <li><%= link_to l(:label_role_and_permissions), {:controller => 'roles'}, :class => 'roles' %></li>
7 <li><%= link_to l(:label_tracker_plural), {:controller => 'trackers'}, :class => 'trackers' %></li>
8 <li><%= link_to l(:label_issue_status_plural), {:controller => 'issue_statuses'}, :class => 'issue_statuses' %></li>
9 <li><%= link_to l(:label_workflow), {:controller => 'workflows', :action => 'edit'}, :class => 'workflows' %></li>
10 <li><%= link_to l(:label_custom_field_plural), {:controller => 'custom_fields'}, :class => 'custom_fields' %></li>
11 <li><%= link_to l(:label_enumerations), {:controller => 'enumerations'}, :class => 'enumerations' %></li>
12 <li><%= link_to l(:label_settings), {:controller => 'settings'}, :class => 'settings' %></li>
13 <% menu_items_for(:admin_menu) do |item| -%>
14 <li><%= link_to h(item.caption), item.url, item.html_options %></li>
15 <% end -%>
16 <li><%= link_to l(:label_plugins), {:controller => 'admin', :action => 'plugins'}, :class => 'plugins' %></li>
17 <li><%= link_to l(:label_information_plural), {:controller => 'admin', :action => 'info'}, :class => 'info' %></li>
18 </ul>
25 19 </div>
@@ -1,56 +1,8
1 1 <h2><%=l(:label_administration)%></h2>
2 2
3 <div id="admin-index">
3 4 <%= render :partial => 'no_data' if @no_configuration_data %>
4
5 <p class="icon22 icon22-projects">
6 <%= link_to l(:label_project_plural), :controller => 'admin', :action => 'projects' %> |
7 <%= link_to l(:label_new), :controller => 'projects', :action => 'add' %>
8 </p>
9
10 <p class="icon22 icon22-users">
11 <%= link_to l(:label_user_plural), :controller => 'users' %> |
12 <%= link_to l(:label_new), :controller => 'users', :action => 'add' %>
13 </p>
14
15 <p class="icon22 icon22-groups">
16 <%= link_to l(:label_group_plural), :controller => 'groups' %> |
17 <%= link_to l(:label_new), :controller => 'groups', :action => 'new' %>
18 </p>
19
20 <p class="icon22 icon22-role">
21 <%= link_to l(:label_role_and_permissions), :controller => 'roles' %>
22 </p>
23
24 <p class="icon22 icon22-tracker">
25 <%= link_to l(:label_tracker_plural), :controller => 'trackers' %> |
26 <%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses' %> |
27 <%= link_to l(:label_workflow), :controller => 'workflows', :action => 'edit' %>
28 </p>
29
30 <p class="icon22 icon22-workflow">
31 <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields' %>
32 </p>
33
34 <p class="icon22 icon22-options">
35 <%= link_to l(:label_enumerations), :controller => 'enumerations' %>
36 </p>
37
38 <p class="icon22 icon22-settings">
39 <%= link_to l(:label_settings), :controller => 'settings' %>
40 </p>
41
42 <% menu_items_for(:admin_menu) do |item| -%>
43 <%= content_tag 'p',
44 link_to(h(item.caption), item.url, item.html_options),
45 :class => ["icon22", "icon22-#{item.name}"].join(' ') %>
46 <% end -%>
47
48 <p class="icon22 icon22-plugin">
49 <%= link_to l(:label_plugins), :controller => 'admin', :action => 'plugins' %>
50 </p>
51
52 <p class="icon22 icon22-info">
53 <%= link_to l(:label_information_plural), :controller => 'admin', :action => 'info' %>
54 </p>
5 <%= render :partial => 'menu' %>
6 </div>
55 7
56 8 <% html_title(l(:label_administration)) -%>
1 NO CONTENT: modified file, binary diff hidden
1 NO CONTENT: modified file, binary diff hidden
@@ -1,844 +1,861
1 1 body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; }
2 2
3 3 h1, h2, h3, h4 { font-family: "Trebuchet MS", Verdana, sans-serif;}
4 4 h1 {margin:0; padding:0; font-size: 24px;}
5 5 h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
6 6 h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
7 7 h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;}
8 8
9 9 /***** Layout *****/
10 10 #wrapper {background: white;}
11 11
12 12 #top-menu {background: #2C4056; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}
13 13 #top-menu ul {margin: 0; padding: 0;}
14 14 #top-menu li {
15 15 float:left;
16 16 list-style-type:none;
17 17 margin: 0px 0px 0px 0px;
18 18 padding: 0px 0px 0px 0px;
19 19 white-space:nowrap;
20 20 }
21 21 #top-menu a {color: #fff; margin-right: 8px; font-weight: bold;}
22 22 #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
23 23
24 24 #account {float:right;}
25 25
26 26 #header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;}
27 27 #header a {color:#f8f8f8;}
28 28 #header h1 a.ancestor { font-size: 80%; }
29 29 #quick-search {float:right;}
30 30
31 31 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;}
32 32 #main-menu ul {margin: 0; padding: 0;}
33 33 #main-menu li {
34 34 float:left;
35 35 list-style-type:none;
36 36 margin: 0px 2px 0px 0px;
37 37 padding: 0px 0px 0px 0px;
38 38 white-space:nowrap;
39 39 }
40 40 #main-menu li a {
41 41 display: block;
42 42 color: #fff;
43 43 text-decoration: none;
44 44 font-weight: bold;
45 45 margin: 0;
46 46 padding: 4px 10px 4px 10px;
47 47 }
48 48 #main-menu li a:hover {background:#759FCF; color:#fff;}
49 49 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
50 50
51 #admin-menu ul {margin: 0; padding: 0;}
52 #admin-menu li {margin: 0; padding: 0 0 12px 0; list-style-type:none;}
53
54 #admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;}
55 #admin-menu a.projects { background-image: url(../images/projects.png); }
56 #admin-menu a.users { background-image: url(../images/user.png); }
57 #admin-menu a.groups { background-image: url(../images/group.png); }
58 #admin-menu a.roles { background-image: url(../images/database_key.png); }
59 #admin-menu a.trackers { background-image: url(../images/ticket.png); }
60 #admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); }
61 #admin-menu a.workflows { background-image: url(../images/ticket_go.png); }
62 #admin-menu a.custom_fields { background-image: url(../images/textfield.png); }
63 #admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); }
64 #admin-menu a.settings { background-image: url(../images/changeset.png); }
65 #admin-menu a.plugins { background-image: url(../images/plugin.png); }
66 #admin-menu a.info { background-image: url(../images/help.png); }
67
51 68 #main {background-color:#EEEEEE;}
52 69
53 70 #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;}
54 71 * html #sidebar{ width: 17%; }
55 72 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
56 73 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
57 74 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
58 75
59 76 #content { width: 80%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
60 77 * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
61 78 html>body #content { min-height: 600px; }
62 79 * html body #content { height: 600px; } /* IE */
63 80
64 81 #main.nosidebar #sidebar{ display: none; }
65 82 #main.nosidebar #content{ width: auto; border-right: 0; }
66 83
67 84 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
68 85
69 86 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
70 87 #login-form table td {padding: 6px;}
71 88 #login-form label {font-weight: bold;}
72 89 #login-form input#username, #login-form input#password { width: 300px; }
73 90
74 91 input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; }
75 92
76 93 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
77 94
78 95 /***** Links *****/
79 96 a, a:link, a:visited{ color: #2A5685; text-decoration: none; }
80 97 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
81 98 a img{ border: 0; }
82 99
83 100 a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; }
84 101
85 102 /***** Tables *****/
86 103 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
87 104 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
88 105 table.list td { vertical-align: top; }
89 106 table.list td.id { width: 2%; text-align: center;}
90 107 table.list td.checkbox { width: 15px; padding: 0px;}
91 108 table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; }
92 109 table.list td.buttons a { padding-right: 0.6em; }
93 110
94 111 tr.project td.name a { padding-left: 16px; white-space:nowrap; }
95 112 tr.project.parent td.name a { background: url('../images/bullet_toggle_minus.png') no-repeat; }
96 113
97 114 tr.issue { text-align: center; white-space: nowrap; }
98 115 tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }
99 116 tr.issue td.subject { text-align: left; }
100 117 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
101 118
102 119 tr.entry { border: 1px solid #f8f8f8; }
103 120 tr.entry td { white-space: nowrap; }
104 121 tr.entry td.filename { width: 30%; }
105 122 tr.entry td.size { text-align: right; font-size: 90%; }
106 123 tr.entry td.revision, tr.entry td.author { text-align: center; }
107 124 tr.entry td.age { text-align: right; }
108 125 tr.entry.file td.filename a { margin-left: 16px; }
109 126
110 127 tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
111 128 tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
112 129
113 130 tr.changeset td.author { text-align: center; width: 15%; }
114 131 tr.changeset td.committed_on { text-align: center; width: 15%; }
115 132
116 133 table.files tr.file td { text-align: center; }
117 134 table.files tr.file td.filename { text-align: left; padding-left: 24px; }
118 135 table.files tr.file td.digest { font-size: 80%; }
119 136
120 137 table.members td.roles, table.memberships td.roles { width: 45%; }
121 138
122 139 tr.message { height: 2.6em; }
123 140 tr.message td.last_message { font-size: 80%; }
124 141 tr.message.locked td.subject a { background-image: url(../images/locked.png); }
125 142 tr.message.sticky td.subject a { background-image: url(../images/sticky.png); font-weight: bold; }
126 143
127 144 tr.version.closed, tr.version.closed a { color: #999; }
128 145 tr.version td.name { padding-left: 20px; }
129 146 tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; }
130 147 tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; }
131 148
132 149 tr.user td { width:13%; }
133 150 tr.user td.email { width:18%; }
134 151 tr.user td { white-space: nowrap; }
135 152 tr.user.locked, tr.user.registered { color: #aaa; }
136 153 tr.user.locked a, tr.user.registered a { color: #aaa; }
137 154
138 155 tr.time-entry { text-align: center; white-space: nowrap; }
139 156 tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; }
140 157 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
141 158 td.hours .hours-dec { font-size: 0.9em; }
142 159
143 160 table.plugins td { vertical-align: middle; }
144 161 table.plugins td.configure { text-align: right; padding-right: 1em; }
145 162 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
146 163 table.plugins span.description { display: block; font-size: 0.9em; }
147 164 table.plugins span.url { display: block; font-size: 0.9em; }
148 165
149 166 table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; }
150 167 table.list tbody tr.group span.count { color: #aaa; font-size: 80%; }
151 168
152 169 table.list tbody tr:hover { background-color:#ffffdd; }
153 170 table.list tbody tr.group:hover { background-color:inherit; }
154 171 table td {padding:2px;}
155 172 table p {margin:0;}
156 173 .odd {background-color:#f6f7f8;}
157 174 .even {background-color: #fff;}
158 175
159 176 a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; }
160 177 a.sort.asc { background-image: url(../images/sort_asc.png); }
161 178 a.sort.desc { background-image: url(../images/sort_desc.png); }
162 179
163 180 table.attributes { width: 100% }
164 181 table.attributes th { vertical-align: top; text-align: left; }
165 182 table.attributes td { vertical-align: top; }
166 183
167 184 td.center {text-align:center;}
168 185
169 186 .highlight { background-color: #FCFD8D;}
170 187 .highlight.token-1 { background-color: #faa;}
171 188 .highlight.token-2 { background-color: #afa;}
172 189 .highlight.token-3 { background-color: #aaf;}
173 190
174 191 .box{
175 192 padding:6px;
176 193 margin-bottom: 10px;
177 194 background-color:#f6f6f6;
178 195 color:#505050;
179 196 line-height:1.5em;
180 197 border: 1px solid #e4e4e4;
181 198 }
182 199
183 200 div.square {
184 201 border: 1px solid #999;
185 202 float: left;
186 203 margin: .3em .4em 0 .4em;
187 204 overflow: hidden;
188 205 width: .6em; height: .6em;
189 206 }
190 207 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
191 208 .contextual input, .contextual select {font-size:0.9em;}
192 209 .message .contextual { margin-top: 0; }
193 210
194 211 .splitcontentleft{float:left; width:49%;}
195 212 .splitcontentright{float:right; width:49%;}
196 213 form {display: inline;}
197 214 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
198 215 fieldset {border: 1px solid #e4e4e4; margin:0;}
199 216 legend {color: #484848;}
200 217 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
201 218 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
202 219 blockquote blockquote { margin-left: 0;}
203 220 acronym { border-bottom: 1px dotted; cursor: help; }
204 221 textarea.wiki-edit { width: 99%; }
205 222 li p {margin-top: 0;}
206 223 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
207 224 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
208 225 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
209 226 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
210 227
211 228 fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; }
212 229 fieldset.collapsible legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; }
213 230 fieldset.collapsible.collapsed legend { background-image: url(../images/arrow_collapsed.png); }
214 231
215 232 fieldset#date-range p { margin: 2px 0 2px 0; }
216 233 fieldset#filters table { border-collapse: collapse; }
217 234 fieldset#filters table td { padding: 0; vertical-align: middle; }
218 235 fieldset#filters tr.filter { height: 2em; }
219 236 fieldset#filters td.add-filter { text-align: right; vertical-align: top; }
220 237 .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; }
221 238
222 239 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
223 240 div#issue-changesets .changeset { padding: 4px;}
224 241 div#issue-changesets .changeset { border-bottom: 1px solid #ddd; }
225 242 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
226 243
227 244 div#activity dl, #search-results { margin-left: 2em; }
228 245 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
229 246 div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }
230 247 div#activity dt.me .time { border-bottom: 1px solid #999; }
231 248 div#activity dt .time { color: #777; font-size: 80%; }
232 249 div#activity dd .description, #search-results dd .description { font-style: italic; }
233 250 div#activity span.project:after, #search-results span.project:after { content: " -"; }
234 251 div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; }
235 252
236 253 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
237 254
238 255 div#search-results-counts {float:right;}
239 256 div#search-results-counts ul { margin-top: 0.5em; }
240 257 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
241 258
242 259 dt.issue { background-image: url(../images/ticket.png); }
243 260 dt.issue-edit { background-image: url(../images/ticket_edit.png); }
244 261 dt.issue-closed { background-image: url(../images/ticket_checked.png); }
245 262 dt.issue-note { background-image: url(../images/ticket_note.png); }
246 263 dt.changeset { background-image: url(../images/changeset.png); }
247 264 dt.news { background-image: url(../images/news.png); }
248 265 dt.message { background-image: url(../images/message.png); }
249 266 dt.reply { background-image: url(../images/comments.png); }
250 267 dt.wiki-page { background-image: url(../images/wiki_edit.png); }
251 268 dt.attachment { background-image: url(../images/attachment.png); }
252 269 dt.document { background-image: url(../images/document.png); }
253 270 dt.project { background-image: url(../images/projects.png); }
254 271 dt.time-entry { background-image: url(../images/time.png); }
255 272
256 273 #search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); }
257 274
258 275 div#roadmap fieldset.related-issues { margin-bottom: 1em; }
259 276 div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; }
260 277 div#roadmap .wiki h1:first-child { display: none; }
261 278 div#roadmap .wiki h1 { font-size: 120%; }
262 279 div#roadmap .wiki h2 { font-size: 110%; }
263 280
264 281 div#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
265 282 div#version-summary fieldset { margin-bottom: 1em; }
266 283 div#version-summary .total-hours { text-align: right; }
267 284
268 285 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
269 286 table#time-report tbody tr { font-style: italic; color: #777; }
270 287 table#time-report tbody tr.last-level { font-style: normal; color: #555; }
271 288 table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; }
272 289 table#time-report .hours-dec { font-size: 0.9em; }
273 290
274 291 form#issue-form .attributes { margin-bottom: 8px; }
275 292 form#issue-form .attributes p { padding-top: 1px; padding-bottom: 2px; }
276 293 form#issue-form .attributes select { min-width: 30%; }
277 294
278 295 ul.projects { margin: 0; padding-left: 1em; }
279 296 ul.projects.root { margin: 0; padding: 0; }
280 297 ul.projects ul { border-left: 3px solid #e0e0e0; }
281 298 ul.projects li { list-style-type:none; }
282 299 ul.projects li.root { margin-bottom: 1em; }
283 300 ul.projects li.child { margin-top: 1em;}
284 301 ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }
285 302 .my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; }
286 303
287 304 #tracker_project_ids ul { margin: 0; padding-left: 1em; }
288 305 #tracker_project_ids li { list-style-type:none; }
289 306
290 307 ul.properties {padding:0; font-size: 0.9em; color: #777;}
291 308 ul.properties li {list-style-type:none;}
292 309 ul.properties li span {font-style:italic;}
293 310
294 311 .total-hours { font-size: 110%; font-weight: bold; }
295 312 .total-hours span.hours-int { font-size: 120%; }
296 313
297 314 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
298 315 #user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }
299 316
300 317 #workflow_copy_form select { width: 200px; }
301 318
302 319 .pagination {font-size: 90%}
303 320 p.pagination {margin-top:8px;}
304 321
305 322 /***** Tabular forms ******/
306 323 .tabular p{
307 324 margin: 0;
308 325 padding: 5px 0 8px 0;
309 326 padding-left: 180px; /*width of left column containing the label elements*/
310 327 height: 1%;
311 328 clear:left;
312 329 }
313 330
314 331 html>body .tabular p {overflow:hidden;}
315 332
316 333 .tabular label{
317 334 font-weight: bold;
318 335 float: left;
319 336 text-align: right;
320 337 margin-left: -180px; /*width of left column*/
321 338 width: 175px; /*width of labels. Should be smaller than left column to create some right
322 339 margin*/
323 340 }
324 341
325 342 .tabular label.floating{
326 343 font-weight: normal;
327 344 margin-left: 0px;
328 345 text-align: left;
329 346 width: 270px;
330 347 }
331 348
332 349 .tabular label.block{
333 350 font-weight: normal;
334 351 margin-left: 0px !important;
335 352 text-align: left;
336 353 float: none;
337 354 display: block;
338 355 width: auto;
339 356 }
340 357
341 358 input#time_entry_comments { width: 90%;}
342 359
343 360 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
344 361
345 362 .tabular.settings p{ padding-left: 300px; }
346 363 .tabular.settings label{ margin-left: -300px; width: 295px; }
347 364
348 365 .required {color: #bb0000;}
349 366 .summary {font-style: italic;}
350 367
351 368 #attachments_fields input[type=text] {margin-left: 8px; }
352 369
353 370 div.attachments { margin-top: 12px; }
354 371 div.attachments p { margin:4px 0 2px 0; }
355 372 div.attachments img { vertical-align: middle; }
356 373 div.attachments span.author { font-size: 0.9em; color: #888; }
357 374
358 375 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
359 376 .other-formats span + span:before { content: "| "; }
360 377
361 378 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
362 379
363 380 /* Project members tab */
364 381 div#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% }
365 382 div#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% }
366 383 div#tab-content-members fieldset, div#tab-content-memberships fieldset, div#tab-content-users fieldset { padding:1em; margin-bottom: 1em; }
367 384 div#tab-content-members fieldset legend, div#tab-content-memberships fieldset legend, div#tab-content-users fieldset legend { font-weight: bold; }
368 385 div#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; }
369 386 div#tab-content-members fieldset div, div#tab-content-users fieldset div { max-height: 400px; overflow:auto; }
370 387
371 388 table.members td.group { padding-left: 20px; background: url(../images/users.png) no-repeat 0% 0%; }
372 389
373 390 * html div#tab-content-members fieldset div { height: 450px; }
374 391
375 392 /***** Flash & error messages ****/
376 393 #errorExplanation, div.flash, .nodata, .warning {
377 394 padding: 4px 4px 4px 30px;
378 395 margin-bottom: 12px;
379 396 font-size: 1.1em;
380 397 border: 2px solid;
381 398 }
382 399
383 400 div.flash {margin-top: 8px;}
384 401
385 402 div.flash.error, #errorExplanation {
386 403 background: url(../images/false.png) 8px 5px no-repeat;
387 404 background-color: #ffe3e3;
388 405 border-color: #dd0000;
389 406 color: #550000;
390 407 }
391 408
392 409 div.flash.notice {
393 410 background: url(../images/true.png) 8px 5px no-repeat;
394 411 background-color: #dfffdf;
395 412 border-color: #9fcf9f;
396 413 color: #005f00;
397 414 }
398 415
399 416 div.flash.warning {
400 417 background: url(../images/warning.png) 8px 5px no-repeat;
401 418 background-color: #FFEBC1;
402 419 border-color: #FDBF3B;
403 420 color: #A6750C;
404 421 text-align: left;
405 422 }
406 423
407 424 .nodata, .warning {
408 425 text-align: center;
409 426 background-color: #FFEBC1;
410 427 border-color: #FDBF3B;
411 428 color: #A6750C;
412 429 }
413 430
414 431 #errorExplanation ul { font-size: 0.9em;}
415 432 #errorExplanation h2, #errorExplanation p { display: none; }
416 433
417 434 /***** Ajax indicator ******/
418 435 #ajax-indicator {
419 436 position: absolute; /* fixed not supported by IE */
420 437 background-color:#eee;
421 438 border: 1px solid #bbb;
422 439 top:35%;
423 440 left:40%;
424 441 width:20%;
425 442 font-weight:bold;
426 443 text-align:center;
427 444 padding:0.6em;
428 445 z-index:100;
429 446 filter:alpha(opacity=50);
430 447 opacity: 0.5;
431 448 }
432 449
433 450 html>body #ajax-indicator { position: fixed; }
434 451
435 452 #ajax-indicator span {
436 453 background-position: 0% 40%;
437 454 background-repeat: no-repeat;
438 455 background-image: url(../images/loading.gif);
439 456 padding-left: 26px;
440 457 vertical-align: bottom;
441 458 }
442 459
443 460 /***** Calendar *****/
444 461 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
445 462 table.cal thead th {width: 14%;}
446 463 table.cal tbody tr {height: 100px;}
447 464 table.cal th { background-color:#EEEEEE; padding: 4px; }
448 465 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
449 466 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
450 467 table.cal td.odd p.day-num {color: #bbb;}
451 468 table.cal td.today {background:#ffffdd;}
452 469 table.cal td.today p.day-num {font-weight: bold;}
453 470
454 471 /***** Tooltips ******/
455 472 .tooltip{position:relative;z-index:24;}
456 473 .tooltip:hover{z-index:25;color:#000;}
457 474 .tooltip span.tip{display: none; text-align:left;}
458 475
459 476 div.tooltip:hover span.tip{
460 477 display:block;
461 478 position:absolute;
462 479 top:12px; left:24px; width:270px;
463 480 border:1px solid #555;
464 481 background-color:#fff;
465 482 padding: 4px;
466 483 font-size: 0.8em;
467 484 color:#505050;
468 485 }
469 486
470 487 /***** Progress bar *****/
471 488 table.progress {
472 489 border: 1px solid #D7D7D7;
473 490 border-collapse: collapse;
474 491 border-spacing: 0pt;
475 492 empty-cells: show;
476 493 text-align: center;
477 494 float:left;
478 495 margin: 1px 6px 1px 0px;
479 496 }
480 497
481 498 table.progress td { height: 0.9em; }
482 499 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
483 500 table.progress td.done { background: #DEF0DE none repeat scroll 0%; }
484 501 table.progress td.open { background: #FFF none repeat scroll 0%; }
485 502 p.pourcent {font-size: 80%;}
486 503 p.progress-info {clear: left; font-style: italic; font-size: 80%;}
487 504
488 505 /***** Tabs *****/
489 506 #content .tabs {height: 2.6em; border-bottom: 1px solid #bbbbbb; margin-bottom:1.2em; position:relative; overflow:hidden;}
490 507 #content .tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em; width: 2000px;}
491 508 #content .tabs>ul { bottom:-1px; } /* others */
492 509 #content .tabs ul li {
493 510 float:left;
494 511 list-style-type:none;
495 512 white-space:nowrap;
496 513 margin-right:8px;
497 514 background:#fff;
498 515 }
499 516 #content .tabs ul li a{
500 517 display:block;
501 518 font-size: 0.9em;
502 519 text-decoration:none;
503 520 line-height:1.3em;
504 521 padding:4px 6px 4px 6px;
505 522 border: 1px solid #ccc;
506 523 border-bottom: 1px solid #bbbbbb;
507 524 background-color: #eeeeee;
508 525 color:#777;
509 526 font-weight:bold;
510 527 }
511 528
512 529 #content .tabs ul li a:hover {
513 530 background-color: #ffffdd;
514 531 text-decoration:none;
515 532 }
516 533
517 534 #content .tabs ul li a.selected {
518 535 background-color: #fff;
519 536 border: 1px solid #bbbbbb;
520 537 border-bottom: 1px solid #fff;
521 538 }
522 539
523 540 #content .tabs ul li a.selected:hover {
524 541 background-color: #fff;
525 542 }
526 543
527 544 div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: -1px; }
528 545
529 546 button.tab-left, button.tab-right {
530 547 font-size: 0.9em;
531 548 cursor: pointer;
532 549 height:24px;
533 550 border: 1px solid #ccc;
534 551 border-bottom: 1px solid #bbbbbb;
535 552 position:absolute;
536 553 padding:4px;
537 554 width: 20px;
538 555 }
539 556
540 557 button.tab-left {
541 558 right: 20px;
542 559 bottom: 0;
543 560 background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%;
544 561 }
545 562
546 563 button.tab-right {
547 564 right: 0;
548 565 bottom: 0;
549 566 background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%;}
550 567 }
551 568
552 569 /***** Auto-complete *****/
553 570 div.autocomplete {
554 571 position:absolute;
555 572 width:250px;
556 573 background-color:white;
557 574 margin:0;
558 575 padding:0;
559 576 }
560 577 div.autocomplete ul {
561 578 list-style-type:none;
562 579 margin:0;
563 580 padding:0;
564 581 }
565 582 div.autocomplete ul li.selected { background-color: #ffb;}
566 583 div.autocomplete ul li {
567 584 list-style-type:none;
568 585 display:block;
569 586 margin:0;
570 587 padding:2px;
571 588 cursor:pointer;
572 589 font-size: 90%;
573 590 border-bottom: 1px solid #ccc;
574 591 border-left: 1px solid #ccc;
575 592 border-right: 1px solid #ccc;
576 593 }
577 594 div.autocomplete ul li span.informal {
578 595 font-size: 80%;
579 596 color: #aaa;
580 597 }
581 598
582 599 /***** Diff *****/
583 600 .diff_out { background: #fcc; }
584 601 .diff_in { background: #cfc; }
585 602
586 603 /***** Wiki *****/
587 604 div.wiki table {
588 605 border: 1px solid #505050;
589 606 border-collapse: collapse;
590 607 margin-bottom: 1em;
591 608 }
592 609
593 610 div.wiki table, div.wiki td, div.wiki th {
594 611 border: 1px solid #bbb;
595 612 padding: 4px;
596 613 }
597 614
598 615 div.wiki .external {
599 616 background-position: 0% 60%;
600 617 background-repeat: no-repeat;
601 618 padding-left: 12px;
602 619 background-image: url(../images/external.png);
603 620 }
604 621
605 622 div.wiki a.new {
606 623 color: #b73535;
607 624 }
608 625
609 626 div.wiki pre {
610 627 margin: 1em 1em 1em 1.6em;
611 628 padding: 2px;
612 629 background-color: #fafafa;
613 630 border: 1px solid #dadada;
614 631 width:95%;
615 632 overflow-x: auto;
616 633 }
617 634
618 635 div.wiki ul.toc {
619 636 background-color: #ffffdd;
620 637 border: 1px solid #e4e4e4;
621 638 padding: 4px;
622 639 line-height: 1.2em;
623 640 margin-bottom: 12px;
624 641 margin-right: 12px;
625 642 margin-left: 0;
626 643 display: table
627 644 }
628 645 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
629 646
630 647 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
631 648 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
632 649 div.wiki ul.toc li { list-style-type:none;}
633 650 div.wiki ul.toc li.heading2 { margin-left: 6px; }
634 651 div.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }
635 652
636 653 div.wiki ul.toc a {
637 654 font-size: 0.9em;
638 655 font-weight: normal;
639 656 text-decoration: none;
640 657 color: #606060;
641 658 }
642 659 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
643 660
644 661 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
645 662 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
646 663 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
647 664
648 665 /***** My page layout *****/
649 666 .block-receiver {
650 667 border:1px dashed #c0c0c0;
651 668 margin-bottom: 20px;
652 669 padding: 15px 0 15px 0;
653 670 }
654 671
655 672 .mypage-box {
656 673 margin:0 0 20px 0;
657 674 color:#505050;
658 675 line-height:1.5em;
659 676 }
660 677
661 678 .handle {
662 679 cursor: move;
663 680 }
664 681
665 682 a.close-icon {
666 683 display:block;
667 684 margin-top:3px;
668 685 overflow:hidden;
669 686 width:12px;
670 687 height:12px;
671 688 background-repeat: no-repeat;
672 689 cursor:pointer;
673 690 background-image:url('../images/close.png');
674 691 }
675 692
676 693 a.close-icon:hover {
677 694 background-image:url('../images/close_hl.png');
678 695 }
679 696
680 697 /***** Gantt chart *****/
681 698 .gantt_hdr {
682 699 position:absolute;
683 700 top:0;
684 701 height:16px;
685 702 border-top: 1px solid #c0c0c0;
686 703 border-bottom: 1px solid #c0c0c0;
687 704 border-right: 1px solid #c0c0c0;
688 705 text-align: center;
689 706 overflow: hidden;
690 707 }
691 708
692 709 .task {
693 710 position: absolute;
694 711 height:8px;
695 712 font-size:0.8em;
696 713 color:#888;
697 714 padding:0;
698 715 margin:0;
699 716 line-height:0.8em;
700 717 }
701 718
702 719 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
703 720 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
704 721 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
705 722 .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
706 723
707 724 /***** Icons *****/
708 725 .icon {
709 726 background-position: 0% 40%;
710 727 background-repeat: no-repeat;
711 728 padding-left: 20px;
712 729 padding-top: 2px;
713 730 padding-bottom: 3px;
714 731 }
715 732
716 733 .icon22 {
717 734 background-position: 0% 40%;
718 735 background-repeat: no-repeat;
719 736 padding-left: 26px;
720 737 line-height: 22px;
721 738 vertical-align: middle;
722 739 }
723 740
724 741 .icon-add { background-image: url(../images/add.png); }
725 742 .icon-edit { background-image: url(../images/edit.png); }
726 743 .icon-copy { background-image: url(../images/copy.png); }
727 744 .icon-duplicate { background-image: url(../images/duplicate.png); }
728 745 .icon-del { background-image: url(../images/delete.png); }
729 746 .icon-move { background-image: url(../images/move.png); }
730 747 .icon-save { background-image: url(../images/save.png); }
731 748 .icon-cancel { background-image: url(../images/cancel.png); }
732 749 .icon-multiple { background-image: url(../images/table_multiple.png); }
733 750 .icon-folder { background-image: url(../images/folder.png); }
734 751 .open .icon-folder { background-image: url(../images/folder_open.png); }
735 752 .icon-package { background-image: url(../images/package.png); }
736 753 .icon-home { background-image: url(../images/home.png); }
737 754 .icon-user { background-image: url(../images/user.png); }
738 755 .icon-mypage { background-image: url(../images/user_page.png); }
739 756 .icon-admin { background-image: url(../images/admin.png); }
740 757 .icon-projects { background-image: url(../images/projects.png); }
741 758 .icon-help { background-image: url(../images/help.png); }
742 759 .icon-attachment { background-image: url(../images/attachment.png); }
743 760 .icon-index { background-image: url(../images/index.png); }
744 761 .icon-history { background-image: url(../images/history.png); }
745 762 .icon-time { background-image: url(../images/time.png); }
746 763 .icon-time-add { background-image: url(../images/time_add.png); }
747 764 .icon-stats { background-image: url(../images/stats.png); }
748 765 .icon-warning { background-image: url(../images/warning.png); }
749 766 .icon-fav { background-image: url(../images/fav.png); }
750 767 .icon-fav-off { background-image: url(../images/fav_off.png); }
751 768 .icon-reload { background-image: url(../images/reload.png); }
752 769 .icon-lock { background-image: url(../images/locked.png); }
753 770 .icon-unlock { background-image: url(../images/unlock.png); }
754 771 .icon-checked { background-image: url(../images/true.png); }
755 772 .icon-details { background-image: url(../images/zoom_in.png); }
756 773 .icon-report { background-image: url(../images/report.png); }
757 774 .icon-comment { background-image: url(../images/comment.png); }
758 775 .icon-summary { background-image: url(../images/lightning.png); }
759 776
760 777 .icon-file { background-image: url(../images/files/default.png); }
761 778 .icon-file.text-plain { background-image: url(../images/files/text.png); }
762 779 .icon-file.text-x-c { background-image: url(../images/files/c.png); }
763 780 .icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); }
764 781 .icon-file.text-x-php { background-image: url(../images/files/php.png); }
765 782 .icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); }
766 783 .icon-file.text-xml { background-image: url(../images/files/xml.png); }
767 784 .icon-file.image-gif { background-image: url(../images/files/image.png); }
768 785 .icon-file.image-jpeg { background-image: url(../images/files/image.png); }
769 786 .icon-file.image-png { background-image: url(../images/files/image.png); }
770 787 .icon-file.image-tiff { background-image: url(../images/files/image.png); }
771 788 .icon-file.application-pdf { background-image: url(../images/files/pdf.png); }
772 789 .icon-file.application-zip { background-image: url(../images/files/zip.png); }
773 790 .icon-file.application-x-gzip { background-image: url(../images/files/zip.png); }
774 791
775 792 .icon22-projects { background-image: url(../images/22x22/projects.png); }
776 793 .icon22-users { background-image: url(../images/22x22/users.png); }
777 794 .icon22-groups { background-image: url(../images/22x22/groups.png); }
778 795 .icon22-tracker { background-image: url(../images/22x22/tracker.png); }
779 796 .icon22-role { background-image: url(../images/22x22/role.png); }
780 797 .icon22-workflow { background-image: url(../images/22x22/workflow.png); }
781 798 .icon22-options { background-image: url(../images/22x22/options.png); }
782 799 .icon22-notifications { background-image: url(../images/22x22/notifications.png); }
783 800 .icon22-authent { background-image: url(../images/22x22/authent.png); }
784 801 .icon22-info { background-image: url(../images/22x22/info.png); }
785 802 .icon22-comment { background-image: url(../images/22x22/comment.png); }
786 803 .icon22-package { background-image: url(../images/22x22/package.png); }
787 804 .icon22-settings { background-image: url(../images/22x22/settings.png); }
788 805 .icon22-plugin { background-image: url(../images/22x22/plugin.png); }
789 806
790 807 img.gravatar {
791 808 padding: 2px;
792 809 border: solid 1px #d5d5d5;
793 810 background: #fff;
794 811 }
795 812
796 813 div.issue img.gravatar {
797 814 float: right;
798 815 margin: 0 0 0 1em;
799 816 padding: 5px;
800 817 }
801 818
802 819 div.issue table img.gravatar {
803 820 height: 14px;
804 821 width: 14px;
805 822 padding: 2px;
806 823 float: left;
807 824 margin: 0 0.5em 0 0;
808 825 }
809 826
810 827 #history img.gravatar {
811 828 padding: 3px;
812 829 margin: 0 1.5em 1em 0;
813 830 float: left;
814 831 }
815 832
816 833 td.username img.gravatar {
817 834 float: left;
818 835 margin: 0 1em 0 0;
819 836 }
820 837
821 838 #activity dt img.gravatar {
822 839 float: left;
823 840 margin: 0 1em 1em 0;
824 841 }
825 842
826 843 #activity dt,
827 844 .journal {
828 845 clear: left;
829 846 }
830 847
831 848 .gravatar-margin {
832 849 margin-left: 40px;
833 850 }
834 851
835 852 h2 img { vertical-align:middle; }
836 853
837 854
838 855 /***** Media print specific styles *****/
839 856 @media print {
840 857 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
841 858 #main { background: #fff; }
842 859 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}
843 860 #wiki_add_attachment { display:none; }
844 861 }
General Comments 0
You need to be logged in to leave comments. Login now