Merge pull request #6655 from mabashian/remove-copy-move

Removed copy/move group/host in favor of associate and disassociate.
This commit is contained in:
Michael Abashian 2017-06-23 09:39:10 -04:00 committed by GitHub
commit badb7441ae
179 changed files with 1399 additions and 1155 deletions

View File

@ -20,14 +20,14 @@ export default function BuildAnchor($log, $filter) {
if (activity.operation === 'create' || activity.operation === 'delete'){
// the API formats the changes.inventory field as str 'myInventoryName-PrimaryKey'
var inventory_id = _.last(activity.changes.inventory.split('-'));
url += 'inventories/' + inventory_id + '/manage?group=' + activity.changes.id;
url += 'inventories/' + inventory_id + '/groups/edit/' + activity.changes.id;
}
else {
url += 'inventories/' + activity.summary_fields.inventory[0].id + '/manage?group=' + (activity.changes.id || activity.changes.object1_pk);
url += 'inventories/' + activity.summary_fields.inventory[0].id + '/groups/edit/' + (activity.changes.id || activity.changes.object1_pk);
}
break;
case 'host':
url += 'home/hosts/' + obj.id;
url += 'hosts/' + obj.id;
break;
case 'job':
url += 'jobs/' + obj.id;

View File

@ -39,7 +39,7 @@ if ($basePath) {
// Modules
import portalMode from './portal-mode/main';
import systemTracking from './system-tracking/main';
import inventories from './inventories/main';
import inventoriesHosts from './inventories-hosts/main';
import inventoryScripts from './inventory-scripts/main';
import credentials from './credentials/main';
import credentialTypes from './credential-types/main';
@ -104,7 +104,7 @@ var tower = angular.module('Tower', [
browserData.name,
configuration.name,
systemTracking.name,
inventories.name,
inventoriesHosts.name,
inventoryScripts.name,
credentials.name,
credentialTypes.name,

View File

@ -5,8 +5,8 @@
*************************************************/
export default
['$scope', '$state', '$stateParams', 'GenerateForm', 'ParseTypeChange', 'HostManageService', 'host', '$rootScope',
function($scope, $state, $stateParams, GenerateForm, ParseTypeChange, HostManageService, host, $rootScope){
['$scope', '$state', '$stateParams', 'GenerateForm', 'ParseTypeChange', 'HostsService', 'host', '$rootScope',
function($scope, $state, $stateParams, GenerateForm, ParseTypeChange, HostsService, host, $rootScope){
$scope.parseType = 'yaml';
$scope.formCancel = function(){
$state.go('^', null, {reload: true});
@ -32,7 +32,7 @@
description: $scope.description,
enabled: $scope.host.enabled
};
HostManageService.put(host).then(function(){
HostsService.put(host).then(function(){
$state.go('.', null, {reload: true});
});

View File

@ -110,7 +110,7 @@ export default ['i18n', function(i18n) {
awToolTip: "Create a new Smart Inventory from search results.",
actionClass: 'btn List-buttonDefault',
buttonContent: 'SMART INVENTORY',
ngShow: 'canAdd',
ngShow: 'canAdd && (hosts.length > 0 || !(searchTags | isEmpty))',
dataPlacement: "top",
ngDisabled: '!enableSmartInventoryButton'
}

View File

@ -7,7 +7,7 @@
function HostsList($scope, HostsList, $rootScope, GetBasePath,
rbacUiControlService, Dataset, $state, $filter, Prompt, Wait,
HostManageService, SetStatus, canAdd) {
HostsService, SetStatus, canAdd) {
let list = HostsList;
@ -73,7 +73,7 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath,
var action = function(){
delete $rootScope.promptActionBtnClass;
Wait('start');
HostManageService.delete(id).then(() => {
HostsService.delete(id).then(() => {
$('#prompt-modal').modal('hide');
if (parseInt($state.params.host_id) === id) {
$state.go("hosts", null, {reload: true});
@ -102,7 +102,7 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath,
host.enabled = !host.enabled;
HostManageService.put(host).then(function(){
HostsService.put(host).then(function(){
$state.go($state.current, null, {reload: true});
});
};
@ -139,5 +139,5 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath,
export default ['$scope', 'HostsList', '$rootScope', 'GetBasePath',
'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait',
'HostManageService', 'SetStatus', 'canAdd', HostsList
'HostsService', 'SetStatus', 'canAdd', HostsList
];

View File

@ -0,0 +1,112 @@
/*************************************************
* Copyright (c) 2017 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import hostEdit from './edit/main';
import hostList from './list/main';
import HostsList from './host.list';
import HostsForm from './host.form';
import { templateUrl } from '../../shared/template-url/template-url.factory';
import { N_ } from '../../i18n';
import ansibleFactsRoute from '../shared/ansible-facts/ansible-facts.route';
import insightsRoute from '../inventories/insights/insights.route';
import hostGroupsRoute from './related/groups/hosts-related-groups.route';
import hostGroupsAssociateRoute from './related/groups/hosts-related-groups-associate.route';
import hostGroups from './related/groups/main';
export default
angular.module('host', [
hostEdit.name,
hostList.name,
hostGroups.name
])
.factory('HostsForm', HostsForm)
.factory('HostsList', HostsList)
.config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider',
function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) {
let stateDefinitions = stateDefinitionsProvider.$get(),
stateExtender = $stateExtenderProvider.$get();
let generateHostStates = function(){
let hostTree = stateDefinitions.generateTree({
parent: 'hosts', // top-most node in the generated tree (will replace this state definition)
modes: ['edit'],
list: 'HostsList',
form: 'HostsForm',
controllers: {
edit: 'HostEditController'
},
breadcrumbs: {
edit: '{{breadcrumb.host_name}}'
},
urls: {
list: '/hosts'
},
data: {
activityStream: true,
activityStreamTarget: 'host'
},
resolve: {
edit: {
host: ['Rest', '$stateParams', 'GetBasePath',
function(Rest, $stateParams, GetBasePath) {
let path = GetBasePath('hosts') + $stateParams.host_id;
Rest.setUrl(path);
return Rest.get();
}
]
},
list: {
canAdd: ['rbacUiControlService', function(rbacUiControlService) {
return rbacUiControlService.canAdd('hosts')
.then(function(res) {
return res.canAdd;
})
.catch(function() {
return false;
});
}]
}
},
views: {
'@': {
templateUrl: templateUrl('inventories-hosts/hosts/hosts'),
controller: 'HostListController'
}
},
ncyBreadcrumb: {
label: N_('HOSTS')
}
});
let hostAnsibleFacts = _.cloneDeep(ansibleFactsRoute);
hostAnsibleFacts.name = 'hosts.edit.ansible_facts';
let hostInsights = _.cloneDeep(insightsRoute);
hostInsights.name = 'hosts.edit.insights';
return Promise.all([
hostTree
]).then((generated) => {
return {
states: _.reduce(generated, (result, definition) => {
return result.concat(definition.states);
}, [
stateExtender.buildDefinition(hostAnsibleFacts),
stateExtender.buildDefinition(hostInsights),
stateExtender.buildDefinition(hostGroupsRoute),
stateExtender.buildDefinition(hostGroupsAssociateRoute)
])
};
});
};
$stateProvider.state({
name: 'hosts',
url: '/hosts',
lazyLoad: () => generateHostStates()
});
}
]);

View File

@ -0,0 +1,33 @@
export default {
name: 'hosts.edit.groups.associate',
squashSearchUrl: true,
url: '/associate?inventory_id',
ncyBreadcrumb:{
skip:true
},
views: {
'modal@hosts.edit': {
templateProvider: function() {
return `<associate-groups save-function="associateGroups(selectedItems)"></associate-groups>`;
},
controller: function($scope, $q, GroupsService, $state){
$scope.associateGroups = function(selectedItems){
var deferred = $q.defer();
return $q.all( _.map(selectedItems, (id) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, id)) )
.then( () =>{
deferred.resolve();
}, (error) => {
deferred.reject(error);
});
};
}
}
},
onExit: function($state) {
if ($state.transition) {
$('#associate-groups-modal').modal('hide');
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
},
};

View File

@ -4,14 +4,14 @@
* All Rights Reserved
*************************************************/
export default
['$scope', '$rootScope', '$state', '$stateParams', 'HostGroupsList', 'InventoryUpdate',
'HostManageService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath',
'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'host',
function($scope, $rootScope, $state, $stateParams, HostGroupsList, InventoryUpdate,
HostManageService, CancelSourceUpdate, rbacUiControlService, GetBasePath,
GetHostsStatusMsg, Dataset, Find, qs, inventoryData, host){
['$scope', '$rootScope', '$state', '$stateParams', 'HostsRelatedGroupsList', 'InventoryUpdate',
'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath',
'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'host', 'GroupsService',
function($scope, $rootScope, $state, $stateParams, HostsRelatedGroupsList, InventoryUpdate,
CancelSourceUpdate, rbacUiControlService, GetBasePath,
GetHostsStatusMsg, Dataset, Find, qs, inventoryData, host, GroupsService){
let list = HostGroupsList;
let list = HostsRelatedGroupsList;
init();
@ -73,7 +73,7 @@
$state.go('.', null, {reload: true});
});
HostManageService.disassociateGroup(host, $scope.disassociateGroup.id).then(() => {
GroupsService.disassociateHost(host.id, $scope.disassociateGroup.id).then(() => {
$state.go($state.current, null, {reload: true});
$('#host-disassociate-modal').modal('hide');
$('body').removeClass('modal-open');

View File

@ -49,7 +49,7 @@ export default {
ngClick: "associateGroup()",
awToolTip: "Associate this host with a new group",
actionClass: 'btn List-buttonSubmit',
buttonContent: '&#43; ADD GROUP',
buttonContent: '&#43; ASSOCIATE GROUP',
ngShow: 'canAdd',
dataPlacement: "top",
}

View File

@ -5,7 +5,7 @@
<div class="Modal-title ng-binding">
Disassociate Host
<a href="" id="awp-promote" href=""
aw-pop-over="<dl><dt>Disassociate</dt><dd>Disassociation will remove a host from a group but the host will remain in the inventory.</dd></dl>\n" aw-tool-tip="Click for help"
aw-pop-over="<dl><dt>Disassociate</dt><dd>Disassociation will remove a host from a group but the host will remain in the inventory.</dd></dl>" aw-tool-tip="Click for help"
data-placement="right"
data-container="body"
data-title="Delete Group"
@ -19,7 +19,8 @@
</div>
<div class="Modal-body">
<div>
<div class="Prompt-bodyQuery">Are you sure you want to disassociate this host: <b>{{host.name}}</b> from this group: <b>{{disassociateGroup.name}}</b>?</div>
<div class="Prompt-bodyQuery">Are you sure you want to disassociate the host below from {{disassociateGroup.name}}?</div>
<div class="Prompt-bodyTarget">{{ host.name }}</div>
</div>
<div class="Modal-footer">
<a href="#" data-target="#host-disassociate-modal" data-dismiss="modal" id="prompt_cancel_btn_groups_list" class="btn Modal-defaultButton Modal-footerButton">CANCEL</a>

View File

@ -1,11 +1,11 @@
import { N_ } from '../../i18n';
import {templateUrl} from '../../shared/template-url/template-url.factory';
import { N_ } from '../../../../i18n';
import {templateUrl} from '../../../../shared/template-url/template-url.factory';
export default {
name: "hosts.edit.groups",
url: "/groups?{group_search:queryset}",
resolve: {
Dataset: ['HostGroupsList', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope',
Dataset: ['HostsRelatedGroupsList', '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;
@ -18,16 +18,16 @@ export default {
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}
],
host: ['$stateParams', 'HostManageService', function($stateParams, HostManageService) {
host: ['$stateParams', 'HostsService', function($stateParams, HostsService) {
if($stateParams.host_id){
return HostManageService.get({ id: $stateParams.host_id }).then(function(res) {
return HostsService.get({ id: $stateParams.host_id }).then(function(res) {
return res.data.results[0];
});
}
}],
inventoryData: ['InventoryManageService', '$stateParams', 'host', function(InventoryManageService, $stateParams, host) {
inventoryData: ['InventoriesService', '$stateParams', 'host', function(InventoriesService, $stateParams, host) {
var id = ($stateParams.inventory_id) ? $stateParams.inventory_id : host.summary_fields.inventory.id;
return InventoryManageService.getInventory(id).then(res => res.data);
return InventoriesService.getInventory(id).then(res => res.data);
}]
},
params: {
@ -46,17 +46,17 @@ export default {
},
views: {
'related': {
templateProvider: function(HostGroupsList, generateList, $templateRequest) {
templateProvider: function(HostsRelatedGroupsList, generateList, $templateRequest) {
let html = generateList.build({
list: HostGroupsList,
list: HostsRelatedGroupsList,
mode: 'edit'
});
return $templateRequest(templateUrl('inventories/host-groups/host-groups')).then((template) => {
return $templateRequest(templateUrl('inventories-hosts/hosts/related/groups/hosts-related-groups')).then((template) => {
return html.concat(template);
});
},
controller: 'HostGroupsController'
controller: 'HostsRelatedGroupsController'
}
}
};

View File

@ -0,0 +1,14 @@
/*************************************************
* Copyright (c) 2017 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import controller from './hosts-related-groups.controller';
import hostGroupsDefinition from './hosts-related-groups.list';
export default
angular.module('hostGroups', [])
.value('HostsRelatedGroupsList', hostGroupsDefinition)
.controller('HostsRelatedGroupsController', controller);

View File

@ -4,8 +4,8 @@
* All Rights Reserved
*************************************************/
import {templateUrl} from '../../shared/template-url/template-url.factory';
import { N_ } from '../../i18n';
import {templateUrl} from '../../../shared/template-url/template-url.factory';
import { N_ } from '../../../i18n';
export default {
url: '/adhoc',
@ -20,7 +20,7 @@ export default {
},
views: {
'adhocForm@inventories': {
templateUrl: templateUrl('inventories/adhoc/adhoc'),
templateUrl: templateUrl('inventories-hosts/inventories/adhoc/adhoc'),
controller: 'adhocController'
}
},

View File

@ -1,4 +1,4 @@
@import "../../shared/branding/colors.default.less";
@import "../../../shared/branding/colors.default.less";
.InsightsLastCheck{
display: flex;

View File

@ -1,5 +1,5 @@
import {templateUrl} from '../../shared/template-url/template-url.factory';
import { N_ } from '../../i18n';
import {templateUrl} from '../../../shared/template-url/template-url.factory';
import { N_ } from '../../../i18n';
export default {
url: '/insights',
@ -9,7 +9,7 @@ export default {
views: {
'related': {
controller: 'InsightsController',
templateUrl: templateUrl('inventories/insights/insights')
templateUrl: templateUrl('inventories-hosts/inventories/insights/insights')
}
},
resolve: {

View File

@ -1,6 +1,5 @@
<div class="tab-pane" id="inventories-panel">
<aw-limit-panels max-panels="2" panel-container="inventories-panel"></aw-limit-panels>
<div ui-view="copyMove"></div>
<div ui-view="adhocForm"></div>
<div ui-view="hostForm"></div>
<div ui-view="nestedGroupForm"></div>

View File

@ -1,5 +1,5 @@
import {templateUrl} from '../shared/template-url/template-url.factory';
import { N_ } from '../i18n';
import {templateUrl} from '../../shared/template-url/template-url.factory';
import { N_ } from '../../i18n';
export default {
name: 'inventories', // top-most node in the generated tree (will replace this state definition)
@ -13,7 +13,7 @@ export default {
},
views: {
'@': {
templateUrl: templateUrl('inventories/inventories')
templateUrl: templateUrl('inventories-hosts/inventories/inventories')
},
'list@inventories': {
templateProvider: function(InventoryList, generateList) {

View File

@ -7,7 +7,7 @@ export default ['templateUrl', 'Wait', '$filter', '$compile',
inventory: '='
},
controller: 'HostSummaryPopoverController',
templateUrl: templateUrl('inventories/list/host-summary-popover/host-summary-popover'),
templateUrl: templateUrl('inventories-hosts/inventories/list/host-summary-popover/host-summary-popover'),
link: function(scope) {
function ellipsis(a) {

View File

@ -7,7 +7,7 @@ export default ['templateUrl', '$compile', 'Wait', '$filter',
inventory: '='
},
controller: 'SourceSummaryPopoverController',
templateUrl: templateUrl('inventories/list/source-summary-popover/source-summary-popover'),
templateUrl: templateUrl('inventories-hosts/inventories/list/source-summary-popover/source-summary-popover'),
link: function(scope) {
function ellipsis(a) {

View File

@ -5,72 +5,60 @@
*************************************************/
import adhoc from './adhoc/main';
import host from './hosts/main';
import group from './groups/main';
import sources from './sources/main';
import relatedHost from './related-hosts/main';
import inventoryCompletedJobs from './completed_jobs/main';
import group from './related/groups/main';
import sources from './related/sources/main';
import relatedHost from './related/hosts/main';
import inventoryCompletedJobs from './related/completed-jobs/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 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 completedJobsRoute from './completed_jobs/completed_jobs.route';
import inventorySourceEditRoute from './sources/edit/sources-edit.route';
import inventorySourceEditNotificationsRoute from './sources/edit/sources-notifications.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 completedJobsRoute from './related/completed-jobs/completed-jobs.route';
import inventorySourceEditRoute from './related/sources/edit/sources-edit.route';
import inventorySourceEditNotificationsRoute from './related/sources/edit/sources-notifications.route';
import inventorySourceAddRoute from './related/sources/add/sources-add.route';
import inventorySourceListRoute from './related/sources/list/sources-list.route';
import inventorySourceListScheduleRoute from './related/sources/list/schedule/sources-schedule.route';
import inventorySourceListScheduleAddRoute from './related/sources/list/schedule/sources-schedule-add.route';
import inventorySourceListScheduleEditRoute from './related/sources/list/schedule/sources-schedule-edit.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';
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 inventoryGroupsList from './related/groups/list/groups-list.route';
import inventoryGroupsAdd from './related/groups/add/groups-add.route';
import inventoryGroupsEdit from './related/groups/edit/groups-edit.route';
import groupNestedGroupsRoute from './related/groups/related/nested-groups/group-nested-groups.route';
import hostNestedGroupsRoute from './related/hosts/related/nested-groups/host-nested-groups.route';
import nestedGroupsAdd from './related/groups/related/nested-groups/group-nested-groups-add.route';
import nestedHostsRoute from './related/groups/related/nested-hosts/group-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';
import nestedHostsAdd from './groups/nested-hosts/nested-hosts-add.route';
import nestedHostsEdit from './groups/nested-hosts/nested-hosts-edit.route';
import ansibleFactsRoute from './ansible_facts/ansible_facts.route';
import inventoryHostsAdd from './related/hosts/add/host-add.route';
import inventoryHostsEdit from './related/hosts/edit/host-edit.route';
import ansibleFactsRoute from '../shared/ansible-facts/ansible-facts.route';
import insightsRoute from './insights/insights.route';
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 inventorySourcesProjectRoute from './sources/lookup/sources-lookup-project.route';
import inventorySourcesCredentialRoute from './related/sources/lookup/sources-lookup-credential.route';
import inventorySourcesInventoryScriptRoute from './related/sources/lookup/sources-lookup-inventory-script.route';
import inventorySourcesProjectRoute from './related/sources/lookup/sources-lookup-project.route';
import SmartInventory from './smart-inventory/main';
import StandardInventory from './standard/main';
import StandardInventory from './standard-inventory/main';
import hostNestedGroupsAssociateRoute from './related/hosts/related/nested-groups/host-nested-groups-associate.route';
import groupNestedGroupsAssociateRoute from './related/groups/related/nested-groups/group-nested-groups-associate.route';
import nestedHostsAssociateRoute from './related/groups/related/nested-hosts/group-nested-hosts-associate.route';
import nestedHostsAddRoute from './related/groups/related/nested-hosts/group-nested-hosts-add.route';
export default
angular.module('inventory', [
adhoc.name,
host.name,
group.name,
sources.name,
relatedHost.name,
inventoryCompletedJobs.name,
inventoryList.name,
ansibleFacts.name,
insights.name,
copyMove.name,
hostGroups.name,
SmartInventory.name,
StandardInventory.name
StandardInventory.name,
])
.factory('InventoryList', InventoryList)
.service('InventoryManageService', InventoryManageService)
.config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider',
function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) {
let stateDefinitions = stateDefinitionsProvider.$get(),
@ -180,39 +168,12 @@ angular.module('inventory', [
}
});
let inventoryGroupsEditNestedGroups = _.cloneDeep(nestedGroups);
inventoryGroupsEditNestedGroups.name = "inventories.edit.groups.edit.nested_groups";
inventoryGroupsEditNestedGroups.ncyBreadcrumb = {
parent: "inventories.edit.groups.edit",
label: "ASSOCIATED GROUPS"
};
let inventoryGroupsEditNestedHostsEditGroups = _.cloneDeep(nestedGroups);
inventoryGroupsEditNestedHostsEditGroups.name = "inventories.edit.groups.edit.nested_hosts.edit.nested_groups";
inventoryGroupsEditNestedHostsEditGroups.ncyBreadcrumb = {
parent: "inventories.edit.groups.edit.nested_hosts.edit",
label: "ASSOCIATED GROUPS"
};
let inventoryHostsEditGroups = _.cloneDeep(nestedGroups);
inventoryHostsEditGroups.name = "inventories.edit.hosts.edit.nested_groups";
inventoryHostsEditGroups.ncyBreadcrumb = {
parent: "inventories.edit.hosts.edit",
label: "ASSOCIATED GROUPS"
};
let relatedHostsAnsibleFacts = _.cloneDeep(ansibleFactsRoute);
relatedHostsAnsibleFacts.name = 'inventories.edit.hosts.edit.ansible_facts';
let nestedHostsAnsibleFacts = _.cloneDeep(ansibleFactsRoute);
nestedHostsAnsibleFacts.name = 'inventories.edit.groups.edit.nested_hosts.edit.ansible_facts';
let relatedHostsInsights = _.cloneDeep(insightsRoute);
relatedHostsInsights.name = 'inventories.edit.hosts.edit.insights';
let nestedHostsInsights = _.cloneDeep(insightsRoute);
nestedHostsInsights.name = 'inventories.edit.groups.edit.nested_hosts.edit.insights';
let addSourceCredential = _.cloneDeep(inventorySourcesCredentialRoute);
addSourceCredential.name = 'inventories.edit.inventory_sources.add.credential';
addSourceCredential.url = '/credential';
@ -274,25 +235,17 @@ angular.module('inventory', [
stateExtender.buildDefinition(inventorySourceListScheduleAddRoute),
stateExtender.buildDefinition(inventorySourceListScheduleEditRoute),
stateExtender.buildDefinition(relatedHostsAnsibleFacts),
stateExtender.buildDefinition(nestedHostsAnsibleFacts),
stateExtender.buildDefinition(relatedHostsInsights),
stateExtender.buildDefinition(nestedHostsInsights),
stateExtender.buildDefinition(copyMoveGroupRoute),
stateExtender.buildDefinition(copyMoveHostRoute),
stateExtender.buildDefinition(inventoryGroupsList),
stateExtender.buildDefinition(inventoryGroupsAdd),
stateExtender.buildDefinition(inventoryGroupsEdit),
stateExtender.buildDefinition(inventoryGroupsEditNestedGroups),
stateExtender.buildDefinition(nestedGroupsAdd),
stateExtender.buildDefinition(nestedHosts),
stateExtender.buildDefinition(nestedHostsAdd),
stateExtender.buildDefinition(nestedHostsEdit),
stateExtender.buildDefinition(inventoryGroupsEditNestedHostsEditGroups),
stateExtender.buildDefinition(groupNestedGroupsRoute),
stateExtender.buildDefinition(nestedHostsRoute),
stateExtender.buildDefinition(inventoryHosts),
stateExtender.buildDefinition(smartInventoryHosts),
stateExtender.buildDefinition(inventoryHostsAdd),
stateExtender.buildDefinition(inventoryHostsEdit),
stateExtender.buildDefinition(inventoryHostsEditGroups),
stateExtender.buildDefinition(hostNestedGroupsRoute),
stateExtender.buildDefinition(inventorySourceListRoute),
stateExtender.buildDefinition(inventorySourceAddRoute),
stateExtender.buildDefinition(inventorySourceEditRoute),
@ -304,93 +257,18 @@ angular.module('inventory', [
stateExtender.buildDefinition(editSourceCredential),
stateExtender.buildDefinition(editSourceInventoryScript),
stateExtender.buildDefinition(addSourceProject),
stateExtender.buildDefinition(editSourceProject)
stateExtender.buildDefinition(editSourceProject),
stateExtender.buildDefinition(groupNestedGroupsAssociateRoute),
stateExtender.buildDefinition(hostNestedGroupsAssociateRoute),
stateExtender.buildDefinition(nestedHostsAssociateRoute),
stateExtender.buildDefinition(nestedGroupsAdd),
stateExtender.buildDefinition(nestedHostsAddRoute)
])
};
});
}
let generateHostStates = function(){
let hostTree = stateDefinitions.generateTree({
parent: 'hosts', // top-most node in the generated tree (will replace this state definition)
modes: ['edit'],
list: 'HostsList',
form: 'HostsForm',
controllers: {
edit: 'HostEditController'
},
breadcrumbs: {
edit: '{{breadcrumb.host_name}}'
},
urls: {
list: '/hosts'
},
data: {
activityStream: true,
activityStreamTarget: 'host'
},
resolve: {
edit: {
host: ['Rest', '$stateParams', 'GetBasePath',
function(Rest, $stateParams, GetBasePath) {
let path = GetBasePath('hosts') + $stateParams.host_id;
Rest.setUrl(path);
return Rest.get();
}
]
},
list: {
canAdd: ['rbacUiControlService', function(rbacUiControlService) {
return rbacUiControlService.canAdd('hosts')
.then(function(res) {
return res.canAdd;
})
.catch(function() {
return false;
});
}]
}
},
views: {
'@': {
templateUrl: templateUrl('inventories/hosts/hosts'),
controller: 'HostListController'
}
},
ncyBreadcrumb: {
label: N_('HOSTS')
}
});
let hostAnsibleFacts = _.cloneDeep(ansibleFactsRoute);
hostAnsibleFacts.name = 'hosts.edit.ansible_facts';
let hostInsights = _.cloneDeep(insightsRoute);
hostInsights.name = 'hosts.edit.insights';
return Promise.all([
hostTree
]).then((generated) => {
return {
states: _.reduce(generated, (result, definition) => {
return result.concat(definition.states);
}, [
stateExtender.buildDefinition(hostAnsibleFacts),
stateExtender.buildDefinition(hostInsights),
stateExtender.buildDefinition(hostGroupsRoute),
stateExtender.buildDefinition(hostGroupsAssociateRoute)
])
};
});
};
$stateProvider.state({
name: 'hosts',
url: '/hosts',
lazyLoad: () => generateHostStates()
});
$stateProvider.state({
name: 'inventories',
url: '/inventories',

View File

@ -1,4 +1,4 @@
import { N_ } from '../../i18n';
import { N_ } from '../../../../i18n';
export default {
url: "/completed_jobs",

View File

@ -4,7 +4,7 @@
* All Rights Reserved
*************************************************/
import list from './completed_jobs.list';
import list from './completed-jobs.list';
export default
angular.module('inventoryCompletedJobs', [])

View File

@ -5,11 +5,11 @@
*************************************************/
export default ['$state', '$stateParams', '$scope', 'GroupForm',
'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupManageService',
'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupsService',
'GetChoices', 'GetBasePath', 'CreateSelect2',
'rbacUiControlService', 'ToJSON',
function($state, $stateParams, $scope, GroupForm, ParseTypeChange,
GenerateForm, inventoryData, GroupManageService, GetChoices,
GenerateForm, inventoryData, GroupsService, GetChoices,
GetBasePath, CreateSelect2, rbacUiControlService,
ToJSON) {
@ -48,9 +48,9 @@ export default ['$state', '$stateParams', '$scope', 'GroupForm',
inventory: inventoryData.id
};
GroupManageService.post(group).then(res => {
GroupsService.post(group).then(res => {
if ($stateParams.group_id) {
return GroupManageService.associateGroup(res.data, $stateParams.group_id)
return GroupsService.associateGroup(res.data, $stateParams.group_id)
.then(() => $state.go('^', null, { reload: true }));
} else {
$state.go('^.edit', { group_id: res.data.id }, { reload: true });

View File

@ -1,4 +1,4 @@
import { N_ } from '../../../i18n';
import { N_ } from '../../../../../i18n';
export default {
name: "inventories.edit.groups.add",

View File

@ -5,9 +5,9 @@
*************************************************/
export default ['$state', '$stateParams', '$scope', 'ParseVariableString', 'rbacUiControlService', 'ToJSON',
'ParseTypeChange', 'GroupManageService', 'GetChoices', 'GetBasePath', 'CreateSelect2', 'groupData', '$rootScope',
'ParseTypeChange', 'GroupsService', 'GetChoices', 'GetBasePath', 'CreateSelect2', 'groupData', '$rootScope',
function($state, $stateParams, $scope, ParseVariableString, rbacUiControlService, ToJSON,
ParseTypeChange, GroupManageService, GetChoices, GetBasePath, CreateSelect2, groupData, $rootScope) {
ParseTypeChange, GroupsService, GetChoices, GetBasePath, CreateSelect2, groupData, $rootScope) {
init();
@ -56,7 +56,7 @@ export default ['$state', '$stateParams', '$scope', 'ParseVariableString', 'rbac
inventory: $scope.inventory,
id: groupData.id
};
GroupManageService.put(group).then(() => $state.go($state.current, null, { reload: true }));
GroupsService.put(group).then(() => $state.go($state.current, null, { reload: true }));
};
}

View File

@ -18,8 +18,8 @@ export default {
}
},
resolve: {
groupData: ['$stateParams', 'GroupManageService', function($stateParams, GroupManageService) {
return GroupManageService.get({ id: $stateParams.group_id }).then(res => res.data.results[0]);
groupData: ['$stateParams', 'GroupsService', function($stateParams, GroupsService) {
return GroupsService.get({ id: $stateParams.group_id }).then(res => res.data.results[0]);
}]
}
};

View File

@ -77,43 +77,6 @@ export default {
columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6 text-right',
// group_update: {
// //label: 'Sync',
// mode: 'all',
// ngClick: 'updateGroup(group)',
// awToolTip: "{{ group.launch_tooltip }}",
// dataTipWatch: "group.launch_tooltip",
// ngShow: "(group.status !== 'running' && group.status " +
// "!== 'pending' && group.status !== 'updating') && group.summary_fields.user_capabilities.start",
// ngClass: "group.launch_class",
// dataPlacement: "top",
// },
// cancel: {
// //label: 'Cancel',
// mode: 'all',
// ngClick: "cancelUpdate(group.id)",
// awToolTip: "Cancel sync process",
// 'class': 'red-txt',
// ngShow: "(group.status == 'running' || group.status == 'pending' " +
// "|| group.status == 'updating') && group.summary_fields.user_capabilities.start",
// dataPlacement: "top",
// iconClass: "fa fa-minus-circle"
// },
copy: {
mode: 'all',
ngClick: "copyMoveGroup(group.id)",
awToolTip: 'Copy or move group',
ngShow: "group.id > 0 && group.summary_fields.user_capabilities.copy",
dataPlacement: "top"
},
// schedule: {
// mode: 'all',
// ngClick: "scheduleGroup(group.id)",
// awToolTip: "{{ group.group_schedule_tooltip }}",
// ngClass: "group.scm_type_class",
// dataPlacement: 'top',
// ngShow: "!(group.summary_fields.inventory_source.source === '')"
// },
edit: {
//label: 'Edit',
mode: 'all',
@ -134,7 +97,7 @@ export default {
//label: 'Delete',
mode: 'all',
ngClick: "deleteGroup(group)",
awToolTip: 'Delete group',
awToolTip: 'Disassociate group',
dataPlacement: "top",
ngShow: "group.summary_fields.user_capabilities.delete"
}

View File

@ -5,10 +5,10 @@
*************************************************/
export default
['$scope', '$rootScope', '$state', '$stateParams', 'GroupList', 'InventoryUpdate',
'GroupManageService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath',
'GroupsService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath',
'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'canAdd',
function($scope, $rootScope, $state, $stateParams, GroupList, InventoryUpdate,
GroupManageService, CancelSourceUpdate, rbacUiControlService, GetBasePath,
GroupsService, CancelSourceUpdate, rbacUiControlService, GetBasePath,
GetHostsStatusMsg, Dataset, Find, qs, inventoryData, canAdd){
let list = GroupList;
@ -102,7 +102,7 @@
switch($scope.deleteOption){
case 'promote':
GroupManageService.promote($scope.toDelete.id, $stateParams.inventory_id)
GroupsService.promote($scope.toDelete.id, $stateParams.inventory_id)
.then(() => {
if (parseInt($state.params.group_id) === $scope.toDelete.id) {
$state.go("^", null, {reload: true});
@ -115,7 +115,7 @@
});
break;
default:
GroupManageService.delete($scope.toDelete.id).then(() => {
GroupsService.delete($scope.toDelete.id).then(() => {
if (parseInt($state.params.group_id) === $scope.toDelete.id) {
$state.go("^", null, {reload: true});
} else {
@ -128,7 +128,7 @@
}
};
$scope.updateGroup = function(group) {
GroupManageService.getInventorySource({group: group.id}).then(res =>InventoryUpdate({
GroupsService.getInventorySource({group: group.id}).then(res =>InventoryUpdate({
scope: $scope,
group_id: group.id,
url: res.data.results[0].related.update,
@ -141,10 +141,6 @@
CancelSourceUpdate({ scope: $scope, id: id });
};
$scope.copyMoveGroup = function(id){
$state.go('inventories.edit.groups.copyMoveGroup', {group_id: id, groups: $stateParams.groups});
};
var cleanUpStateChangeListener = $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams) {
if (toState.name === "inventories.edit.groups.edit") {
$scope.rowBeingEdited = toParams.group_id;

View File

@ -1,5 +1,5 @@
import { N_ } from '../../../i18n';
import {templateUrl} from '../../../shared/template-url/template-url.factory';
import { N_ } from '../../../../../i18n';
import {templateUrl} from '../../../../../shared/template-url/template-url.factory';
export default {
name: "inventories.edit.groups",
@ -18,8 +18,8 @@ export default {
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}
],
inventoryData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams) {
return InventoryManageService.getInventory($stateParams.inventory_id).then(res => res.data);
inventoryData: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) {
return InventoriesService.getInventory($stateParams.inventory_id).then(res => res.data);
}],
canAdd: ['rbacUiControlService', '$state', 'GetBasePath', '$stateParams', function(rbacUiControlService, $state, GetBasePath, $stateParams) {
return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups")
@ -62,7 +62,7 @@ export default {
mode: 'edit'
});
// Include the custom group delete modal template
return $templateRequest(templateUrl('inventories/groups/list/groups-list')).then((template) => {
return $templateRequest(templateUrl('inventories-hosts/inventories/related/groups/list/groups-list')).then((template) => {
return html.concat(template);
});
},

View File

@ -7,12 +7,11 @@
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';
import GetHostsStatusMsg from './factories/get-hosts-status-msg.factory';
import nestedGroups from './related/nested-groups/main';
import nestedHosts from './related/nested-hosts/main';
export default
angular.module('group', [
@ -24,5 +23,4 @@ export default
])
.factory('GroupForm', groupFormDefinition)
.value('GroupList', groupListDefinition)
.factory('GetHostsStatusMsg', GetHostsStatusMsg)
.service('GroupManageService', service);
.factory('GetHostsStatusMsg', GetHostsStatusMsg);

View File

@ -5,11 +5,11 @@
*************************************************/
export default ['$state', '$stateParams', '$scope', 'NestedGroupForm',
'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupManageService',
'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupsService',
'GetChoices', 'GetBasePath', 'CreateSelect2',
'rbacUiControlService', 'ToJSON', 'canAdd',
function($state, $stateParams, $scope, NestedGroupForm, ParseTypeChange,
GenerateForm, inventoryData, GroupManageService, GetChoices,
GenerateForm, inventoryData, GroupsService, GetChoices,
GetBasePath, CreateSelect2, rbacUiControlService,
ToJSON, canAdd) {
@ -44,9 +44,9 @@ export default ['$state', '$stateParams', '$scope', 'NestedGroupForm',
inventory: inventoryData.id
};
GroupManageService.post(group).then(res => {
GroupsService.post(group).then(res => {
if ($stateParams.group_id) {
return GroupManageService.associateGroup(res.data, $stateParams.group_id)
return GroupsService.associateGroup(res.data, $stateParams.group_id)
.then(() => $state.go('^', null, { reload: true }));
} else {
$state.go('^.edit', { group_id: res.data.id }, { reload: true });

View File

@ -1,4 +1,4 @@
import { N_ } from '../../../i18n';
import { N_ } from '../../../../../../i18n';
export default {
name: "inventories.edit.groups.edit.nested_groups.add",

View File

@ -0,0 +1,33 @@
export default {
name: 'inventories.edit.groups.edit.nested_groups.associate',
squashSearchUrl: true,
url: '/associate',
ncyBreadcrumb:{
skip:true
},
views: {
'modal@inventories.edit.groups.edit': {
templateProvider: function() {
return `<associate-groups save-function="associateGroups(selectedItems)"></associate-groups>`;
},
controller: function($scope, $q, GroupsService, $state){
$scope.associateGroups = function(selectedItems){
var deferred = $q.defer();
return $q.all( _.map(selectedItems, (id) => GroupsService.associateGroup({id: id}, $state.params.group_id)) )
.then( () =>{
deferred.resolve();
}, (error) => {
deferred.reject(error);
});
};
}
}
},
onExit: function($state) {
if ($state.transition) {
$('#associate-groups-modal').modal('hide');
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
},
};

View File

@ -0,0 +1,35 @@
<div class="modal fade GroupDelete" id="group-disassociate-modal" role="dialog">
<div class="modal-dialog">
<div class="modal-content Modal-content">
<div class="Modal-header">
<div class="Modal-title ng-binding">
Disassociate Group
<a href="" id="awp-promote" href=""
aw-pop-over="<dl><dt>Disassociate</dt><dd>Disassociates this group from the currently targeted parent group.</dd></dl>"
aw-tool-tip="Click for help"
data-placement="right"
data-container="body"
data-title="Disassociate Group"
class="help-link">
<i class="fa fa-question-circle"></i>
</a>
</div>
<div class="Modal-exitHolder">
<button class="close Modal-exit" data-target="#group-disassociate-modal" data-dismiss="modal" aria-hidden="true">
<i class="fa fa-times-circle"></i>
</button>
</div>
</div>
<div class="Modal-body">
<div>
<div class="Prompt-bodyQuery">Are you sure you want to disassociate the group below from {{disassociateFrom.name}}?</div>
<div class="Prompt-bodyTarget">{{ toDisassociate.name }}</div>
</div>
<div class="Modal-footer">
<a href="#" data-target="#group-disassociate-modal" data-dismiss="modal" id="prompt_cancel_btn_groups_list" class="btn Modal-defaultButton Modal-footerButton">CANCEL</a>
<a href="" ng-class="promptActionBtnClass" ng-click="confirmDisassociate()" id="prompt_action_btn_groups_list" class="btn Modal-footerButton Modal-errorButton">DISASSOCIATE</a>
</div>
</div>
</div>
</div>
</div>

View File

@ -5,20 +5,21 @@
*************************************************/
export default
['$scope', '$rootScope', '$state', '$stateParams', 'NestedGroupListDefinition', 'InventoryUpdate',
'GroupManageService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath',
'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'canAdd',
'GroupsService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath',
'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'canAdd', 'groupData', 'ProcessErrors',
function($scope, $rootScope, $state, $stateParams, NestedGroupListDefinition, InventoryUpdate,
GroupManageService, CancelSourceUpdate, rbacUiControlService, GetBasePath,
GetHostsStatusMsg, Dataset, Find, qs, inventoryData, canAdd){
GroupsService, CancelSourceUpdate, rbacUiControlService, GetBasePath,
GetHostsStatusMsg, Dataset, Find, qs, inventoryData, canAdd, groupData, ProcessErrors){
let list = NestedGroupListDefinition;
init();
function init(){
$scope.inventory_id = $stateParams.inventory_id;
$scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc;
$scope.canAdd = canAdd;
$scope.inventory_id = $stateParams.inventory_id;
$scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc;
$scope.canAdd = canAdd;
$scope.disassociateFrom = groupData;
// Search init
$scope.list = list;
@ -72,8 +73,41 @@
{hosts_status_class: hosts_status.class});
}
$scope.createGroup = function(){
$state.go('inventories.edit.groups.edit.nested_groups.add');
$scope.disassociateGroup = function(group){
$scope.toDisassociate = {};
angular.extend($scope.toDisassociate, group);
$('#group-disassociate-modal').modal('show');
};
$scope.confirmDisassociate = function(){
// Bind an even listener for the modal closing. Trying to $state.go() before the modal closes
// will mean that these two things are running async and the modal may not finish closing before
// the state finishes transitioning.
$('#group-disassociate-modal').off('hidden.bs.modal').on('hidden.bs.modal', function () {
// Remove the event handler so that we don't end up with multiple bindings
$('#group-disassociate-modal').off('hidden.bs.modal');
// Reload the inventory manage page and show that the group has been removed
$state.go('.', null, {reload: true});
});
let closeModal = function(){
$('#group-disassociate-modal').modal('hide');
$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
};
GroupsService.disassociateGroup($scope.toDisassociate.id, $scope.disassociateFrom.id)
.then(() => {
closeModal();
}).catch((error) => {
closeModal();
ProcessErrors(null, error.data, error.status, null, {
hdr: 'Error!',
msg: 'Failed to disassociate group from parent group: POST returned status' +
error.status
});
});
};
$scope.editGroup = function(id){

View File

@ -64,14 +64,26 @@ export default {
// awToolTip: "{{ adhocButtonTipContents }}",
// dataTipWatch: "adhocButtonTipContents"
},
create: {
add: {
mode: 'all',
ngClick: "createGroup()",
awToolTip: "Create a new group",
type: 'buttonDropdown',
awToolTip: "Add a group",
actionClass: 'btn List-buttonSubmit',
buttonContent: '&#43; ADD GROUP',
buttonContent: '&#43; ADD',
ngShow: 'canAdd',
dataPlacement: "top",
options: [
{
optionContent: 'Existing Group',
optionSref: '.associate',
ngShow: 'canAdd'
},
{
optionContent: 'New Group',
optionSref: '.add',
ngShow: 'canAdd'
}
],
}
},
@ -79,43 +91,6 @@ export default {
columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6 text-right',
// group_update: {
// //label: 'Sync',
// mode: 'all',
// ngClick: 'updateGroup(group)',
// awToolTip: "{{ group.launch_tooltip }}",
// dataTipWatch: "group.launch_tooltip",
// ngShow: "(group.status !== 'running' && group.status " +
// "!== 'pending' && group.status !== 'updating') && group.summary_fields.user_capabilities.start",
// ngClass: "group.launch_class",
// dataPlacement: "top",
// },
// cancel: {
// //label: 'Cancel',
// mode: 'all',
// ngClick: "cancelUpdate(group.id)",
// awToolTip: "Cancel sync process",
// 'class': 'red-txt',
// ngShow: "(group.status == 'running' || group.status == 'pending' " +
// "|| group.status == 'updating') && group.summary_fields.user_capabilities.start",
// dataPlacement: "top",
// iconClass: "fa fa-minus-circle"
// },
copy: {
mode: 'all',
ngClick: "copyMoveGroup(nested_group.id)",
awToolTip: 'Copy or move group',
ngShow: "group.id > 0 && group.summary_fields.user_capabilities.copy",
dataPlacement: "top"
},
// schedule: {
// mode: 'all',
// ngClick: "scheduleGroup(group.id)",
// awToolTip: "{{ group.group_schedule_tooltip }}",
// ngClass: "group.scm_type_class",
// dataPlacement: 'top',
// ngShow: "!(group.summary_fields.inventory_source.source === '')"
// },
edit: {
//label: 'Edit',
mode: 'all',
@ -135,10 +110,10 @@ export default {
"delete": {
//label: 'Delete',
mode: 'all',
ngClick: "deleteGroup(nested_group)",
ngClick: "disassociateGroup(nested_group)",
awToolTip: 'Delete group',
dataPlacement: "top",
ngShow: "group.summary_fields.user_capabilities.delete"
ngShow: "nested_group.summary_fields.user_capabilities.delete"
}
}
};

View File

@ -1,4 +1,7 @@
import {templateUrl} from '../../../../../../shared/template-url/template-url.factory';
export default {
name: 'inventories.edit.groups.edit.nested_groups',
url: "/nested_groups?{nested_group_search:queryset}",
params: {
nested_group_search: {
@ -10,21 +13,24 @@ export default {
squash: ""
}
},
ncyBreadcrumb: {
parent: "inventories.edit.groups.edit",
label: "ASSOCIATED GROUPS"
},
views: {
// 'related@inventories.edit.groups.edit': {
'related': {
templateProvider: function(NestedGroupListDefinition, generateList) {
templateProvider: function(NestedGroupListDefinition, generateList, $templateRequest) {
let list = _.cloneDeep(NestedGroupListDefinition);
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;
return $templateRequest(templateUrl('inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-disassociate')).then((template) => {
return html.concat(template);
});
},
controller: 'NestedGroupsListController'
}
@ -41,7 +47,7 @@ export default {
path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams });
}
if($stateParams.group_id){
path = `api/v2/groups/${$stateParams.group_id}/children`;
path = GetBasePath('groups') + $stateParams.group_id + '/children';
}
else if($stateParams.host_id){
path = GetBasePath('hosts') + $stateParams.host_id + '/all_groups';
@ -49,16 +55,16 @@ export default {
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}
],
host: ['$stateParams', 'HostManageService', function($stateParams, HostManageService) {
host: ['$stateParams', 'HostsService', function($stateParams, HostsService) {
if($stateParams.host_id){
return HostManageService.get({ id: $stateParams.host_id }).then(function(res) {
return HostsService.get({ id: $stateParams.host_id }).then(function(res) {
return res.data.results[0];
});
}
}],
inventoryData: ['InventoryManageService', '$stateParams', 'host', function(InventoryManageService, $stateParams, host) {
inventoryData: ['InventoriesService', '$stateParams', 'host', function(InventoriesService, $stateParams, host) {
var id = ($stateParams.inventory_id) ? $stateParams.inventory_id : host.summary_fields.inventory.id;
return InventoryManageService.getInventory(id).then(res => res.data);
return InventoriesService.getInventory(id).then(res => res.data);
}],
canAdd: ['rbacUiControlService', '$state', 'GetBasePath', '$stateParams', function(rbacUiControlService, $state, GetBasePath, $stateParams) {
return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups")

View File

@ -4,14 +4,14 @@
* All Rights Reserved
*************************************************/
import nestedGroupListDefinition from './nested-groups.list';
import NestedGroupForm from './nested-groups.form';
import controller from './nested-groups-list.controller';
import addController from './nested-groups-add.controller';
import nestedGroupListDefinition from './group-nested-groups.list';
import controller from './group-nested-groups-list.controller';
import addController from './group-nested-groups-add.controller';
import NestedGroupForm from './group-nested-groups.form';
export default
angular.module('nestedGroups', [])
.value('NestedGroupListDefinition', nestedGroupListDefinition)
.factory('NestedGroupForm', NestedGroupForm)
.value('NestedGroupListDefinition', nestedGroupListDefinition)
.controller('NestedGroupsListController', controller)
.controller('NestedGroupsAddController', addController);

View File

@ -0,0 +1,52 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export default ['$state', '$stateParams', '$scope', 'RelatedHostsFormDefinition', 'ParseTypeChange',
'GenerateForm', 'HostsService', 'rbacUiControlService', 'GetBasePath', 'ToJSON', 'canAdd', 'GroupsService',
function($state, $stateParams, $scope, RelatedHostsFormDefinition, ParseTypeChange,
GenerateForm, HostsService, rbacUiControlService, GetBasePath, ToJSON, canAdd, GroupsService) {
init();
function init() {
$scope.canAdd = canAdd;
$scope.parseType = 'yaml';
$scope.host = { enabled: true };
// apply form definition's default field values
GenerateForm.applyDefaults(RelatedHostsFormDefinition, $scope);
ParseTypeChange({
scope: $scope,
field_id: 'host_host_variables',
variable: 'host_variables',
parse_variable: 'parseType'
});
}
$scope.formCancel = function() {
$state.go('^');
};
$scope.toggleHostEnabled = function() {
if ($scope.host.has_inventory_sources){
return;
}
$scope.host.enabled = !$scope.host.enabled;
};
$scope.formSave = function(){
var json_data = ToJSON($scope.parseType, $scope.host_variables, true),
params = {
variables: json_data,// $scope.variables === '---' || $scope.variables === '{}' ? null : $scope.variables,
name: $scope.name,
description: $scope.description,
enabled: $scope.host.enabled,
inventory: $stateParams.inventory_id
};
HostsService.post(params).then(function(res) {
return GroupsService.associateHost(res.data, $stateParams.group_id)
.then(() => $state.go('^', null, { reload: true }));
});
};
}
];

View File

@ -1,4 +1,4 @@
import { N_ } from '../../../i18n';
import { N_ } from '../../../../../../i18n';
export default {
name: "inventories.edit.groups.edit.nested_hosts.add",
@ -16,7 +16,7 @@ export default {
related: false
});
},
controller: 'RelatedHostAddController'
controller: 'NestedHostsAddController'
}
},
resolve: {

View File

@ -0,0 +1,33 @@
export default {
name: 'inventories.edit.groups.edit.nested_hosts.associate',
squashSearchUrl: true,
url: '/associate',
ncyBreadcrumb:{
skip:true
},
views: {
'modal@inventories.edit.groups.edit': {
templateProvider: function() {
return `<associate-hosts save-function="associateHosts(selectedItems)"></associate-hosts>`;
},
controller: function($scope, $q, GroupsService, $state){
$scope.associateHosts = function(selectedItems){
var deferred = $q.defer();
return $q.all( _.map(selectedItems, (id) => GroupsService.associateHost({id: id}, $state.params.group_id)) )
.then( () =>{
deferred.resolve();
}, (error) => {
deferred.reject(error);
});
};
}
}
},
onExit: function($state) {
if ($state.transition) {
$('#associate-groups-modal').modal('hide');
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
},
};

View File

@ -0,0 +1,35 @@
<div class="modal fade HostDelete" id="host-disassociate-modal" role="dialog">
<div class="modal-dialog">
<div class="modal-content Modal-content">
<div class="Modal-header">
<div class="Modal-title ng-binding">
Disassociate Host
<a href="" id="awp-promote" href=""
aw-pop-over="<dl><dt>Disassociate</dt><dd>Disassociates this host from the currently targeted parent group.</dd></dl>"
aw-tool-tip="Click for help"
data-placement="right"
data-container="body"
data-title="Disassociate Host"
class="help-link">
<i class="fa fa-question-circle"></i>
</a>
</div>
<div class="Modal-exitHolder">
<button class="close Modal-exit" data-target="#host-disassociate-modal" data-dismiss="modal" aria-hidden="true">
<i class="fa fa-times-circle"></i>
</button>
</div>
</div>
<div class="Modal-body">
<div>
<div class="Prompt-bodyQuery">Are you sure you want to disassociate the host below from {{disassociateFrom.name}}?</div>
<div class="Prompt-bodyTarget">{{ toDisassociate.name }}</div>
</div>
<div class="Modal-footer">
<a href="#" data-target="#host-disassociate-modal" data-dismiss="modal" id="prompt_cancel_btn_groups_list" class="btn Modal-defaultButton Modal-footerButton">CANCEL</a>
<a href="" ng-class="promptActionBtnClass" ng-click="confirmDisassociate()" id="prompt_action_btn_groups_list" class="btn Modal-footerButton Modal-errorButton">DISASSOCIATE</a>
</div>
</div>
</div>
</div>
</div>

View File

@ -6,10 +6,10 @@
export default ['$scope', 'NestedHostsListDefinition', '$rootScope', 'GetBasePath',
'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait',
'HostManageService', 'SetStatus', 'canAdd',
'HostsService', 'SetStatus', 'canAdd', 'GroupsService', 'ProcessErrors', 'groupData',
function($scope, NestedHostsListDefinition, $rootScope, GetBasePath,
rbacUiControlService, Dataset, $state, $filter, Prompt, Wait,
HostManageService, SetStatus, canAdd) {
HostsService, SetStatus, canAdd, GroupsService, ProcessErrors, groupData) {
let list = NestedHostsListDefinition;
@ -18,6 +18,7 @@ export default ['$scope', 'NestedHostsListDefinition', '$rootScope', 'GetBasePat
function init(){
$scope.canAdd = canAdd;
$scope.enableSmartInventoryButton = false;
$scope.disassociateFrom = groupData;
// Search init
$scope.list = list;
@ -79,35 +80,47 @@ export default ['$scope', 'NestedHostsListDefinition', '$rootScope', 'GetBasePat
});
}
$scope.createHost = function(){
$state.go('inventories.edit.groups.edit.nested_hosts.add');
$scope.associateHost = function(){
$state.go('inventories.edit.groups.edit.nested_hosts.associate');
};
$scope.editHost = function(id){
$state.go('inventories.edit.groups.edit.nested_hosts.edit', {host_id: id});
$state.go('inventories.edit.hosts.edit', {host_id: id});
};
$scope.deleteHost = function(id, name){
var body = '<div class=\"Prompt-bodyQuery\">Are you sure you want to permanently delete the host below from the inventory?</div><div class=\"Prompt-bodyTarget\">' + $filter('sanitize')(name) + '</div>';
var action = function(){
delete $rootScope.promptActionBtnClass;
Wait('start');
HostManageService.delete(id).then(() => {
$('#prompt-modal').modal('hide');
if (parseInt($state.params.host_id) === id) {
$state.go("hosts", null, {reload: true});
} else {
$state.go($state.current.name, null, {reload: true});
}
Wait('stop');
});
};
// Prompt depends on having $rootScope.promptActionBtnClass available...
Prompt({
hdr: 'Delete Host',
body: body,
action: action,
actionText: 'DELETE',
$scope.disassociateHost = function(host){
$scope.toDisassociate = {};
angular.extend($scope.toDisassociate, host);
$('#host-disassociate-modal').modal('show');
};
$scope.confirmDisassociate = function(){
// Bind an even listener for the modal closing. Trying to $state.go() before the modal closes
// will mean that these two things are running async and the modal may not finish closing before
// the state finishes transitioning.
$('#host-disassociate-modal').off('hidden.bs.modal').on('hidden.bs.modal', function () {
// Remove the event handler so that we don't end up with multiple bindings
$('#host-disassociate-modal').off('hidden.bs.modal');
// Reload the inventory manage page and show that the group has been removed
$state.go('.', null, {reload: true});
});
$rootScope.promptActionBtnClass = 'Modal-errorButton';
let closeModal = function(){
$('#host-disassociate-modal').modal('hide');
$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
};
GroupsService.disassociateHost($scope.toDisassociate.id, $scope.disassociateFrom.id)
.then(() => {
closeModal();
}).catch((error) => {
closeModal();
ProcessErrors(null, error.data, error.status, null, {
hdr: 'Error!',
msg: 'Failed to disassociate host from group: POST returned status' +
error.status
});
});
};
$scope.toggleHost = function(event, host) {
@ -119,15 +132,11 @@ export default ['$scope', 'NestedHostsListDefinition', '$rootScope', 'GetBasePat
host.enabled = !host.enabled;
HostManageService.put(host).then(function(){
HostsService.put(host).then(function(){
$state.go($state.current, null, {reload: true});
});
};
$scope.smartInventory = function() {
$state.go('inventories.addSmartInventory');
};
$scope.systemTracking = function(){
var hostIds = _.map($scope.hostsSelected, (host) => host.id);
$state.go('systemTracking', {
@ -145,8 +154,4 @@ export default ['$scope', 'NestedHostsListDefinition', '$rootScope', 'GetBasePat
$state.go('^.^.^.adhoc', {pattern: pattern});
};
$scope.copyMoveHost = function(id) {
$state.go('inventories.edit.hosts.copyMoveHost', {host_id: id});
};
}];

View File

@ -119,13 +119,6 @@ function(i18n) {
ngClick: "$state.go('inventories.edit.groups.edit.nested_hosts.edit.nested_groups')",
title: i18n._('Groups'),
iterator: 'nested_group'
},
insights: {
name: 'insights',
awToolTip: i18n._('Please save before viewing Insights'),
dataPlacement: 'top',
title: i18n._('Insights'),
skipGenerator: true
}
}
};

View File

@ -4,6 +4,8 @@
* All Rights Reserved
*************************************************/
import { N_ } from '../../../../../../i18n';
export default {
name: 'nested_hosts',
iterator: 'nested_host',
@ -19,6 +21,22 @@ export default {
basePath: 'api/v2/groups/{{$stateParams.group_id}}/all_hosts/',
fields: {
toggleHost: {
ngDisabled: 'host.has_inventory_sources',
label: '',
columnClass: 'List-staticColumn--toggle',
type: "toggle",
ngClick: "toggleHost($event, nested_host)",
awToolTip: "<p>" +
N_("Indicates if a host is available and should be included in running jobs.") +
"</p><p>" +
N_("For hosts that are part of an external" +
" inventory, this flag cannot be changed. It will be" +
" set by the inventory sync process.") +
"</p>",
dataPlacement: "right",
nosort: true,
},
active_failures: {
label: '',
iconOnly: true,
@ -50,13 +68,6 @@ export default {
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)",
@ -74,9 +85,9 @@ export default {
},
"delete": {
//label: 'Delete',
ngClick: "deleteHost(nested_host.id, nested_host.name)",
ngClick: "disassociateHost(nested_host)",
icon: 'icon-trash',
awToolTip: 'Delete host',
awToolTip: 'Disassociate host',
dataPlacement: 'top',
ngShow: 'nested_host.summary_fields.user_capabilities.delete'
}
@ -117,14 +128,26 @@ export default {
actionClass: 'btn List-buttonDefault',
buttonContent: 'REFRESH'
},
create: {
add: {
mode: 'all',
ngClick: "createHost()",
awToolTip: "Create a new host",
type: 'buttonDropdown',
awToolTip: "Add a host",
actionClass: 'btn List-buttonSubmit',
buttonContent: '&#43; ADD HOST',
buttonContent: '&#43; ADD',
ngShow: 'canAdd',
dataPlacement: "top",
options: [
{
optionContent: 'Existing Host',
optionSref: '.associate',
ngShow: 'canAdd'
},
{
optionContent: 'New Host',
optionSref: '.add',
ngShow: 'canAdd'
}
],
}
}

View File

@ -1,4 +1,5 @@
import { N_ } from '../../../i18n';
import { N_ } from '../../../../../../i18n';
import {templateUrl} from '../../../../../../shared/template-url/template-url.factory';
export default {
name: "inventories.edit.groups.edit.nested_hosts",
@ -20,18 +21,16 @@ export default {
views: {
// 'related@inventories.edit.groups.edit': {
'related': {
templateProvider: function(NestedHostsListDefinition, generateList) {
templateProvider: function(NestedHostsListDefinition, generateList, $templateRequest) {
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;
return $templateRequest(templateUrl('inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-disassociate')).then((template) => {
return html.concat(template);
});
},
controller: 'NestedHostsListController'
}
@ -51,8 +50,8 @@ export default {
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}
],
inventoryData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams) {
return InventoryManageService.getInventory($stateParams.inventory_id).then(res => res.data);
inventoryData: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) {
return InventoriesService.getInventory($stateParams.inventory_id).then(res => res.data);
}],
canAdd: ['rbacUiControlService', function(rbacUiControlService) {
return rbacUiControlService.canAdd('hosts')

View File

@ -4,12 +4,14 @@
* All Rights Reserved
*************************************************/
import nestedHostsListDefinition from './nested-hosts.list';
import nestedHostsFormDefinition from './nested-hosts.form';
import controller from './nested-hosts-list.controller';
import nestedHostsListDefinition from './group-nested-hosts.list';
import nestedHostsFormDefinition from './group-nested-hosts.form';
import controller from './group-nested-hosts-list.controller';
import addController from './group-nested-hosts-add.controller';
export default
angular.module('nestedHosts', [])
.value('NestedHostsListDefinition', nestedHostsListDefinition)
.factory('NestedHostsFormDefinition', nestedHostsFormDefinition)
.controller('NestedHostsAddController', addController)
.controller('NestedHostsListController', controller);

View File

@ -5,9 +5,9 @@
*************************************************/
export default ['$state', '$stateParams', '$scope', 'RelatedHostsFormDefinition', 'ParseTypeChange',
'GenerateForm', 'HostManageService', 'rbacUiControlService', 'GetBasePath', 'ToJSON', 'canAdd',
'GenerateForm', 'HostsService', 'rbacUiControlService', 'GetBasePath', 'ToJSON', 'canAdd',
function($state, $stateParams, $scope, RelatedHostsFormDefinition, ParseTypeChange,
GenerateForm, HostManageService, rbacUiControlService, GetBasePath, ToJSON, canAdd) {
GenerateForm, HostsService, rbacUiControlService, GetBasePath, ToJSON, canAdd) {
init();
@ -43,15 +43,8 @@ export default ['$state', '$stateParams', '$scope', 'RelatedHostsFormDefinition'
enabled: $scope.host.enabled,
inventory: $stateParams.inventory_id
};
HostManageService.post(params).then(function(res) {
// assign the host to current group if not at the root level
if ($stateParams.group_id) {
HostManageService.associateGroup(res.data, $stateParams.group_id).then(function() {
$state.go('^.edit', { group_id: $stateParams.group_id, host_id: res.data.id }, { reload: true });
});
} else {
$state.go('^.edit', { host_id: res.data.id }, { reload: true });
}
HostsService.post(params).then(function(res) {
$state.go('^.edit', { host_id: res.data.id }, { reload: true });
});
};
}

View File

@ -1,4 +1,4 @@
import { N_ } from '../../../i18n';
import { N_ } from '../../../../../i18n';
export default {
name: "inventories.edit.hosts.add",

View File

@ -5,8 +5,8 @@
*************************************************/
export default
['$scope', '$state', '$stateParams', 'GenerateForm', 'ParseTypeChange', 'HostManageService', 'host', '$rootScope',
function($scope, $state, $stateParams, GenerateForm, ParseTypeChange, HostManageService, host, $rootScope){
['$scope', '$state', '$stateParams', 'GenerateForm', 'ParseTypeChange', 'HostsService', 'host', '$rootScope',
function($scope, $state, $stateParams, GenerateForm, ParseTypeChange, HostsService, host, $rootScope){
$scope.parseType = 'yaml';
$scope.formCancel = function(){
$state.go('^', null, {reload: true});
@ -28,7 +28,7 @@
description: $scope.description,
enabled: $scope.host.enabled
};
HostManageService.put(host).then(function(){
HostsService.put(host).then(function(){
$state.go('.', null, {reload: true});
});

View File

@ -7,11 +7,8 @@ export default {
},
views: {
'hostForm@inventories': {
templateProvider: function(GenerateForm, RelatedHostsFormDefinition, NestedHostsFormDefinition, $stateParams) {
templateProvider: function(GenerateForm, RelatedHostsFormDefinition) {
let form = RelatedHostsFormDefinition;
if($stateParams.group_id){
form = NestedHostsFormDefinition;
}
return GenerateForm.buildHTML(form, {
mode: 'edit',
related: false
@ -21,8 +18,8 @@ export default {
}
},
resolve: {
host: ['$stateParams', 'HostManageService', function($stateParams, HostManageService) {
return HostManageService.get({ id: $stateParams.host_id }).then(function(res) {
host: ['$stateParams', 'HostsService', function($stateParams, HostsService) {
return HostsService.get({ id: $stateParams.host_id }).then(function(res) {
return res.data.results[0];
});
}]

View File

@ -4,13 +4,13 @@
* All Rights Reserved
*************************************************/
// import HostManageService from './../hosts/host.service';
// import HostsService from './../hosts/host.service';
export default ['$scope', 'ListDefinition', '$rootScope', 'GetBasePath',
'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait',
'HostManageService', 'SetStatus', 'canAdd',
'HostsService', 'SetStatus', 'canAdd',
function($scope, ListDefinition, $rootScope, GetBasePath,
rbacUiControlService, Dataset, $state, $filter, Prompt, Wait,
HostManageService, SetStatus, canAdd) {
HostsService, SetStatus, canAdd) {
let list = ListDefinition;
@ -94,7 +94,7 @@ export default ['$scope', 'ListDefinition', '$rootScope', 'GetBasePath',
var action = function(){
delete $rootScope.promptActionBtnClass;
Wait('start');
HostManageService.delete(id).then(() => {
HostsService.delete(id).then(() => {
$('#prompt-modal').modal('hide');
if (parseInt($state.params.host_id) === id) {
$state.go("hosts", null, {reload: true});
@ -123,7 +123,7 @@ export default ['$scope', 'ListDefinition', '$rootScope', 'GetBasePath',
host.enabled = !host.enabled;
HostManageService.put(host).then(function(){
HostsService.put(host).then(function(){
$state.go($state.current, null, {reload: true});
});
};
@ -149,8 +149,4 @@ export default ['$scope', 'ListDefinition', '$rootScope', 'GetBasePath',
$state.go('^.adhoc', {pattern: pattern});
};
$scope.copyMoveHost = function(id) {
$state.go('inventories.edit.hosts.copyMoveHost', {host_id: id});
};
}];

View File

@ -10,13 +10,15 @@
import relatedHostsListDefinition from './related-host.list';
import relatedHostsFormDefinition from './related-host.form';
import relatedGroupsLabels from './related-groups-labels/main';
import nestedGroups from './related/nested-groups/main';
export default
angular.module('relatedHost', [
relatedHostAdd.name,
relatedHostEdit.name,
relatedHostList.name,
relatedGroupsLabels.name
relatedGroupsLabels.name,
nestedGroups.name
])
.factory('RelatedHostsFormDefinition', relatedHostsFormDefinition)
.factory('RelatedHostsListDefinition', relatedHostsListDefinition);

View File

@ -13,7 +13,7 @@ export default
return {
restrict: 'E',
scope: false,
templateUrl: templateUrl('inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList'),
templateUrl: templateUrl('inventories-hosts/inventories/related/hosts/related-groups-labels/relatedGroupsLabelsList'),
link: function(scope, element, attrs) {
scope.showDelete = attrs.showDelete === 'true';
scope.seeMoreInactive = true;

View File

@ -88,13 +88,6 @@ export default ['i18n', function(i18n) {
dataPlacement: 'top',
ngShow: 'host.insights_system_id'
},
copy: {
mode: 'all',
ngClick: "copyMoveHost(host.id)",
awToolTip: 'Copy or move host to another group',
dataPlacement: "top",
ngShow: 'host.summary_fields.user_capabilities.edit'
},
edit: {
//label: 'Edit',
ngClick: "editHost(host)",

View File

@ -1,4 +1,4 @@
import { N_ } from '../../i18n';
import { N_ } from '../../../../i18n';
export default {
name: "inventories.edit.hosts",
@ -56,19 +56,19 @@ export default {
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}
],
hostsUrl: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams) {
hostsUrl: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) {
return $stateParams.group && $stateParams.group.length > 0 ?
// nested context - provide all hosts managed by nodes
InventoryManageService.childHostsUrl(_.last($stateParams.group)) :
InventoriesService.childHostsUrl(_.last($stateParams.group)) :
// root context - provide all hosts in an inventory
InventoryManageService.rootHostsUrl($stateParams.inventory_id);
InventoriesService.rootHostsUrl($stateParams.inventory_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.inventory_id).then(res => res.data);
inventoryData: ['InventoriesService', '$stateParams', function(InventoriesService, $stateParams) {
return InventoriesService.getInventory($stateParams.inventory_id).then(res => res.data);
}],
canAdd: ['rbacUiControlService', function(rbacUiControlService) {
return rbacUiControlService.canAdd('hosts')

View File

@ -0,0 +1,33 @@
export default {
name: 'inventories.edit.hosts.edit.nested_groups.associate',
squashSearchUrl: true,
url: '/associate',
ncyBreadcrumb:{
skip:true
},
views: {
'modal@inventories.edit.hosts.edit': {
templateProvider: function() {
return `<associate-groups save-function="associateGroups(selectedItems)"></associate-groups>`;
},
controller: function($scope, $q, GroupsService, $state){
$scope.associateGroups = function(selectedItems){
var deferred = $q.defer();
return $q.all( _.map(selectedItems, (id) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, id)) )
.then( () =>{
deferred.resolve();
}, (error) => {
deferred.reject(error);
});
};
}
}
},
onExit: function($state) {
if ($state.transition) {
$('#associate-groups-modal').modal('hide');
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
},
};

View File

@ -0,0 +1,35 @@
<div class="modal fade GroupDelete" id="group-disassociate-modal" role="dialog">
<div class="modal-dialog">
<div class="modal-content Modal-content">
<div class="Modal-header">
<div class="Modal-title ng-binding">
Disassociate Group
<a href="" id="awp-promote" href=""
aw-pop-over="<dl><dt>Disassociate</dt><dd>Disassociates this group from the currently targeted parent group.</dd></dl>"
aw-tool-tip="Click for help"
data-placement="right"
data-container="body"
data-title="Disassociate Group"
class="help-link">
<i class="fa fa-question-circle"></i>
</a>
</div>
<div class="Modal-exitHolder">
<button class="close Modal-exit" data-target="#group-disassociate-modal" data-dismiss="modal" aria-hidden="true">
<i class="fa fa-times-circle"></i>
</button>
</div>
</div>
<div class="Modal-body">
<div>
<div class="Prompt-bodyQuery">Are you sure you want to disassociate the host below from {{disassociateFrom.name}}?</div>
<div class="Prompt-bodyTarget">{{ toDisassociate.name }}</div>
</div>
<div class="Modal-footer">
<a href="#" data-target="#group-disassociate-modal" data-dismiss="modal" id="prompt_cancel_btn_groups_list" class="btn Modal-defaultButton Modal-footerButton">CANCEL</a>
<a href="" ng-class="promptActionBtnClass" ng-click="confirmDisassociate()" id="prompt_action_btn_groups_list" class="btn Modal-footerButton Modal-errorButton">DISASSOCIATE</a>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,122 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export default
['$scope', '$rootScope', '$state', '$stateParams', 'HostNestedGroupListDefinition', 'InventoryUpdate',
'GroupsService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath',
'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'canAdd', 'ProcessErrors', 'host',
function($scope, $rootScope, $state, $stateParams, HostNestedGroupListDefinition, InventoryUpdate,
GroupsService, CancelSourceUpdate, rbacUiControlService, GetBasePath,
GetHostsStatusMsg, Dataset, Find, qs, inventoryData, canAdd, ProcessErrors, host){
let list = HostNestedGroupListDefinition;
init();
function init(){
$scope.toDisassociate = host;
$scope.inventory_id = $stateParams.inventory_id;
$scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc;
$scope.canAdd = canAdd;
// Search init
$scope.list = list;
$scope[`${list.iterator}_dataset`] = Dataset.data;
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
$scope.$watchCollection(list.name, function(){
_.forEach($scope[list.name], buildStatusIndicators);
});
$scope.$on('selectedOrDeselected', function(e, value) {
let item = value.value;
if (value.isSelected) {
if(!$scope.groupsSelected) {
$scope.groupsSelected = [];
}
$scope.groupsSelected.push(item);
} else {
_.remove($scope.groupsSelected, { id: item.id });
if($scope.groupsSelected.length === 0) {
$scope.groupsSelected = null;
}
}
});
}
function buildStatusIndicators(group){
if (group === undefined || group === null) {
group = {};
}
let hosts_status;
hosts_status = GetHostsStatusMsg({
active_failures: group.hosts_with_active_failures,
total_hosts: group.total_hosts,
inventory_id: $scope.inventory_id,
group_id: group.id
});
_.assign(group,
{hosts_status_tip: hosts_status.tooltip},
{hosts_status_class: hosts_status.class});
}
$scope.associateGroup = function() {
$state.go('.associate');
};
$scope.disassociateGroup = function(group){
$scope.disassociateFrom = group;
$('#group-disassociate-modal').modal('show');
};
$scope.confirmDisassociate = function(){
// Bind an even listener for the modal closing. Trying to $state.go() before the modal closes
// will mean that these two things are running async and the modal may not finish closing before
// the state finishes transitioning.
$('#group-disassociate-modal').off('hidden.bs.modal').on('hidden.bs.modal', function () {
// Remove the event handler so that we don't end up with multiple bindings
$('#group-disassociate-modal').off('hidden.bs.modal');
// Reload the inventory manage page and show that the group has been removed
$state.go('.', null, {reload: true});
});
let closeModal = function(){
$('#group-disassociate-modal').modal('hide');
$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
};
GroupsService.disassociateHost($scope.toDisassociate.id, $scope.disassociateFrom.id)
.then(() => {
closeModal();
}).catch((error) => {
closeModal();
ProcessErrors(null, error.data, error.status, null, {
hdr: 'Error!',
msg: 'Failed to disassociate group from parent group: POST returned status' +
error.status
});
});
};
$scope.editGroup = function(id){
$state.go('inventories.edit.groups.edit', {group_id: id});
};
$scope.setAdhocPattern = function(){
var pattern = _($scope.groupsSelected)
.map(function(item){
return item.name;
}).value().join(':');
$state.go('^.^.^.adhoc', {pattern: pattern});
};
}];

View File

@ -0,0 +1,107 @@
/*************************************************
* Copyright (c) 2017 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export default {
name: 'nested_groups',
iterator: 'nested_group',
editTitle: '{{ inventory.name }}',
well: true,
wellOverride: true,
index: false,
hover: true,
multiSelect: true,
trackBy: 'nested_group.id',
basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/root_groups/',
fields: {
failed_hosts: {
label: '',
nosort: true,
mode: 'all',
iconOnly: true,
awToolTip: "{{ nested_group.hosts_status_tip }}",
dataPlacement: "top",
icon: "{{ 'fa icon-job-' + nested_group.hosts_status_class }}",
columnClass: 'status-column List-staticColumn--smallStatus'
},
name: {
label: 'Groups',
key: true,
// ngClick: "groupSelect(group.id)",
ngClick: "editGroup(nested_group.id)",
columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6',
class: 'InventoryManage-breakWord',
}
},
actions: {
refresh: {
mode: 'all',
awToolTip: "Refresh the page",
ngClick: "refreshGroups()",
ngShow: "socketStatus == 'error'",
actionClass: 'btn List-buttonDefault',
buttonContent: 'REFRESH'
},
launch: {
mode: 'all',
ngDisabled: '!groupsSelected',
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.",
dataPlacement: 'top',
actionClass: 'btn List-buttonDefault',
buttonContent: 'RUN COMMANDS',
showTipWhenDisabled: true,
tooltipInnerClass: "Tooltip-wide",
ngShow: 'canAdhoc'
// TODO: set up a tip watcher and change text based on when
// things are selected/not selected. This is started and
// commented out in the inventory controller within the watchers.
// awToolTip: "{{ adhocButtonTipContents }}",
// dataTipWatch: "adhocButtonTipContents"
},
associate: {
mode: 'all',
ngClick: 'associateGroup()',
awToolTip: "Associate an existing group",
actionClass: 'btn List-buttonSubmit',
buttonContent: '&#43; ASSOCIATE GROUP',
ngShow: 'canAdd',
dataPlacement: "top",
}
},
fieldActions: {
columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6 text-right',
edit: {
//label: 'Edit',
mode: 'all',
ngClick: "editGroup(nested_group.id)",
awToolTip: 'Edit group',
dataPlacement: "top",
ngShow: "nested_group.summary_fields.user_capabilities.edit"
},
view: {
//label: 'Edit',
mode: 'all',
ngClick: "editGroup(nested_group.id)",
awToolTip: 'View group',
dataPlacement: "top",
ngShow: "!nested_group.summary_fields.user_capabilities.edit"
},
"delete": {
//label: 'Delete',
mode: 'all',
ngClick: "disassociateGroup(nested_group)",
awToolTip: 'Disassociate group',
dataPlacement: "top",
ngShow: "nested_group.summary_fields.user_capabilities.delete"
}
}
};

Some files were not shown because too many files have changed in this diff Show More