mirror of
https://github.com/ansible/awx.git
synced 2026-01-17 04:31:21 -03:30
Modularized what was left in the controllers directory
This commit is contained in:
parent
986ef9e2eb
commit
7d23160c1a
@ -41,9 +41,6 @@ import './helpers';
|
||||
import './lists';
|
||||
import './widgets';
|
||||
import './filters';
|
||||
import { Home } from './controllers/Home';
|
||||
import { SocketsController } from './controllers/Sockets';
|
||||
import { CredentialsAdd, CredentialsEdit, CredentialsList } from './controllers/Credentials';
|
||||
import portalMode from './portal-mode/main';
|
||||
import systemTracking from './system-tracking/main';
|
||||
import inventories from './inventories/main';
|
||||
@ -62,7 +59,7 @@ import mainMenu from './main-menu/main';
|
||||
import breadCrumb from './bread-crumb/main';
|
||||
import browserData from './browser-data/main';
|
||||
import configuration from './configuration/main';
|
||||
import dashboard from './dashboard/main';
|
||||
import home from './home/main';
|
||||
import moment from './shared/moment/main';
|
||||
import login from './login/main';
|
||||
import activityStream from './activity-stream/main';
|
||||
@ -70,9 +67,9 @@ import standardOut from './standard-out/main';
|
||||
import Templates from './templates/main';
|
||||
import credentials from './credentials/main';
|
||||
import jobs from './jobs/main';
|
||||
import { ProjectsList, ProjectsAdd, ProjectsEdit } from './controllers/Projects';
|
||||
import { UsersList, UsersAdd, UsersEdit } from './controllers/Users';
|
||||
import { TeamsList, TeamsAdd, TeamsEdit } from './controllers/Teams';
|
||||
import teams from './teams/main';
|
||||
import users from './users/main';
|
||||
import projects from './projects/main';
|
||||
|
||||
import RestServices from './rest/main';
|
||||
import access from './access/main';
|
||||
@ -85,7 +82,6 @@ import config from './shared/config/main';
|
||||
import './login/authenticationServices/pendo/ng-pendo';
|
||||
import footer from './footer/main';
|
||||
import scheduler from './scheduler/main';
|
||||
import { N_ } from './i18n';
|
||||
|
||||
var tower = angular.module('Tower', [
|
||||
// how to add CommonJS / AMD third-party dependencies:
|
||||
@ -119,7 +115,7 @@ var tower = angular.module('Tower', [
|
||||
setupMenu.name,
|
||||
mainMenu.name,
|
||||
breadCrumb.name,
|
||||
dashboard.name,
|
||||
home.name,
|
||||
moment.name,
|
||||
login.name,
|
||||
activityStream.name,
|
||||
@ -135,6 +131,9 @@ var tower = angular.module('Tower', [
|
||||
config.name,
|
||||
credentials.name,
|
||||
jobs.name,
|
||||
teams.name,
|
||||
users.name,
|
||||
projects.name,
|
||||
//'templates',
|
||||
'Utilities',
|
||||
'OrganizationFormDefinition',
|
||||
@ -227,10 +226,9 @@ var tower = angular.module('Tower', [
|
||||
});
|
||||
}])
|
||||
.config(['$urlRouterProvider', '$breadcrumbProvider', 'QuerySetProvider',
|
||||
'$urlMatcherFactoryProvider', 'stateDefinitionsProvider', '$stateProvider',
|
||||
'$urlMatcherFactoryProvider',
|
||||
function($urlRouterProvider, $breadcrumbProvider, QuerySet,
|
||||
$urlMatcherFactoryProvider, stateDefinitionsProvider, $stateProvider) {
|
||||
let stateDefinitions = stateDefinitionsProvider.$get();
|
||||
$urlMatcherFactoryProvider) {
|
||||
$urlMatcherFactoryProvider.strictMode(false);
|
||||
$breadcrumbProvider.setOptions({
|
||||
templateUrl: urlPrefix + 'partials/breadcrumb.html'
|
||||
@ -266,109 +264,6 @@ var tower = angular.module('Tower', [
|
||||
// $stateProvider.stateRegistry.onStatesChanged((event, states) =>{
|
||||
// console.log(event, states)
|
||||
// })
|
||||
|
||||
|
||||
// lazily generate a tree of substates which will replace this node in ui-router's stateRegistry
|
||||
// see: stateDefinition.factory for usage documentation
|
||||
$stateProvider.state({
|
||||
name: 'projects',
|
||||
url: '/projects',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
parent: 'projects', // top-most node in the generated tree (will replace this state definition)
|
||||
modes: ['add', 'edit'],
|
||||
list: 'ProjectList',
|
||||
form: 'ProjectsForm',
|
||||
controllers: {
|
||||
list: ProjectsList, // DI strings or objects
|
||||
add: ProjectsAdd,
|
||||
edit: ProjectsEdit
|
||||
},
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'project',
|
||||
socket: {
|
||||
"groups": {
|
||||
"jobs": ["status_changed"]
|
||||
}
|
||||
}
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: N_('PROJECTS')
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$stateProvider.state({
|
||||
name: 'credentials',
|
||||
url: '/credentials',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
parent: 'credentials',
|
||||
modes: ['add', 'edit'],
|
||||
list: 'CredentialList',
|
||||
form: 'CredentialForm',
|
||||
controllers: {
|
||||
list: CredentialsList,
|
||||
add: CredentialsAdd,
|
||||
edit: CredentialsEdit
|
||||
},
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'credential'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: 'setup',
|
||||
label: N_('CREDENTIALS')
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$stateProvider.state({
|
||||
name: 'teams',
|
||||
url: '/teams',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
parent: 'teams',
|
||||
modes: ['add', 'edit'],
|
||||
list: 'TeamList',
|
||||
form: 'TeamForm',
|
||||
controllers: {
|
||||
list: TeamsList,
|
||||
add: TeamsAdd,
|
||||
edit: TeamsEdit
|
||||
},
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'team'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: 'setup',
|
||||
label: N_('TEAMS')
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$stateProvider.state({
|
||||
name: 'users',
|
||||
url: '/users',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
parent: 'users',
|
||||
modes: ['add', 'edit'],
|
||||
list: 'UserList',
|
||||
form: 'UserForm',
|
||||
controllers: {
|
||||
list: UsersList,
|
||||
add: UsersAdd,
|
||||
edit: UsersEdit
|
||||
},
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'user'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: 'setup',
|
||||
label: N_('USERS')
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
])
|
||||
.run(['$stateExtender', '$q', '$compile', '$cookieStore', '$rootScope', '$log', '$stateParams',
|
||||
@ -392,68 +287,6 @@ var tower = angular.module('Tower', [
|
||||
$log.debug(`$state.defaultErrorHandler: ${error}`);
|
||||
});
|
||||
|
||||
$stateExtender.addState({
|
||||
name: 'dashboard',
|
||||
url: '/home',
|
||||
templateUrl: urlPrefix + 'partials/home.html',
|
||||
controller: Home,
|
||||
params: { licenseMissing: null },
|
||||
data: {
|
||||
activityStream: true,
|
||||
refreshButton: true,
|
||||
socket: {
|
||||
"groups": {
|
||||
"jobs": ["status_changed"]
|
||||
}
|
||||
},
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: N_("DASHBOARD")
|
||||
},
|
||||
resolve: {
|
||||
graphData: ['$q', 'jobStatusGraphData', '$rootScope',
|
||||
function($q, jobStatusGraphData, $rootScope) {
|
||||
return $rootScope.featuresConfigured.promise.then(function() {
|
||||
return $q.all({
|
||||
jobStatus: jobStatusGraphData.get("month", "all"),
|
||||
});
|
||||
});
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
$stateExtender.addState({
|
||||
name: 'userCredentials',
|
||||
url: '/users/:user_id/credentials',
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: CredentialsList
|
||||
});
|
||||
|
||||
$stateExtender.addState({
|
||||
name: 'userCredentialAdd',
|
||||
url: '/users/:user_id/credentials/add',
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: CredentialsAdd
|
||||
});
|
||||
|
||||
$stateExtender.addState({
|
||||
name: 'teamUserCredentialEdit',
|
||||
url: '/teams/:user_id/credentials/:credential_id',
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: CredentialsEdit
|
||||
});
|
||||
|
||||
$stateExtender.addState({
|
||||
name: 'sockets',
|
||||
url: '/sockets',
|
||||
templateUrl: urlPrefix + 'partials/sockets.html',
|
||||
controller: SocketsController,
|
||||
ncyBreadcrumb: {
|
||||
label: N_('SOCKETS')
|
||||
}
|
||||
});
|
||||
|
||||
function activateTab() {
|
||||
// Make the correct tab active
|
||||
var base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
|
||||
@ -1,631 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Credentials
|
||||
* @description This controller's for the credentials page
|
||||
*/
|
||||
|
||||
|
||||
export function CredentialsList($scope, $rootScope, $location, $log,
|
||||
$stateParams, Rest, Alert, CredentialList, Prompt, ClearScope,
|
||||
ProcessErrors, GetBasePath, Wait, $state, $filter, rbacUiControlService, Dataset,
|
||||
i18n) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var list = CredentialList,
|
||||
defaultUrl = GetBasePath('credentials');
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
rbacUiControlService.canAdd('credentials')
|
||||
.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;
|
||||
|
||||
$scope.selected = [];
|
||||
}
|
||||
|
||||
$scope.$on(`${list.iterator}_options`, function(event, data){
|
||||
$scope.options = data.data.actions.GET;
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
$scope.$watchCollection(`${$scope.list.name}`, function() {
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
// iterate over the list and add fields like type label, after the
|
||||
// OPTIONS request returns, or the list is sorted/paginated/searched
|
||||
function optionsRequestDataProcessing(){
|
||||
if ($scope[list.name] !== undefined) {
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
|
||||
// Set the item type label
|
||||
if (list.fields.kind && $scope.options &&
|
||||
$scope.options.hasOwnProperty('kind')) {
|
||||
$scope.options.kind.choices.every(function(choice) {
|
||||
if (choice[0] === item.kind) {
|
||||
itm.kind_label = choice[1];
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.addCredential = function() {
|
||||
$state.go('credentials.add');
|
||||
};
|
||||
|
||||
$scope.editCredential = function(id) {
|
||||
$state.go('credentials.edit', { credential_id: id });
|
||||
};
|
||||
|
||||
$scope.deleteCredential = function(id, name) {
|
||||
var action = function() {
|
||||
$('#prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function() {
|
||||
if (parseInt($state.params.credential_id) === id) {
|
||||
$state.go("^", null, { reload: true });
|
||||
} else {
|
||||
$state.go('.', null, {reload: true});
|
||||
}
|
||||
Wait('stop');
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: i18n._('Delete'),
|
||||
body: '<div class="Prompt-bodyQuery">' + i18n._('Are you sure you want to delete the credential below?') + '</div><div class="Prompt-bodyTarget">' + $filter('sanitize')(name) + '</div>',
|
||||
action: action,
|
||||
actionText: i18n._('DELETE')
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
CredentialsList.$inject = ['$scope', '$rootScope', '$location', '$log',
|
||||
'$stateParams', 'Rest', 'Alert', 'CredentialList', 'Prompt', 'ClearScope',
|
||||
'ProcessErrors', 'GetBasePath', 'Wait', '$state', '$filter', 'rbacUiControlService', 'Dataset', 'i18n'
|
||||
];
|
||||
|
||||
|
||||
export function CredentialsAdd($scope, $rootScope, $compile, $location, $log,
|
||||
$stateParams, CredentialForm, GenerateForm, Rest, Alert, ProcessErrors,
|
||||
ClearScope, GetBasePath, GetChoices, Empty, KindChange, BecomeMethodChange,
|
||||
OwnerChange, FormSave, $state, CreateSelect2, i18n) {
|
||||
ClearScope();
|
||||
|
||||
// Inject dynamic view
|
||||
var form = CredentialForm,
|
||||
defaultUrl = GetBasePath('credentials'),
|
||||
url;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
// Load the list of options for Kind
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'kind',
|
||||
variable: 'credential_kind_options'
|
||||
});
|
||||
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'become_method',
|
||||
variable: 'become_options'
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: '#credential_become_method',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: '#credential_kind',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
// apply form definition's default field values
|
||||
GenerateForm.applyDefaults(form, $scope);
|
||||
|
||||
$scope.keyEntered = false;
|
||||
$scope.permissionsTooltip = i18n._('Please save before assigning permissions');
|
||||
|
||||
// determine if the currently logged-in user may share this credential
|
||||
// previous commentary said: "$rootScope.current_user isn't available because a call to the config endpoint hasn't finished resolving yet"
|
||||
// I'm 99% sure this state's will never resolve block will be rejected if setup surrounding config endpoint hasn't completed
|
||||
if ($rootScope.current_user && $rootScope.current_user.is_superuser) {
|
||||
$scope.canShareCredential = true;
|
||||
} else {
|
||||
Rest.setUrl(`/api/v1/users/${$rootScope.current_user.id}/admin_of_organizations`);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.canShareCredential = (data.count) ? true : false;
|
||||
}).error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to find if users is admin of org' + status });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!Empty($stateParams.user_id)) {
|
||||
// Get the username based on incoming route
|
||||
$scope.owner = 'user';
|
||||
$scope.user = $stateParams.user_id;
|
||||
OwnerChange({ scope: $scope });
|
||||
url = GetBasePath('users') + $stateParams.user_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.user_username = data.username;
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve user. GET status: ' + status });
|
||||
});
|
||||
} else if (!Empty($stateParams.team_id)) {
|
||||
// Get the username based on incoming route
|
||||
$scope.owner = 'team';
|
||||
$scope.team = $stateParams.team_id;
|
||||
OwnerChange({ scope: $scope });
|
||||
url = GetBasePath('teams') + $stateParams.team_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.team_name = data.name;
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve team. GET status: ' + status });
|
||||
});
|
||||
} else {
|
||||
// default type of owner to a user
|
||||
$scope.owner = 'user';
|
||||
OwnerChange({ scope: $scope });
|
||||
}
|
||||
|
||||
$scope.$watch("ssh_key_data", function(val) {
|
||||
if (val === "" || val === null || val === undefined) {
|
||||
$scope.keyEntered = false;
|
||||
$scope.ssh_key_unlock_ask = false;
|
||||
$scope.ssh_key_unlock = "";
|
||||
} else {
|
||||
$scope.keyEntered = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Handle Kind change
|
||||
$scope.kindChange = function() {
|
||||
KindChange({ scope: $scope, form: form, reset: true });
|
||||
};
|
||||
|
||||
$scope.becomeMethodChange = function() {
|
||||
BecomeMethodChange({ scope: $scope });
|
||||
};
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
FormSave({ scope: $scope, mode: 'add' });
|
||||
}
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('credentials');
|
||||
};
|
||||
|
||||
// Password change
|
||||
$scope.clearPWConfirm = function(fld) {
|
||||
// If password value changes, make sure password_confirm must be re-entered
|
||||
$scope[fld] = '';
|
||||
$scope[form.name + '_form'][fld].$setValidity('awpassmatch', false);
|
||||
};
|
||||
|
||||
// Respond to 'Ask at runtime?' checkbox
|
||||
$scope.ask = function(fld, associated) {
|
||||
if ($scope[fld + '_ask']) {
|
||||
$scope[fld] = 'ASK';
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "text");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Hide");
|
||||
if (associated !== "undefined") {
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "password");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Show");
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
}
|
||||
} else {
|
||||
$scope[fld] = '';
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "password");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Show");
|
||||
if (associated !== "undefined") {
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "text");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Hide");
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Click clear button
|
||||
$scope.clear = function(fld, associated) {
|
||||
$scope[fld] = '';
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
$scope[form.name + '_form'].$setDirty();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
CredentialsAdd.$inject = ['$scope', '$rootScope', '$compile', '$location',
|
||||
'$log', '$stateParams', 'CredentialForm', 'GenerateForm', 'Rest', 'Alert',
|
||||
'ProcessErrors', 'ClearScope', 'GetBasePath', 'GetChoices', 'Empty', 'KindChange', 'BecomeMethodChange',
|
||||
'OwnerChange', 'FormSave', '$state', 'CreateSelect2', 'i18n'
|
||||
];
|
||||
|
||||
export function CredentialsEdit($scope, $rootScope, $compile, $location, $log,
|
||||
$stateParams, CredentialForm, Rest, Alert, ProcessErrors, ClearScope, Prompt,
|
||||
GetBasePath, GetChoices, KindChange, BecomeMethodChange, Empty, OwnerChange, FormSave, Wait,
|
||||
$state, CreateSelect2, Authorization, i18n) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var defaultUrl = GetBasePath('credentials'),
|
||||
form = CredentialForm,
|
||||
base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
master = {},
|
||||
id = $stateParams.credential_id;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.id = id;
|
||||
$scope.$watch('credential_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||
if (val === false) {
|
||||
$scope.canAdd = false;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.canShareCredential = false;
|
||||
Wait('start');
|
||||
if (!$rootScope.current_user) {
|
||||
Authorization.restoreUserInfo();
|
||||
}
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'kind',
|
||||
variable: 'credential_kind_options',
|
||||
callback: 'choicesReadyCredential'
|
||||
});
|
||||
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'become_method',
|
||||
variable: 'become_options'
|
||||
});
|
||||
|
||||
if ($rootScope.current_user && $rootScope.current_user.is_superuser) {
|
||||
$scope.canShareCredential = true;
|
||||
} else {
|
||||
Rest.setUrl(`/api/v1/users/${$rootScope.current_user.id}/admin_of_organizations`);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.canShareCredential = (data.count) ? true : false;
|
||||
Wait('stop');
|
||||
}).error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to find if users is admin of org' + status });
|
||||
});
|
||||
}
|
||||
|
||||
$scope.$watch('organization', function(val) {
|
||||
if (val === undefined) {
|
||||
$scope.permissionsTooltip = i18n._('Credentials are only shared within an organization. Assign credentials to an organization to delegate credential permissions. The organization cannot be edited after credentials are assigned.');
|
||||
} else {
|
||||
$scope.permissionsTooltip = '';
|
||||
}
|
||||
});
|
||||
|
||||
setAskCheckboxes();
|
||||
OwnerChange({ scope: $scope });
|
||||
$scope.$watch("ssh_key_data", function(val) {
|
||||
if (val === "" || val === null || val === undefined) {
|
||||
$scope.keyEntered = false;
|
||||
$scope.ssh_key_unlock_ask = false;
|
||||
$scope.ssh_key_unlock = "";
|
||||
} else {
|
||||
$scope.keyEntered = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setAskCheckboxes() {
|
||||
var fld, i;
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].type === 'sensitive' && $scope[fld] === 'ASK') {
|
||||
// turn on 'ask' checkbox for password fields with value of 'ASK'
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "text");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Hide");
|
||||
$("#" + fld + "-clear-btn").attr("disabled", "disabled");
|
||||
$scope[fld + '_ask'] = true;
|
||||
} else {
|
||||
$scope[fld + '_ask'] = false;
|
||||
$("#" + fld + "-clear-btn").removeAttr("disabled");
|
||||
}
|
||||
master[fld + '_ask'] = $scope[fld + '_ask'];
|
||||
}
|
||||
|
||||
// Set kind field to the correct option
|
||||
for (i = 0; i < $scope.credential_kind_options.length; i++) {
|
||||
if ($scope.kind === $scope.credential_kind_options[i].value) {
|
||||
$scope.kind = $scope.credential_kind_options[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($scope.removeChoicesReady) {
|
||||
$scope.removeChoicesReady();
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReadyCredential', function() {
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(defaultUrl + ':id/');
|
||||
Rest.get({ params: { id: id } })
|
||||
.success(function(data) {
|
||||
if (data && data.summary_fields &&
|
||||
data.summary_fields.organization &&
|
||||
data.summary_fields.organization.id) {
|
||||
$scope.needsRoleList = true;
|
||||
} else {
|
||||
$scope.needsRoleList = false;
|
||||
}
|
||||
|
||||
$scope.credential_name = data.name;
|
||||
|
||||
var i, fld;
|
||||
|
||||
|
||||
for (fld in form.fields) {
|
||||
if (data[fld] !== null && data[fld] !== undefined) {
|
||||
$scope[fld] = data[fld];
|
||||
master[fld] = $scope[fld];
|
||||
}
|
||||
if (form.fields[fld].type === 'lookup' && data.summary_fields[form.fields[fld].sourceModel]) {
|
||||
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField];
|
||||
}
|
||||
}
|
||||
|
||||
if (!Empty($scope.user)) {
|
||||
$scope.owner = 'user';
|
||||
} else {
|
||||
$scope.owner = 'team';
|
||||
}
|
||||
master.owner = $scope.owner;
|
||||
|
||||
for (i = 0; i < $scope.become_options.length; i++) {
|
||||
if ($scope.become_options[i].value === data.become_method) {
|
||||
$scope.become_method = $scope.become_options[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.become_method && $scope.become_method.value === "") {
|
||||
$scope.become_method = null;
|
||||
}
|
||||
master.become_method = $scope.become_method;
|
||||
|
||||
$scope.$watch('become_method', function(val) {
|
||||
if (val !== null) {
|
||||
if (val.value === "") {
|
||||
$scope.become_username = "";
|
||||
$scope.become_password = "";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (i = 0; i < $scope.credential_kind_options.length; i++) {
|
||||
if ($scope.credential_kind_options[i].value === data.kind) {
|
||||
$scope.kind = $scope.credential_kind_options[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KindChange({
|
||||
scope: $scope,
|
||||
form: form,
|
||||
reset: false
|
||||
});
|
||||
|
||||
master.kind = $scope.kind;
|
||||
|
||||
CreateSelect2({
|
||||
element: '#credential_become_method',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: '#credential_kind',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
switch (data.kind) {
|
||||
case 'aws':
|
||||
$scope.access_key = data.username;
|
||||
$scope.secret_key = data.password;
|
||||
master.access_key = $scope.access_key;
|
||||
master.secret_key = $scope.secret_key;
|
||||
break;
|
||||
case 'ssh':
|
||||
$scope.ssh_password = data.password;
|
||||
master.ssh_password = $scope.ssh_password;
|
||||
break;
|
||||
case 'rax':
|
||||
$scope.api_key = data.password;
|
||||
master.api_key = $scope.api_key;
|
||||
break;
|
||||
case 'gce':
|
||||
$scope.email_address = data.username;
|
||||
$scope.project = data.project;
|
||||
break;
|
||||
case 'azure':
|
||||
$scope.subscription = data.username;
|
||||
break;
|
||||
}
|
||||
$scope.credential_obj = data;
|
||||
|
||||
$scope.$emit('credentialLoaded');
|
||||
Wait('stop');
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to retrieve Credential: ' + $stateParams.id + '. GET status: ' + status
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Save changes to the parent
|
||||
$scope.formSave = function() {
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
FormSave({ scope: $scope, mode: 'edit' });
|
||||
}
|
||||
};
|
||||
|
||||
// Handle Owner change
|
||||
$scope.ownerChange = function() {
|
||||
OwnerChange({ scope: $scope });
|
||||
};
|
||||
|
||||
// Handle Kind change
|
||||
$scope.kindChange = function() {
|
||||
KindChange({ scope: $scope, form: form, reset: true });
|
||||
};
|
||||
|
||||
$scope.becomeMethodChange = function() {
|
||||
BecomeMethodChange({ scope: $scope });
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.transitionTo('credentials');
|
||||
};
|
||||
|
||||
// Related set: Add button
|
||||
$scope.add = function(set) {
|
||||
$rootScope.flashMessage = null;
|
||||
$location.path('/' + base + '/' + $stateParams.id + '/' + set + '/add');
|
||||
};
|
||||
|
||||
// Related set: Edit button
|
||||
$scope.edit = function(set, id) {
|
||||
$rootScope.flashMessage = null;
|
||||
$location.path('/' + base + '/' + $stateParams.id + '/' + set + '/' + id);
|
||||
};
|
||||
|
||||
// Related set: Delete button
|
||||
$scope['delete'] = function(set, itm_id, name, title) {
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
var action = function() {
|
||||
var url = defaultUrl + id + '/' + set + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post({
|
||||
id: itm_id,
|
||||
disassociate: 1
|
||||
})
|
||||
.success(function() {
|
||||
$('#prompt-modal').modal('hide');
|
||||
// @issue: OLD SEARCH
|
||||
// $scope.search(form.related[set].iterator);
|
||||
})
|
||||
.error(function(data, status) {
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. POST returned status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: i18n._('Delete'),
|
||||
body: '<div class="Prompt-bodyQuery">' + i18n.sprintf(i18n._('Are you sure you want to remove the %s below from %s?'), title, $scope.name) + '</div><div class="Prompt-bodyTarget">' + name + '</div>',
|
||||
action: action,
|
||||
actionText: i18n._('DELETE')
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// Password change
|
||||
$scope.clearPWConfirm = function(fld) {
|
||||
// If password value changes, make sure password_confirm must be re-entered
|
||||
$scope[fld] = '';
|
||||
$scope[form.name + '_form'][fld].$setValidity('awpassmatch', false);
|
||||
};
|
||||
|
||||
// Respond to 'Ask at runtime?' checkbox
|
||||
$scope.ask = function(fld, associated) {
|
||||
if ($scope[fld + '_ask']) {
|
||||
$scope[fld] = 'ASK';
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "text");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Hide");
|
||||
if (associated !== "undefined") {
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "password");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Show");
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
}
|
||||
} else {
|
||||
$scope[fld] = '';
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "password");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Show");
|
||||
if (associated !== "undefined") {
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "text");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Hide");
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clear = function(fld, associated) {
|
||||
$scope[fld] = '';
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
$scope[form.name + '_form'].$setDirty();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
CredentialsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location',
|
||||
'$log', '$stateParams', 'CredentialForm', 'Rest', 'Alert',
|
||||
'ProcessErrors', 'ClearScope', 'Prompt', 'GetBasePath', 'GetChoices',
|
||||
'KindChange', 'BecomeMethodChange', 'Empty', 'OwnerChange',
|
||||
'FormSave', 'Wait', '$state', 'CreateSelect2', 'Authorization', 'i18n',
|
||||
];
|
||||
@ -1,142 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Home
|
||||
* @description This controller's for the dashboard
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name controllers.function:Home#Home
|
||||
* @methodOf controllers.function:Home
|
||||
* @description this function loads all the widgets on the dashboard.
|
||||
* dashboardReady (emit) - this is called when the preliminary parts of the dashboard have been loaded, and loads each of the widgets. Note that the
|
||||
* Host count graph should only be loaded if the user is a super user
|
||||
*
|
||||
*/
|
||||
|
||||
export function Home($scope, $compile, $stateParams, $rootScope, $location, $log, Wait,
|
||||
ClearScope, Rest, GetBasePath, ProcessErrors, $window, graphData){
|
||||
|
||||
ClearScope('home');
|
||||
|
||||
var dataCount = 0;
|
||||
|
||||
$scope.$on('ws-jobs', function () {
|
||||
Rest.setUrl(GetBasePath('dashboard'));
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$scope.dashboardData = data;
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard host graph data: ' + status });
|
||||
});
|
||||
|
||||
Rest.setUrl(GetBasePath("jobs") + "?order_by=-finished&page_size=5&finished__isnull=false");
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$scope.dashboardJobsListData = data.results;
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard jobs list: ' + status });
|
||||
});
|
||||
|
||||
Rest.setUrl(GetBasePath("unified_job_templates") + "?order_by=-last_job_run&page_size=5&last_job_run__isnull=false&type=workflow_job_template,job_template");
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$scope.dashboardJobTemplatesListData = data.results;
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard jobs list: ' + status });
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
if ($scope.removeDashboardDataLoadComplete) {
|
||||
$scope.removeDashboardDataLoadComplete();
|
||||
}
|
||||
$scope.removeDashboardDataLoadComplete = $scope.$on('dashboardDataLoadComplete', function () {
|
||||
dataCount++;
|
||||
if (dataCount === 3) {
|
||||
Wait("stop");
|
||||
dataCount = 0;
|
||||
}
|
||||
});
|
||||
|
||||
if ($scope.removeDashboardReady) {
|
||||
$scope.removeDashboardReady();
|
||||
}
|
||||
$scope.removeDashboardReady = $scope.$on('dashboardReady', function (e, data) {
|
||||
$scope.dashboardCountsData = data;
|
||||
$scope.graphData = graphData;
|
||||
$scope.$emit('dashboardDataLoadComplete');
|
||||
|
||||
var cleanupJobListener =
|
||||
$rootScope.$on('DataReceived:JobStatusGraph', function(e, data) {
|
||||
$scope.graphData.jobStatus = data;
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
cleanupJobListener();
|
||||
});
|
||||
});
|
||||
|
||||
if ($scope.removeDashboardJobsListReady) {
|
||||
$scope.removeDashboardJobsListReady();
|
||||
}
|
||||
$scope.removeDashboardJobsListReady = $scope.$on('dashboardJobsListReady', function (e, data) {
|
||||
$scope.dashboardJobsListData = data;
|
||||
$scope.$emit('dashboardDataLoadComplete');
|
||||
});
|
||||
|
||||
if ($scope.removeDashboardJobTemplatesListReady) {
|
||||
$scope.removeDashboardJobTemplatesListReady();
|
||||
}
|
||||
$scope.removeDashboardJobTemplatesListReady = $scope.$on('dashboardJobTemplatesListReady', function (e, data) {
|
||||
$scope.dashboardJobTemplatesListData = data;
|
||||
$scope.$emit('dashboardDataLoadComplete');
|
||||
});
|
||||
|
||||
$scope.refresh = function () {
|
||||
Wait('start');
|
||||
Rest.setUrl(GetBasePath('dashboard'));
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$scope.dashboardData = data;
|
||||
$scope.$emit('dashboardReady', data);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard: ' + status });
|
||||
});
|
||||
Rest.setUrl(GetBasePath("jobs") + "?order_by=-finished&page_size=5&finished__isnull=false");
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
data = data.results;
|
||||
$scope.$emit('dashboardJobsListReady', data);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard jobs list: ' + status });
|
||||
});
|
||||
Rest.setUrl(GetBasePath("unified_job_templates") + "?order_by=-last_job_run&page_size=5&last_job_run__isnull=false&type=workflow_job_template,job_template");
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
data = data.results;
|
||||
$scope.$emit('dashboardJobTemplatesListReady', data);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard job templates list: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
}
|
||||
|
||||
Home.$inject = ['$scope', '$compile', '$stateParams', '$rootScope', '$location', '$log','Wait',
|
||||
'ClearScope', 'Rest', 'GetBasePath', 'ProcessErrors', '$window', 'graphData'
|
||||
];
|
||||
@ -1,356 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:JobEvent
|
||||
* @description This controller's for the job event page
|
||||
*/
|
||||
|
||||
|
||||
export function JobEventsList($sce, $filter, $scope, $rootScope, $location, $log, $stateParams, Rest, Alert, JobEventList, GenerateList,
|
||||
Prompt, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, LookUpInit, ToggleChildren,
|
||||
FormatDate, EventView, Wait) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var list = JobEventList,
|
||||
generator = GenerateList;
|
||||
|
||||
// @issue: OLD SEARCH
|
||||
// var defaultUrl = GetBasePath('jobs') + $stateParams.id + '/job_events/', //?parent__isnull=1';
|
||||
// page;
|
||||
|
||||
list.base = $location.path();
|
||||
$scope.job_id = $stateParams.id;
|
||||
$rootScope.flashMessage = null;
|
||||
$scope.selected = [];
|
||||
$scope.expand = true; //on load, automatically expand all nodes
|
||||
|
||||
$scope.parentNode = 'parent-event'; // used in ngClass to dynamically set row level class and control
|
||||
$scope.childNode = 'child-event'; // link color and cursor
|
||||
|
||||
if ($scope.removeSetHostLinks) {
|
||||
$scope.removeSetHostLinks();
|
||||
}
|
||||
$scope.removeSetHostLinks = $scope.$on('SetHostLinks', function (e, inventory_id) {
|
||||
for (var i = 0; i < $scope.jobevents.length; i++) {
|
||||
if ($scope.jobevents[i].summary_fields.host) {
|
||||
$scope.jobevents[i].hostLink = "/#/inventories/" + inventory_id;
|
||||
//encodeURI($scope.jobevents[i].summary_fields.host.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function formatJSON(eventData) {
|
||||
//turn JSON event data into an html form
|
||||
|
||||
var i, n, rows, fld, txt,
|
||||
html = '',
|
||||
found = false;
|
||||
|
||||
if (eventData.res) {
|
||||
if (typeof eventData.res === 'string') {
|
||||
n = eventData.res.match(/\n/g);
|
||||
rows = (n) ? n.length : 1;
|
||||
rows = (rows > 10) ? 10 : rows;
|
||||
found = true;
|
||||
html += "<div class=\"form-group\">\n";
|
||||
html += "<label>Traceback:</label>\n";
|
||||
html += "<textarea readonly class=\"form-control nowrap\" rows=\"" + rows + "\">" + eventData.res + "</textarea>\n";
|
||||
html += "</div>\n";
|
||||
} else {
|
||||
for (fld in eventData.res) {
|
||||
if ((fld === 'msg' || fld === 'stdout' || fld === 'stderr') &&
|
||||
(eventData.res[fld] !== null && eventData.res[fld] !== '')) {
|
||||
html += "<div class=\"form-group\">\n";
|
||||
html += "<label>";
|
||||
switch (fld) {
|
||||
case 'msg':
|
||||
case 'stdout':
|
||||
html += 'Output:';
|
||||
break;
|
||||
case 'stderr':
|
||||
html += 'Error:';
|
||||
break;
|
||||
}
|
||||
html += "</label>\n";
|
||||
n = eventData.res[fld].match(/\n/g);
|
||||
rows = (n) ? n.length : 1;
|
||||
rows = (rows > 10) ? 10 : rows;
|
||||
html += "<textarea readonly class=\"form-control nowrap\" rows=\"" + rows + "\">" + eventData.res[fld] + "</textarea>\n";
|
||||
//html += "<pre>" + eventData.res[fld] + "</pre>\n";
|
||||
html += "</div>\n";
|
||||
found = true;
|
||||
}
|
||||
if (fld === "results" && Array.isArray(eventData.res[fld]) && eventData.res[fld].length > 0) {
|
||||
txt = '';
|
||||
for (i = 0; i < eventData.res[fld].length; i++) {
|
||||
txt += eventData.res[fld][i];
|
||||
}
|
||||
n = txt.match(/\n/g);
|
||||
rows = (n) ? n.length : 1;
|
||||
rows = (rows > 10) ? 10 : rows;
|
||||
if (txt !== '') {
|
||||
html += "<div class=\"form-group\">\n";
|
||||
html += "<label>Results:</label>\n";
|
||||
html += "<textarea readonly class=\"form-control nowrap mono-space\" rows=\"" + rows + "\">" + txt + "</textarea>\n";
|
||||
//html += "<pre>" + txt + "</pre>\n";
|
||||
html += "</div>\n";
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (fld === "rc" && eventData.res[fld] !== '') {
|
||||
|
||||
html += "<div class=\"form-group\">\n";
|
||||
html += "<label>Return Code:</label><div class=\"return-code\">" + eventData.res[fld] + "</div>\n";
|
||||
//html += "<input type=\"text\" class=\"form-control nowrap mono-space\" value=\"" + eventData.res[fld] + "\" readonly >\n";
|
||||
html += "</div>\n";
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
html = (found) ? "<form class=\"event-form\">\n" + html + "</form>\n" : '';
|
||||
}
|
||||
if (eventData.hosts) {
|
||||
html = "<span class=\"event-detail-host visible-sm\">" + eventData.host + "</span>\n" + html;
|
||||
} else {
|
||||
html = (html === '') ? null : html;
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
if ($scope.removePostRefresh) {
|
||||
$scope.removePostRefresh();
|
||||
}
|
||||
$scope.removePostRefresh = $scope.$on('PostRefresh', function () {
|
||||
// Initialize the parent levels
|
||||
|
||||
generator.inject(list, { mode: 'edit', scope: $scope });
|
||||
|
||||
var set = $scope[list.name], i;
|
||||
for (i = 0; i < set.length; i++) {
|
||||
set[i].event_display = set[i].event_display.replace(/^\u00a0*/g, '');
|
||||
if (set[i].event_level < 3) {
|
||||
set[i].ngicon = 'fa fa-minus-square-o node-toggle';
|
||||
set[i]['class'] = 'parentNode';
|
||||
} else {
|
||||
set[i].ngicon = 'fa fa-square-o node-no-toggle';
|
||||
set[i]['class'] = 'childNode';
|
||||
set[i].event_detail = $sce.trustAsHtml(formatJSON(set[i].event_data));
|
||||
}
|
||||
set[i].show = true;
|
||||
set[i].spaces = set[i].event_level * 24;
|
||||
if ($scope.jobevents[i].failed) {
|
||||
$scope.jobevents[i].status = 'error';
|
||||
if (i === set.length - 1) {
|
||||
$scope.jobevents[i].statusBadgeToolTip = "A failure occurred durring one or more playbook tasks.";
|
||||
} else if (set[i].event_level < 3) {
|
||||
$scope.jobevents[i].statusBadgeToolTip = "A failure occurred within the children of this event.";
|
||||
} else {
|
||||
$scope.jobevents[i].statusBadgeToolTip = "A failure occurred. Click to view details";
|
||||
}
|
||||
} else if ($scope.jobevents[i].changed) {
|
||||
$scope.jobevents[i].status = 'changed';
|
||||
if (i === set.length - 1) {
|
||||
$scope.jobevents[i].statusBadgeToolTip = "A change was completed durring one or more playbook tasks.";
|
||||
} else if (set[i].event_level < 3) {
|
||||
$scope.jobevents[i].statusBadgeToolTip = "A change was completed by one or more children of this event.";
|
||||
} else {
|
||||
$scope.jobevents[i].statusBadgeToolTip = "A change was completed. Click to view details";
|
||||
}
|
||||
} else {
|
||||
$scope.jobevents[i].status = 'success';
|
||||
if (i === set.length - 1) {
|
||||
$scope.jobevents[i].statusBadgeToolTip = "All playbook tasks completed successfully.";
|
||||
} else if (set[i].event_level < 3) {
|
||||
$scope.jobevents[i].statusBadgeToolTip = "All the children of this event completed successfully.";
|
||||
} else {
|
||||
$scope.jobevents[i].statusBadgeToolTip = "No errors occurred. Click to view details";
|
||||
}
|
||||
}
|
||||
//cDate = new Date(set[i].created);
|
||||
//set[i].created = FormatDate(cDate);
|
||||
set[i].created = $filter('longDate')(set[i].created);
|
||||
}
|
||||
|
||||
// Need below lookup to get inventory_id, which is not on event record. Plus, good idea to get status and name
|
||||
// from job in the event that there are no job event records
|
||||
Rest.setUrl(GetBasePath('jobs') + $scope.job_id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$scope.job_status = data.status;
|
||||
$scope.job_name = data.summary_fields.job_template.name;
|
||||
$scope.$emit('SetHostLinks', data.inventory);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to get job status for job: ' + $scope.job_id + '. GET status: ' + status
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// @issue: OLD SEARCH
|
||||
// SearchInit({
|
||||
// scope: $scope,
|
||||
// set: 'jobevents',
|
||||
// list: list,
|
||||
// url: defaultUrl
|
||||
// });
|
||||
//
|
||||
// page = ($stateParams.page) ? parseInt($stateParams.page,10) - 1 : null;
|
||||
//
|
||||
// PaginateInit({
|
||||
// scope: $scope,
|
||||
// list: list,
|
||||
// url: defaultUrl,
|
||||
// page: page
|
||||
// });
|
||||
//
|
||||
// // Called from Inventories tab, host failed events link:
|
||||
// if ($stateParams.host) {
|
||||
// $scope[list.iterator + 'SearchField'] = 'host';
|
||||
// $scope[list.iterator + 'SearchValue'] = $stateParams.host;
|
||||
// $scope[list.iterator + 'SearchFieldLabel'] = list.fields.host.label;
|
||||
// }
|
||||
//
|
||||
// $scope.search(list.iterator, $stateParams.page);
|
||||
|
||||
$scope.toggle = function (id) {
|
||||
ToggleChildren({
|
||||
scope: $scope,
|
||||
list: list,
|
||||
id: id
|
||||
});
|
||||
};
|
||||
|
||||
$scope.viewJobEvent = function (id) {
|
||||
EventView({
|
||||
event_id: id
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refresh = function () {
|
||||
// @issue: OLD SEARCH
|
||||
// $scope.jobSearchSpin = true;
|
||||
$scope.jobLoading = true;
|
||||
Wait('start');
|
||||
|
||||
// @issue: OLD SEARCH
|
||||
// Refresh({
|
||||
// scope: $scope,
|
||||
// set: 'jobevents',
|
||||
// iterator: 'jobevent',
|
||||
// url: $scope.current_url
|
||||
// });
|
||||
};
|
||||
}
|
||||
|
||||
JobEventsList.$inject = ['$sce', '$filter', '$scope', '$rootScope', '$location', '$log', '$stateParams', 'Rest', 'Alert', 'JobEventList',
|
||||
'generateList', 'Prompt', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
|
||||
'GetBasePath', 'LookUpInit', 'ToggleChildren', 'FormatDate', 'EventView', 'Wait'
|
||||
];
|
||||
|
||||
export function JobEventsEdit($scope, $rootScope, $compile, $location, $log, $stateParams, JobEventsForm, GenerateForm,
|
||||
Rest, Alert, ProcessErrors, ClearScope, GetBasePath, FormatDate, EventView, Wait) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var form = JobEventsForm,
|
||||
generator = GenerateForm,
|
||||
defaultUrl = GetBasePath('base') + 'job_events/' + $stateParams.event_id + '/';
|
||||
|
||||
generator.inject(form, { mode: 'edit', related: true, scope: $scope});
|
||||
generator.reset();
|
||||
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Wait('start');
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var cDate, fld, n, rows;
|
||||
$scope.event_display = data.event_display.replace(/^\u00a0*/g, '');
|
||||
for (fld in form.fields) {
|
||||
switch (fld) {
|
||||
case 'status':
|
||||
if (data.failed) {
|
||||
$scope.status = 'error';
|
||||
} else if (data.changed) {
|
||||
$scope.status = 'changed';
|
||||
} else {
|
||||
$scope.status = 'success';
|
||||
}
|
||||
break;
|
||||
case 'created':
|
||||
cDate = new Date(data.created);
|
||||
$scope.created = FormatDate(cDate);
|
||||
break;
|
||||
case 'host':
|
||||
if (data.summary_fields && data.summary_fields.host) {
|
||||
$scope.host = data.summary_fields.host.name;
|
||||
}
|
||||
break;
|
||||
case 'id':
|
||||
case 'task':
|
||||
case 'play':
|
||||
$scope[fld] = data[fld];
|
||||
break;
|
||||
case 'start':
|
||||
case 'end':
|
||||
if (data.event_data && data.event_data.res && data.event_data.res[fld] !== undefined) {
|
||||
cDate = new Date(data.event_data.res[fld]);
|
||||
$scope[fld] = FormatDate(cDate);
|
||||
}
|
||||
break;
|
||||
case 'msg':
|
||||
case 'stdout':
|
||||
case 'stderr':
|
||||
case 'delta':
|
||||
case 'rc':
|
||||
if (data.event_data && data.event_data.res && data.event_data.res[fld] !== undefined) {
|
||||
$scope[fld] = data.event_data.res[fld];
|
||||
if (form.fields[fld].type === 'textarea') {
|
||||
n = data.event_data.res[fld].match(/\n/g);
|
||||
rows = (n) ? n.length : 1;
|
||||
rows = (rows > 15) ? 5 : rows;
|
||||
$('textarea[name="' + fld + '"]').attr('rows', rows);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'module_name':
|
||||
case 'module_args':
|
||||
if (data.event_data.res && data.event_data.res.invocation) {
|
||||
$scope[fld] = data.event_data.res.invocation.fld;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Wait('stop');
|
||||
})
|
||||
.error(function (data) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve host: ' + $stateParams.event_id +
|
||||
'. GET status: ' + status });
|
||||
});
|
||||
|
||||
$scope.navigateBack = function () {
|
||||
var url = '/jobs/' + $stateParams.job_id + '/job_events';
|
||||
if ($stateParams.page) {
|
||||
url += '?page=' + $stateParams.page;
|
||||
}
|
||||
$location.url(url);
|
||||
};
|
||||
|
||||
$scope.rawView = function () {
|
||||
EventView({
|
||||
"event_id": $scope.id
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
JobEventsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$stateParams', 'JobEventsForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'ClearScope', 'GetBasePath', 'FormatDate', 'EventView', 'Wait'
|
||||
];
|
||||
@ -1,121 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:JobHosts
|
||||
* @description This controller's for the job hosts page
|
||||
*/
|
||||
|
||||
|
||||
export function JobHostSummaryList($scope, $rootScope, $location, $log, $stateParams, Rest, Alert, JobHostList, GenerateList,
|
||||
Prompt, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath,
|
||||
JobStatusToolTip) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var list = JobHostList,
|
||||
// @issue: OLD SEARCH
|
||||
// defaultUrl = GetBasePath('jobs') + $stateParams.id + '/job_host_summaries/',
|
||||
view = GenerateList,
|
||||
inventory;
|
||||
|
||||
$scope.job_id = $stateParams.id;
|
||||
$scope.host_id = null;
|
||||
|
||||
// After a refresh, populate any needed summary field values on each row
|
||||
if ($scope.removePostRefresh) {
|
||||
$scope.removePostRefresh();
|
||||
}
|
||||
$scope.removePostRefresh = $scope.$on('PostRefresh', function () {
|
||||
|
||||
// Set status, tooltips, badges icons, etc.
|
||||
$scope.jobhosts.forEach(function(element, i) {
|
||||
$scope.jobhosts[i].host_name = ($scope.jobhosts[i].summary_fields.host) ? $scope.jobhosts[i].summary_fields.host.name : '';
|
||||
$scope.jobhosts[i].status = ($scope.jobhosts[i].failed) ? 'failed' : 'success';
|
||||
$scope.jobhosts[i].statusBadgeToolTip = JobStatusToolTip($scope.jobhosts[i].status) +
|
||||
" Click to view details.";
|
||||
if ($scope.jobhosts[i].summary_fields.host) {
|
||||
$scope.jobhosts[i].statusLinkTo = '/#/job_events/' + $scope.jobhosts[i].job + '/?host=' +
|
||||
encodeURI($scope.jobhosts[i].summary_fields.host.name);
|
||||
}
|
||||
else {
|
||||
$scope.jobhosts[i].statusLinkTo = '/#/job_events/' + $scope.jobhosts[i].job;
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 0; i < $scope.jobhosts.length; i++) {
|
||||
$scope.jobhosts[i].hostLinkTo = '/#/inventories/' + inventory + '/?host_name=' +
|
||||
encodeURI($scope.jobhosts[i].summary_fields.host.name);
|
||||
}
|
||||
});
|
||||
|
||||
if ($scope.removeJobReady) {
|
||||
$scope.removeJobReady();
|
||||
}
|
||||
$scope.removeJobReady = $scope.$on('JobReady', function() {
|
||||
view.inject(list, { mode: 'edit', scope: $scope });
|
||||
|
||||
// @issue: OLD SEARCH
|
||||
// SearchInit({
|
||||
// scope: $scope,
|
||||
// set: 'jobhosts',
|
||||
// list: list,
|
||||
// url: defaultUrl
|
||||
// });
|
||||
//
|
||||
// PaginateInit({
|
||||
// scope: $scope,
|
||||
// list: list,
|
||||
// url: defaultUrl
|
||||
// });
|
||||
//
|
||||
// // Called from Inventories tab, host failed events link:
|
||||
// if ($stateParams.host_name) {
|
||||
// $scope[list.iterator + 'SearchField'] = 'host';
|
||||
// $scope[list.iterator + 'SearchValue'] = $stateParams.host_name;
|
||||
// $scope[list.iterator + 'SearchFieldLabel'] = list.fields.host.label;
|
||||
// }
|
||||
// $scope.search(list.iterator);
|
||||
});
|
||||
|
||||
Rest.setUrl(GetBasePath('jobs') + $scope.job_id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
inventory = data.inventory;
|
||||
$scope.job_status = data.status;
|
||||
$scope.$emit('JobReady');
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to get job status for job: ' + $scope.job_id + '. GET status: ' + status
|
||||
});
|
||||
});
|
||||
|
||||
$scope.showEvents = function (host_name, last_job) {
|
||||
// When click on !Failed Events link, redirect to latest job/job_events for the host
|
||||
Rest.setUrl(last_job);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$location.url('/jobs_events/' + data.id + '/?host=' + encodeURI(host_name));
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to lookup last job: ' + last_job +
|
||||
'. GET status: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refresh = function () {
|
||||
// @issue: OLD SEARCH
|
||||
// $scope.search(list.iterator);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
JobHostSummaryList.$inject = ['$scope', '$rootScope', '$location', '$log', '$stateParams', 'Rest', 'Alert', 'JobHostList',
|
||||
'generateList', 'Prompt', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
|
||||
'GetBasePath', 'JobStatusToolTip', 'Wait'
|
||||
];
|
||||
@ -1,749 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Projects
|
||||
* @description This controller's for the projects page
|
||||
*/
|
||||
|
||||
|
||||
export function ProjectsList($scope, $rootScope, $location, $log, $stateParams,
|
||||
Rest, Alert, ProjectList, Prompt, ReturnToCaller, ClearScope, ProcessErrors,
|
||||
GetBasePath, ProjectUpdate, Wait, GetChoices, Empty, Find, GetProjectIcon,
|
||||
GetProjectToolTip, $filter, $state, rbacUiControlService, Dataset, i18n, qs) {
|
||||
|
||||
var list = ProjectList,
|
||||
defaultUrl = GetBasePath('projects');
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.canAdd = false;
|
||||
|
||||
rbacUiControlService.canAdd('projects')
|
||||
.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;
|
||||
|
||||
_.forEach($scope[list.name], buildTooltips);
|
||||
$rootScope.flashMessage = null;
|
||||
}
|
||||
|
||||
$scope.$on(`${list.iterator}_options`, function(event, data){
|
||||
$scope.options = data.data.actions.GET;
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
$scope.$watchCollection(`${$scope.list.name}`, function() {
|
||||
optionsRequestDataProcessing();
|
||||
}
|
||||
);
|
||||
|
||||
// iterate over the list and add fields like type label, after the
|
||||
// OPTIONS request returns, or the list is sorted/paginated/searched
|
||||
function optionsRequestDataProcessing(){
|
||||
if ($scope[list.name] !== undefined) {
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
|
||||
// Set the item type label
|
||||
if (list.fields.scm_type && $scope.options &&
|
||||
$scope.options.hasOwnProperty('scm_type')) {
|
||||
$scope.options.scm_type.choices.every(function(choice) {
|
||||
if (choice[0] === item.scm_type) {
|
||||
itm.type_label = choice[1];
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
buildTooltips(itm);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function buildTooltips(project) {
|
||||
project.statusIcon = GetProjectIcon(project.status);
|
||||
project.statusTip = GetProjectToolTip(project.status);
|
||||
project.scm_update_tooltip = i18n._("Start an SCM update");
|
||||
project.scm_schedule_tooltip = i18n._("Schedule future SCM updates");
|
||||
project.scm_type_class = "";
|
||||
|
||||
if (project.status === 'failed' && project.summary_fields.last_update && project.summary_fields.last_update.status === 'canceled') {
|
||||
project.statusTip = i18n._('Canceled. Click for details');
|
||||
}
|
||||
|
||||
if (project.status === 'running' || project.status === 'updating') {
|
||||
project.scm_update_tooltip = i18n._("SCM update currently running");
|
||||
project.scm_type_class = "btn-disabled";
|
||||
}
|
||||
if (project.scm_type === 'manual') {
|
||||
project.scm_update_tooltip = i18n._('Manual projects do not require an SCM update');
|
||||
project.scm_schedule_tooltip = i18n._('Manual projects do not require a schedule');
|
||||
project.scm_type_class = 'btn-disabled';
|
||||
project.statusTip = i18n._('Not configured for SCM');
|
||||
project.statusIcon = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
$scope.reloadList = function(){
|
||||
let path = GetBasePath(list.basePath) || GetBasePath(list.name);
|
||||
qs.search(path, $stateParams[`${list.iterator}_search`])
|
||||
.then(function(searchResponse) {
|
||||
$scope[`${list.iterator}_dataset`] = searchResponse.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on(`ws-jobs`, 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.reloadList();
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$scope.addProject = function() {
|
||||
$state.go('projects.add');
|
||||
};
|
||||
|
||||
$scope.editProject = function(id) {
|
||||
$state.go('projects.edit', { project_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(i18n._('No Updates Available'), i18n._('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(i18n._('No SCM Configuration'), i18n._('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: i18n._('Error!'),
|
||||
msg: i18n._('Project lookup failed. GET returned: ') + status });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.deleteProject = function(id, name) {
|
||||
var action = function() {
|
||||
$('#prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function() {
|
||||
if (parseInt($state.params.project_id) === id) {
|
||||
$state.go("^", null, { reload: true });
|
||||
} else {
|
||||
$state.go('.', null, {reload: true});
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Call to %s failed. DELETE returned status: '), url) + status });
|
||||
})
|
||||
.finally(function() {
|
||||
Wait('stop');
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: i18n._('Delete'),
|
||||
body: '<div class="Prompt-bodyQuery">' + i18n._('Are you sure you want to delete the project below?') + '</div>' + '<div class="Prompt-bodyTarget">' + $filter('sanitize')(name) + '</div>',
|
||||
action: action,
|
||||
actionText: 'DELETE'
|
||||
});
|
||||
};
|
||||
|
||||
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(i18n._('SCM Update Cancel'), i18n._('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: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. POST status: '), url) + 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(i18n._('Cancel Not Allowed'), '<div>' + i18n.sprintf(i18n._('Either you do not have access or the SCM update process completed. ' +
|
||||
'Click the %sRefresh%s button to view the latest status.'), '<em>', '</em>') + '</div>', 'alert-info', null, null, null, null, true);
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. GET status: '), url) + 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: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Call to %s failed. GET status: '), data.related.current_update) + status });
|
||||
});
|
||||
} else {
|
||||
Alert(i18n._('Update Not Found'), '<div>' + i18n.sprintf(i18n._('An SCM update does not appear to be running for project: %s. Click the %sRefresh%s ' +
|
||||
'button to view the latest status.'), $filter('sanitize')(name), '<em>', '</em>') + '</div>', 'alert-info',undefined,undefined,undefined,undefined,true);
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'),
|
||||
msg: i18n._('Call to get project failed. GET status: ') + status });
|
||||
});
|
||||
};
|
||||
|
||||
$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)) && !(project.status === 'updating' || project.status === 'running' || project.status === 'pending')) {
|
||||
$state.go('projectSchedules', { id: id });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ProjectsList.$inject = ['$scope', '$rootScope', '$location', '$log', '$stateParams',
|
||||
'Rest', 'Alert', 'ProjectList', 'Prompt', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
|
||||
'GetBasePath', 'ProjectUpdate', 'Wait', 'GetChoices', 'Empty', 'Find', 'GetProjectIcon',
|
||||
'GetProjectToolTip', '$filter', '$state', 'rbacUiControlService', 'Dataset', 'i18n', 'QuerySet'
|
||||
];
|
||||
|
||||
export function ProjectsAdd($scope, $rootScope, $compile, $location, $log,
|
||||
$stateParams, GenerateForm, ProjectsForm, Rest, Alert, ProcessErrors,
|
||||
GetBasePath, GetProjectPath, GetChoices, Wait, $state, CreateSelect2, i18n) {
|
||||
|
||||
var form = ProjectsForm(),
|
||||
base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
defaultUrl = GetBasePath('projects'),
|
||||
master = {};
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
Rest.setUrl(GetBasePath('projects'));
|
||||
Rest.options()
|
||||
.success(function(data) {
|
||||
if (!data.actions.POST) {
|
||||
$state.go("^");
|
||||
Alert(i18n._('Permission Error'), i18n._('You do not have permission to add a project.'), 'alert-info');
|
||||
}
|
||||
});
|
||||
|
||||
// apply form definition's default field values
|
||||
GenerateForm.applyDefaults(form, $scope);
|
||||
}
|
||||
|
||||
GetProjectPath({ scope: $scope, master: master });
|
||||
|
||||
if ($scope.removeChoicesReady) {
|
||||
$scope.removeChoicesReady();
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReady', function() {
|
||||
var i;
|
||||
for (i = 0; i < $scope.scm_type_options.length; i++) {
|
||||
if ($scope.scm_type_options[i].value === '') {
|
||||
$scope.scm_type_options[i].value = "manual";
|
||||
//$scope.scm_type = $scope.scm_type_options[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CreateSelect2({
|
||||
element: '#project_scm_type',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
$scope.scmRequired = false;
|
||||
master.scm_type = $scope.scm_type;
|
||||
});
|
||||
|
||||
// Load the list of options for Kind
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'scm_type',
|
||||
variable: 'scm_type_options',
|
||||
callback: 'choicesReady'
|
||||
});
|
||||
CreateSelect2({
|
||||
element: '#local-path-select',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
var i, fld, url, data = {};
|
||||
data = {};
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].type === 'checkbox_group') {
|
||||
for (i = 0; i < form.fields[fld].fields.length; i++) {
|
||||
data[form.fields[fld].fields[i].name] = $scope[form.fields[fld].fields[i].name];
|
||||
}
|
||||
} else {
|
||||
if (form.fields[fld].type !== 'alertblock') {
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.scm_type.value === "manual") {
|
||||
data.scm_type = "";
|
||||
data.local_path = $scope.local_path.value;
|
||||
} else {
|
||||
data.scm_type = $scope.scm_type.value;
|
||||
delete data.local_path;
|
||||
}
|
||||
|
||||
url = (base === 'teams') ? GetBasePath('teams') + $stateParams.team_id + '/projects/' : defaultUrl;
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.post(data)
|
||||
.success(function(data) {
|
||||
$scope.addedItem = data.id;
|
||||
$state.go('projects.edit', { project_id: data.id }, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'),
|
||||
msg: i18n._('Failed to create new project. POST returned status: ') + status });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.scmChange = function() {
|
||||
// When an scm_type is set, path is not required
|
||||
if ($scope.scm_type) {
|
||||
$scope.pathRequired = ($scope.scm_type.value === 'manual') ? true : false;
|
||||
$scope.scmRequired = ($scope.scm_type.value !== 'manual') ? true : false;
|
||||
$scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? 'Revision #' : 'SCM Branch';
|
||||
}
|
||||
|
||||
// Dynamically update popover values
|
||||
if ($scope.scm_type.value) {
|
||||
switch ($scope.scm_type.value) {
|
||||
case 'git':
|
||||
$scope.urlPopover = '<p>' +
|
||||
i18n._('Example URLs for GIT SCM include:') +
|
||||
'</p><ul class=\"no-bullets\"><li>https://github.com/ansible/ansible.git</li>' +
|
||||
'<li>git@github.com:ansible/ansible.git</li><li>git://servername.example.com/ansible.git</li></ul>' +
|
||||
'<p>' + i18n.sprintf(i18n._('%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, ' +
|
||||
'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' +
|
||||
'SSH. GIT read only protocol (git://) does not use username or password information.'), '<strong>', '</strong>');
|
||||
break;
|
||||
case 'svn':
|
||||
$scope.urlPopover = '<p>' + i18n._('Example URLs for Subversion SCM include:') + '</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://github.com/ansible/ansible</li><li>svn://servername.example.com/path</li>' +
|
||||
'<li>svn+ssh://servername.example.com/path</li></ul>';
|
||||
break;
|
||||
case 'hg':
|
||||
$scope.urlPopover = '<p>' + i18n._('Example URLs for Mercurial SCM include:') + '</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://bitbucket.org/username/project</li><li>ssh://hg@bitbucket.org/username/project</li>' +
|
||||
'<li>ssh://server.example.com/path</li></ul>' +
|
||||
'<p>' + i18n.sprintf(i18n._('%sNote:%s Mercurial does not support password authentication for SSH. ' +
|
||||
'Do not put the username and key in the URL. ' +
|
||||
'If using Bitbucket and SSH, do not supply your Bitbucket username.'), '<strong>', '</strong>');
|
||||
break;
|
||||
default:
|
||||
$scope.urlPopover = '<p> ' + i18n._('URL popover text');
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
$scope.formCancel = function() {
|
||||
$state.go('projects');
|
||||
};
|
||||
}
|
||||
|
||||
ProjectsAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log',
|
||||
'$stateParams', 'GenerateForm', 'ProjectsForm', 'Rest', 'Alert', 'ProcessErrors', 'GetBasePath',
|
||||
'GetProjectPath', 'GetChoices', 'Wait', '$state', 'CreateSelect2', 'i18n'];
|
||||
|
||||
|
||||
export function ProjectsEdit($scope, $rootScope, $compile, $location, $log,
|
||||
$stateParams, ProjectsForm, Rest, Alert, ProcessErrors, GenerateForm,
|
||||
Prompt, ClearScope, GetBasePath, GetProjectPath, Authorization,
|
||||
GetChoices, Empty, DebugForm, Wait, ProjectUpdate, $state, CreateSelect2, ToggleNotification, i18n) {
|
||||
|
||||
ClearScope('htmlTemplate');
|
||||
|
||||
var form = ProjectsForm(),
|
||||
defaultUrl = GetBasePath('projects') + $stateParams.project_id + '/',
|
||||
master = {},
|
||||
id = $stateParams.project_id;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.project_local_paths = [];
|
||||
$scope.base_dir = '';
|
||||
}
|
||||
|
||||
$scope.$watch('project_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||
if (val === false) {
|
||||
$scope.canAdd = false;
|
||||
}
|
||||
});
|
||||
|
||||
if ($scope.pathsReadyRemove) {
|
||||
$scope.pathsReadyRemove();
|
||||
}
|
||||
$scope.pathsReadyRemove = $scope.$on('pathsReady', function () {
|
||||
CreateSelect2({
|
||||
element: '#local-path-select',
|
||||
multiple: false
|
||||
});
|
||||
});
|
||||
|
||||
// After the project is loaded, retrieve each related set
|
||||
if ($scope.projectLoadedRemove) {
|
||||
$scope.projectLoadedRemove();
|
||||
}
|
||||
$scope.projectLoadedRemove = $scope.$on('projectLoaded', function() {
|
||||
var opts = [];
|
||||
|
||||
if (Authorization.getUserInfo('is_superuser') === true) {
|
||||
GetProjectPath({ scope: $scope, master: master });
|
||||
} else {
|
||||
opts.push({
|
||||
label: $scope.local_path,
|
||||
value: $scope.local_path
|
||||
});
|
||||
$scope.project_local_paths = opts;
|
||||
$scope.local_path = $scope.project_local_paths[0];
|
||||
$scope.base_dir = i18n._('You do not have access to view this property');
|
||||
$scope.$emit('pathsReady');
|
||||
}
|
||||
|
||||
$scope.pathRequired = ($scope.scm_type.value === 'manual') ? true : false;
|
||||
$scope.scmRequired = ($scope.scm_type.value !== 'manual') ? true : false;
|
||||
$scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? 'Revision #' : 'SCM Branch';
|
||||
Wait('stop');
|
||||
|
||||
$scope.scmChange();
|
||||
});
|
||||
|
||||
if ($scope.removeChoicesReady) {
|
||||
$scope.removeChoicesReady();
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReady', function() {
|
||||
let i;
|
||||
for (i = 0; i < $scope.scm_type_options.length; i++) {
|
||||
if ($scope.scm_type_options[i].value === '') {
|
||||
$scope.scm_type_options[i].value = "manual";
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.get({ params: { id: id } })
|
||||
.success(function(data) {
|
||||
var fld, i;
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].type === 'checkbox_group') {
|
||||
for (i = 0; i < form.fields[fld].fields.length; i++) {
|
||||
$scope[form.fields[fld].fields[i].name] = data[form.fields[fld].fields[i].name];
|
||||
master[form.fields[fld].fields[i].name] = data[form.fields[fld].fields[i].name];
|
||||
}
|
||||
} else {
|
||||
if (data[fld] !== undefined) {
|
||||
$scope[fld] = data[fld];
|
||||
master[fld] = data[fld];
|
||||
}
|
||||
}
|
||||
if (form.fields[fld].sourceModel && data.summary_fields &&
|
||||
data.summary_fields[form.fields[fld].sourceModel]) {
|
||||
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
}
|
||||
}
|
||||
|
||||
data.scm_type = (Empty(data.scm_type)) ? 'manual' : data.scm_type;
|
||||
for (i = 0; i < $scope.scm_type_options.length; i++) {
|
||||
if ($scope.scm_type_options[i].value === data.scm_type) {
|
||||
$scope.scm_type = $scope.scm_type_options[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.scm_type.value !== 'manual') {
|
||||
$scope.pathRequired = false;
|
||||
$scope.scmRequired = true;
|
||||
} else {
|
||||
$scope.pathRequired = true;
|
||||
$scope.scmRequired = false;
|
||||
}
|
||||
|
||||
master.scm_type = $scope.scm_type;
|
||||
CreateSelect2({
|
||||
element: '#project_scm_type',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
$scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? 'Revision #' : 'SCM Branch';
|
||||
$scope.scm_update_tooltip = i18n._("Start an SCM update");
|
||||
$scope.scm_type_class = "";
|
||||
if (data.status === 'running' || data.status === 'updating') {
|
||||
$scope.scm_update_tooltip = i18n._("SCM update currently running");
|
||||
$scope.scm_type_class = "btn-disabled";
|
||||
}
|
||||
if (Empty(data.scm_type)) {
|
||||
$scope.scm_update_tooltip = i18n._('Manual projects do not require an SCM update');
|
||||
$scope.scm_type_class = "btn-disabled";
|
||||
}
|
||||
|
||||
$scope.project_obj = data;
|
||||
$scope.name = data.name;
|
||||
$scope.$emit('projectLoaded');
|
||||
Wait('stop');
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Failed to retrieve project: %s. GET status: '), id) + status
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Load the list of options for Kind
|
||||
Wait('start');
|
||||
GetChoices({
|
||||
url: GetBasePath('projects'),
|
||||
scope: $scope,
|
||||
field: 'scm_type',
|
||||
variable: 'scm_type_options',
|
||||
callback: 'choicesReady'
|
||||
});
|
||||
|
||||
$scope.toggleNotification = function(event, id, column) {
|
||||
var notifier = this.notification;
|
||||
try {
|
||||
$(event.target).tooltip('hide');
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
ToggleNotification({
|
||||
scope: $scope,
|
||||
url: $scope.project_obj.url,
|
||||
notifier: notifier,
|
||||
column: column,
|
||||
callback: 'NotificationRefresh'
|
||||
});
|
||||
};
|
||||
|
||||
// Save changes to the parent
|
||||
$scope.formSave = function() {
|
||||
var fld, i, params;
|
||||
GenerateForm.clearApiErrors($scope);
|
||||
Wait('start');
|
||||
$rootScope.flashMessage = null;
|
||||
params = {};
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].type === 'checkbox_group') {
|
||||
for (i = 0; i < form.fields[fld].fields.length; i++) {
|
||||
params[form.fields[fld].fields[i].name] = $scope[form.fields[fld].fields[i].name];
|
||||
}
|
||||
} else {
|
||||
if (form.fields[fld].type !== 'alertblock') {
|
||||
params[fld] = $scope[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.scm_type.value === "manual") {
|
||||
params.scm_type = "";
|
||||
params.local_path = $scope.local_path.value;
|
||||
} else {
|
||||
params.scm_type = $scope.scm_type.value;
|
||||
delete params.local_path;
|
||||
}
|
||||
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.put(params)
|
||||
.success(function() {
|
||||
Wait('stop');
|
||||
$state.go($state.current, {}, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Failed to update project: %s. PUT status: '), id) + status });
|
||||
});
|
||||
};
|
||||
|
||||
// Related set: Delete button
|
||||
$scope['delete'] = function(set, itm_id, name, title) {
|
||||
var action = function() {
|
||||
var url = GetBasePath('projects') + id + '/' + set + '/';
|
||||
$rootScope.flashMessage = null;
|
||||
Rest.setUrl(url);
|
||||
Rest.post({ id: itm_id, disassociate: 1 })
|
||||
.success(function() {
|
||||
$('#prompt-modal').modal('hide');
|
||||
// @issue: OLD SEARCH
|
||||
// $scope.search(form.related[set].iterator);
|
||||
})
|
||||
.error(function(data, status) {
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. POST returned status: '), url) + status });
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: i18n._('Delete'),
|
||||
body: '<div class="Prompt-bodyQuery">' + i18n.sprintf(i18n._('Are you sure you want to remove the %s below from %s?'), title, $scope.name) + '</div>' + '<div class="Prompt-bodyTarget">' + name + '</div>',
|
||||
action: action,
|
||||
actionText: i18n._('DELETE')
|
||||
});
|
||||
};
|
||||
|
||||
$scope.scmChange = function() {
|
||||
if ($scope.scm_type) {
|
||||
$scope.pathRequired = ($scope.scm_type.value === 'manual') ? true : false;
|
||||
$scope.scmRequired = ($scope.scm_type.value !== 'manual') ? true : false;
|
||||
$scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? i18n._('Revision #') : i18n._('SCM Branch');
|
||||
}
|
||||
|
||||
// Dynamically update popover values
|
||||
if ($scope.scm_type.value) {
|
||||
switch ($scope.scm_type.value) {
|
||||
case 'git':
|
||||
$scope.urlPopover = '<p>' + i18n._('Example URLs for GIT SCM include:') + '</p><ul class=\"no-bullets\"><li>https://github.com/ansible/ansible.git</li>' +
|
||||
'<li>git@github.com:ansible/ansible.git</li><li>git://servername.example.com/ansible.git</li></ul>' +
|
||||
'<p>' + i18n.sprintf(i18n._('%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, ' +
|
||||
'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' +
|
||||
'SSH. GIT read only protocol (git://) does not use username or password information.'), '<strong>', '</strong>');
|
||||
break;
|
||||
case 'svn':
|
||||
$scope.urlPopover = '<p>' + i18n._('Example URLs for Subversion SCM include:') + '</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://github.com/ansible/ansible</li><li>svn://servername.example.com/path</li>' +
|
||||
'<li>svn+ssh://servername.example.com/path</li></ul>';
|
||||
break;
|
||||
case 'hg':
|
||||
$scope.urlPopover = '<p>' + i18n._('Example URLs for Mercurial SCM include:') + '</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://bitbucket.org/username/project</li><li>ssh://hg@bitbucket.org/username/project</li>' +
|
||||
'<li>ssh://server.example.com/path</li></ul>' +
|
||||
'<p>' + i18n.sprintf(i18n._('%sNote:%s Mercurial does not support password authentication for SSH. ' +
|
||||
'Do not put the username and key in the URL. ' +
|
||||
'If using Bitbucket and SSH, do not supply your Bitbucket username.'), '<strong>', '</strong>');
|
||||
break;
|
||||
default:
|
||||
$scope.urlPopover = '<p> ' + i18n._('URL popover text');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.SCMUpdate = function() {
|
||||
if ($scope.project_obj.scm_type === "Manual" || Empty($scope.project_obj.scm_type)) {
|
||||
// ignore
|
||||
} else if ($scope.project_obj.status === 'updating' || $scope.project_obj.status === 'running' || $scope.project_obj.status === 'pending') {
|
||||
Alert(i18n._('Update in Progress'), i18n._('The SCM update process is running.'), 'alert-info');
|
||||
} else {
|
||||
ProjectUpdate({ scope: $scope, project_id: $scope.project_obj.id });
|
||||
}
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.transitionTo('projects');
|
||||
};
|
||||
}
|
||||
|
||||
ProjectsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log',
|
||||
'$stateParams', 'ProjectsForm', 'Rest', 'Alert', 'ProcessErrors', 'GenerateForm',
|
||||
'Prompt', 'ClearScope', 'GetBasePath', 'GetProjectPath', 'Authorization', 'GetChoices', 'Empty',
|
||||
'DebugForm', 'Wait', 'ProjectUpdate', '$state', 'CreateSelect2', 'ToggleNotification', 'i18n'];
|
||||
@ -1,86 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Schedules
|
||||
* @description This controller's for schedules
|
||||
*/
|
||||
|
||||
|
||||
export function ScheduleEditController($scope, $compile, $location, $stateParams, SchedulesList, Rest, ProcessErrors, ReturnToCaller, ClearScope,
|
||||
GetBasePath, Wait, Find, LoadSchedulesScope, GetChoices) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var base, id, url, parentObject;
|
||||
|
||||
// base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
|
||||
// if ($scope.removePostRefresh) {
|
||||
// $scope.removePostRefresh();
|
||||
// }
|
||||
// $scope.removePostRefresh = $scope.$on('PostRefresh', function() {
|
||||
// var list = $scope.schedules;
|
||||
// list.forEach(function(element, idx) {
|
||||
// list[idx].play_tip = (element.enabled) ? 'Schedule is Active. Click to temporarily stop.' : 'Schedule is temporarily stopped. Click to activate.';
|
||||
// });
|
||||
// });
|
||||
|
||||
// if ($scope.removeParentLoaded) {
|
||||
// $scope.removeParentLoaded();
|
||||
// }
|
||||
// $scope.removeParentLoaded = $scope.$on('ParentLoaded', function() {
|
||||
// url += "schedules/";
|
||||
// SchedulesList.well = true;
|
||||
// LoadSchedulesScope({
|
||||
// parent_scope: $scope,
|
||||
// scope: $scope,
|
||||
// list: SchedulesList,
|
||||
// id: 'schedule-list-target',
|
||||
// url: url,
|
||||
// pageSize: 20
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
if ($scope.removeChoicesReady) {
|
||||
$scope.removeChocesReady();
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReady', function() {
|
||||
// Load the parent object
|
||||
id = $stateParams.id;
|
||||
url = GetBasePath(base) + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
parentObject = data;
|
||||
$scope.$emit('ParentLoaded');
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. GET returned: ' + status });
|
||||
});
|
||||
});
|
||||
|
||||
$scope.refreshJobs = function() {
|
||||
// @issue: OLD SEARCH
|
||||
// $scope.search(SchedulesList.iterator);
|
||||
};
|
||||
|
||||
Wait('start');
|
||||
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: GetBasePath('unified_jobs'), //'/static/sample/data/types/data.json'
|
||||
field: 'type',
|
||||
variable: 'type_choices',
|
||||
callback: 'choicesReady'
|
||||
});
|
||||
}
|
||||
|
||||
ScheduleEditController.$inject = [ '$scope', '$compile', '$location', '$stateParams', 'SchedulesList', 'Rest', 'ProcessErrors', 'ReturnToCaller', 'ClearScope',
|
||||
'GetBasePath', 'Wait', 'Find', 'LoadSchedulesScope', 'GetChoices'];
|
||||
@ -1,119 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Sockets
|
||||
* @description This controller's for controlling websockets
|
||||
* discuss
|
||||
*/
|
||||
|
||||
|
||||
export function SocketsController ($scope, $compile, ClearScope, Socket) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var test_scope = $scope.$new(),
|
||||
jobs_scope = $scope.$new(),
|
||||
job_events_scope = $scope.$new(),
|
||||
schedules_scope = $scope.$new(),
|
||||
test_socket = Socket({ scope: test_scope, endpoint: "test" }),
|
||||
jobs_socket = Socket({ scope: jobs_scope, endpoint: "jobs" }),
|
||||
schedules_socket = Socket({ scope: schedules_scope, endpoint: "schedules" }),
|
||||
job_events_socket = Socket({ scope: job_events_scope, endpoint: "job_events" }),
|
||||
e, html;
|
||||
|
||||
test_scope.messages = [];
|
||||
jobs_scope.messages = [];
|
||||
schedules_scope.messages = [];
|
||||
job_events_scope.messages = [];
|
||||
|
||||
html = "<div class=\"section-title\"><strong>Socket url</strong>: {{ socket_url }} <strong>Status:</strong> {{ socket_status }} {{ socket_reason }}</div>\n" +
|
||||
"<div class=\"message-title\">\n" +
|
||||
"<h5>Received Messages:</h5>\n" +
|
||||
"</div>\n" +
|
||||
"<div class=\"well message-section\">\n" +
|
||||
"<ul>\n" +
|
||||
"<li ng-repeat=\"message in messages\">{{ message }} </li>\n" +
|
||||
"</ul>\n" +
|
||||
"</div>\n";
|
||||
|
||||
e = angular.element(document.getElementById('test-container'));
|
||||
e.append(html);
|
||||
$compile(e)(test_scope);
|
||||
e = angular.element(document.getElementById('schedules-container'));
|
||||
e.append(html);
|
||||
$compile(e)(schedules_scope);
|
||||
e = angular.element(document.getElementById('jobs-container'));
|
||||
e.append(html);
|
||||
$compile(e)(jobs_scope);
|
||||
|
||||
html = "<div class=\"row events-section\">\n" +
|
||||
"<div class=\"col-md-6\">\n" +
|
||||
"<div class=\"section-title\"><strong>Socket url</strong>: {{ socket_url }} <strong>Status:</strong> {{ socket_status }} {{ socket_reason }}</div>\n" +
|
||||
"</div>\n" +
|
||||
"<div class=\"col-md-6\">\n" +
|
||||
"<form class=\"form-inline\">\n" +
|
||||
"<div class=\"form-group\">\n" +
|
||||
"<label for=\"job_id\">Job Id</label>\n" +
|
||||
"<input type=\"text\" name=\"job_id\" id=\"job_id\" ng-model=\"job_id\" class=\"input-sm form-control\">\n" +
|
||||
"</div>\n" +
|
||||
"<button type=\"submit\" ng-disabled=\"!job_id\" ng-click=\"subscribeToJobEvent()\" class=\"btn btn-sm btn-primary\"><i class=\"fa fa-check\"></i> Subscribe</button>\n" +
|
||||
"</form>\n" +
|
||||
"</div>\n" +
|
||||
"</div>\n" +
|
||||
"<div class=\"message-title\">" +
|
||||
"<p>Subscribed to events for job: {{ jobs_list }}</p>\n" +
|
||||
"<h5>Received Messages:</h5>\n" +
|
||||
"</div>\n" +
|
||||
"<div class=\"well message-section\" id=\"event-message-container\">\n" +
|
||||
"<ul>\n" +
|
||||
"<li ng-repeat=\"message in messages\">{{ message }} </li>\n" +
|
||||
"</ul>\n" +
|
||||
"</div>\n";
|
||||
|
||||
e = angular.element(document.getElementById('job-events-container'));
|
||||
e.append(html);
|
||||
$compile(e)(job_events_scope);
|
||||
|
||||
schedules_scope.url = schedules_socket.getUrl();
|
||||
test_scope.url = test_socket.getUrl();
|
||||
jobs_scope.url = jobs_socket.getUrl();
|
||||
job_events_scope.url = job_events_socket.getUrl();
|
||||
|
||||
test_scope.messages.push('Message Displayed Before Connection');
|
||||
|
||||
test_socket.on('test', function(data) {
|
||||
test_scope.messages.push(data);
|
||||
});
|
||||
|
||||
schedules_socket.on("schedule_changed", function(data) {
|
||||
schedules_scope.messages.push(data);
|
||||
});
|
||||
|
||||
jobs_socket.on("status_changed", function(data) {
|
||||
jobs_scope.messages.push(data);
|
||||
});
|
||||
|
||||
jobs_socket.on("summary_complete", function(data) {
|
||||
jobs_scope.messages.push(data);
|
||||
});
|
||||
|
||||
job_events_scope.jobs_list = [];
|
||||
|
||||
job_events_scope.subscribeToJobEvent = function() {
|
||||
job_events_scope.jobs_list.push(job_events_scope.job_id);
|
||||
job_events_socket.on("job_events-" + job_events_scope.job_id, function(data) {
|
||||
job_events_scope.messages.push(data);
|
||||
setTimeout(function() {
|
||||
$(document).scrollTop($(document).prop("scrollHeight"));
|
||||
$('#event-message-container').scrollTop($('#event-message-container').prop("scrollHeight"));
|
||||
}, 300);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
SocketsController.$inject = [ '$scope', '$compile', 'ClearScope', 'Socket'];
|
||||
@ -1,247 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Teams
|
||||
* @description This controller's for teams
|
||||
*/
|
||||
|
||||
export function TeamsList($scope, $rootScope, $log, $stateParams,
|
||||
Rest, Alert, TeamList, Prompt, ClearScope, ProcessErrors,
|
||||
GetBasePath, Wait, $state, $filter, rbacUiControlService, Dataset) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var list = TeamList,
|
||||
defaultUrl = GetBasePath('teams');
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.canAdd = false;
|
||||
|
||||
rbacUiControlService.canAdd('teams')
|
||||
.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;
|
||||
_.forEach($scope[list.name], (team) => {
|
||||
team.organization_name = team.summary_fields.organization.name;
|
||||
});
|
||||
|
||||
$scope.selected = [];
|
||||
}
|
||||
|
||||
$scope.addTeam = function() {
|
||||
$state.go('teams.add');
|
||||
};
|
||||
|
||||
$scope.editTeam = function(id) {
|
||||
$state.go('teams.edit', { team_id: id });
|
||||
};
|
||||
|
||||
$scope.deleteTeam = function(id, name) {
|
||||
|
||||
var action = function() {
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function() {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
if (parseInt($state.params.team_id) === id) {
|
||||
$state.go('^', null, { reload: true });
|
||||
} else {
|
||||
$state.go('.', null, { reload: true });
|
||||
}
|
||||
})
|
||||
.error(function(data, status) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
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 delete the team below?</div><div class="Prompt-bodyTarget">' + $filter('sanitize')(name) + '</div>',
|
||||
action: action,
|
||||
actionText: 'DELETE'
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
TeamsList.$inject = ['$scope', '$rootScope', '$log',
|
||||
'$stateParams', 'Rest', 'Alert', 'TeamList', 'Prompt', 'ClearScope',
|
||||
'ProcessErrors', 'GetBasePath', 'Wait', '$state', '$filter', 'rbacUiControlService', 'Dataset'
|
||||
];
|
||||
|
||||
|
||||
export function TeamsAdd($scope, $rootScope, $stateParams, TeamForm, GenerateForm, Rest, Alert, ProcessErrors,
|
||||
ClearScope, GetBasePath, Wait, $state) {
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//$scope.
|
||||
|
||||
Rest.setUrl(GetBasePath('teams'));
|
||||
Rest.options()
|
||||
.success(function(data) {
|
||||
if (!data.actions.POST) {
|
||||
$state.go("^");
|
||||
Alert('Permission Error', 'You do not have permission to add a team.', 'alert-info');
|
||||
}
|
||||
});
|
||||
|
||||
// Inject dynamic view
|
||||
var defaultUrl = GetBasePath('teams'),
|
||||
form = TeamForm;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
// apply form definition's default field values
|
||||
GenerateForm.applyDefaults(form, $scope);
|
||||
|
||||
$rootScope.flashMessage = null;
|
||||
}
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
var fld, data;
|
||||
GenerateForm.clearApiErrors($scope);
|
||||
Wait('start');
|
||||
Rest.setUrl(defaultUrl);
|
||||
data = {};
|
||||
for (fld in form.fields) {
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
Rest.post(data)
|
||||
.success(function(data) {
|
||||
Wait('stop');
|
||||
$rootScope.flashMessage = "New team successfully created!";
|
||||
$rootScope.$broadcast("EditIndicatorChange", "users", data.id);
|
||||
$state.go('teams.edit', { team_id: data.id }, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to add new team. Post returned status: ' +
|
||||
status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('teams');
|
||||
};
|
||||
}
|
||||
|
||||
TeamsAdd.$inject = ['$scope', '$rootScope', '$stateParams', 'TeamForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'ClearScope', 'GetBasePath', 'Wait', '$state'
|
||||
];
|
||||
|
||||
|
||||
export function TeamsEdit($scope, $rootScope, $stateParams,
|
||||
TeamForm, Rest, ProcessErrors, ClearScope, GetBasePath, Wait, $state) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var form = TeamForm,
|
||||
id = $stateParams.team_id,
|
||||
defaultUrl = GetBasePath('teams') + id;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.team_id = id;
|
||||
Rest.setUrl(defaultUrl);
|
||||
Wait('start');
|
||||
Rest.get(defaultUrl).success(function(data) {
|
||||
setScopeFields(data);
|
||||
$scope.organization_name = data.summary_fields.organization.name;
|
||||
|
||||
$scope.team_obj = data;
|
||||
Wait('stop');
|
||||
});
|
||||
|
||||
$scope.$watch('team_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||
if (val === false) {
|
||||
$scope.canAdd = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
// @issue I think all this really want to do is _.forEach(form.fields, (field) =>{ $scope[field] = data[field]})
|
||||
function setScopeFields(data) {
|
||||
_(data)
|
||||
.pick(function(value, key) {
|
||||
return form.fields.hasOwnProperty(key) === true;
|
||||
})
|
||||
.forEach(function(value, key) {
|
||||
$scope[key] = value;
|
||||
})
|
||||
.value();
|
||||
return;
|
||||
}
|
||||
|
||||
// prepares a data payload for a PUT request to the API
|
||||
function processNewData(fields) {
|
||||
var data = {};
|
||||
_.forEach(fields, function(value, key) {
|
||||
if ($scope[key] !== '' && $scope[key] !== null && $scope[key] !== undefined) {
|
||||
data[key] = $scope[key];
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('teams', null, { reload: true });
|
||||
};
|
||||
|
||||
$scope.formSave = function() {
|
||||
$rootScope.flashMessage = null;
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
var data = processNewData(form.fields);
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.put(data).success(function() {
|
||||
$state.go($state.current, null, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to retrieve user: ' +
|
||||
$stateParams.id + '. GET status: ' + status
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
|
||||
$scope.convertApiUrl = function(str) {
|
||||
if (str) {
|
||||
return str.replace("api/v1", "#");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TeamsEdit.$inject = ['$scope', '$rootScope', '$stateParams', 'TeamForm', 'Rest',
|
||||
'ProcessErrors', 'ClearScope', 'GetBasePath', 'Wait', '$state'
|
||||
];
|
||||
@ -1,357 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Users
|
||||
* @description This controller's the Users page
|
||||
*/
|
||||
|
||||
import { N_ } from "../i18n";
|
||||
|
||||
const user_type_options = [
|
||||
{ type: 'normal', label: N_('Normal User') },
|
||||
{ type: 'system_auditor', label: N_('System Auditor') },
|
||||
{ type: 'system_administrator', label: N_('System Administrator') },
|
||||
];
|
||||
|
||||
function user_type_sync($scope) {
|
||||
return (type_option) => {
|
||||
$scope.is_superuser = false;
|
||||
$scope.is_system_auditor = false;
|
||||
switch (type_option.type) {
|
||||
case 'system_administrator':
|
||||
$scope.is_superuser = true;
|
||||
break;
|
||||
case 'system_auditor':
|
||||
$scope.is_system_auditor = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function UsersList($scope, $rootScope, $stateParams,
|
||||
Rest, Alert, UserList, Prompt, ClearScope, ProcessErrors, GetBasePath,
|
||||
Wait, $state, $filter, rbacUiControlService, Dataset, i18n) {
|
||||
|
||||
for (var i = 0; i < user_type_options.length; i++) {
|
||||
user_type_options[i].label = i18n._(user_type_options[i].label);
|
||||
}
|
||||
|
||||
ClearScope();
|
||||
|
||||
var list = UserList,
|
||||
defaultUrl = GetBasePath('users');
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.canAdd = false;
|
||||
|
||||
rbacUiControlService.canAdd('users')
|
||||
.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;
|
||||
|
||||
|
||||
$rootScope.flashMessage = null;
|
||||
$scope.selected = [];
|
||||
}
|
||||
|
||||
$scope.addUser = function() {
|
||||
$state.go('users.add');
|
||||
};
|
||||
|
||||
$scope.editUser = function(id) {
|
||||
$state.go('users.edit', { user_id: id });
|
||||
};
|
||||
|
||||
$scope.deleteUser = function(id, name) {
|
||||
|
||||
var action = function() {
|
||||
$('#prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function() {
|
||||
if (parseInt($state.params.user_id) === id) {
|
||||
$state.go('^', null, { reload: true });
|
||||
} else {
|
||||
$state.go('.', null, { reload: true });
|
||||
}
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Call to %s failed. DELETE returned status: '), url) + status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: i18n._('Delete'),
|
||||
body: '<div class="Prompt-bodyQuery">' + i18n._('Are you sure you want to delete the user below?') + '</div><div class="Prompt-bodyTarget">' + $filter('sanitize')(name) + '</div>',
|
||||
action: action,
|
||||
actionText: i18n._('DELETE')
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
UsersList.$inject = ['$scope', '$rootScope', '$stateParams',
|
||||
'Rest', 'Alert', 'UserList', 'Prompt', 'ClearScope', 'ProcessErrors', 'GetBasePath',
|
||||
'Wait', '$state', '$filter', 'rbacUiControlService', 'Dataset', 'i18n'
|
||||
];
|
||||
|
||||
|
||||
export function UsersAdd($scope, $rootScope, $stateParams, UserForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, ReturnToCaller, ClearScope,
|
||||
GetBasePath, ResetForm, Wait, CreateSelect2, $state, $location, i18n) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var defaultUrl = GetBasePath('organizations'),
|
||||
form = UserForm;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
// apply form definition's default field values
|
||||
GenerateForm.applyDefaults(form, $scope);
|
||||
|
||||
$scope.ldap_user = false;
|
||||
$scope.not_ldap_user = !$scope.ldap_user;
|
||||
$scope.ldap_dn = null;
|
||||
$scope.socialAuthUser = false;
|
||||
$scope.external_account = null;
|
||||
|
||||
Rest.setUrl(GetBasePath('users'));
|
||||
Rest.options()
|
||||
.success(function(data) {
|
||||
if (!data.actions.POST) {
|
||||
$state.go("^");
|
||||
Alert(i18n._('Permission Error'), i18n._('You do not have permission to add a user.'), 'alert-info');
|
||||
}
|
||||
});
|
||||
|
||||
$scope.user_type_options = user_type_options;
|
||||
$scope.user_type = user_type_options[0];
|
||||
$scope.$watch('user_type', user_type_sync($scope));
|
||||
CreateSelect2({
|
||||
element: '#user_user_type',
|
||||
multiple: false
|
||||
});
|
||||
}
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
var fld, data = {};
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
if ($scope.organization !== undefined && $scope.organization !== null && $scope.organization !== '') {
|
||||
Rest.setUrl(defaultUrl + $scope.organization + '/users/');
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].realName) {
|
||||
data[form.fields[fld].realName] = $scope[fld];
|
||||
} else {
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
}
|
||||
data.is_superuser = $scope.is_superuser;
|
||||
data.is_system_auditor = $scope.is_system_auditor;
|
||||
Wait('start');
|
||||
Rest.post(data)
|
||||
.success(function(data) {
|
||||
var base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
if (base === 'users') {
|
||||
$rootScope.flashMessage = i18n._('New user successfully created!');
|
||||
$rootScope.$broadcast("EditIndicatorChange", "users", data.id);
|
||||
$state.go('users.edit', { user_id: data.id }, { reload: true });
|
||||
} else {
|
||||
ReturnToCaller(1);
|
||||
}
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'), msg: i18n._('Failed to add new user. POST returned status: ') + status });
|
||||
});
|
||||
} else {
|
||||
$scope.organization_name_api_error = i18n._('A value is required');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('users');
|
||||
};
|
||||
|
||||
// Password change
|
||||
$scope.clearPWConfirm = function(fld) {
|
||||
// If password value changes, make sure password_confirm must be re-entered
|
||||
$scope[fld] = '';
|
||||
$scope[form.name + '_form'][fld].$setValidity('awpassmatch', false);
|
||||
};
|
||||
}
|
||||
|
||||
UsersAdd.$inject = ['$scope', '$rootScope', '$stateParams', 'UserForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'ReturnToCaller', 'ClearScope', 'GetBasePath',
|
||||
'ResetForm', 'Wait', 'CreateSelect2', '$state', '$location', 'i18n'
|
||||
];
|
||||
|
||||
export function UsersEdit($scope, $rootScope, $location,
|
||||
$stateParams, UserForm, Rest, ProcessErrors,
|
||||
ClearScope, GetBasePath, ResetForm, Wait, CreateSelect2, $state, i18n) {
|
||||
|
||||
for (var i = 0; i < user_type_options.length; i++) {
|
||||
user_type_options[i].label = i18n._(user_type_options[i].label);
|
||||
}
|
||||
ClearScope();
|
||||
|
||||
var form = UserForm,
|
||||
master = {},
|
||||
id = $stateParams.user_id,
|
||||
defaultUrl = GetBasePath('users') + id;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.hidePagination = false;
|
||||
$scope.hideSmartSearch = false;
|
||||
$scope.user_type_options = user_type_options;
|
||||
$scope.user_type = user_type_options[0];
|
||||
$scope.$watch('user_type', user_type_sync($scope));
|
||||
$scope.$watch('is_superuser', hidePermissionsTabSmartSearchAndPaginationIfSuperUser($scope));
|
||||
Rest.setUrl(defaultUrl);
|
||||
Wait('start');
|
||||
Rest.get(defaultUrl).success(function(data) {
|
||||
$scope.user_id = id;
|
||||
$scope.ldap_user = (data.ldap_dn !== null && data.ldap_dn !== undefined && data.ldap_dn !== '') ? true : false;
|
||||
$scope.not_ldap_user = !$scope.ldap_user;
|
||||
master.ldap_user = $scope.ldap_user;
|
||||
$scope.socialAuthUser = (data.auth.length > 0) ? true : false;
|
||||
$scope.external_account = data.external_account;
|
||||
|
||||
$scope.user_type = $scope.user_type_options[0];
|
||||
$scope.is_system_auditor = false;
|
||||
$scope.is_superuser = false;
|
||||
if (data.is_system_auditor) {
|
||||
$scope.user_type = $scope.user_type_options[1];
|
||||
$scope.is_system_auditor = true;
|
||||
}
|
||||
if (data.is_superuser) {
|
||||
$scope.user_type = $scope.user_type_options[2];
|
||||
$scope.is_superuser = true;
|
||||
}
|
||||
|
||||
$scope.user_obj = data;
|
||||
$scope.name = data.username;
|
||||
|
||||
CreateSelect2({
|
||||
element: '#user_user_type',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
$scope.$watch('user_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||
if (val === false) {
|
||||
$scope.canAdd = false;
|
||||
}
|
||||
});
|
||||
|
||||
setScopeFields(data);
|
||||
Wait('stop');
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Failed to retrieve user: %s. GET status: '), $stateParams.id) + status
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Organizations and Teams tab pagination is hidden through other mechanism
|
||||
function hidePermissionsTabSmartSearchAndPaginationIfSuperUser(scope) {
|
||||
return function(isSuperuserNewValue) {
|
||||
let shouldHide = isSuperuserNewValue;
|
||||
if (shouldHide === true) {
|
||||
scope.hidePagination = true;
|
||||
scope.hideSmartSearch = true;
|
||||
} else if (shouldHide === false) {
|
||||
scope.hidePagination = false;
|
||||
scope.hideSmartSearch = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function setScopeFields(data) {
|
||||
_(data)
|
||||
.pick(function(value, key) {
|
||||
return form.fields.hasOwnProperty(key) === true;
|
||||
})
|
||||
.forEach(function(value, key) {
|
||||
$scope[key] = value;
|
||||
})
|
||||
.value();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.convertApiUrl = function(str) {
|
||||
if (str) {
|
||||
return str.replace("api/v1", "#");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// prepares a data payload for a PUT request to the API
|
||||
var processNewData = function(fields) {
|
||||
var data = {};
|
||||
_.forEach(fields, function(value, key) {
|
||||
if ($scope[key] !== '' && $scope[key] !== null && $scope[key] !== undefined) {
|
||||
data[key] = $scope[key];
|
||||
}
|
||||
});
|
||||
data.is_superuser = $scope.is_superuser;
|
||||
data.is_system_auditor = $scope.is_system_auditor;
|
||||
return data;
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('users', null, { reload: true });
|
||||
};
|
||||
|
||||
$scope.formSave = function() {
|
||||
$rootScope.flashMessage = null;
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
Rest.setUrl(defaultUrl + '/');
|
||||
var data = processNewData(form.fields);
|
||||
Rest.put(data).success(function() {
|
||||
$state.go($state.current, null, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Failed to retrieve user: %s. GET status: '), $stateParams.id) + status
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clearPWConfirm = function(fld) {
|
||||
// If password value changes, make sure password_confirm must be re-entered
|
||||
$scope[fld] = '';
|
||||
$scope[form.name + '_form'][fld].$setValidity('awpassmatch', false);
|
||||
$rootScope.flashMessage = null;
|
||||
};
|
||||
}
|
||||
|
||||
UsersEdit.$inject = ['$scope', '$rootScope', '$location',
|
||||
'$stateParams', 'UserForm', 'Rest', 'ProcessErrors', 'ClearScope', 'GetBasePath',
|
||||
'ResetForm', 'Wait', 'CreateSelect2', '$state', 'i18n'
|
||||
];
|
||||
177
awx/ui/client/src/credentials/add/credentials-add.controller.js
Normal file
177
awx/ui/client/src/credentials/add/credentials-add.controller.js
Normal file
@ -0,0 +1,177 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$compile', '$location',
|
||||
'$log', '$stateParams', 'CredentialForm', 'GenerateForm', 'Rest', 'Alert',
|
||||
'ProcessErrors', 'ClearScope', 'GetBasePath', 'GetChoices', 'Empty', 'KindChange', 'BecomeMethodChange',
|
||||
'OwnerChange', 'FormSave', '$state', 'CreateSelect2', 'i18n',
|
||||
function($scope, $rootScope, $compile, $location, $log,
|
||||
$stateParams, CredentialForm, GenerateForm, Rest, Alert, ProcessErrors,
|
||||
ClearScope, GetBasePath, GetChoices, Empty, KindChange, BecomeMethodChange,
|
||||
OwnerChange, FormSave, $state, CreateSelect2, i18n) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
// Inject dynamic view
|
||||
var form = CredentialForm,
|
||||
defaultUrl = GetBasePath('credentials'),
|
||||
url;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
// Load the list of options for Kind
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'kind',
|
||||
variable: 'credential_kind_options'
|
||||
});
|
||||
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'become_method',
|
||||
variable: 'become_options'
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: '#credential_become_method',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: '#credential_kind',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
// apply form definition's default field values
|
||||
GenerateForm.applyDefaults(form, $scope);
|
||||
|
||||
$scope.keyEntered = false;
|
||||
$scope.permissionsTooltip = i18n._('Please save before assigning permissions');
|
||||
|
||||
// determine if the currently logged-in user may share this credential
|
||||
// previous commentary said: "$rootScope.current_user isn't available because a call to the config endpoint hasn't finished resolving yet"
|
||||
// I'm 99% sure this state's will never resolve block will be rejected if setup surrounding config endpoint hasn't completed
|
||||
if ($rootScope.current_user && $rootScope.current_user.is_superuser) {
|
||||
$scope.canShareCredential = true;
|
||||
} else {
|
||||
Rest.setUrl(`/api/v1/users/${$rootScope.current_user.id}/admin_of_organizations`);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.canShareCredential = (data.count) ? true : false;
|
||||
}).error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to find if users is admin of org' + status });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!Empty($stateParams.user_id)) {
|
||||
// Get the username based on incoming route
|
||||
$scope.owner = 'user';
|
||||
$scope.user = $stateParams.user_id;
|
||||
OwnerChange({ scope: $scope });
|
||||
url = GetBasePath('users') + $stateParams.user_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.user_username = data.username;
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve user. GET status: ' + status });
|
||||
});
|
||||
} else if (!Empty($stateParams.team_id)) {
|
||||
// Get the username based on incoming route
|
||||
$scope.owner = 'team';
|
||||
$scope.team = $stateParams.team_id;
|
||||
OwnerChange({ scope: $scope });
|
||||
url = GetBasePath('teams') + $stateParams.team_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.team_name = data.name;
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve team. GET status: ' + status });
|
||||
});
|
||||
} else {
|
||||
// default type of owner to a user
|
||||
$scope.owner = 'user';
|
||||
OwnerChange({ scope: $scope });
|
||||
}
|
||||
|
||||
$scope.$watch("ssh_key_data", function(val) {
|
||||
if (val === "" || val === null || val === undefined) {
|
||||
$scope.keyEntered = false;
|
||||
$scope.ssh_key_unlock_ask = false;
|
||||
$scope.ssh_key_unlock = "";
|
||||
} else {
|
||||
$scope.keyEntered = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Handle Kind change
|
||||
$scope.kindChange = function() {
|
||||
KindChange({ scope: $scope, form: form, reset: true });
|
||||
};
|
||||
|
||||
$scope.becomeMethodChange = function() {
|
||||
BecomeMethodChange({ scope: $scope });
|
||||
};
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
FormSave({ scope: $scope, mode: 'add' });
|
||||
}
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('credentials');
|
||||
};
|
||||
|
||||
// Password change
|
||||
$scope.clearPWConfirm = function(fld) {
|
||||
// If password value changes, make sure password_confirm must be re-entered
|
||||
$scope[fld] = '';
|
||||
$scope[form.name + '_form'][fld].$setValidity('awpassmatch', false);
|
||||
};
|
||||
|
||||
// Respond to 'Ask at runtime?' checkbox
|
||||
$scope.ask = function(fld, associated) {
|
||||
if ($scope[fld + '_ask']) {
|
||||
$scope[fld] = 'ASK';
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "text");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Hide");
|
||||
if (associated !== "undefined") {
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "password");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Show");
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
}
|
||||
} else {
|
||||
$scope[fld] = '';
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "password");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Show");
|
||||
if (associated !== "undefined") {
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "text");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Hide");
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Click clear button
|
||||
$scope.clear = function(fld, associated) {
|
||||
$scope[fld] = '';
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
$scope[form.name + '_form'].$setDirty();
|
||||
};
|
||||
}
|
||||
];
|
||||
@ -0,0 +1,346 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$compile', '$location',
|
||||
'$log', '$stateParams', 'CredentialForm', 'Rest', 'Alert',
|
||||
'ProcessErrors', 'ClearScope', 'Prompt', 'GetBasePath', 'GetChoices',
|
||||
'KindChange', 'BecomeMethodChange', 'Empty', 'OwnerChange',
|
||||
'FormSave', 'Wait', '$state', 'CreateSelect2', 'Authorization', 'i18n',
|
||||
function($scope, $rootScope, $compile, $location, $log,
|
||||
$stateParams, CredentialForm, Rest, Alert, ProcessErrors, ClearScope, Prompt,
|
||||
GetBasePath, GetChoices, KindChange, BecomeMethodChange, Empty, OwnerChange, FormSave, Wait,
|
||||
$state, CreateSelect2, Authorization, i18n) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var defaultUrl = GetBasePath('credentials'),
|
||||
form = CredentialForm,
|
||||
base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
master = {},
|
||||
id = $stateParams.credential_id;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.id = id;
|
||||
$scope.$watch('credential_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||
if (val === false) {
|
||||
$scope.canAdd = false;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.canShareCredential = false;
|
||||
Wait('start');
|
||||
if (!$rootScope.current_user) {
|
||||
Authorization.restoreUserInfo();
|
||||
}
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'kind',
|
||||
variable: 'credential_kind_options',
|
||||
callback: 'choicesReadyCredential'
|
||||
});
|
||||
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'become_method',
|
||||
variable: 'become_options'
|
||||
});
|
||||
|
||||
if ($rootScope.current_user && $rootScope.current_user.is_superuser) {
|
||||
$scope.canShareCredential = true;
|
||||
} else {
|
||||
Rest.setUrl(`/api/v1/users/${$rootScope.current_user.id}/admin_of_organizations`);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
$scope.canShareCredential = (data.count) ? true : false;
|
||||
Wait('stop');
|
||||
}).error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to find if users is admin of org' + status });
|
||||
});
|
||||
}
|
||||
|
||||
$scope.$watch('organization', function(val) {
|
||||
if (val === undefined) {
|
||||
$scope.permissionsTooltip = i18n._('Credentials are only shared within an organization. Assign credentials to an organization to delegate credential permissions. The organization cannot be edited after credentials are assigned.');
|
||||
} else {
|
||||
$scope.permissionsTooltip = '';
|
||||
}
|
||||
});
|
||||
|
||||
setAskCheckboxes();
|
||||
OwnerChange({ scope: $scope });
|
||||
$scope.$watch("ssh_key_data", function(val) {
|
||||
if (val === "" || val === null || val === undefined) {
|
||||
$scope.keyEntered = false;
|
||||
$scope.ssh_key_unlock_ask = false;
|
||||
$scope.ssh_key_unlock = "";
|
||||
} else {
|
||||
$scope.keyEntered = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setAskCheckboxes() {
|
||||
var fld, i;
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].type === 'sensitive' && $scope[fld] === 'ASK') {
|
||||
// turn on 'ask' checkbox for password fields with value of 'ASK'
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "text");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Hide");
|
||||
$("#" + fld + "-clear-btn").attr("disabled", "disabled");
|
||||
$scope[fld + '_ask'] = true;
|
||||
} else {
|
||||
$scope[fld + '_ask'] = false;
|
||||
$("#" + fld + "-clear-btn").removeAttr("disabled");
|
||||
}
|
||||
master[fld + '_ask'] = $scope[fld + '_ask'];
|
||||
}
|
||||
|
||||
// Set kind field to the correct option
|
||||
for (i = 0; i < $scope.credential_kind_options.length; i++) {
|
||||
if ($scope.kind === $scope.credential_kind_options[i].value) {
|
||||
$scope.kind = $scope.credential_kind_options[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($scope.removeChoicesReady) {
|
||||
$scope.removeChoicesReady();
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReadyCredential', function() {
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(defaultUrl + ':id/');
|
||||
Rest.get({ params: { id: id } })
|
||||
.success(function(data) {
|
||||
if (data && data.summary_fields &&
|
||||
data.summary_fields.organization &&
|
||||
data.summary_fields.organization.id) {
|
||||
$scope.needsRoleList = true;
|
||||
} else {
|
||||
$scope.needsRoleList = false;
|
||||
}
|
||||
|
||||
$scope.credential_name = data.name;
|
||||
|
||||
var i, fld;
|
||||
|
||||
|
||||
for (fld in form.fields) {
|
||||
if (data[fld] !== null && data[fld] !== undefined) {
|
||||
$scope[fld] = data[fld];
|
||||
master[fld] = $scope[fld];
|
||||
}
|
||||
if (form.fields[fld].type === 'lookup' && data.summary_fields[form.fields[fld].sourceModel]) {
|
||||
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField];
|
||||
}
|
||||
}
|
||||
|
||||
if (!Empty($scope.user)) {
|
||||
$scope.owner = 'user';
|
||||
} else {
|
||||
$scope.owner = 'team';
|
||||
}
|
||||
master.owner = $scope.owner;
|
||||
|
||||
for (i = 0; i < $scope.become_options.length; i++) {
|
||||
if ($scope.become_options[i].value === data.become_method) {
|
||||
$scope.become_method = $scope.become_options[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.become_method && $scope.become_method.value === "") {
|
||||
$scope.become_method = null;
|
||||
}
|
||||
master.become_method = $scope.become_method;
|
||||
|
||||
$scope.$watch('become_method', function(val) {
|
||||
if (val !== null) {
|
||||
if (val.value === "") {
|
||||
$scope.become_username = "";
|
||||
$scope.become_password = "";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (i = 0; i < $scope.credential_kind_options.length; i++) {
|
||||
if ($scope.credential_kind_options[i].value === data.kind) {
|
||||
$scope.kind = $scope.credential_kind_options[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KindChange({
|
||||
scope: $scope,
|
||||
form: form,
|
||||
reset: false
|
||||
});
|
||||
|
||||
master.kind = $scope.kind;
|
||||
|
||||
CreateSelect2({
|
||||
element: '#credential_become_method',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: '#credential_kind',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
switch (data.kind) {
|
||||
case 'aws':
|
||||
$scope.access_key = data.username;
|
||||
$scope.secret_key = data.password;
|
||||
master.access_key = $scope.access_key;
|
||||
master.secret_key = $scope.secret_key;
|
||||
break;
|
||||
case 'ssh':
|
||||
$scope.ssh_password = data.password;
|
||||
master.ssh_password = $scope.ssh_password;
|
||||
break;
|
||||
case 'rax':
|
||||
$scope.api_key = data.password;
|
||||
master.api_key = $scope.api_key;
|
||||
break;
|
||||
case 'gce':
|
||||
$scope.email_address = data.username;
|
||||
$scope.project = data.project;
|
||||
break;
|
||||
case 'azure':
|
||||
$scope.subscription = data.username;
|
||||
break;
|
||||
}
|
||||
$scope.credential_obj = data;
|
||||
|
||||
$scope.$emit('credentialLoaded');
|
||||
Wait('stop');
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to retrieve Credential: ' + $stateParams.id + '. GET status: ' + status
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Save changes to the parent
|
||||
$scope.formSave = function() {
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
FormSave({ scope: $scope, mode: 'edit' });
|
||||
}
|
||||
};
|
||||
|
||||
// Handle Owner change
|
||||
$scope.ownerChange = function() {
|
||||
OwnerChange({ scope: $scope });
|
||||
};
|
||||
|
||||
// Handle Kind change
|
||||
$scope.kindChange = function() {
|
||||
KindChange({ scope: $scope, form: form, reset: true });
|
||||
};
|
||||
|
||||
$scope.becomeMethodChange = function() {
|
||||
BecomeMethodChange({ scope: $scope });
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.transitionTo('credentials');
|
||||
};
|
||||
|
||||
// Related set: Add button
|
||||
$scope.add = function(set) {
|
||||
$rootScope.flashMessage = null;
|
||||
$location.path('/' + base + '/' + $stateParams.id + '/' + set + '/add');
|
||||
};
|
||||
|
||||
// Related set: Edit button
|
||||
$scope.edit = function(set, id) {
|
||||
$rootScope.flashMessage = null;
|
||||
$location.path('/' + base + '/' + $stateParams.id + '/' + set + '/' + id);
|
||||
};
|
||||
|
||||
// Related set: Delete button
|
||||
$scope['delete'] = function(set, itm_id, name, title) {
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
var action = function() {
|
||||
var url = defaultUrl + id + '/' + set + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post({
|
||||
id: itm_id,
|
||||
disassociate: 1
|
||||
})
|
||||
.success(function() {
|
||||
$('#prompt-modal').modal('hide');
|
||||
// @issue: OLD SEARCH
|
||||
// $scope.search(form.related[set].iterator);
|
||||
})
|
||||
.error(function(data, status) {
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. POST returned status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: i18n._('Delete'),
|
||||
body: '<div class="Prompt-bodyQuery">' + i18n.sprintf(i18n._('Are you sure you want to remove the %s below from %s?'), title, $scope.name) + '</div><div class="Prompt-bodyTarget">' + name + '</div>',
|
||||
action: action,
|
||||
actionText: i18n._('DELETE')
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// Password change
|
||||
$scope.clearPWConfirm = function(fld) {
|
||||
// If password value changes, make sure password_confirm must be re-entered
|
||||
$scope[fld] = '';
|
||||
$scope[form.name + '_form'][fld].$setValidity('awpassmatch', false);
|
||||
};
|
||||
|
||||
// Respond to 'Ask at runtime?' checkbox
|
||||
$scope.ask = function(fld, associated) {
|
||||
if ($scope[fld + '_ask']) {
|
||||
$scope[fld] = 'ASK';
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "text");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Hide");
|
||||
if (associated !== "undefined") {
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "password");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Show");
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
}
|
||||
} else {
|
||||
$scope[fld] = '';
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "password");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Show");
|
||||
if (associated !== "undefined") {
|
||||
$("#" + form.name + "_" + fld + "_input").attr("type", "text");
|
||||
$("#" + form.name + "_" + fld + "_show_input_button").html("Hide");
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clear = function(fld, associated) {
|
||||
$scope[fld] = '';
|
||||
$scope[associated] = '';
|
||||
$scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
|
||||
$scope[form.name + '_form'].$setDirty();
|
||||
};
|
||||
}
|
||||
];
|
||||
@ -0,0 +1,106 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$location', '$log',
|
||||
'$stateParams', 'Rest', 'Alert', 'CredentialList', 'Prompt', 'ClearScope',
|
||||
'ProcessErrors', 'GetBasePath', 'Wait', '$state', '$filter', 'rbacUiControlService', 'Dataset', 'i18n',
|
||||
function($scope, $rootScope, $location, $log,
|
||||
$stateParams, Rest, Alert, CredentialList, Prompt, ClearScope,
|
||||
ProcessErrors, GetBasePath, Wait, $state, $filter, rbacUiControlService, Dataset,
|
||||
i18n) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var list = CredentialList,
|
||||
defaultUrl = GetBasePath('credentials');
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
rbacUiControlService.canAdd('credentials')
|
||||
.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;
|
||||
|
||||
$scope.selected = [];
|
||||
}
|
||||
|
||||
$scope.$on(`${list.iterator}_options`, function(event, data){
|
||||
$scope.options = data.data.actions.GET;
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
$scope.$watchCollection(`${$scope.list.name}`, function() {
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
// iterate over the list and add fields like type label, after the
|
||||
// OPTIONS request returns, or the list is sorted/paginated/searched
|
||||
function optionsRequestDataProcessing(){
|
||||
if ($scope[list.name] !== undefined) {
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
|
||||
// Set the item type label
|
||||
if (list.fields.kind && $scope.options &&
|
||||
$scope.options.hasOwnProperty('kind')) {
|
||||
$scope.options.kind.choices.every(function(choice) {
|
||||
if (choice[0] === item.kind) {
|
||||
itm.kind_label = choice[1];
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.addCredential = function() {
|
||||
$state.go('credentials.add');
|
||||
};
|
||||
|
||||
$scope.editCredential = function(id) {
|
||||
$state.go('credentials.edit', { credential_id: id });
|
||||
};
|
||||
|
||||
$scope.deleteCredential = function(id, name) {
|
||||
var action = function() {
|
||||
$('#prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function() {
|
||||
if (parseInt($state.params.credential_id) === id) {
|
||||
$state.go("^", null, { reload: true });
|
||||
} else {
|
||||
$state.go('.', null, {reload: true});
|
||||
}
|
||||
Wait('stop');
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: i18n._('Delete'),
|
||||
body: '<div class="Prompt-bodyQuery">' + i18n._('Are you sure you want to delete the credential below?') + '</div><div class="Prompt-bodyTarget">' + $filter('sanitize')(name) + '</div>',
|
||||
action: action,
|
||||
actionText: i18n._('DELETE')
|
||||
});
|
||||
};
|
||||
}
|
||||
];
|
||||
@ -5,7 +5,45 @@
|
||||
*************************************************/
|
||||
|
||||
import ownerList from './ownerList.directive';
|
||||
import CredentialsList from './list/credentials-list.controller';
|
||||
import CredentialsAdd from './add/credentials-add.controller';
|
||||
import CredentialsEdit from './edit/credentials-edit.controller';
|
||||
import { N_ } from '../i18n';
|
||||
|
||||
export default
|
||||
angular.module('credentials', [])
|
||||
.directive('ownerList', ownerList);
|
||||
.directive('ownerList', ownerList)
|
||||
.controller('CredentialsList', CredentialsList)
|
||||
.controller('CredentialsAdd', CredentialsAdd)
|
||||
.controller('CredentialsEdit', CredentialsEdit)
|
||||
.config(['$stateProvider', 'stateDefinitionsProvider',
|
||||
function($stateProvider, stateDefinitionsProvider) {
|
||||
let stateDefinitions = stateDefinitionsProvider.$get();
|
||||
|
||||
// lazily generate a tree of substates which will replace this node in ui-router's stateRegistry
|
||||
// see: stateDefinition.factory for usage documentation
|
||||
$stateProvider.state({
|
||||
name: 'credentials',
|
||||
url: '/credentials',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
parent: 'credentials',
|
||||
modes: ['add', 'edit'],
|
||||
list: 'CredentialList',
|
||||
form: 'CredentialForm',
|
||||
controllers: {
|
||||
list: CredentialsList,
|
||||
add: CredentialsAdd,
|
||||
edit: CredentialsEdit
|
||||
},
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'credential'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: 'setup',
|
||||
label: N_('CREDENTIALS')
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import "../../shared/branding/colors.default.less";
|
||||
@import "../../../shared/branding/colors.default.less";
|
||||
|
||||
/** @define DashboardCounts */
|
||||
|
||||
@ -9,7 +9,7 @@ export default
|
||||
data: '='
|
||||
},
|
||||
replace: false,
|
||||
templateUrl: templateUrl('dashboard/counts/dashboard-counts'),
|
||||
templateUrl: templateUrl('home/dashboard/counts/dashboard-counts'),
|
||||
link: function(scope, element, attrs) {
|
||||
scope.$watch("data", function(data) {
|
||||
if (data && data.hosts) {
|
||||
@ -1,5 +1,5 @@
|
||||
/** @define Dashboard */
|
||||
@import "../shared/branding/colors.default.less";
|
||||
@import "../../shared/branding/colors.default.less";
|
||||
|
||||
.Dashboard {
|
||||
display: flex;
|
||||
@ -5,7 +5,7 @@ export default
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: true,
|
||||
templateUrl: templateUrl('dashboard/dashboard'),
|
||||
templateUrl: templateUrl('home/dashboard/dashboard'),
|
||||
link: function(scope, element, attrs) {
|
||||
}
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
/** @define DashboardGraphs */
|
||||
|
||||
@import "../../shared/branding/colors.default.less";
|
||||
@import "../../../shared/branding/colors.default.less";
|
||||
|
||||
.DashboardGraphs {
|
||||
margin-top: 20px;
|
||||
@ -4,7 +4,7 @@ export default ['templateUrl',
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: true,
|
||||
templateUrl: templateUrl('dashboard/graphs/dashboard-graphs'),
|
||||
templateUrl: templateUrl('home/dashboard/graphs/dashboard-graphs'),
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
function clearStatus() {
|
||||
@ -23,7 +23,7 @@ function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustG
|
||||
scope: {
|
||||
data: '='
|
||||
},
|
||||
templateUrl: templateUrl('dashboard/graphs/job-status/job_status_graph'),
|
||||
templateUrl: templateUrl('home/dashboard/graphs/job-status/job_status_graph'),
|
||||
link: link
|
||||
};
|
||||
|
||||
|
Before Width: | Height: | Size: 39 B After Width: | Height: | Size: 39 B |
@ -1,7 +1,7 @@
|
||||
import JobStatusGraphDirective from './job-status-graph.directive';
|
||||
import JobStatusGraphService from './job-status-graph.service';
|
||||
import DashboardGraphHelpers from '../graph-helpers/main';
|
||||
import templateUrl from '../../../shared/template-url/main';
|
||||
import templateUrl from '../../../../shared/template-url/main';
|
||||
|
||||
export default angular.module('JobStatusGraph', [DashboardGraphHelpers.name, templateUrl.name])
|
||||
.directive('jobStatusGraph', JobStatusGraphDirective)
|
||||
@ -9,7 +9,7 @@ import form from './dashboard-hosts.form';
|
||||
import listController from './dashboard-hosts-list.controller';
|
||||
import editController from './dashboard-hosts-edit.controller';
|
||||
import service from './dashboard-hosts.service';
|
||||
import { N_ } from '../../i18n';
|
||||
import { N_ } from '../../../i18n';
|
||||
|
||||
export default
|
||||
angular.module('dashboardHosts', [])
|
||||
@ -1,6 +1,6 @@
|
||||
/** @define DashboardList */
|
||||
|
||||
@import "../../shared/branding/colors.default.less";
|
||||
@import "../../../shared/branding/colors.default.less";
|
||||
|
||||
.DashboardList {
|
||||
flex: 1;
|
||||
@ -11,7 +11,7 @@ export default
|
||||
scope: {
|
||||
data: '='
|
||||
},
|
||||
templateUrl: templateUrl('dashboard/lists/job-templates/job-templates-list')
|
||||
templateUrl: templateUrl('home/dashboard/lists/job-templates/job-templates-list')
|
||||
};
|
||||
|
||||
function link(scope, element, attr) {
|
||||
@ -1,6 +1,6 @@
|
||||
import JobTemplatesListDirective from './job-templates-list.directive';
|
||||
import systemStatus from '../../../smart-status/main';
|
||||
import jobSubmissionHelper from '../../../helpers/JobSubmission';
|
||||
import systemStatus from '../../../../smart-status/main';
|
||||
import jobSubmissionHelper from '../../../../helpers/JobSubmission';
|
||||
|
||||
export default angular.module('JobTemplatesList', [systemStatus.name, jobSubmissionHelper.name])
|
||||
.directive('jobTemplatesList', JobTemplatesListDirective);
|
||||
@ -10,7 +10,7 @@ export default
|
||||
scope: {
|
||||
data: '='
|
||||
},
|
||||
templateUrl: templateUrl('dashboard/lists/jobs/jobs-list')
|
||||
templateUrl: templateUrl('home/dashboard/lists/jobs/jobs-list')
|
||||
};
|
||||
|
||||
function link(scope, element, attr) {
|
||||
125
awx/ui/client/src/home/home.controller.js
Normal file
125
awx/ui/client/src/home/home.controller.js
Normal file
@ -0,0 +1,125 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$compile', '$stateParams', '$rootScope', '$location', '$log','Wait',
|
||||
'ClearScope', 'Rest', 'GetBasePath', 'ProcessErrors', '$window', 'graphData',
|
||||
function($scope, $compile, $stateParams, $rootScope, $location, $log, Wait,
|
||||
ClearScope, Rest, GetBasePath, ProcessErrors, $window, graphData) {
|
||||
|
||||
ClearScope('home');
|
||||
|
||||
var dataCount = 0;
|
||||
|
||||
$scope.$on('ws-jobs', function () {
|
||||
Rest.setUrl(GetBasePath('dashboard'));
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$scope.dashboardData = data;
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard host graph data: ' + status });
|
||||
});
|
||||
|
||||
Rest.setUrl(GetBasePath("jobs") + "?order_by=-finished&page_size=5&finished__isnull=false");
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$scope.dashboardJobsListData = data.results;
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard jobs list: ' + status });
|
||||
});
|
||||
|
||||
Rest.setUrl(GetBasePath("unified_job_templates") + "?order_by=-last_job_run&page_size=5&last_job_run__isnull=false&type=workflow_job_template,job_template");
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$scope.dashboardJobTemplatesListData = data.results;
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard jobs list: ' + status });
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
if ($scope.removeDashboardDataLoadComplete) {
|
||||
$scope.removeDashboardDataLoadComplete();
|
||||
}
|
||||
$scope.removeDashboardDataLoadComplete = $scope.$on('dashboardDataLoadComplete', function () {
|
||||
dataCount++;
|
||||
if (dataCount === 3) {
|
||||
Wait("stop");
|
||||
dataCount = 0;
|
||||
}
|
||||
});
|
||||
|
||||
if ($scope.removeDashboardReady) {
|
||||
$scope.removeDashboardReady();
|
||||
}
|
||||
$scope.removeDashboardReady = $scope.$on('dashboardReady', function (e, data) {
|
||||
$scope.dashboardCountsData = data;
|
||||
$scope.graphData = graphData;
|
||||
$scope.$emit('dashboardDataLoadComplete');
|
||||
|
||||
var cleanupJobListener =
|
||||
$rootScope.$on('DataReceived:JobStatusGraph', function(e, data) {
|
||||
$scope.graphData.jobStatus = data;
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
cleanupJobListener();
|
||||
});
|
||||
});
|
||||
|
||||
if ($scope.removeDashboardJobsListReady) {
|
||||
$scope.removeDashboardJobsListReady();
|
||||
}
|
||||
$scope.removeDashboardJobsListReady = $scope.$on('dashboardJobsListReady', function (e, data) {
|
||||
$scope.dashboardJobsListData = data;
|
||||
$scope.$emit('dashboardDataLoadComplete');
|
||||
});
|
||||
|
||||
if ($scope.removeDashboardJobTemplatesListReady) {
|
||||
$scope.removeDashboardJobTemplatesListReady();
|
||||
}
|
||||
$scope.removeDashboardJobTemplatesListReady = $scope.$on('dashboardJobTemplatesListReady', function (e, data) {
|
||||
$scope.dashboardJobTemplatesListData = data;
|
||||
$scope.$emit('dashboardDataLoadComplete');
|
||||
});
|
||||
|
||||
$scope.refresh = function () {
|
||||
Wait('start');
|
||||
Rest.setUrl(GetBasePath('dashboard'));
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
$scope.dashboardData = data;
|
||||
$scope.$emit('dashboardReady', data);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard: ' + status });
|
||||
});
|
||||
Rest.setUrl(GetBasePath("jobs") + "?order_by=-finished&page_size=5&finished__isnull=false");
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
data = data.results;
|
||||
$scope.$emit('dashboardJobsListReady', data);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard jobs list: ' + status });
|
||||
});
|
||||
Rest.setUrl(GetBasePath("unified_job_templates") + "?order_by=-last_job_run&page_size=5&last_job_run__isnull=false&type=workflow_job_template,job_template");
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
data = data.results;
|
||||
$scope.$emit('dashboardJobTemplatesListReady', data);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard job templates list: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
|
||||
}
|
||||
];
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
<div class="tab-pane" id="home">
|
||||
<div ng-cloak id="htmlTemplate">
|
||||
<dashboard></dashboard>
|
||||
46
awx/ui/client/src/home/home.route.js
Normal file
46
awx/ui/client/src/home/home.route.js
Normal file
@ -0,0 +1,46 @@
|
||||
import {templateUrl} from '../shared/template-url/template-url.factory';
|
||||
import controller from './home.controller';
|
||||
import { N_ } from '../i18n';
|
||||
|
||||
export default {
|
||||
name: 'dashboard',
|
||||
url: '/home',
|
||||
templateUrl: templateUrl('home/home'),
|
||||
controller: controller,
|
||||
params: { licenseMissing: null },
|
||||
data: {
|
||||
activityStream: true,
|
||||
refreshButton: true,
|
||||
socket: {
|
||||
"groups": {
|
||||
"jobs": ["status_changed"]
|
||||
}
|
||||
},
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: N_("DASHBOARD")
|
||||
},
|
||||
resolve: {
|
||||
graphData: ['$q', 'jobStatusGraphData', '$rootScope',
|
||||
function($q, jobStatusGraphData, $rootScope) {
|
||||
return $rootScope.featuresConfigured.promise.then(function() {
|
||||
return $q.all({
|
||||
jobStatus: jobStatusGraphData.get("month", "all"),
|
||||
});
|
||||
});
|
||||
}
|
||||
]
|
||||
}
|
||||
// name: 'setup.about',
|
||||
// route: '/about',
|
||||
// controller: controller,
|
||||
// ncyBreadcrumb: {
|
||||
// label: N_("ABOUT")
|
||||
// },
|
||||
// onExit: function(){
|
||||
// // hacky way to handle user browsing away via URL bar
|
||||
// $('.modal-backdrop').remove();
|
||||
// $('body').removeClass('modal-open');
|
||||
// },
|
||||
// templateUrl: templateUrl('about/about')
|
||||
};
|
||||
12
awx/ui/client/src/home/main.js
Normal file
12
awx/ui/client/src/home/main.js
Normal file
@ -0,0 +1,12 @@
|
||||
import dashboard from './dashboard/main';
|
||||
import HomeController from './home.controller';
|
||||
import route from './home.route';
|
||||
|
||||
export default
|
||||
angular.module('home', [
|
||||
dashboard.name
|
||||
])
|
||||
.controller('HomeController', HomeController)
|
||||
.run(['$stateExtender', function($stateExtender){
|
||||
$stateExtender.addState(route);
|
||||
}]);
|
||||
154
awx/ui/client/src/projects/add/projects-add.controller.js
Normal file
154
awx/ui/client/src/projects/add/projects-add.controller.js
Normal file
@ -0,0 +1,154 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$compile', '$location', '$log',
|
||||
'$stateParams', 'GenerateForm', 'ProjectsForm', 'Rest', 'Alert', 'ProcessErrors', 'GetBasePath',
|
||||
'GetProjectPath', 'GetChoices', 'Wait', '$state', 'CreateSelect2', 'i18n',
|
||||
function($scope, $rootScope, $compile, $location, $log,
|
||||
$stateParams, GenerateForm, ProjectsForm, Rest, Alert, ProcessErrors,
|
||||
GetBasePath, GetProjectPath, GetChoices, Wait, $state, CreateSelect2, i18n) {
|
||||
|
||||
var form = ProjectsForm(),
|
||||
base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
defaultUrl = GetBasePath('projects'),
|
||||
master = {};
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
Rest.setUrl(GetBasePath('projects'));
|
||||
Rest.options()
|
||||
.success(function(data) {
|
||||
if (!data.actions.POST) {
|
||||
$state.go("^");
|
||||
Alert(i18n._('Permission Error'), i18n._('You do not have permission to add a project.'), 'alert-info');
|
||||
}
|
||||
});
|
||||
|
||||
// apply form definition's default field values
|
||||
GenerateForm.applyDefaults(form, $scope);
|
||||
}
|
||||
|
||||
GetProjectPath({ scope: $scope, master: master });
|
||||
|
||||
if ($scope.removeChoicesReady) {
|
||||
$scope.removeChoicesReady();
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReady', function() {
|
||||
var i;
|
||||
for (i = 0; i < $scope.scm_type_options.length; i++) {
|
||||
if ($scope.scm_type_options[i].value === '') {
|
||||
$scope.scm_type_options[i].value = "manual";
|
||||
//$scope.scm_type = $scope.scm_type_options[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CreateSelect2({
|
||||
element: '#project_scm_type',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
$scope.scmRequired = false;
|
||||
master.scm_type = $scope.scm_type;
|
||||
});
|
||||
|
||||
// Load the list of options for Kind
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'scm_type',
|
||||
variable: 'scm_type_options',
|
||||
callback: 'choicesReady'
|
||||
});
|
||||
CreateSelect2({
|
||||
element: '#local-path-select',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
var i, fld, url, data = {};
|
||||
data = {};
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].type === 'checkbox_group') {
|
||||
for (i = 0; i < form.fields[fld].fields.length; i++) {
|
||||
data[form.fields[fld].fields[i].name] = $scope[form.fields[fld].fields[i].name];
|
||||
}
|
||||
} else {
|
||||
if (form.fields[fld].type !== 'alertblock') {
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.scm_type.value === "manual") {
|
||||
data.scm_type = "";
|
||||
data.local_path = $scope.local_path.value;
|
||||
} else {
|
||||
data.scm_type = $scope.scm_type.value;
|
||||
delete data.local_path;
|
||||
}
|
||||
|
||||
url = (base === 'teams') ? GetBasePath('teams') + $stateParams.team_id + '/projects/' : defaultUrl;
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.post(data)
|
||||
.success(function(data) {
|
||||
$scope.addedItem = data.id;
|
||||
$state.go('projects.edit', { project_id: data.id }, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'),
|
||||
msg: i18n._('Failed to create new project. POST returned status: ') + status });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.scmChange = function() {
|
||||
// When an scm_type is set, path is not required
|
||||
if ($scope.scm_type) {
|
||||
$scope.pathRequired = ($scope.scm_type.value === 'manual') ? true : false;
|
||||
$scope.scmRequired = ($scope.scm_type.value !== 'manual') ? true : false;
|
||||
$scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? 'Revision #' : 'SCM Branch';
|
||||
}
|
||||
|
||||
// Dynamically update popover values
|
||||
if ($scope.scm_type.value) {
|
||||
switch ($scope.scm_type.value) {
|
||||
case 'git':
|
||||
$scope.urlPopover = '<p>' +
|
||||
i18n._('Example URLs for GIT SCM include:') +
|
||||
'</p><ul class=\"no-bullets\"><li>https://github.com/ansible/ansible.git</li>' +
|
||||
'<li>git@github.com:ansible/ansible.git</li><li>git://servername.example.com/ansible.git</li></ul>' +
|
||||
'<p>' + i18n.sprintf(i18n._('%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, ' +
|
||||
'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' +
|
||||
'SSH. GIT read only protocol (git://) does not use username or password information.'), '<strong>', '</strong>');
|
||||
break;
|
||||
case 'svn':
|
||||
$scope.urlPopover = '<p>' + i18n._('Example URLs for Subversion SCM include:') + '</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://github.com/ansible/ansible</li><li>svn://servername.example.com/path</li>' +
|
||||
'<li>svn+ssh://servername.example.com/path</li></ul>';
|
||||
break;
|
||||
case 'hg':
|
||||
$scope.urlPopover = '<p>' + i18n._('Example URLs for Mercurial SCM include:') + '</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://bitbucket.org/username/project</li><li>ssh://hg@bitbucket.org/username/project</li>' +
|
||||
'<li>ssh://server.example.com/path</li></ul>' +
|
||||
'<p>' + i18n.sprintf(i18n._('%sNote:%s Mercurial does not support password authentication for SSH. ' +
|
||||
'Do not put the username and key in the URL. ' +
|
||||
'If using Bitbucket and SSH, do not supply your Bitbucket username.'), '<strong>', '</strong>');
|
||||
break;
|
||||
default:
|
||||
$scope.urlPopover = '<p> ' + i18n._('URL popover text');
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
$scope.formCancel = function() {
|
||||
$state.go('projects');
|
||||
};
|
||||
}
|
||||
];
|
||||
297
awx/ui/client/src/projects/edit/projects-edit.controller.js
Normal file
297
awx/ui/client/src/projects/edit/projects-edit.controller.js
Normal file
@ -0,0 +1,297 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$compile', '$location', '$log',
|
||||
'$stateParams', 'ProjectsForm', 'Rest', 'Alert', 'ProcessErrors', 'GenerateForm',
|
||||
'Prompt', 'ClearScope', 'GetBasePath', 'GetProjectPath', 'Authorization', 'GetChoices', 'Empty',
|
||||
'DebugForm', 'Wait', 'ProjectUpdate', '$state', 'CreateSelect2', 'ToggleNotification', 'i18n',
|
||||
function($scope, $rootScope, $compile, $location, $log,
|
||||
$stateParams, ProjectsForm, Rest, Alert, ProcessErrors, GenerateForm,
|
||||
Prompt, ClearScope, GetBasePath, GetProjectPath, Authorization,
|
||||
GetChoices, Empty, DebugForm, Wait, ProjectUpdate, $state, CreateSelect2, ToggleNotification, i18n) {
|
||||
|
||||
ClearScope('htmlTemplate');
|
||||
|
||||
var form = ProjectsForm(),
|
||||
defaultUrl = GetBasePath('projects') + $stateParams.project_id + '/',
|
||||
master = {},
|
||||
id = $stateParams.project_id;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.project_local_paths = [];
|
||||
$scope.base_dir = '';
|
||||
}
|
||||
|
||||
$scope.$watch('project_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||
if (val === false) {
|
||||
$scope.canAdd = false;
|
||||
}
|
||||
});
|
||||
|
||||
if ($scope.pathsReadyRemove) {
|
||||
$scope.pathsReadyRemove();
|
||||
}
|
||||
$scope.pathsReadyRemove = $scope.$on('pathsReady', function () {
|
||||
CreateSelect2({
|
||||
element: '#local-path-select',
|
||||
multiple: false
|
||||
});
|
||||
});
|
||||
|
||||
// After the project is loaded, retrieve each related set
|
||||
if ($scope.projectLoadedRemove) {
|
||||
$scope.projectLoadedRemove();
|
||||
}
|
||||
$scope.projectLoadedRemove = $scope.$on('projectLoaded', function() {
|
||||
var opts = [];
|
||||
|
||||
if (Authorization.getUserInfo('is_superuser') === true) {
|
||||
GetProjectPath({ scope: $scope, master: master });
|
||||
} else {
|
||||
opts.push({
|
||||
label: $scope.local_path,
|
||||
value: $scope.local_path
|
||||
});
|
||||
$scope.project_local_paths = opts;
|
||||
$scope.local_path = $scope.project_local_paths[0];
|
||||
$scope.base_dir = i18n._('You do not have access to view this property');
|
||||
$scope.$emit('pathsReady');
|
||||
}
|
||||
|
||||
$scope.pathRequired = ($scope.scm_type.value === 'manual') ? true : false;
|
||||
$scope.scmRequired = ($scope.scm_type.value !== 'manual') ? true : false;
|
||||
$scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? 'Revision #' : 'SCM Branch';
|
||||
Wait('stop');
|
||||
|
||||
$scope.scmChange();
|
||||
});
|
||||
|
||||
if ($scope.removeChoicesReady) {
|
||||
$scope.removeChoicesReady();
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReady', function() {
|
||||
let i;
|
||||
for (i = 0; i < $scope.scm_type_options.length; i++) {
|
||||
if ($scope.scm_type_options[i].value === '') {
|
||||
$scope.scm_type_options[i].value = "manual";
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.get({ params: { id: id } })
|
||||
.success(function(data) {
|
||||
var fld, i;
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].type === 'checkbox_group') {
|
||||
for (i = 0; i < form.fields[fld].fields.length; i++) {
|
||||
$scope[form.fields[fld].fields[i].name] = data[form.fields[fld].fields[i].name];
|
||||
master[form.fields[fld].fields[i].name] = data[form.fields[fld].fields[i].name];
|
||||
}
|
||||
} else {
|
||||
if (data[fld] !== undefined) {
|
||||
$scope[fld] = data[fld];
|
||||
master[fld] = data[fld];
|
||||
}
|
||||
}
|
||||
if (form.fields[fld].sourceModel && data.summary_fields &&
|
||||
data.summary_fields[form.fields[fld].sourceModel]) {
|
||||
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
}
|
||||
}
|
||||
|
||||
data.scm_type = (Empty(data.scm_type)) ? 'manual' : data.scm_type;
|
||||
for (i = 0; i < $scope.scm_type_options.length; i++) {
|
||||
if ($scope.scm_type_options[i].value === data.scm_type) {
|
||||
$scope.scm_type = $scope.scm_type_options[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.scm_type.value !== 'manual') {
|
||||
$scope.pathRequired = false;
|
||||
$scope.scmRequired = true;
|
||||
} else {
|
||||
$scope.pathRequired = true;
|
||||
$scope.scmRequired = false;
|
||||
}
|
||||
|
||||
master.scm_type = $scope.scm_type;
|
||||
CreateSelect2({
|
||||
element: '#project_scm_type',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
$scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? 'Revision #' : 'SCM Branch';
|
||||
$scope.scm_update_tooltip = i18n._("Start an SCM update");
|
||||
$scope.scm_type_class = "";
|
||||
if (data.status === 'running' || data.status === 'updating') {
|
||||
$scope.scm_update_tooltip = i18n._("SCM update currently running");
|
||||
$scope.scm_type_class = "btn-disabled";
|
||||
}
|
||||
if (Empty(data.scm_type)) {
|
||||
$scope.scm_update_tooltip = i18n._('Manual projects do not require an SCM update');
|
||||
$scope.scm_type_class = "btn-disabled";
|
||||
}
|
||||
|
||||
$scope.project_obj = data;
|
||||
$scope.name = data.name;
|
||||
$scope.$emit('projectLoaded');
|
||||
Wait('stop');
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Failed to retrieve project: %s. GET status: '), id) + status
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Load the list of options for Kind
|
||||
Wait('start');
|
||||
GetChoices({
|
||||
url: GetBasePath('projects'),
|
||||
scope: $scope,
|
||||
field: 'scm_type',
|
||||
variable: 'scm_type_options',
|
||||
callback: 'choicesReady'
|
||||
});
|
||||
|
||||
$scope.toggleNotification = function(event, id, column) {
|
||||
var notifier = this.notification;
|
||||
try {
|
||||
$(event.target).tooltip('hide');
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
ToggleNotification({
|
||||
scope: $scope,
|
||||
url: $scope.project_obj.url,
|
||||
notifier: notifier,
|
||||
column: column,
|
||||
callback: 'NotificationRefresh'
|
||||
});
|
||||
};
|
||||
|
||||
// Save changes to the parent
|
||||
$scope.formSave = function() {
|
||||
var fld, i, params;
|
||||
GenerateForm.clearApiErrors($scope);
|
||||
Wait('start');
|
||||
$rootScope.flashMessage = null;
|
||||
params = {};
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].type === 'checkbox_group') {
|
||||
for (i = 0; i < form.fields[fld].fields.length; i++) {
|
||||
params[form.fields[fld].fields[i].name] = $scope[form.fields[fld].fields[i].name];
|
||||
}
|
||||
} else {
|
||||
if (form.fields[fld].type !== 'alertblock') {
|
||||
params[fld] = $scope[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.scm_type.value === "manual") {
|
||||
params.scm_type = "";
|
||||
params.local_path = $scope.local_path.value;
|
||||
} else {
|
||||
params.scm_type = $scope.scm_type.value;
|
||||
delete params.local_path;
|
||||
}
|
||||
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.put(params)
|
||||
.success(function() {
|
||||
Wait('stop');
|
||||
$state.go($state.current, {}, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Failed to update project: %s. PUT status: '), id) + status });
|
||||
});
|
||||
};
|
||||
|
||||
// Related set: Delete button
|
||||
$scope['delete'] = function(set, itm_id, name, title) {
|
||||
var action = function() {
|
||||
var url = GetBasePath('projects') + id + '/' + set + '/';
|
||||
$rootScope.flashMessage = null;
|
||||
Rest.setUrl(url);
|
||||
Rest.post({ id: itm_id, disassociate: 1 })
|
||||
.success(function() {
|
||||
$('#prompt-modal').modal('hide');
|
||||
// @issue: OLD SEARCH
|
||||
// $scope.search(form.related[set].iterator);
|
||||
})
|
||||
.error(function(data, status) {
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. POST returned status: '), url) + status });
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: i18n._('Delete'),
|
||||
body: '<div class="Prompt-bodyQuery">' + i18n.sprintf(i18n._('Are you sure you want to remove the %s below from %s?'), title, $scope.name) + '</div>' + '<div class="Prompt-bodyTarget">' + name + '</div>',
|
||||
action: action,
|
||||
actionText: i18n._('DELETE')
|
||||
});
|
||||
};
|
||||
|
||||
$scope.scmChange = function() {
|
||||
if ($scope.scm_type) {
|
||||
$scope.pathRequired = ($scope.scm_type.value === 'manual') ? true : false;
|
||||
$scope.scmRequired = ($scope.scm_type.value !== 'manual') ? true : false;
|
||||
$scope.scmBranchLabel = ($scope.scm_type.value === 'svn') ? i18n._('Revision #') : i18n._('SCM Branch');
|
||||
}
|
||||
|
||||
// Dynamically update popover values
|
||||
if ($scope.scm_type.value) {
|
||||
switch ($scope.scm_type.value) {
|
||||
case 'git':
|
||||
$scope.urlPopover = '<p>' + i18n._('Example URLs for GIT SCM include:') + '</p><ul class=\"no-bullets\"><li>https://github.com/ansible/ansible.git</li>' +
|
||||
'<li>git@github.com:ansible/ansible.git</li><li>git://servername.example.com/ansible.git</li></ul>' +
|
||||
'<p>' + i18n.sprintf(i18n._('%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, ' +
|
||||
'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' +
|
||||
'SSH. GIT read only protocol (git://) does not use username or password information.'), '<strong>', '</strong>');
|
||||
break;
|
||||
case 'svn':
|
||||
$scope.urlPopover = '<p>' + i18n._('Example URLs for Subversion SCM include:') + '</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://github.com/ansible/ansible</li><li>svn://servername.example.com/path</li>' +
|
||||
'<li>svn+ssh://servername.example.com/path</li></ul>';
|
||||
break;
|
||||
case 'hg':
|
||||
$scope.urlPopover = '<p>' + i18n._('Example URLs for Mercurial SCM include:') + '</p>' +
|
||||
'<ul class=\"no-bullets\"><li>https://bitbucket.org/username/project</li><li>ssh://hg@bitbucket.org/username/project</li>' +
|
||||
'<li>ssh://server.example.com/path</li></ul>' +
|
||||
'<p>' + i18n.sprintf(i18n._('%sNote:%s Mercurial does not support password authentication for SSH. ' +
|
||||
'Do not put the username and key in the URL. ' +
|
||||
'If using Bitbucket and SSH, do not supply your Bitbucket username.'), '<strong>', '</strong>');
|
||||
break;
|
||||
default:
|
||||
$scope.urlPopover = '<p> ' + i18n._('URL popover text');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.SCMUpdate = function() {
|
||||
if ($scope.project_obj.scm_type === "Manual" || Empty($scope.project_obj.scm_type)) {
|
||||
// ignore
|
||||
} else if ($scope.project_obj.status === 'updating' || $scope.project_obj.status === 'running' || $scope.project_obj.status === 'pending') {
|
||||
Alert(i18n._('Update in Progress'), i18n._('The SCM update process is running.'), 'alert-info');
|
||||
} else {
|
||||
ProjectUpdate({ scope: $scope, project_id: $scope.project_obj.id });
|
||||
}
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.transitionTo('projects');
|
||||
};
|
||||
}
|
||||
];
|
||||
299
awx/ui/client/src/projects/list/projects-list.controller.js
Normal file
299
awx/ui/client/src/projects/list/projects-list.controller.js
Normal file
@ -0,0 +1,299 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$location', '$log', '$stateParams',
|
||||
'Rest', 'Alert', 'ProjectList', 'Prompt', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
|
||||
'GetBasePath', 'ProjectUpdate', 'Wait', 'GetChoices', 'Empty', 'Find', 'GetProjectIcon',
|
||||
'GetProjectToolTip', '$filter', '$state', 'rbacUiControlService', 'Dataset', 'i18n', 'QuerySet',
|
||||
function($scope, $rootScope, $location, $log, $stateParams,
|
||||
Rest, Alert, ProjectList, Prompt, ReturnToCaller, ClearScope, ProcessErrors,
|
||||
GetBasePath, ProjectUpdate, Wait, GetChoices, Empty, Find, GetProjectIcon,
|
||||
GetProjectToolTip, $filter, $state, rbacUiControlService, Dataset, i18n, qs) {
|
||||
|
||||
var list = ProjectList,
|
||||
defaultUrl = GetBasePath('projects');
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.canAdd = false;
|
||||
|
||||
rbacUiControlService.canAdd('projects')
|
||||
.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;
|
||||
|
||||
_.forEach($scope[list.name], buildTooltips);
|
||||
$rootScope.flashMessage = null;
|
||||
}
|
||||
|
||||
$scope.$on(`${list.iterator}_options`, function(event, data){
|
||||
$scope.options = data.data.actions.GET;
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
$scope.$watchCollection(`${$scope.list.name}`, function() {
|
||||
optionsRequestDataProcessing();
|
||||
}
|
||||
);
|
||||
|
||||
// iterate over the list and add fields like type label, after the
|
||||
// OPTIONS request returns, or the list is sorted/paginated/searched
|
||||
function optionsRequestDataProcessing(){
|
||||
if ($scope[list.name] !== undefined) {
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
|
||||
// Set the item type label
|
||||
if (list.fields.scm_type && $scope.options &&
|
||||
$scope.options.hasOwnProperty('scm_type')) {
|
||||
$scope.options.scm_type.choices.every(function(choice) {
|
||||
if (choice[0] === item.scm_type) {
|
||||
itm.type_label = choice[1];
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
buildTooltips(itm);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function buildTooltips(project) {
|
||||
project.statusIcon = GetProjectIcon(project.status);
|
||||
project.statusTip = GetProjectToolTip(project.status);
|
||||
project.scm_update_tooltip = i18n._("Start an SCM update");
|
||||
project.scm_schedule_tooltip = i18n._("Schedule future SCM updates");
|
||||
project.scm_type_class = "";
|
||||
|
||||
if (project.status === 'failed' && project.summary_fields.last_update && project.summary_fields.last_update.status === 'canceled') {
|
||||
project.statusTip = i18n._('Canceled. Click for details');
|
||||
}
|
||||
|
||||
if (project.status === 'running' || project.status === 'updating') {
|
||||
project.scm_update_tooltip = i18n._("SCM update currently running");
|
||||
project.scm_type_class = "btn-disabled";
|
||||
}
|
||||
if (project.scm_type === 'manual') {
|
||||
project.scm_update_tooltip = i18n._('Manual projects do not require an SCM update');
|
||||
project.scm_schedule_tooltip = i18n._('Manual projects do not require a schedule');
|
||||
project.scm_type_class = 'btn-disabled';
|
||||
project.statusTip = i18n._('Not configured for SCM');
|
||||
project.statusIcon = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
$scope.reloadList = function(){
|
||||
let path = GetBasePath(list.basePath) || GetBasePath(list.name);
|
||||
qs.search(path, $stateParams[`${list.iterator}_search`])
|
||||
.then(function(searchResponse) {
|
||||
$scope[`${list.iterator}_dataset`] = searchResponse.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on(`ws-jobs`, 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.reloadList();
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$scope.addProject = function() {
|
||||
$state.go('projects.add');
|
||||
};
|
||||
|
||||
$scope.editProject = function(id) {
|
||||
$state.go('projects.edit', { project_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(i18n._('No Updates Available'), i18n._('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(i18n._('No SCM Configuration'), i18n._('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: i18n._('Error!'),
|
||||
msg: i18n._('Project lookup failed. GET returned: ') + status });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.deleteProject = function(id, name) {
|
||||
var action = function() {
|
||||
$('#prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function() {
|
||||
if (parseInt($state.params.project_id) === id) {
|
||||
$state.go("^", null, { reload: true });
|
||||
} else {
|
||||
$state.go('.', null, {reload: true});
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Call to %s failed. DELETE returned status: '), url) + status });
|
||||
})
|
||||
.finally(function() {
|
||||
Wait('stop');
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: i18n._('Delete'),
|
||||
body: '<div class="Prompt-bodyQuery">' + i18n._('Are you sure you want to delete the project below?') + '</div>' + '<div class="Prompt-bodyTarget">' + $filter('sanitize')(name) + '</div>',
|
||||
action: action,
|
||||
actionText: 'DELETE'
|
||||
});
|
||||
};
|
||||
|
||||
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(i18n._('SCM Update Cancel'), i18n._('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: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. POST status: '), url) + 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(i18n._('Cancel Not Allowed'), '<div>' + i18n.sprintf(i18n._('Either you do not have access or the SCM update process completed. ' +
|
||||
'Click the %sRefresh%s button to view the latest status.'), '<em>', '</em>') + '</div>', 'alert-info', null, null, null, null, true);
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. GET status: '), url) + 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: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Call to %s failed. GET status: '), data.related.current_update) + status });
|
||||
});
|
||||
} else {
|
||||
Alert(i18n._('Update Not Found'), '<div>' + i18n.sprintf(i18n._('An SCM update does not appear to be running for project: %s. Click the %sRefresh%s ' +
|
||||
'button to view the latest status.'), $filter('sanitize')(name), '<em>', '</em>') + '</div>', 'alert-info',undefined,undefined,undefined,undefined,true);
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'),
|
||||
msg: i18n._('Call to get project failed. GET status: ') + status });
|
||||
});
|
||||
};
|
||||
|
||||
$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)) && !(project.status === 'updating' || project.status === 'running' || project.status === 'pending')) {
|
||||
$state.go('projectSchedules', { id: id });
|
||||
}
|
||||
};
|
||||
}
|
||||
];
|
||||
51
awx/ui/client/src/projects/main.js
Normal file
51
awx/ui/client/src/projects/main.js
Normal file
@ -0,0 +1,51 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import ProjectsList from './list/projects-list.controller';
|
||||
import ProjectsAdd from './add/projects-add.controller';
|
||||
import ProjectsEdit from './edit/projects-edit.controller';
|
||||
import { N_ } from '../i18n';
|
||||
|
||||
export default
|
||||
angular.module('Projects', [])
|
||||
.controller('ProjectsList', ProjectsList)
|
||||
.controller('ProjectsAdd', ProjectsAdd)
|
||||
.controller('ProjectsEdit', ProjectsEdit)
|
||||
.config(['$stateProvider', 'stateDefinitionsProvider',
|
||||
function($stateProvider, stateDefinitionsProvider) {
|
||||
let stateDefinitions = stateDefinitionsProvider.$get();
|
||||
|
||||
// lazily generate a tree of substates which will replace this node in ui-router's stateRegistry
|
||||
// see: stateDefinition.factory for usage documentation
|
||||
$stateProvider.state({
|
||||
name: 'projects',
|
||||
url: '/projects',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
parent: 'projects', // top-most node in the generated tree (will replace this state definition)
|
||||
modes: ['add', 'edit'],
|
||||
list: 'ProjectList',
|
||||
form: 'ProjectsForm',
|
||||
controllers: {
|
||||
list: ProjectsList, // DI strings or objects
|
||||
add: ProjectsAdd,
|
||||
edit: ProjectsEdit
|
||||
},
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'project',
|
||||
socket: {
|
||||
"groups": {
|
||||
"jobs": ["status_changed"]
|
||||
}
|
||||
}
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: N_('PROJECTS')
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
]);
|
||||
68
awx/ui/client/src/teams/add/teams-add.controller.js
Normal file
68
awx/ui/client/src/teams/add/teams-add.controller.js
Normal file
@ -0,0 +1,68 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$stateParams', 'TeamForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'ClearScope', 'GetBasePath', 'Wait', '$state',
|
||||
function($scope, $rootScope, $stateParams, TeamForm, GenerateForm, Rest, Alert, ProcessErrors,
|
||||
ClearScope, GetBasePath, Wait, $state) {
|
||||
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//$scope.
|
||||
|
||||
Rest.setUrl(GetBasePath('teams'));
|
||||
Rest.options()
|
||||
.success(function(data) {
|
||||
if (!data.actions.POST) {
|
||||
$state.go("^");
|
||||
Alert('Permission Error', 'You do not have permission to add a team.', 'alert-info');
|
||||
}
|
||||
});
|
||||
|
||||
// Inject dynamic view
|
||||
var defaultUrl = GetBasePath('teams'),
|
||||
form = TeamForm;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
// apply form definition's default field values
|
||||
GenerateForm.applyDefaults(form, $scope);
|
||||
|
||||
$rootScope.flashMessage = null;
|
||||
}
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
var fld, data;
|
||||
GenerateForm.clearApiErrors($scope);
|
||||
Wait('start');
|
||||
Rest.setUrl(defaultUrl);
|
||||
data = {};
|
||||
for (fld in form.fields) {
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
Rest.post(data)
|
||||
.success(function(data) {
|
||||
Wait('stop');
|
||||
$rootScope.flashMessage = "New team successfully created!";
|
||||
$rootScope.$broadcast("EditIndicatorChange", "users", data.id);
|
||||
$state.go('teams.edit', { team_id: data.id }, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to add new team. Post returned status: ' +
|
||||
status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('teams');
|
||||
};
|
||||
}
|
||||
];
|
||||
97
awx/ui/client/src/teams/edit/teams-edit.controller.js
Normal file
97
awx/ui/client/src/teams/edit/teams-edit.controller.js
Normal file
@ -0,0 +1,97 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$stateParams', 'TeamForm', 'Rest',
|
||||
'ProcessErrors', 'ClearScope', 'GetBasePath', 'Wait', '$state',
|
||||
function($scope, $rootScope, $stateParams,
|
||||
TeamForm, Rest, ProcessErrors, ClearScope, GetBasePath, Wait, $state) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var form = TeamForm,
|
||||
id = $stateParams.team_id,
|
||||
defaultUrl = GetBasePath('teams') + id;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.team_id = id;
|
||||
Rest.setUrl(defaultUrl);
|
||||
Wait('start');
|
||||
Rest.get(defaultUrl).success(function(data) {
|
||||
setScopeFields(data);
|
||||
$scope.organization_name = data.summary_fields.organization.name;
|
||||
|
||||
$scope.team_obj = data;
|
||||
Wait('stop');
|
||||
});
|
||||
|
||||
$scope.$watch('team_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||
if (val === false) {
|
||||
$scope.canAdd = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
// @issue I think all this really want to do is _.forEach(form.fields, (field) =>{ $scope[field] = data[field]})
|
||||
function setScopeFields(data) {
|
||||
_(data)
|
||||
.pick(function(value, key) {
|
||||
return form.fields.hasOwnProperty(key) === true;
|
||||
})
|
||||
.forEach(function(value, key) {
|
||||
$scope[key] = value;
|
||||
})
|
||||
.value();
|
||||
return;
|
||||
}
|
||||
|
||||
// prepares a data payload for a PUT request to the API
|
||||
function processNewData(fields) {
|
||||
var data = {};
|
||||
_.forEach(fields, function(value, key) {
|
||||
if ($scope[key] !== '' && $scope[key] !== null && $scope[key] !== undefined) {
|
||||
data[key] = $scope[key];
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('teams', null, { reload: true });
|
||||
};
|
||||
|
||||
$scope.formSave = function() {
|
||||
$rootScope.flashMessage = null;
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
var data = processNewData(form.fields);
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.put(data).success(function() {
|
||||
$state.go($state.current, null, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to retrieve user: ' +
|
||||
$stateParams.id + '. GET status: ' + status
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
|
||||
$scope.convertApiUrl = function(str) {
|
||||
if (str) {
|
||||
return str.replace("api/v1", "#");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
];
|
||||
81
awx/ui/client/src/teams/list/teams-list.controller.js
Normal file
81
awx/ui/client/src/teams/list/teams-list.controller.js
Normal file
@ -0,0 +1,81 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$log',
|
||||
'$stateParams', 'Rest', 'Alert', 'TeamList', 'Prompt', 'ClearScope',
|
||||
'ProcessErrors', 'GetBasePath', 'Wait', '$state', '$filter', 'rbacUiControlService', 'Dataset',
|
||||
function($scope, $rootScope, $log, $stateParams,
|
||||
Rest, Alert, TeamList, Prompt, ClearScope, ProcessErrors,
|
||||
GetBasePath, Wait, $state, $filter, rbacUiControlService, Dataset) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var list = TeamList,
|
||||
defaultUrl = GetBasePath('teams');
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.canAdd = false;
|
||||
|
||||
rbacUiControlService.canAdd('teams')
|
||||
.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;
|
||||
_.forEach($scope[list.name], (team) => {
|
||||
team.organization_name = team.summary_fields.organization.name;
|
||||
});
|
||||
|
||||
$scope.selected = [];
|
||||
}
|
||||
|
||||
$scope.addTeam = function() {
|
||||
$state.go('teams.add');
|
||||
};
|
||||
|
||||
$scope.editTeam = function(id) {
|
||||
$state.go('teams.edit', { team_id: id });
|
||||
};
|
||||
|
||||
$scope.deleteTeam = function(id, name) {
|
||||
|
||||
var action = function() {
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function() {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
if (parseInt($state.params.team_id) === id) {
|
||||
$state.go('^', null, { reload: true });
|
||||
} else {
|
||||
$state.go('.', null, { reload: true });
|
||||
}
|
||||
})
|
||||
.error(function(data, status) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
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 delete the team below?</div><div class="Prompt-bodyTarget">' + $filter('sanitize')(name) + '</div>',
|
||||
action: action,
|
||||
actionText: 'DELETE'
|
||||
});
|
||||
};
|
||||
}
|
||||
];
|
||||
47
awx/ui/client/src/teams/main.js
Normal file
47
awx/ui/client/src/teams/main.js
Normal file
@ -0,0 +1,47 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import TeamsList from './list/teams-list.controller';
|
||||
import TeamsAdd from './add/teams-add.controller';
|
||||
import TeamsEdit from './edit/teams-edit.controller';
|
||||
import { N_ } from '../i18n';
|
||||
|
||||
export default
|
||||
angular.module('Teams', [])
|
||||
.controller('TeamsList', TeamsList)
|
||||
.controller('TeamsAdd', TeamsAdd)
|
||||
.controller('TeamsEdit', TeamsEdit)
|
||||
.config(['$stateProvider', 'stateDefinitionsProvider',
|
||||
function($stateProvider, stateDefinitionsProvider) {
|
||||
let stateDefinitions = stateDefinitionsProvider.$get();
|
||||
|
||||
// lazily generate a tree of substates which will replace this node in ui-router's stateRegistry
|
||||
// see: stateDefinition.factory for usage documentation
|
||||
$stateProvider.state({
|
||||
name: 'teams',
|
||||
url: '/teams',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
parent: 'teams',
|
||||
modes: ['add', 'edit'],
|
||||
list: 'TeamList',
|
||||
form: 'TeamForm',
|
||||
controllers: {
|
||||
list: TeamsList,
|
||||
add: TeamsAdd,
|
||||
edit: TeamsEdit
|
||||
},
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'team'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: 'setup',
|
||||
label: N_('TEAMS')
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
]);
|
||||
119
awx/ui/client/src/users/add/users-add.controller.js
Normal file
119
awx/ui/client/src/users/add/users-add.controller.js
Normal file
@ -0,0 +1,119 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import { N_ } from "../../i18n";
|
||||
|
||||
const user_type_options = [
|
||||
{ type: 'normal', label: N_('Normal User') },
|
||||
{ type: 'system_auditor', label: N_('System Auditor') },
|
||||
{ type: 'system_administrator', label: N_('System Administrator') },
|
||||
];
|
||||
|
||||
export default ['$scope', '$rootScope', '$stateParams', 'UserForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'ReturnToCaller', 'ClearScope', 'GetBasePath',
|
||||
'ResetForm', 'Wait', 'CreateSelect2', '$state', '$location', 'i18n',
|
||||
function($scope, $rootScope, $stateParams, UserForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, ReturnToCaller, ClearScope,
|
||||
GetBasePath, ResetForm, Wait, CreateSelect2, $state, $location, i18n) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
var defaultUrl = GetBasePath('organizations'),
|
||||
form = UserForm;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
// apply form definition's default field values
|
||||
GenerateForm.applyDefaults(form, $scope);
|
||||
|
||||
$scope.ldap_user = false;
|
||||
$scope.not_ldap_user = !$scope.ldap_user;
|
||||
$scope.ldap_dn = null;
|
||||
$scope.socialAuthUser = false;
|
||||
$scope.external_account = null;
|
||||
|
||||
Rest.setUrl(GetBasePath('users'));
|
||||
Rest.options()
|
||||
.success(function(data) {
|
||||
if (!data.actions.POST) {
|
||||
$state.go("^");
|
||||
Alert(i18n._('Permission Error'), i18n._('You do not have permission to add a user.'), 'alert-info');
|
||||
}
|
||||
});
|
||||
|
||||
$scope.user_type_options = user_type_options;
|
||||
$scope.user_type = user_type_options[0];
|
||||
$scope.$watch('user_type', user_type_sync($scope));
|
||||
CreateSelect2({
|
||||
element: '#user_user_type',
|
||||
multiple: false
|
||||
});
|
||||
}
|
||||
|
||||
function user_type_sync($scope) {
|
||||
return (type_option) => {
|
||||
$scope.is_superuser = false;
|
||||
$scope.is_system_auditor = false;
|
||||
switch (type_option.type) {
|
||||
case 'system_administrator':
|
||||
$scope.is_superuser = true;
|
||||
break;
|
||||
case 'system_auditor':
|
||||
$scope.is_system_auditor = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Save
|
||||
$scope.formSave = function() {
|
||||
var fld, data = {};
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
if ($scope.organization !== undefined && $scope.organization !== null && $scope.organization !== '') {
|
||||
Rest.setUrl(defaultUrl + $scope.organization + '/users/');
|
||||
for (fld in form.fields) {
|
||||
if (form.fields[fld].realName) {
|
||||
data[form.fields[fld].realName] = $scope[fld];
|
||||
} else {
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
}
|
||||
data.is_superuser = $scope.is_superuser;
|
||||
data.is_system_auditor = $scope.is_system_auditor;
|
||||
Wait('start');
|
||||
Rest.post(data)
|
||||
.success(function(data) {
|
||||
var base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
if (base === 'users') {
|
||||
$rootScope.flashMessage = i18n._('New user successfully created!');
|
||||
$rootScope.$broadcast("EditIndicatorChange", "users", data.id);
|
||||
$state.go('users.edit', { user_id: data.id }, { reload: true });
|
||||
} else {
|
||||
ReturnToCaller(1);
|
||||
}
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, form, { hdr: i18n._('Error!'), msg: i18n._('Failed to add new user. POST returned status: ') + status });
|
||||
});
|
||||
} else {
|
||||
$scope.organization_name_api_error = i18n._('A value is required');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('users');
|
||||
};
|
||||
|
||||
// Password change
|
||||
$scope.clearPWConfirm = function(fld) {
|
||||
// If password value changes, make sure password_confirm must be re-entered
|
||||
$scope[fld] = '';
|
||||
$scope[form.name + '_form'][fld].$setValidity('awpassmatch', false);
|
||||
};
|
||||
}
|
||||
];
|
||||
179
awx/ui/client/src/users/edit/users-edit.controller.js
Normal file
179
awx/ui/client/src/users/edit/users-edit.controller.js
Normal file
@ -0,0 +1,179 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import { N_ } from "../../i18n";
|
||||
|
||||
const user_type_options = [
|
||||
{ type: 'normal', label: N_('Normal User') },
|
||||
{ type: 'system_auditor', label: N_('System Auditor') },
|
||||
{ type: 'system_administrator', label: N_('System Administrator') },
|
||||
];
|
||||
|
||||
export default ['$scope', '$rootScope', '$location',
|
||||
'$stateParams', 'UserForm', 'Rest', 'ProcessErrors', 'ClearScope', 'GetBasePath',
|
||||
'ResetForm', 'Wait', 'CreateSelect2', '$state', 'i18n',
|
||||
function($scope, $rootScope, $location,
|
||||
$stateParams, UserForm, Rest, ProcessErrors,
|
||||
ClearScope, GetBasePath, ResetForm, Wait, CreateSelect2, $state, i18n) {
|
||||
|
||||
for (var i = 0; i < user_type_options.length; i++) {
|
||||
user_type_options[i].label = i18n._(user_type_options[i].label);
|
||||
}
|
||||
ClearScope();
|
||||
|
||||
var form = UserForm,
|
||||
master = {},
|
||||
id = $stateParams.user_id,
|
||||
defaultUrl = GetBasePath('users') + id;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.hidePagination = false;
|
||||
$scope.hideSmartSearch = false;
|
||||
$scope.user_type_options = user_type_options;
|
||||
$scope.user_type = user_type_options[0];
|
||||
$scope.$watch('user_type', user_type_sync($scope));
|
||||
$scope.$watch('is_superuser', hidePermissionsTabSmartSearchAndPaginationIfSuperUser($scope));
|
||||
Rest.setUrl(defaultUrl);
|
||||
Wait('start');
|
||||
Rest.get(defaultUrl).success(function(data) {
|
||||
$scope.user_id = id;
|
||||
$scope.ldap_user = (data.ldap_dn !== null && data.ldap_dn !== undefined && data.ldap_dn !== '') ? true : false;
|
||||
$scope.not_ldap_user = !$scope.ldap_user;
|
||||
master.ldap_user = $scope.ldap_user;
|
||||
$scope.socialAuthUser = (data.auth.length > 0) ? true : false;
|
||||
$scope.external_account = data.external_account;
|
||||
|
||||
$scope.user_type = $scope.user_type_options[0];
|
||||
$scope.is_system_auditor = false;
|
||||
$scope.is_superuser = false;
|
||||
if (data.is_system_auditor) {
|
||||
$scope.user_type = $scope.user_type_options[1];
|
||||
$scope.is_system_auditor = true;
|
||||
}
|
||||
if (data.is_superuser) {
|
||||
$scope.user_type = $scope.user_type_options[2];
|
||||
$scope.is_superuser = true;
|
||||
}
|
||||
|
||||
$scope.user_obj = data;
|
||||
$scope.name = data.username;
|
||||
|
||||
CreateSelect2({
|
||||
element: '#user_user_type',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
$scope.$watch('user_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||
if (val === false) {
|
||||
$scope.canAdd = false;
|
||||
}
|
||||
});
|
||||
|
||||
setScopeFields(data);
|
||||
Wait('stop');
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Failed to retrieve user: %s. GET status: '), $stateParams.id) + status
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function user_type_sync($scope) {
|
||||
return (type_option) => {
|
||||
$scope.is_superuser = false;
|
||||
$scope.is_system_auditor = false;
|
||||
switch (type_option.type) {
|
||||
case 'system_administrator':
|
||||
$scope.is_superuser = true;
|
||||
break;
|
||||
case 'system_auditor':
|
||||
$scope.is_system_auditor = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Organizations and Teams tab pagination is hidden through other mechanism
|
||||
function hidePermissionsTabSmartSearchAndPaginationIfSuperUser(scope) {
|
||||
return function(isSuperuserNewValue) {
|
||||
let shouldHide = isSuperuserNewValue;
|
||||
if (shouldHide === true) {
|
||||
scope.hidePagination = true;
|
||||
scope.hideSmartSearch = true;
|
||||
} else if (shouldHide === false) {
|
||||
scope.hidePagination = false;
|
||||
scope.hideSmartSearch = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function setScopeFields(data) {
|
||||
_(data)
|
||||
.pick(function(value, key) {
|
||||
return form.fields.hasOwnProperty(key) === true;
|
||||
})
|
||||
.forEach(function(value, key) {
|
||||
$scope[key] = value;
|
||||
})
|
||||
.value();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.convertApiUrl = function(str) {
|
||||
if (str) {
|
||||
return str.replace("api/v1", "#");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// prepares a data payload for a PUT request to the API
|
||||
var processNewData = function(fields) {
|
||||
var data = {};
|
||||
_.forEach(fields, function(value, key) {
|
||||
if ($scope[key] !== '' && $scope[key] !== null && $scope[key] !== undefined) {
|
||||
data[key] = $scope[key];
|
||||
}
|
||||
});
|
||||
data.is_superuser = $scope.is_superuser;
|
||||
data.is_system_auditor = $scope.is_system_auditor;
|
||||
return data;
|
||||
};
|
||||
|
||||
$scope.formCancel = function() {
|
||||
$state.go('users', null, { reload: true });
|
||||
};
|
||||
|
||||
$scope.formSave = function() {
|
||||
$rootScope.flashMessage = null;
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
Rest.setUrl(defaultUrl + '/');
|
||||
var data = processNewData(form.fields);
|
||||
Rest.put(data).success(function() {
|
||||
$state.go($state.current, null, { reload: true });
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Failed to retrieve user: %s. GET status: '), $stateParams.id) + status
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clearPWConfirm = function(fld) {
|
||||
// If password value changes, make sure password_confirm must be re-entered
|
||||
$scope[fld] = '';
|
||||
$scope[form.name + '_form'][fld].$setValidity('awpassmatch', false);
|
||||
$rootScope.flashMessage = null;
|
||||
};
|
||||
}
|
||||
];
|
||||
90
awx/ui/client/src/users/list/users-list.controller.js
Normal file
90
awx/ui/client/src/users/list/users-list.controller.js
Normal file
@ -0,0 +1,90 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import { N_ } from "../../i18n";
|
||||
|
||||
const user_type_options = [
|
||||
{ type: 'normal', label: N_('Normal User') },
|
||||
{ type: 'system_auditor', label: N_('System Auditor') },
|
||||
{ type: 'system_administrator', label: N_('System Administrator') },
|
||||
];
|
||||
|
||||
export default ['$scope', '$rootScope', '$stateParams',
|
||||
'Rest', 'Alert', 'UserList', 'Prompt', 'ClearScope', 'ProcessErrors', 'GetBasePath',
|
||||
'Wait', '$state', '$filter', 'rbacUiControlService', 'Dataset', 'i18n',
|
||||
function($scope, $rootScope, $stateParams,
|
||||
Rest, Alert, UserList, Prompt, ClearScope, ProcessErrors, GetBasePath,
|
||||
Wait, $state, $filter, rbacUiControlService, Dataset, i18n) {
|
||||
|
||||
for (var i = 0; i < user_type_options.length; i++) {
|
||||
user_type_options[i].label = i18n._(user_type_options[i].label);
|
||||
}
|
||||
|
||||
ClearScope();
|
||||
|
||||
var list = UserList,
|
||||
defaultUrl = GetBasePath('users');
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
$scope.canAdd = false;
|
||||
|
||||
rbacUiControlService.canAdd('users')
|
||||
.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;
|
||||
|
||||
|
||||
$rootScope.flashMessage = null;
|
||||
$scope.selected = [];
|
||||
}
|
||||
|
||||
$scope.addUser = function() {
|
||||
$state.go('users.add');
|
||||
};
|
||||
|
||||
$scope.editUser = function(id) {
|
||||
$state.go('users.edit', { user_id: id });
|
||||
};
|
||||
|
||||
$scope.deleteUser = function(id, name) {
|
||||
|
||||
var action = function() {
|
||||
$('#prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function() {
|
||||
if (parseInt($state.params.user_id) === id) {
|
||||
$state.go('^', null, { reload: true });
|
||||
} else {
|
||||
$state.go('.', null, { reload: true });
|
||||
}
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: i18n._('Error!'),
|
||||
msg: i18n.sprintf(i18n._('Call to %s failed. DELETE returned status: '), url) + status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Prompt({
|
||||
hdr: i18n._('Delete'),
|
||||
body: '<div class="Prompt-bodyQuery">' + i18n._('Are you sure you want to delete the user below?') + '</div><div class="Prompt-bodyTarget">' + $filter('sanitize')(name) + '</div>',
|
||||
action: action,
|
||||
actionText: i18n._('DELETE')
|
||||
});
|
||||
};
|
||||
}
|
||||
];
|
||||
47
awx/ui/client/src/users/main.js
Normal file
47
awx/ui/client/src/users/main.js
Normal file
@ -0,0 +1,47 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import UsersList from './list/users-list.controller';
|
||||
import UsersAdd from './add/users-add.controller';
|
||||
import UsersEdit from './edit/users-edit.controller';
|
||||
import { N_ } from '../i18n';
|
||||
|
||||
export default
|
||||
angular.module('Users', [])
|
||||
.controller('UsersList', UsersList)
|
||||
.controller('UsersAdd', UsersAdd)
|
||||
.controller('UsersEdit', UsersEdit)
|
||||
.config(['$stateProvider', 'stateDefinitionsProvider',
|
||||
function($stateProvider, stateDefinitionsProvider) {
|
||||
let stateDefinitions = stateDefinitionsProvider.$get();
|
||||
|
||||
// lazily generate a tree of substates which will replace this node in ui-router's stateRegistry
|
||||
// see: stateDefinition.factory for usage documentation
|
||||
$stateProvider.state({
|
||||
name: 'users',
|
||||
url: '/users',
|
||||
lazyLoad: () => stateDefinitions.generateTree({
|
||||
parent: 'users',
|
||||
modes: ['add', 'edit'],
|
||||
list: 'UserList',
|
||||
form: 'UserForm',
|
||||
controllers: {
|
||||
list: UsersList,
|
||||
add: UsersAdd,
|
||||
edit: UsersEdit
|
||||
},
|
||||
data: {
|
||||
activityStream: true,
|
||||
activityStreamTarget: 'user'
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: 'setup',
|
||||
label: N_('USERS')
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
]);
|
||||
Loading…
x
Reference in New Issue
Block a user