summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG3
-rw-r--r--app/assets/javascripts/application.js.coffee2
-rw-r--r--app/assets/javascripts/pager.js.coffee42
-rw-r--r--app/assets/stylesheets/sections/projects.scss4
-rw-r--r--app/controllers/application_controller.rb14
-rw-r--r--app/controllers/projects_controller.rb15
-rw-r--r--app/views/projects/_gitlab.html.haml58
-rw-r--r--app/views/projects/_gl_projects.html.haml15
-rw-r--r--app/views/projects/_search.html.haml7
-rw-r--r--app/views/projects/gitlab.html.haml35
-rw-r--r--app/views/projects/gitlab.js.haml6
-rw-r--r--app/views/projects/index.html.haml13
-rw-r--r--vendor/assets/javascripts/jquery.endless-scroll.js128
14 files changed, 269 insertions, 74 deletions
diff --git a/.gitignore b/.gitignore
index 6d3c3ee..794c1ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,5 +16,4 @@ tmp/*
/.bundle
/db/*.sqlite3
/log/*.log
-/vendor
/.idea
diff --git a/CHANGELOG b/CHANGELOG
index b357e06..105b1fc 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+v7.12.0
+ - Endless scroll on the dashboard
+
v7.11.0
- Deploy Jobs API calls
- Projects search on dashboard page
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 3908860..8645c78 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -15,6 +15,8 @@
#= require jquery_ujs
#= require turbolinks
#= require jquery.turbolinks
+#= require jquery.endless-scroll
+#= require pager
#= require nprogress
#= require nprogress-turbolinks
#= require jquery_nested_form
diff --git a/app/assets/javascripts/pager.js.coffee b/app/assets/javascripts/pager.js.coffee
new file mode 100644
index 0000000..fd518c3
--- /dev/null
+++ b/app/assets/javascripts/pager.js.coffee
@@ -0,0 +1,42 @@
+@Pager =
+ init: (@url, @limit = 0, preload, @disable = false) ->
+ if preload
+ @offset = 0
+ @getItems()
+ else
+ @offset = @limit
+ @initLoadMore()
+
+ getItems: ->
+ $(".loading").show()
+ $.ajax
+ type: "GET"
+ url: @url
+ data: "limit=" + @limit + "&offset=" + @offset
+ complete: =>
+ $(".loading").hide()
+ success: (data) =>
+ Pager.append(data.count, data.html)
+ dataType: "json"
+
+ append: (count, html) ->
+ if count > 1
+ $(".content-list").append html
+ if count == @limit
+ @offset += count
+ else
+ @disable = true
+
+ initLoadMore: ->
+ $(document).unbind('scroll')
+ $(document).endlessScroll
+ bottomPixels: 400
+ fireDelay: 1000
+ fireOnce: true
+ ceaseFire: ->
+ Pager.disable
+
+ callback: (i) =>
+ unless $(".loading").is(':visible')
+ $(".loading").show()
+ Pager.getItems()
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index bc9da2f..84ee139 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -55,3 +55,7 @@
margin-bottom: 0;
}
}
+
+.loading{
+ font-size: 20px;
+}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 316fd63..9852736 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -88,6 +88,20 @@ class ApplicationController < ActionController::Base
headers['X-XSS-Protection'] = '1; mode=block'
end
+ # JSON for infinite scroll via Pager object
+ def pager_json(partial, count)
+ html = render_to_string(
+ partial,
+ layout: false,
+ formats: [:html]
+ )
+
+ render json: {
+ html: html,
+ count: count
+ }
+ end
+
def check_config
redirect_to oauth2_help_path unless valid_config?
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 7051045..4c4d34e 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -1,5 +1,5 @@
class ProjectsController < ApplicationController
- PROJECTS_PER_PAGE = 100
+ PROJECTS_BATCH = 100
before_filter :authenticate_user!, except: [:build, :badge, :index, :show]
before_filter :authenticate_public_page!, only: :show
@@ -17,13 +17,20 @@ class ProjectsController < ApplicationController
end
def gitlab
+ @limit, @offset = (params[:limit] || PROJECTS_BATCH).to_i, (params[:offset] || 0).to_i
+ @page = @offset == 0 ? 1 : (@offset / @limit + 1)
+
current_user.reset_cache if params[:reset_cache]
- @page = (params[:page] || 1).to_i
- @per_page = PROJECTS_PER_PAGE
- @gl_projects = current_user.gitlab_projects(params[:search], @page, @per_page)
+
+ @gl_projects = current_user.gitlab_projects(params[:search], @page, @limit)
@projects = Project.where(gitlab_id: @gl_projects.map(&:id)).ordered_by_last_commit_date
@total_count = @gl_projects.size
@gl_projects.reject! { |gl_project| @projects.map(&:gitlab_id).include?(gl_project.id) }
+ respond_to do |format|
+ format.json do
+ pager_json("projects/gitlab", @total_count)
+ end
+ end
rescue Network::UnauthorizedError
raise
rescue
diff --git a/app/views/projects/_gitlab.html.haml b/app/views/projects/_gitlab.html.haml
deleted file mode 100644
index bc7ff0c..0000000
--- a/app/views/projects/_gitlab.html.haml
+++ /dev/null
@@ -1,58 +0,0 @@
-.clearfix.light
- .pull-left.fetch-status
- Fetched from GitLab (#{link_to GitlabCi.config.gitlab_server.url, GitlabCi.config.gitlab_server.url, no_turbolink})
- - if params[:search].present?
- by keyword: "#{params[:search]}",
- #{time_ago_in_words(current_user.sync_at)} ago.
- = link_to gitlab_projects_path(reset_cache: true, search: params[:search]), remote: true, class: 'sync-now btn btn-small btn-default' do
- %i.icon-refresh
- Sync now
- %br
-
- .pull-right
- #{@total_count} projects, #{@projects.size} of them added to CI
-%br
-
-%table.table.projects-table
- %thead
- %tr
- %th Project Name
- %th Last commit
- %th Access
- %th Commits
-
- = render @projects
-
- - @gl_projects.sort_by(&:name_with_namespace).each do |project|
- %tr.light
- %td
- = project.name_with_namespace
- %td
- %small Not added to CI
- %td
- %td
- - if Project.already_added?(project)
- %strong.cgreen
- Added
- - else
- = form_tag projects_path do
- = hidden_field_tag :project, project.to_yaml
- = submit_tag 'Add project to CI', class: 'btn btn-default btn-small'
-
-%ul.pagination.gitlab-projects-pagination
- - if @page > 1
- %li
- = link_to gitlab_projects_path(page: @page - 1), class: 'btn', remote: true do
- %i.icon-angle-left
- Previous
- &nbsp;
- - if @total_count == @per_page
- %li
- = link_to gitlab_projects_path(page: @page + 1, search: params[:search]), class: 'btn', remote: true do
- Next
- %i.icon-angle-right
-
-:coffeescript
- NProgress.done()
- $('.gitlab-projects-pagination').on 'ajax:before', ->
- $('.projects').html('<h1><i class="icon-spinner icon-spin"/></h1>')
diff --git a/app/views/projects/_gl_projects.html.haml b/app/views/projects/_gl_projects.html.haml
new file mode 100644
index 0000000..15cd3f0
--- /dev/null
+++ b/app/views/projects/_gl_projects.html.haml
@@ -0,0 +1,15 @@
+- @gl_projects.sort_by(&:name_with_namespace).each do |project|
+ %tr.light
+ %td
+ = project.name_with_namespace
+ %td
+ %small Not added to CI
+ %td
+ %td
+ - if Project.already_added?(project)
+ %strong.cgreen
+ Added
+ - else
+ = form_tag projects_path do
+ = hidden_field_tag :project, project.to_yaml
+ = submit_tag 'Add project to CI', class: 'btn btn-default btn-small' \ No newline at end of file
diff --git a/app/views/projects/_search.html.haml b/app/views/projects/_search.html.haml
index 1b350c7..a9edbb4 100644
--- a/app/views/projects/_search.html.haml
+++ b/app/views/projects/_search.html.haml
@@ -9,7 +9,10 @@
:coffeescript
$('.search .navbar-form').submit ->
- query = $('.search .navbar-form .search-input').val()
- $.get '#{gitlab_projects_path}' + '?search=' + query
NProgress.start()
+ query = $('.search .navbar-form .search-input').val()
+ $.get '#{gitlab_projects_path}', { search: query }, (data) ->
+ $(".projects").html data.html
+ NProgress.done()
+ Pager.init "#{gitlab_projects_path}" + "?search=" + query, #{ProjectsController::PROJECTS_BATCH}, false
false \ No newline at end of file
diff --git a/app/views/projects/gitlab.html.haml b/app/views/projects/gitlab.html.haml
new file mode 100644
index 0000000..aef0237
--- /dev/null
+++ b/app/views/projects/gitlab.html.haml
@@ -0,0 +1,35 @@
+- if @offset == 0
+ .clearfix.light
+ .pull-left.fetch-status
+ Fetched from GitLab (#{link_to GitlabCi.config.gitlab_server.url, GitlabCi.config.gitlab_server.url, no_turbolink})
+ - if params[:search].present?
+ by keyword: "#{params[:search]}",
+ #{time_ago_in_words(current_user.sync_at)} ago.
+ = link_to gitlab_projects_path(reset_cache: true, search: params[:search]), class: 'sync-now btn btn-small btn-default reset-cache' do
+ %i.icon-refresh
+ Sync now
+ %br
+
+ .pull-right
+ #{@total_count} projects, #{@projects.size} of them added to CI
+ %br
+
+ %table.table.projects-table.content-list
+ %thead
+ %tr
+ %th Project Name
+ %th Last commit
+ %th Access
+ %th Commits
+
+ = render @projects
+
+ = render "gl_projects"
+
+ %p.text-center.hide.loading
+ %i.icon-refresh.icon-spin
+
+- else
+ = render @projects
+
+ = render "gl_projects" \ No newline at end of file
diff --git a/app/views/projects/gitlab.js.haml b/app/views/projects/gitlab.js.haml
deleted file mode 100644
index c7bdefb..0000000
--- a/app/views/projects/gitlab.js.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- if @error
- :plain
- $(".projects").html("#{@error}");
-- else
- :plain
- $(".projects").html("#{escape_javascript(render("gitlab"))}");
diff --git a/app/views/projects/index.html.haml b/app/views/projects/index.html.haml
index 4ec8f68..45445f4 100644
--- a/app/views/projects/index.html.haml
+++ b/app/views/projects/index.html.haml
@@ -9,7 +9,14 @@
%p.fetch-status.light
%i.icon-refresh.icon-spin
Please wait while we fetch from GitLab (#{GitlabCi.config.gitlab_server.url})
- :javascript
- $.get("#{gitlab_projects_path}")
+ :coffeescript
+ $.get '#{gitlab_projects_path}', (data) ->
+ $(".projects").html data.html
+ $('.projects').on 'click', '.reset-cache', ->
+ $.get '#{gitlab_projects_path}', { reset_cache: true }, (data) ->
+ $(".projects").html data.html
+ false
+ Pager.init "#{gitlab_projects_path}", #{ProjectsController::PROJECTS_BATCH}, false
+
- else
- = render 'public'
+ = render 'public' \ No newline at end of file
diff --git a/vendor/assets/javascripts/jquery.endless-scroll.js b/vendor/assets/javascripts/jquery.endless-scroll.js
new file mode 100644
index 0000000..38db6b0
--- /dev/null
+++ b/vendor/assets/javascripts/jquery.endless-scroll.js
@@ -0,0 +1,128 @@
+/**
+ * Endless Scroll plugin for jQuery
+ *
+ * v1.4.8
+ *
+ * Copyright (c) 2008 Fred Wu
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+/**
+ * Usage:
+ *
+ * // using default options
+ * $(document).endlessScroll();
+ *
+ * // using some custom options
+ * $(document).endlessScroll({
+ * fireOnce: false,
+ * fireDelay: false,
+ * loader: "<div class=\"loading\"><div>",
+ * callback: function(){
+ * alert("test");
+ * }
+ * });
+ *
+ * Configuration options:
+ *
+ * bottomPixels integer the number of pixels from the bottom of the page that triggers the event
+ * fireOnce boolean only fire once until the execution of the current event is completed
+ * fireDelay integer delay the subsequent firing, in milliseconds, 0 or false to disable delay
+ * loader string the HTML to be displayed during loading
+ * data string|function plain HTML data, can be either a string or a function that returns a string,
+ * when passed as a function it accepts one argument: fire sequence (the number
+ * of times the event triggered during the current page session)
+ * insertAfter string jQuery selector syntax: where to put the loader as well as the plain HTML data
+ * callback function callback function, accepts one argument: fire sequence (the number of times
+ * the event triggered during the current page session)
+ * resetCounter function resets the fire sequence counter if the function returns true, this function
+ * could also perform hook actions since it is applied at the start of the event
+ * ceaseFire function stops the event (no more endless scrolling) if the function returns true
+ *
+ * Usage tips:
+ *
+ * The plugin is more useful when used with the callback function, which can then make AJAX calls to retrieve content.
+ * The fire sequence argument (for the callback function) is useful for 'pagination'-like features.
+ */
+
+(function($){
+
+ $.fn.endlessScroll = function(options) {
+
+ var defaults = {
+ bottomPixels : 50,
+ fireOnce : true,
+ fireDelay : 150,
+ loader : "<br />Loading...<br />",
+ data : "",
+ insertAfter : "div:last",
+ resetCounter : function() { return false; },
+ callback : function() { return true; },
+ ceaseFire : function() { return false; }
+ };
+
+ var options = $.extend({}, defaults, options),
+ firing = true,
+ fired = false,
+ fireSequence = 0,
+ is_scrollable;
+
+ if (options.ceaseFire.apply(this) === true)
+ firing = false;
+
+ if (firing === true) {
+ $(this).scroll(function() {
+ if (options.ceaseFire.apply(this) === true) {
+ firing = false;
+ return; // Scroll will still get called, but nothing will happen
+ }
+
+ if (this == document || this == window) {
+ is_scrollable = $(document).height() - $(window).height() <= $(window).scrollTop() + options.bottomPixels;
+ } else {
+ // calculates the actual height of the scrolling container
+ var inner_wrap = $(".endless_scroll_inner_wrap", this);
+ if (inner_wrap.length == 0)
+ inner_wrap = $(this).wrapInner("<div class=\"endless_scroll_inner_wrap\" />").find(".endless_scroll_inner_wrap");
+ is_scrollable = inner_wrap.length > 0 &&
+ (inner_wrap.height() - $(this).height() <= $(this).scrollTop() + options.bottomPixels);
+ }
+
+ if (is_scrollable && (options.fireOnce == false || (options.fireOnce == true && fired != true))) {
+ if (options.resetCounter.apply(this) === true) fireSequence = 0;
+
+ fired = true;
+ fireSequence++;
+
+ $(options.insertAfter).after("<div id=\"endless_scroll_loader\">" + options.loader + "</div>");
+
+ data = typeof options.data == 'function' ? options.data.apply(this, [fireSequence]) : options.data;
+
+ if (data !== false) {
+ $(options.insertAfter).after("<div id=\"endless_scroll_data\">" + data + "</div>");
+ $("#endless_scroll_data").hide().fadeIn(250, function() {$(this).removeAttr("id");});
+
+ options.callback.apply(this, [fireSequence]);
+
+ if (options.fireDelay !== false || options.fireDelay !== 0) {
+ $("body").after("<div id=\"endless_scroll_marker\"></div>");
+ // slight delay for preventing event firing twice
+ $("#endless_scroll_marker").fadeTo(options.fireDelay, 1, function() {
+ $(this).remove();
+ fired = false;
+ });
+ }
+ else
+ fired = false;
+ }
+
+ $("#endless_scroll_loader").remove();
+ }
+ });
+ }
+ };
+
+})(jQuery); \ No newline at end of file