mirror of
https://github.com/ansible/awx.git
synced 2026-05-18 06:47:41 -02:30
AC-414 Making red/green bubbles consistent throughout the application. Changes made to Inventory and jobs pages. Tooltip text now dynamic. Improved deep linking, especially on status fields.
This commit is contained in:
@@ -70,7 +70,8 @@ angular.module('ansible', [
|
|||||||
'LicenseFormDefinition',
|
'LicenseFormDefinition',
|
||||||
'License',
|
'License',
|
||||||
'HostGroupsFormDefinition',
|
'HostGroupsFormDefinition',
|
||||||
'ObjectCountWidget'
|
'ObjectCountWidget',
|
||||||
|
'JobsHelper'
|
||||||
])
|
])
|
||||||
.config(['$routeProvider', function($routeProvider) {
|
.config(['$routeProvider', function($routeProvider) {
|
||||||
$routeProvider.
|
$routeProvider.
|
||||||
|
|||||||
@@ -43,15 +43,15 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa
|
|||||||
LoadSearchTree({ scope: scope, inventory_id: scope['inventory_id'] });
|
LoadSearchTree({ scope: scope, inventory_id: scope['inventory_id'] });
|
||||||
|
|
||||||
// Add the selected flag to the hosts set.
|
// Add the selected flag to the hosts set.
|
||||||
if (scope.relatedHostsRemove) {
|
//if (scope.relatedHostsRemove) {
|
||||||
scope.relatedHostsRemove();
|
// scope.relatedHostsRemove();
|
||||||
}
|
//}
|
||||||
scope.relatedHostsRemove = scope.$on('relatedhosts', function() {
|
//scope.relatedHostsRemove = scope.$on('relatedhosts', function() {
|
||||||
scope.toggleAllFlag = false;
|
// scope.toggleAllFlag = false;
|
||||||
for (var i=0; i < scope.hosts.length; i++) {
|
// for (var i=0; i < scope.hosts.length; i++) {
|
||||||
scope.hosts[i].selected = 0;
|
// scope.hosts[i].selected = 0;
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
scope.filterHosts = function() {
|
scope.filterHosts = function() {
|
||||||
HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] });
|
HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] });
|
||||||
|
|||||||
@@ -30,65 +30,79 @@ function InventoriesList ($scope, $rootScope, $location, $log, $routeParams, Res
|
|||||||
scope.search(list.iterator);
|
scope.search(list.iterator);
|
||||||
|
|
||||||
LoadBreadCrumbs();
|
LoadBreadCrumbs();
|
||||||
|
|
||||||
|
if (scope.projectsPostRefresh) {
|
||||||
|
scope.projectsPostRefresh();
|
||||||
|
}
|
||||||
|
scope.projectsPostRefresh = scope.$on('PostRefresh', function() {
|
||||||
|
for (var i=0; i < scope.inventories.length; i++) {
|
||||||
|
if (scope.inventories[i].hosts_with_active_failures > 0) {
|
||||||
|
scope.inventories[i].active_failures_params = "/?has_active_failures=true";
|
||||||
|
}
|
||||||
|
//if (scope.inventories[i].hosts_with_active_failures < 99) {
|
||||||
|
// scope.inventories[i].hosts_with_active_failures = ('00' + scope.inventories[i].hosts_with_active_failures).substr(-2);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
scope.addInventory = function() {
|
scope.addInventory = function() {
|
||||||
$location.path($location.path() + '/add');
|
$location.path($location.path() + '/add');
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.editInventory = function(id) {
|
scope.editInventory = function(id) {
|
||||||
$location.path($location.path() + '/' + id);
|
$location.path($location.path() + '/' + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.deleteInventory = function(id, name) {
|
scope.deleteInventory = function(id, name) {
|
||||||
|
|
||||||
var action = function() {
|
var action = function() {
|
||||||
var url = defaultUrl + id + '/';
|
var url = defaultUrl + id + '/';
|
||||||
$('#prompt-modal').modal('hide');
|
$('#prompt-modal').modal('hide');
|
||||||
Wait('start');
|
Wait('start');
|
||||||
Rest.setUrl(url);
|
Rest.setUrl(url);
|
||||||
Rest.destroy()
|
Rest.destroy()
|
||||||
.success( function(data, status, headers, config) {
|
.success( function(data, status, headers, config) {
|
||||||
scope.search(list.iterator);
|
scope.search(list.iterator);
|
||||||
Wait('stop');
|
Wait('stop');
|
||||||
})
|
})
|
||||||
.error( function(data, status, headers, config) {
|
.error( function(data, status, headers, config) {
|
||||||
Wait('stop');
|
Wait('stop');
|
||||||
ProcessErrors(scope, data, status, null,
|
ProcessErrors(scope, data, status, null,
|
||||||
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Prompt({ hdr: 'Delete',
|
Prompt({ hdr: 'Delete',
|
||||||
body: 'Are you sure you want to delete ' + name + '?',
|
body: 'Are you sure you want to delete ' + name + '?',
|
||||||
action: action
|
action: action
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.lookupOrganization = function(organization_id) {
|
scope.lookupOrganization = function(organization_id) {
|
||||||
Rest.setUrl(GetBasePath('organizations') + organization_id + '/');
|
Rest.setUrl(GetBasePath('organizations') + organization_id + '/');
|
||||||
Rest.get()
|
Rest.get()
|
||||||
.success( function(data, status, headers, config) {
|
.success( function(data, status, headers, config) {
|
||||||
return data.name;
|
return data.name;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status
|
// Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status
|
||||||
scope.viewJobs = function(id) {
|
scope.viewJobs = function(id) {
|
||||||
$location.url('/jobs/?inventory__int=' + id);
|
$location.url('/jobs/?inventory__int=' + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.viewFailedJobs = function(id) {
|
scope.viewFailedJobs = function(id) {
|
||||||
$location.url('/jobs/?inventory__int=' + id + '&status=failed');
|
$location.url('/jobs/?inventory__int=' + id + '&status=failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.editHosts = function(id) {
|
scope.editHosts = function(id) {
|
||||||
$location.url('/inventories/' + id + '/hosts');
|
$location.url('/inventories/' + id + '/hosts');
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.editGroups = function(id) {
|
scope.editGroups = function(id) {
|
||||||
$location.url('/inventories/' + id + '/groups');
|
$location.url('/inventories/' + id + '/groups');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoriesList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'InventoryList', 'GenerateList',
|
InventoriesList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'InventoryList', 'GenerateList',
|
||||||
|
|||||||
@@ -131,12 +131,39 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
|||||||
set[i]['spaces'] = set[i].event_level * 24;
|
set[i]['spaces'] = set[i].event_level * 24;
|
||||||
if (scope.jobevents[i].failed) {
|
if (scope.jobevents[i].failed) {
|
||||||
scope.jobevents[i].status = 'error';
|
scope.jobevents[i].status = 'error';
|
||||||
|
if (i == set.length - 1) {
|
||||||
|
scope.jobevents[i].statusBadgeToolTip = "A failure occurred durring one or more playbook tasks.";
|
||||||
|
}
|
||||||
|
else if (set[i].event_level < 3) {
|
||||||
|
scope.jobevents[i].statusBadgeToolTip = "A failure occurred within the children of this event.";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scope.jobevents[i].statusBadgeToolTip = "A failure occurred. Click to view details";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (scope.jobevents[i].changed) {
|
else if (scope.jobevents[i].changed) {
|
||||||
scope.jobevents[i].status = 'changed';
|
scope.jobevents[i].status = 'changed';
|
||||||
|
if (i == set.length - 1) {
|
||||||
|
scope.jobevents[i].statusBadgeToolTip = "A change was completed durring one or more playbook tasks.";
|
||||||
|
}
|
||||||
|
else if (set[i].event_level < 3) {
|
||||||
|
scope.jobevents[i].statusBadgeToolTip = "A change was completed by one or more children of this event.";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scope.jobevents[i].statusBadgeToolTip = "A change was completed. Click to view details";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
scope.jobevents[i].status = 'success';
|
scope.jobevents[i].status = 'success';
|
||||||
|
if (i == set.length - 1) {
|
||||||
|
scope.jobevents[i].statusBadgeToolTip = "All playbook tasks completed successfully.";
|
||||||
|
}
|
||||||
|
else if (set[i].event_level < 3) {
|
||||||
|
scope.jobevents[i].statusBadgeToolTip = "All the children of this event completed successfully.";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scope.jobevents[i].statusBadgeToolTip = "No errors occurred. Click to view details";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cDate = new Date(set[i].created);
|
cDate = new Date(set[i].created);
|
||||||
set[i].created = FormatDate(cDate);
|
set[i].created = FormatDate(cDate);
|
||||||
@@ -147,6 +174,8 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
|||||||
Rest.get()
|
Rest.get()
|
||||||
.success( function(data, status, headers, config) {
|
.success( function(data, status, headers, config) {
|
||||||
scope.job_status = data.status;
|
scope.job_status = data.status;
|
||||||
|
scope.job_name = data.summary_fields.job_template.name;
|
||||||
|
LoadBreadCrumbs({ path: '/jobs/' + scope.job_id, title: scope.job_name });
|
||||||
if (!(data.status == 'pending' || data.status == 'waiting' || data.status == 'running')) {
|
if (!(data.status == 'pending' || data.status == 'waiting' || data.status == 'running')) {
|
||||||
if ($rootScope.timer) {
|
if ($rootScope.timer) {
|
||||||
clearInterval($rootScope.timer);
|
clearInterval($rootScope.timer);
|
||||||
@@ -181,8 +210,6 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
|||||||
children: children
|
children: children
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadBreadCrumbs();
|
|
||||||
|
|
||||||
scope.viewJobEvent = function(id) {
|
scope.viewJobEvent = function(id) {
|
||||||
EventView({ event_id: id });
|
EventView({ event_id: id });
|
||||||
|
|||||||
@@ -12,13 +12,14 @@
|
|||||||
|
|
||||||
function JobHostSummaryList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobHostList,
|
function JobHostSummaryList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobHostList,
|
||||||
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||||
ClearScope, ProcessErrors, GetBasePath, Refresh)
|
ClearScope, ProcessErrors, GetBasePath, Refresh, JobStatusToolTip)
|
||||||
{
|
{
|
||||||
ClearScope('htmlTemplate');
|
ClearScope('htmlTemplate');
|
||||||
var list = JobHostList;
|
var list = JobHostList;
|
||||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||||
var defaultUrl = GetBasePath(base) + $routeParams.id + '/job_host_summaries/';
|
var defaultUrl = GetBasePath(base) + $routeParams.id + '/job_host_summaries/';
|
||||||
|
var inventory_id;
|
||||||
|
|
||||||
// When viewing all summaries for a particular host, show job ID, otherwise row ID.
|
// When viewing all summaries for a particular host, show job ID, otherwise row ID.
|
||||||
if (base == 'hosts') {
|
if (base == 'hosts') {
|
||||||
list.index = false;
|
list.index = false;
|
||||||
@@ -42,46 +43,71 @@ function JobHostSummaryList ($scope, $rootScope, $location, $log, $routeParams,
|
|||||||
scope.host_id = null;
|
scope.host_id = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scope.RemoveSetHostLink) {
|
||||||
|
scope.RemoveSetHostLink();
|
||||||
|
}
|
||||||
|
scope.RemoveSetHostLink = scope.$on('setHostLink', function(e, inventory_id) {
|
||||||
|
for (var i=0; i < scope.jobhosts.length; i++) {
|
||||||
|
scope.jobhosts[i].hostLinkTo = '/#/inventories/' + inventory_id + '/hosts/?name=' +
|
||||||
|
escape(scope.jobhosts[i].summary_fields.host.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// After a refresh, populate any needed summary field values on each row
|
// After a refresh, populate any needed summary field values on each row
|
||||||
if (scope.PostRefreshRemove) {
|
if (scope.PostRefreshRemove) {
|
||||||
scope.PostRefreshRemove();
|
scope.PostRefreshRemove();
|
||||||
}
|
}
|
||||||
scope.PostRefershRemove = scope.$on('PostRefresh', function() {
|
scope.PostRefreshRemove = scope.$on('PostRefresh', function() {
|
||||||
|
|
||||||
|
// Set status, tooltips, badget icons, etc.
|
||||||
for( var i=0; i < scope.jobhosts.length; i++) {
|
for( var i=0; i < scope.jobhosts.length; i++) {
|
||||||
scope.jobhosts[i].host_name = scope.jobhosts[i].summary_fields.host.name;
|
scope.jobhosts[i].host_name = scope.jobhosts[i].summary_fields.host.name;
|
||||||
scope.jobhosts[i].status = (scope.jobhosts[i].failed) ? 'error' : 'success';
|
scope.jobhosts[i].status = (scope.jobhosts[i].failed) ? 'failed' : 'success';
|
||||||
|
scope.jobhosts[i].statusBadgeToolTip = JobStatusToolTip(scope.jobhosts[i].status) +
|
||||||
|
" Click to view details.";
|
||||||
|
scope.jobhosts[i].statusLinkTo = '/#/jobs/' + scope.jobhosts[i].job + '/job_events/?host=' +
|
||||||
|
escape(scope.jobhosts[i].summary_fields.host.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope.job_id !== null && scope.job_id !== undefined && scope.job_id !== '') {
|
if (scope.job_id !== null && scope.job_id !== undefined && scope.job_id !== '') {
|
||||||
// need job_status so we can show/hide refresh button
|
// need job_status so we can show/hide refresh button
|
||||||
Rest.setUrl(GetBasePath('jobs') + scope.job_id);
|
Rest.setUrl(GetBasePath('jobs') + scope.job_id);
|
||||||
Rest.get()
|
Rest.get()
|
||||||
.success( function(data, status, headers, config) {
|
.success( function(data, status, headers, config) {
|
||||||
scope.job_status = data.status;
|
scope.job_status = data.status;
|
||||||
|
scope.$emit('setHostLink', data.inventory);
|
||||||
if (!(data.status == 'pending' || data.status == 'waiting' || data.status == 'running')) {
|
if (!(data.status == 'pending' || data.status == 'waiting' || data.status == 'running')) {
|
||||||
if ($rootScope.timer) {
|
if ($rootScope.timer) {
|
||||||
clearInterval($rootScope.timer);
|
clearInterval($rootScope.timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.error( function(data, status, headers, config) {
|
.error( function(data, status, headers, config) {
|
||||||
ProcessErrors(scope, data, status, null,
|
ProcessErrors(scope, data, status, null,
|
||||||
{ hdr: 'Error!', msg: 'Failed to get job status for job: ' + scope.job_id + '. GET status: ' + status });
|
{ hdr: 'Error!', msg: 'Failed to get job status for job: ' + scope.job_id + '. GET status: ' + status });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (base == 'hosts' && $routeParams['host_name']) {
|
||||||
|
// Make the host name appear in breadcrumbs
|
||||||
|
LoadBreadCrumbs({ path: '/hosts/' + scope['host_id'], title: $routeParams['host_name'] });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LoadBreadCrumbs();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
SearchInit({ scope: scope, set: 'jobhosts', list: list, url: defaultUrl });
|
SearchInit({ scope: scope, set: 'jobhosts', list: list, url: defaultUrl });
|
||||||
PaginateInit({ scope: scope, list: list, url: defaultUrl });
|
PaginateInit({ scope: scope, list: list, url: defaultUrl });
|
||||||
|
|
||||||
// Called from Inventories tab, host failed events link:
|
// Called from Inventories tab, host failed events link:
|
||||||
if ($routeParams.host) {
|
if ($routeParams['host_name']) {
|
||||||
scope[list.iterator + 'SearchField'] = 'host';
|
scope[list.iterator + 'SearchField'] = 'host';
|
||||||
scope[list.iterator + 'SearchValue'] = $routeParams.host;
|
scope[list.iterator + 'SearchValue'] = $routeParams['host_name'];
|
||||||
scope[list.iterator + 'SearchFieldLabel'] = list.fields['host'].label;
|
scope[list.iterator + 'SearchFieldLabel'] = list.fields['host'].label;
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.search(list.iterator);
|
scope.search(list.iterator);
|
||||||
LoadBreadCrumbs();
|
|
||||||
|
|
||||||
scope.showEvents = function(host_name, last_job) {
|
scope.showEvents = function(host_name, last_job) {
|
||||||
// When click on !Failed Events link, redirect to latest job/job_events for the host
|
// When click on !Failed Events link, redirect to latest job/job_events for the host
|
||||||
@@ -113,5 +139,5 @@ function JobHostSummaryList ($scope, $rootScope, $location, $log, $routeParams,
|
|||||||
|
|
||||||
JobHostSummaryList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobHostList',
|
JobHostSummaryList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobHostList',
|
||||||
'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||||
'ProcessErrors', 'GetBasePath', 'Refresh'
|
'ProcessErrors', 'GetBasePath', 'Refresh', 'JobStatusToolTip'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -27,6 +27,14 @@ function JobTemplatesList ($scope, $rootScope, $location, $log, $routeParams, Re
|
|||||||
|
|
||||||
SearchInit({ scope: scope, set: 'job_templates', list: list, url: defaultUrl });
|
SearchInit({ scope: scope, set: 'job_templates', list: list, url: defaultUrl });
|
||||||
PaginateInit({ scope: scope, list: list, url: defaultUrl });
|
PaginateInit({ scope: scope, list: list, url: defaultUrl });
|
||||||
|
|
||||||
|
// Called from Inventories tab, host failed events link:
|
||||||
|
if ($routeParams['name']) {
|
||||||
|
scope[list.iterator + 'SearchField'] = 'name';
|
||||||
|
scope[list.iterator + 'SearchValue'] = $routeParams['name'];
|
||||||
|
scope[list.iterator + 'SearchFieldLabel'] = list.fields['name'].label;
|
||||||
|
}
|
||||||
|
|
||||||
scope.search(list.iterator);
|
scope.search(list.iterator);
|
||||||
|
|
||||||
LoadBreadCrumbs();
|
LoadBreadCrumbs();
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
|
|
||||||
function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList,
|
function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList,
|
||||||
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||||
ClearScope, ProcessErrors, GetBasePath, LookUpInit, SubmitJob, FormatDate, Refresh)
|
ClearScope, ProcessErrors, GetBasePath, LookUpInit, SubmitJob, FormatDate, Refresh,
|
||||||
|
JobStatusToolTip)
|
||||||
{
|
{
|
||||||
ClearScope('htmlTemplate');
|
ClearScope('htmlTemplate');
|
||||||
var list = JobList;
|
var list = JobList;
|
||||||
@@ -41,6 +42,13 @@ function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
|||||||
scope[list.name][i].created = FormatDate(cDate);
|
scope[list.name][i].created = FormatDate(cDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (var i=0; i < scope.jobs.length; i++) {
|
||||||
|
scope.jobs[i].statusBadgeToolTip = JobStatusToolTip(scope.jobs[i].status) +
|
||||||
|
" Click to view status details.";
|
||||||
|
scope.jobs[i].statusLinkTo = '/#/jobs/' + scope.jobs[i].id;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -157,14 +165,14 @@ function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
|||||||
|
|
||||||
JobsListCtrl.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobList',
|
JobsListCtrl.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobList',
|
||||||
'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||||
'ProcessErrors','GetBasePath', 'LookUpInit', 'SubmitJob', 'FormatDate', 'Refresh'
|
'ProcessErrors','GetBasePath', 'LookUpInit', 'SubmitJob', 'FormatDate', 'Refresh', 'JobStatusToolTip'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm,
|
function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm,
|
||||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
|
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
|
||||||
RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, CredentialList,
|
RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, CredentialList,
|
||||||
ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate)
|
ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate, JobStatusToolTip)
|
||||||
{
|
{
|
||||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||||
//scope.
|
//scope.
|
||||||
@@ -334,7 +342,9 @@ function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope.statusToolTip = JobStatusToolTip(data.status);
|
||||||
|
|
||||||
$('form[name="jobs_form"] input[type="text"], form[name="jobs_form"] jobs_form textarea').attr('readonly','readonly');
|
$('form[name="jobs_form"] input[type="text"], form[name="jobs_form"] jobs_form textarea').attr('readonly','readonly');
|
||||||
$('form[name="jobs_form"] select').prop('disabled', 'disabled');
|
$('form[name="jobs_form"] select').prop('disabled', 'disabled');
|
||||||
$('form[name="jobs_form"] .lookup-btn').prop('disabled', 'disabled');
|
$('form[name="jobs_form"] .lookup-btn').prop('disabled', 'disabled');
|
||||||
@@ -503,5 +513,6 @@ function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
|||||||
JobsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobForm',
|
JobsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobForm',
|
||||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
|
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
|
||||||
'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList',
|
'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList',
|
||||||
'ProjectList', 'LookUpInit', 'PromptPasswords', 'GetBasePath', 'md5Setup', 'FormatDate'
|
'ProjectList', 'LookUpInit', 'PromptPasswords', 'GetBasePath', 'md5Setup', 'FormatDate',
|
||||||
|
'JobStatusToolTip'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -18,13 +18,29 @@ angular.module('InventoryHostsFormDefinition', [])
|
|||||||
fields: {
|
fields: {
|
||||||
name: {
|
name: {
|
||||||
key: true,
|
key: true,
|
||||||
label: 'Host Name',
|
label: 'Name',
|
||||||
ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')",
|
ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')"
|
||||||
|
//columnClass: 'col-lg-3'
|
||||||
|
},
|
||||||
|
active_failures: {
|
||||||
|
label: 'Current<br>Job Status?',
|
||||||
|
ngHref: "\{\{ host.activeFailuresLink \}\}",
|
||||||
|
awToolTip: "\{\{ host.badgeToolTip \}\}",
|
||||||
|
dataPlacement: 'bottom',
|
||||||
|
badgeNgHref: '\{\{ host.activeFailuresLink \}\}',
|
||||||
badgeIcon: "\{\{ 'icon-failures-' + host.has_active_failures \}\}",
|
badgeIcon: "\{\{ 'icon-failures-' + host.has_active_failures \}\}",
|
||||||
badgeToolTip: 'Indicates if host has active failures',
|
|
||||||
badgePlacement: 'left',
|
badgePlacement: 'left',
|
||||||
|
badgeToolTip: "\{\{ host.badgeToolTip \}\}",
|
||||||
badgeTipPlacement: 'bottom',
|
badgeTipPlacement: 'bottom',
|
||||||
columnClass: 'col-lg-3'
|
searchable: false,
|
||||||
|
nosort: true
|
||||||
|
},
|
||||||
|
has_active_failures: {
|
||||||
|
label: 'Current job failed?',
|
||||||
|
searchSingleValue: true,
|
||||||
|
searchType: 'boolean',
|
||||||
|
searchValue: 'true',
|
||||||
|
searchOnly: true
|
||||||
},
|
},
|
||||||
groups: {
|
groups: {
|
||||||
label: 'Groups',
|
label: 'Groups',
|
||||||
@@ -32,7 +48,7 @@ angular.module('InventoryHostsFormDefinition', [])
|
|||||||
sourceModel: 'groups',
|
sourceModel: 'groups',
|
||||||
sourceField: 'name',
|
sourceField: 'name',
|
||||||
nosort: true
|
nosort: true
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ angular.module('JobFormDefinition', [])
|
|||||||
status: {
|
status: {
|
||||||
label: 'Job Status',
|
label: 'Job Status',
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
control: '<div class="job-detail-status job-\{\{ status \}\}"><i class="icon-circle"></i> \{\{ status \}\}</div>',
|
control: '<div class=\"job-detail-status\"><i class=\"icon-job-\{\{ status \}\}\"></i> \{\{ status \}\}</div>',
|
||||||
readonly: true
|
readonly: true
|
||||||
},
|
},
|
||||||
created: {
|
created: {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventDataDefini
|
|||||||
fields: {
|
fields: {
|
||||||
status: {
|
status: {
|
||||||
labelClass: 'job-\{\{ status \}\}',
|
labelClass: 'job-\{\{ status \}\}',
|
||||||
icon: 'icon-circle',
|
icon: 'icon-job-\{\{ status \}\}',
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
section: 'Event',
|
section: 'Event',
|
||||||
control: '<div class=\"job-event-status job-\{\{ status \}\}\">\{\{ status \}\}</div>'
|
control: '<div class=\"job-event-status job-\{\{ status \}\}\">\{\{ status \}\}</div>'
|
||||||
|
|||||||
@@ -147,26 +147,35 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
|||||||
for (var i=0; i < scope.groups.length; i++) {
|
for (var i=0; i < scope.groups.length; i++) {
|
||||||
var last_update = (scope.groups[i].last_updated == null) ? '' : FormatDate(new Date(scope.groups[i].last_updated));
|
var last_update = (scope.groups[i].last_updated == null) ? '' : FormatDate(new Date(scope.groups[i].last_updated));
|
||||||
var source = 'Manual';
|
var source = 'Manual';
|
||||||
var stat;
|
var stat, stat_class, status_tip;
|
||||||
var stat_class;
|
|
||||||
|
|
||||||
|
stat = scope.groups[i].status;
|
||||||
|
stat_class = stat;
|
||||||
switch (scope.groups[i].status) {
|
switch (scope.groups[i].status) {
|
||||||
case 'never updated':
|
case 'never updated':
|
||||||
stat = 'never';
|
stat = 'never';
|
||||||
stat_class = 'never';
|
stat_class = 'never';
|
||||||
|
status_tip = 'Inventory update has not been performed. Click Update button to start it now.';
|
||||||
break;
|
break;
|
||||||
case 'none':
|
case 'none':
|
||||||
stat = 'n/a';
|
stat = 'n/a';
|
||||||
stat_class = 'na';
|
stat_class = 'na';
|
||||||
|
status_tip = 'Not configured for inventory update.';
|
||||||
|
break;
|
||||||
|
case 'failed':
|
||||||
|
status_tip = 'Inventory update completed with errors. Click to view process output.';
|
||||||
|
break;
|
||||||
|
case 'successful':
|
||||||
|
status_tip = 'Inventory update completed with no errors. Click to view process output.';
|
||||||
|
break;
|
||||||
|
case 'updating':
|
||||||
|
status_tip = 'Inventory update process running now.';
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
stat = scope.groups[i].status;
|
|
||||||
stat_class = stat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (scope.groups[i].source) {
|
switch (scope.groups[i].source) {
|
||||||
case 'file':
|
case 'file':
|
||||||
source = 'File';
|
source = 'Local Script';
|
||||||
break;
|
break;
|
||||||
case 'ec2':
|
case 'ec2':
|
||||||
source = 'Amazon EC2';
|
source = 'Amazon EC2';
|
||||||
@@ -175,10 +184,21 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
|||||||
source = 'Rackspace';
|
source = 'Rackspace';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scope.groups[i].summary_fields.group.hosts_with_active_failures > 0) {
|
||||||
|
scope.groups[i].active_failures_params = "/?has_active_failures=true";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scope.groups[i].active_failures_params = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.groups[i].hosts_with_active_failures = scope.groups[i].summary_fields.group.hosts_with_active_failures;
|
||||||
|
scope.groups[i].has_active_failures = scope.groups[i].summary_fields.group.has_active_failures;
|
||||||
scope.groups[i].status = stat;
|
scope.groups[i].status = stat;
|
||||||
scope.groups[i].source = source;
|
scope.groups[i].source = source;
|
||||||
scope.groups[i].last_updated = last_update;
|
scope.groups[i].last_updated = last_update;
|
||||||
scope.groups[i].status_class = stat_class;
|
scope.groups[i].status_badge_class = stat_class;
|
||||||
|
scope.groups[i].status_badge_tooltip = status_tip;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -688,6 +708,36 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Start the update process
|
||||||
|
scope.updateGroup = function() {
|
||||||
|
if (scope[source] == "" || scope.groups[i].source == null) {
|
||||||
|
Alert('Missing Configuration', 'The group is not configured for updates. You must provide Source settings before running the update ' +
|
||||||
|
'process.');
|
||||||
|
}
|
||||||
|
else if (scope[status] == 'updating') {
|
||||||
|
Alert('Update in Progress', 'The inventory update process is currently running for this group <em>' +
|
||||||
|
scope.groups[i].summary_fields.group.name + '</em>. Under the Groupmonitor the status.', 'alert-info');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (scope['source'] == 'Amazon EC2') {
|
||||||
|
scope['sourceUsernameLabel'] = 'Access Key ID';
|
||||||
|
scope['sourcePasswordLabel'] = 'Secret Access Key';
|
||||||
|
scope['sourcePasswordConfirmLabel'] = 'Confirm Secret Access Key';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scope['sourceUsernameLabel'] = 'Username';
|
||||||
|
scope['sourcePasswordLabel'] = 'Password';
|
||||||
|
scope['sourcePasswordConfirmLabel'] = 'Confirm Password';
|
||||||
|
}
|
||||||
|
InventoryUpdate({
|
||||||
|
scope: scope,
|
||||||
|
group_id: id,
|
||||||
|
url: scope.groups[i].related.update,
|
||||||
|
group_name: scope.groups[i].summary_fields.group.name,
|
||||||
|
group_source: scope.groups[i].source
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cancel
|
// Cancel
|
||||||
scope.formReset = function() {
|
scope.formReset = function() {
|
||||||
@@ -697,6 +747,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
|||||||
}
|
}
|
||||||
scope.parseType = 'yaml';
|
scope.parseType = 'yaml';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}])
|
}])
|
||||||
|
|
||||||
|
|||||||
@@ -408,8 +408,8 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
|||||||
}])
|
}])
|
||||||
|
|
||||||
|
|
||||||
.factory('HostsReload', ['SearchInit', 'PaginateInit', 'InventoryHostsForm', 'GetBasePath', 'Wait',
|
.factory('HostsReload', ['$routeParams', 'SearchInit', 'PaginateInit', 'InventoryHostsForm', 'GetBasePath', 'Wait',
|
||||||
function(SearchInit, PaginateInit, InventoryHostsForm, GetBasePath, Wait) {
|
function($routeParams, SearchInit, PaginateInit, InventoryHostsForm, GetBasePath, Wait) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
// Rerfresh the Hosts view on right side of page
|
// Rerfresh the Hosts view on right side of page
|
||||||
|
|
||||||
@@ -424,15 +424,13 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
|||||||
var url = (group_id !== null && group_id !== undefined) ? GetBasePath('groups') + group_id + '/all_hosts/' :
|
var url = (group_id !== null && group_id !== undefined) ? GetBasePath('groups') + group_id + '/all_hosts/' :
|
||||||
GetBasePath('inventory') + params.inventory_id + '/hosts/';
|
GetBasePath('inventory') + params.inventory_id + '/hosts/';
|
||||||
|
|
||||||
if (scope.hostFailureFilter) {
|
|
||||||
url += '?has_active_failures=true';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the groups value in each element of hosts array
|
// Set the groups value in each element of hosts array
|
||||||
if (scope.removePostRefresh) {
|
if (scope.removePostRefresh) {
|
||||||
scope.removePostRefresh();
|
scope.removePostRefresh();
|
||||||
}
|
}
|
||||||
scope.removePostRefresh = scope.$on('PostRefresh', function() {
|
scope.removePostRefresh = scope.$on('PostRefresh', function() {
|
||||||
|
|
||||||
|
// Add a list of groups to each host
|
||||||
var groups, descr, found, list;
|
var groups, descr, found, list;
|
||||||
for (var i=0; i < scope.hosts.length; i++) {
|
for (var i=0; i < scope.hosts.length; i++) {
|
||||||
groups = scope.hosts[i].summary_fields.groups;
|
groups = scope.hosts[i].summary_fields.groups;
|
||||||
@@ -444,14 +442,54 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
|||||||
}
|
}
|
||||||
scope.hosts[i].groups = scope.hosts[i].groups.replace(/\, $/,'');
|
scope.hosts[i].groups = scope.hosts[i].groups.replace(/\, $/,'');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the value displayed in Job Status column
|
||||||
|
for (var i=0; i < scope.hosts.length; i++) {
|
||||||
|
scope.hosts[i].activeFailuresLink = '/#/hosts/' + scope.hosts[i].id + '/job_host_summaries/?inventory=' + scope['inventory_id'] +
|
||||||
|
'&host_name=' + escape(scope.hosts[i].name);
|
||||||
|
if (scope.hosts[i].has_active_failures == true) {
|
||||||
|
scope.hosts[i].badgeToolTip = 'Most recent job failed. Click to view jobs.';
|
||||||
|
scope.hosts[i].active_failures = 'failed';
|
||||||
|
}
|
||||||
|
else if (scope.hosts[i].has_active_failures == false && scope.hosts[i].last_job == null) {
|
||||||
|
scope.hosts[i].has_active_failures = 'none';
|
||||||
|
scope.hosts[i].badgeToolTip = "No job data available.";
|
||||||
|
scope.hosts[i].active_failures = 'n/a';
|
||||||
|
}
|
||||||
|
else if (scope.hosts[i].has_active_failures == false && scope.hosts[i].last_job !== null) {
|
||||||
|
scope.hosts[i].badgeToolTip = "Most recent job successful. Click to view jobs.";
|
||||||
|
scope.hosts[i].active_failures = 'success';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (postAction) {
|
if (postAction) {
|
||||||
postAction();
|
postAction();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
SearchInit({ scope: scope, set: 'hosts', list: InventoryHostsForm, url: url });
|
SearchInit({ scope: scope, set: 'hosts', list: InventoryHostsForm, url: url });
|
||||||
PaginateInit({ scope: scope, list: InventoryHostsForm, url: url });
|
PaginateInit({ scope: scope, list: InventoryHostsForm, url: url });
|
||||||
scope.search('host');
|
|
||||||
|
if ($routeParams['has_active_failures']) {
|
||||||
|
//scope.resetSearch(InventoryHostsForm.iterator);
|
||||||
|
scope[InventoryHostsForm.iterator + 'InputDisable'] = true;
|
||||||
|
scope[InventoryHostsForm.iterator + 'SearchValue'] = $routeParams['has_active_failures'];
|
||||||
|
scope[InventoryHostsForm.iterator + 'SearchField'] = 'has_active_failures';
|
||||||
|
scope[InventoryHostsForm.iterator + 'SearchFieldLabel'] = InventoryHostsForm.fields['has_active_failures'].label;
|
||||||
|
scope[InventoryHostsForm.iterator + 'SearchSelectValue'] = ($routeParams['has_active_failures'] == 'true') ? { value: 1 } : { value: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($routeParams['name']) {
|
||||||
|
console.log('here!');
|
||||||
|
scope[InventoryHostsForm.iterator + 'InputDisable'] = false;
|
||||||
|
scope[InventoryHostsForm.iterator + 'SearchValue'] = $routeParams['name'];
|
||||||
|
scope[InventoryHostsForm.iterator + 'SearchField'] = 'name';
|
||||||
|
scope[InventoryHostsForm.iterator + 'SearchFieldLabel'] = InventoryHostsForm.fields['name'].label;
|
||||||
|
scope[InventoryHostsForm.iterator + 'SearchSelectValue'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.search(InventoryHostsForm.iterator);
|
||||||
|
|
||||||
if (!params.scope.$$phase) {
|
if (!params.scope.$$phase) {
|
||||||
params.scope.$digest();
|
params.scope.$digest();
|
||||||
@@ -467,6 +505,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
|||||||
var scope = params.scope;
|
var scope = params.scope;
|
||||||
var inventory_id = params.inventory_id;
|
var inventory_id = params.inventory_id;
|
||||||
var html = '';
|
var html = '';
|
||||||
|
var toolTip = 'Hosts have failed jobs?';
|
||||||
|
|
||||||
function buildHTML(tree_data) {
|
function buildHTML(tree_data) {
|
||||||
var sorted = SortNodes(tree_data);
|
var sorted = SortNodes(tree_data);
|
||||||
@@ -480,7 +519,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
|||||||
"data-group-id=\"" + sorted[i].id + "\" " +
|
"data-group-id=\"" + sorted[i].id + "\" " +
|
||||||
"><a href=\"\" class=\"expand\"><i class=\"icon-caret-down\"></i></a> " +
|
"><a href=\"\" class=\"expand\"><i class=\"icon-caret-down\"></i></a> " +
|
||||||
"<i class=\"field-badge icon-failures-" + sorted[i].has_active_failures + "\" " +
|
"<i class=\"field-badge icon-failures-" + sorted[i].has_active_failures + "\" " +
|
||||||
"aw-tool-tip=\"Indicates if group contains hosts with active failures\" data-placement=\"bottom\"></i> " +
|
"aw-tool-tip=\"" + toolTip + "\" data-placement=\"bottom\"></i> " +
|
||||||
"<a href=\"\" class=\"activate\">" + sorted[i].name + "</a> ";
|
"<a href=\"\" class=\"activate\">" + sorted[i].name + "</a> ";
|
||||||
if (sorted[i].children.length > 0) {
|
if (sorted[i].children.length > 0) {
|
||||||
buildHTML(sorted[i].children);
|
buildHTML(sorted[i].children);
|
||||||
@@ -651,7 +690,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
|||||||
"data-name=\"" + data.name + "\" " +
|
"data-name=\"" + data.name + "\" " +
|
||||||
"><a href=\"\" class=\"expand\"><i class=\"icon-caret-down\"></i></a> " +
|
"><a href=\"\" class=\"expand\"><i class=\"icon-caret-down\"></i></a> " +
|
||||||
"<i class=\"field-badge icon-failures-" + data.has_active_failures + "\"" +
|
"<i class=\"field-badge icon-failures-" + data.has_active_failures + "\"" +
|
||||||
"aw-tool-tip=\"Indicates if group contains hosts with active failures\" data-placement=\"bottom\"></i> " +
|
"aw-tool-tip=\"" + toolTip + "\" data-placement=\"bottom\"></i> " +
|
||||||
"<a href=\"\" class=\"activate active\">" + data.name + "</a>";
|
"<a href=\"\" class=\"activate active\">" + data.name + "</a>";
|
||||||
scope.$emit('buildAllGroups', data.name, data.related.tree, data.related.groups);
|
scope.$emit('buildAllGroups', data.name, data.related.tree, data.related.groups);
|
||||||
scope.$emit('refreshHost', null, 'All Hosts');
|
scope.$emit('refreshHost', null, 'All Hosts');
|
||||||
|
|||||||
40
awx/ui/static/js/helpers/Jobs.js
Normal file
40
awx/ui/static/js/helpers/Jobs.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*********************************************
|
||||||
|
* Copyright (c) 2013 AnsibleWorks, Inc.
|
||||||
|
*
|
||||||
|
* JobsHelper
|
||||||
|
*
|
||||||
|
* Routines shared by job related controllers
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
angular.module('JobsHelper', [ ])
|
||||||
|
.factory('JobStatusToolTip', [ function() {
|
||||||
|
return function(status) {
|
||||||
|
var toolTip;
|
||||||
|
switch (status) {
|
||||||
|
case 'successful':
|
||||||
|
case 'success':
|
||||||
|
toolTip = 'There were no failed tasks.';
|
||||||
|
break;
|
||||||
|
case 'failed':
|
||||||
|
toolTip = 'Some tasks encountered errors.';
|
||||||
|
break;
|
||||||
|
case 'canceled':
|
||||||
|
toolTip = 'Stopped by user request.';
|
||||||
|
break;
|
||||||
|
case 'new':
|
||||||
|
toolTip = 'In queue, waiting on task manager.';
|
||||||
|
break;
|
||||||
|
case 'waiting':
|
||||||
|
toolTip = 'SCM Update or Inventory Update is executing.';
|
||||||
|
break;
|
||||||
|
case 'pending':
|
||||||
|
toolTip = 'Not in queue, waiting on task manager.';
|
||||||
|
break;
|
||||||
|
case 'running':
|
||||||
|
toolTip = 'Playbook tasks executing.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return toolTip;
|
||||||
|
}
|
||||||
|
}]);
|
||||||
@@ -166,7 +166,6 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
|
|||||||
|
|
||||||
$(tree_id).bind('move_node.jstree', function(e, data) {
|
$(tree_id).bind('move_node.jstree', function(e, data) {
|
||||||
// When user drags-n-drops a node, update the API
|
// When user drags-n-drops a node, update the API
|
||||||
|
|
||||||
Wait('start');
|
Wait('start');
|
||||||
|
|
||||||
var node, target, url, parent, inv_id, variables;
|
var node, target, url, parent, inv_id, variables;
|
||||||
@@ -273,12 +272,11 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// When user clicks on a group
|
// When user clicks on a group
|
||||||
$(tree_id).bind("select_node.jstree", function(e, data){
|
$(tree_id).bind("select_node.jstree", function(e, data){
|
||||||
scope.$emit('NodeSelect', data.inst.get_json()[0]);
|
scope.$emit('NodeSelect', data.inst.get_json()[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Wait('start');
|
Wait('start');
|
||||||
LoadTreeData(params);
|
LoadTreeData(params);
|
||||||
|
|
||||||
|
|||||||
@@ -83,19 +83,57 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
|
|||||||
scope[iterator + 'SelectShow'] = false;
|
scope[iterator + 'SelectShow'] = false;
|
||||||
scope[iterator + 'HideSearchType'] = false;
|
scope[iterator + 'HideSearchType'] = false;
|
||||||
scope[iterator + 'InputHide'] = false;
|
scope[iterator + 'InputHide'] = false;
|
||||||
|
scope[iterator + 'InputDisable'] = false;
|
||||||
|
scope[iterator + 'SearchType'] = 'icontains';
|
||||||
|
|
||||||
if (list.fields[fld].searchType && list.fields[fld].searchType == 'gtzero') {
|
if (list.fields[fld].searchType && list.fields[fld].searchType == 'gtzero') {
|
||||||
scope[iterator + "InputHide"] = true;
|
scope[iterator + "InputHide"] = true;
|
||||||
}
|
}
|
||||||
if (list.fields[fld].searchType && (list.fields[fld].searchType == 'boolean'
|
else if (list.fields[fld].searchSingleValue){
|
||||||
|
// Query a specific attribute for one specific value
|
||||||
|
// searchSingleValue: true
|
||||||
|
// searchType: 'boolean|int|etc.'
|
||||||
|
// searchValue: < value to match for boolean use 'true'|'false' >
|
||||||
|
scope[iterator + "SearchType"] = list.fields[fld].searchType;
|
||||||
|
scope[iterator + 'InputDisable'] = true;
|
||||||
|
scope[iterator + "SearchValue"] = list.fields[fld].searchValue;
|
||||||
|
// For boolean type, SearchValue must be an object
|
||||||
|
if (list.fields[fld].searchType == 'boolean' && list.fields[fld].searchValue == 'true') {
|
||||||
|
scope[iterator + "SearchSelectValue"] = { value: 1 };
|
||||||
|
}
|
||||||
|
else if (list.fields[fld].searchType == 'boolean' && list.fields[fld].searchValue == 'false') {
|
||||||
|
scope[iterator + "SearchSelectValue"] = { value: 0 };
|
||||||
|
}
|
||||||
|
else if (list.fields[fld].searchType == 'boolean') {
|
||||||
|
scope[iterator + "SearchSelectValue"] = { value: list.fields[fld].searchValue };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (list.fields[fld].searchType && (list.fields[fld].searchType == 'boolean'
|
||||||
|| list.fields[fld].searchType == 'select')) {
|
|| list.fields[fld].searchType == 'select')) {
|
||||||
scope[iterator + 'SelectShow'] = true;
|
scope[iterator + 'SelectShow'] = true;
|
||||||
scope[iterator + 'SearchSelectOpts'] = list.fields[fld].searchOptions;
|
scope[iterator + 'SearchSelectOpts'] = list.fields[fld].searchOptions;
|
||||||
}
|
}
|
||||||
if (list.fields[fld].searchType && list.fields[fld].searchType == 'int') {
|
else if (list.fields[fld].searchType && list.fields[fld].searchType == 'int') {
|
||||||
scope[iterator + 'HideSearchType'] = true;
|
scope[iterator + 'HideSearchType'] = true;
|
||||||
|
}
|
||||||
|
scope.search(iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.resetSearch = function(iterator) {
|
||||||
|
// Respdond to click of reset button
|
||||||
|
scope[iterator + "SearchValue"] = '';
|
||||||
|
scope[iterator + "SearchSelectValue"] = '';
|
||||||
|
scope[iterator + 'SelectShow'] = false;
|
||||||
|
scope[iterator + 'HideSearchType'] = false;
|
||||||
|
scope[iterator + 'InputHide'] = false;
|
||||||
|
scope[iterator + 'InputDisable'] = false;
|
||||||
|
for (fld in list.fields) {
|
||||||
|
if (list.fields[fld].searchable == undefined || list.fields[fld].searchable == true) {
|
||||||
|
scope[iterator + 'SearchFieldLabel'] = list.fields[fld].label;
|
||||||
|
scope[iterator + 'SearchField'] = fld;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.search(iterator);
|
scope.search(iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,21 +21,37 @@ angular.module('InventoriesListDefinition', [])
|
|||||||
fields: {
|
fields: {
|
||||||
name: {
|
name: {
|
||||||
key: true,
|
key: true,
|
||||||
label: 'Name',
|
label: 'Name'
|
||||||
badgeIcon: "\{\{ 'icon-failures-' + inventory.has_active_failures \}\}",
|
|
||||||
badgePlacement: 'left',
|
|
||||||
badgeToolTip: 'Indicates if inventory contains hosts with active failures',
|
|
||||||
badgeTipPlacement: 'bottom'
|
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
label: 'Description'
|
label: 'Description',
|
||||||
|
link: true
|
||||||
|
},
|
||||||
|
hosts_with_active_failures: {
|
||||||
|
label: 'Hosts with<br>Failed Job?',
|
||||||
|
ngHref: '/#/inventories/{{ inventory.id }}/hosts{{ inventory.active_failures_params }}',
|
||||||
|
type: 'badgeCount',
|
||||||
|
"class": "{{ 'failures-' + inventory.has_active_failures }}",
|
||||||
|
//badgeIcon: "\{\{ 'icon-failures-' + inventory.has_active_failures \}\}",
|
||||||
|
//badgePlacement: 'left',
|
||||||
|
awToolTip: '# of hosts with failed jobs. Click to view hosts.',
|
||||||
|
dataPlacement: 'bottom',
|
||||||
|
searchable: false
|
||||||
},
|
},
|
||||||
organization: {
|
organization: {
|
||||||
label: 'Organization',
|
label: 'Organization',
|
||||||
ngBind: 'inventory.summary_fields.organization.name',
|
ngBind: 'inventory.summary_fields.organization.name',
|
||||||
|
linkTo: '/organizations/{{ inventory.organization }}',
|
||||||
sourceModel: 'organization',
|
sourceModel: 'organization',
|
||||||
sourceField: 'name',
|
sourceField: 'name',
|
||||||
excludeModal: true
|
excludeModal: true
|
||||||
|
},
|
||||||
|
has_active_failures: {
|
||||||
|
label: 'Hosts with failed jobs?',
|
||||||
|
searchSingleValue: true,
|
||||||
|
searchType: 'boolean',
|
||||||
|
searchValue: 'true',
|
||||||
|
searchOnly: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -25,27 +25,35 @@ angular.module('InventorySummaryDefinition', [])
|
|||||||
noLink: true,
|
noLink: true,
|
||||||
ngBind: "group.summary_fields.group.name",
|
ngBind: "group.summary_fields.group.name",
|
||||||
sourceModel: 'group',
|
sourceModel: 'group',
|
||||||
sourceField: 'name',
|
sourceField: 'name'
|
||||||
badges: [
|
|
||||||
{ //Active Failures
|
|
||||||
icon: "\{\{ 'icon-failures-' + group.summary_fields.group.has_active_failures \}\}",
|
|
||||||
toolTip: 'Indicates if inventory contains hosts with active failures',
|
|
||||||
toolTipPlacement: 'bottom'
|
|
||||||
},
|
|
||||||
{ //Cloud Status
|
|
||||||
icon: "\{\{ 'icon-cloud-' + group.status_class \}\}",
|
|
||||||
toolTip: 'Indicates status of inventory update process',
|
|
||||||
toolTipPlacement: 'bottom'
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
failures: {
|
hosts_with_active_failures: {
|
||||||
label: 'Active<br>Failures',
|
label: 'Hosts with<br>Job Failures?',
|
||||||
ngBind: "group.summary_fields.group.hosts_with_active_failures",
|
ngHref: '/#/inventories/{{ inventory_id }}/hosts{{ group.active_failures_params }}',
|
||||||
sourceModel: 'group',
|
type: 'badgeCount',
|
||||||
sourceField: 'hosts_with_active_failures',
|
"class": "{{ 'failures-' + group.has_active_failures }}",
|
||||||
searchField: 'group__has_active_failures',
|
awToolTip: '# of hosts with job failures. Click to view hosts.',
|
||||||
searchType: 'boolean',
|
dataPlacement: 'bottom',
|
||||||
searchOptions: [{ name: "yes", value: 1 }, { name: "no", value: 0 }]
|
searchable: false,
|
||||||
|
nosort: true
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
label: 'Update<br>Status',
|
||||||
|
searchType: 'select',
|
||||||
|
badgeIcon: 'icon-cloud',
|
||||||
|
badgeToolTip: "\{\{ group.status_badge_tooltip \}\}",
|
||||||
|
badgePlacement: 'left',
|
||||||
|
badgeClass: "\{\{ 'icon-cloud-' + group.status_badge_class \}\}",
|
||||||
|
searchOptions: [
|
||||||
|
{ name: "failed", value: "failed" },
|
||||||
|
{ name: "never", value: "never updated" },
|
||||||
|
{ name: "n/a", value: "none" },
|
||||||
|
{ name: "successful", value: "successful" },
|
||||||
|
{ name: "updating", value: "updating" }]
|
||||||
|
},
|
||||||
|
last_updated: {
|
||||||
|
label: 'Last<br>Updated',
|
||||||
|
searchable: false
|
||||||
},
|
},
|
||||||
source: {
|
source: {
|
||||||
label: 'Source',
|
label: 'Source',
|
||||||
@@ -56,25 +64,20 @@ angular.module('InventorySummaryDefinition', [])
|
|||||||
{ name: "Manual", value: "" },
|
{ name: "Manual", value: "" },
|
||||||
{ name: "Rackspace", value: "rackspace" }]
|
{ name: "Rackspace", value: "rackspace" }]
|
||||||
},
|
},
|
||||||
last_updated: {
|
has_active_failures: {
|
||||||
label: 'Last<br>Updated',
|
label: 'Hosts have job failures?',
|
||||||
searchable: false
|
searchSingleValue: true,
|
||||||
},
|
searchType: 'boolean',
|
||||||
status: {
|
searchValue: 'true',
|
||||||
label: 'Update<br>Status',
|
searchOnly: true,
|
||||||
searchType: 'select',
|
sourceModel: 'group',
|
||||||
searchOptions: [
|
sourceField: 'has_active_failures'
|
||||||
{ name: "failed", value: "failed" },
|
|
||||||
{ name: "never", value: "never updated" },
|
|
||||||
{ name: "n/a", value: "none" },
|
|
||||||
{ name: "successful", value: "successful" },
|
|
||||||
{ name: "updating", value: "updating" }]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
refresh: {
|
refresh: {
|
||||||
awRefresh: true,
|
awRefresh: false,
|
||||||
mode: 'all'
|
mode: 'all'
|
||||||
},
|
},
|
||||||
help: {
|
help: {
|
||||||
|
|||||||
@@ -48,14 +48,20 @@ angular.module('JobEventsListDefinition', [])
|
|||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
label: 'Status',
|
label: 'Status',
|
||||||
icon: 'icon-circle',
|
|
||||||
showValue: true,
|
showValue: true,
|
||||||
"class": 'job-\{\{ jobevent.status \}\}',
|
|
||||||
searchField: 'failed',
|
searchField: 'failed',
|
||||||
searchType: 'boolean',
|
searchType: 'boolean',
|
||||||
searchOptions: [{ name: "success", value: 0 }, { name: "error", value: 1 }],
|
searchOptions: [{ name: "success", value: 0 }, { name: "error", value: 1 }],
|
||||||
nosort: true,
|
nosort: true,
|
||||||
searchable: false
|
searchable: false,
|
||||||
|
ngClick: "viewJobEvent(\{\{ jobevent.id \}\})",
|
||||||
|
awToolTip: "\{\{ jobevent.statusBadgeToolTip \}\}",
|
||||||
|
dataPlacement: 'top',
|
||||||
|
badgeIcon: 'icon-job-\{\{ jobevent.status \}\}',
|
||||||
|
badgePlacement: 'left',
|
||||||
|
badgeToolTip: "\{\{ jobevent.statusBadgeToolTip \}\}",
|
||||||
|
badgeTipPlacement: 'top',
|
||||||
|
badgeNgClick: "viewJobEvent(\{\{ jobevent.id \}\})"
|
||||||
},
|
},
|
||||||
event_display: {
|
event_display: {
|
||||||
label: 'Event',
|
label: 'Event',
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ angular.module('JobHostDefinition', [])
|
|||||||
},
|
},
|
||||||
|
|
||||||
fields: {
|
fields: {
|
||||||
id: {
|
job: {
|
||||||
label: 'Job ID',
|
label: 'Job ID',
|
||||||
ngClick: "showJob(\{\{ jobhost.job \}\})",
|
ngClick: "showJob(\{\{ jobhost.job \}\})",
|
||||||
columnShow: 'host_id !== null',
|
columnShow: 'host_id !== null',
|
||||||
@@ -51,12 +51,18 @@ angular.module('JobHostDefinition', [])
|
|||||||
sourceModel: 'host',
|
sourceModel: 'host',
|
||||||
sourceField: 'name',
|
sourceField: 'name',
|
||||||
ngBind: 'jobhost.host_name',
|
ngBind: 'jobhost.host_name',
|
||||||
ngClick:"showEvents('\{\{ jobhost.summary_fields.host.name \}\}','\{\{ jobhost.related.job \}\}')"
|
ngHref: "\{\{ jobhost.hostLinkTo \}\}"
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
label: 'Status',
|
label: 'Status',
|
||||||
icon: 'icon-circle',
|
badgeNgHref: "\{\{ jobhost.statusLinkTo \}\}",
|
||||||
"class": 'job-\{\{ jobhost.status \}\}',
|
badgeIcon: 'icon-job-\{\{ jobhost.status \}\}',
|
||||||
|
badgePlacement: 'left',
|
||||||
|
badgeToolTip: "\{\{ jobhost.statusBadgeToolTip \}\}",
|
||||||
|
badgeTipPlacement: 'top',
|
||||||
|
ngHref: "\{\{ jobhost.statusLinkTo \}\}",
|
||||||
|
awToolTip: "\{\{ jobhost.statusBadgeToolTip \}\}",
|
||||||
|
dataPlacement: 'top',
|
||||||
searchField: 'failed',
|
searchField: 'failed',
|
||||||
searchType: 'boolean',
|
searchType: 'boolean',
|
||||||
searchOptions: [{ name: "success", value: 0 }, { name: "error", value: 1 }]
|
searchOptions: [{ name: "success", value: 0 }, { name: "error", value: 1 }]
|
||||||
|
|||||||
@@ -37,15 +37,15 @@ angular.module('JobsListDefinition', [])
|
|||||||
job_template: {
|
job_template: {
|
||||||
label: 'Job Template',
|
label: 'Job Template',
|
||||||
ngBind: 'job.summary_fields.job_template.name',
|
ngBind: 'job.summary_fields.job_template.name',
|
||||||
link: true,
|
ngHref: "\{\{ '/#/job_templates/?name=' + job.summary_fields.job_template.name \}\}",
|
||||||
sourceModel: 'job_template',
|
sourceModel: 'job_template',
|
||||||
sourceField: 'name'
|
sourceField: 'name'
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
label: 'Status',
|
label: 'Status',
|
||||||
icon: 'icon-circle',
|
|
||||||
"class": 'job-\{\{ job.status \}\}',
|
"class": 'job-\{\{ job.status \}\}',
|
||||||
searchType: 'select',
|
searchType: 'select',
|
||||||
|
linkTo: "\{\{ job.statusLinkTo \}\}",
|
||||||
searchOptions: [
|
searchOptions: [
|
||||||
{ name: "new", value: "new" },
|
{ name: "new", value: "new" },
|
||||||
{ name: "waiting", value: "waiting" },
|
{ name: "waiting", value: "waiting" },
|
||||||
@@ -54,7 +54,14 @@ angular.module('JobsListDefinition', [])
|
|||||||
{ name: "successful", value: "successful" },
|
{ name: "successful", value: "successful" },
|
||||||
{ name: "error", value: "error" },
|
{ name: "error", value: "error" },
|
||||||
{ name: "failed", value: "failed" },
|
{ name: "failed", value: "failed" },
|
||||||
{ name: "canceled", value: "canceled" } ]
|
{ name: "canceled", value: "canceled" } ],
|
||||||
|
badgeIcon: 'icon-job-\{\{ job.status \}\}',
|
||||||
|
badgePlacement: 'left',
|
||||||
|
badgeToolTip: "\{\{ job.statusBadgeToolTip \}\}",
|
||||||
|
badgeTipPlacement: 'top',
|
||||||
|
badgeNgHref: "\{\{ job.statusLinkTo \}\}",
|
||||||
|
awToolTip: "\{\{ job.statusBadgeToolTip \}\}",
|
||||||
|
dataPlacement: 'top'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,12 @@
|
|||||||
|
|
||||||
@black: #171717;
|
@black: #171717;
|
||||||
@warning: #FF9900;
|
@warning: #FF9900;
|
||||||
@red: #FF0000;
|
@red: #da4f49;;
|
||||||
@green: #5bb75b;
|
@green: #5bb75b;
|
||||||
@blue: #1778c3; /* logo blue */
|
@blue: #1778c3; /* logo blue */
|
||||||
@blue-link: #0088cc;
|
@blue-link: #0088cc;
|
||||||
@grey: #A9A9A9;
|
@grey: #A9A9A9;
|
||||||
|
@green: #5bb75b;
|
||||||
|
|
||||||
html {
|
html {
|
||||||
background-color: @black;
|
background-color: @black;
|
||||||
@@ -32,6 +33,7 @@ body {
|
|||||||
.no-bullets { list-style: none; }
|
.no-bullets { list-style: none; }
|
||||||
.capitalize { text-transform: capitalize; }
|
.capitalize { text-transform: capitalize; }
|
||||||
.grey-txt { color: @grey; }
|
.grey-txt { color: @grey; }
|
||||||
|
.text-center { text-align: center !important; }
|
||||||
|
|
||||||
.success-badge {
|
.success-badge {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
@@ -92,10 +94,6 @@ body {
|
|||||||
z-index: 1050;
|
z-index: 1050;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-center {
|
|
||||||
text-align: center !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
border-color: #e3e3e3;
|
border-color: #e3e3e3;
|
||||||
}
|
}
|
||||||
@@ -607,8 +605,6 @@ select.field-mini-height {
|
|||||||
|
|
||||||
/* Jobs pages */
|
/* Jobs pages */
|
||||||
|
|
||||||
.job-error,
|
|
||||||
.job-failed,
|
|
||||||
.license-expired,
|
.license-expired,
|
||||||
.license-invalid,
|
.license-invalid,
|
||||||
.icon-failures-true,
|
.icon-failures-true,
|
||||||
@@ -633,33 +629,87 @@ select.field-mini-height {
|
|||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.job-new,
|
|
||||||
input[type="text"].job-new,
|
input[type="text"].job-new,
|
||||||
.job-canceled,
|
|
||||||
input[type="text"].job-canceled {
|
input[type="text"].job-canceled {
|
||||||
color: #778899;
|
color: #778899;
|
||||||
}
|
}
|
||||||
|
|
||||||
.job-pending,
|
|
||||||
.job-running,
|
|
||||||
.job-success,
|
|
||||||
.job-successful,
|
|
||||||
.job-waiting,
|
|
||||||
.icon-failures-false,
|
.icon-failures-false,
|
||||||
.license-valid,
|
.license-valid,
|
||||||
input[type="text"].job-success,
|
input[type="text"].job-success,
|
||||||
input[type="text"].job-successful {
|
input[type="text"].job-successful {
|
||||||
color: #5bb75b;
|
color: @green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-job-pending:before,
|
||||||
|
.icon-job-running:before,
|
||||||
|
.icon-job-success:before,
|
||||||
|
.icon-job-successful:before,
|
||||||
|
.icon-job-waiting:before,
|
||||||
|
.icon-job-new:before,
|
||||||
|
.icon-job-canceled:before,
|
||||||
|
.icon-job-changed:before {
|
||||||
|
content: "\f111";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-job-error:before,
|
||||||
|
.icon-job-failed:before {
|
||||||
|
content: "\f06a";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-job-pending,
|
||||||
|
.icon-job-running,
|
||||||
|
.icon-job-success,
|
||||||
|
.icon-job-successful,
|
||||||
|
.icon-job-waiting,
|
||||||
|
.icon-job-new {
|
||||||
|
color: @green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-job-canceled {
|
||||||
|
color: @grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-job-changed {
|
||||||
|
color: @warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-job-error,
|
||||||
|
.icon-job-failed {
|
||||||
|
color: @red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-failures-none {
|
||||||
|
color: @grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-failures-true:before {
|
.icon-failures-true:before {
|
||||||
content: "\f06a";
|
content: "\f06a";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-failures-none:before,
|
||||||
.icon-failures-false:before {
|
.icon-failures-false:before {
|
||||||
content: "\f111";
|
content: "\f111";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
padding: 3px 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inventory job status badge */
|
||||||
|
.failures-true {
|
||||||
|
background-color: @red;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.failures-false {
|
||||||
|
background-color: @green;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
/* Cloud inventory status. i.e. inventory_source.status values */
|
/* Cloud inventory status. i.e. inventory_source.status values */
|
||||||
|
|
||||||
@@ -671,7 +721,7 @@ select.field-mini-height {
|
|||||||
content: "\f0c2";
|
content: "\f0c2";
|
||||||
}
|
}
|
||||||
.icon-cloud-na {
|
.icon-cloud-na {
|
||||||
color: #e3e3e3;
|
color: #888;
|
||||||
}
|
}
|
||||||
.icon-cloud-never {
|
.icon-cloud-never {
|
||||||
color: #888;
|
color: #888;
|
||||||
@@ -684,7 +734,6 @@ select.field-mini-height {
|
|||||||
color: @red;
|
color: @red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.field-success {
|
.field-success {
|
||||||
color: #5bb75b;
|
color: #5bb75b;
|
||||||
}
|
}
|
||||||
@@ -702,11 +751,10 @@ select.field-mini-height {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.field-badge {
|
.field-badge {
|
||||||
font-size: 12px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.job-changed,
|
.license-warning
|
||||||
.license-warning,
|
|
||||||
.license-demo {
|
.license-demo {
|
||||||
color: @warning;
|
color: @warning;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1272,7 +1272,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
|
|||||||
|
|
||||||
html += "<div class=\"hosts-well well\">\n";
|
html += "<div class=\"hosts-well well\">\n";
|
||||||
|
|
||||||
html += SearchWidget({ iterator: form.iterator, template: form, mini: true, size: 'col-md-6 col-lg-6'});
|
html += SearchWidget({ iterator: form.iterator, template: form, mini: true, size: 'col-md-5 col-lg-5'});
|
||||||
|
|
||||||
html += "<div class=\"col-md-5 col-lg-5\">\n"
|
html += "<div class=\"col-md-5 col-lg-5\">\n"
|
||||||
html += "<div class=\"pull-right\">\n";
|
html += "<div class=\"pull-right\">\n";
|
||||||
@@ -1309,26 +1309,28 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
|
|||||||
html += "<tr>\n";
|
html += "<tr>\n";
|
||||||
|
|
||||||
for (var fld in form.fields) {
|
for (var fld in form.fields) {
|
||||||
html += "<th class=\"list-header\" id=\"" + fld + "-header\" ";
|
if (form.fields[fld].searchOnly == undefined || form.fields[fld].searchOnly == false) {
|
||||||
html += (!form.fields[fld].nosort) ? "ng-click=\"sort('"+ fld + "')\"" : "";
|
html += "<th class=\"list-header\" id=\"" + fld + "-header\" ";
|
||||||
html += ">";
|
html += (!form.fields[fld].nosort) ? "ng-click=\"sort('"+ fld + "')\"" : "";
|
||||||
html += (form['fields'][fld].label && form['fields'][fld].type !== 'DropDown') ? form['fields'][fld].label : '';
|
html += ">";
|
||||||
if (form.fields[fld].nosort == undefined || form.fields[fld].nosort == false) {
|
html += (form['fields'][fld].label && form['fields'][fld].type !== 'DropDown') ? form['fields'][fld].label : '';
|
||||||
html += " <i class=\"";
|
if (form.fields[fld].nosort == undefined || form.fields[fld].nosort == false) {
|
||||||
if (form.fields[fld].key) {
|
html += " <i class=\"";
|
||||||
if (form.fields[fld].desc) {
|
if (form.fields[fld].key) {
|
||||||
html += "icon-sort-down";
|
if (form.fields[fld].desc) {
|
||||||
}
|
html += "icon-sort-down";
|
||||||
else {
|
}
|
||||||
html += "icon-sort-up";
|
else {
|
||||||
}
|
html += "icon-sort-up";
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
html += "icon-sort";
|
else {
|
||||||
}
|
html += "icon-sort";
|
||||||
html += "\"></i>";
|
}
|
||||||
|
html += "\"></i>";
|
||||||
|
}
|
||||||
|
html += "</th>\n";
|
||||||
}
|
}
|
||||||
html += "</th>\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html += "<th></th>\n";
|
html += "<th></th>\n";
|
||||||
@@ -1349,11 +1351,11 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
|
|||||||
rfield = form.fields[fld];
|
rfield = form.fields[fld];
|
||||||
if (fld == 'groups' ) {
|
if (fld == 'groups' ) {
|
||||||
// generate group form control/button widget
|
// generate group form control/button widget
|
||||||
html += "<td>";
|
html += "<td class=\"col-lg-5 col-md-4 col-sm-3\">";
|
||||||
html += "<div class=\"input-group input-group-sm\">\n";
|
html += "<div class=\"input-group input-group-sm\">\n";
|
||||||
html += "<span class=\"input-group-btn\">\n";
|
html += "<span class=\"input-group-btn\">\n";
|
||||||
html += "<button class=\"btn btn-default\" type=\"button\" id=\"edit_groups_btn\" ng-click=\"editHostGroups({{ host.id }})\" " +
|
html += "<button class=\"btn btn-default\" type=\"button\" id=\"edit_groups_btn\" ng-click=\"editHostGroups({{ host.id }})\" " +
|
||||||
"aw-tool-tip=\"Change group associations for this host\" data-placement=\"top\" >" +
|
"aw-tool-tip=\"Edit group associations\" data-placement=\"top\" >" +
|
||||||
"<i class=\"icon-sitemap\"></i></button>\n";
|
"<i class=\"icon-sitemap\"></i></button>\n";
|
||||||
html += "</span>\n";
|
html += "</span>\n";
|
||||||
html += "<input type=\"text\" id=\"host_groups\" ng-model=\"host.groups\" class=\"form-control\" disabled=\"disabled\" >\n";
|
html += "<input type=\"text\" id=\"host_groups\" ng-model=\"host.groups\" class=\"form-control\" disabled=\"disabled\" >\n";
|
||||||
@@ -1361,7 +1363,9 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
|
|||||||
html += "</td>\n";
|
html += "</td>\n";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
html += Column({ list: form, fld: fld, options: options, base: null });
|
if (form.fields[fld].searchOnly == undefined || form.fields[fld].searchOnly == false) {
|
||||||
|
html += Column({ list: form, fld: fld, options: options, base: null });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1404,12 +1408,14 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
|
|||||||
html += "</table>\n";
|
html += "</table>\n";
|
||||||
html += "</div>\n"; // close list
|
html += "</div>\n"; // close list
|
||||||
|
|
||||||
|
/*
|
||||||
html += "<div class=\"row host-failure-filter\">\n";
|
html += "<div class=\"row host-failure-filter\">\n";
|
||||||
html += "<div class=\"col-lg-12\">\n";
|
html += "<div class=\"col-lg-12\">\n";
|
||||||
html += "<label class=\"checkbox-inline pull-right\"><input type=\"checkbox\" ng-model=\"hostFailureFilter\" ng-change=\"filterHosts()\" > Only show hosts with failed jobs" +
|
html += "<label class=\"checkbox-inline pull-right\"><input type=\"checkbox\" ng-model=\"hostFailureFilter\" ng-change=\"filterHosts()\" > Only show hosts with failed jobs" +
|
||||||
"</label>\n";
|
"</label>\n";
|
||||||
html += "</div>\n";
|
html += "</div>\n";
|
||||||
html += "</div>\n";
|
html += "</div>\n";
|
||||||
|
*/
|
||||||
|
|
||||||
html += "</div>\n"; // close well
|
html += "</div>\n"; // close well
|
||||||
|
|
||||||
|
|||||||
@@ -186,7 +186,13 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
|||||||
|
|
||||||
var name = field['label'].replace(/ /g,'_');
|
var name = field['label'].replace(/ /g,'_');
|
||||||
|
|
||||||
html = (params.td == undefined || params.td !== false) ? "<td>\n" : "";
|
if (params.td == undefined || params.td !== false) {
|
||||||
|
html = "<td class=\"" + fld + "-column\">\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
html = '';
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
html += "<div class=\"btn-group\">\n";
|
html += "<div class=\"btn-group\">\n";
|
||||||
html += "<button type=\"button\" ";
|
html += "<button type=\"button\" ";
|
||||||
@@ -218,19 +224,49 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
|||||||
html += (field.options[i].ngHide) ? "ng-hide=\"" + field.options[i].ngHide + "\" " : "";
|
html += (field.options[i].ngHide) ? "ng-hide=\"" + field.options[i].ngHide + "\" " : "";
|
||||||
html += "href=\"\">" + field.options[i].label + "</a></li>\n";
|
html += "href=\"\">" + field.options[i].label + "</a></li>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
html += "</ul>\n";
|
html += "</ul>\n";
|
||||||
html += "</div>\n";
|
html += "</div>\n";
|
||||||
|
|
||||||
html += (params.td == undefined || params.td !== false) ? "</td>\n" : "";
|
html += (params.td == undefined || params.td !== false) ? "</td>\n" : "";
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
|
|
||||||
}
|
}
|
||||||
}])
|
}])
|
||||||
|
|
||||||
|
.factory('BadgeCount', [ function() {
|
||||||
|
return function(params) {
|
||||||
|
|
||||||
|
// Adds a badge count with optional tooltip
|
||||||
|
|
||||||
|
var list = params['list'];
|
||||||
|
var fld = params['fld'];
|
||||||
|
var field = list.fields[fld];
|
||||||
|
var options = params['options'];
|
||||||
|
var base = params['base'];
|
||||||
|
var html = "<td class=\"" + fld + "-column"
|
||||||
|
html += (field.columnClass) ? " " + field.columnClass : "";
|
||||||
|
html += "\">\n";
|
||||||
|
html += "<a ng-href=\"" + field.ngHref + "\" aw-tool-tip=\"" + field.awToolTip + "\"";
|
||||||
|
html += (field.dataPlacement) ? " data-placement=\"" + field.dataPlacement + "\"" : "";
|
||||||
|
html += ">";
|
||||||
|
html += "<span class=\"badge";
|
||||||
|
html += (field['class']) ? " " + field['class'] : "";
|
||||||
|
html += "\">";
|
||||||
|
html += "\{\{ " + list.iterator + '.' + fld + " \}\}";
|
||||||
|
html += "</span>";
|
||||||
|
html += (field.badgeLabel) ? " " + field.badgeLabel : "";
|
||||||
|
html += "</a>\n";
|
||||||
|
html += "</td>\n";
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
|
||||||
.factory('Badge', [ function() {
|
.factory('Badge', [ function() {
|
||||||
return function(field) {
|
return function(field) {
|
||||||
|
|
||||||
|
// Adds an icon(s) with optional tooltip
|
||||||
|
|
||||||
var html = '';
|
var html = '';
|
||||||
|
|
||||||
if (field.badges) {
|
if (field.badges) {
|
||||||
@@ -254,7 +290,10 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (field.badgeToolTip) {
|
if (field.badgeToolTip) {
|
||||||
html += "<a href=\"\" aw-tool-tip=\"" + field.badgeToolTip + "\"";
|
html += "<a ";
|
||||||
|
html += (field.badgeNgHref) ? "ng-href=\"" + field.badgeNgHref + "\" " : "href=\"\"";
|
||||||
|
html += (field.ngClick) ? "ng-click=\"" + field.ngClick + "\" " : "";
|
||||||
|
html += " aw-tool-tip=\"" + field.badgeToolTip + "\"";
|
||||||
html += (field.badgeTipPlacement) ? " data-placement=\"" + field.badgeTipPlacement + "\"" : "";
|
html += (field.badgeTipPlacement) ? " data-placement=\"" + field.badgeTipPlacement + "\"" : "";
|
||||||
html += (field.badgeShow) ? " ng-show=\"" + field.badgeShow + "\"" : "";
|
html += (field.badgeShow) ? " ng-show=\"" + field.badgeShow + "\"" : "";
|
||||||
html += ">";
|
html += ">";
|
||||||
@@ -275,7 +314,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
|||||||
}
|
}
|
||||||
}])
|
}])
|
||||||
|
|
||||||
.factory('Column', ['Attr', 'Icon', 'DropDown', 'Badge', function(Attr, Icon, DropDown, Badge) {
|
.factory('Column', ['Attr', 'Icon', 'DropDown', 'Badge', 'BadgeCount', function(Attr, Icon, DropDown, Badge, BadgeCount) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var list = params['list'];
|
var list = params['list'];
|
||||||
var fld = params['fld'];
|
var fld = params['fld'];
|
||||||
@@ -288,6 +327,9 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
|||||||
if (field.type !== undefined && field.type == 'DropDown') {
|
if (field.type !== undefined && field.type == 'DropDown') {
|
||||||
html = DropDown(params);
|
html = DropDown(params);
|
||||||
}
|
}
|
||||||
|
else if (field.type == 'badgeCount') {
|
||||||
|
html = BadgeCount(params);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
html += "<td class=\"" + fld + "-column";
|
html += "<td class=\"" + fld + "-column";
|
||||||
html += (field['class']) ? " " + field['class'] : "";
|
html += (field['class']) ? " " + field['class'] : "";
|
||||||
@@ -314,17 +356,21 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the Link
|
// Start the Link
|
||||||
if ( (field.key || field.link || field.linkTo || field.ngClick ) &&
|
if ( (field.key || field.link || field.linkTo || field.ngClick || field.ngHref) &&
|
||||||
options['mode'] != 'lookup' && options['mode'] != 'select' && !field.noLink ) {
|
options['mode'] != 'lookup' && options['mode'] != 'select' && !field.noLink ) {
|
||||||
var cap=false;
|
var cap=false;
|
||||||
if (field.linkTo) {
|
if (field.linkTo) {
|
||||||
html += "<a href=\"#" + field.linkTo + "\" ";
|
html += "<a href=\"" + field.linkTo + "\" ";
|
||||||
cap = true;
|
cap = true;
|
||||||
}
|
}
|
||||||
else if (field.ngClick) {
|
else if (field.ngClick) {
|
||||||
html += "<a href=\"\"" + Attr(field, 'ngClick') + " ";
|
html += "<a href=\"\"" + Attr(field, 'ngClick') + " ";
|
||||||
cap = true;
|
cap = true;
|
||||||
}
|
}
|
||||||
|
else if (field.ngHref) {
|
||||||
|
html += "<a ng-href=\"" + field.ngHref + "\" ";
|
||||||
|
cap = true;
|
||||||
|
}
|
||||||
else if (field.link || (field.key && (field.link === undefined || field.link))) {
|
else if (field.link || (field.key && (field.link === undefined || field.link))) {
|
||||||
html += "<a href=\"#/" + base + "/{{" + list.iterator + ".id }}\" ";
|
html += "<a href=\"#/" + base + "/{{" + list.iterator + ".id }}\" ";
|
||||||
cap = true;
|
cap = true;
|
||||||
@@ -368,7 +414,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// close the link
|
// close the link
|
||||||
if ( (field.key || field.link || field.linkTo || field.ngClick )
|
if ( (field.key || field.link || field.linkTo || field.ngClick || field.ngHref )
|
||||||
&& options.mode != 'lookup' && options.mode != 'select' && !field.noLink ) {
|
&& options.mode != 'lookup' && options.mode != 'select' && !field.noLink ) {
|
||||||
html += "</a>";
|
html += "</a>";
|
||||||
}
|
}
|
||||||
@@ -458,7 +504,6 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
|||||||
//html += "</a>\n";
|
//html += "</a>\n";
|
||||||
|
|
||||||
html += "<ul class=\"dropdown-menu\" id=\"" + iterator + "SearchDropdown\">\n";
|
html += "<ul class=\"dropdown-menu\" id=\"" + iterator + "SearchDropdown\">\n";
|
||||||
|
|
||||||
for ( var fld in form.fields) {
|
for ( var fld in form.fields) {
|
||||||
if (form.fields[fld].searchable == undefined || form.fields[fld].searchable == true) {
|
if (form.fields[fld].searchable == undefined || form.fields[fld].searchable == true) {
|
||||||
html += "<li><a href=\"\" ng-click=\"setSearchField('" + iterator + "','";
|
html += "<li><a href=\"\" ng-click=\"setSearchField('" + iterator + "','";
|
||||||
@@ -475,8 +520,9 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
|||||||
|
|
||||||
html += "<input id=\"search_value_input\" type=\"text\" ng-hide=\"" + iterator + "SelectShow || " + iterator + "InputHide\" class=\"form-control ";
|
html += "<input id=\"search_value_input\" type=\"text\" ng-hide=\"" + iterator + "SelectShow || " + iterator + "InputHide\" class=\"form-control ";
|
||||||
html += "\" ng-model=\"" + iterator + "SearchValue\" ng-change=\"search('" + iterator +
|
html += "\" ng-model=\"" + iterator + "SearchValue\" ng-change=\"search('" + iterator +
|
||||||
"')\" placeholder=\"Search\" type=\"text\" >\n";
|
"')\" placeholder=\"Search\" type=\"text\" ng-disabled=\"" + iterator + "InputDisable\">\n";
|
||||||
|
|
||||||
|
/*
|
||||||
html += "<div class=\"input-group-btn dropdown\">\n";
|
html += "<div class=\"input-group-btn dropdown\">\n";
|
||||||
html += "<button type=\"button\" ";
|
html += "<button type=\"button\" ";
|
||||||
html += "id=\"search_option_ddown\" ";
|
html += "id=\"search_option_ddown\" ";
|
||||||
@@ -490,7 +536,17 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
|||||||
html += "<li><a href=\"\" ng-click=\"setSearchType('" + iterator + "','icontains','Contains')\">Contains</a></li>\n";
|
html += "<li><a href=\"\" ng-click=\"setSearchType('" + iterator + "','icontains','Contains')\">Contains</a></li>\n";
|
||||||
html += "</ul>\n";
|
html += "</ul>\n";
|
||||||
html += "</div><!-- input-group-btn -->\n";
|
html += "</div><!-- input-group-btn -->\n";
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Reset button
|
||||||
|
html += "<div class=\"input-group-btn\">\n";
|
||||||
|
html += "<button type=\"button\" class=\"btn btn-default btn-small\" ng-click=\"resetSearch('" + iterator + "')\" " +
|
||||||
|
"aw-tool-tip=\"Reset filter\" data-placement=\"top\" " +
|
||||||
|
"><i class=\"icon-undo\"></i></button>\n";
|
||||||
|
html += "</div><!-- input-group-btn -->\n";
|
||||||
html += "</div><!-- input-group -->\n";
|
html += "</div><!-- input-group -->\n";
|
||||||
|
|
||||||
html += "</div><!-- col-lg-x -->\n";
|
html += "</div><!-- col-lg-x -->\n";
|
||||||
html += "<div class=\"col-lg-1 col-md-1 col-sm-1 col-xs-1\"><i class=\"icon-spinner icon-spin icon-large\" ng-show=\"" + iterator +
|
html += "<div class=\"col-lg-1 col-md-1 col-sm-1 col-xs-1\"><i class=\"icon-spinner icon-spin icon-large\" ng-show=\"" + iterator +
|
||||||
"SearchSpin == true\"></i></div>\n";
|
"SearchSpin == true\"></i></div>\n";
|
||||||
|
|||||||
@@ -224,10 +224,10 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list.name == 'inventories' && options.mode !== 'select') {
|
/*if (list.name == 'inventories' && options.mode !== 'select') {
|
||||||
html += "<label class=\"checkbox-inline pull-right\"><input type=\"checkbox\" ng-model=\"inventoryFailureFilter\" " +
|
html += "<label class=\"checkbox-inline pull-right\"><input type=\"checkbox\" ng-model=\"inventoryFailureFilter\" " +
|
||||||
"ng-change=\"search('inventory')\" id=\"failed_jobs_chbox\"> Show only inventories with failed jobs</label>\n";
|
"ng-change=\"search('inventory')\" id=\"failed_jobs_chbox\"> Show only inventories with failed jobs</label>\n";
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//select instructions
|
//select instructions
|
||||||
if (options.mode == 'select' && list.selectInstructions) {
|
if (options.mode == 'select' && list.selectInstructions) {
|
||||||
|
|||||||
@@ -106,6 +106,7 @@
|
|||||||
<script src="{{ STATIC_URL }}js/helpers/Selection.js"></script>
|
<script src="{{ STATIC_URL }}js/helpers/Selection.js"></script>
|
||||||
<script src="{{ STATIC_URL }}js/helpers/Projects.js"></script>
|
<script src="{{ STATIC_URL }}js/helpers/Projects.js"></script>
|
||||||
<script src="{{ STATIC_URL }}js/helpers/Users.js"></script>
|
<script src="{{ STATIC_URL }}js/helpers/Users.js"></script>
|
||||||
|
<script src="{{ STATIC_URL }}js/helpers/Jobs.js"></script>
|
||||||
<script src="{{ STATIC_URL }}js/widgets/ObjectCount.js"></script>
|
<script src="{{ STATIC_URL }}js/widgets/ObjectCount.js"></script>
|
||||||
|
|
||||||
<script src="{{ STATIC_URL }}lib/less/less-1.4.1.min.js"></script>
|
<script src="{{ STATIC_URL }}lib/less/less-1.4.1.min.js"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user