diff --git a/app/assets/javascripts/extra/log-wrapper.js b/app/assets/javascripts/extra/log-wrapper.js new file mode 100644 index 000000000..0204e9275 --- /dev/null +++ b/app/assets/javascripts/extra/log-wrapper.js @@ -0,0 +1,111 @@ +function initLogWrapper() { + var $wrapper = $('div.log-wrapper'); + var $logBody = $wrapper.children('div.log-body').first(); + var $logCont = $logBody.children('.log').first(); + + var logUrl = $logCont.data('url'); + var $logHead = $wrapper.children('div.log-header').first(); + + var $trigger = $logHead.children('span').first(); + var $autoload = $('#autoreload'); + + var state = $logBody.is(':visible'); + var t = null; // timer + var first_open = true; + + if (state) { + $trigger.removeClass('closed'); + $wrapper.removeClass('inactive') + .addClass('active'); + } else { + $trigger.addClass('closed'); + $logBody.addClass('hidden'); + $wrapper.removeClass('active') + .addClass('inactive'); + } + + function getLineHeight(element){ + var temp = document.createElement(element.nodeName); + temp.setAttribute("style","margin:0px;padding:0px;font-family:"+element.style.fontFamily+";font-size:"+element.style.fontSize); + temp.innerHTML = "test"; + temp = element.parentNode.appendChild(temp); + var ret = temp.clientHeight; + temp.parentNode.removeChild(temp); + return ret; + } + + var loadLog = function() { + $.ajax({ + url: logUrl, + type: "GET", + dataType: 'json', + data: $logCont.data(), + beforeSend: function( xhr ) { + var token = $('meta[name="csrf-token"]').attr('content'); + if (token) xhr.setRequestHeader('X-CSRF-Token', token); + }, + success: function(data, textStatus, jqXHR) { + var l = $logCont[0]; + var vScroll = l.scrollTop; + var hScroll = l.scrollLeft; + var onBottom = Math.abs((l.clientHeight + vScroll - l.scrollHeight)) < getLineHeight(l); + + $logCont.text(data.log); + + $logCont.scrollLeft(hScroll); + $logCont.scrollTop((onBottom || first_open) ? l.scrollHeight - l.clientHeight : vScroll); + first_open = false; + if (!data.building) $autoload.attr({'checked': false}).trigger('change'); + } + }); + } + + var reloadChange = function() { + if ($(this).is(':checked')) { + first_open = true; + loadLog(); + $logCont.scrollTop($logCont[0].scrollHeight - $logCont[0].clientHeight); + t = setInterval(function() { + loadLog(); + }, $('#reload_interval').val()); + } else { + clearInterval(t); + } + } + + var toggleHandler = function() { + state = !state; + // if log opened + if (state) { + if ($autoload.is(':checked')) { + $autoload.trigger('change'); + } + } else { + clearInterval(t); + } + $logBody.slideToggle('slow') + .toggleClass('hidden'); + $logHead.toggleClass('active inactive'); + $trigger.toggleClass('closed'); + + window.location.href = $('a#log_anchor').attr('href'); + } + + $wrapper.on('click', '.log-header > span', toggleHandler); + $autoload.on('change', reloadChange); + + $('#word_wrap').on('change', function() { + $logCont.attr({'wrap': ($(this).is(':checked')) ? 'soft' : 'off'}); + }); + + $('#reload_interval').on('change', function() { + clearInterval(t); + if ($autoload.is(':checked')) { + t = setInterval($(this).val()); + } + }); + $('#load_lines').on('change', function() { + $logCont.data('load_lines', $(this).val()); + }).trigger('change'); + loadLog(); +} \ No newline at end of file diff --git a/app/controllers/platforms/product_build_lists_controller.rb b/app/controllers/platforms/product_build_lists_controller.rb index 7b1666545..2b5b80234 100644 --- a/app/controllers/platforms/product_build_lists_controller.rb +++ b/app/controllers/platforms/product_build_lists_controller.rb @@ -2,9 +2,9 @@ class Platforms::ProductBuildListsController < Platforms::BaseController before_filter :authenticate_user!, :except => [:status_build] skip_before_filter :authenticate_user!, :only => [:index] if APP_CONFIG['anonymous_access'] - load_and_authorize_resource :platform, :only => [:create, :destroy, :new, :show] - load_and_authorize_resource :product, :through => :platform, :only => [:create, :destroy, :new, :show] - load_and_authorize_resource :product_build_list, :through => :product, :only => [:create, :destroy, :new, :show] + load_and_authorize_resource :platform, :except => [:index, :status_build] + load_and_authorize_resource :product, :through => :platform, :except => [:index, :status_build] + load_and_authorize_resource :product_build_list, :through => :product, :except => [:index, :status_build] load_and_authorize_resource :only => [:index] before_filter :authenticate_product_builder!, :only => [:status_build] @@ -22,7 +22,17 @@ class Platforms::ProductBuildListsController < Platforms::BaseController end def show - @logs = JSON.parse(Resque.redis.get("abfworker::iso-worker-#{@product_build_list.id}") || '[]') + end + + def log + @log = Resque.redis.get("abfworker::iso-worker-#{@product_build_list.id}") || '' + respond_to do |format| + format.json { + render :json => { + :log => @log, + :building => @product_build_list.build_started? } + } + end end def create diff --git a/app/models/product_build_list.rb b/app/models/product_build_list.rb index 4e6b82aa1..9203942f1 100644 --- a/app/models/product_build_list.rb +++ b/app/models/product_build_list.rb @@ -40,6 +40,10 @@ class ProductBuildList < ActiveRecord::Base before_destroy :can_destroy? after_destroy :xml_delete_iso_container + def build_started? + status == BUILD_STARTED + end + def container_path "/downloads/#{product.platform.name}/product/#{id}/" end diff --git a/app/views/platforms/product_build_lists/show.html.haml b/app/views/platforms/product_build_lists/show.html.haml index 5ec3e4281..163e3b558 100644 --- a/app/views/platforms/product_build_lists/show.html.haml +++ b/app/views/platforms/product_build_lists/show.html.haml @@ -8,12 +8,6 @@ %h3= t("layout.product_build_lists.main_data") .both -%div.reloader - = label_tag :autoreload do - = check_box_tag :autoreload, true, true - = t("layout.autoreload_page") -.both - .leftlist= t("activerecord.attributes.product_build_list.id") .rightlist= pbl.id .both @@ -46,20 +40,8 @@ .rightlist= l(pbl.updated_at, :format => :long) .both -- if @logs.present? - %h3= t("layout.product_build_lists.logs") - %table#logs.tablesorter.width565{:cellpadding => "0", :cellspacing => "0"} - %thead - %tr - %th.lpadding16= '#' - %th - %tbody - - @logs.each do |item| - %tr - %td= item[0] - %td= item[1] - - .both +- if pbl.build_started? + = render 'shared/log', { :build_started => true, :get_log_path => log_platform_product_product_build_list_path(pbl.product.platform, pbl.product, pbl) } %h3= t("layout.product_build_lists.results") - unless pbl.results.present? @@ -82,18 +64,4 @@ :javascript $(function(){ $('article .all').addClass('bigpadding'); - - var reloadChange = function() { - if ($(this).is(':checked')) { - //reload page every 1 minute - t = setTimeout(function() { - window.location.reload(); - }, 10000); - } else { - clearTimeout(t); - } - } - - $('#autoreload').on('change', reloadChange) - .trigger('change'); }); \ No newline at end of file diff --git a/app/views/projects/build_lists/_log.html.haml b/app/views/projects/build_lists/_log.html.haml deleted file mode 100644 index a2cd38da0..000000000 --- a/app/views/projects/build_lists/_log.html.haml +++ /dev/null @@ -1,148 +0,0 @@ -.hr -%a{:name => 'log'} -.log-wrapper - .log-header - .text-wrap - = link_to({:anchor => :log}, {:id => 'log_anchor'}) do - %h3= t("layout.build_lists.log.build_log") - %span - .both - .log-body.hidden - .reloader - %table.options - %tr.top - %td.first - = label_tag :word_wrap do - = check_box_tag :word_wrap - = t("layout.word_wrap") - %td.last{ :class => @build_list.build_started? ? nil : :hidden } - = label_tag :autoreload do - = check_box_tag :autoreload, true, @build_list.build_started? - = t("layout.build_lists.log.autoreload") - = select_tag :reload_interval, log_reload_time_options - %tr.bottom - %td.first - = link_to t("layout.build_lists.log.download"), build_list_log_url(:build), :id => :log_url - %td.last{ :class => @build_list.build_started? ? nil : :hidden } - = label_tag :load_lines do - = raw t("layout.build_lists.log.load_lines", :count => select_tag(:load_lines, log_reload_lines_options)) - .both - %textarea.log{ :readonly => :readonly, :wrap => 'off', - :data => { :url => log_build_list_path(@build_list), :log_type => :build } } - = t("layout.build_lists.log.not_available") - -:javascript - $(function() { - (function() { - var $wrapper = $('div.log-wrapper'); - var $logBody = $wrapper.children('div.log-body').first(); - var $logCont = $logBody.children('.log').first(); - - var logUrl = $logCont.data('url'); - var $logHead = $wrapper.children('div.log-header').first(); - - var $trigger = $logHead.children('span').first(); - var $autoload = $('#autoreload'); - - var state = $logBody.is(':visible'); - var t = null; // timer - var first_open = true; - - if (state) { - $trigger.removeClass('closed'); - $wrapper.removeClass('inactive') - .addClass('active'); - } else { - $trigger.addClass('closed'); - $logBody.addClass('hidden'); - $wrapper.removeClass('active') - .addClass('inactive'); - } - - function getLineHeight(element){ - var temp = document.createElement(element.nodeName); - temp.setAttribute("style","margin:0px;padding:0px;font-family:"+element.style.fontFamily+";font-size:"+element.style.fontSize); - temp.innerHTML = "test"; - temp = element.parentNode.appendChild(temp); - var ret = temp.clientHeight; - temp.parentNode.removeChild(temp); - return ret; - } - - var loadLog = function() { - $.ajax({ - url: logUrl, - type: "GET", - dataType: 'json', - data: $logCont.data(), - beforeSend: function( xhr ) { - var token = $('meta[name="csrf-token"]').attr('content'); - if (token) xhr.setRequestHeader('X-CSRF-Token', token); - }, - success: function(data, textStatus, jqXHR) { - var l = $logCont[0]; - var vScroll = l.scrollTop; - var hScroll = l.scrollLeft; - var onBottom = Math.abs((l.clientHeight + vScroll - l.scrollHeight)) < getLineHeight(l); - - $logCont.text(data.log); - - $logCont.scrollLeft(hScroll); - $logCont.scrollTop((onBottom || first_open) ? l.scrollHeight - l.clientHeight : vScroll); - first_open = false; - if (!data.building) $autoload.attr({'checked': false}).trigger('change'); - } - }); - } - - var reloadChange = function() { - if ($(this).is(':checked')) { - first_open = true; - loadLog(); - $logCont.scrollTop($logCont[0].scrollHeight - $logCont[0].clientHeight); - t = setInterval(function() { - loadLog(); - }, $('#reload_interval').val()); - } else { - clearInterval(t); - } - } - - var toggleHandler = function() { - state = !state; - // if log opened - if (state) { - if ($autoload.is(':checked')) { - $autoload.trigger('change'); - } - } else { - clearInterval(t); - } - $logBody.slideToggle('slow') - .toggleClass('hidden'); - $logHead.toggleClass('active inactive'); - $trigger.toggleClass('closed'); - - window.location.href = $('a#log_anchor').attr('href'); - } - - $wrapper.on('click', '.log-header > span', toggleHandler); - $autoload.on('change', reloadChange); - - $('#word_wrap').on('change', function() { - $logCont.attr({'wrap': ($(this).is(':checked')) ? 'soft' : 'off'}); - }); - - $('#reload_interval').on('change', function() { - clearInterval(t); - if ($autoload.is(':checked')) { - t = setInterval($(this).val()); - } - }); - $('#load_lines').on('change', function() { - $logCont.data('load_lines', $(this).val()); - }).trigger('change'); - loadLog(); - - })(); - }); diff --git a/app/views/projects/build_lists/show.html.haml b/app/views/projects/build_lists/show.html.haml index b0f7f7f22..cbb5670eb 100644 --- a/app/views/projects/build_lists/show.html.haml +++ b/app/views/projects/build_lists/show.html.haml @@ -125,7 +125,7 @@ }); - if BuildList::HUMAN_STATUSES[@build_list.status].in? [:build_started, :build_error, :success] - = render :partial => 'projects/build_lists/log' + = render 'shared/log', { :build_started => @build_list.build_started?, :download_log_url => build_list_log_url(:build), :get_log_path => log_build_list_path(@build_list) } - if (can_publish = @build_list.can_publish? && can?(:publish, @build_list)) diff --git a/app/views/shared/_log.html.haml b/app/views/shared/_log.html.haml new file mode 100644 index 000000000..6ff0518d7 --- /dev/null +++ b/app/views/shared/_log.html.haml @@ -0,0 +1,47 @@ +-# + params: + - build_started + - download_log_url + - get_log_path + +- download_log_url ||= false + +.hr +%a{:name => 'log'} +.log-wrapper + .log-header + .text-wrap + = link_to({:anchor => :log}, {:id => 'log_anchor'}) do + %h3= t("layout.build_lists.log.build_log") + %span + .both + .log-body.hidden + .reloader + %table.options + %tr.top + %td.first + = label_tag :word_wrap do + = check_box_tag :word_wrap + = t("layout.word_wrap") + %td.last{ :class => build_started ? nil : :hidden } + = label_tag :autoreload do + = check_box_tag :autoreload, true, build_started + = t("layout.build_lists.log.autoreload") + = select_tag :reload_interval, log_reload_time_options + %tr.bottom + %td.first + - if download_log_url + = link_to t("layout.build_lists.log.download"), download_log_url, :id => :log_url + %td.last{ :class => build_started ? nil : :hidden } + = label_tag :load_lines do + = raw t("layout.build_lists.log.load_lines", :count => select_tag(:load_lines, log_reload_lines_options)) + .both + %textarea.log{ :readonly => :readonly, :wrap => 'off', + :data => { :url => get_log_path, :log_type => :build } } + = t("layout.build_lists.log.not_available") +.both + +:javascript + $(function() { + initLogWrapper(); + }); diff --git a/config/routes.rb b/config/routes.rb index ed31afa4c..261cb6df8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -145,7 +145,9 @@ Rosa::Application.routes.draw do end resources :key_pairs, :only => [:create, :index, :destroy] resources :products do - resources :product_build_lists, :only => [:create, :destroy, :new, :show] + resources :product_build_lists, :only => [:create, :destroy, :new, :show] do + member { get :log } + end collection { get :autocomplete_project } end resources :maintainers, :only => [:index]