mirror of
https://github.com/ansible/awx.git
synced 2026-01-14 11:20:39 -03:30
Smart inventory implementation
This commit is contained in:
parent
5d867d51f4
commit
1176b9b057
@ -59,6 +59,7 @@
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.Form-title--is_smartinventory,
|
||||
.Form-title--is_superuser,
|
||||
.Form-title--is_system_auditor,
|
||||
.Form-title--is_ldap_user,
|
||||
@ -665,6 +666,19 @@ input[type='radio']:checked:before {
|
||||
.noselect;
|
||||
}
|
||||
|
||||
.Form-textInput--variableHeight {
|
||||
height: inherit;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
.Form-variableHeightButtonGroup {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Form-lookupButton--variableHeight {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
.Form-formGroup {
|
||||
flex: 1 0 auto;
|
||||
|
||||
@ -56,7 +56,7 @@ export default ['i18n', function(i18n) {
|
||||
'used by Projects.') + '</dd>\n' +
|
||||
'<dt>' + i18n._('Cloud') + '</dt>\n' +
|
||||
'<dd>' + i18n._('Usernames, passwords, and access keys for authenticating to the specified cloud or infrastructure ' +
|
||||
'provider. These are used for dynamic inventory sources and for cloud provisioning and deployment ' +
|
||||
'provider. These are used for smart inventory sources and for cloud provisioning and deployment ' +
|
||||
'in playbook runs.') + '</dd>\n' +
|
||||
'</dl>\n',
|
||||
dataTitle: i18n._('Kind'),
|
||||
|
||||
@ -78,7 +78,7 @@ export default ['i18n', function(i18n) {
|
||||
'used by Projects.') + '</dd>\n' +
|
||||
'<dt>' + i18n._('Others (Cloud Providers)') + '</dt>\n' +
|
||||
'<dd>' + i18n._('Usernames, passwords, and access keys for authenticating to the specified cloud or infrastructure ' +
|
||||
'provider. These are used for dynamic inventory sources and for cloud provisioning and deployment ' +
|
||||
'provider. These are used for smart inventory sources and for cloud provisioning and deployment ' +
|
||||
'in playbook runs.') + '</dd>\n' +
|
||||
'</dl>\n',
|
||||
dataTitle: i18n._('Type'),
|
||||
|
||||
@ -34,12 +34,12 @@ export default
|
||||
function createCounts(data) {
|
||||
scope.counts = _.map([
|
||||
{
|
||||
url: "/#/home/hosts",
|
||||
url: "/#/hosts",
|
||||
number: scope.data.hosts.total,
|
||||
label: i18n._("Hosts")
|
||||
},
|
||||
{
|
||||
url: "/#/home/hosts?host_search=has_active_failures:true",
|
||||
url: "/#/hosts?host_search=has_active_failures:true",
|
||||
number: scope.data.hosts.failed,
|
||||
label: i18n._("Failed Hosts"),
|
||||
isFailureCount: true
|
||||
|
||||
@ -1,79 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default
|
||||
['$scope', '$state', '$stateParams', 'DashboardHostsForm', 'GenerateForm', 'ParseTypeChange', 'DashboardHostService', 'host',
|
||||
function($scope, $state, $stateParams, DashboardHostsForm, GenerateForm, ParseTypeChange, DashboardHostService, host){
|
||||
$scope.parseType = 'yaml';
|
||||
$scope.formCancel = function(){
|
||||
$state.go('^', null, {reload: true});
|
||||
};
|
||||
$scope.toggleHostEnabled = function(){
|
||||
if ($scope.host.has_inventory_sources){
|
||||
return;
|
||||
}
|
||||
$scope.host.enabled = !$scope.host.enabled;
|
||||
};
|
||||
$scope.toggleEnabled = function(){
|
||||
$scope.host.enabled = !$scope.host.enabled;
|
||||
};
|
||||
$scope.formSave = function(){
|
||||
var host = {
|
||||
id: $scope.host.id,
|
||||
variables: $scope.variables === '---' || $scope.variables === '{}' ? null : $scope.variables,
|
||||
name: $scope.name,
|
||||
description: $scope.description,
|
||||
enabled: $scope.host.enabled
|
||||
};
|
||||
DashboardHostService.putHost(host).then(function(){
|
||||
$state.go('^', null, {reload: true});
|
||||
});
|
||||
|
||||
};
|
||||
var init = function(){
|
||||
$scope.host = host.data;
|
||||
$scope.name = host.data.name;
|
||||
$scope.description = host.data.description;
|
||||
$scope.variables = getVars(host.data.variables);
|
||||
ParseTypeChange({
|
||||
scope: $scope,
|
||||
field_id: 'host_variables',
|
||||
variable: 'variables',
|
||||
});
|
||||
};
|
||||
|
||||
// Adding this function b/c sometimes extra vars are returned to the
|
||||
// UI as a string (ex: "foo: bar"), and other times as a
|
||||
// json-object-string (ex: "{"foo": "bar"}"). CodeMirror wouldn't know
|
||||
// how to prettify the latter. The latter occurs when host vars were
|
||||
// system generated and not user-input (such as adding a cloud host);
|
||||
function getVars(str){
|
||||
|
||||
// Quick function to test if the host vars are a json-object-string,
|
||||
// by testing if they can be converted to a JSON object w/o error.
|
||||
function IsJsonString(str) {
|
||||
try {
|
||||
JSON.parse(str);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(str === ''){
|
||||
return '---';
|
||||
}
|
||||
else if(IsJsonString(str)){
|
||||
str = JSON.parse(str);
|
||||
return jsyaml.safeDump(str);
|
||||
}
|
||||
else if(!IsJsonString(str)){
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
}];
|
||||
@ -1,58 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$state', '$stateParams', 'GetBasePath', 'DashboardHostsList',
|
||||
'generateList', 'SetStatus', 'DashboardHostService', '$rootScope', 'Dataset',
|
||||
function($scope, $state, $stateParams, GetBasePath, DashboardHostsList,
|
||||
GenerateList, SetStatus, DashboardHostService, $rootScope, Dataset) {
|
||||
|
||||
let list = DashboardHostsList;
|
||||
init();
|
||||
|
||||
function init() {
|
||||
// search init
|
||||
$scope.list = list;
|
||||
$scope[`${list.iterator}_dataset`] = Dataset.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
|
||||
$scope.$watchCollection(list.name, function() {
|
||||
$scope[list.name] = _.map($scope.hosts, function(value) {
|
||||
value.inventory_name = value.summary_fields.inventory.name;
|
||||
value.inventory_id = value.summary_fields.inventory.id;
|
||||
return value;
|
||||
});
|
||||
setJobStatus();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function setJobStatus(){
|
||||
_.forEach($scope.hosts, function(value) {
|
||||
SetStatus({
|
||||
scope: $scope,
|
||||
host: value
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$scope.editHost = function(id) {
|
||||
$state.go('dashboardHosts.edit', { host_id: id });
|
||||
};
|
||||
|
||||
$scope.toggleHostEnabled = function(host) {
|
||||
if (host.has_inventory_sources){
|
||||
return;
|
||||
}
|
||||
DashboardHostService.setHostStatus(host, !host.enabled)
|
||||
.then(function(res) {
|
||||
var index = _.findIndex($scope.hosts, function(o) {
|
||||
return o.id === res.data.id;
|
||||
});
|
||||
$scope.hosts[index].enabled = res.data.enabled;
|
||||
});
|
||||
};
|
||||
}
|
||||
];
|
||||
@ -1,83 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['i18n', function(i18n){
|
||||
return {
|
||||
editTitle: '{{host.name}}',
|
||||
name: 'host',
|
||||
well: true,
|
||||
formLabelSize: 'col-lg-3',
|
||||
formFieldSize: 'col-lg-9',
|
||||
iterator: 'host',
|
||||
basePath: 'hosts',
|
||||
headerFields:{
|
||||
enabled: {
|
||||
//flag: 'host.enabled',
|
||||
class: 'Form-header-field',
|
||||
ngClick: 'toggleHostEnabled()',
|
||||
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',
|
||||
|
||||
value: '{{name}}',
|
||||
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'
|
||||
},
|
||||
description: {
|
||||
label: i18n._('Description'),
|
||||
type: 'text',
|
||||
},
|
||||
variables: {
|
||||
label: i18n._('Variables'),
|
||||
type: 'textarea',
|
||||
rows: 6,
|
||||
class: 'modal-input-xlarge Form-textArea Form-formGroup--fullWidth',
|
||||
dataTitle: i18n._('Host Variables'),
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body',
|
||||
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>',
|
||||
}
|
||||
},
|
||||
buttons: {
|
||||
cancel: {
|
||||
ngClick: 'formCancel()'
|
||||
},
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: "host_form.$invalid"//true //Disable when $pristine or $invalid, optional and when can_edit = false, for permission reasons
|
||||
}
|
||||
}
|
||||
};
|
||||
}];
|
||||
@ -1,75 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
|
||||
export default [ 'i18n', function(i18n){
|
||||
return {
|
||||
name: 'hosts',
|
||||
iterator: 'host',
|
||||
selectTitle: i18n._('Add Existing Hosts'),
|
||||
editTitle: i18n._('HOSTS'),
|
||||
listTitle: i18n._('HOSTS'),
|
||||
index: false,
|
||||
hover: true,
|
||||
well: true,
|
||||
emptyListText: i18n._('NO HOSTS FOUND'),
|
||||
fields: {
|
||||
status: {
|
||||
basePath: 'unified_jobs',
|
||||
label: '',
|
||||
iconOnly: true,
|
||||
nosort: true,
|
||||
icon: 'icon-job-{{ host.active_failures }}',
|
||||
awToolTip: '{{ host.badgeToolTip }}',
|
||||
awTipPlacement: 'right',
|
||||
dataPlacement: 'right',
|
||||
awPopOver: '{{ host.job_status_html }}',
|
||||
dataTitle: '{{host.job_status_title}}',
|
||||
ngClick:'viewHost(host.id)',
|
||||
columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumn--smallStatus'
|
||||
},
|
||||
name: {
|
||||
key: true,
|
||||
label: i18n._('Name'),
|
||||
columnClass: 'col-lg-5 col-md-5 col-sm-5 col-xs-8 ellipsis List-staticColumnAdjacent',
|
||||
ngClick: 'editHost(host.id)'
|
||||
},
|
||||
inventory_name: {
|
||||
label: i18n._('Inventory'),
|
||||
sourceModel: 'inventory',
|
||||
sourceField: 'name',
|
||||
columnClass: 'col-lg-5 col-md-4 col-sm-4 hidden-xs elllipsis',
|
||||
linkTo: "{{ '/#/inventories/' + host.inventory_id }}"
|
||||
},
|
||||
enabled: {
|
||||
label: i18n._('Status'),
|
||||
columnClass: 'List-staticColumn--toggle',
|
||||
type: 'toggle',
|
||||
ngClick: 'toggleHostEnabled(host)',
|
||||
nosort: true,
|
||||
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'
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
|
||||
columnClass: 'col-lg-2 col-md-3 col-sm-3 col-xs-4',
|
||||
edit: {
|
||||
label: i18n._('Edit'),
|
||||
ngClick: 'editHost(host.id)',
|
||||
icon: 'icon-edit',
|
||||
awToolTip: i18n._('Edit host'),
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
||||
}
|
||||
};
|
||||
}];
|
||||
@ -1,30 +0,0 @@
|
||||
export default
|
||||
['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', function($rootScope, Rest, GetBasePath, ProcessErrors){
|
||||
return {
|
||||
|
||||
setHostStatus: function(host, enabled){
|
||||
var url = GetBasePath('hosts') + host.id;
|
||||
Rest.setUrl(url);
|
||||
return Rest.put({enabled: enabled, name: host.name})
|
||||
.success(function(data){
|
||||
return data;
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||
});
|
||||
},
|
||||
putHost: function(host){
|
||||
var url = GetBasePath('hosts') + host.id;
|
||||
Rest.setUrl(url);
|
||||
return Rest.put(host)
|
||||
.success(function(data){
|
||||
return data;
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||
});
|
||||
}
|
||||
};
|
||||
}];
|
||||
@ -1,60 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import list from './dashboard-hosts.list';
|
||||
import form from './dashboard-hosts.form';
|
||||
import listController from './dashboard-hosts-list.controller';
|
||||
import editController from './dashboard-hosts-edit.controller';
|
||||
import service from './dashboard-hosts.service';
|
||||
import { N_ } from '../../../i18n';
|
||||
|
||||
export default
|
||||
angular.module('dashboardHosts', [])
|
||||
.service('DashboardHostService', service)
|
||||
.factory('DashboardHostsList', list)
|
||||
.factory('DashboardHostsForm', form)
|
||||
.config(['$stateProvider', 'stateDefinitionsProvider',
|
||||
function($stateProvider, stateDefinitionsProvider) {
|
||||
let stateDefinitions = stateDefinitionsProvider.$get();
|
||||
|
||||
$stateProvider.state({
|
||||
name: 'dashboardHosts',
|
||||
url: '/home/hosts',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
urls: {
|
||||
list: '/home/hosts'
|
||||
},
|
||||
parent: 'dashboardHosts',
|
||||
modes: ['edit'],
|
||||
list: 'DashboardHostsList',
|
||||
form: 'DashboardHostsForm',
|
||||
controllers: {
|
||||
list: listController,
|
||||
edit: editController
|
||||
},
|
||||
resolve: {
|
||||
edit: {
|
||||
host: ['Rest', '$stateParams', 'GetBasePath',
|
||||
function(Rest, $stateParams, GetBasePath) {
|
||||
let path = GetBasePath('hosts') + $stateParams.host_id;
|
||||
Rest.setUrl(path);
|
||||
return Rest.get();
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'host'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: 'dashboard',
|
||||
label: N_("HOSTS")
|
||||
},
|
||||
})
|
||||
});
|
||||
}
|
||||
]);
|
||||
@ -2,8 +2,7 @@ import dashboardCounts from './counts/main';
|
||||
import dashboardGraphs from './graphs/main';
|
||||
import dashboardLists from './lists/main';
|
||||
import dashboardDirective from './dashboard.directive';
|
||||
import dashboardHosts from './hosts/main';
|
||||
|
||||
export default
|
||||
angular.module('dashboard', [dashboardHosts.name, dashboardCounts.name, dashboardGraphs.name, dashboardLists.name])
|
||||
angular.module('dashboard', [dashboardCounts.name, dashboardGraphs.name, dashboardLists.name])
|
||||
.directive('dashboard', dashboardDirective);
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
export default {
|
||||
searchPrefix: 'credential',
|
||||
name: 'inventories.edit.adhoc.credential',
|
||||
url: '/credential',
|
||||
data: {
|
||||
formChildState: true
|
||||
|
||||
@ -22,7 +22,7 @@ function adhocController($q, $scope, $stateParams,
|
||||
var privateFn = {};
|
||||
this.privateFn = privateFn;
|
||||
|
||||
var id = $stateParams.inventory_id,
|
||||
var id = $stateParams.inventory_id ? $stateParams.inventory_id : $stateParams.smartinventory_id,
|
||||
hostPattern = $stateParams.pattern;
|
||||
|
||||
// note: put any urls that the controller will use in here!!!!
|
||||
@ -189,7 +189,7 @@ function adhocController($q, $scope, $stateParams,
|
||||
|
||||
// launch the job with the provided form data
|
||||
$scope.launchJob = function () {
|
||||
var adhocUrl = GetBasePath('inventory') + $stateParams.inventory_id +
|
||||
var adhocUrl = GetBasePath('inventory') + id +
|
||||
'/ad_hoc_commands/', fld, data={}, html;
|
||||
|
||||
html = '<form class="ng-valid ng-valid-required" ' +
|
||||
@ -233,8 +233,7 @@ function adhocController($q, $scope, $stateParams,
|
||||
];
|
||||
}
|
||||
// Launch the adhoc job
|
||||
Rest.setUrl(GetBasePath('inventory') +
|
||||
$stateParams.inventory_id + '/ad_hoc_commands/');
|
||||
Rest.setUrl(GetBasePath('inventory') + id + '/ad_hoc_commands/');
|
||||
Rest.post(data)
|
||||
.success(function (data) {
|
||||
Wait('stop');
|
||||
|
||||
@ -18,7 +18,6 @@ export default {
|
||||
data: {
|
||||
formChildState: true
|
||||
},
|
||||
name: 'inventories.edit.adhoc',
|
||||
views: {
|
||||
'adhocForm@inventories': {
|
||||
templateUrl: templateUrl('inventories/adhoc/adhoc'),
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { N_ } from '../../i18n';
|
||||
|
||||
export default {
|
||||
name: "inventories.edit.completed_jobs",
|
||||
url: "/completed_jobs",
|
||||
params: {
|
||||
completed_job_search: {
|
||||
@ -14,7 +13,6 @@ export default {
|
||||
}
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: "inventories.edit",
|
||||
label: N_("COMPLETED JOBS")
|
||||
},
|
||||
views: {
|
||||
@ -46,9 +44,11 @@ export default {
|
||||
path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams });
|
||||
}
|
||||
|
||||
$stateParams[`${list.iterator}_search`].or__job__inventory = $stateParams.inventory_id;
|
||||
$stateParams[`${list.iterator}_search`].or__adhoccommand__inventory = $stateParams.inventory_id;
|
||||
$stateParams[`${list.iterator}_search`].or__inventoryupdate__inventory_source__inventory = $stateParams.inventory_id;
|
||||
let inventory_id = $stateParams.inventory_id ? $stateParams.inventory_id : $stateParams.smartinventory_id;
|
||||
|
||||
$stateParams[`${list.iterator}_search`].or__job__inventory = inventory_id;
|
||||
$stateParams[`${list.iterator}_search`].or__adhoccommand__inventory = inventory_id;
|
||||
$stateParams[`${list.iterator}_search`].or__inventoryupdate__inventory_source__inventory = inventory_id;
|
||||
|
||||
return qs.search(path, $stateParams[`${list.iterator}_search`]);
|
||||
}
|
||||
|
||||
@ -41,22 +41,17 @@ export default ['$scope', 'NestedHostsListDefinition', '$rootScope', 'GetBasePat
|
||||
});
|
||||
|
||||
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams) {
|
||||
if(toState.name === 'hosts.addSmartInventory') {
|
||||
$scope.enableSmartInventoryButton = false;
|
||||
if(toParams && toParams.host_search) {
|
||||
let hasMoreThanDefaultKeys = false;
|
||||
angular.forEach(toParams.host_search, function(value, key) {
|
||||
if(key !== 'order_by' && key !== 'page_size') {
|
||||
hasMoreThanDefaultKeys = true;
|
||||
}
|
||||
});
|
||||
$scope.enableSmartInventoryButton = hasMoreThanDefaultKeys ? true : false;
|
||||
}
|
||||
else {
|
||||
if(toParams && toParams.host_search) {
|
||||
let hasMoreThanDefaultKeys = false;
|
||||
angular.forEach(toParams.host_search, function(value, key) {
|
||||
if(key !== 'order_by' && key !== 'page_size') {
|
||||
hasMoreThanDefaultKeys = true;
|
||||
}
|
||||
});
|
||||
$scope.enableSmartInventoryButton = hasMoreThanDefaultKeys ? true : false;
|
||||
}
|
||||
else {
|
||||
$scope.enableSmartInventoryButton = false;
|
||||
}
|
||||
$scope.enableSmartInventoryButton = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
*************************************************/
|
||||
|
||||
export default
|
||||
['$scope', '$state', '$stateParams', 'DashboardHostsForm', 'GenerateForm', 'ParseTypeChange', 'DashboardHostService', 'host', '$rootScope',
|
||||
function($scope, $state, $stateParams, DashboardHostsForm, GenerateForm, ParseTypeChange, DashboardHostService, host, $rootScope){
|
||||
['$scope', '$state', '$stateParams', 'GenerateForm', 'ParseTypeChange', 'HostManageService', 'host', '$rootScope',
|
||||
function($scope, $state, $stateParams, GenerateForm, ParseTypeChange, HostManageService, host, $rootScope){
|
||||
$scope.parseType = 'yaml';
|
||||
$scope.formCancel = function(){
|
||||
$state.go('^', null, {reload: true});
|
||||
@ -32,8 +32,8 @@
|
||||
description: $scope.description,
|
||||
enabled: $scope.host.enabled
|
||||
};
|
||||
DashboardHostService.putHost(host).then(function(){
|
||||
$state.go('^', null, {reload: true});
|
||||
HostManageService.put(host).then(function(){
|
||||
$state.go('.', null, {reload: true});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@ -10,8 +10,7 @@ export default ['i18n', function(i18n) {
|
||||
iterator: 'host',
|
||||
editTitle: '{{ selected_group }}',
|
||||
searchSize: 'col-lg-12 col-md-12 col-sm-12 col-xs-12',
|
||||
nonstandardSearchParam: {
|
||||
root: 'ansible_facts',
|
||||
singleSearchParam: {
|
||||
param: 'host_filter'
|
||||
},
|
||||
showTitle: false,
|
||||
@ -67,13 +66,13 @@ export default ['i18n', function(i18n) {
|
||||
dataType: "host",
|
||||
class: 'InventoryManage-breakWord'
|
||||
},
|
||||
inventory_name: {
|
||||
inventory: {
|
||||
label: i18n._('Inventory'),
|
||||
sourceModel: 'inventory',
|
||||
sourceField: 'name',
|
||||
columnClass: 'col-lg-5 col-md-4 col-sm-4 hidden-xs elllipsis',
|
||||
linkTo: "{{ '/#/inventories/' + host.inventory_id }}"
|
||||
},
|
||||
ngClick: "editInventory(host)"
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
|
||||
97
awx/ui/client/src/inventories/hosts/hosts.partial.html
Normal file
97
awx/ui/client/src/inventories/hosts/hosts.partial.html
Normal file
@ -0,0 +1,97 @@
|
||||
<div class="tab-pane" id="hosts-panel">
|
||||
<aw-limit-panels max-panels="2" panel-container="hosts-panel"></aw-limit-panels>
|
||||
<div ui-view="form"></div>
|
||||
<div 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('inventories')" translate>INVENTORIES</div>
|
||||
<div class="Form-tab Form-tab--notitle is-selected" ng-click="$state.go('hosts')" translate>HOSTS</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="List-actionHolder List-actionHolder--leftAlign">
|
||||
<div class="List-actions">
|
||||
<div ng-include="'/static/partials/shared/list-generator/list-actions.partial.html'"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-hide="hosts.length === 0 && (searchTags | isEmpty)">
|
||||
<smart-search
|
||||
django-model="hosts"
|
||||
search-size="col-lg-12 col-md-12 col-sm-12 col-xs-12"
|
||||
single-search-param="host_filter"
|
||||
base-path="hosts"
|
||||
iterator="host"
|
||||
dataset="host_dataset"
|
||||
list="list"
|
||||
collection="hosts"
|
||||
default-params="host_default_params"
|
||||
query-set="host_queryset"
|
||||
search-tags="searchTags">
|
||||
</smart-search>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-show="hosts.length === 0 && !(searchTags | isEmpty)">
|
||||
<div class="col-lg-12 List-searchNoResults">No records matched your search.</div>
|
||||
</div>
|
||||
<div class="List-noItems" ng-show="hosts.length === 0 && (searchTags | isEmpty)">PLEASE ADD ITEMS TO THIS LIST</div>
|
||||
<div class="list-table-container" ng-show="hosts.length > 0">
|
||||
<table id="hosts_table" class="List-table table-no-border" is-extended="false">
|
||||
<thead>
|
||||
<tr class="List-tableHeaderRow">
|
||||
<th base-path="hosts" collection="hosts" dataset="host_dataset" column-sort="" column-field="toggleHost" column-iterator="host" column-no-sort="true" column-label="" column-custom-class="List-staticColumn--toggle" query-set="host_queryset"></th>
|
||||
<th base-path="hosts" collection="hosts" dataset="host_dataset" column-sort="" column-field="active_failures" column-iterator="host" column-no-sort="true" column-label="" column-custom-class="status-column List-staticColumn--smallStatus" query-set="host_queryset"></th>
|
||||
<th base-path="hosts" collection="hosts" dataset="host_dataset" column-sort="" column-field="name" column-iterator="host" column-no-sort="undefined" column-label="Name" column-custom-class="col-lg-6 col-md-8 col-sm-8 col-xs-7" query-set="host_queryset"></th>
|
||||
<th base-path="hosts" collection="hosts" dataset="host_dataset" column-sort="" column-field="inventory" column-iterator="host" column-no-sort="undefined" column-label="Inventory" column-custom-class="col-lg-5 col-md-4 col-sm-4 hidden-xs elllipsis" query-set="host_queryset"></th>
|
||||
<th class="List-tableHeader List-tableHeader--actions actions-column col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-class="[host.active_class]" id="{{ host.id }}" class="List-tableRow host_class" ng-repeat="host in hosts track by host.id">
|
||||
<td class="List-tableCell toggleHost-column List-staticColumn--toggle">
|
||||
<div class="ScheduleToggle" ng-class="{'is-on': host.enabled, 'ScheduleToggle--disabled': host.has_inventory_sources}" aw-tool-tip="<p>Indicates if a host is available and should be included in running jobs.</p><p>For hosts that are part of an external inventory, this flag cannot be changed. It will be set by the inventory sync process.</p>" data-placement="right" data-tip-watch="undefined">
|
||||
<button ng-disabled="host.has_inventory_sources" ng-show="host.enabled" class="ScheduleToggle-switch is-on" ng-click="toggleHost($event, host)">ON</button>
|
||||
<button ng-disabled="host.has_inventory_sources" ng-show="!host.enabled" class="ScheduleToggle-switch" ng-click="toggleHost($event, host)">OFF</button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="List-tableCell active_failures-column status-column List-staticColumn--smallStatus">
|
||||
<div class="host-name">
|
||||
<a href="" ng-click="noop()" aw-tool-tip="{{ host.badgeToolTip }}" aw-pop-over="{{ host.job_status_html }}" data-placement="top" over-title="{{ host.job_status_title }}">
|
||||
<i class="fa {{ 'fa icon-job-' + host.active_failures }}"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="List-tableCell name-column InventoryManage-breakWord col-lg-6 col-md-8 col-sm-8 col-xs-7">
|
||||
<div class="host-name">
|
||||
<a href="" ng-click="editHost(host.id)">{{host.name }}</a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="List-tableCell inventory_name-column col-lg-5 col-md-4 col-sm-4 hidden-xs elllipsis">
|
||||
<div class="host-name">
|
||||
<a href="" ng-click="editInventory(host)">{{host.inventory_name }}</a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="List-actionsContainer">
|
||||
<div class="List-actionButtonCell List-tableCell">
|
||||
<button id="edit-action" class="List-actionButton " ng-class="{'List-editButton--selected' : $stateParams['host_id'] == host.id}" data-placement="top" ng-click="editHost(host.id)" aw-tool-tip="Edit host" ng-show="host.summary_fields.user_capabilities.edit">
|
||||
<i class="fa fa-pencil"></i>
|
||||
</button>
|
||||
<button id="view-action" class="List-actionButton " data-placement="top" ng-click="editHost(host.id)" aw-tool-tip="View host" ng-show="!host.summary_fields.user_capabilities.edit"><i class="fa fa-search-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div><!-- table container -->
|
||||
<paginate
|
||||
base-path="hosts"
|
||||
collection="hosts"
|
||||
dataset="host_dataset"
|
||||
iterator="host"
|
||||
query-set="host_queryset">
|
||||
</paginate>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -39,22 +39,17 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath,
|
||||
});
|
||||
|
||||
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams) {
|
||||
if(toState.name === 'hosts.addSmartInventory') {
|
||||
$scope.enableSmartInventoryButton = false;
|
||||
if(toParams && toParams.host_search) {
|
||||
let hasMoreThanDefaultKeys = false;
|
||||
angular.forEach(toParams.host_search, function(value, key) {
|
||||
if(key !== 'order_by' && key !== 'page_size') {
|
||||
hasMoreThanDefaultKeys = true;
|
||||
}
|
||||
});
|
||||
$scope.enableSmartInventoryButton = hasMoreThanDefaultKeys ? true : false;
|
||||
}
|
||||
else {
|
||||
if(toParams && toParams.host_search) {
|
||||
let hasMoreThanDefaultKeys = false;
|
||||
angular.forEach(toParams.host_search, function(value, key) {
|
||||
if(key !== 'order_by' && key !== 'page_size') {
|
||||
hasMoreThanDefaultKeys = true;
|
||||
}
|
||||
});
|
||||
$scope.enableSmartInventoryButton = hasMoreThanDefaultKeys ? true : false;
|
||||
}
|
||||
else {
|
||||
$scope.enableSmartInventoryButton = false;
|
||||
}
|
||||
$scope.enableSmartInventoryButton = false;
|
||||
}
|
||||
});
|
||||
|
||||
@ -131,6 +126,17 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath,
|
||||
$state.go('inventories.addSmartInventory', {hostfilter: JSON.stringify(stateParamsCopy)});
|
||||
};
|
||||
|
||||
$scope.editInventory = function(host) {
|
||||
if(host.summary_fields && host.summary_fields.inventory) {
|
||||
if(host.summary_fields.inventory.kind && host.summary_fields.inventory.kind === 'smart') {
|
||||
$state.go('inventories.editSmartInventory', {smartinventory_id: host.inventory});
|
||||
}
|
||||
else {
|
||||
$state.go('inventories.edit', {inventory_id: host.inventory});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default ['$scope', 'HostsList', '$rootScope', 'GetBasePath',
|
||||
|
||||
@ -11,13 +11,12 @@
|
||||
import HostManageService from './hosts.service';
|
||||
import SetStatus from './set-status.factory';
|
||||
import SetEnabledMsg from './set-enabled-msg.factory';
|
||||
import SmartInventory from './smart-inventory/main';
|
||||
|
||||
|
||||
export default
|
||||
angular.module('host', [
|
||||
hostEdit.name,
|
||||
hostList.name,
|
||||
SmartInventory.name,
|
||||
hostList.name
|
||||
])
|
||||
.factory('HostsForm', HostsForm)
|
||||
.factory('HostsList', HostsList)
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', 'QuerySet',
|
||||
function($scope, qs) {
|
||||
$scope.hostFilterTags = [];
|
||||
|
||||
$scope.$watch('hostFilter', function(){
|
||||
$scope.hostFilterTags = qs.stripDefaultParams($scope.hostFilter);
|
||||
});
|
||||
}
|
||||
];
|
||||
@ -1,12 +0,0 @@
|
||||
<div class="input-group Form-mixedInputGroup">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" class="Form-lookupButton btn btn-default" ng-click="openHostFilterModal()">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</span>
|
||||
<span class="form-control Form-textInput input-medium lookup" style="padding: 4px 6px;">
|
||||
<span class="LabelList-tag" ng-repeat="tag in hostFilterTags">
|
||||
<span class="LabelList-name">{{tag}}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@ -1,14 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
function SmartInventoryEdit() {
|
||||
|
||||
console.log('inside smart inventory add');
|
||||
|
||||
}
|
||||
|
||||
export default [ SmartInventoryEdit
|
||||
];
|
||||
@ -1,179 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['i18n', function(i18n) {
|
||||
return {
|
||||
|
||||
addTitle: i18n._('NEW SMART INVENTORY'),
|
||||
editTitle: '{{ inventory_name }}',
|
||||
name: 'smartinventory',
|
||||
basePath: 'inventory',
|
||||
breadcrumbName: 'SMART INVENTORY',
|
||||
stateTree: 'hosts',
|
||||
|
||||
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'
|
||||
},
|
||||
dynamic_hosts: {
|
||||
label: i18n._('Dynamic Hosts'),
|
||||
type: 'custom',
|
||||
control: '<dynamic-inventory-host-filter host-filter="dynamic_hosts"></dynamic-inventory-host-filter>',
|
||||
basePath: 'hosts',
|
||||
list: 'HostsList',
|
||||
sourceModel: 'host',
|
||||
sourceField: 'name',
|
||||
required: true
|
||||
// TODO: add required, ngDisabled, awLookupWhen (?)
|
||||
},
|
||||
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: {
|
||||
key: true,
|
||||
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',
|
||||
}
|
||||
}
|
||||
},
|
||||
hosts: {
|
||||
name: 'hosts',
|
||||
include: "RelatedHostsListDefinition",
|
||||
title: i18n._('Hosts'),
|
||||
iterator: 'host'
|
||||
},
|
||||
//this is a placeholder for when we're ready for completed jobs
|
||||
completed_jobs: {
|
||||
name: 'completed_jobs',
|
||||
// awToolTip: i18n._('Please save before assigning permissions'),
|
||||
// dataPlacement: 'top',
|
||||
basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/completed_jobs/',
|
||||
type: 'collection',
|
||||
title: i18n._('Completed Jobs'),
|
||||
iterator: 'completed_job',
|
||||
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: {
|
||||
name: {
|
||||
label: i18n._('Name'),
|
||||
// linkBase: 'users',
|
||||
class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};}];
|
||||
@ -37,11 +37,16 @@ export default ['i18n', function(i18n) {
|
||||
name: {
|
||||
key: true,
|
||||
label: i18n._('Name'),
|
||||
columnClass: 'col-md-5 col-sm-4 col-xs-6 List-staticColumnAdjacent',
|
||||
columnClass: 'col-md-4 col-sm-3 col-xs-6 List-staticColumnAdjacent',
|
||||
modalColumnClass: 'col-md-11',
|
||||
awToolTip: "{{ inventory.description }}",
|
||||
awTipPlacement: "top",
|
||||
linkTo: '/#/inventories/basic_inventory/{{inventory.id}}'
|
||||
ngClick: 'editInventory(inventory)'
|
||||
},
|
||||
kind: {
|
||||
label: i18n._('Type'),
|
||||
ngBind: 'inventory.kind_label',
|
||||
columnClass: 'col-md-2 col-sm-2 hidden-xs'
|
||||
},
|
||||
organization: {
|
||||
label: i18n._('Organization'),
|
||||
@ -50,7 +55,7 @@ export default ['i18n', function(i18n) {
|
||||
sourceModel: 'organization',
|
||||
sourceField: 'name',
|
||||
excludeModal: true,
|
||||
columnClass: 'col-md-4 col-sm-2 hidden-xs'
|
||||
columnClass: 'col-md-3 col-sm-2 hidden-xs'
|
||||
}
|
||||
},
|
||||
|
||||
@ -71,7 +76,6 @@ export default ['i18n', function(i18n) {
|
||||
{
|
||||
optionContent: i18n._('Smart Inventory'),
|
||||
optionSref: 'inventories.addSmartInventory',
|
||||
//TODO: this should have its own permission
|
||||
ngShow: 'canAddInventory'
|
||||
}
|
||||
],
|
||||
@ -81,18 +85,18 @@ export default ['i18n', function(i18n) {
|
||||
|
||||
fieldActions: {
|
||||
|
||||
columnClass: 'col-md-2 col-sm-4 col-xs-4',
|
||||
columnClass: 'col-md-2 col-sm-3 col-xs-4',
|
||||
|
||||
edit: {
|
||||
label: i18n._('Edit'),
|
||||
ngClick: 'editInventory(inventory.id)',
|
||||
ngClick: 'editInventory(inventory)',
|
||||
awToolTip: i18n._('Edit inventory'),
|
||||
dataPlacement: 'top',
|
||||
ngShow: 'inventory.summary_fields.user_capabilities.edit'
|
||||
},
|
||||
view: {
|
||||
label: i18n._('View'),
|
||||
ngClick: 'editInventory(inventory.id)',
|
||||
ngClick: 'editInventory(inventory)',
|
||||
awToolTip: i18n._('View inventory'),
|
||||
dataPlacement: 'top',
|
||||
ngShow: '!inventory.summary_fields.user_capabilities.edit'
|
||||
|
||||
@ -28,7 +28,7 @@ function InventoriesList($scope, $rootScope, $location,
|
||||
});
|
||||
|
||||
$scope.$watchCollection(list.name, function(){
|
||||
_.forEach($scope[list.name], buildStatusIndicators);
|
||||
_.forEach($scope[list.name], processInventoryRow);
|
||||
});
|
||||
|
||||
// Search init
|
||||
@ -40,6 +40,11 @@ function InventoriesList($scope, $rootScope, $location,
|
||||
|
||||
}
|
||||
|
||||
function processInventoryRow(inventory) {
|
||||
buildStatusIndicators(inventory);
|
||||
buildInventoryTypeLabel(inventory);
|
||||
}
|
||||
|
||||
function buildStatusIndicators(inventory){
|
||||
inventory.launch_class = "";
|
||||
if (inventory.has_inventory_sources) {
|
||||
@ -71,6 +76,10 @@ function InventoriesList($scope, $rootScope, $location,
|
||||
}
|
||||
}
|
||||
|
||||
function buildInventoryTypeLabel(inventory) {
|
||||
inventory.kind_label = inventory.kind === '' ? 'Inventory' : (inventory.kind === 'smart' ? 'Smart Inventory': 'Inventory');
|
||||
}
|
||||
|
||||
function ellipsis(a) {
|
||||
if (a.length > 20) {
|
||||
return a.substr(0,20) + '...';
|
||||
@ -249,12 +258,13 @@ function InventoriesList($scope, $rootScope, $location,
|
||||
|
||||
};
|
||||
|
||||
$scope.addInventory = function () {
|
||||
$state.go('inventories.add');
|
||||
};
|
||||
|
||||
$scope.editInventory = function (id) {
|
||||
$state.go('inventories.edit', {inventory_id: id});
|
||||
$scope.editInventory = function (inventory) {
|
||||
if(inventory.kind && inventory.kind === 'smart') {
|
||||
$state.go('inventories.editSmartInventory', {smartinventory_id: inventory.id});
|
||||
}
|
||||
else {
|
||||
$state.go('inventories.edit', {inventory_id: inventory.id});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.manageInventory = function(id){
|
||||
|
||||
@ -10,28 +10,25 @@ import group from './groups/main';
|
||||
import sources from './sources/main';
|
||||
import relatedHost from './related-hosts/main';
|
||||
import inventoryCompletedJobs from './completed_jobs/main';
|
||||
import inventoryAdd from './add/main';
|
||||
import inventoryEdit from './edit/main';
|
||||
import inventoryList from './list/main';
|
||||
import hostGroups from './host-groups/main';
|
||||
import { templateUrl } from '../shared/template-url/template-url.factory';
|
||||
import { N_ } from '../i18n';
|
||||
import InventoryList from './inventory.list';
|
||||
import InventoryForm from './inventory.form';
|
||||
import InventoryManageService from './inventory-manage.service';
|
||||
import adHocRoute from './adhoc/adhoc.route';
|
||||
import ansibleFacts from './ansible_facts/main';
|
||||
import insights from './insights/main';
|
||||
import { copyMoveGroupRoute, copyMoveHostRoute } from './copy-move/copy-move.route';
|
||||
import copyMove from './copy-move/main';
|
||||
import inventoryCompletedJobsRoute from './completed_jobs/completed_jobs.route';
|
||||
import completedJobsRoute from './completed_jobs/completed_jobs.route';
|
||||
import inventorySourceEditRoute from './sources/edit/sources-edit.route';
|
||||
import inventorySourceAddRoute from './sources/add/sources-add.route';
|
||||
import inventorySourceListRoute from './sources/list/sources-list.route';
|
||||
import inventorySourceListScheduleRoute from './sources/list/schedule/sources-schedule.route';
|
||||
import inventorySourceListScheduleAddRoute from './sources/list/schedule/sources-schedule-add.route';
|
||||
import inventorySourceListScheduleEditRoute from './sources/list/schedule/sources-schedule-edit.route';
|
||||
import inventoryAdhocCredential from './adhoc/adhoc-credential.route';
|
||||
import adhocCredentialRoute from './adhoc/adhoc-credential.route';
|
||||
import inventoryGroupsList from './groups/list/groups-list.route';
|
||||
import inventoryGroupsAdd from './groups/add/groups-add.route';
|
||||
import inventoryGroupsEdit from './groups/edit/groups-edit.route';
|
||||
@ -39,6 +36,7 @@ import nestedGroups from './groups/nested-groups/nested-groups.route';
|
||||
import nestedGroupsAdd from './groups/nested-groups/nested-groups-add.route';
|
||||
import nestedHosts from './groups/nested-hosts/nested-hosts.route';
|
||||
import inventoryHosts from './related-hosts/related-host.route';
|
||||
import smartInventoryHosts from './smart-inventory/smart-inventory-hosts.route';
|
||||
import inventoriesList from './inventories.route';
|
||||
import inventoryHostsAdd from './related-hosts/add/host-add.route';
|
||||
import inventoryHostsEdit from './related-hosts/edit/host-edit.route';
|
||||
@ -50,6 +48,8 @@ import hostGroupsRoute from './host-groups/host-groups.route';
|
||||
import hostGroupsAssociateRoute from './host-groups/host-groups-associate/host-groups-associate.route';
|
||||
import inventorySourcesCredentialRoute from './sources/lookup/sources-lookup-credential.route';
|
||||
import inventorySourcesInventoryScriptRoute from './sources/lookup/sources-lookup-inventory-script.route';
|
||||
import SmartInventory from './smart-inventory/main';
|
||||
import StandardInventory from './standard/main';
|
||||
|
||||
export default
|
||||
angular.module('inventory', [
|
||||
@ -59,15 +59,14 @@ angular.module('inventory', [
|
||||
sources.name,
|
||||
relatedHost.name,
|
||||
inventoryCompletedJobs.name,
|
||||
inventoryAdd.name,
|
||||
inventoryEdit.name,
|
||||
inventoryList.name,
|
||||
ansibleFacts.name,
|
||||
insights.name,
|
||||
copyMove.name,
|
||||
hostGroups.name
|
||||
hostGroups.name,
|
||||
SmartInventory.name,
|
||||
StandardInventory.name
|
||||
])
|
||||
.factory('InventoryForm', InventoryForm)
|
||||
.factory('InventoryList', InventoryList)
|
||||
.service('InventoryManageService', InventoryManageService)
|
||||
.config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider',
|
||||
@ -79,7 +78,7 @@ angular.module('inventory', [
|
||||
|
||||
let basicInventoryAdd = stateDefinitions.generateTree({
|
||||
name: 'inventories.add', // top-most node in the generated tree (will replace this state definition)
|
||||
url: '/basic_inventory/add',
|
||||
url: '/standard_inventory/add',
|
||||
modes: ['add'],
|
||||
form: 'InventoryForm',
|
||||
controllers: {
|
||||
@ -89,7 +88,7 @@ angular.module('inventory', [
|
||||
|
||||
let basicInventoryEdit = stateDefinitions.generateTree({
|
||||
name: 'inventories.edit',
|
||||
url: '/basic_inventory/:inventory_id',
|
||||
url: '/standard_inventory/:inventory_id',
|
||||
modes: ['edit'],
|
||||
form: 'InventoryForm',
|
||||
controllers: {
|
||||
@ -102,9 +101,9 @@ angular.module('inventory', [
|
||||
|
||||
let smartInventoryAdd = stateDefinitions.generateTree({
|
||||
name: 'inventories.addSmartInventory', // top-most node in the generated tree (will replace this state definition)
|
||||
url: '/smart_inventory/add?hostfilter',
|
||||
url: '/smart/add?hostfilter',
|
||||
modes: ['add'],
|
||||
form: 'SmartInventoryForm',
|
||||
form: 'smartInventoryForm',
|
||||
controllers: {
|
||||
add: 'SmartInventoryAddController'
|
||||
}
|
||||
@ -112,11 +111,14 @@ angular.module('inventory', [
|
||||
|
||||
let smartInventoryEdit = stateDefinitions.generateTree({
|
||||
name: 'inventories.editSmartInventory',
|
||||
url: '/smart_inventory/:inventory_id',
|
||||
url: '/smart/:smartinventory_id',
|
||||
modes: ['edit'],
|
||||
form: 'SmartInventoryForm',
|
||||
form: 'smartInventoryForm',
|
||||
controllers: {
|
||||
edit: 'SmartInventoryEditController'
|
||||
},
|
||||
breadcrumbs: {
|
||||
edit: '{{breadcrumb.inventory_name}}'
|
||||
}
|
||||
});
|
||||
|
||||
@ -169,6 +171,24 @@ angular.module('inventory', [
|
||||
editSourceInventoryScript.name = 'inventories.edit.inventory_sources.edit.inventory_script';
|
||||
editSourceInventoryScript.url = '/inventory_script';
|
||||
|
||||
let inventoryCompletedJobsRoute = _.cloneDeep(completedJobsRoute);
|
||||
inventoryCompletedJobsRoute.name = 'inventories.edit.completed_jobs';
|
||||
|
||||
let smartInventoryCompletedJobsRoute = _.cloneDeep(completedJobsRoute);
|
||||
smartInventoryCompletedJobsRoute.name = 'inventories.editSmartInventory.completed_jobs';
|
||||
|
||||
let inventoryAdhocRoute = _.cloneDeep(adHocRoute);
|
||||
inventoryAdhocRoute.name = 'inventories.edit.adhoc';
|
||||
|
||||
let smartInventoryAdhocRoute = _.cloneDeep(adHocRoute);
|
||||
smartInventoryAdhocRoute.name = 'inventories.editSmartInventory.adhoc';
|
||||
|
||||
let inventoryAdhocCredential = _.cloneDeep(adhocCredentialRoute);
|
||||
inventoryAdhocCredential.name = 'inventories.edit.adhoc.credential';
|
||||
|
||||
let smartInventoryAdhocCredential = _.cloneDeep(adhocCredentialRoute);
|
||||
smartInventoryAdhocCredential.name = 'inventories.editSmartInventory.adhoc.credential';
|
||||
|
||||
return Promise.all([
|
||||
basicInventoryAdd,
|
||||
basicInventoryEdit,
|
||||
@ -180,8 +200,10 @@ angular.module('inventory', [
|
||||
return result.concat(definition.states);
|
||||
}, [
|
||||
stateExtender.buildDefinition(inventoriesList),
|
||||
stateExtender.buildDefinition(adHocRoute),
|
||||
stateExtender.buildDefinition(inventoryAdhocRoute),
|
||||
stateExtender.buildDefinition(smartInventoryAdhocRoute),
|
||||
stateExtender.buildDefinition(inventoryAdhocCredential),
|
||||
stateExtender.buildDefinition(smartInventoryAdhocCredential),
|
||||
stateExtender.buildDefinition(inventorySourceListScheduleRoute),
|
||||
stateExtender.buildDefinition(inventorySourceListScheduleAddRoute),
|
||||
stateExtender.buildDefinition(inventorySourceListScheduleEditRoute),
|
||||
@ -201,6 +223,7 @@ angular.module('inventory', [
|
||||
stateExtender.buildDefinition(nestedHostsEdit),
|
||||
stateExtender.buildDefinition(inventoryGroupsEditNestedHostsEditGroups),
|
||||
stateExtender.buildDefinition(inventoryHosts),
|
||||
stateExtender.buildDefinition(smartInventoryHosts),
|
||||
stateExtender.buildDefinition(inventoryHostsAdd),
|
||||
stateExtender.buildDefinition(inventoryHostsEdit),
|
||||
stateExtender.buildDefinition(inventoryHostsEditGroups),
|
||||
@ -208,6 +231,7 @@ angular.module('inventory', [
|
||||
stateExtender.buildDefinition(inventorySourceAddRoute),
|
||||
stateExtender.buildDefinition(inventorySourceEditRoute),
|
||||
stateExtender.buildDefinition(inventoryCompletedJobsRoute),
|
||||
stateExtender.buildDefinition(smartInventoryCompletedJobsRoute),
|
||||
stateExtender.buildDefinition(addSourceCredential),
|
||||
stateExtender.buildDefinition(addSourceInventoryScript),
|
||||
stateExtender.buildDefinition(editSourceCredential),
|
||||
@ -225,7 +249,6 @@ angular.module('inventory', [
|
||||
list: 'HostsList',
|
||||
form: 'HostsForm',
|
||||
controllers: {
|
||||
list: 'HostListController',
|
||||
edit: 'HostEditController'
|
||||
},
|
||||
breadcrumbs: {
|
||||
@ -245,23 +268,14 @@ angular.module('inventory', [
|
||||
]
|
||||
}
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: N_('HOSTS')
|
||||
},
|
||||
views: {
|
||||
'@': {
|
||||
templateUrl: templateUrl('inventories/inventories')
|
||||
},
|
||||
'list@hosts': {
|
||||
templateProvider: function(HostsList, generateList) {
|
||||
let html = generateList.build({
|
||||
list: HostsList,
|
||||
mode: 'edit'
|
||||
});
|
||||
return html;
|
||||
},
|
||||
templateUrl: templateUrl('inventories/hosts/hosts'),
|
||||
controller: 'HostListController'
|
||||
}
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: N_('HOSTS')
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
*************************************************/
|
||||
|
||||
export default
|
||||
['$scope', '$state', '$stateParams', 'DashboardHostsForm', 'GenerateForm', 'ParseTypeChange', 'DashboardHostService', 'host', '$rootScope',
|
||||
function($scope, $state, $stateParams, DashboardHostsForm, GenerateForm, ParseTypeChange, DashboardHostService, host, $rootScope){
|
||||
['$scope', '$state', '$stateParams', 'GenerateForm', 'ParseTypeChange', 'HostManageService', 'host', '$rootScope',
|
||||
function($scope, $state, $stateParams, GenerateForm, ParseTypeChange, HostManageService, host, $rootScope){
|
||||
$scope.parseType = 'yaml';
|
||||
$scope.formCancel = function(){
|
||||
$state.go('^', null, {reload: true});
|
||||
@ -28,8 +28,8 @@
|
||||
description: $scope.description,
|
||||
enabled: $scope.host.enabled
|
||||
};
|
||||
DashboardHostService.putHost(host).then(function(){
|
||||
$state.go('^', null, {reload: true});
|
||||
HostManageService.put(host).then(function(){
|
||||
$state.go('.', null, {reload: true});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@ -5,14 +5,14 @@
|
||||
*************************************************/
|
||||
|
||||
// import HostManageService from './../hosts/host.service';
|
||||
export default ['$scope', 'RelatedHostsListDefinition', '$rootScope', 'GetBasePath',
|
||||
export default ['$scope', 'ListDefinition', '$rootScope', 'GetBasePath',
|
||||
'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait',
|
||||
'HostManageService', 'SetStatus',
|
||||
function($scope, RelatedHostsListDefinition, $rootScope, GetBasePath,
|
||||
function($scope, ListDefinition, $rootScope, GetBasePath,
|
||||
rbacUiControlService, Dataset, $state, $filter, Prompt, Wait,
|
||||
HostManageService, SetStatus) {
|
||||
|
||||
let list = RelatedHostsListDefinition;
|
||||
let list = ListDefinition;
|
||||
|
||||
init();
|
||||
|
||||
@ -42,22 +42,17 @@ export default ['$scope', 'RelatedHostsListDefinition', '$rootScope', 'GetBasePa
|
||||
});
|
||||
|
||||
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams) {
|
||||
if(toState.name === 'hosts.addSmartInventory') {
|
||||
$scope.enableSmartInventoryButton = false;
|
||||
if(toParams && toParams.host_search) {
|
||||
let hasMoreThanDefaultKeys = false;
|
||||
angular.forEach(toParams.host_search, function(value, key) {
|
||||
if(key !== 'order_by' && key !== 'page_size') {
|
||||
hasMoreThanDefaultKeys = true;
|
||||
}
|
||||
});
|
||||
$scope.enableSmartInventoryButton = hasMoreThanDefaultKeys ? true : false;
|
||||
}
|
||||
else {
|
||||
if(toParams && toParams.host_search) {
|
||||
let hasMoreThanDefaultKeys = false;
|
||||
angular.forEach(toParams.host_search, function(value, key) {
|
||||
if(key !== 'order_by' && key !== 'page_size') {
|
||||
hasMoreThanDefaultKeys = true;
|
||||
}
|
||||
});
|
||||
$scope.enableSmartInventoryButton = hasMoreThanDefaultKeys ? true : false;
|
||||
}
|
||||
else {
|
||||
$scope.enableSmartInventoryButton = false;
|
||||
}
|
||||
$scope.enableSmartInventoryButton = false;
|
||||
}
|
||||
});
|
||||
|
||||
@ -142,7 +137,7 @@ export default ['$scope', 'RelatedHostsListDefinition', '$rootScope', 'GetBasePa
|
||||
$scope.systemTracking = function(){
|
||||
var hostIds = _.map($scope.hostsSelected, (host) => host.id);
|
||||
$state.go('systemTracking', {
|
||||
inventoryId: $state.params.inventory_id,
|
||||
inventoryId: $state.params.inventory_id ? $state.params.inventory_id : $state.params.smartinventory_id,
|
||||
hosts: $scope.hostsSelected,
|
||||
hostIds: hostIds
|
||||
});
|
||||
|
||||
@ -109,14 +109,6 @@ export default {
|
||||
tooltipInnerClass: "Tooltip-wide",
|
||||
ngShow: true
|
||||
},
|
||||
refresh: {
|
||||
mode: 'all',
|
||||
awToolTip: "Refresh the page",
|
||||
ngClick: "refreshGroups()",
|
||||
ngShow: "socketStatus == 'error'",
|
||||
actionClass: 'btn List-buttonDefault',
|
||||
buttonContent: 'REFRESH'
|
||||
},
|
||||
create: {
|
||||
mode: 'all',
|
||||
ngClick: "createHost()",
|
||||
|
||||
@ -19,8 +19,8 @@ export default {
|
||||
},
|
||||
views: {
|
||||
'related': {
|
||||
templateProvider: function(RelatedHostsListDefinition, generateList, $stateParams, GetBasePath) {
|
||||
let list = _.cloneDeep(RelatedHostsListDefinition);
|
||||
templateProvider: function(ListDefinition, generateList, $stateParams, GetBasePath) {
|
||||
let list = _.cloneDeep(ListDefinition);
|
||||
if($stateParams && $stateParams.group) {
|
||||
list.basePath = GetBasePath('groups') + _.last($stateParams.group) + '/all_hosts';
|
||||
}
|
||||
@ -38,7 +38,12 @@ export default {
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
Dataset: ['RelatedHostsListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope',
|
||||
ListDefinition: ['RelatedHostsListDefinition', '$stateParams', 'GetBasePath', (RelatedHostsListDefinition, $stateParams, GetBasePath) => {
|
||||
let list = _.cloneDeep(RelatedHostsListDefinition);
|
||||
list.basePath = GetBasePath('inventory') + $stateParams.inventory_id + '/hosts';
|
||||
return list;
|
||||
}],
|
||||
Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope',
|
||||
(list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => {
|
||||
// allow related list definitions to use interpolated $rootScope / $stateParams in basePath field
|
||||
let path, interpolator;
|
||||
@ -58,7 +63,7 @@ export default {
|
||||
// root context - provide all hosts in an inventory
|
||||
InventoryManageService.rootHostsUrl($stateParams.inventory_id);
|
||||
}],
|
||||
hostsDataset: ['RelatedHostsListDefinition', 'QuerySet', '$stateParams', 'hostsUrl', (list, qs, $stateParams, hostsUrl) => {
|
||||
hostsDataset: ['ListDefinition', 'QuerySet', '$stateParams', 'hostsUrl', (list, qs, $stateParams, hostsUrl) => {
|
||||
let path = hostsUrl;
|
||||
return qs.search(path, $stateParams[`${list.iterator}_search`]);
|
||||
}],
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
function SmartInventoryAdd($scope, $location,
|
||||
GenerateForm, SmartInventoryForm, rbacUiControlService, Rest, Alert, ProcessErrors,
|
||||
GenerateForm, smartInventoryForm, rbacUiControlService, Rest, Alert, ProcessErrors,
|
||||
ClearScope, GetBasePath, ParseTypeChange, Wait, ToJSON,
|
||||
$state) {
|
||||
|
||||
@ -34,7 +34,7 @@ function SmartInventoryAdd($scope, $location,
|
||||
|
||||
// Inject dynamic view
|
||||
var defaultUrl = GetBasePath('inventory'),
|
||||
form = SmartInventoryForm;
|
||||
form = smartInventoryForm;
|
||||
|
||||
init();
|
||||
|
||||
@ -49,37 +49,39 @@ function SmartInventoryAdd($scope, $location,
|
||||
$scope.parseType = 'yaml';
|
||||
ParseTypeChange({
|
||||
scope: $scope,
|
||||
variable: 'variables',
|
||||
variable: 'smartinventory_variables',
|
||||
parse_variable: 'parseType',
|
||||
field_id: 'smartinventory_variables'
|
||||
field_id: 'smartinventory_smartinventory_variables'
|
||||
});
|
||||
|
||||
$scope.dynamic_hosts = $state.params.hostfilter ? JSON.parse($state.params.hostfilter) : '';
|
||||
$scope.smart_hosts = $state.params.hostfilter ? JSON.parse($state.params.hostfilter) : '';
|
||||
}
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
Wait('start');
|
||||
try {
|
||||
var fld, json_data, data;
|
||||
let fld, 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];
|
||||
}
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
|
||||
data.variables = ToJSON($scope.parseType, $scope.smartinventory_variables, true);
|
||||
|
||||
let decodedHostFilter = decodeURIComponent($scope.smart_hosts.host_filter);
|
||||
decodedHostFilter = decodedHostFilter.replace(/__icontains_DEFAULT/g, "__icontains");
|
||||
decodedHostFilter = decodedHostFilter.replace(/__search_DEFAULT/g, "__search");
|
||||
data.host_filter = decodedHostFilter;
|
||||
|
||||
data.kind = "smart";
|
||||
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.post(data)
|
||||
.success(function(data) {
|
||||
var inventory_id = data.id;
|
||||
Wait('stop');
|
||||
$location.path('/inventories/' + inventory_id);
|
||||
$state.go('inventories.editSmartInventory', {smartinventory_id: inventory_id}, {reload: true});
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, form, {
|
||||
@ -95,12 +97,12 @@ function SmartInventoryAdd($scope, $location,
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('hosts');
|
||||
$state.go('inventories');
|
||||
};
|
||||
}
|
||||
|
||||
export default ['$scope', '$location',
|
||||
'GenerateForm', 'SmartInventoryForm', 'rbacUiControlService', 'Rest', 'Alert',
|
||||
'GenerateForm', 'smartInventoryForm', 'rbacUiControlService', 'Rest', 'Alert',
|
||||
'ProcessErrors', 'ClearScope', 'GetBasePath', 'ParseTypeChange',
|
||||
'Wait', 'ToJSON', '$state', SmartInventoryAdd
|
||||
];
|
||||
@ -0,0 +1,103 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
function SmartInventoryEdit($scope, $location,
|
||||
$stateParams, InventoryForm, Rest, ProcessErrors,
|
||||
ClearScope, GetBasePath, ParseTypeChange, Wait, ToJSON,
|
||||
ParseVariableString, $state, OrgAdminLookup, resourceData, $rootScope) {
|
||||
|
||||
// Inject dynamic view
|
||||
var defaultUrl = GetBasePath('inventory'),
|
||||
form = InventoryForm,
|
||||
inventory_id = $stateParams.smartinventory_id,
|
||||
inventoryData = resourceData.data;
|
||||
|
||||
ClearScope();
|
||||
init();
|
||||
|
||||
function init() {
|
||||
ClearScope();
|
||||
form.formLabelSize = null;
|
||||
form.formFieldSize = null;
|
||||
$scope.inventory_id = inventory_id;
|
||||
|
||||
$scope = angular.extend($scope, inventoryData);
|
||||
|
||||
$scope.smartinventory_variables = inventoryData.variables === null || inventoryData.variables === '' ? '---' : ParseVariableString(inventoryData.variables);
|
||||
$scope.organization_name = inventoryData.summary_fields.organization.name;
|
||||
|
||||
$scope.$watch('inventory_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||
if (val === false) {
|
||||
$scope.canAdd = false;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.parseType = 'yaml';
|
||||
|
||||
$rootScope.$on('$stateChangeSuccess', function(event, toState) {
|
||||
if(toState.name === 'inventories.editSmartInventory') {
|
||||
ParseTypeChange({
|
||||
scope: $scope,
|
||||
variable: 'smartinventory_variables',
|
||||
parse_variable: 'parseType',
|
||||
field_id: 'smartinventory_smartinventory_variables'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
OrgAdminLookup.checkForAdminAccess({organization: inventoryData.organization})
|
||||
.then(function(canEditOrg){
|
||||
$scope.canEditOrg = canEditOrg;
|
||||
});
|
||||
|
||||
$scope.inventory_obj = inventoryData;
|
||||
$rootScope.breadcrumb.inventory_name = inventoryData.name;
|
||||
|
||||
$scope.smart_hosts = {
|
||||
host_filter: encodeURIComponent($scope.host_filter)
|
||||
};
|
||||
}
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
Wait('start');
|
||||
|
||||
let fld, data = {};
|
||||
|
||||
for (fld in form.fields) {
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
|
||||
data.variables = ToJSON($scope.parseType, $scope.smartinventory_variables, true);
|
||||
data.host_filter = decodeURIComponent($scope.smart_hosts.host_filter);
|
||||
data.kind = "smart";
|
||||
|
||||
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('inventories');
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default [ '$scope', '$location',
|
||||
'$stateParams', 'InventoryForm', 'Rest',
|
||||
'ProcessErrors', 'ClearScope', 'GetBasePath', 'ParseTypeChange', 'Wait',
|
||||
'ToJSON', 'ParseVariableString',
|
||||
'$state', 'OrgAdminLookup', 'resourceData', '$rootScope', SmartInventoryEdit
|
||||
];
|
||||
@ -6,15 +6,15 @@
|
||||
|
||||
import smartInventoryAdd from './add/main';
|
||||
import smartInventoryEdit from './edit/main';
|
||||
import SmartInventoryForm from './smart-inventory.form';
|
||||
import dynamicInventoryHostFilter from './dynamic-inventory-host-filter/dynamic-inventory-host-filter.directive';
|
||||
import hostFilterModal from './dynamic-inventory-host-filter/host-filter-modal/host-filter-modal.directive';
|
||||
import smartInventoryForm from './smart-inventory.form';
|
||||
import smartInventoryHostFilter from './smart-inventory-host-filter/smart-inventory-host-filter.directive';
|
||||
import hostFilterModal from './smart-inventory-host-filter/host-filter-modal/host-filter-modal.directive';
|
||||
|
||||
export default
|
||||
angular.module('smartInventory', [
|
||||
smartInventoryAdd.name,
|
||||
smartInventoryEdit.name
|
||||
])
|
||||
.factory('SmartInventoryForm', SmartInventoryForm)
|
||||
.directive('dynamicInventoryHostFilter', dynamicInventoryHostFilter)
|
||||
.factory('smartInventoryForm', smartInventoryForm)
|
||||
.directive('smartInventoryHostFilter', smartInventoryHostFilter)
|
||||
.directive('hostFilterModal', hostFilterModal);
|
||||
@ -4,7 +4,7 @@ export default ['templateUrl', function(templateUrl) {
|
||||
scope: {
|
||||
hostFilter: '='
|
||||
},
|
||||
templateUrl: templateUrl('inventories/hosts/smart-inventory/dynamic-inventory-host-filter/host-filter-modal/host-filter-modal'),
|
||||
templateUrl: templateUrl('inventories/smart-inventory/smart-inventory-host-filter/host-filter-modal/host-filter-modal'),
|
||||
link: function(scope, element) {
|
||||
|
||||
$('#host-filter-modal').on('hidden.bs.modal', function () {
|
||||
@ -44,7 +44,7 @@ export default ['templateUrl', function(templateUrl) {
|
||||
let hostList = _.cloneDeep(HostsList);
|
||||
delete hostList.fields.toggleHost;
|
||||
delete hostList.fields.active_failures;
|
||||
delete hostList.fields.inventory_name;
|
||||
delete hostList.fields.inventory;
|
||||
let html = GenerateList.build({
|
||||
list: hostList,
|
||||
input_type: 'foobar',
|
||||
@ -0,0 +1,32 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', 'QuerySet',
|
||||
function($scope, qs) {
|
||||
$scope.hostFilterTags = [];
|
||||
|
||||
$scope.$watch('hostFilter', function(){
|
||||
$scope.hostFilterTags = [];
|
||||
|
||||
if($scope.hostFilter && $scope.hostFilter !== '') {
|
||||
let hostFilterCopy = angular.copy($scope.hostFilter);
|
||||
|
||||
let searchParam = hostFilterCopy.host_filter.split('%20and%20');
|
||||
delete hostFilterCopy.host_filter;
|
||||
|
||||
$.each(searchParam, function(index, param) {
|
||||
let paramParts = decodeURIComponent(param).split(/=(.+)/);
|
||||
paramParts[0] = paramParts[0].replace(/__icontains(_DEFAULT)?/g, "");
|
||||
paramParts[0] = paramParts[0].replace(/__search(_DEFAULT)?/g, "");
|
||||
let reconstructedSearchString = qs.decodeParam(paramParts[1], paramParts[0]);
|
||||
$scope.hostFilterTags.push(reconstructedSearchString);
|
||||
});
|
||||
|
||||
$scope.hostFilterTags = $scope.hostFilterTags.concat(qs.stripDefaultParams(hostFilterCopy));
|
||||
}
|
||||
});
|
||||
}
|
||||
];
|
||||
@ -4,7 +4,7 @@
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import dynamicInventoryHostFilterController from './dynamic-inventory-host-filter.controller';
|
||||
import smartInventoryHostFilterController from './smart-inventory-host-filter.controller';
|
||||
|
||||
export default ['templateUrl', '$compile',
|
||||
function(templateUrl, $compile) {
|
||||
@ -13,8 +13,8 @@ export default ['templateUrl', '$compile',
|
||||
hostFilter: '='
|
||||
},
|
||||
restrict: 'E',
|
||||
templateUrl: templateUrl('inventories/hosts/smart-inventory/dynamic-inventory-host-filter/dynamic-inventory-host-filter'),
|
||||
controller: dynamicInventoryHostFilterController,
|
||||
templateUrl: templateUrl('inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter'),
|
||||
controller: smartInventoryHostFilterController,
|
||||
link: function(scope) {
|
||||
scope.openHostFilterModal = function() {
|
||||
$('#content-container').append($compile('<host-filter-modal host-filter="hostFilter"></host-filter-modal>')(scope));
|
||||
@ -0,0 +1,12 @@
|
||||
<div class="input-group Form-mixedInputGroup">
|
||||
<span class="input-group-btn Form-variableHeightButtonGroup">
|
||||
<button type="button" class="Form-lookupButton Form-lookupButton--variableHeight btn btn-default" ng-click="openHostFilterModal()">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</span>
|
||||
<span class="form-control Form-textInput Form-textInput--variableHeight input-medium lookup" style="padding: 4px 6px;">
|
||||
<span class="LabelList-tag" ng-repeat="tag in hostFilterTags">
|
||||
<span class="LabelList-name">{{tag}}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@ -0,0 +1,63 @@
|
||||
import { N_ } from '../../i18n';
|
||||
|
||||
export default {
|
||||
name: "inventories.editSmartInventory.hosts",
|
||||
url: "/hosts?{host_search:queryset}",
|
||||
params: {
|
||||
host_search: {
|
||||
value: {
|
||||
page_size: "20",
|
||||
order_by: "name"
|
||||
},
|
||||
dynamic: true,
|
||||
squash:""
|
||||
}
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: N_("HOSTS")
|
||||
},
|
||||
views: {
|
||||
'related': {
|
||||
templateProvider: function(ListDefinition, generateList) {
|
||||
let list = _.cloneDeep(ListDefinition);
|
||||
let html = generateList.build({
|
||||
list: list,
|
||||
mode: 'edit'
|
||||
});
|
||||
return html;
|
||||
},
|
||||
controller: 'RelatedHostListController'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
ListDefinition: ['RelatedHostsListDefinition', '$stateParams', 'GetBasePath', (RelatedHostsListDefinition, $stateParams, GetBasePath) => {
|
||||
let list = _.cloneDeep(RelatedHostsListDefinition);
|
||||
list.basePath = GetBasePath('inventory') + $stateParams.smartinventory_id + '/hosts';
|
||||
delete list.actions.create;
|
||||
return list;
|
||||
}],
|
||||
Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope',
|
||||
(list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => {
|
||||
// allow related list definitions to use interpolated $rootScope / $stateParams in basePath field
|
||||
let path, interpolator;
|
||||
if (GetBasePath(list.basePath)) {
|
||||
path = GetBasePath(list.basePath);
|
||||
} else {
|
||||
interpolator = $interpolate(list.basePath);
|
||||
path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams });
|
||||
}
|
||||
return qs.search(path, $stateParams[`${list.iterator}_search`]);
|
||||
}
|
||||
],
|
||||
hostsUrl: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams) {
|
||||
return InventoryManageService.rootHostsUrl($stateParams.smartinventory_id);
|
||||
}],
|
||||
hostsDataset: ['ListDefinition', 'QuerySet', '$stateParams', 'hostsUrl', (list, qs, $stateParams, hostsUrl) => {
|
||||
let path = hostsUrl;
|
||||
return qs.search(path, $stateParams[`${list.iterator}_search`]);
|
||||
}],
|
||||
inventoryData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams) {
|
||||
return InventoryManageService.getInventory($stateParams.smartinventory_id).then(res => res.data);
|
||||
}]
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,169 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['i18n', 'InventoryCompletedJobsList', function(i18n, InventoryCompletedJobsList) {
|
||||
|
||||
var completed_jobs_object = {
|
||||
name: 'completed_jobs',
|
||||
index: false,
|
||||
basePath: "unified_jobs",
|
||||
title: i18n._('Completed Jobs'),
|
||||
iterator: 'completed_job',
|
||||
generateList: true,
|
||||
skipGenerator: true,
|
||||
search: {
|
||||
"or__job__inventory": ''
|
||||
},
|
||||
ngClick: "$state.go('inventories.editSmartInventory.completed_jobs')"
|
||||
};
|
||||
|
||||
let clone = _.clone(InventoryCompletedJobsList);
|
||||
completed_jobs_object = angular.extend(clone, completed_jobs_object);
|
||||
|
||||
return {
|
||||
|
||||
addTitle: i18n._('NEW SMART INVENTORY'),
|
||||
editTitle: '{{ name }}',
|
||||
name: 'smartinventory',
|
||||
basePath: 'inventory',
|
||||
breadcrumbName: 'SMART INVENTORY',
|
||||
stateTree: 'inventories',
|
||||
activeEditState: 'inventories.editSmartInventory',
|
||||
detailsClick: "$state.go('inventories.editSmartInventory')",
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
label: i18n._('Name'),
|
||||
type: 'text',
|
||||
required: true,
|
||||
capitalize: false,
|
||||
ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
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'
|
||||
},
|
||||
smart_hosts: {
|
||||
label: i18n._('Smart Hosts'),
|
||||
type: 'custom',
|
||||
control: '<smart-inventory-host-filter host-filter="smart_hosts"></smart-inventory-host-filter>',
|
||||
basePath: 'hosts',
|
||||
list: 'HostsList',
|
||||
sourceModel: 'host',
|
||||
sourceField: 'name',
|
||||
required: true,
|
||||
class: 'Form-formGroup--fullWidth'
|
||||
},
|
||||
smartinventory_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.smartinventory_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: {
|
||||
key: true,
|
||||
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',
|
||||
}
|
||||
},
|
||||
ngClick: "$state.go('inventories.editSmartInventory.permissions');"
|
||||
},
|
||||
hosts: {
|
||||
name: 'hosts',
|
||||
include: "RelatedHostsListDefinition",
|
||||
title: i18n._('Hosts'),
|
||||
iterator: 'host',
|
||||
ngClick: "$state.go('inventories.editSmartInventory.hosts');",
|
||||
skipGenerator: true
|
||||
},
|
||||
completed_jobs: completed_jobs_object
|
||||
}
|
||||
|
||||
};
|
||||
}];
|
||||
@ -95,7 +95,7 @@
|
||||
$state.go('inventories.edit.inventory_sources.edit', {inventory_source_id: id});
|
||||
};
|
||||
$scope.deleteSource = function(inventory_source){
|
||||
var body = '<div class=\"Prompt-bodyQuery\">Are you sure you want to permanently delete the inventory source below from the inventory? Hosts generated by this inventory source will also be deleted.</div><div class=\"Prompt-bodyTarget\">' + $filter('sanitize')(inventory_source.name) + '</div>';
|
||||
var body = '<div class=\"Prompt-bodyQuery\">Are you sure you want to permanently delete the inventory source below from the inventory?</div><div class=\"Prompt-bodyTarget\">' + $filter('sanitize')(inventory_source.name) + '</div>';
|
||||
var action = function(){
|
||||
delete $rootScope.promptActionBtnClass;
|
||||
Wait('start');
|
||||
|
||||
@ -30,9 +30,7 @@ function InventoriesEdit($scope, $location,
|
||||
$scope = angular.extend($scope, inventoryData);
|
||||
|
||||
$scope.organization_name = inventoryData.summary_fields.organization.name;
|
||||
|
||||
$scope.inventory_variables = inventoryData.variables === null || inventoryData.variables === '' ? '---' : ParseVariableString(inventoryData.variables);
|
||||
|
||||
$scope.parseType = 'yaml';
|
||||
|
||||
$rootScope.$on('$stateChangeSuccess', function(event, toState) {
|
||||
@ -31,7 +31,7 @@ function(i18n, InventoryCompletedJobsList) {
|
||||
|
||||
return {
|
||||
|
||||
addTitle: i18n._('NEW INVENTORY'),
|
||||
addTitle: i18n._('NEW STANDARD INVENTORY'),
|
||||
editTitle: '{{ inventory_name }}',
|
||||
name: 'inventory',
|
||||
basePath: 'inventory',
|
||||
16
awx/ui/client/src/inventories/standard/main.js
Normal file
16
awx/ui/client/src/inventories/standard/main.js
Normal file
@ -0,0 +1,16 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import inventoryAdd from './add/main';
|
||||
import inventoryEdit from './edit/main';
|
||||
import InventoryForm from './inventory.form';
|
||||
|
||||
export default
|
||||
angular.module('standardInventory', [
|
||||
inventoryAdd.name,
|
||||
inventoryEdit.name
|
||||
])
|
||||
.factory('InventoryForm', InventoryForm);
|
||||
@ -55,6 +55,14 @@ function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTy
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if(key === 'inventory') {
|
||||
if($scope.job.summary_fields.inventory && $scope.job.summary_fields.inventory.kind && $scope.job.summary_fields.inventory.kind === 'smart') {
|
||||
return '/#/inventories/smart_inventory/' + $scope.job.summary_fields.inventory.id;
|
||||
}
|
||||
else {
|
||||
return '/#/inventories/standard_inventory/' + $scope.job.summary_fields.inventory.id;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($scope.job.related[key]) {
|
||||
return '/#/' + $scope.job.related[key]
|
||||
|
||||
@ -163,9 +163,9 @@ export default [
|
||||
Rest.setUrl(schedule.related.unified_job_template);
|
||||
Rest.get().then( (res) => {
|
||||
deferred.resolve({
|
||||
name: 'inventoryManage.editGroup.schedules.edit',
|
||||
name: 'inventories.edit.inventory_sources.edit.schedules.edit',
|
||||
params: {
|
||||
group_id: res.data.group,
|
||||
inventory_source_id: res.data.id,
|
||||
inventory_id: res.data.inventory,
|
||||
schedule_id: schedule.id,
|
||||
}
|
||||
@ -198,23 +198,8 @@ export default [
|
||||
}
|
||||
|
||||
function routeToScheduleForm(schedule){
|
||||
|
||||
buildStateMap(schedule).then( (state) =>{
|
||||
$state.go(state.name, state.params).catch((err) =>{
|
||||
// stateDefinition.lazyLoad'd state name matcher is not configured to match inventoryManage.* state names
|
||||
// However, the stateDefinition.lazyLoad url matcher will load the correct tree.
|
||||
// Expected error:
|
||||
// Transition rejection error
|
||||
// type: 4 // SUPERSEDED = 2, ABORTED = 3, INVALID = 4, IGNORED = 5, ERROR = 6
|
||||
// detail : "Could not resolve 'inventoryManage.editGroup.schedules.edit' from state 'jobs.schedules'"
|
||||
// message: "This transition is invalid"
|
||||
if (err.type === 4 && err.detail.includes('inventoryManage.editGroup.schedules.edit')){
|
||||
$location.path(`/inventories/${state.params.inventory_id}/manage/edit-group/${state.params.group_id}/schedules/${state.params.schedule_id}`);
|
||||
}
|
||||
else {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
buildStateMap(schedule).then((state) =>{
|
||||
$state.go(state.name, state.params);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -1464,6 +1464,10 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
html+= "<span class=\"Form-title--is_external_account\" "+
|
||||
"ng-show='external_account'>{{external_account}}</span>";
|
||||
}
|
||||
if(this.form.name === "smartinventory"){
|
||||
html+= "<span class=\"Form-title--is_smartinventory\" "+
|
||||
">" + i18n._("Smart Inventory") + "</span>";
|
||||
}
|
||||
html += "</div>\n";
|
||||
html += "<div class=\"Form-header--fields\">";
|
||||
if(this.form.headerFields){
|
||||
|
||||
@ -198,15 +198,13 @@ export default ['$compile', 'Attr', 'Icon',
|
||||
list.searchSize = 'col-lg-7 col-md-12 col-sm-12 col-xs-12';
|
||||
}
|
||||
if (options.showSearch === undefined || options.showSearch === true) {
|
||||
let nonstandardSearchParam = list.nonstandardSearchParam && list.nonstandardSearchParam.param ? list.nonstandardSearchParam.param : undefined;
|
||||
let nonstandardSearchParamRoot = list.nonstandardSearchParam && list.nonstandardSearchParam.root ? list.nonstandardSearchParam.root : undefined;
|
||||
let singleSearchParam = list.singleSearchParam && list.singleSearchParam.param ? `single-search-param="${list.singleSearchParam.param}"` : '';
|
||||
html += `
|
||||
<div ng-hide="${list.name}.length === 0 && (searchTags | isEmpty)">
|
||||
<smart-search
|
||||
django-model="${list.name}"
|
||||
search-size="${list.searchSize}"
|
||||
nonstandard-search-param="${nonstandardSearchParam}"
|
||||
nonstandard-search-param-root="${nonstandardSearchParamRoot}"
|
||||
${singleSearchParam}
|
||||
base-path="${list.basePath || list.name}"
|
||||
iterator="${list.iterator}"
|
||||
dataset="${list.iterator}_dataset"
|
||||
|
||||
@ -29,23 +29,6 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
||||
return defer.promise;
|
||||
},
|
||||
|
||||
/* @extendme
|
||||
// example:
|
||||
// retrieving options from a polymorphic model (unified_job)
|
||||
getPolymorphicModelOptions(path, name) {
|
||||
let defer = $q.defer(),
|
||||
paths = {
|
||||
project_update: GetBasePath('project_update'),
|
||||
inventory_update: GetBasePath('inventory_update'),
|
||||
job: GetBasePath('jobs'),
|
||||
ad_hoc_command: GetBasePath('ad_hoc_commands'),
|
||||
system_job: GetBasePath('system_jobs')
|
||||
};
|
||||
defer.all( // for each getCommonModelOptions() );
|
||||
return defer.promise;
|
||||
},
|
||||
*/
|
||||
|
||||
// encodes ui-router params from {operand__key__comparator: value} pairs to API-consumable URL
|
||||
encodeQueryset(params) {
|
||||
let queryset;
|
||||
@ -57,10 +40,11 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
||||
|
||||
function encodeTerm(value, key){
|
||||
|
||||
let root = key.split("__")[0].replace(/^-/, '');
|
||||
key = key.toString().replace(/__icontains_DEFAULT/g, "__icontains");
|
||||
key = key.toString().replace(/__search_DEFAULT/g, "__search");
|
||||
|
||||
key = key.replace(/__icontains_DEFAULT/g, "__icontains");
|
||||
key = key.replace(/__search_DEFAULT/g, "__search");
|
||||
value = value.toString().replace(/__icontains_DEFAULT/g, "__icontains");
|
||||
value = value.toString().replace(/__search_DEFAULT/g, "__search");
|
||||
|
||||
if (Array.isArray(value)){
|
||||
value = _.uniq(_.flattenDeep(value));
|
||||
@ -72,26 +56,10 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
||||
concated += `${key}=${item}&`;
|
||||
});
|
||||
|
||||
if(root === 'ansible_facts') {
|
||||
return `host_filter=${encodeURIComponent(concated)}&`;
|
||||
}
|
||||
else {
|
||||
return concated;
|
||||
}
|
||||
return concated;
|
||||
}
|
||||
else {
|
||||
if(value && typeof value === 'string') {
|
||||
value = decodeURIComponent(value).replace(/"|'/g, "");
|
||||
}
|
||||
|
||||
if(root === 'ansible_facts') {
|
||||
let foobar = encodeURIComponent(`${key}=${value}`);
|
||||
return `host_filter=${foobar}&`;
|
||||
}
|
||||
else {
|
||||
return `${key}=${value}&`;
|
||||
}
|
||||
|
||||
return `${key}=${value}&`;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -144,7 +112,12 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
||||
}
|
||||
}
|
||||
|
||||
return {[paramString] : encodeURIComponent(valueString)};
|
||||
if(params.singleSearchParam) {
|
||||
return {[params.singleSearchParam]: encodeURIComponent(paramString + "=" + valueString)};
|
||||
}
|
||||
else {
|
||||
return {[paramString] : encodeURIComponent(valueString)};
|
||||
}
|
||||
},
|
||||
// decodes a django queryset param into a ui smart-search tag or set of tags
|
||||
decodeParam(value, key){
|
||||
@ -155,8 +128,8 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
||||
return decodeURIComponent(`${searchString}`);
|
||||
}
|
||||
else {
|
||||
key = key.replace(/__icontains_DEFAULT/g, "");
|
||||
key = key.replace(/__search_DEFAULT/g, "");
|
||||
key = key.toString().replace(/__icontains_DEFAULT/g, "");
|
||||
key = key.toString().replace(/__search_DEFAULT/g, "");
|
||||
let split = key.split('__');
|
||||
let decodedParam = searchString;
|
||||
let exclude = false;
|
||||
|
||||
@ -6,31 +6,31 @@ export default ['$stateParams', '$scope', '$state', 'GetBasePath', 'QuerySet', '
|
||||
queryset,
|
||||
stateChangeSuccessListener;
|
||||
|
||||
if($scope.defaultParams) {
|
||||
defaults = $scope.defaultParams;
|
||||
}
|
||||
else {
|
||||
// steps through the current tree of $state configurations, grabs default search params
|
||||
defaults = _.find($state.$current.path, (step) => {
|
||||
if(step && step.params && step.params.hasOwnProperty(`${$scope.iterator}_search`)){
|
||||
return step.params.hasOwnProperty(`${$scope.iterator}_search`);
|
||||
}
|
||||
}).params[`${$scope.iterator}_search`].config.value;
|
||||
}
|
||||
|
||||
if($scope.querySet) {
|
||||
queryset = _.cloneDeep($scope.querySet);
|
||||
}
|
||||
else {
|
||||
queryset = $state.params[`${$scope.iterator}_search`];
|
||||
}
|
||||
|
||||
// build $scope.tags from $stateParams.QuerySet, build fieldset key
|
||||
init();
|
||||
|
||||
function init() {
|
||||
|
||||
if($scope.defaultParams) {
|
||||
defaults = $scope.defaultParams;
|
||||
}
|
||||
else {
|
||||
// steps through the current tree of $state configurations, grabs default search params
|
||||
defaults = _.find($state.$current.path, (step) => {
|
||||
if(step && step.params && step.params.hasOwnProperty(`${$scope.iterator}_search`)){
|
||||
return step.params.hasOwnProperty(`${$scope.iterator}_search`);
|
||||
}
|
||||
}).params[`${$scope.iterator}_search`].config.value;
|
||||
}
|
||||
|
||||
if($scope.querySet) {
|
||||
queryset = _.cloneDeep($scope.querySet);
|
||||
}
|
||||
else {
|
||||
queryset = $state.params[`${$scope.iterator}_search`];
|
||||
}
|
||||
|
||||
path = GetBasePath($scope.basePath) || $scope.basePath;
|
||||
$scope.searchTags = qs.stripDefaultParams(queryset, defaults);
|
||||
generateSearchTags();
|
||||
qs.initFieldset(path, $scope.djangoModel).then((data) => {
|
||||
$scope.models = data.models;
|
||||
$scope.options = data.options.data;
|
||||
@ -69,7 +69,7 @@ export default ['$stateParams', '$scope', '$state', 'GetBasePath', 'QuerySet', '
|
||||
});
|
||||
|
||||
$scope.searchTerm = null;
|
||||
$scope.searchTags = qs.stripDefaultParams(queryset, defaults);
|
||||
generateSearchTags();
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -86,7 +86,53 @@ export default ['$stateParams', '$scope', '$state', 'GetBasePath', 'QuerySet', '
|
||||
});
|
||||
}
|
||||
|
||||
function setDefaults(term) {
|
||||
function generateSearchTags() {
|
||||
$scope.searchTags = [];
|
||||
|
||||
let querysetCopy = angular.copy(queryset);
|
||||
|
||||
if($scope.singleSearchParam && querysetCopy[$scope.singleSearchParam]) {
|
||||
let searchParam = querysetCopy[$scope.singleSearchParam].split('%20and%20');
|
||||
delete querysetCopy[$scope.singleSearchParam];
|
||||
|
||||
$.each(searchParam, function(index, param) {
|
||||
let paramParts = decodeURIComponent(param).split(/=(.+)/);
|
||||
let reconstructedSearchString = qs.decodeParam(paramParts[1], paramParts[0]);
|
||||
$scope.searchTags.push(reconstructedSearchString);
|
||||
});
|
||||
}
|
||||
|
||||
$scope.searchTags = $scope.searchTags.concat(qs.stripDefaultParams(querysetCopy, defaults));
|
||||
}
|
||||
|
||||
function revertSearch(queryToBeRestored) {
|
||||
queryset = queryToBeRestored;
|
||||
// https://ui-router.github.io/docs/latest/interfaces/params.paramdeclaration.html#dynamic
|
||||
// This transition will not reload controllers/resolves/views
|
||||
// but will register new $stateParams[$scope.iterator + '_search'] terms
|
||||
if(!$scope.querySet) {
|
||||
$state.go('.', {
|
||||
[$scope.iterator + '_search']: queryset }, {notify: false});
|
||||
}
|
||||
qs.search(path, queryset).then((res) => {
|
||||
if($scope.querySet) {
|
||||
$scope.querySet = queryset;
|
||||
}
|
||||
$scope.dataset = res.data;
|
||||
$scope.collection = res.data.results;
|
||||
});
|
||||
|
||||
$scope.searchTerm = null;
|
||||
|
||||
generateSearchTags();
|
||||
}
|
||||
|
||||
function searchWithoutKey(term) {
|
||||
if($scope.singleSearchParam) {
|
||||
return {
|
||||
[$scope.singleSearchParam]: encodeURIComponent("search=" + term)
|
||||
};
|
||||
}
|
||||
return {
|
||||
search: encodeURIComponent(term)
|
||||
};
|
||||
@ -96,100 +142,8 @@ export default ['$stateParams', '$scope', '$state', 'GetBasePath', 'QuerySet', '
|
||||
$scope.showKeyPane = !$scope.showKeyPane;
|
||||
};
|
||||
|
||||
$scope.clearAll = function(){
|
||||
let cleared = _.cloneDeep(defaults);
|
||||
delete cleared.page;
|
||||
queryset = cleared;
|
||||
if(!$scope.querySet) {
|
||||
$state.go('.', {[$scope.iterator + '_search']: queryset}, {notify: false});
|
||||
}
|
||||
qs.search(path, queryset).then((res) => {
|
||||
if($scope.querySet) {
|
||||
$scope.querySet = queryset;
|
||||
}
|
||||
$scope.dataset = res.data;
|
||||
$scope.collection = res.data.results;
|
||||
});
|
||||
$scope.searchTags = qs.stripDefaultParams(queryset, defaults);
|
||||
};
|
||||
|
||||
// remove tag, merge new queryset, $state.go
|
||||
$scope.remove = function(index) {
|
||||
let tagToRemove = $scope.searchTags.splice(index, 1)[0],
|
||||
termParts = SmartSearchService.splitTermIntoParts(tagToRemove),
|
||||
removed;
|
||||
|
||||
let removeFromQuerySet = function(set) {
|
||||
_.each(removed, (value, key) => {
|
||||
if (Array.isArray(set[key])){
|
||||
_.remove(set[key], (item) => item === value);
|
||||
// If the array is now empty, remove that key
|
||||
if(set[key].length === 0) {
|
||||
delete set[key];
|
||||
}
|
||||
}
|
||||
else {
|
||||
delete set[key];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (termParts.length === 1) {
|
||||
removed = setDefaults(tagToRemove);
|
||||
}
|
||||
else {
|
||||
let root = termParts[0].split(".")[0].replace(/^-/, '');
|
||||
let encodeParams = {
|
||||
term: tagToRemove
|
||||
};
|
||||
if($scope.models[$scope.list.name]) {
|
||||
if(_.has($scope.models[$scope.list.name].base, root)) {
|
||||
if($scope.models[$scope.list.name].base[root].type && $scope.models[$scope.list.name].base[root].type === 'field') {
|
||||
encodeParams.relatedSearchTerm = true;
|
||||
}
|
||||
else {
|
||||
encodeParams.searchTerm = true;
|
||||
}
|
||||
removed = qs.encodeParam(encodeParams);
|
||||
}
|
||||
else if(_.contains($scope.models[$scope.list.name].related, root)) {
|
||||
encodeParams.relatedSearchTerm = true;
|
||||
removed = qs.encodeParam(encodeParams);
|
||||
}
|
||||
else if($scope.nonstandardSearchParam && $scope.nonstandardSearchParamRoot && root === $scope.nonstandardSearchParamRoot) {
|
||||
removed = qs.encodeParam(encodeParams);
|
||||
}
|
||||
else {
|
||||
removed = setDefaults(termParts[termParts.length-1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
removed = setDefaults(termParts[termParts.length-1]);
|
||||
}
|
||||
}
|
||||
removeFromQuerySet(queryset);
|
||||
if(!$scope.querySet) {
|
||||
$state.go('.', {
|
||||
[$scope.iterator + '_search']: queryset }, {notify: false}).then(function(){
|
||||
// ISSUE: for some reason deleting a tag from a list in a modal does not
|
||||
// remove the param from $stateParams. Here we'll manually check to make sure
|
||||
// that that happened and remove it if it didn't.
|
||||
|
||||
removeFromQuerySet($stateParams[`${$scope.iterator}_search`]);
|
||||
});
|
||||
}
|
||||
qs.search(path, queryset).then((res) => {
|
||||
if($scope.querySet) {
|
||||
$scope.querySet = queryset;
|
||||
}
|
||||
$scope.dataset = res.data;
|
||||
$scope.collection = res.data.results;
|
||||
});
|
||||
$scope.searchTags = qs.stripDefaultParams(queryset, defaults);
|
||||
};
|
||||
|
||||
// add a search tag, merge new queryset, $state.go()
|
||||
$scope.add = function(terms) {
|
||||
$scope.addTerm = function(terms) {
|
||||
let params = {},
|
||||
origQueryset = _.clone(queryset);
|
||||
|
||||
@ -209,40 +163,53 @@ export default ['$stateParams', '$scope', '$state', 'GetBasePath', 'QuerySet', '
|
||||
}
|
||||
else {
|
||||
if(a) {
|
||||
return [a,b];
|
||||
if($scope.singleSearchParam) {
|
||||
return a + "%20and%20" + b;
|
||||
}
|
||||
else {
|
||||
return [a,b];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if only a value is provided, search using default keys
|
||||
if (termParts.length === 1) {
|
||||
params = _.merge(params, setDefaults(term), combineSameSearches);
|
||||
} else {
|
||||
// Figure out if this is a search term
|
||||
let root = termParts[0].split(".")[0].replace(/^-/, '');
|
||||
if(_.has($scope.models[$scope.list.name].base, root)) {
|
||||
if($scope.models[$scope.list.name].base[root].type && $scope.models[$scope.list.name].base[root].type === 'field') {
|
||||
if($scope.singleSearchParam) {
|
||||
if (termParts.length === 1) {
|
||||
params = _.merge(params, searchWithoutKey(term), combineSameSearches);
|
||||
}
|
||||
else {
|
||||
params = _.merge(params, qs.encodeParam({term: term, searchTerm: true, singleSearchParam: $scope.singleSearchParam ? $scope.singleSearchParam : false}), combineSameSearches);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
// if only a value is provided, search using default keys
|
||||
if (termParts.length === 1) {
|
||||
params = _.merge(params, searchWithoutKey(term), combineSameSearches);
|
||||
} else {
|
||||
// Figure out if this is a search term
|
||||
let root = termParts[0].split(".")[0].replace(/^-/, '');
|
||||
if(_.has($scope.models[$scope.list.name].base, root)) {
|
||||
if($scope.models[$scope.list.name].base[root].type && $scope.models[$scope.list.name].base[root].type === 'field') {
|
||||
params = _.merge(params, qs.encodeParam({term: term, relatedSearchTerm: true}), combineSameSearches);
|
||||
}
|
||||
else {
|
||||
params = _.merge(params, qs.encodeParam({term: term, searchTerm: true}), combineSameSearches);
|
||||
}
|
||||
}
|
||||
// The related fields need to also be checked for related searches.
|
||||
// The related fields for the search are retrieved from the API
|
||||
// options endpoint, and are stored in the $scope.model. FYI, the
|
||||
// Django search model is what sets the related fields on the model.
|
||||
else if(_.contains($scope.models[$scope.list.name].related, root)) {
|
||||
params = _.merge(params, qs.encodeParam({term: term, relatedSearchTerm: true}), combineSameSearches);
|
||||
}
|
||||
// Its not a search term or a related search term - treat it as a string
|
||||
else {
|
||||
params = _.merge(params, qs.encodeParam({term: term, searchTerm: true}), combineSameSearches);
|
||||
params = _.merge(params, searchWithoutKey(term), combineSameSearches);
|
||||
}
|
||||
}
|
||||
// The related fields need to also be checked for related searches.
|
||||
// The related fields for the search are retrieved from the API
|
||||
// options endpoint, and are stored in the $scope.model. FYI, the
|
||||
// Django search model is what sets the related fields on the model.
|
||||
else if(_.contains($scope.models[$scope.list.name].related, root)) {
|
||||
params = _.merge(params, qs.encodeParam({term: term, relatedSearchTerm: true}), combineSameSearches);
|
||||
}
|
||||
else if($scope.nonstandardSearchParam && $scope.nonstandardSearchParamRoot && root === $scope.nonstandardSearchParamRoot) {
|
||||
params = _.merge(params, qs.encodeParam({term: term, searchTerm: true}), combineSameSearches);
|
||||
}
|
||||
// Its not a search term or a related search term - treat it as a string
|
||||
else {
|
||||
params = _.merge(params, setDefaults(term), combineSameSearches);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -254,6 +221,14 @@ export default ['$stateParams', '$scope', '$state', 'GetBasePath', 'QuerySet', '
|
||||
return object[key];
|
||||
}
|
||||
else {
|
||||
if($scope.singleSearchParam) {
|
||||
if(!object[key]) {
|
||||
return sourceValue;
|
||||
}
|
||||
else {
|
||||
return object[key] + "%20and%20" + sourceValue;
|
||||
}
|
||||
}
|
||||
// Start the array of keys
|
||||
return [object[key], sourceValue];
|
||||
}
|
||||
@ -287,22 +262,90 @@ export default ['$stateParams', '$scope', '$state', 'GetBasePath', 'QuerySet', '
|
||||
$scope.collection = res.data.results;
|
||||
})
|
||||
.catch(function() {
|
||||
$scope.revertSearch(origQueryset);
|
||||
revertSearch(origQueryset);
|
||||
});
|
||||
|
||||
$scope.searchTerm = null;
|
||||
$scope.searchTags = qs.stripDefaultParams(queryset, defaults);
|
||||
|
||||
generateSearchTags();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.revertSearch = function(queryToBeRestored) {
|
||||
queryset = queryToBeRestored;
|
||||
// https://ui-router.github.io/docs/latest/interfaces/params.paramdeclaration.html#dynamic
|
||||
// This transition will not reload controllers/resolves/views
|
||||
// but will register new $stateParams[$scope.iterator + '_search'] terms
|
||||
// remove tag, merge new queryset, $state.go
|
||||
$scope.removeTerm = function(index) {
|
||||
let tagToRemove = $scope.searchTags.splice(index, 1)[0],
|
||||
termParts = SmartSearchService.splitTermIntoParts(tagToRemove),
|
||||
removed;
|
||||
|
||||
let removeFromQuerySet = function(set) {
|
||||
_.each(removed, (value, key) => {
|
||||
if (Array.isArray(set[key])){
|
||||
_.remove(set[key], (item) => item === value);
|
||||
// If the array is now empty, remove that key
|
||||
if(set[key].length === 0) {
|
||||
delete set[key];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if($scope.singleSearchParam && set[$scope.singleSearchParam] && set[$scope.singleSearchParam].includes("%20and%20")) {
|
||||
let searchParamParts = set[$scope.singleSearchParam].split("%20and%20");
|
||||
var index = searchParamParts.indexOf(value);
|
||||
if (index !== -1) {
|
||||
searchParamParts.splice(index, 1);
|
||||
}
|
||||
set[$scope.singleSearchParam] = searchParamParts.join("%20and%20");
|
||||
}
|
||||
else {
|
||||
delete set[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (termParts.length === 1) {
|
||||
removed = searchWithoutKey(tagToRemove);
|
||||
}
|
||||
else {
|
||||
let root = termParts[0].split(".")[0].replace(/^-/, '');
|
||||
let encodeParams = {
|
||||
term: tagToRemove,
|
||||
singleSearchParam: $scope.singleSearchParam ? $scope.singleSearchParam : false
|
||||
};
|
||||
if($scope.models[$scope.list.name]) {
|
||||
if($scope.singleSearchParam) {
|
||||
removed = qs.encodeParam(encodeParams);
|
||||
}
|
||||
else if(_.has($scope.models[$scope.list.name].base, root)) {
|
||||
if($scope.models[$scope.list.name].base[root].type && $scope.models[$scope.list.name].base[root].type === 'field') {
|
||||
encodeParams.relatedSearchTerm = true;
|
||||
}
|
||||
else {
|
||||
encodeParams.searchTerm = true;
|
||||
}
|
||||
removed = qs.encodeParam(encodeParams);
|
||||
}
|
||||
else if(_.contains($scope.models[$scope.list.name].related, root)) {
|
||||
encodeParams.relatedSearchTerm = true;
|
||||
removed = qs.encodeParam(encodeParams);
|
||||
}
|
||||
else {
|
||||
removed = searchWithoutKey(termParts[termParts.length-1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
removed = searchWithoutKey(termParts[termParts.length-1]);
|
||||
}
|
||||
}
|
||||
removeFromQuerySet(queryset);
|
||||
if(!$scope.querySet) {
|
||||
$state.go('.', {
|
||||
[$scope.iterator + '_search']: queryset }, {notify: false});
|
||||
[$scope.iterator + '_search']: queryset }, {notify: false}).then(function(){
|
||||
// ISSUE: for some reason deleting a tag from a list in a modal does not
|
||||
// remove the param from $stateParams. Here we'll manually check to make sure
|
||||
// that that happened and remove it if it didn't.
|
||||
|
||||
removeFromQuerySet($stateParams[`${$scope.iterator}_search`]);
|
||||
});
|
||||
}
|
||||
qs.search(path, queryset).then((res) => {
|
||||
if($scope.querySet) {
|
||||
@ -312,7 +355,23 @@ export default ['$stateParams', '$scope', '$state', 'GetBasePath', 'QuerySet', '
|
||||
$scope.collection = res.data.results;
|
||||
});
|
||||
|
||||
$scope.searchTerm = null;
|
||||
generateSearchTags();
|
||||
};
|
||||
|
||||
$scope.clearAllTerms = function(){
|
||||
let cleared = _.cloneDeep(defaults);
|
||||
delete cleared.page;
|
||||
queryset = cleared;
|
||||
if(!$scope.querySet) {
|
||||
$state.go('.', {[$scope.iterator + '_search']: queryset}, {notify: false});
|
||||
}
|
||||
qs.search(path, queryset).then((res) => {
|
||||
if($scope.querySet) {
|
||||
$scope.querySet = queryset;
|
||||
}
|
||||
$scope.dataset = res.data;
|
||||
$scope.collection = res.data.results;
|
||||
});
|
||||
$scope.searchTags = qs.stripDefaultParams(queryset, defaults);
|
||||
};
|
||||
}
|
||||
|
||||
@ -18,8 +18,7 @@ export default ['templateUrl',
|
||||
disableSearch: '=',
|
||||
defaultParams: '=',
|
||||
querySet: '=',
|
||||
nonstandardSearchParam: '@',
|
||||
nonstandardSearchParamRoot: '@'
|
||||
singleSearchParam: '@'
|
||||
},
|
||||
controller: 'SmartSearchController',
|
||||
templateUrl: templateUrl('shared/smart-search/smart-search')
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
<div class="SmartSearch-bar">
|
||||
<div class="SmartSearch-searchTermContainer">
|
||||
<!-- string search input -->
|
||||
<form name="smartSearch" class="SmartSearch-form" aw-enter-key="add(searchTerm)" novalidate>
|
||||
<form name="smartSearch" class="SmartSearch-form" aw-enter-key="addTerm(searchTerm)" novalidate>
|
||||
<input class="SmartSearch-input" ng-model="searchTerm" placeholder="{{searchPlaceholder}}"
|
||||
ng-disabled="disableSearch">
|
||||
</form>
|
||||
<div type="submit" class="SmartSearch-searchButton" ng-disabled="!searchTerm" ng-click="add(searchTerm)">
|
||||
<div type="submit" class="SmartSearch-searchButton" ng-disabled="!searchTerm" ng-click="addTerm(searchTerm)">
|
||||
<i class="fa fa-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
@ -20,14 +20,14 @@
|
||||
<div class="SmartSearch-tagSection">
|
||||
<div class="SmartSearch-flexContainer">
|
||||
<div class="SmartSearch-tagContainer" ng-repeat="tag in searchTags track by $index">
|
||||
<div class="SmartSearch-deleteContainer" ng-click="remove($index)">
|
||||
<div class="SmartSearch-deleteContainer" ng-click="removeTerm($index)">
|
||||
<i class="fa fa-times SmartSearch-tagDelete"></i>
|
||||
</div>
|
||||
<div class="SmartSearch-tag SmartSearch-tag--deletable">
|
||||
<span class="SmartSearch-name">{{tag}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a href class="SmartSearch-clearAll" ng-click="clearAll()" ng-show="!(searchTags | isEmpty)" translate>CLEAR ALL</a>
|
||||
<a href class="SmartSearch-clearAll" ng-click="clearAllTerms()" ng-show="!(searchTags | isEmpty)" translate>CLEAR ALL</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -54,7 +54,17 @@ export function JobStdoutController ($rootScope, $scope, $state, $stateParams,
|
||||
$scope.project_name = (data.summary_fields.project) ? data.summary_fields.project.name : '';
|
||||
$scope.inventory_name = (data.summary_fields.inventory) ? data.summary_fields.inventory.name : '';
|
||||
$scope.job_template_url = '/#/templates/' + data.unified_job_template;
|
||||
$scope.inventory_url = ($scope.inventory_name && data.inventory) ? '/#/inventories/' + data.inventory : '';
|
||||
if($scope.inventory_name && data.inventory && data.summary_fields.inventory && data.summary_fields.inventory.kind) {
|
||||
if(data.summary_fields.inventory.kind === '') {
|
||||
$scope.inventory_url = '/#/inventories/standard_inventory' + data.inventory;
|
||||
}
|
||||
else if(data.summary_fields.inventory.kind === 'smart') {
|
||||
$scope.inventory_url = '/#/inventories/smart_inventory' + data.inventory;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$scope.inventory_url = '';
|
||||
}
|
||||
$scope.project_url = ($scope.project_name && data.project) ? '/#/projects/' + data.project : '';
|
||||
$scope.credential_name = (data.summary_fields.credential) ? data.summary_fields.credential.name : '';
|
||||
$scope.credential_url = (data.credential) ? '/#/credentials/' + data.credential : '';
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
|
||||
.LabelList-tagContainer,
|
||||
.LabelList-tagContainer,
|
||||
.LabelList-seeMoreLess {
|
||||
display: flex;
|
||||
max-width: 200px;
|
||||
@ -23,6 +23,7 @@
|
||||
background-color: @default-list-header-bg;
|
||||
margin-right: 5px;
|
||||
max-width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.LabelList-seeMoreLess {
|
||||
@ -89,4 +90,4 @@
|
||||
.List-tableCell.col-md-4 {
|
||||
padding-left: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,9 +10,15 @@ describe('Controller: jobResultsController', () => {
|
||||
statusSocket = function() {
|
||||
var fn = function() {};
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
jobData = {
|
||||
related: {}
|
||||
related: {},
|
||||
summary_fields: {
|
||||
inventory: {
|
||||
id: null,
|
||||
kind: ''
|
||||
}
|
||||
}
|
||||
};
|
||||
jobDataOptions = {
|
||||
actions: {
|
||||
@ -85,7 +91,7 @@ describe('Controller: jobResultsController', () => {
|
||||
$provide.value('ParseVariableString', ParseVariableString);
|
||||
$provide.value('jobResultsService', jobResultsService);
|
||||
$provide.value('eventQueue', eventQueue);
|
||||
$provide.value('Dataset', Dataset)
|
||||
$provide.value('Dataset', Dataset);
|
||||
$provide.value('Rest', Rest);
|
||||
$provide.value('$state', $state);
|
||||
$provide.value('QuerySet', QuerySet);
|
||||
@ -140,7 +146,7 @@ describe('Controller: jobResultsController', () => {
|
||||
eventQueue.populate.and
|
||||
.returnValue(populateResolve);
|
||||
|
||||
jobResultsService.getJobData = function(blah) {
|
||||
jobResultsService.getJobData = function() {
|
||||
var deferred = $q.defer();
|
||||
deferred.resolve({});
|
||||
return deferred.promise;
|
||||
@ -200,12 +206,17 @@ describe('Controller: jobResultsController', () => {
|
||||
"network_credential": "api/v1/credentials/14",
|
||||
};
|
||||
|
||||
jobData.summary_fields.inventory = {
|
||||
id: 12,
|
||||
kind: ''
|
||||
};
|
||||
|
||||
bootstrapTest();
|
||||
});
|
||||
|
||||
it('should transform related links and set to scope var', () => {
|
||||
expect($scope.created_by_link).toBe('/#/users/12');
|
||||
expect($scope.inventory_link).toBe('/#/inventories/12');
|
||||
expect($scope.inventory_link).toBe('/#/inventories/standard_inventory/12');
|
||||
expect($scope.project_link).toBe('/#/projects/12');
|
||||
expect($scope.machine_credential_link).toBe('/#/credentials/12');
|
||||
expect($scope.cloud_credential_link).toBe('/#/credentials/13');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user