From 7eb5b5e395c8587ef2d58b91fdf5cfbf3c4f1bbb Mon Sep 17 00:00:00 2001 From: Alexander Machehin Date: Mon, 26 May 2014 23:42:27 +0600 Subject: [PATCH] [#369] monitoring page; some fixes --- .../javascripts/angular-new/config.js.erb | 29 ++- .../controllers/activity_controller.js | 29 ++- .../controllers/build_lists_controller.js.erb | 74 +++++++- .../controllers/rosa_abf_controller.js | 7 +- .../models/build_list.js.erb | 2 +- app/assets/javascripts/new_application.js | 10 +- app/assets/stylesheets/custom_bootstrap.scss | 32 +++- .../projects/build_lists_controller.rb | 38 ++-- app/views/home/activity.html.haml | 7 - app/views/layouts/bootstrap.html.haml | 7 +- app/views/layouts/menu/_new_top.html.haml | 4 +- .../projects/build_lists/_filter.html.haml | 179 ++++++++---------- .../build_lists/_server_status.html.haml | 78 ++++---- .../projects/build_lists/index.html.haml | 126 ++++++------ .../projects/build_lists/index.json.jbuilder | 8 +- config/environments/production.rb | 2 +- config/locales/models/build_list.en.yml | 13 +- config/locales/models/build_list.ru.yml | 13 +- .../angular-1.2.15-locale_ru-ru.js | 99 ++++++++++ 19 files changed, 484 insertions(+), 273 deletions(-) rename app/assets/javascripts/{angularjs => angular-new}/controllers/build_lists_controller.js.erb (67%) rename app/assets/javascripts/{angularjs => angular-new}/models/build_list.js.erb (99%) create mode 100644 vendor/assets/javascripts/angular-1.2.15-locale_ru-ru.js diff --git a/app/assets/javascripts/angular-new/config.js.erb b/app/assets/javascripts/angular-new/config.js.erb index 4e50a39b7..353bc602f 100644 --- a/app/assets/javascripts/angular-new/config.js.erb +++ b/app/assets/javascripts/angular-new/config.js.erb @@ -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', '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 = { 'ru' : 'ru-ru', 'en' : 'en-us' @@ -17,4 +16,26 @@ RosaABF.factory("LocalesHelper", ['$locale', function($locale) { RosaABF.config(function(cfpLoadingBarProvider) { cfpLoadingBarProvider.includeSpinner = false; -}); \ No newline at end of file +}); + +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); diff --git a/app/assets/javascripts/angular-new/controllers/activity_controller.js b/app/assets/javascripts/angular-new/controllers/activity_controller.js index f91922d68..790a4f99d 100644 --- a/app/assets/javascripts/angular-new/controllers/activity_controller.js +++ b/app/assets/javascripts/angular-new/controllers/activity_controller.js @@ -1,13 +1,13 @@ -RosaABF.controller('ActivityCtrl', ['$scope', '$http', '$timeout', '$q', '$filter', - function($scope, $http, $timeout, $q, $filter) { - $scope.activity_tab = { title: 'activity_menu.activity_feed', active: false, filter: 'all', +RosaABF.controller('ActivityCtrl', ['$scope', '$http', '$timeout', '$q', '$filter', '$location', + function($scope, $http, $timeout, $q, $filter, $location) { + $scope.activity_tab = { title: 'activity_menu.activity_feed', filter: 'all', 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', all_count: 0, assigned_count: 0, created_count: 0, closed_count: 0 }, sort: { sort: 'updated', direction: 'desc', updated_class: 'fa-chevron-up' }, 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', all_count: 0, assigned_count: 0, created_count: 0, closed_count: 0 }, 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){ var cur_tab = $scope.$eval(tab+'_tab'); + var tmp = $location.path(); if (tab === 'activity') { + $scope.activity_tab.active = true; + $scope.tracker_tab.active = false; + $scope.pull_requests_tab.active = false; $scope.getActivityContent(); + if($location.path() !== '/') { + $location.path('/').replace() + }; } 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.getIssuesContent(); + if($location.path() !== '/issues') { + $location.path('/issues').replace() + }; } 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.getIssuesContent(); + if($location.path() !== '/pull_requests') { + $location.path('/pull_requests').replace() + }; }; }; diff --git a/app/assets/javascripts/angularjs/controllers/build_lists_controller.js.erb b/app/assets/javascripts/angular-new/controllers/build_lists_controller.js.erb similarity index 67% rename from app/assets/javascripts/angularjs/controllers/build_lists_controller.js.erb rename to app/assets/javascripts/angular-new/controllers/build_lists_controller.js.erb index f9d6da334..53f47e8b6 100644 --- a/app/assets/javascripts/angularjs/controllers/build_lists_controller.js.erb +++ b/app/assets/javascripts/angular-new/controllers/build_lists_controller.js.erb @@ -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.first_run = true; @@ -22,16 +24,70 @@ RosaABF.controller('BuildListsController', ['$scope', '$http', '$location', '$ti <%=BuildList::FAILED_PUBLISH%>: 1, <%=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 - $("#monitoring_filter").on('submit', function(){ return false; }); + $scope.clear = function () { + //$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() { // Disable 'Search' button $scope.isRequest = true; - + $http.get(Routes.build_lists_path({format: 'json'}), {params: $location.search()}).success(function(results) { // Render Server status $scope.server_status = results.server_status; @@ -73,11 +129,12 @@ RosaABF.controller('BuildListsController', ['$scope', '$http', '$location', '$ti $scope.build_lists.push(bl); } }); - // Shows groups which have been opened before + // Shows groups which have been opened before _.each(to_open, function(bl){ $scope.showRelated(bl, true); }); // Render pagination - $scope.pages = results.pages; + $scope.page = results.page; + $scope.build_lists_count = results.build_lists_count; // Enable 'Search' button $scope.isRequest = false; }).error(function(data, status, headers, config) { @@ -94,7 +151,8 @@ RosaABF.controller('BuildListsController', ['$scope', '$http', '$location', '$ti // Waits for render of build_lists if (!disable_effect) $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); }); } @@ -156,4 +214,4 @@ RosaABF.controller('BuildListsController', ['$scope', '$http', '$location', '$ti $scope.updateParams(); // Waits for render of filters $timeout($scope.refresh, 100); -}]); \ No newline at end of file +}]); diff --git a/app/assets/javascripts/angular-new/controllers/rosa_abf_controller.js b/app/assets/javascripts/angular-new/controllers/rosa_abf_controller.js index b4f545621..d3f5b26cc 100644 --- a/app/assets/javascripts/angular-new/controllers/rosa_abf_controller.js +++ b/app/assets/javascripts/angular-new/controllers/rosa_abf_controller.js @@ -1,7 +1,8 @@ -RosaABF.controller('RosaABFController', ['$scope', 'LocalesHelper', function($scope, LocalesHelper) { - - $scope.init = function(locale) { +RosaABF.controller('RosaABFController', ['$scope', 'LocalesHelper', 'SoundNotificationsHelper', + function($scope, LocalesHelper, SoundNotificationsHelper) { + $scope.init = function(locale, sound_notifications) { LocalesHelper.setLocale(locale); moment.lang(locale); + SoundNotificationsHelper.enabled(sound_notifications); } }]); diff --git a/app/assets/javascripts/angularjs/models/build_list.js.erb b/app/assets/javascripts/angular-new/models/build_list.js.erb similarity index 99% rename from app/assets/javascripts/angularjs/models/build_list.js.erb rename to app/assets/javascripts/angular-new/models/build_list.js.erb index 9941ef3e8..a54471938 100644 --- a/app/assets/javascripts/angularjs/models/build_list.js.erb +++ b/app/assets/javascripts/angular-new/models/build_list.js.erb @@ -50,7 +50,7 @@ var BuildList = function(atts, dictionary) { case <%=BuildList::BUILD_ERROR%>: case <%=BuildList::FAILED_PUBLISH%>: 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 default: self.status_color = 'nocolor'; } diff --git a/app/assets/javascripts/new_application.js b/app/assets/javascripts/new_application.js index a6026af1a..01e197f6e 100644 --- a/app/assets/javascripts/new_application.js +++ b/app/assets/javascripts/new_application.js @@ -1,11 +1,11 @@ //= require jquery //= require jquery_ujs +//= require jquery-ui //= require js-routes // Loads all Bootstrap javascripts //= require bootstrap -// require unstable/angular //= require angular //= require angular-sanitize //= require angular-ui-bootstrap-tpls @@ -13,8 +13,16 @@ //= require angular-i18n //= require angularjs/locales +//= require angular-resource +//= require ng-rails-csrf +//= require angular-cookies +//= require soundmanager2-nodebug-jsmin + //= require moment //= require angularjs/angular-moment //= require_tree ./angular-new //= require loading-bar + +//= require underscore + diff --git a/app/assets/stylesheets/custom_bootstrap.scss b/app/assets/stylesheets/custom_bootstrap.scss index 1da1f072b..93f72dc81 100644 --- a/app/assets/stylesheets/custom_bootstrap.scss +++ b/app/assets/stylesheets/custom_bootstrap.scss @@ -18,7 +18,7 @@ a.navbar-brand, .navbar .navbar-right .avatar { padding-top: ($navbar-height - $logo-mini-height) / 2; } -.nav a { +.nav a, .pagination a, .carousel a, .panel-title a { cursor: pointer; } @@ -52,3 +52,33 @@ footer { [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { 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; + } +} \ No newline at end of file diff --git a/app/controllers/projects/build_lists_controller.rb b/app/controllers/projects/build_lists_controller.rb index 96254d147..f2fe8c058 100644 --- a/app/controllers/projects/build_lists_controller.rb +++ b/app/controllers/projects/build_lists_controller.rb @@ -1,4 +1,5 @@ class Projects::BuildListsController < Projects::BaseController + layout 'bootstrap', only: [:index] include FileStoreHelper NESTED_ACTIONS = [:index, :new, :create] @@ -23,20 +24,21 @@ class Projects::BuildListsController < Projects::BaseController format.html format.json do @filter = BuildList::Filter.new(@project, current_user, current_ability, params[:filter] || {}) - @bls = @filter.find.recent - .paginate( - :page => (params[:page].to_i == 0 ? nil : params[:page]), - per_page: BuildList::Filter::PER_PAGE.include?(params[:per_page].to_i) ? params[:per_page].to_i : 25 - ) + params[:page] = params[:page].to_i == 0 ? nil : params[:page] + params[:per_page] = if BuildList::Filter::PER_PAGE.include? params[:per_page].to_i + params[:per_page].to_i + 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 - .includes( - :save_to_platform, - :save_to_repository, - :build_for_platform, - :user, - :source_packages, - project: :project_statistics - ) + .includes(:save_to_platform, + :save_to_repository, + :build_for_platform, + :user, + :source_packages, + project: :project_statistics) @build_server_status = AbfWorker::StatusInspector.projects_status end @@ -45,7 +47,7 @@ class Projects::BuildListsController < Projects::BaseController def new 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 render :new 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.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 build_lists << @build_list - notices << t("flash.build_list.saved", flash_options) + notices << t('flash.build_list.saved', flash_options) else - errors << t("flash.build_list.save_error", flash_options) + errors << t('flash.build_list.save_error', flash_options) 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? @build_list ||= BuildList.new flash[:error] = errors.join('
').html_safe diff --git a/app/views/home/activity.html.haml b/app/views/home/activity.html.haml index 4de87df0a..2cd172b58 100644 --- a/app/views/home/activity.html.haml +++ b/app/views/home/activity.html.haml @@ -1,12 +1,5 @@ -set_meta_tags title: nil -.voffset20 .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}')" } %tabset.offset20 = render 'activity_tab' diff --git a/app/views/layouts/bootstrap.html.haml b/app/views/layouts/bootstrap.html.haml index f148acae3..69c1a9164 100644 --- a/app/views/layouts/bootstrap.html.haml +++ b/app/views/layouts/bootstrap.html.haml @@ -7,11 +7,14 @@ - 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']) - %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' %article.container-fluid .row= yield = render 'layouts/menu/new_bottom' = stylesheet_link_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' diff --git a/app/views/layouts/menu/_new_top.html.haml b/app/views/layouts/menu/_new_top.html.haml index fa276c8ff..f99f4bd77 100644 --- a/app/views/layouts/menu/_new_top.html.haml +++ b/app/views/layouts/menu/_new_top.html.haml @@ -20,9 +20,9 @@ .form-group = text_field_tag 'query', @query, placeholder: t('layout.search.header'), class: 'form-control' %ul.nav.navbar-nav.navbar-right - %li - .avatar= image_tag avatar_url(current_user), alt: 'avatar', height: "32", class: 'img-responsive' - if current_user + %li + .avatar= image_tag avatar_url(current_user), alt: 'avatar', height: "32", class: 'img-responsive' %li.dropdown %a.dropdown-toggle{ "data-toggle" => "dropdown", href: "#" } = current_user.uname diff --git a/app/views/projects/build_lists/_filter.html.haml b/app/views/projects/build_lists/_filter.html.haml index 1e4b93550..909504edd 100644 --- a/app/views/projects/build_lists/_filter.html.haml +++ b/app/views/projects/build_lists/_filter.html.haml @@ -1,106 +1,81 @@ --html_options = {class: 'sel80 medium input_cleanse', tabindex: 2} -.top.box - .filter - = form_for :filter, html: {class: :form, id: 'monitoring_filter', 'ng-submit' => 'refresh(true)'}, authenticity_token: false do |f| - .column - = render 'server_status' - = hidden_field_tag :name_with_owner, @project.try(:name_with_owner) - .reloader +-html_options = { class: 'form-control' } +%accordion{ 'close-others' => 'false', 'ng-cloak' => true } + %accordion-group{ heading: t('layout.build_lists.build_server_status.header'), 'is-open' => 'isOpenServerStatus', + 'ng-click' => 'toggleServerStatus()' } + = render 'server_status' + + %accordion-group{ heading: t('layout.build_lists.filters'), 'is-open' => 'isOpenFilters', + '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 = check_box_tag :autoreload, true, true = t 'layout.autoreload_page' - .column - - if current_user - .bordered.nopadding - %h3.medium= t("layout.build_lists.ownership.header") - =f.hidden_field :ownership, value: '{{params.filter.ownership}}' + .col-md-4.col-sm-6.col-md-offset-4.offset20 + .btn-group.btn-group-justified + .btn-group{ 'ng-show' => 'isRequest' } + %button.btn.btn-default{ type: 'button', disabled: true } + = t('layout.processing') + .btn-group{ 'ng-hide' => 'isRequest' } + %button.btn.btn-default{ type: 'button', 'ng-click' => 'refresh(true)' } + = t('layout.search.header') .btn-group - - ['owned', (@project ? nil : 'related'), 'everything'].compact.each do |ownership| - -options = {'ng-class' =>"{active: params.filter.ownership == '#{ownership}'}",value: ownership, style: (@project ? 'width:50%;' : '')} - %button.btn.ownership{options}= t "layout.build_lists.ownership.#{ownership}" - %h3.medium= t 'number_rows' - =hidden_field_tag :per_page, '{{params.per_page}}' - =hidden_field_tag :page, '{{params.page}}' - .btn-group - -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 - } + %button.btn.btn-default{ type: 'button', 'ng-click' => 'clear()' }= t('reset') + -if @project and can?(:create, @project.build_lists.build) + .btn-group + %button.btn.btn-default{ id: 'filter_new_build', type: 'button', + onclick: "location.href='#{new_project_build_list_path(@project)}'", + value: t('layout.build_lists.new_header') } + = hidden_field_tag :name_with_owner, @project.try(:name_with_owner) diff --git a/app/views/projects/build_lists/_server_status.html.haml b/app/views/projects/build_lists/_server_status.html.haml index e1d56b0ab..db3a15786 100644 --- a/app/views/projects/build_lists/_server_status.html.haml +++ b/app/views/projects/build_lists/_server_status.html.haml @@ -1,43 +1,35 @@ -.bordered.nopadding - %h3.medium= t('layout.build_lists.build_server_status.header') - - .table - .lefter= t("layout.build_lists.build_server_status.rpm_workers") - .both - .table - .lefter= t("layout.build_lists.build_server_status.amount") - .both - .table - .lefter= t("layout.build_lists.build_server_status.abf") - .righter {{server_status.rpm.workers}} - .both - .table - .lefter= t("layout.build_lists.build_server_status.custom") - .righter {{server_status.rpm.other_workers}} - .both - .table - .lefter= t("layout.build_lists.build_server_status.tasks") - .both - - [['custom', :default_tasks], ['mass_build_tasks', :low_tasks], ['build_tasks', :build_tasks]].each do |label, metric| - .table - .lefter= t("layout.build_lists.build_server_status.#{label}") - .righter= "{{server_status.rpm.#{metric}}}" - .both - %br - - .table - .lefter= t("layout.build_lists.build_server_status.publish_workers") - .both - .table - .lefter= t("layout.build_lists.build_server_status.amount") - .righter= "{{server_status.publish.workers}}" - .both - - [:tasks, :build_tasks].each do |metric| - .table - .lefter= t("layout.build_lists.build_server_status.#{metric}") - .righter= "{{server_status.publish.#{metric}}}" - .both - %br - - - +.row + .col-md-4.col-sm-6 + %h5= t 'layout.build_lists.build_server_status.rpm_workers' + %ul.list-unstyled + %li + = t 'layout.build_lists.build_server_status.amount' + %ul + %li + = t 'layout.build_lists.build_server_status.abf' + %span.bg-primary.badge.pull-right {{server_status.rpm.workers}} + %li + = t 'layout.build_lists.build_server_status.custom' + %span.bg-primary.badge.pull-right {{server_status.rpm.other_workers}} + .col-md-4.col-sm-6 + %h5= t 'layout.build_lists.build_server_status.tasks' + %ul.list-unstyled + %li + %ul + - [['custom', :default_tasks], ['mass_build_tasks', :low_tasks]].each do |label, metric| + %li + = t "layout.build_lists.build_server_status.#{label}" + %span.bg-primary.badge.pull-right {{server_status.rpm.#{metric}}} + %li + = t 'layout.build_lists.build_server_status.build_tasks' + %span.bg-primary.badge.pull-right {{server_status.rpm.build_tasks}} + .col-md-4.col-sm-6 + %h5= t 'layout.build_lists.build_server_status.publish_workers' + %ul.list-unstyled + %li + = t 'layout.build_lists.build_server_status.amount' + %span.bg-primary.badge.pull-right {{server_status.publish.workers}} + - [:tasks, :build_tasks].each do |metric| + %li + = t "layout.build_lists.build_server_status.#{metric}" + %span.bg-primary.badge.pull-right {{server_status.publish.#{metric}}} diff --git a/app/views/projects/build_lists/index.html.haml b/app/views/projects/build_lists/index.html.haml index dc76338d8..4ff56d208 100644 --- a/app/views/projects/build_lists/index.html.haml +++ b/app/views/projects/build_lists/index.html.haml @@ -1,73 +1,85 @@ -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"} - %thead - %tr - %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'} + %a{'ng-href' => '{{bl.url}}' } {{bl.id}} + %div{'ng-show' => 'bl.hasRelated'} + %div{'ng-repeat' => 'related in bl.related', 'ng-class' => '"status bg-" + related.status_color'}   - / id - %td.build-list-statuses - %a.expand{'ng-show' => 'bl.hasRelated'} - %span.icon-chevron-down{'ng-show' => 'bl.relatedHidden', 'ng-click' => 'showRelated(bl)'} - %span.icon-chevron-up{'ng-hide' => 'bl.relatedHidden', 'ng-click' => 'hideRelated(bl)'} - %a{'ng-href' => '{{bl.url}}' } {{bl.id}} - %div{'ng-show' => 'bl.hasRelated'} - .status{'ng-repeat' => 'related in bl.related', class: '{{related.status_color}}'}   + / status + %td + {{bl.human_status | i18n}} + %br + %time{'ng-show' => 'bl.duration'} + {{bl.duration}} + %time{'ng-show' => 'bl.average_build_time'} + \/{{bl.average_build_time}} - / status - %td - {{bl.human_status | i18n}} - %br - %time{'ng-show' => 'bl.duration'} - {{bl.duration}} - %time{'ng-show' => 'bl.average_build_time'} - \/{{bl.average_build_time}} + / project + %td.centered{'ng-hide' => 'bl.project', colspan: 2} + = t('layout.projects.unexisted_project') + %td{'ng-show' => 'bl.project'} + %a{'ng-href' => '{{bl.project.url}}' } {{bl.project.name_with_owner}} - / project - %td.centered{'ng-hide' => 'bl.project', colspan: 2} - = t('layout.projects.unexisted_project') - %td{'ng-show' => 'bl.project'} - %a{'ng-href' => '{{bl.project.url}}' } {{bl.project.name_with_owner}} + / diff + %td + %a{'ng-href' => '{{bl.version_link_url}}', 'ng-show' => 'bl.project'} + {{bl.version_link_text}} - / diff - %td - %a{'ng-href' => '{{bl.version_link_url}}', 'ng-show' => 'bl.project'} - {{bl.version_link_text}} + / project_version + %td {{bl.version_release}} - / project_version - %td {{bl.version_release}} + / save_to_repository + %td + %a{'ng-href' => '{{bl.save_to_repository_url}}' } {{bl.save_to_repository_name}} - / save_to_repository - %td - %a{'ng-href' => '{{bl.save_to_repository_url}}' } {{bl.save_to_repository_name}} + / arch_short + %td{'ng-show' => 'bl.arch'} {{bl.arch.name}} + %td{'ng-hide' => 'bl.arch'}= t('layout.arches.unexisted_arch') - / arch_short - %td{'ng-show' => 'bl.arch'} {{bl.arch.name}} - %td{'ng-hide' => 'bl.arch'}= t('layout.arches.unexisted_arch') + / user + %td + %a{'ng-href' => '{{bl.user.url}}' } {{bl.user.fullname}} - / user - %td - %a{'ng-href' => '{{bl.user.url}}' } {{bl.user.fullname}} + / updated_at + %td{'am-time-ago' => 'bl.updated_at', title: "{{bl.updated_at | amDateFormat:'ddd, LLL'}}"} - / updated_at - %td{'am-time-ago' => 'bl.updated_at', title: '{{bl.updated_at_utc}}'} + %pagination{ 'boundary-links' => 'true', + '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' diff --git a/app/views/projects/build_lists/index.json.jbuilder b/app/views/projects/build_lists/index.json.jbuilder index 42d3d4fe9..5287e8b30 100644 --- a/app/views/projects/build_lists/index.json.jbuilder +++ b/app/views/projects/build_lists/index.json.jbuilder @@ -12,7 +12,6 @@ json.build_lists @build_lists do |build_list| json.version_release get_version_release(build_list) 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] projects |= [build_list.project] platforms |= [build_list.build_for_platform, build_list.save_to_platform] @@ -39,6 +38,7 @@ json.dictionary do end end -json.server_status @build_server_status -json.filter @filter.try(:options) -json.pages angularjs_will_paginate(@bls) +json.server_status @build_server_status +json.filter @filter.try(:options) +json.page params[:page] +json.build_lists_count @bls.count diff --git a/config/environments/production.rb b/config/environments/production.rb index d004d608e..6623aa5ef 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -65,7 +65,7 @@ Rosa::Application.configure do # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) config.assets.precompile += %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. config.assets.js_compressor = :uglifier diff --git a/config/locales/models/build_list.en.yml b/config/locales/models/build_list.en.yml index da920d984..e20102451 100644 --- a/config/locales/models/build_list.en.yml +++ b/config/locales/models/build_list.en.yml @@ -116,12 +116,12 @@ en: build_server_status: header: Build server status - amount: '- amount' - abf: '-- ABF' - tasks: '- tasks in queue' - custom: "-- user's" - mass_build_tasks: "-- mass build's" - build_tasks: '- tasks in execution' + amount: amount + abf: ABF + tasks: tasks in queue + custom: user's + mass_build_tasks: mass build's + build_tasks: tasks in execution rpm_workers: Workers of building iso_workers: Workers of building publish_workers: Workers of publishing @@ -178,6 +178,7 @@ en: show_filter: Show filters hide_filter: Hide filters + filters: Filters last_build_lists: Last Build Lists recreate_build_list: Recreate Build List diff --git a/config/locales/models/build_list.ru.yml b/config/locales/models/build_list.ru.yml index 4ea7165e5..7b7a04132 100644 --- a/config/locales/models/build_list.ru.yml +++ b/config/locales/models/build_list.ru.yml @@ -115,12 +115,12 @@ ru: build_server_status: header: Статус сборочного сервера - amount: '- количество' - abf: '-- ABF' - tasks: '- заданий в очереди' - custom: '-- пользовательских' - mass_build_tasks: '-- массовой сборки' - build_tasks: '- заданий выполняется' + amount: количество + abf: ABF + tasks: заданий в очереди + custom: пользовательских + mass_build_tasks: массовой сборки + build_tasks: заданий выполняется rpm_workers: Воркеры сборки iso_workers: Воркеры сборки publish_workers: Воркеры публикации @@ -178,6 +178,7 @@ ru: show_filter: Показать фильтры hide_filter: Скрыть фильтры + filters: Фильтры last_build_lists: Последние сборки recreate_build_list: Пересоздать сборку diff --git a/vendor/assets/javascripts/angular-1.2.15-locale_ru-ru.js b/vendor/assets/javascripts/angular-1.2.15-locale_ru-ru.js new file mode 100644 index 000000000..e963e9365 --- /dev/null +++ b/vendor/assets/javascripts/angular-1.2.15-locale_ru-ru.js @@ -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;} +}); +}]); \ No newline at end of file