New interface

This commit is contained in:
Wedge 2016-04-29 17:10:30 +03:00
parent 8e7cf0dcaf
commit 71104f61bb
135 changed files with 2899 additions and 3008 deletions

10
Gemfile
View File

@ -31,8 +31,6 @@ gem 'sprockets'
gem 'will_paginate' gem 'will_paginate'
gem 'meta-tags', require: 'meta_tags' gem 'meta-tags', require: 'meta_tags'
gem 'haml-rails' gem 'haml-rails'
gem 'jquery-rails'
gem 'jquery-migrate-rails'
gem 'ruby-haml-js' gem 'ruby-haml-js'
gem 'slim' gem 'slim'
gem 'simple_form', '3.1.0.rc2' gem 'simple_form', '3.1.0.rc2'
@ -45,27 +43,21 @@ gem 'ohm-expire', '~> 0.1.3'
gem 'pygments.rb' gem 'pygments.rb'
gem 'ffi'
gem 'attr_encrypted' gem 'attr_encrypted'
# AngularJS related stuff # AngularJS related stuff
gem 'angular-rails-templates'
gem 'underscore-rails' gem 'underscore-rails'
gem 'angularjs-rails', '~> 1.3.14'
gem 'ng-rails-csrf' gem 'ng-rails-csrf'
gem 'momentjs-rails'
gem 'angular-i18n' gem 'angular-i18n'
gem 'js-routes' gem 'js-routes'
gem 'soundmanager-rails' gem 'soundmanager-rails'
gem 'angular-ui-bootstrap-rails'
gem 'angular-rails-templates'
gem 'ngmin-rails' gem 'ngmin-rails'
gem 'time_diff' gem 'time_diff'
gem 'sass-rails' gem 'sass-rails'
gem 'coffee-rails' gem 'coffee-rails'
gem 'bootstrap-sass'
gem 'font-awesome-rails' gem 'font-awesome-rails'
gem 'compass-rails' gem 'compass-rails'

View File

@ -76,16 +76,11 @@ GEM
railties (>= 3.1) railties (>= 3.1)
sprockets (~> 2) sprockets (~> 2)
tilt tilt
angular-ui-bootstrap-rails (0.13.0)
angularjs-rails (1.3.14)
arbre (1.0.3) arbre (1.0.3)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
arel (6.0.0) arel (6.0.0)
attr_encrypted (1.3.4) attr_encrypted (1.3.4)
encryptor (>= 1.3.0) encryptor (>= 1.3.0)
autoprefixer-rails (5.2.0)
execjs
json
bcrypt (3.1.10) bcrypt (3.1.10)
better_errors (2.1.1) better_errors (2.1.1)
coderay (>= 1.0.0) coderay (>= 1.0.0)
@ -93,9 +88,6 @@ GEM
rack (>= 0.9.0) rack (>= 0.9.0)
binding_of_caller (0.7.2) binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
bootstrap-sass (3.3.4.1)
autoprefixer-rails (>= 5.0.0.1)
sass (>= 3.2.19)
bourbon (4.2.3) bourbon (4.2.3)
sass (~> 3.4) sass (~> 3.4)
thor thor
@ -208,7 +200,6 @@ GEM
jbuilder (2.2.16) jbuilder (2.2.16)
activesupport (>= 3.0.0, < 5) activesupport (>= 3.0.0, < 5)
multi_json (~> 1.2) multi_json (~> 1.2)
jquery-migrate-rails (1.2.1)
jquery-rails (4.0.4) jquery-rails (4.0.4)
rails-dom-testing (~> 1.0) rails-dom-testing (~> 1.0)
railties (>= 4.2.0) railties (>= 4.2.0)
@ -257,8 +248,6 @@ GEM
modware (0.1.2) modware (0.1.2)
its-it its-it
key_struct (~> 0.4) key_struct (~> 0.4)
momentjs-rails (2.10.2)
railties (>= 3.1)
mono_logger (1.1.0) mono_logger (1.1.0)
multi_json (1.11.1) multi_json (1.11.1)
multipart-post (2.0.0) multipart-post (2.0.0)
@ -581,12 +570,9 @@ DEPENDENCIES
ancestry ancestry
angular-i18n angular-i18n
angular-rails-templates angular-rails-templates
angular-ui-bootstrap-rails
angularjs-rails (~> 1.3.14)
attr_encrypted attr_encrypted
better_errors better_errors
binding_of_caller binding_of_caller
bootstrap-sass
cape cape
capistrano capistrano
capistrano_colors capistrano_colors
@ -596,22 +582,18 @@ DEPENDENCIES
devise devise
factory_girl_rails factory_girl_rails
faraday-http-cache faraday-http-cache
ffi
font-awesome-rails font-awesome-rails
friendly_id friendly_id
haml-rails haml-rails
highline (~> 1.6.20) highline (~> 1.6.20)
hirb hirb
jbuilder jbuilder
jquery-migrate-rails
jquery-rails
js-routes js-routes
localeapp localeapp
mailcatcher mailcatcher
meta-tags meta-tags
meta_request meta_request
mock_redis mock_redis
momentjs-rails
newrelic_rpm newrelic_rpm
ng-rails-csrf ng-rails-csrf
ngmin-rails ngmin-rails

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 981 B

View File

@ -1,6 +1,5 @@
var RosaABF = angular.module('RosaABF', ['ui.bootstrap', 'angular-i18n', 'angularMoment', var RosaABF = angular.module('RosaABF', ['ui.bootstrap', 'angular-i18n', 'angularMoment', 'templates',
'chieffancypants.loadingBar', 'ngSanitize', 'templates', 'ngResource', 'ng-rails-csrf', 'ngCookies', 'ngSanitize']);
'ngResource', 'ng-rails-csrf', 'ngCookies']);
RosaABF.factory('LocalesHelper', ['$locale', function($locale) { RosaABF.factory('LocalesHelper', ['$locale', function($locale) {
var locales = { var locales = {
@ -14,15 +13,14 @@ RosaABF.factory('LocalesHelper', ['$locale', function($locale) {
} }
}]); }]);
RosaABF.config(function(cfpLoadingBarProvider) { RosaABF.config(['$compileProvider', function ($compileProvider) {
cfpLoadingBarProvider.includeSpinner = false; $compileProvider.debugInfoEnabled(false);
}); }]);
var SoundNotificationsHelper = function() { var SoundNotificationsHelper = function() {
var isOn = true; var isOn = true;
var statusChangedSound = null; var statusChangedSound = null;
soundManager.setup({ soundManager.setup({
// url: '/assets/swf/',
preferFlash: false, preferFlash: false,
onready: function() { onready: function() {
statusChangedSound = soundManager.createSound({url: "<%=asset_path('garbage_shattering.wav')%>"}); statusChangedSound = soundManager.createSound({url: "<%=asset_path('garbage_shattering.wav')%>"});

View File

@ -0,0 +1,190 @@
angular.module("u2i.bootstrap.tpls", ["uib/template/tabs/tab.html", "uib/template/tabs/tabset.html", "uib/template/typeahead/typeahead-match.html",
"uib/template/typeahead/typeahead-popup.html", "uib/template/pagination/pager.html",
"uib/template/pagination/pagination.html", "uib/template/datepicker/datepicker.html",
"uib/template/datepicker/popup.html", "uib/template/datepicker/year.html",
"uib/template/datepicker/month.html", "uib/template/datepicker/day.html"]);
angular.module("uib/template/tabs/tab.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/tabs/tab.html",
"<li ng-class=\"[{active: active, disabled: disabled}, classes]\" class=\"uib-tab nav-item\">\n" +
" <a href ng-click=\"select($event)\" class=\"nav-link\" uib-tab-heading-transclude>{{heading}}</a>\n" +
"</li>\n" +
"");
}]);
angular.module("uib/template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/tabs/tabset.html",
"<div>\n" +
" <ul class=\"nav nav-{{tabset.type || 'tabs'}} bottom-space\" ng-class=\"{'nav-stacked': vertical, 'nav-justified': justified}\" ng-transclude></ul>\n" +
" <div class=\"tab-content\">\n" +
" <div class=\"tab-pane\"\n" +
" ng-repeat=\"tab in tabset.tabs\"\n" +
" ng-class=\"{active: tabset.active === tab.index}\"\n" +
" uib-tab-content-transclude=\"tab\">\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"");
}]);
angular.module("uib/template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/typeahead/typeahead-match.html",
"<a href\n" +
" tabindex=\"-1\"\n" +
" ng-bind-html=\"match.label | uibTypeaheadHighlight:query\"\n" +
" ng-attr-title=\"{{match.label}}\"></a>\n" +
"");
}]);
angular.module("uib/template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/typeahead/typeahead-popup.html",
"<ul class=\"dropdown-menu\" ng-show=\"isOpen() && !moveInProgress\" ng-style=\"{top: position().top+'px', left: position().left+'px'}\" role=\"listbox\" aria-hidden=\"{{!isOpen()}}\">\n" +
" <li ng-repeat=\"match in matches track by $index\" ng-class=\"{active: isActive($index) }\" ng-mouseenter=\"selectActive($index)\" ng-click=\"selectMatch($index, $event)\" role=\"option\" id=\"{{::match.id}}\">\n" +
" <div uib-typeahead-match index=\"$index\" match=\"match\" query=\"query\" template-url=\"templateUrl\"></div>\n" +
" </li>\n" +
"</ul>\n" +
"");
}]);
angular.module("uib/template/pagination/pager.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/pagination/pager.html",
"<ul class=\"pager\">\n" +
" <li ng-class=\"{disabled: noPrevious()||ngDisabled, previous: align}\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
" <li ng-class=\"{disabled: noNext()||ngDisabled, next: align}\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
"</ul>\n" +
"");
}]);
angular.module("uib/template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/pagination/pagination.html",
"<ul class=\"pagination\">\n" +
" <li ng-if=\"::boundaryLinks\" ng-class=\"{disabled: noPrevious()||ngDisabled}\" class=\"pagination-first\"><a href ng-click=\"selectPage(1, $event)\">{{::getText('first')}}</a></li>\n" +
" <li ng-if=\"::directionLinks\" ng-class=\"{disabled: noPrevious()||ngDisabled}\" class=\"pagination-prev\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
" <li ng-repeat=\"page in pages track by $index\" ng-class=\"{active: page.active,disabled: ngDisabled&&!page.active}\" class=\"pagination-page\"><a href ng-click=\"selectPage(page.number, $event)\">{{page.text}}</a></li>\n" +
" <li ng-if=\"::directionLinks\" ng-class=\"{disabled: noNext()||ngDisabled}\" class=\"pagination-next\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
" <li ng-if=\"::boundaryLinks\" ng-class=\"{disabled: noNext()||ngDisabled}\" class=\"pagination-last\"><a href ng-click=\"selectPage(totalPages, $event)\">{{::getText('last')}}</a></li>\n" +
"</ul>\n" +
"");
}]);
angular.module("uib/template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/datepicker/datepicker.html",
"<div class=\"uib-datepicker\" ng-switch=\"datepickerMode\" role=\"application\" ng-keydown=\"keydown($event)\">\n" +
" <uib-daypicker ng-switch-when=\"day\" tabindex=\"0\"></uib-daypicker>\n" +
" <uib-monthpicker ng-switch-when=\"month\" tabindex=\"0\"></uib-monthpicker>\n" +
" <uib-yearpicker ng-switch-when=\"year\" tabindex=\"0\"></uib-yearpicker>\n" +
"</div>\n" +
"");
}]);
angular.module("uib/template/datepicker/day.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/datepicker/day.html",
"<table class=\"uib-daypicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
" <thead>\n" +
" <tr>\n" +
" <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left uib-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
" <th colspan=\"{{::5 + showWeeks}}\"><button id=\"{{::uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm uib-title\" ng-click=\"toggleMode()\" ng-disabled=\"datepickerMode === maxMode\" tabindex=\"-1\"><strong>{{title}}</strong></button></th>\n" +
" <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right uib-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
" </tr>\n" +
" <tr>\n" +
" <th ng-if=\"showWeeks\" class=\"text-center\"></th>\n" +
" <th ng-repeat=\"label in ::labels track by $index\" class=\"text-center\"><small aria-label=\"{{::label.full}}\">{{::label.abbr}}</small></th>\n" +
" </tr>\n" +
" </thead>\n" +
" <tbody>\n" +
" <tr class=\"uib-weeks\" ng-repeat=\"row in rows track by $index\">\n" +
" <td ng-if=\"showWeeks\" class=\"text-center h6\"><em>{{ weekNumbers[$index] }}</em></td>\n" +
" <td ng-repeat=\"dt in row\" class=\"uib-day text-center\" role=\"gridcell\"\n" +
" id=\"{{::dt.uid}}\"\n" +
" ng-class=\"::dt.customClass\">\n" +
" <button type=\"button\" class=\"btn btn-default btn-sm\"\n" +
" uib-is-class=\"\n" +
" 'btn-info' for selectedDt,\n" +
" 'active' for activeDt\n" +
" on dt\"\n" +
" ng-click=\"select(dt.date)\"\n" +
" ng-disabled=\"::dt.disabled\"\n" +
" tabindex=\"-1\"><span ng-class=\"::{'text-muted': dt.secondary, 'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
" </td>\n" +
" </tr>\n" +
" </tbody>\n" +
"</table>\n" +
"");
}]);
angular.module("uib/template/datepicker/month.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/datepicker/month.html",
"<table class=\"uib-monthpicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
" <thead>\n" +
" <tr>\n" +
" <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left uib-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
" <th><button id=\"{{::uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm uib-title\" ng-click=\"toggleMode()\" ng-disabled=\"datepickerMode === maxMode\" tabindex=\"-1\"><strong>{{title}}</strong></button></th>\n" +
" <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right uib-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
" </tr>\n" +
" </thead>\n" +
" <tbody>\n" +
" <tr class=\"uib-months\" ng-repeat=\"row in rows track by $index\">\n" +
" <td ng-repeat=\"dt in row\" class=\"uib-month text-center\" role=\"gridcell\"\n" +
" id=\"{{::dt.uid}}\"\n" +
" ng-class=\"::dt.customClass\">\n" +
" <button type=\"button\" class=\"btn btn-default\"\n" +
" uib-is-class=\"\n" +
" 'btn-info' for selectedDt,\n" +
" 'active' for activeDt\n" +
" on dt\"\n" +
" ng-click=\"select(dt.date)\"\n" +
" ng-disabled=\"::dt.disabled\"\n" +
" tabindex=\"-1\"><span ng-class=\"::{'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
" </td>\n" +
" </tr>\n" +
" </tbody>\n" +
"</table>\n" +
"");
}]);
angular.module("uib/template/datepicker/popup.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/datepicker/popup.html",
"<div>\n" +
" <ul class=\"uib-datepicker-popup dropdown-menu uib-position-measure\" dropdown-nested ng-if=\"isOpen\" ng-keydown=\"keydown($event)\" ng-click=\"$event.stopPropagation()\">\n" +
" <li ng-transclude></li>\n" +
" <li ng-if=\"showButtonBar\" class=\"uib-button-bar\">\n" +
" <span class=\"btn-group pull-left\">\n" +
" <button type=\"button\" class=\"btn btn-sm btn-info uib-datepicker-current\" ng-click=\"select('today', $event)\" ng-disabled=\"isDisabled('today')\">{{ getText('current') }}</button>\n" +
" <button type=\"button\" class=\"btn btn-sm btn-danger uib-clear\" ng-click=\"select(null, $event)\">{{ getText('clear') }}</button>\n" +
" </span>\n" +
" <button type=\"button\" class=\"btn btn-sm btn-success pull-right uib-close\" ng-click=\"close($event)\">{{ getText('close') }}</button>\n" +
" </li>\n" +
" </ul>\n" +
"</div>\n" +
"");
}]);
angular.module("uib/template/datepicker/year.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("uib/template/datepicker/year.html",
"<table class=\"uib-yearpicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
" <thead>\n" +
" <tr>\n" +
" <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left uib-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
" <th colspan=\"{{::columns - 2}}\"><button id=\"{{::uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm uib-title\" ng-click=\"toggleMode()\" ng-disabled=\"datepickerMode === maxMode\" tabindex=\"-1\"><strong>{{title}}</strong></button></th>\n" +
" <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right uib-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
" </tr>\n" +
" </thead>\n" +
" <tbody>\n" +
" <tr class=\"uib-years\" ng-repeat=\"row in rows track by $index\">\n" +
" <td ng-repeat=\"dt in row\" class=\"uib-year text-center\" role=\"gridcell\"\n" +
" id=\"{{::dt.uid}}\"\n" +
" ng-class=\"::dt.customClass\">\n" +
" <button type=\"button\" class=\"btn btn-default\"\n" +
" uib-is-class=\"\n" +
" 'btn-info' for selectedDt,\n" +
" 'active' for activeDt\n" +
" on dt\"\n" +
" ng-click=\"select(dt.date)\"\n" +
" ng-disabled=\"::dt.disabled\"\n" +
" tabindex=\"-1\"><span ng-class=\"::{'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
" </td>\n" +
" </tr>\n" +
" </tbody>\n" +
"</table>\n" +
"");
}]);

View File

@ -1,188 +1,126 @@
RosaABF.controller('BuildListsController', RosaABF.controller('BuildListsController', ['$scope', 'BuildListsService', '$location', '$interval', '$uibModal', 'ProjectSelectService',
['$scope', '$http', '$location', '$timeout', '$cookies', function($scope, BuildListsService, $location, $interval, $uibModal, ProjectSelectService) {
function($scope, $http, $location, $timeout, $cookies) { $scope.params = null;
$scope.build_lists = [];
$scope.isRequest = false; // Disable 'Search' button
$scope.opened = {};
$scope.ProjectSelectService = ProjectSelectService;
$scope.params = null; var refresh, is_autoreload_on;
$scope.first_run = true; var default_filters = {page: '1', per_page: '25', 'ownership': 'owned'};
$scope.server_status = null;
$scope.build_lists = [];
$scope.isRequest = false; // Disable 'Search' button
$scope.pages = [];
$scope.opened = {};
$scope.map_priorities = { $scope.setAutoreload = function(autoreload) {
<%=BuildList::WAITING_FOR_RESPONSE%>: 13, is_autoreload_on = autoreload;
<%=BuildList::BUILD_PENDING%>: 12, if(autoreload) {
<%=BuildList::RERUN_TESTS%>: 11, if(refresh) {
<%=BuildList::BUILD_CANCELING%>: 10, $interval.cancel(refresh);
<%=BuildList::BUILD_CANCELED%>: 9, }
<%=BuildList::BUILD_STARTED%>: 8, refresh = $interval($scope.getBuildLists, 60000);
<%=BuildList::RERUNNING_TESTS%>: 7,
<%=BuildList::BUILD_PUBLISH%>: 6,
<%=BuildList::BUILD_PUBLISHED%>: 5,
<%=BuildList::BUILD_ERROR%>: 4,
<%=BuildList::SUCCESS%>: 3,
<%=BuildList::TESTS_FAILED%>: 2,
<%=BuildList::FAILED_PUBLISH%>: 1,
<%=BuildList::REJECTED_PUBLISH%>: 0
};
$scope.clear = function () {
//$scope.dt = null;
$scope.params = { page: '1',
per_page: '25',
filter: { ownership: 'owned' }
};
};
$scope.init = function init() {
$scope.name_with_owner = $('#name_with_owner').val();
if ($scope.name_with_owner) {
$scope.build_lists_path = Routes.project_build_lists_path($scope.name_with_owner, {format: 'json'});
} }
else { else if(!autoreload && refresh) {
$scope.build_lists_path = Routes.build_lists_path({format: 'json'}); $interval.cancel(refresh);
refresh = null;
} }
//$scope.isOpenServerStatus = $cookies.isOpenServerStatus === 'true' ? true : false;
$scope.isOpenFilters = $cookies.isOpenFilters === 'true' ? true : false;
};
// $scope.$watch('isOpenServerStatus', function(){
// $cookies.isOpenServerStatus = $scope.isOpenServerStatus.toString();
// }, true);
$scope.$watch('isOpenFilters', function(){
$cookies.isOpenFilters = $scope.isOpenFilters.toString();
}, true);
$scope.getBuildLists = function() {
if ( $scope.isRequest) {
return;
}
// Disable 'Search' button
$scope.isRequest = true;
$http.get($scope.build_lists_path, {params: $location.search()}).success(function(results) {
// Render Server status
$scope.$parent.server_status = results.server_status;
// TMP fields
var dictionary = results.dictionary;
var build_lists = [];
var groups = {};
var to_open = [];
// Grouping of build_lists
_.each(results.build_lists, function(r){
var bl = new BuildList(r, dictionary);
var key = bl.project_id + '-';
key += bl.group_id ? bl.group_id : (bl.commit_hash + '-' + bl.user_id);
if (groups[key]) {
groups[key].addRelated(bl);
} else {
groups[key] = bl;
build_lists.push(bl);
if ( bl.id in $scope.opened ) { to_open.push(bl); }
}
});
// Adds all build_lists into the table (group by group)
$scope.build_lists = [];
$scope.opened = {};
_.each(build_lists, function(bl){
if (bl.related.length > 1) {
var sorted_build_lists = _.sortBy(bl.related, function(b) { return $scope.map_priorities[b.status]; });
bl.clearRelated();
var first_in_group = sorted_build_lists[0];
first_in_group.clearRelated();
_.each(sorted_build_lists, function(b){
if (b != first_in_group) { first_in_group.addRelated(b); }
$scope.build_lists.push(b);
});
} else {
$scope.build_lists.push(bl);
}
});
// Shows groups which have been opened before
_.each(to_open, function(bl){ $scope.showRelated(bl, true); });
// Render pagination
$scope.page = results.page;
$scope.total_items = results.total_items;
// Enable 'Search' button
$scope.isRequest = false;
}).error(function(data, status, headers, config) {
// Enable 'Search' button
$scope.isRequest = false;
});;
$scope.first_run = false;
} }
$scope.showRelated = function(build_list, disable_effect) { $scope.getBuildLists = function() {
if ($scope.isRequest) {
return;
}
ProjectSelectService.disable_bl = true;
$scope.isRequest = true;
if(ProjectSelectService.project) {
var project = ProjectSelectService.project;
}
var filter = Object.assign(Object.create(null), default_filters, $location.search());
var fixed_filter = Object.create(null);
_.map(filter, function(val, key) {
if(key != "page" && key != "per_page") {
fixed_filter['filter[' + key + ']'] = val;
}
else {
fixed_filter[key] = val;
}
});
BuildListsService.getBuildLists(fixed_filter, project).then(function(res) {
_.each(res.build_lists, function(item) {
if(item.hasRelated) {
var chevronHtml = "";
_.each(item.related, function(rel) {
chevronHtml += "<div class=\"status bg-"+rel.status_color+"\">&nbsp;</div>";
});
item.chevronHtml = chevronHtml;
}
if(item.id in $scope.opened) {
$scope.showRelated(item);
}
});
$scope.build_lists = res.build_lists;
$scope.page = res.page;
$scope.total_items = res.total_items;
$location.search(Object.assign(filter, res.filter));
$scope.per_page = filter.per_page;
$scope.isRequest = false;
ProjectSelectService.disable_bl = false;
ProjectSelectService.load_project_info = ProjectSelectService.project;
});
}
$scope.clearProject = function() {
ProjectSelectService.project = "";
}
$scope.showRelated = function(build_list) {
build_list.relatedHidden = false; build_list.relatedHidden = false;
$scope.opened[build_list.id] = true;
_.each(build_list.related, function(bl){ _.each(build_list.related, function(bl){
bl.show = true; bl.show = true;
$scope.opened[bl.id] = true;
// Waits for render of build_lists
if (!disable_effect)
$timeout(function() {
var tmp = $('#build-list-' + bl.id + ' td');
$('#build-list-' + bl.id + ' td').effect('highlight', {}, 1000);
}, 100);
}); });
} }
$scope.hideRelated = function(build_list) { $scope.hideRelated = function(build_list) {
build_list.relatedHidden = true; build_list.relatedHidden = true;
delete $scope.opened[build_list.id];
_.each(build_list.related, function(bl){ _.each(build_list.related, function(bl){
bl.show = false; bl.show = false;
delete $scope.opened[bl.id];
}); });
build_list.show = true; build_list.show = true;
} }
$scope.cancelRefresh = null; $scope.openFilters = function() {
$scope.refresh = function(force) { var turn_back_on = is_autoreload_on;
if ($('#autoreload').is(':checked') || force) { $scope.setAutoreload(false);
var params = {};
_.each($("#monitoring_filter").serializeArray(), function(a){ var FilterModalInstance = $uibModal.open({
if (a.value) { params[a.name] = a.value; } animation: $scope.animationsEnabled,
}); templateUrl: 'build_list_filters.html',
$location.search(params); controller: 'FiltersInstanceController',
$scope.getBuildLists(); size: 'lg',
} resolve: {
if (!force) params: function() {
$scope.cancelRefresh = $timeout($scope.refresh, 60000); return $location.search();
} }
$scope.$on('$locationChangeSuccess', function(event) {
$scope.updateParams();
if (!$scope.first_run) { $scope.getBuildLists(); }
});
$scope.updateParams = function() {
var params = $location.search();
$scope.params = {
page: params.page || 1,
per_page: params.per_page || 25,
filter: {
ownership: params['filter[ownership]'] || 'owned',
status: params['filter[status]'],
save_to_platform_id: params['filter[save_to_platform_id]'],
arch_id: params['filter[arch_id]'],
mass_build_id: params['filter[mass_build_id]'],
updated_at_start: params['filter[updated_at_start]'],
updated_at_end: params['filter[updated_at_end]'],
project_name: params['filter[project_name]'],
id: params['filter[id]']
} }
} });
FilterModalInstance.result.then(function(ret) {
$location.search(ret);
$scope.getBuildLists();
}, function(reason) {
if(reason == 'reset') {
$location.search(default_filters);
$scope.getBuildLists();
}
}).finally(function() {
$scope.setAutoreload(turn_back_on);
});
} }
$scope.goToPage = function(number) { $scope.goToPage = function(number) {
@ -190,7 +128,41 @@ RosaABF.controller('BuildListsController',
$scope.getBuildLists(); $scope.getBuildLists();
} }
$scope.updateParams(); $scope.setAutoreload(true);
// Waits for render of filters
$timeout($scope.refresh, 100); var project_hash = $location.search();
if(project_hash['project']) {
ProjectSelectService.project = project_hash['project'];
$location.search('project', null);
}
$scope.$watch(function() {
return ProjectSelectService.project;
}, function() {
var turn_back_on = is_autoreload_on;
if(ProjectSelectService.project) {
$scope.widget_title = " | " + ProjectSelectService.project;
}
else {
$scope.widget_title = "";
}
$scope.setAutoreload(false);
$scope.getBuildLists();
$scope.setAutoreload(turn_back_on);
});
}]);
RosaABF.controller('FiltersInstanceController', ['$scope', '$uibModalInstance', 'params',
function($scope, $uibModalInstance, params) {
console.log(params);
$scope.params = params;
$scope.apply = function() {
$uibModalInstance.close($scope.params);
}
$scope.reset = function() {
$uibModalInstance.dismiss('reset');
}
}]); }]);

View File

@ -1,4 +1,4 @@
RosaABF.controller 'BuildLogController', ['$scope', '$http', '$timeout', ($scope, $http, $timeout) -> RosaABF.controller 'BuildLogController', ['$scope', '$http', '$timeout', '$sanitize', ($scope, $http, $timeout, $sanitize) ->
$scope.path = null $scope.path = null
$scope.log = null $scope.log = null

View File

@ -144,33 +144,6 @@ NewBuildListController = (dataservice, $http) ->
vm.selected_extra_build_list = null vm.selected_extra_build_list = null
false false
vm.updateFilterOwner = ->
vm.last_build_lists_filter.owner = !vm.last_build_lists_filter.owner;
updateLastBuilds()
vm.updateFilterStatus = ->
vm.last_build_lists_filter.status = !vm.last_build_lists_filter.status;
updateLastBuilds()
updateLastBuilds = ->
path = Routes.list_project_build_lists_path(
{
name_with_owner: vm.name_with_owner,
page: vm.last_build_lists_filter.page
owner_filter: vm.last_build_lists_filter.owner
status_filter: vm.last_build_lists_filter.status
}
)
$http.get(path).then (response) ->
vm.last_build_lists = response.data.build_lists
vm.total_items = response.data.total_items
false
vm.goToPage = (page) ->
vm.last_build_lists_filter.page = page
updateLastBuilds()
vm.cloneBuildList = (id) -> vm.cloneBuildList = (id) ->
path = Routes.new_project_build_list_path( path = Routes.new_project_build_list_path(
{ {
@ -213,11 +186,6 @@ NewBuildListController = (dataservice, $http) ->
vm.hidePlatform = (platform) -> vm.hidePlatform = (platform) ->
vm.is_build_for_main_platform and platform.id isnt vm.build_for_platform_id vm.is_build_for_main_platform and platform.id isnt vm.build_for_platform_id
if !vm.last_build_lists
vm.last_build_lists = []
vm.last_build_lists_filter = { owner: true, status: true, page: 1 }
updateLastBuilds()
init(dataservice) init(dataservice)
vm.selectSaveToRepository() if !dataservice.build_list_id vm.selectSaveToRepository() if !dataservice.build_list_id
return true return true

View File

@ -1,132 +0,0 @@
ActivityController = ($scope, $http, $timeout, $q, $filter, $location, ActivityFilter) ->
calculateChangeDate = (feed)->
prev_date = null
_.each(feed, (event)->
cur_date = $filter('amDateFormat')(event.date, 'll')
event.is_date_changed = cur_date isnt prev_date
prev_date = cur_date
)
$scope.$watch (->
vm.current_activity_tab.owner_uname_filter_tmp
), () ->
vm.selectOwnerFilter({uname: null}, null, null) unless vm.current_activity_tab.owner_uname_filter_tmp
$scope.$watch (->
vm.current_activity_tab.project_name_filter_tmp
), () ->
vm.selectProjectNameFilter({name: null}, null, null) unless vm.current_activity_tab.project_name_filter_tmp
vm = this
vm.processing = false
vm.activity_tab =
filter: 'build'
build: {}
owner_filter: null
project_name_filter: null
owner_uname_filter_tmp: null
project_name_filter_tmp: null
vm.own_activity_tab = $.extend({}, vm.activity_tab)
vm.current_activity_tab = vm.activity_tab
vm.init = (active_tab)->
switch active_tab
when 'activity'
vm.activity_tab.active = true
vm.current_activity_tab = vm.activity_tab
when 'own_activity'
vm.own_activity_tab.active = true
vm.current_activity_tab = vm.own_activity_tab
true
vm.getContent = (tab)->
switch tab
when 'activity'
vm.activity_tab.active = true
vm.own_activity_tab.active = false
vm.current_activity_tab = vm.activity_tab
vm.getActivityContent()
if $location.path() isnt '/'
$location.path('/').replace()
when 'own_activity'
vm.activity_tab.active = false
vm.own_activity_tab.active = true
vm.current_activity_tab = vm.own_activity_tab
vm.getActivityContent()
if $location.path() isnt '/own_activity'
$location.path('/own_activity').replace()
vm.getTimeLinefaClass = (content)->
template = switch content.kind
when 'build_list_notification' then 'btn-success fa-gear'
else 'btn-warning fa-question'
template
vm.getCurActivity = ()->
vm.current_activity_tab[vm.current_activity_tab.filter]
vm.getTemplate = (content)->
content.kind + '.html'
vm.load_more = ()->
cur_tab = vm.getCurActivity()
path = cur_tab.next_page_link
return unless path
$http.get(path).then (res)->
cur_tab.feed.push.apply(cur_tab.feed, res.data.feed)
cur_tab.next_page_link = res.data.next_page_link
vm.getActivityContent = ()->
vm.processing = true
options =
owner_filter: vm.current_activity_tab.owner_filter
project_name_filter: vm.current_activity_tab.project_name_filter
format: 'json'
if vm.activity_tab.active
path = Routes.root_path(options)
else
path = Routes.own_activity_path(options)
$http.get(path).then (res)->
feed = res.data.feed
vm.getCurActivity().feed = feed
vm.getCurActivity().next_page_link = res.data.next_page_link
calculateChangeDate(feed)
vm.processing = false
true
vm.getOwnersList = (value)->
return [] if value.length < 1
ActivityFilter.get_owners(value)
vm.selectOwnerFilter = (item, model, label)->
return if vm.current_activity_tab.owner_filter is item.uname
vm.current_activity_tab.owner_filter = item.uname
vm.current_activity_tab.project_name_filter = null
vm.current_activity_tab.project_name_filter_tmp = null
vm.getActivityContent()
true
vm.getProjectNamesList = (value)->
return [] if value.length < 1
ActivityFilter.get_project_names(vm.current_activity_tab.owner_filter, value)
vm.selectProjectNameFilter = (item, model, label)->
return if vm.current_activity_tab.project_name_filter is item.name
vm.current_activity_tab.project_name_filter = item.name
vm.getActivityContent()
true
angular
.module("RosaABF")
.controller "ActivityController", ActivityController
ActivityController.$inject = ['$scope', '$http', '$timeout', '$q', '$filter', '$location', 'ActivityFilter']

View File

@ -0,0 +1,39 @@
RosaABF.controller('ActivityFeedController', ['$scope', 'ActivityService', 'ProjectSelectService',
function($scope, ActivityService, ProjectSelectService) {
$scope.feed = [];
$scope.next_link_present = false;
$scope.owner_tmp = "";
$scope.project_tmp = "";
$scope.no_loading = false;
var owner_uname, project_name;
$scope.getFeed = function(options, no_loading) {
if($scope.requesting) {
return;
}
$scope.no_loading = no_loading;
if(ProjectSelectService.project) {
if(!options) {
options = {};
}
var split = ProjectSelectService.project.split('/');
options.owner_uname = split[0];
options.project_name = split[1];
}
$scope.requesting = true;
ActivityService.getFeed(options).then(function(res) {
$scope.requesting = false;
$scope.next_link_present = res.next_link_present;
$scope.feed = res.feed;
});
}
$scope.$watch(function() {
return ProjectSelectService.project;
}, function() {
$scope.getFeed();
});
$scope.getFeed();
}]);

View File

@ -51,11 +51,12 @@ DatePickerController = ($scope, datepickerPopupConfig) ->
<% end %> <% end %>
#datepickerPopupConfig.appendToBody = 'true' #datepickerPopupConfig.appendToBody = 'true'
return vm
angular angular
.module("RosaABF") .module("RosaABF")
.controller "DatePickerController", DatePickerController .controller "DatePickerController", DatePickerController
DatePickerController.$inject = [ DatePickerController.$inject = [
'$scope' '$scope'
'datepickerPopupConfig'
] ]

View File

@ -0,0 +1,9 @@
RosaABF.controller('PlatformsController', ['$scope', 'PlatformsService', function($scope, PlatformsService) {
$scope.platforms = null;
$scope.requesting = true;
PlatformsService.getPlatforms().then(function(platforms) {
$scope.requesting = false;
$scope.platforms = platforms;
});
}]);

View File

@ -1,20 +0,0 @@
RosaABF.controller('PlatformsCtrl', ['$scope', '$http', function($scope, $http) {
$scope.total_items = null;
$scope.page = null;
$scope.platforms = null;
$scope.getPlatforms = function() {
$http.get(Routes.platforms_path({format: 'json', page: $scope.page})).then(function(res) {
$scope.page = res.data.page;
$scope.total_items = res.data.platforms_count;
$scope.platforms = res.data.platforms;
});
};
$scope.goToPage = function(page) {
$scope.page = page;
$scope.getPlatforms();
};
$scope.getPlatforms();
}]);

View File

@ -0,0 +1,25 @@
RosaABF.controller('ProjectInfoController', ['$scope', 'ProjectInfoService', 'ProjectSelectService',
function($scope, ProjectInfoService, ProjectSelectService) {
$scope.widget_title = "";
$scope.$watch(function() {
return ProjectSelectService.load_project_info;
}, function() {
var project = ProjectSelectService.load_project_info;
if(project) {
$scope.requesting = true;
ProjectSelectService.disable_pi = true;
ProjectInfoService.getProjectInfo(project).then(function(res) {
$scope.project = project;
$scope.project_info = res;
$scope.requesting = false;
$scope.widget_title = " | " + project;
ProjectSelectService.disable_pi = false;
});
}
else {
$scope.project_info = null;
$scope.project = "";
$scope.widget_title = "";
}
});
}]);

View File

@ -1,73 +1,24 @@
RosaABF.controller('ProjectsCtrl', ['$scope', '$http', function($scope, $http) { RosaABF.controller('ProjectsController', ['$scope', 'ProjectsService', 'ProjectSelectService',
$scope.total_items = null; function($scope, ProjectsService, ProjectSelectService) {
$scope.page = null; $scope.projects = null;
$scope.projects = null; $scope.ProjectSelectService = ProjectSelectService;
$scope.filter_users = []; $scope.search = "";
$scope.filter_groups = [];
// remove_user_project_path(project), method: :delete
$scope.init = function(total_items, page) { var promiseResolve = function(projects) {
$scope.total_items = total_items; $scope.requesting = false;
$scope.page = page; $scope.projects = projects;
}; }
$scope.getProjects = function() { $scope.searchProjects = function(search) {
var params = { format: 'json', page: $scope.page, search: $scope.search, $scope.requesting = true;
users: $scope.filter_users, groups: $scope.filter_groups }; $scope.search = search;
$http.get(Routes.projects_path(params)).then(function(res) { ProjectsService.getProjects(search).then(promiseResolve);
$scope.page = res.data.page; }
$scope.total_items = res.data.projects_count;
$scope.projects = res.data.projects;
});
};
$scope.goToPage = function(page) { $scope.selectProject = function(project) {
$scope.page = page; ProjectSelectService.project = project;
$scope.getProjects(); }
};
$scope.leave_project = function(project) { $scope.requesting = true;
project.can_leave_project = false; ProjectsService.getProjects().then(promiseResolve);
var path = Routes.remove_user_project_path(project.name_with_owner, {format: 'json'});
$http.delete(path).success(function(res){
//$scope.getProjects();
// Find and remove item from an array
var i = $scope.projects.indexOf(project);
if(i != -1) {
$scope.projects.splice(i, 1);
}
}).error(function() {
$scope.getProjects();
});
};
$scope.change_user_filter = function(user_id) {
var position = $.inArray(user_id, $scope.filter_users);
var filter = 'user_filter_'+user_id+'_class';
if( ~position ) {
$scope.filter_users.splice(position, 1);
$scope[filter] = false;
}
else {
$scope.filter_users.push(user_id);
$scope[filter] = true;
}
$scope.getProjects();
};
$scope.change_group_filter = function(group_id) {
var position = $.inArray(group_id, $scope.filter_groups);
var filter = 'group_filter_'+group_id+'_class';
if( ~position ) {
$scope.filter_groups.splice(position, 1);
$scope[filter] = false;
}
else {
$scope.filter_groups.push(group_id);
$scope[filter] = true;
}
$scope.getProjects();
};
$scope.getProjects();
}]); }]);

View File

@ -1,8 +1,12 @@
RosaABF.controller('RosaABFController', ['$scope', 'LocalesHelper', 'SoundNotificationsHelper', RosaABF.controller('RosaABFController', ['$scope', 'LocalesHelper', 'SoundNotificationsHelper', '$timeout',
function($scope, LocalesHelper, SoundNotificationsHelper) { function($scope, LocalesHelper, SoundNotificationsHelper, $timeout) {
$scope.hideAlerts = false;
$scope.init = function(locale, sound_notifications) { $scope.init = function(locale, sound_notifications) {
LocalesHelper.setLocale(locale); LocalesHelper.setLocale(locale);
moment.locale(locale); //moment.locale(locale);
SoundNotificationsHelper.enabled(sound_notifications); SoundNotificationsHelper.enabled(sound_notifications);
$timeout(function() { $scope.hideAlerts = true; }, 5000);
console.log($scope);
} }
}]); }]);

View File

@ -12,11 +12,7 @@ RosaABF.controller 'StatisticsController', ['$scope', '$http', '$timeout', ($sco
'56, 132, 158', '56, 132, 158',
'77, 169, 68', '77, 169, 68',
'241, 128, 73', '241, 128, 73',
'174, 199, 232', '174, 199, 232'
# '255, 187, 120',
# '152, 223, 138',
# '214, 39, 40',
# '31, 119, 180'
] ]
$scope.charts = {} $scope.charts = {}
@ -25,12 +21,6 @@ RosaABF.controller 'StatisticsController', ['$scope', '$http', '$timeout', ($sco
startingDay: 1 startingDay: 1
$scope.init = -> $scope.init = ->
$('#statistics-form .date_picker').datepicker
'dateFormat': 'yy-mm-dd'
maxDate: 0
minDate: -366
showButtonPanel: true
$scope.update() $scope.update()
true true
@ -85,18 +75,6 @@ RosaABF.controller 'StatisticsController', ['$scope', '$http', '$timeout', ($sco
if $scope.statistics.build_lists if $scope.statistics.build_lists
$scope.initBuildListsChart() $scope.initBuildListsChart()
# PullRequests
if $scope.statistics.pull_requests
$scope.initPullRequestsChart()
# Issues
if $scope.statistics.issues
$scope.initIssuesChart()
# Commits
if $scope.statistics.commits
$scope.initCommitsChart()
.error (data, status, headers, config) -> .error (data, status, headers, config) ->
console.log 'error:' console.log 'error:'
$scope.loading = false $scope.loading = false
@ -157,23 +135,4 @@ RosaABF.controller 'StatisticsController', ['$scope', '$http', '$timeout', ($sco
$scope.statistics.build_lists.build_published $scope.statistics.build_lists.build_published
] ]
$scope.initCommitsChart = ->
$scope.dateChart '#commits_chart', [
$scope.statistics.commits.chart
]
$scope.initPullRequestsChart = ->
$scope.dateChart '#pull_requests_chart', [
$scope.statistics.pull_requests.open,
$scope.statistics.pull_requests.merged
$scope.statistics.pull_requests.closed,
]
$scope.initIssuesChart = ->
$scope.dateChart '#issues_chart', [
$scope.statistics.issues.open,
$scope.statistics.issues.reopen,
$scope.statistics.issues.closed
]
] ]

View File

@ -0,0 +1,16 @@
/**
* Loading Directive
* @see http://tobiasahlin.com/spinkit/
*/
angular
.module('RosaABF')
.directive('rdLoading', rdLoading);
function rdLoading() {
var directive = {
restrict: 'AE',
template: '<div class="loading"><div class="double-bounce1"></div><div class="double-bounce2"></div></div>'
};
return directive;
};

View File

@ -0,0 +1,22 @@
/**
* Widget Body Directive
*/
angular
.module('RosaABF')
.directive('rdWidgetBody', rdWidgetBody);
function rdWidgetBody() {
var directive = {
requires: '^rdWidget',
replace: true,
scope: {
loading: '&',
classes: '@'
},
transclude: true,
template: '<div class="widget-body" ng-class="classes"><rd-loading ng-show="loading()"></rd-loading><div ng-hide="loading()" class="widget-content" ng-transclude></div></div>',
restrict: 'E'
};
return directive;
};

View File

@ -0,0 +1,18 @@
/**
* Widget Footer Directive
*/
angular
.module('RosaABF')
.directive('rdWidgetFooter', rdWidgetFooter);
function rdWidgetFooter() {
var directive = {
requires: '^rdWidget',
transclude: true,
replace: true,
template: '<div class="widget-footer" ng-transclude></div>',
restrict: 'E'
};
return directive;
};

View File

@ -0,0 +1,22 @@
/**
* Widget Header Directive
*/
angular
.module('RosaABF')
.directive('rdWidgetHeader', rdWidgetTitle);
function rdWidgetTitle() {
var directive = {
requires: '^rdWidget',
replace: true,
scope: {
title: '@',
icon: '@'
},
transclude: true,
template: '<div class="widget-header"><div class="row"><div class="pull-left"><i class="fa" ng-class="icon"></i> {{title}} </div><div class="pull-right col-xs-6 col-sm-4" ng-transclude></div></div></div>',
restrict: 'E'
};
return directive;
};

View File

@ -0,0 +1,21 @@
/**
* Widget Directive
*/
angular
.module('RosaABF')
.directive('rdWidget', rdWidget);
function rdWidget() {
var directive = {
transclude: true,
template: '<div class="widget" ng-transclude></div>',
replace: true,
restrict: 'EA'
};
return directive;
function link(scope, element, attrs) {
/* */
}
};

View File

@ -36,7 +36,7 @@ var BuildList = function(atts, dictionary) {
self.version_link_text = self.commit_hash || self.project_version; self.version_link_text = self.commit_hash || self.project_version;
self.version_link_url = Routes.commit_path(self.project.name_with_owner, self.version_link_text); self.version_link_url = Routes.commit_path(self.project.name_with_owner, self.version_link_text);
} }
self.project.url = Routes.project_path(self.project.name_with_owner); self.project.url = '';//Routes.project_path(self.project.name_with_owner);
} }
if (self.user) if (self.user)

View File

@ -1,27 +0,0 @@
ActivityFilterService = ($http) ->
get_owners: (val) ->
path = Routes.get_owners_list_path(
{
term: val
}
)
$http.get(path).then (response) ->
response.data
get_project_names: (owner, val) ->
path = Routes.get_project_names_list_path(
{
owner_uname: owner
term: val
}
)
$http.get(path).then (response) ->
response.data
angular
.module("RosaABF")
.factory "ActivityFilter", ActivityFilterService
ActivityFilterService.$inject = ['$http']

View File

@ -0,0 +1,85 @@
angular.module("RosaABF").factory('ActivityService', ["$http", "$filter", function($http, $filter) {
var ActivityService = {};
var feed;
var next_page_link = null;
var last_date;
var last_is_own = false;
var processFeed = function(feed) {
var res = [];
_.each(feed, function(item) {
var cur_date = $filter('amDateFormat')(item.date, 'll')
if(cur_date != last_date) {
res.push({kind: 'new_day', date: cur_date, class: 'timeline-day'});
last_date = cur_date;
}
res.push(item);
});
return res;
}
ActivityService.getFeed = function(options) {
if(Object.prototype.toString.apply(options) != '[object Object]') {
options = {is_own: last_is_own, load_next_page: false};
}
var url;
if(!options['load_next_page']) {
last_date = null;
feed = {};
params = {format: 'json'};
if(options['owner_uname']) {
params['owner_filter'] = options['owner_uname'];
}
if(options['project_name']) {
params['project_name_filter'] = options['project_name'];
}
last_is_own = options['is_own'];
url = options['is_own'] ? Routes.own_activity_path(params) : Routes.activity_feeds_path(params);
}
else {
if(!next_page_link) {
return false;
}
url = next_page_link;
}
return $http.get(url).then(function(res) {
next_page_link = res.data.next_page_link;
var new_feed = processFeed(res.data.feed);
var ret;
if(options['load_next_page']) {
ret = feed;
ret.push.apply(ret, new_feed);
}
else {
feed = ret = new_feed;
}
return {feed: ret, next_link_present: !!next_page_link};
});
}
ActivityService.getOwnersList = function(val) {
var path = Routes.get_owners_list_path({term: val});
return $http.get(path).then(function(res) {
return res.data;
});
}
ActivityService.getProjectNamesList = function(owner_uname, val) {
var path = Routes.get_project_names_list_path({owner_uname: owner_uname, term: val});
return $http.get(path).then(function(res) {
return res.data;
});
}
return ActivityService;
}]);

View File

@ -0,0 +1,77 @@
angular.module("RosaABF").factory('BuildListsService', ["$http", function($http) {
var BuildListsService = {};
var map_priorities = {
<%=BuildList::WAITING_FOR_RESPONSE%>: 13,
<%=BuildList::BUILD_PENDING%>: 12,
<%=BuildList::RERUN_TESTS%>: 11,
<%=BuildList::BUILD_CANCELING%>: 10,
<%=BuildList::BUILD_CANCELED%>: 9,
<%=BuildList::BUILD_STARTED%>: 8,
<%=BuildList::RERUNNING_TESTS%>: 7,
<%=BuildList::BUILD_PUBLISH%>: 6,
<%=BuildList::BUILD_PUBLISHED%>: 5,
<%=BuildList::BUILD_ERROR%>: 4,
<%=BuildList::SUCCESS%>: 3,
<%=BuildList::TESTS_FAILED%>: 2,
<%=BuildList::FAILED_PUBLISH%>: 1,
<%=BuildList::REJECTED_PUBLISH%>: 0
};
BuildListsService.getBuildLists = function(params, project) {
var url;
if(project) {
url = Routes.project_build_lists_path(project, {format: 'json'});
}
else {
url = Routes.build_lists_path({format: 'json'});
}
return $http.get(url, {params: params}).then(function(results) {
// TMP fields
var dictionary = results.data.dictionary;
var build_lists = [];
var groups = {};
// Grouping of build_lists
_.each(results.data.build_lists, function(r){
var bl = new BuildList(r, dictionary);
var key = bl.project_id + '-';
key += bl.group_id ? bl.group_id : (bl.commit_hash + '-' + bl.user_id);
if (groups[key]) {
groups[key].addRelated(bl);
}
else {
groups[key] = bl;
build_lists.push(bl);
}
});
// Adds all build_lists into the table (group by group)
var build_lists_final = [];
_.each(build_lists, function(bl){
if (bl.related.length > 1) {
var sorted_build_lists = _.sortBy(bl.related, function(b) { return map_priorities[b.status]; });
bl.clearRelated();
var first_in_group = sorted_build_lists[0];
first_in_group.clearRelated();
_.each(sorted_build_lists, function(b){
if (b != first_in_group) { first_in_group.addRelated(b); }
build_lists_final.push(b);
});
} else {
build_lists_final.push(bl);
}
});
return {
build_lists: build_lists_final,
page: results.data.page,
total_items: results.data.total_items,
filter: results.data.filter
};
});
}
return BuildListsService;
}]);

View File

@ -1,11 +0,0 @@
compileHTML = ($compile) ->
run: (scope, data) ->
template = angular.element(data)
linkFn = $compile(template)
linkFn(scope)
angular
.module("RosaABF")
.service "compileHTML", compileHTML
compileHTML.$inject = ['$compile']

View File

@ -0,0 +1,11 @@
angular.module("RosaABF").factory('PlatformsService', ["$http", function($http) {
var PlatformsService = {};
PlatformsService.getPlatforms = function() {
return $http.get(Routes.platforms_path({ format: 'json' })).then(function(res) {
return res.data.platforms;
});
}
return PlatformsService;
}]);

View File

@ -0,0 +1,11 @@
angular.module("RosaABF").factory('ProjectInfoService', ["$http", function($http) {
var ProjectInfoService = {};
ProjectInfoService.getProjectInfo = function(name_with_owner) {
return $http.get(Routes.project_info_path(name_with_owner, { format: 'json' })).then(function(res) {
return res.data.project_info;
});
}
return ProjectInfoService;
}]);

View File

@ -0,0 +1,10 @@
angular.module("RosaABF").factory('ProjectSelectService', function() {
return {
project: "",
disable_bl: false,
disable_pi: false,
disable: function() {
return this.disable_bl || this.disable_pi;
}
};
});

View File

@ -0,0 +1,15 @@
angular.module("RosaABF").factory('ProjectsService', ["$http", function($http) {
var ProjectsService = {};
ProjectsService.getProjects = function(search) {
var params = { format: 'json' };
if(search) {
params.search = search;
}
return $http.get(Routes.projects_path(params)).then(function(res) {
return res.data.projects;
});
}
return ProjectsService;
}]);

View File

@ -1,18 +0,0 @@
%i.img-circle.btn-info.fa.fa-gears
.timeline-item{ 'ng-cloak' => true }
%h3.timeline-header
%a{ 'ng-href' => "{{item.user.link}}" }
%img{ 'ng-src' => "{{item.user.image}}" }
{{item.user.uname}}
%span.time{ popover: "{{item.date | amDateFormat:'ddd, LLL'}}",
"popover-trigger" => "mouseenter", 'popover-append-to-body' => 'true' }
%span.glyphicon.glyphicon-time
%span {{item.date | amDateFormat:'HH:mm'}}
.clearfix
.timeline-body
%p
{{'notification.build_list' | i18n}}
%a{ 'ng-href' => "{{item.build_list.link}}" } {{item.build_list.id}}
{{'notification.in_project' | i18n}}
%a{ 'ng-href' => "{{item.project_link}}" } {{item.project_name_with_owner}}
{{item.build_list.status_message}}

View File

@ -0,0 +1,15 @@
.timeline-item
.row
a ng-href="{{item.user.link}}"
img src="{{item.user.image}}"
| {{item.user.uname}}
span.pull-right
| {{item.date | amDateFormat:'HH:mm'}}
.timeline-item-body
| {{'notification.build_list' | i18n}}
a ng-href="{{item.build_list.link}}"
| {{item.build_list.id}}
| {{'notification.in_project' | i18n}}
a ng-href="{{item.project_link}}"
| {{item.project_name_with_owner}}
| {{item.build_list.status_message}}

View File

@ -1,4 +1,4 @@
- size = Avatar::AVATAR_SIZES[:small] - size = Avatar::AVATAR_SIZES[:small]
a a
img ng-src= "{{match.model.avatar_path}}" height= size width= size img ng-src= "{{match.model.avatar_path}}" height= size width= size
span< bind-html-unsafe= "match.model.uname | typeaheadHighlight:query" span< ng-bind-html= "match.model.uname | uibTypeaheadHighlight:query"

View File

@ -0,0 +1,2 @@
span
| {{item.date}}

View File

@ -1,3 +0,0 @@
a
img ng-src = "{{match.model.avatar_path}}"
span< bind-html-unsafe = "match.model.fullname | typeaheadHighlight:query"

View File

@ -0,0 +1,555 @@
(function($, undefined) {
/**
* Unobtrusive scripting adapter for jQuery
* https://github.com/rails/jquery-ujs
*
* Requires jQuery 1.8.0 or later.
*
* Released under the MIT license
*
*/
// Cut down on the number of issues from people inadvertently including jquery_ujs twice
// by detecting and raising an error when it happens.
'use strict';
if ( $.rails !== undefined ) {
$.error('jquery-ujs has already been loaded!');
}
// Shorthand to make it a little easier to call public rails functions from within rails.js
var rails;
var $document = $(document);
$.rails = rails = {
// Link elements bound by jquery-ujs
linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]:not([disabled]), a[data-disable-with], a[data-disable]',
// Button elements bound by jquery-ujs
buttonClickSelector: 'button[data-remote]:not([form]):not(form button), button[data-confirm]:not([form]):not(form button)',
// Select elements bound by jquery-ujs
inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]',
// Form elements bound by jquery-ujs
formSubmitSelector: 'form',
// Form input elements bound by jquery-ujs
formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type]), input[type=submit][form], input[type=image][form], button[type=submit][form], button[form]:not([type])',
// Form input elements disabled during form submission
disableSelector: 'input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled',
// Form input elements re-enabled after form submission
enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled',
// Form required input elements
requiredInputSelector: 'input[name][required]:not([disabled]), textarea[name][required]:not([disabled])',
// Form file input elements
fileInputSelector: 'input[type=file]:not([disabled])',
// Link onClick disable selector with possible reenable after remote submission
linkDisableSelector: 'a[data-disable-with], a[data-disable]',
// Button onClick disable selector with possible reenable after remote submission
buttonDisableSelector: 'button[data-remote][data-disable-with], button[data-remote][data-disable]',
// Up-to-date Cross-Site Request Forgery token
csrfToken: function() {
return $('meta[name=csrf-token]').attr('content');
},
// URL param that must contain the CSRF token
csrfParam: function() {
return $('meta[name=csrf-param]').attr('content');
},
// Make sure that every Ajax request sends the CSRF token
CSRFProtection: function(xhr) {
var token = rails.csrfToken();
if (token) xhr.setRequestHeader('X-CSRF-Token', token);
},
// Make sure that all forms have actual up-to-date tokens (cached forms contain old ones)
refreshCSRFTokens: function(){
$('form input[name="' + rails.csrfParam() + '"]').val(rails.csrfToken());
},
// Triggers an event on an element and returns false if the event result is false
fire: function(obj, name, data) {
var event = $.Event(name);
obj.trigger(event, data);
return event.result !== false;
},
// Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
confirm: function(message) {
return confirm(message);
},
// Default ajax function, may be overridden with custom function in $.rails.ajax
ajax: function(options) {
return $.ajax(options);
},
// Default way to get an element's href. May be overridden at $.rails.href.
href: function(element) {
return element[0].href;
},
// Checks "data-remote" if true to handle the request through a XHR request.
isRemote: function(element) {
return element.data('remote') !== undefined && element.data('remote') !== false;
},
// Submits "remote" forms and links with ajax
handleRemote: function(element) {
var method, url, data, withCredentials, dataType, options;
if (rails.fire(element, 'ajax:before')) {
withCredentials = element.data('with-credentials') || null;
dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType);
if (element.is('form')) {
method = element.data('ujs:submit-button-formmethod') || element.attr('method');
url = element.data('ujs:submit-button-formaction') || element.attr('action');
data = $(element[0]).serializeArray();
// memoized value from clicked submit button
var button = element.data('ujs:submit-button');
if (button) {
data.push(button);
element.data('ujs:submit-button', null);
}
element.data('ujs:submit-button-formmethod', null);
element.data('ujs:submit-button-formaction', null);
} else if (element.is(rails.inputChangeSelector)) {
method = element.data('method');
url = element.data('url');
data = element.serialize();
if (element.data('params')) data = data + '&' + element.data('params');
} else if (element.is(rails.buttonClickSelector)) {
method = element.data('method') || 'get';
url = element.data('url');
data = element.serialize();
if (element.data('params')) data = data + '&' + element.data('params');
} else {
method = element.data('method');
url = rails.href(element);
data = element.data('params') || null;
}
options = {
type: method || 'GET', data: data, dataType: dataType,
// stopping the "ajax:beforeSend" event will cancel the ajax request
beforeSend: function(xhr, settings) {
if (settings.dataType === undefined) {
xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
}
if (rails.fire(element, 'ajax:beforeSend', [xhr, settings])) {
element.trigger('ajax:send', xhr);
} else {
return false;
}
},
success: function(data, status, xhr) {
element.trigger('ajax:success', [data, status, xhr]);
},
complete: function(xhr, status) {
element.trigger('ajax:complete', [xhr, status]);
},
error: function(xhr, status, error) {
element.trigger('ajax:error', [xhr, status, error]);
},
crossDomain: rails.isCrossDomain(url)
};
// There is no withCredentials for IE6-8 when
// "Enable native XMLHTTP support" is disabled
if (withCredentials) {
options.xhrFields = {
withCredentials: withCredentials
};
}
// Only pass url to `ajax` options if not blank
if (url) { options.url = url; }
return rails.ajax(options);
} else {
return false;
}
},
// Determines if the request is a cross domain request.
isCrossDomain: function(url) {
var originAnchor = document.createElement('a');
originAnchor.href = location.href;
var urlAnchor = document.createElement('a');
try {
urlAnchor.href = url;
// This is a workaround to a IE bug.
urlAnchor.href = urlAnchor.href;
// If URL protocol is false or is a string containing a single colon
// *and* host are false, assume it is not a cross-domain request
// (should only be the case for IE7 and IE compatibility mode).
// Otherwise, evaluate protocol and host of the URL against the origin
// protocol and host.
return !(((!urlAnchor.protocol || urlAnchor.protocol === ':') && !urlAnchor.host) ||
(originAnchor.protocol + '//' + originAnchor.host ===
urlAnchor.protocol + '//' + urlAnchor.host));
} catch (e) {
// If there is an error parsing the URL, assume it is crossDomain.
return true;
}
},
// Handles "data-method" on links such as:
// <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
handleMethod: function(link) {
var href = rails.href(link),
method = link.data('method'),
target = link.attr('target'),
csrfToken = rails.csrfToken(),
csrfParam = rails.csrfParam(),
form = $('<form method="post" action="' + href + '"></form>'),
metadataInput = '<input name="_method" value="' + method + '" type="hidden" />';
if (csrfParam !== undefined && csrfToken !== undefined && !rails.isCrossDomain(href)) {
metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />';
}
if (target) { form.attr('target', target); }
form.hide().append(metadataInput).appendTo('body');
form.submit();
},
// Helper function that returns form elements that match the specified CSS selector
// If form is actually a "form" element this will return associated elements outside the from that have
// the html form attribute set
formElements: function(form, selector) {
return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector);
},
/* Disables form elements:
- Caches element value in 'ujs:enable-with' data store
- Replaces element text with value of 'data-disable-with' attribute
- Sets disabled property to true
*/
disableFormElements: function(form) {
rails.formElements(form, rails.disableSelector).each(function() {
rails.disableFormElement($(this));
});
},
disableFormElement: function(element) {
var method, replacement;
method = element.is('button') ? 'html' : 'val';
replacement = element.data('disable-with');
if (replacement !== undefined) {
element.data('ujs:enable-with', element[method]());
element[method](replacement);
}
element.prop('disabled', true);
element.data('ujs:disabled', true);
},
/* Re-enables disabled form elements:
- Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
- Sets disabled property to false
*/
enableFormElements: function(form) {
rails.formElements(form, rails.enableSelector).each(function() {
rails.enableFormElement($(this));
});
},
enableFormElement: function(element) {
var method = element.is('button') ? 'html' : 'val';
if (element.data('ujs:enable-with') !== undefined) {
element[method](element.data('ujs:enable-with'));
element.removeData('ujs:enable-with'); // clean up cache
}
element.prop('disabled', false);
element.removeData('ujs:disabled');
},
/* For 'data-confirm' attribute:
- Fires `confirm` event
- Shows the confirmation dialog
- Fires the `confirm:complete` event
Returns `true` if no function stops the chain and user chose yes; `false` otherwise.
Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
*/
allowAction: function(element) {
var message = element.data('confirm'),
answer = false, callback;
if (!message) { return true; }
if (rails.fire(element, 'confirm')) {
try {
answer = rails.confirm(message);
} catch (e) {
(console.error || console.log).call(console, e.stack || e);
}
callback = rails.fire(element, 'confirm:complete', [answer]);
}
return answer && callback;
},
// Helper function which checks for blank inputs in a form that match the specified CSS selector
blankInputs: function(form, specifiedSelector, nonBlank) {
var foundInputs = $(),
input,
valueToCheck,
radiosForNameWithNoneSelected,
radioName,
selector = specifiedSelector || 'input,textarea',
requiredInputs = form.find(selector),
checkedRadioButtonNames = {};
requiredInputs.each(function() {
input = $(this);
if (input.is('input[type=radio]')) {
// Don't count unchecked required radio as blank if other radio with same name is checked,
// regardless of whether same-name radio input has required attribute or not. The spec
// states https://www.w3.org/TR/html5/forms.html#the-required-attribute
radioName = input.attr('name');
// Skip if we've already seen the radio with this name.
if (!checkedRadioButtonNames[radioName]) {
// If none checked
if (form.find('input[type=radio]:checked[name="' + radioName + '"]').length === 0) {
radiosForNameWithNoneSelected = form.find(
'input[type=radio][name="' + radioName + '"]');
foundInputs = foundInputs.add(radiosForNameWithNoneSelected);
}
// We only need to check each name once.
checkedRadioButtonNames[radioName] = radioName;
}
} else {
valueToCheck = input.is('input[type=checkbox],input[type=radio]') ? input.is(':checked') : !!input.val();
if (valueToCheck === nonBlank) {
foundInputs = foundInputs.add(input);
}
}
});
return foundInputs.length ? foundInputs : false;
},
// Helper function which checks for non-blank inputs in a form that match the specified CSS selector
nonBlankInputs: function(form, specifiedSelector) {
return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank
},
// Helper function, needed to provide consistent behavior in IE
stopEverything: function(e) {
$(e.target).trigger('ujs:everythingStopped');
e.stopImmediatePropagation();
return false;
},
// Replace element's html with the 'data-disable-with' after storing original html
// and prevent clicking on it
disableElement: function(element) {
var replacement = element.data('disable-with');
if (replacement !== undefined) {
element.data('ujs:enable-with', element.html()); // store enabled state
element.html(replacement);
}
element.bind('click.railsDisable', function(e) { // prevent further clicking
return rails.stopEverything(e);
});
element.data('ujs:disabled', true);
},
// Restore element to its original state which was disabled by 'disableElement' above
enableElement: function(element) {
if (element.data('ujs:enable-with') !== undefined) {
element.html(element.data('ujs:enable-with')); // set to old enabled state
element.removeData('ujs:enable-with'); // clean up cache
}
element.unbind('click.railsDisable'); // enable element
element.removeData('ujs:disabled');
}
};
if (rails.fire($document, 'rails:attachBindings')) {
$.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }});
// This event works the same as the load event, except that it fires every
// time the page is loaded.
//
// See https://github.com/rails/jquery-ujs/issues/357
// See https://developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching
$(window).on('pageshow.rails', function () {
$($.rails.enableSelector).each(function () {
var element = $(this);
if (element.data('ujs:disabled')) {
$.rails.enableFormElement(element);
}
});
$($.rails.linkDisableSelector).each(function () {
var element = $(this);
if (element.data('ujs:disabled')) {
$.rails.enableElement(element);
}
});
});
$document.delegate(rails.linkDisableSelector, 'ajax:complete', function() {
rails.enableElement($(this));
});
$document.delegate(rails.buttonDisableSelector, 'ajax:complete', function() {
rails.enableFormElement($(this));
});
$document.delegate(rails.linkClickSelector, 'click.rails', function(e) {
var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey;
if (!rails.allowAction(link)) return rails.stopEverything(e);
if (!metaClick && link.is(rails.linkDisableSelector)) rails.disableElement(link);
if (rails.isRemote(link)) {
if (metaClick && (!method || method === 'GET') && !data) { return true; }
var handleRemote = rails.handleRemote(link);
// Response from rails.handleRemote() will either be false or a deferred object promise.
if (handleRemote === false) {
rails.enableElement(link);
} else {
handleRemote.fail( function() { rails.enableElement(link); } );
}
return false;
} else if (method) {
rails.handleMethod(link);
return false;
}
});
$document.delegate(rails.buttonClickSelector, 'click.rails', function(e) {
var button = $(this);
if (!rails.allowAction(button) || !rails.isRemote(button)) return rails.stopEverything(e);
if (button.is(rails.buttonDisableSelector)) rails.disableFormElement(button);
var handleRemote = rails.handleRemote(button);
// Response from rails.handleRemote() will either be false or a deferred object promise.
if (handleRemote === false) {
rails.enableFormElement(button);
} else {
handleRemote.fail( function() { rails.enableFormElement(button); } );
}
return false;
});
$document.delegate(rails.inputChangeSelector, 'change.rails', function(e) {
var link = $(this);
if (!rails.allowAction(link) || !rails.isRemote(link)) return rails.stopEverything(e);
rails.handleRemote(link);
return false;
});
$document.delegate(rails.formSubmitSelector, 'submit.rails', function(e) {
var form = $(this),
remote = rails.isRemote(form),
blankRequiredInputs,
nonBlankFileInputs;
if (!rails.allowAction(form)) return rails.stopEverything(e);
// Skip other logic when required values are missing or file upload is present
if (form.attr('novalidate') === undefined) {
if (form.data('ujs:formnovalidate-button') === undefined) {
blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector, false);
if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
return rails.stopEverything(e);
}
} else {
// Clear the formnovalidate in case the next button click is not on a formnovalidate button
// Not strictly necessary to do here, since it is also reset on each button click, but just to be certain
form.data('ujs:formnovalidate-button', undefined);
}
}
if (remote) {
nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
if (nonBlankFileInputs) {
// Slight timeout so that the submit button gets properly serialized
// (make it easy for event handler to serialize form without disabled values)
setTimeout(function(){ rails.disableFormElements(form); }, 13);
var aborted = rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
// Re-enable form elements if event bindings return false (canceling normal form submission)
if (!aborted) { setTimeout(function(){ rails.enableFormElements(form); }, 13); }
return aborted;
}
rails.handleRemote(form);
return false;
} else {
// Slight timeout so that the submit button gets properly serialized
setTimeout(function(){ rails.disableFormElements(form); }, 13);
}
});
$document.delegate(rails.formInputClickSelector, 'click.rails', function(event) {
var button = $(this);
if (!rails.allowAction(button)) return rails.stopEverything(event);
// Register the pressed submit button
var name = button.attr('name'),
data = name ? {name:name, value:button.val()} : null;
var form = button.closest('form');
if (form.length === 0) {
form = $('#' + button.attr('form'));
}
form.data('ujs:submit-button', data);
// Save attributes from button
form.data('ujs:formnovalidate-button', button.attr('formnovalidate'));
form.data('ujs:submit-button-formaction', button.attr('formaction'));
form.data('ujs:submit-button-formmethod', button.attr('formmethod'));
});
$document.delegate(rails.formSubmitSelector, 'ajax:send.rails', function(event) {
if (this === event.target) rails.disableFormElements($(this));
});
$document.delegate(rails.formSubmitSelector, 'ajax:complete.rails', function(event) {
if (this === event.target) rails.enableFormElements($(this));
});
$(function(){
rails.refreshCSRFTokens();
});
}
})( jQuery );

View File

@ -1,54 +1,15 @@
//= require jquery //= require jquery.rails
//= require jquery_ujs
//= require jquery-ui
//= require js-routes //= require js-routes
//= require bootstrap-sprockets
//= require angular
//= require angular-sanitize
//= require angular-ui-bootstrap-tpls
//= require angular-i18n //= require angular-i18n
//= require angular-resource
//= require ng-rails-csrf //= require ng-rails-csrf
//= require angular-cookies
//= require soundmanager2-nodebug-jsmin //= require soundmanager2-nodebug-jsmin
//= require angular-rails-templates //= require angular-rails-templates
//= require moment
//= require_tree ./angularjs //= require_tree ./angularjs
//= require loading-bar
//= require underscore //= require underscore
//= require notifyjs
//= require notifyjs/styles/bootstrap/notify-bootstrap
//= require lib/Chart //= require lib/Chart
//= require lib/bootstrap-typeahead
//= require lib/custom-bootstrap-typeahead
//= require extra/scroller
//= require_self
$(document).ready(function() {
$('.datetime_moment').each(function() {
var mtime = moment($(this).attr('origin_datetime'), 'YYYY-MM-DD HH:mm Z');
$(this).attr('title', mtime.utc().format('YYYY-MM-DD HH:mm:ss UTC'));
});
window.updateTime = function () {
$('.datetime_moment').each(function() {
var time = moment($(this).attr('origin_datetime'), 'YYYY-MM-DD HH:mm Z');
$(this).html(time.format('D MMM YYYY, HH:mm') + ' (' + time.fromNow() + ')');
});
};
updateTime();
setInterval( updateTime, 15000 );
});

View File

@ -1,680 +0,0 @@
/*
* https://github.com/lu4/BootstrapXL/blob/7c64e2ea5ee1f72ed3db9892c091d5a0380c4518/BootstrapXL.css
*
* CSS file with Bootstrap grid classes for screens bigger than 1600px. Just add this file after the Bootstrap CSS file and you will be able to use col-xl, col-xl-push, hidden-xl, etc.
*
* Author: Marc van Nieuwenhuijzen
* Company: WebVakman
* Site: WebVakman.nl
*
*/
.visible-xs,
.visible-xs-block,
.visible-xs-inline,
.visible-xs-inline-block,
.visible-sm,
.visible-sm-block,
.visible-sm-inline,
.visible-sm-inline-block,
.visible-md,
.visible-md-block,
.visible-md-inline,
.visible-md-inline-block,
.visible-lg,
.visible-lg-block,
.visible-lg-inline,
.visible-lg-inline-block,
.visible-xl,
.visible-xl-block,
.visible-xl-inline,
.visible-xl-inline-block,
.visible-xx,
.visible-xx-block,
.visible-xx-inline,
.visible-xx-inline-block {
display: none !important;
}
@media (max-width: 768px) {
.visible-xs {
display: block !important;
}
table.visible-xs {
display: table;
}
tr.visible-xs {
display: table-row !important;
}
th.visible-xs, td.visible-xs {
display: table-cell !important;
}
.visible-xs-block {
display: block !important;
}
.visible-xs-inline {
display: inline !important;
}
.visible-xs-inline-block {
display: inline-block !important;
}
.hidden-xs {
display: none !important;
}
}
@media (min-width: 768px) and (max-width: 991px) {
.visible-sm {
display: block !important;
}
table.visible-sm {
display: table;
}
tr.visible-sm {
display: table-row !important;
}
th.visible-sm, td.visible-sm {
display: table-cell !important;
}
.visible-sm-block {
display: block !important;
}
.visible-sm-inline {
display: inline !important;
}
.visible-sm-inline-block {
display: inline-block !important;
}
.hidden-sm {
display: none !important;
}
}
@media (min-width: 992px) and (max-width: 1199px) {
.visible-md {
display: block !important;
}
table.visible-md {
display: table;
}
tr.visible-md {
display: table-row !important;
}
th.visible-md, td.visible-md {
display: table-cell !important;
}
.visible-md-block {
display: block !important;
}
.visible-md-inline {
display: inline !important;
}
.visible-md-inline-block {
display: inline-block !important;
}
.hidden-md {
display: none !important;
}
}
@media (min-width: 1200px) {
.col-lg-3 {
width: 25%;
}
.visible-lg {
display: block !important;
}
table.visible-lg {
display: table;
}
tr.visible-lg {
display: table-row !important;
}
th.visible-lg, td.visible-lg {
display: table-cell !important;
}
.visible-lg-block {
display: block !important;
}
.visible-lg-inline {
display: inline !important;
}
.visible-lg-inline-block {
display: inline-block !important;
}
.hidden-lg {
display: none !important;
}
}
@media (min-width: 1600px) {
.visible-lg {
display: none !important;
}
}
@media (min-width: 1600px) {
.container {
width: 1570px;
}
.col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12 {
float: left;
}
.col-xl-12 {
width: 100%;
}
.col-xl-11 {
width: 91.66666667%;
}
.col-xl-10 {
width: 83.33333333%;
}
.col-xl-9 {
width: 75%;
}
.col-xl-8 {
width: 66.66666667%;
}
.col-xl-7 {
width: 58.33333333%;
}
.col-xl-6 {
width: 50%;
}
.col-xl-5 {
width: 41.66666667%;
}
.col-xl-4 {
width: 33.33333333%;
}
.col-xl-3 {
width: 25%;
}
.col-xl-2 {
width: 16.66666667%;
}
.col-xl-1 {
width: 8.33333333%;
}
.col-xl-pull-12 {
right: 100%;
}
.col-xl-pull-11 {
right: 91.66666667%;
}
.col-xl-pull-10 {
right: 83.33333333%;
}
.col-xl-pull-9 {
right: 75%;
}
.col-xl-pull-8 {
right: 66.66666667%;
}
.col-xl-pull-7 {
right: 58.33333333%;
}
.col-xl-pull-6 {
right: 50%;
}
.col-xl-pull-5 {
right: 41.66666667%;
}
.col-xl-pull-4 {
right: 33.33333333%;
}
.col-xl-pull-3 {
right: 25%;
}
.col-xl-pull-2 {
right: 16.66666667%;
}
.col-xl-pull-1 {
right: 8.33333333%;
}
.col-xl-pull-0 {
right: auto;
}
.col-xl-push-12 {
left: 100%;
}
.col-xl-push-11 {
left: 91.66666667%;
}
.col-xl-push-10 {
left: 83.33333333%;
}
.col-xl-push-9 {
left: 75%;
}
.col-xl-push-8 {
left: 66.66666667%;
}
.col-xl-push-7 {
left: 58.33333333%;
}
.col-xl-push-6 {
left: 50%;
}
.col-xl-push-5 {
left: 41.66666667%;
}
.col-xl-push-4 {
left: 33.33333333%;
}
.col-xl-push-3 {
left: 25%;
}
.col-xl-push-2 {
left: 16.66666667%;
}
.col-xl-push-1 {
left: 8.33333333%;
}
.col-xl-push-0 {
left: auto;
}
.col-xl-offset-12 {
margin-left: 100%;
}
.col-xl-offset-11 {
margin-left: 91.66666667%;
}
.col-xl-offset-10 {
margin-left: 83.33333333%;
}
.col-xl-offset-9 {
margin-left: 75%;
}
.col-xl-offset-8 {
margin-left: 66.66666667%;
}
.col-xl-offset-7 {
margin-left: 58.33333333%;
}
.col-xl-offset-6 {
margin-left: 50%;
}
.col-xl-offset-5 {
margin-left: 41.66666667%;
}
.col-xl-offset-4 {
margin-left: 33.33333333%;
}
.col-xl-offset-3 {
margin-left: 25%;
}
.col-xl-offset-2 {
margin-left: 16.66666667%;
}
.col-xl-offset-1 {
margin-left: 8.33333333%;
}
.col-xl-offset-0 {
margin-left: 0;
}
.visible-xl {
display: block !important;
}
table.visible-xl {
display: table;
}
tr.visible-xl {
display: table-row !important;
}
th.visible-xl, td.visible-xl {
display: table-cell !important;
}
.visible-xl-block {
display: block !important;
}
.visible-xl-inline {
display: inline !important;
}
.visible-xl-inline-block {
display: inline-block !important;
}
.hidden-xl {
display: none !important;
}
}
@media (min-width: 2048px) {
.visible-xl {
display: none !important;
}
}
@media (min-width: 2048px) {
.container {
width: 1570px;
}
.col-xx-1, .col-xx-2, .col-xx-3, .col-xx-4, .col-xx-5, .col-xx-6, .col-xx-7, .col-xx-8, .col-xx-9, .col-xx-10, .col-xx-11, .col-xx-12 {
float: left;
}
.col-xx-12 {
width: 100%;
}
.col-xx-11 {
width: 91.66666667%;
}
.col-xx-10 {
width: 83.33333333%;
}
.col-xx-9 {
width: 75%;
}
.col-xx-8 {
width: 66.66666667%;
}
.col-xx-7 {
width: 58.33333333%;
}
.col-xx-6 {
width: 50%;
}
.col-xx-5 {
width: 41.66666667%;
}
.col-xx-4 {
width: 33.33333333%;
}
.col-xx-3 {
width: 25%;
}
.col-xx-2 {
width: 16.66666667%;
}
.col-xx-1 {
width: 8.33333333%;
}
.col-xx-pull-12 {
right: 100%;
}
.col-xx-pull-11 {
right: 91.66666667%;
}
.col-xx-pull-10 {
right: 83.33333333%;
}
.col-xx-pull-9 {
right: 75%;
}
.col-xx-pull-8 {
right: 66.66666667%;
}
.col-xx-pull-7 {
right: 58.33333333%;
}
.col-xx-pull-6 {
right: 50%;
}
.col-xx-pull-5 {
right: 41.66666667%;
}
.col-xx-pull-4 {
right: 33.33333333%;
}
.col-xx-pull-3 {
right: 25%;
}
.col-xx-pull-2 {
right: 16.66666667%;
}
.col-xx-pull-1 {
right: 8.33333333%;
}
.col-xx-pull-0 {
right: auto;
}
.col-xx-push-12 {
left: 100%;
}
.col-xx-push-11 {
left: 91.66666667%;
}
.col-xx-push-10 {
left: 83.33333333%;
}
.col-xx-push-9 {
left: 75%;
}
.col-xx-push-8 {
left: 66.66666667%;
}
.col-xx-push-7 {
left: 58.33333333%;
}
.col-xx-push-6 {
left: 50%;
}
.col-xx-push-5 {
left: 41.66666667%;
}
.col-xx-push-4 {
left: 33.33333333%;
}
.col-xx-push-3 {
left: 25%;
}
.col-xx-push-2 {
left: 16.66666667%;
}
.col-xx-push-1 {
left: 8.33333333%;
}
.col-xx-push-0 {
left: auto;
}
.col-xx-offset-12 {
margin-left: 100%;
}
.col-xx-offset-11 {
margin-left: 91.66666667%;
}
.col-xx-offset-10 {
margin-left: 83.33333333%;
}
.col-xx-offset-9 {
margin-left: 75%;
}
.col-xx-offset-8 {
margin-left: 66.66666667%;
}
.col-xx-offset-7 {
margin-left: 58.33333333%;
}
.col-xx-offset-6 {
margin-left: 50%;
}
.col-xx-offset-5 {
margin-left: 41.66666667%;
}
.col-xx-offset-4 {
margin-left: 33.33333333%;
}
.col-xx-offset-3 {
margin-left: 25%;
}
.col-xx-offset-2 {
margin-left: 16.66666667%;
}
.col-xx-offset-1 {
margin-left: 8.33333333%;
}
.col-xx-offset-0 {
margin-left: 0;
}
.visible-xx {
display: block !important;
}
table.visible-xx {
display: table;
}
tr.visible-xx {
display: table-row !important;
}
th.visible-xx, td.visible-xx {
display: table-cell !important;
}
.visible-xx-block {
display: block !important;
}
.visible-xx-inline {
display: inline !important;
}
.visible-xx-inline-block {
display: inline-block !important;
}
.hidden-xx {
display: none !important;
}
}

View File

@ -1,237 +0,0 @@
article.container-fluid
background: #FFF
$logo-mini-height: 32px
$mini-avatar-height: 30px
.top_menu
min-height: $top-menu-height
margin-bottom: 0
.navbar-brand
padding: $top-menu-padding-vertical $navbar-padding-horizontal
height: $top-menu-height
.navbar-nav
@media (min-width: $grid-float-breakpoint)
> li
> a
padding-top: $top-menu-padding-vertical
padding-bottom: $top-menu-padding-vertical
.navbar-form,
.navbar-toggle
margin-top: (($top-menu-height - $input-height-base) / 2)
margin-bottom: (($top-menu-height - $input-height-base) / 2)
.navbar-right .avatar
margin-top: (($top-menu-height - $mini-avatar-height) / 2)
margin-bottom: (($top-menu-height - $mini-avatar-height) / 2)
a.navbar-brand
padding-top: (($top-menu-height - $logo-mini-height) / 2)
padding-bottom: (($top-menu-height - $logo-mini-height) / 2)
.nav a,
.pagination a,
.carousel a,
.panel-title a,
i.fa-question-circle[data-toggle='modal'],
span.fa.fa-times,
.navbar a, ul.dropdown-menu a
cursor: pointer
footer
padding-top: 20px
padding-bottom: 20px
text-align: center
background-color: $navbar-default-bg
ul li
display: inline
padding: 0
font-size: 12px
color: $navbar-default-link-color
a
color: $navbar-default-link-color
a:hover,
a:focus
color: $navbar-default-link-hover-color
.offset5
margin-top: 10px
.offset10
margin-top: 10px
.offset20
margin-top: 20px
.offset0
margin-top: 0
.boffset5
margin-bottom: 5px
.boffset10
margin-bottom: 10px
.boffset20
margin-bottom: 20px
.boffset0
margin-bottom: 0
.loffset5
margin-left: 5px
.loffset10
margin-left: 10px
.roffset5
margin-right: 5px
.boffset_auto
margin-bottom: auto
.lroffset-15
margin-left: 15px
margin-right: 15px
.lpadding-5
padding-left: 5px
.ubpadding-5
padding-top: 5px
padding-bottom: 5px
.padding-5
padding: 5px
[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
td.build-list-chevrons
background: #FFF !important
a
cursor: pointer
tr.group-start td
border-top: 2px solid #125687
tr.group-end td
border-bottom: 2px solid #125687
thead > tr > th.icon
width: 12px
table.table-borderless > tbody > tr > td,
table.table-borderless > thead > tr > th
border: 0
.build-list
.panel-heading
.build-list-status
padding: 5px 10px
color: #000
.build-list-time
padding: 5px 10px
.bg-nocolor
background-color: #fff
form .row [class^=col-]
padding-top: 5px
padding-bottom: 5px
.submenu
margin-bottom: 0
#submenu-navbar-collapse ul.left-border
border-left: 1px solid #dcdcdc
#repo-block-navbar-collapse
padding-left: 0
form#clone_url
padding-left: 0px
padding-right: 1px
#copy_to_clipboard.navbar-text.navbar-left
margin-left: 8px
#git-help.navbar-text.navbar-left
margin-left: 8px
margin-right: 8px
p.navbar-text.navbar-right.current_branch
margin-right: 0
#output.formatted
overflow-x: auto
table.highlighttable
width: 100%
max-width: 100%
td.linenos
min-width: 52px
width: 2%
cursor: pointer
.highlight-line
background-color: #FF9900
textarea.resize-vertical
resize: vertical
.label-flag
float: left
margin: 1px 2px
border: 1px solid
.colors
a.fa
text-decoration: none
.update-label, .update-status, .pointer
cursor: pointer
.no-pointer
cursor: default !important
#scroller
position: fixed
bottom: 20px
left: 20px
cursor: pointer
display: none
nav.navbar
form#clone_url
width: 35%
.form-group
display: inline
input
width: 100%
.pre-fail-reason
border: none
border-radius: 0
background: none
padding: 0
margin: 0

View File

@ -35,10 +35,7 @@ $navbar-inverse-toggle-border-color: #ddd;
$blockquote-font-size: 14px; $blockquote-font-size: 14px;
@import "bootstrap-sprockets"; @import "rdash";
@import "bootstrap";
@import "BootstrapXL";
@import "custom_bootstrap";
@import "timeline"; @import "timeline";
@import "font-awesome"; @import "font-awesome";
@import "loading-bar"; @import "loading-bar";

View File

@ -0,0 +1,517 @@
.content-wrapper {
padding-left: 0;
margin-left: 0;
width: 100%;
height: auto;
}
@media only screen and (min-width: 561px) {
.page-wrapper.open {
padding-left: 250px;
}
}
@media only screen and (max-width: 560px) {
.page-wrapper.open {
padding-left: 70px;
}
}
.page-wrapper.open .sidebar-wrapper {
left: 150px;
}
/**
* Hamburg Menu
* When the class of 'hamburg' is applied to the body tag of the document,
* the sidebar changes it's style to attempt to mimic a menu on a phone app,
* where the content is overlaying the content, rather than push it.
*/
@media only screen and (max-width: 560px) {
body.hamburg .page-wrapper {
padding-left: 0;
}
body.hamburg .page-wrapper:not(.open) .sidebar-wrapper {
position: absolute;
left: -100px;
}
body.hamburg .page-wrapper:not(.open) ul.sidebar .sidebar-title.separator {
display: none;
}
body.hamburg .page-wrapper.open .sidebar-wrapper {
position: fixed;
}
body.hamburg .page-wrapper.open .sidebar-wrapper ul.sidebar li.sidebar-main {
margin-left: 0px;
}
body.hamburg .sidebar-wrapper ul.sidebar li.sidebar-main,
body.hamburg .row.header .meta {
margin-left: 70px;
}
body.hamburg .sidebar-wrapper ul.sidebar li.sidebar-main,
body.hamburg .page-wrapper.open .sidebar-wrapper ul.sidebar li.sidebar-main {
transition: margin-left 0.4s ease 0s;
}
}
/**
* Header
*/
.row.header {
height: 60px;
background: #fff;
/*margin-bottom: 15px;*/
}
.row.header > div:last-child {
padding-right: 0;
}
.row.header .meta .page {
font-size: 17px;
padding-top: 11px;
}
.row.header .meta .breadcrumb-links {
font-size: 10px;
}
.row.header .meta div {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.row.header .login a {
padding: 18px;
display: block;
}
.row.header .user {
min-width: 130px;
}
.row.header .user > .item {
width: 65px;
height: 60px;
float: right;
display: inline-block;
text-align: center;
vertical-align: middle;
}
.row.header .user > .item a {
color: #919191;
display: block;
}
.row.header .user > .item i {
font-size: 20px;
line-height: 55px;
}
.row.header .user > .item img {
width: 40px;
height: 40px;
margin-top: 10px;
border-radius: 2px;
}
.row.header .user > .item ul.dropdown-menu {
border-radius: 2px;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.05);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.05);
}
.row.header .user > .item ul.dropdown-menu .dropdown-header {
text-align: center;
}
.row.header .user > .item ul.dropdown-menu li.link {
text-align: left;
}
.row.header .user > .item ul.dropdown-menu li.link a {
padding-left: 7px;
padding-right: 7px;
}
.row.header .user > .item ul.dropdown-menu:before {
position: absolute;
top: -7px;
right: 23px;
display: inline-block;
border-right: 7px solid transparent;
border-bottom: 7px solid rgba(0, 0, 0, 0.2);
border-left: 7px solid transparent;
content: '';
}
.row.header .user > .item ul.dropdown-menu:after {
position: absolute;
top: -6px;
right: 24px;
display: inline-block;
border-right: 6px solid transparent;
border-bottom: 6px solid #ffffff;
border-left: 6px solid transparent;
content: '';
}
.loading {
width: 40px;
height: 40px;
position: relative;
margin: 100px auto;
}
.double-bounce1,
.double-bounce2 {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #333;
opacity: 0.6;
position: absolute;
top: 0;
left: 0;
-webkit-animation: bounce 2s infinite ease-in-out;
animation: bounce 2s infinite ease-in-out;
}
.double-bounce2 {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
@-webkit-keyframes bounce {
0%,
100% {
-webkit-transform: scale(0);
}
50% {
-webkit-transform: scale(1);
}
}
@keyframes bounce {
0%,
100% {
transform: scale(0);
-webkit-transform: scale(0);
}
50% {
transform: scale(1);
-webkit-transform: scale(1);
}
}
/* Fonts */
@font-face {
font-family: 'Montserrat';
/* src: url('../fonts/montserrat-regular-webfont.eot');
src: url('../fonts/montserrat-regular-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/montserrat-regular-webfont.woff') format('woff'), url('../fonts/montserrat-regular-webfont.ttf') format('truetype'), url('../fonts/montserrat-regular-webfont.svg#montserratregular') format('svg');
*/
font-weight: normal;
font-style: normal;
}
@media screen and (-webkit-min-device-pixel-ratio: 0) {
@font-face {
font-family: 'Montserrat';
/* src: url('../fonts/montserrat-regular-webfont.svg') format('svg'); */
}
select {
font-family: Arial, Helvetica, sans-serif;
}
}
/* Base */
html {
overflow-y: scroll;
}
body {
background: #f3f3f3;
font-family: "Montserrat";
color: #333333 !important;
}
.row {
margin-left: 0 !important;
margin-right: 0 !important;
}
.alerts-container .alert:last-child {
margin-bottom: 0;
}
.page-wrapper {
padding-left: 70px;
height: 100%;
}
.sidebar-wrapper {
margin-left: -150px;
left: -30px;
width: 250px;
position: fixed;
height: 100%;
z-index: 999;
}
.page-wrapper,
.sidebar-wrapper {
transition: all .4s ease 0s;
}
.green {
background: #23ae89 !important;
}
.blue {
background: #2361ae !important;
}
.orange {
background: #d3a938 !important;
}
.red {
background: #ae2323 !important;
}
.form-group .help-block.form-group-inline-message {
padding-top: 5px;
}
div.input-mask {
padding-top: 7px;
}
/* #592727 RED */
/* #2f5927 GREEN */
/* #30426a BLUE (default)*/
/* Sidebar background color */
/* Sidebar header and footer color */
/* Sidebar title text colour */
/* Sidebar menu item hover color */
/**
* Sidebar
*/
.sidebar-wrapper {
background: #30426a;
}
ul.sidebar .sidebar-main a,
.sidebar-footer,
ul.sidebar .sidebar-list a:hover,
.page-wrapper:not(.open) ul.sidebar .sidebar-title.separator {
/* Sidebar header and footer color */
background: #2d3e63;
}
ul.sidebar {
position: absolute;
top: 0;
bottom: 0;
padding: 0;
margin: 0;
list-style: none;
text-indent: 20px;
overflow-x: hidden;
overflow-y: auto;
}
ul.sidebar li a {
color: #fff;
display: block;
float: left;
text-decoration: none;
width: 250px;
}
ul.sidebar .sidebar-main {
height: 65px;
}
ul.sidebar .sidebar-main a {
font-size: 18px;
line-height: 60px;
}
ul.sidebar .sidebar-main a:hover {
cursor: pointer;
}
ul.sidebar .sidebar-main .menu-icon {
float: right;
font-size: 18px;
padding-right: 28px;
line-height: 60px;
}
ul.sidebar .sidebar-title {
color: #738bc0;
font-size: 12px;
height: 35px;
line-height: 40px;
text-transform: uppercase;
transition: all .6s ease 0s;
}
ul.sidebar .sidebar-list {
height: 40px;
}
ul.sidebar .sidebar-list a {
text-indent: 25px;
font-size: 15px;
color: #b2bfdc;
line-height: 40px;
}
ul.sidebar .sidebar-list a:hover {
color: #fff;
border-left: 3px solid #e99d1a;
text-indent: 22px;
}
ul.sidebar .sidebar-list a:hover .menu-icon {
text-indent: 25px;
}
ul.sidebar .sidebar-list .menu-icon {
float: right;
padding-right: 29px;
line-height: 40px;
width: 70px;
}
.page-wrapper:not(.open) ul.sidebar {
bottom: 0;
}
.page-wrapper:not(.open) ul.sidebar .sidebar-title {
display: none;
height: 0px;
text-indent: -100px;
}
.page-wrapper:not(.open) ul.sidebar .sidebar-title.separator {
display: block;
height: 2px;
margin: 13px 0;
}
.page-wrapper:not(.open) ul.sidebar .sidebar-list a:hover span {
border-left: 3px solid #e99d1a;
text-indent: 22px;
}
.page-wrapper:not(.open) .sidebar-footer {
display: none;
}
.sidebar-footer {
position: absolute;
height: 40px;
bottom: 0;
width: 100%;
padding: 0;
margin: 0;
transition: all .6s ease 0s;
text-align: center;
}
.sidebar-footer div a {
color: #b2bfdc;
font-size: 12px;
line-height: 43px;
}
.sidebar-footer div a:hover {
color: #ffffff;
text-decoration: none;
}
/* #592727 RED */
/* #2f5927 GREEN */
/* #30426a BLUE (default)*/
/* Sidebar background color */
/* Sidebar header and footer color */
/* Sidebar title text colour */
/* Sidebar menu item hover color */
/**
* Widgets
*/
.widget {
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
-moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
background: #ffffff;
border: 1px solid transparent;
border-radius: 2px;
border-color: #e9e9e9;
}
.widget .widget-header .pagination,
.widget .widget-footer .pagination {
margin: 0;
}
.widget .widget-header {
color: #767676;
background-color: #f6f6f6;
padding: 10px 15px;
border-bottom: 1px solid #e9e9e9;
line-height: 30px;
}
.widget .widget-header i {
margin-right: 5px;
}
.widget .widget-body {
padding: 20px;
}
.widget .widget-body table thead {
background: #fafafa;
}
.widget .widget-body table thead * {
font-size: 14px !important;
}
.widget .widget-body table tbody * {
font-size: 13px !important;
}
.widget .widget-body .error {
color: #ff0000;
}
.widget .widget-body button {
margin-left: 5px;
}
.widget .widget-body div.alert {
margin-bottom: 10px;
}
.widget .widget-body.large {
height: 350px;
overflow-y: auto;
}
.widget .widget-body.medium {
height: 250px;
overflow-y: auto;
}
.widget .widget-body.small {
height: 150px;
overflow-y: auto;
}
.widget .widget-body.no-padding {
padding: 0;
}
.widget .widget-body.no-padding .error,
.widget .widget-body.no-padding .message {
padding: 20px;
}
.widget .widget-footer {
border-top: 1px solid #e9e9e9;
padding: 10px;
}
.widget .widget-icon {
background: #30426a;
width: 65px;
height: 65px;
border-radius: 50%;
text-align: center;
vertical-align: middle;
margin-right: 15px;
}
.widget .widget-icon i {
line-height: 66px;
color: #ffffff;
font-size: 30px;
}
.widget .widget-footer {
border-top: 1px solid #e9e9e9;
padding: 10px;
}
.widget .widget-title .pagination,
.widget .widget-footer .pagination {
margin: 0;
}
.widget .widget-content .title {
font-size: 28px;
display: block;
}
.no-left-gutter {
/*padding-right:0;*/
padding-left: 0;
}
.top-space {
margin-top: 15px;
}
.bottom-space {
margin-bottom: 15px;
}
table tbody td.build-list-statuses .status {
float: left;
border: 1px solid #DDD;
margin: 1px 2px;
}
table tbody td.build-list-statuses {
background: none !important;
}
table tbody td.build-list-chevrons {
background: none !important;
}
table tbody tr.group-start td {
border-top: 2px solid #125687
}
table tbody tr.group-end td {
border-bottom: 2px solid #125687
}
.no-align {
text-align: left;
}
.form-inline > * {
margin-left: 5px;
}

View File

@ -0,0 +1,28 @@
ul.timeline {
list-style: none;
padding: 0;
margin-bottom: 0;
}
ul.timeline > li.timeline-day {
margin-top: 5px;
padding: 5px;
border-bottom: none;
}
ul.timeline > li.timeline-day span {
padding: 3px;
border-radius: 3px;
border: 1px solid rgb(221, 221, 221);
background: rgb(250, 250, 250);
}
ul.timeline > li {
border-bottom: 1px solid rgb(221, 221, 221);
}
ul.timeline > li:last-of-type {
border-bottom: none;
}
ul.timeline > li div.timeline-item {
padding: 10px;
}
ul.timeline > li div.timeline-item > div.timeline-item-body {
margin-top: 5px;
}

View File

@ -1,12 +0,0 @@
table.table.blame
tr
td
padding-top: 0
padding-bottom: 0
pre
margin-bottom: 0
border: 0
.highlight
pre
background: none

View File

@ -1,71 +0,0 @@
.table-responsive.overflow-auto
border: 1px solid #DDD
overflow-x: auto
table.table.diff.inline
margin-bottom: 0
tr.changes
pre
padding: 0
margin: 0
background: none
border: none
.diff-content
padding: 0
margin: 0
tr
td.header
background: whitesmoke
padding: 0 0 0 10px
td.code, td.line_numbers
padding: 0 0 0 10px
border-top: none
td.line_numbers
background-color: #ECECEC
border-right: 1px solid #DDD
text-align: right
vertical-align: middle
padding: 0 6px
width: 40px
td.code.del
background-color: #FFDDDD
.idiff
background-color: #F2ACAD
td.code.ins
background-color: #DDFFDD
td.code.highlight-line
background-color: #FFFFCC
tr.inline-comments
border-top: 1px solid #DDD
.add_line-comment
position: absolute
width: 25px
height: 18px
margin-left: -103px
margin-top: 0
cursor: pointer
opacity: 0
filter: alpha(Opacity=0)
-moz-opacity: 0
tr:hover .add_line-comment
opacity: 1
filter: alpha(Opacity=100)
-moz-opacity: 1
.line-comment, #new_inline_comment
max-width: 700px
div.file div.top
min-height: 28px
background: #ededed

View File

@ -119,7 +119,6 @@ class Api::V1::JobsController < Api::V1::BaseController
arches = params[:arches].to_s.split(',') arches = params[:arches].to_s.split(',')
native_arches = params[:native_arches].to_s.split(',') native_arches = params[:native_arches].to_s.split(',')
native_arches &= arches if !arches.empty? native_arches &= arches if !arches.empty?
puts native_arches
native_arches.present? ? Arch.where(name: native_arches).pluck(:id) : [] native_arches.present? ? Arch.where(name: native_arches).pluck(:id) : []
end end
end end

View File

@ -2,12 +2,14 @@ class HomeController < ApplicationController
before_action :authenticate_user!, except: [:root] before_action :authenticate_user!, except: [:root]
skip_after_action :verify_authorized skip_after_action :verify_authorized
def index
redirect_to projects_dashboard_path
end
def activity(is_my_activity = false) def activity(is_my_activity = false)
#@filter = :build
@activity_feeds = current_user.activity_feeds @activity_feeds = current_user.activity_feeds
.by_project_name(params[:project_name_filter]) .by_project_name(params[:project_name_filter])
.by_owner_uname(params[:owner_filter]) .by_owner_uname(params[:owner_filter])
#@activity_feeds = @activity_feeds.where(kind: "ActivityFeed::#{@filter.upcase}".constantize) unless @filter == :all
@activity_feeds = if is_my_activity @activity_feeds = if is_my_activity
@activity_feeds.where(creator_id: current_user) @activity_feeds.where(creator_id: current_user)
@ -17,8 +19,17 @@ class HomeController < ApplicationController
@activity_feeds = @activity_feeds.paginate page: current_page @activity_feeds = @activity_feeds.paginate page: current_page
if @activity_feeds.next_page
if is_my_activity
method = :own_activity_path
else
method = :activity_feeds_path
end
@next_page_link = method.to_proc.call(self, page: @activity_feeds.next_page, owner_filter: params[:owner_filter],
project_name_filter: params[:project_name_filter], format: :json)
end
respond_to do |format| respond_to do |format|
format.html { render 'activity' }
format.json { render 'activity' } format.json { render 'activity' }
format.atom format.atom
end end

View File

@ -11,8 +11,6 @@ class Platforms::PlatformsController < Platforms::BaseController
format.json { format.json {
@platforms = PlatformPolicy::Scope.new(current_user, Platform).related @platforms = PlatformPolicy::Scope.new(current_user, Platform).related
@platforms_count = @platforms.count
@platforms = @platforms.paginate(page: current_page, per_page: Platform.per_page)
} }
end end
end end

View File

@ -16,7 +16,6 @@ class Projects::BuildListsController < Projects::BaseController
params[:filter].each{|k,v| params[:filter].delete(k) if v.blank? } if params[:filter] params[:filter].each{|k,v| params[:filter].delete(k) if v.blank? } if params[:filter]
respond_to do |format| respond_to do |format|
format.html
format.json do format.json do
@filter = BuildList::Filter.new(@project, current_user, params[:filter] || {}) @filter = BuildList::Filter.new(@project, current_user, params[:filter] || {})
params[:page] = params[:page].to_i == 0 ? nil : params[:page] params[:page] = params[:page].to_i == 0 ? nil : params[:page]
@ -84,7 +83,8 @@ class Projects::BuildListsController < Projects::BaseController
else else
BuildList.where(id: build_lists.map(&:id)).update_all(group_id: build_lists[0].id) if build_lists.size > 1 BuildList.where(id: build_lists.map(&:id)).update_all(group_id: build_lists[0].id) if build_lists.size > 1
flash[:notice] = notices.join('<br>').html_safe flash[:notice] = notices.join('<br>').html_safe
redirect_to project_build_lists_path(@project) puts root_path(anchor: "project=" + @project.name_with_owner)
redirect_to root_path(anchor: "?project=" + @project.name_with_owner)
end end
end end
@ -153,18 +153,6 @@ class Projects::BuildListsController < Projects::BaseController
} }
end end
def list
@build_lists = @project.build_lists
@build_lists = @build_lists.where(user_id: current_user) if params[:owner_filter] == 'true'
@build_lists = @build_lists.where(status: [BuildList::BUILD_ERROR, BuildList::FAILED_PUBLISH, BuildList::REJECTED_PUBLISH]) if params[:status_filter] == 'true'
@total_build_lists = @build_lists.count
@build_lists = @build_lists.recent.paginate(page: current_page)
render partial: 'build_lists_ajax', layout: false
end
protected protected
def build_list_params def build_list_params

View File

@ -8,70 +8,57 @@ class Projects::ProjectsController < Projects::BaseController
def index def index
authorize :project authorize :project
@projects = ProjectPolicy::Scope.new(current_user, Project).membered.search(params[:search])
respond_to do |format| respond_to do |format|
format.html {
@groups = current_user.groups
@owners = User.where(id: @projects.where(owner_type: 'User').uniq.pluck(:owner_id))
}
format.json { format.json {
groups = params[:groups] || [] if not params[:search].present?
owners = params[:users] || [] @projects = Project.find(current_user.build_lists.group(:project_id).limit(10).pluck(:project_id))
@projects = @projects.by_owners(groups, owners) if groups.present? || owners.present? else
@projects_count = @projects.count @projects = ProjectPolicy::Scope.new(current_user, Project).membered.search(params[:search]).limit(20)
@projects = @projects.recent.paginate(page: current_page, per_page: Project.per_page) end
} }
end end
end end
def project_info
authorize @project
respond_to do |format|
format.json {
@github_basic_info = @project.github_data
@commits = []
@project.github_branches.each do |branch|
last_commit_info = @project.github_last_commit(branch.name)[0]
if last_commit_info
last_commit = {
branch: branch.name,
url: last_commit_info['html_url'],
sha: last_commit_info['sha'],
message: last_commit_info['commit']['message']
}
if last_commit_info['committer']
last_commit[:committer_login] = last_commit_info['committer']['login']
last_commit[:committer_url] = last_commit_info['committer']['html_url']
else
last_commit[:committer_login] = last_commit_info['commit']['author']['name']
last_commit[:committer_url] = ''
end
@commits << last_commit
end
end
}
end
end
def dashboard
authorize :project
end
def new def new
authorize :project authorize :project
@project = Project.new @project = Project.new
end end
def mass_import
authorize :project
@project = Project.new(mass_import: true)
end
def mass_create
authorize :project
@project = Project.new(mass_create: true)
end
def run_mass_import
@project = Project.new project_params
@project.owner = choose_owner
authorize @project
@project.valid?
@project.errors.messages.slice! :url
if @project.errors.messages.blank? # We need only url validation
@project.init_mass_import
flash[:notice] = t('flash.project.mass_import_added_to_queue')
redirect_to projects_path
else
render :mass_import
end
end
def run_mass_create
@project = Project.new project_params
@project.owner = choose_owner
authorize @project
@project.valid?
@project.errors.messages.slice! :url
if @project.errors.messages.blank? # We need only url validation
@project.init_mass_create
flash[:notice] = t('flash.project.mass_create_added_to_queue')
redirect_to projects_path
else
render :mass_create
end
end
def edit def edit
authorize @project authorize @project
@project_aliases = Project.project_aliases(@project).paginate(page: current_page)
end end
def create def create
@ -96,7 +83,7 @@ class Projects::ProjectsController < Projects::BaseController
format.html do format.html do
if @project.update_attributes(project_params) if @project.update_attributes(project_params)
flash[:notice] = t('flash.project.saved') flash[:notice] = t('flash.project.saved')
redirect_to @project redirect_to root_path
else else
flash[:error] = t('flash.project.save_error') flash[:error] = t('flash.project.save_error')
flash[:warning] = @project.errors.full_messages.join('. ') flash[:warning] = @project.errors.full_messages.join('. ')
@ -137,31 +124,6 @@ class Projects::ProjectsController < Projects::BaseController
redirect_to @project.owner redirect_to @project.owner
end end
def sections
authorize @project, :update?
if request.patch?
if @project.update_attributes(project_params)
flash[:notice] = t('flash.project.saved')
redirect_to sections_project_path(@project)
else
@project.save
flash[:error] = t('flash.project.save_error')
end
end
end
def remove_user
authorize @project
@project.relations.by_actor(current_user).destroy_all
respond_to do |format|
format.html do
flash[:notice] = t("flash.project.user_removed")
redirect_to projects_path
end
format.json { render nothing: true }
end
end
def autocomplete_maintainers def autocomplete_maintainers
authorize @project authorize @project
term, limit = params[:query], params[:limit] || 10 term, limit = params[:query], params[:limit] || 10
@ -179,10 +141,6 @@ class Projects::ProjectsController < Projects::BaseController
redirect_to 'https://github.com/' + @project.github_get_organization + '/' + @project.name + '/compare/' + params[:diff] redirect_to 'https://github.com/' + @project.github_get_organization + '/' + @project.name + '/compare/' + params[:diff]
end end
def bl_redirect
redirect_to controller: "build_lists", action: "index"
end
protected protected
def project_params def project_params

View File

@ -4,7 +4,7 @@ module Project::GithubApi
extend ActiveSupport::Concern extend ActiveSupport::Concern
def github_data def github_data
Octokit.repo github_get_organization + '/' + name rescue nil Octokit.repo github_get_organization + '/' + name rescue {}
end end
def github_branches def github_branches
@ -15,6 +15,14 @@ module Project::GithubApi
Octokit.tags github_get_organization + '/' + name rescue [] Octokit.tags github_get_organization + '/' + name rescue []
end end
def github_last_commit(branch = nil)
if branch.present?
Octokit.commits github_get_organization + '/' + name, sha: branch, per_page: 1 rescue []
else
Octokit.commits github_get_organization + '/' + name, per_page: 1 rescue []
end
end
def github_get_organization def github_get_organization
return github_organization if github_organization.presence return github_organization if github_organization.presence
APP_CONFIG['github_organization'] APP_CONFIG['github_organization']

View File

@ -5,6 +5,7 @@ class ProductBuildList < ActiveRecord::Base
include EventLoggable include EventLoggable
include ProductBuildLists::Statusable include ProductBuildLists::Statusable
include ProductBuildLists::AbfWorkerable include ProductBuildLists::AbfWorkerable
include EventLoggable
LIVE_TIME = 2.week # for autostart LIVE_TIME = 2.week # for autostart
MAX_LIVE_TIME = 3.month # for manual start; MAX_LIVE_TIME = 3.month # for manual start;

View File

@ -3,6 +3,7 @@ class ProjectPolicy < ApplicationPolicy
def index? def index?
!user.guest? !user.guest?
end end
alias_method :dashboard?, :index?
alias_method :autocomplete_project?, :index? alias_method :autocomplete_project?, :index?
alias_method :remove_user?, :index? alias_method :remove_user?, :index?
alias_method :preview?, :index? alias_method :preview?, :index?
@ -15,11 +16,12 @@ class ProjectPolicy < ApplicationPolicy
local_reader? local_reader?
end end
alias_method :commit?, :show? alias_method :commit?, :show?
alias_method :read?, :show? alias_method :read?, :show?
alias_method :archive?, :show? alias_method :archive?, :show?
alias_method :get_id?, :show? alias_method :get_id?, :show?
alias_method :refs_list?, :show? alias_method :refs_list?, :show?
alias_method :project_info?, :show?
def fork? def fork?
!user.guest? && show? !user.guest? && show?

View File

@ -1,13 +1,11 @@
.panel.panel-default rd-widget
.panel-heading rd-widget-header title=t('devise.passwords.new_password')
h4= t('devise.passwords.new_password') rd-widget-body
.panel-body
= simple_form_for resource, url: password_path(resource_name), html: { method: :put } do |f| = simple_form_for resource, url: password_path(resource_name), html: { method: :put } do |f|
= f.hidden_field :reset_password_token = f.hidden_field :reset_password_token
= f.input :password = f.input :password
= f.input :password_confirmation = f.input :password_confirmation
hr .row
.pull-right .pull-right
= f.button :submit, t('devise.passwords.edit_button') = f.button :submit, t('devise.passwords.edit_button')

View File

@ -1,12 +1,12 @@
.panel.panel-default .row.top-space
.panel-heading .col-md-6.col-md-offset-3
h4= t('devise.passwords.forgot') rd-widget
.panel-body rd-widget-header title=t('devise.passwords.forgot')
rd-widget-body
= simple_form_for resource, url: password_path(resource_name), html: { method: :post } do |f|
= hidden_field_tag :invitation_token, @invitation_token
= simple_form_for resource, url: password_path(resource_name), html: { method: :post } do |f| = f.input :email
= hidden_field_tag :invitation_token, @invitation_token .row
.pull-right
= f.input :email = f.button :submit, t('devise.passwords.send')
hr
.pull-right
= f.button :submit, t('devise.passwords.send')

View File

@ -1,18 +1,16 @@
.row.top-space
.col-md-6.col-md-offset-3
rd-widget
rd-widget-header title=t('layout.devise.shared_links.sign_up')
rd-widget-body
= simple_form_for resource, url: registration_path(resource_name) do |f|
= hidden_field_tag :invitation_token, @invitation_token
.panel.panel-default = f.input :uname
.panel-heading = f.input :name
h4= t('layout.devise.shared_links.sign_up') = f.input :email
.panel-body = f.input :password
= f.input :password_confirmation
= simple_form_for resource, url: registration_path(resource_name) do |f| .row
= hidden_field_tag :invitation_token, @invitation_token .pull-right
= f.button :submit, t('layout.devise.shared_links.sign_up')
= f.input :uname
= f.input :name
= f.input :email
= f.input :password
= f.input :password_confirmation
hr
.pull-right
= f.button :submit, t('layout.devise.shared_links.sign_up')

View File

@ -1,22 +1,19 @@
.row.top-space
.col-md-6.col-md-offset-3
rd-widget
rd-widget-header title=t('layout.devise.shared_links.sign_in')
rd-widget-body
- login = t('devise.sessions.login'); password = t('devise.sessions.password')
= hidden_field_tag :login_default, login
= hidden_field_tag :password_default, password
= simple_form_for resource, url: session_path(resource_name) do |f|
.panel.panel-default = f.input :login
.panel-heading = f.input :password
h4= t('layout.devise.shared_links.sign_in') .row
.panel-body .pull-left
= f.input :remember_me, as: :boolean, checked: true
.pull-right
- login = t('devise.sessions.login'); password = t('devise.sessions.password') = f.button :submit, t('layout.devise.shared_links.sign_in')
= hidden_field_tag :login_default, login .row
= hidden_field_tag :password_default, password = link_to t('layout.devise.shared_links.forgot_password'), new_password_path(resource_name)
= simple_form_for resource, url: session_path(resource_name) do |f|
= f.input :login
= f.input :password
hr
.pull-left
= f.input :remember_me, as: :boolean, checked: true
.pull-right
= f.button :submit, t('layout.devise.shared_links.sign_in')
= link_to t('layout.devise.shared_links.forgot_password'), new_password_path(resource_name)

View File

@ -1,13 +0,0 @@
tab[ heading= t('activity_menu.activity_feed')
active= "actCtrl.activity_tab.active"
select = "actCtrl.getContent('activity')" ]
.row
.col-md-3.offset10== render 'sidebar'
.col-md-9.offset10
h3
= t 'layout.activity_feed.header'
= link_to image_tag('rss.ico', width: '15px', height: '15px', class: 'atom_icon'),
atom_activity_feeds_path(format: 'atom', token: current_user.authentication_token)
i< class= 'fa fa-spinner fa-spin fa-lg offset10 boffset10' ng-show= 'actCtrl.processing'
== render 'activity_tabsets'

View File

@ -1,18 +0,0 @@
div ng-hide= 'actCtrl.processing'
/ The time line
.row.offset10
.col-md-12.col-sm-12
ul.timeline
/ timeline time label
li.time-label ng-repeat-start= 'item in actCtrl.getCurActivity().feed'
span ng-show= "item.is_date_changed"
| {{item.date | amDateFormat:'ll'}}
/ timeline item
li ng-include= "actCtrl.getTemplate(item)"
.hide ng-repeat-end= true
li
i.img-circle.bg-primary.fa.fa-clock-o
hr
btn.center-block.btn.btn-primary[ ng-show= 'actCtrl.getCurActivity().next_page_link'
ng-click= "actCtrl.load_more()" ]
= t('layout.activity_feed.load_messages')

View File

@ -1,5 +0,0 @@
.sub-menu.activity-tabs
%nav
%ul
- (collection = t 'feed_menu').each do |base, title|
%li= link_to title, root_path(filter: base), class: @filter == base ? 'active' : ''

View File

@ -1,21 +0,0 @@
hr
h4
=> t('layout.relations.filters')
.form-group
= text_field_tag :owner_uname, nil,
class: 'form-control',
placeholder: t('search.placeholders.owner_filter'),
'ng-model' => 'actCtrl.current_activity_tab.owner_uname_filter_tmp',
'typeahead' => 'owner.uname for owner in actCtrl.getOwnersList($viewValue)',
'typeahead-on-select' => 'actCtrl.selectOwnerFilter($item, $model, $label)',
'typeahead-template-url' => "get_owners.html"
.form-group
= text_field_tag :project_name, nil,
class: 'form-control',
placeholder: t('search.placeholders.name_filter'),
'ng-model' => 'actCtrl.current_activity_tab.project_name_filter_tmp',
'ng-value' => 'actCtrl.current_activity_tab.project_name_filter_tmp',
'typeahead' => 'project.name for project in actCtrl.getProjectNamesList($viewValue)',
'typeahead-on-select' => 'actCtrl.selectProjectNameFilter($item, $model, $label)'

View File

@ -1,10 +0,0 @@
tab[ heading= t('activity_menu.own_activity')
active= "actCtrl.own_activity_tab.active"
select = "actCtrl.getContent('own_activity')" ]
.row
.col-md-3.offset10== render 'sidebar'
.col-md-9.offset10
h3
= t 'layout.activity_feed.own_header'
i< class= 'fa fa-spinner fa-spin fa-lg offset10 boffset10' ng-show= 'actCtrl.processing'
== render 'activity_tabsets'

View File

@ -1,30 +0,0 @@
p
= link_to t('layout.activity_feed.new_project'), new_project_path,
class: 'btn btn-primary btn-small', role: 'button'
== render 'filters'
hr
h5= t('layout.activity_feed.my_last_projects')
ul.nav.nav-pills.nav-stacked
- current_user.projects.order(updated_at: :desc).limit(5).each do |project|
li
= link_to project_path(project) do
= fa_visibility_icon project
= project.name_with_owner
li
= link_to t('layout.activity_feed.all_my_projects'), projects_path
hr
- midnight = Time.now.utc.to_date
h5= t 'layout.activity_feed.my_builds_by_day'
ul.nav.nav-pills.nav-stacked
- ['BuildList::BUILD_PUBLISHED', 'BuildList::SUCCESS', 'BuildList::BUILD_STARTED',
'BuildList::BUILD_PENDING', 'BuildList::BUILD_ERROR'].each do |state|
li
a[ href = build_lists_path(filter: {status: state.constantize, 'updated_at_start(1i)' => midnight.year,
'updated_at_start(2i)' => midnight.month, 'updated_at_start(3i)' => midnight.day}) ]
span.badge.pull-right
= BuildList.for_status(state.constantize).for_user(current_user).for_notified_date_period(midnight, nil).count
= t "layout.build_lists.statuses.#{state.demodulize.downcase}"
li
a[ href = build_lists_path ]=t 'layout.activity_feed.all_my_builds'

View File

@ -1,7 +0,0 @@
-set_meta_tags title: nil
.row
.col-xs-12.col-md-10.col-md-offset-1[ ng-controller= 'ActivityController as actCtrl'
ng-init= "actCtrl.init('#{action_name}')" ]
tabset.offset10 ng-cloak= true
== render 'activity_tab'
== render 'own_activity_tab'

View File

@ -1,9 +1,5 @@
if @activity_feeds.next_page if @activity_feeds.next_page
json.next_page_link root_path(filter: @filter, json.next_page_link @next_page_link
page: @activity_feeds.next_page,
owner_filter: @owner_filter,
project_name_filter: @project_name_filter,
format: :json)
end end
json.feed do json.feed do

View File

@ -0,0 +1,147 @@
.row.top-space
.col-md-6
rd-widget
div ng-controller="ProjectsController"
rd-widget-header title=(t "dashboard.projects.title") icon="fa-cube"
input.form-control.input-sm [ng-model="search" placeholder=(t "dashboard.projects.search")
ng-change="searchProjects(search)" ng-model-options="{ debounce: 500 }"]
rd-widget-body classes="medium no-padding" loading="requesting"
.table-responsive
table.table ng-cloak=true
thead
tr
th ng-show="search" = t 'dashboard.projects.name'
th ng-hide="search" = t 'dashboard.projects.last_projects'
th
th
tbody
tr ng-repeat = 'item in projects'
td
button[ ng-click = 'selectProject(item.name_with_owner)'
ng-disabled="ProjectSelectService.disable()" class="btn btn-xs btn-link"] {{::item.name_with_owner}}
td
a[ ng-href = '{{::item.new_build_list_link}}'] = t 'dashboard.projects.new_build'
td
a[ ng-href = '{{::item.edit_link}}'
ng-show='::item.edit_link' target='_blank'] = t 'project_menu.settings'
- if policy(:project).create?
rd-widget-footer
ul.nav.nav-justified
li
= link_to t('layout.projects.new'), new_project_path, target: '_blank'
.col-md-6
rd-widget
div ng-controller="ProjectInfoController"
rd-widget-header title=(t('dashboard.project_info.title') + '{{widget_title}}')
rd-widget-body class="medium" loading="requesting"
div ng-hide="widget_title"
= t('dashboard.project_info.select')
div ng-show="widget_title"
div
a ng-href="{{project_info.html_url}}" target="_blank"
| {{project}}
div.bottom-space
| {{project_info.description}}
div
div.bottom-space ng-repeat="commit in project_info.commits"
div
span
| {{::commit.branch}}
span.pull-right
a ng-href="{{::commit.committer_url}}" target="_blank"
| {{::commit.committer_login}}
div
a ng-href="{{::commit.url}}" target="_blank"
| {{::commit.sha}}
div
| {{::commit.message}}
.row.top-space
.col-md-12
== render 'projects/build_lists/filter'
rd-widget
div ng-controller="BuildListsController"
rd-widget-header title="Build Lists{{widget_title}}" icon="fa-gears"
.form-inline ng-init="autoreload=true"
button ng-model="autoreload" ng-click="setAutoreload(autoreload)" class="btn btn-default" uib-btn-checkbox=""
= t 'layout.autoreload_page'
button class="btn btn-default" ng-click="openFilters()" ng-disabled="isRequest"
| Filters
button [class="btn btn-default" ng-show="widget_title"
ng-click="clearProject()" ng-disabled="ProjectSelectService.disable()"]
| Clear selected project
rd-widget-body classes="large no-padding" loading="isRequest"
.row
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.hostname')
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
a[ ng-href = '{{::bl.url}}' ] {{::bl.id}}
div ng-show = '::bl.hasRelated' ng-bind-html="::bl.chevronHtml"
/ 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'
| {{::bl.project.name_with_owner}}
/ diff
td
a ng-href = '{{::bl.version_link_url}}' ng-show = '::bl.project'
| {{::bl.version_link_text}}
/ project_version
td[] {{::bl.version_release}}
/ 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')
/ user
td
a[ ng-href = '{{::bl.user.url}}' ] {{::bl.user.fullname}}
/ hostname
td[] {{::bl.hostname}}
/ updated_at
td title = '{{::bl.updated_at_utc}}'
| {{::bl.updated_at | amDateFormat:'YYYY-MM-DD HH:mm' }}
rd-widget-footer ng-show="total_items > per_page"
== angularjs_paginate( per_page: 'per_page' )

View File

@ -1,6 +1,6 @@
.row - unless flash.empty?
.col-lx-12.col-md-10.col-md-offset-1 .row.top-space.alerts-container ng-hide="hideAlerts"
- flash.each do |type, message| .col-md-10.col-md-offset-1
.alert.text-center class = alert_class(type) - flash.each do |type, message|
button.close[ type = 'button' data-dismiss = 'alert' aria-hidden = true ] &times; uib-alert.alert.text-center class=alert_class(type)
== message == message

View File

@ -1 +0,0 @@
#scroller.fa.fa-arrow-circle-up.fa-2x.text-primary.hidden-xs

View File

@ -3,36 +3,59 @@ html
head head
meta name="viewport" content="width=device-width, initial-scale=1.0" meta name="viewport" content="width=device-width, initial-scale=1.0"
meta content="text/html; charset=utf-8" http-equiv="Content-Type" meta content="text/html; charset=utf-8" http-equiv="Content-Type"
== render 'shared/header'
== csrf_meta_tag == csrf_meta_tag
= display_meta_tags site: APP_CONFIG['project_name'], reverse: true, separator: '-' = display_meta_tags site: APP_CONFIG['project_name'], reverse: true, separator: '-'
- 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'])
script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js" type="text/javascript"
link href='//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css' rel='stylesheet'
link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css'
== stylesheet_link_tag 'new_application', cache: 'application' == stylesheet_link_tag 'new_application', cache: 'application'
body[ ng-app='RosaABF' ng-controller='RosaABFController' body[ ng-app='RosaABF' ng-controller='RosaABFController' ng-strict-di=''
ng-init="init('#{I18n.locale}', #{!!current_user.try(:sound_notifications)})" ] ng-init="init('#{I18n.locale}', #{!!current_user.try(:sound_notifications)})" ng-cloak="true"]
== render 'layouts/menu/new_top' .page-wrapper.open
== yield :submenu if content_for?(:submenu) .sidebar-wrapper
ul.sidebar
li.sidebar-main
a href="/"
= link_to image_tag('logo-mini.png', alt: 'ABF'), root_path
== render 'layouts/menu/new_top'
- if current_user || APP_CONFIG['anonymous_access'] .content-wrapper
- if (flash_notify = FlashNotify.published_first_cached) && flash_notify.should_show?(cookies[:flash_notify_hash]) .page-content
javascript: .row.header
var FLASH_HASH_ID = "#{flash_notify.hash_id}"; .col-md-12
.notify.alert.alert-dismissable.text-center class=alert_class(flash_notify.status) .user.pull-right
button.close type='button' data-dismiss='alert' aria-hidden=true - if current_user
= flash_notify.body(I18n.locale).html_safe .item.dropdown(uib-dropdown)
a(uib-dropdown-toggle)
= image_tag avatar_url(current_user), alt: 'avatar'
ul.dropdown-menu.dropdown-menu-right
li.link= link_to current_user.uname, current_user
li.link= link_to t('layout.settings.label'), profile_settings_path
li.divider
li.link= link_to t('layout.logout'), destroy_user_session_path, method: :delete
- else
ul.nav.navbar-nav
li= link_to t('layout.devise.shared_links.sign_up'), new_user_registration_path
li= link_to t('layout.devise.shared_links.sign_in'), new_user_session_path
.meta
.page
== yield :submenu if content_for?(:submenu)
== render 'layouts/noscript'
== render "layouts/flashes"
== render 'layouts/noscript' == yield
== render "layouts/flashes"
article.container-fluid script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.min.js" type="text/javascript"
== yield script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-resource.js" type="text/javascript"
== render 'layouts/menu/new_bottom' script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-cookies.js" type="text/javascript"
== javascript_include_tag 'new_application', cache: 'application' script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-sanitize.js" type="text/javascript"
- if I18n.locale == :ru script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.2.5/ui-bootstrap-tpls.js" type="text/javascript"
== javascript_include_tag 'moment/ru.js', cache: 'moment' script src="https://code.jquery.com/jquery-2.2.2.min.js" integrity="sha256-36cp2Co+/62rEAAYHLmRCPIych47CvdM+uTBJwSzWjI=" crossorigin="anonymous"
== javascript_include_tag 'angular-locale_ru-ru', cache: 'angular-locale' == javascript_include_tag 'new_application', cache: 'application'
== yield :additional_scripts if content_for?(:additional_scripts) == yield :additional_scripts if content_for?(:additional_scripts)
- if I18n.locale == :ru
== render '/layouts/scroller' == javascript_include_tag 'moment/ru.js', cache: 'moment'
== javascript_include_tag 'angular-locale_ru-ru', cache: 'angular-locale'

View File

@ -1,22 +0,0 @@
!!!
%html
%head
%meta{content: "text/html; charset=utf-8", "http-equiv" => "Content-Type"}/
%title=t 'invites.title'
%script{src: "http://html5shiv.googlecode.com/svn/trunk/html5.js", type: "text/javascript"}
%link{href: "/styles/prereg.css", rel: "stylesheet", type: "text/css"}/
%body
.wrap
= yield :nav if content_for?(:nav)
/ Top block
%header
.logo
.text=t 'invites.header'
.both
/ Page
%article
=yield
.both
/ Footer
%footer= render "layouts/menu/bottom"
= render 'layouts/counters' if !current_user.try(:admin?) && Rails.env.production?

View File

@ -0,0 +1,2 @@
div ng-if="false"

View File

@ -1,62 +1,12 @@
nav.navbar.navbar-inverse.top_menu role = "navigation" -if current_user
.container-fluid -if policy(:project).dashboard?
/ Brand and toggle get grouped for better mobile display li.sidebar-list
.navbar-header a href=projects_dashboard_path
button.navbar-toggle[ data-target = "#top-menu-navbar-collapse" data-toggle = "collapse" type = "button" ] =t 'dashboard.dashboard_name'
span.sr-only Toggle navigation span.menu-icon.fa.fa-tachometer
span.icon-bar - (collection = t 'top_menu').each do |base, title|
span.icon-bar - if policy(base.to_s.singularize.to_sym).index?
span.icon-bar li.sidebar-list
= link_to image_tag('logo-mini.png', alt: 'ABF'), root_path, class: 'navbar-brand' a href=send("#{base}_path")
/ Collect the nav links, forms, and other content for toggling = title
#top-menu-navbar-collapse.collapse.navbar-collapse span.menu-icon.fa class=top_menu_icon(base)
ul.nav.navbar-nav
- (collection = t 'top_menu').each do |base, title|
- if policy(base.to_s.singularize.to_sym).index?
li class=top_menu_class(base)
a href=send("#{base}_path")
i.fa.hidden-sm class=top_menu_icon(base)
i.fa.visible-sm-inline-block.fa-2x class=top_menu_icon(base)
span.hidden-sm
=< title
li
a href="http://repoclosure.openmandriva.org"
i.fa.hidden-sm class="fa-bicycle"
i.fa.visible-sm-inline-block.fa-2x class="fa-bicycle"
span.hidden-sm
=< t('repoclosure')
- if current_user.try(:admin?)
li class=top_menu_class('admin')
a href=admin_users_path target="_blank"
i.fa.fa-lock.hidden-sm
i.fa.fa-lock.visible-sm-inline-block.fa-2x
span.hidden-sm
=< t('admins_menu_header')
li
= form_tag search_index_path, method: 'get', class: 'navbar-form navbar-left',
role: 'search' do
.form-group
= text_field_tag 'query', @query, placeholder: t('layout.search.header'), class: 'form-control'
ul.nav.navbar-nav.navbar-right
- if current_user
li.hidden-xs
.avatar
= image_tag avatar_url(current_user), alt: 'avatar', class: 'img-responsive'
li.dropdown
a.dropdown[ data-toggle = 'dropdown' href = '#' id = 'userMenuLabel'
aria-haspopup = 'true' aria-expanded = 'false' ]
span.visible-xs-inline-block.visible-lg-inline-block>
= current_user.uname
i.fa.fa-cog.hidden-sm
i.fa.fa-cog.visible-sm-inline-block.fa-2x
ul.dropdown-menu role = 'menu' aria-labelledby = 'userMenuLabel'
li= link_to current_user.uname, current_user
li= link_to t('layout.settings.label'), profile_settings_path
li.divider
li= link_to t('layout.logout'), destroy_user_session_path, method: :delete
- else
ul.nav.navbar-nav
li= link_to t('layout.devise.shared_links.sign_up'), new_user_registration_path
li= link_to t('layout.devise.shared_links.sign_in'), new_user_session_path
/ /.navbar-collapse
/ /.container-fluid

View File

@ -3,27 +3,59 @@ html
head head
meta name="viewport" content="width=device-width, initial-scale=1.0" meta name="viewport" content="width=device-width, initial-scale=1.0"
meta content="text/html; charset=utf-8" http-equiv="Content-Type" meta content="text/html; charset=utf-8" http-equiv="Content-Type"
== render 'shared/header'
== csrf_meta_tag == csrf_meta_tag
= display_meta_tags site: APP_CONFIG['project_name'], reverse: true, separator: '-' = display_meta_tags site: APP_CONFIG['project_name'], reverse: true, separator: '-'
- 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'])
script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js" type="text/javascript"
link href='//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css' rel='stylesheet'
link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css'
== stylesheet_link_tag 'new_application', cache: 'application' == stylesheet_link_tag 'new_application', cache: 'application'
body body[ ng-app='RosaABF' ng-controller='RosaABFController' ng-strict-di=''
== render 'layouts/menu/new_top' ng-init="init('#{I18n.locale}', #{!!current_user.try(:sound_notifications)})" ng-cloak="true"]
== render 'layouts/noscript' .page-wrapper.open
== render "layouts/flashes" .sidebar-wrapper
ul.sidebar
li.sidebar-main
a href="/"
= link_to image_tag('logo-mini.png', alt: 'ABF'), root_path
== render 'layouts/menu/new_top'
.content-wrapper
.page-content
.row.header
.col-md-12
.user.pull-right
- if current_user
.item.dropdown(uib-dropdown)
a(uib-dropdown-toggle)
= image_tag avatar_url(current_user), alt: 'avatar'
ul.dropdown-menu.dropdown-menu-right
li.link= link_to current_user.uname, current_user
li.link= link_to t('layout.settings.label'), profile_settings_path
li.divider
li.link= link_to t('layout.logout'), destroy_user_session_path, method: :delete
- else
ul.nav.navbar-nav
li= link_to t('layout.devise.shared_links.sign_up'), new_user_registration_path
li= link_to t('layout.devise.shared_links.sign_in'), new_user_session_path
.meta
.page
== yield :submenu if content_for?(:submenu)
== render 'layouts/noscript'
== render "layouts/flashes"
article.container-fluid.offset10
.row
.col-md-6.col-md-offset-3
.panel.panel-primary
.panel-heading
= image_tag 'logo.png', class: 'img-responsive center-block img-rounded'
== yield == yield
== render 'layouts/menu/new_bottom'
== javascript_include_tag 'new_application', cache: 'application' script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.min.js" type="text/javascript"
== javascript_include_tag 'login' script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-resource.js" type="text/javascript"
- if I18n.locale == :ru script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-cookies.js" type="text/javascript"
== javascript_include_tag 'moment/ru.js', cache: 'moment' script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-sanitize.js" type="text/javascript"
== javascript_include_tag 'angular-locale_ru-ru', cache: 'angular-locale' script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.2.5/ui-bootstrap-tpls.js" type="text/javascript"
== yield :additional_scripts if content_for?(:additional_scripts) script src="https://code.jquery.com/jquery-2.2.2.min.js" integrity="sha256-36cp2Co+/62rEAAYHLmRCPIych47CvdM+uTBJwSzWjI=" crossorigin="anonymous"
== javascript_include_tag 'new_application', cache: 'application'
== yield :additional_scripts if content_for?(:additional_scripts)
- if I18n.locale == :ru
== javascript_include_tag 'moment/ru.js', cache: 'moment'
== javascript_include_tag 'angular-locale_ru-ru', cache: 'angular-locale'

View File

@ -5,39 +5,33 @@
.container-fluid .container-fluid
/ Brand and toggle get grouped for better mobile display / Brand and toggle get grouped for better mobile display
.navbar-header .navbar-header
button.navbar-toggle data-target='#submenu-navbar-collapse' data-toggle='collapse' type='button'
span.sr-only Toggle navigation
span.icon-bar
span.icon-bar
span.icon-bar
.navbar-brand .navbar-brand
= link_to platform_printed_name(@platform), @platform = link_to platform_printed_name(@platform), @platform
/ Collect the nav links, forms, and other content for toggling / Collect the nav links, forms, and other content for toggling
#submenu-navbar-collapse.collapse.navbar-collapse ul.nav.navbar-nav.left-border
ul.nav.navbar-nav.left-border
li class=('active' if act == :show && contr == :platforms) li class=('active' if act == :show && contr == :platforms)
= link_to t("layout.platforms.about"), platform_path(@platform) = link_to t("layout.platforms.about"), platform_path(@platform)
li class=('active' if contr == :repositories) li class=('active' if contr == :repositories)
= link_to t("layout.repositories.list_header"), platform_repositories_path(@platform) = link_to t("layout.repositories.list_header"), platform_repositories_path(@platform)
li class=('active' if contr == :contents) li class=('active' if contr == :contents)
= link_to t('layout.platforms.contents'), platform_contents_path(@platform) = link_to t('layout.platforms.contents'), platform_contents_path(@platform)
- if policy(@platform).show? - if policy(@platform).show?
li class=('active' if act == :index && contr == :maintainers) li class=('active' if act == :index && contr == :maintainers)
= link_to t("layout.platforms.maintainers"), platform_maintainers_path(@platform) = link_to t("layout.platforms.maintainers"), platform_maintainers_path(@platform)
li class=('active' if contr == :mass_builds) li class=('active' if contr == :mass_builds)
= link_to t("layout.platforms.mass_build"), platform_mass_builds_path(@platform) = link_to t("layout.platforms.mass_build"), platform_mass_builds_path(@platform)
- if policy(@platform.products.build).show? - if policy(@platform.products.build).show?
li class=('active' if contr == :products) li class=('active' if contr == :products)
= link_to t("layout.products.list_header"), platform_products_path(@platform) = link_to t("layout.products.list_header"), platform_products_path(@platform)
- if policy(@platform).update? - if policy(@platform).update?
li class=('active' if act == :edit && contr == :platforms) li class=('active' if act == :edit && contr == :platforms)
= link_to t("platform_menu.settings"), edit_platform_path(@platform) = link_to t("platform_menu.settings"), edit_platform_path(@platform)
- if policy(@platform).local_admin_manage? - if policy(@platform).local_admin_manage?
li class=('active' if act == :members && contr == :platforms) li class=('active' if act == :members && contr == :platforms)
= link_to t("layout.platforms.members"), members_platform_path(@platform) = link_to t("layout.platforms.members"), members_platform_path(@platform)
- if policy(@platform).edit? - if policy(@platform).edit?
li class=('active' if contr == :key_pairs) li class=('active' if contr == :key_pairs)
= link_to t("layout.key_pairs.header"), platform_key_pairs_path(@platform) = link_to t("layout.key_pairs.header"), platform_key_pairs_path(@platform)
li class=('active' if contr == :tokens) li class=('active' if contr == :tokens)
= link_to t('layout.tokens.header'), platform_tokens_path(@platform) = link_to t('layout.tokens.header'), platform_tokens_path(@platform)

View File

@ -1,7 +1,7 @@
- set_meta_tags title: [title_object(@platform), t('layout.platforms.contents')] - set_meta_tags title: [title_object(@platform), t('layout.platforms.contents')]
= render 'platforms/base/submenu' = render 'platforms/base/submenu'
.col-xs-12.col-md-10.col-md-offset-1 .col-xs-12.col-md-12
h3 h3
= t('layout.platforms.contents_of') = t('layout.platforms.contents_of')
| &nbsp; | &nbsp;

View File

@ -1,7 +1,7 @@
- set_meta_tags title: [title_object(@platform), t('layout.maintainers.list_header')] - set_meta_tags title: [title_object(@platform), t('layout.maintainers.list_header')]
/ FIXME: no these 'base' links! / FIXME: no these 'base' links!
= render 'platforms/base/submenu' = render 'platforms/base/submenu'
.col-xs-12.col-md-10.col-md-offset-1 .col-xs-12.col-md-12
.row .row
/ = render partial: 'list', object: @maintainers / = render partial: 'list', object: @maintainers
/ = will_paginate @maintainers / = will_paginate @maintainers

View File

@ -1,6 +1,6 @@
= render 'platforms/base/submenu' = render 'platforms/base/submenu'
.col-xs-12.col-md-10.col-md-offset-1 .col-md-12
.row .row
- if policy(@platform.mass_builds.build).create? - if policy(@platform.mass_builds.build).create?
a.btn.btn-primary href=new_platform_mass_build_path(@platform) a.btn.btn-primary href=new_platform_mass_build_path(@platform)

View File

@ -2,12 +2,11 @@
= render 'platforms/base/submenu' = render 'platforms/base/submenu'
.col-xs-12.col-md-10.col-md-offset-1 .col-md-12
.row[ ng-controller = 'NewMassBuildController as newMassBuildCtrl' .row[ ng-controller = 'NewMassBuildController as newMassBuildCtrl'
ng-cloak = true ] ng-cloak = true ]
= simple_form_for @mass_build, url: platform_mass_builds_path(@platform) do |f| = simple_form_for @mass_build, url: platform_mass_builds_path(@platform) do |f|
.col-md-4.col-md-offset-2 .col-md-8
= f.input :description, as: :text, input_html: { class: 'resize-vertical' } = f.input :description, as: :text, input_html: { class: 'resize-vertical' }
b b

View File

@ -7,7 +7,7 @@
= render 'submenu' = render 'submenu'
.col-xs-12.col-md-10.col-md-offset-1 .col-md-12
.row .row
h3 h3
= t('activerecord.models.mass_build') = t('activerecord.models.mass_build')

View File

@ -1,7 +1,7 @@
- set_meta_tags title: [title_object(@platform), t('layout.platforms.edit')] - set_meta_tags title: [title_object(@platform), t('layout.platforms.edit')]
= render 'submenu' = render 'submenu'
.container.col-md-offset-2.col-md-8 .container.col-md-12
.row .row
= simple_form_for @platform, wrapper_mappings: { boolean: :vertical_boolean } do |f| = simple_form_for @platform, wrapper_mappings: { boolean: :vertical_boolean } do |f|
= render 'form', f: f = render 'form', f: f

View File

@ -1,23 +1,24 @@
- set_meta_tags title: t('layout.platforms.list_header') - set_meta_tags title: t('layout.platforms.list_header')
.row ng-controller='PlatformsCtrl' .row.top-space ng-controller='PlatformsController'
.col-md-6.col-md-offset-3 ng-cloak=true .col-md-6.col-md-offset-3
- if policy(:platform).create? rd-widget
a.btn.btn-primary href=new_platform_path rd-widget-header title=(t('layout.platforms.list_header'))
= t('layout.platforms.new') rd-widget-body class="no-padding"
table.table.table-hover.offset10 table.table.table-hover
thead thead
tr tr
th th= t 'activerecord.attributes.platform.name'
th= t 'activerecord.attributes.platform.name' th= t 'activerecord.attributes.platform.distrib_type'
th= t 'activerecord.attributes.platform.distrib_type' tbody
tbody tr ng-repeat='item in platforms'
tr ng-repeat='item in platforms' td
td a ng-href="{{item.link}}"
i.fa.fa-lg ng-class='item.visibility_class' | {{item.name}}
td td
a ng-href="{{item.link}}" | {{item.distrib_type}}
| {{item.name}} - if policy(:platform).create?
td rd-widget-footer
| {{item.distrib_type}} ul.nav.nav-justified
li
= angularjs_paginate per_page: Platform.per_page a href=new_platform_path
= t('layout.platforms.new')

View File

@ -4,10 +4,6 @@ json.platforms do
json.name platform_printed_name(item) json.name platform_printed_name(item)
json.link platform_path(item) json.link platform_path(item)
json.distrib_type item.distrib_type json.distrib_type item.distrib_type
json.visibility_class fa_platform_visibility_icon(item)
end end
end end
end end
json.page params[:page]
json.platforms_count @platforms_count

View File

@ -1,7 +1,7 @@
-set_meta_tags title: [title_object(@platform), t('layout.platforms.members')] -set_meta_tags title: [title_object(@platform), t('layout.platforms.members')]
= render 'submenu' = render 'submenu'
.container.col-md-offset-2.col-md-8 .container.col-md-12
.row .row
= render "shared/members_table", = render "shared/members_table",
remove_members_path: remove_members_platform_path(@platform), remove_members_path: remove_members_platform_path(@platform),

View File

@ -1,7 +1,7 @@
.container .container
.row .row
.col-md-offset-2.col-md-8 .col-md-12
= simple_form_for @platform, html: { class: 'form-horizontal' }, = simple_form_for @platform, html: { class: 'form-horizontal' },
wrapper: :horizontal_form, wrapper: :horizontal_form,
wrapper_mappings: { boolean: :horizontal_boolean } do |f| wrapper_mappings: { boolean: :horizontal_boolean } do |f|

View File

@ -7,7 +7,7 @@
= render 'submenu' = render 'submenu'
.col-xs-12.col-md-10.col-md-offset-1 .col-md-12
.row .row
.col-md-6 .col-md-6
h3 h3

View File

@ -2,7 +2,7 @@
= render 'submenu' = render 'submenu'
.container.col-md-offset-2.col-md-8 .container.col-md-12
.row .row
- pbl = @product_build_list - pbl = @product_build_list
= simple_form_for @product_build_list, url: platform_product_product_build_lists_path(@platform, @product) do |f| = simple_form_for @product_build_list, url: platform_product_product_build_lists_path(@platform, @product) do |f|

View File

@ -10,7 +10,7 @@
- product = pbl.product - product = pbl.product
- platform = product.platform - platform = product.platform
.container.col-md-offset-2.col-md-8 ng-controller='ProductBuildListController' .container.col-md-12 ng-controller='ProductBuildListController'
.row .row
h3 h3
= t('layout.product_build_lists.main_data') = t('layout.product_build_lists.main_data')

View File

@ -1,7 +1,7 @@
- set_meta_tags title: [title_object(@product), t('title_editing')] - set_meta_tags title: [title_object(@product), t('title_editing')]
= render 'submenu' = render 'submenu'
.container.col-md-offset-2.col-md-8 .container.col-md-12
.row .row
h3 h3
= t('layout.products.edit_header') = t('layout.products.edit_header')

View File

@ -2,7 +2,7 @@
= render 'submenu' if params[:platform_id] = render 'submenu' if params[:platform_id]
.container.col-md-offset-2.col-md-8 .container.col-md-12
.row .row
- if policy(@platform.products.build).create? - if policy(@platform.products.build).create?

View File

@ -2,7 +2,7 @@
= render 'submenu' = render 'submenu'
.container.col-md-offset-2.col-md-8 .container.col-md-12
.row .row
= simple_form_for [@platform, @product] do |f| = simple_form_for [@platform, @product] do |f|
= render 'form', f: f = render 'form', f: f

View File

@ -7,7 +7,7 @@
= render 'submenu' = render 'submenu'
.container.col-md-offset-2.col-md-8 .container.col-md-12
.row .row
h3 h3

View File

@ -8,7 +8,7 @@
= render 'submenu' if params[:platform_id] = render 'submenu' if params[:platform_id]
.container.col-md-offset-2.col-md-8 .container.col-md-12
- if policy(@platform.repositories.build).create? - if policy(@platform.repositories.build).create?
.row .row
a.btn.btn-primary href=new_platform_repository_path(@platform) a.btn.btn-primary href=new_platform_repository_path(@platform)

View File

@ -6,7 +6,7 @@
description: truncate(@repository.description, length: 200) } description: truncate(@repository.description, length: 200) }
= render 'submenu' = render 'submenu'
.container.col-md-offset-2.col-md-8 .container.col-md-12
.row .row
h3 h3
= t("layout.repositories.about") = t("layout.repositories.about")

View File

@ -1,57 +0,0 @@
- content_for :submenu do
- act = action_name.to_sym; contr = controller_name.to_sym;
- github_success = @project.github_data != nil
- github_base_url = @project.github_data.html_url unless not github_success
nav.navbar.navbar-default role='navigation'
.container-fluid ng-cloak = true
/ Brand and toggle get grouped for better mobile display
.navbar-header
button.navbar-toggle data-target='#submenu-navbar-collapse' data-toggle='collapse' type='button'
span.sr-only Toggle navigation
span.icon-bar
span.icon-bar
span.icon-bar
.navbar-brand
= fa_visibility_icon @project
= link_to @project.owner.uname, @project.owner
| /
= link_to @project.name, project_path(@project)
/ Collect the nav links, forms, and other content for toggling
#submenu-navbar-collapse.collapse.navbar-collapse
ul.nav.navbar-nav.left-border
- if github_success
li
a href=github_base_url target="_blank"
i.fa.fa-github>
= t('project_menu.github')
- if @project.is_package
li class=('active' if contr == :build_lists)
a href=project_build_lists_path(@project)
i.fa.fa-cogs>
= t('project_menu.builds')
- if github_success and @project.github_data.has_issues
li
a href=(github_base_url + "/issues") target="_blank"
i.fa.fa-exclamation-circle>
= t('project_menu.tracker', count: @project.github_data.open_issues_count)
- if github_success
li
a href=(github_base_url + "/pulls") target="_blank"
i.fa.fa-tasks>
= t('project_menu.pull_requests')
- if github_success and @project.github_data.has_wiki
li
a href=(github_base_url + "/wiki") target="_blank"
i.fa.fa-book>
= t('project_menu.wiki')
- if policy(@project).update?
li class=('active' if act.in?(%i[edit update sections]) && contr == :projects)
a href=edit_project_path(@project)
i.fa.fa-cog>
= t('project_menu.settings')
- if contr == :build_lists && act == :index
.clearfix
== render 'server_status'
/ /.navbar-collapse
/ /.container-fluid

View File

@ -1,30 +0,0 @@
json.build_lists @build_lists do |bl|
json.id bl.id
json.path build_list_path(bl)
json.human_status bl.human_status
json.version do
json.name build_list_version_name(bl)
json.path get_build_list_version_path(bl)
json.release get_version_release(bl)
end
if bl.build_for_platform && bl.save_to_platform.personal?
build_for = " (#{bl.build_for_platform.name})"
end
json.save_to_repository do
json.path platform_repository_path(bl.save_to_platform, bl.save_to_repository)
json.name "#{bl.save_to_platform.name}/#{bl.save_to_repository.name}#{build_for}"
end
json.arch bl.arch.try(:name) || t('layout.arches.unexisted_arch')
json.user do
json.path user_path(bl.user) if bl.user
json.fullname bl.user.try(:fullname)
end
json.updated_at bl.updated_at
end
json.total_items @total_build_lists

View File

@ -1,92 +1,60 @@
- html_options = { class: 'form-control' } script type="text/ng-template" id="build_list_filters.html"
.panel.panel-info .modal-header
.panel-heading.pointer ng-click = 'isOpenFilters = !isOpenFilters' | Bleh
span.fa.fa-filter.fa-lg .modal-body
=< t 'layout.build_lists.filters' .row
span.pull-right.fa ng-class = "{'fa-chevron-down': isOpenFilters, 'fa-chevron-up': !isOpenFilters}" - html_options = { class: 'form-control' }
.panel-body ng-show = 'isOpenFilters' = form_for :filter, html: { id: 'monitoring_filter' }, authenticity_token: false do |f|
= form_for :filter, html: { class: :form, id: 'monitoring_filter' }, authenticity_token: false do |f|
.row
.col-xl-12.col-md-4 .col-xl-12.col-md-4
h4= t 'layout.build_lists.ownership.header' h4= t 'layout.build_lists.ownership.header'
=f.hidden_field :ownership, value: '{{params.filter.ownership}}' if current_user
.btn-group.btn-group-justified .btn-group.btn-group-justified
- ['owned', (@project ? nil : 'related'), 'everything'].compact.each do |ownership| - ['owned', (@project ? nil : 'related'), 'everything'].compact.each do |ownership|
.btn-group .btn-group
button.btn.btn-default[ ng-model = 'params.filter.ownership' label.btn.btn-default [ ng-model = 'params.ownership'
btn-radio = "'#{ownership}'" uib-btn-radio = "'#{ownership}'" ]
type = 'button'
disabled = !current_user ]
= t "layout.build_lists.ownership.#{ownership}" = t "layout.build_lists.ownership.#{ownership}"
h4= t 'number_rows' h4= t 'number_rows'
=hidden_field_tag :per_page, '{{params.per_page}}'
=hidden_field_tag :page, '{{params.page}}'
.btn-group.btn-group-justified .btn-group.btn-group-justified
-BuildList::Filter::PER_PAGE.each do |num| -BuildList::Filter::PER_PAGE.each do |num|
.btn-group .btn-group
button.btn.btn-default[ ng-model = 'params.per_page' btn-radio = "'#{num}'" type = 'button' ]= num label.btn.btn-default[ ng-model = 'params.per_page' uib-btn-radio = "'#{num}'" ]= num
h4= t 'activerecord.attributes.build_list.status' h4= t 'activerecord.attributes.build_list.status'
= f.select :status, BuildList::STATUSES.collect{ |status| [BuildList.human_status(status), status] }, = f.select :status, BuildList::STATUSES.collect{ |status| [BuildList.human_status(status), status] },
{ include_blank: true }, { include_blank: true },
html_options.merge(id: 'status', 'ng-model' => 'params.filter.status') html_options.merge(id: 'status', 'ng-model' => 'params.status')
.col-xl-12.col-md-4 .col-xl-12.col-md-4
h4= t 'activerecord.models.platform' h4= t 'activerecord.models.platform'
= f.select :save_to_platform_id, filter_by_save_to_platform, = f.select :save_to_platform_id, filter_by_save_to_platform,
{ include_blank: true }, { include_blank: true },
html_options.merge(id: 'platform', 'ng-model' => 'params.filter.save_to_platform_id') html_options.merge(id: 'platform', 'ng-model' => 'params.save_to_platform_id')
h4= t 'activerecord.attributes.build_list.arch' h4= t 'activerecord.attributes.build_list.arch'
= f.select :arch_id, Arch.recent.collect{ |arch| [arch.name, arch.id] }, { include_blank: true }, = 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') html_options.merge(id: 'architecture', 'ng-model' => 'params.arch_id')
h4= t 'activerecord.models.mass_build' h4= t 'activerecord.models.mass_build'
= f.select :mass_build_id, mass_build_options, { include_blank: true }, = f.select :mass_build_id, mass_build_options, { include_blank: true },
html_options.merge(id: 'mass_build', 'ng-model' => 'params.filter.mass_build_id') html_options.merge(id: 'mass_build', 'ng-model' => 'params.mass_build_id')
.col-xl-12.col-md-4 .col-xl-12.col-md-4
.row ng-controller = 'DatePickerController as datePickerCtrl' .row ng-controller = 'DatePickerController as datePickerCtrl'
-[:updated_at_start, :updated_at_end].each do |attr| -[:updated_at_start, :updated_at_end].each do |attr|
.col-xl-12.col-md-6 h4= t attr == :updated_at_start ? '_on' : 'until'
h4= t attr == :updated_at_start ? '_on' : 'until' = f.text_field attr, size: 10, class: 'form-control',
= f.text_field attr, size: 10, class: 'form-control', 'uib-datepicker-popup' => '{{datePickerCtrl.format}}',
'datepicker-popup' => '{{datePickerCtrl.format}}', 'ng-model' => "$scope.$parent.params.#{attr}",
'ng-model' => "$scope.$parent.params.filter.#{attr}", 'is-open' => "datePickerCtrl.#{attr}_opened",
'is-open' => "datePickerCtrl.#{attr}_opened", min: 'datePickerCtrl.minDate',
min: 'datePickerCtrl.minDate', max: 'datePickerCtrl.maxDate',
max: 'datePickerCtrl.maxDate', 'datepicker-options' => 'datePickerCtrl.dateOptions',
'datepicker-options' => 'datePickerCtrl.dateOptions', 'date-disabled' => "datePickerCtrl.disabled(date, mode)",
'date-disabled' => "datePickerCtrl.disabled(date, mode)", 'ng-click' => "datePickerCtrl.open_#{attr}($event)"
'ng-click' => "datePickerCtrl.open_#{attr}($event)"
h4.medium= t 'layout.build_lists.project_name_search'
input#filter_project_name.form-control[ name = 'filter[project_name]'
size = '30'
type = 'text'
value = '{{params.filter.filter_project_name}}'
disabled = @project.present? ]
h4= t 'layout.build_lists.id_search' .modal-footer
input#filter_id.form-control[ name = 'filter{id}' button.btn.btn-primary type = 'button' ng-click = 'apply()'
size = '30' i.fa.fa-search
type = 'text' = t('layout.search.header')
value = '{{params.filter.id}}' button.btn.btn-primary[ type = 'button' ng-click = 'reset()' ]= t('reset')
disabled = @project.present? ]
.clearfix
.col-xl-12.col-md-4.offset10
= label_tag :autoreload do
= check_box_tag :autoreload, true, true
= t 'layout.autoreload_page'
.col-xl-12.col-xl-offset-0.col-md-4.col-md-offset-4.offset10
.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-primary type = 'button' ng-click = 'refresh(true)'
i.fa.fa-search
= t('layout.search.header')
.btn-group
button.btn.btn-primary[ type = 'button' ng-click = 'clear()' ]= t('reset')

View File

@ -1,26 +1,23 @@
.row rd-widget ng-show='build_list.item_groups'
h3 rd-widget-header title=t('layout.build_lists.items_header')
= t('layout.build_lists.items_header') rd-widget-body
h4 ng-hide='build_list.item_groups' div ng-repeat='group in build_list.item_groups'
= t("layout.build_lists.no_items_data") .row ng-repeat='item in group'
h4
| {{item.name + ' #' + item.level}}
div ng-repeat='group in build_list.item_groups' table.table
.row ng-repeat='item in group' thead
h4 tr
| {{item.name + ' #' + item.level}} th= t('activerecord.attributes.build_list/item.name')
th= t('activerecord.attributes.build_list/item.version')
table.table th= t('activerecord.attributes.build_list/item.status')
thead tbody
tr tr class="{{build_list.itemStatusColor(item.status)}}"
th= t('activerecord.attributes.build_list/item.name') td
th= t('activerecord.attributes.build_list/item.version') | {{item.name}}
th= t('activerecord.attributes.build_list/item.status') td
tbody a ng-href='{{item.path.href}}'
tr class="{{build_list.itemStatusColor(item.status)}}" | {{item.path.text}}
td td
| {{item.name}} | {{build_list.humanStatus(item.status) | i18n}}
td
a ng-href='{{item.path.href}}'
| {{item.path.text}}
td
| {{build_list.humanStatus(item.status) | i18n}}

View File

@ -1,51 +1,50 @@
.row ng-show='build_list.packages' rd-widget ng-show='build_list.packages'
hr rd-widget-header title=t('layout.build_lists.packages_header')
h3 rd-widget-body class="no-padding"
= t('layout.build_lists.packages_header') table.table.table-hover
table.table.table-hover thead
thead tr
tr th
th th= t('activerecord.attributes.build_list/package.fullname')
th= t('activerecord.attributes.build_list/package.fullname') th= t('activerecord.attributes.build_list/package.name')
th= t('activerecord.attributes.build_list/package.name') th= t('activerecord.attributes.build_list/package.epoch')
th= t('activerecord.attributes.build_list/package.epoch') th= t('activerecord.attributes.build_list/package.version')
th= t('activerecord.attributes.build_list/package.version') th= t('activerecord.attributes.build_list/package.release')
th= t('activerecord.attributes.build_list/package.release') tbody
tbody tr ng-repeat-start='package in build_list.packages'
tr ng-repeat-start='package in build_list.packages' td
td a.expand ng-show='package.dependent_projects'
a.expand ng-show='package.dependent_projects' span.fa.fa-chevron-up[
span.fa.fa-chevron-up[ ng-show = 'package.show_dependent_projects'
ng-show = 'package.show_dependent_projects' ng-click = 'package.show_dependent_projects = false' ]
ng-click = 'package.show_dependent_projects = false' ] span.fa.fa-chevron-down[
span.fa.fa-chevron-down[ ng-hide = 'package.show_dependent_projects'
ng-hide = 'package.show_dependent_projects' ng-click = 'package.show_dependent_projects = true' ]
ng-click = 'package.show_dependent_projects = true' ] td
td div ng-if='!package.url'
div ng-if='!package.url' | {{package.fullname}}
| {{package.fullname}} a ng-if='package.url' ng-href="{{package.url}}"
a ng-if='package.url' ng-href="{{package.url}}" | {{package.fullname}}
| {{package.fullname}} td
td | {{package.name}}
| {{package.name}} td
td | {{package.epoch}}
| {{package.epoch}} td
td | {{package.version}}
| {{package.version}} td
td | {{package.release}}
| {{package.release}}
tr[ tr[
ng-repeat-end = '' ng-repeat-end = ''
ng-show = 'package.show_dependent_projects' ng-show = 'package.show_dependent_projects'
ng-repeat = 'project in package.dependent_projects' ] ng-repeat = 'project in package.dependent_projects' ]
td td
td td
a ng-href="{{project.url}}" a ng-href="{{project.url}}"
| {{project.name}} | {{project.name}}
td td
p ng-repeat='package in project.dependent_packages' p ng-repeat='package in project.dependent_packages'
| {{package}} | {{package}}
td colspan=3 td colspan=3
a ng-href='{{project.new_url}}' a ng-href='{{project.new_url}}'
= t('layout.build_lists.create_build_list') = t('layout.build_lists.create_build_list')

View File

@ -1,5 +0,0 @@
%tr{id: "row#{platform_build_list_counter}"}
%td= link_to platform_build_list.id, platform_build_list
%td= platform_build_list.human_status
%td= link_to platform_build_list.project.name, platform_build_list.project
%td= platform_build_list.updated_at

View File

@ -1,5 +0,0 @@
= form_for [build_list.project, build_list.project.build_lists.new], html: { class: :form, method: :post } do |f|
= hidden_field_tag :build_list_id, build_list.id
= f.hidden_field :project_id
= f.submit t('layout.build_lists.recreate_build_list'), data: {'disable-with' => t('layout.processing')}
.both

Some files were not shown because too many files have changed in this diff Show More