Revision 1078:b9e34a051f82 app
| app/controllers/activities_controller.rb | ||
|---|---|---|
| 40 | 40 |
|
| 41 | 41 |
events = @activity.events(@date_from, @date_to) |
| 42 | 42 |
|
| 43 |
if events.empty? || stale?(:etag => [@activity.scope, @date_to, @date_from, @with_subprojects, @author, events.first, User.current, current_language]) |
|
| 43 |
@institution_name = params[:institution] |
|
| 44 |
if !@institution_name.blank? |
|
| 45 |
events = events.select do |e| |
|
| 46 |
e.respond_to?(:event_author) and e.event_author and |
|
| 47 |
e.event_author.respond_to?(:ssamr_user_detail) and |
|
| 48 |
!e.event_author.ssamr_user_detail.nil? and |
|
| 49 |
e.event_author.ssamr_user_detail.institution_name == @institution_name |
|
| 50 |
end |
|
| 51 |
if events.empty? |
|
| 52 |
# We don't want to dump into the output any arbitrary string |
|
| 53 |
# from the URL that has no matching events |
|
| 54 |
@institution_name = "" |
|
| 55 |
end |
|
| 56 |
end |
|
| 57 |
|
|
| 58 |
if events.empty? || stale?(:etag => [@activity.scope, @date_to, @date_from, @with_subprojects, @author, @institution_name, events.first, User.current, current_language]) |
|
| 44 | 59 |
respond_to do |format| |
| 45 | 60 |
format.html {
|
| 46 | 61 |
@events_by_day = events.group_by(&:event_date) |
| app/controllers/attachments_controller.rb | ||
|---|---|---|
| 17 | 17 |
|
| 18 | 18 |
class AttachmentsController < ApplicationController |
| 19 | 19 |
|
| 20 |
include AttachmentsHelper |
|
| 21 |
helper :attachments |
|
| 22 |
|
|
| 20 | 23 |
before_filter :find_project |
| 21 | 24 |
before_filter :file_readable, :read_authorize, :except => :destroy |
| 22 | 25 |
before_filter :delete_authorize, :only => :destroy |
| ... | ... | |
| 49 | 52 |
end |
| 50 | 53 |
|
| 51 | 54 |
def download |
| 52 |
if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project) |
|
| 55 |
# cc: formerly this happened only if "@attachment.container.is_a?(Version)" |
|
| 56 |
# or Project. Not good for us, we want to tally all downloads [by humans] |
|
| 57 |
if not user_is_search_bot? |
|
| 53 | 58 |
@attachment.increment_download |
| 54 | 59 |
end |
| 55 | 60 |
|
| app/controllers/projects_controller.rb | ||
|---|---|---|
| 20 | 20 |
menu_item :roadmap, :only => :roadmap |
| 21 | 21 |
menu_item :settings, :only => :settings |
| 22 | 22 |
|
| 23 |
before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ] |
|
| 24 |
before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy] |
|
| 23 |
before_filter :find_project, :except => [ :index, :list, :explore, :new, :create, :copy ]
|
|
| 24 |
before_filter :authorize, :except => [ :index, :list, :explore, :new, :create, :copy, :archive, :unarchive, :destroy]
|
|
| 25 | 25 |
before_filter :authorize_global, :only => [:new, :create] |
| 26 | 26 |
before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ] |
| 27 | 27 |
accept_rss_auth :index |
| ... | ... | |
| 43 | 43 |
helper :repositories |
| 44 | 44 |
include RepositoriesHelper |
| 45 | 45 |
include ProjectsHelper |
| 46 |
include ActivitiesHelper |
|
| 47 |
helper :activities |
|
| 46 | 48 |
|
| 47 | 49 |
# Lists visible projects. Paginator is for top-level projects only |
| 48 | 50 |
# (subprojects belong to them) |
| ... | ... | |
| 76 | 78 |
end |
| 77 | 79 |
end |
| 78 | 80 |
|
| 81 |
# A different view of projects using explore boxes |
|
| 82 |
def explore |
|
| 83 |
respond_to do |format| |
|
| 84 |
format.html {
|
|
| 85 |
@projects = Project.visible |
|
| 86 |
render :template => 'projects/explore.html.erb', :layout => !request.xhr? |
|
| 87 |
} |
|
| 88 |
end |
|
| 89 |
end |
|
| 90 |
|
|
| 79 | 91 |
def new |
| 80 | 92 |
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
| 81 | 93 |
@trackers = Tracker.all |
| ... | ... | |
| 99 | 111 |
end |
| 100 | 112 |
# end of code to be removed |
| 101 | 113 |
|
| 102 |
|
|
| 103 |
if validate_parent_id && @project.save |
|
| 114 |
if validate_is_public_key && validate_parent_id && @project.save |
|
| 104 | 115 |
@project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
|
| 105 | 116 |
# Add current user as a project member if he is not admin |
| 106 | 117 |
unless User.current.admin? |
| ... | ... | |
| 288 | 299 |
render_404 |
| 289 | 300 |
end |
| 290 | 301 |
|
| 302 |
def validate_is_public_key |
|
| 303 |
# Although is_public isn't mandatory in the project model (it gets |
|
| 304 |
# defaulted), it must be present in params -- it can be true or |
|
| 305 |
# false, but it must be there. This permits us to make forms in |
|
| 306 |
# which the user _has_ to select public or private (rather than |
|
| 307 |
# defaulting it) if we want to |
|
| 308 |
if params.nil? || params[:project].nil? || !params[:project].has_key?(:is_public) |
|
| 309 |
@project.errors.add :is_public, :public_or_private |
|
| 310 |
return false |
|
| 311 |
end |
|
| 312 |
true |
|
| 313 |
end |
|
| 314 |
|
|
| 291 | 315 |
# Validates parent_id param according to user's permissions |
| 292 | 316 |
# TODO: move it to Project model in a validation that depends on User.current |
| 293 | 317 |
def validate_parent_id |
| app/controllers/welcome_controller.rb | ||
|---|---|---|
| 25 | 25 |
@site_project = Project.find_by_identifier "soundsoftware-site" |
| 26 | 26 |
@site_news = [] |
| 27 | 27 |
@site_news = News.latest_for @site_project if @site_project |
| 28 |
@projects = Project.latest User.current |
|
| 29 | 28 |
|
| 30 | 29 |
# tests if user is logged in to generate the tips of the day list |
| 31 | 30 |
if User.current.logged? |
| app/helpers/activities_helper.rb | ||
|---|---|---|
| 1 |
|
|
| 2 |
module ActivitiesHelper |
|
| 3 |
|
|
| 4 |
def busy_projects(events, count) |
|
| 5 |
# Transform events list into hash from project id to number of |
|
| 6 |
# occurrences of project in list (there is surely a tidier way |
|
| 7 |
# to do this, e.g. chunk() in Ruby 1.9 but not in 1.8) |
|
| 8 |
phash = events.map { |e| e.project unless !e.respond_to?(:project) }.sort.group_by { |p| p.id }
|
|
| 9 |
phash = phash.merge(phash) { |k,v| v.length }
|
|
| 10 |
threshold = phash.values.sort.last(count).first |
|
| 11 |
busy = phash.keys.select { |k| phash[k] >= threshold }.sample(count)
|
|
| 12 |
busy.map { |pid| Project.find(pid) }
|
|
| 13 |
end |
|
| 14 |
|
|
| 15 |
def busy_institutions(events, count) |
|
| 16 |
authors = events.map do |e| |
|
| 17 |
e.event_author unless !e.respond_to?(:event_author) |
|
| 18 |
end.compact |
|
| 19 |
institutions = authors.map do |a| |
|
| 20 |
if a.respond_to?(:ssamr_user_detail) and !a.ssamr_user_detail.nil? |
|
| 21 |
a.ssamr_user_detail.institution_name |
|
| 22 |
end |
|
| 23 |
end |
|
| 24 |
insthash = institutions.compact.sort.group_by { |i| i }
|
|
| 25 |
insthash = insthash.merge(insthash) { |k,v| v.length }
|
|
| 26 |
threshold = insthash.values.sort.last(count).first |
|
| 27 |
insthash.keys.select { |k| insthash[k] >= threshold }.sample(count)
|
|
| 28 |
end |
|
| 29 |
|
|
| 30 |
end |
|
| app/helpers/attachments_helper.rb | ||
|---|---|---|
| 42 | 42 |
api.created_on attachment.created_on |
| 43 | 43 |
end |
| 44 | 44 |
end |
| 45 |
|
|
| 46 |
# Returns true if user agent appears (approximately) to be a search |
|
| 47 |
# bot or crawler |
|
| 48 |
def user_is_search_bot? |
|
| 49 |
agent = request.env['HTTP_USER_AGENT'] |
|
| 50 |
agent and agent =~ /(bot|slurp|crawler|spider)\b/i |
|
| 51 |
end |
|
| 45 | 52 |
end |
| app/helpers/projects_helper.rb | ||
|---|---|---|
| 162 | 162 |
|
| 163 | 163 |
end |
| 164 | 164 |
|
| 165 |
# Renders a tree of projects that the current user does not belong |
|
| 166 |
# to, or of all projects if the current user is not logged in. The |
|
| 167 |
# given collection may be a subset of the whole project tree |
|
| 168 |
# (eg. some intermediate nodes are private and can not be seen). We |
|
| 169 |
# are potentially interested in various things: the project name, |
|
| 170 |
# description, manager(s), creation date, last activity date, |
|
| 171 |
# general activity level, whether there is anything actually hosted |
|
| 172 |
# here for the project, etc. |
|
| 165 |
# Renders a tree of projects. The given collection may be a subset |
|
| 166 |
# of the whole project tree (eg. some intermediate nodes are private |
|
| 167 |
# and can not be seen). We are potentially interested in various |
|
| 168 |
# things: the project name, description, manager(s), creation date, |
|
| 169 |
# last activity date, general activity level, whether there is |
|
| 170 |
# anything actually hosted here for the project, etc. |
|
| 173 | 171 |
def render_project_table(projects) |
| 174 | 172 |
|
| 175 | 173 |
s = "" |
| app/views/activities/_busy.html.erb | ||
|---|---|---|
| 1 |
<% events = @events_by_day %> |
|
| 2 |
<% if (events.nil?) |
|
| 3 |
activity = Redmine::Activity::Fetcher.new(User.anonymous) |
|
| 4 |
events = activity.events(Date.today - 14, Date.today + 1) |
|
| 5 |
end |
|
| 6 |
%> |
|
| 7 |
|
|
| 8 |
<% if events.empty? %> |
|
| 9 |
|
|
| 10 |
<% else %> |
|
| 11 |
|
|
| 12 |
<ul> |
|
| 13 |
|
|
| 14 |
<% |
|
| 15 |
for project in busy_projects(events, 5) |
|
| 16 |
%> |
|
| 17 |
|
|
| 18 |
<li class="busy"> |
|
| 19 |
<span class="title"> |
|
| 20 |
<% if !project.root? %> |
|
| 21 |
<% project.ancestors.each do |p| %> |
|
| 22 |
<%= h(p) %> » |
|
| 23 |
<% end %> |
|
| 24 |
<% end %> |
|
| 25 |
<%= link_to_project project %> |
|
| 26 |
</span> |
|
| 27 |
<% if !project.is_public? %> |
|
| 28 |
<span class="private"><%= l(:field_is_private) %></span> |
|
| 29 |
<% end %> |
|
| 30 |
<span class='managers'> |
|
| 31 |
<% |
|
| 32 |
u = project.users_by_role |
|
| 33 |
if ! u.empty? %> |
|
| 34 |
(<%= |
|
| 35 |
mgmt_roles = u.keys.select{ |r| r.allowed_to?(:edit_project) }
|
|
| 36 |
managers = mgmt_roles.map{ |r| u[r] }.flatten.sort.uniq
|
|
| 37 |
managers.map{ |m| m.name }.join(', ')
|
|
| 38 |
%>)<% |
|
| 39 |
end |
|
| 40 |
%> |
|
| 41 |
</span> |
|
| 42 |
|
|
| 43 |
<%= render_project_short_description project %> |
|
| 44 |
</li> |
|
| 45 |
|
|
| 46 |
<% end %> |
|
| 47 |
</ul> |
|
| 48 |
<% end %> |
|
| app/views/activities/_busy_institution.html.erb | ||
|---|---|---|
| 1 |
<% events = @events_by_day %> |
|
| 2 |
<% if (events.nil?) |
|
| 3 |
activity = Redmine::Activity::Fetcher.new(User.anonymous) |
|
| 4 |
days = Setting.activity_days_default.to_i |
|
| 5 |
events = activity.events(Date.today - days, Date.today + 1) |
|
| 6 |
end |
|
| 7 |
%> |
|
| 8 |
|
|
| 9 |
<% if events.empty? %> |
|
| 10 |
|
|
| 11 |
<% else %> |
|
| 12 |
|
|
| 13 |
<ul> |
|
| 14 |
|
|
| 15 |
<% |
|
| 16 |
for institution in busy_institutions(events, 5) |
|
| 17 |
%> |
|
| 18 |
|
|
| 19 |
<li class="busy"> |
|
| 20 |
<span class="title"> |
|
| 21 |
<%= link_to h(institution), { :controller => 'activities', :institution => institution } %>
|
|
| 22 |
</span> |
|
| 23 |
</li> |
|
| 24 |
|
|
| 25 |
<% end %> |
|
| 26 |
</ul> |
|
| 27 |
<% end %> |
|
| 28 |
|
|
| app/views/activities/index.html.erb | ||
|---|---|---|
| 1 |
<h2><%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)) %></h2> |
|
| 1 |
<h2><%= |
|
| 2 |
if @author.nil? |
|
| 3 |
if @institution_name.blank? |
|
| 4 |
l(:label_activity) |
|
| 5 |
else |
|
| 6 |
l(:label_institution_activity, h(@institution_name)) |
|
| 7 |
end |
|
| 8 |
else |
|
| 9 |
l(:label_user_activity, link_to_user(@author)) |
|
| 10 |
end |
|
| 11 |
%></h2> |
|
| 2 | 12 |
<p class="subtitle"><%= l(:label_date_from_to, :start => format_date(@date_to - @days), :end => format_date(@date_to-1)) %></p> |
| 3 | 13 |
|
| 4 | 14 |
<div id="activity"> |
| app/views/attachments/_form.html.erb | ||
|---|---|---|
| 2 | 2 |
<span> |
| 3 | 3 |
<%= file_field_tag 'attachments[1][file]', :size => 30, :id => nil, :class => 'file', |
| 4 | 4 |
:onchange => "checkFileSize(this, #{Setting.attachment_max_size.to_i.kilobytes}, '#{escape_javascript(l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)))}');" -%>
|
| 5 |
<label class="inline"><%= l(:label_optional_description) %><%= text_field_tag 'attachments[1][description]', '', :size => 60, :id => nil, :class => 'description' %></label> |
|
| 6 |
<%= link_to_function(image_tag('delete.png'), 'removeFileField(this)', :title => (l(:button_delete))) %>
|
|
| 5 |
<nobr><label class="inline"><%= l(:label_optional_description) %><%= text_field_tag 'attachments[1][description]', '', :size => 60, :id => nil, :class => 'description' %></label>
|
|
| 6 |
<%= link_to_function(image_tag('delete.png'), 'removeFileField(this)', :title => (l(:button_delete))) %></nobr>
|
|
| 7 | 7 |
</span> |
| 8 | 8 |
</span> |
| 9 |
<small><%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;' %> |
|
| 9 |
<br><small><%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;' %>
|
|
| 10 | 10 |
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>) |
| 11 | 11 |
</small> |
| app/views/attachments/_links.html.erb | ||
|---|---|---|
| 2 | 2 |
<% for attachment in attachments %> |
| 3 | 3 |
<p><%= link_to_attachment attachment, :class => 'icon icon-attachment' -%> |
| 4 | 4 |
<%= h(" - #{attachment.description}") unless attachment.description.blank? %>
|
| 5 |
<span class="size">(<%= number_to_human_size attachment.filesize %>)</span>
|
|
| 5 |
<span class="size_and_count"><%= number_to_human_size attachment.filesize %><%= ", " + l(:label_x_downloads, :count => attachment.downloads) unless attachment.downloads == 0 %></span>
|
|
| 6 | 6 |
<% if options[:deletable] %> |
| 7 | 7 |
<%= link_to image_tag('delete.png'), attachment_path(attachment),
|
| 8 | 8 |
:confirm => l(:text_are_you_sure), |
| app/views/projects/_form.html.erb | ||
|---|---|---|
| 21 | 21 |
<br /> |
| 22 | 22 |
<em> <%= l(:text_project_homepage_info) %></em> |
| 23 | 23 |
</p> |
| 24 |
<p><%= f.check_box :is_public %> |
|
| 24 |
<p> |
|
| 25 |
<%= label(:project, :is_public_1, l(:field_public_or_private) + content_tag("span", " *", :class => "required")) %>
|
|
| 26 |
<% |
|
| 27 |
# if the project hasn't been created fully yet, then we don't |
|
| 28 |
# want to set either public or private (make the user decide) |
|
| 29 |
initialised = !@project.id.nil? |
|
| 30 |
%> |
|
| 31 |
<%= f.radio_button :is_public, 1, :checked => (initialised && @project.is_public?) %> |
|
| 32 |
<%= l(:text_project_public_info) %> |
|
| 25 | 33 |
<br /> |
| 26 |
<em> <%= l(:text_project_visibility_info) %></em> |
|
| 34 |
<%= f.radio_button :is_public, 0, :checked => (initialised && !@project.is_public?) %> |
|
| 35 |
<%= l(:text_project_private_info) %> |
|
| 36 |
<br> |
|
| 37 |
<em><%= l(:text_project_visibility_info) %></em> |
|
| 27 | 38 |
</p> |
| 28 | 39 |
<%= wikitoolbar_for 'project_description' %> |
| 29 | 40 |
|
| app/views/projects/_latest.html.erb | ||
|---|---|---|
| 1 |
<ul> |
|
| 2 |
<% for project in Project.latest(User.current) %> |
|
| 3 |
<li class="latest"> |
|
| 4 |
<span class="title"> |
|
| 5 |
<% if !project.root? %> |
|
| 6 |
<% project.ancestors.each do |p| %> |
|
| 7 |
<%= h(p) %> » |
|
| 8 |
<% end %> |
|
| 9 |
<% end %> |
|
| 10 |
<%= link_to_project project %> |
|
| 11 |
</span> |
|
| 12 |
<% if !project.is_public? %> |
|
| 13 |
<span class="private"><%= l(:field_is_private) %></span> |
|
| 14 |
<% end %> |
|
| 15 |
<span class="time"><%= format_time(project.created_on)%></span> |
|
| 16 |
<%= render_project_short_description project %> |
|
| 17 |
</li> |
|
| 18 |
<% end %> |
|
| 19 |
</ul> |
|
| app/views/projects/_members_box.html.erb | ||
|---|---|---|
| 1 | 1 |
<% if @users_by_role.any? %> |
| 2 |
<div class="members box">
|
|
| 2 |
<div id="memberbox"><div class="box">
|
|
| 3 | 3 |
<h3><%=l(:label_member_plural)%></h3> |
| 4 | 4 |
<p><% @users_by_role.keys.sort.each do |role| %> |
| 5 | 5 |
<%=h role %>: <%= @users_by_role[role].sort.collect{|u| link_to_user u}.join(", ") %><br />
|
| 6 | 6 |
<% end %></p> |
| 7 |
</div> |
|
| 7 |
</div></div>
|
|
| 8 | 8 |
<% end %> |
| app/views/projects/explore.html.erb | ||
|---|---|---|
| 1 |
<% content_for :header_tags do %> |
|
| 2 |
<%= stylesheet_link_tag 'redmine_tags', :plugin => 'redmine_tags' %> |
|
| 3 |
<% end %> |
|
| 4 |
|
|
| 5 |
<% cache(:action => 'explore', :action_suffix => 'tags', :expires_in => 1.hour) do %> |
|
| 6 |
<h2><%= l(:label_explore_projects) %></h2> |
|
| 7 |
<div class="tags box"> |
|
| 8 |
<h3><%=l(:label_project_tags_all)%></h3> |
|
| 9 |
<%= render :partial => 'projects/tagcloud' %> |
|
| 10 |
</div> |
|
| 11 |
<% end %> |
|
| 12 |
|
|
| 13 |
<div class="splitcontentleft"> |
|
| 14 |
<% cache(:action => 'explore', :action_suffix => 'busy_institutions', :expires_in => 1.hour) do %> |
|
| 15 |
<div class="institutions box"> |
|
| 16 |
<h3><%=l(:label_institutions_busy)%></h3> |
|
| 17 |
<%= render :partial => 'activities/busy_institution' %> |
|
| 18 |
</div> |
|
| 19 |
<% end %> |
|
| 20 |
<div class="projects box"> |
|
| 21 |
<h3><%=l(:label_project_latest)%></h3> |
|
| 22 |
<%= render :partial => 'projects/latest' %> |
|
| 23 |
</div> |
|
| 24 |
</div> |
|
| 25 |
<div class="splitcontentright"> |
|
| 26 |
<% cache(:action => 'explore', :action_suffix => 'busy_projects', :expires_in => 1.hour) do %> |
|
| 27 |
<div class="projects box"> |
|
| 28 |
<h3><%=l(:label_projects_busy)%></h3> |
|
| 29 |
<%= render :partial => 'activities/busy' %> |
|
| 30 |
</div> |
|
| 31 |
<% end %> |
|
| 32 |
</div> |
|
| app/views/projects/new.html.erb | ||
|---|---|---|
| 3 | 3 |
<% labelled_tabular_form_for @project do |f| %> |
| 4 | 4 |
<%= render :partial => 'form', :locals => { :f => f } %>
|
| 5 | 5 |
<%= submit_tag l(:button_create) %> |
| 6 |
<%= submit_tag l(:button_create_and_continue), :name => 'continue' %> |
|
| 7 | 6 |
<%= javascript_tag "Form.Element.focus('project_name');" %>
|
| 8 | 7 |
<% end %> |
| app/views/welcome/index.html.erb | ||
|---|---|---|
| 14 | 14 |
|
| 15 | 15 |
<div class="splitcontentright"> |
| 16 | 16 |
<% if @site_news.any? %> |
| 17 |
<div class="news box"> |
|
| 18 |
<h3><%=l(:label_news_site_latest)%></h3>
|
|
| 17 |
<div class="news box">
|
|
| 18 |
<h3><%=l(:label_news_site_latest)%></h3>
|
|
| 19 | 19 |
<%= render :partial => 'news/news', :locals => { :project => @site_project }, :collection => @site_news %>
|
| 20 |
|
|
| 21 | 20 |
<%= link_to l(:label_news_more), { :controller => 'projects', :action => @site_project.identifier, :id => 'news' } %>
|
| 22 | 21 |
</div> |
| 23 | 22 |
<% end %> |
| 24 |
<% if @projects.any? %> |
|
| 25 | 23 |
<div class="projects box"> |
| 26 | 24 |
<h3><%=l(:label_project_latest)%></h3> |
| 27 |
<ul> |
|
| 28 |
<% for project in @projects %> |
|
| 29 |
<% @project = project %> |
|
| 30 |
<li class="latest"> |
|
| 31 |
<span class="title"> |
|
| 32 |
<% if !project.root? %> |
|
| 33 |
<% project.ancestors.each do |p| %> |
|
| 34 |
<%= h(p) %> » |
|
| 35 |
<% end %> |
|
| 36 |
<% end %> |
|
| 37 |
<%= link_to_project project %> |
|
| 38 |
</span> |
|
| 39 |
<% if !project.is_public? %> |
|
| 40 |
<span class="private"><%= l(:field_is_private) %></span> |
|
| 41 |
<% end %> |
|
| 42 |
<span class="time"><%= format_time(project.created_on)%></span> |
|
| 43 |
<%= render_project_short_description project %> |
|
| 44 |
</li> |
|
| 45 |
<% end %> |
|
| 46 |
<% @project = nil %> |
|
| 47 |
</ul> |
|
| 48 |
<%= link_to l(:label_projects_more), :controller => 'projects' %> |
|
| 25 |
<%= render :partial => 'projects/latest' %> |
|
| 26 |
<%= link_to l(:label_projects_more), :controller => 'projects' %> |
|
| 49 | 27 |
</div> |
| 50 |
<% end %> |
|
| 51 | 28 |
<%= call_hook(:view_welcome_index_right, :projects => @projects) %> |
| 52 | 29 |
</div> |
| 53 | 30 |
|
Also available in: Unified diff