mirror of
https://github.com/ansible/awx.git
synced 2026-03-14 07:27:28 -02:30
Merge branch 'release_3.0.0' of github.com:ansible/ansible-tower into JobDetailHostEvents
This commit is contained in:
@@ -15,13 +15,13 @@
|
||||
multiSelectExtended: true,
|
||||
index: false,
|
||||
hover: true,
|
||||
|
||||
emptyListText : 'No Teams exist',
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'name'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
multiSelectExtended: true,
|
||||
index: false,
|
||||
hover: true,
|
||||
emptyListText : 'No Users exist',
|
||||
|
||||
fields: {
|
||||
first_name: {
|
||||
|
||||
@@ -23,7 +23,7 @@ export default
|
||||
return i.role;
|
||||
}))
|
||||
.filter((role) => {
|
||||
return !!attrs.teamRoleList == !!role.team_id;
|
||||
return Boolean(attrs.teamRoleList) === Boolean(role.team_id);
|
||||
})
|
||||
.sort((a, b) => {
|
||||
if (a.name
|
||||
|
||||
@@ -79,6 +79,7 @@ __deferLoadIfEnabled();
|
||||
|
||||
var tower = angular.module('Tower', [
|
||||
//'ngAnimate',
|
||||
'lrInfiniteScroll',
|
||||
'ngSanitize',
|
||||
'ngCookies',
|
||||
about.name,
|
||||
@@ -269,7 +270,7 @@ var tower = angular.module('Tower', [
|
||||
}).
|
||||
|
||||
state('projects', {
|
||||
url: '/projects',
|
||||
url: '/projects?{status}',
|
||||
templateUrl: urlPrefix + 'partials/projects.html',
|
||||
controller: ProjectsList,
|
||||
data: {
|
||||
@@ -297,6 +298,10 @@ var tower = angular.module('Tower', [
|
||||
controller: ProjectsEdit,
|
||||
data: {
|
||||
activityStreamId: 'id'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: 'projects',
|
||||
label: 'EDIT PROJECT'
|
||||
}
|
||||
}).
|
||||
state('projectOrganizations', {
|
||||
@@ -340,6 +345,10 @@ var tower = angular.module('Tower', [
|
||||
controller: TeamsEdit,
|
||||
data: {
|
||||
activityStreamId: 'team_id'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: "teams",
|
||||
label: "EDIT TEAM"
|
||||
}
|
||||
}).
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ export default
|
||||
var licenseInfo = FeaturesService.getLicenseInfo();
|
||||
scope.licenseType = licenseInfo ? licenseInfo.license_type : null;
|
||||
if (!licenseInfo) {
|
||||
console.warn("License info not loaded correctly");
|
||||
console.warn("License info not loaded correctly"); // jshint ignore:line
|
||||
}
|
||||
})
|
||||
.catch(function (response) {
|
||||
|
||||
@@ -22,7 +22,7 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $stateParams,
|
||||
Wait('start');
|
||||
|
||||
var list = ProjectList,
|
||||
defaultUrl = GetBasePath('projects'),
|
||||
defaultUrl = GetBasePath('projects') + ($stateParams.status ? '?status=' + $stateParams.status : ''),
|
||||
view = GenerateList,
|
||||
base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
mode = (base === 'projects') ? 'edit' : 'select',
|
||||
@@ -495,6 +495,35 @@ export function ProjectsAdd(Refresh, $scope, $rootScope, $compile, $location, $l
|
||||
$scope.scmRequired = ($scope.scm_type.value !== 'manual') ? true : false;
|
||||
$scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? 'Revision #' : 'SCM Branch';
|
||||
}
|
||||
|
||||
// Dynamically update popover values
|
||||
if($scope.scm_type.value) {
|
||||
switch ($scope.scm_type.value) {
|
||||
case 'git':
|
||||
$scope.urlPopover = '<p>Example URLs for GIT SCM include:</p><ul class=\"no-bullets\"><li>https://github.com/ansible/ansible.git</li>' +
|
||||
'<li>git@github.com:ansible/ansible.git</li><li>git://servername.example.com/ansible.git</li></ul>' +
|
||||
'<p><strong>Note:</strong> When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, ' +
|
||||
'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' +
|
||||
'SSH. GIT read only protocol (git://) does not use username or password information.';
|
||||
break;
|
||||
case 'svn':
|
||||
$scope.urlPopover = '<p>Example URLs for Subversion SCM include:</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://github.com/ansible/ansible</li><li>svn://servername.example.com/path</li>' +
|
||||
'<li>svn+ssh://servername.example.com/path</li></ul>';
|
||||
break;
|
||||
case 'hg':
|
||||
$scope.urlPopover = '<p>Example URLs for Mercurial SCM include:</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://bitbucket.org/username/project</li><li>ssh://hg@bitbucket.org/username/project</li>' +
|
||||
'<li>ssh://server.example.com/path</li></ul>' +
|
||||
'<p><strong>Note:</strong> Mercurial does not support password authentication for SSH. ' +
|
||||
'Do not put the username and key in the URL. ' +
|
||||
'If using Bitbucket and SSH, do not supply your Bitbucket username.';
|
||||
break;
|
||||
default:
|
||||
$scope.urlPopover = '<p> URL popover text';
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$scope.formCancel = function () {
|
||||
|
||||
@@ -162,7 +162,7 @@ export function UsersAdd($scope, $rootScope, $compile, $location, $log,
|
||||
generator.reset();
|
||||
|
||||
$scope.user_type_options = user_type_options;
|
||||
$scope.user_type = user_type_options[0]
|
||||
$scope.user_type = user_type_options[0];
|
||||
$scope.$watch('user_type', user_type_sync($scope));
|
||||
|
||||
CreateSelect2({
|
||||
@@ -271,7 +271,7 @@ export function UsersEdit($scope, $rootScope, $location,
|
||||
generator.reset();
|
||||
|
||||
$scope.user_type_options = user_type_options;
|
||||
$scope.user_type = user_type_options[0]
|
||||
$scope.user_type = user_type_options[0];
|
||||
$scope.$watch('user_type', user_type_sync($scope));
|
||||
|
||||
var setScopeFields = function(data){
|
||||
|
||||
@@ -49,7 +49,7 @@ export default
|
||||
label: "Inventories",
|
||||
},
|
||||
{
|
||||
url: "/#/inventories/?inventory_sources_with_failures",
|
||||
url: "/#/inventories?status=sync-failed",
|
||||
number: scope.data.inventories.inventory_failed,
|
||||
label: "Inventory Sync Failures",
|
||||
isFailureCount: true
|
||||
@@ -60,7 +60,7 @@ export default
|
||||
label: "Projects"
|
||||
},
|
||||
{
|
||||
url: "/#/projects/?status=failed",
|
||||
url: "/#/projects?status=failed",
|
||||
number: scope.data.projects.failed,
|
||||
label: "Project Sync Failures",
|
||||
isFailureCount: true
|
||||
|
||||
@@ -118,6 +118,7 @@
|
||||
top: auto;
|
||||
box-shadow: none;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.DashboardGraphs-periodDropdown,
|
||||
|
||||
@@ -246,7 +246,7 @@ export default
|
||||
rows: 10,
|
||||
awPopOver: "SSH key description",
|
||||
awPopOverWatch: "key_description",
|
||||
dataTitle: 'Help',
|
||||
dataTitle: 'Private Key',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body",
|
||||
subForm: "credentialSubForm"
|
||||
|
||||
@@ -81,6 +81,11 @@ export default
|
||||
},
|
||||
project: {
|
||||
label: 'Project',
|
||||
labelAction: {
|
||||
label: 'RESET',
|
||||
ngClick: 'resetProjectToDefault()',
|
||||
'class': "{{!(job_type.value === 'scan' && project_name !== 'Default') ? 'hidden' : ''}}",
|
||||
},
|
||||
type: 'lookup',
|
||||
sourceModel: 'project',
|
||||
sourceField: 'name',
|
||||
@@ -99,6 +104,7 @@ export default
|
||||
label: 'Playbook',
|
||||
type:'select',
|
||||
ngOptions: 'book for book in playbook_options track by book',
|
||||
ngDisabled: "job_type.value === 'scan' && project_name === 'Default'",
|
||||
id: 'playbook-select',
|
||||
awRequiredWhen: {
|
||||
reqExpression: "playbookrequired",
|
||||
@@ -110,12 +116,6 @@ export default
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body",
|
||||
},
|
||||
default_scan: {
|
||||
type: 'custom',
|
||||
column: 1,
|
||||
ngShow: 'job_type.value === "scan" && project_name !== "Default"',
|
||||
control: '<a href="" ng-click="toggleScanInfo()">Reset to default project and playbook</a>'
|
||||
},
|
||||
credential: {
|
||||
label: 'Machine Credential',
|
||||
type: 'lookup',
|
||||
@@ -204,7 +204,7 @@ export default
|
||||
},
|
||||
job_tags: {
|
||||
label: 'Job Tags',
|
||||
type: 'textarea',
|
||||
type: 'text',
|
||||
rows: 1,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
|
||||
@@ -64,11 +64,10 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
||||
ngChange: 'scmChange()',
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
hasSubForm: true
|
||||
hasSubForm: true,
|
||||
},
|
||||
missing_path_alert: {
|
||||
type: 'alertblock',
|
||||
"class": 'alert-info',
|
||||
ngShow: "showMissingPlaybooksAlert && scm_type.value == 'manual'",
|
||||
alertTxt: '<p class=\"text-justify\"><strong>WARNING:</strong> There are no available playbook directories in {{ base_dir }}. ' +
|
||||
'Either that directory is empty, or all of the contents are already assigned to other projects. ' +
|
||||
@@ -79,7 +78,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
||||
base_dir: {
|
||||
label: 'Project Base Path',
|
||||
type: 'text',
|
||||
//"class": 'col-lg-6',
|
||||
class: 'Form-textUneditable',
|
||||
showonly: true,
|
||||
ngShow: "scm_type.value == 'manual' " ,
|
||||
awPopOver: '<p>Base path used for locating playbooks. Directories found inside this path will be listed in the playbook directory drop-down. ' +
|
||||
@@ -115,30 +114,12 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
||||
init: false
|
||||
},
|
||||
subForm: 'sourceSubForm',
|
||||
helpCollapse: [{
|
||||
hdr: 'GIT URLs',
|
||||
content: '<p>Example URLs for GIT SCM include:</p><ul class=\"no-bullets\"><li>https://github.com/ansible/ansible.git</li>' +
|
||||
'<li>git@github.com:ansible/ansible.git</li><li>git://servername.example.com/ansible.git</li></ul>' +
|
||||
'<p><strong>Note:</strong> When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, ' +
|
||||
'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' +
|
||||
'SSH. GIT read only protocol (git://) does not use username or password information.',
|
||||
show: "scm_type.value == 'git'"
|
||||
}, {
|
||||
hdr: 'SVN URLs',
|
||||
content: '<p>Example URLs for Subversion SCM include:</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://github.com/ansible/ansible</li><li>svn://servername.example.com/path</li>' +
|
||||
'<li>svn+ssh://servername.example.com/path</li></ul>',
|
||||
show: "scm_type.value == 'svn'"
|
||||
}, {
|
||||
hdr: 'Mercurial URLs',
|
||||
content: '<p>Example URLs for Mercurial SCM include:</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://bitbucket.org/username/project</li><li>ssh://hg@bitbucket.org/username/project</li>' +
|
||||
'<li>ssh://server.example.com/path</li></ul>' +
|
||||
'<p><strong>Note:</strong> Mercurial does not support password authentication for SSH. ' +
|
||||
'Do not put the username and key in the URL. ' +
|
||||
'If using Bitbucket and SSH, do not supply your Bitbucket username.',
|
||||
show: "scm_type.value == 'hg'"
|
||||
}],
|
||||
hideSubForm: "scm_type.value === 'manual'",
|
||||
awPopOverWatch: "urlPopover",
|
||||
awPopOver: "set in controllers/projects",
|
||||
dataTitle: 'SCM URL',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right'
|
||||
},
|
||||
scm_branch: {
|
||||
labelBind: "scmBranchLabel",
|
||||
@@ -174,7 +155,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
||||
dataTitle: 'SCM Clean',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
labelClass: 'checkbox-options stack-inline'
|
||||
}, {
|
||||
name: 'scm_delete_on_update',
|
||||
label: 'Delete on Update',
|
||||
@@ -186,7 +167,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
||||
dataTitle: 'SCM Delete',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
labelClass: 'checkbox-options stack-inline'
|
||||
}, {
|
||||
name: 'scm_update_on_launch',
|
||||
label: 'Update on Launch',
|
||||
@@ -197,7 +178,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
||||
dataTitle: 'SCM Update',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
labelClass: 'checkbox-options stack-inline'
|
||||
}]
|
||||
},
|
||||
scm_update_cache_timeout: {
|
||||
@@ -273,7 +254,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
||||
}
|
||||
},
|
||||
notifications: {
|
||||
include: "NotificationsList"
|
||||
include: "NotificationsList",
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -132,9 +132,10 @@ export default
|
||||
"delete": {
|
||||
label: 'Remove',
|
||||
ngClick: 'deletePermissionFromTeam(team_id, team_obj.name, role.name, role.summary_fields.resource_name, role.related.teams)',
|
||||
class: "List-actionButton--delete",
|
||||
'class': "List-actionButton--delete",
|
||||
iconClass: 'fa fa-times',
|
||||
awToolTip: 'Dissasociate permission from team'
|
||||
awToolTip: 'Dissasociate permission from team',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
},
|
||||
hideOnSuperuser: true
|
||||
|
||||
@@ -138,7 +138,6 @@ export default
|
||||
iterator: 'team',
|
||||
open: false,
|
||||
index: false,
|
||||
|
||||
actions: {},
|
||||
|
||||
fields: {
|
||||
|
||||
@@ -784,7 +784,6 @@ export default
|
||||
url, play;
|
||||
|
||||
scope.tasks = [];
|
||||
|
||||
if (scope.selectedPlay) {
|
||||
url = scope.job.url + 'job_tasks/?event_id=' + scope.selectedPlay;
|
||||
url += (scope.search_task_name) ? '&task__icontains=' + scope.search_task_name : '';
|
||||
@@ -912,16 +911,25 @@ export default
|
||||
scope.tasks[idx].taskActiveClass = '';
|
||||
}
|
||||
});
|
||||
params = {
|
||||
parent: scope.selectedTask,
|
||||
event__startswith: 'runner',
|
||||
page_size: scope.hostResultsMaxRows,
|
||||
order: 'host_name,counter',
|
||||
};
|
||||
JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){
|
||||
scope.hostResults = JobDetailService.processHostEvents(res.results);
|
||||
if (scope.selectedTask !== null){
|
||||
params = {
|
||||
parent: scope.selectedTask,
|
||||
event__startswith: 'runner',
|
||||
page_size: scope.hostResultsMaxRows,
|
||||
order: 'host_name,counter',
|
||||
};
|
||||
if (scope.search_host_status === 'failed'){
|
||||
params.failed = true;
|
||||
}
|
||||
JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){
|
||||
scope.hostResults = JobDetailService.processHostEvents(res.results);
|
||||
scope.hostResultsLoading = false;
|
||||
});
|
||||
}
|
||||
else{
|
||||
scope.hostResults = [];
|
||||
scope.hostResultsLoading = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
@@ -934,7 +942,7 @@ export default
|
||||
graph_data.push({
|
||||
label: 'OK',
|
||||
value: count.ok.length,
|
||||
color: '#60D66F'
|
||||
color: '#5CB85C'
|
||||
});
|
||||
}
|
||||
if (count.changed.length > 0) {
|
||||
@@ -979,18 +987,19 @@ export default
|
||||
job_detail_chart = nv.models.pieChart()
|
||||
.margin({bottom: 15})
|
||||
.x(function(d) {
|
||||
return d.label +': '+ Math.round((d.value/total)*100) + "%";
|
||||
return d.label +': '+ Math.floor((d.value/total)*100) + "%";
|
||||
})
|
||||
.y(function(d) { return d.value; })
|
||||
.showLabels(true)
|
||||
.showLegend(false)
|
||||
.showLabels(false)
|
||||
.showLegend(true)
|
||||
.growOnHover(false)
|
||||
.labelThreshold(0.01)
|
||||
.tooltipContent(function(x, y) {
|
||||
return '<p>'+x+'</p>'+ '<p>' + Math.floor(y.replace(',','')) + ' HOSTS ' + '</p>';
|
||||
})
|
||||
.color(colors);
|
||||
|
||||
job_detail_chart.legend.rightAlign(false);
|
||||
job_detail_chart.legend.margin({top: 5, right: 450, left:0, bottom: 0});
|
||||
d3.select(element.find('svg')[0])
|
||||
.datum(dataset)
|
||||
.transition().duration(350)
|
||||
@@ -1000,19 +1009,15 @@ export default
|
||||
"font-style": "normal",
|
||||
"font-weight":400,
|
||||
"src": "url(/static/assets/OpenSans-Regular.ttf)",
|
||||
"width": 500,
|
||||
"width": 600,
|
||||
"height": 300,
|
||||
"color": '#848992'
|
||||
});
|
||||
|
||||
d3.select(element.find(".nv-label text")[0])
|
||||
.attr("class", "HostSummary-graph--successful")
|
||||
d3.select(element.find(".nv-noData")[0])
|
||||
.style({
|
||||
"font-family": 'Open Sans',
|
||||
"font-size": "16px",
|
||||
"text-transform" : "uppercase",
|
||||
"fill" : colors[0],
|
||||
"src": "url(/static/assets/OpenSans-Regular.ttf)"
|
||||
"text-anchor": 'start'
|
||||
});
|
||||
/*
|
||||
d3.select(element.find(".nv-label text")[1])
|
||||
.attr("class", "HostSummary-graph--changed")
|
||||
.style({
|
||||
@@ -1040,6 +1045,7 @@ export default
|
||||
"fill" : colors[3],
|
||||
"src": "url(/static/assets/OpenSans-Regular.ttf)"
|
||||
});
|
||||
*/
|
||||
return job_detail_chart;
|
||||
};
|
||||
}])
|
||||
|
||||
@@ -177,7 +177,7 @@ angular.module('JobTemplatesHelper', ['Utilities'])
|
||||
});
|
||||
|
||||
|
||||
if(scope.project === "" && scope.playbook === ""){
|
||||
if (scope.project === "" && scope.playbook === "") {
|
||||
scope.toggleScanInfo();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export default
|
||||
angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelper', 'SearchHelper', 'PaginationHelpers', listGenerator.name, 'ModalDialog',
|
||||
'GeneratorHelpers'])
|
||||
|
||||
.factory('EditSchedule', ['SchedulerInit', '$rootScope', 'Wait', 'Rest',
|
||||
.factory('EditSchedule', ['SchedulerInit', '$rootScope', 'Wait', 'Rest',
|
||||
'ProcessErrors', 'GetBasePath', 'SchedulePost', '$state',
|
||||
function(SchedulerInit, $rootScope, Wait, Rest, ProcessErrors,
|
||||
GetBasePath, SchedulePost, $state) {
|
||||
@@ -176,7 +176,7 @@ export default
|
||||
};
|
||||
}])
|
||||
|
||||
.factory('AddSchedule', ['$location', '$rootScope', '$stateParams',
|
||||
.factory('AddSchedule', ['$location', '$rootScope', '$stateParams',
|
||||
'SchedulerInit', 'Wait', 'GetBasePath', 'Empty', 'SchedulePost', '$state', 'Rest', 'ProcessErrors',
|
||||
function($location, $rootScope, $stateParams, SchedulerInit,
|
||||
Wait, GetBasePath, Empty, SchedulePost, $state, Rest,
|
||||
@@ -295,8 +295,7 @@ export default
|
||||
}])
|
||||
|
||||
.factory('SchedulePost', ['Rest', 'ProcessErrors', 'RRuleToAPI', 'Wait',
|
||||
'ToJSON',
|
||||
function(Rest, ProcessErrors, RRuleToAPI, Wait, ToJSON) {
|
||||
function(Rest, ProcessErrors, RRuleToAPI, Wait) {
|
||||
return function(params) {
|
||||
var scope = params.scope,
|
||||
url = params.url,
|
||||
@@ -326,8 +325,8 @@ export default
|
||||
schedule.extra_data = JSON.stringify(extra_vars);
|
||||
}
|
||||
else if(scope.extraVars){
|
||||
schedule.extra_data = scope.parseType === 'yaml' ?
|
||||
(scope.extraVars === '---' ? "" : jsyaml.safeLoad(scope.extraVars)) : scope.extraVars;
|
||||
schedule.extra_data = scope.parseType === 'yaml' ?
|
||||
(scope.extraVars === '---' ? "" : jsyaml.safeLoad(scope.extraVars)) : scope.extraVars;
|
||||
}
|
||||
Rest.setUrl(url);
|
||||
if (mode === 'add') {
|
||||
|
||||
@@ -17,7 +17,7 @@ function InventoriesList($scope, $rootScope, $location, $log,
|
||||
Find, Empty, $state) {
|
||||
|
||||
var list = InventoryList,
|
||||
defaultUrl = GetBasePath('inventory'),
|
||||
defaultUrl = GetBasePath('inventory') + ($stateParams.status === 'sync-failed' ? '?not__inventory_sources_with_failures=0' : ''),
|
||||
view = generateList,
|
||||
paths = $location.path().replace(/^\//, '').split('/'),
|
||||
mode = (paths[0] === 'inventories') ? 'edit' : 'select';
|
||||
|
||||
@@ -9,7 +9,7 @@ import InventoriesList from './inventory-list.controller';
|
||||
|
||||
export default {
|
||||
name: 'inventories',
|
||||
route: '/inventories',
|
||||
route: '/inventories?{status}',
|
||||
templateUrl: templateUrl('inventories/inventories'),
|
||||
controller: InventoriesList,
|
||||
data: {
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
group_id: id
|
||||
});
|
||||
};
|
||||
$scope.showFailedHosts = function(x, y, z){
|
||||
$scope.showFailedHosts = function() {
|
||||
$state.go('inventoryManage', {failed: true}, {reload: true});
|
||||
};
|
||||
$scope.scheduleGroup = function(id) {
|
||||
@@ -91,7 +91,7 @@
|
||||
$scope.$parent.groupsSelected = selection.length > 0 ? true : false;
|
||||
$scope.$parent.groupsSelectedItems = selection.selectedItems;
|
||||
});
|
||||
$scope.$on('PostRefresh', () =>{
|
||||
$scope.$on('PostRefresh', () => {
|
||||
$scope.groups.forEach( (group, index) => {
|
||||
var group_status, hosts_status;
|
||||
group_status = GetSyncStatusMsg({
|
||||
|
||||
@@ -8,7 +8,7 @@ import {ManageHostsAdd, ManageHostsEdit} from './hosts.route';
|
||||
|
||||
export default
|
||||
angular.module('manageHosts', [])
|
||||
.run(['$stateExtender', '$state', function($stateExtender, $state){
|
||||
.run(['$stateExtender', function($stateExtender){
|
||||
$stateExtender.addState(ManageHostsAdd);
|
||||
$stateExtender.addState(ManageHostsEdit);
|
||||
}]);
|
||||
|
||||
@@ -61,7 +61,7 @@ export default
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
}
|
||||
}
|
||||
$scope.canEdit = data['script'] !== null;
|
||||
$scope.canEdit = data.script !== null;
|
||||
if (!$scope.canEdit) {
|
||||
$scope.script = "Script contents hidden";
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
<div id="hosts-summary-section" class="section">
|
||||
<div class="JobDetail-instructions"><span class="badge">4</span> Please select a host below to view a summary of all associated tasks.</div>
|
||||
<div class="JobDetail-instructions" ng-hide="hosts.length == 0"><span class="badge">4</span> Please select a host below to view a summary of all associated tasks.</div>
|
||||
<div class="JobDetail-searchHeaderRow" ng-hide="hosts.length == 0">
|
||||
<div class="JobDetail-searchContainer form-group">
|
||||
<div class="search-name">
|
||||
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
<div class="JobDetail-tableToggleContainer form-group">
|
||||
<div class="btn-group" >
|
||||
<button
|
||||
<button
|
||||
ng-click="setFilter('all')"
|
||||
class="JobDetail-tableToggle btn btn-xs" ng-class="{'btn-default': filter === 'failed', 'btn-primary': filter === 'all'}">All</button>
|
||||
<button ng-click="setFilter('failed')"
|
||||
@@ -34,7 +34,7 @@
|
||||
</div>
|
||||
|
||||
<div id="hosts-summary-table" class="table-detail" lr-infinite-scroll="getNextPage" scroll-threshold="10" time-threshold="500">
|
||||
<table class="table">
|
||||
<table class="table" ng-class="{'JobDetails-table--noResults': hosts.length === 0}">
|
||||
<tbody>
|
||||
<tr class="List-tableRow" ng-repeat="host in hosts track by $index" id="{{ host.id }}" ng-class-even="'List-tableRow--evenRow'" ng-class-odd="'List-tableRow--oddRow'">
|
||||
<td class="List-tableCell name col-lg-6 col-md-6 col-sm-6 col-xs-6">
|
||||
|
||||
@@ -13,9 +13,15 @@
|
||||
.JobDetail-instructions{
|
||||
color: @default-interface-txt;
|
||||
margin: 10px 0 10px 0;
|
||||
|
||||
.badge {
|
||||
background-color: @default-list-header-bg;
|
||||
color: @default-interface-txt;
|
||||
padding: 5px 7px;
|
||||
}
|
||||
}
|
||||
.JobDetail{
|
||||
.OnePlusOne-container(100%, @breakpoint-md);
|
||||
.OnePlusOne-container(100%, @breakpoint-md);
|
||||
}
|
||||
|
||||
.JobDetail-leftSide{
|
||||
@@ -151,8 +157,25 @@
|
||||
background-color: @default-link;
|
||||
border: 1px solid @default-link;
|
||||
color: @default-bg;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @default-link-hov;
|
||||
}
|
||||
}
|
||||
.JobDetail .nvd3.nv-noData{
|
||||
color: @default-interface-txt;
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
.JobDetail .nv-series{
|
||||
padding-right: 30px;
|
||||
display: block;
|
||||
}
|
||||
.JobDetail-instructions .badge{
|
||||
background-color: @default-list-header-bg;
|
||||
color: @default-interface-txt;
|
||||
}
|
||||
.JobDetail-tableToggle--left{
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
@@ -185,6 +208,12 @@
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
.JobDetails-table--noResults {
|
||||
tr > td {
|
||||
border-top: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.JobDetail-statusIcon--results{
|
||||
padding-left: 0px;
|
||||
padding-right: 10px;
|
||||
@@ -196,7 +225,13 @@
|
||||
}
|
||||
|
||||
.JobDetail-stdoutActionButton--active{
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
flex:none;
|
||||
width:0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.JobDetail-leftSide.JobDetail-stdoutActionButton--active {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
@@ -673,21 +673,9 @@ export default
|
||||
|
||||
scope.lessStatus = false; // close the view more status option
|
||||
|
||||
// Detail table height adjusting. First, put page height back to 'normal'.
|
||||
$('#plays-table-detail').height(80);
|
||||
//$('#plays-table-detail').mCustomScrollbar("update");
|
||||
// $('#tasks-table-detail').height(120);
|
||||
//$('#tasks-table-detail').mCustomScrollbar("update");
|
||||
$('#hosts-table-detail').height(150);
|
||||
//$('#hosts-table-detail').mCustomScrollbar("update");
|
||||
|
||||
height = $(window).height() - $('#main-menu-container .navbar').outerHeight() -
|
||||
$('#job-detail-container').outerHeight() - 20;
|
||||
if (height > 15) {
|
||||
// there's a bunch of white space at the bottom, let's use it
|
||||
$('#plays-table-detail').height(80 + (height * 0.10));
|
||||
$('#tasks-table-detail').height(120 + (height * 0.20));
|
||||
$('#hosts-table-detail').height(150 + (height * 0.10));
|
||||
}
|
||||
scope.$emit('RefreshCompleted');
|
||||
};
|
||||
|
||||
@@ -776,6 +764,15 @@ export default
|
||||
}
|
||||
};
|
||||
|
||||
scope.filterTaskStatus = function() {
|
||||
scope.search_task_status = (scope.search_task_status === 'all') ? 'failed' : 'all';
|
||||
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
||||
LoadTasks({
|
||||
scope: scope
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
scope.filterPlayStatus = function() {
|
||||
scope.search_play_status = (scope.search_play_status === 'all') ? 'failed' : 'all';
|
||||
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
||||
@@ -785,6 +782,26 @@ export default
|
||||
}
|
||||
};
|
||||
|
||||
scope.filterHostStatus = function(){
|
||||
scope.search_host_status = (scope.search_host_status === 'all') ? 'failed' : 'all';
|
||||
if (!scope.liveEventProcessing || scope.pauseLiveEvents){
|
||||
if (scope.selectedTask !== null && scope.selectedPlay !== null){
|
||||
var params = {
|
||||
parent: scope.selectedTask,
|
||||
page_size: scope.hostResultsMaxRows,
|
||||
order: 'host_name,counter',
|
||||
};
|
||||
if (scope.search_host_status === 'failed'){
|
||||
params.failed = true;
|
||||
}
|
||||
JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){
|
||||
scope.hostResults = JobDetailService.processHostEvents(res.results);
|
||||
scope.hostResultsLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.searchPlays = function() {
|
||||
if (scope.search_play_name) {
|
||||
scope.searchPlaysEnabled = false;
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
<div id="plays-table-header" class="table-header">
|
||||
<div id="plays-table-header" class="table-header" ng-show="plays.length !== 0">
|
||||
<table class="table table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -202,7 +202,7 @@
|
||||
</div>
|
||||
<div id="plays-table-detail" class="table-detail" lr-infinite-scroll="playsScrollDown"
|
||||
scroll-threshold="10" time-threshold="500">
|
||||
<table class="table">
|
||||
<table class="table" ng-class="{'JobDetails-table--noResults': plays.length === 0}">
|
||||
<tbody>
|
||||
<tr class="List-tableRow cursor-pointer" ng-repeat="play in plays" ng-class-odd="'List-tableRow--oddRow'" ng-class-even="'List-tableRow--evenRow'" ng-class="play.playActiveClass" ng-click="selectPlay(play.id, $event)">
|
||||
<td class="List-tableCell col-lg-7 col-md-6 col-sm-6 col-xs-4 status-column" aw-tool-tip="{{ play.status_tip }}" data-tip-watch="play.status_tip" data-placement="top"><i class="JobDetail-statusIcon fa icon-job-{{ play.status }}"></i>{{ play.name }}</td>
|
||||
@@ -248,7 +248,7 @@
|
||||
</div>
|
||||
|
||||
<div class="table-header">
|
||||
<table id="tasks-table-header" class="table table-condensed">
|
||||
<table id="tasks-table-header" class="table table-condensed" ng-show="taskList.length !== 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="List-tableHeader col-lg-3 col-md-3 col-sm-6 col-xs-4">Tasks</th>
|
||||
@@ -261,7 +261,7 @@
|
||||
</div>
|
||||
<div id="tasks-table-detail" class="table-detail" lr-infinite-scroll="tasksScrollDown"
|
||||
scroll-threshold="10" time-threshold="500">
|
||||
<table class="table">
|
||||
<table class="table" ng-class="{'JobDetails-table--noResults': taskList.length === 0}">
|
||||
<tbody>
|
||||
<tr class="List-tableRow cursor-pointer" ng-class-odd="'List-tableRow--oddRow'" ng-class-even="'List-tableRow--evenRow'" ng-repeat="task in taskList = (tasks) track by $index" ng-class="task.taskActiveClass" ng-click="selectTask(task.id)">
|
||||
<td class="List-tableCell col-lg-3 col-md-3 col-sm-6 col-xs-4 status-column" aw-tool-tip="{{ task.status_tip }}"
|
||||
@@ -331,7 +331,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-header" id="hosts-table-header">
|
||||
<table class="table table-condensed">
|
||||
<table class="table table-condensed" ng-show="results.length !== 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="List-tableHeader col-lg-4 col-md-3 col-sm-3 col-xs-3">Hosts</th>
|
||||
@@ -343,7 +343,7 @@
|
||||
</div>
|
||||
|
||||
<div id="hosts-table-detail" class="table-detail" lr-infinite-scroll="hostResultsScrollDown" scroll-threshold="10" time-threshold="500">
|
||||
<table class="table">
|
||||
<table class="table" ng-class="{'JobDetails-table--noResults': results.length === 0}">
|
||||
<tbody>
|
||||
<tr class="List-tableRow cursor-pointer" ng-class-odd="'List-tableRow--oddRow'" ng-class-even="'List-tableRow--evenRow'" ng-repeat="result in results = (hostResults) track by $index">
|
||||
<td class="List-tableCell col-lg-4 col-md-3 col-sm-3 col-xs-3 status-column">
|
||||
@@ -404,7 +404,7 @@
|
||||
<button class="StandardOut-actionButton" aw-tool-tip="Toggle Output" data-placement="top" ng-class="{'StandardOut-actionButton--active': stdoutFullScreen}" ng-click="toggleStdoutFullscreen()">
|
||||
<i class="fa fa-arrows-alt"></i>
|
||||
</button>
|
||||
<a ng-show="job_status.status === ('failed' || 'successful')" href="/api/v1/jobs/{{ job.id }}/stdout?format=txt_download&token={{ token }}">
|
||||
<a ng-show="job_status.status === 'failed' || job_status.status === 'successful' || job_status.status === 'canceled'" href="/api/v1/jobs/{{ job.id }}/stdout?format=txt_download&token={{ token }}">
|
||||
<button class="StandardOut-actionButton" aw-tool-tip="Download Output" data-placement="top">
|
||||
<i class="fa fa-download"></i>
|
||||
</button>
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
jQuery.extend(true, CloudCredentialList, CredentialList);
|
||||
CloudCredentialList.name = 'cloudcredentials';
|
||||
CloudCredentialList.iterator = 'cloudcredential';
|
||||
CloudCredentialList.basePath = '/api/v1/credentials?cloud=true';
|
||||
|
||||
SurveyControllerInit({
|
||||
scope: $scope,
|
||||
@@ -196,12 +197,20 @@
|
||||
});
|
||||
});
|
||||
|
||||
function sync_playbook_select2() {
|
||||
CreateSelect2({
|
||||
element:'#playbook-select',
|
||||
multiple: false
|
||||
});
|
||||
}
|
||||
|
||||
// Update playbook select whenever project value changes
|
||||
selectPlaybook = function (oldValue, newValue) {
|
||||
var url;
|
||||
if($scope.job_type.value === 'scan' && $scope.project_name === "Default"){
|
||||
$scope.playbook_options = ['Default'];
|
||||
$scope.playbook = 'Default';
|
||||
sync_playbook_select2();
|
||||
Wait('stop');
|
||||
}
|
||||
else if (oldValue !== newValue) {
|
||||
@@ -216,6 +225,7 @@
|
||||
opts.push(data[i]);
|
||||
}
|
||||
$scope.playbook_options = opts;
|
||||
sync_playbook_select2();
|
||||
Wait('stop');
|
||||
})
|
||||
.error(function (data, status) {
|
||||
@@ -226,32 +236,37 @@
|
||||
}
|
||||
};
|
||||
|
||||
$scope.jobTypeChange = function(){
|
||||
if($scope.job_type){
|
||||
if($scope.job_type.value === 'scan'){
|
||||
// If the job_type is 'scan' then we don't want the user to be
|
||||
// able to prompt for job type or inventory
|
||||
$scope.ask_job_type_on_launch = false;
|
||||
$scope.ask_inventory_on_launch = false;
|
||||
$scope.toggleScanInfo();
|
||||
}
|
||||
else if($scope.project_name === "Default"){
|
||||
$scope.project_name = null;
|
||||
$scope.playbook_options = [];
|
||||
// $scope.playbook = 'null';
|
||||
$scope.job_templates_form.playbook.$setPristine();
|
||||
}
|
||||
}
|
||||
let last_non_scan_project_name = null;
|
||||
let last_non_scan_playbook = "";
|
||||
let last_non_scan_playbook_options = [];
|
||||
$scope.jobTypeChange = function() {
|
||||
if ($scope.job_type) {
|
||||
if ($scope.job_type.value === 'scan') {
|
||||
if ($scope.project_name !== "Default") {
|
||||
last_non_scan_project_name = $scope.project_name;
|
||||
last_non_scan_playbook = $scope.playbook;
|
||||
last_non_scan_playbook_options = $scope.playbook_options;
|
||||
}
|
||||
// If the job_type is 'scan' then we don't want the user to be
|
||||
// able to prompt for job type or inventory
|
||||
$scope.ask_job_type_on_launch = false;
|
||||
$scope.ask_inventory_on_launch = false;
|
||||
$scope.resetProjectToDefault();
|
||||
}
|
||||
else if ($scope.project_name === "Default") {
|
||||
$scope.project_name = last_non_scan_project_name;
|
||||
$scope.playbook_options = last_non_scan_playbook_options;
|
||||
$scope.playbook = last_non_scan_playbook;
|
||||
$scope.job_templates_form.playbook.$setPristine();
|
||||
}
|
||||
}
|
||||
sync_playbook_select2();
|
||||
};
|
||||
|
||||
$scope.toggleScanInfo = function() {
|
||||
$scope.resetProjectToDefault = function() {
|
||||
$scope.project_name = 'Default';
|
||||
if($scope.project === null){
|
||||
selectPlaybook();
|
||||
}
|
||||
else {
|
||||
$scope.project = null;
|
||||
}
|
||||
$scope.project = null;
|
||||
selectPlaybook('force_load');
|
||||
};
|
||||
|
||||
// Detect and alert user to potential SCM status issues
|
||||
|
||||
@@ -76,6 +76,13 @@ export default
|
||||
$scope.playbook = null;
|
||||
generator.reset();
|
||||
|
||||
function sync_playbook_select2() {
|
||||
CreateSelect2({
|
||||
element:'#playbook-select',
|
||||
multiple: false
|
||||
});
|
||||
}
|
||||
|
||||
getPlaybooks = function (project) {
|
||||
var url;
|
||||
if ($scope.playbook) {
|
||||
@@ -85,6 +92,7 @@ export default
|
||||
if($scope.job_type.value === 'scan' && $scope.project_name === "Default"){
|
||||
$scope.playbook_options = ['Default'];
|
||||
$scope.playbook = 'Default';
|
||||
sync_playbook_select2();
|
||||
Wait('stop');
|
||||
}
|
||||
else if (!Empty(project)) {
|
||||
@@ -93,14 +101,14 @@ export default
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var i;
|
||||
$scope.playbook_options = [];
|
||||
for (i = 0; i < data.length; i++) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
$scope.playbook_options.push(data[i]);
|
||||
if (data[i] === $scope.playbook) {
|
||||
$scope.job_templates_form.playbook.$setValidity('required', true);
|
||||
}
|
||||
}
|
||||
sync_playbook_select2();
|
||||
if ($scope.playbook) {
|
||||
$scope.$emit('jobTemplateLoadFinished');
|
||||
} else {
|
||||
@@ -108,7 +116,7 @@ export default
|
||||
}
|
||||
})
|
||||
.error(function (ret,status_code) {
|
||||
if (status_code == 403) {
|
||||
if (status_code === 403) {
|
||||
/* user doesn't have access to see the project, no big deal. */
|
||||
} else {
|
||||
Alert('Missing Playbooks', 'Unable to retrieve the list of playbooks for this project. Choose a different ' +
|
||||
@@ -122,23 +130,31 @@ export default
|
||||
}
|
||||
};
|
||||
|
||||
$scope.jobTypeChange = function(){
|
||||
if($scope.job_type){
|
||||
if($scope.job_type.value === 'scan'){
|
||||
// If the job_type is 'scan' then we don't want the user to be
|
||||
// able to prompt for job type or inventory
|
||||
$scope.ask_job_type_on_launch = false;
|
||||
$scope.ask_inventory_on_launch = false;
|
||||
$scope.toggleScanInfo();
|
||||
}
|
||||
else if($scope.project_name === "Default"){
|
||||
$scope.project_name = null;
|
||||
$scope.playbook_options = [];
|
||||
// $scope.playbook = 'null';
|
||||
$scope.job_templates_form.playbook.$setPristine();
|
||||
}
|
||||
|
||||
}
|
||||
let last_non_scan_project_name = null;
|
||||
let last_non_scan_playbook = "";
|
||||
let last_non_scan_playbook_options = [];
|
||||
$scope.jobTypeChange = function() {
|
||||
if ($scope.job_type) {
|
||||
if ($scope.job_type.value === 'scan') {
|
||||
if ($scope.project_name !== "Default") {
|
||||
last_non_scan_project_name = $scope.project_name;
|
||||
last_non_scan_playbook = $scope.playbook;
|
||||
last_non_scan_playbook_options = $scope.playbook_options;
|
||||
}
|
||||
// If the job_type is 'scan' then we don't want the user to be
|
||||
// able to prompt for job type or inventory
|
||||
$scope.ask_job_type_on_launch = false;
|
||||
$scope.ask_inventory_on_launch = false;
|
||||
$scope.resetProjectToDefault();
|
||||
}
|
||||
else if ($scope.project_name === "Default") {
|
||||
$scope.project_name = last_non_scan_project_name;
|
||||
$scope.playbook_options = last_non_scan_playbook_options;
|
||||
$scope.playbook = last_non_scan_playbook;
|
||||
$scope.job_templates_form.playbook.$setPristine();
|
||||
}
|
||||
}
|
||||
sync_playbook_select2();
|
||||
};
|
||||
|
||||
$scope.toggleNotification = function(event, notifier_id, column) {
|
||||
@@ -159,14 +175,10 @@ export default
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleScanInfo = function() {
|
||||
$scope.resetProjectToDefault = function() {
|
||||
$scope.project_name = 'Default';
|
||||
if($scope.project === null){
|
||||
getPlaybooks();
|
||||
}
|
||||
else {
|
||||
$scope.project = null;
|
||||
}
|
||||
$scope.project = null;
|
||||
getPlaybooks();
|
||||
};
|
||||
|
||||
// Detect and alert user to potential SCM status issues
|
||||
@@ -198,7 +210,7 @@ export default
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
if (status == 403) {
|
||||
if (status === 403) {
|
||||
/* User doesn't have read access to the project, no problem. */
|
||||
} else {
|
||||
ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to get project ' + $scope.project +
|
||||
@@ -288,6 +300,7 @@ export default
|
||||
jQuery.extend(true, CloudCredentialList, CredentialList);
|
||||
CloudCredentialList.name = 'cloudcredentials';
|
||||
CloudCredentialList.iterator = 'cloudcredential';
|
||||
CloudCredentialList.basePath = '/api/v1/credentials?cloud=true';
|
||||
LookUpInit({
|
||||
url: GetBasePath('credentials') + '?cloud=true',
|
||||
scope: $scope,
|
||||
|
||||
@@ -20,6 +20,7 @@ export default
|
||||
index: false,
|
||||
hover: true,
|
||||
well: false,
|
||||
emptyListText: 'No completed jobs',
|
||||
|
||||
fields: {
|
||||
status: {
|
||||
|
||||
@@ -15,6 +15,7 @@ export default
|
||||
index: true,
|
||||
hover: true,
|
||||
well: false,
|
||||
emptyListText: 'No schedules exist',
|
||||
|
||||
fields: {
|
||||
status: {
|
||||
|
||||
@@ -157,11 +157,11 @@
|
||||
ng-href="/#/portal"
|
||||
ng-if="!licenseMissing"
|
||||
ng-class="{'is-currentRoute' : isCurrentState('portalMode'), 'is-loggedOut' : !$root.current_user.username}"
|
||||
aw-tool-tip="Portal Mode"
|
||||
aw-tool-tip="My View"
|
||||
data-placement="bottom"
|
||||
data-trigger="hover"
|
||||
data-container="body">
|
||||
<i class="MainMenu-itemImage MainMenu-itemImage--settings fa fa-columns"
|
||||
<i class="MainMenu-itemImage MainMenu-itemImage--settings fa fa-tasks"
|
||||
alt="Portal Mode">
|
||||
</i>
|
||||
</a>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<div ui-view></div>
|
||||
<div class="tab-pane Panel" id="management_jobs">
|
||||
<div class="List-title">
|
||||
<div class="List-titleText">
|
||||
@@ -7,7 +8,6 @@
|
||||
{{ mgmtCards.length }}
|
||||
</span>
|
||||
</div>
|
||||
<div ui-view></div>
|
||||
<div class="MgmtCards">
|
||||
<div class="MgmtCards-card"
|
||||
ng-repeat="card in mgmtCards track by card.id">
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
.MgmtCards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.MgmtCards-card {
|
||||
@@ -11,15 +12,14 @@
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid @default-border;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
margin-top: 20px;
|
||||
width: 32%;
|
||||
}
|
||||
|
||||
.MgmtCards-card--selected {
|
||||
padding-left: 16px;
|
||||
border-left: 5px solid #337AB7;
|
||||
border-left: 5px solid @default-link;
|
||||
}
|
||||
|
||||
.MgmtCards-card--promptElements{
|
||||
@@ -44,7 +44,6 @@
|
||||
font-weight: bold;
|
||||
color: @default-interface-txt;
|
||||
margin-bottom: 25px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
@@ -86,46 +85,19 @@
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
@media (min-width: 1179px) {
|
||||
.MgmtCards-card {
|
||||
width: ~"calc(25% - 15px)";
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.MgmtCards-card:nth-child(4n+4) {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 901px) and (max-width: 1178px) {
|
||||
.MgmtCards-card {
|
||||
width: ~"calc(33% - 11px)";
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.MgmtCards-card:nth-child(3n+3) {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 616px) and (max-width: 900px) {
|
||||
.MgmtCards-card {
|
||||
width: ~"calc(50% - 10px)";
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.MgmtCards-card:nth-child(2n+2) {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 615px) {
|
||||
@media (max-width: 840px) {
|
||||
.MgmtCards-card {
|
||||
width: 100%;
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 840px) and (max-width: 1240px) {
|
||||
.MgmtCards-card {
|
||||
width: ~"calc(50% - 10px)";
|
||||
}
|
||||
}
|
||||
|
||||
#prompt-for-days-facts, #prompt-for-days {
|
||||
overflow-x: hidden;
|
||||
font-family: "Open Sans";
|
||||
|
||||
@@ -141,7 +141,23 @@ export default function() {
|
||||
reqExpression: "channel_required",
|
||||
init: "false"
|
||||
},
|
||||
ngShow: "notification_type.value == 'slack' || notification_type.value == 'hipchat'",
|
||||
ngShow: "notification_type.value == 'slack'",
|
||||
subForm: 'typeSubForm'
|
||||
},
|
||||
rooms: {
|
||||
label: 'Destination Channels',
|
||||
type: 'textarea',
|
||||
rows: 3,
|
||||
awPopOver: '<p>Type an option on each line. The pound symbol (#) is not required.</p>'+
|
||||
'<p>For example:<br>engineering<br>\n #support<br>\n',
|
||||
dataTitle: 'Destination Channels',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body",
|
||||
awRequiredWhen: {
|
||||
reqExpression: "room_required",
|
||||
init: "false"
|
||||
},
|
||||
ngShow: "notification_type.value == 'hipchat'",
|
||||
subForm: 'typeSubForm'
|
||||
},
|
||||
token: {
|
||||
@@ -243,8 +259,9 @@ export default function() {
|
||||
subForm: 'typeSubForm'
|
||||
},
|
||||
api_url: {
|
||||
label: 'API URL (e.g: https://mycompany.hiptchat.com)',
|
||||
label: 'API URL',
|
||||
type: 'text',
|
||||
placeholder: 'https://mycompany.hipchat.com',
|
||||
awRequiredWhen: {
|
||||
reqExpression: "hipchat_required",
|
||||
init: "false"
|
||||
@@ -264,11 +281,7 @@ export default function() {
|
||||
},
|
||||
notify: {
|
||||
label: 'Notify Channel',
|
||||
type: 'text',
|
||||
awRequiredWhen: {
|
||||
reqExpression: "hipchat_required",
|
||||
init: "false"
|
||||
},
|
||||
type: 'checkbox',
|
||||
ngShow: "notification_type.value == 'hipchat' ",
|
||||
subForm: 'typeSubForm'
|
||||
},
|
||||
|
||||
@@ -13,6 +13,7 @@ export default function(){
|
||||
iterator: 'notification_template',
|
||||
index: false,
|
||||
hover: false,
|
||||
emptyListText: 'No notifications exist',
|
||||
|
||||
fields: {
|
||||
status: {
|
||||
|
||||
@@ -14,6 +14,7 @@ export default function(){
|
||||
iterator: 'notification',
|
||||
index: false,
|
||||
hover: false,
|
||||
emptyListText: 'No Notifications exist',
|
||||
basePath: 'notifications',
|
||||
fields: {
|
||||
name: {
|
||||
|
||||
@@ -39,7 +39,7 @@ function () {
|
||||
case 'hipchat':
|
||||
obj.tokenLabel = ' Token';
|
||||
obj.hipchat_required = true;
|
||||
obj.channel_required = true;
|
||||
obj.room_required = true;
|
||||
obj.token_required = true;
|
||||
break;
|
||||
case 'twilio':
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<div id="scheduled_jobs_link" class="Form-tab"
|
||||
ng-class="{'is-selected': schedulesSelected }"
|
||||
ng-click="toggleTab('scheduled')">
|
||||
Schedule
|
||||
Schedules
|
||||
</div>
|
||||
</div>
|
||||
<div id="jobs-tab-content" class="Form-tabSection"
|
||||
|
||||
@@ -8,7 +8,7 @@ export default {
|
||||
name: 'portalMode',
|
||||
url: '/portal',
|
||||
ncyBreadcrumb: {
|
||||
label: "PORTAL MODE"
|
||||
label: "MY VIEW"
|
||||
},
|
||||
resolve: {
|
||||
features: ['FeaturesService', function(FeaturesService) {
|
||||
@@ -30,4 +30,4 @@ export default {
|
||||
controller: PortalModeJobsController
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -37,19 +37,28 @@ export default
|
||||
name: 'projectSchedules',
|
||||
route: '/projects/:id/schedules',
|
||||
templateUrl: templateUrl("scheduler/scheduler"),
|
||||
controller: 'schedulerController'
|
||||
controller: 'schedulerController',
|
||||
ncyBreadcrumb: {
|
||||
label: 'PROJECT SCHEDULES'
|
||||
}
|
||||
});
|
||||
$stateExtender.addState({
|
||||
name: 'projectSchedules.add',
|
||||
route: '/add',
|
||||
templateUrl: templateUrl("scheduler/schedulerForm"),
|
||||
controller: 'schedulerAddController'
|
||||
controller: 'schedulerAddController',
|
||||
ncyBreadcrumb: {
|
||||
label: 'PROJECT SCHEDULES ADD'
|
||||
}
|
||||
});
|
||||
$stateExtender.addState({
|
||||
name: 'projectSchedules.edit',
|
||||
route: '/:schedule_id',
|
||||
templateUrl: templateUrl("scheduler/schedulerForm"),
|
||||
controller: 'schedulerEditController'
|
||||
controller: 'schedulerEditController',
|
||||
ncyBreadcrumb: {
|
||||
label: 'PROJECT SCHEDULES EDIT'
|
||||
}
|
||||
});
|
||||
$stateExtender.addState({
|
||||
name: 'inventoryManage.schedules',
|
||||
|
||||
@@ -509,7 +509,7 @@
|
||||
Please provide a valid date.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group SchedulerForm-formGroup"
|
||||
<div class="form-group SchedulerForm-formGroup"
|
||||
ng-if="schedulerEnd && schedulerEnd.value == 'on'">
|
||||
<label class="Form-inputLabel">
|
||||
<span class="red-text">*</span>
|
||||
@@ -583,7 +583,7 @@
|
||||
<div class="SchedulerFormDetail-container"
|
||||
ng-show="schedulerIsValid">
|
||||
<label class="SchedulerFormDetail-label">
|
||||
Description
|
||||
Schedule Description
|
||||
</label>
|
||||
<div class="SchedulerFormDetail-nlp">
|
||||
{{ rrule_nlp_description }}
|
||||
@@ -651,7 +651,7 @@
|
||||
<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>"
|
||||
data-placement="right" data-container="body" over-title="Extra Variables" class="help-link" data-original-title="" title="" tabindex="-1">
|
||||
<i class="fa fa-question-circle"></i>
|
||||
</a>
|
||||
</a>
|
||||
|
||||
<div class="parse-selection">
|
||||
<input type="radio" ng-model="parseType" ng-change="parseTypeChange()" value="yaml"><span class="parse-label">YAML</span>
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
align-items: center;
|
||||
max-height: 400px;
|
||||
width: 120px;
|
||||
overflow-y: scroll;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ export default {
|
||||
name: 'setup',
|
||||
route: '/setup',
|
||||
ncyBreadcrumb: {
|
||||
label: "SETUP"
|
||||
label: "SETTINGS"
|
||||
},
|
||||
templateUrl: templateUrl('setup-menu/setup-menu')
|
||||
};
|
||||
|
||||
@@ -59,7 +59,7 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper'])
|
||||
callback = params.callback,
|
||||
beforeDestroy = params.beforeDestroy,
|
||||
closeOnEscape = (params.closeOnEscape === undefined) ? false : params.closeOnEscape,
|
||||
resizable = (params.resizable === undefined) ? true : params.resizable,
|
||||
resizable = (params.resizable === undefined) ? false : params.resizable,
|
||||
draggable = (params.draggable === undefined) ? true : params.draggable,
|
||||
dialogClass = params.dialogClass,
|
||||
forms = _.chain([params.form]).flatten().compact().value(),
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
// buttons
|
||||
@btn-bg: @default-bg;
|
||||
@btn-bord: @default-border;
|
||||
@btn-bord: @d7grey;
|
||||
@btn-txt: @default-interface-txt;
|
||||
@btn-bg-hov: @default-tertiary-bg;
|
||||
@btn-bg-sel: @default-icon-hov;
|
||||
|
||||
@@ -714,13 +714,10 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
function label() {
|
||||
var html = '';
|
||||
if (field.label || field.labelBind) {
|
||||
html += "<label ";
|
||||
if (horizontal || field.labelClass) {
|
||||
html += "class=\"";
|
||||
html += (field.labelClass) ? field.labelClass : "";
|
||||
html += (horizontal) ? " " + getLabelWidth() : "";
|
||||
html += "\" ";
|
||||
}
|
||||
html += "<label class=\"";
|
||||
html += (field.labelClass) ? field.labelClass : "";
|
||||
html += (horizontal) ? " " + getLabelWidth() : "Form-inputLabelContainer ";
|
||||
html += "\" ";
|
||||
html += (field.labelNGClass) ? "ng-class=\"" + field.labelNGClass + "\" " : "";
|
||||
html += "for=\"" + fld + '">\n';
|
||||
html += (field.icon) ? Icon(field.icon) : "";
|
||||
@@ -742,6 +739,14 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
html += "\" value=\"json\" ng-change=\"parseTypeChange()\"> <span class=\"parse-label\">JSON</span>\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
if (field.labelAction) {
|
||||
let action = field.labelAction;
|
||||
let href = action.href || "";
|
||||
let ngClick = action.ngClick || "";
|
||||
let cls = action["class"] || "";
|
||||
html += `<a class="Form-labelAction ${cls}" href="${href}" ng-click="${ngClick}">${action.label}</a>`;
|
||||
}
|
||||
html += "\n\t</label>\n";
|
||||
}
|
||||
return html;
|
||||
@@ -787,7 +792,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
|
||||
if ((!field.readonly) || (field.readonly && options.mode === 'edit')) {
|
||||
|
||||
if((field.excludeMode === undefined || field.excludeMode !== options.mode)) {
|
||||
if((field.excludeMode === undefined || field.excludeMode !== options.mode) && field.type !== 'alertblock') {
|
||||
|
||||
|
||||
html += "<div class='form-group Form-formGroup ";
|
||||
@@ -1612,7 +1617,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
currentSubForm = field.subForm;
|
||||
var subFormTitle = this.form.subFormTitles[field.subForm];
|
||||
|
||||
html += '<div class="Form-subForm '+ currentSubForm + '" ng-hide="'+ hasSubFormField + '.value === undefined"> ';
|
||||
html += '<div class="Form-subForm '+ currentSubForm + '" ng-hide="'+ hasSubFormField + '.value === undefined || ' + field.hideSubForm + '"> ';
|
||||
html += '<span class="Form-subForm--title">'+ subFormTitle +'</span>';
|
||||
}
|
||||
else if (!field.subForm && currentSubForm !== undefined) {
|
||||
@@ -1838,7 +1843,12 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
`;
|
||||
|
||||
// Show the "no items" box when loading is done and the user isn't actively searching and there are no results
|
||||
html += "<div class=\"List-noItems\" ng-show=\"" + collection.iterator + "Loading == false && " + collection.iterator + "_active_search == false && " + collection.iterator + "_total_rows < 1\">PLEASE ADD ITEMS TO THIS LIST</div>";
|
||||
// Allow for the suppression of the empty list text to avoid duplication between form generator and list generator
|
||||
var emptyListText = (collection.emptyListText) ? collection.emptyListText : "PLEASE ADD ITEMS TO THIS LIST";
|
||||
html += '<div ng-hide="is_superuser">';
|
||||
html += "<div class=\"List-noItems\" ng-hide=\"is_superuser\" ng-show=\"" + collection.iterator + "Loading == false && " + collection.iterator + "_active_search == false && " + collection.iterator + "_total_rows < 1\">" + emptyListText + "</div>";
|
||||
html += '</div>';
|
||||
//}
|
||||
|
||||
html += `
|
||||
<div class=\"List-noItems\" ng-show=\"is_superuser\">
|
||||
|
||||
@@ -8,7 +8,6 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce
|
||||
function ($log, $rootScope, $scope, $state, $stateParams, ProcessErrors, Rest, Wait) {
|
||||
|
||||
var api_complete = false,
|
||||
stdout_url,
|
||||
current_range,
|
||||
loaded_sections = [],
|
||||
event_queue = 0,
|
||||
@@ -87,7 +86,7 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce
|
||||
});
|
||||
|
||||
function loadStdout() {
|
||||
Rest.setUrl($scope.stdoutEndpoint + '?format=json&start_line=-' + page_size);
|
||||
Rest.setUrl($scope.stdoutEndpoint + '?format=json&start_line=0&end_line=' + page_size);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
Wait('stop');
|
||||
@@ -145,38 +144,17 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce
|
||||
});
|
||||
}
|
||||
|
||||
$scope.stdOutScrollToTop = function() {
|
||||
// scroll up or back in time toward the beginning of the file
|
||||
var start, end, url;
|
||||
if (loaded_sections.length > 0 && loaded_sections[0].start > 0) {
|
||||
start = (loaded_sections[0].start - page_size > 0) ? loaded_sections[0].start - page_size : 0;
|
||||
end = loaded_sections[0].start - 1;
|
||||
}
|
||||
else if (loaded_sections.length === 0) {
|
||||
start = 0;
|
||||
end = page_size;
|
||||
}
|
||||
if (start !== undefined && end !== undefined) {
|
||||
$('#stdoutMoreRowsTop').fadeIn();
|
||||
url = stdout_url + '?format=json&start_line=' + start + '&end_line=' + end;
|
||||
// lrInfiniteScroll handler
|
||||
// grabs the next stdout section
|
||||
$scope.stdOutGetNextSection = function(){
|
||||
if (current_range.absolute_end > current_range.end){
|
||||
var url = $scope.stdoutEndpoint + '?format=json&start_line=' + current_range.end +
|
||||
'&end_line=' + (current_range.end + page_size);
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data) {
|
||||
//var currentPos = $('#pre-container').scrollTop();
|
||||
var newSH, oldSH = $('#pre-container').prop('scrollHeight'),
|
||||
st = $('#pre-container').scrollTop();
|
||||
|
||||
$('#pre-container-content').prepend(data.content);
|
||||
|
||||
newSH = $('#pre-container').prop('scrollHeight');
|
||||
$('#pre-container').scrollTop(newSH - oldSH + st);
|
||||
|
||||
loaded_sections.unshift({
|
||||
start: (data.range.start < 0) ? 0 : data.range.start,
|
||||
end: data.range.end
|
||||
});
|
||||
.success(function(data){
|
||||
$('#pre-container-content').append(data.content);
|
||||
current_range = data.range;
|
||||
$('#stdoutMoreRowsTop').fadeOut(400);
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<div class="StandardOut-consoleOutput">
|
||||
<div id="pre-container" class="body_background body_foreground pre mono-space StandardOut-preContainer"
|
||||
lr-infinite-scroll="stdOutScrollToTop" scroll-threshold="300" data-direction="up" time-threshold="500">
|
||||
<div class="StandardOut-consoleOutput" lr-infinite-scroll="stdOutGetNextSection" scroll-threshold="300" time-threshold="500">
|
||||
<div id="pre-container" class="body_background body_foreground pre mono-space StandardOut-preContainer">
|
||||
<div id="pre-container-content" class="StandardOut-preContent"></div>
|
||||
</div>
|
||||
<div class="scroll-spinner" id="stdoutMoreRowsBottom">
|
||||
|
||||
Reference in New Issue
Block a user