remove PortalJobs widget and replace with a view/controller pattern resolves #939 & #940

This commit is contained in:
Leigh Johnson 2016-03-31 18:11:07 -04:00
parent 7ed44ec167
commit 235cc6bbd5
19 changed files with 163 additions and 435 deletions

View File

@ -40,7 +40,6 @@
@import "dashboard.less";
@import "jPushMenu.less";
@import "survey-maker.less";
@import "portal.less";
@import "text-label.less";
@import "./bootstrap-datepicker.less";
@import "awx/ui/client/src/shared/branding/colors.default.less";

View File

@ -1,49 +0,0 @@
/*********************************************
* Copyright (c) 2015 Ansible, Inc.
*
* portal.css
*
* custom styles for poral mode
*
*/
.portal-container{
border: 1px solid @grey;
border-radius: 4px;
padding: 5px;
}
.portal-header{
margin: 5px;
margin-left: 10px;
font-size: 14px;
font-weight: bold;
}
#portal-jobs{
margin-top: 20px;
}
@media (min-width: 769px) {
.left-side {
padding-right: 7px;
}
.right-side {
padding-left: px;
}
}
#job_templates_table,
#portal_jobs_table {
table-layout:fixed;
}
#portal_jobs_table .name-column,
#job_templates_table .name-column {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

View File

@ -165,7 +165,6 @@ var tower = angular.module('Tower', [
'md5Helper',
'SelectionHelper',
'HostGroupsFormDefinition',
'PortalJobsWidget',
'StreamWidget',
'JobsHelper',
'InventoryGroupsHelpDefinition',

View File

@ -75,13 +75,7 @@ export default
scope.viewJobDetails = function(job) {
var goToJobDetails = function(state) {
if(scope.$parent.portalMode===true){
var url = $state.href(state, {id: job.id});
$window.open(url, '_blank');
}
else {
$state.go(state, {id: job.id});
}
$state.go(state, {id: job.id});
}
switch(job.type) {

View File

@ -45,7 +45,6 @@ export default
ngClick: 'addJobTemplate()',
basePaths: ['job_templates'],
awToolTip: 'Create a new template',
ngHide: 'portalMode===true',
actionClass: 'btn List-buttonSubmit',
buttonContent: '+ ADD'
}

View File

@ -9,10 +9,9 @@ export default
angular.module('PortalJobsListDefinition', [])
.value( 'PortalJobsList', {
name: 'portal_jobs',
iterator: 'portal_job',
name: 'jobs',
iterator: 'job',
editTitle: 'Jobs',
'class': 'table-condensed',
index: false,
hover: true,
well: true,
@ -22,8 +21,8 @@ export default
status: {
label: '',
columnClass: 'List-staticColumn--smallStatus',
dataTitle: "{{ portal_job.status_popover_title }}",
icon: 'icon-job-{{ portal_job.status }}',
dataTitle: "{{ job.status_popover_title }}",
icon: 'icon-job-{{ job.status }}',
iconOnly: true,
searchable: true,
nosort: true,
@ -46,10 +45,11 @@ export default
},
*/
name: {
key: true,
label: 'Name',
columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-6',
defaultSearchField: true,
linkTo: '/#/jobs/{{portal_job.id}}'
linkTo: '/#/jobs/{{job.id}}'
},
started: {
label: 'Started',
@ -57,7 +57,7 @@ export default
searchable: false,
filter: "longDate",
nosort: true,
columnClass: "col-lg-4 col-md-4 col-sm-3 hidden-xs"
columnClass: "col-lg-4 col-md-4 col-sm-3"
}
},

View File

@ -35,7 +35,6 @@ export default
ngClick: 'addScanJobTemplate()',
basePaths: ['job_templates'],
awToolTip: 'Create a new template',
ngHide: 'portalMode===true',
actionClass: 'btn List-buttonSubmit',
buttonContent: '+ ADD'
}

View File

@ -5,11 +5,9 @@
*************************************************/
import route from './portal-mode.route';
import {PortalModeController} from './portal-mode.controller';
export default
export default
angular.module('portalMode', [])
.controller('PortalModeController', PortalModeController)
.run(['$stateExtender', function($stateExtender){
$stateExtender.addState(route);
}]);

View File

@ -0,0 +1,47 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export function PortalModeJobTemplatesController($scope, $rootScope, GetBasePath, GenerateList, PortalJobTemplateList, SearchInit, PaginateInit, PlaybookRun){
var jobs_scope,
list = PortalJobTemplateList,
view= GenerateList,
defaultUrl = GetBasePath('job_templates'),
pageSize = 12;
$scope.submitJob = function (id) {
PlaybookRun({ scope: $scope, id: id });
};
var init = function(){
view.inject( list, {
id : 'portal-job-templates',
mode: 'edit',
scope: $scope,
searchSize: 'col-md-10 col-xs-12'
});
SearchInit({
scope: $scope,
set: 'job_templates',
list: list,
url: defaultUrl
});
PaginateInit({
scope: $scope,
list: list,
url: defaultUrl,
pageSize: pageSize
});
$scope.search(list.iterator);
};
init()
}
PortalModeJobTemplatesController.$inject = ['$scope', '$rootScope', 'GetBasePath', 'generateList', 'PortalJobTemplateList', 'SearchInit', 'PaginateInit', 'PlaybookRun'
];

View File

@ -0,0 +1,4 @@
<div id="portal-container-job-templates" class="Panel">
<div id="portal-job-templates" >
</div>
</div>

View File

@ -0,0 +1,59 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export function PortalModeJobsController($scope, $rootScope, GetBasePath, GenerateList, PortalJobsList, SearchInit,
PaginateInit){
var list = PortalJobsList,
view = GenerateList,
// show user jobs by default
defaultUrl = GetBasePath('jobs') + '?created_by=' + $rootScope.current_user.id,
pageSize = 12;
$scope.iterator = list.iterator;
$scope.activeFilter = 'user';
var init = function(){
view.inject(list, {
id: 'portal-jobs',
mode: 'edit',
scope: $scope,
searchSize: 'col-md-10 col-xs-12'
});
SearchInit({
scope: $scope,
set: 'jobs',
list: list,
url: defaultUrl
});
PaginateInit({
scope: $scope,
list: list,
url: defaultUrl,
pageSize: pageSize
});
$scope.search (list.iterator);
};
$scope.filterUser = function(){
$scope.activeFilter = 'user';
defaultUrl = GetBasePath('jobs') + '?created_by=' + $rootScope.current_user.id;
init();
};
$scope.filterAll = function(){
$scope.activeFilter = 'all';
defaultUrl = GetBasePath('jobs');
init();
};
init();
}
PortalModeJobsController.$inject = ['$scope', '$rootScope', 'GetBasePath', 'generateList', 'PortalJobsList', 'SearchInit',
'PaginateInit']

View File

@ -0,0 +1,11 @@
<div id="portal-container-jobs" class="Panel">
<div class="btn-group PortalMode-filter">
<button ng-class="{'btn-primary ': activeFilter == 'user',
'btn-default' : activeFilter != 'user' }"
ng-click='filterUser()' class="btn btn-xs">My Jobs</button>
<button ng-class="{'btn-primary' : activeFilter == 'all',
'btn-default' : activeFilter != 'all'}" ng-click='filterAll()' class="btn btn-xs btn-default">All Jobs</button>
</div>
<div id="portal-jobs" >
</div>
</div>

View File

@ -15,17 +15,9 @@
</div>
</div>
<div class="PortalMode-container">
<div class="PortalMode-panel--left">
<div id="portal-container-job-templates" class="Panel">
<div id="portal-job-templates" >
</div>
</div>
<div ui-view="job-templates" class="PortalMode-panel--left">
</div>
<div class="PortalMode-panel--right">
<div id="portal-container-jobs" class="Panel">
<div id="portal-jobs" >
</div>
</div>
<div ui-view="jobs" class="PortalMode-panel--right">
</div>
</div>
</div>

View File

@ -9,11 +9,15 @@
}
.PortalMode-panel--right{
.OnePlusOne-panel--right;
.List-tableHeader:last-of-type{
text-align:left;
}
}
.PortalMode-panelHeader{
.OnePlusOne-panelHeader;
}
@media(max-width: 767px){
table {word-wrap: normal !important};
.PortalMode-filter{
position: absolute;
top: 35px;
right: 35px;
}

View File

@ -1,144 +0,0 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
/**
* @ngdoc function
* @name controllers.function:Portal
* @description This controller's for portal mode
*/
/**
* @ngdoc method
* @name controllers.function:Portal#Portal
* @methodOf controllers.function:Portal
* @description portal mode woohoo
*
*
*/
export function PortalModeController($scope, $compile, $stateParams, $rootScope, $location, $log, Wait, ClearScope, Rest, GetBasePath, ProcessErrors,
PortalJobsWidget, GenerateList, PortalJobTemplateList, SearchInit, PaginateInit, PlaybookRun){
ClearScope('portal');
var jobs_scope,
pageSize = 12,
list = PortalJobTemplateList,
view= GenerateList,
defaultUrl = GetBasePath('job_templates'),
max_rows;
if ($scope.removeLoadPortal) {
$scope.removeLoadPortal();
}
$scope.removeLoadPortal = $scope.$on('LoadPortal', function () {
view.inject( list, {
id : 'portal-job-templates',
mode: 'edit',
scope: $scope,
searchSize: 'col-lg-6 col-md-6'
});
$scope.job_templatePageSize = $scope.getMaxRows();
console.log($scope.job_templatePageSize);
SearchInit({
scope: $scope,
set: 'job_templates',
list: list,
url: defaultUrl
});
PaginateInit({
scope: $scope,
list: list,
url: defaultUrl,
pageSize: pageSize
});
$scope.search(list.iterator);
PortalJobsWidget({
scope: $scope,
target: 'portal-jobs',
searchSize: 'col-lg-6 col-md-6'
});
});
if ($scope.removeWidgetLoaded) {
$scope.removeWidgetLoaded();
}
$scope.removeWidgetLoaded = $scope.$on('WidgetLoaded', function (e, label, jobscope) {
if(label==="portal_jobs"){
jobs_scope = jobscope;
}
$('.actions-column:eq(0)').text('Launch');
$('.actions-column:eq(1)').text('Details');
$('.list-well:eq(1)').css('margin-top' , '0px');
});
if ($rootScope.removeJobStatusChange) {
$rootScope.removeJobStatusChange();
}
$rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange-portal', function() {
jobs_scope.search('portal_job'); //processEvent(event);
});
$scope.getMaxRows = function(){
var docw = $(window).width(),
box_height, available_height, search_row, page_row, height, header, row_height;
available_height = Math.floor($(window).height() - $('#main-menu-container .navbar').outerHeight() - $('#refresh-row').outerHeight() - 35);
$('.portal-job-template-container').height(available_height);
$('.portal-container').height(available_height);
search_row = Math.max($('.search-row:eq(0)').outerHeight(), 50);
page_row = Math.max($('.page-row:eq(0)').outerHeight(), 33);
header = 0; //Math.max($('#completed_jobs_table thead').height(), 41);
height = Math.floor(available_height) - header - page_row - search_row ;
if (docw < 765 && docw >= 493) {
row_height = 27;
}
else if (docw < 493) {
row_height = 47;
}
else if (docw < 865) {
row_height = 87;
}
else if (docw < 925) {
row_height = 67;
}
else if (docw < 1415) {
row_height = 47;
}
else {
row_height = 44;
}
max_rows = Math.floor(height / row_height);
if (max_rows < 5){
box_height = header+page_row + search_row + 40 + (5 * row_height);
if (docw < 1140) {
box_height += 40;
}
// $('.portal-job-template-container').height(box_height);
max_rows = 5;
}
return max_rows;
};
$scope.submitJob = function (id) {
PlaybookRun({ scope: $scope, id: id });
};
$scope.refresh = function () {
$scope.$emit('LoadPortal');
};
$scope.refresh();
}
PortalModeController.$inject = ['$scope', '$compile', '$stateParams', '$rootScope', '$location', '$log','Wait', 'ClearScope', 'Rest', 'GetBasePath', 'ProcessErrors',
'PortalJobsWidget', 'generateList' , 'PortalJobTemplateList', 'SearchInit', 'PaginateInit', 'PlaybookRun'
];

View File

@ -1,16 +1,31 @@
import {templateUrl} from '../shared/template-url/template-url.factory';
import {PortalModeJobTemplatesController} from './portal-mode-job-templates.controller';
import {PortalModeJobsController} from './portal-mode-jobs.controller';
// Using multiple named views requires a parent layout
// https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
export default {
abstract: true,
name: 'portalMode',
url: '/portal',
templateUrl: templateUrl('portal-mode/portal-mode'),
controller: 'PortalModeController',
ncyBreadcrumb: {
label: "PORTAL MODE"
},
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
}]
},
views: {
// the empty parent ui-view
"" : {
templateUrl: templateUrl('portal-mode/portal-mode-layout'),
},
// named ui-views inside the above
'job-templates@portalMode': {
templateUrl: templateUrl('portal-mode/portal-mode-job-templates'),
controller: PortalModeJobTemplatesController
},
'jobs@portalMode': {
templateUrl: templateUrl('portal-mode/portal-mode-jobs'),
controller: PortalModeJobsController
}
}
}
};

View File

@ -13,7 +13,8 @@ export default function($stateProvider){
data: state.data,
ncyBreadcrumb: state.ncyBreadcrumb,
onEnter: state.onEnter,
onExit: state.onExit
onExit: state.onExit,
views: state.views
});
}
};

View File

@ -7,6 +7,5 @@
import "./widgets/InventorySyncStatus";
import "./widgets/JobStatus";
import "./widgets/ObjectCount";
import "./widgets/PortalJobs";
import "./widgets/SCMSyncStatus";
import "./widgets/Stream";
import "./widgets/Stream";

View File

@ -1,199 +0,0 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
/**
* @ngdoc function
* @name widgets.function:PortalJobs
* @description
*
*/
angular.module('PortalJobsWidget', ['RestServices', 'Utilities'])
.factory('PortalJobsWidget', ['$rootScope', '$compile', 'LoadSchedulesScope', 'LoadJobsScope', 'PortalJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'PortalJobTemplateList' ,
function ($rootScope, $compile, LoadSchedulesScope, LoadJobsScope, PortalJobsList, ScheduledJobsList, GetChoices, GetBasePath, PortalJobTemplateList ) {
return function (params) {
var scope = params.scope,
target = params.target,
filter = params.filter || "User" ,
choicesCount = 0,
listCount = 0,
jobs_scope = scope.$new(true),
pageSize = 12,
max_rows,
user,
html, e,
url;
if (scope.removeListLoaded) {
scope.removeListLoaded();
}
scope.removeListLoaded = scope.$on('listLoaded', function() {
listCount++;
if (listCount === 1) {
//api_complete = true;
scope.$emit('WidgetLoaded', "portal_jobs", jobs_scope);
}
});
// After all choices are ready, load up the lists and populate the page
if (scope.removeBuildJobsList) {
scope.removeBuildJobsList();
}
scope.removeBuildJobsList = scope.$on('buildJobsList', function() {
if (PortalJobsList.fields.type) {
PortalJobsList.fields.type.searchOptions = scope.type_choices;
}
user = scope.$parent.current_user.id;
url = (filter === "All Jobs" ) ? GetBasePath('jobs') : GetBasePath('jobs')+'?created_by='+user ;
LoadJobsScope({
parent_scope: scope,
scope: jobs_scope,
list: PortalJobsList,
id: 'active-jobs',
url: url , //GetBasePath('jobs')+'?created_by='+user,
pageSize: pageSize,
spinner: true
});
$(window).resize(_.debounce(function() {
resizePortalJobsWidget();
}, 500));
});
if (scope.removeChoicesReady) {
scope.removeChoicesReady();
}
scope.removeChoicesReady = scope.$on('choicesReady', function() {
choicesCount++;
if (choicesCount === 2) {
//setPortalJobsHeight();
scope.$emit('buildJobsList');
}
});
scope.filterPortalJobs = function(filter) {
$("#active-jobs").empty();
$("#active-jobs-search-container").empty();
user = scope.$parent.current_user.id;
url = (filter === "All Jobs" ) ? GetBasePath('jobs') : GetBasePath('jobs')+'?created_by='+user ;
LoadJobsScope({
parent_scope: scope,
scope: jobs_scope,
list: PortalJobsList,
id: 'active-jobs',
url: url , //GetBasePath('jobs')+'?created_by='+user,
pageSize: max_rows,
spinner: true
});
};
html = '';
html += "<div class=\"portal-job-template-container\">\n";
html += "<div class=\"tab-pane active\" id=\"active-jobs-tab\">\n";
html += "<div class=\"row search-row\" id='portal-job-template-search'>\n";
html += "<div class=\"col-md-6 col-xs-12\" id=\"active-jobs-search-container\"></div>\n";
html += "<div class=\"form-group col-md-6 col-xs-12\">" ;
html += "<div class=\"btn-group\" aw-toggle-button data-after-toggle=\"filterPortalJobs\">" ;
html += "<button id='portal-toggle-user' class=\"btn btn-xs btn-primary active\">My Jobs</button>" ;
html += "<button id='portal-toggle-all' class=\"btn btn-xs btn-default\">All Jobs</button>" ;
html += "</div>" ;
html += "</div>" ;
html += "</div>\n"; //row
html += "<div class=\"job-list\" id=\"active-jobs-container\">\n";
html += "<div id=\"active-jobs\" class=\"job-list-target\"></div>\n";
html += "</div>\n"; //list
html += "</div>\n"; //active-jobs-tab
html += "</div>\n";
e = angular.element(document.getElementById(target));
e.html(html);
$compile(e)(scope);
GetChoices({
scope: scope,
url: GetBasePath('unified_jobs'),
field: 'status',
variable: 'status_choices',
callback: 'choicesReady'
});
GetChoices({
scope: scope,
url: GetBasePath('unified_jobs'),
field: 'type',
variable: 'type_choices',
callback: 'choicesReady'
});
// Set the height of each container and calc max number of rows containers can hold
/*
function setPortalJobsHeight() {
var docw = $(window).width(),
box_height, available_height, search_row, page_row, height, header, row_height;
available_height = Math.floor($(window).height() - $('#main-menu-container .navbar').outerHeight() - $('#refresh-row').outerHeight() - 35);
$('.portal-job-template-container').height(available_height);
$('.portal-container').height(available_height);
search_row = Math.max($('.search-row:eq(0)').outerHeight(), 50);
page_row = Math.max($('.page-row:eq(0)').outerHeight(), 33);
header = 100; //Math.max($('#completed_jobs_table thead').height(), 41);
height = Math.floor(available_height) - header - page_row - search_row ;
if (docw < 765 && docw >= 493) {
row_height = 27;
}
else if (docw < 493) {
row_height = 47;
}
else if (docw < 768) {
row_height = 44;
}
else if (docw < 865) {
row_height = 87;
}
else if (docw < 925) {
row_height = 67;
}
else if (docw < 992) {
row_height = 55;
}
else if (docw < 1415) {
row_height = 47;
}
else {
row_height = 44;
}
max_rows = Math.floor(height / row_height);
if (max_rows < 5){
box_height = header+page_row + search_row + 40 + (5 * row_height);
if (docw < 1140) {
box_height += 40;
}
$('.portal-job-template-container').height(box_height);
max_rows = 5;
}
}
// Set container height and return the number of allowed rows
function resizePortalJobsWidget() {
setPortalJobsHeight();
jobs_scope[PortalJobsList.iterator + '_page_size'] = max_rows;
jobs_scope.changePageSize(PortalJobsList.name, PortalJobsList.iterator, false);
scope[PortalJobTemplateList.iterator + '_page_size'] = max_rows;
scope[PortalJobTemplateList.iterator + 'PageSize'] = max_rows;
scope.changePageSize(PortalJobTemplateList.name, PortalJobTemplateList.iterator, false);
}
*/
};
}
]);