[#369] monitoring page; some fixes

This commit is contained in:
Alexander Machehin 2014-05-26 23:42:27 +06:00
parent ed21e0475b
commit 7eb5b5e395
19 changed files with 484 additions and 273 deletions

View File

@ -1,9 +1,8 @@
//var RosaABF = angular.module('RosaABF', ['ngResource', 'ng-rails-csrf', 'angular-i18n', 'angularMoment']);
var RosaABF = angular.module('RosaABF', ['ui.bootstrap', 'angular-i18n', 'angularMoment', var RosaABF = angular.module('RosaABF', ['ui.bootstrap', 'angular-i18n', 'angularMoment',
'chieffancypants.loadingBar', 'ngSanitize', 'templates', 'chieffancypants.loadingBar', 'ngSanitize', 'templates',
'ui.codemirror']); 'ui.codemirror', 'ngResource', 'ng-rails-csrf', 'ngCookies']);
RosaABF.factory("LocalesHelper", ['$locale', function($locale) { RosaABF.factory('LocalesHelper', ['$locale', function($locale) {
var locales = { var locales = {
'ru' : 'ru-ru', 'ru' : 'ru-ru',
'en' : 'en-us' 'en' : 'en-us'
@ -18,3 +17,25 @@ RosaABF.factory("LocalesHelper", ['$locale', function($locale) {
RosaABF.config(function(cfpLoadingBarProvider) { RosaABF.config(function(cfpLoadingBarProvider) {
cfpLoadingBarProvider.includeSpinner = false; cfpLoadingBarProvider.includeSpinner = false;
}); });
var SoundNotificationsHelper = function() {
var isOn = true;
var statusChangedSound = null;
soundManager.setup({
// url: '/assets/swf/',
preferFlash: false,
onready: function() {
statusChangedSound = soundManager.createSound({url: "<%=asset_path('garbage_shattering.wav')%>"});
}
});
return {
buildStatusChanged: function() {
if (isOn && statusChangedSound)
statusChangedSound.play();
},
enabled: function(status) {
isOn = status;
}
}
}
RosaABF.factory('SoundNotificationsHelper', SoundNotificationsHelper);

View File

@ -1,13 +1,13 @@
RosaABF.controller('ActivityCtrl', ['$scope', '$http', '$timeout', '$q', '$filter', RosaABF.controller('ActivityCtrl', ['$scope', '$http', '$timeout', '$q', '$filter', '$location',
function($scope, $http, $timeout, $q, $filter) { function($scope, $http, $timeout, $q, $filter, $location) {
$scope.activity_tab = { title: 'activity_menu.activity_feed', active: false, filter: 'all', $scope.activity_tab = { title: 'activity_menu.activity_feed', filter: 'all',
all: {}, code: {}, tracker: {}, build: {}, wiki: {} }; all: {}, code: {}, tracker: {}, build: {}, wiki: {} };
$scope.tracker_tab = { title: 'activity_menu.tracker', content: [] , active: false, $scope.tracker_tab = { title: 'activity_menu.tracker', content: [] ,
filter: { all: true, assigned: false, created: false, name: 'all', filter: { all: true, assigned: false, created: false, name: 'all',
all_count: 0, assigned_count: 0, created_count: 0, closed_count: 0 }, all_count: 0, assigned_count: 0, created_count: 0, closed_count: 0 },
sort: { sort: 'updated', direction: 'desc', updated_class: 'fa-chevron-up' }, sort: { sort: 'updated', direction: 'desc', updated_class: 'fa-chevron-up' },
status: 'open', pagination: { page: 1, total_count: 0 } }; status: 'open', pagination: { page: 1, total_count: 0 } };
$scope.pull_requests_tab = { title: 'activity_menu.pull_requests', content: [] , active: false, $scope.pull_requests_tab = { title: 'activity_menu.pull_requests', content: [] ,
filter: { all: true, assigned: false, created: false, name: 'all', filter: { all: true, assigned: false, created: false, name: 'all',
all_count: 0, assigned_count: 0, created_count: 0, closed_count: 0 }, all_count: 0, assigned_count: 0, created_count: 0, closed_count: 0 },
sort: { sort: 'updated', direction: 'desc', updated_class: 'fa-chevron-up' }, sort: { sort: 'updated', direction: 'desc', updated_class: 'fa-chevron-up' },
@ -27,18 +27,33 @@ RosaABF.controller('ActivityCtrl', ['$scope', '$http', '$timeout', '$q', '$filte
$scope.getContent = function(tab){ $scope.getContent = function(tab){
var cur_tab = $scope.$eval(tab+'_tab'); var cur_tab = $scope.$eval(tab+'_tab');
var tmp = $location.path();
if (tab === 'activity') { if (tab === 'activity') {
$scope.activity_tab.active = true;
$scope.tracker_tab.active = false;
$scope.pull_requests_tab.active = false;
$scope.getActivityContent(); $scope.getActivityContent();
if($location.path() !== '/') {
$location.path('/').replace()
};
} }
else if (tab === 'tracker') { else if (tab === 'tracker') {
$scope.tracker_tab.active = true; $scope.activity_tab.active = false;
$scope.tracker_tab.active = true;
$scope.pull_requests_tab.active = false; $scope.pull_requests_tab.active = false;
$scope.getIssuesContent(); $scope.getIssuesContent();
if($location.path() !== '/issues') {
$location.path('/issues').replace()
};
} }
else if (tab === 'pull_requests') { else if (tab === 'pull_requests') {
$scope.tracker_tab.active = false; $scope.activity_tab.active = false;
$scope.tracker_tab.active = false;
$scope.pull_requests_tab.active = true; $scope.pull_requests_tab.active = true;
$scope.getIssuesContent(); $scope.getIssuesContent();
if($location.path() !== '/pull_requests') {
$location.path('/pull_requests').replace()
};
}; };
}; };

View File

@ -1,4 +1,6 @@
RosaABF.controller('BuildListsController', ['$scope', '$http', '$location', '$timeout', function($scope, $http, $location, $timeout) { RosaABF.controller('BuildListsController',
['$scope', '$http', '$location', '$timeout', 'datepickerPopupConfig', '$cookies',
function($scope, $http, $location, $timeout, datepickerPopupConfig, $cookies) {
$scope.params = null; $scope.params = null;
$scope.first_run = true; $scope.first_run = true;
@ -22,10 +24,64 @@ RosaABF.controller('BuildListsController', ['$scope', '$http', '$location', '$ti
<%=BuildList::FAILED_PUBLISH%>: 1, <%=BuildList::FAILED_PUBLISH%>: 1,
<%=BuildList::REJECTED_PUBLISH%>: 0 <%=BuildList::REJECTED_PUBLISH%>: 0
}; };
$scope.minDate = new Date(2010, 1, 1);
$scope.maxDate = moment().add('months', 1).calendar();
$scope.today = function() {
$scope.dt = new Date();
};
$scope.today();
// Fixes: redirect to page after form submit $scope.clear = function () {
$("#monitoring_filter").on('submit', function(){ return false; }); //$scope.dt = null;
$scope.params = { page: '1',
per_page: '25',
filter: { ownership: 'owned' }
};
};
// Disable weekend selection
$scope.disabled = function(date, mode) {
return ( mode === 'day' && ( date.getDay() === 0 || date.getDay() === 6 ) );
};
$scope.toggleMin = function() {
$scope.minDate = $scope.minDate ? null : new Date();
};
$scope.toggleMin();
$scope.dateOptions = {
formatYear: 'yy',
startingDay: <%= I18n.locale == :ru ? 1 : 0 %>,
'show-weeks': false
};
$scope.initDate = $scope.today();
$scope.format = 'mediumDate';
<% if I18n.locale == :ru %>
// TRANSLATION
datepickerPopupConfig.currentText = 'Сегодня';
datepickerPopupConfig.clearText = 'Очистить';
datepickerPopupConfig.weeksText = 'Недели';
datepickerPopupConfig.closeText = 'Закрыть';
<% end %>
datepickerPopupConfig.appendToBody = 'true';
$scope.init = function init() {
$scope.isOpenServerStatus = $cookies.isOpenServerStatus === 'true' ? true : false;
$scope.isOpenFilters = $cookies.isOpenFilters === 'true' ? true : false;
};
$scope.toggleServerStatus = function() {
$scope.isOpenServerStatus = !$scope.isOpenServerStatus;
$cookies.isOpenServerStatus = $scope.isOpenServerStatus.toString();
};
$scope.toggleFilters = function() {
$scope.isOpenFilters = !$scope.isOpenFilters;
$cookies.isOpenFilters = $scope.isOpenFilters.toString();
};
$scope.getBuildLists = function() { $scope.getBuildLists = function() {
// Disable 'Search' button // Disable 'Search' button
@ -77,7 +133,8 @@ RosaABF.controller('BuildListsController', ['$scope', '$http', '$location', '$ti
_.each(to_open, function(bl){ $scope.showRelated(bl, true); }); _.each(to_open, function(bl){ $scope.showRelated(bl, true); });
// Render pagination // Render pagination
$scope.pages = results.pages; $scope.page = results.page;
$scope.build_lists_count = results.build_lists_count;
// Enable 'Search' button // Enable 'Search' button
$scope.isRequest = false; $scope.isRequest = false;
}).error(function(data, status, headers, config) { }).error(function(data, status, headers, config) {
@ -94,7 +151,8 @@ RosaABF.controller('BuildListsController', ['$scope', '$http', '$location', '$ti
// Waits for render of build_lists // Waits for render of build_lists
if (!disable_effect) if (!disable_effect)
$timeout(function() { $timeout(function() {
$('#build-list-' + bl.id + ' td:visible').effect('highlight', {}, 1000); var tmp = $('#build-list-' + bl.id + ' td');
$('#build-list-' + bl.id + ' td').effect('highlight', {}, 1000);
}, 100); }, 100);
}); });
} }

View File

@ -1,7 +1,8 @@
RosaABF.controller('RosaABFController', ['$scope', 'LocalesHelper', function($scope, LocalesHelper) { RosaABF.controller('RosaABFController', ['$scope', 'LocalesHelper', 'SoundNotificationsHelper',
function($scope, LocalesHelper, SoundNotificationsHelper) {
$scope.init = function(locale) { $scope.init = function(locale, sound_notifications) {
LocalesHelper.setLocale(locale); LocalesHelper.setLocale(locale);
moment.lang(locale); moment.lang(locale);
SoundNotificationsHelper.enabled(sound_notifications);
} }
}]); }]);

View File

@ -50,7 +50,7 @@ var BuildList = function(atts, dictionary) {
case <%=BuildList::BUILD_ERROR%>: case <%=BuildList::BUILD_ERROR%>:
case <%=BuildList::FAILED_PUBLISH%>: case <%=BuildList::FAILED_PUBLISH%>:
case <%=BuildList::FAILED_PUBLISH_INTO_TESTING%>: case <%=BuildList::FAILED_PUBLISH_INTO_TESTING%>:
case <%=BuildList::REJECTED_PUBLISH%>: self.status_color = 'error'; break case <%=BuildList::REJECTED_PUBLISH%>: self.status_color = 'danger'; break
case <%=BuildList::TESTS_FAILED%>: self.status_color = 'warning'; break case <%=BuildList::TESTS_FAILED%>: self.status_color = 'warning'; break
default: self.status_color = 'nocolor'; default: self.status_color = 'nocolor';
} }

View File

@ -1,11 +1,11 @@
//= require jquery //= require jquery
//= require jquery_ujs //= require jquery_ujs
//= require jquery-ui
//= require js-routes //= require js-routes
// Loads all Bootstrap javascripts // Loads all Bootstrap javascripts
//= require bootstrap //= require bootstrap
// require unstable/angular
//= require angular //= require angular
//= require angular-sanitize //= require angular-sanitize
//= require angular-ui-bootstrap-tpls //= require angular-ui-bootstrap-tpls
@ -13,8 +13,16 @@
//= require angular-i18n //= require angular-i18n
//= require angularjs/locales //= require angularjs/locales
//= require angular-resource
//= require ng-rails-csrf
//= require angular-cookies
//= require soundmanager2-nodebug-jsmin
//= require moment //= require moment
//= require angularjs/angular-moment //= require angularjs/angular-moment
//= require_tree ./angular-new //= require_tree ./angular-new
//= require loading-bar //= require loading-bar
//= require underscore

View File

@ -18,7 +18,7 @@ a.navbar-brand, .navbar .navbar-right .avatar {
padding-top: ($navbar-height - $logo-mini-height) / 2; padding-top: ($navbar-height - $logo-mini-height) / 2;
} }
.nav a { .nav a, .pagination a, .carousel a, .panel-title a {
cursor: pointer; cursor: pointer;
} }
@ -52,3 +52,33 @@ footer {
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important; display: none !important;
} }
table tbody {
td.build-list-statuses {
background: #FFF !important;
.status {
float: left;
border: 1px solid #DDD;
margin: 1px 2px;
}
.nocolor { background: #FFF; }
.expand {
position: absolute;
margin: -9px 0 0 -23px;
border: 1px solid #DDD;
border-right-color: #FFF;
padding: 1px;
cursor: pointer;
}
}
td.build-list-chevrons {
background: #FFF !important;
}
tr.group-start td {
border-top: 2px solid #125687;
}
tr.group-end td {
border-bottom: 2px solid #125687;
}
}

View File

@ -1,4 +1,5 @@
class Projects::BuildListsController < Projects::BaseController class Projects::BuildListsController < Projects::BaseController
layout 'bootstrap', only: [:index]
include FileStoreHelper include FileStoreHelper
NESTED_ACTIONS = [:index, :new, :create] NESTED_ACTIONS = [:index, :new, :create]
@ -23,20 +24,21 @@ class Projects::BuildListsController < Projects::BaseController
format.html format.html
format.json do format.json do
@filter = BuildList::Filter.new(@project, current_user, current_ability, params[:filter] || {}) @filter = BuildList::Filter.new(@project, current_user, current_ability, params[:filter] || {})
@bls = @filter.find.recent params[:page] = params[:page].to_i == 0 ? nil : params[:page]
.paginate( params[:per_page] = if BuildList::Filter::PER_PAGE.include? params[:per_page].to_i
:page => (params[:page].to_i == 0 ? nil : params[:page]), params[:per_page].to_i
per_page: BuildList::Filter::PER_PAGE.include?(params[:per_page].to_i) ? params[:per_page].to_i : 25 else
) BuildList::Filter::PER_PAGE.first
end
@bls_count = @filter.find.count
@bls = @filter.find.recent.paginate(page: params[:page], per_page: params[:per_page])
@build_lists = BuildList.where(id: @bls.pluck(:id)).recent @build_lists = BuildList.where(id: @bls.pluck(:id)).recent
.includes( .includes(:save_to_platform,
:save_to_platform, :save_to_repository,
:save_to_repository, :build_for_platform,
:build_for_platform, :user,
:user, :source_packages,
:source_packages, project: :project_statistics)
project: :project_statistics
)
@build_server_status = AbfWorker::StatusInspector.projects_status @build_server_status = AbfWorker::StatusInspector.projects_status
end end
@ -45,7 +47,7 @@ class Projects::BuildListsController < Projects::BaseController
def new def new
if params[:show] == 'inline' && params[:build_list_id].present? if params[:show] == 'inline' && params[:build_list_id].present?
render '_new_form', layout: false, locals: {project: @project, build_list: @build_list} render '_new_form', layout: false, locals: { project: @project, build_list: @build_list }
else else
render :new render :new
end end
@ -70,16 +72,16 @@ class Projects::BuildListsController < Projects::BaseController
@build_list.include_repos = @build_list.include_repos.select {|ir| @build_list.build_for_platform.repository_ids.include? ir.to_i} @build_list.include_repos = @build_list.include_repos.select {|ir| @build_list.build_for_platform.repository_ids.include? ir.to_i}
@build_list.priority = current_user.build_priority # User builds more priority than mass rebuild with zero priority @build_list.priority = current_user.build_priority # User builds more priority than mass rebuild with zero priority
flash_options = {project_version: @build_list.project_version, arch: arch.name, build_for_platform: build_for_platform.name} flash_options = { project_version: @build_list.project_version, arch: arch.name, build_for_platform: build_for_platform.name }
if authorize!(:create, @build_list) && @build_list.save if authorize!(:create, @build_list) && @build_list.save
build_lists << @build_list build_lists << @build_list
notices << t("flash.build_list.saved", flash_options) notices << t('flash.build_list.saved', flash_options)
else else
errors << t("flash.build_list.save_error", flash_options) errors << t('flash.build_list.save_error', flash_options)
end end
end end
end end
errors << t("flash.build_list.no_arch_or_platform_selected") if errors.blank? and notices.blank? errors << t('flash.build_list.no_arch_or_platform_selected') if errors.blank? and notices.blank?
if errors.present? if errors.present?
@build_list ||= BuildList.new @build_list ||= BuildList.new
flash[:error] = errors.join('<br>').html_safe flash[:error] = errors.join('<br>').html_safe

View File

@ -1,12 +1,5 @@
-set_meta_tags title: nil -set_meta_tags title: nil
.voffset20
.container .container
/ =#render 'feed_tabs'
/ =render 'list'
/ - content_for :sidebar, render('sidebar')
/ - render 'top_menu'
%div{ 'ng-controller' => 'ActivityCtrl', 'cg-busy' => "'activity'", 'ng-init' => "init('#{action_name}')" } %div{ 'ng-controller' => 'ActivityCtrl', 'cg-busy' => "'activity'", 'ng-init' => "init('#{action_name}')" }
%tabset.offset20 %tabset.offset20
= render 'activity_tab' = render 'activity_tab'

View File

@ -7,11 +7,14 @@
- if user_signed_in? - if user_signed_in?
= auto_discovery_link_tag :atom, atom_activity_feeds_path(format: 'atom', token: current_user.authentication_token), title: t("layout.atom_link_tag_title", nickname: current_user.uname, app_name: APP_CONFIG['project_name']) = auto_discovery_link_tag :atom, atom_activity_feeds_path(format: 'atom', token: current_user.authentication_token), title: t("layout.atom_link_tag_title", nickname: current_user.uname, app_name: APP_CONFIG['project_name'])
%body{ 'ng-app' => 'RosaABF', 'ng-controller' => 'RosaABFController', 'ng-init' => "init('#{I18n.locale}')" } %body{ 'ng-app' => 'RosaABF', 'ng-controller' => 'RosaABFController',
'ng-init' => "init('#{I18n.locale}', #{!!current_user.try(:sound_notifications)})" }
= render 'layouts/menu/new_top' = render 'layouts/menu/new_top'
%article.container-fluid %article.container-fluid
.row= yield .row= yield
= render 'layouts/menu/new_bottom' = render 'layouts/menu/new_bottom'
= stylesheet_link_tag 'new_application' = stylesheet_link_tag 'new_application'
= javascript_include_tag 'new_application' = javascript_include_tag 'new_application'
= javascript_include_tag 'moment/ru.js' if I18n.locale == :ru - if I18n.locale == :ru
= javascript_include_tag 'moment/ru.js'
= javascript_include_tag 'angular-1.2.15-locale_ru-ru'

View File

@ -20,9 +20,9 @@
.form-group .form-group
= text_field_tag 'query', @query, placeholder: t('layout.search.header'), class: 'form-control' = text_field_tag 'query', @query, placeholder: t('layout.search.header'), class: 'form-control'
%ul.nav.navbar-nav.navbar-right %ul.nav.navbar-nav.navbar-right
%li
.avatar= image_tag avatar_url(current_user), alt: 'avatar', height: "32", class: 'img-responsive'
- if current_user - if current_user
%li
.avatar= image_tag avatar_url(current_user), alt: 'avatar', height: "32", class: 'img-responsive'
%li.dropdown %li.dropdown
%a.dropdown-toggle{ "data-toggle" => "dropdown", href: "#" } %a.dropdown-toggle{ "data-toggle" => "dropdown", href: "#" }
= current_user.uname = current_user.uname

View File

@ -1,106 +1,81 @@
-html_options = {class: 'sel80 medium input_cleanse', tabindex: 2} -html_options = { class: 'form-control' }
.top.box %accordion{ 'close-others' => 'false', 'ng-cloak' => true }
.filter %accordion-group{ heading: t('layout.build_lists.build_server_status.header'), 'is-open' => 'isOpenServerStatus',
= form_for :filter, html: {class: :form, id: 'monitoring_filter', 'ng-submit' => 'refresh(true)'}, authenticity_token: false do |f| 'ng-click' => 'toggleServerStatus()' }
.column = render 'server_status'
= render 'server_status'
= hidden_field_tag :name_with_owner, @project.try(:name_with_owner) %accordion-group{ heading: t('layout.build_lists.filters'), 'is-open' => 'isOpenFilters',
.reloader 'ng-click' => 'toggleFilters()' }
= form_for :filter, html: { class: :form, id: 'monitoring_filter' },
authenticity_token: false do |f|
.row
.col-md-4.col-sm-6
%h4= t 'layout.build_lists.ownership.header'
=f.hidden_field :ownership, value: '{{params.filter.ownership}}' if current_user
.btn-group.btn-group-justified
- ['owned', (@project ? nil : 'related'), 'everything'].compact.each do |ownership|
.btn-group
%button.btn.btn-default{ 'ng-model' => 'params.filter.ownership', 'btn-radio' => "'#{ownership}'",
type: 'button', disabled: !current_user }
= t "layout.build_lists.ownership.#{ownership}"
.col-md-4.col-sm-6
%h4= t 'activerecord.models.platform'
= f.select :platform_id, availables_main_platforms.collect{ |pl| [pl.name, pl.id] },
{ include_blank: true },
html_options.merge(id: 'platform', 'ng-model' => 'params.filter.platform_id')
-[:updated_at_start, :updated_at_end].each do |attr|
.col-md-2.col-sm-4
%h4= t attr == :updated_at_start ? '_on' : 'until'
= f.text_field attr, size: 10, class: 'form-control',
'datepicker-popup' => '{{format}}', 'ng-model' => "params.filter.#{attr}",
'is-opened' => 'opened', min: 'minDate', max: 'maxDate',
'datepicker-options' => 'dateOptions', 'date-disabled' => "disabled(date, mode)"
.col-md-4.col-sm-6
%h4= t 'number_rows'
=hidden_field_tag :per_page, '{{params.per_page}}'
=hidden_field_tag :page, '{{params.page}}'
.btn-group.btn-group-justified
-BuildList::Filter::PER_PAGE.each do |num|
.btn-group
%button.btn.btn-default{ 'ng-model' => 'params.per_page', 'btn-radio' => "'#{num}'", type: 'button' }= num
.col-md-4.col-sm-6
%h4= t 'activerecord.attributes.build_list.arch'
= f.select :arch_id, Arch.recent.collect{ |arch| [arch.name, arch.id] }, { include_blank: true },
html_options.merge(id: 'architecture', 'ng-model' => 'params.filter.arch_id')
.col-md-4.col-sm-6
%h4.medium= t 'layout.build_lists.project_name_search'
%input#filter_project_name.form-control{ name: 'filter[filter_project_name]', size: '30',
type: 'text', value: '{{params.filter.filter_project_name}}' }
.col-md-4.col-sm-6
%h4= t 'activerecord.attributes.build_list.status'
= f.select :status, BuildList::STATUSES.collect{ |status| [BuildList.human_status(status), status] },
{ include_blank: true },
html_options.merge(id: 'status', 'ng-model' => 'params.filter.status')
.col-md-4.col-sm-6
%h4= t 'activerecord.models.mass_build'
= f.select :mass_build_id, mass_build_options, { include_blank: true },
html_options.merge(id: 'mass_build', 'ng-model' => 'params.filter.mass_build_id')
.col-md-4.col-sm-6
%h4= t 'layout.build_lists.id_search'
%input#filter_id.form-control{ name: 'filter{id}', size: '30', type: 'text', value: '{{params.filter.id}}' }
.clearfix
.col-md-4.col-sm-6.offset20
= label_tag :autoreload do = label_tag :autoreload do
= check_box_tag :autoreload, true, true = check_box_tag :autoreload, true, true
= t 'layout.autoreload_page' = t 'layout.autoreload_page'
.column .col-md-4.col-sm-6.col-md-offset-4.offset20
- if current_user .btn-group.btn-group-justified
.bordered.nopadding .btn-group{ 'ng-show' => 'isRequest' }
%h3.medium= t("layout.build_lists.ownership.header") %button.btn.btn-default{ type: 'button', disabled: true }
=f.hidden_field :ownership, value: '{{params.filter.ownership}}' = t('layout.processing')
.btn-group{ 'ng-hide' => 'isRequest' }
%button.btn.btn-default{ type: 'button', 'ng-click' => 'refresh(true)' }
= t('layout.search.header')
.btn-group .btn-group
- ['owned', (@project ? nil : 'related'), 'everything'].compact.each do |ownership| %button.btn.btn-default{ type: 'button', 'ng-click' => 'clear()' }= t('reset')
-options = {'ng-class' =>"{active: params.filter.ownership == '#{ownership}'}",value: ownership, style: (@project ? 'width:50%;' : '')} -if @project and can?(:create, @project.build_lists.build)
%button.btn.ownership{options}= t "layout.build_lists.ownership.#{ownership}" .btn-group
%h3.medium= t 'number_rows' %button.btn.btn-default{ id: 'filter_new_build', type: 'button',
=hidden_field_tag :per_page, '{{params.per_page}}' onclick: "location.href='#{new_project_build_list_path(@project)}'",
=hidden_field_tag :page, '{{params.page}}' value: t('layout.build_lists.new_header') }
.btn-group = hidden_field_tag :name_with_owner, @project.try(:name_with_owner)
-BuildList::Filter::PER_PAGE.each do |num|
%button.btn.per_page{value: num, 'ng-class' => "{active: params.per_page == #{num}}"}=num
%h3.medium= t 'activerecord.attributes.build_list.status'
.lineForm.aside
= f.select :status, BuildList::STATUSES.collect{|status| [BuildList.human_status(status), status]}, {include_blank: true},
html_options.merge(id: 'status', 'ng-model' => 'params.filter.status')
.both
%br/
.column
%h3.medium= t 'activerecord.models.platform'
.lineForm.aside
= f.select :platform_id, availables_main_platforms.collect{|pl| [pl.name, pl.id]}, {include_blank: true}, html_options.merge(id: 'platform', 'ng-model' => 'params.filter.platform_id')
%h3.medium= t 'activerecord.attributes.build_list.arch'
.lineForm.aside
= f.select :arch_id, Arch.recent.collect{|arch| [arch.name, arch.id]}, {include_blank: true}, html_options.merge(id: 'architecture', 'ng-model' => 'params.filter.arch_id')
%h3.medium= t 'activerecord.models.mass_build'
.lineForm.aside
= f.select :mass_build_id, mass_build_options, {include_blank: true},
html_options.merge(id: 'mass_build', 'ng-model' => 'params.filter.mass_build_id')
.column
-[:updated_at_start, :updated_at_end].each do |attr|
-class_name, message = attr == :updated_at_start ? %w[floatleft _on] : %w[floatright until]
%div{class: class_name}
%h3.medium= t message
=f.text_field attr, readonly: "readonly", size: 10, class: 'mediumheight min input_cleanse', value: "{{params.filter.#{attr}}}"
=link_to image_tag('x.png', alt: 'x', class: 'semi'), "#filter_#{attr}", id: 'updated_at_clear'
.both
-%w[project_name id].each do |filter|
%h3.medium= t "layout.build_lists.#{filter}_search"
%input.mediumheight.input_cleanse{id: "filter_#{filter}", name: "filter[#{filter}]", size: "30", type: "text", value: "{{params.filter.#{filter}}}"}
%br/
%br/
.butgrp
= f.submit t('layout.search.header'), 'ng-hide' => 'isRequest'
= f.submit t('layout.processing'), disabled: true, 'ng-show' => 'isRequest'
= f.submit t('reset'), id: 'filter_clear'
-if @project and can?(:create, @project.build_lists.build)
%input{id: 'filter_new_build', type: 'button', onclick: "location.href='#{new_project_build_list_path(@project)}'", value: t('layout.build_lists.new_header')}
.both
.both
.switch
%a{href: "#"}= t 'layout.build_lists.hide_filter'
:javascript
var MONITORING_FILTER_HIDE = "monitoring_filter_hide";
$(".switch").toggle(
function () {
var d = new Date();
d.setMonth(d.getMonth() + 1);
$(".filter").hide("slow");
$(".switch a").text("#{t 'layout.build_lists.show_filter'}");
setCookie(MONITORING_FILTER_HIDE, 'true', d);
},
function () {
$(".filter").show("slow");
$(".switch a").text("#{t 'layout.build_lists.hide_filter'}");
var d = new Date();
d.setMonth(d.getMonth() + 1);
setCookie(MONITORING_FILTER_HIDE, 'false', d);
}
);
#{cookies[:monitoring_filter_hide] == 'true' ? "$('.switch').click();" : ''}
#{if I18n.locale == :ru
"$.datepicker.regional['ru'] = {
closeText: 'Закрыть',
prevText: '<Пред',
nextText: 'След>',
currentText: 'Сейчас',
monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь',
'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],
dayNames: ['Воскресенье','Понедельник','Вторник','Среда','Четверг','Пятница','Суббота'],
dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'],
weekHeader: 'Не',
dateFormat: 'dd/mm/yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''
};
$.datepicker.setDefaults($.datepicker.regional['ru']);"
end
}

View File

@ -1,43 +1,35 @@
.bordered.nopadding .row
%h3.medium= t('layout.build_lists.build_server_status.header') .col-md-4.col-sm-6
%h5= t 'layout.build_lists.build_server_status.rpm_workers'
.table %ul.list-unstyled
.lefter= t("layout.build_lists.build_server_status.rpm_workers") %li
.both = t 'layout.build_lists.build_server_status.amount'
.table %ul
.lefter= t("layout.build_lists.build_server_status.amount") %li
.both = t 'layout.build_lists.build_server_status.abf'
.table %span.bg-primary.badge.pull-right {{server_status.rpm.workers}}
.lefter= t("layout.build_lists.build_server_status.abf") %li
.righter {{server_status.rpm.workers}} = t 'layout.build_lists.build_server_status.custom'
.both %span.bg-primary.badge.pull-right {{server_status.rpm.other_workers}}
.table .col-md-4.col-sm-6
.lefter= t("layout.build_lists.build_server_status.custom") %h5= t 'layout.build_lists.build_server_status.tasks'
.righter {{server_status.rpm.other_workers}} %ul.list-unstyled
.both %li
.table %ul
.lefter= t("layout.build_lists.build_server_status.tasks") - [['custom', :default_tasks], ['mass_build_tasks', :low_tasks]].each do |label, metric|
.both %li
- [['custom', :default_tasks], ['mass_build_tasks', :low_tasks], ['build_tasks', :build_tasks]].each do |label, metric| = t "layout.build_lists.build_server_status.#{label}"
.table %span.bg-primary.badge.pull-right {{server_status.rpm.#{metric}}}
.lefter= t("layout.build_lists.build_server_status.#{label}") %li
.righter= "{{server_status.rpm.#{metric}}}" = t 'layout.build_lists.build_server_status.build_tasks'
.both %span.bg-primary.badge.pull-right {{server_status.rpm.build_tasks}}
%br .col-md-4.col-sm-6
%h5= t 'layout.build_lists.build_server_status.publish_workers'
.table %ul.list-unstyled
.lefter= t("layout.build_lists.build_server_status.publish_workers") %li
.both = t 'layout.build_lists.build_server_status.amount'
.table %span.bg-primary.badge.pull-right {{server_status.publish.workers}}
.lefter= t("layout.build_lists.build_server_status.amount") - [:tasks, :build_tasks].each do |metric|
.righter= "{{server_status.publish.workers}}" %li
.both = t "layout.build_lists.build_server_status.#{metric}"
- [:tasks, :build_tasks].each do |metric| %span.bg-primary.badge.pull-right {{server_status.publish.#{metric}}}
.table
.lefter= t("layout.build_lists.build_server_status.#{metric}")
.righter= "{{server_status.publish.#{metric}}}"
.both
%br

View File

@ -1,73 +1,85 @@
-set_meta_tags title: t('.title') -set_meta_tags title: t('.title')
%div{'ng-controller' => 'BuildListsController'} %div{'ng-controller' => 'BuildListsController', 'ng-init' => 'init()', 'ng-cloak' => true }
= render 'filter' .row.offset20
.container= render 'filter'
.row
.container
%table.table.table-condensed
%thead
%tr
%th
%th= t('activerecord.attributes.build_list.id')
%th= t('activerecord.attributes.build_list.status')
%th= t('activerecord.attributes.build_list.project')
%th= t('diff')
%th= t('activerecord.attributes.build_list.project_version')
%th= t('activerecord.attributes.build_list.save_to_repository')
%th= t('activerecord.attributes.build_list.arch_short')
%th= t('activerecord.attributes.build_list.user')
%th= t('activerecord.attributes.build_list.updated_at')
%tbody
%tr{'ng-repeat' => 'bl in build_lists', class: '{{bl.status_color}}', id: 'build-list-{{bl.id}}', 'ng-class' => "{'group-start': !bl.relatedHidden, 'group-end': bl.lastRelated}", 'ng-show' => 'bl.show'}
%td.build-list-chevrons
%a.expand{'ng-show' => 'bl.hasRelated'}
%span.fa.fa-chevron-down{ 'ng-show' => 'bl.relatedHidden', 'ng-click' => 'showRelated(bl)' }
%span.fa.fa-chevron-up{ 'ng-hide' => 'bl.relatedHidden', 'ng-click' => 'hideRelated(bl)' }
/ id
%td.build-list-statuses
%table.tablesorter{cellpadding: "0", cellspacing: "0"} %a{'ng-href' => '{{bl.url}}' } {{bl.id}}
%thead %div{'ng-show' => 'bl.hasRelated'}
%tr %div{'ng-repeat' => 'related in bl.related', 'ng-class' => '"status bg-" + related.status_color'} &nbsp;
%th.lpadding16= t("activerecord.attributes.build_list.id")
%th.lpadding16= t("activerecord.attributes.build_list.status")
%th.lpadding16= t("activerecord.attributes.build_list.project")
%th.lpadding16= t("diff")
%th.lpadding16= t("activerecord.attributes.build_list.project_version")
%th.lpadding16= t("activerecord.attributes.build_list.save_to_repository")
%th.lpadding6= t("activerecord.attributes.build_list.arch_short")
%th.lpadding16= t("activerecord.attributes.build_list.user")
%th.lpadding6= t("activerecord.attributes.build_list.updated_at")
%tbody
%tr{'ng-repeat' => 'bl in build_lists', class: '{{bl.status_color}}', id: 'build-list-{{bl.id}}', 'ng-class' => "{'group-start': !bl.relatedHidden, 'group-end': bl.lastRelated}", 'ng-show' => 'bl.show'}
/ id / status
%td.build-list-statuses %td
%a.expand{'ng-show' => 'bl.hasRelated'} {{bl.human_status | i18n}}
%span.icon-chevron-down{'ng-show' => 'bl.relatedHidden', 'ng-click' => 'showRelated(bl)'} %br
%span.icon-chevron-up{'ng-hide' => 'bl.relatedHidden', 'ng-click' => 'hideRelated(bl)'} %time{'ng-show' => 'bl.duration'}
%a{'ng-href' => '{{bl.url}}' } {{bl.id}} {{bl.duration}}
%div{'ng-show' => 'bl.hasRelated'} %time{'ng-show' => 'bl.average_build_time'}
.status{'ng-repeat' => 'related in bl.related', class: '{{related.status_color}}'} &nbsp; \/{{bl.average_build_time}}
/ status / project
%td %td.centered{'ng-hide' => 'bl.project', colspan: 2}
{{bl.human_status | i18n}} = t('layout.projects.unexisted_project')
%br %td{'ng-show' => 'bl.project'}
%time{'ng-show' => 'bl.duration'} %a{'ng-href' => '{{bl.project.url}}' } {{bl.project.name_with_owner}}
{{bl.duration}}
%time{'ng-show' => 'bl.average_build_time'}
\/{{bl.average_build_time}}
/ project / diff
%td.centered{'ng-hide' => 'bl.project', colspan: 2} %td
= t('layout.projects.unexisted_project') %a{'ng-href' => '{{bl.version_link_url}}', 'ng-show' => 'bl.project'}
%td{'ng-show' => 'bl.project'} {{bl.version_link_text}}
%a{'ng-href' => '{{bl.project.url}}' } {{bl.project.name_with_owner}}
/ diff / project_version
%td %td {{bl.version_release}}
%a{'ng-href' => '{{bl.version_link_url}}', 'ng-show' => 'bl.project'}
{{bl.version_link_text}}
/ project_version / save_to_repository
%td {{bl.version_release}} %td
%a{'ng-href' => '{{bl.save_to_repository_url}}' } {{bl.save_to_repository_name}}
/ save_to_repository / arch_short
%td %td{'ng-show' => 'bl.arch'} {{bl.arch.name}}
%a{'ng-href' => '{{bl.save_to_repository_url}}' } {{bl.save_to_repository_name}} %td{'ng-hide' => 'bl.arch'}= t('layout.arches.unexisted_arch')
/ arch_short / user
%td{'ng-show' => 'bl.arch'} {{bl.arch.name}} %td
%td{'ng-hide' => 'bl.arch'}= t('layout.arches.unexisted_arch') %a{'ng-href' => '{{bl.user.url}}' } {{bl.user.fullname}}
/ user / updated_at
%td %td{'am-time-ago' => 'bl.updated_at', title: "{{bl.updated_at | amDateFormat:'ddd, LLL'}}"}
%a{'ng-href' => '{{bl.user.url}}' } {{bl.user.fullname}}
/ updated_at %pagination{ 'boundary-links' => 'true',
%td{'am-time-ago' => 'bl.updated_at', title: '{{bl.updated_at_utc}}'} 'total-items' => 'build_lists_count',
'page' => 'page',
'previous-text' => "", 'next-text' => "",
'first-text' => "«", "last-text" => "»",
'items-per-page' => "{{params.per_page}}",
'max-size' => 5,
'rotate' => 'false',
'ng-show' => "build_lists_count > params.per_page",
'on-select-page' => "goToPage(page)" }
.both
= render 'shared/angularjs_will_paginate'
= render @project ? 'projects/base/submenu' : 'projects/build_lists/submenu' = render @project ? 'projects/base/submenu' : 'projects/build_lists/submenu'

View File

@ -12,7 +12,6 @@ json.build_lists @build_lists do |build_list|
json.version_release get_version_release(build_list) json.version_release get_version_release(build_list)
json.updated_at build_list.updated_at json.updated_at build_list.updated_at
json.updated_at_utc build_list.updated_at.strftime('%Y-%m-%d %H:%M:%S UTC')
users |= [build_list.user] users |= [build_list.user]
projects |= [build_list.project] projects |= [build_list.project]
platforms |= [build_list.build_for_platform, build_list.save_to_platform] platforms |= [build_list.build_for_platform, build_list.save_to_platform]
@ -39,6 +38,7 @@ json.dictionary do
end end
end end
json.server_status @build_server_status json.server_status @build_server_status
json.filter @filter.try(:options) json.filter @filter.try(:options)
json.pages angularjs_will_paginate(@bls) json.page params[:page]
json.build_lists_count @bls.count

View File

@ -65,7 +65,7 @@ Rosa::Application.configure do
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
config.assets.precompile += config.assets.precompile +=
%w(login.css login.js reg_session.css tour.css tour.js gollum/editor/langs/*.js moment/ru.js %w(login.css login.js reg_session.css tour.css tour.js gollum/editor/langs/*.js moment/ru.js
codemirror_editor.js codemirror_editor.css new_application.css new_application.js) codemirror_editor.js codemirror_editor.css new_application.css new_application.js angular-1.2.15-locale_ru-ru.js)
# Compress JavaScripts and CSS. # Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier config.assets.js_compressor = :uglifier

View File

@ -116,12 +116,12 @@ en:
build_server_status: build_server_status:
header: Build server status header: Build server status
amount: '- amount' amount: amount
abf: '-- ABF' abf: ABF
tasks: '- tasks in queue' tasks: tasks in queue
custom: "-- user's" custom: user's
mass_build_tasks: "-- mass build's" mass_build_tasks: mass build's
build_tasks: '- tasks in execution' build_tasks: tasks in execution
rpm_workers: Workers of building rpm_workers: Workers of building
iso_workers: Workers of building iso_workers: Workers of building
publish_workers: Workers of publishing publish_workers: Workers of publishing
@ -178,6 +178,7 @@ en:
show_filter: Show filters show_filter: Show filters
hide_filter: Hide filters hide_filter: Hide filters
filters: Filters
last_build_lists: Last Build Lists last_build_lists: Last Build Lists
recreate_build_list: Recreate Build List recreate_build_list: Recreate Build List

View File

@ -115,12 +115,12 @@ ru:
build_server_status: build_server_status:
header: Статус сборочного сервера header: Статус сборочного сервера
amount: '- количество' amount: количество
abf: '-- ABF' abf: ABF
tasks: '- заданий в очереди' tasks: заданий в очереди
custom: '-- пользовательских' custom: пользовательских
mass_build_tasks: '-- массовой сборки' mass_build_tasks: массовой сборки
build_tasks: '- заданий выполняется' build_tasks: заданий выполняется
rpm_workers: Воркеры сборки rpm_workers: Воркеры сборки
iso_workers: Воркеры сборки iso_workers: Воркеры сборки
publish_workers: Воркеры публикации publish_workers: Воркеры публикации
@ -178,6 +178,7 @@ ru:
show_filter: Показать фильтры show_filter: Показать фильтры
hide_filter: Скрыть фильтры hide_filter: Скрыть фильтры
filters: Фильтры
last_build_lists: Последние сборки last_build_lists: Последние сборки
recreate_build_list: Пересоздать сборку recreate_build_list: Пересоздать сборку

View File

@ -0,0 +1,99 @@
'use strict';
angular.module("ngLocale", [], ["$provide", function($provide) {
var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
$provide.value("$locale", {
"DATETIME_FORMATS": {
"AMPMS": [
"\u0434\u043e \u043f\u043e\u043b\u0443\u0434\u043d\u044f",
"\u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0434\u043d\u044f"
],
"DAY": [
"\u0432\u043e\u0441\u043a\u0440\u0435\u0441\u0435\u043d\u044c\u0435",
"\u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a",
"\u0432\u0442\u043e\u0440\u043d\u0438\u043a",
"\u0441\u0440\u0435\u0434\u0430",
"\u0447\u0435\u0442\u0432\u0435\u0440\u0433",
"\u043f\u044f\u0442\u043d\u0438\u0446\u0430",
"\u0441\u0443\u0431\u0431\u043e\u0442\u0430"
],
"MONTH": [
"\u044f\u043d\u0432\u0430\u0440\u044f",
"\u0444\u0435\u0432\u0440\u0430\u043b\u044f",
"\u043c\u0430\u0440\u0442\u0430",
"\u0430\u043f\u0440\u0435\u043b\u044f",
"\u043c\u0430\u044f",
"\u0438\u044e\u043d\u044f",
"\u0438\u044e\u043b\u044f",
"\u0430\u0432\u0433\u0443\u0441\u0442\u0430",
"\u0441\u0435\u043d\u0442\u044f\u0431\u0440\u044f",
"\u043e\u043a\u0442\u044f\u0431\u0440\u044f",
"\u043d\u043e\u044f\u0431\u0440\u044f",
"\u0434\u0435\u043a\u0430\u0431\u0440\u044f"
],
"SHORTDAY": [
"\u0432\u0441",
"\u043f\u043d",
"\u0432\u0442",
"\u0441\u0440",
"\u0447\u0442",
"\u043f\u0442",
"\u0441\u0431"
],
"SHORTMONTH": [
"\u044f\u043d\u0432.",
"\u0444\u0435\u0432\u0440.",
"\u043c\u0430\u0440\u0442\u0430",
"\u0430\u043f\u0440.",
"\u043c\u0430\u044f",
"\u0438\u044e\u043d\u044f",
"\u0438\u044e\u043b\u044f",
"\u0430\u0432\u0433.",
"\u0441\u0435\u043d\u0442.",
"\u043e\u043a\u0442.",
"\u043d\u043e\u044f\u0431.",
"\u0434\u0435\u043a."
],
"fullDate": "EEEE, d MMMM y\u00a0'\u0433'.",
"longDate": "d MMMM y\u00a0'\u0433'.",
"medium": "dd.MM.yyyy H:mm:ss",
"mediumDate": "dd.MM.yyyy",
"mediumTime": "H:mm:ss",
"short": "dd.MM.yy H:mm",
"shortDate": "dd.MM.yy",
"shortTime": "H:mm"
},
"NUMBER_FORMATS": {
"CURRENCY_SYM": "\u0440\u0443\u0431.",
"DECIMAL_SEP": ",",
"GROUP_SEP": "\u00a0",
"PATTERNS": [
{
"gSize": 3,
"lgSize": 3,
"macFrac": 0,
"maxFrac": 3,
"minFrac": 0,
"minInt": 1,
"negPre": "-",
"negSuf": "",
"posPre": "",
"posSuf": ""
},
{
"gSize": 3,
"lgSize": 3,
"macFrac": 0,
"maxFrac": 2,
"minFrac": 2,
"minInt": 1,
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
"id": "ru-ru",
"pluralCat": function (n) { if (n % 10 == 1 && n % 100 != 11) { return PLURAL_CATEGORY.ONE; } if (n == (n | 0) && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) { return PLURAL_CATEGORY.FEW; } if (n % 10 == 0 || n == (n | 0) && n % 10 >= 5 && n % 10 <= 9 || n == (n | 0) && n % 100 >= 11 && n % 100 <= 14) { return PLURAL_CATEGORY.MANY; } return PLURAL_CATEGORY.OTHER;}
});
}]);