Split portal mode jobs into two separate states

This commit is contained in:
Michael Abashian
2017-07-21 11:09:55 -04:00
parent 825dfc9df9
commit fc0a76cd25
18 changed files with 132 additions and 74 deletions

View File

@@ -7,7 +7,6 @@
export default ['i18n', function(i18n) { export default ['i18n', function(i18n) {
return { return {
searchSize: 'col-lg-12 col-md-12 col-sm-12 col-xs-12',
name: 'teams', name: 'teams',
iterator: 'team', iterator: 'team',
listTitleBadge: false, listTitleBadge: false,

View File

@@ -9,7 +9,6 @@ export default ['i18n', function(i18n) {
name: 'hosts', name: 'hosts',
iterator: 'host', iterator: 'host',
editTitle: '{{ selected_group }}', editTitle: '{{ selected_group }}',
searchSize: 'col-lg-12 col-md-12 col-sm-12 col-xs-12',
singleSearchParam: { singleSearchParam: {
param: 'host_filter' param: 'host_filter'
}, },

View File

@@ -154,7 +154,7 @@
</a> </a>
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--right" <a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--right"
id="main_menu_portal_link" id="main_menu_portal_link"
ng-href="/#/portal" ng-href="/#/portal/myjobs"
ng-hide="licenseMissing" ng-hide="licenseMissing"
ng-class="{'is-currentRoute' : isCurrentState('portalMode'), 'is-loggedOut' : !current_user || !current_user.username}" ng-class="{'is-currentRoute' : isCurrentState('portalMode'), 'is-loggedOut' : !current_user || !current_user.username}"
aw-tool-tip="{{'My View'|translate}}" aw-tool-tip="{{'My View'|translate}}"

View File

@@ -67,7 +67,6 @@ export default [{
ngClick: 'addUsers()' ngClick: 'addUsers()'
} }
}; };
list.searchSize = "col-lg-12 col-md-12 col-sm-12 col-xs-12";
return list; return list;
}] }]
} }
@@ -107,7 +106,6 @@ export default [{
delete list.fieldActions.delete; delete list.fieldActions.delete;
list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/teams`; list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/teams`;
list.emptyListText = "This list is populated by teams added from the&nbsp;<a ui-sref='teams.add'>Teams</a>&nbsp;section"; list.emptyListText = "This list is populated by teams added from the&nbsp;<a ui-sref='teams.add'>Teams</a>&nbsp;section";
list.searchSize = "col-lg-12 col-md-12 col-sm-12 col-xs-12";
return list; return list;
}], }],
OrgTeamsDataset: ['OrgTeamList', 'QuerySet', '$stateParams', 'GetBasePath', OrgTeamsDataset: ['OrgTeamList', 'QuerySet', '$stateParams', 'GetBasePath',
@@ -153,7 +151,6 @@ export default [{
delete list.fieldActions.delete; delete list.fieldActions.delete;
list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/inventories`; list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/inventories`;
list.emptyListText = "This list is populated by inventories added from the&nbsp;<a ui-sref='inventories.add'>Inventories</a>&nbsp;section"; list.emptyListText = "This list is populated by inventories added from the&nbsp;<a ui-sref='inventories.add'>Inventories</a>&nbsp;section";
list.searchSize = "col-lg-12 col-md-12 col-sm-12 col-xs-12";
return list; return list;
}], }],
OrgInventoryDataset: ['OrgInventoryList', 'QuerySet', '$stateParams', 'GetBasePath', OrgInventoryDataset: ['OrgInventoryList', 'QuerySet', '$stateParams', 'GetBasePath',
@@ -204,7 +201,6 @@ export default [{
delete list.fieldActions.delete; delete list.fieldActions.delete;
list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/projects`; list.basePath = `${GetBasePath('organizations')}${$stateParams.organization_id}/projects`;
list.emptyListText = "This list is populated by projects added from the&nbsp;<a ui-sref='projects.add'>Projects</a>&nbsp;section"; list.emptyListText = "This list is populated by projects added from the&nbsp;<a ui-sref='projects.add'>Projects</a>&nbsp;section";
list.searchSize = "col-lg-12 col-md-12 col-sm-12 col-xs-12";
return list; return list;
}], }],
OrgProjectDataset: ['OrgProjectList', 'QuerySet', '$stateParams', 'GetBasePath', OrgProjectDataset: ['OrgProjectList', 'QuerySet', '$stateParams', 'GetBasePath',
@@ -265,7 +261,6 @@ export default [{
delete list.fields.type; delete list.fields.type;
list.listTitle = N_('Job Templates'); list.listTitle = N_('Job Templates');
list.emptyListText = "This list is populated by job templates added from the&nbsp;<a ui-sref='templates.addJobTemplate'>Job Templates</a>&nbsp;section"; list.emptyListText = "This list is populated by job templates added from the&nbsp;<a ui-sref='templates.addJobTemplate'>Job Templates</a>&nbsp;section";
list.searchSize = "col-lg-12 col-md-12 col-sm-12 col-xs-12";
list.iterator = 'template'; list.iterator = 'template';
list.name = 'job_templates'; list.name = 'job_templates';
list.basePath = "job_templates"; list.basePath = "job_templates";
@@ -349,7 +344,6 @@ export default [{
ngClick: 'addUsers()' ngClick: 'addUsers()'
} }
}; };
list.searchSize = "col-lg-12 col-md-12 col-sm-12 col-xs-12";
list.listTitle = 'Admins'; list.listTitle = 'Admins';
return list; return list;
}] }]

View File

@@ -27,7 +27,6 @@
</div> </div>
<!-- smart-search directive bindings: <!-- smart-search directive bindings:
djangoModel: '@', // one-way, interpolated djangoModel: '@', // one-way, interpolated
searchSize: '@',
basePath: '@', basePath: '@',
iterator: '@', iterator: '@',
dataset: '=', // two-way dataset: '=', // two-way

View File

@@ -0,0 +1,49 @@
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 {
name: 'portalMode.allJobs',
url: '/alljobs?{job_search:queryset}',
ncyBreadcrumb: {
skip: true
},
params: {
job_search: {
value: {
page_size: '20',
order_by: '-finished'
},
dynamic: true
}
},
data: {
socket: {
"groups": {
"jobs": ["status_changed"]
}
}
},
views: {
'jobs@portalMode': {
templateProvider: function(PortalJobsList, generateList) {
let html = generateList.build({
list: PortalJobsList,
mode: 'edit'
});
return html;
},
controller: PortalModeJobsController
}
},
resolve: {
jobsDataset: ['PortalJobsList', 'QuerySet', '$rootScope', '$stateParams', 'GetBasePath',
function(list, qs, $rootScope, $stateParams, GetBasePath) {
let path = GetBasePath(list.basePath) || GetBasePath(list.name);
return $rootScope.loginConfig.promise.then(() => {
return qs.search(path, $stateParams[`${list.iterator}_search`]);
});
}
]
}
};

View File

@@ -0,0 +1,51 @@
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 {
name: 'portalMode.myJobs',
url: '/myjobs?{job_search:queryset}',
ncyBreadcrumb: {
skip: true
},
params: {
job_search: {
value: {
page_size: '20',
order_by: '-finished',
created_by: null
},
dynamic: true
}
},
data: {
socket: {
"groups": {
"jobs": ["status_changed"]
}
}
},
views: {
'jobs@portalMode': {
templateProvider: function(PortalJobsList, generateList) {
let html = generateList.build({
list: PortalJobsList,
mode: 'edit'
});
return html;
},
controller: PortalModeJobsController
}
},
resolve: {
jobsDataset: ['PortalJobsList', 'QuerySet', '$rootScope', '$stateParams', 'GetBasePath',
function(list, qs, $rootScope, $stateParams, GetBasePath) {
let path = GetBasePath(list.basePath) || GetBasePath(list.name);
return $rootScope.loginConfig.promise.then(() => {
$stateParams[`${list.iterator}_search`].created_by = $rootScope.current_user.id;
return qs.search(path, $stateParams[`${list.iterator}_search`]);
});
}
]
}
};

View File

@@ -5,6 +5,8 @@
*************************************************/ *************************************************/
import route from './portal-mode.route'; import route from './portal-mode.route';
import myJobsRoute from './jobs/portal-mode-my-jobs.route';
import allJobsRoute from './jobs/portal-mode-all-jobs.route';
import PortalJobsList from './portal-jobs.list'; import PortalJobsList from './portal-jobs.list';
import PortalJobTemplateList from './portal-job-templates.list'; import PortalJobTemplateList from './portal-job-templates.list';
@@ -14,4 +16,6 @@ export default
.factory('PortalJobTemplateList', PortalJobTemplateList) .factory('PortalJobTemplateList', PortalJobTemplateList)
.run(['$stateExtender', function($stateExtender){ .run(['$stateExtender', function($stateExtender){
$stateExtender.addState(route); $stateExtender.addState(route);
$stateExtender.addState(myJobsRoute);
$stateExtender.addState(allJobsRoute);
}]); }]);

View File

@@ -16,6 +16,7 @@ export default ['i18n', function(i18n) {
hover: true, hover: true,
well: true, well: true,
emptyListText: i18n._('There are no job templates to display at this time'), emptyListText: i18n._('There are no job templates to display at this time'),
searchBarFullWidth: true,
fields: { fields: {
name: { name: {
key: true, key: true,

View File

@@ -16,6 +16,7 @@ export default ['i18n', function(i18n) {
well: true, well: true,
listTitle: i18n._('JOBS'), listTitle: i18n._('JOBS'),
emptyListText: i18n._('There are no jobs to display at this time'), emptyListText: i18n._('There are no jobs to display at this time'),
searchBarFullWidth: true,
fields: { fields: {
status: { status: {

View File

@@ -29,10 +29,6 @@ export function PortalModeJobsController($scope, $state, qs, GetBasePath, Portal
$scope.iterator = list.iterator; $scope.iterator = list.iterator;
} }
$scope.$on('filterPortalJobs', function(e, data){
init(data);
});
$scope.refresh = function() { $scope.refresh = function() {
$state.go('.', null, {reload: true}); $state.go('.', null, {reload: true});
}; };

View File

@@ -8,13 +8,13 @@
<div class="PortalMode-filterHolder"> <div class="PortalMode-filterHolder">
<div class="FormToggle-container"> <div class="FormToggle-container">
<div class="btn-group"> <div class="btn-group">
<button ng-class="{'btn-primary': activeFilter === 'user', 'Button-primary--hollow': activeFilter !== 'user'}" <button ng-class="{'btn-primary': $state.is('portalMode.myJobs'), 'Button-primary--hollow': $state.is('portalMode.allJobs')}"
ng-click='filterUser()' ng-click='filterUser()'
class="btn btn-xs" class="btn btn-xs"
translate> translate>
My Jobs My Jobs
</button> </button>
<button ng-class="{'btn-primary': activeFilter === 'all', 'Button-primary--hollow': activeFilter !== 'all'}" <button ng-class="{'btn-primary': $state.is('portalMode.allJobs'), 'Button-primary--hollow': $state.is('portalMode.myJobs')}"
ng-click='filterAll()' ng-click='filterAll()'
class="btn btn-xs" class="btn btn-xs"
translate> translate>

View File

@@ -1,7 +1,12 @@
@import "./client/src/shared/layouts/one-plus-one.less"; @import "./client/src/shared/layouts/one-plus-one.less";
.PortalMode-container{ .PortalMode-container{
.OnePlusOne-container; display: flex;
flex-direction: row;
@media screen and(max-width: 900px){
flex-direction: column;
height: 100%;
}
} }
.PortalMode-panel--left{ .PortalMode-panel--left{

View File

@@ -1,28 +1,23 @@
import { templateUrl } from '../shared/template-url/template-url.factory'; import { templateUrl } from '../shared/template-url/template-url.factory';
import { PortalModeJobTemplatesController } from './portal-mode-job-templates.controller'; import { PortalModeJobTemplatesController } from './portal-mode-job-templates.controller';
import { PortalModeJobsController } from './portal-mode-jobs.controller';
import { N_ } from '../i18n'; import { N_ } from '../i18n';
// Using multiple named views requires a parent layout // Using multiple named views requires a parent layout
// https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views // https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
export default { export default {
name: 'portalMode', name: 'portalMode',
url: '/portal?{group_search:queryset}{host_search:queryset}', url: '/portal?{job_template_search:queryset}',
abstract: true,
ncyBreadcrumb: { ncyBreadcrumb: {
label: N_('MY VIEW') label: N_('MY VIEW')
}, },
params: { params: {
job_search: {
value: {
page_size: '20',
order_by: '-finished'
}
},
job_template_search: { job_template_search: {
value: { value: {
page_size: '20', page_size: '20',
order_by: 'name' order_by: 'name'
} },
dynamic: true
} }
}, },
data: { data: {
@@ -35,31 +30,15 @@ export default {
views: { views: {
'@': { '@': {
templateUrl: templateUrl('portal-mode/portal-mode-layout'), templateUrl: templateUrl('portal-mode/portal-mode-layout'),
controller: ['$scope', '$rootScope', '$state', '$stateParams', 'GetBasePath', 'QuerySet', controller: ['$scope', '$state',
function($scope, $rootScope, $state, $stateParams, GetBasePath, qs) { function($scope, $state) {
let path;
init();
function init() {
$scope.activeFilter = parseInt($stateParams.job_search.created_by) === $rootScope.current_user.id ? 'user' : 'all';
}
$scope.filterUser = function() { $scope.filterUser = function() {
$scope.activeFilter = 'user'; $state.go('portalMode.myJobs');
path = GetBasePath('jobs');
$stateParams.job_search.created_by = $rootScope.current_user.id;
qs.search(path, $stateParams.job_search).then((response) => {
$scope.$broadcast('filterPortalJobs', response);
});
}; };
$scope.filterAll = function() { $scope.filterAll = function() {
$scope.activeFilter = 'all'; $state.go('portalMode.allJobs');
delete $stateParams.job_search.created_by;
path = GetBasePath('jobs');
qs.search(path, $stateParams.job_search).then((response) => {
$scope.$broadcast('filterPortalJobs', response);
});
}; };
} }
] ]
@@ -74,28 +53,9 @@ export default {
return html; return html;
}, },
controller: PortalModeJobTemplatesController controller: PortalModeJobTemplatesController
},
'jobs@portalMode': {
templateProvider: function(PortalJobsList, generateList) {
let html = generateList.build({
list: PortalJobsList,
mode: 'edit'
});
return html;
},
controller: PortalModeJobsController
} }
}, },
resolve: { resolve: {
jobsDataset: ['PortalJobsList', 'QuerySet', '$rootScope', '$stateParams', 'GetBasePath',
function(list, qs, $rootScope, $stateParams, GetBasePath) {
let path = GetBasePath(list.basePath) || GetBasePath(list.name);
return $rootScope.loginConfig.promise.then(() => {
$stateParams[`${list.iterator}_search`].created_by = $rootScope.current_user.id;
return qs.search(path, $stateParams[`${list.iterator}_search`]);
});
}
],
job_templatesDataset: ['PortalJobTemplateList', 'QuerySet', '$stateParams', 'GetBasePath', job_templatesDataset: ['PortalJobTemplateList', 'QuerySet', '$stateParams', 'GetBasePath',
function(list, qs, $stateParams, GetBasePath) { function(list, qs, $stateParams, GetBasePath) {
let path = GetBasePath(list.basePath) || GetBasePath(list.name); let path = GetBasePath(list.basePath) || GetBasePath(list.name);

View File

@@ -23,7 +23,6 @@
* | mode | Yes | One of 'edit', 'lookup', 'select', or 'summary'. Generally this will be 'edit'. helpers/Lookup.js uses 'lookup' to generate the lookup dialog. The 'select' option is used in certain controllers when multiple objects are being added to a parent object. For example, building a select list of Users that can be added to an Oranization. 'summary' is no longer used. | * | mode | Yes | One of 'edit', 'lookup', 'select', or 'summary'. Generally this will be 'edit'. helpers/Lookup.js uses 'lookup' to generate the lookup dialog. The 'select' option is used in certain controllers when multiple objects are being added to a parent object. For example, building a select list of Users that can be added to an Oranization. 'summary' is no longer used. |
* | scope | | If the HTML will be injected into the DOM by list generator, pass in an optional $scope to be used in conjuction with $compile. The list will be associated with the scope value. Otherwise, the scope of the DOM element will be fetched passed to $compile. | * | scope | | If the HTML will be injected into the DOM by list generator, pass in an optional $scope to be used in conjuction with $compile. The list will be associated with the scope value. Otherwise, the scope of the DOM element will be fetched passed to $compile. |
* | showSearch | | true or false. Set to false, if the search widget should not be included in the generated HTML. | * | showSearch | | true or false. Set to false, if the search widget should not be included in the generated HTML. |
* | searchSize | | Bootstrap size class (e.g. col-lg-3, col-md-4, col-sm-5, etc.) to apply to the search widget. Defaults to 'col-lg-4 col-md-6 col-sm-8 col-xs-9'. |
* *
* #HTML only * #HTML only
* *
@@ -198,16 +197,12 @@ export default ['$compile', 'Attr', 'Icon',
} }
html += (list.searchRowActions) ? "<div class='row'><div class=\"col-lg-8 col-md-8 col-sm-8 col-xs-12\">" : ""; html += (list.searchRowActions) ? "<div class='row'><div class=\"col-lg-8 col-md-8 col-sm-8 col-xs-12\">" : "";
if (list.searchRowActions && !list.searchSize) {
list.searchSize = 'col-lg-7 col-md-12 col-sm-12 col-xs-12';
}
if (options.showSearch === undefined || options.showSearch === true) { if (options.showSearch === undefined || options.showSearch === true) {
let singleSearchParam = list.singleSearchParam && list.singleSearchParam.param ? `single-search-param="${list.singleSearchParam.param}"` : ''; let singleSearchParam = list.singleSearchParam && list.singleSearchParam.param ? `single-search-param="${list.singleSearchParam.param}"` : '';
html += ` html += `
<div ng-hide="${list.name}.length === 0 && (searchTags | isEmpty)"> <div ng-hide="${list.name}.length === 0 && (searchTags | isEmpty)">
<smart-search <smart-search
django-model="${list.name}" django-model="${list.name}"
search-size="${list.searchSize}"
${singleSearchParam} ${singleSearchParam}
base-path="${list.basePath || list.name}" base-path="${list.basePath || list.name}"
iterator="${list.iterator}" iterator="${list.iterator}"
@@ -216,6 +211,7 @@ export default ['$compile', 'Attr', 'Icon',
collection="${list.name}" collection="${list.name}"
default-params="${list.iterator}_default_params" default-params="${list.iterator}_default_params"
query-set="${list.iterator}_queryset" query-set="${list.iterator}_queryset"
search-bar-full-width="${list.searchBarFullWidth}"
search-tags="searchTags"> search-tags="searchTags">
</smart-search> </smart-search>
</div> </div>

View File

@@ -17,6 +17,10 @@
width: 50%; width: 50%;
} }
.SmartSearch-bar--fullWidth {
width: 100%;
}
.SmartSearch-tags{ .SmartSearch-tags{
padding-left: 0px; padding-left: 0px;
} }

View File

@@ -8,7 +8,6 @@ export default ['templateUrl',
}, },
scope: { scope: {
djangoModel: '@', djangoModel: '@',
searchSize: '@',
basePath: '@', basePath: '@',
iterator: '@', iterator: '@',
list: '=', list: '=',
@@ -18,7 +17,8 @@ export default ['templateUrl',
disableSearch: '=', disableSearch: '=',
defaultParams: '=', defaultParams: '=',
querySet: '=', querySet: '=',
singleSearchParam: '@' singleSearchParam: '@',
searchBarFullWidth: '='
}, },
controller: 'SmartSearchController', controller: 'SmartSearchController',
templateUrl: templateUrl('shared/smart-search/smart-search') templateUrl: templateUrl('shared/smart-search/smart-search')

View File

@@ -1,6 +1,6 @@
<div class="SmartSearch row"> <div class="SmartSearch row">
<!-- input --> <!-- input -->
<div class="SmartSearch-bar"> <div class="SmartSearch-bar" ng-class="{'SmartSearch-bar--fullWidth': searchBarFullWidth}">
<div class="SmartSearch-searchTermContainer"> <div class="SmartSearch-searchTermContainer">
<!-- string search input --> <!-- string search input -->
<form name="smartSearch" class="SmartSearch-form" aw-enter-key="addTerm(searchTerm)" novalidate> <form name="smartSearch" class="SmartSearch-form" aw-enter-key="addTerm(searchTerm)" novalidate>