mirror of
https://github.com/ansible/awx.git
synced 2024-10-31 06:51:10 +03:00
Adding nested-groups (related tab) and completed jobs to inventories
This commit is contained in:
parent
78ff5f5301
commit
0fa9aa6bcb
@ -0,0 +1,80 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
import JobsListController from '../../jobs/jobs-list.controller';
|
||||
export default ['InventoryCompletedJobsList', '$stateExtender', 'templateUrl', '$injector',
|
||||
function(InventoryCompletedJobsList, $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}`,
|
||||
name: `${formStateDefinition.name}.${list.iterator}s`,
|
||||
url: `/${list.iterator}s`,
|
||||
ncyBreadcrumb: {
|
||||
parent: `${formStateDefinition.name}`,
|
||||
label: `${breadcrumbLabel}`
|
||||
},
|
||||
params: {
|
||||
completed_job_search: {
|
||||
value: {
|
||||
or__job__inventory: '',
|
||||
or__adhoccommand__inventory: '',
|
||||
or__inventoryupdate__inventory_source__inventory: ''
|
||||
},
|
||||
squash: ''
|
||||
}
|
||||
},
|
||||
views: {
|
||||
'related': {
|
||||
templateProvider: function(FormDefinition, GenerateForm) {
|
||||
let html = GenerateForm.buildCollection({
|
||||
mode: 'edit',
|
||||
related: `${list.iterator}s`,
|
||||
form: typeof(FormDefinition) === 'function' ?
|
||||
FormDefinition() : FormDefinition
|
||||
});
|
||||
return html;
|
||||
},
|
||||
controller: JobsListController
|
||||
}
|
||||
},
|
||||
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 });
|
||||
}
|
||||
|
||||
$stateParams[`${list.iterator}_search`].or__job__inventory = $stateParams.inventory_id;
|
||||
$stateParams[`${list.iterator}_search`].or__adhoccommand__inventory = $stateParams.inventory_id;
|
||||
$stateParams[`${list.iterator}_search`].or__inventoryupdate__inventory_source__inventory = $stateParams.inventory_id;
|
||||
|
||||
return qs.search(path, $stateParams[`${list.iterator}_search`]);
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
];
|
@ -0,0 +1,88 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
|
||||
export default ['i18n', function(i18n) {
|
||||
return {
|
||||
// These tooltip fields are consumed to build disabled related tabs tooltips in the form > add view
|
||||
awToolTip: i18n._('Please save and run a job to view'),
|
||||
dataPlacement: 'top',
|
||||
name: 'completed_jobs',
|
||||
basePath: 'unified_jobs',
|
||||
iterator: 'completed_job',
|
||||
search: {
|
||||
"or__job__inventory": ''
|
||||
},
|
||||
editTitle: i18n._('COMPLETED JOBS'),
|
||||
index: false,
|
||||
hover: true,
|
||||
well: false,
|
||||
emptyListText: i18n._('No completed jobs'),
|
||||
|
||||
fields: {
|
||||
status: {
|
||||
label: '',
|
||||
columnClass: 'List-staticColumn--smallStatus',
|
||||
awToolTip: "{{ completed_job.status_tip }}",
|
||||
awTipPlacement: "right",
|
||||
dataTitle: "{{ completed_job.status_popover_title }}",
|
||||
icon: 'icon-job-{{ completed_job.status }}',
|
||||
iconOnly: true,
|
||||
ngClick:"viewjobResults(completed_job)",
|
||||
},
|
||||
id: {
|
||||
label: 'ID',
|
||||
ngClick:"viewjobResults(completed_job)",
|
||||
columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumnAdjacent',
|
||||
awToolTip: "{{ completed_job.status_tip }}",
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
name: {
|
||||
label: i18n._('Name'),
|
||||
columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-6',
|
||||
ngClick: "viewjobResults(completed_job)",
|
||||
awToolTip: "{{ completed_job.name | sanitize }}",
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
type: {
|
||||
label: i18n._('Type'),
|
||||
ngBind: 'completed_job.type_label',
|
||||
link: false,
|
||||
columnClass: "col-lg-2 col-md-2 hidden-sm hidden-xs",
|
||||
},
|
||||
finished: {
|
||||
label: i18n._('Finished'),
|
||||
noLink: true,
|
||||
filter: "longDate",
|
||||
columnClass: "col-lg-3 col-md-3 col-sm-3 hidden-xs",
|
||||
key: true,
|
||||
desc: true
|
||||
}
|
||||
},
|
||||
|
||||
actions: { },
|
||||
|
||||
fieldActions: {
|
||||
|
||||
columnClass: 'col-lg-2 col-md-2 col-sm-3 col-xs-4',
|
||||
|
||||
submit: {
|
||||
icon: 'icon-rocket',
|
||||
mode: 'all',
|
||||
ngClick: 'relaunchJob($event, completed_job.id)',
|
||||
awToolTip: i18n._('Relaunch using the same parameters'),
|
||||
dataPlacement: 'top',
|
||||
ngShow: "!completed_job.type == 'system_job' || completed_job.summary_fields.user_capabilities.start"
|
||||
},
|
||||
"delete": {
|
||||
mode: 'all',
|
||||
ngClick: 'deleteJob(completed_job.id)',
|
||||
awToolTip: i18n._('Delete the job'),
|
||||
dataPlacement: 'top',
|
||||
ngShow: 'completed_job.summary_fields.user_capabilities.delete'
|
||||
}
|
||||
}
|
||||
};}];
|
13
awx/ui/client/src/inventories/completed_jobs/main.js
Normal file
13
awx/ui/client/src/inventories/completed_jobs/main.js
Normal file
@ -0,0 +1,13 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import list from './completed_jobs.list';
|
||||
import buildInventoryCompletedJobsState from './build-inventory-completed-jobs-state.factory';
|
||||
|
||||
export default
|
||||
angular.module('inventoryCompletedJobs', [])
|
||||
.factory('InventoryCompletedJobsList', list)
|
||||
.factory('buildInventoryCompletedJobsState', buildInventoryCompletedJobsState);
|
@ -10,70 +10,88 @@
|
||||
* @description This form is for adding/editing a Group on the inventory page
|
||||
*/
|
||||
|
||||
export default {
|
||||
addTitle: 'CREATE GROUP',
|
||||
editTitle: '{{ name }}',
|
||||
showTitle: true,
|
||||
name: 'group',
|
||||
basePath: 'groups',
|
||||
parent: 'inventories.edit.groups',
|
||||
// the parent node this generated state definition tree expects to attach to
|
||||
stateTree: 'inventories',
|
||||
// form generator inspects the current state name to determine whether or not to set an active (.is-selected) class on a form tab
|
||||
// this setting is optional on most forms, except where the form's edit state name is not parentStateName.edit
|
||||
activeEditState: 'inventories.edit.groups.editGroup',
|
||||
detailsClick: "$state.go('inventories.edit.groups.editGroup')",
|
||||
well: false,
|
||||
fields: {
|
||||
name: {
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)',
|
||||
required: true,
|
||||
tab: 'properties'
|
||||
export default ['i18n', 'nestedGroupListState',
|
||||
function(i18n, nestedGroupListState){
|
||||
return {
|
||||
addTitle: 'CREATE GROUP',
|
||||
editTitle: '{{ name }}',
|
||||
showTitle: true,
|
||||
name: 'group',
|
||||
basePath: 'groups',
|
||||
parent: 'inventories.edit.groups',
|
||||
// the parent node this generated state definition tree expects to attach to
|
||||
stateTree: 'inventories',
|
||||
// form generator inspects the current state name to determine whether or not to set an active (.is-selected) class on a form tab
|
||||
// this setting is optional on most forms, except where the form's edit state name is not parentStateName.edit
|
||||
activeEditState: 'inventories.edit.groups.edit',
|
||||
detailsClick: "$state.go('inventories.edit.groups.edit')",
|
||||
well: false,
|
||||
tabs: true,
|
||||
fields: {
|
||||
name: {
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)',
|
||||
required: true,
|
||||
tab: 'properties'
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)',
|
||||
tab: 'properties'
|
||||
},
|
||||
variables: {
|
||||
label: 'Variables',
|
||||
type: 'textarea',
|
||||
class: 'Form-textAreaLabel Form-formGroup--fullWidth',
|
||||
rows: 6,
|
||||
'default': '---',
|
||||
dataTitle: 'Group Variables',
|
||||
dataPlacement: 'right',
|
||||
parseTypeName: 'parseType',
|
||||
awPopOver: "<p>Variables defined here apply to all child groups and hosts.</p>" +
|
||||
"<p>Enter variables using either JSON or YAML syntax. Use the " +
|
||||
"radio button to toggle between the two.</p>" +
|
||||
"JSON:<br />\n" +
|
||||
"<blockquote>{<br />  \"somevar\": \"somevalue\",<br /> \"password\": \"magic\"<br /> }</blockquote>\n" +
|
||||
"YAML:<br />\n" +
|
||||
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" +
|
||||
'<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' +
|
||||
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
||||
dataContainer: 'body',
|
||||
tab: 'properties'
|
||||
}
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)',
|
||||
tab: 'properties'
|
||||
},
|
||||
variables: {
|
||||
label: 'Variables',
|
||||
type: 'textarea',
|
||||
class: 'Form-textAreaLabel Form-formGroup--fullWidth',
|
||||
rows: 6,
|
||||
'default': '---',
|
||||
dataTitle: 'Group Variables',
|
||||
dataPlacement: 'right',
|
||||
parseTypeName: 'parseType',
|
||||
awPopOver: "<p>Variables defined here apply to all child groups and hosts.</p>" +
|
||||
"<p>Enter variables using either JSON or YAML syntax. Use the " +
|
||||
"radio button to toggle between the two.</p>" +
|
||||
"JSON:<br />\n" +
|
||||
"<blockquote>{<br />  \"somevar\": \"somevalue\",<br /> \"password\": \"magic\"<br /> }</blockquote>\n" +
|
||||
"YAML:<br />\n" +
|
||||
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" +
|
||||
'<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' +
|
||||
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
||||
dataContainer: 'body',
|
||||
tab: 'properties'
|
||||
}
|
||||
},
|
||||
|
||||
buttons: {
|
||||
cancel: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
buttons: {
|
||||
cancel: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
close: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true,
|
||||
ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
}
|
||||
},
|
||||
close: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true,
|
||||
ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
related: {
|
||||
nested_groups: {
|
||||
name: 'nested_groups',
|
||||
ngClick: "$state.go('inventories.edit.groups.edit.nested_groups')",
|
||||
include: "NestedGroupListDefinition",
|
||||
includeForm: "NestedGroupFormDefinition",
|
||||
title: i18n._('Groups'),
|
||||
iterator: 'nested_group',
|
||||
listState: nestedGroupListState,
|
||||
// addState: buildGroupsAddState,
|
||||
// editState: buildGroupsEditState
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}];
|
||||
|
@ -31,17 +31,9 @@ export default {
|
||||
name: {
|
||||
label: 'Groups',
|
||||
key: true,
|
||||
ngClick: "groupSelect(group.id)",
|
||||
ngClick: "editGroup(group.id)",
|
||||
columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6',
|
||||
class: 'InventoryManage-breakWord',
|
||||
},
|
||||
total_groups: {
|
||||
nosort: true,
|
||||
label: '',
|
||||
type: 'badgeCount',
|
||||
ngHide: 'group.total_groups == 0',
|
||||
noLink: true,
|
||||
awToolTip: "{{group.name | sanitize}} contains {{group.total_groups}} {{group.total_groups === 1 ? 'child' : 'children'}}"
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
import groupList from './list/main';
|
||||
import groupAdd from './add/main';
|
||||
import groupEdit from './edit/main';
|
||||
import nestedGroups from './nested-groups/main';
|
||||
import groupFormDefinition from './groups.form';
|
||||
import groupListDefinition from './groups.list';
|
||||
import service from './groups.service';
|
||||
@ -20,9 +21,10 @@ export default
|
||||
angular.module('group', [
|
||||
groupList.name,
|
||||
groupAdd.name,
|
||||
groupEdit.name
|
||||
groupEdit.name,
|
||||
nestedGroups.name
|
||||
])
|
||||
.value('GroupForm', groupFormDefinition)
|
||||
.factory('GroupForm', groupFormDefinition)
|
||||
.value('GroupList', groupListDefinition)
|
||||
.factory('GetHostsStatusMsg', GetHostsStatusMsg)
|
||||
.factory('GetSourceTypeOptions', GetSourceTypeOptions)
|
||||
|
17
awx/ui/client/src/inventories/groups/nested-groups/main.js
Normal file
17
awx/ui/client/src/inventories/groups/nested-groups/main.js
Normal file
@ -0,0 +1,17 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import nestedGroupListState from './nested-groups-list-state.factory';
|
||||
import nestedGroupListDefinition from './nested-groups.list';
|
||||
import nestedGroupFormDefinition from './nested-groups.form';
|
||||
import controller from './nested-groups-list.controller';
|
||||
|
||||
export default
|
||||
angular.module('nestedGroups', [])
|
||||
.factory('nestedGroupListState', nestedGroupListState)
|
||||
.value('NestedGroupListDefinition', nestedGroupListDefinition)
|
||||
.factory('NestedGroupFormDefinition', nestedGroupFormDefinition)
|
||||
.controller('NestedGroupsListController', controller);
|
@ -0,0 +1,224 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
export default
|
||||
['$scope', '$rootScope', '$state', '$stateParams', 'NestedGroupListDefinition', 'InventoryUpdate',
|
||||
'GroupManageService', 'GroupsCancelUpdate', 'ViewUpdateStatus', 'rbacUiControlService', 'GetBasePath',
|
||||
'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData',
|
||||
function($scope, $rootScope, $state, $stateParams, NestedGroupListDefinition, InventoryUpdate,
|
||||
GroupManageService, GroupsCancelUpdate, ViewUpdateStatus, rbacUiControlService, GetBasePath,
|
||||
GetSyncStatusMsg, GetHostsStatusMsg, Dataset, Find, qs, inventoryData){
|
||||
|
||||
let list = NestedGroupListDefinition;
|
||||
|
||||
init();
|
||||
|
||||
function init(){
|
||||
$scope.inventory_id = $stateParams.inventory_id;
|
||||
$scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc;
|
||||
$scope.canAdd = false;
|
||||
|
||||
rbacUiControlService.canAdd(GetBasePath('inventory') + $scope.inventory_id + "/groups")
|
||||
.then(function(canAdd) {
|
||||
$scope.canAdd = canAdd;
|
||||
});
|
||||
|
||||
// Search init
|
||||
$scope.list = list;
|
||||
$scope[`${list.iterator}_dataset`] = Dataset.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
|
||||
// The ncy breadcrumb directive will look at this attribute when attempting to bind to the correct scope.
|
||||
// In this case, we don't want to incidentally bind to this scope when editing a host or a group. See:
|
||||
// https://github.com/ncuillery/angular-breadcrumb/issues/42 for a little more information on the
|
||||
// problem that this solves.
|
||||
$scope.ncyBreadcrumbIgnore = true;
|
||||
if($state.current.name === "inventoryManage.editGroup") {
|
||||
$scope.rowBeingEdited = $state.params.group_id;
|
||||
$scope.listBeingEdited = "groups";
|
||||
}
|
||||
|
||||
$scope.inventory_id = $stateParams.inventory_id;
|
||||
_.forEach($scope[list.name], buildStatusIndicators);
|
||||
|
||||
}
|
||||
|
||||
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.groupSelect = function(id){
|
||||
var group = $stateParams.group === undefined ? [id] : _($stateParams.group).concat(id).value();
|
||||
$state.go('inventoryManage', {
|
||||
inventory_id: $stateParams.inventory_id,
|
||||
group: group,
|
||||
group_search: {
|
||||
page_size: '20',
|
||||
page: '1',
|
||||
order_by: 'name',
|
||||
}
|
||||
}, {reload: true});
|
||||
};
|
||||
$scope.createGroup = function(){
|
||||
$state.go('inventories.edit.groups.add');
|
||||
};
|
||||
$scope.editGroup = function(id){
|
||||
$state.go('inventories.edit.groups.edit', {group_id: id});
|
||||
};
|
||||
$scope.deleteGroup = function(group){
|
||||
$scope.toDelete = {};
|
||||
angular.extend($scope.toDelete, group);
|
||||
if($scope.toDelete.total_groups === 0 && $scope.toDelete.total_hosts === 0) {
|
||||
// This group doesn't have any child groups or hosts - the user is just trying to delete
|
||||
// the group
|
||||
$scope.deleteOption = "delete";
|
||||
}
|
||||
$('#group-delete-modal').modal('show');
|
||||
};
|
||||
$scope.confirmDelete = 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-delete-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-delete-modal').off('hidden.bs.modal');
|
||||
// Reload the inventory manage page and show that the group has been removed
|
||||
$state.go('inventoryManage', null, {reload: true});
|
||||
});
|
||||
|
||||
switch($scope.deleteOption){
|
||||
case 'promote':
|
||||
GroupManageService.promote($scope.toDelete.id, $stateParams.inventory_id)
|
||||
.then(() => {
|
||||
if (parseInt($state.params.group_id) === $scope.toDelete.id) {
|
||||
$state.go("inventoryManage", null, {reload: true});
|
||||
} else {
|
||||
$state.go($state.current, null, {reload: true});
|
||||
}
|
||||
$('#group-delete-modal').modal('hide');
|
||||
$('body').removeClass('modal-open');
|
||||
$('.modal-backdrop').remove();
|
||||
});
|
||||
break;
|
||||
default:
|
||||
GroupManageService.delete($scope.toDelete.id).then(() => {
|
||||
if (parseInt($state.params.group_id) === $scope.toDelete.id) {
|
||||
$state.go("inventoryManage", null, {reload: true});
|
||||
} else {
|
||||
$state.go($state.current, null, {reload: true});
|
||||
}
|
||||
$('#group-delete-modal').modal('hide');
|
||||
$('body').removeClass('modal-open');
|
||||
$('.modal-backdrop').remove();
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.updateGroup = function(group) {
|
||||
GroupManageService.getInventorySource({group: group.id}).then(res =>InventoryUpdate({
|
||||
scope: $scope,
|
||||
group_id: group.id,
|
||||
url: res.data.results[0].related.update,
|
||||
group_name: group.name,
|
||||
group_source: res.data.results[0].source
|
||||
}));
|
||||
};
|
||||
|
||||
$scope.$on(`ws-jobs`, function(e, data){
|
||||
var group = Find({ list: $scope.groups, key: 'id', val: data.group_id });
|
||||
|
||||
if (group === undefined || group === null) {
|
||||
group = {};
|
||||
}
|
||||
|
||||
if(data.status === 'failed' || data.status === 'successful'){
|
||||
let path;
|
||||
if($stateParams && $stateParams.group && $stateParams.group.length > 0) {
|
||||
path = GetBasePath('groups') + _.last($stateParams.group) + '/children';
|
||||
}
|
||||
else {
|
||||
//reaches here if the user is on the root level group
|
||||
path = GetBasePath('inventory') + $stateParams.inventory_id + '/root_groups';
|
||||
}
|
||||
qs.search(path, $state.params[`${list.iterator}_search`])
|
||||
.then(function(searchResponse) {
|
||||
$scope[`${list.iterator}_dataset`] = searchResponse.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
_.forEach($scope[list.name], buildStatusIndicators);
|
||||
});
|
||||
} else {
|
||||
var status = GetSyncStatusMsg({
|
||||
status: data.status,
|
||||
has_inventory_sources: group.has_inventory_sources,
|
||||
source: group.source
|
||||
});
|
||||
group.status = data.status;
|
||||
group.status_class = status.class;
|
||||
group.status_tooltip = status.tooltip;
|
||||
group.launch_tooltip = status.launch_tip;
|
||||
group.launch_class = status.launch_class;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.cancelUpdate = function (id) {
|
||||
GroupsCancelUpdate({ scope: $scope, id: id });
|
||||
};
|
||||
$scope.viewUpdateStatus = function (id) {
|
||||
ViewUpdateStatus({
|
||||
scope: $scope,
|
||||
group_id: id
|
||||
});
|
||||
};
|
||||
$scope.showFailedHosts = function() {
|
||||
$state.go('inventoryManage', {failed: true}, {reload: true});
|
||||
};
|
||||
$scope.scheduleGroup = function(id) {
|
||||
// Add this group's id to the array of group id's so that it gets
|
||||
// added to the breadcrumb trail
|
||||
var groupsArr = $stateParams.group ? $stateParams.group : [];
|
||||
groupsArr.push(id);
|
||||
$state.go('inventoryManage.editGroup.schedules', {group_id: id, group: groupsArr}, {reload: true});
|
||||
};
|
||||
// $scope.$parent governed by InventoryManageController, for unified multiSelect options
|
||||
$scope.$on('multiSelectList.selectionChanged', (event, selection) => {
|
||||
$scope.$parent.groupsSelected = selection.length > 0 ? true : false;
|
||||
$scope.$parent.groupsSelectedItems = selection.selectedItems;
|
||||
});
|
||||
|
||||
$scope.copyMoveGroup = function(id){
|
||||
$state.go('inventoryManage.copyMoveGroup', {group_id: id, groups: $stateParams.groups});
|
||||
};
|
||||
|
||||
var cleanUpStateChangeListener = $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams) {
|
||||
if (toState.name === "inventoryManage.editGroup") {
|
||||
$scope.rowBeingEdited = toParams.group_id;
|
||||
$scope.listBeingEdited = "groups";
|
||||
}
|
||||
else {
|
||||
delete $scope.rowBeingEdited;
|
||||
delete $scope.listBeingEdited;
|
||||
}
|
||||
});
|
||||
|
||||
// Remove the listener when the scope is destroyed to avoid a memory leak
|
||||
$scope.$on('$destroy', function() {
|
||||
cleanUpStateChangeListener();
|
||||
});
|
||||
|
||||
}];
|
@ -0,0 +1,98 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name forms.function:Groups
|
||||
* @description This form is for adding/editing a Group on the inventory page
|
||||
*/
|
||||
|
||||
export default ['i18n', 'nestedGroupListState',
|
||||
function(i18n, nestedGroupListState){
|
||||
return {
|
||||
addTitle: 'CREATE GROUP',
|
||||
editTitle: '{{ name }}',
|
||||
showTitle: true,
|
||||
name: 'nested_group',
|
||||
iterator: "nested_group",
|
||||
basePath: 'groups',
|
||||
parent: 'inventories.edit.groups',
|
||||
// the parent node this generated state definition tree expects to attach to
|
||||
stateTree: 'inventories',
|
||||
// form generator inspects the current state name to determine whether or not to set an active (.is-selected) class on a form tab
|
||||
// this setting is optional on most forms, except where the form's edit state name is not parentStateName.edit
|
||||
activeEditState: 'inventories.edit.groups.edit',
|
||||
detailsClick: "$state.go('inventories.edit.groups.edit')",
|
||||
well: false,
|
||||
tabs: true,
|
||||
fields: {
|
||||
name: {
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)',
|
||||
required: true,
|
||||
tab: 'properties'
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)',
|
||||
tab: 'properties'
|
||||
},
|
||||
variables: {
|
||||
label: 'Variables',
|
||||
type: 'textarea',
|
||||
class: 'Form-textAreaLabel Form-formGroup--fullWidth',
|
||||
rows: 6,
|
||||
'default': '---',
|
||||
dataTitle: 'Group Variables',
|
||||
dataPlacement: 'right',
|
||||
parseTypeName: 'parseType',
|
||||
awPopOver: "<p>Variables defined here apply to all child groups and hosts.</p>" +
|
||||
"<p>Enter variables using either JSON or YAML syntax. Use the " +
|
||||
"radio button to toggle between the two.</p>" +
|
||||
"JSON:<br />\n" +
|
||||
"<blockquote>{<br />  \"somevar\": \"somevalue\",<br /> \"password\": \"magic\"<br /> }</blockquote>\n" +
|
||||
"YAML:<br />\n" +
|
||||
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" +
|
||||
'<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' +
|
||||
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
||||
dataContainer: 'body',
|
||||
tab: 'properties'
|
||||
}
|
||||
},
|
||||
|
||||
buttons: {
|
||||
cancel: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
close: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
},
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true,
|
||||
ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
}
|
||||
},
|
||||
related: {
|
||||
nested_groups: {
|
||||
name: 'related_groups',
|
||||
ngClick: "$state.go('inventories.edit.groups.edit.related_groups')",
|
||||
include: "RelatedGroupListDefinition",
|
||||
includeForm: "RelatedGroupFormDefinition",
|
||||
title: i18n._('Groups'),
|
||||
iterator: 'related_group',
|
||||
listState: nestedGroupListState,
|
||||
// addState: buildGroupsAddState,
|
||||
// editState: buildGroupsEditState
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
}];
|
@ -0,0 +1,146 @@
|
||||
/*************************************************
|
||||
* 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: "{{ group.hosts_status_tip }}",
|
||||
dataPlacement: "top",
|
||||
ngClick: "showFailedHosts(group)",
|
||||
icon: "{{ 'fa icon-job-' + group.hosts_status_class }}",
|
||||
columnClass: 'status-column List-staticColumn--smallStatus'
|
||||
},
|
||||
name: {
|
||||
label: 'Groups',
|
||||
key: true,
|
||||
|
||||
// ngClick: "groupSelect(group.id)",
|
||||
ngClick: "editGroup(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',
|
||||
// $scope.$parent is governed by InventoryManageController,
|
||||
ngDisabled: '!$parent.groupsSelected && !$parent.hostsSelected',
|
||||
ngClick: '$parent.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",
|
||||
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"
|
||||
},
|
||||
create: {
|
||||
mode: 'all',
|
||||
ngClick: "createGroup()",
|
||||
awToolTip: "Create a new group",
|
||||
actionClass: 'btn List-buttonSubmit',
|
||||
buttonContent: '+ ADD GROUP',
|
||||
ngShow: 'canAdd',
|
||||
dataPlacement: "top",
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
|
||||
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',
|
||||
ngClick: "editGroup(group.id)",
|
||||
awToolTip: 'Edit group',
|
||||
dataPlacement: "top",
|
||||
ngShow: "group.summary_fields.user_capabilities.edit"
|
||||
},
|
||||
view: {
|
||||
//label: 'Edit',
|
||||
mode: 'all',
|
||||
ngClick: "editGroup(group.id)",
|
||||
awToolTip: 'View group',
|
||||
dataPlacement: "top",
|
||||
ngShow: "!group.summary_fields.user_capabilities.edit"
|
||||
},
|
||||
"delete": {
|
||||
//label: 'Delete',
|
||||
mode: 'all',
|
||||
ngClick: "deleteGroup(group)",
|
||||
awToolTip: 'Delete group',
|
||||
dataPlacement: "top",
|
||||
ngShow: "group.summary_fields.user_capabilities.delete"
|
||||
}
|
||||
}
|
||||
};
|
@ -13,10 +13,29 @@
|
||||
export default ['i18n', 'buildGroupsListState', 'buildGroupsAddState',
|
||||
'buildGroupsEditState', 'buildHostListState', 'buildHostAddState',
|
||||
'buildHostEditState', 'buildSourcesListState', 'buildSourcesAddState',
|
||||
'buildSourcesEditState',
|
||||
'buildSourcesEditState', 'buildInventoryCompletedJobsState',
|
||||
'InventoryCompletedJobsList',
|
||||
function(i18n, buildGroupsListState, buildGroupsAddState, buildGroupsEditState,
|
||||
buildHostListState, buildHostAddState, buildHostEditState,
|
||||
buildSourcesListState, buildSourcesAddState,buildSourcesEditState) {
|
||||
buildSourcesListState, buildSourcesAddState,buildSourcesEditState,
|
||||
buildInventoryCompletedJobsState, InventoryCompletedJobsList) {
|
||||
|
||||
var completed_jobs_object = {
|
||||
name: 'completed_jobs',
|
||||
index: false,
|
||||
basePath: "unified_jobs",
|
||||
include: "InventoryCompletedJobsList",
|
||||
title: i18n._('Completed Jobs'),
|
||||
iterator: 'completed_job',
|
||||
generateList: true,
|
||||
listState: buildInventoryCompletedJobsState,
|
||||
search: {
|
||||
"or__job__inventory": ''
|
||||
}
|
||||
};
|
||||
let clone = _.clone(InventoryCompletedJobsList);
|
||||
completed_jobs_object = angular.extend(clone, completed_jobs_object);
|
||||
|
||||
return {
|
||||
|
||||
addTitle: i18n._('NEW INVENTORY'),
|
||||
@ -96,7 +115,7 @@ function(i18n, buildGroupsListState, buildGroupsAddState, buildGroupsEditState,
|
||||
name: 'permissions',
|
||||
awToolTip: i18n._('Please save before assigning permissions'),
|
||||
dataPlacement: 'top',
|
||||
basePath: 'api/v1/inventories/{{$stateParams.inventory_id}}/access_list/',
|
||||
basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/access_list/',
|
||||
type: 'collection',
|
||||
title: i18n._('Permissions'),
|
||||
iterator: 'permission',
|
||||
@ -165,39 +184,7 @@ function(i18n, buildGroupsListState, buildGroupsAddState, buildGroupsEditState,
|
||||
addState: buildSourcesAddState,
|
||||
editState: buildSourcesEditState
|
||||
},
|
||||
//this is a placeholder for when we're ready for completed jobs
|
||||
completed_jobs: {
|
||||
name: 'completed_jobs',
|
||||
// awToolTip: i18n._('Please save before assigning permissions'),
|
||||
// dataPlacement: 'top',
|
||||
basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/completed_jobs/',
|
||||
type: 'collection',
|
||||
title: i18n._('Completed Jobs'),
|
||||
iterator: 'completed_job',
|
||||
index: false,
|
||||
open: false,
|
||||
// search: {
|
||||
// order_by: 'username'
|
||||
// },
|
||||
actions: {
|
||||
add: {
|
||||
label: i18n._('Add'),
|
||||
ngClick: "$state.go('.add')",
|
||||
awToolTip: i18n._('Add a permission'),
|
||||
actionClass: 'btn List-buttonSubmit',
|
||||
buttonContent: '+ ADD',
|
||||
// ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||
|
||||
}
|
||||
},
|
||||
fields: {
|
||||
name: {
|
||||
label: i18n._('Name'),
|
||||
// linkBase: 'users',
|
||||
class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4'
|
||||
}
|
||||
}
|
||||
}
|
||||
completed_jobs: completed_jobs_object
|
||||
}
|
||||
|
||||
};}];
|
||||
|
@ -8,6 +8,7 @@ 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 inventoryAdd from './add/main';
|
||||
import inventoryEdit from './edit/main';
|
||||
import inventoryList from './list/main';
|
||||
@ -22,6 +23,7 @@ angular.module('inventory', [
|
||||
group.name,
|
||||
sources.name,
|
||||
relatedHost.name,
|
||||
inventoryCompletedJobs.name,
|
||||
inventoryAdd.name,
|
||||
inventoryEdit.name,
|
||||
inventoryList.name
|
||||
|
@ -576,6 +576,7 @@ function($injector, $stateExtender, $log, i18n) {
|
||||
if(field.includeForm){
|
||||
let form = field.includeForm ? $injector.get(field.includeForm) : field;
|
||||
states.push(that.generateLookupNodes(form, formState));
|
||||
states.push(that.generateFormListDefinitions(form, formState, params));
|
||||
}
|
||||
states = _.flatten(states);
|
||||
}
|
||||
@ -678,6 +679,7 @@ function($injector, $stateExtender, $log, i18n) {
|
||||
if (field.search) {
|
||||
state.params[`${field.iterator}_search`].value = _.merge(state.params[`${field.iterator}_search`].value, field.search);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
return _(form.related).map(buildListNodes).flatten().value();
|
||||
|
Loading…
Reference in New Issue
Block a user