mirror of
https://github.com/ansible/awx.git
synced 2026-01-13 19:10:07 -03:30
Merge pull request #2110 from mabashian/1928-organizations-action-buttons-v2
Organization lists bug fixes
This commit is contained in:
commit
854b613bb7
@ -976,6 +976,7 @@ input[type="checkbox"].checkbox-no-label {
|
||||
/* Display list actions next to search widget */
|
||||
.list-actions {
|
||||
text-align: right;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.fa-lg {
|
||||
vertical-align: -8%;
|
||||
|
||||
@ -112,7 +112,9 @@ export default
|
||||
// use $state.go with reload: true option to re-instantiate sockets in
|
||||
$state.go('jobDetail', {id: job}, {reload: true});
|
||||
}
|
||||
scope.clearDialog();
|
||||
if(scope.clearDialog) {
|
||||
scope.clearDialog();
|
||||
}
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
|
||||
@ -19,6 +19,6 @@ export default {
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: "organizations",
|
||||
label: "{{name}}"
|
||||
label: "{{organization_name}}"
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<div class="AddUsers-header">
|
||||
<div class="List-header">
|
||||
<div class="List-title">
|
||||
<div class="List-titleText ng-binding">{{ $parent.org_name }}<div class="List-titleLockup"></div>Add {{ addType }}
|
||||
<div class="List-titleText ng-binding">{{ $parent.organization_name }}<div class="List-titleLockup"></div>Add {{ addType }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="Form-exitHolder">
|
||||
|
||||
@ -0,0 +1,101 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$stateParams', '$scope', 'UserList', 'Rest', '$state', 'generateList', '$compile',
|
||||
'SearchInit', 'PaginateInit', 'Wait', 'Prompt', 'ProcessErrors', 'GetBasePath',
|
||||
function($stateParams, $scope, UserList, Rest, $state, GenerateList, $compile,
|
||||
SearchInit, PaginateInit, Wait, Prompt, ProcessErrors, GetBasePath) {
|
||||
|
||||
var list,
|
||||
url,
|
||||
generator = GenerateList,
|
||||
orgBase = GetBasePath('organizations');
|
||||
|
||||
Rest.setUrl(orgBase + $stateParams.organization_id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
// include name of item in listTitle
|
||||
var listTitle = data.name + "<div class='List-titleLockup'></div>ADMINS";
|
||||
|
||||
$scope.$parent.activeCard = parseInt($stateParams.organization_id);
|
||||
$scope.$parent.activeMode = 'admins';
|
||||
$scope.organization_name = data.name;
|
||||
$scope.org_id = data.id;
|
||||
var listMode = 'users';
|
||||
|
||||
list = _.cloneDeep(UserList);
|
||||
list.emptyListText = "Please add items to this list";
|
||||
delete list.actions.add;
|
||||
list.searchRowActions = {
|
||||
add: {
|
||||
buttonContent: '+ ADD administrator',
|
||||
awToolTip: 'Add existing user to organization as administrator',
|
||||
actionClass: 'btn List-buttonSubmit',
|
||||
ngClick: 'addUsers()'
|
||||
}
|
||||
};
|
||||
url = data.related.admins;
|
||||
list.listTitle = listTitle;
|
||||
list.basePath = url;
|
||||
|
||||
$scope.orgRelatedUrls = data.related;
|
||||
|
||||
generator.inject(list, { mode: 'edit', scope: $scope, cancelButton: true });
|
||||
|
||||
SearchInit({
|
||||
scope: $scope,
|
||||
set: listMode,
|
||||
list: list,
|
||||
url: url
|
||||
});
|
||||
PaginateInit({
|
||||
scope: $scope,
|
||||
list: list,
|
||||
url: url
|
||||
});
|
||||
$scope.search(list.iterator);
|
||||
});
|
||||
|
||||
$scope.addUsers = function () {
|
||||
$compile("<add-users class='AddUsers'></add-users>")($scope);
|
||||
};
|
||||
|
||||
$scope.editUser = function (id) {
|
||||
$state.transitionTo('users.edit', {user_id: id});
|
||||
};
|
||||
|
||||
$scope.deleteUser = function (id, name) {
|
||||
var action = function () {
|
||||
$('#prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
var url = orgBase + $stateParams.organization_id + '/admins/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post({
|
||||
id: id,
|
||||
disassociate: true
|
||||
}).success(function () {
|
||||
$scope.search(list.iterator);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: 'Delete',
|
||||
body: '<div class="Prompt-bodyQuery">Are you sure you want to remove the following administrator from this organization?</div><div class="Prompt-bodyTarget">' + name + '</div>',
|
||||
action: action,
|
||||
actionText: 'DELETE'
|
||||
});
|
||||
};
|
||||
|
||||
$scope.formCancel = function(){
|
||||
$state.go('organizations');
|
||||
};
|
||||
|
||||
}
|
||||
];
|
||||
@ -0,0 +1,343 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$location', '$log',
|
||||
'$stateParams', '$compile', '$filter', 'sanitizeFilter', 'Rest', 'Alert', 'InventoryList',
|
||||
'generateList', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller',
|
||||
'ClearScope', 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state',
|
||||
function($scope, $rootScope, $location, $log,
|
||||
$stateParams, $compile, $filter, sanitizeFilter, Rest, Alert, InventoryList,
|
||||
generateList, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||
ClearScope, ProcessErrors, GetBasePath, Wait,
|
||||
Find, Empty, $state) {
|
||||
|
||||
var list,
|
||||
invUrl,
|
||||
orgBase = GetBasePath('organizations'),
|
||||
generator = generateList;
|
||||
|
||||
// Go out and get the organization
|
||||
Rest.setUrl(orgBase + $stateParams.organization_id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
// include name of item in listTitle
|
||||
var listTitle = data.name + "<div class='List-titleLockup'></div>INVENTORIES";
|
||||
|
||||
$scope.$parent.activeCard = parseInt($stateParams.organization_id);
|
||||
$scope.$parent.activeMode = 'inventories';
|
||||
$scope.organization_name = data.name;
|
||||
$scope.org_id = data.id;
|
||||
|
||||
list = _.cloneDeep(InventoryList);
|
||||
list.emptyListText = "This list is populated by inventories added from the <a ui-sref='inventories.add'>Inventories</a> section";
|
||||
delete list.actions.add;
|
||||
delete list.fieldActions.delete;
|
||||
invUrl = data.related.inventories;
|
||||
list.listTitle = listTitle;
|
||||
list.basePath = invUrl;
|
||||
|
||||
$scope.orgRelatedUrls = data.related;
|
||||
|
||||
generator.inject(list, { mode: 'edit', scope: $scope, cancelButton: true });
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
SearchInit({
|
||||
scope: $scope,
|
||||
set: 'inventories',
|
||||
list: list,
|
||||
url: invUrl
|
||||
});
|
||||
PaginateInit({
|
||||
scope: $scope,
|
||||
list: list,
|
||||
url: invUrl
|
||||
});
|
||||
|
||||
if ($stateParams.name) {
|
||||
$scope[InventoryList.iterator + 'InputDisable'] = false;
|
||||
$scope[InventoryList.iterator + 'SearchValue'] = $stateParams.name;
|
||||
$scope[InventoryList.iterator + 'SearchField'] = 'name';
|
||||
$scope[InventoryList.iterator + 'SearchFieldLabel'] = InventoryList.fields.name.label;
|
||||
$scope[InventoryList.iterator + 'SearchSelectValue'] = null;
|
||||
}
|
||||
|
||||
if ($stateParams.has_active_failures) {
|
||||
$scope[InventoryList.iterator + 'InputDisable'] = true;
|
||||
$scope[InventoryList.iterator + 'SearchValue'] = $stateParams.has_active_failures;
|
||||
$scope[InventoryList.iterator + 'SearchField'] = 'has_active_failures';
|
||||
$scope[InventoryList.iterator + 'SearchFieldLabel'] = InventoryList.fields.has_active_failures.label;
|
||||
$scope[InventoryList.iterator + 'SearchSelectValue'] = ($stateParams.has_active_failures === 'true') ? {
|
||||
value: 1
|
||||
} : {
|
||||
value: 0
|
||||
};
|
||||
}
|
||||
|
||||
if ($stateParams.has_inventory_sources) {
|
||||
$scope[InventoryList.iterator + 'InputDisable'] = true;
|
||||
$scope[InventoryList.iterator + 'SearchValue'] = $stateParams.has_inventory_sources;
|
||||
$scope[InventoryList.iterator + 'SearchField'] = 'has_inventory_sources';
|
||||
$scope[InventoryList.iterator + 'SearchFieldLabel'] = InventoryList.fields.has_inventory_sources.label;
|
||||
$scope[InventoryList.iterator + 'SearchSelectValue'] = ($stateParams.has_inventory_sources === 'true') ? {
|
||||
value: 1
|
||||
} : {
|
||||
value: 0
|
||||
};
|
||||
}
|
||||
|
||||
if ($stateParams.inventory_sources_with_failures) {
|
||||
// pass a value of true, however this field actually contains an integer value
|
||||
$scope[InventoryList.iterator + 'InputDisable'] = true;
|
||||
$scope[InventoryList.iterator + 'SearchValue'] = $stateParams.inventory_sources_with_failures;
|
||||
$scope[InventoryList.iterator + 'SearchField'] = 'inventory_sources_with_failures';
|
||||
$scope[InventoryList.iterator + 'SearchFieldLabel'] = InventoryList.fields.inventory_sources_with_failures.label;
|
||||
$scope[InventoryList.iterator + 'SearchType'] = 'gtzero';
|
||||
}
|
||||
|
||||
$scope.search(list.iterator);
|
||||
});
|
||||
|
||||
function ellipsis(a) {
|
||||
if (a.length > 20) {
|
||||
return a.substr(0,20) + '...';
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
function attachElem(event, html, title) {
|
||||
var elem = $(event.target).parent();
|
||||
try {
|
||||
elem.tooltip('hide');
|
||||
elem.popover('destroy');
|
||||
}
|
||||
catch(err) {
|
||||
//ignore
|
||||
}
|
||||
$('.popover').each(function() {
|
||||
// remove lingering popover <div>. Seems to be a bug in TB3 RC1
|
||||
$(this).remove();
|
||||
});
|
||||
$('.tooltip').each( function() {
|
||||
// close any lingering tool tipss
|
||||
$(this).hide();
|
||||
});
|
||||
elem.attr({
|
||||
"aw-pop-over": html,
|
||||
"data-popover-title": title,
|
||||
"data-placement": "right" });
|
||||
$compile(elem)($scope);
|
||||
elem.on('shown.bs.popover', function() {
|
||||
$('.popover').each(function() {
|
||||
$compile($(this))($scope); //make nested directives work!
|
||||
});
|
||||
$('.popover-content, .popover-title').click(function() {
|
||||
elem.popover('hide');
|
||||
});
|
||||
});
|
||||
elem.popover('show');
|
||||
}
|
||||
|
||||
if ($scope.removePostRefresh) {
|
||||
$scope.removePostRefresh();
|
||||
}
|
||||
$scope.removePostRefresh = $scope.$on('PostRefresh', function () {
|
||||
//If we got here by deleting an inventory, stop the spinner and cleanup events
|
||||
Wait('stop');
|
||||
try {
|
||||
$('#prompt-modal').modal('hide');
|
||||
}
|
||||
catch(e) {
|
||||
// ignore
|
||||
}
|
||||
$scope.inventories.forEach(function(inventory, idx) {
|
||||
$scope.inventories[idx].launch_class = "";
|
||||
if (inventory.has_inventory_sources) {
|
||||
if (inventory.inventory_sources_with_failures > 0) {
|
||||
$scope.inventories[idx].syncStatus = 'error';
|
||||
$scope.inventories[idx].syncTip = inventory.inventory_sources_with_failures + ' groups with sync failures. Click for details';
|
||||
}
|
||||
else {
|
||||
$scope.inventories[idx].syncStatus = 'successful';
|
||||
$scope.inventories[idx].syncTip = 'No inventory sync failures. Click for details.';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$scope.inventories[idx].syncStatus = 'na';
|
||||
$scope.inventories[idx].syncTip = 'Not configured for inventory sync.';
|
||||
$scope.inventories[idx].launch_class = "btn-disabled";
|
||||
}
|
||||
if (inventory.has_active_failures) {
|
||||
$scope.inventories[idx].hostsStatus = 'error';
|
||||
$scope.inventories[idx].hostsTip = inventory.hosts_with_active_failures + ' hosts with failures. Click for details.';
|
||||
}
|
||||
else if (inventory.total_hosts) {
|
||||
$scope.inventories[idx].hostsStatus = 'successful';
|
||||
$scope.inventories[idx].hostsTip = 'No hosts with failures. Click for details.';
|
||||
}
|
||||
else {
|
||||
$scope.inventories[idx].hostsStatus = 'none';
|
||||
$scope.inventories[idx].hostsTip = 'Inventory contains 0 hosts.';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if ($scope.removeRefreshInventories) {
|
||||
$scope.removeRefreshInventories();
|
||||
}
|
||||
$scope.removeRefreshInventories = $scope.$on('RefreshInventories', function () {
|
||||
// Reflect changes after inventory properties edit completes
|
||||
$scope.search(list.iterator);
|
||||
});
|
||||
|
||||
if ($scope.removeHostSummaryReady) {
|
||||
$scope.removeHostSummaryReady();
|
||||
}
|
||||
$scope.removeHostSummaryReady = $scope.$on('HostSummaryReady', function(e, event, data) {
|
||||
|
||||
var html, title = "Recent Jobs";
|
||||
Wait('stop');
|
||||
if (data.count > 0) {
|
||||
html = "<table class=\"table table-condensed flyout\" style=\"width: 100%\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>";
|
||||
html += "<th>Status</th>";
|
||||
html += "<th>Finished</th>";
|
||||
html += "<th>Name</th>";
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
|
||||
data.results.forEach(function(row) {
|
||||
html += "<tr>\n";
|
||||
html += "<td><a href=\"#/jobs/" + row.id + "\" " + "aw-tool-tip=\"" + row.status.charAt(0).toUpperCase() + row.status.slice(1) +
|
||||
". Click for details\" aw-tip-placement=\"top\"><i class=\"fa icon-job-" + row.status + "\"></i></a></td>\n";
|
||||
html += "<td>" + ($filter('longDate')(row.finished)).replace(/ /,'<br />') + "</td>";
|
||||
html += "<td><a href=\"#/jobs/" + row.id + "\" " + "aw-tool-tip=\"" + row.status.charAt(0).toUpperCase() + row.status.slice(1) +
|
||||
". Click for details\" aw-tip-placement=\"top\">" + ellipsis(row.name) + "</a></td>";
|
||||
html += "</tr>\n";
|
||||
});
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
}
|
||||
else {
|
||||
html = "<p>No recent job data available for this inventory.</p>\n";
|
||||
}
|
||||
attachElem(event, html, title);
|
||||
});
|
||||
|
||||
if ($scope.removeGroupSummaryReady) {
|
||||
$scope.removeGroupSummaryReady();
|
||||
}
|
||||
$scope.removeGroupSummaryReady = $scope.$on('GroupSummaryReady', function(e, event, inventory, data) {
|
||||
var html, title;
|
||||
|
||||
Wait('stop');
|
||||
|
||||
// Build the html for our popover
|
||||
html = "<table class=\"table table-condensed flyout\" style=\"width: 100%\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>";
|
||||
html += "<th>Status</th>";
|
||||
html += "<th>Last Sync</th>";
|
||||
html += "<th>Group</th>";
|
||||
html += "</tr>";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
data.results.forEach( function(row) {
|
||||
if (row.related.last_update) {
|
||||
html += "<tr>";
|
||||
html += "<td><a href=\"\" ng-click=\"viewJob('" + row.related.last_update + "')\" aw-tool-tip=\"" + row.status.charAt(0).toUpperCase() + row.status.slice(1) + ". Click for details\" aw-tip-placement=\"top\"><i class=\"fa icon-job-" + row.status + "\"></i></a></td>";
|
||||
html += "<td>" + ($filter('longDate')(row.last_updated)).replace(/ /,'<br />') + "</td>";
|
||||
html += "<td><a href=\"\" ng-click=\"viewJob('" + row.related.last_update + "')\">" + ellipsis(row.summary_fields.group.name) + "</a></td>";
|
||||
html += "</tr>\n";
|
||||
}
|
||||
else {
|
||||
html += "<tr>";
|
||||
html += "<td><a href=\"\" aw-tool-tip=\"No sync data\" aw-tip-placement=\"top\"><i class=\"fa icon-job-none\"></i></a></td>";
|
||||
html += "<td>NA</td>";
|
||||
html += "<td><a href=\"\">" + ellipsis(row.summary_fields.group.name) + "</a></td>";
|
||||
html += "</tr>\n";
|
||||
}
|
||||
});
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
title = "Sync Status";
|
||||
attachElem(event, html, title);
|
||||
});
|
||||
|
||||
$scope.showGroupSummary = function(event, id) {
|
||||
var inventory;
|
||||
if (!Empty(id)) {
|
||||
inventory = Find({ list: $scope.inventories, key: 'id', val: id });
|
||||
if (inventory.syncStatus !== 'na') {
|
||||
Wait('start');
|
||||
Rest.setUrl(inventory.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5');
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.$emit('GroupSummaryReady', event, inventory, data);
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + inventory.related.inventory_sources + ' failed. GET returned status: ' + status
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.showHostSummary = function(event, id) {
|
||||
var url, inventory;
|
||||
if (!Empty(id)) {
|
||||
inventory = Find({ list: $scope.inventories, key: 'id', val: id });
|
||||
if (inventory.total_hosts > 0) {
|
||||
Wait('start');
|
||||
url = GetBasePath('jobs') + "?type=job&inventory=" + id + "&failed=";
|
||||
url += (inventory.has_active_failures) ? 'true' : "false";
|
||||
url += "&order_by=-finished&page_size=5";
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data) {
|
||||
$scope.$emit('HostSummaryReady', event, data);
|
||||
})
|
||||
.error( function(data, status) {
|
||||
ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. GET returned: ' + status
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.viewJob = function(url) {
|
||||
// Pull the id out of the URL
|
||||
var id = url.replace(/^\//, '').split('/')[3];
|
||||
$state.go('inventorySyncStdout', {id: id});
|
||||
|
||||
};
|
||||
|
||||
$scope.editInventory = function (id) {
|
||||
$state.go('inventories.edit', {inventory_id: id});
|
||||
};
|
||||
|
||||
$scope.manageInventory = function(id){
|
||||
$location.path($location.path() + '/' + id + '/manage');
|
||||
};
|
||||
|
||||
// Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status
|
||||
$scope.viewJobs = function (id) {
|
||||
$location.url('/jobs/?inventory__int=' + id);
|
||||
};
|
||||
|
||||
$scope.viewFailedJobs = function (id) {
|
||||
$location.url('/jobs/?inventory__int=' + id + '&status=failed');
|
||||
};
|
||||
|
||||
$scope.formCancel = function(){
|
||||
$state.go('organizations');
|
||||
};
|
||||
|
||||
}
|
||||
];
|
||||
@ -0,0 +1,91 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$location', '$log',
|
||||
'$stateParams', 'Rest', 'Alert', 'JobTemplateList', 'generateList',
|
||||
'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||
'ProcessErrors', 'GetBasePath', 'JobTemplateForm', 'CredentialList',
|
||||
'LookUpInit', 'InitiatePlaybookRun', 'Wait', '$compile',
|
||||
'$state',
|
||||
function($scope, $rootScope, $location, $log,
|
||||
$stateParams, Rest, Alert, JobTemplateList, GenerateList, Prompt,
|
||||
SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors,
|
||||
GetBasePath, JobTemplateForm, CredentialList, LookUpInit, InitiatePlaybookRun,
|
||||
Wait, $compile, $state) {
|
||||
|
||||
var list,
|
||||
jobTemplateUrl,
|
||||
generator = GenerateList,
|
||||
orgBase = GetBasePath('organizations');
|
||||
|
||||
Rest.setUrl(orgBase + $stateParams.organization_id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
// include name of item in listTitle
|
||||
var listTitle = data.name + "<div class='List-titleLockup'></div>JOB TEMPLATES";
|
||||
|
||||
$scope.$parent.activeCard = parseInt($stateParams.organization_id);
|
||||
$scope.$parent.activeMode = 'job_templates';
|
||||
$scope.organization_name = data.name;
|
||||
$scope.org_id = data.id;
|
||||
|
||||
list = _.cloneDeep(JobTemplateList);
|
||||
list.emptyListText = "This list is populated by job templates added from the <a ui-sref='jobTemplates.add'>Job Templates</a> section";
|
||||
delete list.actions.add;
|
||||
delete list.fieldActions.delete;
|
||||
jobTemplateUrl = "/api/v1/job_templates/?project__organization=" + data.id;
|
||||
list.listTitle = listTitle;
|
||||
list.basePath = jobTemplateUrl;
|
||||
|
||||
$scope.orgRelatedUrls = data.related;
|
||||
|
||||
generator.inject(list, { mode: 'edit', scope: $scope, cancelButton: true });
|
||||
|
||||
if ($scope.removePostRefresh) {
|
||||
$scope.removePostRefresh();
|
||||
}
|
||||
$scope.removePostRefresh = $scope.$on('PostRefresh', function () {
|
||||
// Cleanup after a delete
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
});
|
||||
|
||||
SearchInit({
|
||||
scope: $scope,
|
||||
set: 'job_templates',
|
||||
list: list,
|
||||
url: jobTemplateUrl
|
||||
});
|
||||
PaginateInit({
|
||||
scope: $scope,
|
||||
list: list,
|
||||
url: jobTemplateUrl
|
||||
});
|
||||
$scope.search(list.iterator);
|
||||
});
|
||||
|
||||
$scope.addJobTemplate = function () {
|
||||
$state.transitionTo('jobTemplates.add');
|
||||
};
|
||||
|
||||
$scope.editJobTemplate = function (id) {
|
||||
$state.transitionTo('jobTemplates.edit', {template_id: id});
|
||||
};
|
||||
|
||||
$scope.submitJob = function (id) {
|
||||
InitiatePlaybookRun({ scope: $scope, id: id });
|
||||
};
|
||||
|
||||
$scope.scheduleJob = function (id) {
|
||||
$state.go('jobTemplateSchedules', {id: id});
|
||||
};
|
||||
|
||||
$scope.formCancel = function(){
|
||||
$state.go('organizations');
|
||||
};
|
||||
|
||||
}
|
||||
];
|
||||
@ -0,0 +1,350 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$location', '$log',
|
||||
'$stateParams', 'Rest', 'Alert', 'ProjectList', 'generateList', 'Prompt',
|
||||
'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||
'ProcessErrors', 'GetBasePath', 'SelectionInit', 'ProjectUpdate',
|
||||
'Refresh', 'Wait', 'GetChoices', 'Empty', 'Find',
|
||||
'GetProjectIcon', 'GetProjectToolTip', '$filter', '$state',
|
||||
function($scope, $rootScope, $location, $log, $stateParams,
|
||||
Rest, Alert, ProjectList, GenerateList, Prompt, SearchInit,
|
||||
PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath,
|
||||
SelectionInit, ProjectUpdate, Refresh, Wait, GetChoices, Empty,
|
||||
Find, GetProjectIcon, GetProjectToolTip, $filter, $state) {
|
||||
|
||||
var list,
|
||||
projUrl,
|
||||
choiceCount = 0,
|
||||
orgBase = GetBasePath('organizations'),
|
||||
projBase = GetBasePath('projects'),
|
||||
generator = GenerateList;
|
||||
|
||||
// Go out and get the organization
|
||||
Rest.setUrl(orgBase + $stateParams.organization_id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
// include name of item in listTitle
|
||||
var listTitle = data.name + "<div class='List-titleLockup'></div>PROJECTS";
|
||||
|
||||
$scope.$parent.activeCard = parseInt($stateParams.organization_id);
|
||||
$scope.$parent.activeMode = 'projects';
|
||||
$scope.organization_name = data.name;
|
||||
$scope.org_id = data.id;
|
||||
|
||||
list = _.cloneDeep(ProjectList);
|
||||
list.emptyListText = "This list is populated by projects added from the <a ui-sref='projects.add'>Projects</a> section";
|
||||
delete list.actions.add;
|
||||
delete list.fieldActions.delete;
|
||||
projUrl = data.related.projects;
|
||||
list.listTitle = listTitle;
|
||||
list.basePath = projUrl;
|
||||
|
||||
$scope.orgRelatedUrls = data.related;
|
||||
|
||||
generator.inject(list, { mode: 'edit', scope: $scope, cancelButton: true });
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
if ($scope.removePostRefresh) {
|
||||
$scope.removePostRefresh();
|
||||
}
|
||||
$scope.removePostRefresh = $scope.$on('PostRefresh', function () {
|
||||
Wait('stop');
|
||||
if ($scope.projects) {
|
||||
$scope.projects.forEach(function(project, i) {
|
||||
$scope.projects[i].statusIcon = GetProjectIcon(project.status);
|
||||
$scope.projects[i].statusTip = GetProjectToolTip(project.status);
|
||||
$scope.projects[i].scm_update_tooltip = "Start an SCM update";
|
||||
$scope.projects[i].scm_schedule_tooltip = "Schedule future SCM updates";
|
||||
$scope.projects[i].scm_type_class = "";
|
||||
|
||||
if (project.status === 'failed' && project.summary_fields.last_update && project.summary_fields.last_update.status === 'canceled') {
|
||||
$scope.projects[i].statusTip = 'Canceled. Click for details';
|
||||
}
|
||||
|
||||
if (project.status === 'running' || project.status === 'updating') {
|
||||
$scope.projects[i].scm_update_tooltip = "SCM update currently running";
|
||||
$scope.projects[i].scm_type_class = "btn-disabled";
|
||||
}
|
||||
|
||||
$scope.project_scm_type_options.forEach(function(type) {
|
||||
if (type.value === project.scm_type) {
|
||||
$scope.projects[i].scm_type = type.label;
|
||||
if (type.label === 'Manual') {
|
||||
$scope.projects[i].scm_update_tooltip = 'Manual projects do not require an SCM update';
|
||||
$scope.projects[i].scm_schedule_tooltip = 'Manual projects do not require a schedule';
|
||||
$scope.projects[i].scm_type_class = 'btn-disabled';
|
||||
$scope.projects[i].statusTip = 'Not configured for SCM';
|
||||
$scope.projects[i].statusIcon = 'none';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Handle project update status changes
|
||||
if ($rootScope.removeJobStatusChange) {
|
||||
$rootScope.removeJobStatusChange();
|
||||
}
|
||||
$rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange-projects', function(e, data) {
|
||||
var project;
|
||||
$log.debug(data);
|
||||
if ($scope.projects) {
|
||||
// Assuming we have a list of projects available
|
||||
project = Find({ list: $scope.projects, key: 'id', val: data.project_id });
|
||||
if (project) {
|
||||
// And we found the affected project
|
||||
$log.debug('Received event for project: ' + project.name);
|
||||
$log.debug('Status changed to: ' + data.status);
|
||||
if (data.status === 'successful' || data.status === 'failed') {
|
||||
$scope.search(list.iterator, null, null, null, null, false);
|
||||
}
|
||||
else {
|
||||
project.scm_update_tooltip = "SCM update currently running";
|
||||
project.scm_type_class = "btn-disabled";
|
||||
}
|
||||
project.status = data.status;
|
||||
project.statusIcon = GetProjectIcon(data.status);
|
||||
project.statusTip = GetProjectToolTip(data.status);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if ($scope.removeChoicesHere) {
|
||||
$scope.removeChoicesHere();
|
||||
}
|
||||
$scope.removeChoicesHere = $scope.$on('choicesCompleteProjectList', function () {
|
||||
var opt;
|
||||
|
||||
list.fields.scm_type.searchOptions = $scope.project_scm_type_options;
|
||||
list.fields.status.searchOptions = $scope.project_status_options;
|
||||
|
||||
if ($stateParams.scm_type && $stateParams.status) {
|
||||
// Request coming from home page. User wants all errors for an scm_type
|
||||
projUrl += '?status=' + $stateParams.status;
|
||||
}
|
||||
|
||||
SearchInit({
|
||||
scope: $scope,
|
||||
set: 'projects',
|
||||
list: list,
|
||||
url: projUrl
|
||||
});
|
||||
PaginateInit({
|
||||
scope: $scope,
|
||||
list: list,
|
||||
url: projUrl
|
||||
});
|
||||
|
||||
if ($stateParams.scm_type) {
|
||||
$scope[list.iterator + 'SearchType'] = '';
|
||||
$scope[list.iterator + 'SearchField'] = 'scm_type';
|
||||
$scope[list.iterator + 'SelectShow'] = true;
|
||||
$scope[list.iterator + 'SearchSelectOpts'] = list.fields.scm_type.searchOptions;
|
||||
$scope[list.iterator + 'SearchFieldLabel'] = list.fields.scm_type.label.replace(/<br\>/g, ' ');
|
||||
for (opt in list.fields.scm_type.searchOptions) {
|
||||
if (list.fields.scm_type.searchOptions[opt].value === $stateParams.scm_type) {
|
||||
$scope[list.iterator + 'SearchSelectValue'] = list.fields.scm_type.searchOptions[opt];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ($stateParams.status) {
|
||||
$scope[list.iterator + 'SearchType'] = '';
|
||||
$scope[list.iterator + 'SearchValue'] = $stateParams.status;
|
||||
$scope[list.iterator + 'SearchField'] = 'status';
|
||||
$scope[list.iterator + 'SelectShow'] = true;
|
||||
$scope[list.iterator + 'SearchFieldLabel'] = list.fields.status.label;
|
||||
$scope[list.iterator + 'SearchSelectOpts'] = list.fields.status.searchOptions;
|
||||
for (opt in list.fields.status.searchOptions) {
|
||||
if (list.fields.status.searchOptions[opt].value === $stateParams.status) {
|
||||
$scope[list.iterator + 'SearchSelectValue'] = list.fields.status.searchOptions[opt];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$scope.search(list.iterator);
|
||||
});
|
||||
|
||||
if ($scope.removeChoicesReadyList) {
|
||||
$scope.removeChoicesReadyList();
|
||||
}
|
||||
$scope.removeChoicesReadyList = $scope.$on('choicesReadyProjectList', function () {
|
||||
choiceCount++;
|
||||
if (choiceCount === 2) {
|
||||
$scope.$emit('choicesCompleteProjectList');
|
||||
}
|
||||
});
|
||||
|
||||
// Load options for status --used in search
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: projBase,
|
||||
field: 'status',
|
||||
variable: 'project_status_options',
|
||||
callback: 'choicesReadyProjectList'
|
||||
});
|
||||
|
||||
// Load the list of options for Kind
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: projBase,
|
||||
field: 'scm_type',
|
||||
variable: 'project_scm_type_options',
|
||||
callback: 'choicesReadyProjectList'
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$scope.editProject = function (id) {
|
||||
$state.transitionTo('projects.edit', {id: id});
|
||||
};
|
||||
|
||||
if ($scope.removeGoToJobDetails) {
|
||||
$scope.removeGoToJobDetails();
|
||||
}
|
||||
$scope.removeGoToJobDetails = $scope.$on('GoToJobDetails', function(e, data) {
|
||||
if (data.summary_fields.current_update || data.summary_fields.last_update) {
|
||||
|
||||
Wait('start');
|
||||
|
||||
// Grab the id from summary_fields
|
||||
var id = (data.summary_fields.current_update) ? data.summary_fields.current_update.id : data.summary_fields.last_update.id;
|
||||
|
||||
$state.go('scmUpdateStdout', {id: id});
|
||||
|
||||
} else {
|
||||
Alert('No Updates Available', 'There is no SCM update information available for this project. An update has not yet been ' +
|
||||
' completed. If you have not already done so, start an update for this project.', 'alert-info');
|
||||
}
|
||||
});
|
||||
|
||||
$scope.showSCMStatus = function (id) {
|
||||
// Refresh the project list
|
||||
var project = Find({ list: $scope.projects, key: 'id', val: id });
|
||||
if (Empty(project.scm_type) || project.scm_type === 'Manual') {
|
||||
Alert('No SCM Configuration', 'The selected project is not configured for SCM. To configure for SCM, edit the project and provide SCM settings, ' +
|
||||
'and then run an update.', 'alert-info');
|
||||
} else {
|
||||
// Refresh what we have in memory to insure we're accessing the most recent status record
|
||||
Rest.setUrl(project.url);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.$emit('GoToJobDetails', data);
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Project lookup failed. GET returned: ' + status });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if ($scope.removeCancelUpdate) {
|
||||
$scope.removeCancelUpdate();
|
||||
}
|
||||
$scope.removeCancelUpdate = $scope.$on('Cancel_Update', function (e, url) {
|
||||
// Cancel the project update process
|
||||
Rest.setUrl(url);
|
||||
Rest.post()
|
||||
.success(function () {
|
||||
Alert('SCM Update Cancel', 'Your request to cancel the update was submitted to the task manager.', 'alert-info');
|
||||
$scope.refresh();
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + ' failed. POST status: ' + status });
|
||||
});
|
||||
});
|
||||
|
||||
if ($scope.removeCheckCancel) {
|
||||
$scope.removeCheckCancel();
|
||||
}
|
||||
$scope.removeCheckCancel = $scope.$on('Check_Cancel', function (e, data) {
|
||||
// Check that we 'can' cancel the update
|
||||
var url = data.related.cancel;
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
if (data.can_cancel) {
|
||||
$scope.$emit('Cancel_Update', url);
|
||||
} else {
|
||||
Alert('Cancel Not Allowed', 'Either you do not have access or the SCM update process completed. ' +
|
||||
'Click the <em>Refresh</em> button to view the latest status.', 'alert-info', null, null, null, null, true);
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + ' failed. GET status: ' + status });
|
||||
});
|
||||
});
|
||||
|
||||
$scope.cancelUpdate = function (id, name) {
|
||||
Rest.setUrl(GetBasePath("projects") + id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
if (data.related.current_update) {
|
||||
Rest.setUrl(data.related.current_update);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$scope.$emit('Check_Cancel', data);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + data.related.current_update + ' failed. GET status: ' + status });
|
||||
});
|
||||
} else {
|
||||
Alert('Update Not Found', 'An SCM update does not appear to be running for project: ' + $filter('sanitize')(name) + '. Click the <em>Refresh</em> ' +
|
||||
'button to view the latest status.', 'alert-info',undefined,undefined,undefined,undefined,true);
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to get project failed. GET status: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refresh = function () {
|
||||
$scope.search(list.iterator);
|
||||
};
|
||||
|
||||
$scope.SCMUpdate = function (project_id, event) {
|
||||
try {
|
||||
$(event.target).tooltip('hide');
|
||||
}
|
||||
catch(e) {
|
||||
// ignore
|
||||
}
|
||||
$scope.projects.every(function(project) {
|
||||
if (project.id === project_id) {
|
||||
if (project.scm_type === "Manual" || Empty(project.scm_type)) {
|
||||
// Do not respond. Button appears greyed out as if it is disabled. Not disabled though, because we need mouse over event
|
||||
// to work. So user can click, but we just won't do anything.
|
||||
//Alert('Missing SCM Setup', 'Before running an SCM update, edit the project and provide the SCM access information.', 'alert-info');
|
||||
} else if (project.status === 'updating' || project.status === 'running' || project.status === 'pending') {
|
||||
// Alert('Update in Progress', 'The SCM update process is running. Use the Refresh button to monitor the status.', 'alert-info');
|
||||
} else {
|
||||
ProjectUpdate({ scope: $scope, project_id: project.id });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.editSchedules = function(id) {
|
||||
var project = Find({ list: $scope.projects, key: 'id', val: id });
|
||||
if (project.scm_type === "Manual" || Empty(project.scm_type)) {
|
||||
// Nothing to do
|
||||
}
|
||||
else {
|
||||
$location.path('/projects/' + id + '/schedules');
|
||||
}
|
||||
};
|
||||
|
||||
$scope.formCancel = function(){
|
||||
$state.go('organizations');
|
||||
};
|
||||
|
||||
}
|
||||
];
|
||||
@ -0,0 +1,93 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$location', '$log', '$stateParams',
|
||||
'Rest', 'Alert', 'TeamList', 'generateList', 'Prompt', 'SearchInit', 'PaginateInit',
|
||||
'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'SetTeamListeners', 'GetBasePath',
|
||||
'SelectionInit', 'Wait', '$state', 'Refresh',
|
||||
function($scope, $rootScope, $location, $log, $stateParams,
|
||||
Rest, Alert, TeamList, GenerateList, Prompt, SearchInit, PaginateInit,
|
||||
ReturnToCaller, ClearScope, ProcessErrors, SetTeamListeners, GetBasePath,
|
||||
SelectionInit, Wait, $state, Refresh) {
|
||||
|
||||
var list,
|
||||
teamUrl,
|
||||
orgBase = GetBasePath('organizations'),
|
||||
generator = GenerateList;
|
||||
|
||||
// Go out and get the organization
|
||||
Rest.setUrl(orgBase + $stateParams.organization_id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
// include name of item in listTitle
|
||||
var listTitle = data.name + "<div class='List-titleLockup'></div>TEAMS";
|
||||
|
||||
$scope.$parent.activeCard = parseInt($stateParams.organization_id);
|
||||
$scope.$parent.activeMode = 'teams';
|
||||
$scope.organization_name = data.name;
|
||||
$scope.org_id = data.id;
|
||||
|
||||
list = _.cloneDeep(TeamList);
|
||||
list.emptyListText = "This list is populated by teams added from the <a ui-sref='teams.add'>Teams</a> section";
|
||||
delete list.actions.add;
|
||||
delete list.fieldActions.delete;
|
||||
teamUrl = data.related.teams;
|
||||
list.listTitle = listTitle;
|
||||
list.basePath = teamUrl;
|
||||
|
||||
$scope.orgRelatedUrls = data.related;
|
||||
|
||||
generator.inject(list, { mode: 'edit', scope: $scope, cancelButton: true });
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
$scope.$on("RefreshTeamsList", function() {
|
||||
generator.inject(list, { mode: 'edit', scope: $scope, cancelButton: true });
|
||||
Refresh({
|
||||
scope: $scope,
|
||||
set: 'teams',
|
||||
iterator: 'team',
|
||||
url: GetBasePath('teams') + "?order_by=name&page_size=" + $scope.team_page_size
|
||||
});
|
||||
});
|
||||
|
||||
if ($scope.removePostRefresh) {
|
||||
$scope.removePostRefresh();
|
||||
}
|
||||
$scope.removePostRefresh = $scope.$on('PostRefresh', function () {
|
||||
// After a refresh, populate the organization name on each row
|
||||
var i;
|
||||
if ($scope.teams) {
|
||||
for (i = 0; i < $scope.teams.length; i++) {
|
||||
if ($scope.teams[i].summary_fields.organization) {
|
||||
$scope.teams[i].organization_name = $scope.teams[i].summary_fields.organization.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
SearchInit({
|
||||
scope: $scope,
|
||||
set: 'teams',
|
||||
list: list,
|
||||
url: teamUrl
|
||||
});
|
||||
PaginateInit({
|
||||
scope: $scope,
|
||||
list: list,
|
||||
url: teamUrl
|
||||
});
|
||||
$scope.search(list.iterator);
|
||||
});
|
||||
|
||||
$scope.editTeam = function (id) {
|
||||
$state.transitionTo('teams.edit', {team_id: id});
|
||||
};
|
||||
|
||||
$scope.formCancel = function(){
|
||||
$state.go('organizations');
|
||||
};
|
||||
}
|
||||
];
|
||||
@ -0,0 +1,100 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$stateParams', '$scope', 'UserList', 'Rest', '$state', 'generateList', '$compile',
|
||||
'SearchInit', 'PaginateInit', 'Wait', 'Prompt', 'ProcessErrors', 'GetBasePath',
|
||||
function($stateParams, $scope, UserList, Rest, $state, GenerateList, $compile,
|
||||
SearchInit, PaginateInit, Wait, Prompt, ProcessErrors, GetBasePath) {
|
||||
|
||||
var list,
|
||||
url,
|
||||
generator = GenerateList,
|
||||
orgBase = GetBasePath('organizations');
|
||||
|
||||
Rest.setUrl(orgBase + $stateParams.organization_id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
// include name of item in listTitle
|
||||
var listTitle = data.name + "<div class='List-titleLockup'></div>USERS";
|
||||
|
||||
$scope.$parent.activeCard = parseInt($stateParams.organization_id);
|
||||
$scope.$parent.activeMode = 'users';
|
||||
$scope.organization_name = data.name;
|
||||
$scope.org_id = data.id;
|
||||
|
||||
list = _.cloneDeep(UserList);
|
||||
list.emptyListText = "Please add items to this list";
|
||||
delete list.actions.add;
|
||||
list.searchRowActions = {
|
||||
add: {
|
||||
buttonContent: '+ ADD user',
|
||||
awToolTip: 'Add existing user to organization',
|
||||
actionClass: 'btn List-buttonSubmit',
|
||||
ngClick: 'addUsers()'
|
||||
}
|
||||
};
|
||||
url = data.related.users;
|
||||
list.listTitle = listTitle;
|
||||
list.basePath = url;
|
||||
|
||||
$scope.orgRelatedUrls = data.related;
|
||||
|
||||
generator.inject(list, { mode: 'edit', scope: $scope, cancelButton: true });
|
||||
|
||||
SearchInit({
|
||||
scope: $scope,
|
||||
set: 'users',
|
||||
list: list,
|
||||
url: url
|
||||
});
|
||||
PaginateInit({
|
||||
scope: $scope,
|
||||
list: list,
|
||||
url: url
|
||||
});
|
||||
$scope.search(list.iterator);
|
||||
});
|
||||
|
||||
$scope.addUsers = function () {
|
||||
$compile("<add-users class='AddUsers'></add-users>")($scope);
|
||||
};
|
||||
|
||||
$scope.editUser = function (id) {
|
||||
$state.transitionTo('users.edit', {user_id: id});
|
||||
};
|
||||
|
||||
$scope.deleteUser = function (id, name) {
|
||||
var action = function () {
|
||||
$('#prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
var url = orgBase + $stateParams.organization_id + '/users/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post({
|
||||
id: id,
|
||||
disassociate: true
|
||||
}).success(function () {
|
||||
$scope.search(list.iterator);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: 'Delete',
|
||||
body: '<div class="Prompt-bodyQuery">Are you sure you want to remove the following user from this organization?</div><div class="Prompt-bodyTarget">' + name + '</div>',
|
||||
action: action,
|
||||
actionText: 'DELETE'
|
||||
});
|
||||
};
|
||||
|
||||
$scope.formCancel = function(){
|
||||
$state.go('organizations');
|
||||
};
|
||||
|
||||
}
|
||||
];
|
||||
@ -1,100 +0,0 @@
|
||||
export default ['$compile', '$scope', '$stateParams', '$state', 'Rest', 'UserList', 'InventoryList', 'JobTemplateList', 'TeamList', 'ProjectList', 'generateList', 'SearchInit', 'PaginateInit', function($compile, $scope, $stateParams, $state, Rest, UserList, InventoryList, JobTemplateList, TeamList, ProjectList, GenerateList, SearchInit, PaginateInit) {
|
||||
|
||||
var getList = function(mode) {
|
||||
var list = {};
|
||||
if (mode === 'users') {
|
||||
list = _.cloneDeep(UserList);
|
||||
list.emptyListText = "Please add items to this list";
|
||||
list.actions.add.label = "Add a user to the organization";
|
||||
list.actions.add.buttonContent = '+ ADD user';
|
||||
list.actions.add.awToolTip = 'Add existing user to organization';
|
||||
list.actions.add.ngClick = 'addUsers()';
|
||||
} else if (mode === 'inventories') {
|
||||
list = _.cloneDeep(InventoryList);
|
||||
list.emptyListText = "List is empty";
|
||||
delete list.actions.add;
|
||||
} else if (mode === 'job_templates') {
|
||||
list = _.cloneDeep(JobTemplateList);
|
||||
list.emptyListText = "List is empty";
|
||||
delete list.actions.add;
|
||||
} else if (mode === 'teams') {
|
||||
list = _.cloneDeep(TeamList);
|
||||
list.emptyListText = "List is empty";
|
||||
delete list.actions.add;
|
||||
} else if (mode === 'projects') {
|
||||
list = _.cloneDeep(ProjectList);
|
||||
list.emptyListText = "List is empty";
|
||||
delete list.actions.add;
|
||||
} else if (mode === 'admins') {
|
||||
list = _.cloneDeep(UserList);
|
||||
list.emptyListText = "Please add items to this list";
|
||||
list.actions.add.buttonContent = '+ ADD administrator';
|
||||
list.actions.add.awToolTip = 'Add existing user to organization as administrator';
|
||||
list.actions.add.ngClick = 'addUsers()';
|
||||
}
|
||||
return list;
|
||||
};
|
||||
|
||||
var getUrl = function(mode, data) {
|
||||
var url = "";
|
||||
if (mode === 'users') {
|
||||
url = data.related.users;
|
||||
} else if (mode === 'inventories') {
|
||||
url = data.related.inventories;
|
||||
} else if (mode === 'job_templates') {
|
||||
url = "/api/v1/job_templates/?project__organization=" + data.id;
|
||||
} else if (mode === 'teams') {
|
||||
url = data.related.teams;
|
||||
} else if (mode === 'projects') {
|
||||
url = data.related.projects;
|
||||
} else if (mode === 'admins') {
|
||||
url = data.related.admins;
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
Rest.setUrl("/api/v1/organizations/" + $stateParams.organization_id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
// include name of item in listTitle
|
||||
var mode = $state.current.name.split(".")[1],
|
||||
listTitle = data.name +
|
||||
"<div class='List-titleLockup'></div>" +
|
||||
mode.replace('_', ' '),
|
||||
list,
|
||||
url,
|
||||
generator = GenerateList;
|
||||
$scope.$parent.activeCard = parseInt($stateParams.organization_id);
|
||||
$scope.$parent.activeMode = mode;
|
||||
$scope.org_name = data.name;
|
||||
$scope.org_id = data.id;
|
||||
var listMode = (mode === 'admins') ? 'users' : mode;
|
||||
|
||||
list = getList(mode);
|
||||
url = getUrl(mode, data);
|
||||
list.listTitle = listTitle;
|
||||
list.basePath = url;
|
||||
|
||||
$scope.orgRelatedUrls = data.related;
|
||||
|
||||
generator
|
||||
.inject(list, { mode: 'edit', scope: $scope });
|
||||
|
||||
$scope.addUsers = function () {
|
||||
$compile("<add-users class='AddUsers'></add-users>")($scope);
|
||||
};
|
||||
|
||||
SearchInit({
|
||||
scope: $scope,
|
||||
set: listMode,
|
||||
list: list,
|
||||
url: url
|
||||
});
|
||||
PaginateInit({
|
||||
scope: $scope,
|
||||
list: list,
|
||||
url: url
|
||||
});
|
||||
$scope.search(list.iterator);
|
||||
});
|
||||
}];
|
||||
@ -5,14 +5,19 @@
|
||||
*************************************************/
|
||||
|
||||
import {templateUrl} from '../../shared/template-url/template-url.factory';
|
||||
import OrganizationsLinkout from './organizations-linkout.controller';
|
||||
import OrganizationsAdmins from './controllers/organizations-admins.controller';
|
||||
import OrganizationsInventories from './controllers/organizations-inventories.controller';
|
||||
import OrganizationsJobTemplates from './controllers/organizations-job-templates.controller';
|
||||
import OrganizationsProjects from './controllers/organizations-projects.controller';
|
||||
import OrganizationsTeams from './controllers/organizations-teams.controller';
|
||||
import OrganizationsUsers from './controllers/organizations-users.controller';
|
||||
|
||||
export default [
|
||||
{
|
||||
name: 'organizations.users',
|
||||
route: '/:organization_id/users',
|
||||
templateUrl: templateUrl('organizations/linkout/organizations-linkout'),
|
||||
controller: OrganizationsLinkout,
|
||||
controller: OrganizationsUsers,
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'organization'
|
||||
@ -20,9 +25,9 @@ export default [
|
||||
ncyBreadcrumb: {
|
||||
parent: function($scope) {
|
||||
$scope.$parent.$emit("ReloadOrgListView");
|
||||
return "setup";
|
||||
return "organizations.edit";
|
||||
},
|
||||
label: "ORGANIZATIONS"
|
||||
label: "USERS"
|
||||
},
|
||||
resolve: {
|
||||
features: ['FeaturesService', function(FeaturesService) {
|
||||
@ -34,7 +39,7 @@ export default [
|
||||
name: 'organizations.teams',
|
||||
route: '/:organization_id/teams',
|
||||
templateUrl: templateUrl('organizations/linkout/organizations-linkout'),
|
||||
controller: OrganizationsLinkout,
|
||||
controller: OrganizationsTeams,
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'organization'
|
||||
@ -42,9 +47,9 @@ export default [
|
||||
ncyBreadcrumb: {
|
||||
parent: function($scope) {
|
||||
$scope.$parent.$emit("ReloadOrgListView");
|
||||
return "setup";
|
||||
return "organizations.edit";
|
||||
},
|
||||
label: "ORGANIZATIONS"
|
||||
label: "TEAMS"
|
||||
},
|
||||
resolve: {
|
||||
features: ['FeaturesService', function(FeaturesService) {
|
||||
@ -56,7 +61,7 @@ export default [
|
||||
name: 'organizations.inventories',
|
||||
route: '/:organization_id/inventories',
|
||||
templateUrl: templateUrl('organizations/linkout/organizations-linkout'),
|
||||
controller: OrganizationsLinkout,
|
||||
controller: OrganizationsInventories,
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'organization'
|
||||
@ -64,9 +69,9 @@ export default [
|
||||
ncyBreadcrumb: {
|
||||
parent: function($scope) {
|
||||
$scope.$parent.$emit("ReloadOrgListView");
|
||||
return "setup";
|
||||
return "organizations.edit";
|
||||
},
|
||||
label: "ORGANIZATIONS"
|
||||
label: "INVENTORIES"
|
||||
},
|
||||
resolve: {
|
||||
features: ['FeaturesService', function(FeaturesService) {
|
||||
@ -78,7 +83,7 @@ export default [
|
||||
name: 'organizations.projects',
|
||||
route: '/:organization_id/projects',
|
||||
templateUrl: templateUrl('organizations/linkout/organizations-linkout'),
|
||||
controller: OrganizationsLinkout,
|
||||
controller: OrganizationsProjects,
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'organization'
|
||||
@ -86,9 +91,9 @@ export default [
|
||||
ncyBreadcrumb: {
|
||||
parent: function($scope) {
|
||||
$scope.$parent.$emit("ReloadOrgListView");
|
||||
return "setup";
|
||||
return "organizations.edit";
|
||||
},
|
||||
label: "ORGANIZATIONS"
|
||||
label: "PROJECTS"
|
||||
},
|
||||
resolve: {
|
||||
features: ['FeaturesService', function(FeaturesService) {
|
||||
@ -100,7 +105,7 @@ export default [
|
||||
name: 'organizations.job_templates',
|
||||
route: '/:organization_id/job_templates',
|
||||
templateUrl: templateUrl('organizations/linkout/organizations-linkout'),
|
||||
controller: OrganizationsLinkout,
|
||||
controller: OrganizationsJobTemplates,
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'organization'
|
||||
@ -108,9 +113,9 @@ export default [
|
||||
ncyBreadcrumb: {
|
||||
parent: function($scope) {
|
||||
$scope.$parent.$emit("ReloadOrgListView");
|
||||
return "setup";
|
||||
return "organizations.edit";
|
||||
},
|
||||
label: "ORGANIZATIONS"
|
||||
label: "JOB TEMPLATES"
|
||||
},
|
||||
resolve: {
|
||||
features: ['FeaturesService', function(FeaturesService) {
|
||||
@ -122,7 +127,7 @@ export default [
|
||||
name: 'organizations.admins',
|
||||
route: '/:organization_id/admins',
|
||||
templateUrl: templateUrl('organizations/linkout/organizations-linkout'),
|
||||
controller: OrganizationsLinkout,
|
||||
controller: OrganizationsAdmins,
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'organization'
|
||||
@ -130,9 +135,9 @@ export default [
|
||||
ncyBreadcrumb: {
|
||||
parent: function($scope) {
|
||||
$scope.$parent.$emit("ReloadOrgListView");
|
||||
return "setup";
|
||||
return "organizations.edit";
|
||||
},
|
||||
label: "ORGANIZATIONS"
|
||||
label: "ADMINS"
|
||||
},
|
||||
resolve: {
|
||||
features: ['FeaturesService', function(FeaturesService) {
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-8 col-md-12 col-sm-12 col-xs-12">
|
||||
<div class="col-lg-7 col-md-12 col-sm-12 col-xs-12">
|
||||
<div class="TagSearch-tagSection">
|
||||
<div class="TagSearch-flexContainer">
|
||||
<div class="TagSearch-tagContainer"
|
||||
|
||||
@ -99,9 +99,9 @@
|
||||
import {templateUrl} from '../../shared/template-url/template-url.factory';
|
||||
|
||||
export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'PaginateWidget', 'Attr', 'Icon', 'getSearchHtml',
|
||||
'Column', 'DropDown', 'NavigationLink', 'SelectIcon',
|
||||
'Column', 'DropDown', 'NavigationLink', 'SelectIcon', 'ActionButton',
|
||||
function ($location, $compile, $rootScope, SearchWidget, PaginateWidget, Attr, Icon, getSearchHtml, Column, DropDown, NavigationLink,
|
||||
SelectIcon) {
|
||||
SelectIcon, ActionButton) {
|
||||
return {
|
||||
|
||||
setList: function (list) {
|
||||
@ -363,10 +363,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate
|
||||
html += "<div class=\"List-well\">\n";
|
||||
}
|
||||
|
||||
// Show the "no items" box when loading is done and the user isn't actively searching and there are no results
|
||||
html += "<div class=\"List-noItems\" ng-show=\"" + list.iterator + "Loading == false && " + list.iterator + "_active_search == false && " + list.iterator + "_total_rows < 1\">";
|
||||
html += (list.emptyListText) ? list.emptyListText : "PLEASE ADD ITEMS TO THIS LIST";
|
||||
html += "</div>";
|
||||
html += (list.searchRowActions) ? "<div class='row'><div class=\"col-lg-8 col-md-8 col-sm-8 col-xs-12\">" : "";
|
||||
if (options.showSearch=== undefined || options.showSearch === true) {
|
||||
var tagSearch = getSearchHtml
|
||||
.inject(getSearchHtml.getList(list),
|
||||
@ -381,12 +378,35 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate
|
||||
${tagSearch}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
if(list.searchRowActions) {
|
||||
html += "</div><div class='col-lg-4 col-md-4 col-sm-4 col-xs-12'>";
|
||||
|
||||
var actionButtons = "";
|
||||
Object.keys(list.searchRowActions || {})
|
||||
.forEach(act => {
|
||||
actionButtons += ActionButton(list.searchRowActions[act]);
|
||||
});
|
||||
html += `
|
||||
<div class=\"list-actions\">
|
||||
${actionButtons}
|
||||
</div>
|
||||
`;
|
||||
html += "</div></div>";
|
||||
}
|
||||
|
||||
if (options.showSearch=== undefined || options.showSearch === true) {
|
||||
// Message for when a search returns no results. This should only get shown after a search is executed with no results.
|
||||
html += "<div class=\"row\" ng-show=\"" + list.iterator + "Loading == false && " + list.iterator + "_active_search == true && " + list.name + ".length == 0\">\n";
|
||||
html += "<div class=\"col-lg-12 List-searchNoResults\">No records matched your search.</div>\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
// Show the "no items" box when loading is done and the user isn't actively searching and there are no results
|
||||
html += "<div class=\"List-noItems\" ng-show=\"" + list.iterator + "Loading == false && " + list.iterator + "_active_search == false && " + list.iterator + "_total_rows < 1\">";
|
||||
html += (list.emptyListText) ? list.emptyListText : "PLEASE ADD ITEMS TO THIS LIST";
|
||||
html += "</div>";
|
||||
|
||||
// Add a title and optionally a close button (used on Inventory->Groups)
|
||||
if (options.mode !== 'lookup' && list.showTitle) {
|
||||
html += "<div class=\"form-title\">";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user