AC-331 Inventories Groups tab just about completed

This commit is contained in:
chouseknecht
2013-08-13 17:57:28 -04:00
parent 07280e8abe
commit 22af7cf6b0
8 changed files with 333 additions and 158 deletions

View File

@@ -185,7 +185,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt, RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt,
OrganizationList, TreeInit, GetBasePath, GroupsList, GroupsAdd, GroupsEdit, LoadInventory, OrganizationList, TreeInit, GetBasePath, GroupsList, GroupsAdd, GroupsEdit, LoadInventory,
GroupsDelete, HostsList, HostsAdd, HostsEdit, HostsDelete, RefreshGroupName, ParseTypeChange, GroupsDelete, HostsList, HostsAdd, HostsEdit, HostsDelete, RefreshGroupName, ParseTypeChange,
HostsReload, EditInventory) HostsReload, EditInventory, RefreshTree)
{ {
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope. //scope.
@@ -225,80 +225,6 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] }); HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] });
} }
function PostSave() {
// Make sure the inventory name in the tree is correct
RefreshGroupName($('#inventory-node'), scope['inventory_name'], scope['inventory_description']);
// Reset the form to disable the form action buttons
scope[form.name + '_form'].$setPristine();
// Show the flash message for 5 seconds, letting the user know the save worked
scope['flashMessage'] = 'Your changes were successfully saved!';
setTimeout(function() {
scope['flashMessage'] = null;
if (!scope.$$phase) {
scope.$digest();
}
}, 5000);
}
// Save
scope.formSave = function() {
try {
// Make sure we have valid variable data
if (scope.inventoryParseType == 'json') {
var json_data = JSON.parse(scope.inventory_variables); //make sure JSON parses
}
else {
var json_data = jsyaml.load(scope.inventory_variables); //parse yaml
}
// Make sure our JSON is actually an object
if (typeof json_data !== 'object') {
throw "failed to return an object!";
}
var data = {}
for (var fld in form.fields) {
if (fld != 'inventory_variables') {
if (form.fields[fld].realName) {
data[form.fields[fld].realName] = scope[fld];
}
else {
data[fld] = scope[fld];
}
}
}
Rest.setUrl(defaultUrl + id + '/');
Rest.put(data)
.success( function(data, status, headers, config) {
if (scope.inventory_variables) {
Rest.setUrl(data.related.variable_data);
Rest.put(json_data)
.success( function(data, status, headers, config) {
PostSave();
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, form,
{ hdr: 'Error!', msg: 'Failed to update inventory varaibles. PUT returned status: ' + status });
});
}
else {
PostSave();
}
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, form,
{ hdr: 'Error!', msg: 'Failed to update new inventory. Post returned status: ' + status });
});
}
catch(err) {
Alert("Error", "Error parsing inventory variables. Parser returned: " + err);
}
};
// Cancel // Cancel
scope.formReset = function() { scope.formReset = function() {
generator.reset(); generator.reset();
@@ -350,6 +276,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
}; };
scope.treeController = function($node) { scope.treeController = function($node) {
var nodeType = $($node).attr('type'); var nodeType = $($node).attr('type');
if (nodeType == 'inventory') { if (nodeType == 'inventory') {
return { return {
@@ -361,10 +288,11 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
scope.$digest(); scope.$digest();
} }
EditInventory({ scope: scope, "inventory_id": id }); EditInventory({ scope: scope, "inventory_id": id });
} },
separator_after: true
}, },
addGroup: { addGroup: {
label: 'Create Group', label: 'Create New Group',
action: function(obj) { action: function(obj) {
scope.group_id = null; scope.group_id = null;
if (!scope.$$phase) { if (!scope.$$phase) {
@@ -386,11 +314,11 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
} }
GroupsEdit({ "inventory_id": id, group_id: $(obj).attr('group_id') }); GroupsEdit({ "inventory_id": id, group_id: $(obj).attr('group_id') });
}, },
separator_before: true separator_after: true
}, },
addGroup: { addGroup: {
label: 'Add Existing', label: 'Add Existing Group',
action: function(obj) { action: function(obj) {
scope.group_id = $(obj).attr('group_id'); scope.group_id = $(obj).attr('group_id');
if (!scope.$$phase) { if (!scope.$$phase) {
@@ -401,7 +329,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
}, },
createGroup: { createGroup: {
label: 'Create New', label: 'Create New Group',
action: function(obj) { action: function(obj) {
scope.group_id = $(obj).attr('group_id'); scope.group_id = $(obj).attr('group_id');
if (!scope.$$phase) { if (!scope.$$phase) {
@@ -435,15 +363,18 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
scope['selectedNode'] = node; scope['selectedNode'] = node;
scope['selectedNodeName'] = node.attr('name'); scope['selectedNodeName'] = node.attr('name');
scope['selectedNodeName'] += (node.attr('data-failures') == 'true') ?
' <span class="nav-badge">' +
'<i class="icon-exclamation-sign" title="Contains hosts with active failures"></i></span>' : '';
$('#tree-view').jstree('open_node',node); $('#tree-view').jstree('open_node',node);
if (type == 'group') { if (type == 'group') {
url = node.attr('all'); url = node.attr('all');
scope.groupAddHide = false; scope.groupAddHide = false;
scope.groupCreateHide = false; scope.groupCreateHide = false;
scope.groupEditHide =false; scope.groupEditHide = false;
scope.inventoryEditHide=true; scope.inventoryEditHide = true;
scope.groupDeleteHide = false; scope.groupDeleteHide = false;
scope.createButtonShow = true; scope.createButtonShow = true;
scope.group_id = node.attr('group_id'); scope.group_id = node.attr('group_id');
@@ -473,7 +404,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
}); });
scope.addGroup = function() { scope.addGroup = function() {
GroupsList({ "inventory_id": id, group_id: scope.group_id }); GroupsList({ "inventory_id": id, group_id: scope.group_id });
} }
scope.createGroup = function() { scope.createGroup = function() {
@@ -531,6 +462,6 @@ InventoriesEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$l
'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt',
'OrganizationList', 'TreeInit', 'GetBasePath', 'GroupsList', 'GroupsAdd', 'GroupsEdit', 'LoadInventory', 'OrganizationList', 'TreeInit', 'GetBasePath', 'GroupsList', 'GroupsAdd', 'GroupsEdit', 'LoadInventory',
'GroupsDelete', 'HostsList', 'HostsAdd', 'HostsEdit', 'HostsDelete', 'RefreshGroupName', 'GroupsDelete', 'HostsList', 'HostsAdd', 'HostsEdit', 'HostsDelete', 'RefreshGroupName',
'ParseTypeChange', 'HostsReload', 'EditInventory' 'ParseTypeChange', 'HostsReload', 'EditInventory', 'RefreshTree'
]; ];

View File

@@ -18,6 +18,14 @@ angular.module('GroupFormDefinition', [])
formFieldSize: 'col-lg-9', formFieldSize: 'col-lg-9',
fields: { fields: {
has_active_failures: {
label: 'Status',
control: '<div class="job-failures-\{\{ has_active_failures \}\}">' +
'<i class="icon-exclamation-sign"></i> Contains hosts with failed jobs</div>',
type: 'custom',
ngShow: 'has_active_failures',
readonly: true
},
name: { name: {
label: 'Name', label: 'Name',
type: 'text', type: 'text',

View File

@@ -20,9 +20,9 @@ angular.module('InventoryFormDefinition', [])
fields: { fields: {
has_active_failures: { has_active_failures: {
label: 'Host Status', label: 'Status',
control: '<div class="job-failures-\{\{ has_active_failures \}\}">' + control: '<div class="job-failures-\{\{ has_active_failures \}\}">' +
'<i class="icon-exclamation-sign"></i> Failed jobs</div>', '<i class="icon-exclamation-sign"></i> Contains hosts with failed jobs</div>',
type: 'custom', type: 'custom',
ngShow: 'has_active_failures', ngShow: 'has_active_failures',
readonly: true readonly: true

View File

@@ -31,19 +31,23 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
var treeData = []; var treeData = [];
// Ater inventory top-level hosts, load top-level groups // Ater inventory top-level hosts, load top-level groups
if (scope.HostLoadedRemove) { if (scope.inventoryLoadedRemove) {
scope.HostLoadedRemove(); scope.inventoryLoadedRemove();
} }
scope.HostLoadedRemove = scope.$on('hostsLoaded', function() { scope.inventoryLoadedRemove = scope.$on('inventoryLoaded', function() {
var filter = (scope.inventoryFailureFilter) ? "has_active_failures__int=1&" : ""; var filter = (scope.inventoryFailureFilter) ? "has_active_failures=true&" : "";
var url = groups + '?' + filter + 'order_by=name'; var url = groups + '?' + filter + 'order_by=name';
var title;
Rest.setUrl(url); Rest.setUrl(url);
Rest.get() Rest.get()
.success( function(data, status, headers, config) { .success( function(data, status, headers, config) {
for (var i=0; i < data.results.length; i++) { for (var i=0; i < data.results.length; i++) {
title = data.results[i].name;
title += (data.results[i].has_active_failures) ? ' <span class="tree-badge" title="Contains hosts with failed jobs">' +
'<i class="icon-exclamation-sign"></i></span>' : '';
treeData[0].children.push({ treeData[0].children.push({
data: { data: {
title: data.results[i].name title: title
}, },
attr: { attr: {
id: idx, id: idx,
@@ -69,39 +73,35 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
}); });
}); });
// Setup tree_data var title = inventory_name;
Rest.setUrl(hosts + '?order_by=name'); title += (has_active_failures) ? ' <span class="tree-badge" title="Contains hosts with failed jobs">' +
Rest.get() '<i class="icon-exclamation-sign"></i></span>' : '';
.success ( function(data, status, headers, config) { treeData =
treeData = [{
[{ data: {
data: { title: title
title: inventory_name },
}, attr: {
attr: { type: 'inventory',
type: 'inventory', id: 'inventory-node',
id: 'inventory-node', url: inventory_url,
url: inventory_url, 'inventory_id': inventory_id,
'inventory_id': inventory_id, hosts: hosts,
hosts: hosts, name: inventory_name,
name: inventory_name, description: inventory_descr,
description: inventory_descr, "data-failures": inventory.has_active_failures
"data-failures": inventory.has_active_failures },
}, state: 'open',
state: 'open', children:[]
children:[] }];
}]; scope.$emit('inventoryLoaded');
scope.$emit('hostsLoaded');
})
.error ( function(data, status, headers, config) {
Alert('Error', 'Failed to laod tree data. Url: ' + hosts + ' GET status: ' + status);
});
} }
}]) }])
.factory('TreeInit', ['Alert', 'Rest', 'Authorization', '$http', 'LoadTreeData', .factory('TreeInit', ['Alert', 'Rest', 'Authorization', '$http', 'LoadTreeData', 'GetBasePath', 'ProcessErrors',
function(Alert, Rest, Authorization, $http, LoadTreeData) { function(Alert, Rest, Authorization, $http, LoadTreeData, GetBasePath, ProcessErrors) {
return function(params) { return function(params) {
var scope = params.scope; var scope = params.scope;
@@ -121,7 +121,9 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
scope.buildTreeRemove = scope.$on('buildTree', function(e, treeData, index) { scope.buildTreeRemove = scope.$on('buildTree', function(e, treeData, index) {
var idx = index; var idx = index;
$(tree_id).jstree({ $(tree_id).jstree({
"core": { "initially_open":['inventory_node'] }, "core": { "initially_open":['inventory_node'],
"html_titles": true,
},
"plugins": ['themes', 'json_data', 'ui', 'contextmenu', 'dnd', 'crrm'], "plugins": ['themes', 'json_data', 'ui', 'contextmenu', 'dnd', 'crrm'],
"themes": { "themes": {
"theme": "ansible", "theme": "ansible",
@@ -142,11 +144,15 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
headers: { 'Authorization': 'Token ' + Authorization.getToken() }, headers: { 'Authorization': 'Token ' + Authorization.getToken() },
success: function(data) { success: function(data) {
var response = []; var response = [];
var filter = (scope.inventoryFailureFilter) ? "has_active_failures__int=1&" : ""; var title;
var filter = (scope.inventoryFailureFilter) ? "has_active_failures=true&" : "";
for (var i=0; i < data.results.length; i++) { for (var i=0; i < data.results.length; i++) {
title = data.results[i].name;
title += (data.results[i].has_active_failures) ? ' <span class="tree-badge" title="Contains hosts with failed jobs">' +
'<i class="icon-exclamation-sign"></i></span>' : '';
response.push({ response.push({
data: { data: {
title: data.results[i].name title: title
}, },
attr: { attr: {
id: idx, id: idx,
@@ -170,7 +176,18 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
} }
}, },
"dnd": { }, "dnd": { },
"crrm": { }, "crrm": {
"move": {
"check_move": function(m) {
if (m.op.attr('id') == m.np.attr('id')) {
// old parent and new parent cannot be the same
return false;
}
return true;
}
}
},
"crrm" : { },
"contextmenu": { "contextmenu": {
items: scope.treeController items: scope.treeController
} }
@@ -182,20 +199,121 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
}); });
$(tree_id).bind('move_node.jstree', function(e, data) { $(tree_id).bind('move_node.jstree', function(e, data) {
if (data.rslt.o[0].id !== 'inventory_id') { // When user drags-n-drops a node, update the API
console.log('group_id: ' + $('#tree-view li[id="' + data.rslt.o[0].id+ '"]').attr('group_id')); var node, target, url, parent, inv_id, variables;
node = $('#tree-view li[id="' + data.rslt.o[0].id + '"]'); // node being moved
parent = $('#tree-view li[id="' + data.args[0].op[0].id + '"]'); //node moving from
target = $('#tree-view li[id="' + data.rslt.np[0].id + '"]'); // node moving to
inv_id = inventory_id;
if (scope.removeCopyVariables) {
scope.removeCopyVariables();
} }
else { scope.removeCopyVariables = scope.$on('copyVariables', function(e, id, url) {
console.log('id: ' + data.rslt.o[0].id);
function showSuccessMsg() {
var parent_descr = (parent.attr('type') == 'inventory') ? 'the inventory root' : parent.attr('name');
var target_descr = (target.attr('type') == 'inventory') ? 'the inventory root' : target.attr('name');
Alert('Group Moved', 'Group ' + node.attr('name') + ' was successfully moved from ' + parent_descr +
' to ' + target_descr + '.', 'alert-success');
scope['treeLoading'] = false;
if (!scope.$$phase) {
scope.$digest();
}
}
if (variables) {
Rest.setUrl(url);
Rest.put(variables)
.success(function(data, status, headers, config) {
showSuccessMsg();
})
.error(function(data, status, headers, config) {
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Failed to update variables. PUT returned status: ' + status });
});
}
else {
showSuccessMsg();
}
});
if (scope['addToTargetRemove']) {
scope.addToTargetRemove();
} }
scope.addToTargetRemove = scope.$on('addToTarget', function() {
// add the new group to the target parent
var url = (target.attr('type') == 'group') ? GetBasePath('base') + 'groups/' + target.attr('group_id') + '/children/' :
GetBasePath('inventory') + inv_id + '/groups/';
var group = {
name: node.attr('name'),
description: node.attr('description'),
inventory: node.attr('inventory')
}
Rest.setUrl(url);
Rest.post(group)
.success( function(data, status, headers, config) {
//Update the node with new attributes
var filter = (scope.inventoryFailureFilter) ? "has_active_failures=true&" : "";
node.attr('group_id', data.id);
node.attr('variable', data.related.variable_data);
node.attr('all', data.related.all_hosts);
node.attr('children', data.related.children + '?' + filter + 'order_by=name');
node.attr('hosts', data.related.hosts);
node.attr('data-failures', data.has_active_failures);
scope.$emit('copyVariables', data.id, data.related.variable_data);
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Failed to add ' + node.attr('name') + ' to ' +
target.attr('name') + '. POST returned status: ' + status });
});
});
// disassociate the group from the original parent
if (scope.removeGroupRemove) {
scope.removeGroupRemove();
}
scope.removeGroupRemove = scope.$on('removeGroup', function() {
var url = (parent.attr('type') == 'group') ? GetBasePath('base') + 'groups/' + parent.attr('group_id') + '/children/' :
GetBasePath('inventory') + inv_id + '/groups/';
Rest.setUrl(url);
Rest.post({ id: node.attr('group_id'), disassociate: 1 })
.success( function(data, status, headers, config) {
scope.$emit('addToTarget');
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Failed to remove ' + node.attr('name') + ' from ' +
parent.attr('name') + '. POST returned status: ' + status });
});
});
// Lookup the inventory. We already have what we need except for variables.
Rest.setUrl(GetBasePath('base') + 'groups/' + node.attr('group_id') + '/');
Rest.get()
.success( function(data, status, headers, config) {
variables = (data.variables) ? JSON.parse(data.variables) : "";
scope.$emit('removeGroup');
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Failed to lookup group ' + node.attr('name') +
'. GET returned status: ' + status });
});
scope['treeLoading'] = true;
if (!scope.$$phase) {
scope.$digest();
}
}); });
// When user clicks on a group, display the related hosts in the list view // When user clicks on a group, display the related hosts in the list view
$(tree_id).bind("select_node.jstree", function(e, data){ $(tree_id).bind("select_node.jstree", function(e, data){
//selected node object: data.inst.get_json()[0];
//selected node text: data.inst.get_json()[0].data
scope.$emit('NodeSelect', data.inst.get_json()[0]); scope.$emit('NodeSelect', data.inst.get_json()[0]);
}); });
}); });
scope['treeLoading'] = true; scope['treeLoading'] = true;
@@ -267,6 +385,10 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
// Call after GroupsEdit controller saves changes // Call after GroupsEdit controller saves changes
$('#tree-view').jstree('rename_node', node, name); $('#tree-view').jstree('rename_node', node, name);
node.attr('description', description); node.attr('description', description);
scope = angular.element(getElementById('htmlTemplate')).scope();
scope['selectedNodeName'] = name;
scope['selectedNodeName'] += (node.attr('data-failures') == 'true') ?
' <span class="nav-badge"><i class="icon-exclamation-sign" title="Contains hosts with failed jobs"></i></span>' : '';
} }
}]) }])
@@ -323,6 +445,8 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
$('#tree-view').jstree('destroy'); $('#tree-view').jstree('destroy');
TreeInit(scope.TreeParams); TreeInit(scope.TreeParams);
}); });
scope.treeLoading = true;
LoadInventory({ scope: scope, doPostSteps: true }); LoadInventory({ scope: scope, doPostSteps: true });
} }
@@ -330,9 +454,9 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
.factory('EditInventory', ['InventoryForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList', .factory('EditInventory', ['InventoryForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList',
'GetBasePath', 'ParseTypeChange', 'LoadInventory', 'GetBasePath', 'ParseTypeChange', 'LoadInventory', 'RefreshGroupName',
function(InventoryForm, GenerateForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, function(InventoryForm, GenerateForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange,
LoadInventory) { LoadInventory, RefreshGroupName) {
return function(params) { return function(params) {
var generator = GenerateForm; var generator = GenerateForm;
@@ -396,6 +520,82 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
if (!scope.$$phase) { if (!scope.$$phase) {
scope.$digest(); scope.$digest();
} }
function PostSave() {
$('#form-modal').modal('hide');
// Make sure the inventory name appears correctly in the tree and the navbar
RefreshGroupName($('#inventory-node'), scope['inventory_name'], scope['inventory_description']);
// Reset the form to disable the form action buttons
//scope[form.name + '_form'].$setPristine();
// Show the flash message for 5 seconds, letting the user know the save worked
//scope['flashMessage'] = 'Your changes were successfully saved!';
//setTimeout(function() {
// scope['flashMessage'] = null;
// if (!scope.$$phase) {
// scope.$digest();
// }
// }, 5000);
}
// Save
scope.formModalAction = function() {
try {
// Make sure we have valid variable data
if (scope.inventoryParseType == 'json') {
var json_data = JSON.parse(scope.inventory_variables); //make sure JSON parses
}
else {
var json_data = jsyaml.load(scope.inventory_variables); //parse yaml
}
// Make sure our JSON is actually an object
if (typeof json_data !== 'object') {
throw "failed to return an object!";
}
var data = {}
for (var fld in form.fields) {
if (fld != 'inventory_variables') {
if (form.fields[fld].realName) {
data[form.fields[fld].realName] = scope[fld];
}
else {
data[fld] = scope[fld];
}
}
}
Rest.setUrl(defaultUrl + scope['inventory_id'] + '/');
Rest.put(data)
.success( function(data, status, headers, config) {
if (scope.inventory_variables) {
Rest.setUrl(data.related.variable_data);
Rest.put(json_data)
.success( function(data, status, headers, config) {
PostSave();
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, form,
{ hdr: 'Error!', msg: 'Failed to update inventory varaibles. PUT returned status: ' + status });
});
}
else {
PostSave();
}
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, form,
{ hdr: 'Error!', msg: 'Failed to update inventory. POST returned status: ' + status });
});
}
catch(err) {
Alert("Error", "Error parsing inventory variables. Parser returned: " + err);
}
};
} }
}]); }]);

View File

@@ -526,16 +526,43 @@ input[type="text"].job-successful {
.nav a { .nav a {
color: @blue-link; color: @blue-link;
font-size: 12px;
i {
font-size: 14px;
}
}
.navbar-form {
display: inline-block;
float: right;
margin-top: 13px;
margin-left: 20px;
margin-right: 10px;
label {
font-size: 12px;
line-height: normal;
}
input[type="checkbox"] {
margin-top: 0;
}
} }
/* the brand is't really a link */ /* the brand is't really a link */
.navbar-brand { .navbar-brand {
color: @grey; color: @black;
text-align: left;
font-size: 14px;
max-width: 100%;
i {
color: @red;
}
} }
.navbar-brand:hover { .navbar-brand:hover {
color: @grey; color: @black;
cursor: default; cursor: default;
} }
/* neither is the status spinner */ /* neither is the status spinner */
.nav .status { .nav .status {
color: @black; color: @black;
@@ -547,6 +574,11 @@ input[type="text"].job-successful {
} }
.tree-badge {
color: @red;
font-size: 12px;
}
.inventory-title { .inventory-title {
margin-top: 15px; margin-top: 15px;
font-weight: bold; font-weight: bold;

View File

@@ -914,20 +914,24 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
// build the groups tab // build the groups tab
html += "<div class=\"navbar groups-menu\">\n"; html += "<div class=\"navbar groups-menu\">\n";
html += "<a class=\"navbar-brand\" ng-bind=\"selectedNodeName\" href=\"\"></a>\n"; html += "<a class=\"navbar-brand\" ng-bind-html-unsafe=\"selectedNodeName\" href=\"\"></a>\n";
html += "<ul class=\"nav navbar-nav\">\n"; html += "<ul class=\"nav navbar-nav\">\n";
html += "<li><a href=\"\" ng-click=\"editInventory()\" ng-hide=\"inventoryEditHide\" " + html += "<li><a href=\"\" ng-click=\"editInventory()\" ng-hide=\"inventoryEditHide\" " +
"aw-tool-tip=\"Edit inventory properties\" data-placement=\"bottom\"><i class=\"icon-edit\"></i> Inventory Properties</a></li>\n"; "aw-tool-tip=\"Edit inventory properties\" data-placement=\"bottom\"><i class=\"icon-edit\"></i> Inventory Properties</a></li>\n";
html += "<li><a href=\"\" ng-click=\"editGroup()\" ng-hide=\"groupEditHide\" " + html += "<li><a href=\"\" ng-click=\"editGroup()\" ng-hide=\"groupEditHide\" " +
"aw-tool-tip=\"Edit the selected group\" data-placement=\"bottom\"><i class=\"icon-edit\"></i> Group Properties</a></li>\n"; "aw-tool-tip=\"Edit the selected group\" data-placement=\"bottom\"><i class=\"icon-edit\"></i> Group Properties</a></li>\n";
html += "<li><a href=\"\" ng-click=\"addGroup()\" ng-hide=\"groupAddHide\" " + html += "<li><a href=\"\" ng-click=\"addGroup()\" ng-hide=\"groupAddHide\" " +
"aw-tool-tip=\"Add an existing group\" data-placement=\"bottom\"><i class=\"icon-check\"></i> Add Existing</a></li>\n"; "aw-tool-tip=\"Add an existing group\" data-placement=\"bottom\"><i class=\"icon-check\"></i> Add Existing Group</a></li>\n";
html += "<li><a href=\"\" ng-click=\"createGroup()\" ng-hide=\"groupCreateHide\" " + html += "<li><a href=\"\" ng-click=\"createGroup()\" ng-hide=\"groupCreateHide\" " +
"aw-tool-tip=\"Create a new group\" data-placement=\"bottom\"><i class=\"icon-plus\"></i> Create New</a></li>\n"; "aw-tool-tip=\"Create a new group\" data-placement=\"bottom\"><i class=\"icon-plus\"></i> Create New Group</a></li>\n";
html += "<li><a href=\"\" ng-click=\"deleteGroup()\" ng-hide=\"groupDeleteHide\" " + html += "<li><a href=\"\" ng-click=\"deleteGroup()\" ng-hide=\"groupDeleteHide\" " +
"aw-tool-tip=\"Delete the selected group\" data-placement=\"bottom\"><i class=\"icon-trash\"></i> Delete Group</a></li>\n"; "aw-tool-tip=\"Delete the selected group\" data-placement=\"bottom\"><i class=\"icon-trash\"></i> Delete Group</a></li>\n";
html += "<li><a class=\"status\" ng-show=\"treeLoading\" href=\"\"><i class=\"icon-spinner icon-spin icon-large\"></i> Loading...</a></li>\n"; html += "<li><a class=\"status\" ng-show=\"treeLoading\" href=\"\"><i class=\"icon-spinner icon-spin icon-large\"></i> Loading...</a></li>\n";
html += "</ul>\n"; html += "</ul>\n";
html += "<form class=\"navbar-form\">\n";
html += "<label class=\"checkbox-inline\"><input type=\"checkbox\" ng-model=\"inventoryFailureFilter\" ng-change=\"filterInventory()\" > Only show groups with failed hosts" +
"</label>\n";
html += "</form>\n";
html += "</div><!-- navbar -->\n"; html += "</div><!-- navbar -->\n";
html += "<div id=\"tree-view\" class=\"tree-container\"></div>\n"; html += "<div id=\"tree-view\" class=\"tree-container\"></div>\n";
//html += "<span ng-show=\"has_active_failures == true\"><label class=\"checkbox inline\">"; //html += "<span ng-show=\"has_active_failures == true\"><label class=\"checkbox inline\">";

View File

@@ -27,9 +27,9 @@
.jstree-ansible .jstree-clicked { background:#d9edf7; border:1px solid #3a87ad; padding:0 2px 0 1px; color: #000; } .jstree-ansible .jstree-clicked { background:#d9edf7; border:1px solid #3a87ad; padding:0 2px 0 1px; color: #000; }
/* if data-failures=true (set usng has_active_failures on hosts, groups, inventory), link color is red */ /* if data-failures=true (set usng has_active_failures on hosts, groups, inventory), link color is red */
.jstree-ansible li[data-failures="true"] .jstree-clicked { color: #FF0000; } .jstree-ansible li[data-failures="true"] .jstree-clicked { color: #000; }
.jstree-ansible li[data-failures="false"] .jstree-clicked { color: #000; } .jstree-ansible li[data-failures="false"] .jstree-clicked { color: #000; }
.jstree-ansible li[data-failures="true"] a { color: #FF0000; } .jstree-ansible li[data-failures="true"] a { color: #000; }
.jstree-ansible li[data-failures="false"] a { color: #000; } .jstree-ansible li[data-failures="false"] a { color: #000; }
.jstree-ansible a .jstree-icon { background-position:-56px -19px; } .jstree-ansible a .jstree-icon { background-position:-56px -19px; }

View File

@@ -205,24 +205,6 @@
</div><!-- modal-dialog --> </div><!-- modal-dialog -->
</div><!-- modal --> </div><!-- modal -->
<!-- Lookup dialog. Use for attribute selection -->
<div id="lookup-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-target="#lookup-modal"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="lookupHeader"></h3>
</div>
<div class="modal-body" id="lookup-modal-body"></div>
<div class="modal-footer">
<a href="#" data-target="#lookup-modal" data-dismiss="modal" class="btn btn-default">Cancel</a>
<a href="" ng-click="selectAction()" class="btn btn-primary">Select</a>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->
<!-- Generic Form dialog --> <!-- Generic Form dialog -->
<div id="form-modal" class="modal fade"> <div id="form-modal" class="modal fade">
<div class="modal-dialog"> <div class="modal-dialog">
@@ -262,6 +244,24 @@
</div><!-- modal-dialog --> </div><!-- modal-dialog -->
</div><!-- modal --> </div><!-- modal -->
<!-- Lookup dialog. Use for attribute selection -->
<div id="lookup-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-target="#lookup-modal"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="lookupHeader"></h3>
</div>
<div class="modal-body" id="lookup-modal-body"></div>
<div class="modal-footer">
<a href="#" data-target="#lookup-modal" data-dismiss="modal" class="btn btn-default">Cancel</a>
<a href="" ng-click="selectAction()" class="btn btn-primary">Select</a>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->
<!-- Confirmation Dialog --> <!-- Confirmation Dialog -->
<div id="prompt-modal" class="modal fade"> <div id="prompt-modal" class="modal fade">
<div class="modal-dialog"> <div class="modal-dialog">