# HG changeset patch # User Chris Cannam # Date 1295451299 0 # Node ID bf38a7365edfa6d3634c11223558e36bdb429d9e # Parent cede720e8f534fd88cb89c1fecea7166a8f615fe# Parent 6a2f8e88344ebf1e36bec0534350af0ed440e182 Merge fixes for bug #51 and bug #35 from branch "cannam-pre-20110113-merge" diff -r cede720e8f53 -r bf38a7365edf app/controllers/members_controller.rb --- a/app/controllers/members_controller.rb Mon Dec 20 22:15:06 2010 +0000 +++ b/app/controllers/members_controller.rb Wed Jan 19 15:34:59 2011 +0000 @@ -94,6 +94,7 @@ def autocomplete_for_member @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals + logger.debug "Query for #{params[:q]} returned #{@principals.size} results" render :layout => false end diff -r cede720e8f53 -r bf38a7365edf app/controllers/projects_controller.rb --- a/app/controllers/projects_controller.rb Mon Dec 20 22:15:06 2010 +0000 +++ b/app/controllers/projects_controller.rb Wed Jan 19 15:34:59 2011 +0000 @@ -45,12 +45,22 @@ helper :repositories include RepositoriesHelper include ProjectsHelper - + # Lists visible projects def index respond_to do |format| format.html { - @projects = Project.visible.find(:all, :order => 'lft') + sort_init 'lft' + sort_update %w(lft title created_on updated_on) + @limit = per_page_option + @project_count = Project.visible.count + @project_pages = Paginator.new self, @project_count, @limit, params['page'] + @offset ||= @project_pages.current.offset + @projects = Project.visible.all(:offset => @offset, :limit => @limit, :order => sort_clause) + if User.current.logged? + @user_projects = User.current.projects.sort_by(&:lft) + end + render :template => 'projects/index.rhtml', :layout => !request.xhr? } format.xml { @projects = Project.visible.find(:all, :order => 'lft') diff -r cede720e8f53 -r bf38a7365edf app/helpers/application_helper.rb --- a/app/helpers/application_helper.rb Mon Dec 20 22:15:06 2010 +0000 +++ b/app/helpers/application_helper.rb Wed Jan 19 15:34:59 2011 +0000 @@ -273,7 +273,7 @@ def principals_check_box_tags(name, principals) s = '' principals.sort.each do |principal| - s << "\n" + s << "\n" end s end diff -r cede720e8f53 -r bf38a7365edf app/helpers/projects_helper.rb --- a/app/helpers/projects_helper.rb Mon Dec 20 22:15:06 2010 +0000 +++ b/app/helpers/projects_helper.rb Wed Jan 19 15:34:59 2011 +0000 @@ -121,7 +121,12 @@ classes = (ancestors.empty? ? 'root' : 'child') s << "
  • " + - link_to_project(project, {}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}") + link_to_project(project, {}, :class => "project my-project") + if project.is_public? + s << " " << l("field_is_public") << "" + else + s << " " << l("field_is_private") << "" + end s << "
    #{textilizable(project.short_description, :project => project)}
    " unless project.description.blank? s << "
    \n" ancestors << project @@ -143,66 +148,93 @@ a end - # Renders a tree of projects where the current DOES NOT belong - # as a nested set of unordered lists - # The given collection may be a subset of the whole project tree - # (eg. some intermediate nodes are private and can not be seen) - def render_other_project_hierarchy(projects) - a = '' - s = '' + # Renders a tree of projects that the current user does not belong + # to, or of all projects if the current user is not logged in. The + # given collection may be a subset of the whole project tree + # (eg. some intermediate nodes are private and can not be seen). We + # are potentially interested in various things: the project name, + # description, manager(s), creation date, last activity date, + # general activity level, whether there is anything actually hosted + # here for the project, etc. + def render_project_table(projects) - # True if user has any projects (affects the heading used) - t = FALSE + s = "" + s << "
    " + s << "" + s << "" + + s << sort_header_tag('lft', :caption => l("field_name"), :default_order => 'desc') + s << "" + s << sort_header_tag('created_on', :default_order => 'desc') + s << sort_header_tag('updated_on', :default_order => 'desc') - if projects.any? - ancestors = [] - original_project = @project - projects.each do |project| - # set the project environment to please macros. + s << "" - @project = project + ancestors = [] + original_project = @project + oddeven = 'even' + level = 0 - if not User.current.member_of?(project): + projects.each do |project| - if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) - s << "\n" + # set the project environment to please macros. + + @project = project + + if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) + level = level + 1 + else + level = 0 + oddeven = cycle('odd','even') + ancestors.pop + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + ancestors.pop + end + end + + classes = (ancestors.empty? ? 'root' : 'child') + + s << "" + s << "" + s << "" + s << "" + s << "" - s << ("\n" * ancestors.size) - @project = original_project + s << "" + s << "" + s << "" + s << "" + s << "" + + ancestors << project end - if t == TRUE - a << "

    " - a << l("label_other_project_plural") - a << "

    " - a << s - else - a << "

    " - a << l("label_project_all") - a << "

    " - a << s - end + s << "
    " << l("label_managers") << "
    " << link_to_project(project, {}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}") << "" + + u = project.users_by_role + if u + u.keys.each do |r| + if r.allowed_to?(:edit_project) + mgrs = [] + u[r].sort.each do |m| + mgrs << link_to_user(m) + end + if mgrs.size < 3 + s << '' << mgrs.join(', ') << '' + else + s << mgrs.join(', ') end end + end + end - classes = (ancestors.empty? ? 'root' : 'child') - s << "
  • " + - link_to_project(project, {}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}") - s << "
    #{textilizable(project.short_description, :project => project)}
    " unless project.description.blank? - s << "
    \n" - ancestors << project - else - t = TRUE - end - end + s << "
  • " << format_date(project.created_on) << "" << format_date(project.updated_on) << "
    " + s << textilizable(project.short_description, :project => project) unless project.description.blank? + s << " 
    " - a + @project = original_project + + s end diff -r cede720e8f53 -r bf38a7365edf app/models/project.rb --- a/app/models/project.rb Mon Dec 20 22:15:06 2010 +0000 +++ b/app/models/project.rb Wed Jan 19 15:34:59 2011 +0000 @@ -418,7 +418,14 @@ # Returns a short description of the projects (first lines) def short_description(length = 255) - description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description + ## Original Redmine code: this truncates to the CR that is more + ## than "length" characters from the start. + # description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description + ## That's too much for us, and also we want to omit images and the + ## like. Truncate instead to the first CR that follows _any_ + ## non-blank text, and to the next word break beyond "length" + ## characters if the result is still longer than that. + description.gsub(/![^\s]+!/, '').gsub(/^(\s*[^\n\r]*).*$/m, '\1').gsub(/^(.{#{length}}\b).*$/m, '\1 ...').strip if description end def css_classes diff -r cede720e8f53 -r bf38a7365edf app/views/members/autocomplete_for_member.rhtml --- a/app/views/members/autocomplete_for_member.rhtml Mon Dec 20 22:15:06 2010 +0000 +++ b/app/views/members/autocomplete_for_member.rhtml Wed Jan 19 15:34:59 2011 +0000 @@ -1,1 +1,3 @@ -<%= principals_check_box_tags 'member[user_ids][]', @principals %> \ No newline at end of file +<% if params[:q] && params[:q].length > 1 %> +<%= principals_check_box_tags 'member[user_ids][]', @principals %> +<% end %> diff -r cede720e8f53 -r bf38a7365edf app/views/projects/index.rhtml --- a/app/views/projects/index.rhtml Mon Dec 20 22:15:06 2010 +0000 +++ b/app/views/projects/index.rhtml Wed Jan 19 15:34:59 2011 +0000 @@ -8,18 +8,19 @@ <%= '| ' + link_to(l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add') if User.current.allowed_to?(:add_project, nil, :global => true) %>
    -<% if User.current.logged? %> +<% if @user_projects %> - <%= render_my_project_hierarchy(@projects)%> + <%= render_my_project_hierarchy(@user_projects)%> - <%= render_other_project_hierarchy(@projects)%> - -<% else %> - -

    <%=l(:label_project_plural)%>

    - <%= render_project_hierarchy(@projects)%> <% end %> +

    +<%= l("label_project_all") %> +

    + +<%= render_project_table(@projects) %> + +

    <%= pagination_links_full @project_pages, @project_count %>

    <% other_formats_links do |f| %> diff -r cede720e8f53 -r bf38a7365edf app/views/projects/settings/_members.rhtml --- a/app/views/projects/settings/_members.rhtml Mon Dec 20 22:15:06 2010 +0000 +++ b/app/views/projects/settings/_members.rhtml Wed Jan 19 15:34:59 2011 +0000 @@ -50,7 +50,7 @@ -<% principals = Principal.active.find(:all, :limit => 10, :order => 'type, login, lastname ASC') - @project.principals %> +<% principals = Principal.active.find(:all, :limit => 100, :order => 'type, login, lastname ASC') - @project.principals %>
    <% if roles.any? && principals.any? %> @@ -66,9 +66,11 @@ :url => { :controller => 'members', :action => 'autocomplete_for_member', :id => @project }, :with => 'q') %> - +
    - <%= principals_check_box_tags 'member[user_ids][]', principals %> + <% if params[:q] && params[:q].length > 1 %> + <%= principals_check_box_tags 'member[user_ids][]', @principals %> + <% end %>

    <%= l(:label_role_plural) %>: diff -r cede720e8f53 -r bf38a7365edf app/views/projects/settings/_repository.rhtml --- a/app/views/projects/settings/_repository.rhtml Mon Dec 20 22:15:06 2010 +0000 +++ b/app/views/projects/settings/_repository.rhtml Wed Jan 19 15:34:59 2011 +0000 @@ -7,7 +7,7 @@

    <% if !@repository || !@repository.url %> -
    • The repository for a project will normally be set up automatically within a few minutes of the project being created.
    +
    • <%= l(:text_settings_repo_creation) %>
    <% end %>

    <%= label_tag('repository_scm', l(:label_scm)) %><%= scm_select_tag(@repository) %>

    <%= repository_field_tags(f, @repository) if @repository %> diff -r cede720e8f53 -r bf38a7365edf config/locales/en-GB.yml --- a/config/locales/en-GB.yml Mon Dec 20 22:15:06 2010 +0000 +++ b/config/locales/en-GB.yml Wed Jan 19 15:34:59 2011 +0000 @@ -237,6 +237,7 @@ field_role: Role field_homepage: Homepage field_is_public: Public + field_is_private: Private field_parent: Subproject of field_is_in_roadmap: Issues displayed in roadmap field_login: Login @@ -430,6 +431,7 @@ other: "{{count}} projects" label_project_all: All Projects label_project_latest: Latest projects + label_managers: Managed by label_issue: Issue label_issue_new: New issue label_issue_plural: Issues @@ -841,6 +843,7 @@ text_tip_issue_end_day: task ending this day text_tip_issue_begin_end_day: task beginning and ending this day text_project_identifier_info: 'Only lower case letters (a-z), numbers and dashes are allowed.
    This will be used in all project-related URLs, and as the repository name. Once saved, the identifier can not be changed.' + text_project_homepage_info: 'Link to an external project page.' text_project_name_info: "This will be the name of your project throughout this site.
    You can change your project's name at any time, in the project's settings." text_project_visibility_info: "If your project is not public, it will only be visible to users that you have added as project members." text_user_ssamr_description_info: 'Please describe your current research or development interests, within the fields of audio and music.
    This information is publicly visible in your profile and you can edit it at any time.
    It may also be used to establish eligibility for your initial registration.' @@ -885,6 +888,7 @@ text_wiki_page_destroy_children: "Delete child pages and all their descendants" text_wiki_page_reassign_children: "Reassign child pages to this parent page" text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" + text_settings_repo_creation: The repository for a project should be set up automatically within a few minutes of the project being created.
    You should not have to adjust any settings here; please check again in ten minutes. default_role_manager: Manager default_role_developer: Developer @@ -943,7 +947,7 @@ label_user_mail_option_only_my_events: Only for things I watch or I'm involved in label_user_mail_option_only_assigned: Only for things I am assigned to notice_not_authorized_archived_project: The project you're trying to access has been archived. - label_principal_search: "Search for user or group:" + label_principal_search: "Search by name:" label_user_search: "Search for user:" field_visible: Visible setting_emails_header: Emails header diff -r cede720e8f53 -r bf38a7365edf config/locales/en.yml --- a/config/locales/en.yml Mon Dec 20 22:15:06 2010 +0000 +++ b/config/locales/en.yml Wed Jan 19 15:34:59 2011 +0000 @@ -242,6 +242,7 @@ field_role: Role field_homepage: Homepage field_is_public: Public + field_is_private: Private field_parent: Subproject of field_is_in_roadmap: Issues displayed in roadmap field_login: Login @@ -444,6 +445,7 @@ other: "{{count}} projects" label_project_all: All Projects label_project_latest: Latest projects + label_managers: Managed by label_issue: Issue label_issue_new: New issue label_issue_plural: Issues @@ -793,7 +795,7 @@ label_profile: Profile label_subtask_plural: Subtasks label_project_copy_notifications: Send email notifications during the project copy - label_principal_search: "Search for user or group:" + label_principal_search: "Search by name:" label_user_search: "Search for user:" button_login: Login @@ -914,6 +916,7 @@ text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" text_zoom_in: Zoom in text_zoom_out: Zoom out + text_settings_repo_creation: The repository for a project should be set up automatically within a few minutes of the project being created.
    You should not have to adjust any settings here.
    Please check again in ten minutes, and contact us if there is any problem. default_role_manager: Manager default_role_developer: Developer diff -r cede720e8f53 -r bf38a7365edf public/themes/soundsoftware/stylesheets/application.css --- a/public/themes/soundsoftware/stylesheets/application.css Mon Dec 20 22:15:06 2010 +0000 +++ b/public/themes/soundsoftware/stylesheets/application.css Wed Jan 19 15:34:59 2011 +0000 @@ -67,6 +67,17 @@ tr.entry { border-left: 1px solid #a9b680; border-right: 1px solid #a9b680; } tr.entry:last-child { border-bottom: 1px solid #a9b680; } +table.projects th { text-align: left; } +table.projects th.managers { color: #3e442c; } +table.projects .hosted_here { font-weight: bold; } +table.projects .child .name { font-weight: normal; } +table.projects .child .description { font-size: 0.95em; } +table.projects .child .firstcol { padding-left: 1em } +table.projects .level2 .firstcol { padding-left: 2em; } +table.projects .level3 .firstcol { padding-left: 3em; } + +ul.projects .public, ul.projects .private { padding-left: 0.5em; color: #3e442c; font-size: 0.95em } + #top-menu { position: absolute; top: 0; z-index: 1; left: 0px; width: 100%; font-size: 90%; /* height: 2em; */ margin: 0; padding: 0; padding-top: 0.5em; background-color: #3e442c; } #top-menu ul { margin-left: 10px; } #top-menu a { font-weight: bold; }