Dashboard perfomance improved. Filter for projects page

This commit is contained in:
Dmitriy Zaporozhets 2011-12-20 08:24:14 +02:00
parent 6d5c969872
commit cff9519127
16 changed files with 215 additions and 112 deletions

View file

@ -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

View 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"});
}

View 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) {
$(".day-commits-table li.commit").live('click', function(e){
if(e.target.nodeName != "A") {
location.href = $(this).attr("url");
e.stopPropagation();
return false;
}
});
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"});
},
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();
},
initLoadMore:
function() {
$(window).bind('scroll', function(){
if($(window).scrollTop() == $(document).height() - $(window).height()){
$(window).unbind('scroll');
CommitsList.getOld();
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"});
},
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();
}
});
}
}

View 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,
init:
function(limit) {
this.limit=limit;
this.offset=limit;
this.initLoadMore();
$('.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"});
},
replace:
function(count, html) {
$(".tile").html(html);
if(count == ProjectsList.limit) {
this.offset = count;
this.initLoadMore();
} else {
this.offset = 0;
}
},
append:
function(count, html) {
$(".tile").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');
$('.loading').show();
ProjectsList.getOld();
}
});
}
});
$("#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;
});
}

View file

@ -647,3 +647,9 @@ h4.middle-panel {
border-radius:3px;
float:left;
}
.project_search {
margin: 1.5em 0;
padding: 8px !important;
width: 300px;
}

View 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

View 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

View 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

View 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

View 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"

View file

@ -15,3 +15,5 @@
ago
.clear
- if @commits.empty?
%p.cgray Nothing to merge

View file

@ -20,3 +20,5 @@
%p
%center No preview for this file type
- if @diffs.empty?
%p.cgray Nothing to merge

View file

@ -10,10 +10,10 @@
%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

View 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

View file

@ -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'))}");

View file

@ -1,5 +1,3 @@
#if defined?(Footnotes) && Rails.env.development?
#Footnotes.run! # first of all
# ... other init code
#end