mirror of
https://github.com/ansible/awx.git
synced 2024-10-31 06:51:10 +03:00
Set up new inventory directory and states
This commit is contained in:
parent
8c7adddaf3
commit
f9b46b7c3d
@ -130,6 +130,10 @@
|
||||
.noselect;
|
||||
}
|
||||
|
||||
.Form-tab--notitle {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.Form-tab:hover {
|
||||
color: @btn-txt;
|
||||
background-color: @btn-bg-hov;
|
||||
|
@ -40,6 +40,7 @@ if ($basePath) {
|
||||
import portalMode from './portal-mode/main';
|
||||
import systemTracking from './system-tracking/main';
|
||||
import inventories from './inventories/main';
|
||||
import inventorynew from './inventoriesnew/main';
|
||||
import inventoryScripts from './inventory-scripts/main';
|
||||
import credentialTypes from './credential-types/main';
|
||||
import organizations from './organizations/main';
|
||||
@ -99,6 +100,7 @@ var tower = angular.module('Tower', [
|
||||
configuration.name,
|
||||
systemTracking.name,
|
||||
inventories.name,
|
||||
inventorynew.name,
|
||||
inventoryScripts.name,
|
||||
credentialTypes.name,
|
||||
organizations.name,
|
||||
|
@ -250,7 +250,7 @@ function InventoriesList($scope, $rootScope, $location,
|
||||
};
|
||||
|
||||
$scope.addInventory = function () {
|
||||
$state.go('inventories.add');
|
||||
$state.go('inventoriesnew.add');
|
||||
};
|
||||
|
||||
$scope.editInventory = function (id) {
|
||||
|
104
awx/ui/client/src/inventoriesnew/add/inventory-add.controller.js
Normal file
104
awx/ui/client/src/inventoriesnew/add/inventory-add.controller.js
Normal file
@ -0,0 +1,104 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Inventories
|
||||
* @description This controller's for the Inventory page
|
||||
*/
|
||||
|
||||
function InventoriesAdd($scope, $location,
|
||||
GenerateForm, InventoryForm, rbacUiControlService, Rest, Alert, ProcessErrors,
|
||||
ClearScope, GetBasePath, ParseTypeChange, Wait, ToJSON,
|
||||
$state) {
|
||||
|
||||
$scope.canAdd = false;
|
||||
rbacUiControlService.canAdd(GetBasePath('inventory'))
|
||||
.then(function(canAdd) {
|
||||
$scope.canAdd = canAdd;
|
||||
});
|
||||
|
||||
Rest.setUrl(GetBasePath('inventory'));
|
||||
Rest.options()
|
||||
.success(function(data) {
|
||||
if (!data.actions.POST) {
|
||||
$state.go("^");
|
||||
Alert('Permission Error', 'You do not have permission to add an inventory.', 'alert-info');
|
||||
}
|
||||
});
|
||||
|
||||
ClearScope();
|
||||
|
||||
// Inject dynamic view
|
||||
var defaultUrl = GetBasePath('inventory'),
|
||||
form = InventoryForm;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.canEditOrg = true;
|
||||
form.formLabelSize = null;
|
||||
form.formFieldSize = null;
|
||||
|
||||
// apply form definition's default field values
|
||||
GenerateForm.applyDefaults(form, $scope);
|
||||
|
||||
$scope.parseType = 'yaml';
|
||||
ParseTypeChange({
|
||||
scope: $scope,
|
||||
variable: 'variables',
|
||||
parse_variable: 'parseType',
|
||||
field_id: 'inventory_variables'
|
||||
});
|
||||
}
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
Wait('start');
|
||||
try {
|
||||
var fld, json_data, data;
|
||||
|
||||
json_data = ToJSON($scope.parseType, $scope.variables, true);
|
||||
|
||||
data = {};
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].realName) {
|
||||
data[form.fields[fld].realName] = $scope[fld];
|
||||
} else {
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
}
|
||||
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.post(data)
|
||||
.success(function(data) {
|
||||
var inventory_id = data.id;
|
||||
Wait('stop');
|
||||
$location.path('/inventoriesnew/' + inventory_id);
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to add new inventory. Post returned status: ' + status
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
Wait('stop');
|
||||
Alert("Error", "Error parsing inventory variables. Parser returned: " + err);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('inventoriesnew');
|
||||
};
|
||||
}
|
||||
|
||||
export default ['$scope', '$location',
|
||||
'GenerateForm', 'InventoryForm', 'rbacUiControlService', 'Rest', 'Alert',
|
||||
'ProcessErrors', 'ClearScope', 'GetBasePath', 'ParseTypeChange',
|
||||
'Wait', 'ToJSON', '$state', InventoriesAdd
|
||||
];
|
11
awx/ui/client/src/inventoriesnew/add/main.js
Normal file
11
awx/ui/client/src/inventoriesnew/add/main.js
Normal file
@ -0,0 +1,11 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import controller from './inventory-add.controller';
|
||||
|
||||
export default
|
||||
angular.module('newInventoryAdd', [])
|
||||
.controller('NewInventoryAddController', controller);
|
@ -0,0 +1,136 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Inventories
|
||||
* @description This controller's for the Inventory page
|
||||
*/
|
||||
|
||||
function InventoriesEdit($scope, $location,
|
||||
$stateParams, InventoriesNewForm, Rest, ProcessErrors,
|
||||
ClearScope, GetBasePath, ParseTypeChange, Wait, ToJSON,
|
||||
ParseVariableString, $state, OrgAdminLookup) {
|
||||
|
||||
// Inject dynamic view
|
||||
var defaultUrl = GetBasePath('inventory'),
|
||||
form = InventoriesNewForm,
|
||||
inventory_id = $stateParams.inventory_id,
|
||||
master = {},
|
||||
fld, json_data, data;
|
||||
|
||||
ClearScope();
|
||||
init();
|
||||
|
||||
function init() {
|
||||
ClearScope();
|
||||
form.formLabelSize = null;
|
||||
form.formFieldSize = null;
|
||||
$scope.inventory_id = inventory_id;
|
||||
|
||||
$scope.$watch('inventory_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||
if (val === false) {
|
||||
$scope.canAdd = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Wait('start');
|
||||
Rest.setUrl(GetBasePath('inventory') + inventory_id + '/');
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
var fld;
|
||||
for (fld in form.fields) {
|
||||
if (fld === 'variables') {
|
||||
$scope.variables = ParseVariableString(data.variables);
|
||||
master.variables = $scope.variables;
|
||||
} else if (fld === 'inventory_name') {
|
||||
$scope[fld] = data.name;
|
||||
master[fld] = $scope[fld];
|
||||
} else if (fld === 'inventory_description') {
|
||||
$scope[fld] = data.description;
|
||||
master[fld] = $scope[fld];
|
||||
} else if (data[fld]) {
|
||||
$scope[fld] = data[fld];
|
||||
master[fld] = $scope[fld];
|
||||
}
|
||||
if (form.fields[fld].sourceModel && data.summary_fields &&
|
||||
data.summary_fields[form.fields[fld].sourceModel]) {
|
||||
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
}
|
||||
}
|
||||
|
||||
Wait('stop');
|
||||
$scope.parseType = 'yaml';
|
||||
ParseTypeChange({
|
||||
scope: $scope,
|
||||
variable: 'variables',
|
||||
parse_variable: 'parseType',
|
||||
field_id: 'inventory_variables'
|
||||
});
|
||||
|
||||
OrgAdminLookup.checkForAdminAccess({organization: data.organization})
|
||||
.then(function(canEditOrg){
|
||||
$scope.canEditOrg = canEditOrg;
|
||||
});
|
||||
|
||||
$scope.inventory_obj = data;
|
||||
$scope.name = data.name;
|
||||
|
||||
$scope.$emit('inventoryLoaded');
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status
|
||||
});
|
||||
});
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
Wait('start');
|
||||
|
||||
// Make sure we have valid variable data
|
||||
json_data = ToJSON($scope.parseType, $scope.variables);
|
||||
|
||||
data = {};
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].realName) {
|
||||
data[form.fields[fld].realName] = $scope[fld];
|
||||
} else {
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
}
|
||||
|
||||
Rest.setUrl(defaultUrl + inventory_id + '/');
|
||||
Rest.put(data)
|
||||
.success(function() {
|
||||
Wait('stop');
|
||||
$state.go($state.current, {}, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to update inventory. PUT returned status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('inventoriesnew');
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default ['$scope', '$location',
|
||||
'$stateParams', 'InventoriesNewForm', 'Rest',
|
||||
'ProcessErrors', 'ClearScope', 'GetBasePath', 'ParseTypeChange', 'Wait',
|
||||
'ToJSON', 'ParseVariableString',
|
||||
'$state', 'OrgAdminLookup', InventoriesEdit,
|
||||
];
|
11
awx/ui/client/src/inventoriesnew/edit/main.js
Normal file
11
awx/ui/client/src/inventoriesnew/edit/main.js
Normal file
@ -0,0 +1,11 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import controller from './inventory-edit.controller';
|
||||
|
||||
export default
|
||||
angular.module('newInventoryEdit', [])
|
||||
.controller('NewInventoryEditController', controller);
|
@ -0,0 +1,14 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
function HostsAdd($scope) {
|
||||
|
||||
console.log('inside host add');
|
||||
|
||||
}
|
||||
|
||||
export default ['$scope', HostsAdd
|
||||
];
|
11
awx/ui/client/src/inventoriesnew/hosts/add/main.js
Normal file
11
awx/ui/client/src/inventoriesnew/hosts/add/main.js
Normal file
@ -0,0 +1,11 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import controller from './host-add.controller';
|
||||
|
||||
export default
|
||||
angular.module('hostsAdd', [])
|
||||
.controller('NewHostAddController', controller);
|
@ -0,0 +1,14 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
function HostsEdit($scope) {
|
||||
|
||||
console.log('inside host edit');
|
||||
|
||||
}
|
||||
|
||||
export default ['$scope', HostsEdit
|
||||
];
|
11
awx/ui/client/src/inventoriesnew/hosts/edit/main.js
Normal file
11
awx/ui/client/src/inventoriesnew/hosts/edit/main.js
Normal file
@ -0,0 +1,11 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import controller from './host-edit.controller';
|
||||
|
||||
export default
|
||||
angular.module('hostsEdit', [])
|
||||
.controller('NewHostEditController', controller);
|
103
awx/ui/client/src/inventoriesnew/hosts/host.form.js
Normal file
103
awx/ui/client/src/inventoriesnew/hosts/host.form.js
Normal file
@ -0,0 +1,103 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name forms.function:Hosts
|
||||
* @description This form is for adding/editing a host on the inventory page
|
||||
*/
|
||||
|
||||
export default ['i18n', function(i18n) {
|
||||
return {
|
||||
|
||||
addTitle: i18n._('CREATE HOST'),
|
||||
editTitle: '{{ host.name }}',
|
||||
name: 'host',
|
||||
basePath: 'hosts',
|
||||
well: false,
|
||||
formLabelSize: 'col-lg-3',
|
||||
formFieldSize: 'col-lg-9',
|
||||
iterator: 'host',
|
||||
headerFields:{
|
||||
enabled: {
|
||||
class: 'Form-header-field',
|
||||
ngClick: 'toggleHostEnabled(host)',
|
||||
type: 'toggle',
|
||||
awToolTip: "<p>" +
|
||||
i18n._("Indicates if a host is available and should be included in running jobs.") +
|
||||
"</p><p>" +
|
||||
i18n._("For hosts that are part of an external" +
|
||||
" inventory, this flag cannot be changed. It will be" +
|
||||
" set by the inventory sync process.") +
|
||||
"</p>",
|
||||
dataTitle: i18n._('Host Enabled'),
|
||||
ngDisabled: 'host.has_inventory_sources'
|
||||
}
|
||||
},
|
||||
fields: {
|
||||
name: {
|
||||
label: i18n._('Host Name'),
|
||||
type: 'text',
|
||||
required: true,
|
||||
awPopOver: "<p>" +
|
||||
i18n._("Provide a host name, ip address, or ip address:port. Examples include:") +
|
||||
"</p>" +
|
||||
"<blockquote>myserver.domain.com<br/>" +
|
||||
"127.0.0.1<br />" +
|
||||
"10.1.0.140:25<br />" +
|
||||
"server.example.com:25" +
|
||||
"</blockquote>",
|
||||
dataTitle: i18n._('Host Name'),
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body',
|
||||
ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
description: {
|
||||
label: i18n._('Description'),
|
||||
ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd)',
|
||||
type: 'text'
|
||||
},
|
||||
variables: {
|
||||
label: i18n._('Variables'),
|
||||
type: 'textarea',
|
||||
rows: 6,
|
||||
class: 'Form-formGroup--fullWidth',
|
||||
"default": "---",
|
||||
awPopOver: "<p>" + i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "</p>" +
|
||||
"JSON:<br />\n" +
|
||||
"<blockquote>{<br /> \"somevar\": \"somevalue\",<br /> \"password\": \"magic\"<br /> }</blockquote>\n" +
|
||||
"YAML:<br />\n" +
|
||||
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" +
|
||||
'<p>' + i18n.sprintf(i18n._('View JSON examples at %s'), '<a href="http://www.json.org" target="_blank">www.json.org</a>') + '</p>' +
|
||||
'<p>' + i18n.sprintf(i18n._('View YAML examples at %s'), '<a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a>') + '</p>',
|
||||
dataTitle: i18n._('Host Variables'),
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body'
|
||||
},
|
||||
inventory: {
|
||||
type: 'hidden',
|
||||
includeOnEdit: true,
|
||||
includeOnAdd: true
|
||||
}
|
||||
},
|
||||
|
||||
buttons: {
|
||||
cancel: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '(host.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
close: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '!(host.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true,
|
||||
ngShow: '(host.summary_fields.user_capabilities.edit || canAdd)'
|
||||
}
|
||||
},
|
||||
};
|
||||
}];
|
121
awx/ui/client/src/inventoriesnew/hosts/host.list.js
Normal file
121
awx/ui/client/src/inventoriesnew/hosts/host.list.js
Normal file
@ -0,0 +1,121 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['i18n', function(i18n) {
|
||||
return {
|
||||
name: 'hosts',
|
||||
iterator: 'host',
|
||||
editTitle: '{{ selected_group }}',
|
||||
searchSize: 'col-lg-12 col-md-12 col-sm-12 col-xs-12',
|
||||
showTitle: false,
|
||||
well: true,
|
||||
index: false,
|
||||
hover: true,
|
||||
hasChildren: true,
|
||||
'class': 'table-no-border',
|
||||
trackBy: 'host.id',
|
||||
title: false,
|
||||
|
||||
fields: {
|
||||
toggleHost: {
|
||||
ngDisabled: "!host.summary_fields.user_capabilities.edit",
|
||||
label: '',
|
||||
columnClass: 'List-staticColumn--toggle',
|
||||
type: "toggle",
|
||||
ngClick: "toggleHost($event, host)",
|
||||
awToolTip: "<p>" +
|
||||
i18n._("Indicates if a host is available and should be included in running jobs.") +
|
||||
"</p><p>" +
|
||||
i18n._("For hosts that are part of an external" +
|
||||
" inventory, this flag cannot be changed. It will be" +
|
||||
" set by the inventory sync process.") +
|
||||
"</p>",
|
||||
dataPlacement: "right",
|
||||
nosort: true,
|
||||
},
|
||||
active_failures: {
|
||||
label: '',
|
||||
iconOnly: true,
|
||||
nosort: true,
|
||||
// do not remove this ng-click directive
|
||||
// the list generator case to handle fields without ng-click
|
||||
// cannot handle the aw-* directives
|
||||
ngClick: 'noop()',
|
||||
awPopOver: "{{ host.job_status_html }}",
|
||||
dataTitle: "{{ host.job_status_title }}",
|
||||
awToolTip: "{{ host.badgeToolTip }}",
|
||||
dataPlacement: 'top',
|
||||
icon: "{{ 'fa icon-job-' + host.active_failures }}",
|
||||
id: 'active-failures-action',
|
||||
columnClass: 'status-column List-staticColumn--smallStatus'
|
||||
},
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name',
|
||||
ngClick: "editHost(host.id)",
|
||||
columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7',
|
||||
dataHostId: "{{ host.id }}",
|
||||
dataType: "host",
|
||||
class: 'InventoryManage-breakWord'
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
|
||||
columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right',
|
||||
copy: {
|
||||
mode: 'all',
|
||||
ngClick: "copyMoveHost(host.id)",
|
||||
awToolTip: 'Copy or move host to another group',
|
||||
dataPlacement: "top",
|
||||
ngShow: 'host.summary_fields.user_capabilities.edit'
|
||||
},
|
||||
edit: {
|
||||
//label: 'Edit',
|
||||
ngClick: "editHost(host.id)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Edit host',
|
||||
dataPlacement: 'top',
|
||||
ngShow: 'host.summary_fields.user_capabilities.edit'
|
||||
},
|
||||
view: {
|
||||
//label: 'Edit',
|
||||
ngClick: "editHost(host.id)",
|
||||
awToolTip: 'View host',
|
||||
dataPlacement: 'top',
|
||||
ngShow: '!host.summary_fields.user_capabilities.edit'
|
||||
},
|
||||
"delete": {
|
||||
//label: 'Delete',
|
||||
ngClick: "deleteHost(host.id, host.name)",
|
||||
icon: 'icon-trash',
|
||||
awToolTip: 'Delete host',
|
||||
dataPlacement: 'top',
|
||||
ngShow: 'host.summary_fields.user_capabilities.delete'
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
refresh: {
|
||||
mode: 'all',
|
||||
awToolTip: "Refresh the page",
|
||||
ngClick: "refreshGroups()",
|
||||
ngShow: "socketStatus == 'error'",
|
||||
actionClass: 'btn List-buttonDefault',
|
||||
buttonContent: 'REFRESH'
|
||||
},
|
||||
smart_inventory: {
|
||||
mode: 'all',
|
||||
ngClick: "smartInventory()",
|
||||
awToolTip: "Create a new Smart Inventory from results.",
|
||||
actionClass: 'btn List-buttonDefault',
|
||||
buttonContent: 'SMART INVENTORY',
|
||||
ngShow: 'canAdd',
|
||||
dataPlacement: "top",
|
||||
}
|
||||
}
|
||||
};
|
||||
}];
|
@ -0,0 +1,80 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
function HostsList($scope, HostsNewList, $rootScope, GetBasePath,
|
||||
rbacUiControlService, Dataset, $state, $filter, Prompt, Wait, HostManageService) {
|
||||
|
||||
let list = HostsNewList;
|
||||
|
||||
init();
|
||||
|
||||
function init(){
|
||||
$scope.canAdd = false;
|
||||
|
||||
rbacUiControlService.canAdd('hosts')
|
||||
.then(function(canAdd) {
|
||||
$scope.canAdd = canAdd;
|
||||
});
|
||||
|
||||
// Search init
|
||||
$scope.list = list;
|
||||
$scope[`${list.iterator}_dataset`] = Dataset.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
}
|
||||
|
||||
$scope.createHost = function(){
|
||||
$state.go('hostsnew.add');
|
||||
};
|
||||
$scope.editHost = function(id){
|
||||
$state.go('hostsnew.edit', {host_id: id});
|
||||
};
|
||||
$scope.deleteHost = function(id, name){
|
||||
var body = '<div class=\"Prompt-bodyQuery\">Are you sure you want to permanently delete the host below from the inventory?</div><div class=\"Prompt-bodyTarget\">' + $filter('sanitize')(name) + '</div>';
|
||||
var action = function(){
|
||||
delete $rootScope.promptActionBtnClass;
|
||||
Wait('start');
|
||||
HostManageService.delete(id).then(() => {
|
||||
$('#prompt-modal').modal('hide');
|
||||
if (parseInt($state.params.host_id) === id) {
|
||||
$state.go("hostsnew", null, {reload: true});
|
||||
} else {
|
||||
$state.go($state.current.name, null, {reload: true});
|
||||
}
|
||||
Wait('stop');
|
||||
});
|
||||
};
|
||||
// Prompt depends on having $rootScope.promptActionBtnClass available...
|
||||
Prompt({
|
||||
hdr: 'Delete Host',
|
||||
body: body,
|
||||
action: action,
|
||||
actionText: 'DELETE',
|
||||
});
|
||||
$rootScope.promptActionBtnClass = 'Modal-errorButton';
|
||||
};
|
||||
|
||||
$scope.toggleHost = function(event, host) {
|
||||
try {
|
||||
$(event.target).tooltip('hide');
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
host.enabled = !host.enabled;
|
||||
|
||||
HostManageService.put(host).then(function(){
|
||||
$state.go($state.current, null, {reload: true});
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default ['$scope', 'HostsNewList', '$rootScope', 'GetBasePath',
|
||||
'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait', 'HostManageService', HostsList
|
||||
];
|
11
awx/ui/client/src/inventoriesnew/hosts/list/main.js
Normal file
11
awx/ui/client/src/inventoriesnew/hosts/list/main.js
Normal file
@ -0,0 +1,11 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import controller from './host-list.controller';
|
||||
|
||||
export default
|
||||
angular.module('hostsList', [])
|
||||
.controller('NewHostListController', controller);
|
20
awx/ui/client/src/inventoriesnew/hosts/main.js
Normal file
20
awx/ui/client/src/inventoriesnew/hosts/main.js
Normal file
@ -0,0 +1,20 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import hostAdd from './add/main';
|
||||
import hostEdit from './edit/main';
|
||||
import hostList from './list/main';
|
||||
import HostsNewList from './host.list';
|
||||
import HostsNewForm from './host.form';
|
||||
|
||||
export default
|
||||
angular.module('hostnew', [
|
||||
hostAdd.name,
|
||||
hostEdit.name,
|
||||
hostList.name
|
||||
])
|
||||
.factory('HostsNewForm', HostsNewForm)
|
||||
.factory('HostsNewList', HostsNewList);
|
14
awx/ui/client/src/inventoriesnew/inventories.partial.html
Normal file
14
awx/ui/client/src/inventoriesnew/inventories.partial.html
Normal file
@ -0,0 +1,14 @@
|
||||
<div class="tab-pane" id="inventoriesnew-panel">
|
||||
<div ui-view="form"></div>
|
||||
<div ng-cloak id="htmlTemplate" class="Panel">
|
||||
<div class="row Form-tabRow">
|
||||
<div class="col-lg-12">
|
||||
<div class="Form-tabHolder">
|
||||
<div class="Form-tab Form-tab--notitle" ng-click="$state.go('inventoriesnew')" ng-class="{'is-selected': $state.includes('inventoriesnew')}" translate>INVENTORIES</div>
|
||||
<div class="Form-tab Form-tab--notitle" ng-click="$state.go('hostsnew')" ng-class="{'is-selected': $state.includes('hostsnew')}" translate>HOSTS</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ui-view="list"></div>
|
||||
</div>
|
||||
</div>
|
135
awx/ui/client/src/inventoriesnew/inventory.form.js
Normal file
135
awx/ui/client/src/inventoriesnew/inventory.form.js
Normal file
@ -0,0 +1,135 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name forms.function:Inventories
|
||||
* @description This form is for adding/editing an inventory
|
||||
*/
|
||||
|
||||
export default ['i18n', function(i18n) {
|
||||
return {
|
||||
|
||||
addTitle: i18n._('NEW INVENTORY'),
|
||||
editTitle: '{{ inventory_name }}',
|
||||
name: 'inventory',
|
||||
basePath: 'inventory',
|
||||
// the top-most node of this generated state tree
|
||||
stateTree: 'inventoriesnew',
|
||||
tabs: true,
|
||||
|
||||
fields: {
|
||||
inventory_name: {
|
||||
realName: 'name',
|
||||
label: i18n._('Name'),
|
||||
type: 'text',
|
||||
required: true,
|
||||
capitalize: false,
|
||||
ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
inventory_description: {
|
||||
realName: 'description',
|
||||
label: i18n._('Description'),
|
||||
type: 'text',
|
||||
ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
organization: {
|
||||
label: i18n._('Organization'),
|
||||
type: 'lookup',
|
||||
basePath: 'organizations',
|
||||
list: 'OrganizationList',
|
||||
sourceModel: 'organization',
|
||||
sourceField: 'name',
|
||||
awRequiredWhen: {
|
||||
reqExpression: "organizationrequired",
|
||||
init: "true"
|
||||
},
|
||||
ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd) || !canEditOrg',
|
||||
awLookupWhen: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd) && canEditOrg'
|
||||
},
|
||||
variables: {
|
||||
label: i18n._('Variables'),
|
||||
type: 'textarea',
|
||||
class: 'Form-formGroup--fullWidth',
|
||||
rows: 6,
|
||||
"default": "---",
|
||||
awPopOver: "<p>" + i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "</p>" +
|
||||
"JSON:<br />\n" +
|
||||
"<blockquote>{<br /> \"somevar\": \"somevalue\",<br /> \"password\": \"magic\"<br /> }</blockquote>\n" +
|
||||
"YAML:<br />\n" +
|
||||
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" +
|
||||
'<p>' + i18n.sprintf(i18n._('View JSON examples at %s'), '<a href="http://www.json.org" target="_blank">www.json.org</a>') + '</p>' +
|
||||
'<p>' + i18n.sprintf(i18n._('View YAML examples at %s'), '<a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a>') + '</p>',
|
||||
dataTitle: i18n._('Inventory Variables'),
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body',
|
||||
ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working
|
||||
}
|
||||
},
|
||||
|
||||
buttons: {
|
||||
cancel: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
close: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true,
|
||||
ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
}
|
||||
},
|
||||
related: {
|
||||
permissions: {
|
||||
name: 'permissions',
|
||||
awToolTip: i18n._('Please save before assigning permissions'),
|
||||
dataPlacement: 'top',
|
||||
basePath: 'api/v1/inventories/{{$stateParams.inventory_id}}/access_list/',
|
||||
type: 'collection',
|
||||
title: i18n._('Permissions'),
|
||||
iterator: 'permission',
|
||||
index: false,
|
||||
open: false,
|
||||
search: {
|
||||
order_by: 'username'
|
||||
},
|
||||
actions: {
|
||||
add: {
|
||||
label: i18n._('Add'),
|
||||
ngClick: "$state.go('.add')",
|
||||
awToolTip: i18n._('Add a permission'),
|
||||
actionClass: 'btn List-buttonSubmit',
|
||||
buttonContent: '+ ADD',
|
||||
ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
|
||||
}
|
||||
},
|
||||
fields: {
|
||||
username: {
|
||||
label: i18n._('User'),
|
||||
linkBase: 'users',
|
||||
class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4'
|
||||
},
|
||||
role: {
|
||||
label: i18n._('Role'),
|
||||
type: 'role',
|
||||
nosort: true,
|
||||
class: 'col-lg-4 col-md-4 col-sm-4 col-xs-4',
|
||||
},
|
||||
team_roles: {
|
||||
label: i18n._('Team Roles'),
|
||||
type: 'team_roles',
|
||||
nosort: true,
|
||||
class: 'col-lg-5 col-md-5 col-sm-5 col-xs-4',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};}];
|
98
awx/ui/client/src/inventoriesnew/inventory.list.js
Normal file
98
awx/ui/client/src/inventoriesnew/inventory.list.js
Normal file
@ -0,0 +1,98 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
|
||||
export default ['i18n', function(i18n) {
|
||||
return {
|
||||
|
||||
name: 'inventoriesnew',
|
||||
iterator: 'inventory',
|
||||
selectTitle: i18n._('Add Inventories'),
|
||||
editTitle: i18n._('INVENTORIES'),
|
||||
listTitle: i18n._('INVENTORIES'),
|
||||
selectInstructions: i18n.sprintf(i18n._("Click on a row to select it, and click Finished when done. Click the %s button to create a new inventory."), "<i class=\"icon-plus\"></i> "),
|
||||
index: false,
|
||||
hover: true,
|
||||
basePath: 'inventory',
|
||||
title: false,
|
||||
|
||||
fields: {
|
||||
status: {
|
||||
label: '',
|
||||
columnClass: 'List-staticColumn--mediumStatus',
|
||||
nosort: true,
|
||||
ngClick: "null",
|
||||
iconOnly: true,
|
||||
excludeModal: true,
|
||||
icons: [{
|
||||
icon: "{{ 'icon-cloud-' + inventory.syncStatus }}",
|
||||
awToolTip: "{{ inventory.syncTip }}",
|
||||
awTipPlacement: "right",
|
||||
ngClick: "showGroupSummary($event, inventory.id)",
|
||||
ngClass: "inventory.launch_class"
|
||||
},{
|
||||
icon: "{{ 'icon-job-' + inventory.hostsStatus }}",
|
||||
awToolTip: false,
|
||||
ngClick: "showHostSummary($event, inventory.id)",
|
||||
ngClass: ""
|
||||
}]
|
||||
},
|
||||
name: {
|
||||
key: true,
|
||||
label: i18n._('Name'),
|
||||
columnClass: 'col-md-5 col-sm-5 col-xs-8 List-staticColumnAdjacent',
|
||||
modalColumnClass: 'col-md-11',
|
||||
linkTo: '/#/inventoriesnew/{{inventory.id}}'
|
||||
},
|
||||
organization: {
|
||||
label: i18n._('Organization'),
|
||||
ngBind: 'inventory.summary_fields.organization.name',
|
||||
linkTo: '/#/organizations/{{ inventory.organization }}',
|
||||
sourceModel: 'organization',
|
||||
sourceField: 'name',
|
||||
excludeModal: true,
|
||||
columnClass: 'col-md-5 col-sm-3 hidden-xs'
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addInventory()',
|
||||
awToolTip: i18n._('Create a new inventory'),
|
||||
actionClass: 'btn List-buttonSubmit',
|
||||
buttonContent: '+ ' + i18n._('ADD'),
|
||||
ngShow: 'canAdd'
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
|
||||
columnClass: 'col-md-2 col-sm-4 col-xs-4',
|
||||
|
||||
edit: {
|
||||
label: i18n._('Edit'),
|
||||
ngClick: 'editInventory(inventory.id)',
|
||||
awToolTip: i18n._('Edit inventory'),
|
||||
dataPlacement: 'top',
|
||||
ngShow: 'inventory.summary_fields.user_capabilities.edit'
|
||||
},
|
||||
view: {
|
||||
label: i18n._('View'),
|
||||
ngClick: 'editInventory(inventory.id)',
|
||||
awToolTip: i18n._('View inventory'),
|
||||
dataPlacement: 'top',
|
||||
ngShow: '!inventory.summary_fields.user_capabilities.edit'
|
||||
},
|
||||
"delete": {
|
||||
label: i18n._('Delete'),
|
||||
ngClick: "deleteInventory(inventory.id, inventory.name)",
|
||||
awToolTip: i18n._('Delete inventory'),
|
||||
dataPlacement: 'top',
|
||||
ngShow: 'inventory.summary_fields.user_capabilities.delete'
|
||||
}
|
||||
}
|
||||
};}];
|
@ -0,0 +1,308 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Inventories
|
||||
* @description This controller's for the Inventory page
|
||||
*/
|
||||
|
||||
function InventoriesList($scope, $rootScope, $location,
|
||||
$compile, $filter, Rest, InventoriesNewList, Prompt,
|
||||
ProcessErrors, GetBasePath, Wait, Find, Empty, $state, rbacUiControlService, Dataset) {
|
||||
|
||||
let list = InventoriesNewList,
|
||||
defaultUrl = GetBasePath('inventory');
|
||||
|
||||
init();
|
||||
|
||||
function init(){
|
||||
$scope.canAdd = false;
|
||||
|
||||
rbacUiControlService.canAdd('inventory')
|
||||
.then(function(canAdd) {
|
||||
$scope.canAdd = canAdd;
|
||||
});
|
||||
|
||||
$scope.$watchCollection(list.name, function(){
|
||||
_.forEach($scope[list.name], buildStatusIndicators);
|
||||
});
|
||||
|
||||
// Search init
|
||||
$scope.list = list;
|
||||
$scope[`${list.iterator}_dataset`] = Dataset.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
}
|
||||
|
||||
function buildStatusIndicators(inventory){
|
||||
inventory.launch_class = "";
|
||||
if (inventory.has_inventory_sources) {
|
||||
if (inventory.inventory_sources_with_failures > 0) {
|
||||
inventory.syncStatus = 'error';
|
||||
inventory.syncTip = inventory.inventory_sources_with_failures + ' groups with sync failures. Click for details';
|
||||
}
|
||||
else {
|
||||
inventory.syncStatus = 'successful';
|
||||
inventory.syncTip = 'No inventory sync failures. Click for details.';
|
||||
}
|
||||
}
|
||||
else {
|
||||
inventory.syncStatus = 'na';
|
||||
inventory.syncTip = 'Not configured for inventory sync.';
|
||||
inventory.launch_class = "btn-disabled";
|
||||
}
|
||||
if (inventory.has_active_failures) {
|
||||
inventory.hostsStatus = 'error';
|
||||
inventory.hostsTip = inventory.hosts_with_active_failures + ' hosts with failures. Click for details.';
|
||||
}
|
||||
else if (inventory.total_hosts) {
|
||||
inventory.hostsStatus = 'successful';
|
||||
inventory.hostsTip = 'No hosts with failures. Click for details.';
|
||||
}
|
||||
else {
|
||||
inventory.hostsStatus = 'none';
|
||||
inventory.hostsTip = 'Inventory contains 0 hosts.';
|
||||
}
|
||||
}
|
||||
|
||||
function ellipsis(a) {
|
||||
if (a.length > 20) {
|
||||
return a.substr(0,20) + '...';
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
function attachElem(event, html, title) {
|
||||
var elem = $(event.target).parent();
|
||||
try {
|
||||
elem.tooltip('hide');
|
||||
elem.popover('destroy');
|
||||
}
|
||||
catch(err) {
|
||||
//ignore
|
||||
}
|
||||
$('.popover').each(function() {
|
||||
// remove lingering popover <div>. Seems to be a bug in TB3 RC1
|
||||
$(this).remove();
|
||||
});
|
||||
$('.tooltip').each( function() {
|
||||
// close any lingering tool tipss
|
||||
$(this).hide();
|
||||
});
|
||||
elem.attr({
|
||||
"aw-pop-over": html,
|
||||
"data-popover-title": title,
|
||||
"data-placement": "right" });
|
||||
elem.removeAttr('ng-click');
|
||||
$compile(elem)($scope);
|
||||
$scope.triggerPopover(event);
|
||||
}
|
||||
if ($scope.removeHostSummaryReady) {
|
||||
$scope.removeHostSummaryReady();
|
||||
}
|
||||
$scope.removeHostSummaryReady = $scope.$on('HostSummaryReady', function(e, event, data) {
|
||||
|
||||
var html, title = "Recent Jobs";
|
||||
Wait('stop');
|
||||
if (data.count > 0) {
|
||||
html = "<table class=\"table table-condensed flyout\" style=\"width: 100%\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>";
|
||||
html += "<th>Status</th>";
|
||||
html += "<th>Finished</th>";
|
||||
html += "<th>Name</th>";
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
|
||||
data.results.forEach(function(row) {
|
||||
html += "<tr>\n";
|
||||
html += "<td><a href=\"#/jobs/" + row.id + "\" " + "aw-tool-tip=\"" + row.status.charAt(0).toUpperCase() + row.status.slice(1) +
|
||||
". Click for details\" aw-tip-placement=\"top\"><i class=\"fa SmartStatus-tooltip--" + row.status + " icon-job-" + row.status + "\"></i></a></td>\n";
|
||||
html += "<td>" + ($filter('longDate')(row.finished)).replace(/ /,'<br />') + "</td>";
|
||||
html += "<td><a href=\"#/jobs/" + row.id + "\" " + "aw-tool-tip=\"" + row.status.charAt(0).toUpperCase() + row.status.slice(1) +
|
||||
". Click for details\" aw-tip-placement=\"top\">" + $filter('sanitize')(ellipsis(row.name)) + "</a></td>";
|
||||
html += "</tr>\n";
|
||||
});
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
}
|
||||
else {
|
||||
html = "<p>No recent job data available for this inventory.</p>\n";
|
||||
}
|
||||
attachElem(event, html, title);
|
||||
});
|
||||
|
||||
if ($scope.removeGroupSummaryReady) {
|
||||
$scope.removeGroupSummaryReady();
|
||||
}
|
||||
$scope.removeGroupSummaryReady = $scope.$on('GroupSummaryReady', function(e, event, inventory, data) {
|
||||
var html, title;
|
||||
|
||||
Wait('stop');
|
||||
|
||||
// Build the html for our popover
|
||||
html = "<table class=\"table table-condensed flyout\" style=\"width: 100%\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>";
|
||||
html += "<th>Status</th>";
|
||||
html += "<th>Last Sync</th>";
|
||||
html += "<th>Group</th>";
|
||||
html += "</tr>";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
data.results.forEach( function(row) {
|
||||
if (row.related.last_update) {
|
||||
html += "<tr>";
|
||||
html += `<td><a href="" ng-click="viewJob('${row.related.last_update}')" aw-tool-tip="${row.status.charAt(0).toUpperCase() + row.status.slice(1)}. Click for details" aw-tip-placement="top"><i class="SmartStatus-tooltip--${row.status} fa icon-job-${row.status}"></i></a></td>`;
|
||||
html += "<td>" + ($filter('longDate')(row.last_updated)).replace(/ /,'<br />') + "</td>";
|
||||
html += "<td><a href=\"\" ng-click=\"viewJob('" + row.related.last_update + "')\">" + $filter('sanitize')(ellipsis(row.summary_fields.group.name)) + "</a></td>";
|
||||
html += "</tr>\n";
|
||||
}
|
||||
else {
|
||||
html += "<tr>";
|
||||
html += "<td><a href=\"\" aw-tool-tip=\"No sync data\" aw-tip-placement=\"top\"><i class=\"fa icon-job-none\"></i></a></td>";
|
||||
html += "<td>NA</td>";
|
||||
html += "<td><a href=\"\">" + $filter('sanitize')(ellipsis(row.summary_fields.group.name)) + "</a></td>";
|
||||
html += "</tr>\n";
|
||||
}
|
||||
});
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
title = "Sync Status";
|
||||
attachElem(event, html, title);
|
||||
});
|
||||
|
||||
$scope.showGroupSummary = function(event, id) {
|
||||
try{
|
||||
var elem = $(event.target).parent();
|
||||
// if the popover is visible already, then exit the function here
|
||||
if(elem.data()['bs.popover'].tip().hasClass('in')){
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(err){
|
||||
var inventory;
|
||||
if (!Empty(id)) {
|
||||
inventory = Find({ list: $scope.inventories, key: 'id', val: id });
|
||||
if (inventory.syncStatus !== 'na') {
|
||||
Wait('start');
|
||||
Rest.setUrl(inventory.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5');
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.$emit('GroupSummaryReady', event, inventory, data);
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + inventory.related.inventory_sources + ' failed. GET returned status: ' + status
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.showHostSummary = function(event, id) {
|
||||
try{
|
||||
var elem = $(event.target).parent();
|
||||
// if the popover is visible already, then exit the function here
|
||||
if(elem.data()['bs.popover'].tip().hasClass('in')){
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(err){
|
||||
var url, inventory;
|
||||
if (!Empty(id)) {
|
||||
inventory = Find({ list: $scope.inventories, key: 'id', val: id });
|
||||
if (inventory.total_hosts > 0) {
|
||||
Wait('start');
|
||||
url = GetBasePath('jobs') + "?type=job&inventory=" + id + "&failed=";
|
||||
url += (inventory.has_active_failures) ? 'true' : "false";
|
||||
url += "&order_by=-finished&page_size=5";
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data) {
|
||||
$scope.$emit('HostSummaryReady', event, data);
|
||||
})
|
||||
.error( function(data, status) {
|
||||
ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. GET returned: ' + status
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.viewJob = function(url) {
|
||||
|
||||
// Pull the id out of the URL
|
||||
var id = url.replace(/^\//, '').split('/')[3];
|
||||
|
||||
$state.go('inventorySyncStdout', {id: id});
|
||||
|
||||
};
|
||||
|
||||
$scope.addInventory = function () {
|
||||
$state.go('inventoriesnew.add');
|
||||
};
|
||||
|
||||
$scope.editInventory = function (id) {
|
||||
$state.go('inventoriesnew.edit', {inventory_id: id});
|
||||
};
|
||||
|
||||
$scope.manageInventory = function(id){
|
||||
$location.path($location.path() + '/' + id + '/manage');
|
||||
};
|
||||
|
||||
$scope.deleteInventory = function (id, name) {
|
||||
|
||||
var action = function () {
|
||||
var url = defaultUrl + id + '/';
|
||||
Wait('start');
|
||||
$('#prompt-modal').modal('hide');
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function () {
|
||||
if (parseInt($state.params.inventory_id) === id) {
|
||||
$state.go("^", null, {reload: true});
|
||||
} else {
|
||||
$state.go('.', null, {reload: true});
|
||||
Wait('stop');
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: 'Delete',
|
||||
body: '<div class="Prompt-bodyQuery">Are you sure you want to delete the inventory below?</div><div class="Prompt-bodyTarget">' + $filter('sanitize')(name) + '</div>',
|
||||
action: action,
|
||||
actionText: 'DELETE'
|
||||
});
|
||||
};
|
||||
|
||||
// Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status
|
||||
$scope.viewJobs = function (id) {
|
||||
$location.url('/jobs/?inventory__int=' + id);
|
||||
};
|
||||
|
||||
$scope.viewFailedJobs = function (id) {
|
||||
$location.url('/jobs/?inventory__int=' + id + '&status=failed');
|
||||
};
|
||||
}
|
||||
|
||||
export default ['$scope', '$rootScope', '$location',
|
||||
'$compile', '$filter', 'Rest', 'InventoriesNewList',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state', 'rbacUiControlService', 'Dataset', InventoriesList
|
||||
];
|
11
awx/ui/client/src/inventoriesnew/list/main.js
Normal file
11
awx/ui/client/src/inventoriesnew/list/main.js
Normal file
@ -0,0 +1,11 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import controller from './inventory-list.controller';
|
||||
|
||||
export default
|
||||
angular.module('newInventoryList', [])
|
||||
.controller('NewInventoryListController', controller);
|
236
awx/ui/client/src/inventoriesnew/main.js
Normal file
236
awx/ui/client/src/inventoriesnew/main.js
Normal file
@ -0,0 +1,236 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import hostnew from './hosts/main';
|
||||
import inventoryAdd from './add/main';
|
||||
import inventoryEdit from './edit/main';
|
||||
import inventoryList from './list/main';
|
||||
import { templateUrl } from '../shared/template-url/template-url.factory';
|
||||
import { N_ } from '../i18n';
|
||||
// import inventoriesnewRoute from './inventories.route';
|
||||
import InventoriesNewList from './inventory.list';
|
||||
import InventoriesNewForm from './inventory.form';
|
||||
export default
|
||||
angular.module('inventorynew', [
|
||||
hostnew.name,
|
||||
inventoryAdd.name,
|
||||
inventoryEdit.name,
|
||||
inventoryList.name
|
||||
])
|
||||
.factory('InventoriesNewForm', InventoriesNewForm)
|
||||
.factory('InventoriesNewList', InventoriesNewList)
|
||||
.config(['$stateProvider', '$stateExtenderProvider', 'stateDefinitionsProvider',
|
||||
function($stateProvider, $stateExtenderProvider, stateDefinitionsProvider) {
|
||||
// When stateDefinition.lazyLoad() resolves, states matching name.** or /url** will be de-registered and replaced with resolved states
|
||||
// This means inventoryManage states will not be registered correctly on page refresh, unless they're registered at the same time as the inventories state tree
|
||||
let stateDefinitions = stateDefinitionsProvider.$get();
|
||||
|
||||
$stateProvider.state({
|
||||
name: 'inventoriesnew',
|
||||
url: '/inventoriesnew',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
parent: 'inventoriesnew', // top-most node in the generated tree (will replace this state definition)
|
||||
modes: ['add', 'edit'],
|
||||
list: 'InventoriesNewList',
|
||||
form: 'InventoriesNewForm',
|
||||
controllers: {
|
||||
list: 'NewInventoryListController',
|
||||
add: 'NewInventoryAddController',
|
||||
edit: 'NewInventoryEditController'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: N_('INVENTORIESNEW')
|
||||
},
|
||||
views: {
|
||||
'@': {
|
||||
templateUrl: templateUrl('inventoriesnew/inventories')
|
||||
},
|
||||
'list@inventoriesnew': {
|
||||
templateProvider: function(InventoriesNewList, generateList) {
|
||||
let html = generateList.build({
|
||||
list: InventoriesNewList,
|
||||
mode: 'edit'
|
||||
});
|
||||
return html;
|
||||
},
|
||||
controller: 'NewInventoryListController'
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$stateProvider.state({
|
||||
name: 'hostsnew',
|
||||
url: '/hostsnew',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
parent: 'hostsnew', // top-most node in the generated tree (will replace this state definition)
|
||||
modes: ['add', 'edit'],
|
||||
list: 'HostsNewList',
|
||||
form: 'HostsNewForm',
|
||||
controllers: {
|
||||
list: 'NewHostListController',
|
||||
add: 'NewHostAddController',
|
||||
edit: 'NewHostEditController'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: N_('HOSTSNEW')
|
||||
},
|
||||
views: {
|
||||
'@': {
|
||||
templateUrl: templateUrl('inventoriesnew/inventories')
|
||||
},
|
||||
'list@hostsnew': {
|
||||
templateProvider: function(HostsNewList, generateList) {
|
||||
let html = generateList.build({
|
||||
list: HostsNewList,
|
||||
mode: 'edit'
|
||||
});
|
||||
return html;
|
||||
},
|
||||
controller: 'NewHostListController'
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
|
||||
// function generateInvAddStateTree() {
|
||||
//
|
||||
// let addInventory = stateDefinitions.generateTree({
|
||||
// url: '/add',
|
||||
// name: 'inventoriesnew.add',
|
||||
// modes: ['add'],
|
||||
// form: 'InventoriesNewForm',
|
||||
// controllers: {
|
||||
// add: 'NewInventoryAddController'
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// return Promise.all([
|
||||
// addInventory,
|
||||
// ]).then((generated) => {
|
||||
// return {
|
||||
// states: _.reduce(generated, (result, definition) => {
|
||||
// return result.concat(definition.states);
|
||||
// }, [])
|
||||
// };
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// function generateInvEditStateTree() {
|
||||
//
|
||||
// let editInventory = stateDefinitions.generateTree({
|
||||
// url: '/:inventory_id',
|
||||
// name: 'inventoriesnew.edit',
|
||||
// modes: ['edit'],
|
||||
// form: 'InventoriesNewForm',
|
||||
// controllers: {
|
||||
// edit: 'NewInventoryEditController'
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// return Promise.all([
|
||||
// editInventory,
|
||||
// ]).then((generated) => {
|
||||
// return {
|
||||
// states: _.reduce(generated, (result, definition) => {
|
||||
// return result.concat(definition.states);
|
||||
// }, [])
|
||||
// };
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// let inventoriesnew = {
|
||||
// name: 'inventoriesnew',
|
||||
// route: '/inventoriesnew',
|
||||
// ncyBreadcrumb: {
|
||||
// label: N_("INVENTORIESNEW")
|
||||
// },
|
||||
// params: {
|
||||
// inventory_search: {
|
||||
// value: {order_by: 'name', page_size: '20', role_level: 'admin_role'},
|
||||
// dynamic: true
|
||||
// }
|
||||
// },
|
||||
// resolve: {
|
||||
// Dataset: ['InventoriesNewList', 'QuerySet', '$stateParams', 'GetBasePath', (list, qs, $stateParams, GetBasePath) => {
|
||||
// let path = GetBasePath(list.basePath) || GetBasePath(list.name);
|
||||
// return qs.search(path, $stateParams[`${list.iterator}_search`]);
|
||||
// }],
|
||||
// ListDefinition: ['InventoriesNewList', (list) => {
|
||||
// return list;
|
||||
// }]
|
||||
// },
|
||||
// views: {
|
||||
// '@': {
|
||||
// templateUrl: templateUrl('inventoriesnew/inventories')
|
||||
// },
|
||||
// 'list@inventoriesnew': {
|
||||
// templateProvider: function(InventoriesNewList, generateList) {
|
||||
// let html = generateList.build({
|
||||
// list: InventoriesNewList,
|
||||
// mode: 'edit'
|
||||
// });
|
||||
// return html;
|
||||
// },
|
||||
// controller: 'NewInventoryListController'
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// stateExtender.addState(inventoriesnew);
|
||||
//
|
||||
// let hostsnew = {
|
||||
// name: 'inventoriesnew.hosts',
|
||||
// route: '/hosts',
|
||||
// ncyBreadcrumb: {
|
||||
// label: N_("HOSTS")
|
||||
// },
|
||||
// params: {
|
||||
// host_search: {
|
||||
// value: {order_by: 'name', page_size: '20'},
|
||||
// dynamic: true
|
||||
// }
|
||||
// },
|
||||
// resolve: {
|
||||
// Dataset: ['HostsNewList', 'QuerySet', '$stateParams', 'GetBasePath', (list, qs, $stateParams, GetBasePath) => {
|
||||
// let path = GetBasePath(list.basePath) || GetBasePath(list.name);
|
||||
// return qs.search(path, $stateParams[`${list.iterator}_search`]);
|
||||
// }],
|
||||
// ListDefinition: ['HostsNewList', (list) => {
|
||||
// return list;
|
||||
// }]
|
||||
// },
|
||||
// views: {
|
||||
// 'list@inventoriesnew': {
|
||||
// templateProvider: function(HostsNewList, generateList) {
|
||||
// let html = generateList.build({
|
||||
// list: HostsNewList,
|
||||
// mode: 'edit'
|
||||
// });
|
||||
// return html;
|
||||
// },
|
||||
// controller: 'NewHostListController'
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// stateExtender.addState(hostsnew);
|
||||
//
|
||||
// let addInventoryTree = {
|
||||
// name: 'inventoriesnew.add',
|
||||
// url: '/add',
|
||||
// lazyLoad: () => generateInvAddStateTree()
|
||||
// };
|
||||
// $stateProvider.state(addInventoryTree);
|
||||
//
|
||||
// let editInventoryTree = {
|
||||
// name: 'inventoriesnew.edit',
|
||||
// url: '/:inventory_id',
|
||||
// lazyLoad: () => generateInvEditStateTree()
|
||||
// };
|
||||
// $stateProvider.state(editInventoryTree);
|
||||
}
|
||||
]);
|
@ -27,6 +27,14 @@
|
||||
<translate>INVENTORIES</translate>
|
||||
</span>
|
||||
</a>
|
||||
<a class="MainMenu-item"
|
||||
id="main_menu_inventoriesnew_mobile_link"
|
||||
href="/#/inventoriesnew"
|
||||
ng-class="{'is-currentRoute' : isCurrentState('inventoriesnew')}">
|
||||
<span class="MainMenu-itemText">
|
||||
<translate>INVENTORIES NEW</translate>
|
||||
</span>
|
||||
</a>
|
||||
<a class="MainMenu-item"
|
||||
id="main_menu_job_templates_mobile_link"
|
||||
href="/#/templates"
|
||||
@ -104,6 +112,15 @@
|
||||
<translate>INVENTORIES</translate>
|
||||
</span>
|
||||
</a>
|
||||
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--left"
|
||||
id="main_menu_inventoriesnew_link"
|
||||
href="/#/inventoriesnew"
|
||||
ng-hide="licenseMissing"
|
||||
ng-class="{'is-currentRoute' : isCurrentState('inventoriesnew'), 'is-loggedOut' : !current_user || !current_user.username}">
|
||||
<span class="MainMenu-itemText">
|
||||
<translate>INVENTORIES NEW</translate>
|
||||
</span>
|
||||
</a>
|
||||
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--left"
|
||||
id="main_menu_job_templates_link"
|
||||
href="/#/templates"
|
||||
|
@ -89,6 +89,16 @@ export default ['$injector', '$stateExtender', '$log', 'i18n', function($injecto
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let views = params.views ? params.views : {
|
||||
'@': {
|
||||
// resolves to a variable property name:
|
||||
// 'templateUrl' OR 'templateProvider'
|
||||
[params.templates && params.templates.list ? 'templateUrl' : 'templateProvider']: generateTemplateBlock(),
|
||||
controller: params.controllers.list,
|
||||
}
|
||||
};
|
||||
|
||||
state = $stateExtender.buildDefinition({
|
||||
searchPrefix: list.iterator,
|
||||
name: params.parent,
|
||||
@ -106,14 +116,7 @@ export default ['$injector', '$stateExtender', '$log', 'i18n', function($injecto
|
||||
],
|
||||
ListDefinition: () => list
|
||||
},
|
||||
views: {
|
||||
'@': {
|
||||
// resolves to a variable property name:
|
||||
// 'templateUrl' OR 'templateProvider'
|
||||
[params.templates && params.templates.list ? 'templateUrl' : 'templateProvider']: generateTemplateBlock(),
|
||||
controller: params.controllers.list,
|
||||
}
|
||||
}
|
||||
views: views
|
||||
});
|
||||
// allow passed-in params to override default resolve block
|
||||
if (params.resolve && params.resolve.list) {
|
||||
@ -125,7 +128,7 @@ export default ['$injector', '$stateExtender', '$log', 'i18n', function($injecto
|
||||
}
|
||||
if (list.search) {
|
||||
state.params[`${list.iterator}_search`].value = _.merge(state.params[`${list.iterator}_search`].value, list.search);
|
||||
}
|
||||
}if(state.name === 'inventoriesnew'){console.log(state);}
|
||||
return state;
|
||||
},
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user