Adding the ability to add/edit hosts to a group

includes adding the ansible facts to that host form
This commit is contained in:
Jared Tabor 2017-04-24 13:14:13 -07:00 committed by Jared Tabor
parent 0bec96ff28
commit fe63303816
11 changed files with 268 additions and 39 deletions

View File

@ -75,9 +75,6 @@ export default [
if(key === "AD_HOC_COMMANDS"){
$scope[key] = data[key].toString();
}
else if(key === "AUTH_LDAP_USER_SEARCH" || key === "AUTH_LDAP_GROUP_SEARCH"){
$scope[key] = JSON.stringify(data[key]);
}
else {
$scope[key] = ConfigurationUtils.arrayToList(data[key], key);
}
@ -356,38 +353,27 @@ export default [
clearApiErrors();
_.each(keys, function(key) {
if($scope.configDataResolve[key].type === 'choice' || multiselectDropdowns.indexOf(key) !== -1) {
// Handle AD_HOC_COMMANDS
if(multiselectDropdowns.indexOf(key) !== -1) {
let newModules = $("#configuration_jobs_template_AD_HOC_COMMANDS > option")
.filter("[data-select2-tag=true]")
.map((i, val) => ({value: $(val).text()}));
newModules.each(function(i, val) {
$scope[key].push(val);
});
payload[key] = ConfigurationUtils.listToArray(_.map($scope[key], 'value').join(','));
}
//Parse dropdowns and dropdowns labeled as lists
else if($scope[key] === null) {
if($scope[key] === null) {
payload[key] = null;
} else if($scope[key][0] && $scope[key][0].value !== undefined) {
payload[key] = _.map($scope[key], 'value').join(',');
if(multiselectDropdowns.indexOf(key) !== -1) {
// Handle AD_HOC_COMMANDS
payload[key] = ConfigurationUtils.listToArray(_.map($scope[key], 'value').join(','));
} else {
payload[key] = _.map($scope[key], 'value').join(',');
}
} else {
payload[key] = $scope[key].value;
if(multiselectDropdowns.indexOf(key) !== -1) {
// Default AD_HOC_COMMANDS to an empty list
payload[key] = $scope[key].value || [];
} else {
payload[key] = $scope[key].value;
}
}
} else if($scope.configDataResolve[key].type === 'list' && $scope[key] !== null) {
if(key === "AUTH_LDAP_USER_SEARCH" || key === "AUTH_LDAP_GROUP_SEARCH"){
payload[key] = $scope[key] === "{}" ? [] : ToJSON($scope.parseType,
$scope[key]);
}
else {
// Parse lists
payload[key] = ConfigurationUtils.listToArray($scope[key], key);
}
// Parse lists
payload[key] = ConfigurationUtils.listToArray($scope[key], key);
}
else if($scope.configDataResolve[key].type === 'nested object') {
if($scope[key] === '') {

View File

@ -10,8 +10,9 @@
* @description This form is for adding/editing a Group on the inventory page
*/
export default ['i18n', 'nestedGroupListState',
function(i18n, nestedGroupListState){
export default ['i18n', 'nestedGroupListState', 'nestedHostsListState',
'buildHostAddState',
function(i18n, nestedGroupListState, nestedHostsListState, buildHostAddState){
return {
addTitle: 'CREATE GROUP',
editTitle: '{{ name }}',
@ -91,6 +92,16 @@ function(i18n, nestedGroupListState){
// addState: buildGroupsAddState,
// editState: buildGroupsEditState
},
nested_hosts: {
name: 'nested_hosts',
ngClick: "$state.go('inventories.edit.groups.edit.nested_hosts')",
include: "NestedHostsListDefinition",
title: i18n._('Hosts'),
iterator: 'nested_hosts',
listState: nestedHostsListState,
addState: buildHostAddState,
// editState: buildGroupsEditState
},
}
};

View File

@ -8,6 +8,7 @@ import groupList from './list/main';
import groupAdd from './add/main';
import groupEdit from './edit/main';
import nestedGroups from './nested-groups/main';
import nestedHosts from './nested-hosts/main';
import groupFormDefinition from './groups.form';
import groupListDefinition from './groups.list';
import service from './groups.service';
@ -22,7 +23,8 @@ export default
groupList.name,
groupAdd.name,
groupEdit.name,
nestedGroups.name
nestedGroups.name,
nestedHosts.name
])
.factory('GroupForm', groupFormDefinition)
.value('GroupList', groupListDefinition)

View File

@ -0,0 +1,17 @@
/*************************************************
* Copyright (c) 2017 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import nestedHostsListState from './nested-hosts-list-state.factory';
import nestedHostsListDefinition from './nested-hosts.list';
import nestedHostsFormDefinition from './nested-hosts.form';
import controller from './nested-hosts-list.controller';
export default
angular.module('nestedHosts', [])
.factory('nestedHostsListState', nestedHostsListState)
.value('NestedHostsListDefinition', nestedHostsListDefinition)
.factory('NestedHostsFormDefinition', nestedHostsFormDefinition)
.controller('NestedHostsListController', controller);

View File

@ -0,0 +1,79 @@
/*************************************************
* Copyright (c) 2017 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import NestedHostsListController from './nested-hosts-list.controller';
export default ['NestedHostsListDefinition', '$stateExtender', 'templateUrl', '$injector',
function(NestedHostsListDefinition, $stateExtender, templateUrl, $injector){
var val = function(field, formStateDefinition) {
let state,
list = field.include ? $injector.get(field.include) : field,
breadcrumbLabel = (field.iterator.replace('_', ' ') + 's').toUpperCase(),
stateConfig = {
searchPrefix: `${list.iterator}`,
squash: '',
name: `${formStateDefinition.name}.nested_hosts`,
url: `/${list.iterator}s`,
ncyBreadcrumb: {
parent: `${formStateDefinition.name}`,
label: `${breadcrumbLabel}`
},
params: {
[list.iterator + '_search']: {
value: { order_by: field.order_by ? field.order_by : 'name' }
},
},
views: {
// 'related@inventories.edit.groups.edit': {
'related': {
templateProvider: function(NestedHostsListDefinition, generateList) {
let list = _.cloneDeep(NestedHostsListDefinition);
let html = generateList.build({
list: list,
mode: 'edit'
});
// Include the custom group delete modal template
// return $templateRequest(templateUrl('inventories/groups/list/groups-list')).then((template) => {
// return html.concat(template);
// });
return html;
},
controller: NestedHostsListController
}
},
resolve: {
ListDefinition: () => {
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 });
}
path = `api/v2/groups/${$stateParams.group_id}/all_hosts`;
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}
],
inventoryData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams) {
return InventoryManageService.getInventory($stateParams.inventory_id).then(res => res.data);
}]
}
};
state = $stateExtender.buildDefinition(stateConfig);
// appy any default search parameters in form definition
if (field.search) {
state.params[`${field.iterator}_search`].value = _.merge(state.params[`${field.iterator}_search`].value, field.search);
}
return state;
};
return val;
}
];

View File

@ -0,0 +1,131 @@
/*************************************************
* Copyright (c) 2017 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export default {
name: 'nested_hosts',
iterator: 'nested_host',
editTitle: '{{ nested_host.name }}', // i don't think this is correct
// showTitle: false,
well: true,
wellOverride: true,
index: false,
hover: true,
// hasChildren: true,
multiSelect: true,
trackBy: 'nested_host.id',
basePath: 'api/v2/groups/{{$stateParams.group_id}}/all_hosts/',
fields: {
active_failures: {
label: '',
iconOnly: true,
nosort: true,
// do not remove this ng-click directive
// the list generator case to handle fields without ng-click
// cannot handle the aw-* directives
ngClick: 'noop()',
awPopOver: "{{ nested_host.job_status_html }}",
dataTitle: "{{ nested_host.job_status_title }}",
awToolTip: "{{ nested_host.badgeToolTip }}",
dataPlacement: 'top',
icon: "{{ 'fa icon-job-' + nested_host.active_failures }}",
id: 'active-failures-action',
columnClass: 'status-column List-staticColumn--smallStatus'
},
name: {
key: true,
label: 'Hosts',
ngClick: "editHost(nested_host.id)",
ngClass: "{ 'host-disabled-label': !nested_host.enabled }",
columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7',
dataHostId: "{{ nested_host.id }}",
dataType: "nested_host",
class: 'InventoryManage-breakWord'
}
},
fieldActions: {
columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right',
copy: {
mode: 'all',
ngClick: "copyMoveHost(nested_host.id)",
awToolTip: 'Copy or move host to another group',
dataPlacement: "top",
ngShow: 'nested_host.summary_fields.user_capabilities.edit'
},
edit: {
//label: 'Edit',
ngClick: "editHost(nested_host.id)",
icon: 'icon-edit',
awToolTip: 'Edit host',
dataPlacement: 'top',
ngShow: 'nested_host.summary_fields.user_capabilities.edit'
},
view: {
//label: 'Edit',
ngClick: "editHost(nested_host.id)",
awToolTip: 'View host',
dataPlacement: 'top',
ngShow: '!nested_host.summary_fields.user_capabilities.edit'
},
"delete": {
//label: 'Delete',
ngClick: "deleteHost(nested_host.id, nested_host.name)",
icon: 'icon-trash',
awToolTip: 'Delete host',
dataPlacement: 'top',
ngShow: 'nested_host.summary_fields.user_capabilities.delete'
}
},
actions: {
launch: {
mode: 'all',
ngDisabled: '!hostsSelected',
ngClick: 'setAdhocPattern()',
awToolTip: "Select an inventory source by clicking the check box beside it. The inventory source can be a single group or host, a selection of multiple hosts, or a selection of multiple groups.",
dataTipWatch: "adhocCommandTooltip",
actionClass: 'btn List-buttonDefault',
buttonContent: 'RUN COMMANDS',
showTipWhenDisabled: true,
tooltipInnerClass: "Tooltip-wide",
// TODO: we don't always want to show this
ngShow: true
},
system_tracking: {
buttonContent: 'System Tracking',
ngClick: 'systemTracking()',
awToolTip: "Select one or two hosts by clicking the checkbox beside the host. System tracking offers the ability to compare the results of two scan runs from different dates on one host or the same date on two hosts.",
dataTipWatch: "systemTrackingTooltip",
dataPlacement: 'top',
awFeature: 'system_tracking',
actionClass: 'btn List-buttonDefault system-tracking',
ngDisabled: 'systemTrackingDisabled || !hostsSelected',
showTipWhenDisabled: true,
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()",
awToolTip: "Create a new host",
actionClass: 'btn List-buttonSubmit',
buttonContent: '+ ADD HOST',
ngShow: 'canAdd',
dataPlacement: "top",
}
}
};

View File

@ -1,8 +1,8 @@
<div class="tab-pane" id="inventories-panel">
<div ui-view="copyMove"></div>
<div ui-view="adhocForm"></div>
<div ui-view="groupForm"></div>
<div ui-view="hostForm"></div>
<div ui-view="groupForm"></div>
<div ui-view="sourcesForm"></div>
<div ui-view="form"></div>
<div ng-cloak id="htmlTemplate" class="Panel">

View File

@ -256,6 +256,7 @@ angular.module('inventory', [
};
let relatedHostsAnsibleFacts = factsConfig('inventories.edit.hosts.edit.ansible_facts');
let nestedHostsAnsibleFacts = factsConfig('inventories.edit.groups.edit.nested_hosts.edit.ansible_facts');
return Promise.all([
basicInventoryAdd,
@ -304,6 +305,7 @@ angular.module('inventory', [
stateExtender.buildDefinition(addSchedule),
stateExtender.buildDefinition(editSchedule),
stateExtender.buildDefinition(relatedHostsAnsibleFacts),
stateExtender.buildDefinition(nestedHostsAnsibleFacts),
stateExtender.buildDefinition(copyMoveGroupRoute),
stateExtender.buildDefinition(copyMoveHostRoute)
])

View File

@ -50,9 +50,9 @@ export default ['$state', '$stateParams', '$scope', 'RelatedHostsFormDefinition'
};
HostManageService.post(params).then(function(res) {
// assign the host to current group if not at the root level
if ($stateParams.group) {
HostManageService.associateGroup(res.data, _.last($stateParams.group)).then(function() {
$state.go('^.edit', { host_id: res.data.id }, { reload: true });
if ($stateParams.group_id) {
HostManageService.associateGroup(res.data, $stateParams.group_id).then(function() {
$state.go('inventories.edit.groups.edit.nested_hosts', { group_id: $stateParams.group_id }, { reload: true });
});
} else {
$state.go('^.edit', { host_id: res.data.id }, { reload: true });

View File

@ -21,7 +21,8 @@ export default ['i18n', function(i18n) {
formLabelSize: 'col-lg-3',
formFieldSize: 'col-lg-9',
iterator: 'host',
activeEditState: 'inventories.edit.hosts.edit',
// activeEditState: 'inventories.edit.hosts.edit',
// activeEditState: 'inventories.edit.groups.edit.nested_hosts.edit',
stateTree: 'inventories.edit.hosts',
headerFields:{
enabled: {

View File

@ -563,7 +563,7 @@ function($injector, $stateExtender, $log, i18n) {
if(field && field.addState){
let formState = field.addState(field, formStateDefinition, params);
states.push(formState);
// intent here is to add lookup states for any add-forms
// intent below is to add lookup states for any add-forms
if(field.includeForm){
let form = field.includeForm ? $injector.get(field.includeForm) : field;
states.push(that.generateLookupNodes(form, formState));
@ -573,7 +573,7 @@ function($injector, $stateExtender, $log, i18n) {
if(field && field.editState){
let formState = field.editState(field, formStateDefinition, params);
states.push(formState);
// intent here is to add lookup states for any edit-forms
// intent below is to add lookup states for any edit-forms
if(field.includeForm){
let form = field.includeForm ? $injector.get(field.includeForm) : field;
states.push(that.generateLookupNodes(form, formState));