OSDN Git Service

Dashboard perfomance improved. Filter for projects page
authorDmitriy Zaporozhets <dzaporozhets@sphereconsultinginc.com>
Tue, 20 Dec 2011 06:24:14 +0000 (08:24 +0200)
committerDmitriy Zaporozhets <dzaporozhets@sphereconsultinginc.com>
Tue, 20 Dec 2011 06:24:14 +0000 (08:24 +0200)
16 files changed:
README.md
app/assets/javascripts/application.js
app/assets/javascripts/commits.js
app/assets/javascripts/projects.js
app/assets/stylesheets/projects.css.scss
app/controllers/dashboard_controller.rb
app/controllers/projects_controller.rb
app/models/merge_request.rb
app/models/project.rb
app/views/dashboard/_sidebar.html.haml
app/views/merge_requests/_commits.html.haml
app/views/merge_requests/_diffs.html.haml
app/views/projects/_tile.html.haml
app/views/projects/index.html.haml
app/views/projects/index.js.haml [new file with mode: 0644]
config/initializers/rails_footnotes.rb

index ff81ede..2287d48 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,9 +3,6 @@
 GitLab is a free Project/Repository management application
 
 
-<img src="http://gitlabhq.com/front.png" width="900" height="471">
-
-
 ## Application details
 
 rails 3.1
index 93dbd7d..04d4f0b 100644 (file)
@@ -16,7 +16,7 @@
 //= require branch-graph
 //= require_tree .
 
-$(function(){
+$(document).ready(function(){
   $(".one_click_select").live("click", function(){
     $(this).select();
   });
@@ -27,8 +27,50 @@ $(function(){
   $(".account-box").mouseenter(showMenu);
   $(".account-box").mouseleave(resetMenu);
 
+  $("#projects-list .project").live('click', function(e){
+    if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
+      location.href = $(this).attr("url");
+      e.stopPropagation();
+      return false;
+    }
+  });
+
+  $("#issues-table .issue").live('click', function(e){
+    if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
+      location.href = $(this).attr("url");
+      e.stopPropagation();
+      return false;
+    }
+  });
+
+  $(document).keypress(function(e) {
+    if( $(e.target).is(":input") ) return;
+    switch(e.which)  {
+      case 115:  focusSearch();
+        e.preventDefault();
+    }
+  });
+
 });
 
+function focusSearch() {
+  $("#search").focus();
+}
+
+function taggifyForm(){
+  var tag_field = $('#tag_field').tagify();
+
+  tag_field.tagify('inputField').autocomplete({
+      source: '/tags.json'
+  });
+
+  $('form').submit( function() {
+    var tag_field = $('#tag_field')
+       tag_field.val( tag_field.tagify('serialize') );
+       return true;
+  });
+}
+
 function updatePage(data){
   $.ajax({type: "GET", url: location.href, data: data, dataType: "script"});
 }
index 6e5b210..bb06df5 100644 (file)
@@ -1,55 +1,52 @@
-$(document).ready(function(){
-  $(".day-commits-table li.commit").live('click', function(e){
-    if(e.target.nodeName != "A") {
-      location.href = $(this).attr("url");
-      e.stopPropagation();
-      return false;
-    }
-  });
-});
-
 var CommitsList = {
+  ref:null,
+  limit:0,
+  offset:0,
 
-ref:null,
-limit:0,
-offset:0,
-
-init:
-  function(ref, limit) {
-    this.ref=ref;
-    this.limit=limit;
-    this.offset=limit;
-    this.initLoadMore();
-    $('.loading').show();
-  },
-
-getOld:
-  function() {
-    $('.loading').show();
-    $.ajax({
-      type: "GET",
-      url: location.href,
-      data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref,
-      complete: function(){ $('.loading').hide()},
-      dataType: "script"});
-  },
+  init:
+    function(ref, limit) {
+      $(".day-commits-table li.commit").live('click', function(e){
+        if(e.target.nodeName != "A") {
+          location.href = $(this).attr("url");
+          e.stopPropagation();
+          return false;
+        }
+      });
 
-append:
-  function(count, html) {
-    $("#commits_list").append(html);
-    if(count > 0) {
-      this.offset += count;
+      this.ref=ref;
+      this.limit=limit;
+      this.offset=limit;
       this.initLoadMore();
-    }
-  },
+      $('.loading').show();
+    },
+
+  getOld:
+    function() {
+      $('.loading').show();
+      $.ajax({
+        type: "GET",
+        url: location.href,
+        data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref,
+        complete: function(){ $('.loading').hide()},
+        dataType: "script"});
+    },
 
-initLoadMore:
-  function() {
-    $(window).bind('scroll', function(){
-      if($(window).scrollTop() == $(document).height() - $(window).height()){
-        $(window).unbind('scroll');
-        CommitsList.getOld();
+  append:
+    function(count, html) {
+      $("#commits_list").append(html);
+      if(count > 0) {
+        this.offset += count;
+        this.initLoadMore();
       }
-    });
-  }
+    },
+
+  initLoadMore:
+    function() {
+      $(window).bind('scroll', function(){
+        if($(window).scrollTop() == $(document).height() - $(window).height()){
+          $(window).unbind('scroll');
+          CommitsList.getOld();
+        }
+      });
+    }
 }
index 7d21f06..a80e593 100644 (file)
@@ -1,45 +1,66 @@
-$(document).ready(function(){
-  $("#projects-list .project").live('click', function(e){
-    if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
-      location.href = $(this).attr("url");
-      e.stopPropagation();
-      return false;
-    }
-  });
+var ProjectsList = {
+  limit:0,
+  offset:0,
 
-  $("#issues-table .issue").live('click', function(e){
-    if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
-      location.href = $(this).attr("url");
-      e.stopPropagation();
-      return false;
-    }
-  });
+  init:
+    function(limit) {
+      this.limit=limit;
+      this.offset=limit;
+      this.initLoadMore();
 
-  $(document).keypress(function(e) {
-    if( $(e.target).is(":input") ) return;
-    switch(e.which)  {
-      case 115:  focusSearch();
-        e.preventDefault();
-    }
-  });
+      $('.project_search').keyup(function() {
+        var terms = $(this).val();
+        if (terms.length >= 2 || terms.length == 0) {
+          url = $('.project_search').parent().attr('action');
+          $.ajax({
+            type: "GET",
+            url: location.href,
+            data: { 'terms': terms, 'replace': true  },
+            dataType: "script"
+          });
+        }
+      });
+    },
 
-});
+  getOld:
+    function() {
+      $('.loading').show();
+      $.ajax({
+        type: "GET",
+        url: location.href,
+        data: "limit=" + this.limit + "&offset=" + this.offset,
+        complete: function(){ $('.loading').hide()},
+        dataType: "script"});
+    },
 
-function focusSearch() {
-  $("#search").focus();
-}
+  replace:
+    function(count, html) {
+      $(".tile").html(html);
+      if(count == ProjectsList.limit) {
+        this.offset = count;
+        this.initLoadMore();
+      } else {
+        this.offset = 0;
+      }
+    },
 
-function taggifyForm(){
-  var tag_field = $('#tag_field').tagify();
+  append:
+    function(count, html) {
+      $(".tile").append(html);
+      if(count > 0) {
+        this.offset += count;
+        this.initLoadMore();
+      }
+    },
 
-  tag_field.tagify('inputField').autocomplete({
-      source: '/tags.json'
-  });
-
-  $('form').submit( function() {
-    var tag_field = $('#tag_field')
-       tag_field.val( tag_field.tagify('serialize') );
-       return true;
-  });
+  initLoadMore:
+    function() {
+      $(window).bind('scroll', function(){
+        if($(window).scrollTop() == $(document).height() - $(window).height()){
+          $(window).unbind('scroll');
+          $('.loading').show();
+          ProjectsList.getOld();
+        }
+      });
+    }
 }
-
index 366a0d8..f1b7ac0 100644 (file)
@@ -647,3 +647,9 @@ h4.middle-panel {
   border-radius:3px;
   float:left;
 }
+
+.project_search { 
+  margin: 1.5em 0;
+  padding: 8px !important;
+  width: 300px;
+}
index 959585a..39c7064 100644 (file)
@@ -3,7 +3,7 @@ class DashboardController < ApplicationController
 
   def index
     @projects = current_user.projects.all
-    @active_projects = @projects.select(&:last_activity_date).sort_by(&:last_activity_date).reverse
+    @active_projects = @projects.select(&:last_activity_date_cached).sort_by(&:last_activity_date_cached).reverse
 
     respond_to do |format|
       format.html
index 5f4f252..f0eafee 100644 (file)
@@ -11,9 +11,10 @@ class ProjectsController < ApplicationController
   before_filter :require_non_empty_project, :only => [:blob, :tree, :graph]
 
   def index
-    source = current_user.projects
-    source = source.tagged_with(params[:tag]) unless params[:tag].blank?
-    @projects = source.all
+    @limit, @offset = (params[:limit] || 16), (params[:offset] || 0)
+    @projects = current_user.projects
+    @projects = @projects.where("name LIKE ?", "%#{params[:terms]}%") unless params[:terms].blank?
+    @projects = @projects.limit(@limit).offset(@offset)
   end
 
   def new
index 67f6123..8af4624 100644 (file)
@@ -35,9 +35,8 @@ class MergeRequest < ActiveRecord::Base
   end
 
   def diffs
-    commit = project.commit(source_branch)
     commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)}
-    diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id)
+    diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue []
   end
 
   def last_commit
index d7c9515..4ffb9c4 100644 (file)
@@ -52,6 +52,9 @@ class Project < ActiveRecord::Base
 
   scope :public_only, where(:private_flag => false)
 
+  def self.active
+    joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC")
+  end
 
   def self.access_options
     {
@@ -195,6 +198,24 @@ class Project < ActiveRecord::Base
     last_activity.try(:created_at)
   end
 
+  def last_activity_date_cached(expire = 1.hour)
+    activity_date_key = "project_#{id}_activity_date"
+
+    cached_activities = Rails.cache.read(activity_date_key)
+    if cached_activities
+      activity_date = if cached_activities == "Never"
+                        nil
+                      else
+                        cached_activities
+                      end
+    else
+      activity_date = last_activity_date
+      Rails.cache.write(activity_date_key, activity_date || "Never", :expires_in => expire)
+    end
+
+    activity_date
+  end
+
   # Get project updates from cache
   # or calculate. 
   def cached_updates(limit, expire = 2.minutes)
@@ -204,7 +225,7 @@ class Project < ActiveRecord::Base
       activities = cached_activities
     else
       activities = updates(limit)
-      Rails.cache.write(activities_key, activities, :expires_in => 60.seconds)
+      Rails.cache.write(activities_key, activities, :expires_in => expire)
     end
 
     activities
index 337c154..9f6378b 100644 (file)
@@ -11,5 +11,5 @@
           %span.project-name= project.name
           %span.time
             %strong Last activity:
-            = project.last_activity_date ? time_ago_in_words(project.last_activity_date) + " ago" : "Never"
+            = project.last_activity_date_cached ? time_ago_in_words(project.last_activity_date_cached) + " ago" : "Never"
 
index 508aa23..c0d7486 100644 (file)
@@ -15,3 +15,5 @@
           ago
   .clear
 
+- if @commits.empty? 
+  %p.cgray Nothing to merge
index 2ea6c79..ef6b0f1 100644 (file)
@@ -20,3 +20,5 @@
         %p
           %center No preview for this file type
 
+- if @diffs.empty? 
+  %p.cgray Nothing to merge
index a96e0b6..3bccaaa 100644 (file)
             %input{ :value => project.url_to_repo, :class => ['git-url', 'one_click_select', 'text', 'project_list_url'], :readonly => 'readonly' }
           %p.title.activity
             %span Last Activity:
-            - last_note = project.notes.last
-            = last_note ? last_note.created_at.stamp("24 Aug, 2011") : "Never"
-
-          %p.small-tags= tag_list project
+            - if project.last_activity_date_cached
+              = project.last_activity_date_cached.stamp("24 Aug, 2011")
+            - else 
+              Never
 
         .buttons
           %a.browse-code.button.yellow{:href => tree_project_ref_path(project, project.root_ref)} Browse code
index e5255ae..9cbfd95 100644 (file)
@@ -7,13 +7,23 @@
       %h2.icon
         %span
         Projects
+      %center
+        = form_tag projects_path, :method => :get, :remote => true, :id => "projects_search_form" do
+          = search_field_tag :project_search, nil, { :placeholder => 'Filter projects by name', :class => 'project_search text' }
 
     %div.clear
     - unless @projects.empty?
-      %div{:class => "tile", :style => view_mode_style("tile")}
+      %div{:class => "tile"}
         = render "tile"
-      %div{:class => "list", :style => view_mode_style("list")}
-        = render "list"
+      .clear
+      .loading{ :style => "display:none;"}
+        %center= image_tag "ajax-loader.gif"
+
+      - if @projects.count == @limit
+        :javascript
+          $(function(){
+            ProjectsList.init(16);
+          });
     - else
       %center.prepend-top
         %h2
diff --git a/app/views/projects/index.js.haml b/app/views/projects/index.js.haml
new file mode 100644 (file)
index 0000000..9b99073
--- /dev/null
@@ -0,0 +1,7 @@
+- if params[:replace]
+  :plain
+    ProjectsList.replace(#{@projects.count}, "#{escape_javascript(render(:partial => 'projects/tile'))}");
+- else 
+  :plain
+    ProjectsList.append(#{@projects.count}, "#{escape_javascript(render(:partial => 'projects/tile'))}");
+
index db71e39..afe6f3a 100644 (file)
@@ -1,5 +1,3 @@
 #if defined?(Footnotes) && Rails.env.development?
   #Footnotes.run! # first of all
-
-  # ... other init code
 #end